conspire/physics/molecular/potential/morse/
mod.rs1use crate::{
2 math::{Quantity, Scalar},
3 physics::molecular::potential::Potential,
4 units::{
5 Energy, Force, ForcePerLength, Length, ReciprocalForcePerLength, ReciprocalLength, Stress,
6 },
7};
8
9#[derive(Clone, Debug)]
12pub struct Morse {
13 pub rest_length: Scalar,
15 pub depth: Scalar,
17 pub parameter: Scalar,
19}
20
21impl Morse {
22 fn depth(&self) -> Quantity<Energy> {
24 Quantity::new(self.depth)
25 }
26 fn parameter(&self) -> Quantity<ReciprocalLength> {
28 Quantity::new(self.parameter)
29 }
30}
31
32impl Potential for Morse {
33 fn energy(&self, length: Quantity<Length>) -> Quantity<Energy> {
37 let exp = (self.parameter() * (self.rest_length() - length)).exp();
38 self.depth() * (1.0 - exp).powi(2)
39 }
40 fn force(&self, length: Quantity<Length>) -> Quantity<Force> {
44 let exp = (self.parameter() * (self.rest_length() - length)).exp();
45 2.0 * self.parameter() * self.depth() * exp * (1.0 - exp)
46 }
47 fn forces_at_energy(&self, energy: Quantity<Energy>) -> [Quantity<Force>; 2] {
51 let y = energy / self.depth();
52 let f = 2.0 * self.parameter() * self.depth() * y.sqrt();
53 let tensile = if (0.0..=1.0).contains(&y) {
54 f * (1.0 - y.sqrt())
55 } else {
56 Quantity::new(Scalar::NAN)
57 };
58 [tensile, -f * (1.0 + y.sqrt())]
59 }
60 fn stiffness(&self, length: Quantity<Length>) -> Quantity<ForcePerLength> {
64 let exp = (self.parameter() * (self.rest_length() - length)).exp();
65 2.0 * (self.parameter() * self.parameter()) * self.depth() * exp * (2.0 * exp - 1.0)
66 }
67 fn anharmonicity(&self, length: Quantity<Length>) -> Quantity<Stress> {
71 let exp = (self.parameter() * (self.rest_length() - length)).exp();
72 2.0 * (self.parameter() * self.parameter())
73 * self.depth()
74 * self.parameter()
75 * exp
76 * (1.0 - 4.0 * exp)
77 }
78 fn extension(&self, force: Quantity<Force>) -> Quantity<Length> {
82 let y = force / self.peak_force();
83 if y <= 1.0 {
84 (2.0 / (1.0 + (1.0 - y).sqrt())).ln() / self.parameter()
85 } else {
86 Quantity::new(Scalar::NAN)
87 }
88 }
89 fn extensions_at_energy(&self, energy: Quantity<Energy>) -> [Quantity<Length>; 2] {
93 let y = energy / self.depth();
94 let tensile = if (0.0..=1.0).contains(&y) {
95 (1.0 / (1.0 - y.sqrt())).ln() / self.parameter()
96 } else {
97 Quantity::new(Scalar::NAN)
98 };
99 [tensile, (1.0 / (1.0 + y.sqrt())).ln() / self.parameter()]
100 }
101 fn compliance(&self, force: Quantity<Force>) -> Quantity<ReciprocalForcePerLength> {
105 let y = force / self.peak_force();
106 if (0.0..1.0).contains(&y) {
107 let s = (1.0 - y).sqrt();
108 1.0 / (self.parameter() * self.parameter() * self.depth()) / (s * (1.0 + s))
109 } else if y == 0.0 {
110 Quantity::new(Scalar::INFINITY)
111 } else {
112 Quantity::new(Scalar::NAN)
113 }
114 }
115 fn peak(&self) -> Quantity<Length> {
119 self.rest_length() + 2.0_f64.ln() / self.parameter()
120 }
121 fn peak_force(&self) -> Quantity<Force> {
125 0.5 * self.parameter() * self.depth()
126 }
127 fn rest_length(&self) -> Quantity<Length> {
131 Quantity::new(self.rest_length)
132 }
133}