Metadata-Version: 2.4
Name: mmff-rs-python
Version: 0.2.9
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Rust
Classifier: Topic :: Scientific/Engineering :: Chemistry
Requires-Dist: numpy>=1.24
Requires-Dist: ase>=3.22
License-File: LICENSE
License-File: data/licenses/AMBER-FORCE-FIELDS-PUBLIC-DOMAIN.txt
License-File: data/licenses/CHEMATIC-MIT.txt
License-File: data/licenses/CLAYFF-2004-NOTICE.txt
License-File: data/licenses/GENERATOR-MIT.txt
License-File: data/licenses/GROMACS-LGPL-2.1.txt
License-File: data/licenses/LAMMPS-GPL-2.0.txt
License-File: data/licenses/MOYO-MIT.txt
License-File: data/licenses/PYSIMM-MIT.txt
License-File: data/licenses/RDKIT-BSD-3-Clause.txt
License-File: data/licenses/RUST-DEPENDENCY-NOTICES.txt
License-File: data/licenses/SOBOL-BSD-3-CLAUSE.txt
License-File: data/licenses/THIRD_PARTY_RUST_LICENSES.txt
Summary: Python and ASE interfaces for mmff-rs
Keywords: molecular mechanics,force field,chemistry,ASE,Rust
Home-Page: https://github.com/ss0832/mmff-rs
Author: ss0832
License-Expression: GPL-3.0-or-later
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Changelog, https://github.com/ss0832/mmff-rs/blob/main/CHANGELOG.md
Project-URL: Documentation, https://github.com/ss0832/mmff-rs/tree/main/docs
Project-URL: Homepage, https://github.com/ss0832/mmff-rs
Project-URL: Issues, https://github.com/ss0832/mmff-rs/issues
Project-URL: Repository, https://github.com/ss0832/mmff-rs

# 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

```bash
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:

```bash
pip install mmff-rs-python
```

For an editable source checkout:

```bash
pip install maturin && maturin develop --release
```

## Quick start

```bash
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
```

```rust
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>(())
```

```python
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:

```bash
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](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](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](docs/rust-api.md) and
[docs/python-api.md](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](https://doi.org/10.1021/j100389a010) | pysimm `fb338141` (MIT) | LAMMPS |
| UFF 1992 | `uff-1992` | [10.1021/ja00051a040](https://doi.org/10.1021/ja00051a040) | RDKit `56506230` (BSD-3) | RDKit |
| GAFF 1.4 | `gaff-1` | [10.1002/jcc.20035](https://doi.org/10.1002/jcc.20035) | Amber via Open Babel 2.3.2 | LAMMPS |
| OPLS-AA/L | `opls-aa-1996` | [10.1021/ja9621760](https://doi.org/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](https://doi.org/10.1021/jp004368u) | **fetch externally**, see below | LAMMPS |
| CLAYFF 2004 | `clayff-2004` | [10.1021/jp0363287](https://doi.org/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.

```bash
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.

```bash
mmff-rs energy molecule.xyz --force-field reaxff-2010 --parameters ffield.reax.cho
```

```rust
let calculator = mmff_rs::Calculator::reaxff_from_ffield("ffield.reax.cho")?;
```

```python
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:

```bash
mmff-rs energy molecule.sdf --force-field custom \
  --parameters base.toml --parameter-overlay tweaks.json
```

Details: [rust-api.md sections 2 and 12](docs/rust-api.md#2-choosing-a-force-field),
[python-api.md section 12](docs/python-api.md#12-reaxff-and-custom-packs), and
[data/README.md](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](docs/REFERENCES.md), and the provenance of each
imported parameter table -- source commit, licence, and SHA-256 -- is in
[docs/FORCE_FIELD_PROVENANCE.md](docs/FORCE_FIELD_PROVENANCE.md).

## Documentation

| Document | Contents |
|---|---|
| [docs/rust-api.md](docs/rust-api.md) | Full Rust and CLI reference with examples |
| [docs/python-api.md](docs/python-api.md) | Full native-Python and ASE reference with examples |
| [docs/EQUATIONS.md](docs/EQUATIONS.md) | Functional-form mapping per model |
| [docs/ATOM_TYPING.md](docs/ATOM_TYPING.md) | Perception rules and their limits |
| [docs/PERFORMANCE.md](docs/PERFORMANCE.md) | Timings, reproducing commands, parallel policy |
| [docs/CONFORMER_BENCHMARK.md](docs/CONFORMER_BENCHMARK.md) | Conformer search against reference minima |
| [docs/FORCE_FIELD_PROVENANCE.md](docs/FORCE_FIELD_PROVENANCE.md) | Upstream revisions and digests |
| [docs/REFERENCES.md](docs/REFERENCES.md) | Primary literature for every model and method |
| [docs/PARAMETER_LICENSING.md](docs/PARAMETER_LICENSING.md) | Data rights policy |
| [CHANGELOG.md](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](data/README.md).

