"docs-source/vscode:/vscode.git/clone" did not exist on "cddeb60f6af9f25a2f8313651b868ac03259a3ba"
Commit 818db2b2 authored by jchodera's avatar jchodera
Browse files

Also return residue templates; add docs.

parent 88d7ee6a
...@@ -1961,6 +1961,32 @@ are :code:`wo1`\ , :code:`wo2`\ , :code:`wo3`\ , :code:`wx1`\ , :code:`wx2`\ , ...@@ -1961,6 +1961,32 @@ are :code:`wo1`\ , :code:`wo2`\ , :code:`wo3`\ , :code:`wx1`\ , :code:`wx2`\ ,
:code:`wx3`\ , :code:`wy1`\ , :code:`wy2`\ , :code:`wy3`\ , :code:`p1`\ , :code:`wx3`\ , :code:`wy1`\ , :code:`wy2`\ , :code:`wy3`\ , :code:`p1`\ ,
:code:`p2`\ , and :code:`p3`\ . :code:`p2`\ , and :code:`p3`\ .
Missing residue templates
=========================
.. CAUTION::
This feature is experimental, and its API is subject to change.
You can use the :method:`getUnmatchedResidues()` method to get a list of residues
in the provided :code:`topology` object that do not currently have a matching
residue template defined in the :class:`ForceField`.
::
pdb = PDBFile('input.pdb')
forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
unmatched_residues = forcefield.getUnmatchedResidues(topology)
This is useful for idenfitying issues with prepared systems, debugging issues
with residue template definitions, or identifying which additional residues need
to be parameterized.
As a convenience for parameterizing new residues, you can also get a list of
residues and empty residue templates using :method:`getUniqueUnmatchedResidues`
::
pdb = PDBFile('input.pdb')
forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
[residues, templates] = forcefield.getUniqueUnmatchedResidues(topology)
<HarmonicBondForce> <HarmonicBondForce>
=================== ===================
......
...@@ -640,24 +640,15 @@ class ForceField(object): ...@@ -640,24 +640,15 @@ class ForceField(object):
unmatched_residues = self.getUnmatchedResidues(topology) unmatched_residues = self.getUnmatchedResidues(topology)
# Generate a unique list of unmatched residues by comparing fingerprints. # Generate a unique list of unmatched residues by comparing fingerprints.
bondedToAtom = self._buildBondedToAtomList(topology) bondedToAtom = self._buildBondedToAtomList(topology)
unique_unmatched_residues = list() unique_unmatched_residues = list() # list of unique unmatched Residue objects from topology
templates = list() # corresponding _TemplateData templates
signatures = set() signatures = set()
for residue in unmatched_residues: for residue in unmatched_residues:
signature = _createResidueSignature([ atom.element for atom in residue.atoms() ]) signature = _createResidueSignature([ atom.element for atom in residue.atoms() ])
template = _createResidueTemplate(residue)
is_unique = True is_unique = True
if signature in signatures: if signature in signatures:
# Signature is the same as an existing residue; check connectivity. # Signature is the same as an existing residue; check connectivity.
template = ForceField._TemplateData(residue.name)
for atom in residue.atoms():
template.atoms.append(ForceField._TemplateAtomData(atom.name, 'X', atom.element))
for (atom1,atom2) in residue.internal_bonds():
template.addBondByName(atom1.name, atom2.name)
residue_atoms = [ atom for atom in residue.atoms() ]
for (atom1,atom2) in residue.external_bonds():
if atom1 in residue_atoms:
template.addExternalBondByName(atom1.name)
elif atom2 in residue_atoms:
template.addExternalBondByName(atom2.name)
for check_residue in unique_unmatched_residues: for check_residue in unique_unmatched_residues:
matches = _matchResidue(check_residue, template, bondedToAtom) matches = _matchResidue(check_residue, template, bondedToAtom)
if matches is not None: if matches is not None:
...@@ -667,7 +658,7 @@ class ForceField(object): ...@@ -667,7 +658,7 @@ class ForceField(object):
unique_unmatched_residues.append(residue) unique_unmatched_residues.append(residue)
signatures.add(signature) signatures.add(signature)
return unique_unmatched_residues return [unique_unmatched_residues, templates]
def createSystem(self, topology, nonbondedMethod=NoCutoff, nonbondedCutoff=1.0*unit.nanometer, def createSystem(self, topology, nonbondedMethod=NoCutoff, nonbondedCutoff=1.0*unit.nanometer,
constraints=None, rigidWater=True, removeCMMotion=True, hydrogenMass=None, **args): constraints=None, rigidWater=True, removeCMMotion=True, hydrogenMass=None, **args):
...@@ -949,7 +940,6 @@ def _createResidueSignature(elements): ...@@ -949,7 +940,6 @@ def _createResidueSignature(elements):
s += element.symbol+str(count) s += element.symbol+str(count)
return s return s
def _matchResidue(res, template, bondedToAtom): def _matchResidue(res, template, bondedToAtom):
"""Determine whether a residue matches a template and return a list of corresponding atoms. """Determine whether a residue matches a template and return a list of corresponding atoms.
...@@ -1094,6 +1084,34 @@ def _findMatchErrors(forcefield, res): ...@@ -1094,6 +1084,34 @@ def _findMatchErrors(forcefield, res):
return 'The set of atoms is similar to %s, but it is missing %d atoms.' % (bestMatchName, numBestMatchAtoms-numResidueAtoms) return 'The set of atoms is similar to %s, but it is missing %d atoms.' % (bestMatchName, numBestMatchAtoms-numResidueAtoms)
return 'This might mean your input topology is missing some atoms or bonds, or possibly that you are using the wrong force field.' return 'This might mean your input topology is missing some atoms or bonds, or possibly that you are using the wrong force field.'
def _createResidueTemplate(residue):
"""Create a _TemplateData template from a Residue object.
Parameters
----------
residue : Residue
The Residue from which the template is to be constructed.
Returns
-------
template : _TemplateData
The residue template, with atom types set to None.
This method may be useful in creating new residue templates for residues without templates defined by the ForceField.
"""
template = ForceField._TemplateData(residue.name)
for atom in residue.atoms():
template.atoms.append(ForceField._TemplateAtomData(atom.name, 'X', atom.element))
for (atom1,atom2) in residue.internal_bonds():
template.addBondByName(atom1.name, atom2.name)
residue_atoms = [ atom for atom in residue.atoms() ]
for (atom1,atom2) in residue.external_bonds():
if atom1 in residue_atoms:
template.addExternalBondByName(atom1.name)
elif atom2 in residue_atoms:
template.addExternalBondByName(atom2.name)
return template
# The following classes are generators that know how to create Force subclasses and add them to a System that is being # The following classes are generators that know how to create Force subclasses and add them to a System that is being
# created. Each generator class must define two methods: 1) a static method that takes an etree Element and a ForceField, # created. Each generator class must define two methods: 1) a static method that takes an etree Element and a ForceField,
......
...@@ -261,19 +261,10 @@ class TestForceField(unittest.TestCase): ...@@ -261,19 +261,10 @@ class TestForceField(unittest.TestCase):
from uuid import uuid4 from uuid import uuid4
template_name = uuid4() template_name = uuid4()
# Create residue template. # Create residue template.
template = ForceField._TemplateData(template_name) template = ForceField._createResidueTemplate(residue)
for atom in residue.atoms(): template.name = template_name
typename = 'XXX' for (template_atom, residue_atom) in zip(template.atoms, residue.atoms()):
atom_template = ForceField._TemplateAtomData(atom.name, typename, atom.element) template_atom.type = 'XXX'
template.atoms.append(atom_template)
for (atom1,atom2) in residue.internal_bonds():
template.addBondByName(atom1.name, atom2.name)
residue_atoms = [ atom for atom in residue.atoms() ]
for (atom1,atom2) in residue.external_bonds():
if atom1 in residue_atoms:
template.addExternalBondByName(atom1.name)
elif atom2 in residue_atoms:
template.addExternalBondByName(atom2.name)
# Register the template. # Register the template.
forcefield.registerResidueTemplate(template) forcefield.registerResidueTemplate(template)
...@@ -385,13 +376,18 @@ class TestForceField(unittest.TestCase): ...@@ -385,13 +376,18 @@ class TestForceField(unittest.TestCase):
forcefield = ForceField('tip3p.xml') forcefield = ForceField('tip3p.xml')
# Get list of unmatched residues. # Get list of unmatched residues.
unmatched_residues = forcefield.getUnmatchedResidues(pdb.topology) unmatched_residues = forcefield.getUnmatchedResidues(pdb.topology)
unique_unmatched_residues = forcefield.getUniqueUnmatchedResidues(pdb.topology) [unique_unmatched_residues, templates] = forcefield.getUniqueUnmatchedResidues(pdb.topology)
# Check results. # Check results.
self.assertEqual(len(unmatched_residues), 24) self.assertEqual(len(unmatched_residues), 24)
self.assertEqual(len(unique_unmatched_residues), 2) self.assertEqual(len(unique_unmatched_residues), 2)
unique_names = set([ residue.name for residue in unique_unmatched_residues ]) unique_names = set([ residue.name for residue in unique_unmatched_residues ])
self.assertTrue('HOH' not in unique_names)
self.assertTrue('NA' in unique_names) self.assertTrue('NA' in unique_names)
self.assertTrue('CL' in unique_names) self.assertTrue('CL' in unique_names)
template_names = set([ template.name for template in templates ])
self.assertTrue('HOH' not in template_names)
self.assertTrue('NA' in template_names)
self.assertTrue('CL' in template_names)
class AmoebaTestForceField(unittest.TestCase): class AmoebaTestForceField(unittest.TestCase):
"""Test the ForceField.createSystem() method with the AMOEBA forcefield.""" """Test the ForceField.createSystem() method with the AMOEBA forcefield."""
......
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