hoomd_mc/translate/
hyperboloid.rs1use rand::{Rng, distr::Distribution};
7
8use crate::{LocalTrial, Translate};
9use hoomd_manifold::{Hyperbolic, HyperbolicDisk, Minkowski};
10use hoomd_microstate::property::{Orientation, OrientedHyperbolicPoint, Point, Position};
11use hoomd_vector::Angle;
12
13impl LocalTrial<Point<Hyperbolic<3>>> for Translate<Point<Hyperbolic<3>>> {
14 #[inline]
59 fn propose<R: Rng>(
60 &self,
61 rng: &mut R,
62 body_properties: Point<Hyperbolic<3>>,
63 ) -> Point<Hyperbolic<3>> {
64 let mut trial = body_properties;
65 let disk = HyperbolicDisk {
66 disk_radius: *self.maximum_distance(),
67 point: *trial.position_mut(),
68 };
69 let trial_sample: Hyperbolic<3> = disk.sample(rng);
70 *trial.position_mut() = Hyperbolic::from_minkowski_coordinates(Minkowski::from([
72 trial_sample.coordinates()[0],
73 trial_sample.coordinates()[1],
74 (trial_sample.point()[0].powi(2) + trial_sample.point()[1].powi(2) + 1.0_f64).sqrt(),
75 ]));
76 trial
77 }
78}
79
80impl LocalTrial<OrientedHyperbolicPoint<3, Angle>>
81 for Translate<OrientedHyperbolicPoint<3, Angle>>
82{
83 #[inline]
85 fn propose<R: Rng>(
86 &self,
87 rng: &mut R,
88 body_properties: OrientedHyperbolicPoint<3, Angle>,
89 ) -> OrientedHyperbolicPoint<3, Angle> {
90 let mut trial = body_properties;
91 let original_orientation = body_properties.orientation.theta;
92 let disk = HyperbolicDisk {
93 disk_radius: *self.maximum_distance(),
94 point: *trial.position_mut(),
95 };
96 let (trial_sample, boost, rotation) =
97 OrientedHyperbolicPoint::<3, Angle>::sample(&disk, rng);
98 let del_phi = OrientedHyperbolicPoint::<3, Angle>::deck_transform(
100 boost,
101 rotation,
102 &body_properties.position,
103 );
104 *trial.orientation_mut() = Angle::from(original_orientation + del_phi);
105 *trial.position_mut() = Hyperbolic::from_minkowski_coordinates(Minkowski::from([
107 trial_sample.coordinates()[0],
108 trial_sample.coordinates()[1],
109 (trial_sample.point()[0].powi(2) + trial_sample.point()[1].powi(2) + 1.0_f64).sqrt(),
110 ]));
111 trial
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use approxim::assert_relative_eq;
119 use hoomd_manifold::{Hyperbolic, Minkowski};
120 use hoomd_microstate::property::{OrientedHyperbolicPoint, Point, Position};
121 use hoomd_vector::{Angle, Metric};
122 use rand::{SeedableRng, rngs::StdRng};
123 use rstest::*;
124
125 const N: usize = 256;
127
128 #[rstest]
129 fn translate_hyperbolic_point(#[values(0.01, 0.1, 1.0)] d: f64) {
130 let mut rng = StdRng::seed_from_u64(42);
131 let rho: f64 = 1.0;
132 let body_properties = Point::new(Hyperbolic::from_minkowski_coordinates(
133 [1.0, 0.0, (2.0_f64).sqrt()].into(),
134 ));
135 let translate =
136 Translate::with_maximum_distance(d.try_into().expect("hard-coded positive real"));
137
138 for _ in 0..N {
139 let new_body_properties = translate.propose(&mut rng, body_properties);
140
141 assert_relative_eq!(
143 new_body_properties
144 .position()
145 .point()
146 .distance_squared(&Minkowski::from([0.0, 0.0, 0.0])),
147 -(rho.powi(2)),
148 epsilon = 1e-12
149 );
150
151 assert!(
153 d > new_body_properties.position().distance(
154 &Hyperbolic::from_minkowski_coordinates(Minkowski::from([
155 1.0,
156 0.0,
157 (2.0_f64).sqrt()
158 ]),)
159 )
160 );
161 }
162 }
163
164 #[rstest]
165 fn translate_oriented_hyperbolic_point(#[values(0.01, 0.1, 1.0)] d: f64) {
166 let mut rng = StdRng::seed_from_u64(42);
167 let body_properties = OrientedHyperbolicPoint {
168 position: Hyperbolic::from_minkowski_coordinates([1.0, 0.0, (2.0_f64).sqrt()].into()),
169 orientation: Angle::from(0.0),
170 };
171 let translate =
172 Translate::with_maximum_distance(d.try_into().expect("hard-coded positive real"));
173
174 for _ in 0..N {
175 let new_body_properties = translate.propose(&mut rng, body_properties);
176
177 assert_relative_eq!(
179 new_body_properties
180 .position()
181 .point()
182 .distance_squared(&Minkowski::from([0.0, 0.0, 0.0])),
183 -1.0,
184 epsilon = 1e-12
185 );
186
187 assert!(
189 d > new_body_properties.position().distance(
190 &Hyperbolic::from_minkowski_coordinates(Minkowski::from([
191 1.0,
192 0.0,
193 (2.0_f64).sqrt()
194 ]))
195 )
196 );
197 }
198 }
199}