Commit ccc0ba85 authored by Peter Eastman's avatar Peter Eastman
Browse files

Moved OpenMM app into the main OpenMM project

parent 7bf291e0
......@@ -36,6 +36,7 @@ foreach(SUBDIR ${SUBDIRS})
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.py"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.i"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.sh"
"${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/*.xml"
)
foreach(file ${STAGING_INPUT_FILES1})
set(STAGING_INPUT_FILES ${STAGING_INPUT_FILES} "${file}")
......
......@@ -81,11 +81,15 @@ def buildKeywordDictionary(major_version_num=MAJOR_VERSION_NUM,
setupKeywords["download_url"] = "https://simtk.org/home/openmm"
setupKeywords["packages"] = ["simtk",
"simtk.unit",
"simtk.openmm"]
"simtk.openmm",
"simtk.openmm.app",
"simtk.openmm.app.internal"]
setupKeywords["data_files"] = []
setupKeywords["package_data"] = {"simtk" : [],
"simtk.unit" : [],
"simtk.openmm" : []}
"simtk.openmm" : [],
"simtk.openmm.app" : ['data/*.xml'],
"simtk.openmm.app.internal" : []}
setupKeywords["platforms"] = ["Linux", "Mac OS X", "Windows"]
setupKeywords["description"] = \
"Python wrapper for OpenMM (a C++ MD package)"
......
"""
OpenMM Application
"""
__docformat__ = "epytext en"
__author__ = "Peter Eastman"
__copyright__ = "Copyright 2011, Stanford University and Peter Eastman"
__credits__ = []
__license__ = "MIT"
__maintainer__ = "Peter Eastman"
__email__ = "peastman@stanford.edu"
from topology import Topology, Chain, Residue, Atom
from pdbfile import PDBFile
from forcefield import ForceField
from simulation import Simulation
from pdbreporter import PDBReporter
from amberprmtopfile import AmberPrmtopFile
from amberinpcrdfile import AmberInpcrdFile
from dcdfile import DCDFile
from dcdreporter import DCDReporter
# Enumerated values
NoCutoff = forcefield.NoCutoff
CutoffNonPeriodic = forcefield.CutoffNonPeriodic
CutoffPeriodic = forcefield.CutoffPeriodic
Ewald = forcefield.Ewald
PME = forcefield.PME
HBonds = forcefield.HBonds
AllBonds = forcefield.AllBonds
HAngles = forcefield.HAngles
OBC = amberprmtopfile.OBC
"""
armberinpcrdfile.py: Used for loading AMBER inpcrd files.
"""
__author__ = "Peter Eastman"
__version__ = "1.0"
from simtk.openmm.app.internal import amber_file_parser
class AmberInpcrdFile(object):
"""AmberInpcrdFile parses an AMBER inpcrd file and loads the data stored in it."""
def __init__(self, file, loadVelocities=False, loadBoxVectors=False):
"""Load an inpcrd file.
An inpcrd file contains atom positions and, optionally, velocities and periodic box dimensions.
Unfortunately, it is sometimes impossible to determine from the file itself exactly what data
it contains. You therefore must specify in advance what data to load. It is stored into this
object's "positions", "velocities", and "boxVectors" fields.
Parameters:
- file (string) the name of the file to load
- loadVelocities (boolean=False) whether to load velocities from the file
- loadBoxVectors (boolean=False) whether to load the periodic box vectors
"""
results = amber_file_parser.readAmberCoordinates(file, read_velocities=loadVelocities, read_box=loadBoxVectors)
if loadVelocities:
self.positions = results[0]
if loadBoxVectors:
self.boxVectors = results[1]
self.velocities = results[2]
else:
self.velocities = results[1]
elif loadBoxVectors:
self.positions = results[0]
self.boxVectors = results[1]
else:
self.positions = results
"""
armberprmtopfile.py: Used for loading AMBER prmtop files.
"""
__author__ = "Peter Eastman"
__version__ = "1.0"
from simtk.openmm.app import Topology
from simtk.openmm.app.internal import amber_file_parser
import forcefield as ff
import element as elem
import simtk.unit as unit
# Enumerated values for implicit solvent model
OBC = object()
class AmberPrmtopFile(object):
"""AmberPrmtopFile parses an AMBER prmtop file and constructs a Topology and (optionally) an OpenMM System from it."""
def __init__(self, file):
"""Load a prmtop file."""
top = Topology()
self.topology = top
# Load the prmtop file
prmtop = amber_file_parser.PrmtopLoader(file)
self.prmtop = prmtop
# Add atoms to the topology
lastResidue = None
c = top.addChain()
for index in range(prmtop.getNumAtoms()):
resNumber = prmtop.getResidueNumber(index)
if resNumber != lastResidue:
lastResidue = resNumber
resName = prmtop.getResidueLabel(iAtom=index)
r = top.addResidue(resName, c)
atomName = prmtop.getAtomName(index)
# Try to guess the element.
upper = atomName.upper()
if upper.startswith('CL'):
element = elem.chlorine
elif upper.startswith('NA'):
element = elem.sodium
elif upper.startswith('MG'):
element = elem.magnesium
else:
try:
element = elem.get_by_symbol(atomName[0])
except KeyError:
pass
top.addAtom(atomName, element, r)
# Add bonds to the topology
for bond in prmtop.getBondsWithH():
top.addBond(bond[0], bond[1])
for bond in prmtop.getBondsNoH():
top.addBond(bond[0], bond[1])
def createSystem(self, nonbondedMethod=ff.NoCutoff, nonbondedCutoff=1.0*unit.nanometer,
constraints=None, rigidWater=True, implicitSolvent=None):
"""Construct an OpenMM System representing the topology described by this prmtop file.
Parameters:
- nonbondedMethod (object=NoCutoff) The method to use for nonbonded interactions. Allowed values are
NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME.
- nonbondedCutoff (distance=1*nanometer) The cutoff distance to use for nonbonded interactions
- constraints (object=None) Specifies which bonds angles should be implemented with constraints.
Allowed values are None, HBonds, AllBonds, or HAngles.
- rigidWater (boolean=True) If true, water molecules will be fully rigid regardless of the value passed for the constraints argument
- implicitSolvent (object=None) If not None, the implicit solvent model to use
Returns: the newly created System
"""
methodMap = {ff.NoCutoff:'NoCutoff',
ff.CutoffNonPeriodic:'CutoffNonPeriodic',
ff.CutoffPeriodic:'CutoffPeriodic',
ff.Ewald:'Ewald',
ff.PME:'PME'}
if nonbondedMethod not in methodMap:
raise ValueError('Illegal value for nonbonded method')
if not self.prmtop.getIfBox() and nonbondedMethod in (ff.CutoffPeriodic, ff.Ewald, ff.PME):
raise ValueError('Illegal nonbonded method for a non-periodic system')
if nonbondedMethod == ff.NoCutoff:
nonbondedCutoff = None
constraintMap = {None:None,
ff.HBonds:'h-bonds',
ff.AllBonds:'all-bonds',
ff.HAngles:'h-angles'}
if constraints == ff.NoConstraints:
constraintString = None
elif constraints in constraintMap:
constraintString = constraintMap[constraints]
else:
raise ValueError('Illegal value for constraints')
if implicitSolvent is None:
implicitString = None
elif implicitSolvent == OBC:
implicitString = 'OBC'
else:
raise ValueError('Illegal value for implicit solvent model')
return amber_file_parser.readAmberSystem(prmtop_loader=self.prmtop, shake=constraintString, nonbondedCutoff=nonbondedCutoff,
nonbondedMethod=methodMap[nonbondedMethod], flexibleConstraints=False, gbmodel=implicitString)
\ No newline at end of file
"""
dcdfile.py: Used for writing DCD files.
"""
__author__ = "Peter Eastman"
__version__ = "1.0"
import array
import os
import time
import struct
from simtk.unit import picoseconds, nanometers, angstroms, is_quantity
class DCDFile(object):
"""DCDFile provides methods for creating DCD files.
DCD is a file format for storing simulation trajectories. It is supported by many programs, such
as CHARMM, NAMD, and X-PLOR. Note, however, that different programs produce subtly different
versions of the format. This class generates the CHARMM version. Also note that there is no
standard byte ordering (big-endian or little-endian) for this format. This class always generates
files with little-endian ordering.
To use this class, create a DCDFile object, then call writeModel() once for each model in the file."""
def __init__(self, file, topology, dt, firstStep=0, interval=1):
"""Create a DCD file and write out the header.
Parameters:
- file (file) A file to write to
- topology (Topology) The Topology defining the molecular system being written
- dt (time) The time step used in the trajectory
- firstStep (int=0) The index of the first step in the trajectory
- interval (int=1) The frequency (measured in time steps) at which states are written to the trajectory
"""
self._file = file
self._topology = topology
self._firstStep = firstStep
self._interval = interval
self._modelCount = 0
if is_quantity(dt):
dt = dt.value_in_unit(picoseconds)
dt /= 0.04888821
boxFlag = 0
if topology.getUnitCellDimensions() is not None:
boxFlag = 1
header = struct.pack('<i4c9if', 84, 'C', 'O', 'R', 'D', 0, firstStep, interval, 0, 0, 0, 0, 0, 0, dt)
header += struct.pack('<13i', boxFlag, 0, 0, 0, 0, 0, 0, 0, 0, 24, 84, 164, 2)
header += struct.pack('<80s', 'Created by OpenMM')
header += struct.pack('<80s', 'Created '+time.asctime(time.localtime(time.time())))
header += struct.pack('<4i', 164, 4, len(list(topology.atoms())), 4)
file.write(header)
def writeModel(self, positions):
"""Write out a model to the DCD file.
Parameters:
- positions (list) The list of atomic positions to write
"""
if len(list(self._topology.atoms())) != len(positions):
raise ValueError('The number of positions must match the number of atoms')
if is_quantity(positions):
positions = positions.value_in_unit(nanometers)
file = self._file
# Update the header.
self._modelCount += 1
file.seek(8, os.SEEK_SET)
file.write(struct.pack('<i', self._modelCount))
file.seek(20, os.SEEK_SET)
file.write(struct.pack('<i', self._firstStep+self._modelCount*self._interval))
# Write the data.
file.seek(0, os.SEEK_END)
boxSize = self._topology.getUnitCellDimensions()
if boxSize is not None:
size = boxSize.value_in_unit(angstroms)
file.write(struct.pack('<i6di', 48, size[0], 0, size[1], 0, 0, size[2], 48))
length = struct.pack('<i', 4*len(positions))
for i in range(3):
file.write(length)
data = array.array('f', (10*x[i] for x in positions))
data.tofile(file)
file.write(length)
"""
dcdreporter.py: Outputs simulation trajectories in DCD format
"""
__author__ = "Peter Eastman"
__version__ = "1.0"
import simtk.openmm as mm
from simtk.openmm.app import DCDFile
class DCDReporter(object):
"""DCDReporter outputs a series of frames from a Simulation to a DCD file.
To use it, create a DCDReporter, than add it to the Simulation's list of reporters.
"""
def __init__(self, file, reportInterval):
"""Create a DCDReporter.
Parameters:
- file (string) The file to write to
- reportInterval (int) The interval (in time steps) at which to write frames
"""
self._reportInterval = reportInterval
self._out = open(file, 'wb')
self._dcd = None
def describeNextReport(self, simulation):
"""Get information about the next report this object will generate.
Parameters:
- simulation (Simulation) The Simulation to generate a report for
Returns: A five element tuple. The first element is the number of steps until the
next report. The remaining elements specify whether that report will require
positions, velocities, forces, and energies respectively.
"""
steps = self._reportInterval - simulation.currentStep%self._reportInterval
return (steps, True, False, False, False)
def report(self, simulation, state):
"""Generate a report.
Parameters:
- simulation (Simulation) The Simulation to generate a report for
- state (State) The current state of the simulation
"""
if self._dcd is None:
self._dcd = DCDFile(self._out, simulation.topology, simulation.integrator.getStepSize(), 0, self._reportInterval)
self._dcd.writeModel(state.getPositions())
def __del__(self):
self._out.close()
#!/bin/env python
"""
element.py: Used for managing elements.
"""
__author__ = "Christopher M. Bruns"
__version__ = "1.0"
from simtk.unit import daltons
class Element:
elements_by_symbol = {}
def __init__(self, number, name, symbol, mass):
self.atomic_number = number
self.name = name
self.symbol = symbol
self.mass = mass
# Index this element in a global table
s = symbol.strip().upper()
assert s not in Element.elements_by_symbol
Element.elements_by_symbol[s] = self
def get_by_symbol(symbol):
s = symbol.strip().upper()
return Element.elements_by_symbol[s]
hydrogen = Element( 1, "hydrogen", "H", 1.007947*daltons)
deuterium = Element( 1, "deuterium", "D", 2.01355321270*daltons)
helium = Element( 2, "helium", "He", 4.003*daltons)
lithium = Element( 3, "lithium", "Li", 6.9412*daltons)
beryllium = Element( 4, "beryllium", "Be", 9.0121823*daltons)
boron = Element( 5, "boron", "B", 10.8117*daltons)
carbon = Element( 6, "carbon", "C", 12.01078*daltons)
nitrogen = Element( 7, "nitrogen", "N", 14.00672*daltons)
oxygen = Element( 8, "oxygen", "O", 15.99943*daltons)
fluorine = Element( 9, "fluorine", "F", 18.99840325*daltons)
neon = Element( 10, "neon", "Ne", 20.17976*daltons)
sodium = Element( 11, "sodium", "Na", 22.989769282*daltons)
magnesium = Element( 12, "magnesium", "Mg", 24.30506*daltons)
aluminum = Element( 13, "aluminum", "Al", 26.98153868*daltons)
silicon = Element( 14, "silicon", "Si", 28.08553*daltons)
phosphorus = Element( 15, "phosphorus", "P", 30.9737622*daltons)
sulfur = Element( 16, "sulfur", "S", 32.0655*daltons)
chlorine = Element( 17, "chlorine", "Cl", 35.4532*daltons)
argon = Element( 18, "argon", "Ar", 39.9481*daltons)
potassium = Element( 19, "potassium", "K", 39.09831*daltons)
calcium = Element( 20, "calcium", "Ca", 40.0784*daltons)
scandium = Element( 21, "scandium", "Sc", 44.9559126*daltons)
titanium = Element( 22, "titanium", "Ti", 47.8671*daltons)
vanadium = Element( 23, "vanadium", "V", 50.94151*daltons)
chromium = Element( 24, "chromium", "Cr", 51.99616*daltons)
manganese = Element( 25, "manganese", "Mn", 54.9380455*daltons)
iron = Element( 26, "iron", "Fe", 55.8452*daltons)
cobalt = Element( 27, "cobalt", "Co", 58.9331955*daltons)
nickel = Element( 28, "nickel", "Ni", 58.69342*daltons)
copper = Element( 29, "copper", "Cu", 63.5463*daltons)
zinc = Element( 30, "zinc", "Zn", 65.4094*daltons)
gallium = Element( 31, "gallium", "Ga", 69.7231*daltons)
germanium = Element( 32, "germanium", "Ge", 72.641*daltons)
arsenic = Element( 33, "arsenic", "As", 74.921602*daltons)
selenium = Element( 34, "selenium", "Se", 78.963*daltons)
bromine = Element( 35, "bromine", "Br", 79.9041*daltons)
krypton = Element( 36, "krypton", "Kr", 83.7982*daltons)
rubidium = Element( 37, "rubidium", "Rb", 85.46783*daltons)
strontium = Element( 38, "strontium", "Sr", 87.621*daltons)
yttrium = Element( 39, "yttrium", "Y", 88.905852*daltons)
zirconium = Element( 40, "zirconium", "Zr", 91.2242*daltons)
niobium = Element( 41, "niobium", "Nb", 92.906382*daltons)
molybdenum = Element( 42, "molybdenum", "Mo", 95.942*daltons)
technetium = Element( 43, "technetium", "Tc", 98*daltons)
ruthenium = Element( 44, "ruthenium", "Ru", 101.072*daltons)
rhodium = Element( 45, "rhodium", "Rh", 102.905502*daltons)
palladium = Element( 46, "palladium", "Pd", 106.421*daltons)
silver = Element( 47, "silver", "Ag", 107.86822*daltons)
cadmium = Element( 48, "cadmium", "Cd", 112.4118*daltons)
indium = Element( 49, "indium", "In", 114.8183*daltons)
tin = Element( 50, "tin", "Sn", 118.7107*daltons)
antimony = Element( 51, "antimony", "Sb", 121.7601*daltons)
tellurium = Element( 52, "tellurium", "Te", 127.603*daltons)
iodine = Element( 53, "iodine", "I", 126.904473*daltons)
xenon = Element( 54, "xenon", "Xe", 131.2936*daltons)
cesium = Element( 55, "cesium", "Cs", 132.90545192*daltons)
barium = Element( 56, "barium", "Ba", 137.3277*daltons)
lanthanum = Element( 57, "lanthanum", "La", 138.905477*daltons)
cerium = Element( 58, "cerium", "Ce", 140.1161*daltons)
praseodymium = Element( 59, "praseodymium", "Pr", 140.907652*daltons)
neodymium = Element( 60, "neodymium", "Nd", 144.2423*daltons)
promethium = Element( 61, "promethium", "Pm", 145*daltons)
samarium = Element( 62, "samarium", "Sm", 150.362*daltons)
europium = Element( 63, "europium", "Eu", 151.9641*daltons)
gadolinium = Element( 64, "gadolinium", "Gd", 157.253*daltons)
terbium = Element( 65, "terbium", "Tb", 158.925352*daltons)
dysprosium = Element( 66, "dysprosium", "Dy", 162.5001*daltons)
holmium = Element( 67, "holmium", "Ho", 164.930322*daltons)
erbium = Element( 68, "erbium", "Er", 167.2593*daltons)
thulium = Element( 69, "thulium", "Tm", 168.934212*daltons)
ytterbium = Element( 70, "ytterbium", "Yb", 173.043*daltons)
lutetium = Element( 71, "lutetium", "Lu", 174.9671*daltons)
hafnium = Element( 72, "hafnium", "Hf", 178.492*daltons)
tantalum = Element( 73, "tantalum", "Ta", 180.947882*daltons)
tungsten = Element( 74, "tungsten", "W", 183.841*daltons)
rhenium = Element( 75, "rhenium", "Re", 186.2071*daltons)
osmium = Element( 76, "osmium", "Os", 190.233*daltons)
iridium = Element( 77, "iridium", "Ir", 192.2173*daltons)
platinum = Element( 78, "platinum", "Pt", 195.0849*daltons)
gold = Element( 79, "gold", "Au", 196.9665694*daltons)
mercury = Element( 80, "mercury", "Hg", 200.592*daltons)
thallium = Element( 81, "thallium", "Tl", 204.38332*daltons)
lead = Element( 82, "lead", "Pb", 207.21*daltons)
bismuth = Element( 83, "bismuth", "Bi", 208.980401*daltons)
polonium = Element( 84, "polonium", "Po", 209*daltons)
astatine = Element( 85, "astatine", "At", 210*daltons)
radon = Element( 86, "radon", "Rn", 222.018*daltons)
francium = Element( 87, "francium", "Fr", 223*daltons)
radium = Element( 88, "radium", "Ra", 226*daltons)
actinium = Element( 89, "actinium", "Ac", 227*daltons)
thorium = Element( 90, "thorium", "Th", 232.038062*daltons)
protactinium = Element( 91, "protactinium", "Pa", 231.035882*daltons)
uranium = Element( 92, "uranium", "U", 238.028913*daltons)
neptunium = Element( 93, "neptunium", "Np", 237*daltons)
plutonium = Element( 94, "plutonium", "Pu", 244*daltons)
americium = Element( 95, "americium", "Am", 243*daltons)
curium = Element( 96, "curium", "Cm", 247*daltons)
berkelium = Element( 97, "berkelium", "Bk", 247*daltons)
californium = Element( 98, "californium", "Cf", 251*daltons)
einsteinium = Element( 99, "einsteinium", "Es", 252*daltons)
fermium = Element(100, "fermium", "Fm", 257*daltons)
mendelevium = Element(101, "mendelevium", "Md", 258*daltons)
nobelium = Element(102, "nobelium", "No", 259*daltons)
lawrencium = Element(103, "lawrencium", "Lr", 262*daltons)
rutherfordium = Element(104, "rutherfordium", "Rf", 261*daltons)
dubnium = Element(105, "dubnium", "Db", 262*daltons)
seaborgium = Element(106, "seaborgium", "Sg", 266*daltons)
bohrium = Element(107, "bohrium", "Bh", 264*daltons)
hassium = Element(108, "hassium", "Hs", 269*daltons)
meitnerium = Element(109, "meitnerium", "Mt", 268*daltons)
darmstadtium = Element(110, "darmstadtium", "Ds", 281*daltons)
roentgenium = Element(111, "roentgenium", "Rg", 272*daltons)
ununbium = Element(112, "ununbium", "Uub", 285*daltons)
ununtrium = Element(113, "ununtrium", "Uut", 284*daltons)
ununquadium = Element(114, "ununquadium", "Uuq", 289*daltons)
ununpentium = Element(115, "ununpentium", "Uup", 288*daltons)
ununhexium = Element(116, "ununhexium", "Uuh", 292*daltons)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
"""
pdbfile.py: Used for loading PDB files.
"""
__author__ = "Peter Eastman"
__version__ = "1.0"
import os
import sys
import xml.etree.ElementTree as etree
from copy import copy
from simtk.openmm import Vec3
from simtk.openmm.app.internal.pdbstructure import PdbStructure
from simtk.openmm.app import Topology
from simtk.unit import nanometers, angstroms, is_quantity
import element as elem
class PDBFile(object):
"""PDBFile parses a Protein Data Bank (PDB) file and constructs a Topology and a set of atom positions from it.
This class also provides methods for creating PDB files. To write a file containing a single model, call
writeFile(). You also can create files that contain multiple models. To do this, first call writeHeader(),
then writeModel() once for each model in the file, and finally writeFooter() to complete the file."""
_residueNameReplacements = {}
_atomNameReplacements = {}
def __init__(self, file):
"""Load a PDB file.
The atom positions and Topology are stored into this object's "positions" and "topology" fields.
Parameters:
- file (string) the name of the file to load
"""
top = Topology()
coords = [];
self.topology = top
# Load the PDB file
pdb = PdbStructure(open(file))
PDBFile._loadNameReplacementTables()
# Build the topology
for chain in pdb.iter_chains():
c = top.addChain()
for residue in chain.iter_residues():
resName = residue.get_name()
if resName in PDBFile._residueNameReplacements:
resName = PDBFile._residueNameReplacements[resName]
r = top.addResidue(resName, c)
if resName in PDBFile._atomNameReplacements:
atomReplacements = PDBFile._atomNameReplacements[resName]
else:
atomReplacements = {}
for atom in residue.iter_atoms():
atomName = atom.get_name()
if atomName in atomReplacements:
atomName = atomReplacements[atomName]
atomName = atomName.strip()
element = None
# Try to guess the element.
upper = atomName.upper()
if upper.startswith('CL'):
element = elem.chlorine
elif upper.startswith('NA'):
element = elem.sodium
elif upper.startswith('MG'):
element = elem.magnesium
elif upper.startswith('BE'):
element = elem.beryllium
elif upper.startswith('LI'):
element = elem.lithium
elif upper.startswith('K'):
element = elem.potassium
elif( len( residue ) == 1 and upper.startswith('CA') ):
element = elem.calcium
else:
try:
element = elem.get_by_symbol(atomName[0])
except KeyError:
pass
top.addAtom(atomName, element, r)
pos = atom.get_position().value_in_unit(nanometers)
coords.append(Vec3(pos[0], pos[1], pos[2]))
self.positions = coords*nanometers
self.topology.setUnitCellDimensions(pdb.get_unit_cell_dimensions())
self.topology.createStandardBonds()
self.topology.createDisulfideBonds(self.positions)
@staticmethod
def _loadNameReplacementTables():
"""Load the list of atom and residue name replacements."""
if len(PDBFile._residueNameReplacements) == 0:
tree = etree.parse(os.path.join(os.path.dirname(__file__), 'data', 'pdbNames.xml'))
allResidues = {}
proteinResidues = {}
nucleicAcidResidues = {}
for residue in tree.getroot().findall('Residue'):
name = residue.attrib['name']
if name == 'All':
PDBFile._parseResidueAtoms(residue, allResidues)
elif name == 'Protein':
PDBFile._parseResidueAtoms(residue, proteinResidues)
elif name == 'Nucleic':
PDBFile._parseResidueAtoms(residue, nucleicAcidResidues)
for atom in allResidues:
proteinResidues[atom] = allResidues[atom]
nucleicAcidResidues[atom] = allResidues[atom]
for residue in tree.getroot().findall('Residue'):
name = residue.attrib['name']
for id in residue.attrib:
if id == 'name' or id.startswith('alt'):
PDBFile._residueNameReplacements[residue.attrib[id]] = name
if 'type' not in residue.attrib:
atoms = copy(allResidues)
elif residue.attrib['type'] == 'Protein':
atoms = copy(proteinResidues)
elif residue.attrib['type'] == 'Nucleic':
atoms = copy(nucleicAcidResidues)
else:
atoms = copy(allResidues)
PDBFile._parseResidueAtoms(residue, atoms)
PDBFile._atomNameReplacements[name] = atoms
@staticmethod
def _parseResidueAtoms(residue, map):
for atom in residue.findall('Atom'):
name = atom.attrib['name']
for id in atom.attrib:
map[atom.attrib[id]] = name
@staticmethod
def writeFile(topology, positions, file=sys.stdout, modelIndex=None):
"""Write a PDB file containing a single model.
Parameters:
- topology (Topology) The Topology defining the model to write
- positions (list) The list of atomic positions to write
- file (file=stdout) A file to write to
"""
PDBFile.writeHeader(topology, file)
PDBFile.writeModel(topology, positions, file)
PDBFile.writeFooter(topology, file)
@staticmethod
def writeHeader(topology, file=sys.stdout):
"""Write out the header for a PDB file.
Parameters:
- topology (Topology) The Topology defining the molecular system being written
- file (file=stdout) A file to write the file to
"""
boxSize = topology.getUnitCellDimensions()
if boxSize is not None:
size = boxSize.value_in_unit(angstroms)
print >>file, "CRYST1%9.3f%9.3f%9.3f 90.00 90.00 90.00 P 1 1 " % size
@staticmethod
def writeModel(topology, positions, file=sys.stdout, modelIndex=None):
"""Write out a model to a PDB file.
Parameters:
- topology (Topology) The Topology defining the model to write
- positions (list) The list of atomic positions to write
- file (file=stdout) A file to write the model to
- modelIndex (int=None) If not None, the model will be surrounded by MODEL/ENDMDL records with this index
"""
if len(list(topology.atoms())) != len(positions):
raise ValueError('The number of positions must match the number of atoms')
if is_quantity(positions):
positions = positions.value_in_unit(angstroms)
atomIndex = 1
posIndex = 0
if modelIndex is not None:
print >>file, "MODEL %4d" % modelIndex
for (chainIndex, chain) in enumerate(topology.chains()):
chainName = chr(ord('A')+chainIndex)
residues = list(chain.residues())
for (resIndex, res) in enumerate(residues):
if len(res.name) > 3:
resName = res.name[:3]
else:
resName = res.name
for atom in res.atoms():
if len(atom.name) < 4:
atomName = ' '+atom.name
elif len(atom.name) > 4:
atomName = atom.name[:4]
else:
atomName = atom.name
coords = positions[posIndex]
print >>file, "ATOM %5d %-4s %3s %s%4d %8.3f%8.3f%8.3f 1.00 0.00" % (atomIndex, atomName, resName, chainName, resIndex+1, coords[0], coords[1], coords[2])
posIndex += 1
atomIndex += 1
if resIndex == len(residues)-1:
print >>file, "TER %5d %3s %s%4d" % (atomIndex, resName, chainName, resIndex+1)
atomIndex += 1
if modelIndex is not None:
print >>file, "ENDMDL"
@staticmethod
def writeFooter(topology, file=sys.stdout):
"""Write out the footer for a PDB file.
Parameters:
- topology (Topology) The Topology defining the molecular system being written
- file (file=stdout) A file to write the file to
"""
print >>file, "END"
"""
pdbreporter.py: Outputs simulation trajectories in PDB format
"""
__author__ = "Peter Eastman"
__version__ = "1.0"
import simtk.openmm as mm
from simtk.openmm.app import PDBFile
class PDBReporter(object):
"""PDBReporter outputs a series of frames from a Simulation to a PDB file.
To use it, create a PDBReporter, than add it to the Simulation's list of reporters.
"""
def __init__(self, file, reportInterval):
"""Create a PDBReporter.
Parameters:
- file (string) The file to write to
- reportInterval (int) The interval (in time steps) at which to write frames
"""
self._reportInterval = reportInterval
self._out = open(file, 'w')
self._topology = None
self._nextModel = 0
def describeNextReport(self, simulation):
"""Get information about the next report this object will generate.
Parameters:
- simulation (Simulation) The Simulation to generate a report for
Returns: A five element tuple. The first element is the number of steps until the
next report. The remaining elements specify whether that report will require
positions, velocities, forces, and energies respectively.
"""
steps = self._reportInterval - simulation.currentStep%self._reportInterval
return (steps, True, False, False, False)
def report(self, simulation, state):
"""Generate a report.
Parameters:
- simulation (Simulation) The Simulation to generate a report for
- state (State) The current state of the simulation
"""
if self._nextModel == 0:
PDBFile.writeHeader(simulation.topology, self._out)
self._topology = simulation.topology
self._nextModel += 1
PDBFile.writeModel(simulation.topology, state.getPositions(), self._out, self._nextModel)
self._nextModel += 1
def __del__(self):
PDBFile.writeFooter(self._topology, self._out)
self._out.close()
"""
simulation.py: Provides a simplified API for running simulations.
"""
__author__ = "Peter Eastman"
__version__ = "1.0"
import simtk.openmm as mm
import simtk.unit as unit
class Simulation(object):
"""Simulation provides a simplified API for running simulations with OpenMM and reporting results.
A Simulation ties together various objects used for running a simulation: a Topology, System,
Integrator, and Context. To use it, you provide the Topology, System, and Integrator, and it
creates the Context automatically.
Simulation also maintains a list of "reporter" objects that record or analyze data as the simulation
runs, such as writing coordinates to files or displaying structures on the screen. For example,
the following line will cause a file called "output.pdb" to be created, and a structure written to
it every 1000 time steps:
simulation.reporters.append(PDBReporter('output.pdb', 1000))
"""
def __init__(self, topology, system, integrator, platform=None, platformProperties=None):
"""Create a Simulation.
Parameters:
- topology (Topology) A Topology describing the the system to simulation
- system (System) The OpenMM System object to simulate
- integrator (Integrator) The OpenMM Integrator to use for simulating the System
- platform (Platform=None) If not None, the OpenMM Platform to use
- platformProperties (map=None) If not None, a set of platform-specific properties to pass
to the Context's constructor
"""
self.topology = topology
self.system = system
self.integrator = integrator
self.currentStep = 0
self.reporters = []
if platform is None:
self.context = mm.Context(system, integrator)
elif platformProperties is None:
self.context = mm.Context(system, integrator, platform)
else:
self.context = mm.Context(system, integrator, platform, platformProperties)
def minimizeEnergy(self, tolerance=1*unit.kilojoule/unit.mole, maxIterations=0):
"""Perform a local energy minimization on the system.
Parameters:
- tolerance (energy=1*kilojoule/mole) The energy tolerance to which the system should be minimized
- maxIterations (int=0) The maximum number of iterations to perform. If this is 0, minimization is continued
until the results converge without regard to how many iterations it takes.
"""
mm.LocalEnergyMinimizer.minimize(self.context, tolerance, maxIterations)
def step(self, steps):
"""Advance the simulation by integrating a specified number of time steps."""
stepTo = self.currentStep+steps
nextReport = [None]*len(self.reporters)
while self.currentStep < stepTo:
nextSteps = stepTo-self.currentStep
anyReport = False
for i, reporter in enumerate(self.reporters):
nextReport[i] = reporter.describeNextReport(self)
if nextReport[i][0] > 0 and nextReport[i][0] <= nextSteps:
nextSteps = nextReport[i][0]
anyReport = True
self.integrator.step(nextSteps)
self.currentStep += nextSteps
if anyReport:
getPositions = False
getVelocities = False
getForces = False
getEnergy = False
for reporter, next in zip(self.reporters, nextReport):
if next[0] == nextSteps:
if next[1]:
getPositions = True
if next[2]:
getVelocities = True
if next[3]:
getForces = True
if next[4]:
getEnergy = True
state = self.context.getState(getPositions=getPositions, getVelocities=getVelocities, getForces=getForces, getEnergy=getEnergy, getParameters=True)
for reporter, next in zip(self.reporters, nextReport):
if next[0] == nextSteps:
reporter.report(self, state)
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment