#[cfg(test)]
mod test;
mod harmonic;
mod morse;
pub use harmonic::Harmonic;
pub use morse::Morse;
use crate::{
math::{Quantity, Scalar},
units::{
BOLTZMANN_CONSTANT, Energy, Force, ForcePerLength, Length, ReciprocalForcePerLength,
Stress, Temperature,
},
};
use std::fmt::Debug;
pub trait Potential
where
Self: Clone + Debug,
{
fn energy(&self, length: Quantity<Length>) -> Quantity<Energy>;
fn nondimensional_energy(
&self,
nondimensional_length: Scalar,
temperature: Quantity<Temperature>,
) -> Scalar {
let length = self.rest_length() * nondimensional_length;
(self.energy(length) / (BOLTZMANN_CONSTANT * temperature)).value()
}
fn energy_at_force(&self, force: Quantity<Force>) -> Quantity<Energy> {
let extension = self.extension(force);
let length = self.rest_length() + extension;
self.energy(length)
}
fn nondimensional_energy_at_nondimensional_force(
&self,
nondimensional_force: Scalar,
temperature: Quantity<Temperature>,
) -> Scalar {
let force = BOLTZMANN_CONSTANT * temperature / self.rest_length() * nondimensional_force;
(self.energy_at_force(force) / (BOLTZMANN_CONSTANT * temperature)).value()
}
fn force(&self, length: Quantity<Length>) -> Quantity<Force>;
fn nondimensional_force(
&self,
nondimensional_length: Scalar,
temperature: Quantity<Temperature>,
) -> Scalar {
let length = self.rest_length() * nondimensional_length;
((self.force(length) * self.rest_length()) / (BOLTZMANN_CONSTANT * temperature)).value()
}
fn forces_at_energy(&self, energy: Quantity<Energy>) -> [Quantity<Force>; 2];
fn nondimensional_forces_at_nondimensional_energy(
&self,
nondimensional_energy: Scalar,
temperature: Quantity<Temperature>,
) -> [Scalar; 2] {
let energy = BOLTZMANN_CONSTANT * temperature * nondimensional_energy;
self.forces_at_energy(energy).map(|force| {
((force * self.rest_length()) / (BOLTZMANN_CONSTANT * temperature)).value()
})
}
fn stiffness(&self, length: Quantity<Length>) -> Quantity<ForcePerLength>;
fn nondimensional_stiffness(
&self,
nondimensional_length: Scalar,
temperature: Quantity<Temperature>,
) -> Scalar {
let length = self.rest_length() * nondimensional_length;
((self.stiffness(length) * (self.rest_length() * self.rest_length()))
/ (BOLTZMANN_CONSTANT * temperature))
.value()
}
fn anharmonicity(&self, length: Quantity<Length>) -> Quantity<Stress>;
fn nondimensional_anharmonicity(
&self,
nondimensional_length: Scalar,
temperature: Quantity<Temperature>,
) -> Scalar {
let length = self.rest_length() * nondimensional_length;
((self.anharmonicity(length)
* (self.rest_length() * self.rest_length() * self.rest_length()))
/ (BOLTZMANN_CONSTANT * temperature))
.value()
}
fn legendre(&self, force: Quantity<Force>) -> Quantity<Energy> {
let extension = self.extension(force);
let length = self.rest_length() + extension;
self.energy(length) - force * extension
}
fn nondimensional_legendre(
&self,
nondimensional_force: Scalar,
temperature: Quantity<Temperature>,
) -> Scalar {
let force = BOLTZMANN_CONSTANT * temperature / self.rest_length() * nondimensional_force;
(self.legendre(force) / (BOLTZMANN_CONSTANT * temperature)).value()
}
fn extension(&self, force: Quantity<Force>) -> Quantity<Length>;
fn nondimensional_extension(
&self,
nondimensional_force: Scalar,
temperature: Quantity<Temperature>,
) -> Scalar {
let force = BOLTZMANN_CONSTANT * temperature / self.rest_length() * nondimensional_force;
(self.extension(force) / self.rest_length()).value()
}
fn length(&self, force: Quantity<Force>) -> Quantity<Length> {
self.rest_length() + self.extension(force)
}
fn nondimensional_length(
&self,
nondimensional_force: Scalar,
temperature: Quantity<Temperature>,
) -> Scalar {
1.0 + self.nondimensional_extension(nondimensional_force, temperature)
}
fn extensions_at_energy(&self, energy: Quantity<Energy>) -> [Quantity<Length>; 2];
fn nondimensional_extensions_at_nondimensional_energy(
&self,
nondimensional_energy: Scalar,
temperature: Quantity<Temperature>,
) -> [Scalar; 2] {
let energy = BOLTZMANN_CONSTANT * temperature * nondimensional_energy;
self.extensions_at_energy(energy)
.map(|extension| (extension / self.rest_length()).value())
}
fn lengths_at_energy(&self, energy: Quantity<Energy>) -> [Quantity<Length>; 2] {
self.extensions_at_energy(energy)
.map(|extension| extension + self.rest_length())
}
fn nondimensional_lengths_at_nondimensional_energy(
&self,
nondimensional_energy: Scalar,
temperature: Quantity<Temperature>,
) -> [Scalar; 2] {
self.nondimensional_extensions_at_nondimensional_energy(nondimensional_energy, temperature)
.map(|extension| extension + 1.0)
}
fn compliance(&self, force: Quantity<Force>) -> Quantity<ReciprocalForcePerLength>;
fn nondimensional_compliance(
&self,
nondimensional_force: Scalar,
temperature: Quantity<Temperature>,
) -> Scalar {
let force = BOLTZMANN_CONSTANT * temperature / self.rest_length() * nondimensional_force;
((self.compliance(force) * (BOLTZMANN_CONSTANT * temperature))
/ (self.rest_length() * self.rest_length()))
.value()
}
fn peak(&self) -> Quantity<Length>;
fn peak_force(&self) -> Quantity<Force>;
fn rest_length(&self) -> Quantity<Length>;
}