"tests/TestPeriodicTorsionForce.h" did not exist on "2a53088236129e8a85e7d63965d8cce56212ba25"
Commit 73183c61 authored by ChayaSt's avatar ChayaSt
Browse files

resolved conflict

parents 0e218233 32e08b87
......@@ -120,21 +120,27 @@ class ForceField(object):
self._forces = []
self._scripts = []
self._templateGenerators = []
for file in files:
self.loadFile(file)
self.loadFile(files)
def loadFile(self, file):
def loadFile(self, files):
"""Load an XML file and add the definitions from it to this ForceField.
Parameters
----------
file : string or file
An XML file containing force field definitions. It may be either an
absolute file path, a path relative to the current working
files : string or file or tuple
An XML file or tuple of XML files containing force field definitions.
Each entry may be either an absolute file path, a path relative to the current working
directory, a path relative to this module's data subdirectory (for
built in force fields), or an open file-like object with a read()
method from which the forcefield XML data can be loaded.
"""
if not isinstance(files, tuple):
files = (files,)
trees = []
for file in files:
try:
# this handles either filenames or open file-like objects
tree = etree.parse(file)
......@@ -152,20 +158,25 @@ class ForceField(object):
msg += "ForceField.loadFile() encountered an error reading file '%s'\n" % filename
raise Exception(msg)
root = tree.getroot()
trees.append(tree)
# Load the atom types.
for tree in trees:
if tree.getroot().find('AtomTypes') is not None:
for type in tree.getroot().find('AtomTypes').findall('Type'):
self.registerAtomType(type.attrib)
# Load the residue templates.
for tree in trees:
if tree.getroot().find('Residues') is not None:
for residue in root.find('Residues').findall('Residue'):
for residue in tree.getroot().find('Residues').findall('Residue'):
resName = residue.attrib['name']
template = ForceField._TemplateData(resName)
if 'overload' in residue.attrib:
template.overloadLevel = int(residue.attrib['overload'])
atomIndices = {}
for atom in residue.findall('Atom'):
params = {}
......@@ -194,12 +205,14 @@ class ForceField(object):
# Load force definitions
for child in root:
for tree in trees:
for child in tree.getroot():
if child.tag in parsers:
parsers[child.tag](child, self)
# Load scripts
for tree in trees:
for node in tree.getroot().findall('Script'):
self.registerScript(node.text)
......@@ -237,6 +250,24 @@ class ForceField(object):
self._templates[template.name] = template
signature = _createResidueSignature([atom.element for atom in template.atoms])
if signature in self._templateSignatures:
registered = False
for regtemplate in self._templateSignatures[signature]:
if regtemplate.name == template.name:
if regtemplate.overloadLevel > template.overloadLevel:
# ok to break - this is done every time a template is
# registered so there can only be one already existing
# with same name at a time
registered = True
break
elif regtemplate.overloadLevel < template.overloadLevel:
self._templateSignatures[signature].remove(regtemplate)
self._templateSignatures[signature].append(template)
registered = True
else:
raise Exception('Residue template %s with the same overloadLevel %d already exists.' %
(template.name, template.overloadLevel)
)
if not registered:
self._templateSignatures[signature].append(template)
else:
self._templateSignatures[signature] = [template]
......@@ -379,6 +410,7 @@ class ForceField(object):
self.virtualSites = []
self.bonds = []
self.externalBonds = []
self.overloadLevel = 0
def getAtomIndexByName(self, atom_name):
"""Look up an atom index by atom name, providing a helpful error message if not found."""
......@@ -566,11 +598,16 @@ class ForceField(object):
matches = None
signature = _createResidueSignature([atom.element for atom in res.atoms()])
if signature in self._templateSignatures:
allMatches = []
for t in self._templateSignatures[signature]:
matches = _matchResidue(res, t, bondedToAtom)
if matches is not None:
template = t
break
match = _matchResidue(res, t, bondedToAtom)
if match is not None:
allMatches.append((t, match))
if len(allMatches) == 1:
template = allMatches[0][0]
matches = allMatches[0][1]
elif len(allMatches) > 1:
raise Exception('Multiple matching templates found for residue %d (%s).' % (res.index+1, res.name))
return [template, matches]
def _buildBondedToAtomList(self, topology):
......@@ -703,7 +740,7 @@ class ForceField(object):
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):
constraints=None, rigidWater=True, removeCMMotion=True, hydrogenMass=None, residueTemplates=dict(), **args):
"""Construct an OpenMM System representing a Topology with this force field.
Parameters
......@@ -727,6 +764,13 @@ class ForceField(object):
The mass to use for hydrogen atoms bound to heavy atoms. Any mass
added to a hydrogen is subtracted from the heavy atom to keep
their total mass the same.
residueTemplates : dict=dict()
Key: Topology Residue object
Value: string, name of _TemplateData residue template object to use for
(Key) residue
This allows user to specify which template to apply to particular Residues
in the event that multiple matching templates are available (e.g Fe2+ and Fe3+
templates in the ForceField for a monoatomic iron ion in the topology).
args
Arbitrary additional keyword arguments may also be specified.
This allows extra parameters to be specified that are specific to
......@@ -765,6 +809,13 @@ class ForceField(object):
for chain in topology.chains():
for res in chain.residues():
if res in residueTemplates:
tname = residueTemplates[res]
template = self._templates[tname]
matches = _matchResidue(res, template, bondedToAtom)
if matches is None:
raise Exception('User-supplied template %s does not match the residue %d (%s)' % (tname, res.index+1, res.name))
else:
# Attempt to match one of the existing templates.
[template, matches] = self._getResidueTemplateMatches(res, bondedToAtom)
if matches is None:
......@@ -1183,8 +1234,12 @@ class HarmonicBondGenerator(object):
@staticmethod
def parseElement(element, ff):
existing = [f for f in ff._forces if isinstance(f, HarmonicBondGenerator)]
if len(existing) == 0:
generator = HarmonicBondGenerator(ff)
ff.registerGenerator(generator)
else:
generator = existing[0]
for bond in element.findall('Bond'):
generator.registerBond(bond.attrib)
......@@ -1236,8 +1291,12 @@ class HarmonicAngleGenerator(object):
@staticmethod
def parseElement(element, ff):
existing = [f for f in ff._forces if isinstance(f, HarmonicAngleGenerator)]
if len(existing) == 0:
generator = HarmonicAngleGenerator(ff)
ff.registerGenerator(generator)
else:
generator = existing[0]
for angle in element.findall('Angle'):
generator.registerAngle(angle.attrib)
......@@ -1320,8 +1379,12 @@ class PeriodicTorsionGenerator(object):
@staticmethod
def parseElement(element, ff):
existing = [f for f in ff._forces if isinstance(f, PeriodicTorsionGenerator)]
if len(existing) == 0:
generator = PeriodicTorsionGenerator(ff)
ff.registerGenerator(generator)
else:
generator = existing[0]
for torsion in element.findall('Proper'):
generator.registerProperTorsion(torsion.attrib)
for torsion in element.findall('Improper'):
......@@ -1419,8 +1482,12 @@ class RBTorsionGenerator(object):
@staticmethod
def parseElement(element, ff):
existing = [f for f in ff._forces if isinstance(f, RBTorsionGenerator)]
if len(existing) == 0:
generator = RBTorsionGenerator(ff)
ff.registerGenerator(generator)
else:
generator = existing[0]
for torsion in element.findall('Proper'):
types = ff._findAtomTypes(torsion.attrib, 4)
if None not in types:
......@@ -1523,8 +1590,12 @@ class CMAPTorsionGenerator(object):
@staticmethod
def parseElement(element, ff):
existing = [f for f in ff._forces if isinstance(f, CMAPTorsionGenerator)]
if len(existing) == 0:
generator = CMAPTorsionGenerator(ff)
ff.registerGenerator(generator)
else:
generator = existing[0]
for map in element.findall('Map'):
values = [float(x) for x in map.text.split()]
size = sqrt(len(values))
......
......@@ -6,7 +6,7 @@ Simbios, the NIH National Center for Physics-Based Simulation of
Biological Structures at Stanford, funded under the NIH Roadmap for
Medical Research, grant U54 GM072970. See https://simtk.org.
Portions copyright (c) 2012-2015 Stanford University and the Authors.
Portions copyright (c) 2012-2016 Stanford University and the Authors.
Authors: Peter Eastman
Contributors: Jason Swails
......@@ -814,7 +814,7 @@ class GromacsTopFile(object):
map = []
for i in range(mapSize):
for j in range(mapSize):
map.append(float(params[8+mapSize*((j+mapSize/2)%mapSize)+((i+mapSize/2)%mapSize)]))
map.append(float(params[8+mapSize*((j+mapSize//2)%mapSize)+((i+mapSize//2)%mapSize)]))
map = tuple(map)
if map not in mapIndices:
mapIndices[map] = cmap.addMap(mapSize, map)
......
......@@ -535,7 +535,7 @@ class GBSAGBnForce(CustomAmberGBForce):
def addParticle(self, parameters):
parameters = CustomAmberGBForce.addParticle(self, parameters)
if parameters[1] < 0.1 or parameters[1] > 0.2:
if parameters[1] + self.OFFSET < 0.1 or parameters[1] + self.OFFSET > 0.2:
raise ValueError('Radii must be between 1 and 2 Angstroms for neck lookup')
def setParticleParameters(self, idx, parameters):
......
......@@ -35,7 +35,7 @@ __author__ = "Peter Eastman"
__version__ = "1.0"
from simtk.openmm.app import Topology, PDBFile, ForceField
from simtk.openmm.app.forcefield import HAngles, AllBonds, _createResidueSignature, _matchResidue, DrudeGenerator
from simtk.openmm.app.forcefield import HAngles, AllBonds, CutoffNonPeriodic, _createResidueSignature, _matchResidue, DrudeGenerator
from simtk.openmm.app.topology import Residue
from simtk.openmm.vec3 import Vec3
from simtk.openmm import System, Context, NonbondedForce, CustomNonbondedForce, HarmonicBondForce, HarmonicAngleForce, VerletIntegrator, LocalEnergyMinimizer
......@@ -857,7 +857,7 @@ class Modeller(object):
if forcefield is not None:
# Use the ForceField the user specified.
system = forcefield.createSystem(newTopology, rigidWater=False)
system = forcefield.createSystem(newTopology, rigidWater=False, nonbondedMethod=CutoffNonPeriodic)
atoms = list(newTopology.atoms())
for i in range(system.getNumParticles()):
if atoms[i].element != elem.hydrogen:
......@@ -869,6 +869,8 @@ class Modeller(object):
system = System()
nonbonded = CustomNonbondedForce('100/((r/0.1)^4+1)')
nonbonded.setNonbondedMethod(CustomNonbondedForce.CutoffNonPeriodic);
nonbonded.setCutoffDistance(1*nanometer)
bonds = HarmonicBondForce()
angles = HarmonicAngleForce()
system.addForce(nonbonded)
......
......@@ -6,7 +6,7 @@ Simbios, the NIH National Center for Physics-Based Simulation of
Biological Structures at Stanford, funded under the NIH Roadmap for
Medical Research, grant U54 GM072970. See https://simtk.org.
Portions copyright (c) 2012-2015 Stanford University and the Authors.
Portions copyright (c) 2012-2016 Stanford University and the Authors.
Authors: Peter Eastman
Contributors:
......@@ -58,6 +58,9 @@ class PDBFile(object):
_residueNameReplacements = {}
_atomNameReplacements = {}
_standardResidues = ['ALA', 'ASN', 'CYS', 'GLU', 'HIS', 'LEU', 'MET', 'PRO', 'THR', 'TYR',
'ARG', 'ASP', 'GLN', 'GLY', 'ILE', 'LYS', 'PHE', 'SER', 'TRP', 'VAL',
'A', 'G', 'C', 'U', 'I', 'DA', 'DG', 'DC', 'DT', 'DI', 'HOH']
def __init__(self, file, extraParticleIdentifier='EP'):
"""Load a PDB file.
......@@ -75,10 +78,6 @@ class PDBFile(object):
metalElements = ['Al','As','Ba','Ca','Cd','Ce','Co','Cs','Cu','Dy','Fe','Gd','Hg','Ho','In','Ir','K','Li','Mg',
'Mn','Mo','Na','Ni','Pb','Pd','Pt','Rb','Rh','Sm','Sr','Te','Tl','V','W','Yb','Zn']
standardResidues = ['ALA', 'ASN', 'CYS', 'GLU', 'HIS', 'LEU', 'MET', 'PRO', 'THR', 'TYR',
'ARG', 'ASP', 'GLN', 'GLY', 'ILE', 'LYS', 'PHE', 'SER', 'TRP', 'VAL',
'A', 'G', 'C', 'U', 'I', 'DA', 'DG', 'DC', 'DT', 'DI', 'HOH']
top = Topology()
## The Topology read from the PDB file
self.topology = top
......@@ -173,9 +172,9 @@ class PDBFile(object):
if atomByNumber[i].element is not None and atomByNumber[j].element is not None:
if atomByNumber[i].element.symbol not in metalElements and atomByNumber[j].element.symbol not in metalElements:
connectBonds.append((atomByNumber[i], atomByNumber[j]))
elif atomByNumber[i].element.symbol in metalElements and atomByNumber[j].residue.name not in standardResidues:
elif atomByNumber[i].element.symbol in metalElements and atomByNumber[j].residue.name not in PDBFile._standardResidues:
connectBonds.append((atomByNumber[i], atomByNumber[j]))
elif atomByNumber[j].element.symbol in metalElements and atomByNumber[i].residue.name not in standardResidues:
elif atomByNumber[j].element.symbol in metalElements and atomByNumber[i].residue.name not in PDBFile._standardResidues:
connectBonds.append((atomByNumber[i], atomByNumber[j]))
else:
connectBonds.append((atomByNumber[i], atomByNumber[j]))
......@@ -331,6 +330,8 @@ class PDBFile(object):
raise ValueError('Particle position is NaN')
if any(math.isinf(norm(pos)) for pos in positions):
raise ValueError('Particle position is infinite')
nonHeterogens = PDBFile._standardResidues[:]
nonHeterogens.remove('HOH')
atomIndex = 1
posIndex = 0
if modelIndex is not None:
......@@ -350,6 +351,10 @@ class PDBFile(object):
resId = res.id
else:
resId = "%4d" % ((resIndex+1)%10000)
if res.name in nonHeterogens:
recordName = "ATOM "
else:
recordName = "HETATM"
for atom in res.atoms():
if atom.element is not None:
symbol = atom.element.symbol
......@@ -362,8 +367,8 @@ class PDBFile(object):
else:
atomName = atom.name
coords = positions[posIndex]
line = "ATOM %5d %-4s %3s %s%4s %s%s%s 1.00 0.00 %2s " % (
atomIndex%100000, atomName, resName, chainName, resId, _format_83(coords[0]),
line = "%s%5d %-4s %3s %s%4s %s%s%s 1.00 0.00 %2s " % (
recordName, atomIndex%100000, atomName, resName, chainName, resId, _format_83(coords[0]),
_format_83(coords[1]), _format_83(coords[2]), symbol)
assert len(line) == 80, 'Fixed width overflow detected'
print(line, file=file)
......@@ -388,12 +393,9 @@ class PDBFile(object):
"""
# Identify bonds that should be listed as CONECT records.
standardResidues = ['ALA', 'ASN', 'CYS', 'GLU', 'HIS', 'LEU', 'MET', 'PRO', 'THR', 'TYR',
'ARG', 'ASP', 'GLN', 'GLY', 'ILE', 'LYS', 'PHE', 'SER', 'TRP', 'VAL',
'A', 'G', 'C', 'U', 'I', 'DA', 'DG', 'DC', 'DT', 'DI', 'HOH']
conectBonds = []
for atom1, atom2 in topology.bonds():
if atom1.residue.name not in standardResidues or atom2.residue.name not in standardResidues:
if atom1.residue.name not in PDBFile._standardResidues or atom2.residue.name not in PDBFile._standardResidues:
conectBonds.append((atom1, atom2))
elif atom1.name == 'SG' and atom2.name == 'SG' and atom1.residue.name == 'CYS' and atom2.residue.name == 'CYS':
conectBonds.append((atom1, atom2))
......
......@@ -361,5 +361,17 @@ class TestAmberPrmtopFile(unittest.TestCase):
# Make sure it says something about chamber
self.assertTrue('chamber' in str(e).lower())
def testGBneckRadii(self):
""" Tests that GBneck radii limits are correctly enforced """
from simtk.openmm.app.internal.customgbforces import GBSAGBnForce
f = GBSAGBnForce()
# Make sure legal parameters do not raise
f.addParticle([0, 0.1, 0.5])
f.addParticle([0, 0.2, 0.5])
f.addParticle([0, 0.15, 0.5])
# Now make sure that out-of-range parameters *do* raise
self.assertRaises(ValueError, lambda: f.addParticle([0, 0.9, 0.5]))
self.assertRaises(ValueError, lambda: f.addParticle([0, 0.21, 0.5]))
if __name__ == '__main__':
unittest.main()
......@@ -449,6 +449,183 @@ class TestForceField(unittest.TestCase):
self.assertEqual(templates[1].name, 'ALA')
self.assertEqual(templates[2].name, 'CALA')
def test_Wildcard(self):
"""Test that PeriodicTorsionForces using wildcard ('') for atom types / classes in the ffxml are correctly registered"""
# Use wildcards in types
xml = """
<ForceField>
<AtomTypes>
<Type name="C" class="C" element="C" mass="12.010000"/>
<Type name="O" class="O" element="O" mass="16.000000"/>
</AtomTypes>
<PeriodicTorsionForce>
<Proper type1="" type2="C" type3="C" type4="" periodicity1="2" phase1="3.141593" k1="15.167000"/>
<Improper type1="C" type2="" type3="" type4="O" periodicity1="2" phase1="3.141593" k1="43.932000"/>
</PeriodicTorsionForce>
</ForceField>"""
ff = ForceField(StringIO(xml))
self.assertEqual(len(ff._forces[0].proper), 1)
self.assertEqual(len(ff._forces[0].improper), 1)
# Use wildcards in classes
xml = """
<ForceField>
<AtomTypes>
<Type name="C" class="C" element="C" mass="12.010000"/>
<Type name="O" class="O" element="O" mass="16.000000"/>
</AtomTypes>
<PeriodicTorsionForce>
<Proper class1="" class2="C" class3="C" class4="" periodicity1="2" phase1="3.141593" k1="15.167000"/>
<Improper class1="C" class2="" class3="" class4="O" periodicity1="2" phase1="3.141593" k1="43.932000"/>
</PeriodicTorsionForce>
</ForceField>"""
ff = ForceField(StringIO(xml))
self.assertEqual(len(ff._forces[0].proper), 1)
self.assertEqual(len(ff._forces[0].improper), 1)
def test_ScalingFactorCombining(self):
""" Tests that FFs can be combined if their scaling factors are very close """
forcefield = ForceField('amber99sb.xml', os.path.join('systems', 'test_amber_ff.xml'))
# This would raise an exception if it didn't work
def test_MultipleFilesandForceTags(self):
"""Test that the order of listing of multiple ffxmls does not matter.
Tests that one generator per force type is created and that the ffxml
defining atom types does not have to be listed first"""
ffxml = """<ForceField>
<Residues>
<Residue name="ACE-Test">
<Atom name="HH31" type="710"/>
<Atom name="CH3" type="711"/>
<Atom name="HH32" type="710"/>
<Atom name="HH33" type="710"/>
<Atom name="C" type="712"/>
<Atom name="O" type="713"/>
<Bond from="0" to="1"/>
<Bond from="1" to="2"/>
<Bond from="1" to="3"/>
<Bond from="1" to="4"/>
<Bond from="4" to="5"/>
<ExternalBond from="4"/>
</Residue>
</Residues>
<PeriodicTorsionForce>
<Proper class1="C" class2="C" class3="C" class4="C" periodicity1="2" phase1="3.14159265359" k1="10.46"/>
<Improper class1="C" class2="C" class3="C" class4="C" periodicity1="2" phase1="3.14159265359" k1="43.932"/>
</PeriodicTorsionForce>
</ForceField>"""
ff1 = ForceField(StringIO(ffxml), 'amber99sbildn.xml')
ff2 = ForceField('amber99sbildn.xml', StringIO(ffxml))
self.assertEqual(len(ff1._forces), 4)
self.assertEqual(len(ff2._forces), 4)
pertorsion1 = ff1._forces[0]
pertorsion2 = ff2._forces[2]
self.assertEqual(len(pertorsion1.proper), 110)
self.assertEqual(len(pertorsion1.improper), 42)
self.assertEqual(len(pertorsion2.proper), 110)
self.assertEqual(len(pertorsion2.improper), 42)
def test_ResidueTemplateUserChoice(self):
"""Test createSystem does not allow multiple matching templates, unless
user has specified which template to use via residueTemplates arg"""
ffxml = """<ForceField>
<AtomTypes>
<Type name="Fe2+" class="Fe2+" element="Fe" mass="55.85"/>
<Type name="Fe3+" class="Fe3+" element="Fe" mass="55.85"/>
</AtomTypes>
<Residues>
<Residue name="FE2">
<Atom name="FE2" type="Fe2+" charge="2.0"/>
</Residue>
<Residue name="FE">
<Atom name="FE" type="Fe3+" charge="3.0"/>
</Residue>
</Residues>
<NonbondedForce coulomb14scale="0.833333333333" lj14scale="0.5">
<UseAttributeFromResidue name="charge"/>
<Atom type="Fe2+" sigma="0.227535532613" epsilon="0.0150312292"/>
<Atom type="Fe3+" sigma="0.192790482606" epsilon="0.00046095128"/>
</NonbondedForce>
</ForceField>"""
pdb_string = "ATOM 1 FE FE A 1 20.956 27.448 -29.067 1.00 0.00 Fe"
ff = ForceField(StringIO(ffxml))
pdb = PDBFile(StringIO(pdb_string))
self.assertRaises(Exception, lambda: ff.createSystem(pdb.topology))
sys = ff.createSystem(pdb.topology, residueTemplates={list(pdb.topology.residues())[0] : 'FE2'})
# confirm charge
self.assertEqual(sys.getForce(0).getParticleParameters(0)[0]._value, 2.0)
sys = ff.createSystem(pdb.topology, residueTemplates={list(pdb.topology.residues())[0] : 'FE'})
# confirm charge
self.assertEqual(sys.getForce(0).getParticleParameters(0)[0]._value, 3.0)
def test_ResidueOverloading(self):
"""Test residue overloading via overload tag in the XML"""
ffxml1 = """<ForceField>
<AtomTypes>
<Type name="Fe2+_tip3p_HFE" class="Fe2+_tip3p_HFE" element="Fe" mass="55.85"/>
</AtomTypes>
<Residues>
<Residue name="FE2">
<Atom name="FE2" type="Fe2+_tip3p_HFE" charge="2.0"/>
</Residue>
</Residues>
<NonbondedForce coulomb14scale="0.833333333333" lj14scale="0.5">
<UseAttributeFromResidue name="charge"/>
<Atom type="Fe2+_tip3p_HFE" sigma="0.227535532613" epsilon="0.0150312292"/>
</NonbondedForce>
</ForceField>"""
ffxml2 = """<ForceField>
<AtomTypes>
<Type name="Fe2+_tip3p_standard" class="Fe2+_tip3p_standard" element="Fe" mass="55.85"/>
</AtomTypes>
<Residues>
<Residue name="FE2">
<Atom name="FE2" type="Fe2+_tip3p_standard" charge="2.0"/>
</Residue>
</Residues>
<NonbondedForce coulomb14scale="0.833333333333" lj14scale="0.5">
<UseAttributeFromResidue name="charge"/>
<Atom type="Fe2+_tip3p_standard" sigma="0.241077193129" epsilon="0.03940482832"/>
</NonbondedForce>
</ForceField>"""
ffxml3 = """<ForceField>
<AtomTypes>
<Type name="Fe2+_tip3p_standard" class="Fe2+_tip3p_standard" element="Fe" mass="55.85"/>
</AtomTypes>
<Residues>
<Residue name="FE2" overload="1">
<Atom name="FE2" type="Fe2+_tip3p_standard" charge="2.0"/>
</Residue>
</Residues>
<NonbondedForce coulomb14scale="0.833333333333" lj14scale="0.5">
<UseAttributeFromResidue name="charge"/>
<Atom type="Fe2+_tip3p_standard" sigma="0.241077193129" epsilon="0.03940482832"/>
</NonbondedForce>
</ForceField>"""
pdb_string = "ATOM 1 FE FE A 1 20.956 27.448 -29.067 1.00 0.00 Fe"
pdb = PDBFile(StringIO(pdb_string))
self.assertRaises(Exception, lambda: ForceField(StringIO(ffxml1), StringIO(ffxml2)))
ff = ForceField(StringIO(ffxml1), StringIO(ffxml3))
self.assertEqual(ff._templates['FE2'].atoms[0].type, 'Fe2+_tip3p_standard')
ff.createSystem(pdb.topology)
class AmoebaTestForceField(unittest.TestCase):
"""Test the ForceField.createSystem() method with the AMOEBA forcefield."""
......@@ -539,11 +716,9 @@ class AmoebaTestForceField(unittest.TestCase):
def test_LennardJones_generator(self):
""" Test the LennardJones generator"""
warnings.filterwarnings('ignore', category=CharmmPSFWarning)
psf = CharmmPsfFile('systems/methanol_ions.psf')
pdb = PDBFile('systems/methanol_ions.pdb')
params = CharmmParameterSet('systems/top_all36_cgenff.rtf',
'systems/par_all36_cgenff.prm',
'systems/toppar_water_ions.str'
psf = CharmmPsfFile('systems/ions.psf')
pdb = PDBFile('systems/ions.pdb')
params = CharmmParameterSet('systems/toppar_water_ions.str'
)
# Box dimensions (found from bounding box)
......@@ -565,27 +740,10 @@ class AmoebaTestForceField(unittest.TestCase):
xml = """
<ForceField>
<AtomTypes>
<Type name="CG331" class="CG331" element="C" mass="12.011"/>
<Type name="OG311" class="OG311" element="O" mass="15.9994"/>
<Type name="HGP1" class="HGP1" element="H" mass="1.008"/>
<Type name="HGA3" class="HGA3" element="H" mass="1.008"/>
<Type name="SOD" class="SOD" element="Na" mass="22.98977"/>
<Type name="CLA" class="CLA" element="Cl" mass="35.45"/>
</AtomTypes>
<Residues>
<Residue name="MEOH">
<Atom name="CB" type="CG331" charge="0.0"/>
<Atom name="OG" type="OG311" charge="0.0"/>
<Atom name="HG1" type="HGP1" charge="0.0"/>
<Atom name="HB1" type="HGA3" charge="0.0"/>
<Atom name="HB2" type="HGA3" charge="0.0"/>
<Atom name="HB3" type="HGA3" charge="0.0"/>
<Bond atomName1="CB" atomName2="OG"/>
<Bond atomName1="OG" atomName2="HG1"/>
<Bond atomName1="CB" atomName2="HB1"/>
<Bond atomName1="CB" atomName2="HB2"/>
<Bond atomName1="CB" atomName2="HB3"/>
</Residue>
<Residue name="CLA">
<Atom name="CLA" type="CLA" charge="0.0"/>
</Residue>
......@@ -593,37 +751,12 @@ class AmoebaTestForceField(unittest.TestCase):
<Atom name="SOD" type="SOD" charge="0.0"/>
</Residue>
</Residues>
<HarmonicBondForce>
<Bond type1="CG331" type2="OG311" length="0.142" k="358150.4"/>
<Bond type1="CG331" type2="HGA3" length="0.1111" k="269449.6"/>
<Bond type1="OG311" type2="HGP1" length="0.096" k="456056.0"/>
</HarmonicBondForce>
<HarmonicAngleForce>
<Angle type1="HGA3" type2="CG331" type3="HGA3" angle="1.89193690916" k="297.064"/>
<Angle type1="CG331" type2="OG311" type3="HGP1" angle="1.85004900711" k="481.16"/>
<Angle type1="OG311" type2="CG331" type3="HGA3" angle="1.9004890225" k="384.0912"/>
</HarmonicAngleForce>
<!-- Urey-Bradley terms -->
<AmoebaUreyBradleyForce>
<UreyBradley type1="HGA3" type2="CG331" type3="HGA3" d="0.1802" k="2259.36"/>
</AmoebaUreyBradleyForce>
<PeriodicTorsionForce>
<Proper type1="HGA3" type2="CG331" type3="OG311" type4="HGP1" periodicity1="3" phase1="0.0" k1="0.75312"/>
</PeriodicTorsionForce>
<NonbondedForce coulomb14scale="1.0" lj14scale="1.0">
<UseAttributeFromResidue name="charge"/>
<Atom type="CG331" sigma="1.0" epsilon="0.0"/>
<Atom type="OG311" sigma="1.0" epsilon="0.0"/>
<Atom type="HGP1" sigma="1.0" epsilon="0.0"/>
<Atom type="HGA3" sigma="1.0" epsilon="0.0"/>
<Atom type="SOD" sigma="1.0" epsilon="0.0"/>
<Atom type="CLA" sigma="1.0" epsilon="0.0"/>
</NonbondedForce>
<LennardJonesForce lj14scale="1.0">
<Atom type="CG331" sigma="0.365268474438" epsilon="0.326352"/>
<Atom type="OG311" sigma="0.314487247504" epsilon="0.8037464"/>
<Atom type="HGP1" sigma="0.0400013524445" epsilon="0.192464"/>
<Atom type="HGA3" sigma="0.238760856462" epsilon="0.100416"/>
<Atom type="CLA" sigma="0.404468018036" epsilon="0.6276"/>
<Atom type="SOD" sigma="0.251367073323" epsilon="0.1962296"/>
<NBFixPair type1="CLA" type2="SOD" emin="0.350933" rmin="0.3731"/>
......@@ -641,50 +774,5 @@ class AmoebaTestForceField(unittest.TestCase):
ene2 = state2.getPotentialEnergy().value_in_unit(kilocalories_per_mole)
self.assertAlmostEqual(ene, ene2)
def test_Wildcard(self):
"""Test that PeriodicTorsionForces using wildcard ('') for atom types / classes in the ffxml are correctly registered"""
# Use wildcards in types
xml = """
<ForceField>
<AtomTypes>
<Type name="C" class="C" element="C" mass="12.010000"/>
<Type name="O" class="O" element="O" mass="16.000000"/>
</AtomTypes>
<PeriodicTorsionForce>
<Proper type1="" type2="C" type3="C" type4="" periodicity1="2" phase1="3.141593" k1="15.167000"/>
<Improper type1="C" type2="" type3="" type4="O" periodicity1="2" phase1="3.141593" k1="43.932000"/>
</PeriodicTorsionForce>
</ForceField>"""
ff = ForceField(StringIO(xml))
self.assertEqual(len(ff._forces[0].proper), 1)
self.assertEqual(len(ff._forces[0].improper), 1)
# Use wildcards in classes
xml = """
<ForceField>
<AtomTypes>
<Type name="C" class="C" element="C" mass="12.010000"/>
<Type name="O" class="O" element="O" mass="16.000000"/>
</AtomTypes>
<PeriodicTorsionForce>
<Proper class1="" class2="C" class3="C" class4="" periodicity1="2" phase1="3.141593" k1="15.167000"/>
<Improper class1="C" class2="" class3="" class4="O" periodicity1="2" phase1="3.141593" k1="43.932000"/>
</PeriodicTorsionForce>
</ForceField>"""
ff = ForceField(StringIO(xml))
self.assertEqual(len(ff._forces[0].proper), 1)
self.assertEqual(len(ff._forces[0].improper), 1)
def test_ScalingFactorCombining(self):
""" Tests that FFs can be combined if their scaling factors are very close """
forcefield = ForceField('amber99sb.xml', os.path.join('systems', 'test_amber_ff.xml'))
# This would raise an exception if it didn't work
if __name__ == '__main__':
unittest.main()
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