In this tutorial, we show how to setup and run a Brownian Dynamics simulation in IMP.
This tutorial can be followed in several ways:
Setup
We need to import IMP modules that we plan to use in the script:
from __future__ import print_function, division
import RMF
import GranuleFactory
Next, we can set parameters for the simulation:
RMF_FILENAME = "pbc_simple.rmf"
L = 50000
R = 20000
R_NUCLEUS = 10000
N_GRANULES = 50
R_GRANULES = 1500
N_GRANULE_PATCHES = 6
K_BB = 0.1
K_EXCLUDED=0.1
BD_STEP_SIZE_SEC= 10E-8
SIM_TIME_SEC= 0.050
bd_step_size_fs= BD_STEP_SIZE_SEC * 1E+15
sim_time_ns= SIM_TIME_SEC * 1E+9
RMF_DUMP_INTERVAL_NS= sim_time_ns / 1000.0
Representing parts
To represent parts of the system, we use a number of Python classes provided by IMP:
- IMP.Model A container for all of the system’s parts
- IMP.Particle A particle is the elementary data unit describing a system part in IMP
- IMP.Decorator Dynamic descriptors of the properties of IMP particles
- IMP.container Static or dynamic collections of particles, particle pairs, etc.
To see these classes used in a simulation, look at the file pbc_simple.py
in the scripts
directory. First, we create an IMP Model, and set up the root of a hierarchy of particles:
h_root = IMP.atom.Hierarchy.setup_particle(p_root)
Next, we can set up a coarse-grained nucleus by calling the create_nucleus
function. The nucleus particle is given XYZ coordinates and a radius using the XYZR decorator. We then add it to the existing hierarchy:
def create_nucleus(m, R):
'''
Generate a coarse-grained spherical nuclear envelope
of radius R in model m
'''
xyzr = IMP.core.XYZR.setup_particle(p)
xyzr.set_coordinates_are_optimized(True)
xyzr.set_coordinates([0,0,0])
xyzr.set_radius(R)
IMP.atom.Hierarchy.setup_particle(p)
return p
p_nucleus = create_nucleus(m, R_NUCLEUS)
h_root.add_child(h_nucleus)
Next, we create a number of insulin granules at random locations in the cytoplasm. This is done using a simple piece of code, that creates similar XYZR particles, in GranuleFactory.py
:
h_granules_root= IMP.atom.Hierarchy.setup_particle(p_granules_root)
h_root.add_child(h_granules_root)
gf=GranuleFactory.GranuleFactory(
model=m, default_R=R_GRANULES,
cell_sphere=pbc_sphere,
nucleus_sphere=nucleus_sphere)
for i in range(N_GRANULES):
granule= gf.create_simple_granule("Granule_{}".format(i))
h_granules_root.add_child(h_granule)
Representing interactions
Next, we need to tell IMP the nature of the interactions in the system. These are handled by several IMP classes:
pbc_sphere)
bb)
rs = []
h_granules_root.get_children()))
h_granules_root.get_children()))
K_EXCLUDED,
10,
"EV")
rs.append(ev)
Representing dynamics
Finally we can tell IMP to run Brownian Dynamics. This uses the IMP.atom.BrownianDynamics class. First, we set properties of the simulation, such as the temperature and number of time steps:
bd.set_log_level(IMP.SILENT)
bd.set_scoring_function(sf)
bd.set_maximum_time_step(bd_step_size_fs)
bd.set_temperature(300)
Next, we request output of the trajectory in RMF format (using the add_optimizer_state
method):
def convert_time_ns_to_frames(time_ns, step_size_fs):
'''
Given time in nanoseconds time_ns and step size in femtosecond
step_size_fs, return an integer number of frames greater or equal
to 1, such that time_ns*step_size_fs is as close as possible to
time_ns.
'''
FS_PER_NS= 1E6
time_fs= time_ns * FS_PER_NS
n_frames_float= (time_fs+0.0) / step_size_fs
n_frames= int(round(n_frames_float))
return max(n_frames, 1)
sim_time_frames= convert_time_ns_to_frames(sim_time_ns, bd_step_size_fs)
rmf_dump_interval_frames= convert_time_ns_to_frames(RMF_DUMP_INTERVAL_NS, bd_step_size_fs)
print("Simulation time {:.1e} ns / {} frames; "
"RMF dump interval {:.1e} ns / {} frames".format(sim_time_ns,
sim_time_frames,
RMF_DUMP_INTERVAL_NS,
rmf_dump_interval_frames))
rmf = RMF.create_rmf_file(RMF_FILENAME)
rmf.set_description("Brownian dynamics trajectory with {}fs timestep.\n"\
.format(bd_step_size_fs))
IMP.rmf.add_hierarchy(rmf, h_root)
IMP.rmf.add_restraints(rmf, rs)
sos.set_log_level(IMP.SILENT)
sos.set_simulator(bd)
sos.set_period(rmf_dump_interval_frames)
bd.add_optimizer_state(sos)
sos.update_always("initial conformation")
Finally, we run the simulation by calling optimize (this takes a minute or two to run):
print("Running simulation")
print("Score before: {:f}".format(sf.evaluate(True)))
bd.optimize(sim_time_frames)
print("Run finished successfully")
print("Score after: {:f}".format(sf.evaluate(True)))
Running the script
The script can be run with Python by simply running:
python pbc_simple.py
Visualization
The final RMF trajectory pbc_simple.rmf
can be viewed in UCSF Chimera, or in UCSF ChimeraX with the RMF plugin (installed from the Tools menu under 'More Tools').
Next steps
This demonstration uses a very simple representation of the insulin granules. See also pbc_patches.py
and pbc_interacting_patches.py
in the scripts directory of the GitHub repository for similar scripts that use a more realistic representation.