Skip to content

Commit

Permalink
Add support for steered molecular dynamics with GROMACS. [ref #192]
Browse files Browse the repository at this point in the history
  • Loading branch information
lohedges committed Apr 16, 2021
1 parent 12d0acf commit dc40edc
Showing 1 changed file with 86 additions and 5 deletions.
91 changes: 86 additions & 5 deletions python/BioSimSpace/Process/_gromacs.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,11 +597,6 @@ def _generate_config(self):
# Convert the timestep to picoseconds.
timestep = self._protocol.getTimeStep().picoseconds().magnitude()

# Get the metadynamics hill deposition frequency. We write GROMACS
# records at the same frequency so that the PLUMED data can be
# cross-referenced.
hill_freq = self._protocol.getHillFrequency()

config.append("integrator = sd") # Leap-frog stochastic dynamics.
config.append("ld-seed = %d" % seed) # Random number seed.
config.append("dt = %.3f" % timestep) # Integration time step.
Expand Down Expand Up @@ -665,6 +660,92 @@ def _generate_config(self):
setattr(self, "sampleConfigurations", self._sampleConfigurations)
setattr(self, "getTime", self._getTime)

# Add configuration variables for a steered molecular dynamics protocol.
elif type(self._protocol) is _Protocol.Steering:

# Work out the number of integration steps.
steps = _math.ceil(self._protocol.getRunTime() / self._protocol.getTimeStep())

# Get the report and restart intervals.
report_interval = self._protocol.getReportInterval()
restart_interval = self._protocol.getRestartInterval()

# Cap the intervals at the total number of steps.
if report_interval > steps:
report_interval = steps
if restart_interval > steps:
restart_interval = steps

# Set the random number seed.
if self._is_seeded:
seed = self._seed
else:
seed = -1

# Convert the timestep to picoseconds.
timestep = self._protocol.getTimeStep().picoseconds().magnitude()

config.append("integrator = sd") # Leap-frog stochastic dynamics.
config.append("ld-seed = %d" % seed) # Random number seed.
config.append("dt = %.3f" % timestep) # Integration time step.
config.append("nsteps = %d" % steps) # Number of integration steps.
config.append("nstlog = %d" % report_interval) # Interval between writing to the log file.
config.append("nstenergy = %d" % report_interval) # Interval between writing to the energy file.
config.append("nstxout = %d" % restart_interval) # Interval between writing to the trajectory file.
if has_box and self._has_water:
config.append("pbc = xyz") # Simulate a fully periodic box.
config.append("cutoff-scheme = Verlet") # Use Verlet pair lists.
config.append("ns-type = grid") # Use a grid to search for neighbours.
config.append("nstlist = 10") # Rebuild neigbour list every 10 steps.
config.append("rlist = 1.2") # Set short-range cutoff.
config.append("rvdw = 1.2") # Set van der Waals cutoff.
config.append("rcoulomb = 1.2") # Set Coulomb cutoff.
config.append("coulombtype = PME") # Fast smooth Particle-Mesh Ewald.
config.append("DispCorr = EnerPres") # Dispersion corrections for energy and pressure.
else:
config.append("pbc = no") # No boundary conditions.
config.append("cutoff-scheme = group") # Generate pair lists for groups of atoms.
config.append("nstlist = 0") # Single neighbour list (all particles interact).
config.append("rlist = 0") # Zero short-range cutoff.
config.append("rvdw = 0") # Zero van der Waals cutoff.
config.append("rcoulomb = 0") # Zero Coulomb cutoff.
config.append("coulombtype = Cut-off") # Plain cut-off.
config.append("vdwtype = Cut-off") # Twin-range van der Waals cut-off.
config.append("constraints = h-bonds") # Rigid water molecules.
config.append("constraint-algorithm = LINCS") # Linear constraint solver.

# Temperature control.
# No need for "berendsen" with integrator "sd".
config.append("tc-grps = system") # A single temperature group for the entire system.
config.append("tau-t = 2.0") # 2ps time constant for temperature coupling.
# Set the reference temperature.
config.append("ref-t = %.2f" % self._protocol.getTemperature().kelvin().magnitude())

# Pressure control.
if self._protocol.getPressure() is not None and has_box and self._has_water:
config.append("pcoupl = berendsen") # Berendsen barostat.
config.append("tau-p = 1.0") # 1ps time constant for pressure coupling.
config.append("ref-p = %.5f" # Pressure in bar.
% self._protocol.getPressure().bar().magnitude())
config.append("compressibility = 4.5e-5") # Compressibility of water.

# Create the PLUMED input file and copy auxillary files to the working directory.
self._plumed = _Plumed(self._work_dir)
plumed_config, auxillary_files = self._plumed.createConfig(self._system, self._protocol)
self._setPlumedConfig(plumed_config)
if auxillary_files is not None:
for file in auxillary_files:
file_name = _os.path.basename(file)
_shutil.copyfile(file, self._work_dir + f"/{file_name}")
self._input_files.append(self._plumed_config_file)

# Expose the PLUMED specific member functions.
setattr(self, "getPlumedConfig", self._getPlumedConfig)
setattr(self, "getPlumedConfigFile", self._getPlumedConfigFile)
setattr(self, "setPlumedConfig", self._setPlumedConfig)
setattr(self, "getCollectiveVariable", self._getCollectiveVariable)
setattr(self, "getTime", self._getTime)

# Set the configuration.
self.setConfig(config)

Expand Down

0 comments on commit dc40edc

Please sign in to comment.