use super::IsotropicTwobodyEnergy;
#[cfg(feature = "serde")]
use crate::{sqrt_serialize, square_deserialize};
use crate::{CombinationRule, Cutoff};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Default)]
#[cfg_attr(
feature = "serde",
derive(Deserialize, Serialize),
serde(deny_unknown_fields)
)]
pub struct HardSphere {
#[cfg_attr(
feature = "serde",
serde(
rename = "sigma",
alias = "σ",
serialize_with = "sqrt_serialize",
deserialize_with = "square_deserialize"
)
)]
min_distance_squared: f64,
}
impl HardSphere {
pub const fn new(min_distance: f64) -> Self {
Self {
min_distance_squared: min_distance * min_distance,
}
}
pub fn from_combination_rule(rule: CombinationRule, sigmas: (f64, f64)) -> Self {
let sigma = rule.mix_sigmas(sigmas);
Self::new(sigma)
}
}
impl IsotropicTwobodyEnergy for HardSphere {
#[inline(always)]
fn isotropic_twobody_energy(&self, distance_squared: f64) -> f64 {
if distance_squared < self.min_distance_squared {
f64::INFINITY
} else {
0.0
}
}
#[inline(always)]
fn isotropic_twobody_force(&self, _distance_squared: f64) -> f64 {
0.0
}
}
impl Cutoff for HardSphere {
fn cutoff(&self) -> f64 {
self.cutoff_squared().sqrt()
}
fn cutoff_squared(&self) -> f64 {
self.min_distance_squared
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hardsphere_force() {
let hs = HardSphere::new(2.0);
assert_eq!(hs.isotropic_twobody_force(1.0), 0.0);
assert_eq!(hs.isotropic_twobody_force(5.0), 0.0);
}
}