mmff-rs
An extensible molecular-mechanics library in Rust, with a CLI, native Python bindings, and an ASE calculator.
It also provides PBC-aware substituent, ligand and linker editing, pure-Rust conformer search, and molecular-crystal packing. An arbitrary XYZ file can be edited: connectivity comes from covalent radii, and the bond orders are read from the geometry by the same pass the calculation path uses. Use SDF/MOL2/CIF/JSON when exact bond orders or coordination roles must be guaranteed rather than perceived.
Coordinate-only preparation uses a conservative second pass when the initial graph is incomplete: provisional multiple and aromatic orders are retained, and only neutral atoms that remain unresolved may gain slightly longer candidate bonds. The cutoff is never relaxed globally, and the preparation report records when this local recovery was needed.
Seven force fields run against provenance-recorded parameter tables, validated against RDKit or LAMMPS. Custom force fields are declarative. Periodic cells are general 3D triclinic. Coordinate, strain, and mixed derivatives are analytic at arbitrary order, from one Taylor kernel shared by every model.
Install
cargo build --release --bin mmff-rs
cargo install --path . --bin mmff-rs
Run those commands from the released source tree. v0.2.9 is distributed on
PyPI and as a versioned source ZIP, not as a crates.io crate: Cargo's registry
packaging would remove the root patches for the bundled Rust 1.87 and native
link compatibility dependencies. publish = false prevents an incomplete
crate from being uploaded accidentally.
Install the published Python wheel from PyPI:
pip install mmff-rs-python
For an editable source checkout:
pip install maturin && maturin develop --release
Quick start
mmff-rs energy molecule.sdf --force-field uff-1992
mmff-rs force-fields
mmff-rs optimize molecule.sdf --force-field mmff94 -o optimized.xyz
mmff-rs fragments
mmff-rs edit replace molecule.xyz --target serial:2 --fragment butyl -o products.sdf
mmff-rs edit resize complex.cif --target 'smarts:[CH2]' --fragment ethylene -o resized.cif
mmff-rs conformers molecule.sdf --mode diverse --count 100 --parallel-strategy auto -o conformers.sdf
mmff-rs pack molecule.sdf --space-group p1 --budget 20000 --parallel-strategy auto -o packings.cif
use mmff_rs::{Calculator, ForceFieldKind, read_structure};
let calculator = Calculator::builtin(ForceFieldKind::Mmff94)?;
let system = read_structure("molecule.sdf")?;
println!("{} Hartree", calculator.energy(&system)?);
# Ok::<(), mmff_rs::MmffError>(())
from ase.build import molecule
from mmff_rs.ase import MMFF
atoms = molecule("H2O")
atoms.calc = MMFF(force_field="mmff94")
print(atoms.get_potential_energy(), "eV")
The Cargo binary, Python console script, module entry point, and compatibility name all use the same Rust-backed unified parser and implementation:
mmff-rs --help
python -m mmff_rs --help
mmff_rs_cli --help
mmff-rs --help groups commands by purpose and includes quick examples;
mmff-rs help <COMMAND> shows command-specific usage and units. The complete
guide is docs/CLI.md.
mmff-rs models (also mmff-rs force-fields) prints the force fields known to
the CLI together with availability and derivative/PBC capabilities.
Complex multi-point and ligand edits use a JSON or TOML EditRecipe. Built-in
fragments number 182 (127 one-port, 51 two-port, two three-port, and two
four-port); arbitrary fragments use mapped attachment wildcards such
as [*:1]CC[*:2] or port-annotated JSON/TOML. JSON and CIF preserve stable IDs,
bond roles, periodic images, and vacant coordination sites. CLI projection to
XYZ, SDF, and MOL2 needs no --lossy; keep JSON or CIF when metadata must be
represented.
The categorized list is in docs/FRAGMENT_CATALOG.md.
Ambiguous replacement families are enumerated. For example, --fragment butyl
returns n-, sec-, iso-, and tert-butyl products, and tied chemically distinct
multi-port attachments are returned as separate candidates. Without -o,
structure commands print JSON followed by Cartesian XYZ frames.
When a selector names the first atom of an acyclic substituent, replacement
can expand to the smallest complete group with the required number of ports.
Tied smallest regions are all returned. This inference never starts from or
enters a ring: select a substituent root or a complete SMARTS region explicitly
instead. Use --replacement-region-state-limit N to change the positive
automatic-search limit (default 4096). Multiple-result commands print a
NOTICE: and add candidate_notice to their JSON.
edit replace accepts repeated --target values as one selected region. This
is the CLI route for three- and four-port fragments; for example, select all
three methyl arms while retaining phosphorus and use --fragment ph-smap to
build the three P-C-C-Si bridges of Ph-SMAP. v0.2.9 guarantees and tests one
through four ports. edit insert intentionally remains a two-anchor linker
operation.
For edit ligand --geometry auto, coordination number is the retained occupied
sites plus every attachment port on every added fragment plus --vacant-sites.
Thus one bidentate and one monodentate fragment select three-coordinate geometry;
four-coordinate geometry remains ambiguous and must be specified explicitly.
ase_to_structure_document(atoms) uses the same Rust distance-and-valence bond
inference as XYZ input when neither a bonds argument nor atoms.info["mmff_bonds"]
is present. Pass bonds=[], or store an empty mmff_bonds list, to preserve an
intentional empty bond graph without inference.
Full API reference with examples: docs/rust-api.md and docs/python-api.md.
Units
Rust, CLI, and native Python use atomic units: Hartree, bohr, electron charge, radians. The ASE adapter alone uses eV, Angstrom, and Kelvin.
Force fields
| Model | Identifier | Scientific reference | Parameter source | Oracle |
|---|---|---|---|---|
| DREIDING 1990 | dreiding-1990 |
10.1021/j100389a010 | pysimm fb338141 (MIT) |
LAMMPS |
| UFF 1992 | uff-1992 |
10.1021/ja00051a040 | RDKit 56506230 (BSD-3) |
RDKit |
| GAFF 1.4 | gaff-1 |
10.1002/jcc.20035 | Amber via Open Babel 2.3.2 | LAMMPS |
| OPLS-AA/L | opls-aa-1996 |
10.1021/ja9621760 | GROMACS v2025.4 (LGPL-2.1) | LAMMPS |
| MMFF94 | mmff94 |
Halgren, J. Comput. Chem. 1996, 17, I-V | RDKit 56506230 (BSD-3) |
RDKit |
| ReaxFF | reaxff-2010 |
10.1021/jp004368u | fetch externally, see below | LAMMPS |
| CLAYFF 2004 | clayff-2004 |
10.1021/jp0363287 | independent transcription | LAMMPS |
| Custom | custom |
-- | your TOML/JSON pack | -- |
Loading parameters
Three routes, all available from Rust, Python, and the CLI.
Bundled tables. Everything but ReaxFF works with no parameter file at all; the table is embedded and its SHA-256 is reported with every result.
mmff-rs energy molecule.sdf --force-field uff-1992
A ReaxFF ffield file. ReaxFF ships no bundled parameters, so fetch one
externally: any file in the standard ffield.reax format works, whether from a
LAMMPS checkout's potentials/ directory or from the supplementary material of
the paper whose parameterisation you want. A ReaxFF pack is specific to its
element set and training data, so that paper is the authority on what it may be
applied to.
mmff-rs energy molecule.xyz --force-field reaxff-2010 --parameters ffield.reax.cho
let calculator = mmff_rs::Calculator::reaxff_from_ffield("ffield.reax.cho")?;
MMFFNativeCalculator(force_field="reaxff-2010", parameters="ffield.reax.cho")
A custom or overlaid pack. A TOML/JSON pack declares its own atom types, potential expressions and provenance. Layers merge field by field, so an overlay can patch one charge without restating the rest:
mmff-rs energy molecule.sdf --force-field custom \
--parameters base.toml --parameter-overlay tweaks.json
Details: rust-api.md sections 2 and 12, python-api.md section 12, and data/README.md for each bundled table's provenance.
What it computes
Energy with a per-category breakdown, analytic gradients, Hessians, virial and stress; L-BFGS and steepest-descent optimization with a streaming trajectory; harmonic frequencies; and, for periodic systems, clamped and relaxed elastic constants, high-order elastic tensors, Gamma-point phonons, Gruneisen parameters, thermal expansion, piezoelectric tensors, and a Birch-Murnaghan equation of state.
Every calculation reports the parameter pack name and SHA-256 digest alongside the result, so a number can always be traced to the data that produced it.
Scope and limitations
Results depend on input bond orders, aromaticity labels, charge policy, atom types, and the selected parameter pack. Support for an element does not mean every chemical environment has been validated.
DREIDING is a generic rule-based force field for structure generation, initial relaxation, and approximate conformational assessment. It has no intrinsic charge model and can be ambiguous for transition-metal coordination. UFF has no charge model either, and rejects supplied partial charges rather than silently discarding them.
Fixed-topology models do not form or break bonds; ReaxFF is the reactive
exception. CLAYFF environment types (ob, obos, obts, obss, oh, ohs)
must be given explicitly, because coordinates and elements do not uniquely
encode substitution sites.
The published parameter tables are not always complete. GAFF 1.4 tabulates no
torsion across a cc/cd-to-ca bond, so a benzo-fused heteroaromatic such as
tryptophan's indole reports a missing parameter; the Amber workflow fills these
by analogy with parmchk2. This library does not guess. Supply the term through
a custom parameter layer instead, and the number stays traceable to data you
chose.
This release does not promise high-accuracy relative energies or reaction barriers.
References
Every force field and numerical method is implemented from the primary literature; no upstream engine is linked or called. The full citation list is in docs/REFERENCES.md, and the provenance of each imported parameter table -- source commit, licence, and SHA-256 -- is in docs/FORCE_FIELD_PROVENANCE.md.
Documentation
| Document | Contents |
|---|---|
| docs/rust-api.md | Full Rust and CLI reference with examples |
| docs/python-api.md | Full native-Python and ASE reference with examples |
| docs/EQUATIONS.md | Functional-form mapping per model |
| docs/ATOM_TYPING.md | Perception rules and their limits |
| docs/PERFORMANCE.md | Timings, reproducing commands, parallel policy |
| docs/CONFORMER_BENCHMARK.md | Conformer search against reference minima |
| docs/FORCE_FIELD_PROVENANCE.md | Upstream revisions and digests |
| docs/REFERENCES.md | Primary literature for every model and method |
| docs/PARAMETER_LICENSING.md | Data rights policy |
| CHANGELOG.md | Release history |
License
Code is GPL-3.0-or-later.
Bundled parameter data keeps its own license and is not relicensed: MIT
(pysimm), BSD-3-Clause (RDKit), LGPL-2.1 (GROMACS), and a public-domain claim
(Amber/GAFF). The applicable notices ship under data/licenses/; per-table
provenance and digests are in data/README.md.
Release files for mmff-rs-python 0.2.9
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mmff_rs_python-0.2.9.tar.gz | 1.5 MB | Details |
Release files / mmff_rs_python-0.2.9.tar.gz
| Download URL | mmff_rs_python-0.2.9.tar.gz |
|---|---|
| Size | 1.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f01b9802b7508a01529a4ef58b5dcea8869bd53540b0161d6b00905ff3342ebe
|
|
BLAKE2b-256 checksum How to use checksums |
2d41e462597bc222233f77f4f1caca1aa682bf8250fb506b992c440c8e5737e9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.9
|