potentials/meta/
cutoff.rs1use crate::base::Potential2;
19use crate::math::{Mask, Vector};
20
21#[derive(Clone, Copy, Debug)]
28pub struct Cutoff<P, T> {
29 inner: P,
30 rc_sq: T,
31}
32
33impl<P, T: Vector> Cutoff<P, T> {
34 #[inline]
50 pub fn new(inner: P, rc: f64) -> Self {
51 Self {
52 inner,
53 rc_sq: T::splat(rc * rc),
54 }
55 }
56
57 #[inline]
59 pub fn inner(&self) -> &P {
60 &self.inner
61 }
62}
63
64impl<P: Potential2<T>, T: Vector> Potential2<T> for Cutoff<P, T> {
65 #[inline(always)]
66 fn energy(&self, r_sq: T) -> T {
67 let e = self.inner.energy(r_sq);
68 let mask = r_sq.lt(self.rc_sq);
69 mask.select(e, T::zero())
70 }
71
72 #[inline(always)]
73 fn force_factor(&self, r_sq: T) -> T {
74 let s = self.inner.force_factor(r_sq);
75 let mask = r_sq.lt(self.rc_sq);
76 mask.select(s, T::zero())
77 }
78
79 #[inline(always)]
80 fn energy_force(&self, r_sq: T) -> (T, T) {
81 let (e, s) = self.inner.energy_force(r_sq);
82 let mask = r_sq.lt(self.rc_sq);
83 (mask.select(e, T::zero()), mask.select(s, T::zero()))
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90 use crate::pair::Lj;
91 use approx::assert_relative_eq;
92
93 #[test]
94 fn test_cutoff_inside() {
95 let lj: Lj<f64> = Lj::new(1.0, 3.4);
96 let lj_cut = Cutoff::new(lj, 12.0);
97
98 let r_sq = 16.0;
99
100 let e_base = lj.energy(r_sq);
101 let e_cut = lj_cut.energy(r_sq);
102
103 assert_relative_eq!(e_base, e_cut, epsilon = 1e-10);
104 }
105
106 #[test]
107 fn test_cutoff_outside() {
108 let lj: Lj<f64> = Lj::new(1.0, 3.4);
109 let lj_cut = Cutoff::new(lj, 10.0);
110
111 let r_sq = 121.0;
112
113 let e = lj_cut.energy(r_sq);
114 assert_relative_eq!(e, 0.0, epsilon = 1e-10);
115
116 let s = lj_cut.force_factor(r_sq);
117 assert_relative_eq!(s, 0.0, epsilon = 1e-10);
118 }
119
120 #[test]
121 fn test_cutoff_at_boundary() {
122 let lj: Lj<f64> = Lj::new(1.0, 3.4);
123 let rc = 10.0;
124 let lj_cut = Cutoff::new(lj, rc);
125
126 let r_in = rc - 0.001;
127 let e_in = lj_cut.energy(r_in * r_in);
128 assert!(e_in != 0.0);
129
130 let r_out = rc + 0.001;
131 let e_out = lj_cut.energy(r_out * r_out);
132 assert_relative_eq!(e_out, 0.0, epsilon = 1e-10);
133 }
134}