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 Distribution

mofchecker_next-0.1.1.tar.gz (46.5 kB view details)

Uploaded Source

Built Distributions

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

mofchecker_next-0.1.1-cp310-abi3-win_amd64.whl (185.4 kB view details)

Uploaded CPython 3.10+Windows x86-64

mofchecker_next-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (321.3 kB view details)

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

mofchecker_next-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (312.1 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

mofchecker_next-0.1.1-cp310-abi3-macosx_11_0_arm64.whl (281.6 kB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

Details for the file mofchecker_next-0.1.1.tar.gz.

File metadata

  • Download URL: mofchecker_next-0.1.1.tar.gz
  • Upload date:
  • Size: 46.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mofchecker_next-0.1.1.tar.gz
Algorithm Hash digest
SHA256 d003ea207eb8d7edfbdbb5417b03683d6a89eec17871b9eac75a5ff7371a72e8
MD5 b19c9dc90308396969eaf63af0631843
BLAKE2b-256 28736d09cd904da6240b2dd9686665704d10c1eac66048eb2a0b54cd3c30d402

See more details on using hashes here.

Provenance

The following attestation bundles were made for mofchecker_next-0.1.1.tar.gz:

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.1-cp310-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for mofchecker_next-0.1.1-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 cd96fc68ed6045a0330210ea8e710931d988e45c044ab147385a891d1b87ad79
MD5 35b8169d57bfa11d818e5ca39e1920c8
BLAKE2b-256 0d316b8e4d62b0233037d2e400da49d6740d2c709d7aa06ce14c528008021e35

See more details on using hashes here.

Provenance

The following attestation bundles were made for mofchecker_next-0.1.1-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.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for mofchecker_next-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f8cbed70e2508d4c93ffde9e46f04540cc188e6c7b24272167547631b523c58f
MD5 f1f4d7de84282b8e53de2f2fdb46191e
BLAKE2b-256 b43f7718d415b00e7d262605272e51d2f5d147f0fce84b73e03ca484aedc298b

See more details on using hashes here.

Provenance

The following attestation bundles were made for mofchecker_next-0.1.1-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.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for mofchecker_next-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 bd04be2750635318cb8b448755953f52f9154006a8ecf53efe7f28f4d42c62ff
MD5 94001109a2fbcfb9a270718540031974
BLAKE2b-256 c7ee5e06e29b92bf2e68950da5fb52c126f0cc5b05dd299b50d72dd6be9ee9fb

See more details on using hashes here.

Provenance

The following attestation bundles were made for mofchecker_next-0.1.1-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.1-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for mofchecker_next-0.1.1-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 884b9e1dd82f2c1236f7b33dc5e2424b8cb8e237a3fbba3e09e1a65c5896cd9e
MD5 c8a6d34e54c49eb07325f0644b13a5c7
BLAKE2b-256 322f2a018182c53afc12df7422e5964a7416fe87dc56aaa367d9c03bf59c8b83

See more details on using hashes here.

Provenance

The following attestation bundles were made for mofchecker_next-0.1.1-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