Commit 23667642 by Peter Eastman

Non-standard residues are transformed to their standard versions

parent cde53ba9
...@@ -42,6 +42,23 @@ import os ...@@ -42,6 +42,23 @@ import os
import os.path import os.path
import math import math
substitutions = {
'2AS':'ASP', '3AH':'HIS', '5HP':'GLU', 'ACL':'ARG', 'AGM':'ARG', 'AIB':'ALA', 'ALM':'ALA', 'ALO':'THR', 'ALY':'LYS', 'ARM':'ARG',
'ASA':'ASP', 'ASB':'ASP', 'ASK':'ASP', 'ASL':'ASP', 'ASQ':'ASP', 'AYA':'ALA', 'BCS':'CYS', 'BHD':'ASP', 'BMT':'THR', 'BNN':'ALA',
'BUC':'CYS', 'BUG':'LEU', 'C5C':'CYS', 'C6C':'CYS', 'CCS':'CYS', 'CEA':'CYS', 'CGU':'GLU', 'CHG':'ALA', 'CLE':'LEU', 'CME':'CYS',
'CSD':'ALA', 'CSO':'CYS', 'CSP':'CYS', 'CSS':'CYS', 'CSW':'CYS', 'CSX':'CYS', 'CXM':'MET', 'CY1':'CYS', 'CY3':'CYS', 'CYG':'CYS',
'CYM':'CYS', 'CYQ':'CYS', 'DAH':'PHE', 'DAL':'ALA', 'DAR':'ARG', 'DAS':'ASP', 'DCY':'CYS', 'DGL':'GLU', 'DGN':'GLN', 'DHA':'ALA',
'DHI':'HIS', 'DIL':'ILE', 'DIV':'VAL', 'DLE':'LEU', 'DLY':'LYS', 'DNP':'ALA', 'DPN':'PHE', 'DPR':'PRO', 'DSN':'SER', 'DSP':'ASP',
'DTH':'THR', 'DTR':'TRP', 'DTY':'TYR', 'DVA':'VAL', 'EFC':'CYS', 'FLA':'ALA', 'FME':'MET', 'GGL':'GLU', 'GL3':'GLY', 'GLZ':'GLY',
'GMA':'GLU', 'GSC':'GLY', 'HAC':'ALA', 'HAR':'ARG', 'HIC':'HIS', 'HIP':'HIS', 'HMR':'ARG', 'HPQ':'PHE', 'HTR':'TRP', 'HYP':'PRO',
'IIL':'ILE', 'IYR':'TYR', 'KCX':'LYS', 'LLP':'LYS', 'LLY':'LYS', 'LTR':'TRP', 'LYM':'LYS', 'LYZ':'LYS', 'MAA':'ALA', 'MEN':'ASN',
'MHS':'HIS', 'MIS':'SER', 'MLE':'LEU', 'MPQ':'GLY', 'MSA':'GLY', 'MSE':'MET', 'MVA':'VAL', 'NEM':'HIS', 'NEP':'HIS', 'NLE':'LEU',
'NLN':'LEU', 'NLP':'LEU', 'NMC':'GLY', 'OAS':'SER', 'OCS':'CYS', 'OMT':'MET', 'PAQ':'TYR', 'PCA':'GLU', 'PEC':'CYS', 'PHI':'PHE',
'PHL':'PHE', 'PR3':'CYS', 'PRR':'ALA', 'PTR':'TYR', 'PYX':'CYS', 'SAC':'SER', 'SAR':'GLY', 'SCH':'CYS', 'SCS':'CYS', 'SCY':'CYS',
'SEL':'SER', 'SEP':'SER', 'SET':'SER', 'SHC':'CYS', 'SHR':'LYS', 'SMC':'CYS', 'SOC':'CYS', 'STY':'TYR', 'SVA':'SER', 'TIH':'ALA',
'TPL':'TRP', 'TPO':'THR', 'TPQ':'ALA', 'TRG':'LYS', 'TRO':'TRP', 'TYB':'TYR', 'TYQ':'TYR', 'TYS':'TYR', 'TYY':'TYR'
}
def overlayPoints(points1, points2): def overlayPoints(points1, points2):
"""Given two sets of points, determine the translation and rotation that matches them as closely as possible. """Given two sets of points, determine the translation and rotation that matches them as closely as possible.
...@@ -73,7 +90,7 @@ def overlayPoints(points1, points2): ...@@ -73,7 +90,7 @@ def overlayPoints(points1, points2):
return (-1*center2, np.dot(u, v).transpose(), center1) return (-1*center2, np.dot(u, v).transpose(), center1)
def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMolecules): def addMissingAtoms(topology, positions, templates, missingAtoms, heavyAtomsOnly, omitUnknownMolecules):
"""Create a new Topology in which missing atoms have been added.""" """Create a new Topology in which missing atoms have been added."""
newTopology = app.Topology() newTopology = app.Topology()
...@@ -82,7 +99,7 @@ def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMol ...@@ -82,7 +99,7 @@ def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMol
existingAtomMap = {} existingAtomMap = {}
addedAtomMap = {} addedAtomMap = {}
addedOXT = [] addedOXT = []
for chain in pdb.topology.chains(): for chain in topology.chains():
if omitUnknownMolecules and not any(residue.name in templates for residue in chain.residues()): if omitUnknownMolecules and not any(residue.name in templates for residue in chain.residues()):
continue continue
newChain = newTopology.addChain() newChain = newTopology.addChain()
...@@ -97,13 +114,13 @@ def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMol ...@@ -97,13 +114,13 @@ def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMol
newAtom = newTopology.addAtom(atom.name, atom.element, newResidue) newAtom = newTopology.addAtom(atom.name, atom.element, newResidue)
newAtoms.append(newAtom) newAtoms.append(newAtom)
existingAtomMap[atom] = newAtom existingAtomMap[atom] = newAtom
newPositions.append(pdb.positions[atom.index]) newPositions.append(positions[atom.index])
if residue in missingAtoms: if residue in missingAtoms:
# Find corresponding atoms in the residue and the template. # Find corresponding atoms in the residue and the template.
template = templates[residue.name] template = templates[residue.name]
atomPositions = dict((atom.name, pdb.positions[atom.index]) for atom in residue.atoms()) atomPositions = dict((atom.name, positions[atom.index]) for atom in residue.atoms())
points1 = [] points1 = []
points2 = [] points2 = []
for atom in template.topology.atoms(): for atom in template.topology.atoms():
...@@ -128,7 +145,7 @@ def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMol ...@@ -128,7 +145,7 @@ def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMol
# If a terminal OXT is missing, add it. # If a terminal OXT is missing, add it.
if residue == chainResidues[-1] and residue.name in templates: if residue == chainResidues[-1] and residue.name in templates:
atomPositions = dict((atom.name, pdb.positions[atom.index].value_in_unit(unit.nanometer)) for atom in residue.atoms()) atomPositions = dict((atom.name, positions[atom.index].value_in_unit(unit.nanometer)) for atom in residue.atoms())
if 'OXT' not in atomPositions and all(name in atomPositions for name in ['C', 'O', 'CA']): if 'OXT' not in atomPositions and all(name in atomPositions for name in ['C', 'O', 'CA']):
newAtom = newTopology.addAtom('OXT', oxygen, newResidue) newAtom = newTopology.addAtom('OXT', oxygen, newResidue)
newAtoms.append(newAtom) newAtoms.append(newAtom)
...@@ -141,7 +158,7 @@ def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMol ...@@ -141,7 +158,7 @@ def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMol
# Add bonds from the original Topology. # Add bonds from the original Topology.
for atom1, atom2 in pdb.topology.bonds(): for atom1, atom2 in topology.bonds():
if atom1 in existingAtomMap and atom2 in existingAtomMap: if atom1 in existingAtomMap and atom2 in existingAtomMap:
newTopology.addBond(existingAtomMap[atom1], existingAtomMap[atom2]) newTopology.addBond(existingAtomMap[atom1], existingAtomMap[atom2])
...@@ -174,6 +191,8 @@ def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMol ...@@ -174,6 +191,8 @@ def addMissingAtoms(pdb, templates, missingAtoms, heavyAtomsOnly, omitUnknownMol
# Load the PDB file. # Load the PDB file.
pdb = app.PDBFile(sys.argv[1]) pdb = app.PDBFile(sys.argv[1])
topology = pdb.topology
positions = pdb.positions
# Load the templates. # Load the templates.
...@@ -183,10 +202,43 @@ for file in os.listdir('templates'): ...@@ -183,10 +202,43 @@ for file in os.listdir('templates'):
name = templatePdb.topology.residues().next().name name = templatePdb.topology.residues().next().name
templates[name] = templatePdb templates[name] = templatePdb
# Find non-standard residues to replace with standard versions.
replaceResidues = [r for r in topology.residues() if r.name in substitutions]
if len(replaceResidues) > 0:
deleteHeavyAtoms = set()
deleteHydrogens = set()
# Find heavy atoms that should be deleted.
for residue in replaceResidues:
residue.name = substitutions[residue.name]
template = templates[residue.name]
standardAtoms = set(atom.name for atom in template.topology.atoms())
for atom in residue.atoms():
if atom.element not in (None, hydrogen) and atom.name not in standardAtoms:
deleteHeavyAtoms.add(atom)
# We should also delete any hydrogen bonded to a heavy atom that is being deleted.
for atom1, atom2 in topology.bonds():
if atom1 not in deleteHeavyAtoms:
(atom1, atom2) = (atom2, atom1)
if atom1 in deleteHeavyAtoms:
if atom2.element in (None, hydrogen):
deleteHydrogens.add(atom2)
# Delete them.
modeller = app.Modeller(topology, positions)
modeller.delete(deleteHeavyAtoms.union(deleteHydrogens))
topology = modeller.topology
positions = modeller.positions
# Loop over residues to see which ones have missing heavy atoms. # Loop over residues to see which ones have missing heavy atoms.
missingAtoms = {} missingAtoms = {}
for residue in pdb.topology.residues(): for residue in topology.residues():
if residue.name in templates: if residue.name in templates:
template = templates[residue.name] template = templates[residue.name]
atomNames = set(atom.name for atom in residue.atoms()) atomNames = set(atom.name for atom in residue.atoms())
...@@ -199,7 +251,7 @@ for residue in pdb.topology.residues(): ...@@ -199,7 +251,7 @@ for residue in pdb.topology.residues():
# Create a Topology that 1) adds missing atoms, 2) removes all hydrogens, and 3) removes unknown molecules. # Create a Topology that 1) adds missing atoms, 2) removes all hydrogens, and 3) removes unknown molecules.
(newTopology, newPositions, newAtoms, existingAtomMap) = addMissingAtoms(pdb, templates, missingAtoms, True, True) (newTopology, newPositions, newAtoms, existingAtomMap) = addMissingAtoms(topology, positions, templates, missingAtoms, True, True)
# Create a System for energy minimizing it. # Create a System for energy minimizing it.
...@@ -214,11 +266,11 @@ for atom in existingAtomMap.itervalues(): ...@@ -214,11 +266,11 @@ for atom in existingAtomMap.itervalues():
# If any heavy atoms were omitted, add them back to avoid steric clashes. # If any heavy atoms were omitted, add them back to avoid steric clashes.
nonbonded = [f for f in system.getForces() if isinstance(f, mm.CustomNonbondedForce)][0] nonbonded = [f for f in system.getForces() if isinstance(f, mm.CustomNonbondedForce)][0]
for atom in pdb.topology.atoms(): for atom in topology.atoms():
if atom.element is not None and atom.element != hydrogen and atom not in existingAtomMap: if atom.element not in (None, hydrogen) and atom not in existingAtomMap:
system.addParticle(0.0) system.addParticle(0.0)
nonbonded.addParticle([]) nonbonded.addParticle([])
newPositions.append(pdb.positions[atom.index]) newPositions.append(positions[atom.index])
# For efficiency, only compute interactions that involve a new atom. # For efficiency, only compute interactions that involve a new atom.
...@@ -234,7 +286,7 @@ state = context.getState(getPositions=True) ...@@ -234,7 +286,7 @@ state = context.getState(getPositions=True)
# Now create a new Topology, including all atoms from the original one and adding the missing atoms. # Now create a new Topology, including all atoms from the original one and adding the missing atoms.
(newTopology2, newPositions2, newAtoms2, existingAtomMap2) = addMissingAtoms(pdb, templates, missingAtoms, False, False) (newTopology2, newPositions2, newAtoms2, existingAtomMap2) = addMissingAtoms(topology, positions, templates, missingAtoms, False, False)
# Copy over the minimized positions for the new atoms. # Copy over the minimized positions for the new atoms.
......
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