Unverified Commit 5d407c94 authored by Peter Eastman's avatar Peter Eastman Committed by GitHub
Browse files

Fixed errors with residueTemplates arguments to Modeller methods (#4528)

parent 8ac9cc44
...@@ -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) 2012-2023 Stanford University and the Authors. Portions copyright (c) 2012-2024 Stanford University and the Authors.
Authors: Peter Eastman Authors: Peter Eastman
Contributors: Contributors:
...@@ -856,12 +856,15 @@ class Modeller(object): ...@@ -856,12 +856,15 @@ class Modeller(object):
newTopology.setPeriodicBoxVectors(self.topology.getPeriodicBoxVectors()) newTopology.setPeriodicBoxVectors(self.topology.getPeriodicBoxVectors())
newAtoms = {} newAtoms = {}
newPositions = []*nanometer newPositions = []*nanometer
newResidueTemplates = {}
newIndices = [] newIndices = []
acceptors = [atom for atom in self.topology.atoms() if atom.element in (elem.oxygen, elem.nitrogen)] acceptors = [atom for atom in self.topology.atoms() if atom.element in (elem.oxygen, elem.nitrogen)]
for chain in self.topology.chains(): for chain in self.topology.chains():
newChain = newTopology.addChain(chain.id) newChain = newTopology.addChain(chain.id)
for residue in chain.residues(): for residue in chain.residues():
newResidue = newTopology.addResidue(residue.name, newChain, residue.id, residue.insertionCode) newResidue = newTopology.addResidue(residue.name, newChain, residue.id, residue.insertionCode)
if residue in residueTemplates:
newResidueTemplates[newResidue] = residueTemplates[residue]
isNTerminal = (residue == chain._residues[0]) isNTerminal = (residue == chain._residues[0])
isCTerminal = (residue == chain._residues[-1]) isCTerminal = (residue == chain._residues[-1])
if residue.name in Modeller._residueHydrogens: if residue.name in Modeller._residueHydrogens:
...@@ -1012,8 +1015,7 @@ class Modeller(object): ...@@ -1012,8 +1015,7 @@ class Modeller(object):
if forcefield is not None: if forcefield is not None:
# Use the ForceField the user specified. # Use the ForceField the user specified.
system = forcefield.createSystem(newTopology, rigidWater=False, nonbondedMethod=CutoffNonPeriodic, residueTemplates=residueTemplates) system = forcefield.createSystem(newTopology, rigidWater=False, nonbondedMethod=CutoffNonPeriodic, residueTemplates=newResidueTemplates)
atoms = list(newTopology.atoms())
for i in range(system.getNumParticles()): for i in range(system.getNumParticles()):
if i not in addedH: if i not in addedH:
# Existing atom, make it immobile. # Existing atom, make it immobile.
...@@ -1128,11 +1130,14 @@ class Modeller(object): ...@@ -1128,11 +1130,14 @@ class Modeller(object):
newTopology.setPeriodicBoxVectors(self.topology.getPeriodicBoxVectors()) newTopology.setPeriodicBoxVectors(self.topology.getPeriodicBoxVectors())
newAtoms = {} newAtoms = {}
newPositions = []*nanometer newPositions = []*nanometer
newResidueTemplates = {}
missingPositions = set() missingPositions = set()
for chain in self.topology.chains(): for chain in self.topology.chains():
newChain = newTopology.addChain(chain.id) newChain = newTopology.addChain(chain.id)
for residue in chain.residues(): for residue in chain.residues():
newResidue = newTopology.addResidue(residue.name, newChain, residue.id, residue.insertionCode) newResidue = newTopology.addResidue(residue.name, newChain, residue.id, residue.insertionCode)
if residue in residueTemplates:
newResidueTemplates[newResidue] = residueTemplates[residue]
template = templates[residue.index] template = templates[residue.index]
if len(template.atoms) == len(list(residue.atoms())): if len(template.atoms) == len(list(residue.atoms())):
# Just copy the residue over. # Just copy the residue over.
...@@ -1233,7 +1238,7 @@ class Modeller(object): ...@@ -1233,7 +1238,7 @@ class Modeller(object):
# There were particles whose position we couldn't identify before, since they were neither virtual sites nor Drude particles. # There were particles whose position we couldn't identify before, since they were neither virtual sites nor Drude particles.
# Try to figure them out based on bonds. First, use the ForceField to create a list of every bond involving one of them. # Try to figure them out based on bonds. First, use the ForceField to create a list of every bond involving one of them.
system = forcefield.createSystem(newTopology, constraints=AllBonds, residueTemplates=residueTemplates) system = forcefield.createSystem(newTopology, constraints=AllBonds, residueTemplates=newResidueTemplates)
bonds = [] bonds = []
for i in range(system.getNumConstraints()): for i in range(system.getNumConstraints()):
bond = system.getConstraintParameters(i) bond = system.getConstraintParameters(i)
...@@ -1580,6 +1585,10 @@ class Modeller(object): ...@@ -1580,6 +1585,10 @@ class Modeller(object):
if len(toDelete) > 0: if len(toDelete) > 0:
modeller.delete(toDelete) modeller.delete(toDelete)
newResidueTemplates = {}
for r1, r2 in zip(self.topology.residues(), modeller.topology.residues()):
if r1 in residueTemplates:
newResidueTemplates[r2] = residueTemplates[r1]
self.topology = modeller.topology self.topology = modeller.topology
self.positions = modeller.positions self.positions = modeller.positions
...@@ -1620,7 +1629,7 @@ class Modeller(object): ...@@ -1620,7 +1629,7 @@ class Modeller(object):
if lowerZBoundary < waterZ.value_in_unit(nanometer) < upperZBoundary: if lowerZBoundary < waterZ.value_in_unit(nanometer) < upperZBoundary:
del waterPos[wRes] del waterPos[wRes]
self._addIons(forcefield, numTotalWaters, waterPos, positiveIon=positiveIon, negativeIon=negativeIon, ionicStrength=ionicStrength, neutralize=neutralize, residueTemplates=residueTemplates) self._addIons(forcefield, numTotalWaters, waterPos, positiveIon=positiveIon, negativeIon=negativeIon, ionicStrength=ionicStrength, neutralize=neutralize, residueTemplates=newResidueTemplates)
class _CellList(object): class _CellList(object):
......
...@@ -1270,6 +1270,49 @@ class TestModeller(unittest.TestCase): ...@@ -1270,6 +1270,49 @@ class TestModeller(unittest.TestCase):
{(None, None), (Single, 1.0), (Double, 2.0)} {(None, None), (Single, 1.0), (Double, 2.0)}
) )
def test_residueTemplates(self):
"""Test the residueTemplates argument to Modeller methods"""
# Create a Topology and ForceField involving residues that match multiple templates.
topology = Topology()
chain = topology.addChain()
residue1 = topology.addResidue('Fe', chain)
topology.addAtom('Fe', element.iron, residue1)
residue2 = topology.addResidue('Fe', chain)
topology.addAtom('Fe', element.iron, residue2)
positions = [Vec3(0, 0, 0), Vec3(1, 0, 0)]*nanometers
ff = ForceField('amber14/tip3pfb.xml', 'amber14/lipid17.xml')
residueTemplates = {residue1: 'FE2', residue2: 'FE'}
# Test addSolvent().
modeller = Modeller(topology, positions)
with self.assertRaises(Exception):
modeller.addSolvent(ff, padding=1*nanometer)
modeller.addSolvent(ff, padding=1*nanometer, residueTemplates=residueTemplates)
# Test addHydrogens().
modeller = Modeller(topology, positions)
with self.assertRaises(Exception):
modeller.addHydrogens(ff)
modeller.addHydrogens(ff, residueTemplates=residueTemplates)
# Test addExtraParticles().
modeller = Modeller(topology, positions)
with self.assertRaises(Exception):
modeller.addExtraParticles(ff)
modeller.addExtraParticles(ff, residueTemplates=residueTemplates)
# Test addMembrane().
modeller = Modeller(topology, positions)
with self.assertRaises(Exception):
modeller.addMembrane(ff)
modeller.addMembrane(ff, residueTemplates=residueTemplates)
def assertVecAlmostEqual(self, p1, p2, tol=1e-7): def assertVecAlmostEqual(self, p1, p2, tol=1e-7):
scale = max(1.0, norm(p1),) scale = max(1.0, norm(p1),)
for i in range(3): for i in range(3):
......
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