Skip to content

Commit

Permalink
Optimizations to _findNearestDistance() (#268)
Browse files Browse the repository at this point in the history
* Optimizations to _findNearestDistance()

* Minor changes based on review comments
  • Loading branch information
peastman authored Feb 16, 2023
1 parent 12c4231 commit 3db52f1
Showing 1 changed file with 28 additions and 13 deletions.
41 changes: 28 additions & 13 deletions pdbfixer/pdbfixer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Biological Structures at Stanford, funded under the NIH Roadmap for
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
Contributors:
Expand Down Expand Up @@ -954,20 +954,30 @@ def addMissingAtoms(self, seed=None):
mm.LocalEnergyMinimizer.minimize(context)
state = context.getState(getPositions=True)
if newTopology.getNumResidues() > 1:
nearest = self._findNearestDistance(context, newTopology, newAtoms)
if nearest < 0.13:
# When looking for pairs of atoms that are too close to each other, exclude pairs that
# 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
# repulsive interaction to try to improve the result.

for i in range(10):
context.setParameter('C', 0.15*(i+1))
integrator.step(200)
d = self._findNearestDistance(context, newTopology, newAtoms)
d = self._findNearestDistance(context, newAtoms, cutoff, exclusions)
if d > nearest:
nearest = d
state = context.getState(getPositions=True)
if nearest >= 0.13:
if nearest >= cutoff:
break
context.setState(state)
context.setParameter('C', 1.0)
Expand Down Expand Up @@ -1195,18 +1205,23 @@ def _createForceField(self, newTopology, water):
forcefield._templateSignatures[signature] = [template]
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."""

positions = context.getState(getPositions=True).getPositions(asNumpy=True).value_in_unit(unit.nanometer)
atomResidue = [atom.residue for atom in topology.atoms()]
nearest = sys.float_info.max
boxSize = np.max(positions, axis=0)-np.min(positions, axis=0)
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:
p = positions-positions[atom.index]
dist = math.sqrt(min(np.dot(p[i], p[i]) for i in range(len(atomResidue)) if atomResidue[i] != atom.residue))
if dist < nearest:
nearest = dist
return nearest
excluded = exclusions[atom]
for i in cells.neighbors(positions[atom.index]):
if i not in excluded:
p = positions[atom.index]-positions[i]
dist_squared = np.dot(p, p)
if dist_squared < nearest_squared:
nearest_squared = dist_squared
return np.sqrt(nearest_squared)


def main():
Expand Down

0 comments on commit 3db52f1

Please sign in to comment.