Skip to main content

molcryst

CI Docs PyPI Python versions License

Documentation: https://delonecommons.github.io/molcryst/


molcryst is a Python package for representing and analyzing molecular crystals, with an emphasis on a clear crystal object model (COM) and exact, reproducible symmetry handling.

The core goals are:

  • a clear crystal object model (COM) (records → entities → keys → views)
  • exact, reproducible symmetry handling (deterministic integer-grid logic)
  • practical building blocks for workflows around bonds, components, and contacts

Current candidate

The current candidate source reports version 0.3.0. WP1–WP4 are accepted and merged; exact-revision qualification and publication remain pending under WP5. Its implemented building blocks include:

  • the canonical root façade import molcryst as mc
  • deterministic integer-grid symmetry primitives (FracQ, SymOp, derive_Q)
  • a strict structure-owned symmetry service via Structure.symmetry
  • uniform orbit helpers on Atom, Bond, Component, and Contact
  • CIF I/O through gemmi, including multi-block helpers
  • periodic covalent bonds and covalent components (molecules vs networks)
  • reusable contact definitions via Structure.contacts(...) and ContactSet
  • declarative contact filtering via ContactSelection and ContactSubset
  • line-of-sight (LoS) contact annotation on top of stored contacts
  • record-level hydrogen normalization with configurable XHScheme / overrides
  • atomref-backed curated element, radii, and X-H dataset lookup through molcryst.chem

Status

molcryst is pre-alpha and under closed, maintainer-led development. Scientific correctness comes first; architectural simplicity comes second. There are currently no external users and no external-user backward-compatibility commitment. Obsolete or unnecessary functionality, APIs, and abstractions are removed outright within approved work; internal callers, tests, examples, and documentation are updated together. See the closed-development policy.

Only the maintainer decides when development opens and what compatibility commitments follow. There is no scheduled opening date. Correct native xyz2mol functionality, a minimum useful feature set to be defined during development, and qualification on COD are the anticipated basis for considering that decision; completing them does not automatically open the project.

The current root façade is the preferred interface to teach and test:

  • the root import path and the structure/view object model are the primary public surface
  • symmetry partitions and representative choice are owned by Structure.symmetry
  • hard dependencies (atomref, pbcgraph) are expected to fail eagerly on normal import paths

Known limitations include restricted operation denominators, a finite-image nearest-distance search, and incomplete handling of unresolved disorder. See capabilities and limitations before relying on general CIF coverage. Recording these limitations does not implement their fixes.

Where to go next


Quickstart

A minimal end-to-end workflow looks like this:

  1. read a CIF,
  2. build a reusable contact definition,
  3. compute LoS annotations,
  4. narrow to a filtered subset,
  5. traverse through structure-bound views.

Load a structure

import molcryst as mc

# Load the first CIF block by default.
s = mc.Structure.from_cif_file('my_structure.cif')

# If a CIF contains multiple blocks, choose by index or block name.
# s = mc.Structure.from_cif_file('multi.cif', block=0)
# s = mc.Structure.from_cif_file('multi.cif', block='MYBLOCK')

The Structure object is the main convenience façade. It lazily builds and caches canonical atom entities, bonds/components, contacts, and several periodic graph views.

Build a contact definition

# Intermolecular contacts up to a cutoff (Å).
base = s.contacts(cutoff=3.5, scope='inter')

print('n selected:', len(base))
print('n store total:', len(s.contact_store))

Notes:

  • Structure owns a single mutable ContactStore.
  • base is a lightweight ContactSet bound to a full contact definition (ContactSettings), not just a (cutoff, scope) pair.
  • public contact definitions are non-covalent relative to the active bond layer, so directly bonded pairs are excluded from the store.
  • Passing cutoff= to Structure.contacts(...) is a convenience that asks for an absolute-distance contact definition.

Compute LoS annotations

# Compute LoS (line-of-sight) for this definition.
params_id = base.ensure_los(definition='chernyshov2020')

# You can also request the Taylor definition.
# params_id = base.ensure_los(definition='taylor2014')

LoS is implemented as an annotation layer on top of the selected contacts. No new contacts are enumerated; existing contacts are annotated.

Narrow to a filtered subset

los = base.select(
    mc.ContactSelection(
        annotation_method='los',
        annotation_params_id=params_id,
        annotation_where=lambda ann: bool(ann.data['los']),
    )
)

print('n LoS:', len(los))

You can use the same API for distance windows, vdW-gap windows, or additional scope filtering.

Inspect one contact

k = los.keys[0]
c = los.get(k)
ann = c.annotations[('los', params_id)]

print('edge:', k)
print('distance:', c.distance)
print('los:', ann.data['los'])
print('dR:', ann.data['dR'])
print('shield atom:', ann.data['shield_atom_id'], (ann.data['shield_tx'], ann.data['shield_ty'], ann.data['shield_tz']))
print('valid:', ann.data['valid'], 'radii_complete:', ann.data['radii_complete'])

Traverse with views and build graphs

center = s.atom(0)
print('bonded neighbors:', center.bonded_neighbors())
print('LoS contact neighbors:', center.contact_neighbors(sel=los))

atom_graph = los.atom_graph()
component_graph, bundles = los.component_graph()

print('atom graph edges:', len(atom_graph.edges))
print('component graph edges:', len(component_graph.edges))

Work with symmetry orbits

All orbit partitioning is owned by Structure.symmetry.

print('unique atom ids:', s.symmetry.unique_atom_ids())
print('unique bond edges:', [b.edge for b in s.symmetry.unique_bonds()])
print('unique component ids:', s.symmetry.unique_component_ids())

unique_contacts = s.symmetry.unique_contacts(los, rep_policy='canonical')
print('unique LoS contacts:', [c.edge for c in unique_contacts])

Views expose matching convenience helpers:

atom = s.atom(0)
print('atom orbit size:', atom.orbit_size())
print('atom rep:', atom.orbit_rep().atom_id)

contact = unique_contacts[0]
print('contact orbit size in selection:', contact.orbit_size(selection=los))
print('contact rep in selection:', contact.orbit_rep(selection=los).edge)

Notes:

  • Atom, Bond, and Component orbit helpers classify the underlying reference-cell object; the view shift does not change orbit identity.
  • Contact orbit helpers are selection-scoped, so the selection must be passed explicitly.
  • Symmetry queries are strict: if a requested surface is unavailable or not symmetry-closed, molcryst raises instead of silently degrading.

Installation and local development

molcryst is a research-focused, pre-alpha Python package.

Requirements

  • Package metadata requires Python >=3.10. The explicit v0.3 release qualification matrix is 3.10–3.13; candidate qualification remains pending. Python 3.14 is outside that matrix.
  • Runtime dependencies are installed automatically:
    • atomref (curated element/radii/X-H datasets and transfer engine)
    • gemmi (CIF parsing)
    • scipy (KDTree-based neighbour candidates)
    • pbcgraph (periodic graph utilities)

Published release

After 0.3.0 has been qualified and published, install the published release with:

python -m pip install molcryst==0.3.0

The current source is a 0.3.0 candidate; this command is not a claim that publication has happened.

Local candidate wheel

To inspect a locally supplied candidate wheel, create a separate environment and install the exact file:

python -m venv .venv-candidate
# Activate .venv-candidate using the command appropriate for your shell.
python -m pip install /path/to/molcryst-0.3.0-py3-none-any.whl

Installing a candidate does not establish release qualification.

Contributor editable checkout

Run contributor commands from a repository checkout:

python -m venv .venv
# Activate .venv using the command appropriate for your shell.
python -m pip install -e ".[test,docs,dev]"

Respect the declared dependency ranges, including pbcgraph>=0.1.4 and atomref>=0.1.4,<0.2; an arbitrary sibling checkout may not satisfy them. Installing sibling HEADs or widening their ranges is a separate compatibility task, not a prerequisite for ordinary documentation work.

This installs:

  • the package itself
  • test dependencies (pytest)
  • docs dependencies (mkdocs, mkdocs-material, mkdocstrings, nbconvert, ...)
  • development tools (flake8, build helpers)

For a runtime-only editable checkout, omit the extras:

python -m pip install -e .

The test, documentation and notebook commands below are repository workflows. The public sdist contains package source, build metadata, README and legal files plus .gitignore; it does not contain tests, docs, notebooks or contributor tools.

Run repository tests

python -m pytest

Build or preview existing documentation

For a prose/navigation change, regenerate/check only the README and build the site from the committed example pages:

python tools/gen_readme.py
python tools/gen_readme.py --check
python -m mkdocs build --clean --strict
# Or preview the same pages locally:
python -m mkdocs serve

See development validation and the development entry point for checks and work plans.

Generated docs artifacts

The local docs workflow maintains two generated artifacts:

  • example pages under docs/examples/, rendered from the source notebooks in notebooks/
  • the root README.md, generated from selected docs pages so the package landing page stays aligned with the site

The current README source pages are:

  • docs/index.md
  • docs/guide/quickstart.md
  • docs/guide/install.md

The notebook renderer executes source notebooks in place and writes their outputs. sync_docs.py --check-readme also executes notebooks unless paired with --readme-only. Do not run a notebook refresh merely to validate a prose edit; use a disposable copy when qualifying notebook execution.

For an intentional notebook/output refresh, refresh both generated artifacts and build the site:

python tools/sync_docs.py
python -m mkdocs build

After that intentional refresh, python -m mkdocs serve previews the generated pages without another notebook execution.

Under the hood, this runs tools/render_examples.py (examples) and tools/gen_readme.py (README).

Sync only the README

python tools/sync_docs.py --readme-only
# or:
python tools/gen_readme.py

To verify that the committed README is still in sync without rewriting it:

python tools/sync_docs.py --readme-only --check-readme
# or:
python tools/gen_readme.py --check

This README is auto-generated from selected docs pages (docs/index.md, docs/guide/quickstart.md, and docs/guide/install.md). To update it, edit those docs pages and re-run: python tools/sync_docs.py --readme-only (or python tools/gen_readme.py).

Download files

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

Source Distribution

molcryst-0.3.0.tar.gz (153.0 kB view details)

Uploaded Source

Built Distribution

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

molcryst-0.3.0-py3-none-any.whl (212.8 kB view details)

Uploaded Python 3

File details

Details for the file molcryst-0.3.0.tar.gz.

File metadata

  • Download URL: molcryst-0.3.0.tar.gz
  • Upload date:
  • Size: 153.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.15

File hashes

Hashes for molcryst-0.3.0.tar.gz
Algorithm Hash digest
SHA256 63987a29a9d5c8e388e5204e1ab3f063906f39e2d121c534d74b352e8147acb1
MD5 fe31e8702a8aff32e75bfc8ad0c77770
BLAKE2b-256 ad2e95e834c59eff36535611fca6730daf0fe50c0d099f3512ea7b436a6562fd

See more details on using hashes here.

File details

Details for the file molcryst-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: molcryst-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 212.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.15

File hashes

Hashes for molcryst-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e501632e8f164ca209f6303e36d0fbf61c2bb2d26426ba650aa7d7f451990188
MD5 590e028b1150c62fd153e22dfa53a952
BLAKE2b-256 6b2bd9eb65c3ccb9ab1e980a312d60f61890a66db265680ad21baa8cdc25c50e

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page