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
85b0ef02
"...tests/TestSerializeMonteCarloAnisotropicBarostat.cpp" did not exist on "0e879806cdd38e58b04481ecf7fcd93c44c7dc27"
Commit
85b0ef02
authored
Nov 02, 2015
by
Peter Eastman
Browse files
Added neutralize option to addSolvent()
parent
f680718e
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
81 additions
and
75 deletions
+81
-75
wrappers/python/simtk/openmm/app/modeller.py
wrappers/python/simtk/openmm/app/modeller.py
+11
-9
wrappers/python/tests/TestModeller.py
wrappers/python/tests/TestModeller.py
+70
-66
No files found.
wrappers/python/simtk/openmm/app/modeller.py
View file @
85b0ef02
...
...
@@ -241,13 +241,13 @@ class Modeller(object):
self
.
topology
=
newTopology
self
.
positions
=
newPositions
def
addSolvent
(
self
,
forcefield
,
model
=
'tip3p'
,
boxSize
=
None
,
boxVectors
=
None
,
padding
=
None
,
numAdded
=
None
,
positiveIon
=
'Na+'
,
negativeIon
=
'Cl-'
,
ionicStrength
=
0
*
molar
):
def
addSolvent
(
self
,
forcefield
,
model
=
'tip3p'
,
boxSize
=
None
,
boxVectors
=
None
,
padding
=
None
,
numAdded
=
None
,
positiveIon
=
'Na+'
,
negativeIon
=
'Cl-'
,
ionicStrength
=
0
*
molar
,
neutralize
=
True
):
"""Add solvent (both water and ions) to the model to fill a rectangular box.
The algorithm works as follows:
1. Water molecules are added to fill the box.
2. Water molecules are removed if their distance to any solute atom is less than the sum of their van der Waals radii.
3. If the solute is charged, enough positive or negative ions are added to neutralize it. Each ion is added by
3. If the solute is charged
and neutralize=True
, enough positive or negative ions are added to neutralize it. Each ion is added by
randomly selecting a water molecule and replacing it with the ion.
4. Ion pairs are added to give the requested total ionic strength.
...
...
@@ -258,7 +258,7 @@ class Modeller(object):
3. You can give a padding distance. The largest dimension of the solute (along the x, y, or z axis) is determined, and a cubic
box of size (largest dimension)+2*padding is used.
4. You can specify the total number of molecules (both waters and ions) to add. A cubic box is then created whose size is
just large enough hold the specified amount of solvent.
just large enough
to
hold the specified amount of solvent.
5. Finally, if none of the above options is specified, the existing Topology's box vectors are used.
Parameters:
...
...
@@ -273,6 +273,7 @@ class Modeller(object):
that not all force fields support all ion types.
- ionicStrength (concentration=0*molar) the total concentration of ions (both positive and negative) to add. This
does not include ions that are added to neutralize the system.
- neutralize (bool=True) whether to add ions to neutralize the system
"""
if
len
([
x
for
x
in
(
boxSize
,
boxVectors
,
padding
,
numAdded
)
if
x
is
not
None
])
>
1
:
raise
ValueError
(
'At most one of the following arguments may be specified: boxSize, boxVectors, padding, numAdded'
)
...
...
@@ -478,9 +479,6 @@ class Modeller(object):
# Add ions to neutralize the system.
totalCharge
=
int
(
floor
(
0.5
+
sum
((
nonbonded
.
getParticleParameters
(
i
)[
0
].
value_in_unit
(
elementary_charge
)
for
i
in
range
(
system
.
getNumParticles
())))))
if
abs
(
totalCharge
)
>
len
(
addedWaters
):
raise
Exception
(
'Cannot neutralize the system because the charge is greater than the number of available positions for ions'
)
def
addIon
(
element
):
# Replace a water by an ion.
index
=
random
.
randint
(
0
,
len
(
addedWaters
)
-
1
)
...
...
@@ -488,6 +486,10 @@ class Modeller(object):
newTopology
.
addAtom
(
element
.
symbol
,
element
,
newResidue
)
newPositions
.
append
(
addedWaters
[
index
][
1
]
*
nanometer
)
del
addedWaters
[
index
]
if
neutralize
:
totalCharge
=
int
(
floor
(
0.5
+
sum
((
nonbonded
.
getParticleParameters
(
i
)[
0
].
value_in_unit
(
elementary_charge
)
for
i
in
range
(
system
.
getNumParticles
())))))
if
abs
(
totalCharge
)
>
len
(
addedWaters
):
raise
Exception
(
'Cannot neutralize the system because the charge is greater than the number of available positions for ions'
)
for
i
in
range
(
abs
(
totalCharge
)):
addIon
(
positiveElement
if
totalCharge
<
0
else
negativeElement
)
...
...
wrappers/python/tests/TestModeller.py
View file @
85b0ef02
...
...
@@ -401,6 +401,7 @@ class TestModeller(unittest.TestCase):
topology_start
=
self
.
pdb
.
topology
topology_start
.
setUnitCellDimensions
(
Vec3
(
3.5
,
3.5
,
3.5
)
*
nanometers
)
for
neutralize
in
(
True
,
False
):
# set up modeller with no solvent
modeller
=
Modeller
(
topology_start
,
self
.
positions
)
modeller
.
deleteWater
()
...
...
@@ -416,7 +417,7 @@ class TestModeller(unittest.TestCase):
positions_toAdd
=
[
Vec3
(
1.0
,
1.2
,
1.5
),
Vec3
(
1.7
,
1.0
,
1.4
),
Vec3
(
1.5
,
2.0
,
1.0
),
Vec3
(
2.0
,
2.0
,
2.0
),
Vec3
(
2.0
,
1.5
,
1.0
)]
*
nanometers
modeller
.
add
(
topology_toAdd
,
positions_toAdd
)
modeller
.
addSolvent
(
self
.
forcefield
,
ionicStrength
=
1.0
*
molar
)
modeller
.
addSolvent
(
self
.
forcefield
,
ionicStrength
=
1.0
*
molar
,
neutralize
=
neutralize
)
topology_after
=
modeller
.
getTopology
()
water_count
=
0
...
...
@@ -432,9 +433,10 @@ class TestModeller(unittest.TestCase):
total_water_ions
=
water_count
+
sodium_count
+
chlorine_count
expected_ion_fraction
=
1.0
*
molar
/
(
55.4
*
molar
)
expected_ions
=
math
.
floor
((
total_water_ions
-
10
)
*
expected_ion_fraction
/
2
+
0.5
)
+
5
self
.
assertEqual
(
sodium_count
,
expected_ions
)
self
.
assertEqual
(
chlorine_count
,
expected_ions
)
expected_chlorine
=
math
.
floor
((
total_water_ions
-
10
)
*
expected_ion_fraction
/
2
+
0.5
)
+
5
expected_sodium
=
expected_chlorine
if
neutralize
else
expected_chlorine
-
5
self
.
assertEqual
(
sodium_count
,
expected_sodium
)
self
.
assertEqual
(
chlorine_count
,
expected_chlorine
)
def
test_addSolventPositiveSolvent
(
self
):
""" Test the addSolvent() method; test adding ions to a positively charged solvent. """
...
...
@@ -442,6 +444,7 @@ class TestModeller(unittest.TestCase):
topology_start
=
self
.
pdb
.
topology
topology_start
.
setUnitCellDimensions
(
Vec3
(
3.5
,
3.5
,
3.5
)
*
nanometers
)
for
neutralize
in
(
True
,
False
):
# set up modeller with no solvent
modeller
=
Modeller
(
topology_start
,
self
.
positions
)
modeller
.
deleteWater
()
...
...
@@ -459,7 +462,7 @@ class TestModeller(unittest.TestCase):
# positions_toAdd doesn't need to change
modeller
.
add
(
topology_toAdd
,
positions_toAdd
)
modeller
.
addSolvent
(
self
.
forcefield
,
ionicStrength
=
1.0
*
molar
)
modeller
.
addSolvent
(
self
.
forcefield
,
ionicStrength
=
1.0
*
molar
,
neutralize
=
neutralize
)
topology_after
=
modeller
.
getTopology
()
water_count
=
0
...
...
@@ -475,9 +478,10 @@ class TestModeller(unittest.TestCase):
total_water_ions
=
water_count
+
sodium_count
+
chlorine_count
expected_ion_fraction
=
1.0
*
molar
/
(
55.4
*
molar
)
expected_ions
=
math
.
floor
((
total_water_ions
-
10
)
*
expected_ion_fraction
/
2
+
0.5
)
+
5
self
.
assertEqual
(
sodium_count
,
expected_ions
)
self
.
assertEqual
(
chlorine_count
,
expected_ions
)
expected_sodium
=
math
.
floor
((
total_water_ions
-
10
)
*
expected_ion_fraction
/
2
+
0.5
)
+
5
expected_chlorine
=
expected_sodium
if
neutralize
else
expected_sodium
-
5
self
.
assertEqual
(
sodium_count
,
expected_sodium
)
self
.
assertEqual
(
chlorine_count
,
expected_chlorine
)
def
test_addSolventIons
(
self
):
""" Test the addSolvent() method with all possible choices for positive and negative ions. """
...
...
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