Skip to main content

Incremental Rust/Python geometry kernels for MOF checking

Project description

mofchecker-next

A fast, drop-in replacement for MOFChecker 2.0 — same diagnostics, same API, ~20–25× faster per core, built on Rust kernels and rustworkx graph algorithms.

CI PyPI Python versions License Speedup Built with Rust

Designed for the workloads where the original is painful: validating thousands of model-generated MOFs (e.g. from a diffusion model), where the slow paths — floating-solvent extraction and dimensionality — dominate.

💪 Getting started

from mofchecker_next import MOFChecker

mc = MOFChecker.from_cif("structure.cif")     # also .from_ase(atoms) / MOFChecker(structure)
mc.has_atomic_overlaps, mc.has_lone_molecule, mc.has_oms, mc.metal_number
descriptors = mc.get_mof_descriptors()        # OrderedDict of every diagnostic

Validating many structures? mofchecker_next.batch parallelizes across structures, builds each graph once, and never aborts the run on a single bad structure:

from mofchecker_next.batch import check_structures

# inputs may be CIF paths, pymatgen Structures, ASE Atoms, or a mix
results = check_structures(inputs, n_workers=16)          # all CPUs by default
bad = [r for r in results if r["has_atomic_overlaps"]]

# subset to skip work: composition-only descriptors skip graph construction entirely
fast = check_structures(inputs, descriptors=["has_atomic_overlaps", "has_overcoordinated_c"])

Each result is a dict with index, id, n_atoms, and the requested descriptors. DEFAULT_DESCRIPTORS is the in-scope diagnostic suite (including bit-exact has_high_charges); ALL_DESCRIPTORS adds metadata, symmetry, and graph hashes. A structure that fails gets an error field (on_error="record") instead of aborting the batch.

🚀 Installation

pip install mofchecker-next

Latest from source (needs a Rust toolchain):

pip install git+https://github.com/henk789/mofchecker-next.git

✨ Why use it

  • Fast. On 150-atom MOFs, 57.8 ms/structure single-core vs 1.34 s for MOFChecker 2.0 (23×); 149 structures/s across 10 cores. The hot paths (floating solvent, 3D-connectivity) were ported off networkx; the numeric kernels (distances, contacts, connected components, EQeq) are Rust.
  • 🔌 Drop-in. MOFChecker-compatible class — same properties, same get_mof_descriptors(). Switch the import and existing code keeps working.
  • Parity-verified. 100% agreement with MOFChecker 2.0 on real QMOFs (4500/4500 descriptor-comparisons over 250 structures × 18 descriptors; 16/16 on the reference test CIFs). See Parity below.
  • 📦 Built for batches. Parallel check_structures, graph built once per structure, failures isolated.
  • 🔋 Bit-exact charges. has_high_charges is a faithful Rust port of EQeq (bit-exact equilibrated charges).
  • 🔁 Reproducible. symmetry_hash is deterministic (the reference's depends on Python hash randomization).

⚡ Performance

120 generated 150-atom CIFs, full geometric descriptor set, MOFChecker 2.0 vs mofchecker-next on identical inputs (10-core node):

per structure throughput speedup
MOFChecker 2.0 — 1 core 1338 ms 0.7 /s
mofchecker-next — 1 core 57.8 ms 17.3 /s 23.2×
MOFChecker 2.0 — 10 cores 174.9 ms 5.7 /s
mofchecker-next — 10 cores 6.7 ms 149.3 /s 26.1×

Where the speedup comes from: MOFChecker's floating-solvent check builds a 3×3×3 supercell graph via pymatgen StructureGraph.__mul__ (networkx union/relabel of 27 copies, ~2.3 s/structure), and 3D-connectivity runs Larsen dimensionality over networkx. Both are replaced by direct integer image-offset algorithms on a rustworkx graph — O(N+E), no supercell — while the geometry kernels run in Rust.

⚙️ How it works

Python owns CIF/structure loading, pymatgen integration, and orchestration. The heavy lifting is delegated:

  • Rust (_rust PyO3 extension): minimum-image distances, short contacts, neighbor candidates, connected components, graph degrees, and the EQeq charge solve.
  • rustworkx (checks/_subgraph_rx.py): floating-solvent / lone-molecule detection (finite connected components via an image-offset consistency test) and Larsen dimensionality (rank of the lattice-image vectors a component spans). These replace the networkx-heavy paths.
  • structuregraph_helpers is retained for the logic-critical, non-hot pieces it does well: graph construction (tuned VESTA cutoffs) and the Weisfeiler–Lehman graph hashes.

The structure graph is built once per MOFChecker and reused across all checks.

✅ Parity

Verified against a MOFChecker 2.0 checkout (used only as a behavioral oracle) via the harnesses in scripts/:

  • Real QMOFs: 4500/4500 descriptor-comparisons (250 structures × 18 descriptors) — 100%.
  • Reference test CIFs: 16/16.
  • Generated (distorted) structures: 3899/3900. The single difference is has_lone_molecule, where mofchecker-next is more correct — see Limitations.

Reproduce: scripts/qmof_parity.py (real QMOFs), scripts/generated_parity.py (generated CIFs), scripts/validate_subgraph_rx.py (floating-solvent port). Point them at a local QMOF CIF directory with QMOF_DIR=....

⚠️ Limitations & deliberate differences

  • Healing not implemented. adding_hydrogen / adding_linker raise NotImplementedError.
  • No porosity. is_porous returns None (no bundled Zeo++).
  • has_lone_molecule is more correct than the reference. MOFChecker 2.0's supercell + in-cell-filter heuristic silently misses finite molecules that wrap the unit-cell boundary (the origin-cell copy is truncated at the supercell face). mofchecker-next detects them via a topological finite-component test. This is the only descriptor that ever disagrees with the reference, only on pathological/distorted structures (0 disagreements on real QMOFs).
  • Graph construction is still the floor. pymatgen's VESTA neighbor-finding is unchanged; the speedup is in the graph algorithms, not bond perception.
  • Determinism. symmetry_hash is deterministic by design and will not match the reference's randomized value across runs.

⚖️ License

The published package is GPLv2, because it bundles py/mofchecker_next/eqeq/ — a faithful translation of EQeq (GPLv2, see py/mofchecker_next/eqeq/LICENSE) — and the GPL governs the combined work. The non-eqeq sources are MIT (LICENSE); for an MIT-only build, omit the eqeq subpackage and the has_high_charges diagnostic.

The MOFChecker 2.0 checkout used as the behavioral oracle (ANCSA 1.0) is not redistributed; see external/REFERENCE.md to reproduce it locally.

🛠️ For developers

Build, test, and release
python -m maturin develop --release          # build the Rust extension into the venv
python -m pytest -q                          # Python tests
cargo test --release --manifest-path rust/Cargo.toml   # Rust tests

Layout

  • py/mofchecker_next/ — Python package (checks/, diagnostics.py, the eqeq subpackage).
  • py/mofchecker_next/checks/_subgraph_rx.py — rustworkx floating-solvent + dimensionality.
  • rust/ — the _rust PyO3 extension (geometry + EQeq kernels).
  • scripts/ — parity harnesses and the speed benchmark.
  • tests/ — Rust and Python unit tests.
  • docs/DIAGNOSTIC_INVENTORY.md — per-diagnostic parity status.

Making a release — wheels are built and published by .github/workflows/release.yml via PyPI Trusted Publishing on a version tag:

git tag v0.1.0 && git push origin v0.1.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

mofchecker_next-0.1.0-cp310-abi3-win_amd64.whl (184.3 kB view details)

Uploaded CPython 3.10+Windows x86-64

mofchecker_next-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (320.2 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

mofchecker_next-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (311.0 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

mofchecker_next-0.1.0-cp310-abi3-macosx_11_0_arm64.whl (280.5 kB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

Details for the file mofchecker_next-0.1.0-cp310-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for mofchecker_next-0.1.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 d9704a1024f22b3e0dcc71b879e46383194132d36670728b4f11e07afb2cbcf6
MD5 ad54d21251ca3a64c57bb687062e853c
BLAKE2b-256 7b0cde6c518b8197e80317f7533291bb756fdce189ac7a6b55fc12079f0dbba0

See more details on using hashes here.

Provenance

The following attestation bundles were made for mofchecker_next-0.1.0-cp310-abi3-win_amd64.whl:

Publisher: release.yml on henk789/mofchecker-next

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mofchecker_next-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for mofchecker_next-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 abaaf5c6168a1768a73cd397dca92116e9d7724ad2d33eda7574cceb5c9e89ce
MD5 ba1234ef0df3fad3ebf5daf504cb5d70
BLAKE2b-256 3993b52ff8b6130c222764ffba5225f7d97bc40392ec95c1e9df03146c9856e4

See more details on using hashes here.

Provenance

The following attestation bundles were made for mofchecker_next-0.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on henk789/mofchecker-next

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mofchecker_next-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for mofchecker_next-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ca6bf8f10a448ebf58fcb4d6ac93bcbcffd4f61a71a89b79fc25c8c23c9cca4b
MD5 ce570223db66da27335c2a8fb6012e59
BLAKE2b-256 665e5958394ff0c195b0c6fc053713e262772f4e08474646d6e1ebae5b5b9d44

See more details on using hashes here.

Provenance

The following attestation bundles were made for mofchecker_next-0.1.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on henk789/mofchecker-next

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mofchecker_next-0.1.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for mofchecker_next-0.1.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 3f4deba17d7e6424ca8ed9460a93a407f16f254d021b23e2454d09c78b12b603
MD5 9500bc777c88573484fa2da891b4825f
BLAKE2b-256 14c2781fb8c872f703c5b0135a29df725d2860a06b9f3e3d8893a6599b77b09a

See more details on using hashes here.

Provenance

The following attestation bundles were made for mofchecker_next-0.1.0-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on henk789/mofchecker-next

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page