use super::pbc::SimulationBox;
use super::state::LiveMolecularSystem;
#[derive(Debug, Clone)]
pub struct BerendsenBarostat {
pub target_pressure_bar: f64,
pub tau_p_fs: f64,
pub compressibility: f64,
}
impl BerendsenBarostat {
pub fn new(target_pressure_bar: f64, tau_p_fs: f64, compressibility: f64) -> Self {
Self {
target_pressure_bar,
tau_p_fs,
compressibility,
}
}
pub fn apply(
&self,
system: &mut LiveMolecularSystem,
sim_box: &mut SimulationBox,
instantaneous_pressure_bar: f64,
dt_fs: f64,
) {
if !sim_box.periodic {
return;
}
let dp = instantaneous_pressure_bar - self.target_pressure_bar;
let mu = (1.0 - (self.compressibility * dt_fs / (3.0 * self.tau_p_fs)) * dp).cbrt();
let mu = mu.clamp(0.95, 1.05);
for atom in &mut system.atoms {
for d in 0..3 {
atom.position[d] *= mu;
}
}
for i in 0..3 {
for j in 0..3 {
sim_box.lattice[i][j] *= mu;
}
}
*sim_box =
SimulationBox::triclinic(sim_box.lattice[0], sim_box.lattice[1], sim_box.lattice[2]);
system.sync_flat_from_atoms();
}
}
pub fn compute_pressure_bar(
kinetic_energy_kcal_mol: f64,
virial_kcal_mol: f64,
volume_ang3: f64,
) -> f64 {
const KCAL_MOL_ANG3_TO_BAR: f64 = 6.9477e4;
(2.0 * kinetic_energy_kcal_mol + virial_kcal_mol) / (3.0 * volume_ang3) * KCAL_MOL_ANG3_TO_BAR
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compute_pressure_bar_positive() {
let ke = 10.0; let virial = 0.0;
let vol = 1000.0; let p = compute_pressure_bar(ke, virial, vol);
assert!(p > 0.0, "pressure should be positive");
}
#[test]
fn barostat_scaling() {
let barostat = BerendsenBarostat::new(1.0, 1000.0, 4.5e-5);
assert!((barostat.target_pressure_bar - 1.0).abs() < 1e-10);
assert!((barostat.compressibility - 4.5e-5).abs() < 1e-15);
}
}