Get RMSD#

Calculating the root-mean-square deviation without prior spatial superposition.

The function molsysmt.structure.get_rmsd() measures the root-mean-square deviation (RMSD) of atomic positions relative to a reference structure directly in the global coordinate frame without applying rigid-body translations or rotations.

Added in version 1.0.0.

Basic usage#

Let’s show how to calculate the raw RMSD of backbone atoms over a pentalanine trajectory relative to the initial frame:

import molsysmt as msm
import matplotlib.pyplot as plt
import pyunitwizard as puw
molsys = msm.convert(msm.systems['pentalanine']['traj_pentalanine.h5msm'])

We compute the unaligned RMSD using molsysmt.structure.get_rmsd() with reference_structure_index=0:

rmsd_raw = msm.structure.get_rmsd(molsys, selection='backbone', reference_structure_index=0)
print('RMSD array shape:', rmsd_raw.shape)
print(f'RMSD at frame 0 (self-comparison): {rmsd_raw[0]:.4f}')
print(f'RMSD at frame 1: {rmsd_raw[1]:.4f}')
RMSD array shape: (5000,)
RMSD at frame 0 (self-comparison): 0.0000 nanometer
RMSD at frame 1: 0.4440 nanometer

RMSD evolution across structural ensembles#

We plot the unaligned RMSD over simulation time to observe positional drift:

time = msm.get(molsys, element='system', time=True)
time_val = puw.get_value(time, to_unit='ps')
rmsd_val = puw.get_value(rmsd_raw, to_unit='nm')

plt.figure(figsize=(9, 4.5))
plt.plot(time_val, rmsd_val, color='navy', lw=1.2, label='Unaligned RMSD')
plt.xlabel('Time (ps)')
plt.ylabel('RMSD (nm)')
plt.title('Backbone RMSD vs. Simulation Time (No Superposition)')
plt.grid(True, linestyle='--', alpha=0.5)
plt.legend()
plt.tight_layout()
plt.show()
../../../../_images/4245c1c9f881c59b7dde4a97319403fc9262043456f5fbe0665e1cef87c6086d.png

Comparing unaligned RMSD against optimal least-RMSD#

While molsysmt.structure.get_rmsd() includes overall translation and rotation drift, molsysmt.structure.get_least_rmsd() superposes each structure onto the reference before calculating deviation, isolating pure internal conformational changes:

rmsd_least = msm.structure.get_least_rmsd(molsys, selection='backbone', reference_structure_index=0)
rmsd_least_val = puw.get_value(rmsd_least, to_unit='nm')

plt.figure(figsize=(9, 4.5))
plt.plot(time_val, rmsd_val, color='navy', lw=1.0, alpha=0.7, label='Raw RMSD (includes drift)')
plt.plot(time_val, rmsd_least_val, color='crimson', lw=1.2, label='Least RMSD (internal deformation)')
plt.xlabel('Time (ps)')
plt.ylabel('RMSD (nm)')
plt.title('Comparison: Unaligned RMSD vs. Optimal Least-RMSD')
plt.grid(True, linestyle='--', alpha=0.5)
plt.legend()
plt.tight_layout()
plt.show()
../../../../_images/80a07c79bb2dc89066012b968448b51007cd75de6f350d3bafc7e3c1a3731be5.png