Skip to content

Molecular Alignment and RMSD (Kabsch Algorithm)

The Kabsch algorithm finds the optimal rotation to align two molecular structures, minimizing the root-mean-square deviation (RMSD). sci-form uses SVD-based Kabsch alignment for conformer comparison and benchmarking.

Kabsch SVD Pipeline

Step 1: Center Both Structures

Given reference structure P and target structure Q (both N×3 matrices):

P¯=Pcentroid(P),Q¯=Qcentroid(Q)

where centroid(P)=1Ni=1NPi.

Step 2: Cross-Covariance Matrix

Compute the 3×3 cross-covariance matrix:

H=P¯TQ¯

Step 3: Singular Value Decomposition

Decompose H into:

H=UΣVT

Step 4: Optimal Rotation

The rotation matrix that minimizes RMSD:

d=sign(det(VUT))R=Vdiag(1,1,d)UT

The sign correction d ensures a proper rotation (not a reflection).

Step 5: RMSD Calculation

After applying rotation R:

RMSD=1Ni=1N|RP¯iQ¯i|2

RMSD Properties

The RMSD metric satisfies:

PropertyFormulaMeaning
Non-negativeRMSD0Always positive or zero
IdentityRMSD(P,P)=0Identical structures
SymmetryRMSD(P,Q)=RMSD(Q,P)Order doesn't matter
Triangle inequalityRMSD(P,R)RMSD(P,Q)+RMSD(Q,R)Metric property
Rotation invarianceRMSD(RP,Q)=RMSD(P,Q)Optimal alignment removes rotation

RMSD Variants

sci-form supports:

  • All-atom RMSD: Includes all atoms including hydrogens
  • Heavy-atom RMSD: Excludes hydrogen atoms (more chemically meaningful for conformer comparison)
  • Type-specific RMSD: Only certain element types (e.g., backbone atoms)

Alignment Result

The AlignmentResult contains both the RMSD and the transformation:

rust
pub struct AlignmentResult {
    pub rmsd: f64,
    pub rotation: [[f64; 3]; 3],
    pub translation_p: [f64; 3],
    pub translation_q: [f64; 3],
    pub aligned_coords: Vec<[f64; 3]>,
}

API

Rust

rust
use sci_form::compute_rmsd;

let rmsd = compute_rmsd(
    &elements,
    &coords_reference,
    &coords_target,
    false, // heavy_atom_only
);

CLI

bash
sci-form rmsd --reference ref.xyz --target target.xyz
# Output: RMSD value and alignment metadata

Python

python
import sci_form
result = sci_form.rmsd(elements, coords_ref, coords_target)
print(result.rmsd)             # 0.12 Å
print(result.aligned_coords)   # aligned reference coordinates

Benchmarking Use

RMSD is the primary metric for evaluating conformer quality:

  • < 0.5 Å: Excellent agreement with reference
  • 0.5–1.0 Å: Good conformer, minor deviations
  • > 1.0 Å: Significant geometric differences
  • > 2.0 Å: Likely incorrect conformer

sci-form targets RMSD < 0.5 Å for the majority of molecules when compared to RDKit reference conformers.


Quaternion Alignment (Coutsias Method)

sci-form also implements an independent quaternion eigenvector method for optimal rotation, based on Coutsias et al. (2004). This method is numerically more stable than SVD in near-degenerate cases and avoids explicit matrix decomposition.

The Davenport Key Matrix

From the same cross-covariance matrix R=P¯TQ¯ (where Sij denotes element Rij), build the 4×4 symmetric key matrix F:

F=(Sxx+Syy+SzzSyzSzySzxSxzSxySyxSyzSzySxxSyySzzSxy+SyxSzx+SxzSzxSxzSxy+SyxSxx+SyySzzSyz+SzySxySyxSzx+SxzSyz+SzySxxSyy+Szz)

The optimal rotation quaternion q=(q0,q1,q2,q3) is the eigenvector of F corresponding to its largest eigenvalue λmax.

This works because the RMSD objective can be rewritten as:

RMSD2=1N(P¯F2+Q¯F22λmax)

Quaternion to Rotation Matrix

Given the unit quaternion (q0,q1,q2,q3):

R=(q02+q12q22q322(q1q2q0q3)2(q1q3+q0q2)2(q1q2+q0q3)q02q12+q22q322(q2q3q0q1)2(q1q3q0q2)2(q2q3+q0q1)q02q12q22+q32)

This is a unit rotation matrix (det = +1, no reflection correction needed) because it is derived directly from a unit quaternion.

Numerical Stability

The quaternion method avoids the sign-correction step required in Kabsch SVD and handles symmetric molecules (where multiple equivalent alignments exist) without numerical issues. Both methods are verified to produce identical RMSD values:

rust
use sci_form::alignment::{align_coordinates, align_quaternion};

let kabsch = align_coordinates(&coords, &reference);
let quat   = align_quaternion(&coords, &reference);

assert!((kabsch.rmsd - quat.rmsd).abs() < 1e-10);

API

rust
use sci_form::alignment::align_quaternion;

let result = align_quaternion(&mobile_coords, &reference_coords);
println!("RMSD = {:.4} Å", result.rmsd);
println!("Rotation matrix: {:?}", result.rotation);

Reference

  • Coutsias, E. A.; Seok, C.; Dill, K. A. Using quaternions to calculate RMSD. J. Comput. Chem. 2004, 25, 1849–1857.

Released under the MIT License.