hoomd_md/lib.rs
1// Copyright (c) 2024-2026 The Regents of the University of Michigan.
2// Part of hoomd-rs, released under the BSD 3-Clause License.
3
4#![doc(
5 html_favicon_url = "https://raw.githubusercontent.com/glotzerlab/hoomd-rs/7352214172a490cc716492e9724ff42720a0018a/doc/theme/favicon.svg"
6)]
7#![doc(
8 html_logo_url = "https://raw.githubusercontent.com/glotzerlab/hoomd-rs/7352214172a490cc716492e9724ff42720a0018a/doc/theme/favicon.svg"
9)]
10
11//! Apply the molecular dynamics simulation method to systems of bodies.
12//!
13//! `hoomd-md` provides building blocks that you can use to create a molecular dynamics
14//! simulation model. Start with a [`Microstate`] to represent the properties of all the
15//! bodies and sites. Form an interaction model using types from [`hoomd_interaction`]
16//! that implement [`NetBodyForceAndVirial`] or [`NetBodyForceVirialAndTorque`] and set the macrostate
17//! using one of the types from [`hoomd_simulation`].
18//!
19//! [`Microstate`]: hoomd_microstate::Microstate
20//! [`NetBodyForceAndVirial`]: hoomd_interaction::NetBodyForceAndVirial
21//! [`NetBodyForceVirialAndTorque`]: hoomd_interaction::NetBodyForceVirialAndTorque
22//! [`DeltaEnergyRemove`]: hoomd_interaction::DeltaEnergyRemove
23//! [`TotalEnergy`]: hoomd_interaction::TotalEnergy
24//!
25//! # Integration methods
26//!
27//! The [`TranslationalMotion`] and [`RotationalMotion`] traits describe types that
28//! can integrate the translational and/or rotational degrees of freedom in the
29//! microstate, respectively. Most users will call [`integrate_translation`]
30//! or [`integrate_translation_and_rotation`] to advance all bodies in the microstate
31//! forward one time step. See the trait documentation for details on how to pin some bodies
32//! in place and/or apply different integration methods to different bodies.
33//!
34//! [`integrate_translation`]: TranslationalMotion::integrate_translation
35//! [`integrate_translation_and_rotation`]: RotationalMotion::integrate_translation_and_rotation
36//!
37//! The [`ConstantVolume`] method integrates the equations of motion for the model
38//! while keeping the volume of the simulation boundary fixed. [`ConstantVolume`]
39//! can sample the microcanonical (NVE) or canonical (NVT) ensembles based on the
40//! choice of thermostat (see below).
41//!
42//! [`ConstantVolume`]: crate::method::ConstantVolume
43//!
44//! ## Body and site properties
45//!
46//! Currently, *hoomd-rs* implements [`TranslationalMotion`] for any [`InnerProduct`] vector
47//! space for bodies with [`Mass`], [`Momentum`], and [`NetForce`] properties in the same
48//! vector space as [`Position`]. For systems with only translational degrees of freedom,
49//! most users will choose [`DynamicPoint<Cartesian<N>>`] body properties and
50//! [`Point<Cartesian<N>>`] site properties.
51//!
52//! [`InnerProduct`]: hoomd_vector::InnerProduct
53//! [`Mass`]: hoomd_microstate::property::Mass
54//! [`Momentum`]: hoomd_microstate::property::Momentum
55//! [`NetForce`]: hoomd_microstate::property::NetForce
56//! [`Position`]: hoomd_microstate::property::Position
57//! [`DynamicPoint<Cartesian<N>>`]: hoomd_microstate::property::DynamicPoint
58//! [`Point<Cartesian<N>>`]: hoomd_microstate::property::Point
59//!
60//! Due to the mathematical nature of rotational degrees of freedom, *hoomd-rs* implements
61//! [`RotationalMotion`] specifically for [`DynamicOrientedPoint<Cartesian<2>, Angle>`] for
62//! 2D simulations and [`DynamicOrientedPoint<Cartesian<3>, Versor>`] for 3D. You must use
63//! one of these two types for body properties to integrate rotational degrees of freedom.
64//! There are fewer restrictions on the site properties type. Most users will choose
65//! [`Point<Cartesian<N>>`] or [`OrientedPoint<Cartesian<N>>`] site properties for
66//! models with rotational degrees of freedom, while some will need custom types.
67//! The choice for site properties is driven by the interaction model, not the integration
68//! method.
69//!
70//! [`DynamicOrientedPoint<Cartesian<2>, Angle>`]: hoomd_microstate::property::DynamicOrientedPoint
71//! [`DynamicOrientedPoint<Cartesian<3>, Versor>`]: hoomd_microstate::property::DynamicOrientedPoint
72//! [`OrientedPoint<Cartesian<N>>`]: hoomd_microstate::property::OrientedPoint
73//!
74//! ## Thermostats
75//!
76//! Some of the integration methods sample constant temperature ensembles using velocity
77//! rescaling thermostats. There are many algorithms to choose from. Find them in the
78//! [`thermostat`] module. Use [`NoThermostat`] to sample constant energy (or enthalpy)
79//! ensembles.
80//!
81//! [`NoThermostat`]: thermostat::NoThermostat
82//!
83//! # The `Rigid` interaction model
84//!
85//! All integration methods in *hoomd-rs* model bodies as rigid bodies. The net force and
86//! torque on each body results from the forces and torques applied to its sites.
87//! The [`Rigid`] type implements [`NetBodyForceAndVirial`] and [`NetBodyForceVirialAndTorque`] when
88//! it wraps a type that computes forces ([`NetSiteForceAndVirial`]) and torques
89//! ([`NetSiteForceVirialAndTorque`]) on sites. For example:
90//! `Rigid<PairwiseCutoff<Isotropic<LennardJones>>>` is a valid interaction model
91//! for use with molecular dynamics integration methods.
92//!
93//! [`Rigid`]: hoomd_interaction::Rigid
94//! [`NetSiteForceAndVirial`]: hoomd_interaction::NetSiteForceAndVirial
95//! [`NetSiteForceVirialAndTorque`]: hoomd_interaction::NetSiteForceVirialAndTorque
96//!
97//! Most differentiable interaction models implement both [`NetSiteForceAndVirial`] and all the
98//! Hamiltonian traits needed for Monte Carlo simulations in *hoomd-mc*. With these
99//! interaction models, you can freely swap between MD and MC simulation steps.
100//! Non-differentiable energies, such as [`Boxcar`] implement energy traits,
101//! but not forces and can therefore only be used with MC. Others, like active forces,
102//! might implement the force traits but not energy and can only be used with MD.
103//! Rust will validate the trait bounds and issue a compile error for invalid
104//! combinations.
105//!
106//! [`Boxcar`]: hoomd_interaction::univariate::Boxcar
107//!
108//! # Microstate modifiers
109//!
110//! Use [`ThermalizeMomentum`] and [`ThermalizeAngularMomentum`] to sample random
111//! momenta from a thermal distribution. Use [`ZeroCenterMomentum`] and
112//! [`ZeroCenterAngularMomentum`] to remove motion of the center of mass.
113//!
114//! All of these modifier traits are implemented for [`Microstate`] itself:
115//! e.g. `microstate.zero_center_momentum()`.
116//!
117//! # Compute properties of the microstate
118//!
119//! Use [`TranslationalKineticEnergy`] to compute the translational kinetic
120//! energy and count the corresponding translational degrees of freedom
121//! in the microstate. [`RotationalKineticEnergy`] does the same for
122//! rotational degrees of freedom.
123//!
124//! As with the modifies, the compute traits are implemented for [`Microstate`].
125
126use rand::Rng;
127
128use hoomd_microstate::{Body, Microstate, Tagged};
129
130pub mod method;
131pub mod thermostat;
132
133mod compute;
134pub use compute::{RotationalKineticEnergy, TranslationalKineticEnergy};
135
136mod modify;
137pub use modify::{
138 ThermalizeAngularMomentum, ThermalizeMomentum, ZeroCenterAngularMomentum, ZeroCenterMomentum,
139};
140
141mod update_net_force;
142pub use update_net_force::{UpdateNetForceAndVirial, UpdateNetForceVirialAndTorque};
143
144/// Scale momenta to hold the system at constant temperature.
145///
146/// Use any of the thermostats in the [`thermostat`] module along with the
147/// integration method of your choice.
148///
149/// The [`ConstantVolume`] integration method rescales every momentum in the
150/// system following the given [`Thermostat`] to sample trajectories from the
151/// canonical ensemble.
152///
153/// [`ConstantVolume`]: crate::method::ConstantVolume
154pub trait Thermostat<M> {
155 /// Integrate the thermostat one half step forward in time.
156 ///
157 /// Returns the momentum scaling factor to use during the first half step.
158 fn integrate_half_step_one<R: Rng + ?Sized>(
159 &mut self,
160 rng: &mut R,
161 macrostate: &M,
162 delta_t: f64,
163 kinetic_energy: f64,
164 degrees_of_freedom: usize,
165 ) -> f64;
166
167 /// Integrate the thermostat one half step forward in time.
168 ///
169 /// Returns the momentum scaling factor to use during the second half step.
170 fn integrate_half_step_two<R: Rng + ?Sized>(
171 &mut self,
172 rng: &mut R,
173 macrostate: &M,
174 delta_t: f64,
175 kinetic_energy: f64,
176 degrees_of_freedom: usize,
177 ) -> f64;
178}
179
180/// Integrate translational degrees of freedom.
181///
182/// [`TranslationalMotion`] integrates the [`Position`] and [`Momentum`] degrees of
183/// freedom for selected bodies.
184///
185/// To integrate the whole system forward one step, call [`integrate_translation`]:
186/// ```
187/// # use hoomd_microstate::{Body, Microstate, property::{DynamicPoint, Point}};
188/// # use hoomd_vector::Cartesian;
189/// # use hoomd_md::{ThermalizeMomentum, TranslationalMotion, method::ConstantVolume};
190/// # use hoomd_interaction::{Rigid, Zero};
191/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
192/// # let mut microstate = Microstate::builder()
193/// # .bodies([
194/// # Body::single_site(DynamicPoint {
195/// # position: Cartesian::from([1.0, 2.0]),
196/// # ..Default::default()
197/// # },
198/// # Point::default(),
199/// # ),
200/// # Body::single_site(DynamicPoint {
201/// # position: Cartesian::from([-2.0, 3.0]),
202/// # ..Default::default()
203/// # },
204/// # Point::default(),
205/// # ),
206/// # ])
207/// # .try_build()?;
208/// # microstate.thermalize_momentum(1.5);
209/// # let mut integration_method = ConstantVolume::builder(0.001).build();
210/// # let interaction_model = Rigid(Zero);
211/// # let macrostate = ();
212/// integration_method.integrate_translation(&mut microstate, ¯ostate, &interaction_model);
213/// microstate.increment_step();
214/// # Ok(())
215/// # }
216/// ```
217///
218/// To integrate only some bodies, call [`integrate_translation_with_filter`]:
219/// ```
220/// # use hoomd_microstate::{Body, Microstate, property::{DynamicPoint, Point}};
221/// # use hoomd_vector::Cartesian;
222/// # use hoomd_md::{ThermalizeMomentum, TranslationalMotion, method::ConstantVolume};
223/// # use hoomd_interaction::{Rigid, Zero};
224/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
225/// # let mut microstate = Microstate::builder()
226/// # .bodies([
227/// # Body::single_site(DynamicPoint {
228/// # position: Cartesian::from([1.0, 2.0]),
229/// # ..Default::default()
230/// # },
231/// # Point::default(),
232/// # ),
233/// # Body::single_site(DynamicPoint {
234/// # position: Cartesian::from([-2.0, 3.0]),
235/// # ..Default::default()
236/// # },
237/// # Point::default(),
238/// # ),
239/// # ])
240/// # .try_build()?;
241/// # microstate.thermalize_momentum(1.5);
242/// # let mut integration_method = ConstantVolume::builder(0.001).build();
243/// # let interaction_model = Rigid(Zero);
244/// # let macrostate = ();
245/// integration_method.integrate_translation_with_filter(&mut microstate, ¯ostate, &interaction_model, |b| b.tag < 2);
246/// microstate.increment_step();
247/// # Ok(())
248/// # }
249/// ```
250///
251/// To integrate some bodies with one integration method and other bodies with another,
252/// call [`integrate_translation_half_step_one_with_filter`] for all methods, then call
253/// `update_net_force`, and finish with [`integrate_translation_half_step_one_with_filter`].
254/// The filters must select distinct subsets of bodies. The filters must also select
255/// the same bodies in half step one and half step two.
256/// ```
257/// # use hoomd_microstate::{Body, Microstate, property::{DynamicPoint, Point}};
258/// # use hoomd_vector::Cartesian;
259/// # use hoomd_md::{UpdateNetForceAndVirial, ThermalizeMomentum, TranslationalMotion, method::ConstantVolume};
260/// # use hoomd_interaction::{Rigid, Zero};
261/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
262/// # let mut microstate = Microstate::builder()
263/// # .bodies([
264/// # Body::single_site(DynamicPoint {
265/// # position: Cartesian::from([1.0, 2.0]),
266/// # ..Default::default()
267/// # },
268/// # Point::default(),
269/// # ),
270/// # Body::single_site(DynamicPoint {
271/// # position: Cartesian::from([-2.0, 3.0]),
272/// # ..Default::default()
273/// # },
274/// # Point::default(),
275/// # ),
276/// # ])
277/// # .try_build()?;
278/// # microstate.thermalize_momentum(1.5);
279/// # let mut integration_method_1 = ConstantVolume::builder(0.001).build();
280/// # let mut integration_method_2 = ConstantVolume::builder(0.001).build();
281/// # let interaction_model = Rigid(Zero);
282/// # let macrostate = ();
283/// integration_method_1.integrate_translation_half_step_one_with_filter(&mut microstate, ¯ostate, |b| b.tag < 2);
284/// integration_method_2.integrate_translation_half_step_one_with_filter(&mut microstate, ¯ostate, |b| b.tag >= 2);
285/// microstate.update_net_force_and_virial(&interaction_model);
286/// integration_method_1.integrate_translation_half_step_two_with_filter(&mut microstate, ¯ostate, |b| b.tag < 2);
287/// integration_method_2.integrate_translation_half_step_two_with_filter(&mut microstate, ¯ostate, |b| b.tag >= 2);
288/// microstate.increment_step();
289/// # Ok(())
290/// # }
291/// ```
292///
293/// The generic type names are:
294/// * `B`: The [`Body::properties`](hoomd_microstate::Body) type.
295/// * `S`: The [`Site::properties`](hoomd_microstate::Site) type.
296/// * `X`: The spatial data structure type.
297/// * `C`: The [`boundary`](hoomd_microstate::boundary) condition type.
298/// * `M`: The [`macrostate`](hoomd_simulation::macrostate) type.
299///
300/// [`integrate_translation`]: Self::integrate_translation
301/// [`integrate_translation_with_filter`]: Self::integrate_translation_with_filter
302/// [`integrate_translation_half_step_one_with_filter`]: Self::integrate_translation_half_step_one_with_filter
303/// [`integrate_translation_half_step_two_with_filter`]: Self::integrate_translation_half_step_two_with_filter
304/// [`Position`]: hoomd_microstate::property::Position
305/// [`Momentum`]: hoomd_microstate::property::Momentum
306pub trait TranslationalMotion<B, S, X, C, M> {
307 /// Integrate all body positions forward a full step and the momenta forward a half step.
308 #[inline]
309 fn integrate_translation_half_step_one(
310 &mut self,
311 microstate: &mut Microstate<B, S, X, C>,
312 macrostate: &M,
313 ) {
314 self.integrate_translation_half_step_one_with_filter(microstate, macrostate, |_| true);
315 }
316
317 /// Integrate selected body positions forward a full step and the momenta forward a half step.
318 fn integrate_translation_half_step_one_with_filter<F: Fn(&Tagged<Body<B, S>>) -> bool>(
319 &mut self,
320 microstate: &mut Microstate<B, S, X, C>,
321 macrostate: &M,
322 should_integrate_body: F,
323 );
324
325 /// Integrate all body momenta forward a half step.
326 #[inline]
327 fn integrate_translation_half_step_two(
328 &mut self,
329 microstate: &mut Microstate<B, S, X, C>,
330 macrostate: &M,
331 ) {
332 self.integrate_translation_half_step_two_with_filter(microstate, macrostate, |_| true);
333 }
334
335 /// Integrate selected body momenta forward a half step.
336 fn integrate_translation_half_step_two_with_filter<F: Fn(&Tagged<Body<B, S>>) -> bool>(
337 &mut self,
338 microstate: &mut Microstate<B, S, X, C>,
339 macrostate: &M,
340 should_integrate_body: F,
341 );
342
343 /// Integrate selected body translational degrees of freedom forward one step.
344 #[inline]
345 fn integrate_translation_with_filter<E, F>(
346 &mut self,
347 microstate: &mut Microstate<B, S, X, C>,
348 macrostate: &M,
349 interaction_model: &E,
350 should_integrate_body: F,
351 ) where
352 F: Fn(&Tagged<Body<B, S>>) -> bool,
353 Microstate<B, S, X, C>: UpdateNetForceAndVirial<E>,
354 {
355 self.integrate_translation_half_step_one_with_filter(
356 microstate,
357 macrostate,
358 &should_integrate_body,
359 );
360 microstate.update_net_force_and_virial(interaction_model);
361 self.integrate_translation_half_step_two_with_filter(
362 microstate,
363 macrostate,
364 &should_integrate_body,
365 );
366 }
367
368 /// Integrate all body translational degrees of freedom forward one step.
369 #[inline]
370 fn integrate_translation<E>(
371 &mut self,
372 microstate: &mut Microstate<B, S, X, C>,
373 macrostate: &M,
374 interaction_model: &E,
375 ) where
376 Microstate<B, S, X, C>: UpdateNetForceAndVirial<E>,
377 {
378 self.integrate_translation_half_step_one_with_filter(microstate, macrostate, |_| true);
379 microstate.update_net_force_and_virial(interaction_model);
380 self.integrate_translation_half_step_two_with_filter(microstate, macrostate, |_| true);
381 }
382}
383
384/// Integrate rotational degrees of freedom.
385///
386/// [`RotationalMotion`] integrates the [`Orientation`] and [`AngularMomentum`] degrees of
387/// freedom for selected bodies.
388///
389/// The generic type names are:
390/// * `B`: The [`Body::properties`](hoomd_microstate::Body) type.
391/// * `S`: The [`Site::properties`](hoomd_microstate::Site) type.
392/// * `X`: The spatial data structure type.
393/// * `C`: The [`boundary`](hoomd_microstate::boundary) condition type.
394/// * `M`: The [`macrostate`](hoomd_simulation::macrostate) type.
395///
396/// To integrate the whole system forward one step, call [`integrate_translation_and_rotation`]:
397/// ```
398/// # use hoomd_microstate::{Body, Microstate, property::{DynamicOrientedPoint, Point}};
399/// # use hoomd_vector::Cartesian;
400/// # use hoomd_md::{ThermalizeMomentum, RotationalMotion, TranslationalMotion, method::ConstantVolume};
401/// # use hoomd_interaction::{Rigid, Zero};
402/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
403/// # let mut microstate = Microstate::builder()
404/// # .bodies([
405/// # Body::single_site(DynamicOrientedPoint {
406/// # position: Cartesian::from([1.0, 2.0]),
407/// # ..Default::default()
408/// # },
409/// # Point::default(),
410/// # ),
411/// # Body::single_site(DynamicOrientedPoint {
412/// # position: Cartesian::from([-2.0, 3.0]),
413/// # ..Default::default()
414/// # },
415/// # Point::default(),
416/// # ),
417/// # ])
418/// # .try_build()?;
419/// # microstate.thermalize_momentum(1.5);
420/// # let mut integration_method = ConstantVolume::builder(0.001).build();
421/// # let interaction_model = Rigid(Zero);
422/// # let macrostate = ();
423/// integration_method.integrate_translation_and_rotation(&mut microstate, ¯ostate, &interaction_model);
424/// microstate.increment_step();
425/// # Ok(())
426/// # }
427/// ```
428///
429/// To integrate only some bodies, call [`integrate_translation_and_rotation_with_filter`]:
430/// ```
431/// # use hoomd_microstate::{Body, Microstate, property::{DynamicOrientedPoint, Point}};
432/// # use hoomd_vector::{Angle, Cartesian};
433/// # use hoomd_md::{ThermalizeMomentum, RotationalMotion, TranslationalMotion, method::ConstantVolume};
434/// # use hoomd_interaction::{Rigid, Zero};
435/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
436/// # let mut microstate = Microstate::builder()
437/// # .bodies([
438/// # Body::single_site(DynamicOrientedPoint {
439/// # position: Cartesian::from([1.0, 2.0]),
440/// # orientation: Angle::default(),
441/// # ..Default::default()
442/// # },
443/// # Point::default(),
444/// # ),
445/// # Body::single_site(DynamicOrientedPoint {
446/// # position: Cartesian::from([-2.0, 3.0]),
447/// # ..Default::default()
448/// # },
449/// # Point::default(),
450/// # ),
451/// # ])
452/// # .try_build()?;
453/// # microstate.thermalize_momentum(1.5);
454/// # let mut integration_method = ConstantVolume::builder(0.001).build();
455/// # let interaction_model = Rigid(Zero);
456/// # let macrostate = ();
457/// integration_method.integrate_translation_with_filter(&mut microstate, ¯ostate, &interaction_model, |b| b.tag < 2);
458/// microstate.increment_step();
459/// # Ok(())
460/// # }
461/// ```
462///
463/// To integrate some bodies with one integration method and other bodies with another,
464/// call `integrate_translation_half_step_one_with_filter`
465/// [`integrate_rotation_half_step_one_with_filter`] for all methods, then call
466/// `update_net_force_and_torque`, and finish with `integrate_translation_half_step_one_with_filter`
467/// [`integrate_rotation_half_step_one_with_filter`].
468/// The filters must select distinct subsets of bodies. The filters must also select
469/// the same bodies in half step one and half step two.
470/// ```
471/// # use hoomd_microstate::{Body, Microstate, property::{DynamicOrientedPoint, Point}};
472/// # use hoomd_vector::Cartesian;
473/// # use hoomd_md::{UpdateNetForceVirialAndTorque, ThermalizeMomentum, RotationalMotion, TranslationalMotion, method::ConstantVolume};
474/// # use hoomd_interaction::{Rigid, Zero};
475/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
476/// # let mut microstate = Microstate::builder()
477/// # .bodies([
478/// # Body::single_site(DynamicOrientedPoint {
479/// # position: Cartesian::from([1.0, 2.0]),
480/// # ..Default::default()
481/// # },
482/// # Point::default(),
483/// # ),
484/// # Body::single_site(DynamicOrientedPoint {
485/// # position: Cartesian::from([-2.0, 3.0]),
486/// # ..Default::default()
487/// # },
488/// # Point::default(),
489/// # ),
490/// # ])
491/// # .try_build()?;
492/// # microstate.thermalize_momentum(1.5);
493/// # let mut integration_method_1 = ConstantVolume::builder(0.001).build();
494/// # let mut integration_method_2 = ConstantVolume::builder(0.001).build();
495/// # let interaction_model = Rigid(Zero);
496/// # let macrostate = ();
497/// integration_method_1.integrate_translation_half_step_one_with_filter(&mut microstate, ¯ostate, |b| b.tag < 2);
498/// integration_method_1.integrate_rotation_half_step_one_with_filter(&mut microstate, ¯ostate, |b| b.tag < 2);
499/// integration_method_2.integrate_translation_half_step_one_with_filter(&mut microstate, ¯ostate, |b| b.tag >= 2);
500/// integration_method_2.integrate_rotation_half_step_one_with_filter(&mut microstate, ¯ostate, |b| b.tag >= 2);
501/// microstate.update_net_force_virial_and_torque(&interaction_model);
502/// integration_method_1.integrate_translation_half_step_two_with_filter(&mut microstate, ¯ostate, |b| b.tag < 2);
503/// integration_method_1.integrate_rotation_half_step_two_with_filter(&mut microstate, ¯ostate, |b| b.tag < 2);
504/// integration_method_2.integrate_translation_half_step_two_with_filter(&mut microstate, ¯ostate, |b| b.tag >= 2);
505/// integration_method_2.integrate_rotation_half_step_two_with_filter(&mut microstate, ¯ostate, |b| b.tag >= 2);
506/// microstate.increment_step();
507/// # Ok(())
508/// # }
509/// ```
510///
511/// [`integrate_translation_and_rotation`]: Self::integrate_translation_and_rotation
512/// [`integrate_translation_and_rotation_with_filter`]: Self::integrate_translation_and_rotation_with_filter
513/// [`integrate_rotation_half_step_one_with_filter`]: Self::integrate_rotation_half_step_one_with_filter
514/// [`integrate_rotation_half_step_two_with_filter`]: Self::integrate_rotation_half_step_two_with_filter
515/// [`Orientation`]: hoomd_microstate::property::Orientation
516/// [`AngularMomentum`]: hoomd_microstate::property::AngularMomentum
517pub trait RotationalMotion<B, S, X, C, M> {
518 /// Integrate all body orientations forward a full step and their angular momenta forward a half step.
519 #[inline]
520 fn integrate_rotation_half_step_one(
521 &mut self,
522 microstate: &mut Microstate<B, S, X, C>,
523 macrostate: &M,
524 ) {
525 self.integrate_rotation_half_step_one_with_filter(microstate, macrostate, |_| true);
526 }
527
528 /// Integrate selected body orientations forward a full step and their angular momenta forward a half step.
529 fn integrate_rotation_half_step_one_with_filter<F: Fn(&Tagged<Body<B, S>>) -> bool>(
530 &mut self,
531 microstate: &mut Microstate<B, S, X, C>,
532 macrostate: &M,
533 should_integrate_body: F,
534 );
535
536 /// Integrate all body angular momenta forward a half step.
537 #[inline]
538 fn integrate_rotation_half_step_two(
539 &mut self,
540 microstate: &mut Microstate<B, S, X, C>,
541 macrostate: &M,
542 ) {
543 self.integrate_rotation_half_step_two_with_filter(microstate, macrostate, |_| true);
544 }
545
546 /// Integrate selected body angular momenta forward a half step.
547 fn integrate_rotation_half_step_two_with_filter<F: Fn(&Tagged<Body<B, S>>) -> bool>(
548 &mut self,
549 microstate: &mut Microstate<B, S, X, C>,
550 macrostate: &M,
551 should_integrate_body: F,
552 );
553
554 /// Integrate selected body translational and rotational degrees of freedom forward one step.
555 #[inline]
556 fn integrate_translation_and_rotation_with_filter<E, F>(
557 &mut self,
558 microstate: &mut Microstate<B, S, X, C>,
559 macrostate: &M,
560 interaction_model: &E,
561 should_integrate_body: F,
562 ) where
563 F: Fn(&Tagged<Body<B, S>>) -> bool,
564 Microstate<B, S, X, C>: UpdateNetForceVirialAndTorque<E>,
565 Self: TranslationalMotion<B, S, X, C, M>,
566 {
567 self.integrate_translation_half_step_one_with_filter(
568 microstate,
569 macrostate,
570 &should_integrate_body,
571 );
572 self.integrate_rotation_half_step_one_with_filter(
573 microstate,
574 macrostate,
575 &should_integrate_body,
576 );
577 microstate.update_net_force_virial_and_torque(interaction_model);
578 self.integrate_translation_half_step_two_with_filter(
579 microstate,
580 macrostate,
581 &should_integrate_body,
582 );
583 self.integrate_rotation_half_step_two_with_filter(
584 microstate,
585 macrostate,
586 &should_integrate_body,
587 );
588 }
589
590 /// Integrate all body translational and rotational degrees of freedom forward one step.
591 #[inline]
592 fn integrate_translation_and_rotation<E>(
593 &mut self,
594 microstate: &mut Microstate<B, S, X, C>,
595 macrostate: &M,
596 interaction_model: &E,
597 ) where
598 Microstate<B, S, X, C>: UpdateNetForceVirialAndTorque<E>,
599 Self: TranslationalMotion<B, S, X, C, M>,
600 {
601 self.integrate_translation_half_step_one_with_filter(microstate, macrostate, |_| true);
602 self.integrate_rotation_half_step_one_with_filter(microstate, macrostate, |_| true);
603 microstate.update_net_force_virial_and_torque(interaction_model);
604 self.integrate_translation_half_step_two_with_filter(microstate, macrostate, |_| true);
605 self.integrate_rotation_half_step_two_with_filter(microstate, macrostate, |_| true);
606 }
607}