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
6a985cfd
Commit
6a985cfd
authored
Oct 28, 2015
by
peastman
Browse files
Merge pull request #1182 from peastman/residueparams
[WIP] Per-atom parameters can be taken from residue templates
parents
ef9a1050
1f7985e7
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
279 additions
and
145 deletions
+279
-145
docs-source/usersguide/application.rst
docs-source/usersguide/application.rst
+54
-9
wrappers/python/simtk/openmm/app/forcefield.py
wrappers/python/simtk/openmm/app/forcefield.py
+126
-134
wrappers/python/tests/TestForceField.py
wrappers/python/tests/TestForceField.py
+67
-2
wrappers/python/tests/systems/alanine-dipeptide-amoeba-forces.xml
.../python/tests/systems/alanine-dipeptide-amoeba-forces.xml
+32
-0
No files found.
docs-source/usersguide/application.rst
View file @
6a985cfd
...
@@ -1843,7 +1843,7 @@ The :code:`<ForceField>` tag contains the following children:
...
@@ -1843,7 +1843,7 @@ The :code:`<ForceField>` tag contains the following children:
*
Zero
or
more
tags
defining
specific
forces
*
Zero
or
more
tags
defining
specific
forces
The
order
of
these
tags
does
not
matter
.
They
are
described
in
detail
s
below
.
The
order
of
these
tags
does
not
matter
.
They
are
described
in
detail
below
.
<
AtomTypes
>
<
AtomTypes
>
===========
===========
...
@@ -1927,9 +1927,9 @@ as in the following example:
...
@@ -1927,9 +1927,9 @@ as in the following example:
Each
:
code
:`<
VirtualSite
>`
tag
indicates
an
atom
in
the
residue
that
should
Each
:
code
:`<
VirtualSite
>`
tag
indicates
an
atom
in
the
residue
that
should
be
represented
with
a
virtual
site
.
The
:
code
:`
type
`
attribute
may
equal
be
represented
with
a
virtual
site
.
The
:
code
:`
type
`
attribute
may
equal
:
code
:`
"average2"
`\
,
:
code
:`
"average3"
`\
,
or
:
code
:`
"outOfPlane"
`\
,
which
:
code
:`
"average2"
`\
,
:
code
:`
"average3"
`\
,
:
code
:`
"outOfPlane"
`\
,
or
correspond
to
the
TwoParticleAverageSite
,
ThreeParticleAverageSite
,
and
:
code
:`
"localCoords"
`\
,
which
correspond
to
the
TwoParticleAverageSite
,
ThreeParticleAverageSite
,
OutOfPlaneSite
classes
respectively
.
The
:
code
:`
index
`
attribute
gives
the
OutOfPlaneSite
,
and
LocalCoordinatesSite
classes
respectively
.
The
:
code
:`
index
`
attribute
gives
the
index
(
starting
from
0
)
of
the
atom
to
represent
with
a
virtual
site
.
The
atoms
index
(
starting
from
0
)
of
the
atom
to
represent
with
a
virtual
site
.
The
atoms
it
is
calculated
based
on
are
specified
by
:
code
:`
atom1
`\
,
:
code
:`
atom2
`\
,
it
is
calculated
based
on
are
specified
by
:
code
:`
atom1
`\
,
:
code
:`
atom2
`\
,
and
(
for
virtual
site
classes
that
involve
three
atoms
)
:
code
:`
atom3
`\
.
The
and
(
for
virtual
site
classes
that
involve
three
atoms
)
:
code
:`
atom3
`\
.
The
...
@@ -1938,7 +1938,10 @@ parameters for calculating the site position. For a TwoParticleAverageSite,
...
@@ -1938,7 +1938,10 @@ parameters for calculating the site position. For a TwoParticleAverageSite,
they
are
:
code
:`
weight1
`
and
:
code
:`
weight2
`\
.
For
a
they
are
:
code
:`
weight1
`
and
:
code
:`
weight2
`\
.
For
a
ThreeParticleAverageSite
,
they
are
:
code
:`
weight1
`\
,
:
code
:`
weight2
`\
,
and
ThreeParticleAverageSite
,
they
are
:
code
:`
weight1
`\
,
:
code
:`
weight2
`\
,
and
\
:
code
:`
weight3
`\
.
For
an
OutOfPlaneSite
,
they
are
:
code
:`
weight12
`\
,
\
:
code
:`
weight3
`\
.
For
an
OutOfPlaneSite
,
they
are
:
code
:`
weight12
`\
,
:
code
:`
weight13
`\
,
and
:
code
:`
weightCross
`\
.
:
code
:`
weight13
`\
,
and
:
code
:`
weightCross
`\
.
For
a
LocalCoordinatesSite
,
they
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
`\
.
<
HarmonicBondForce
>
<
HarmonicBondForce
>
...
@@ -2496,8 +2499,9 @@ The following operators are supported: + (add), - (subtract), * (multiply), /
...
@@ -2496,8 +2499,9 @@ The following operators are supported: + (add), - (subtract), * (multiply), /
The
following
standard
functions
are
supported
:
sqrt
,
exp
,
log
,
sin
,
cos
,
sec
,
The
following
standard
functions
are
supported
:
sqrt
,
exp
,
log
,
sin
,
cos
,
sec
,
csc
,
tan
,
cot
,
asin
,
acos
,
atan
,
sinh
,
cosh
,
tanh
,
erf
,
erfc
,
min
,
max
,
abs
,
csc
,
tan
,
cot
,
asin
,
acos
,
atan
,
sinh
,
cosh
,
tanh
,
erf
,
erfc
,
min
,
max
,
abs
,
step
.
step
(
x
)
=
0
if
x
<
0
,
1
otherwise
.
Some
custom
forces
allow
additional
floor
,
ceil
,
step
,
delta
,
select
.
step
(
x
)
=
0
if
x
<
0
,
1
otherwise
.
functions
to
be
defined
from
tabulated
values
.
delta
(
x
)
=
1
if
x
is
0
,
0
otherwise
.
select
(
x
,
y
,
z
)
=
z
if
x
=
0
,
y
otherwise
.
Some
custom
forces
allow
additional
functions
to
be
defined
from
tabulated
values
.
Numbers
may
be
given
in
either
decimal
or
exponential
form
.
All
of
the
Numbers
may
be
given
in
either
decimal
or
exponential
form
.
All
of
the
following
are
valid
numbers
:
5
,
-
3.1
,
1e6
,
and
3.12e-2
.
following
are
valid
numbers
:
5
,
-
3.1
,
1e6
,
and
3.12e-2
.
...
@@ -2521,8 +2525,8 @@ values. All uses of a value must appear *before* that value’s definition.
...
@@ -2521,8 +2525,8 @@ values. All uses of a value must appear *before* that value’s definition.
..
_tabulated
-
functions
:
..
_tabulated
-
functions
:
TabulatedFunctions
Tabulated
Functions
==================
==================
=
Some
forces
,
such
as
CustomNonbondedForce
and
CustomGBForce
,
allow
you
to
define
Some
forces
,
such
as
CustomNonbondedForce
and
CustomGBForce
,
allow
you
to
define
tabulated
functions
.
To
define
a
function
,
include
a
:
code
:`<
Function
>`
tag
inside
the
tabulated
functions
.
To
define
a
function
,
include
a
:
code
:`<
Function
>`
tag
inside
the
...
@@ -2569,6 +2573,47 @@ successive values separated by white space. See the API documentation for more
...
@@ -2569,6 +2573,47 @@ successive values separated by white space. See the API documentation for more
details
.
details
.
Residue
Template
Parameters
===========================
In
forces
that
use
an
:
code
:`<
Atom
>`
tag
to
define
parameters
for
atom
types
or
classes
,
there
is
an
alternate
mechanism
you
can
also
use
:
defining
those
parameter
values
in
the
residue
template
.
This
is
useful
for
situations
that
come
up
in
certain
force
fields
.
For
example
,
:
code
:`
NonbondedForce
`
and
:
code
:`
GBSAOBCForce
`
each
have
a
:
code
:`
charge
`
attribute
.
If
you
only
have
to
define
the
charge
of
each
atom
type
once
,
that
is
more
convenient
and
avoids
potential
bugs
.
Also
,
many
force
fields
have
a
different
charge
for
each
atom
type
,
but
Lennard
-
Jones
parameters
that
are
the
same
for
all
types
in
a
class
.
It
would
be
preferable
not
to
have
to
repeat
those
parameter
values
many
times
over
.
When
writing
a
residue
template
,
you
can
add
arbitrary
additional
attributes
to
each
:
code
:`<
Atom
>`
tag
.
For
example
,
you
might
include
a
:
code
:`
charge
`
attribute
as
follows
:
..
code
-
block
::
xml
<
Atom
name
=
"CA"
type
=
"53"
charge
=
"0.0381"
/>
When
writing
the
tag
for
a
force
,
you
can
then
include
a
:
code
:`<
UseAttributeFromResidue
>`
tag
inside
it
.
This
indicates
that
a
specified
attribute
should
be
taken
from
the
residue
template
.
Finally
,
you
simply
omit
that
attribute
in
the
force
's own :code:`<Atom>` tags. For example:
.. code-block:: xml
<NonbondedForce coulomb14scale="0.833333" lj14scale="0.5">
<UseAttributeFromResidue name="charge"/>
<Atom class="CX" sigma="0.339966950842" epsilon="0.4577296"/>
...
</NonbondedForce>
Notice that the :code:`charge` attribute is missing, and that the parameters
are specified by class, not by type. This means that sigma and epsilon only
need to be specified once for each class. The atom charges, which are different
for each type, are taken from the residue template instead.
Using Multiple Files
Using Multiple Files
********************
********************
...
...
wrappers/python/simtk/openmm/app/forcefield.py
View file @
6a985cfd
...
@@ -150,7 +150,11 @@ class ForceField(object):
...
@@ -150,7 +150,11 @@ class ForceField(object):
resName
=
residue
.
attrib
[
'name'
]
resName
=
residue
.
attrib
[
'name'
]
template
=
ForceField
.
_TemplateData
(
resName
)
template
=
ForceField
.
_TemplateData
(
resName
)
for
atom
in
residue
.
findall
(
'Atom'
):
for
atom
in
residue
.
findall
(
'Atom'
):
template
.
atoms
.
append
(
ForceField
.
_TemplateAtomData
(
atom
.
attrib
[
'name'
],
atom
.
attrib
[
'type'
],
self
.
_atomTypes
[
atom
.
attrib
[
'type'
]][
2
]))
params
=
{}
for
key
in
atom
.
attrib
:
if
key
not
in
(
'name'
,
'type'
):
params
[
key
]
=
_convertParameterToNumber
(
atom
.
attrib
[
key
])
template
.
atoms
.
append
(
ForceField
.
_TemplateAtomData
(
atom
.
attrib
[
'name'
],
atom
.
attrib
[
'type'
],
self
.
_atomTypes
[
atom
.
attrib
[
'type'
]][
2
],
params
))
for
site
in
residue
.
findall
(
'VirtualSite'
):
for
site
in
residue
.
findall
(
'VirtualSite'
):
template
.
virtualSites
.
append
(
ForceField
.
_VirtualSiteData
(
site
))
template
.
virtualSites
.
append
(
ForceField
.
_VirtualSiteData
(
site
))
for
bond
in
residue
.
findall
(
'Bond'
):
for
bond
in
residue
.
findall
(
'Bond'
):
...
@@ -256,6 +260,7 @@ class ForceField(object):
...
@@ -256,6 +260,7 @@ class ForceField(object):
"""Inner class used to encapsulate data about the system being created."""
"""Inner class used to encapsulate data about the system being created."""
def
__init__
(
self
):
def
__init__
(
self
):
self
.
atomType
=
{}
self
.
atomType
=
{}
self
.
atomParameters
=
{}
self
.
atoms
=
[]
self
.
atoms
=
[]
self
.
excludeAtomWith
=
[]
self
.
excludeAtomWith
=
[]
self
.
virtualSites
=
{}
self
.
virtualSites
=
{}
...
@@ -282,10 +287,11 @@ class ForceField(object):
...
@@ -282,10 +287,11 @@ class ForceField(object):
class
_TemplateAtomData
:
class
_TemplateAtomData
:
"""Inner class used to encapsulate data about an atom in a residue template definition."""
"""Inner class used to encapsulate data about an atom in a residue template definition."""
def
__init__
(
self
,
name
,
type
,
element
):
def
__init__
(
self
,
name
,
type
,
element
,
parameters
=
{}
):
self
.
name
=
name
self
.
name
=
name
self
.
type
=
type
self
.
type
=
type
self
.
element
=
element
self
.
element
=
element
self
.
parameters
=
parameters
self
.
bondedTo
=
[]
self
.
bondedTo
=
[]
self
.
externalBonds
=
0
self
.
externalBonds
=
0
...
@@ -325,6 +331,77 @@ class ForceField(object):
...
@@ -325,6 +331,77 @@ class ForceField(object):
else
:
else
:
self
.
excludeWith
=
self
.
atoms
[
0
]
self
.
excludeWith
=
self
.
atoms
[
0
]
class
_AtomTypeParameters
:
"""Inner class used to record parameter values for atom types."""
def
__init__
(
self
,
forcefield
,
forceName
,
atomTag
,
paramNames
):
self
.
ff
=
forcefield
self
.
forceName
=
forceName
self
.
atomTag
=
atomTag
self
.
paramNames
=
paramNames
self
.
paramsForType
=
{}
self
.
extraParamsForType
=
{}
def
registerAtom
(
self
,
parameters
,
expectedParams
=
None
):
if
expectedParams
is
None
:
expectedParams
=
self
.
paramNames
types
=
self
.
ff
.
_findAtomTypes
(
parameters
,
1
)
if
None
not
in
types
:
values
=
{}
extraValues
=
{}
for
key
in
parameters
:
if
key
in
expectedParams
:
values
[
key
]
=
_convertParameterToNumber
(
parameters
[
key
])
else
:
extraValues
[
key
]
=
parameters
[
key
]
if
len
(
values
)
<
len
(
expectedParams
):
for
key
in
expectedParams
:
if
key
not
in
values
:
raise
ValueError
(
'%s: No value specified for "%s"'
%
(
self
.
forceName
,
key
))
for
t
in
types
[
0
]:
self
.
paramsForType
[
t
]
=
values
self
.
extraParamsForType
[
t
]
=
extraValues
def
parseDefinitions
(
self
,
element
):
""""Load the definitions from an XML element."""
expectedParams
=
list
(
self
.
paramNames
)
excludedParams
=
[
node
.
attrib
[
'name'
]
for
node
in
element
.
findall
(
'UseAttributeFromResidue'
)]
for
param
in
excludedParams
:
if
param
not
in
expectedParams
:
raise
ValueError
(
'%s: <UseAttributeFromResidue> specified an invalid attribute: %s'
%
(
self
.
forceName
,
param
))
expectedParams
.
remove
(
param
)
for
atom
in
element
.
findall
(
self
.
atomTag
):
for
param
in
excludedParams
:
if
param
in
atom
.
attrib
:
raise
ValueError
(
'%s: The attribute "%s" appeared in both <%s> and <UseAttributeFromResidue> tags'
%
(
self
.
forceName
,
param
,
self
.
atomTag
))
self
.
registerAtom
(
atom
.
attrib
,
expectedParams
)
def
getAtomParameters
(
self
,
atom
,
data
):
"""Get the parameter values for a particular atom."""
t
=
data
.
atomType
[
atom
]
p
=
data
.
atomParameters
[
atom
]
if
t
in
self
.
paramsForType
:
values
=
self
.
paramsForType
[
t
]
result
=
[
None
]
*
len
(
self
.
paramNames
)
for
i
,
name
in
enumerate
(
self
.
paramNames
):
if
name
in
values
:
result
[
i
]
=
values
[
name
]
elif
name
in
p
:
result
[
i
]
=
p
[
name
]
else
:
raise
ValueError
(
'%s: No value specified for "%s"'
%
(
self
.
forceName
,
name
))
return
result
else
:
raise
ValueError
(
'%s: No parameters defined for atom type %s'
%
(
self
.
forceName
,
t
))
def
getExtraParameters
(
self
,
atom
,
data
):
"""Get extra parameter values for an atom that appeared in the <Atom> tag but were not included in paramNames."""
t
=
data
.
atomType
[
atom
]
if
t
in
self
.
paramsForType
:
return
self
.
extraParamsForType
[
t
]
else
:
raise
ValueError
(
'%s: No parameters defined for atom type %s'
%
(
self
.
forceName
,
t
))
def
createSystem
(
self
,
topology
,
nonbondedMethod
=
NoCutoff
,
nonbondedCutoff
=
1.0
*
unit
.
nanometer
,
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
,
**
args
):
"""Construct an OpenMM System representing a Topology with this force field.
"""Construct an OpenMM System representing a Topology with this force field.
...
@@ -385,6 +462,7 @@ class ForceField(object):
...
@@ -385,6 +462,7 @@ class ForceField(object):
matchAtoms
=
dict
(
zip
(
matches
,
res
.
atoms
()))
matchAtoms
=
dict
(
zip
(
matches
,
res
.
atoms
()))
for
atom
,
match
in
zip
(
res
.
atoms
(),
matches
):
for
atom
,
match
in
zip
(
res
.
atoms
(),
matches
):
data
.
atomType
[
atom
]
=
template
.
atoms
[
match
].
type
data
.
atomType
[
atom
]
=
template
.
atoms
[
match
].
type
data
.
atomParameters
[
atom
]
=
template
.
atoms
[
match
].
parameters
for
site
in
template
.
virtualSites
:
for
site
in
template
.
virtualSites
:
if
match
==
site
.
index
:
if
match
==
site
.
index
:
data
.
virtualSites
[
atom
]
=
(
site
,
[
matchAtoms
[
i
].
index
for
i
in
site
.
atoms
],
matchAtoms
[
site
.
excludeWith
].
index
)
data
.
virtualSites
[
atom
]
=
(
site
,
[
matchAtoms
[
i
].
index
for
i
in
site
.
atoms
],
matchAtoms
[
site
.
excludeWith
].
index
)
...
@@ -1138,14 +1216,10 @@ class NonbondedGenerator:
...
@@ -1138,14 +1216,10 @@ class NonbondedGenerator:
self
.
ff
=
forcefield
self
.
ff
=
forcefield
self
.
coulomb14scale
=
coulomb14scale
self
.
coulomb14scale
=
coulomb14scale
self
.
lj14scale
=
lj14scale
self
.
lj14scale
=
lj14scale
self
.
typeMap
=
{}
self
.
params
=
ForceField
.
_AtomTypeParameters
(
forcefield
,
'NonbondedForce'
,
'Atom'
,
(
'charge'
,
'sigma'
,
'epsilon'
))
def
registerAtom
(
self
,
parameters
):
def
registerAtom
(
self
,
parameters
):
types
=
self
.
ff
.
_findAtomTypes
(
parameters
,
1
)
self
.
params
.
registerAtom
(
parameters
)
if
None
not
in
types
:
values
=
(
_convertParameterToNumber
(
parameters
[
'charge'
]),
_convertParameterToNumber
(
parameters
[
'sigma'
]),
_convertParameterToNumber
(
parameters
[
'epsilon'
]))
for
t
in
types
[
0
]:
self
.
typeMap
[
t
]
=
values
@
staticmethod
@
staticmethod
def
parseElement
(
element
,
ff
):
def
parseElement
(
element
,
ff
):
...
@@ -1158,8 +1232,7 @@ class NonbondedGenerator:
...
@@ -1158,8 +1232,7 @@ class NonbondedGenerator:
generator
=
existing
[
0
]
generator
=
existing
[
0
]
if
generator
.
coulomb14scale
!=
float
(
element
.
attrib
[
'coulomb14scale'
])
or
generator
.
lj14scale
!=
float
(
element
.
attrib
[
'lj14scale'
]):
if
generator
.
coulomb14scale
!=
float
(
element
.
attrib
[
'coulomb14scale'
])
or
generator
.
lj14scale
!=
float
(
element
.
attrib
[
'lj14scale'
]):
raise
ValueError
(
'Found multiple NonbondedForce tags with different 1-4 scales'
)
raise
ValueError
(
'Found multiple NonbondedForce tags with different 1-4 scales'
)
for
atom
in
element
.
findall
(
'Atom'
):
generator
.
params
.
parseDefinitions
(
element
)
generator
.
registerAtom
(
atom
.
attrib
)
def
createForce
(
self
,
sys
,
data
,
nonbondedMethod
,
nonbondedCutoff
,
args
):
def
createForce
(
self
,
sys
,
data
,
nonbondedMethod
,
nonbondedCutoff
,
args
):
methodMap
=
{
NoCutoff
:
mm
.
NonbondedForce
.
NoCutoff
,
methodMap
=
{
NoCutoff
:
mm
.
NonbondedForce
.
NoCutoff
,
...
@@ -1171,12 +1244,8 @@ class NonbondedGenerator:
...
@@ -1171,12 +1244,8 @@ class NonbondedGenerator:
raise
ValueError
(
'Illegal nonbonded method for NonbondedForce'
)
raise
ValueError
(
'Illegal nonbonded method for NonbondedForce'
)
force
=
mm
.
NonbondedForce
()
force
=
mm
.
NonbondedForce
()
for
atom
in
data
.
atoms
:
for
atom
in
data
.
atoms
:
t
=
data
.
atomType
[
atom
]
values
=
self
.
params
.
getAtomParameters
(
atom
,
data
)
if
t
in
self
.
typeMap
:
force
.
addParticle
(
values
[
0
],
values
[
1
],
values
[
2
])
values
=
self
.
typeMap
[
t
]
force
.
addParticle
(
values
[
0
],
values
[
1
],
values
[
2
])
else
:
raise
ValueError
(
'No nonbonded parameters defined for atom type '
+
t
)
force
.
setNonbondedMethod
(
methodMap
[
nonbondedMethod
])
force
.
setNonbondedMethod
(
methodMap
[
nonbondedMethod
])
force
.
setCutoffDistance
(
nonbondedCutoff
)
force
.
setCutoffDistance
(
nonbondedCutoff
)
if
'ewaldErrorTolerance'
in
args
:
if
'ewaldErrorTolerance'
in
args
:
...
@@ -1225,14 +1294,10 @@ class GBSAOBCGenerator:
...
@@ -1225,14 +1294,10 @@ class GBSAOBCGenerator:
def
__init__
(
self
,
forcefield
):
def
__init__
(
self
,
forcefield
):
self
.
ff
=
forcefield
self
.
ff
=
forcefield
self
.
typeMap
=
{}
self
.
params
=
ForceField
.
_AtomTypeParameters
(
forcefield
,
'GBSAOBCForce'
,
'Atom'
,
(
'charge'
,
'radius'
,
'scale'
))
def
registerAtom
(
self
,
parameters
):
def
registerAtom
(
self
,
parameters
):
types
=
self
.
ff
.
_findAtomTypes
(
parameters
,
1
)
self
.
params
.
registerAtom
(
parameters
)
if
None
not
in
types
:
values
=
(
_convertParameterToNumber
(
parameters
[
'charge'
]),
_convertParameterToNumber
(
parameters
[
'radius'
]),
_convertParameterToNumber
(
parameters
[
'scale'
]))
for
t
in
types
[
0
]:
self
.
typeMap
[
t
]
=
values
@
staticmethod
@
staticmethod
def
parseElement
(
element
,
ff
):
def
parseElement
(
element
,
ff
):
...
@@ -1243,8 +1308,7 @@ class GBSAOBCGenerator:
...
@@ -1243,8 +1308,7 @@ class GBSAOBCGenerator:
else
:
else
:
# Multiple <GBSAOBCForce> tags were found, probably in different files. Simply add more types to the existing one.
# Multiple <GBSAOBCForce> tags were found, probably in different files. Simply add more types to the existing one.
generator
=
existing
[
0
]
generator
=
existing
[
0
]
for
atom
in
element
.
findall
(
'Atom'
):
generator
.
params
.
parseDefinitions
(
element
)
generator
.
registerAtom
(
atom
.
attrib
)
def
createForce
(
self
,
sys
,
data
,
nonbondedMethod
,
nonbondedCutoff
,
args
):
def
createForce
(
self
,
sys
,
data
,
nonbondedMethod
,
nonbondedCutoff
,
args
):
methodMap
=
{
NoCutoff
:
mm
.
NonbondedForce
.
NoCutoff
,
methodMap
=
{
NoCutoff
:
mm
.
NonbondedForce
.
NoCutoff
,
...
@@ -1254,12 +1318,8 @@ class GBSAOBCGenerator:
...
@@ -1254,12 +1318,8 @@ class GBSAOBCGenerator:
raise
ValueError
(
'Illegal nonbonded method for GBSAOBCForce'
)
raise
ValueError
(
'Illegal nonbonded method for GBSAOBCForce'
)
force
=
mm
.
GBSAOBCForce
()
force
=
mm
.
GBSAOBCForce
()
for
atom
in
data
.
atoms
:
for
atom
in
data
.
atoms
:
t
=
data
.
atomType
[
atom
]
values
=
self
.
params
.
getAtomParameters
(
atom
,
data
)
if
t
in
self
.
typeMap
:
force
.
addParticle
(
values
[
0
],
values
[
1
],
values
[
2
])
values
=
self
.
typeMap
[
t
]
force
.
addParticle
(
values
[
0
],
values
[
1
],
values
[
2
])
else
:
raise
ValueError
(
'No GBSAOBC parameters defined for atom type '
+
t
)
force
.
setNonbondedMethod
(
methodMap
[
nonbondedMethod
])
force
.
setNonbondedMethod
(
methodMap
[
nonbondedMethod
])
force
.
setCutoffDistance
(
nonbondedCutoff
)
force
.
setCutoffDistance
(
nonbondedCutoff
)
if
'soluteDielectric'
in
args
:
if
'soluteDielectric'
in
args
:
...
@@ -1577,7 +1637,6 @@ class CustomNonbondedGenerator:
...
@@ -1577,7 +1637,6 @@ class CustomNonbondedGenerator:
self
.
ff
=
forcefield
self
.
ff
=
forcefield
self
.
energy
=
energy
self
.
energy
=
energy
self
.
bondCutoff
=
bondCutoff
self
.
bondCutoff
=
bondCutoff
self
.
typeMap
=
{}
self
.
globalParams
=
{}
self
.
globalParams
=
{}
self
.
perParticleParams
=
[]
self
.
perParticleParams
=
[]
self
.
functions
=
[]
self
.
functions
=
[]
...
@@ -1590,12 +1649,8 @@ class CustomNonbondedGenerator:
...
@@ -1590,12 +1649,8 @@ class CustomNonbondedGenerator:
generator
.
globalParams
[
param
.
attrib
[
'name'
]]
=
float
(
param
.
attrib
[
'defaultValue'
])
generator
.
globalParams
[
param
.
attrib
[
'name'
]]
=
float
(
param
.
attrib
[
'defaultValue'
])
for
param
in
element
.
findall
(
'PerParticleParameter'
):
for
param
in
element
.
findall
(
'PerParticleParameter'
):
generator
.
perParticleParams
.
append
(
param
.
attrib
[
'name'
])
generator
.
perParticleParams
.
append
(
param
.
attrib
[
'name'
])
for
atom
in
element
.
findall
(
'Atom'
):
generator
.
params
=
ForceField
.
_AtomTypeParameters
(
ff
,
'CustomNonbondedForce'
,
'Atom'
,
generator
.
perParticleParams
)
types
=
ff
.
_findAtomTypes
(
atom
.
attrib
,
1
)
generator
.
params
.
parseDefinitions
(
element
)
if
None
not
in
types
:
values
=
[
float
(
atom
.
attrib
[
param
])
for
param
in
generator
.
perParticleParams
]
for
t
in
types
[
0
]:
generator
.
typeMap
[
t
]
=
values
def
createForce
(
self
,
sys
,
data
,
nonbondedMethod
,
nonbondedCutoff
,
args
):
def
createForce
(
self
,
sys
,
data
,
nonbondedMethod
,
nonbondedCutoff
,
args
):
methodMap
=
{
NoCutoff
:
mm
.
CustomNonbondedForce
.
NoCutoff
,
methodMap
=
{
NoCutoff
:
mm
.
CustomNonbondedForce
.
NoCutoff
,
...
@@ -1622,11 +1677,8 @@ class CustomNonbondedGenerator:
...
@@ -1622,11 +1677,8 @@ class CustomNonbondedGenerator:
elif
type
==
'Discrete3D'
:
elif
type
==
'Discrete3D'
:
force
.
addTabulatedFunction
(
name
,
mm
.
Discrete2DFunction
(
params
[
'xsize'
],
params
[
'ysize'
],
params
[
'zsize'
],
values
))
force
.
addTabulatedFunction
(
name
,
mm
.
Discrete2DFunction
(
params
[
'xsize'
],
params
[
'ysize'
],
params
[
'zsize'
],
values
))
for
atom
in
data
.
atoms
:
for
atom
in
data
.
atoms
:
t
=
data
.
atomType
[
atom
]
values
=
self
.
params
.
getAtomParameters
(
atom
,
data
)
if
t
in
self
.
typeMap
:
force
.
addParticle
(
values
)
force
.
addParticle
(
self
.
typeMap
[
t
])
else
:
raise
ValueError
(
'No CustomNonbonded parameters defined for atom type '
+
t
)
force
.
setNonbondedMethod
(
methodMap
[
nonbondedMethod
])
force
.
setNonbondedMethod
(
methodMap
[
nonbondedMethod
])
force
.
setCutoffDistance
(
nonbondedCutoff
)
force
.
setCutoffDistance
(
nonbondedCutoff
)
sys
.
addForce
(
force
)
sys
.
addForce
(
force
)
...
@@ -1671,7 +1723,6 @@ class CustomGBGenerator:
...
@@ -1671,7 +1723,6 @@ class CustomGBGenerator:
def
__init__
(
self
,
forcefield
):
def
__init__
(
self
,
forcefield
):
self
.
ff
=
forcefield
self
.
ff
=
forcefield
self
.
typeMap
=
{}
self
.
globalParams
=
{}
self
.
globalParams
=
{}
self
.
perParticleParams
=
[]
self
.
perParticleParams
=
[]
self
.
computedValues
=
[]
self
.
computedValues
=
[]
...
@@ -1686,12 +1737,8 @@ class CustomGBGenerator:
...
@@ -1686,12 +1737,8 @@ class CustomGBGenerator:
generator
.
globalParams
[
param
.
attrib
[
'name'
]]
=
float
(
param
.
attrib
[
'defaultValue'
])
generator
.
globalParams
[
param
.
attrib
[
'name'
]]
=
float
(
param
.
attrib
[
'defaultValue'
])
for
param
in
element
.
findall
(
'PerParticleParameter'
):
for
param
in
element
.
findall
(
'PerParticleParameter'
):
generator
.
perParticleParams
.
append
(
param
.
attrib
[
'name'
])
generator
.
perParticleParams
.
append
(
param
.
attrib
[
'name'
])
for
atom
in
element
.
findall
(
'Atom'
):
generator
.
params
=
ForceField
.
_AtomTypeParameters
(
ff
,
'CustomGBForce'
,
'Atom'
,
generator
.
perParticleParams
)
types
=
ff
.
_findAtomTypes
(
atom
.
attrib
,
1
)
generator
.
params
.
parseDefinitions
(
element
)
if
None
not
in
types
:
values
=
[
float
(
atom
.
attrib
[
param
])
for
param
in
generator
.
perParticleParams
]
for
t
in
types
[
0
]:
generator
.
typeMap
[
t
]
=
values
computationMap
=
{
"SingleParticle"
:
mm
.
CustomGBForce
.
SingleParticle
,
computationMap
=
{
"SingleParticle"
:
mm
.
CustomGBForce
.
SingleParticle
,
"ParticlePair"
:
mm
.
CustomGBForce
.
ParticlePair
,
"ParticlePair"
:
mm
.
CustomGBForce
.
ParticlePair
,
"ParticlePairNoExclusions"
:
mm
.
CustomGBForce
.
ParticlePairNoExclusions
}
"ParticlePairNoExclusions"
:
mm
.
CustomGBForce
.
ParticlePairNoExclusions
}
...
@@ -1742,11 +1789,8 @@ class CustomGBGenerator:
...
@@ -1742,11 +1789,8 @@ class CustomGBGenerator:
elif
type
==
'Discrete3D'
:
elif
type
==
'Discrete3D'
:
force
.
addTabulatedFunction
(
name
,
mm
.
Discrete2DFunction
(
params
[
'xsize'
],
params
[
'ysize'
],
params
[
'zsize'
],
values
))
force
.
addTabulatedFunction
(
name
,
mm
.
Discrete2DFunction
(
params
[
'xsize'
],
params
[
'ysize'
],
params
[
'zsize'
],
values
))
for
atom
in
data
.
atoms
:
for
atom
in
data
.
atoms
:
t
=
data
.
atomType
[
atom
]
values
=
self
.
params
.
getAtomParameters
(
atom
,
data
)
if
t
in
self
.
typeMap
:
force
.
addParticle
(
values
)
force
.
addParticle
(
self
.
typeMap
[
t
])
else
:
raise
ValueError
(
'No CustomGB parameters defined for atom type '
+
t
)
force
.
setNonbondedMethod
(
methodMap
[
nonbondedMethod
])
force
.
setNonbondedMethod
(
methodMap
[
nonbondedMethod
])
force
.
setCutoffDistance
(
nonbondedCutoff
)
force
.
setCutoffDistance
(
nonbondedCutoff
)
sys
.
addForce
(
force
)
sys
.
addForce
(
force
)
...
@@ -1764,7 +1808,6 @@ class CustomManyParticleGenerator:
...
@@ -1764,7 +1808,6 @@ class CustomManyParticleGenerator:
self
.
energy
=
energy
self
.
energy
=
energy
self
.
permutationMode
=
permutationMode
self
.
permutationMode
=
permutationMode
self
.
bondCutoff
=
bondCutoff
self
.
bondCutoff
=
bondCutoff
self
.
typeMap
=
{}
self
.
globalParams
=
{}
self
.
globalParams
=
{}
self
.
perParticleParams
=
[]
self
.
perParticleParams
=
[]
self
.
functions
=
[]
self
.
functions
=
[]
...
@@ -1782,12 +1825,8 @@ class CustomManyParticleGenerator:
...
@@ -1782,12 +1825,8 @@ class CustomManyParticleGenerator:
generator
.
perParticleParams
.
append
(
param
.
attrib
[
'name'
])
generator
.
perParticleParams
.
append
(
param
.
attrib
[
'name'
])
for
param
in
element
.
findall
(
'TypeFilter'
):
for
param
in
element
.
findall
(
'TypeFilter'
):
generator
.
typeFilters
.
append
((
int
(
param
.
attrib
[
'index'
]),
[
int
(
x
)
for
x
in
param
.
attrib
[
'types'
].
split
(
','
)]))
generator
.
typeFilters
.
append
((
int
(
param
.
attrib
[
'index'
]),
[
int
(
x
)
for
x
in
param
.
attrib
[
'types'
].
split
(
','
)]))
for
atom
in
element
.
findall
(
'Atom'
):
generator
.
params
=
ForceField
.
_AtomTypeParameters
(
ff
,
'CustomManyParticleForce'
,
'Atom'
,
generator
.
perParticleParams
)
types
=
ff
.
_findAtomTypes
(
atom
.
attrib
,
1
)
generator
.
params
.
parseDefinitions
(
element
)
if
None
not
in
types
:
values
=
[
float
(
atom
.
attrib
[
param
])
for
param
in
generator
.
perParticleParams
]
for
t
in
types
[
0
]:
generator
.
typeMap
[
t
]
=
(
values
,
int
(
atom
.
attrib
[
'filterType'
]))
def
createForce
(
self
,
sys
,
data
,
nonbondedMethod
,
nonbondedCutoff
,
args
):
def
createForce
(
self
,
sys
,
data
,
nonbondedMethod
,
nonbondedCutoff
,
args
):
methodMap
=
{
NoCutoff
:
mm
.
CustomManyParticleForce
.
NoCutoff
,
methodMap
=
{
NoCutoff
:
mm
.
CustomManyParticleForce
.
NoCutoff
,
...
@@ -1817,12 +1856,9 @@ class CustomManyParticleGenerator:
...
@@ -1817,12 +1856,9 @@ class CustomManyParticleGenerator:
elif
type
==
'Discrete3D'
:
elif
type
==
'Discrete3D'
:
force
.
addTabulatedFunction
(
name
,
mm
.
Discrete2DFunction
(
params
[
'xsize'
],
params
[
'ysize'
],
params
[
'zsize'
],
values
))
force
.
addTabulatedFunction
(
name
,
mm
.
Discrete2DFunction
(
params
[
'xsize'
],
params
[
'ysize'
],
params
[
'zsize'
],
values
))
for
atom
in
data
.
atoms
:
for
atom
in
data
.
atoms
:
t
=
data
.
atomType
[
atom
]
values
=
self
.
params
.
getAtomParameters
(
atom
,
data
)
if
t
in
self
.
typeMap
:
type
=
int
(
self
.
params
.
getExtraParameters
(
atom
,
data
)[
'filterType'
])
values
=
self
.
typeMap
[
t
]
force
.
addParticle
(
values
,
type
)
force
.
addParticle
(
values
[
0
],
values
[
1
])
else
:
raise
ValueError
(
'No CustomManyParticle parameters defined for atom type '
+
t
)
force
.
setNonbondedMethod
(
methodMap
[
nonbondedMethod
])
force
.
setNonbondedMethod
(
methodMap
[
nonbondedMethod
])
force
.
setCutoffDistance
(
nonbondedCutoff
)
force
.
setCutoffDistance
(
nonbondedCutoff
)
sys
.
addForce
(
force
)
sys
.
addForce
(
force
)
...
@@ -3083,8 +3119,6 @@ class AmoebaVdwGenerator:
...
@@ -3083,8 +3119,6 @@ class AmoebaVdwGenerator:
self
.
vdw14Scale
=
vdw14Scale
self
.
vdw14Scale
=
vdw14Scale
self
.
vdw15Scale
=
vdw15Scale
self
.
vdw15Scale
=
vdw15Scale
self
.
typeMap
=
{}
#=============================================================================================
#=============================================================================================
@
staticmethod
@
staticmethod
...
@@ -3097,31 +3131,10 @@ class AmoebaVdwGenerator:
...
@@ -3097,31 +3131,10 @@ class AmoebaVdwGenerator:
generator
=
AmoebaVdwGenerator
(
element
.
attrib
[
'type'
],
element
.
attrib
[
'radiusrule'
],
element
.
attrib
[
'radiustype'
],
element
.
attrib
[
'radiussize'
],
element
.
attrib
[
'epsilonrule'
],
generator
=
AmoebaVdwGenerator
(
element
.
attrib
[
'type'
],
element
.
attrib
[
'radiusrule'
],
element
.
attrib
[
'radiustype'
],
element
.
attrib
[
'radiussize'
],
element
.
attrib
[
'epsilonrule'
],
float
(
element
.
attrib
[
'vdw-13-scale'
]),
float
(
element
.
attrib
[
'vdw-14-scale'
]),
float
(
element
.
attrib
[
'vdw-15-scale'
]))
float
(
element
.
attrib
[
'vdw-13-scale'
]),
float
(
element
.
attrib
[
'vdw-14-scale'
]),
float
(
element
.
attrib
[
'vdw-15-scale'
]))
forceField
.
_forces
.
append
(
generator
)
forceField
.
_forces
.
append
(
generator
)
generator
.
params
=
ForceField
.
_AtomTypeParameters
(
forceField
,
'AmoebaVdwForce'
,
'Vdw'
,
(
'sigma'
,
'epsilon'
,
'reduction'
))
generator
.
params
.
parseDefinitions
(
element
)
two_six
=
1.122462048309372
two_six
=
1.122462048309372
# types[] = [ sigma, epsilon, reductionFactor, class ]
# sigma is modified based on radiustype and radiussize
for
atom
in
element
.
findall
(
'Vdw'
):
types
=
forceField
.
_findAtomTypes
(
atom
.
attrib
,
1
)
if
None
not
in
types
:
values
=
[
float
(
atom
.
attrib
[
'sigma'
]),
float
(
atom
.
attrib
[
'epsilon'
]),
float
(
atom
.
attrib
[
'reduction'
])]
if
(
generator
.
radiustype
==
'SIGMA'
):
values
[
0
]
*=
two_six
if
(
generator
.
radiussize
==
'DIAMETER'
):
values
[
0
]
*=
0.5
for
t
in
types
[
0
]:
generator
.
typeMap
[
t
]
=
values
else
:
outputString
=
"AmoebaVdwGenerator: error getting type: %s"
%
(
atom
.
attrib
[
'class'
])
raise
ValueError
(
outputString
)
#=============================================================================================
#=============================================================================================
# Return a set containing the indices of particles bonded to particle with index=particleIndex
# Return a set containing the indices of particles bonded to particle with index=particleIndex
...
@@ -3199,28 +3212,25 @@ class AmoebaVdwGenerator:
...
@@ -3199,28 +3212,25 @@ class AmoebaVdwGenerator:
force
=
existing
[
0
]
force
=
existing
[
0
]
# add particles to force
# add particles to force
# throw error if particle type not available
sigmaScale
=
1
if
self
.
radiustype
==
'SIGMA'
:
sigmaScale
=
1.122462048309372
if
self
.
radiussize
==
'DIAMETER'
:
sigmaScale
=
0.5
for
(
i
,
atom
)
in
enumerate
(
data
.
atoms
):
for
(
i
,
atom
)
in
enumerate
(
data
.
atoms
):
t
=
data
.
atomType
[
atom
]
values
=
self
.
params
.
getAtomParameters
(
atom
,
data
)
if
t
in
self
.
typeMap
:
# ivIndex = index of bonded partner for hydrogens; otherwise ivIndex = particle index
values
=
self
.
typeMap
[
t
]
ivIndex
=
i
if
atom
.
element
==
elem
.
hydrogen
and
len
(
data
.
atomBonds
[
i
])
==
1
:
# ivIndex = index of bonded partner for hydrogens; otherwise ivIndex = particle index
bondIndex
=
data
.
atomBonds
[
i
][
0
]
if
(
data
.
bonds
[
bondIndex
].
atom1
==
i
):
ivIndex
=
i
ivIndex
=
data
.
bonds
[
bondIndex
].
atom2
mass
=
sys
.
getParticleMass
(
i
)
/
unit
.
dalton
else
:
if
(
mass
<
1.9
and
len
(
data
.
atomBonds
[
i
])
==
1
):
ivIndex
=
data
.
bonds
[
bondIndex
].
atom1
bondIndex
=
data
.
atomBonds
[
i
][
0
]
if
(
data
.
bonds
[
bondIndex
].
atom1
==
i
):
ivIndex
=
data
.
bonds
[
bondIndex
].
atom2
else
:
ivIndex
=
data
.
bonds
[
bondIndex
].
atom1
force
.
addParticle
(
ivIndex
,
values
[
0
],
values
[
1
],
values
[
2
])
force
.
addParticle
(
ivIndex
,
values
[
0
]
*
sigmaScale
,
values
[
1
],
values
[
2
])
else
:
raise
ValueError
(
'No vdw type for atom %s'
%
(
atom
.
name
))
# set combining rules
# set combining rules
...
@@ -3937,8 +3947,6 @@ class AmoebaWcaDispersionGenerator:
...
@@ -3937,8 +3947,6 @@ class AmoebaWcaDispersionGenerator:
self
.
dispoff
=
dispoff
self
.
dispoff
=
dispoff
self
.
shctd
=
shctd
self
.
shctd
=
shctd
self
.
typeMap
=
{}
#=========================================================================================
#=========================================================================================
@
staticmethod
@
staticmethod
...
@@ -3957,19 +3965,8 @@ class AmoebaWcaDispersionGenerator:
...
@@ -3957,19 +3965,8 @@ class AmoebaWcaDispersionGenerator:
element
.
attrib
[
'dispoff'
],
element
.
attrib
[
'dispoff'
],
element
.
attrib
[
'shctd'
])
element
.
attrib
[
'shctd'
])
forceField
.
_forces
.
append
(
generator
)
forceField
.
_forces
.
append
(
generator
)
generator
.
params
=
ForceField
.
_AtomTypeParameters
(
forceField
,
'AmoebaWcaDispersionForce'
,
'WcaDispersion'
,
(
'radius'
,
'epsilon'
))
# typeMap[] = [ radius, epsilon ]
generator
.
params
.
parseDefinitions
(
element
)
for
atom
in
element
.
findall
(
'WcaDispersion'
):
types
=
forceField
.
_findAtomTypes
(
atom
.
attrib
,
1
)
if
None
not
in
types
:
values
=
[
float
(
atom
.
attrib
[
'radius'
]),
float
(
atom
.
attrib
[
'epsilon'
])]
for
t
in
types
[
0
]:
generator
.
typeMap
[
t
]
=
values
else
:
outputString
=
"AmoebaWcaDispersionGenerator: error getting type: %s"
%
(
atom
.
attrib
[
'class'
])
raise
ValueError
(
outputString
)
#=========================================================================================
#=========================================================================================
...
@@ -3997,14 +3994,9 @@ class AmoebaWcaDispersionGenerator:
...
@@ -3997,14 +3994,9 @@ class AmoebaWcaDispersionGenerator:
force
.
setAwater
(
float
(
self
.
awater
))
force
.
setAwater
(
float
(
self
.
awater
))
force
.
setShctd
(
float
(
self
.
shctd
))
force
.
setShctd
(
float
(
self
.
shctd
))
for
(
i
,
atom
)
in
enumerate
(
data
.
atoms
):
for
atom
in
data
.
atoms
:
t
=
data
.
atomType
[
atom
]
values
=
self
.
params
.
getAtomParameters
(
atom
,
data
)
if
t
in
self
.
typeMap
:
force
.
addParticle
(
values
[
0
],
values
[
1
])
values
=
self
.
typeMap
[
t
]
force
.
addParticle
(
values
[
0
],
values
[
1
])
else
:
raise
ValueError
(
'No WcaDispersion type for atom %s of %s %d'
%
(
atom
.
name
,
atom
.
residue
.
name
,
atom
.
residue
.
index
))
parsers
[
"AmoebaWcaDispersionForce"
]
=
AmoebaWcaDispersionGenerator
.
parseElement
parsers
[
"AmoebaWcaDispersionForce"
]
=
AmoebaWcaDispersionGenerator
.
parseElement
...
...
wrappers/python/tests/TestForceField.py
View file @
6a985cfd
...
@@ -6,6 +6,10 @@ from simtk.unit import *
...
@@ -6,6 +6,10 @@ from simtk.unit import *
import
simtk.openmm.app.element
as
elem
import
simtk.openmm.app.element
as
elem
import
simtk.openmm.app.forcefield
as
forcefield
import
simtk.openmm.app.forcefield
as
forcefield
import
math
import
math
if
sys
.
version_info
>=
(
3
,
0
):
from
io
import
StringIO
else
:
from
cStringIO
import
StringIO
class
TestForceField
(
unittest
.
TestCase
):
class
TestForceField
(
unittest
.
TestCase
):
"""Test the ForceField.createSystem() method."""
"""Test the ForceField.createSystem() method."""
...
@@ -144,7 +148,8 @@ class TestForceField(unittest.TestCase):
...
@@ -144,7 +148,8 @@ class TestForceField(unittest.TestCase):
context
=
Context
(
system
,
integrator
)
context
=
Context
(
system
,
integrator
)
context
.
setPositions
(
pdb
.
positions
)
context
.
setPositions
(
pdb
.
positions
)
state1
=
context
.
getState
(
getForces
=
True
)
state1
=
context
.
getState
(
getForces
=
True
)
state2
=
XmlSerializer
.
deserialize
(
open
(
'systems/lysozyme-implicit-forces.xml'
).
read
())
with
open
(
'systems/lysozyme-implicit-forces.xml'
)
as
input
:
state2
=
XmlSerializer
.
deserialize
(
input
.
read
())
numDifferences
=
0
numDifferences
=
0
for
f1
,
f2
,
in
zip
(
state1
.
getForces
().
value_in_unit
(
kilojoules_per_mole
/
nanometer
),
state2
.
getForces
().
value_in_unit
(
kilojoules_per_mole
/
nanometer
)):
for
f1
,
f2
,
in
zip
(
state1
.
getForces
().
value_in_unit
(
kilojoules_per_mole
/
nanometer
),
state2
.
getForces
().
value_in_unit
(
kilojoules_per_mole
/
nanometer
)):
diff
=
norm
(
f1
-
f2
)
diff
=
norm
(
f1
-
f2
)
...
@@ -197,7 +202,51 @@ class TestForceField(unittest.TestCase):
...
@@ -197,7 +202,51 @@ class TestForceField(unittest.TestCase):
for
i
in
range
(
3
):
for
i
in
range
(
3
):
self
.
assertEqual
(
vectors
[
i
],
self
.
pdb1
.
topology
.
getPeriodicBoxVectors
()[
i
])
self
.
assertEqual
(
vectors
[
i
],
self
.
pdb1
.
topology
.
getPeriodicBoxVectors
()[
i
])
self
.
assertEqual
(
vectors
[
i
],
system
.
getDefaultPeriodicBoxVectors
()[
i
])
self
.
assertEqual
(
vectors
[
i
],
system
.
getDefaultPeriodicBoxVectors
()[
i
])
def
test_ResidueAttributes
(
self
):
"""Test a ForceField that gets per-particle parameters from residue attributes."""
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"/>
</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
))
# Build a water box.
modeller
=
Modeller
(
Topology
(),
[])
modeller
.
addSolvent
(
ff
,
boxSize
=
Vec3
(
3
,
3
,
3
)
*
nanometers
)
# Create a system and make sure all nonbonded parameters are correct.
system
=
ff
.
createSystem
(
modeller
.
topology
)
nonbonded
=
[
f
for
f
in
system
.
getForces
()
if
isinstance
(
f
,
NonbondedForce
)][
0
]
atoms
=
list
(
modeller
.
topology
.
atoms
())
for
i
in
range
(
len
(
atoms
)):
params
=
nonbonded
.
getParticleParameters
(
i
)
if
atoms
[
i
].
element
==
elem
.
oxygen
:
self
.
assertEqual
(
params
[
0
],
-
0.834
*
elementary_charge
)
self
.
assertEqual
(
params
[
1
],
0.315
*
nanometers
)
self
.
assertEqual
(
params
[
2
],
0.635
*
kilojoule_per_mole
)
else
:
self
.
assertEqual
(
params
[
0
],
0.417
*
elementary_charge
)
self
.
assertEqual
(
params
[
1
],
1.0
*
nanometers
)
self
.
assertEqual
(
params
[
2
],
0.0
*
kilojoule_per_mole
)
class
AmoebaTestForceField
(
unittest
.
TestCase
):
class
AmoebaTestForceField
(
unittest
.
TestCase
):
"""Test the ForceField.createSystem() method with the AMOEBA forcefield."""
"""Test the ForceField.createSystem() method with the AMOEBA forcefield."""
...
@@ -270,6 +319,22 @@ class AmoebaTestForceField(unittest.TestCase):
...
@@ -270,6 +319,22 @@ class AmoebaTestForceField(unittest.TestCase):
self
.
assertAlmostEqual
(
constraints
[(
0
,
2
)],
hoDist
)
self
.
assertAlmostEqual
(
constraints
[(
0
,
2
)],
hoDist
)
self
.
assertAlmostEqual
(
constraints
[(
1
,
2
)],
hohDist
)
self
.
assertAlmostEqual
(
constraints
[(
1
,
2
)],
hohDist
)
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/alanine-dipeptide-implicit.pdb'
)
forcefield
=
ForceField
(
'amoeba2013.xml'
,
'amoeba2013_gk.xml'
)
system
=
forcefield
.
createSystem
(
pdb
.
topology
,
polarization
=
'direct'
)
integrator
=
VerletIntegrator
(
0.001
)
context
=
Context
(
system
,
integrator
)
context
.
setPositions
(
pdb
.
positions
)
state1
=
context
.
getState
(
getForces
=
True
)
with
open
(
'systems/alanine-dipeptide-amoeba-forces.xml'
)
as
input
:
state2
=
XmlSerializer
.
deserialize
(
input
.
read
())
for
f1
,
f2
,
in
zip
(
state1
.
getForces
().
value_in_unit
(
kilojoules_per_mole
/
nanometer
),
state2
.
getForces
().
value_in_unit
(
kilojoules_per_mole
/
nanometer
)):
diff
=
norm
(
f1
-
f2
)
self
.
assertTrue
(
diff
<
0.1
or
diff
/
norm
(
f1
)
<
1e-3
)
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
unittest
.
main
()
unittest
.
main
()
wrappers/python/tests/systems/alanine-dipeptide-amoeba-forces.xml
0 → 100644
View file @
6a985cfd
<?xml version="1.0" ?>
<State
time=
"0"
type=
"State"
version=
"1"
>
<PeriodicBoxVectors>
<A
x=
"2"
y=
"0"
z=
"0"
/>
<B
x=
"0"
y=
"2"
z=
"0"
/>
<C
x=
"0"
y=
"0"
z=
"2"
/>
</PeriodicBoxVectors>
<Forces>
<Force
x=
"-60.899006905648534"
y=
"-704.8991281062977"
z=
".0364180169671772"
/>
<Force
x=
"1179.7263311404506"
y=
"629.2168542831286"
z=
"1.563821009034657"
/>
<Force
x=
"-484.4401097634541"
y=
"135.94210610096957"
z=
"558.0155391926069"
/>
<Force
x=
"-484.1625627429897"
y=
"136.02915381525668"
z=
"-557.7203977673528"
/>
<Force
x=
"-804.8403408476064"
y=
"-857.579131840898"
z=
"118.43755474210333"
/>
<Force
x=
"84.24441920455223"
y=
"-421.86322192608037"
z=
"120.734742628977"
/>
<Force
x=
"666.4942549112259"
y=
"-479.03339298154526"
z=
"19.66166555862896"
/>
<Force
x=
"-518.9062723002917"
y=
"686.3850843706331"
z=
".7311137123231983"
/>
<Force
x=
"-105.62094199225953"
y=
"710.9845370176521"
z=
"-508.0677463920413"
/>
<Force
x=
"285.6690654282444"
y=
"-111.35548608152155"
z=
"847.8096733172159"
/>
<Force
x=
"-396.4822698774795"
y=
"24.462223992557014"
z=
"297.9581483103431"
/>
<Force
x=
"-168.22340166944585"
y=
"110.99779797739818"
z=
"-824.0916382722021"
/>
<Force
x=
"805.7023041833917"
y=
"15.738288953519556"
z=
"-340.2263402925698"
/>
<Force
x=
"366.3025998383222"
y=
"-647.7535895818237"
z=
"-273.83047817845636"
/>
<Force
x=
"-649.7310636705703"
y=
"-495.52797252280067"
z=
"317.36013856851315"
/>
<Force
x=
"-480.120788018345"
y=
"172.44477988154952"
z=
"-16.235455767965004"
/>
<Force
x=
"-486.20230228601736"
y=
"982.6376366390087"
z=
"127.20818643942287"
/>
<Force
x=
"820.5730252078641"
y=
"-78.71234329038225"
z=
"109.31395566365498"
/>
<Force
x=
"355.03388135028814"
y=
"-1391.2776654673507"
z=
".9942543092954484"
/>
<Force
x=
"-511.3467906691061"
y=
"677.7717086552518"
z=
".008253291392112616"
/>
<Force
x=
"293.66157422204157"
y=
"452.68343054060256"
z=
"502.83463917630775"
/>
<Force
x=
"293.5683952568295"
y=
"452.70832957117113"
z=
"-502.49604726620026"
/>
</Forces>
</State>
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