AtomGroup¶
A Universe
contains all particles in the molecular system. MDAnalysis calls a particle an Atom
, regardless of whether it really is (e.g. it may be a united-atom particle or coarse-grained bead). Atom
s are grouped with an AtomGroup
; the ‘master’ AtomGroup
of a Universe is accessible at Universe.atoms
.
Note
The AtomGroup
is probably the most important object in MDAnalysis. Virtually everything can be accessed through an AtomGroup
.
Creating an AtomGroup¶
Atom selection language¶
AtomGroup instances are typically created with Universe.select_atoms
or by manipulating another AtomGroup
, e.g. by slicing.
In [1]: import MDAnalysis as mda
In [2]: from MDAnalysis.tests.datafiles import PDB
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-1af40771f7a7> in <module>
----> 1 from MDAnalysis.tests.datafiles import PDB
~/checkouts/readthedocs.org/user_builds/mdauserguide/conda/rms-1.0/lib/python3.8/site-packages/MDAnalysis/tests/datafiles.py in <module>
41
42 try:
---> 43 from MDAnalysisTests.datafiles import *
44 except ImportError:
45 print("*** ERROR ***")
~/checkouts/readthedocs.org/user_builds/mdauserguide/conda/rms-1.0/lib/python3.8/site-packages/MDAnalysisTests/__init__.py in <module>
124 try:
125 import matplotlib
--> 126 matplotlib.use('agg', warn=False)
127 except ImportError:
128 pass
TypeError: use() got an unexpected keyword argument 'warn'
In [3]: u = mda.Universe(PDB)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-3-d282fce7308e> in <module>
----> 1 u = mda.Universe(PDB)
NameError: name 'PDB' is not defined
In [4]: u.select_atoms('resname ARG')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-4-06dd7984b0cf> in <module>
----> 1 u.select_atoms('resname ARG')
NameError: name 'u' is not defined
See Atom selection language for more information.
Indexing and slicing¶
An AtomGroup
can be indexed and sliced like a list:
In [5]: print(u.atoms[0])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-5-7c40b0468243> in <module>
----> 1 print(u.atoms[0])
NameError: name 'u' is not defined
Slicing returns another AtomGroup
. The below code returns an AtomGroup
of every second element from the first to the 6th element, corresponding to indices 0, 2, and 4.
In [6]: ag = u.atoms[0:6:2]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-6-8c4d802e0de2> in <module>
----> 1 ag = u.atoms[0:6:2]
NameError: name 'u' is not defined
In [7]: ag.indices
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-7-4647456c5040> in <module>
----> 1 ag.indices
NameError: name 'ag' is not defined
MDAnalysis also supports fancy indexing: passing a ndarray
or a list
.
In [8]: indices = [0, 3, -1, 10, 3]
In [9]: u.atoms[indices].indices
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-9-d6abd0bb4889> in <module>
----> 1 u.atoms[indices].indices
NameError: name 'u' is not defined
Boolean indexing allows you to pass in an array of True
or False
values to create a new AtomGroup
from another. The array must be the same length as the original AtomGroup
. This allows you to select atoms on conditions.
In [10]: arr = u.atoms.resnames == 'ARG'
In [11]: len(arr) == len(u.atoms)
In [12]: arr
Out[12]: Out[11]: array([False, False, False, ..., False, False, False])
In [13]: u.atoms[arr]
Group operators and set methods¶
MDAnalysis supports a number of ways to compare AtomGroup
s or construct a new one: group operators (e.g. concatenate()
, subtract()
) and set methods (e.g. union()
, difference()
). Group operators achieve a similar outcome to set methods. However, a key difference is that concatenate()
and subtract()
preserve the order of the atoms and any duplicates. union()
and difference()
return an AtomGroup
where each atom is unique, and ordered by its topology index.
In [14]: ag1 = u.atoms[1:6]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-14-d43729ffd1d4> in <module>
----> 1 ag1 = u.atoms[1:6]
NameError: name 'u' is not defined
In [15]: ag2 = u.atoms[8:3:-1]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-15-9e2b4f98e768> in <module>
----> 1 ag2 = u.atoms[8:3:-1]
NameError: name 'u' is not defined
In [16]: concat = ag1 + ag2
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-16-a7cf5435d978> in <module>
----> 1 concat = ag1 + ag2
NameError: name 'ag1' is not defined
In [17]: concat.indices
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-17-9e98c66f6ef6> in <module>
----> 1 concat.indices
NameError: name 'concat' is not defined
In [18]: union = ag1 | ag2
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-18-5933e3b4946c> in <module>
----> 1 union = ag1 | ag2
NameError: name 'ag1' is not defined
In [19]: union.indices
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-19-904e38f6cd07> in <module>
----> 1 union.indices
NameError: name 'union' is not defined
Available operators
Unlike set methods and atom selection language, concatenation and subtraction keep the order of the atoms as well as duplicates.
Operation |
Equivalent |
Result |
---|---|---|
|
number of atoms in the group |
|
|
test if |
|
|
|
new Group with elements
from |
|
new Group with elements
from |
Available set methods
Each of these methods create groups that are sorted sets of unique Atom
s.
Operation |
Equivalent |
Result |
---|---|---|
|
|
|
|
test if all elements of
|
|
|
test if all elements of
|
|
|
test if all elements of
|
|
|
test if all elements of
|
|
|
|
new Group with elements
from both |
|
|
new Group with elements
common to |
|
|
new Group with elements of
|
|
|
new Group with elements
that are part of |
Groupby and split¶
An AtomGroup
can be constructed from another by separating atoms by properties.
AtomGroup.split
can create a list of AtomGroup
s by splitting another AtomGroup
by the ‘level’ of connectivity: one of atom, residue, molecule, or segment.
In [20]: ag1 = u.atoms[:100]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-20-0ca8a4466d33> in <module>
----> 1 ag1 = u.atoms[:100]
NameError: name 'u' is not defined
In [21]: ag1.split('residue')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-21-cac78030a317> in <module>
----> 1 ag1.split('residue')
NameError: name 'ag1' is not defined
An AtomGroup
can also be separated according to values of topology attributes to produce a dictionary of {value:AtomGroup}
.
In [22]: u.atoms.groupby('masses')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-22-84426c808b49> in <module>
----> 1 u.atoms.groupby('masses')
NameError: name 'u' is not defined
Passing in multiple attributes groups them in order:
In [23]: u.select_atoms('resname SOL NA+').groupby(['masses', 'resnames'])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-23-eb03c8faaaeb> in <module>
----> 1 u.select_atoms('resname SOL NA+').groupby(['masses', 'resnames'])
NameError: name 'u' is not defined
Constructing from Atoms¶
An AtomGroup
can be created from an iterable of Atom
instances:
In [24]: atom1 = u.atoms[4]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-24-f0566366e4ae> in <module>
----> 1 atom1 = u.atoms[4]
NameError: name 'u' is not defined
In [25]: atom2 = u.atoms[6]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-25-c8b5bad5021e> in <module>
----> 1 atom2 = u.atoms[6]
NameError: name 'u' is not defined
In [26]: atom3 = u.atoms[2]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-26-34c1f3934f08> in <module>
----> 1 atom3 = u.atoms[2]
NameError: name 'u' is not defined
In [27]: ag = mda.AtomGroup([atom1, atom2, atom3])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-27-5521d34591bf> in <module>
----> 1 ag = mda.AtomGroup([atom1, atom2, atom3])
NameError: name 'atom1' is not defined
In [28]: print(ag)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-28-ffcd2afdaec3> in <module>
----> 1 print(ag)
NameError: name 'ag' is not defined
A neat shortcut for this is to simply add an Atom
to another Atom
or AtomGroup
:
In [29]: ag = atom1 + atom2
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-29-d81c3d44e3e6> in <module>
----> 1 ag = atom1 + atom2
NameError: name 'atom1' is not defined
In [30]: print(ag)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-30-ffcd2afdaec3> in <module>
----> 1 print(ag)
NameError: name 'ag' is not defined
In [31]: ag += atom3
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-31-a298d774d9c3> in <module>
----> 1 ag += atom3
NameError: name 'ag' is not defined
In [32]: print(ag)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-32-ffcd2afdaec3> in <module>
----> 1 print(ag)
NameError: name 'ag' is not defined
An alternative method is to provide a list of indices and the Universe that the Atom
s belong to:
In [33]: ag = mda.AtomGroup([4, 6, 2], u)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-33-1a70539b93f3> in <module>
----> 1 ag = mda.AtomGroup([4, 6, 2], u)
NameError: name 'u' is not defined
In [34]: print(ag)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-34-ffcd2afdaec3> in <module>
----> 1 print(ag)
NameError: name 'ag' is not defined
Order and uniqueness¶
These methods of creating an AtomGroup
result in a sorted, unique list of atoms:
Atom selection language
Slicing
Boolean indexing
Set methods
These methods return a user-ordered AtomGroup
that can contain duplicates:
Fancy indexing (with arrays or lists)
Group operations (
AtomGroup.concatenate
andAtomGroup.subtract
)Constructing directly from
Atom
s
Empty AtomGroups¶
MDAnalysis can also work with empty AtomGroups:
In [35]: null = u.atoms[[]]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-35-24450a88ec32> in <module>
----> 1 null = u.atoms[[]]
NameError: name 'u' is not defined
In [36]: null
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-36-d910b0287107> in <module>
----> 1 null
NameError: name 'null' is not defined
The above is the same as creating an AtomGroup
from an empty list and a Universe
.
In [37]: mda.AtomGroup([], u)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-37-8cb851cc070f> in <module>
----> 1 mda.AtomGroup([], u)
NameError: name 'u' is not defined
Each method of creating an AtomGroup can also be used to create an empty one. For example, using selection language:
In [38]: u.select_atoms("resname DOES_NOT_EXIST")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-38-c7b2283a4137> in <module>
----> 1 u.select_atoms("resname DOES_NOT_EXIST")
NameError: name 'u' is not defined
and indexing:
In [39]: u.atoms[6:6]
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-39-90d4d68136fa> in <module>
----> 1 u.atoms[6:6]
NameError: name 'u' is not defined
or set methods:
In [40]: u.atoms - u.atoms
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-40-bd3056daf1d1> in <module>
----> 1 u.atoms - u.atoms
NameError: name 'u' is not defined
Empty AtomGroups have a length of 0 and evaluate to False
in a boolean context.
In [41]: bool(null)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-41-d10f2c52cdaa> in <module>
----> 1 bool(null)
NameError: name 'null' is not defined
This allows analysis methods to skip over empty AtomGroups instead of raising an error, which is helpful as occasionally empty AtomGroups can arise from selection logic that is too restrictive (e.g. geometric selections).
Dynamically updating AtomGroups¶
A normal AtomGroup is static, and the atoms within it do not change as the trajectory frame changes. Several methods require dynamically updating AtomGroups. These are typically created using atom selection language. See Dynamic selections for more information.
Methods¶
Most of the analysis functionality in MDAnalysis is implemented in the analysis module, but many interesting methods can be accessed from an AtomGroup
directly. For example, Bonds, Angles, Dihedrals and ImproperDihedrals can be created from AtomGroups. Providing that required topology attributes are present, a number of analysis methods are also available to a AtomGroup
, ResidueGroup
, and SegmentGroup
.