Commit 3db52f1a by Peter Eastman Committed by GitHub

Optimizations to _findNearestDistance() (#268)

* Optimizations to _findNearestDistance()

* Minor changes based on review comments
parent 12c42311
...@@ -6,7 +6,7 @@ Simbios, the NIH National Center for Physics-Based Simulation of ...@@ -6,7 +6,7 @@ Simbios, the NIH National Center for Physics-Based Simulation of
Biological Structures at Stanford, funded under the NIH Roadmap for Biological Structures at Stanford, funded under the NIH Roadmap for
Medical Research, grant U54 GM072970. See https://simtk.org. Medical Research, grant U54 GM072970. See https://simtk.org.
Portions copyright (c) 2013-2022 Stanford University and the Authors. Portions copyright (c) 2013-2023 Stanford University and the Authors.
Authors: Peter Eastman Authors: Peter Eastman
Contributors: Contributors:
...@@ -954,8 +954,18 @@ class PDBFixer(object): ...@@ -954,8 +954,18 @@ class PDBFixer(object):
mm.LocalEnergyMinimizer.minimize(context) mm.LocalEnergyMinimizer.minimize(context)
state = context.getState(getPositions=True) state = context.getState(getPositions=True)
if newTopology.getNumResidues() > 1: if newTopology.getNumResidues() > 1:
nearest = self._findNearestDistance(context, newTopology, newAtoms) # When looking for pairs of atoms that are too close to each other, exclude pairs that
if nearest < 0.13: # are in the same residue or are directly bonded to each other.
exclusions = dict((atom, {a.index for a in atom.residue.atoms()}) for atom in newAtoms)
for a1, a2 in newTopology.bonds():
if a1 in exclusions:
exclusions[a1].add(a2.index)
if a2 in exclusions:
exclusions[a2].add(a1.index)
cutoff = 0.13
nearest = self._findNearestDistance(context, newAtoms, cutoff, exclusions)
if nearest < cutoff:
# Some atoms are very close together. Run some dynamics while slowly increasing the strength of the # Some atoms are very close together. Run some dynamics while slowly increasing the strength of the
# repulsive interaction to try to improve the result. # repulsive interaction to try to improve the result.
...@@ -963,11 +973,11 @@ class PDBFixer(object): ...@@ -963,11 +973,11 @@ class PDBFixer(object):
for i in range(10): for i in range(10):
context.setParameter('C', 0.15*(i+1)) context.setParameter('C', 0.15*(i+1))
integrator.step(200) integrator.step(200)
d = self._findNearestDistance(context, newTopology, newAtoms) d = self._findNearestDistance(context, newAtoms, cutoff, exclusions)
if d > nearest: if d > nearest:
nearest = d nearest = d
state = context.getState(getPositions=True) state = context.getState(getPositions=True)
if nearest >= 0.13: if nearest >= cutoff:
break break
context.setState(state) context.setState(state)
context.setParameter('C', 1.0) context.setParameter('C', 1.0)
...@@ -1195,18 +1205,23 @@ class PDBFixer(object): ...@@ -1195,18 +1205,23 @@ class PDBFixer(object):
forcefield._templateSignatures[signature] = [template] forcefield._templateSignatures[signature] = [template]
return forcefield return forcefield
def _findNearestDistance(self, context, topology, newAtoms): def _findNearestDistance(self, context, newAtoms, cutoff, exclusions):
"""Given a set of newly added atoms, find the closest distance between one of those atoms and another atom.""" """Given a set of newly added atoms, find the closest distance between one of those atoms and another atom."""
positions = context.getState(getPositions=True).getPositions(asNumpy=True).value_in_unit(unit.nanometer) positions = context.getState(getPositions=True).getPositions(asNumpy=True).value_in_unit(unit.nanometer)
atomResidue = [atom.residue for atom in topology.atoms()] boxSize = np.max(positions, axis=0)-np.min(positions, axis=0)
nearest = sys.float_info.max boxVectors = [(boxSize[0], 0, 0), (0, boxSize[1], 0), (0, 0, boxSize[2])]
cells = app.modeller._CellList(positions, cutoff, boxVectors, False)
nearest_squared = sys.float_info.max
for atom in newAtoms: for atom in newAtoms:
p = positions-positions[atom.index] excluded = exclusions[atom]
dist = math.sqrt(min(np.dot(p[i], p[i]) for i in range(len(atomResidue)) if atomResidue[i] != atom.residue)) for i in cells.neighbors(positions[atom.index]):
if dist < nearest: if i not in excluded:
nearest = dist p = positions[atom.index]-positions[i]
return nearest dist_squared = np.dot(p, p)
if dist_squared < nearest_squared:
nearest_squared = dist_squared
return np.sqrt(nearest_squared)
def main(): def main():
......
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