conspire/physics/molecular/potential/
mod.rs1#[cfg(test)]
2mod test;
3
4mod harmonic;
5mod morse;
7
8pub use harmonic::Harmonic;
9pub use morse::Morse;
10
11use crate::{
12 math::{Quantity, Scalar},
13 units::{
14 BOLTZMANN_CONSTANT, Energy, Force, ForcePerLength, Length, ReciprocalForcePerLength,
15 Stress, Temperature,
16 },
17};
18use std::fmt::Debug;
19
20pub trait Potential
22where
23 Self: Clone + Debug,
24{
25 fn energy(&self, length: Quantity<Length>) -> Quantity<Energy>;
29 fn nondimensional_energy(
33 &self,
34 nondimensional_length: Scalar,
35 temperature: Quantity<Temperature>,
36 ) -> Scalar {
37 let length = self.rest_length() * nondimensional_length;
38 (self.energy(length) / (BOLTZMANN_CONSTANT * temperature)).value()
39 }
40 fn energy_at_force(&self, force: Quantity<Force>) -> Quantity<Energy> {
44 let extension = self.extension(force);
45 let length = self.rest_length() + extension;
46 self.energy(length)
47 }
48 fn nondimensional_energy_at_nondimensional_force(
52 &self,
53 nondimensional_force: Scalar,
54 temperature: Quantity<Temperature>,
55 ) -> Scalar {
56 let force = BOLTZMANN_CONSTANT * temperature / self.rest_length() * nondimensional_force;
57 (self.energy_at_force(force) / (BOLTZMANN_CONSTANT * temperature)).value()
58 }
59 fn force(&self, length: Quantity<Length>) -> Quantity<Force>;
63 fn nondimensional_force(
67 &self,
68 nondimensional_length: Scalar,
69 temperature: Quantity<Temperature>,
70 ) -> Scalar {
71 let length = self.rest_length() * nondimensional_length;
72 ((self.force(length) * self.rest_length()) / (BOLTZMANN_CONSTANT * temperature)).value()
73 }
74 fn forces_at_energy(&self, energy: Quantity<Energy>) -> [Quantity<Force>; 2];
78 fn nondimensional_forces_at_nondimensional_energy(
82 &self,
83 nondimensional_energy: Scalar,
84 temperature: Quantity<Temperature>,
85 ) -> [Scalar; 2] {
86 let energy = BOLTZMANN_CONSTANT * temperature * nondimensional_energy;
87 self.forces_at_energy(energy).map(|force| {
88 ((force * self.rest_length()) / (BOLTZMANN_CONSTANT * temperature)).value()
89 })
90 }
91 fn stiffness(&self, length: Quantity<Length>) -> Quantity<ForcePerLength>;
95 fn nondimensional_stiffness(
99 &self,
100 nondimensional_length: Scalar,
101 temperature: Quantity<Temperature>,
102 ) -> Scalar {
103 let length = self.rest_length() * nondimensional_length;
104 ((self.stiffness(length) * (self.rest_length() * self.rest_length()))
105 / (BOLTZMANN_CONSTANT * temperature))
106 .value()
107 }
108 fn anharmonicity(&self, length: Quantity<Length>) -> Quantity<Stress>;
112 fn nondimensional_anharmonicity(
116 &self,
117 nondimensional_length: Scalar,
118 temperature: Quantity<Temperature>,
119 ) -> Scalar {
120 let length = self.rest_length() * nondimensional_length;
121 ((self.anharmonicity(length)
122 * (self.rest_length() * self.rest_length() * self.rest_length()))
123 / (BOLTZMANN_CONSTANT * temperature))
124 .value()
125 }
126 fn legendre(&self, force: Quantity<Force>) -> Quantity<Energy> {
130 let extension = self.extension(force);
131 let length = self.rest_length() + extension;
132 self.energy(length) - force * extension
133 }
134 fn nondimensional_legendre(
138 &self,
139 nondimensional_force: Scalar,
140 temperature: Quantity<Temperature>,
141 ) -> Scalar {
142 let force = BOLTZMANN_CONSTANT * temperature / self.rest_length() * nondimensional_force;
143 (self.legendre(force) / (BOLTZMANN_CONSTANT * temperature)).value()
144 }
145 fn extension(&self, force: Quantity<Force>) -> Quantity<Length>;
149 fn nondimensional_extension(
153 &self,
154 nondimensional_force: Scalar,
155 temperature: Quantity<Temperature>,
156 ) -> Scalar {
157 let force = BOLTZMANN_CONSTANT * temperature / self.rest_length() * nondimensional_force;
158 (self.extension(force) / self.rest_length()).value()
159 }
160 fn length(&self, force: Quantity<Force>) -> Quantity<Length> {
164 self.rest_length() + self.extension(force)
165 }
166 fn nondimensional_length(
170 &self,
171 nondimensional_force: Scalar,
172 temperature: Quantity<Temperature>,
173 ) -> Scalar {
174 1.0 + self.nondimensional_extension(nondimensional_force, temperature)
175 }
176 fn extensions_at_energy(&self, energy: Quantity<Energy>) -> [Quantity<Length>; 2];
180 fn nondimensional_extensions_at_nondimensional_energy(
184 &self,
185 nondimensional_energy: Scalar,
186 temperature: Quantity<Temperature>,
187 ) -> [Scalar; 2] {
188 let energy = BOLTZMANN_CONSTANT * temperature * nondimensional_energy;
189 self.extensions_at_energy(energy)
190 .map(|extension| (extension / self.rest_length()).value())
191 }
192 fn lengths_at_energy(&self, energy: Quantity<Energy>) -> [Quantity<Length>; 2] {
196 self.extensions_at_energy(energy)
197 .map(|extension| extension + self.rest_length())
198 }
199 fn nondimensional_lengths_at_nondimensional_energy(
203 &self,
204 nondimensional_energy: Scalar,
205 temperature: Quantity<Temperature>,
206 ) -> [Scalar; 2] {
207 self.nondimensional_extensions_at_nondimensional_energy(nondimensional_energy, temperature)
208 .map(|extension| extension + 1.0)
209 }
210 fn compliance(&self, force: Quantity<Force>) -> Quantity<ReciprocalForcePerLength>;
214 fn nondimensional_compliance(
218 &self,
219 nondimensional_force: Scalar,
220 temperature: Quantity<Temperature>,
221 ) -> Scalar {
222 let force = BOLTZMANN_CONSTANT * temperature / self.rest_length() * nondimensional_force;
223 ((self.compliance(force) * (BOLTZMANN_CONSTANT * temperature))
224 / (self.rest_length() * self.rest_length()))
225 .value()
226 }
227 fn peak(&self) -> Quantity<Length>;
231 fn peak_force(&self) -> Quantity<Force>;
235 fn rest_length(&self) -> Quantity<Length>;
239}