Residue, Chain and Segment Properties

Residues, chains and segments can also have their own properties.

Residue properties

For example, we will now create a new residue property that holds the radius of each residue. First, let’s load the molecules again.

>>> import sire as sr
>>> mols = sr.load(sr.expand(sr.tutorial_url, ["ala.top", "ala.crd"]))
>>> mol = mols[0]

Now, we will use a cursor to add a residue_center property to each residue.

>>> cursor = mol.cursor()
>>> for residue in cursor.residues():
...     center = residue.evaluate().center_of_mass()
...     residue["residue_center"] = center
>>> mol = cursor.commit()
>>> print(mol.property("residue_center"))
SireMol::ResPropertyProperty( size=3
0: ( 18.9264, 4.47803, 14.1498 )
1: ( 16.0195, 4.60992, 15.5812 )
2: ( 14.3873, 4.27636, 18.0041 )
)

Note

Calling .evaluate() on a molecule view or on a Cursor will return a sire.mol.Evaluator for that view. This can be used to evaluate a number of things that are derived from the molecular properties. In this case, center_of_mass evaluates the center of mass of the atoms in the view, based on the atoms coordinates and mass properties.

We will also add a radius for each residue. We will do this by calling sire.mol.Evaluator.radius() and passing in the center calculated above.

We could do this either via a loop…

>>> cursor = mol.cursor()
>>> for residue in cursor.residues():
...    residue["residue_radius"] = residue.evaluate().radius(residue["residue_center"])
>>> mol = cursor.commit()
>>> print(mol.property("residue_radius"))

…or via apply and a lambda expression…

>>> mol = mol.residues().cursor().apply(
...         lambda res: res.set("residue_radius",
...                             res.evaluate().radius(res["residue_center"]))
...  ).commit()
>>> print(mol.property("residue_radius"))

Residue properties are a lot like atom properties. They behave like a list, with one value per residue (in residue index order). Default-constructed values are used for residues that don’t have a property set.

Chain properties

Chain properties work in the same way as residue properties. For example, load up protein 7SA1.

>>> mols = sr.load("7SA1")
>>> mol = mols[0]

We will loop over each chain, adding in a sphere property that contains a bounding sphere for the entire chain.

We could do this via a loop…

>>> cursor = mol.cursor()
>>> for chain in cursor.chains():
...     chain["sphere"] = chain.evaluate().bounding_sphere()
>>> mol = cursor.commit()
>>> print(mol.property("sphere"))
SireMol::ChainPropertyProperty( size=4
0: Sphere( center() == ( -44.5915, 10.0365, 16.132 ), radius == 40.2531 )
1: Sphere( center() == ( -31.0725, 27.279, 3.387 ), radius == 65.6821 )
2: Sphere( center() == ( -5.827, 22.1885, 49.5585 ), radius == 40.2047 )
3: Sphere( center() == ( 6.3375, 5.929, 31.511 ), radius == 65.5556 )
)

…or via an apply

>>> mol = mol.chains().cursor().apply(
...        lambda chain: chain.set("sphere",
...                                chain.evaluate().bounding_sphere())
...       ).commit()
>>> print(mol.property("sphere"))
SireMol::ChainPropertyProperty( size=4
0: Sphere( center() == ( -44.5915, 10.0365, 16.132 ), radius == 40.2531 )
1: Sphere( center() == ( -31.0725, 27.279, 3.387 ), radius == 65.6821 )
2: Sphere( center() == ( -5.827, 22.1885, 49.5585 ), radius == 40.2047 )
3: Sphere( center() == ( 6.3375, 5.929, 31.511 ), radius == 65.5556 )
)

Chain properties behave identically to residue properties, i.e. like a list with one value per chain, in chain index order. Default-constructed values are used for chains that don’t have a property set.

Segment properties

Segment properties behave exactly like residue and chain properties. To demonstrate this, load up alanin again…

>>> mols = sr.load(sr.expand(sr.tutorial_url, "alanin.psf"))
>>> mol = mols[0]

We will now add a property to the segments that is the number of atoms in that segment. Again, we can do this via a loop…

>>> cursor = mol.cursor()
>>> for segment in cursor.segments():
...     segment["seg_atom_count"] = segment.view().num_atoms()
>>> mol = cursor.commit()
>>> print(mol.property("seg_atom_count"))
SireMol::SegIntProperty( size=1
0: 66
)

…or via an apply

>>> mol = mol.segments().cursor().apply(
...     lambda seg: seg.set("seg_atom_count", seg.view().num_atoms())
...   ).commit()
>>> print(mol.property("seg_atom_count"))
SireMol::SegIntProperty( size=1
0: 66
)

Note

Note how we use cursor.view() to gain access to the view on which the cursor is operating. This is useful to call functions on that view, e.g. segment.num_atoms() in this case.

Segment properties behave identically to chain and residue properties, i.e. like a list with one value per segment, in segment index order. Default-constructed values are used for segments that don’t have a property set.