Running a PyRETIS simulation with OpenMM¶
In this example we will show the interface between OpenMM
and PyRETIS.
The implementation, so far, only exists as a library. So instead of using the
standard PyRETIS input files, this example will consist of python scripts.
They will import PyRETIS and OpenMM
objects and use them directly.
First we will have to generate an OpenMM Simulation
object. We use the online
tool OpenMM Script Builder to generate the example
pdb
of 2 water molecules.
##########################################################################
# this script was generated by openmm-builder. to customize it further,
# you can save the file to disk and edit it with your favorite editor.
##########################################################################
from simtk.openmm import app
import simtk.openmm as mm
from simtk import unit
pdb = app.PDBFile('input.pdb')
forcefield = app.ForceField('amber99sbildn.xml', 'tip3p.xml')
system = forcefield.createSystem(pdb.topology, nonbondedMethod=app.PME,
nonbondedCutoff=1.0*unit.nanometers,
constraints=app.HBonds, rigidWater=True,
ewaldErrorTolerance=0.0005)
integrator = mm.LangevinIntegrator(300*unit.kelvin,
1.0/unit.picoseconds,
2.0*unit.femtoseconds)
integrator.setConstraintTolerance(0.00001)
platform = mm.Platform.getPlatformByName('CPU')
simulation = app.Simulation(pdb.topology, system, integrator, platform)
simulation.context.setPositions(pdb.positions)
With this Simulation
object we can now construct the internal PyRETIS system
and OpenMMEngine
objects
import simtk.unit as u
from pyretis.core import System, Particles
from pyretis.core.box import create_box, box_matrix_to_list
from pyretis.engines import OpenMMEngine
def make_pyretis_system(simulation):
"""Makes PyRETIS system from OpenMM Simulation."""
state = simulation.context.getState(getPositions=True, getVelocities=True)
box = state.getPeriodicBoxVectors(asNumpy=True).T
box = create_box(cell=box_matrix_to_list(box),
periodic=[True, True, True])
system = System(units='gromacs', box=box,
temperature=simulation.integrator.getTemperature())
system.particles = Particles(system.get_dim())
pos = state.getPositions(asNumpy=True)
vel = state.getVelocities(asNumpy=True)
for i, atom in enumerate(simulation.topology.atoms()):
mass = simulation.system.getParticleMass(i)
mass = mass.value_in_unit(u.grams/u.mole)
name = atom.name
system.particles.add_particle(pos=pos[i], vel=vel[i],
force=[None, None, None],
mass=mass, name=name)
return system
# Make system and initialise the engine.
system = make_pyretis_system(simulation=simulation)
engine = OpenMMEngine(simulation=simulation)
From this point on we can define an order parameter, interfaces and propagate
with this engine
inside the TIS ensemble.
from pyretis.core.random_gen import RandomGenerator
from pyretis.core.path import Path
from pyretis.orderparameter import Distance
import numpy as np
# Get a random number generator
rgen = RandomGenerator(seed=1)
# Define an empty path of a specific max length (10 in this case)
path = Path(None, maxlen=10)
# Define the order parameter, the distance between the two water oxygens
order_parameter = Distance((0, 3), periodic=False)
# Define state A, Interface and state B of the sampled TIS ensemble.
ifaces = (1, 2, 3)
# Modify the velocities of the shooting point
engine.modify_velocities(system, rgen=rgen,
sigma_v=None, aimless=True,
momentum=False, rescale=None)
# Propegate forward
engine.propagate(path=path, initial_system=system,
order_function=order_parameter,
interfaces=ifaces , reverse=False)
The path
variable now will have the newly generated path for the user to apply
acceptance criteria on. The communication to and from the OpenMM kernel
has been reduced to a minimum, as communication can be expensive for simulations
on GPUs. Further integration with the PyRETIS application
layer is envisioned for later PyRETIS releases.