Metadata-Version: 2.4
Name: rgpycrumbs
Version: 1.9.19
Summary: A dispatcher-based analytical and computational suite for chemical physics
Project-URL: Documentation, https://rgpycrumbs.rgoswami.me
Project-URL: Issues, https://github.com/HaoZeke/rgpycrumbs/issues
Project-URL: Source, https://github.com/HaoZeke/rgpycrumbs
Author-email: Rohit Goswami <rgoswami@ieee.org>
License: MIT
License-File: LICENSE
Keywords: analysis,compchem,interpolation,surfaces
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: Implementation :: CPython
Requires-Python: >=3.10
Requires-Dist: click>=8.1
Requires-Dist: numpy>=1.24
Requires-Dist: rich>=13.0
Provides-Extra: lint
Requires-Dist: ruff>=0.1.6; extra == 'lint'
Provides-Extra: release
Requires-Dist: build>=0.10; extra == 'release'
Requires-Dist: towncrier>=24.8.0; extra == 'release'
Requires-Dist: twine>=4.0; extra == 'release'
Requires-Dist: wheel>=0.40; extra == 'release'
Provides-Extra: test
Requires-Dist: pytest-cov>=4.1.0; extra == 'test'
Requires-Dist: pytest-pep723>=0.1.0; extra == 'test'
Requires-Dist: pytest>=9.0; extra == 'test'
Description-Content-Type: text/markdown


# Table of Contents

-   [About](#about)
    -   [Ecosystem Overview](#ecosys)
    -   [CLI Design Philosophy](#cli-how)
-   [Usage](#usage)
    -   [Library API](#library-api)
    -   [CLI Tools](#cli-tools)
        -   [eOn](#cli-eon)
-   [Contributing](#contributing)
    -   [Development](#development)
        -   [Branch Structure](#dev:branch)
        -   [When is pixi needed?](#dev:whypixi)
        -   [Versioning](#dev:versions)
    -   [Release Process](#release-notes)
-   [License](#license)

> Canonical source note: this Org file is authoritative for contributor-facing
> documentation. Rendered Markdown files are derived artifacts and should not be
> edited separately.


<a id="about"></a>

# About

![img](https://raw.githubusercontent.com/HaoZeke/rgpycrumbs/refs/heads/main/branding/logo/pycrumbs_logo.webp)

[![Tests](https://github.com/HaoZeke/rgpycrumbs/actions/workflows/ci_test.yml/badge.svg)](https://github.com/HaoZeke/rgpycrumbs/actions/workflows/ci_test.yml)
[![Linting](https://github.com/HaoZeke/rgpycrumbs/actions/workflows/ci_prek.yml/badge.svg)](https://github.com/HaoZeke/rgpycrumbs/actions/workflows/ci_prek.yml)
[![Docs](https://github.com/HaoZeke/rgpycrumbs/actions/workflows/ci_docs.yml/badge.svg)](https://github.com/HaoZeke/rgpycrumbs/actions/workflows/ci_docs.yml)
[![PyPI](https://img.shields.io/pypi/v/rgpycrumbs)](https://pypi.org/project/rgpycrumbs/)
[![Python](https://img.shields.io/pypi/pyversions/rgpycrumbs)](https://pypi.org/project/rgpycrumbs/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![One Good Tutorial docs checklist v1: adopted](https://onegoodtutorial.org/badge/adopted-v1.svg)](https://onegoodtutorial.org/about/badge/?v=1)
[![Benchmarks](https://img.shields.io/badge/benchmarks-asv--perch-orange)](https://github.com/HaoZeke/asv-perch)
[![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
[![DOI](https://zenodo.org/badge/795596895.svg)](https://doi.org/10.5281/zenodo.18529798)

A **pure-python** computational library and CLI toolkit for chemical physics
research. `rgpycrumbs` provides both importable library modules for
computational tasks (surface fitting, structure analysis, interpolation) and a
dispatcher-based CLI for running self-contained research scripts.

Heavy optional dependencies (JAX, SciPy, ASE) are resolved lazily at first use.
A bare `pip install rgpycrumbs` gives the full API surface; the actual backend
libraries load on demand from the current environment, a shared cache, or (with
`RGPYCRUMBS_AUTO_DEPS=1`) via automatic `uv` installation. CUDA-aware
resolution avoids pulling GPU libraries on CPU-only machines.

The library side offers:

-   **Surface fitting** (`rgpycrumbs.surfaces`) &#x2013; JAX-based kernel methods (TPS, RBF, Matern, SE, IMQ) with gradient-enhanced variants for energy landscape interpolation
-   **Structure analysis** (`rgpycrumbs.geom.analysis`) &#x2013; distance matrices, bond matrices, and fragment detection via ASE
-   **IRA matching** (`rgpycrumbs.geom.ira`) &#x2013; iterative rotations and assignments for RMSD-based structure comparison
-   **Interpolation** (`rgpycrumbs.interpolation`) &#x2013; spline interpolation utilities
-   **Data types** (`rgpycrumbs.basetypes`) &#x2013; shared data structures for NEB paths, saddle searches, and molecular geometries

The CLI tools rely on optional dependencies fetched on-demand via PEP 723 + `uv`.


<a id="ecosys"></a>

## Ecosystem Overview

`rgpycrumbs` is the central hub of an interlinked suite of libraries.

![img](branding/logo/ecosystem.png)


<a id="cli-how"></a>

## CLI Design Philosophy

The library is designed with the following principles in mind:

-   **Dispatcher-Based Architecture (preferred entry):** Use
    `rgpycrumbs <group> <tool>` or `python -m rgpycrumbs.cli ...` — **not** raw
    `uv run path/to/script.py` as the primary path. The dispatcher sets
    `PYTHONPATH`, defaults `RGPYCRUMBS_AUTO_DEPS=1`, optional editable peers, and
    optional SBOM pins. Scripts remain self-contained PEP 723 units invoked in a
    subprocess via `uv run` when isolation is chosen.

-   **Isolated & Reproducible Execution:** Each script declares dependencies via
    [PEP 723](https://peps.python.org/pep-0723/) (including a `rgpycrumbs` floor so
    standalone `uv run` can resolve the package). For **pinned** installs, pass a
    lock the uv resolver already understands:

    * `uv.lock` (native)
    * PEP 751 `pylock.toml` / `pylock.*.toml` (e.g. `uv export --format pylock.toml`)
    * CycloneDX JSON (e.g. eb-stack `--sbom-out`, `uv export --format cyclonedx1.5`)

    via `--lock PATH` / `RGPYCRUMBS_LOCK` (or `--sbom` / `RGPYCRUMBS_SBOM`).
    PyPI packages become `name==version` constraints for `uv` / `ensure_import`;
    non-PyPI CDX rows (`pkg:generic/...`) are skipped. No lock → floating PEP 723
    / AUTO_DEPS.

    **Suite config** (TOML; shared with chemparseplot / other rgpkgs — not a
    per-package silo):

    * User: `~/.config/rgpkgs/config.toml`
    * Project: `rgpkgs.toml` or `.rgpkgs.toml` (walk up from CWD)
    * Override: `RGPKGS_CONFIG=/path/to.toml`
    * Legacy: `rgpycrumbs.toml` and `~/.config/rgpycrumbs/` still work

    Shared `[pins]` / `[pins.packages]`; tool keys under `[rgpycrumbs.dispatch]`.
    Example: `docs/examples/rgpkgs.config.toml`.

    **Stable consumer API** (chemparseplot, pychum, wailord):

        from rgpycrumbs.api import load_config, load_pypi_pins, ensure_import

    See `docs/orgmode/explanation/public_api.org`. Debug: `rgpycrumbs config show`.

-   **Lightweight Core, On-Demand Dependencies:** The installable `rgpycrumbs`
    package has minimal core dependencies (`click`, `numpy`, `rich`). There are
    **no runtime feature extras**. CLI tools fetch deps via PEP 723 + `uv run`.
    Library modules use `ensure_import` when `RGPYCRUMBS_AUTO_DEPS=1` (CLI
    dispatch enables this by default), with CUDA-aware resolution so CPU hosts
    do not pull GPU JAX. Install only `rgpycrumbs`; optional packages arrive on
    demand.

-   **Modular & Extensible Tooling:** Each utility is an independent script. This
    modularity simplifies development, testing, and maintenance, as changes to one
    tool cannot inadvertently affect another. New tools can be added to the
    collection without modifying the core dispatcher logic, making the system
    easily extensible.


<a id="usage"></a>

# Usage


<a id="library-api"></a>

## Library API

The library modules can be imported directly. Dependencies resolve
automatically when `RGPYCRUMBS_AUTO_DEPS=1` is set (requires `uv` on PATH):

    export RGPYCRUMBS_AUTO_DEPS=1

    # Surface fitting (jax via ensure_import)
    from rgpycrumbs.surfaces import get_surface_model
    model = get_surface_model("tps")

    # Structure analysis (ase/scipy via ensure_import)
    from rgpycrumbs.geom.analysis import analyze_structure

    # Spline interpolation (scipy via ensure_import)
    from rgpycrumbs.interpolation import spline_interp

    # Data types (core only)
    from rgpycrumbs.basetypes import nebpath, SaddleMeasure


<a id="cli-tools"></a>

## CLI Tools

The general command structure is:

    python -m rgpycrumbs.cli [subcommand-group] [script-name] [script-options]

You can see the list of available command groups:

    $ python -m rgpycrumbs.cli --help
    Usage: rgpycrumbs [OPTIONS] COMMAND [ARGS]...
    
      A dispatcher that runs self-contained scripts using 'uv'.
    
    Options:
      --help  Show this message and exit.
    
    Commands:
      eon  Dispatches to a script within the 'eon' submodule.


<a id="cli-eon"></a>

### eOn

-   Plotting NEB Paths (`plt-neb`), including energy-unit selection and xyzrender strips
-   Stitch multi-segment NEB bands (`plt-neb-stitch`) for full-path 1D/2D views (v1.8+)
-   Seed dimer searches from NEB peaks (`gen-dimer`) and KMC timeline plots (`plt-kmc`)
-   Single-ended minimization landscapes (`plt-min`) with optional `--energy-cap` windows

    This script visualizes the energy landscape of Nudged Elastic Band (NEB) calculations,
    generating 2D surface plots with optional structure rendering.
    
    The default `grad_imq` method uses gradient-enhanced Inverse Multiquadric interpolation
    on 2D RMSD projections [1]. The approach projects high-dimensional structures onto
    2D coordinates (reactant distance `r` vs product distance `p`) and fits a smooth
    surface using energy values and their gradients.
    
    [1] R. Goswami, "Two-dimensional RMSD projections for reaction path visualization
    and validation," *MethodsX*, p. 103851, Mar. 2026,
    doi: [10.1016/j.mex.2026.103851](https://doi.org/10.1016/j.mex.2026.103851).
    generating 2D surface plots with optional structure rendering.
    
    -   Basic Usage
    
            python -m rgpycrumbs.cli eon plt-neb --con-file trajectory.con --plot-type landscape -o neb_landscape.png
    
    -   Key Options
    
        <table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
        
        
        <colgroup>
        <col  class="org-left" />
        
        <col  class="org-left" />
        
        <col  class="org-left" />
        </colgroup>
        <thead>
        <tr>
        <th scope="col" class="org-left">Option</th>
        <th scope="col" class="org-left">Description</th>
        <th scope="col" class="org-left">Default</th>
        </tr>
        </thead>
        <tbody>
        <tr>
        <td class="org-left"><code>--con-file PATH</code></td>
        <td class="org-left">Trajectory file with NEB images</td>
        <td class="org-left">None</td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--plot-type</code></td>
        <td class="org-left"><code>landscape</code> (2D surface) or <code>profile</code></td>
        <td class="org-left"><code>profile</code></td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--surface-type</code></td>
        <td class="org-left">Surface method: <code>grad_imq</code>, <code>grad_matern</code>, <code>grad_imq_ny</code>, <code>rbf</code></td>
        <td class="org-left"><code>grad_imq</code></td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--project-path</code> / <code>--no-project-path</code></td>
        <td class="org-left">Project to reaction valley coordinates</td>
        <td class="org-left"><code>--project-path</code></td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--plot-structures</code></td>
        <td class="org-left">Structure strip: <code>none</code>, <code>all</code>, <code>crit_points</code></td>
        <td class="org-left"><code>none</code></td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--energy-unit</code></td>
        <td class="org-left">Presentation unit: <code>eV</code>, <code>kcal/mol</code>, <code>kJ/mol</code></td>
        <td class="org-left"><code>eV</code></td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--strip-renderer</code></td>
        <td class="org-left">Structure renderer backend</td>
        <td class="org-left"><code>xyzrender</code></td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--xyzrender-config</code></td>
        <td class="org-left">xyzrender preset used for strips</td>
        <td class="org-left"><code>paton</code></td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--show-legend</code></td>
        <td class="org-left">Show colorbar legend</td>
        <td class="org-left">Off</td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--show-pts</code> / <code>--no-show-pts</code></td>
        <td class="org-left">Show data points on surface</td>
        <td class="org-left"><code>--show-pts</code></td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--landscape-path</code></td>
        <td class="org-left">Path overlay: <code>final</code>, <code>all</code>, <code>none</code></td>
        <td class="org-left"><code>final</code></td>
        </tr>
        
        <tr>
        <td class="org-left"><code>--ira-kmax</code></td>
        <td class="org-left">kmax factor for IRA RMSD calculation</td>
        <td class="org-left">14.0</td>
        </tr>
        
        <tr>
        <td class="org-left"><code>-o PATH</code></td>
        <td class="org-left">Output image filename</td>
        <td class="org-left">None (display)</td>
        </tr>
        </tbody>
        </table>
        
        Use `--landscape-path all` to overlay all optimization steps and visualize convergence.
        This shows the full trajectory from initial guess to final path [1].
    
    -   Examples
    
        Full landscape with gradient-enhanced IMQ surface and critical point structures:
        
            python -m rgpycrumbs.cli eon plt-neb \
              --con-file neb.con \
              --plot-type landscape \
              --project-path \
              --plot-structures crit_points \
              --surface-type grad_matern \
              --ira-kmax 14 \
              --energy-unit kJ/mol \
              --show-legend \
              -o neb_landscape.png
        
        Surface-only plot without structure strip:
        
            python -m rgpycrumbs.cli eon plt-neb \
              --plot-type landscape \
              --surface-type grad_matern \
              --no-show-pts \
              -o surface.png
        
        Convergence visualization with all optimization steps:
        
            python -m rgpycrumbs.cli eon plt-neb \
              --con-file neb.con \
              --plot-type landscape \
              --landscape-path all \
              --surface-type grad_imq \
              --show-legend \
              -o neb_convergence.png
    
    -   Surface Methods
    
        -   **`grad_imq`:** Gradient-enhanced Inverse Multiquadric (recommended, uses energy + gradients)
        -   **`grad_matern`:** Gradient-enhanced Matérn 5/2 (uses energy + gradients)
        -   **`grad_imq_ny`:** Nystrom-approximated grad<sub>imq</sub> for large datasets (>1000 points)
        -   **`rbf`:** Radial Basis Function / Thin Plate Spline (fast, no gradients)

-   Splitting CON files (`con-splitter`)

    This script takes a multi-image trajectory file (e.g., from a finished NEB
    calculation) and splits it into individual frame files, creating an input file
    for a new calculation.
    
    To split a trajectory file:
    
        rgpycrumbs eon con-splitter neb_final_path.con -o initial_images
    
    This will create a directory named `initial_images` containing `ipath_000.con`,
    `ipath_001.con`, etc., along with an `ipath.dat` file listing their paths.


<a id="contributing"></a>

# Contributing

All contributions are welcome, but for the CLI tools please follow [established
best practices](https://realpython.com/python-script-structure/).


<a id="development"></a>

## Development

This project uses [`uv`](https://docs.astral.sh/uv/) as the primary development tool with
[`hatchling`](https://hatch.pypa.io/) + [`hatch-vcs`](https://github.com/ofek/hatch-vcs) for building and versioning.

    # Clone and install in development mode with test dependencies
    uv sync --extra test
    
    # Run the pure tests (no heavy optional deps)
    uv run pytest -m pure
    
    # Run interpolation tests (needs scipy)
    uv run --extra interpolation pytest -m interpolation


<a id="dev:branch"></a>

### Branch Structure

Development happens on the `main` branch. The `readme` branch is an
auto-generated orphan containing only the rendered `README.md` and branding
assets; it is the GitHub default branch.


<a id="dev:whypixi"></a>

### When is pixi needed?

[Pixi](https://prefix.dev/) is mainly needed for pixi-only or heavy optional packages that we do not auto-install by default:

-   `fragments` tests: need `tblite`, `ira_mod`, and `pyvista`
-   some heavy visualization workflows may still be easier to manage in pixi

For everything else, `uv` is sufficient.


<a id="dev:versions"></a>

### Versioning

Versions are derived automatically from **git tags** via `hatch-vcs`
(setuptools-scm). There is no manual version field; the version is the latest
tag (e.g. `v1.0.0` → `1.0.0`). Between tags, dev versions are generated
automatically (e.g. `1.0.1.dev3+gabcdef`).


<a id="release-notes"></a>

## Release Process

    # 1. Run the same checks the tag-triggered release workflow expects
    uv sync --extra test --extra release
    uv run --extra test pytest -m pure
    uv run --extra test pytest --pep723-check -m pep723 --override-ini="python_files=" --ignore=rgpycrumbs/chemgp rgpycrumbs/
    uvx prek run -a -vvv
    pixi run -e docs docbld
    
    # 2. Preview the next semantic version from Conventional Commits
    uvx cocogitto cog bump --dry-run --auto
    
    # 3. Build the release notes from towncrier fragments
    #    towncrier headings use X.Y.Z, while the git tag stays vX.Y.Z
    uvx towncrier build --version "1.7.1"
    
    # 4. Commit the release notes (historically: release: vX.Y.Z)
    git add CHANGELOG.rst docs/newsfragments
    git commit -m "release: v1.7.1"
    
    # 5. Tag the release commit (hatch-vcs derives the package version from tags)
    uvx cocogitto cog bump --auto
    
    # 6. Push main and tags; GitHub Actions handles build/publish/release
    git push origin main --tags

The existing `.github/workflows/release.yml` publishes to PyPI and creates the
GitHub release when a `v*` tag is pushed.


<a id="license"></a>

# License

MIT. However, this is an academic resource, so **please cite** as much as possible
via:

-   The [Zenodo DOI](https://doi.org/10.5281/zenodo.18529798) for general use.
-   The `wailord` paper for ORCA usage

