interatomic/twobody/
wca.rs1use crate::twobody::IsotropicTwobodyEnergy;
16use crate::{twobody::LennardJones, Cutoff};
17
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Serialize};
20
21#[derive(Debug, Clone, PartialEq, Default)]
40#[cfg_attr(
41 feature = "serde",
42 derive(Deserialize, Serialize),
43 serde(deny_unknown_fields)
44)]
45pub struct WeeksChandlerAndersen {
46 #[cfg_attr(feature = "serde", serde(flatten))]
47 lennard_jones: LennardJones,
48}
49
50impl WeeksChandlerAndersen {
51 const ONEFOURTH: f64 = 0.25;
52 pub(crate) const TWOTOTWOSIXTH: f64 = 1.2599210498948732; pub const fn new(epsilon: f64, sigma: f64) -> Self {
56 Self {
57 lennard_jones: LennardJones::new(epsilon, sigma),
58 }
59 }
60}
61
62impl Cutoff for WeeksChandlerAndersen {
63 #[inline(always)]
64 fn cutoff_squared(&self) -> f64 {
65 self.lennard_jones.sigma_squared * Self::TWOTOTWOSIXTH
66 }
67 #[inline(always)]
68 fn cutoff(&self) -> f64 {
69 self.cutoff_squared().sqrt()
70 }
71 fn lower_cutoff(&self) -> f64 {
72 self.lennard_jones.lower_cutoff()
73 }
74}
75
76impl From<LennardJones> for WeeksChandlerAndersen {
78 fn from(lennard_jones: LennardJones) -> Self {
79 Self { lennard_jones }
80 }
81}
82
83impl IsotropicTwobodyEnergy for WeeksChandlerAndersen {
84 #[inline(always)]
85 fn isotropic_twobody_energy(&self, distance_squared: f64) -> f64 {
86 if distance_squared > self.cutoff_squared() {
87 return 0.0;
88 }
89 let x6 = (self.lennard_jones.sigma_squared / distance_squared).powi(3); self.lennard_jones.four_times_epsilon * (x6 * x6 - x6 + Self::ONEFOURTH)
91 }
92
93 #[inline(always)]
94 fn isotropic_twobody_force(&self, distance_squared: f64) -> f64 {
95 if distance_squared > self.cutoff_squared() {
96 return 0.0;
97 }
98 self.lennard_jones.isotropic_twobody_force(distance_squared)
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::twobody::LennardJones;
106 use approx::assert_relative_eq;
107
108 #[test]
109 fn test_wca_force() {
110 let (epsilon, sigma) = (1.5, 2.0);
111 let wca = WeeksChandlerAndersen::new(epsilon, sigma);
112 let lj = LennardJones::new(epsilon, sigma);
113 assert_relative_eq!(
115 wca.isotropic_twobody_force(4.0),
116 lj.isotropic_twobody_force(4.0)
117 );
118 assert_relative_eq!(wca.isotropic_twobody_force(6.0), 0.0);
120 }
121}