diff --git a/a3fe/_version.py b/a3fe/_version.py index 3d26edf7..df124332 100644 --- a/a3fe/_version.py +++ b/a3fe/_version.py @@ -1 +1 @@ -__version__ = "0.4.1" +__version__ = "0.4.2" diff --git a/a3fe/configuration/engine_config.py b/a3fe/configuration/engine_config.py index 90d01a22..8af3e0ab 100644 --- a/a3fe/configuration/engine_config.py +++ b/a3fe/configuration/engine_config.py @@ -4,6 +4,7 @@ "SomdConfig", ] +import math as _math import os as _os from abc import ABC as _ABC from abc import abstractmethod as _abstractmethod @@ -117,9 +118,13 @@ class SomdConfig(_EngineConfig): ### Integrator - ncycles modified as required by a3fe ### timestep: float = _Field(4.0, description="Timestep in femtoseconds(fs)") + max_nmoves: int = _Field( + 250000, + description="Maximum number of moves per cycle. nmoves and ncycles are computed from runtime, timestep, and max_nmoves.", + ) runtime: _Union[int, float] = _Field( 5.0, - description="Runtime in nanoseconds(ns), and must be a multiple of timestep", + description="Runtime in nanoseconds(ns), must be a multiple of timestep and ncycles will be calculated from runtime and nmoves", ) ### Constraints ### @@ -224,30 +229,72 @@ class SomdConfig(_EngineConfig): default_factory=dict, description="Extra options to pass to the SOMD engine" ) + def _get_total_nmoves(self) -> int: + """Calculate total number of moves from runtime and timestep.""" + runtime_fs = _Decimal(str(self.runtime)) * _Decimal("1_000_000") + timestep = _Decimal(str(self.timestep)) + return int(runtime_fs / timestep) + @property def nmoves(self) -> int: """ - Make sure runtime is a multiple of timestep + Number of moves per cycle. + + If total_nmoves <= max_nmoves, returns total_nmoves (ncycles=1). + Otherwise returns the largest factor of total_nmoves that is both + <= max_nmoves and divisible by energy_frequency(default 200), ensuring that + energy output points align with every cycle boundary. """ - # Convert runtime to femtoseconds (ns -> fs) + total_nmoves = self._get_total_nmoves() + + if total_nmoves <= self.max_nmoves: + return total_nmoves + + best = 1 + for d in range(1, int(_math.isqrt(total_nmoves)) + 1): + if total_nmoves % d == 0: + for candidate in (d, total_nmoves // d): + if ( + candidate <= self.max_nmoves + and candidate % self.energy_frequency == 0 + ): + best = max(best, candidate) + + return best + + @property + def ncycles(self) -> int: + """Number of cycles, computed as total_nmoves / nmoves.""" + return max(1, self._get_total_nmoves() // self.nmoves) + + @_model_validator(mode="after") + def _validate_runtime_timestep_nmoves(self): + """Validate that runtime is a multiple of both timestep and energy_frequency * timestep.""" + if self.max_nmoves < self.energy_frequency: + raise ValueError( + f"max_nmoves ({self.max_nmoves}) must be >= energy_frequency " + f"({self.energy_frequency}) so that each cycle contains at least one energy output." + ) + runtime_fs = _Decimal(str(self.runtime)) * _Decimal("1_000_000") timestep = _Decimal(str(self.timestep)) - # Check if runtime is a multiple of timestep - remainder = runtime_fs % timestep - if round(float(remainder), 4) != 0: + if round(float(runtime_fs % timestep), 4) != 0: raise ValueError( - ( - "Runtime must be a multiple of the timestep. " - f"Runtime is {self.runtime} ns ({runtime_fs} fs), " - f"and timestep is {self.timestep} fs." - ) + f"Runtime must be a multiple of timestep. " + f"Runtime is {self.runtime} ns ({runtime_fs} fs), " + f"timestep is {self.timestep} fs." ) - # Calculate the number of moves - nmoves = round(float(runtime_fs) / float(timestep)) + energy_block_fs = timestep * _Decimal(str(self.energy_frequency)) + if round(float(runtime_fs % energy_block_fs), 4) != 0: + raise ValueError( + f"Runtime must be a multiple of energy_frequency * timestep " + f"({self.energy_frequency} * {self.timestep} fs = {float(energy_block_fs)} fs). " + f"Runtime is {self.runtime} ns ({runtime_fs} fs)." + ) - return nmoves + return self @_model_validator(mode="after") def _check_rf_dielectric(self): @@ -336,6 +383,7 @@ def write_config( config_lines = [ "### Integrator ###", f"timestep = {self.timestep} * femtosecond", + f"ncycles = {self.ncycles}", f"nmoves = {self.nmoves}", f"constraint = {self.constraint}", f"hydrogen mass repartitioning factor = {self.hydrogen_mass_factor}", diff --git a/a3fe/data/example_calc_set/mdm2_short/Calculation.pkl b/a3fe/data/example_calc_set/mdm2_short/Calculation.pkl index 8e413ede..5a203bd8 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/Calculation.pkl and b/a3fe/data/example_calc_set/mdm2_short/Calculation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/Leg.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/Leg.pkl index 29637d05..a872ab24 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/Leg.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/Leg.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/Stage.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/Stage.pkl index 567d11b1..62df4e65 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/Stage.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/Stage.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/LamWindow.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/LamWindow.pkl index 47f67557..d2e5706c 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/LamWindow.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_01/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_01/Simulation.pkl index 4220610c..a25046f7 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_02/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_02/Simulation.pkl index 7cf8218d..cbefd5e7 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_03/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_03/Simulation.pkl index 65fb3338..43a2d5de 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_04/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_04/Simulation.pkl index c9c44797..887a9f62 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_05/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_05/Simulation.pkl index c2689c95..b8152275 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.000/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/LamWindow.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/LamWindow.pkl index 283af623..04cd4a1f 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/LamWindow.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_01/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_01/Simulation.pkl index c6efaadf..ac9723b0 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_02/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_02/Simulation.pkl index 27380543..9841ce39 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_03/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_03/Simulation.pkl index 9aa1430f..e581771c 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_04/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_04/Simulation.pkl index b7eb11f5..fdc4b7d4 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_05/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_05/Simulation.pkl index fb8f2aee..b3013758 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.125/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/LamWindow.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/LamWindow.pkl index be60d138..07a77ab7 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/LamWindow.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_01/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_01/Simulation.pkl index 9214bfe7..74109138 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_02/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_02/Simulation.pkl index 3f1e0fdd..1b1180ad 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_03/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_03/Simulation.pkl index e92c63a5..49303cd0 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_04/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_04/Simulation.pkl index 2057da31..1314efae 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_05/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_05/Simulation.pkl index cf929e4e..989e5890 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.250/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/LamWindow.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/LamWindow.pkl index 298c6c31..a528de32 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/LamWindow.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_01/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_01/Simulation.pkl index 951ec3a2..57ab5b4b 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_02/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_02/Simulation.pkl index 888f596c..cc4a5c03 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_03/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_03/Simulation.pkl index 09508cf7..cf9fe9e9 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_04/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_04/Simulation.pkl index 4e21545e..403fd097 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_05/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_05/Simulation.pkl index 2c5db831..25844eca 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.375/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/LamWindow.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/LamWindow.pkl index 7e081718..85535ae4 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/LamWindow.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_01/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_01/Simulation.pkl index ee8a61a3..19e074ee 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_02/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_02/Simulation.pkl index 36d621c1..6f8c0a2d 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_03/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_03/Simulation.pkl index d1bd6bba..722ffcc6 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_04/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_04/Simulation.pkl index 62d92cd8..e2cd72df 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_05/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_05/Simulation.pkl index 84e9f368..36239784 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_0.500/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/LamWindow.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/LamWindow.pkl index 96372604..da3b535f 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/LamWindow.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_01/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_01/Simulation.pkl index 33aa23f0..9a48fc4e 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_02/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_02/Simulation.pkl index cb1734c0..7d4ca940 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_03/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_03/Simulation.pkl index 1d741b15..3fd6eb8f 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_04/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_04/Simulation.pkl index d9648a06..7650dffb 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_05/Simulation.pkl b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_05/Simulation.pkl index 1b9b3fd7..f39ead9c 100644 Binary files a/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/mdm2_short/bound/restrain/output/lambda_1.000/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/Calculation.pkl b/a3fe/data/example_calc_set/t4l/Calculation.pkl index ec35c6cb..d9f139d4 100644 Binary files a/a3fe/data/example_calc_set/t4l/Calculation.pkl and b/a3fe/data/example_calc_set/t4l/Calculation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/Leg.pkl b/a3fe/data/example_calc_set/t4l/bound/Leg.pkl index b1e044f1..e91ea418 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/Leg.pkl and b/a3fe/data/example_calc_set/t4l/bound/Leg.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/Stage.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/Stage.pkl index 4df4bb21..b728ab18 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/Stage.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/Stage.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/LamWindow.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/LamWindow.pkl index 0449ce04..9829f74a 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/LamWindow.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_01/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_01/Simulation.pkl index dfcf9075..44a0d386 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_02/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_02/Simulation.pkl index 94b30141..2a214262 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_03/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_03/Simulation.pkl index 49462e29..c78a261d 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_04/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_04/Simulation.pkl index a8fb6b65..63f35c22 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_05/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_05/Simulation.pkl index 5fe0eea3..01bb333e 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.000/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/LamWindow.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/LamWindow.pkl index 4cf68af0..d1ac1d69 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/LamWindow.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_01/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_01/Simulation.pkl index a977acb7..3bb56783 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_02/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_02/Simulation.pkl index 64d7f821..a18af2fe 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_03/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_03/Simulation.pkl index 3aabaa22..f354a6e0 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_04/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_04/Simulation.pkl index b7ead490..ec41e7ef 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_05/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_05/Simulation.pkl index 650f2c92..8830bf29 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.125/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/LamWindow.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/LamWindow.pkl index f8433cf3..21c640e8 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/LamWindow.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_01/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_01/Simulation.pkl index f3078b25..a8401a77 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_02/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_02/Simulation.pkl index 289ad571..0bf9bf7a 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_03/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_03/Simulation.pkl index f9086c93..0f84a2df 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_04/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_04/Simulation.pkl index 6aab8f31..23b690b8 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_05/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_05/Simulation.pkl index 117350ed..ff9a40f0 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.250/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/LamWindow.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/LamWindow.pkl index c76bac2b..3609c3db 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/LamWindow.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_01/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_01/Simulation.pkl index 17415f71..356ae265 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_02/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_02/Simulation.pkl index ee7ef75c..db5edc4a 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_03/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_03/Simulation.pkl index 0eb2a382..da487bbc 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_04/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_04/Simulation.pkl index 73b173db..342c1a01 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_05/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_05/Simulation.pkl index 8d22661a..4da94246 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.375/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/LamWindow.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/LamWindow.pkl index 5e24bbd3..a2811c9f 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/LamWindow.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_01/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_01/Simulation.pkl index 0888e092..20c6df2f 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_02/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_02/Simulation.pkl index b6b08c44..1c935a39 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_03/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_03/Simulation.pkl index 5811e4ab..1c2bb5df 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_04/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_04/Simulation.pkl index 3a2b53e5..9ef1b3e2 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_05/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_05/Simulation.pkl index 3b041815..6aaee504 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_0.500/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/LamWindow.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/LamWindow.pkl index df51cb2f..aa2f5464 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/LamWindow.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/LamWindow.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_01/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_01/Simulation.pkl index 87b1d2e3..c811d054 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_01/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_01/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_02/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_02/Simulation.pkl index c0247cd6..68a5ef7f 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_02/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_02/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_03/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_03/Simulation.pkl index e85e9e1d..6a37c07f 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_03/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_03/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_04/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_04/Simulation.pkl index c97f9c19..275fc3c6 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_04/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_04/Simulation.pkl differ diff --git a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_05/Simulation.pkl b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_05/Simulation.pkl index ff426fad..1447e048 100644 Binary files a/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_05/Simulation.pkl and b/a3fe/data/example_calc_set/t4l/bound/restrain/output/lambda_1.000/run_05/Simulation.pkl differ diff --git a/a3fe/data/example_restraint_stage/Stage.pkl b/a3fe/data/example_restraint_stage/Stage.pkl index 55f9fd6d..115d258f 100644 Binary files a/a3fe/data/example_restraint_stage/Stage.pkl and b/a3fe/data/example_restraint_stage/Stage.pkl differ diff --git a/a3fe/tests/test_engine_configuration.py b/a3fe/tests/test_engine_configuration.py index 705634d8..48a23d99 100644 --- a/a3fe/tests/test_engine_configuration.py +++ b/a3fe/tests/test_engine_configuration.py @@ -106,6 +106,95 @@ def test_charge_cutoff_validation(engine_config, charge, cutoff, should_pass): engine_config(ligand_charge=charge, cutoff_type=cutoff, runtime=1) +@pytest.mark.parametrize( + "runtime,max_nmoves,timestep,expected_nmoves,expected_ncycles", + [ + # total_nmoves < max_nmoves: single cycle + (0.008, 250000, 4.0, 2000, 1), + # total_nmoves == max_nmoves: single cycle boundary + (1.0, 250000, 4.0, 250000, 1), + # Clean division into max-sized cycles (adaptive 0.1 ns grid typical case) + (5.0, 250000, 4.0, 250000, 5), + # 0.1 ns grid not divisible by max_nmoves: largest energy_frequency-aligned factor + # 5.3 ns -> total=1_325_000, largest factor <=250_000 and %200==0 is 53_000 + (5.3, 250000, 4.0, 53000, 25), + ], +) +def test_ncycles_calculation( + somd_engine_config, runtime, max_nmoves, timestep, expected_nmoves, expected_ncycles +): + """Test that nmoves and ncycles are correctly computed from runtime, max_nmoves and timestep.""" + config = somd_engine_config( + runtime=runtime, max_nmoves=max_nmoves, timestep=timestep + ) + assert config.nmoves == expected_nmoves + assert config.ncycles == expected_ncycles + assert config.nmoves * config.ncycles == config._get_total_nmoves() + assert config.nmoves % config.energy_frequency == 0 + + +def test_ncycles_invalid_runtime(somd_engine_config): + """Test that ValueError is raised when runtime is not a multiple of timestep or energy_frequency * timestep.""" + with pytest.raises(ValueError, match="Runtime must be a multiple of timestep"): + somd_engine_config(runtime=5.0, timestep=3.0) + # 0.123 ns: total_nmoves=30750, 30750 % 200 = 150 != 0 + with pytest.raises(ValueError, match="energy_frequency"): + somd_engine_config(runtime=0.123, timestep=4.0) + # 6.666 ns: total_nmoves=1_666_500, 1_666_500 % 200 = 100 != 0 + with pytest.raises(ValueError, match="energy_frequency"): + somd_engine_config(runtime=6.666, timestep=4.0) + + +def test_ncycles_updates_on_runtime_change(somd_engine_config): + """Test that nmoves and ncycles update when runtime is changed.""" + config = somd_engine_config(runtime=5.0, max_nmoves=250000, timestep=4.0) + assert config.nmoves == 250000 + assert config.ncycles == 5 + + config.runtime = 10.0 + assert config.nmoves == 250000 + assert config.ncycles == 10 + + +def test_ncycles_updates_on_timestep_or_max_nmoves_change(somd_engine_config): + """SSOT: changing timestep or max_nmoves re-derives nmoves/ncycles.""" + config = somd_engine_config(runtime=5.0, timestep=4.0, max_nmoves=250000) + assert config.nmoves == 250000 and config.ncycles == 5 + + config.timestep = 2.0 # total_nmoves doubles to 2_500_000 + assert config.nmoves == 250000 + assert config.ncycles == 10 + + config.max_nmoves = 500000 # now single cycle fits? total=2_500_000 > 500_000 + assert config.nmoves == 500000 + assert config.ncycles == 5 + + +def test_max_nmoves_below_energy_frequency_rejected(somd_engine_config): + """max_nmoves must be >= energy_frequency to guarantee an energy output per cycle.""" + with pytest.raises(ValueError, match="max_nmoves"): + somd_engine_config(runtime=1.0, timestep=4.0, max_nmoves=100) + + +def test_write_config_cycles_match_properties(somd_engine_config): + """The written somd.cfg must contain ncycles/nmoves matching the computed properties.""" + with TemporaryDirectory() as dirname: + config = somd_engine_config(runtime=10.0, timestep=4.0) + config.lambda_values = [0.0, 0.5, 1.0] + config.write_config( + run_dir=dirname, + lambda_val=0.0, + runtime=config.runtime, + top_file="somd.prm7", + coord_file="somd.rst7", + morph_file="somd.pert", + ) + with open(os.path.join(dirname, config.get_file_name()), "r") as f: + content = f.read() + assert f"ncycles = {config.ncycles}" in content + assert f"nmoves = {config.nmoves}" in content + + def test_ligand_charge_validation(engine_config): """Test that ligand charge validation works correctly.""" diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index da420341..ba93b29f 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -2,6 +2,11 @@ Change Log =============== +0.4.2 +==================== +- Added ``max_nmoves`` as a configurable field in ``SomdConfig`` and made ``nmoves``/``ncycles`` computed properties derived from ``runtime``, ``timestep``, ``max_nmoves`` and ``energy_frequency``. +This prevents memory overflow from single-cycle long runtimes while keeping ``runtime`` the single source of truth. + 0.4.1 ==================== - Fixed the statistical inefficiency timestep units from femtoseconds to nanoseconds. diff --git a/docs/guides.rst b/docs/guides.rst index 1b72ce0f..0b942e9d 100644 --- a/docs/guides.rst +++ b/docs/guides.rst @@ -9,7 +9,7 @@ The most basic input that a3fe accepts is PDB files of the protein and crystallo file for the ligand. Pre-parameterised inputs in AMBER-format are also accepted. The table below details the combinations of input files that can be supplied to a3fe, and the names that they must be given (files for both the free and bound leg must be provided). The preparation stage will be detected by a3fe when you instantiate a Calculation, and only the required preparation -steps will be carried out for each leg. +steps will be carried out for each leg. You can also find out which input files are required for a given preparation stage for a given leg programmatically, e.g: @@ -21,7 +21,7 @@ You can also find out which input files are required for a given preparation sta .. list-table:: Preparation stage types and required input files :widths: 25 25 25 50 :header-rows: 1 - + * - PreparationStage - LegType - Required Input Files @@ -95,13 +95,13 @@ completely happy with the input files. * If the above fails, this is often due to residue/ atom names which do not match the templates. Read the errors to find out which residues / atoms are causing the issues, then check the expected names in library which was loaded after typing ``source leaprc.protein.ff14SB`` e.g. ``cat $AMBERHOME/dat/leap/lib/amino12.lib``. Rename the offending atoms/ residues and repeat the above step. * Finally, rename ``protein_fully_sanitised.pdb`` to ``protein.pdb`` and run a3fe again. -Alternatively, if you have a parameterised protein (protein.rst7 and protein.prm7), and ligand.sdf (and optionally waters.prm7 and waters.rst7), you can use the +Alternatively, if you have a parameterised protein (protein.rst7 and protein.prm7), and ligand.sdf (and optionally waters.prm7 and waters.rst7), you can use the notebook supplied in a3fe/a3fe/data/example_run_dir/parameterise_and_assemble_input.ipynb to parameterise the ligand and create the parameterised input files required by a3fe. Running Standard Non-Adaptive Calculations ******************************************* -Once you have the required files in `input` as described above, you can run a standard non-adaptive ABFE calculation. To run 5 replicates with 5 ns of sampling per window +Once you have the required files in `input` as described above, you can run a standard non-adaptive ABFE calculation. To run 5 replicates with 5 ns of sampling per window (discarding 1 ns of this to equilibration): .. code-block:: python @@ -123,7 +123,7 @@ Customising Calculations ************************* Engine Configuration ------------------ +-------------------- The default simulation engine is SOMD. You can customize its configuration by using :class:`a3fe.configuration.engine_config.SomdConfig`. For example, to change the timestep, create a ``SomdConfig`` object and pass it to ``Calculation``: @@ -132,17 +132,23 @@ For example, to change the timestep, create a ``SomdConfig`` object and pass it engine_config = a3.SomdConfig(timestep=2.0) # fs (femtoseconds), Create configuration with custom parameters calc = a3.Calculation(engine_config=engine_config) # Pass to Calculation during creation - + # Or modify parameters after creating the Calculation calc = a3.Calculation() - # Works if the calculation has not been setup yet - calc.engine_config.timestep = 2.0 # fs - # Works if the calculation has already been setup - calc.update_engine_config_option(timestep=2.0) # fs + # Before setup(): modify the engine_config directly + calc.engine_config.timestep = 2.0 # fs + + # After setup(): use update_engine_config_option(option, value) + # to propagate the change to all sub-simulations + calc.update_engine_config_option("timestep", 2.0) # fs .. warning:: - After calling ``calc.setup()``, do not modify engine_config directly. - Use ``calc.update_engine_config_option()`` instead. + After calling ``calc.setup()``, always use ``calc.update_engine_config_option("option", value)`` + rather than modifying ``engine_config`` directly. + +.. note:: + ``nmoves`` and ``ncycles`` are computed properties derived from ``runtime``, ``timestep``, and + ``max_nmoves``; they cannot be set directly. To see a complete list of available configuration options, run ``somd-freenrg --help-config`` or inspect the :class:`a3.SomdConfig` API reference. @@ -180,7 +186,7 @@ also set other options: .. note:: - The molecular dynamics simulations should be run on GPUs - they are unbearably slow on CPU. However, you may want to run the MBAR analysis on CPUs to minimise submissions to the CPU queue. + The molecular dynamics simulations should be run on GPUs - they are unbearably slow on CPU. However, you may want to run the MBAR analysis on CPUs to minimise submissions to the CPU queue. To do this, you can supply an ``analysis_slurm_config`` which is different to the ``slurm_config``, which will only be used for the MBAR analysis. .. code-block:: python @@ -226,7 +232,7 @@ simulation time allocation, and equilibration detection algorithms. # of 2 kcal mol-1 calc.get_optimal_lam_vals(delta_er = 2) # Run adaptively with a runtime constant of 0.0005 kcal**2 mol-2 ns**-1 - # Note that automatic equilibration detection with the paired t-test + # Note that automatic equilibration detection with the paired t-test # method will also be carried out. calc.run(adaptive=True, runtime_constant = 0.0005) calc.wait() @@ -244,7 +250,7 @@ simulation time allocation, and equilibration detection algorithms. During the adaptive allocation of simulation time, the allocated runtime is computed taking into account the relative simulation cost. To obtain comparable total simulation times to those described in the manuscript, you should set the reference simulation time to the cost (hr / ns) of the bound leg of the - MIF/ MIF180 complex ([input files here](https://github.com/michellab/Automated-ABFE-Paper/tree/main/simulations/initial_systems/mif/input)). The cost can be obtained + MIF/ MIF180 complex ([input files here](https://github.com/michellab/Automated-ABFE-Paper/tree/main/simulations/initial_systems/mif/input)). The cost can be obtained by running a short simulation for the leg and checking the cost with e.g. ``ref_cost = calc.legs[0].tot_gpu_time / calc.legs[0].tot_simtime``. This should then be passed when optimising the lambda schedule with e.g. ``calc.get_optimal_lam_vals(delta_er = 2, reference_sim_cost = ref_cost)``. @@ -255,7 +261,7 @@ Analysis can be performed with: .. code-block:: python - # Calculate the free energy changes using MBAR and + # Calculate the free energy changes using MBAR and # generate a variety of plots to aid analysis. # Run through SLURM as MBAR can be computationally intensive. # Avoid costly RMSD analysis. @@ -272,7 +278,7 @@ Analysis can be performed with: ``calc.analyse()`` generates a variety of outputs in the ``output`` directories of the calculation, leg, and stage directories. The most detailed information is given in the stage output directories. You can get a detailed breakdown of the results as a pandas dataframe by running ``calc.get_results_df()``. -Convergence analysis involves repeatedly calculating the free energy changes with different subsets of the +Convergence analysis involves repeatedly calculating the free energy changes with different subsets of the data, and is computationally intensive. Hence, it is implemented in a different function. To run convergence analysis, enter ``calc.analyse_convergence()``. Plots of the free energy change against total simulation time will be created in each output directory. @@ -325,4 +331,3 @@ Since A3FE 0.2.0, ABFE calculations with charged ligands are supported using a c calc = a3.Calculation(engine_config=engine_config) # Pass to Calculation The default ``SomdConfig`` uses reaction field instead of PME. This is faster (around twice as fast for some of our systems) and has been shown to give equivalent results for neutral ligands in RBFE calculations - see https://pubs.acs.org/doi/full/10.1021/acs.jcim.0c01424. -