pub struct MdState {Show 20 fields
pub cfg: MdConfig,
pub atoms: Vec<AtomDynamics>,
pub water: Vec<WaterMolOpc>,
pub adjacency_list: Vec<Vec<usize>>,
pub time: f64,
pub step_count: usize,
pub snapshots: Vec<Snapshot>,
pub cell: SimBox,
pub neighbors_nb: NeighborsNb,
pub water_pme_sites_forces: Vec<[Vec3; 3]>,
pub kinetic_energy: f64,
pub potential_energy: f64,
pub potential_energy_nonbonded: f64,
pub potential_energy_bonded: f64,
pub potential_energy_between_mols: Vec<f64>,
pub neighbor_rebuild_count: usize,
pub computation_time: ComputationTimeSums,
pub mol_start_indices: Vec<usize>,
pub alchemical: StateAlchemical,
pub run_index: Option<usize>,
/* private fields */
}Fields§
§cfg: MdConfig§atoms: Vec<AtomDynamics>§water: Vec<WaterMolOpc>§adjacency_list: Vec<Vec<usize>>Note: We don’t use bond structs once the simulation is set up; the adjacency list is the source of this.
time: f64Current simulation time, in picoseconds.
step_count: usize§snapshots: Vec<Snapshot>These are the snapshots we keep in memory, accumulating.
cell: SimBox§neighbors_nb: NeighborsNb§water_pme_sites_forces: Vec<[Vec3; 3]>§kinetic_energy: f64kcal/mol
potential_energy: f64§potential_energy_nonbonded: f64A newer, simpler approach for energy between molecules, compared to potential_energy_between_mols.
This is simply the potential energy from non-bonded interactions, and excludes that from bonded.
potential_energy_bonded: f64E.g. energy in covalent bonds, as modelled as oscillators.
potential_energy_between_mols: Vec<f64>Every so many snapshots, write these to file, then clear from memory. Used to track which molecule each atom is associated with in our flattened structures. This is the potential energy between every pair of molecules.
neighbor_rebuild_count: usize§computation_time: ComputationTimeSums§mol_start_indices: Vec<usize>Used to track which molecule each atom is associated with in our flattened structures.
alchemical: StateAlchemical§run_index: Option<usize>Index assigned at the start of each MD run. Trajectory files are named
traj_N.dcd, traj_N.trr, etc. so that successive runs never overwrite
each other. Chosen as the lowest N for which no such files exist yet.
None until the first call to handle_ss_file_writes.
Implementations§
Source§impl MdState
impl MdState
Sourcepub fn apply_angle_bending_forces(&mut self)
pub fn apply_angle_bending_forces(&mut self)
This maintains bond angles between sets of three atoms as they should be from hybridization. It reflects this hybridization, steric clashes, and partial double-bond character. This identifies deviations from the ideal angle, calculates restoring torque, and applies forces based on this to push the atoms back into their ideal positions in the molecule.
Valence angles, which are the angle formed by two adjacent bonds ba et bc in a same molecule; a valence angle tends to maintain constant the anglê abc. A valence angle is thus concerned by the positions of three atoms.
Source§impl MdState
impl MdState
Sourcepub fn step(
&mut self,
dev: &ComputationDevice,
dt: f32,
external_force: Option<Vec<Vec3>>,
)
pub fn step( &mut self, dev: &ComputationDevice, dt: f32, external_force: Option<Vec<Vec3>>, )
Perform one integration step. This is the entry point for running the simulation.
One step of length dt is in picoseconds (10^-12),
with typical values of 0.001, or 0.002ps (1 or 2fs).
This method orchestrates the dynamics at each time step. Uses a Verlet Velocity base,
with different thermostat approaches depending on configuration.
External force allows injection of a specific force into the system. It’s indexed by atom.
Examples found in repository?
11fn main() {
12 let dev = ComputationDevice::Cpu;
13 let param_set = FfParamSet::new_amber().unwrap();
14
15 let mut protein = MmCif::load(Path::new("1c8k.cif")).unwrap();
16 let mol = Mol2::load(Path::new("CPB.mol2")).unwrap();
17
18 // Add Hydrogens, force field type, and partial charge to atoms in the protein; these usually aren't
19 // included from RSCB PDB. You can also call `populate_hydrogens_dihedrals()`, and
20 // `populate_peptide_ff_and_q() separately. Add bonds.
21 let (_bonds, _dihedrals) = prepare_peptide_mmcif(
22 &mut protein,
23 ¶m_set.peptide_ff_q_map.as_ref().unwrap(),
24 7.0,
25 )
26 .unwrap();
27
28 let mols = vec![
29 MolDynamics::from_mol2(&mol, None),
30 MolDynamics {
31 ff_mol_type: FfMolType::Peptide,
32 atoms: protein.atoms.clone(),
33 static_: true,
34 ..Default::default()
35 },
36 ];
37
38 let (mut md, _) = MdState::new(&dev, &MdConfig::default(), &mols, ¶m_set).unwrap();
39
40 let n_steps = 100;
41 let dt = 0.002; // picoseconds.
42
43 for _ in 0..n_steps {
44 md.step(&dev, dt, None);
45 }
46
47 let snap = &md.snapshots[md.snapshots.len() - 1]; // A/R.
48 let energy = snap.energy_data.as_ref().unwrap();
49 println!(
50 "KE: {}, PE: {}, Atom posits:",
51 energy.energy_kinetic, energy.energy_potential
52 );
53 for posit in &snap.atom_posits {
54 println!("Posit: {posit}");
55 // Also keeps track of velocities, and solvent molecule positions/velocity
56 }
57
58 // Do something with snapshot data, like displaying atom positions in your UI.
59 // You can save to DCD file, and adjust the ratio they're saved at using the `MdConfig.snapshot_setup`
60 // field: See the example below.
61 for _snap in &md.snapshots {}
62}More examples
21pub fn build_dynamics(
22 dev: &ComputationDevice,
23 ligs: Vec<&mut Sdf>,
24 peptide: &MmCif,
25 param_set: &FfParamSet,
26 cfg: &MdConfig,
27 n_steps: u32,
28 dt: f32,
29) -> Result<MdState, ParamError> {
30 println!("Setting up dynamics...");
31
32 let mut mols = Vec::new();
33
34 for lig in &ligs {
35 mols.push(MolDynamics {
36 ff_mol_type: FfMolType::SmallOrganic,
37 atoms: lig.atoms.clone(),
38 atom_posits: None,
39 atom_init_velocities: None,
40 bonds: lig.bonds.clone(),
41 // Adj list is created atomatically, but can be passed from a cache.
42 adjacency_list: None,
43 static_: false,
44 mol_specific_params: None,
45 bonded_only: false,
46 // Or: ..Default::default()
47 });
48 }
49
50 // A demonstration of only selecting peptide atoms near a ligand.
51 // We assume hetero atoms are ligands, solvent etc, and are not part of the protein.
52 let atoms: Vec<_> = peptide
53 .atoms
54 .iter()
55 .filter(|a| {
56 let mut closest_dist = f64::MAX;
57 for lig in &ligs {
58 // You should probably use a special position set vs the native atom positions.
59 for a in &lig.atoms {
60 let posit = a.posit;
61 let dist = (posit - a.posit).magnitude();
62 if dist < closest_dist {
63 closest_dist = dist;
64 }
65 }
66 }
67
68 !a.hetero && closest_dist < STATIC_ATOM_DIST_THRESH
69 })
70 .map(|a| a.clone())
71 .collect();
72
73 let bonds = create_bonds(&atoms);
74
75 mols.push(MolDynamics {
76 ff_mol_type: FfMolType::Peptide,
77 atoms,
78 bonds,
79 static_: true,
80 ..Default::default()
81 });
82
83 // See also: `MolDynamics::from_sdf()`, `::from_mol2()`, and `::from_amber_geostd("CPB")`
84
85 println!("Initializing MD state...");
86 let (mut md_state, _) = MdState::new(dev, cfg, &mols, param_set)?;
87 println!("Done.");
88
89 let start = Instant::now();
90
91 for _ in 0..n_steps {
92 md_state.step(dev, dt, None);
93 }
94
95 let elapsed = start.elapsed();
96 println!("MD complete in {:.2} s", elapsed.as_secs());
97
98 change_snapshot(ligs, &md_state.snapshots[0]);
99
100 Ok(md_state)
101}Source§impl MdState
impl MdState
Sourcepub fn apply_nonbonded_forces(&mut self, dev: &ComputationDevice)
pub fn apply_nonbonded_forces(&mut self, dev: &ComputationDevice)
Run the appropriate force-computation function to get force on non-solvent atoms, force on solvent atoms, and virial sum for the barostat. Uses GPU if available.
Applies Coulomb and Van der Waals (Lennard-Jones) forces on non-solvent atoms, in place. We use the MD-standard [S]PME approach to handle approximated Coulomb forces. This function applies forces from non-solvent, and solvent sources.
Source§impl MdState
impl MdState
pub fn pack_atoms(&mut self)
Source§impl MdState
impl MdState
Sourcepub fn flush_snapshot_queues(&mut self)
pub fn flush_snapshot_queues(&mut self)
Flush any remaining snapshots in the DCD/TRR/XTC queues to disk.
Call this at the end of a simulation run to ensure the last frames
(those accumulated since the most recent TRAJ_FILE_SAVE_INTERVAL
write) are not lost.
Source§impl MdState
impl MdState
Sourcepub fn md_on_solute_only(&mut self, dev: &ComputationDevice)
pub fn md_on_solute_only(&mut self, dev: &ComputationDevice)
Use this to help initialize solvent molecules to realistic geometry of hydrogen bond networks, prior to the first proper simulation step. Runs MD on solvent only. Make sure to only run this after state is properly initialized, e.g. towards the end of init; not immediately after populating waters.
This will result in an immediate energy bump as solvent positions settle from their grid into position. As they settle, the thermostat will bring the velocities down to set the target temp. This sim should run long enough to the solvent is stable by the time the main sim starts.
Source§impl MdState
impl MdState
Sourcepub fn shrink_cell_towards(
&mut self,
dev: &ComputationDevice,
target_cell: SimBox,
cfg: ShrinkingBoxCfg,
) -> bool
pub fn shrink_cell_towards( &mut self, dev: &ComputationDevice, target_cell: SimBox, cfg: ShrinkingBoxCfg, ) -> bool
Scale each molecule’s centroid into the next smaller box while preserving its internal geometry. Water is treated as a rigid molecule as well.
Sourcepub fn rebuild_spatial_caches(&mut self, dev: &ComputationDevice)
pub fn rebuild_spatial_caches(&mut self, dev: &ComputationDevice)
Rebuild cell-dependent caches after a caller deliberately moves molecules.
Sourcepub fn redistribute_interleaved_opc_waters(
&mut self,
dev: &ComputationDevice,
solvent_centers: &[Vec3F64],
solvent_spacing: Vec3F64,
) -> bool
pub fn redistribute_interleaved_opc_waters( &mut self, dev: &ComputationDevice, solvent_centers: &[Vec3F64], solvent_spacing: Vec3F64, ) -> bool
Redistribute the state’s existing OPC waters throughout a grid of co-packed solvent molecules. This avoids sparse explicit water counts occupying only the first region traversed by the template initializer.
Source§impl MdState
impl MdState
Sourcepub fn initialize_velocities(&mut self, target_k: f32, zero_com_drift: bool)
pub fn initialize_velocities(&mut self, target_k: f32, zero_com_drift: bool)
Assign Maxwell-Boltzmann velocities at the requested temperature.
Solute atoms are sampled independently. OPC water is sampled as a rigid body, with a translational COM velocity and angular momentum, so the initial velocities respect the same rigid-water model used by integration.
Source§impl MdState
impl MdState
Sourcepub fn zero_linear_momentum(&mut self)
pub fn zero_linear_momentum(&mut self)
Remove center-of-mass drift. This can help stabilize system energy. We perform the sums here as f64.
Sourcepub fn zero_angular_momentum(&mut self)
pub fn zero_angular_momentum(&mut self)
Remove rigid-body rotation. Computes ω from I ω = L about the atoms’ COM, then sets v’ = v - ω × (r - r_cm).
Source§impl MdState
impl MdState
Sourcepub fn minimize_energy(
&mut self,
dev: &ComputationDevice,
max_iters: usize,
external_force: Option<Vec<Vec3>>,
)
pub fn minimize_energy( &mut self, dev: &ComputationDevice, max_iters: usize, external_force: Option<Vec<Vec3>>, )
Relaxes the molecules using a steepest-descent energy minimizer. Use this at the start of the simulation to control kinetic energy that arrises from differences between atom positions, and bonded parameters. It can also be called externally. It also stabilizes the solvent molecules, so that their hydrogen bond structure is correct at initialization.
Uses flexible bonds to hydrogen. (Not Shake/Rattle constraints)
We don’t apply this to solvent molecules, as we have a pre-sim set up for them that runs prior to this.
Sourcepub fn minimize_energy_setup(
&mut self,
dev: &ComputationDevice,
external_force: &Option<Vec<Vec3>>,
) -> (Vec<Vec3>, f32, f64, Vec<Vec3>, bool)
pub fn minimize_energy_setup( &mut self, dev: &ComputationDevice, external_force: &Option<Vec<Vec3>>, ) -> (Vec<Vec3>, f32, f64, Vec<Vec3>, bool)
Separate, so can be called `separately by an application, e.g. if it needs to apply a new external force each step.
Sourcepub fn minimize_energy_cleanup(
&mut self,
dev: &ComputationDevice,
prev_long_range: bool,
initial_velocities: &[Vec3],
)
pub fn minimize_energy_cleanup( &mut self, dev: &ComputationDevice, prev_long_range: bool, initial_velocities: &[Vec3], )
See the note on minimize_energy_setup; this is broken out so it can be called separately
by an application.
Sourcepub fn step_energy_min(
&mut self,
dev: &ComputationDevice,
last_step: &mut [Vec3],
alpha: &mut f32,
e_prev: &mut f64,
external_force: &Option<Vec<Vec3>>,
) -> bool
pub fn step_energy_min( &mut self, dev: &ComputationDevice, last_step: &mut [Vec3], alpha: &mut f32, e_prev: &mut f64, external_force: &Option<Vec<Vec3>>, ) -> bool
One iteration of energy minimization. Returns true if the energy is converged, indicating
to abort further steps.
Source§impl MdState
impl MdState
Sourcepub fn configure_alchemical_window(
&mut self,
dev: &ComputationDevice,
mol_idx: usize,
lambda: f64,
) -> Result<(), AlchemicalError>
pub fn configure_alchemical_window( &mut self, dev: &ComputationDevice, mol_idx: usize, lambda: f64, ) -> Result<(), AlchemicalError>
Enable alchemical decoupling for one molecule at a fixed λ value. This is the entry point to enable an alchemical computation for an MD run. The application sequences the λ values by setting up MD runs, and calling this with the appropraite λ.
It validates the molecule index, stores the λ value, clears cached reciprocal data, and rebuilds non-bonded pairs so cross interactions with the selected molecule use alchemical LJ/Coulomb force handling.
Sourcepub fn clear_alchemical_window(&mut self, dev: &ComputationDevice)
pub fn clear_alchemical_window(&mut self, dev: &ComputationDevice)
Disable alchemical scaling and rebuild non-bonded pairs.
Source§impl MdState
impl MdState
Sourcepub fn new(
dev: &ComputationDevice,
cfg: &MdConfig,
mols: &[MolDynamics],
param_set: &FfParamSet,
) -> Result<(Self, Vec<MolDynamics>), ParamError>
pub fn new( dev: &ComputationDevice, cfg: &MdConfig, mols: &[MolDynamics], param_set: &FfParamSet, ) -> Result<(Self, Vec<MolDynamics>), ParamError>
Also returns any explicit solvent molecules added. This may be needed by applications in order to create molecule sets for rendering the trajectories. These are placed, in the trajectory, after all solute atoms.
Examples found in repository?
11fn main() {
12 let dev = ComputationDevice::Cpu;
13 let param_set = FfParamSet::new_amber().unwrap();
14
15 let mut protein = MmCif::load(Path::new("1c8k.cif")).unwrap();
16 let mol = Mol2::load(Path::new("CPB.mol2")).unwrap();
17
18 // Add Hydrogens, force field type, and partial charge to atoms in the protein; these usually aren't
19 // included from RSCB PDB. You can also call `populate_hydrogens_dihedrals()`, and
20 // `populate_peptide_ff_and_q() separately. Add bonds.
21 let (_bonds, _dihedrals) = prepare_peptide_mmcif(
22 &mut protein,
23 ¶m_set.peptide_ff_q_map.as_ref().unwrap(),
24 7.0,
25 )
26 .unwrap();
27
28 let mols = vec![
29 MolDynamics::from_mol2(&mol, None),
30 MolDynamics {
31 ff_mol_type: FfMolType::Peptide,
32 atoms: protein.atoms.clone(),
33 static_: true,
34 ..Default::default()
35 },
36 ];
37
38 let (mut md, _) = MdState::new(&dev, &MdConfig::default(), &mols, ¶m_set).unwrap();
39
40 let n_steps = 100;
41 let dt = 0.002; // picoseconds.
42
43 for _ in 0..n_steps {
44 md.step(&dev, dt, None);
45 }
46
47 let snap = &md.snapshots[md.snapshots.len() - 1]; // A/R.
48 let energy = snap.energy_data.as_ref().unwrap();
49 println!(
50 "KE: {}, PE: {}, Atom posits:",
51 energy.energy_kinetic, energy.energy_potential
52 );
53 for posit in &snap.atom_posits {
54 println!("Posit: {posit}");
55 // Also keeps track of velocities, and solvent molecule positions/velocity
56 }
57
58 // Do something with snapshot data, like displaying atom positions in your UI.
59 // You can save to DCD file, and adjust the ratio they're saved at using the `MdConfig.snapshot_setup`
60 // field: See the example below.
61 for _snap in &md.snapshots {}
62}More examples
21pub fn build_dynamics(
22 dev: &ComputationDevice,
23 ligs: Vec<&mut Sdf>,
24 peptide: &MmCif,
25 param_set: &FfParamSet,
26 cfg: &MdConfig,
27 n_steps: u32,
28 dt: f32,
29) -> Result<MdState, ParamError> {
30 println!("Setting up dynamics...");
31
32 let mut mols = Vec::new();
33
34 for lig in &ligs {
35 mols.push(MolDynamics {
36 ff_mol_type: FfMolType::SmallOrganic,
37 atoms: lig.atoms.clone(),
38 atom_posits: None,
39 atom_init_velocities: None,
40 bonds: lig.bonds.clone(),
41 // Adj list is created atomatically, but can be passed from a cache.
42 adjacency_list: None,
43 static_: false,
44 mol_specific_params: None,
45 bonded_only: false,
46 // Or: ..Default::default()
47 });
48 }
49
50 // A demonstration of only selecting peptide atoms near a ligand.
51 // We assume hetero atoms are ligands, solvent etc, and are not part of the protein.
52 let atoms: Vec<_> = peptide
53 .atoms
54 .iter()
55 .filter(|a| {
56 let mut closest_dist = f64::MAX;
57 for lig in &ligs {
58 // You should probably use a special position set vs the native atom positions.
59 for a in &lig.atoms {
60 let posit = a.posit;
61 let dist = (posit - a.posit).magnitude();
62 if dist < closest_dist {
63 closest_dist = dist;
64 }
65 }
66 }
67
68 !a.hetero && closest_dist < STATIC_ATOM_DIST_THRESH
69 })
70 .map(|a| a.clone())
71 .collect();
72
73 let bonds = create_bonds(&atoms);
74
75 mols.push(MolDynamics {
76 ff_mol_type: FfMolType::Peptide,
77 atoms,
78 bonds,
79 static_: true,
80 ..Default::default()
81 });
82
83 // See also: `MolDynamics::from_sdf()`, `::from_mol2()`, and `::from_amber_geostd("CPB")`
84
85 println!("Initializing MD state...");
86 let (mut md_state, _) = MdState::new(dev, cfg, &mols, param_set)?;
87 println!("Done.");
88
89 let start = Instant::now();
90
91 for _ in 0..n_steps {
92 md_state.step(dev, dt, None);
93 }
94
95 let elapsed = start.elapsed();
96 println!("MD complete in {:.2} s", elapsed.as_secs());
97
98 change_snapshot(ligs, &md_state.snapshots[0]);
99
100 Ok(md_state)
101}pub fn computation_time(&self) -> Result<ComputationTime>
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for MdState
impl !Send for MdState
impl !Sync for MdState
impl !UnwindSafe for MdState
impl Freeze for MdState
impl Unpin for MdState
impl UnsafeUnpin for MdState
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.Source§impl<T> ToCompactString for Twhere
T: Display,
impl<T> ToCompactString for Twhere
T: Display,
Source§fn try_to_compact_string(&self) -> Result<CompactString, ToCompactStringError>
fn try_to_compact_string(&self) -> Result<CompactString, ToCompactStringError>
ToCompactString::to_compact_string() Read moreSource§fn to_compact_string(&self) -> CompactString
fn to_compact_string(&self) -> CompactString
CompactString. Read more