use serde::{Deserialize, Serialize};
use super::{UnivariateEnergy, UnivariateForce};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct HarmonicRepulsion {
pub a: f64,
pub r_cut: f64,
}
impl UnivariateEnergy for HarmonicRepulsion {
#[inline]
fn energy(&self, r: f64) -> f64 {
if r < self.r_cut {
0.5 * self.a / self.r_cut * (r - self.r_cut).powi(2)
} else {
0.0
}
}
}
impl UnivariateForce for HarmonicRepulsion {
#[inline]
fn force(&self, r: f64) -> f64 {
if r < self.r_cut {
self.a / self.r_cut * (self.r_cut - r)
} else {
0.0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use approxim::assert_relative_eq;
use rstest::*;
#[rstest]
fn outside_rcut(#[values(1.0, 2.0, 5.0, 10.0)] a: f64, #[values(1.0, 2.0, 3.0)] r_cut: f64) {
let h_repulsion = HarmonicRepulsion { a, r_cut };
assert_eq!(h_repulsion.a, a);
assert_eq!(h_repulsion.r_cut, r_cut);
assert_eq!(h_repulsion.energy(r_cut + 1.0), 0.0);
assert_eq!(h_repulsion.force(r_cut + 1.0), 0.0);
}
#[rstest]
fn general_case(#[values(1.0, 2.0, 5.0, 10.0)] a: f64, #[values(1.0, 2.0, 3.0)] r_cut: f64) {
let r = 0.5;
let h_repulsion = HarmonicRepulsion { a, r_cut };
assert_eq!(h_repulsion.a, a);
assert_eq!(h_repulsion.r_cut, r_cut);
let expected_energy = a * (r_cut - r) - 0.5 * a / r_cut * (r_cut * r_cut - r * r);
let expected_force = a * (1.0 - r / r_cut);
assert_relative_eq!(h_repulsion.energy(r), expected_energy);
assert_relative_eq!(h_repulsion.force(r), expected_force);
}
}