Rust-native implementation of the PM6 semiempirical NDDO method (J. J. P. Stewart, J. Mol. Model. 13, 1173 (2007)). Non-periodic heats of formation, fully analytic nuclear gradients and Hessians, L-BFGS geometry optimization, P-RFO transition-state search, and the PM6-D3 / PM6-D3H4 / PM6-D3H4X post-SCF corrections, with Rust, Python-native and ASE APIs.
- Author: ss0832
- License: GPL-3.0-or-later
- Pure Rust linear algebra (
faer+rayon); no LAPACK/BLAS.
Validated against the MOPAC v23.2.5 oracle (openmopac/mopac, Apache-2.0); parameters are extracted from the same release.
| Capability | Status |
|---|---|
| SCF energy (RHF + UHF), heats of formation | ✅ frozen molecular set; s/p ≤1e-6, hypervalent/TM ≤1e-4 kcal/mol vs MOPAC; see limitations below |
| d-orbital two-center integrals (S, P, Cl, transition metals, …) | ✅ e.g. TiCl₄ ≤2e-5, HCl ≤1e-8 kcal/mol |
| Analytic gradient (dual-number, Hellmann–Feynman) | ✅ s/p and d, matches MOPAC & FD |
| Analytic Hessian + frequencies | ✅ closed-shell s/p/d CPHF; open-shell d uses FD-of-analytic-gradient |
| L-BFGS geometry optimization | ✅ all elements, matches MOPAC minima |
| Mulliken charges, dipole | ✅ (≤1e-5 e / ≤1e-4 D) |
| Lanthanide sparkles (Ce…Yb) | |
| D3 dispersion (PM6-D3) | |
| H4 / X corrections (PM6-D3H4 / -D3H4X) | |
| Python native + ASE APIs (energy/grad/forces/Hessian/opt/freq) | ✅ |
| PBC | ⛔ out of scope (PM6 is molecular) |
✅ = validated to the stated tolerance; docs/scope.md and THIRD_PARTY_NOTICES.md.
Internal computation uses eV and Bohr with MOPAC's 2018-CODATA model
constants (src/constants.rs). At the boundaries:
- Rust and Python-native APIs return atomic units (Hartree, Bohr), plus convenience eV fields and ΔH_f in kcal/mol.
- The ASE calculator uses eV / Å (PM6 is natively eV, so no round-trip).
cargo build --release # library + pm6_rs_cli
cargo test # unit + MOPAC-oracle regression testspm6_rs_cli energy water.xyz
pm6_rs_cli gradient water.xyz
pm6_rs_cli optimize water.xyz # writes water.pm6opt.xyz
pm6_rs_cli frequencies water.pm6opt.xyz
pm6_rs_cli charges water.xyz --charge 0 --multiplicity 1
pm6_rs_cli energy dimer.xyz --method PM6-D3H4X # PM6 | PM6-D3 | PM6-D3H4 | PM6-D3H4Xuse pm6_rs::{Molecule, Pm6Parameters, Pm6Options, run_pm6};
let mol = Molecule::from_xyz_file("water.xyz", 0.0)?;
let params = Pm6Parameters::standard()?;
let r = run_pm6(&mol, ¶ms, &Pm6Options::default())?;
println!("ΔHf = {} kcal/mol", r.heat_of_formation_kcal);pip install maturin
maturin develop --release --features python # or: pip install pm6-rs-pythonimport pm6_rs
import numpy as np
numbers = [8, 1, 1]
positions = np.array([[0.0, 0.0, 0.0], [0.9584, 0.0, 0.0], [-0.24, 0.9278, 0.0]])
# charge, multiplicity and reference ("auto"/"rhf"/"uhf") are per-call arguments.
out = pm6_rs.single_point(numbers, positions, charge=0.0, multiplicity=1, reference="auto")
print(out["heat_of_formation_kcal"], out["charges"])
g = pm6_rs.gradient(numbers, positions) # dE/dR (Hartree/Bohr and eV/Å)
f = pm6_rs.forces(numbers, positions) # −dE/dR
h = pm6_rs.hessian(numbers, positions) # Hartree/Bohr², 3N×3N
w = pm6_rs.frequencies(numbers, positions) # cm⁻¹ (evaluate at a minimum)from ase.build import molecule
from pm6_rs.ase import PM6
atoms = molecule("H2O")
atoms.calc = PM6(charge=0, multiplicity=1, reference="auto")
print(atoms.get_potential_energy()) # eV
print(atoms.get_forces()) # eV/Å
print(atoms.calc.get_gradient()) # eV/Å (= −forces)
print(atoms.calc.get_hessian()) # eV/Ų, 3N×3N- J. J. P. Stewart, J. Mol. Model. 13, 1173 (2007) — PM6.
- W. Thiel, A. A. Voityuk, J. Phys. Chem. 100, 616 (1996) — MNDO-d.
- S. Grimme et al., J. Chem. Phys. 132, 154104 (2010) — D3.
- J. Řezáč, P. Hobza, J. Chem. Theory Comput. 8, 141 (2012) — H4.
- J. J. P. Moussa, J. J. P. Stewart, J. Open Source Softw. 11(119), 8025 (2026) — MOPAC.