Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
tsoc
openmm
Commits
c1d35c3e
Commit
c1d35c3e
authored
Apr 05, 2016
by
peastman
Browse files
Continuing to implement force field patches
parent
e1f8d449
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
178 additions
and
11 deletions
+178
-11
wrappers/python/simtk/openmm/app/forcefield.py
wrappers/python/simtk/openmm/app/forcefield.py
+66
-5
wrappers/python/tests/TestPatches.py
wrappers/python/tests/TestPatches.py
+112
-6
No files found.
wrappers/python/simtk/openmm/app/forcefield.py
View file @
c1d35c3e
...
@@ -38,6 +38,7 @@ import itertools
...
@@ -38,6 +38,7 @@ import itertools
import xml.etree.ElementTree as etree
import xml.etree.ElementTree as etree
import math
import math
from math import sqrt, cos
from math import sqrt, cos
from copy import deepcopy
import simtk.openmm as mm
import simtk.openmm as mm
import simtk.unit as unit
import simtk.unit as unit
from . import element as elem
from . import element as elem
...
@@ -203,7 +204,7 @@ class ForceField(object):
...
@@ -203,7 +204,7 @@ class ForceField(object):
template.addExternalBondByName(bond.attrib['atomName'])
template.addExternalBondByName(bond.attrib['atomName'])
else:
else:
template.addExternalBond(int(bond.attrib['from']))
template.addExternalBond(int(bond.attrib['from']))
for
patch
in
patch
.
findall
(
'AllowPatch'
):
for patch in
residue
.findall('AllowPatch'):
patchName = patch.attrib['name']
patchName = patch.attrib['name']
if ':' in name:
if ':' in name:
colonIndex = name.find(':')
colonIndex = name.find(':')
...
@@ -235,7 +236,7 @@ class ForceField(object):
...
@@ -235,7 +236,7 @@ class ForceField(object):
allAtomNames.add(atomName)
allAtomNames.add(atomName)
atomDescription = ForceField._PatchAtomData(atomName)
atomDescription = ForceField._PatchAtomData(atomName)
typeName = atom.attrib['type']
typeName = atom.attrib['type']
patchData
.
addedAtoms
.
append
(
ForceField
.
_TemplateAtomData
(
atomDescription
,
typeName
,
self
.
_atomTypes
[
typeName
].
element
,
params
))
patchData.addedAtoms
[atomDescription.residue]
.append(ForceField._TemplateAtomData(atomDescription
.name
, typeName, self._atomTypes[typeName].element, params))
for atom in patch.findall('ChangeAtom'):
for atom in patch.findall('ChangeAtom'):
params = {}
params = {}
for key in atom.attrib:
for key in atom.attrib:
...
@@ -247,7 +248,7 @@ class ForceField(object):
...
@@ -247,7 +248,7 @@ class ForceField(object):
allAtomNames.add(atomName)
allAtomNames.add(atomName)
atomDescription = ForceField._PatchAtomData(atomName)
atomDescription = ForceField._PatchAtomData(atomName)
typeName = atom.attrib['type']
typeName = atom.attrib['type']
patchData
.
changedAtoms
.
append
(
ForceField
.
_TemplateAtomData
(
atomDescription
,
typeName
,
self
.
_atomTypes
[
typeName
].
element
,
params
))
patchData.changedAtoms
[atomDescription.residue]
.append(ForceField._TemplateAtomData(atomDescription
.name
, typeName, self._atomTypes[typeName].element, params))
for atom in patch.findall('RemoveAtom'):
for atom in patch.findall('RemoveAtom'):
atomName = atom.attrib['name']
atomName = atom.attrib['name']
if atomName in allAtomNames:
if atomName in allAtomNames:
...
@@ -586,14 +587,74 @@ class ForceField(object):
...
@@ -586,14 +587,74 @@ class ForceField(object):
def __init__(self, name, numResidues):
def __init__(self, name, numResidues):
self.name = name
self.name = name
self.numResidues = numResidues
self.numResidues = numResidues
self
.
addedAtoms
=
[]
self.addedAtoms = [[] for i in range(numResidues)]
self.changedAtoms = [[] for i in range(numResidues)]
self.deletedAtoms = []
self.deletedAtoms = []
self
.
changedAtoms
=
[]
self.addedBonds = []
self.addedBonds = []
self.deletedBonds = []
self.deletedBonds = []
self.addedExternalBonds = []
self.addedExternalBonds = []
self.deletedExternalBonds = []
self.deletedExternalBonds = []
def createPatchedTemplates(self, templates):
"""Apply this patch to a set of templates, creating new modified ones."""
if len(templates) != self.numResidues:
raise ValueError("Patch '%s' expected %d templates, received %d", (self.name, self.numResidues, len(templates)))
# Construct a new version of each template.
newTemplates = []
for index, template in enumerate(templates):
newTemplate = ForceField._TemplateData("%s-%s" % (template.name, self.name))
newTemplates.append(newTemplate)
# Build the list of atoms in it.
for atom in template.atoms:
if not any(deleted.name == atom.name and deleted.residue == index for deleted in self.deletedAtoms):
newTemplate.atoms.append(deepcopy(atom))
for atom in self.addedAtoms[index]:
newTemplate.atoms.append(deepcopy(atom))
oldAtomIndex = dict([(atom.name, i) for i, atom in enumerate(template.atoms)])
newAtomIndex = dict([(atom.name, i) for i, atom in enumerate(newTemplate.atoms)])
for atom in self.changedAtoms[index]:
if atom.name not in newAtomIndex:
raise ValueError("Patch '%s' modifies nonexistent atom '%s' in template '%s'" % (self.name, atom.name, template.name))
newTemplate.atoms[newAtomIndex[atom.name]] = deepcopy(atom)
# Copy over the virtual sites, translating the atom indices.
indexMap = dict([(oldAtomIndex[name], newAtomIndex[name]) for name in newAtomIndex if name in oldAtomIndex])
for site in template.virtualSites:
if site.index in indexMap and all(i in indexMap for i in site.atoms):
newSite = deepcopy(site)
newSite.index = indexMap[site.index]
newSite.atoms = [indexMap[i] for i in site.atoms]
newTemplate.virtualSites.append(newSite)
# Build the lists of bonds and external bonds.
atomMap = dict([(template.atoms[i], indexMap[i]) for i in indexMap])
deletedBonds = [(atom1.name, atom2.name) for atom1, atom2 in self.deletedBonds if atom1.residue == index and atom2.residue == index]
for atom1, atom2 in template.bonds:
a1 = template.atoms[atom1]
a2 = template.atoms[atom2]
if (a1.name, a2.name) not in deletedBonds and (a2.name, a1.name) not in deletedBonds:
newTemplate.addBond(atomMap[a1], atomMap[a2])
deletedExternalBonds = [atom.name for atom in self.deletedExternalBonds if atom.residue == index]
for atom in template.externalBonds:
if template.atoms[atom].name not in deletedExternalBonds:
newTemplate.addExternalBond(atomMap[atom])
for atom1, atom2 in self.addedBonds:
if atom1.residue == index and atom2.residue == index:
newTemplate.addBondByName(atom1.name, atom2.name)
elif atom1.residue == index:
newTemplate.addExternalBondByName(atom1.name)
elif atom2.residue == index:
newTemplate.addExternalBondByName(atom2.name)
for atom in self.addedExternalBonds:
newTemplate.addExternalBondByName(atom.name)
return newTemplates
class _PatchAtomData(object):
class _PatchAtomData(object):
"""Inner class used to encapsulate data about an atom in a patch definition."""
"""Inner class used to encapsulate data about an atom in a patch definition."""
def __init__(self, description):
def __init__(self, description):
...
...
wrappers/python/tests/TestPatches.py
View file @
c1d35c3e
...
@@ -39,7 +39,9 @@ class TestForceField(unittest.TestCase):
...
@@ -39,7 +39,9 @@ class TestForceField(unittest.TestCase):
self
.
assertEqual
(
1
,
len
(
ff
.
_patches
))
self
.
assertEqual
(
1
,
len
(
ff
.
_patches
))
patch
=
ff
.
_patches
[
'Test'
]
patch
=
ff
.
_patches
[
'Test'
]
self
.
assertEqual
(
1
,
len
(
patch
.
addedAtoms
))
self
.
assertEqual
(
1
,
len
(
patch
.
addedAtoms
))
self
.
assertEqual
(
1
,
len
(
patch
.
addedAtoms
[
0
]))
self
.
assertEqual
(
1
,
len
(
patch
.
changedAtoms
))
self
.
assertEqual
(
1
,
len
(
patch
.
changedAtoms
))
self
.
assertEqual
(
1
,
len
(
patch
.
changedAtoms
[
0
]))
self
.
assertEqual
(
1
,
len
(
patch
.
deletedAtoms
))
self
.
assertEqual
(
1
,
len
(
patch
.
deletedAtoms
))
self
.
assertEqual
(
1
,
len
(
patch
.
addedBonds
))
self
.
assertEqual
(
1
,
len
(
patch
.
addedBonds
))
self
.
assertEqual
(
1
,
len
(
patch
.
deletedBonds
))
self
.
assertEqual
(
1
,
len
(
patch
.
deletedBonds
))
...
@@ -47,12 +49,10 @@ class TestForceField(unittest.TestCase):
...
@@ -47,12 +49,10 @@ class TestForceField(unittest.TestCase):
self
.
assertEqual
(
1
,
len
(
patch
.
deletedExternalBonds
))
self
.
assertEqual
(
1
,
len
(
patch
.
deletedExternalBonds
))
self
.
assertEqual
(
1
,
len
(
ff
.
_templatePatches
))
self
.
assertEqual
(
1
,
len
(
ff
.
_templatePatches
))
self
.
assertEqual
(
1
,
len
(
ff
.
_templatePatches
[
'RES'
]))
self
.
assertEqual
(
1
,
len
(
ff
.
_templatePatches
[
'RES'
]))
self
.
assertEqual
(
'A'
,
patch
.
addedAtoms
[
0
].
name
.
name
)
self
.
assertEqual
(
'A'
,
patch
.
addedAtoms
[
0
][
0
].
name
)
self
.
assertEqual
(
0
,
patch
.
addedAtoms
[
0
].
name
.
residue
)
self
.
assertEqual
(
'A type'
,
patch
.
addedAtoms
[
0
][
0
].
type
)
self
.
assertEqual
(
'A type'
,
patch
.
addedAtoms
[
0
].
type
)
self
.
assertEqual
(
'B'
,
patch
.
changedAtoms
[
0
][
0
].
name
)
self
.
assertEqual
(
'B'
,
patch
.
changedAtoms
[
0
].
name
.
name
)
self
.
assertEqual
(
'B type'
,
patch
.
changedAtoms
[
0
][
0
].
type
)
self
.
assertEqual
(
0
,
patch
.
changedAtoms
[
0
].
name
.
residue
)
self
.
assertEqual
(
'B type'
,
patch
.
changedAtoms
[
0
].
type
)
self
.
assertEqual
(
'C'
,
patch
.
deletedAtoms
[
0
].
name
)
self
.
assertEqual
(
'C'
,
patch
.
deletedAtoms
[
0
].
name
)
self
.
assertEqual
(
0
,
patch
.
deletedAtoms
[
0
].
residue
)
self
.
assertEqual
(
0
,
patch
.
deletedAtoms
[
0
].
residue
)
self
.
assertEqual
(
'A'
,
patch
.
addedBonds
[
0
][
0
].
name
)
self
.
assertEqual
(
'A'
,
patch
.
addedBonds
[
0
][
0
].
name
)
...
@@ -70,5 +70,111 @@ class TestForceField(unittest.TestCase):
...
@@ -70,5 +70,111 @@ class TestForceField(unittest.TestCase):
self
.
assertEqual
(
'Test'
,
ff
.
_templatePatches
[
'RES'
][
0
][
0
])
self
.
assertEqual
(
'Test'
,
ff
.
_templatePatches
[
'RES'
][
0
][
0
])
self
.
assertEqual
(
0
,
ff
.
_templatePatches
[
'RES'
][
0
][
1
])
self
.
assertEqual
(
0
,
ff
.
_templatePatches
[
'RES'
][
0
][
1
])
def
testParseMultiresiduePatch
(
self
):
"""Test parsing a <Patch> tag that affects two residues."""
xml
=
"""
<ForceField>
<AtomTypes>
<Type name="A type" class="A class" element="O" mass="15.99943"/>
<Type name="B type" class="B class" element="H" mass="1.007947"/>
</AtomTypes>
<Patches>
<Patch name="Test" residues="2">
<AddAtom name="1:A" type="A type"/>
<ChangeAtom name="2:B" type="B type"/>
<AddBond atomName1="1:A" atomName2="2:B"/>
<ApplyToResidue name="1:RESA"/>
<ApplyToResidue name="2:RESB"/>
</Patch>
</Patches>
</ForceField>"""
ff
=
ForceField
(
StringIO
(
xml
))
self
.
assertEqual
(
1
,
len
(
ff
.
_patches
))
patch
=
ff
.
_patches
[
'Test'
]
self
.
assertEqual
(
2
,
len
(
patch
.
addedAtoms
))
self
.
assertEqual
(
1
,
len
(
patch
.
addedAtoms
[
0
]))
self
.
assertEqual
(
0
,
len
(
patch
.
addedAtoms
[
1
]))
self
.
assertEqual
(
2
,
len
(
patch
.
changedAtoms
))
self
.
assertEqual
(
0
,
len
(
patch
.
changedAtoms
[
0
]))
self
.
assertEqual
(
1
,
len
(
patch
.
changedAtoms
[
1
]))
self
.
assertEqual
(
1
,
len
(
patch
.
addedBonds
))
self
.
assertEqual
(
2
,
len
(
ff
.
_templatePatches
))
self
.
assertEqual
(
1
,
len
(
ff
.
_templatePatches
[
'RESA'
]))
self
.
assertEqual
(
1
,
len
(
ff
.
_templatePatches
[
'RESB'
]))
self
.
assertEqual
(
'A'
,
patch
.
addedAtoms
[
0
][
0
].
name
)
self
.
assertEqual
(
'A type'
,
patch
.
addedAtoms
[
0
][
0
].
type
)
self
.
assertEqual
(
'B'
,
patch
.
changedAtoms
[
1
][
0
].
name
)
self
.
assertEqual
(
'B type'
,
patch
.
changedAtoms
[
1
][
0
].
type
)
self
.
assertEqual
(
'A'
,
patch
.
addedBonds
[
0
][
0
].
name
)
self
.
assertEqual
(
0
,
patch
.
addedBonds
[
0
][
0
].
residue
)
self
.
assertEqual
(
'B'
,
patch
.
addedBonds
[
0
][
1
].
name
)
self
.
assertEqual
(
1
,
patch
.
addedBonds
[
0
][
1
].
residue
)
self
.
assertEqual
(
'Test'
,
ff
.
_templatePatches
[
'RESA'
][
0
][
0
])
self
.
assertEqual
(
0
,
ff
.
_templatePatches
[
'RESA'
][
0
][
1
])
self
.
assertEqual
(
'Test'
,
ff
.
_templatePatches
[
'RESB'
][
0
][
0
])
self
.
assertEqual
(
1
,
ff
.
_templatePatches
[
'RESB'
][
0
][
1
])
def
testApplyPatch
(
self
):
"""Test applying a patch to a template."""
xml
=
"""
<ForceField>
<AtomTypes>
<Type name="A type" class="A class" element="O" mass="15.99943"/>
<Type name="B type" class="B class" element="H" mass="1.007947"/>
<Type name="C type" class="C class" element="H" mass="1.007947"/>
<Type name="D type" class="D class" element="C" mass="12.010000"/>
</AtomTypes>
<Residues>
<Residue name="RES">
<Atom name="A" type="A type"/>
<Atom name="B" type="B type"/>
<Atom name="C" type="C type"/>
<Bond atomName1="A" atomName2="B"/>
<Bond atomName1="B" atomName2="C"/>
<ExternalBond atomName="C"/>
<VirtualSite type="average2" siteName="C" atomName1="B" atomName2="C" weight1="0.6" weight2="0.4"/>
</Residue>
</Residues>
<Patches>
<Patch name="Test">
<AddAtom name="D" type="D type"/>
<ChangeAtom name="B" type="A type"/>
<RemoveAtom name="A"/>
<AddBond atomName1="B" atomName2="D"/>
<RemoveBond atomName1="A" atomName2="B"/>
<AddExternalBond atomName="D"/>
<RemoveExternalBond atomName="C"/>
<ApplyToResidue name="RES"/>
</Patch>
</Patches>
</ForceField>"""
ff
=
ForceField
(
StringIO
(
xml
))
self
.
assertEqual
(
1
,
len
(
ff
.
_patches
))
patch
=
ff
.
_patches
[
'Test'
]
template
=
ff
.
_templates
[
'RES'
]
newTemplates
=
patch
.
createPatchedTemplates
([
template
])
self
.
assertEqual
(
1
,
len
(
newTemplates
))
t
=
newTemplates
[
0
]
self
.
assertEqual
(
3
,
len
(
t
.
atoms
))
self
.
assertTrue
(
any
(
a
.
name
==
'B'
and
a
.
type
==
'A type'
for
a
in
t
.
atoms
))
self
.
assertTrue
(
any
(
a
.
name
==
'C'
and
a
.
type
==
'C type'
for
a
in
t
.
atoms
))
self
.
assertTrue
(
any
(
a
.
name
==
'D'
and
a
.
type
==
'D type'
for
a
in
t
.
atoms
))
indexMap
=
dict
([(
a
.
name
,
i
)
for
i
,
a
in
enumerate
(
t
.
atoms
)])
self
.
assertEqual
(
2
,
len
(
t
.
bonds
))
self
.
assertTrue
((
indexMap
[
'B'
],
indexMap
[
'C'
])
in
t
.
bonds
)
self
.
assertTrue
((
indexMap
[
'B'
],
indexMap
[
'D'
])
in
t
.
bonds
)
self
.
assertEqual
(
1
,
len
(
t
.
externalBonds
))
self
.
assertTrue
(
indexMap
[
'D'
]
in
t
.
externalBonds
)
self
.
assertEqual
(
1
,
len
(
t
.
virtualSites
))
v
=
t
.
virtualSites
[
0
]
self
.
assertEqual
(
'average2'
,
v
.
type
)
self
.
assertEqual
(
0.6
,
v
.
weights
[
0
])
self
.
assertEqual
(
0.4
,
v
.
weights
[
1
])
self
.
assertEqual
(
indexMap
[
'C'
],
v
.
index
)
self
.
assertEqual
(
indexMap
[
'B'
],
v
.
atoms
[
0
])
self
.
assertEqual
(
indexMap
[
'C'
],
v
.
atoms
[
1
])
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
unittest
.
main
()
unittest
.
main
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment