Skip to content

Fix low-mode vibrational analysis to use mass-weighted coordinates#5

Merged
corinwagen merged 2 commits into
rowansci:masterfrom
mooreneural:master
Jun 19, 2026
Merged

Fix low-mode vibrational analysis to use mass-weighted coordinates#5
corinwagen merged 2 commits into
rowansci:masterfrom
mooreneural:master

Conversation

@mooreneural

@mooreneural mooreneural commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

The GF-matrix method (Wilson, Decius & Cross) requires building the rigid-body
translation/rotation basis and projecting the Hessian in mass-weighted
Cartesian coordinates q = M^{1/2} x. The previous implementation used
unweighted Cartesian coordinates, causing heavy atoms (Br, I, S) to artificially
inflate mode eigenvalues and misrank the true soft conformational modes.

Changes

  • _build_vibrational_basis: translation vectors now weighted by √m_i per atom;
    rotation vectors weighted by √m_i · (r_i × e_k); near-zero threshold scales
    with √(total_mass) accordingly.
  • _select_low_modes: projects the mass-weighted Hessian F_mw = M^{-1/2} H M^{-1/2}
    into the vibrational subspace, diagonalises, then unweights eigenvectors back
    to Cartesian displacement vectors and renormalises columns.
  • config.py: corrects low_mode_eigenvalue_threshold docstring units from
    kcal/mol/Ų to kcal/mol/Ų/Da (mass-weighted, proportional to ω²) with
    calibration reference values for torsional vs. stretch modes.

Benchmark

Cosine similarity measures alignment between the old and new softest-mode vectors.
Values near 1.0 mean the fix is a near no-op; lower values indicate the mode
ordering was substantially corrected for that molecule.

Molecule Max mass (Da) Old soft modes New soft modes Cosine
Propane 12 4 5 0.986
Hexane 12 5 5 0.973
Thioanisole 32 5 5 0.912
Chlorobenzene 35 4 5 0.721
Bromobenzene 80 5 5 0.680
4-Bromobenzyl alcohol 80 5 5 0.937
2-Iodothiophene 127 3 5 0.624
Dibromomethane 80 0 4

For C-only molecules the fix is a near no-op (cosine ~0.99). For Br/I molecules
the soft-mode vectors are substantially corrected, iodothiophene's softest mode
previously assigned 59% of displacement to the I atom; the corrected mode assigns
~3%. Mode-select overhead is <1 ms vs. 4–12 ms for Hessian computation.

The GF-matrix method (Wilson, Decius & Cross) requires building the
rigid-body translation/rotation basis and projecting the Hessian in
mass-weighted Cartesian coordinates q = M^{1/2} x. The previous
implementation used unweighted Cartesian coordinates, causing heavy
atoms (Br, I, S) to artificially inflate mode eigenvalues and misrank
the true soft conformational modes.

Changes:
- _build_vibrational_basis: translation vectors now weighted by sqrt(m_i)
  per atom; rotation vectors weighted by sqrt(m_i) * (r_i x e_k); the
  near-zero threshold scales with sqrt(total_mass) accordingly.
- _select_low_modes: projects the mass-weighted Hessian F_mw = M^{-1/2} H M^{-1/2}
  into the vibrational subspace, diagonalises, then unweights eigenvectors
  back to Cartesian displacement vectors and renormalises.
- config.py docstring: corrects eigenvalue threshold units from kcal/mol/A2
  to kcal/mol/A2/Da (mass-weighted) with calibration reference values.

Benchmark on 10 molecules spanning C/Cl/S/Br/I:
- C-only molecules: cosine similarity ~0.97-0.99 (fix is near no-op, as expected)
- Br/I molecules: cosine similarity 0.62-0.72 (modes substantially reranked)
- 2-iodothiophene: soft mode count corrected from 3 to 5
- Mode overhead is <1ms vs 4-12ms for Hessian computation (negligible)
@corinwagen

Copy link
Copy Markdown
Member

Hey @mooreneural, thanks for the PR. We originally did this intentionally w/ the non-MW Hessian, following the literature precedent, but we ran our own benchmarks on this PR and performance seems good for "normal" non–heavy element systems, so I think this is a real improvement.

A couple notes:

  • can you fix the errors flagged by Ruff? I think it's just because of the "x" character
  • can you update the docstring for generate_low_mode_seeds to match here?

I'll be happy to merge after this changes.

Replace Unicode multiplication sign (x) with ASCII x in rotation comments
to resolve Ruff RUF003. Update eigenvalue_threshold docstring in
generate_low_mode_seeds to reflect mass-weighted units (kcal/mol/A2/Da)
introduced by the GF-matrix fix.
@mooreneural

Copy link
Copy Markdown
Contributor Author

Fixed both! Replaced the Unicode multiplication signs with ASCII x to clear the Ruff warnings, and updated the generate_low_mode_seeds docstring to reflect the mass-weighted units (kcal/mol/Ų/Da). Ready to merge when you are.

@corinwagen corinwagen merged commit b2fe26d into rowansci:master Jun 19, 2026
1 check passed
@corinwagen

Copy link
Copy Markdown
Member

merged! ty for the contribution

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants