Commit 1857850c authored by peastman's avatar peastman
Browse files

Merge pull request #1258 from peastman/atomnames

Residue templates can specify atoms by name instead of index
parents be0387b6 7139275a
...@@ -1889,12 +1889,12 @@ The residue template definitions look like this: ...@@ -1889,12 +1889,12 @@ The residue template definitions look like this:
<Atom name="HH33" type="710"/> <Atom name="HH33" type="710"/>
<Atom name="C" type="712"/> <Atom name="C" type="712"/>
<Atom name="O" type="713"/> <Atom name="O" type="713"/>
<Bond from="0" to="1"/> <Bond atomName1="HH31" atomName2="CH3"/>
<Bond from="1" to="2"/> <Bond atomName1="CH3" atomName2="HH32"/>
<Bond from="1" to="3"/> <Bond atomName1="CH3" atomName2="HH33"/>
<Bond from="1" to="4"/> <Bond atomName1="CH3" atomName2="C"/>
<Bond from="4" to="5"/> <Bond atomName1="C" atomName2="O"/>
<ExternalBond from="4"/> <ExternalBond atomName="C"/>
</Residue> </Residue>
<Residue name="ALA"> <Residue name="ALA">
... ...
...@@ -1908,12 +1908,16 @@ contains the following tags: ...@@ -1908,12 +1908,16 @@ contains the following tags:
* An :code:`<Atom>` tag for each atom in the residue. This specifies the * An :code:`<Atom>` tag for each atom in the residue. This specifies the
name of the atom and its atom type. name of the atom and its atom type.
* A :code:`<Bond>` tag for each pair of atoms that are bonded to each * A :code:`<Bond>` tag for each pair of atoms that are bonded to each
other. The :code:`to` and :code:`from` attributes are the indices of other. The :code:`atomName1` and :code:`atomName2` attributes are the names
the two bonded atoms (starting from 0) in the order they were listed. For of the two bonded atoms. (Some older force fields use the alternate tags
example, :code:`<Bond from="1" to="3"/>` describes a bond between atom CH3 :code:`to` and :code:`from` to specify the atoms by index instead of name.
and atom HH33. This is still supported for backward compatibility, but specifying atoms by
name is recommended, since it makes the residue definition much easier to
understand.)
* An :code:`<ExternalBond>` tag for each atom that will be bonded to an * An :code:`<ExternalBond>` tag for each atom that will be bonded to an
atom of a different residue. atom of a different residue. :code:`atomName` is the name of the atom.
(Alternatively, the deprecated :code:`from` tag may indicate the atom by
index instead of name.)
The :code:`<Residue>` tag may also contain :code:`<VirtualSite>` tags, The :code:`<Residue>` tag may also contain :code:`<VirtualSite>` tags,
...@@ -1926,21 +1930,24 @@ as in the following example: ...@@ -1926,21 +1930,24 @@ as in the following example:
<Atom name="H1" type="tip4pew-H"/> <Atom name="H1" type="tip4pew-H"/>
<Atom name="H2" type="tip4pew-H"/> <Atom name="H2" type="tip4pew-H"/>
<Atom name="M" type="tip4pew-M"/> <Atom name="M" type="tip4pew-M"/>
<VirtualSite type="average3" index="3" atom1="0" atom2="1" atom3="2" <VirtualSite type="average3" siteName="M" atomName1="O" atomName2="H1" atomName3="H2"
weight1="0.786646558" weight2="0.106676721" weight3="0.106676721"/> weight1="0.786646558" weight2="0.106676721" weight3="0.106676721"/>
<Bond from="0" to="1"/> <Bond atomName1="O" atomName2="H1"/>
<Bond from="0" to="2"/> <Bond atomName1="O" atomName2="H2"/>
</Residue> </Residue>
Each :code:`<VirtualSite>` tag indicates an atom in the residue that should Each :code:`<VirtualSite>` tag indicates an atom in the residue that should
be represented with a virtual site. The :code:`type` attribute may equal be represented with a virtual site. The :code:`type` attribute may equal
:code:`"average2"`\ , :code:`"average3"`\ , :code:`"outOfPlane"`\ , or :code:`"average2"`\ , :code:`"average3"`\ , :code:`"outOfPlane"`\ , or
:code:`"localCoords"`\ , which correspond to the TwoParticleAverageSite, ThreeParticleAverageSite, :code:`"localCoords"`\ , which correspond to the TwoParticleAverageSite, ThreeParticleAverageSite,
OutOfPlaneSite, and LocalCoordinatesSite classes respectively. The :code:`index` attribute gives the OutOfPlaneSite, and LocalCoordinatesSite classes respectively. The :code:`siteName`
index (starting from 0) of the atom to represent with a virtual site. The atoms attribute gives the name of the atom to represent with a virtual site. The atoms
it is calculated based on are specified by :code:`atom1`\ , :code:`atom2`\ , it is calculated based on are specified by :code:`atomName1`\ , :code:`atomName2`\ ,
and (for virtual site classes that involve three atoms) :code:`atom3`\ . The and (for virtual site classes that involve three atoms) :code:`atomName3`\ .
remaining attributes are specific to the virtual site class, and specify the (Some old force fields use the deprecated tags :code:`index`, :code:`atom1`,
:code:`atom2`, and :code:`atom3` to refer to them by index instead of name.)
The remaining attributes are specific to the virtual site class, and specify the
parameters for calculating the site position. For a TwoParticleAverageSite, parameters for calculating the site position. For a TwoParticleAverageSite,
they are :code:`weight1` and :code:`weight2`\ . For a they are :code:`weight1` and :code:`weight2`\ . For a
ThreeParticleAverageSite, they are :code:`weight1`\ , :code:`weight2`\ , and ThreeParticleAverageSite, they are :code:`weight1`\ , :code:`weight2`\ , and
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
<Atom name="O" type="spce-O"/> <Atom name="O" type="spce-O"/>
<Atom name="H1" type="spce-H"/> <Atom name="H1" type="spce-H"/>
<Atom name="H2" type="spce-H"/> <Atom name="H2" type="spce-H"/>
<Bond from="0" to="1"/> <Bond atomName1="O" atomName2="H1"/>
<Bond from="0" to="2"/> <Bond atomName1="O" atomName2="H2"/>
</Residue> </Residue>
</Residues> </Residues>
<HarmonicBondForce> <HarmonicBondForce>
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
<Atom name="O" type="tip3p-O"/> <Atom name="O" type="tip3p-O"/>
<Atom name="H1" type="tip3p-H"/> <Atom name="H1" type="tip3p-H"/>
<Atom name="H2" type="tip3p-H"/> <Atom name="H2" type="tip3p-H"/>
<Bond from="0" to="1"/> <Bond atomName1="O" atomName2="H1"/>
<Bond from="0" to="2"/> <Bond atomName1="O" atomName2="H2"/>
</Residue> </Residue>
</Residues> </Residues>
<HarmonicBondForce> <HarmonicBondForce>
......
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
<Atom name="H1" type="tip4pew-H"/> <Atom name="H1" type="tip4pew-H"/>
<Atom name="H2" type="tip4pew-H"/> <Atom name="H2" type="tip4pew-H"/>
<Atom name="M" type="tip4pew-M"/> <Atom name="M" type="tip4pew-M"/>
<VirtualSite type="average3" index="3" atom1="0" atom2="1" atom3="2" weight1="0.786646558" weight2="0.106676721" weight3="0.106676721"/> <VirtualSite type="average3" siteName="M" atomName1="O" atomName2="H1" atomName3="H2" weight1="0.786646558" weight2="0.106676721" weight3="0.106676721"/>
<Bond from="0" to="1"/> <Bond atomName1="O" atomName2="H1"/>
<Bond from="0" to="2"/> <Bond atomName1="O" atomName2="H2"/>
</Residue> </Residue>
</Residues> </Residues>
<HarmonicBondForce> <HarmonicBondForce>
......
...@@ -11,10 +11,10 @@ ...@@ -11,10 +11,10 @@
<Atom name="H2" type="tip5p-H"/> <Atom name="H2" type="tip5p-H"/>
<Atom name="M1" type="tip5p-M"/> <Atom name="M1" type="tip5p-M"/>
<Atom name="M2" type="tip5p-M"/> <Atom name="M2" type="tip5p-M"/>
<VirtualSite type="outOfPlane" index="3" atom1="0" atom2="1" atom3="2" weight12="-0.34490826" weight13="-0.34490826" weightCross="-6.4437903"/> <VirtualSite type="outOfPlane" siteName="M1" atomName1="O" atomName2="H1" atomName3="H2" weight12="-0.34490826" weight13="-0.34490826" weightCross="-6.4437903"/>
<VirtualSite type="outOfPlane" index="4" atom1="0" atom2="1" atom3="2" weight12="-0.34490826" weight13="-0.34490826" weightCross="6.4437903"/> <VirtualSite type="outOfPlane" siteName="M2" atomName1="O" atomName2="H1" atomName3="H2" weight12="-0.34490826" weight13="-0.34490826" weightCross="6.4437903"/>
<Bond from="0" to="1"/> <Bond atomName1="O" atomName2="H1"/>
<Bond from="0" to="2"/> <Bond atomName1="O" atomName2="H2"/>
</Residue> </Residue>
</Residues> </Residues>
<HarmonicBondForce> <HarmonicBondForce>
......
...@@ -153,17 +153,28 @@ class ForceField(object): ...@@ -153,17 +153,28 @@ class ForceField(object):
for residue in root.find('Residues').findall('Residue'): for residue in root.find('Residues').findall('Residue'):
resName = residue.attrib['name'] resName = residue.attrib['name']
template = ForceField._TemplateData(resName) template = ForceField._TemplateData(resName)
atomIndices = {}
for atom in residue.findall('Atom'): for atom in residue.findall('Atom'):
params = {} params = {}
for key in atom.attrib: for key in atom.attrib:
if key not in ('name', 'type'): if key not in ('name', 'type'):
params[key] = _convertParameterToNumber(atom.attrib[key]) params[key] = _convertParameterToNumber(atom.attrib[key])
template.atoms.append(ForceField._TemplateAtomData(atom.attrib['name'], atom.attrib['type'], self._atomTypes[atom.attrib['type']][2], params)) atomName = atom.attrib['name']
if atomName in atomIndices:
raise ValueError('Residue '+resName+' contains multiple atoms named '+atomName)
atomIndices[atomName] = len(template.atoms)
template.atoms.append(ForceField._TemplateAtomData(atomName, atom.attrib['type'], self._atomTypes[atom.attrib['type']][2], params))
for site in residue.findall('VirtualSite'): for site in residue.findall('VirtualSite'):
template.virtualSites.append(ForceField._VirtualSiteData(site)) template.virtualSites.append(ForceField._VirtualSiteData(site, atomIndices))
for bond in residue.findall('Bond'): for bond in residue.findall('Bond'):
if 'atomName1' in bond.attrib:
template.addBond(atomIndices[bond.attrib['atomName1']], atomIndices[bond.attrib['atomName2']])
else:
template.addBond(int(bond.attrib['from']), int(bond.attrib['to'])) template.addBond(int(bond.attrib['from']), int(bond.attrib['to']))
for bond in residue.findall('ExternalBond'): for bond in residue.findall('ExternalBond'):
if 'atomName' in bond.attrib:
b = atomIndices[bond.attrib['atomName']]
else:
b = int(bond.attrib['from']) b = int(bond.attrib['from'])
template.externalBonds.append(b) template.externalBonds.append(b)
template.atoms[b].externalBonds += 1 template.atoms[b].externalBonds += 1
...@@ -320,27 +331,32 @@ class ForceField(object): ...@@ -320,27 +331,32 @@ class ForceField(object):
class _VirtualSiteData: class _VirtualSiteData:
"""Inner class used to encapsulate data about a virtual site.""" """Inner class used to encapsulate data about a virtual site."""
def __init__(self, node): def __init__(self, node, atomIndices):
attrib = node.attrib attrib = node.attrib
self.index = int(attrib['index'])
self.type = attrib['type'] self.type = attrib['type']
if self.type == 'average2': if self.type == 'average2':
self.atoms = [int(attrib['atom1']), int(attrib['atom2'])] numAtoms = 2
self.weights = [float(attrib['weight1']), float(attrib['weight2'])] self.weights = [float(attrib['weight1']), float(attrib['weight2'])]
elif self.type == 'average3': elif self.type == 'average3':
self.atoms = [int(attrib['atom1']), int(attrib['atom2']), int(attrib['atom3'])] numAtoms = 3
self.weights = [float(attrib['weight1']), float(attrib['weight2']), float(attrib['weight3'])] self.weights = [float(attrib['weight1']), float(attrib['weight2']), float(attrib['weight3'])]
elif self.type == 'outOfPlane': elif self.type == 'outOfPlane':
self.atoms = [int(attrib['atom1']), int(attrib['atom2']), int(attrib['atom3'])] numAtoms = 3
self.weights = [float(attrib['weight12']), float(attrib['weight13']), float(attrib['weightCross'])] self.weights = [float(attrib['weight12']), float(attrib['weight13']), float(attrib['weightCross'])]
elif self.type == 'localCoords': elif self.type == 'localCoords':
self.atoms = [int(attrib['atom1']), int(attrib['atom2']), int(attrib['atom3'])] numAtoms = 3
self.originWeights = [float(attrib['wo1']), float(attrib['wo2']), float(attrib['wo3'])] self.originWeights = [float(attrib['wo1']), float(attrib['wo2']), float(attrib['wo3'])]
self.xWeights = [float(attrib['wx1']), float(attrib['wx2']), float(attrib['wx3'])] self.xWeights = [float(attrib['wx1']), float(attrib['wx2']), float(attrib['wx3'])]
self.yWeights = [float(attrib['wy1']), float(attrib['wy2']), float(attrib['wy3'])] self.yWeights = [float(attrib['wy1']), float(attrib['wy2']), float(attrib['wy3'])]
self.localPos = [float(attrib['p1']), float(attrib['p2']), float(attrib['p3'])] self.localPos = [float(attrib['p1']), float(attrib['p2']), float(attrib['p3'])]
else: else:
raise ValueError('Unknown virtual site type: %s' % self.type) raise ValueError('Unknown virtual site type: %s' % self.type)
if 'siteName' in attrib:
self.index = atomIndices[attrib['siteName']]
self.atoms = [atomIndices[attrib['atomName%d'%(i+1)]] for i in range(numAtoms)]
else:
self.index = int(attrib['index'])
self.atoms = [int(attrib['atom%d'%(i+1)]) for i in range(numAtoms)]
if 'excludeWith' in attrib: if 'excludeWith' in attrib:
self.excludeWith = int(attrib['excludeWith']) self.excludeWith = int(attrib['excludeWith'])
else: else:
......
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