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
a8865f61
Unverified
Commit
a8865f61
authored
Jun 30, 2021
by
Peter Eastman
Committed by
GitHub
Jun 30, 2021
Browse files
Allow custom template matchers for residues (#3161)
parent
71bc7c8c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
81 additions
and
0 deletions
+81
-0
wrappers/python/openmm/app/forcefield.py
wrappers/python/openmm/app/forcefield.py
+23
-0
wrappers/python/tests/TestForceField.py
wrappers/python/tests/TestForceField.py
+58
-0
No files found.
wrappers/python/openmm/app/forcefield.py
View file @
a8865f61
...
@@ -208,6 +208,7 @@ class ForceField(object):
...
@@ -208,6 +208,7 @@ class ForceField(object):
self
.
_atomClasses
=
{
''
:
set
()}
self
.
_atomClasses
=
{
''
:
set
()}
self
.
_forces
=
[]
self
.
_forces
=
[]
self
.
_scripts
=
[]
self
.
_scripts
=
[]
self
.
_templateMatchers
=
[]
self
.
_templateGenerators
=
[]
self
.
_templateGenerators
=
[]
self
.
loadFile
(
files
)
self
.
loadFile
(
files
)
...
@@ -478,6 +479,21 @@ class ForceField(object):
...
@@ -478,6 +479,21 @@ class ForceField(object):
def
registerScript
(
self
,
script
):
def
registerScript
(
self
,
script
):
"""Register a new script to be executed after building the System."""
"""Register a new script to be executed after building the System."""
self
.
_scripts
.
append
(
script
)
self
.
_scripts
.
append
(
script
)
def
registerTemplateMatcher
(
self
,
matcher
):
"""Register an object that can override the default logic for matching templates to residues.
A template matcher is a callable object that can be invoked as::
template = f(forcefield, residue)
where ``forcefield`` is the ForceField invoking it and ``residue`` is a openmm.app.Residue object.
It should return a _TemplateData object that matches the residue. Alternatively it may return
None, in which case the standard logic will be used to find a template for the residue.
.. CAUTION:: This method is experimental, and its API is subject to change.
"""
self
.
_templateMatchers
.
append
(
matcher
)
def
registerTemplateGenerator
(
self
,
generator
):
def
registerTemplateGenerator
(
self
,
generator
):
"""Register a residue template generator that can be used to parameterize residues that do not match existing forcefield templates.
"""Register a residue template generator that can be used to parameterize residues that do not match existing forcefield templates.
...
@@ -957,6 +973,13 @@ class ForceField(object):
...
@@ -957,6 +973,13 @@ class ForceField(object):
"""
"""
template
=
None
template
=
None
matches
=
None
matches
=
None
for
matcher
in
self
.
_templateMatchers
:
template
=
matcher
(
self
,
res
)
if
template
is
not
None
:
match
=
compiled
.
matchResidueToTemplate
(
res
,
template
,
bondedToAtom
,
ignoreExternalBonds
,
ignoreExtraParticles
)
if
match
is
None
:
raise
ValueError
(
'A custom template matcher returned a template for residue %s, but it does not match the residue.'
%
res
.
name
)
return
[
template
,
match
]
if
templateSignatures
is
None
:
if
templateSignatures
is
None
:
templateSignatures
=
self
.
_templateSignatures
templateSignatures
=
self
.
_templateSignatures
signature
=
_createResidueSignature
([
atom
.
element
for
atom
in
res
.
atoms
()])
signature
=
_createResidueSignature
([
atom
.
element
for
atom
in
res
.
atoms
()])
...
...
wrappers/python/tests/TestForceField.py
View file @
a8865f61
...
@@ -391,6 +391,64 @@ class TestForceField(unittest.TestCase):
...
@@ -391,6 +391,64 @@ class TestForceField(unittest.TestCase):
self
.
assertEqual
(
params
[
1
],
1.0
*
nanometers
)
self
.
assertEqual
(
params
[
1
],
1.0
*
nanometers
)
self
.
assertEqual
(
params
[
2
],
0.0
*
kilojoule_per_mole
)
self
.
assertEqual
(
params
[
2
],
0.0
*
kilojoule_per_mole
)
def
test_residueMatcher
(
self
):
"""Test using a custom template matcher to select templates."""
xml
=
"""
<ForceField>
<AtomTypes>
<Type name="tip3p-O" class="OW" element="O" mass="15.99943"/>
<Type name="tip3p-H" class="HW" element="H" mass="1.007947"/>
</AtomTypes>
<Residues>
<Residue name="HOH">
<Atom name="O" type="tip3p-O" charge="-0.834"/>
<Atom name="H1" type="tip3p-H" charge="0.417"/>
<Atom name="H2" type="tip3p-H" charge="0.417"/>
<Bond from="0" to="1"/>
<Bond from="0" to="2"/>
<Bond from="1" to="2"/>
</Residue>
<Residue name="HOH2">
<Atom name="O" type="tip3p-O" charge="0.834"/>
<Atom name="H1" type="tip3p-H" charge="-0.417"/>
<Atom name="H2" type="tip3p-H" charge="-0.417"/>
<Bond from="0" to="1"/>
<Bond from="0" to="2"/>
<Bond from="1" to="2"/>
</Residue>
</Residues>
<NonbondedForce coulomb14scale="0.833333" lj14scale="0.5">
<UseAttributeFromResidue name="charge"/>
<Atom type="tip3p-O" sigma="0.315" epsilon="0.635"/>
<Atom type="tip3p-H" sigma="1" epsilon="0"/>
</NonbondedForce>
</ForceField>"""
ff
=
ForceField
(
StringIO
(
xml
))
# Load a water box.
prmtop
=
AmberPrmtopFile
(
'systems/water-box-216.prmtop'
)
top
=
prmtop
.
topology
# Building a System should fail, because two templates match each residue.
self
.
assertRaises
(
Exception
,
lambda
:
ff
.
createSystem
(
top
))
# Register a template matcher that selects a particular one.
def
matcher
(
ff
,
res
):
return
ff
.
_templates
[
'HOH2'
]
ff
.
registerTemplateMatcher
(
matcher
)
# It should now succeed in building a System.
system
=
ff
.
createSystem
(
top
)
# Make sure it used the correct parameters.
nb
=
[
f
for
f
in
system
.
getForces
()
if
isinstance
(
f
,
NonbondedForce
)][
0
]
for
atom
in
top
.
atoms
():
charge
,
sigma
,
epsilon
=
nb
.
getParticleParameters
(
atom
.
index
)
if
atom
.
name
==
'O'
:
self
.
assertEqual
(
0.834
*
elementary_charge
,
charge
)
else
:
self
.
assertEqual
(
-
0.417
*
elementary_charge
,
charge
)
def
test_residueTemplateGenerator
(
self
):
def
test_residueTemplateGenerator
(
self
):
"""Test the ability to add residue template generators to parameterize unmatched residues."""
"""Test the ability to add residue template generators to parameterize unmatched residues."""
def
simpleTemplateGenerator
(
forcefield
,
residue
):
def
simpleTemplateGenerator
(
forcefield
,
residue
):
...
...
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