Commit 97136edd authored by peastman's avatar peastman
Browse files

Merge pull request #1350 from jchodera/forcefield

Add methods to retrieve residues without matching forcefield residue templates
parents fbf0a0a2 a2289e84
......@@ -723,7 +723,7 @@ For the main force field, OpenMM provides the following options:
.. tabularcolumns:: |l|L|
============================= ================================================================================
File Force Field
File Force Field
============================= ================================================================================
:code:`amber96.xml` Amber96\ :cite:`Kollman1997`
:code:`amber99sb.xml` Amber99\ :cite:`Wang2000` with modified backbone torsions\ :cite:`Hornak2006`
......@@ -731,7 +731,7 @@ File Force Field
:code:`amber99sbnmr.xml` Amber99SB with modifications to fit NMR data\ :cite:`Li2010`
:code:`amber03.xml` Amber03\ :cite:`Duan2003`
:code:`amber10.xml` Amber10 (documented in the AmberTools_ manual as `ff10`)
:code:`amoeba2009.xml` AMOEBA 2009\ :cite:`Ren2002`. This force field is deprecated. It is
:code:`amoeba2009.xml` AMOEBA 2009\ :cite:`Ren2002`. This force field is deprecated. It is
recommended to use AMOEBA 2013 instead.
:code:`amoeba2013.xml` AMOEBA 2013\ :cite:`Shi2013`
:code:`charmm_polar_2013.xml` CHARMM 2013 polarizable force field\ :cite:`Lopes2013`
......@@ -746,14 +746,14 @@ files:
.. tabularcolumns:: |l|L|
=================== ============================================
File Water Model
File Water Model
=================== ============================================
:code:`tip3p.xml` TIP3P water model\ :cite:`Jorgensen1983`
:code:`tip3pfb.xml` TIP3P-FB water model\ :cite:`Wang2014`
:code:`tip4pew.xml` TIP4P-Ew water model\ :cite:`Horn2004`
:code:`tip4pfb.xml` TIP4P-FB water model\ :cite:`Wang2014`
:code:`tip5p.xml` TIP5P water model\ :cite:`Mahoney2000`
:code:`spce.xml` SPC/E water model\ :cite:`Berendsen1987`
:code:`tip3p.xml` TIP3P water model\ :cite:`Jorgensen1983`
:code:`tip3pfb.xml` TIP3P-FB water model\ :cite:`Wang2014`
:code:`tip4pew.xml` TIP4P-Ew water model\ :cite:`Horn2004`
:code:`tip4pfb.xml` TIP4P-FB water model\ :cite:`Wang2014`
:code:`tip5p.xml` TIP5P water model\ :cite:`Mahoney2000`
:code:`spce.xml` SPC/E water model\ :cite:`Berendsen1987`
:code:`swm4ndp.xml` SWM4-NDP water model\ :cite:`Lamoureux2006`
=================== ============================================
......@@ -769,7 +769,7 @@ the following files:
.. tabularcolumns:: |l|L|
========================= =================================================================================================
File Implicit Solvation Model
File Implicit Solvation Model
========================= =================================================================================================
:code:`amber96_obc.xml` GBSA-OBC solvation model\ :cite:`Onufriev2004` for use with Amber96 force field
:code:`amber99_obc.xml` GBSA-OBC solvation model for use with Amber99 force fields
......@@ -821,15 +821,15 @@ allowed values for :code:`implicitSolvent`\ :
.. tabularcolumns:: |l|L|
============= ==================================================================================================================================
Value Meaning
Value Meaning
============= ==================================================================================================================================
:code:`None` No implicit solvent is used.
:code:`HCT` Hawkins-Cramer-Truhlar GBSA model\ :cite:`Hawkins1995` (corresponds to igb=1 in AMBER)
:code:`OBC1` Onufriev-Bashford-Case GBSA model\ :cite:`Onufriev2004` using the GB\ :sup:`OBC`\ I parameters (corresponds to igb=2 in AMBER).
:code:`None` No implicit solvent is used.
:code:`HCT` Hawkins-Cramer-Truhlar GBSA model\ :cite:`Hawkins1995` (corresponds to igb=1 in AMBER)
:code:`OBC1` Onufriev-Bashford-Case GBSA model\ :cite:`Onufriev2004` using the GB\ :sup:`OBC`\ I parameters (corresponds to igb=2 in AMBER).
:code:`OBC2` Onufriev-Bashford-Case GBSA model\ :cite:`Onufriev2004` using the GB\ :sup:`OBC`\ II parameters (corresponds to igb=5 in AMBER).
This is the same model used by the GBSA-OBC files described in Section :ref:`force-fields`.
:code:`GBn` GBn solvation model\ :cite:`Mongan2007` (corresponds to igb=7 in AMBER).
:code:`GBn2` GBn2 solvation model\ :cite:`Nguyen2013` (corresponds to igb=8 in AMBER).
:code:`GBn` GBn solvation model\ :cite:`Mongan2007` (corresponds to igb=7 in AMBER).
:code:`GBn2` GBn2 solvation model\ :cite:`Nguyen2013` (corresponds to igb=8 in AMBER).
============= ==================================================================================================================================
......@@ -867,13 +867,13 @@ The :code:`nonbondedMethod` parameter can have any of the following values:
.. tabularcolumns:: |l|L|
========================= ===========================================================================================================================================================================================================================================
Value Meaning
Value Meaning
========================= ===========================================================================================================================================================================================================================================
:code:`NoCutoff` No cutoff is applied.
:code:`CutoffNonPeriodic` The reaction field method is used to eliminate all interactions beyond a cutoff distance. Not valid for AMOEBA.
:code:`NoCutoff` No cutoff is applied.
:code:`CutoffNonPeriodic` The reaction field method is used to eliminate all interactions beyond a cutoff distance. Not valid for AMOEBA.
:code:`CutoffPeriodic` The reaction field method is used to eliminate all interactions beyond a cutoff distance. Periodic boundary conditions are applied, so each atom interacts only with the nearest periodic copy of every other atom. Not valid for AMOEBA.
:code:`Ewald` Periodic boundary conditions are applied. Ewald summation is used to compute long range interactions. (This option is rarely used, since PME is much faster for all but the smallest systems.) Not valid for AMOEBA.
:code:`PME` Periodic boundary conditions are applied. The Particle Mesh Ewald method is used to compute long range interactions.
:code:`Ewald` Periodic boundary conditions are applied. Ewald summation is used to compute long range interactions. (This option is rarely used, since PME is much faster for all but the smallest systems.) Not valid for AMOEBA.
:code:`PME` Periodic boundary conditions are applied. The Particle Mesh Ewald method is used to compute long range interactions.
========================= ===========================================================================================================================================================================================================================================
......@@ -988,11 +988,11 @@ The :code:`constraints` parameter can have any of the following values:
.. tabularcolumns:: |l|L|
================ =============================================================================================================================================
Value Meaning
Value Meaning
================ =============================================================================================================================================
:code:`None` No constraints are applied. This is the default value.
:code:`HBonds` The lengths of all bonds that involve a hydrogen atom are constrained.
:code:`AllBonds` The lengths of all bonds are constrained.
:code:`None` No constraints are applied. This is the default value.
:code:`HBonds` The lengths of all bonds that involve a hydrogen atom are constrained.
:code:`AllBonds` The lengths of all bonds are constrained.
:code:`HAngles` The lengths of all bonds are constrained. In addition, all angles of the form H-X-H or H-O-X (where X is an arbitrary atom) are constrained.
================ =============================================================================================================================================
......@@ -1678,19 +1678,19 @@ Here is the definition of the :class:`ForceReporter` class:
.. samepage::
::
class ForceReporter(object):
def __init__(self, file, reportInterval):
self._out = open(file, 'w')
self._reportInterval = reportInterval
def __del__(self):
self._out.close()
def describeNextReport(self, simulation):
steps = self._reportInterval - simulation.currentStep%self._reportInterval
return (steps, False, False, True, False)
def report(self, simulation, state):
forces = state.getForces().value_in_unit(kilojoules/mole/nanometer)
for f in forces:
......@@ -1961,6 +1961,38 @@ are :code:`wo1`\ , :code:`wo2`\ , :code:`wo3`\ , :code:`wx1`\ , :code:`wx2`\ ,
:code:`wx3`\ , :code:`wy1`\ , :code:`wy2`\ , :code:`wy3`\ , :code:`p1`\ ,
:code:`p2`\ , and :code:`p3`\ .
Missing residue templates
=========================
.. CAUTION::
These features are experimental, and its API is subject to change.
You can use the :method:`getUnmatchedResidues()` method to get a list of residues
in the provided :code:`topology` object that do not currently have a matching
residue template defined in the :class:`ForceField`.
::
pdb = PDBFile('input.pdb')
forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
unmatched_residues = forcefield.getUnmatchedResidues(topology)
This is useful for idenfitying issues with prepared systems, debugging issues
with residue template definitions, or identifying which additional residues need
to be parameterized.
As a convenience for parameterizing new residues, you can also get a list of
residues and empty residue templates using :method:`generateTemplatesForUnmatchedResidues`
::
pdb = PDBFile('input.pdb')
forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
[templates, residues] = forcefield.generateTemplatesForUnmatchedResidues(topology)
# Se the atom types
for template in templates:
for atom in template.atoms:
atom.type = ... # set the atom types here
# Register the template with the forcefield.
forcefield.registerResidueTemplate(template)
<HarmonicBondForce>
===================
......
......@@ -573,6 +573,104 @@ class ForceField(object):
break
return [template, matches]
def _buildBondedToAtomList(self, topology):
"""Build a list of which atom indices are bonded to each atom.
Parameters
----------
topology : Topology
The Topology whose bonds are to be indexed.
Returns
-------
bondedToAtom : list of set of int
bondedToAtom[index] is the set of atom indices bonded to atom `index`
"""
bondedToAtom = []
for atom in topology.atoms():
bondedToAtom.append(set())
for (atom1, atom2) in topology.bonds():
bondedToAtom[atom1.index].add(atom2.index)
bondedToAtom[atom2.index].add(atom1.index)
return bondedToAtom
def getUnmatchedResidues(self, topology):
"""Return a list of Residue objects from specified topology for which no forcefield templates are available.
.. CAUTION:: This method is experimental, and its API is subject to change.
Parameters
----------
topology : Topology
The Topology whose residues are to be checked against the forcefield residue templates.
Returns
-------
unmatched_residues : list of Residue
List of Residue objects from `topology` for which no forcefield residue templates are available.
Note that multiple instances of the same residue appearing at different points in the topology may be returned.
This method may be of use in generating missing residue templates or diagnosing parameterization failures.
"""
# Find the template matching each residue, compiling a list of residues for which no templates are available.
bondedToAtom = self._buildBondedToAtomList(topology)
unmatched_residues = list() # list of unmatched residues
for chain in topology.chains():
for res in chain.residues():
# Attempt to match one of the existing templates.
[template, matches] = self._getResidueTemplateMatches(res, bondedToAtom)
if matches is None:
# No existing templates match.
unmatched_residues.append(res)
return unmatched_residues
def generateTemplatesForUnmatchedResidues(self, topology):
"""Generate forcefield residue templates for residues in specified topology for which no forcefield templates are available.
.. CAUTION:: This method is experimental, and its API is subject to change.
Parameters
----------
topology : Topology
The Topology whose residues are to be checked against the forcefield residue templates.
Returns
-------
templates : list of _TemplateData
List of forcefield residue templates corresponding to residues in `topology` for which no forcefield templates are currently available.
Atom types will be set to `None`, but template name, atom names, elements, and connectivity will be taken from corresponding Residue objects.
residues : list of Residue
List of Residue objects that were used to generate the templates.
`residues[index]` is the Residue that was used to generate the template `templates[index]`
"""
# Get a non-unique list of unmatched residues.
unmatched_residues = self.getUnmatchedResidues(topology)
# Generate a unique list of unmatched residues by comparing fingerprints.
bondedToAtom = self._buildBondedToAtomList(topology)
unique_unmatched_residues = list() # list of unique unmatched Residue objects from topology
templates = list() # corresponding _TemplateData templates
signatures = set()
for residue in unmatched_residues:
signature = _createResidueSignature([ atom.element for atom in residue.atoms() ])
template = _createResidueTemplate(residue)
is_unique = True
if signature in signatures:
# Signature is the same as an existing residue; check connectivity.
for check_residue in unique_unmatched_residues:
matches = _matchResidue(check_residue, template, bondedToAtom)
if matches is not None:
is_unique = False
if is_unique:
# Residue is unique.
unique_unmatched_residues.append(residue)
signatures.add(signature)
templates.append(template)
return [templates, unique_unmatched_residues]
def createSystem(self, topology, nonbondedMethod=NoCutoff, nonbondedCutoff=1.0*unit.nanometer,
constraints=None, rigidWater=True, removeCMMotion=True, hydrogenMass=None, **args):
"""Construct an OpenMM System representing a Topology with this force field.
......@@ -853,7 +951,6 @@ def _createResidueSignature(elements):
s += element.symbol+str(count)
return s
def _matchResidue(res, template, bondedToAtom):
"""Determine whether a residue matches a template and return a list of corresponding atoms.
......@@ -998,6 +1095,34 @@ def _findMatchErrors(forcefield, res):
return 'The set of atoms is similar to %s, but it is missing %d atoms.' % (bestMatchName, numBestMatchAtoms-numResidueAtoms)
return 'This might mean your input topology is missing some atoms or bonds, or possibly that you are using the wrong force field.'
def _createResidueTemplate(residue):
"""Create a _TemplateData template from a Residue object.
Parameters
----------
residue : Residue
The Residue from which the template is to be constructed.
Returns
-------
template : _TemplateData
The residue template, with atom types set to None.
This method may be useful in creating new residue templates for residues without templates defined by the ForceField.
"""
template = ForceField._TemplateData(residue.name)
for atom in residue.atoms():
template.atoms.append(ForceField._TemplateAtomData(atom.name, None, atom.element))
for (atom1,atom2) in residue.internal_bonds():
template.addBondByName(atom1.name, atom2.name)
residue_atoms = [ atom for atom in residue.atoms() ]
for (atom1,atom2) in residue.external_bonds():
if atom1 in residue_atoms:
template.addExternalBondByName(atom1.name)
elif atom2 in residue_atoms:
template.addExternalBondByName(atom2.name)
return template
# The following classes are generators that know how to create Force subclasses and add them to a System that is being
# created. Each generator class must define two methods: 1) a static method that takes an etree Element and a ForceField,
......@@ -4558,3 +4683,5 @@ class DrudeGenerator:
drude.addScreenedPair(drude1, drude2, thole1+thole2)
parsers["DrudeForce"] = DrudeGenerator.parseElement
#=============================================================================================
......@@ -13,9 +13,9 @@ else:
class TestForceField(unittest.TestCase):
"""Test the ForceField.createSystem() method."""
def setUp(self):
"""Set up the tests by loading the input pdb files and force field
"""Set up the tests by loading the input pdb files and force field
xml files.
"""
......@@ -33,16 +33,16 @@ class TestForceField(unittest.TestCase):
def test_NonbondedMethod(self):
"""Test all five options for the nonbondedMethod parameter."""
methodMap = {NoCutoff:NonbondedForce.NoCutoff,
CutoffNonPeriodic:NonbondedForce.CutoffNonPeriodic,
CutoffPeriodic:NonbondedForce.CutoffPeriodic,
methodMap = {NoCutoff:NonbondedForce.NoCutoff,
CutoffNonPeriodic:NonbondedForce.CutoffNonPeriodic,
CutoffPeriodic:NonbondedForce.CutoffPeriodic,
Ewald:NonbondedForce.Ewald, PME: NonbondedForce.PME}
for method in methodMap:
system = self.forcefield1.createSystem(self.pdb1.topology,
nonbondedMethod=method)
forces = system.getForces()
self.assertTrue(any(isinstance(f, NonbondedForce) and
f.getNonbondedMethod()==methodMap[method]
self.assertTrue(any(isinstance(f, NonbondedForce) and
f.getNonbondedMethod()==methodMap[method]
for f in forces))
def test_DispersionCorrection(self):
......@@ -50,7 +50,7 @@ class TestForceField(unittest.TestCase):
for useDispersionCorrection in [True, False]:
system = self.forcefield1.createSystem(self.pdb1.topology,
nonbondedCutoff=2*nanometer,
nonbondedCutoff=2*nanometer,
useDispersionCorrection=useDispersionCorrection)
for force in system.getForces():
......@@ -62,8 +62,8 @@ class TestForceField(unittest.TestCase):
for method in [CutoffNonPeriodic, CutoffPeriodic, Ewald, PME]:
system = self.forcefield1.createSystem(self.pdb1.topology,
nonbondedMethod=method,
nonbondedCutoff=2*nanometer,
nonbondedMethod=method,
nonbondedCutoff=2*nanometer,
constraints=HBonds)
cutoff_distance = 0.0*nanometer
cutoff_check = 2.0*nanometer
......@@ -81,29 +81,29 @@ class TestForceField(unittest.TestCase):
def test_RigidWaterAndConstraints(self):
"""Test all eight options for the constraints and rigidWater parameters."""
topology = self.pdb1.topology
for constraints_value in [None, HBonds, AllBonds, HAngles]:
for rigidWater_value in [True, False]:
system = self.forcefield1.createSystem(topology,
constraints=constraints_value,
constraints=constraints_value,
rigidWater=rigidWater_value)
validateConstraints(self, topology, system,
validateConstraints(self, topology, system,
constraints_value, rigidWater_value)
def test_ImplicitSolvent(self):
"""Test the four types of implicit solvents using the implicitSolvent
"""Test the four types of implicit solvents using the implicitSolvent
parameter.
"""
topology = self.pdb2.topology
topology = self.pdb2.topology
system = self.forcefield2.createSystem(topology)
forces = system.getForces()
self.assertTrue(any(isinstance(f, GBSAOBCForce) for f in forces))
def test_ImplicitSolventParameters(self):
"""Test that solventDielectric and soluteDielectric are passed correctly
"""Test that solventDielectric and soluteDielectric are passed correctly
for the different types of implicit solvent.
"""
......@@ -121,12 +121,12 @@ class TestForceField(unittest.TestCase):
found_matching_solute_dielectric = True
if isinstance(force, NonbondedForce):
self.assertEqual(force.getReactionFieldDielectric(), 1.0)
self.assertTrue(found_matching_solvent_dielectric and
self.assertTrue(found_matching_solvent_dielectric and
found_matching_solute_dielectric)
def test_HydrogenMass(self):
"""Test that altering the mass of hydrogens works correctly."""
topology = self.pdb1.topology
hydrogenMass = 4*amu
system1 = self.forcefield1.createSystem(topology)
......@@ -138,10 +138,10 @@ class TestForceField(unittest.TestCase):
totalMass1 = sum([system1.getParticleMass(i) for i in range(system1.getNumParticles())]).value_in_unit(amu)
totalMass2 = sum([system2.getParticleMass(i) for i in range(system2.getNumParticles())]).value_in_unit(amu)
self.assertAlmostEqual(totalMass1, totalMass2)
def test_Forces(self):
"""Compute forces and compare them to ones generated with a previous version of OpenMM to ensure they haven't changed."""
pdb = PDBFile('systems/lysozyme-implicit.pdb')
system = self.forcefield2.createSystem(pdb.topology)
integrator = VerletIntegrator(0.001)
......@@ -156,10 +156,10 @@ class TestForceField(unittest.TestCase):
if diff > 0.1 and diff/norm(f1) > 1e-3:
numDifferences += 1
self.assertTrue(numDifferences < system.getNumParticles()/20) # Tolerate occasional differences from numerical error
def test_ProgrammaticForceField(self):
"""Test building a ForceField programmatically."""
# Build the ForceField for TIP3P programmatically.
ff = ForceField()
ff.registerAtomType({'name':'tip3p-O', 'class':'OW', 'mass':15.99943*daltons, 'element':elem.oxygen})
......@@ -181,11 +181,11 @@ class TestForceField(unittest.TestCase):
nonbonded.registerAtom({'type':'tip3p-O', 'charge':-0.834, 'sigma':0.31507524065751241*nanometers, 'epsilon':0.635968*kilojoules_per_mole})
nonbonded.registerAtom({'type':'tip3p-H', 'charge':0.417, 'sigma':1*nanometers, 'epsilon':0*kilojoules_per_mole})
ff.registerGenerator(nonbonded)
# Build a water box.
modeller = Modeller(Topology(), [])
modeller.addSolvent(ff, boxSize=Vec3(3, 3, 3)*nanometers)
# Create a system using the programmatic force field as well as one from an XML file.
system1 = ff.createSystem(modeller.topology)
ff2 = ForceField('tip3p.xml')
......@@ -261,19 +261,11 @@ class TestForceField(unittest.TestCase):
from uuid import uuid4
template_name = uuid4()
# Create residue template.
template = ForceField._TemplateData(template_name)
for atom in residue.atoms():
typename = 'XXX'
atom_template = ForceField._TemplateAtomData(atom.name, typename, atom.element)
template.atoms.append(atom_template)
for (atom1,atom2) in residue.internal_bonds():
template.addBondByName(atom1.name, atom2.name)
residue_atoms = [ atom for atom in residue.atoms() ]
for (atom1,atom2) in residue.external_bonds():
if atom1 in residue_atoms:
template.addExternalBondByName(atom1.name)
elif atom2 in residue_atoms:
template.addExternalBondByName(atom2.name)
from simtk.openmm.app.forcefield import _createResidueTemplate
template = _createResidueTemplate(residue) # use helper function
template.name = template_name # replace template name
for (template_atom, residue_atom) in zip(template.atoms, residue.atoms()):
template_atom.type = 'XXX' # replace atom type
# Register the template.
forcefield.registerResidueTemplate(template)
......@@ -347,11 +339,103 @@ class TestForceField(unittest.TestCase):
system = forcefield.createSystem(pdb.topology, nonbondedMethod=test['nonbondedMethod'])
# TODO: Test energies are finite?
def test_getUnmatchedResidues(self):
"""Test retrieval of list of residues for which no templates are available."""
# Load the PDB file.
pdb = PDBFile(os.path.join('systems', 'T4-lysozyme-L99A-p-xylene-implicit.pdb'))
# Create a ForceField object.
forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
# Get list of unmatched residues.
unmatched_residues = forcefield.getUnmatchedResidues(pdb.topology)
# Check results.
self.assertEqual(len(unmatched_residues), 1)
self.assertEqual(unmatched_residues[0].name, 'TMP')
self.assertEqual(unmatched_residues[0].id, '163')
# Load the PDB file.
pdb = PDBFile(os.path.join('systems', 'ala_ala_ala.pdb'))
# Create a ForceField object.
forcefield = ForceField('tip3p.xml')
# Get list of unmatched residues.
unmatched_residues = forcefield.getUnmatchedResidues(pdb.topology)
# Check results.
self.assertEqual(len(unmatched_residues), 3)
self.assertEqual(unmatched_residues[0].name, 'ALA')
self.assertEqual(unmatched_residues[0].chain.id, 'X')
self.assertEqual(unmatched_residues[0].id, '1')
def test_ggenerateTemplatesForUnmatchedResidues(self):
"""Test generation of blank forcefield residue templates for unmatched residues."""
#
# Test where we generate parameters for only a ligand.
#
# Load the PDB file.
pdb = PDBFile(os.path.join('systems', 'nacl-water.pdb'))
# Create a ForceField object.
forcefield = ForceField('tip3p.xml')
# Get list of unmatched residues.
unmatched_residues = forcefield.getUnmatchedResidues(pdb.topology)
[templates, residues] = forcefield.generateTemplatesForUnmatchedResidues(pdb.topology)
# Check results.
self.assertEqual(len(unmatched_residues), 24)
self.assertEqual(len(residues), 2)
self.assertEqual(len(templates), 2)
unique_names = set([ residue.name for residue in residues ])
self.assertTrue('HOH' not in unique_names)
self.assertTrue('NA' in unique_names)
self.assertTrue('CL' in unique_names)
template_names = set([ template.name for template in templates ])
self.assertTrue('HOH' not in template_names)
self.assertTrue('NA' in template_names)
self.assertTrue('CL' in template_names)
# Define forcefield parameters using returned templates.
# NOTE: This parameter definition file will currently only work for residues that either have
# no external bonds or external bonds to other residues parameterized by the simpleTemplateGenerator.
simple_ffxml_contents = """
<ForceField>
<AtomTypes>
<Type name="XXX" class="XXX" element="C" mass="12.0"/>
</AtomTypes>
<HarmonicBondForce>
<Bond type1="XXX" type2="XXX" length="0.1409" k="392459.2"/>
</HarmonicBondForce>
<HarmonicAngleForce>
<Angle type1="XXX" type2="XXX" type3="XXX" angle="2.09439510239" k="527.184"/>
</HarmonicAngleForce>
<NonbondedForce coulomb14scale="0.833333" lj14scale="0.5">
<Atom type="XXX" charge="0.000" sigma="0.315" epsilon="0.635"/>
</NonbondedForce>
</ForceField>"""
#
# Test the pre-geenration of missing residue template for a ligand.
#
# Load the PDB file.
pdb = PDBFile(os.path.join('systems', 'T4-lysozyme-L99A-p-xylene-implicit.pdb'))
# Create a ForceField object.
forcefield = ForceField('amber99sb.xml', 'tip3p.xml', StringIO(simple_ffxml_contents))
# Get list of unique unmatched residues.
[templates, residues] = forcefield.generateTemplatesForUnmatchedResidues(pdb.topology)
# Add residue templates to forcefield.
for template in templates:
# Replace atom types.
for atom in template.atoms:
atom.type = 'XXX'
# Register the template.
forcefield.registerResidueTemplate(template)
# Parameterize system.
system = forcefield.createSystem(pdb.topology, nonbondedMethod=NoCutoff)
# TODO: Test energies are finite?
class AmoebaTestForceField(unittest.TestCase):
"""Test the ForceField.createSystem() method with the AMOEBA forcefield."""
def setUp(self):
"""Set up the tests by loading the input pdb files and force field
"""Set up the tests by loading the input pdb files and force field
xml files.
"""
......@@ -475,4 +559,3 @@ class AmoebaTestForceField(unittest.TestCase):
if __name__ == '__main__':
unittest.main()
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