Commit 5a613f45 authored by João Rodrigues's avatar João Rodrigues
Browse files

Fixed bug in calculation of number of ionic species to add in addMembrane. Addresses #2439

parent 138de127
......@@ -258,13 +258,16 @@ class Modeller(object):
self.topology = newTopology
self.positions = newPositions
def _addIons(self, forcefield, replaceableMols, ionCutoff=0.05*nanometer, positiveIon='Na+', negativeIon='Cl-', ionicStrength=0*molar, neutralize=True):
def _addIons(self, forcefield, numWaters, replaceableMols, ionCutoff=0.05*nanometer, positiveIon='Na+', negativeIon='Cl-', ionicStrength=0*molar, neutralize=True):
"""Adds ions to the system by replacing certain molecules.
Parameters
----------
forcefield : ForceField
the ForceField to use to determine the total charge of the system.
numWaters : int
the total number of water molecules in the simulation box, used to
calculate the number of ions / concentration to add.
replaceableMols : dict
the molecules to replace by ions, as a dictionary of residue:positions
ionCutoff: distance=0.5*nanometer
......@@ -326,12 +329,13 @@ class Modeller(object):
numPositive -= totalCharge
if ionicStrength > 0 * molar:
numIons = (numReplaceableMols - numPositive - numNegative) * ionicStrength / (55.4 * molar) # Pure water is about 55.4 molar (depending on temperature)
numIons = (numWaters - numPositive - numNegative) * ionicStrength / (55.4 * molar) # Pure water is about 55.4 molar (depending on temperature)
numPairs = int(floor(numIons + 0.5))
numPositive += numPairs
numNegative += numPairs
totalIons = numPositive + numNegative
if totalIons > 0:
# Randomly select a set of waters
# while ensuring ions are not placed too close to each other.
modeller = Modeller(self.topology, self.positions)
......@@ -621,8 +625,11 @@ class Modeller(object):
if atom.element == _oxygen:
waterPos[residue] = newPositions[atom.index]
# Total number of waters in the box
numTotalWaters = len(waterPos)
# Add ions to neutralize the system.
self._addIons(forcefield, waterPos, positiveIon=positiveIon, negativeIon=negativeIon, ionicStrength=ionicStrength, neutralize=neutralize)
self._addIons(forcefield, numTotalWaters, waterPos, positiveIon=positiveIon, negativeIon=negativeIon, ionicStrength=ionicStrength, neutralize=neutralize)
class _ResidueData:
"""Inner class used to encapsulate data about the hydrogens for a residue."""
......@@ -1348,7 +1355,6 @@ class Modeller(object):
# number get removed from each leaf.
overlapCutoff = 0.22
chain = membraneTopology.addChain()
addedWater = []
addedLipids = []
removedFromLeaf = [0, 0]
......@@ -1538,6 +1544,11 @@ class Modeller(object):
if atom.element == elem.oxygen:
waterPos[residue] = modeller.positions[atom.index]
# Total number of water molecules
# Use this number to avoid underestimating the concentration of ions
# in _addIons after we exclude waters close to lipids.
numTotalWaters = len(waterPos)
# Calculate lipid Z boundaries
lipidNames = {res.name for res in patch.topology.residues() if res.name != 'HOH'}
lipidZMax = sys.float_info.min
......@@ -1559,7 +1570,7 @@ class Modeller(object):
if lowerZBoundary < waterZ.value_in_unit(nanometer) < upperZBoundary:
del waterPos[wRes]
self._addIons(forcefield, waterPos, positiveIon=positiveIon, negativeIon=negativeIon, ionicStrength=ionicStrength, neutralize=neutralize)
self._addIons(forcefield, numTotalWaters, waterPos, positiveIon=positiveIon, negativeIon=negativeIon, ionicStrength=ionicStrength, neutralize=neutralize)
class _CellList(object):
......
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