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). Atoms 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 AtomGroups 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

len(s)

number of atoms in the group

s == t

test if s and t contain the same elements in the same order

s.concatenate(t)

s + t

new Group with elements from s and from t

s.subtract(t)

new Group with elements from s that are not in t

Available set methods

Each of these methods create groups that are sorted sets of unique Atoms.

Operation

Equivalent

Result

s.isdisjoint(t)

True if s and t do not share elements

s.issubset(t)

test if all elements of s are part of t

s.is_strict_subset(t)

test if all elements of s are part of t, and s != t

s.issuperset(t)

test if all elements of t are part of s

s.is_strict_superset(t)

test if all elements of t are part of s, and s != t

s.union(t)

s | t

new Group with elements from both s and t

s.intersection(t)

s & t

new Group with elements common to s and t

s.difference(t)

s - t

new Group with elements of s that are not in t

s.symmetric_difference(t)

s ^ t

new Group with elements that are part of s or t but not both

Groupby and split

An AtomGroup can be constructed from another by separating atoms by properties.

AtomGroup.split can create a list of AtomGroups 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 Atoms 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:

These methods return a user-ordered AtomGroup that can contain duplicates:

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.