How to compute RMSD and RMSF#
Goal#
Measure structural deviation across frames (RMSD) or per-atom positional fluctuation over a trajectory (RMSF).
Minimal example#
from moleculekit.molecule import Molecule
from moleculekit.util import molRMSD
mol = Molecule("3PTB")
ref = mol.copy()
# Select Cα indices for both molecule and reference
ca_idx = mol.atomselect("protein and name CA", indexes=True)
# RMSD of all frames against the reference (returns one value per frame)
rmsd = molRMSD(mol, ref, ca_idx, ca_idx)
print(rmsd)
Parameters that matter#
Common variations#
import numpy as np
# RMSF per Cα atom over a trajectory
from moleculekit.projections.metricfluctuation import MetricFluctuation
# .project returns squared per-atom displacement (shape (n_frames, n_CA),
# units Ų). RMSF = sqrt(mean over frames of the squared displacement).
sq_disp = MetricFluctuation("protein and name CA").project(mol)
rmsf = np.sqrt(sq_disp.mean(axis=0)) # shape (n_CA,), units Å
# Align before computing RMSD to separate rotation from internal motion
mol.align("protein and name CA", refmol=ref)
rmsd_aligned = molRMSD(mol, ref, ca_idx, ca_idx)
Gotchas#
molRMSD()computes raw (non-mass-weighted) RMSD; align the structures first if you want to remove rigid-body motion.RMSF is per-atom and depends on the choice of reference (mean structure); the result is sensitive to conformational heterogeneity.
Both
molandrefmolmust have the same number of selected atoms.MetricFluctuationreturns squared per-atom displacement ((n_frames, n_atoms), units Ų) — as its own docstring states (“to get the RMSD you need to compute the square root of the mean of the results this projection returns”). For RMSF takenp.sqrt(sq_disp.mean(axis=0));sq_disp.mean(axis=0)alone is mean-squared-fluctuation, not RMSF.