The topologyobjects module

The topologyobjects module contains a wide array of classes used extensively in the core structure.Structure class.

Atom([list, atomic_number, name, type, ...]) An atom.
Residue(name[, number, chain, ...]) A single residue that is composed of a small number of atoms
AtomList(\*args) Array of Atoms
ResidueList(\*args) Array of Residue instances
Bond(atom1, atom2[, type, order]) A covalent bond connecting two atoms.
Angle(atom1, atom2, atom3[, type]) A valence angle between 3 atoms separated by two covalent bonds.
UreyBradley(atom1, atom2[, type]) A Urey-Bradley angle type with a set of parameters.
Dihedral(atom1, atom2, atom3, atom4[, ...]) A valence dihedral between 4 atoms separated by three covalent bonds.
Improper(atom1, atom2, atom3, atom4[, type]) A CHARMM-style improper torsion between 4 atoms.
Cmap(atom1, atom2, atom3, atom4, atom5[, type]) A coupled-torsion correction map term defined between 5 atoms connected by four covalent bonds.
AtomType(name, number, mass[, ...]) Atom types can either be compared by indexes or names.
BondType(k, req[, list]) A bond type with a set of bond parameters
AngleType(k, theteq[, list]) An angle type with a set of angle parameters
DihedralType(phi_k, per, phase[, scee, ...]) A dihedral type with a set of dihedral parameters
DihedralTypeList(\*args, \*\*kwargs) Dihedral types are a Fourier expansion of terms.
ImproperType(psi_k, psi_eq[, list]) An improper type with a set of improper torsion parameters

Using the Atom class

The Atom class behaves much as you would expect it to. It has various attributes, including the name of the atom, the type of the atom, its mass, atomic_number, and many other properties typically stored in one of the supported file formats. For example:

>>> atom = Atom(name="CA", mass=12.01, type="CT", atomic_number=12)
>>> atom.name
'CA'
>>> atom.type
'CT'
>>> atom.atomic_number
12
>>> atom.mass
12.01
  • It also stores references to all of the parameter types in which this belongs. For instance, the bonds, angles, dihedrals, impropers, and cmaps attributes are lists of references to the Bond, Angle, Dihedral, Improper, and Cmap instances in which this atom is a member.
  • Instances of Atom should be considered singletons – that is, their equality is based on identity. As such, you should use the is operator rather than == when comparing the equality of two atoms. In fact, Atom.__eq__ is not implemented at all, so it works the same way that is does in this case. This is an important distinction, because it makes Atom instances hashable, meaning that they can serve as keys in a dict or can be added to a set.
  • Atom ordering is determined based on positions within a particular AtomList. When an Atom belongs to an AtomList, it knows its absolute position within that list via the idx attribute (which is set to -1 if the Atom is not part of an AtomList). The idx attribute is automatically updated if the parent AtomList is changed in any way (e.g., some atoms are deleted or inserted). This allows sublists of Atom instances to be sorted according to their order in their main AtomList. (Note, each Atom can belong to no more than one AtomList)
  • Atoms store lists of other Atom instances that are connected to that atom via covalent bonds, angles, torsions, or coupled-torsions maps in the bond_partners, angle_partners, dihedral_partners, and tortor_partners, respectively. These are primarily used to determine pairs of atoms that are excluded from a nonbonded interaction in traditional force fields. There is an additional exclusion_partners array that contains a list of arbitrary pairs of atoms that are not connected by any of the valence terms mentioned above. Each atom can appear in one, and only one list of another atom, with preference given to the “partner” arrays in the order they were listed above. Membership in these arrays is always symmetric—that is, if one atom is in the bond_partners array of another, that other atom is also in the bond_partners array of the first. These lists are populated automatically when the relevant valence terms are created (see below).

You will typically not have to instantiate an Atom or AtomList instance on your own, as they are created as part of a structure.Structure instance created by the various structure file parsers.

Using the Residue class

The Residue class is an object that represents a typical residue in a biomolecular system. Examples include a single amino or nucleic acid in a peptide or nucleotide chain. A Residue is a collection of atoms, each of which is connected to the other ones through a network of bonds (and may be bonded to other residues as well, although that is not required).

Residues have 4 primary attributes of general use:

  • name : The name of the residue
  • chain : The chain identifier of the residue (a common identifier in the PDB)
  • insertion_code : Also used as part of the PDB, these are primarily used to align homologous sequences when some homologies have an extra residue compared to the other(s)
  • atoms : A list of Atom instances contained within the residue

Residues are uniquely identified by their name, chain, and insertion_code within a single system.

Common things you can do with a Residue

In the following code sample, assume atom is an instance of Atom which is one of the atoms inside residue (an instance of Residue).

  1. Iterate through the atoms:

    for atom in residue:
        print(atom.name)
    
  2. Get the i’th atom from a residue:

    atomI = residue[i]
    
  3. Determine if an atom is part of a residue:

    if atom in residue:
        print("Atom %s is inside residue %s" % (atom.name, residue.name))
    
  4. Find out how many atoms are in a residue:

    n_atoms_in_res = len(residue)
    
  5. Add an atom to a residue:

    residue.add_atom(atom)
    assert atom in residue
    
  6. Delete an atom from a residue:

    residue.delete_atom(atom)
    assert atom not in residue
    

The AtomList class

AtomList is a subclass of the basic Python list type, with some added features:

  • The AtomList claims ownership of any Atom added to it and sets the idx attribute of each of the atoms to their position in the array. Atoms should never be part of multiple AtomList instances.
  • The AtomList has a changed attribute that is set to True any time the list is changed (i.e., if an atom is added, deleted, inserted, moved, etc.) – you must manaully set this changed attribute to False afterwards if you wish to track any future changes.

This class is also typically instantiated by the structure.Structure parsers (e.g., structure.read_PDB(), structure.read_CIF(), ...)

The ResidueList class

ResidueList is also a subclass of list with some added features of its own:

  • The ResidueList contains a list of Residue instances, and sets the idx attribute on them to point to their current location in the list.

  • Atoms can be added directly to the residue list. This is done because most file formats list atoms sequentially, and the beginning and end of each residue is detected by either the residue name, number, chain ID, or insertion code changing. As long as these residue properties are the same as the last Atom instance you added, the atom will be added to that last residue. If it is a new residue, ResidueList will create a new Residue object, append it to itself, and add that atom to it. For example:

    >>> residues = ResidueList()
    >>> residues.add_atom(Atom(name='C1'), 'RE1', 1, 'A')
    >>> residues.add_atom(Atom(name='C2'), 'RE1', 1, 'A')
    >>> residues.add_atom(Atom(name='C3'), 'RE1', 1, 'A')
    >>> residues.add_atom(Atom(name='C4'), 'RE2', 2, 'A') # new residue
    >>> residues.add_atom(Atom(name='C5'), 'RE2', 3, 'A') # new residue
    >>> len(residues)
    3
    >>> len(residues[0])
    3
    >>> len(residues[1])
    1
    >>> len(residues[2])
    1
    

The Bond class

The covalent bond is the simplest of topological features in a molecule. The Bond class represents a covalent bonds between two Atom instances. Creating a Bond between two Atom instances adds the resulting Bond to the bonds list of both atoms. It also adds each atom to the bond_partners list of the other atom. For example:

>>> a1 = Atom(name='CA')
>>> a2 = Atom(name='CB')
>>> bond = Bond(a1, a2)
>>> a1.bonds[0] is bond
True
>>> a2.bonds[0] is bond
True
>>> a2 in a1.bond_partners
True
>>> a1 in a2.bond_partners
True

Bonds can also contain Atom instances. Continuing from the example above:

>>> a1 in bond
True
>>> a2 in bond
True
>>> a3 = Atom(name='HA')
>>> a3 in bond
False

Bonds are unique valence terms since they are the simplest of valence terms. Other valence terms (described below) can contain both Atom and Bond instances.

The ordering of the two atoms in the Bond constructor does not matter, as the bond a1--a2 and a2--a1 are equivalent.

The Angle class

The valence angle is formed from two adjacent bonds that form a common center. The Angle class represents a valence angle between 3 atoms in which two of the three atoms are bonded to a central atom. In this case, the order of the middle atom in the constructor matters, but the order of the outer atoms does not. For example:

>>> a1 = Atom(name='CA')
>>> a2 = Atom(name='CB')
>>> a3 = Atom(name='CG')
>>> b1 = Bond(a1, a2)
>>> b2 = Bond(a2, a3)
>>> b3 = Bond(a1, a3) # let's make this a triangle
>>> angle = Angle(a1, a2, a3)

In the above example, our angle is formed between the bonds a1--a2--a3, so angle contains the three atoms as well as b1 and b2, but not b3:

>>> a1 in angle
True
>>> a2 in angle
True
>>> a3 in angle
True
>>> b1 in angle
True
>>> b2 in angle
True
>>> b3 in angle
False

Like with the Bond class, creating an Angle adds the created angle to the angles list on all three of the atoms. Furthermore, the angle_partners attribute of a1 and a3 have a3 and a1 added to them, respectively. As mentioned above, the same Atom instance will never appear in two xxx_partners arrays. For example:

>>> a1 in a3.angle_partners
True
>>> a1 in a3.bond_partners
False
>>> a1 in a2.bond_partners
True
>>> a1 in a3.angle_partners
False

The UreyBradley class

The UreyBradley class defines a covalent bond-like interaction between two atoms separated by a valence angle, adding anharmonicity to purely harmonic angle terms. The interface to UreyBradley terms is analogous to those for Bond and Angle above.

The Dihedral class

The Dihedral class follows the same trend as the Angle class described above, and behaves in an analogous way. There are a couple unique aspects to Dihedrals, though. A Dihedral can be an improper dihedral (in which all 4 atoms are ideally coplanar, with the third atom being the “central” atom bonded to all of the others). The Dihedral instance has a boolean attribute improper that indicates whether or not it is an improper torsion.

The Improper class

The Improper class is strictly an improper torsion, and is used where certain force fields utilize a separate functional form for “proper” and “improper” torsions (e.g., the CHARMM force field). You are forwarded to the API documentation for Improper for more details.

The Cmap class

The Cmap class is a correction map defined between adjacent torsions (i.e., 5 atoms separated by 4 bonds). Like the other valence terms described above, it contains 5 Atom instances and may contain 4 Bond instances (as tested via the in operator). See the API documentation for Cmap for more details.

The XyzType classes

Every valence term described above contains a type attribute that is either None if unassigned or the relevant ParameterType (e.g., BondType for Bond and UreyBradley classes) instance. Certain functionality (e.g., simulations using OpenMM or writing Amber topology files) requires all parameters be present and assigned. These types have, where applicable, force constants and equilibrium values for the various parameter types.

Amoeba-specific terms

The AMOEBA force field has nominal support in ParmEd (with improved support planned). This force field contains a large number of additional terms and parameters for use with the AMOEBA force field. For convenience, they are listed below. Consult the API documentation in the resulting links for more information.

TrigonalAngle(atom1, atom2, atom3, atom4[, type]) A trigonal-angle term in the AMOEBA force field.
OutOfPlaneBend(atom1, atom2, atom3, atom4[, ...]) Out-of-plane bending term in the AMOEBA force field.
OutOfPlaneBendType(k[, list]) An angle type with a set of angle parameters
PiTorsion(atom1, atom2, atom3, atom4, atom5, ...) Defines a pi-torsion term in the AMOEBA force field.
StretchBend(atom1, atom2, atom3[, type]) This term models the stretching and bending of a standard valence angle, and
StretchBendType(k1, k2, req1, req2, theteq) A stretch-bend type with two distances and an angle in AMOEBA
TorsionTorsion(atom1, atom2, atom3, atom4, atom5) This is a coupled-torsion map used in the AMOEBA force field similar to the
TorsionTorsionType(dims, ang1, ang2, f[, ...]) The type containing the parameter maps for the Amoeba torsion-torsion potentials.
ChiralFrame(atom1, atom2, chirality) A chiral frame as defined in the AMOEBA force field.
MultipoleFrame(atom, frame_pt_num, vectail, ...) This defines the frame of reference for computing multipole interactions in the AMOEBA force field.
NonbondedException(atom1, atom2[, type]) The AMOEBA force field has complex exclusion and exception rules (referred to as “adjustments” in the Amber-converted files).
NonbondedExceptionType(rmin, epsilon[, ...]) A parameter describing how the various nonbonded interactions between a