Module 8: Extracting Molecular Attributes#
Welcome back, Apprentice Master. In Module 7: Selection Mechanism, you mastered how to build query expressions to target specific subsets of a molecular system. Now, we couple those selection queries with MolSysMT’s primary extraction engine: msm.get().
While msm.info() is designed for human inspection via formatted tables, msm.get() is engineered for programmatic data extraction and hierarchical navigation. It converts internal data structures into clean Python primitives, lists, NumPy arrays, physical quantities, covalent bond matrices, and relational mappings that can be passed directly to data science libraries like numpy, scipy, pandas, or scikit-learn.
Learning Outcomes
By the end of this module, you will be able to:
Extract single attributes into direct Python primitives and NumPy arrays.
Extract multiple attributes simultaneously using structured tuple unpacking.
Retrieve spatial coordinate tensors with shape
(n_structures, n_atoms, 3).Extract periodic box vectors, angles, and volumes.
Extract the covalent bond connectivity matrix (
bonded_atom_pairs=True).Map upwards from child elements (e.g. atoms) to parent elements (groups, chains, entities).
Map downwards from parent elements (e.g. entities, chains) to constituent atoms.
Extract cross-level counts and structural summaries.
1. Extracting Single Attributes#
Let’s begin by importing MolSysMT and NumPy, and loading our T4 Lysozyme demonstration system.
import molsysmt as msm
from molsysmt import systems
import numpy as np
# Load T4 Lysozyme file
lysozyme = systems['T4 lysozyme L99A']['181l.bcif.gz']
When you request a single attribute from msm.get(), it returns that property directly without wrapping it in a tuple.
Let’s query the names of the first 5 atoms and the total number of atoms in the system:
# Get atom names for the first 5 atoms
names = msm.get(lysozyme, selection=[0, 1, 2, 3, 4], atom_name=True)
print(f"First 5 atom names: {names}")
# Get the total number of atoms
n_atoms = msm.get(lysozyme, element='system', n_atoms=True)
print(f"Total system atoms: {n_atoms}")
First 5 atom names: ['N', 'CA', 'C', 'O', 'CB']
Total system atoms: 1441
Hint
msm.get(): Form-agnostic attribute extraction engine. Converts internal data into Python lists, NumPy arrays, or scalar primitives. See API doc: molsysmt.basic.get().
2. Extracting Multiple Attributes#
When you request multiple attributes in a single msm.get() call, it returns a tuple containing the requested properties in the exact order specified in your function call.
# Extract atom_id, atom_name, and atom_type for specific atom indices
ids, names, types = msm.get(lysozyme, selection=[10, 20, 30], atom_id=True, atom_name=True, atom_type=True)
for atom_id, name, atom_type in zip(ids, names, types):
print(f"ID: {atom_id:>4} | Name: {name:<4} | Type: {atom_type}")
ID: 11 | Name: C | Type: C
ID: 21 | Name: CB | Type: C
ID: 31 | Name: CD1 | Type: C
3. Extracting Coordinate Tensors#
Coordinates are the most frequently extracted structural attribute. As established in Module 2, coordinates are returned as a 3D NumPy array with shape (n_structures, n_atoms, 3).
Let’s extract the coordinates of all protein atoms and compute their geometric center using numpy.mean():
# Extract coordinates of all protein atoms
coords = msm.get(lysozyme, selection='molecule_type == "protein"', coordinates=True)
print(f"Coordinates array shape: {coords.shape} (n_structures, n_atoms, spatial:x,y,z)")
# Compute geometric center of protein atoms across structure 0
center = np.mean(coords[0], axis=0)
print(f"Geometric center (X, Y, Z) in nanometers: {center}")
Coordinates array shape: (1, 1289, 3) (n_structures, n_atoms, spatial:x,y,z)
Geometric center (X, Y, Z) in nanometers: [3.4858737781225804 1.1384903801396447 0.9543625290923174] nanometer
4. Extracting Periodic Box Properties#
When a molecular system includes periodic boundary conditions, msm.get() can derive its box vectors, lengths, angles, and volume:
# Extract box lengths, angles, and volume
lengths, angles, volume = msm.get(
lysozyme,
element='system',
box_lengths=True,
box_angles=True,
box_volume=True
)
print(f"Box lengths: {lengths}")
print(f"Box angles : {angles}")
print(f"Box volume : {volume}")
Box lengths: [[6.09 6.09 9.7]] nanometer
Box angles : [[1.570796 1.570796 2.094395]] radian
Box volume : [311.55659621309997] nanometer ** 3
5. Extracting Covalent Bonds#
You can extract the full matrix of covalent bond pairs using msm.get() with bonded_atom_pairs=True:
# Retrieve bonded atom index pairs
bonds = msm.get(lysozyme, element='system', bonded_atom_pairs=True)
print(f"Total covalent bonds in system: {len(bonds)}")
print(f"First 5 bonded atom pairs:\n{bonds[:5]}")
Total covalent bonds in system: 1322
First 5 bonded atom pairs:
[[np.int64(0), np.int64(1)], [np.int64(1), np.int64(2)], [np.int64(1), np.int64(4)], [np.int64(2), np.int64(3)], [np.int64(2), np.int64(8)]]
6. Upward Hierarchical Mapping#
Molecular systems are hierarchical networks. msm.get() allows you to map upwards from child elements (such as atom indices) to query parent attributes (such as group_name, group_index, or chain_id):
target_atoms = [10, 50, 100]
# Query group_name, group_index, and chain_id for specific atom indices
group_names, group_indices, chain_ids = msm.get(
lysozyme,
element='atom',
selection=target_atoms,
group_name=True,
group_index=True,
chain_id=True
)
for atom, g_name, g_idx, c_id in zip(target_atoms, group_names, group_indices, chain_ids):
print(f"Atom {atom:>3} -> Group: {g_name} (index {g_idx}) | Chain: {c_id}")
Atom 10 -> Group: ASN (index 1) | Chain: A
Atom 50 -> Group: MET (index 5) | Chain: A
Atom 100 -> Group: LEU (index 12) | Chain: A
7. Downward Hierarchical Mapping#
You can also map downwards from a parent element (such as an entity or chain) to retrieve all of its constituent child elements (such as atom or group indices):
# Query atom indices composing the BENZENE entity
benzene_atom_indices = msm.get(lysozyme, element='entity', selection='entity_name == "BENZENE"', atom_index=True)
print(f"Atom indices composing BENZENE entity: {benzene_atom_indices}")
Atom indices composing BENZENE entity: [[1299, 1300, 1301, 1302, 1303, 1304]]
8. Cross-Level Summaries#
You can combine element scoping to extract counts of child elements across parent containers (for instance, asking how many groups exist in each chain):
# Extract chain indices and the number of groups contained in each chain
chain_indices, n_groups_per_chain = msm.get(lysozyme, element='chain', chain_index=True, n_groups=True)
for c_idx, n_g in zip(chain_indices, n_groups_per_chain):
print(f"Chain index {c_idx} contains {n_g} groups.")
Chain index 0 contains 162 groups.
Chain index 1 contains 1 groups.
Chain index 2 contains 1 groups.
Chain index 3 contains 1 groups.
Chain index 4 contains 1 groups.
Chain index 5 contains 136 groups.
🏆 Challenge 8: The Data Scientist#
Load the T4 Lysozyme system (
systems['T4 lysozyme L99A']['181l.bcif.gz']).Extract the coordinates of all Nitrogen atoms (
selection='atom_name == "N"').Use
numpy.mean()on the extracted coordinates array to find their center of geometry.Extract the
bonded_atom_pairsfor the Benzene ligand (selection='molecule_name == "BENZENE"').
Now that you can extract raw numerical datasets and navigate hierarchies programmatically, you must ensure that physical quantities maintain mathematical safety. In Module 9: Physical Unit Safety, we will explore physical unit management.
See also
API Documentation for Functions in this Module:
molsysmt.basic.get()— Form-agnostic attribute extraction engine.
Related Course Modules & Guides:
Previous Module: Module 7: Selection Mechanism
Next Module: Module 9: Physical Unit Safety
User Guide: user-foundations