hoomd_mc/translate/
cartesian.rs1use rand::{Rng, distr::Distribution};
7
8use super::Translate;
9use crate::LocalTrial;
10use hoomd_microstate::property::Position;
11use hoomd_vector::{Cartesian, distribution::Ball};
12
13impl<const N: usize, B> LocalTrial<B> for Translate<Cartesian<N>>
14where
15 B: Position<Position = Cartesian<N>>,
16 Ball: Distribution<Cartesian<N>>,
17{
18 #[inline]
40 fn propose<R: Rng>(&self, rng: &mut R, body_properties: B) -> B {
41 let mut trial = body_properties;
42
43 let ball = Ball {
44 radius: self.maximum_distance,
45 };
46
47 let delta_r = ball.sample(rng);
48 *trial.position_mut() += delta_r;
49
50 trial
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use hoomd_microstate::property::Point;
58 use hoomd_vector::{Cartesian, InnerProduct};
59 use rand::{SeedableRng, rngs::StdRng};
60 use rstest::*;
61
62 const N: usize = 2048;
64
65 #[rstest]
66 fn translate(#[values(0.1, 1.0)] d: f64) {
67 let mut total = Cartesian::from([0.0, 0.0, 0.0]);
71 let mut min_norm = f64::INFINITY;
72 let mut max_norm = 0.0_f64;
73
74 let mut rng = StdRng::seed_from_u64(1);
75 let a = Point::new(Cartesian::from([1.0, -5.0, 2.5]));
76 let translate = Translate::<Cartesian<3>>::with_maximum_distance(
77 d.try_into()
78 .expect("hard-coded constant should be a positive real"),
79 );
80
81 for _ in 0..N {
82 let b = translate.propose(&mut rng, a);
83
84 let delta_r = b.position - a.position;
85 total += delta_r;
86 min_norm = min_norm.min(delta_r.norm());
87 max_norm = max_norm.max(delta_r.norm());
88 }
89
90 assert!(max_norm <= d);
91
92 let average = total / N as f64;
93
94 assert!(min_norm < d * 0.1);
96 assert!(max_norm > d * 0.9);
97 for x in average.coordinates {
98 assert!(x.abs() < d * 0.1);
99 }
100 }
101}