Skip to content

Commit

Permalink
Added thorough testing for restarting, verifying that all options tha…
Browse files Browse the repository at this point in the history
…t cannot be changed between runs throw the relevant error. Options that cannot be changed are the following: 'runtime', 'restart', 'temperature', 'minimise', 'max_threads', 'equilibration_time', 'equilibration_timestep', 'energy_frequency', 'save_trajectory', 'frame_frequency', 'save_velocities', 'checkpoint_frequency', 'platform', 'max_threads', 'max_gpus', 'run_parallel', 'restart', 'save_trajectories', 'write_config', 'log_level', 'log_file', 'supress_overwrite_warning'
  • Loading branch information
mb2055 committed Nov 6, 2023
1 parent b85be1b commit 485ae5a
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 20 deletions.
93 changes: 73 additions & 20 deletions src/somd2/runner/_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,20 +119,13 @@ def __init__(self, system, config):
if self._config.h_mass_factor > 1:
self._repartition_h_mass()

# Check the output directories and create names of output files.
self._check_directory()

# Save config whenever 'configure' is called to keep it up to date
if self._config.write_config:
_dict_to_yaml(
self._config.as_dict(),
self._config.output_directory,
self._fnames[self._lambda_values[0]]["config"],
)

# Flag whether this is a GPU simulation.
self._is_gpu = self._config.platform in ["cuda", "opencl", "hip"]

# Need to verify before doing any directory checks
if self._config.restart:
self._verify_restart_config()

# Setup proper logging level
import sys

Expand All @@ -145,6 +138,17 @@ def __init__(self, system, config):
enqueue=True,
)

# Check the output directories and create names of output files.
self._check_directory()

# Save config whenever 'configure' is called to keep it up to date
if self._config.write_config:
_dict_to_yaml(
self._config.as_dict(),
self._config.output_directory,
self._fnames[self._lambda_values[0]]["config"],
)

def __str__(self):
"""Return a string representation of the object."""
return f"Runner(system={self._system}, config={self._config})"
Expand Down Expand Up @@ -231,16 +235,65 @@ def _verify_restart_config(self):
"""
import yaml as _yaml

with open(
self._config.output_directory
/ self._fnames[self._lambda_values[0]]["config"]
) as file:
config = _yaml.safe_load(file)
if config != self._config.as_dict():
raise ValueError(
"The configuration file does not match the configuration used to create the "
"checkpoint file."
def get_last_config(output_directory):
"""
Returns the last config file in the output directory.
"""
import os as _os

config_files = [
file
for file in _os.listdir(output_directory)
if file.endswith(".yaml") and file.startswith("config")
]
config_files.sort()
return config_files[-1]

try:
last_config = get_last_config(self._config.output_directory)
except IndexError:
raise IndexError(
f"No config files found in {self._config.output_directory}"
)
with open(self._config.output_directory / last_config) as file:
_logger.debug(f"Opening config file {last_config}")
config = _yaml.safe_load(file)
# Define the subset of settings that are allowed to change after restart
allowed_diffs = [
"runtime",
"restart",
"temperature",
"minimise",
"max_threads",
"equilibration_time",
"equilibration_timestep",
"energy_frequency",
"save_trajectory",
"frame_frequency",
"save_velocities",
"checkpoint_frequency",
"platform",
"max_threads",
"max_gpus",
"run_parallel",
"restart",
"save_trajectories",
"write_config",
"log_level",
"log_file",
"supress_overwrite_warning",
]
for key in config.keys():
if key not in allowed_diffs:
_logger.debug(f"Checking {key}")
_logger.debug(
f"""old value: {config[key]}
new value: {self._config.as_dict()[key]}"""
)
if config[key] != self._config.as_dict()[key]:
raise ValueError(
f"{key} has changed since the last run. This is not allowed when using the restart option."
)

def get_options(self):
"""
Expand Down
103 changes: 103 additions & 0 deletions tests/runner/test_restart.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from somd2.io import *
from pathlib import Path
import sire as sr
import pytest


def test_restart():
Expand Down Expand Up @@ -52,6 +53,7 @@ def test_restart():
"max_threads": 1,
"num_lambda": 2,
"supress_overwrite_warning": True,
"log_level": "DEBUG",
}

runner2 = Runner(mols, Config(**config_new))
Expand All @@ -72,6 +74,107 @@ def test_restart():
assert Path.exists(Path(tmpdir) / "traj_0.dcd")
assert Path.exists(Path(tmpdir) / "traj_0_1.dcd")

config_difftimestep = config_new.copy()
config_difftimestep["runtime"] = "36fs"
config_difftimestep["timestep"] = "2fs"

with pytest.raises(ValueError):
runner_timestep = Runner(mols, Config(**config_difftimestep))

config_diffscalefactor = config_new.copy()
config_diffscalefactor["runtime"] = "36fs"
config_diffscalefactor["charge_scale_factor"] = 0.5

with pytest.raises(ValueError):
runner_scalefactor = Runner(mols, Config(**config_diffscalefactor))

config_diffconstraint = config_new.copy()
config_diffconstraint["runtime"] = "36fs"
config_diffconstraint["constraint"] = "bonds"

with pytest.raises(ValueError):
runner_constraints = Runner(mols, Config(**config_diffconstraint))

config_diffcoulombpower = config_new.copy()
config_diffcoulombpower["runtime"] = "36fs"
config_diffcoulombpower["coulomb_power"] = 0.5

with pytest.raises(ValueError):
runner_coulombpower = Runner(mols, Config(**config_diffcoulombpower))

config_diffcutofftype = config_new.copy()
config_diffcutofftype["runtime"] = "36fs"
config_diffcutofftype["cutoff_type"] = "rf"

with pytest.raises(ValueError):
runner_cutofftype = Runner(mols, Config(**config_diffcutofftype))

config_diffhmassfactor = config_new.copy()
config_diffhmassfactor["runtime"] = "36fs"
config_diffhmassfactor["h_mass_factor"] = 2.0

with pytest.raises(ValueError):
runner_hmassfactor = Runner(mols, Config(**config_diffhmassfactor))

config_diffintegrator = config_new.copy()
config_diffintegrator["runtime"] = "36fs"
config_diffintegrator["integrator"] = "verlet"

with pytest.raises(ValueError):
runner_integrator = Runner(mols, Config(**config_diffintegrator))

config_difflambdaschedule = config_new.copy()
config_difflambdaschedule["runtime"] = "36fs"
config_difflambdaschedule["charge_scale_factor"] = 0.5
config_difflambdaschedule["lambda_schedule"] = "charge_scaled_morph"

with pytest.raises(ValueError):
runner_lambdaschedule = Runner(mols, Config(**config_difflambdaschedule))

config_diffnumlambda = config_new.copy()
config_diffnumlambda["runtime"] = "36fs"
config_diffnumlambda["num_lambda"] = 3

with pytest.raises(ValueError):
runner_numlambda = Runner(mols, Config(**config_diffnumlambda))

config_diffoutputdirectory = config_new.copy()
config_diffoutputdirectory["runtime"] = "36fs"
config_diffoutputdirectory["output_directory"] = "test"

with pytest.raises(IndexError):
runner_outputdirectory = Runner(mols, Config(**config_diffoutputdirectory))

config_diffperturbableconstraint = config_new.copy()
config_diffperturbableconstraint["runtime"] = "36fs"
config_diffperturbableconstraint["perturbable_constraint"] = "bonds"

with pytest.raises(ValueError):
runner_perturbableconstraint = Runner(
mols, Config(**config_diffperturbableconstraint)
)

config_diffpressure = config_new.copy()
config_diffpressure["runtime"] = "36fs"
config_diffpressure["pressure"] = "1.5 atm"

with pytest.raises(ValueError):
runner_pressure = Runner(mols, Config(**config_diffpressure))

config_diffshiftdelta = config_new.copy()
config_diffshiftdelta["runtime"] = "36fs"
config_diffshiftdelta["shift_delta"] = "3 Angstrom"

with pytest.raises(ValueError):
runner_shiftdelta = Runner(mols, Config(**config_diffshiftdelta))

config_diffswapendstates = config_new.copy()
config_diffswapendstates["runtime"] = "36fs"
config_diffswapendstates["swap_end_states"] = True

with pytest.raises(ValueError):
runner_swapendstates = Runner(mols, Config(**config_diffswapendstates))


if __name__ == "__main__":
test_restart()
Expand Down

0 comments on commit 485ae5a

Please sign in to comment.