diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 44ff819ea3..2ca3150a54 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -22,21 +22,24 @@ RMG-Py is the Reaction Mechanism Generator - an automatic chemical kinetics mech ### Cython Architecture Performance-critical code uses Cython (`.pyx` files) with declaration files (`.pxd`): -- Always pair `.pyx` with `.pxd` for public cdef classes/methods +- Some `.py` files are also cythonized — they have a `.pxd` sibling and are listed in `setup.py` `ext_modules` (e.g. `rmgpy/species.py`, `rmgpy/reaction.py`, `rmgpy/quantity.py`, `rmgpy/constants.py`, and most of `rmgpy/molecule/`). The compiled `.so` is what gets imported, so edits won't take effect until rebuilt. +- Always pair `.pyx` (or cythonized `.py`) with `.pxd` for public cdef classes/methods - Use `cpdef` for methods callable from both Python and Cython - Use `cimport` for Cython-level imports (e.g., `cimport rmgpy.constants as constants`) - Register new Cython modules in `setup.py` `ext_modules` list -- Remember to re-compile (e.g. run `make`) after modifying any `.pyx` or `.pxd` files, or if there seem to be weird bugs in them. +- Remember to re-compile (`make build`) after modifying any `.pyx`, `.pxd`, or cythonized `.py` file, or if there seem to be weird bugs in them. ## Development Commands ```bash -make install # Build Cython extensions and install in editable mode +make install # First-time pip editable install + Cython build. Writes a .installed sentinel; subsequent `make install` is a no-op until `make clean`. +make build # Incremental in-place Cython rebuild (`setup.py build_ext --inplace`). Fast — use this after editing .pyx/.pxd/cythonized .py. +make # Default target: dep check, install if needed (via sentinel), then `make build`. Safe go-to. make test # Run unit tests (excludes functional/database tests) make test-functional # Run functional tests make test-database # Run database tests make test-all # Run all tests -make clean # Remove build artifacts -make decython # Remove .so files for "pure Python" debugging. Pure python mode is not reliably tested and might not work. +make clean # Remove .so/.pyc/.c build artifacts, the build/ dir, the .installed sentinel, and pip-uninstall the package. +make decython # Remove most .so files for "pure Python" debugging (keeps _statmech.so, quantity.so, and rmgpy/solver/*.so). Pure python mode is not reliably tested and might not work. make documentation # Build Sphinx docs ``` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..12c3d571bd --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,143 @@ +# CLAUDE.md + +Guidance for AI agents working in this repo. Also read [.github/copilot-instructions.md](.github/copilot-instructions.md) for project overview, package layout, and code patterns. This file focuses on the non-obvious mechanics of building, testing, and contributing. + +## What this repo is + +**RMG-Py** = Reaction Mechanism Generator (chemical kinetics mechanism generator). Two installable packages: `rmgpy/` (mechanism generation) and `arkane/` (statistical mechanics from QM calculations). Heavy use of Cython for performance. Depends on a sibling repo **RMG-database** for thermo/kinetics data. + +Entry points: +- `rmg.py ` — runs RMG on a Python-style input file (see `examples/rmg/minimal/input.py`) +- `Arkane.py ` — runs Arkane +- Both are also installed as console scripts (`rmg.py`, `Arkane.py`) via `setup.py`. They thin-wrap `rmgpy.__main__:main` / `arkane.__main__:main`. +- Scripts under `scripts/` are also installed (e.g. `simulate.py`, `diffModels.py`, `mergeModels.py`, `rmg2to3.py`). + +## Setup + +The conda env is the only supported install path. Python is pinned `>=3.9,<3.12`. + +```bash +conda env create --file environment.yml # creates env named `rmg_env` +conda activate rmg_env +git clone https://github.com/ReactionMechanismGenerator/RMG-database ../RMG-database +make install +``` + +`make install` runs `python utilities.py check-pydas` (which writes [rmgpy/solver/settings.pxi](rmgpy/solver/settings.pxi) — see Cython section), then `pip install --no-build-isolation -vv -e .`, then touches a `.installed` sentinel. Subsequent `make` invocations skip reinstall unless the sentinel is missing. + +**Always keep [environment.yml](environment.yml) and [.conda/meta.yaml](.conda/meta.yaml) in sync** — both define runtime deps and CI builds from `meta.yaml` for the conda package. + +Optional pieces: +- `./install_rms.sh` — installs ReactionMechanismSimulator (Julia-based reactor backend). Required for `rms*` reactor types in input files. Honors `RMS_INSTALLER={continuous,standard,developer}` and `RMS_BRANCH` (default `for_rmg`). +- `make q2dtor` — clones Q2DTor into `external/` for 2D rotor calculations in Arkane. + +## Build / Cython + +Cython modules are listed explicitly in `setup.py` `ext_modules`. **Some `.py` files are cythonized** (not just `.pyx`): e.g. `rmgpy/molecule/molecule.py`, `group.py`, `atomtype.py`, `rmgpy/species.py`, `rmgpy/reaction.py`, `rmgpy/quantity.py`, `rmgpy/constants.py`. If you edit one of these, **rebuild** — the `.so` is what gets imported, not the `.py`. + +Workflow: +- `make build` — incremental in-place `setup.py build_ext --inplace`. Fast. Use this after editing `.pyx`/`.pxd`/cythonized `.py`. +- `make` (default `all`) — checks deps, ensures `.installed` sentinel, then `make build`. Safe go-to. +- `make clean` — removes `.so`, `.pyc`, generated `.c`, `build/`, and `.installed`. Also `pip uninstall`s the package. +- `make decython` — deletes most `.so` files (keeps `_statmech.so`, `quantity.so`, and `rmgpy/solver/*.so`) so pure Python is loaded for debugging. **Pure Python mode is not reliably tested**; expect breakage. + +Cython conventions in this repo: +- Compile language level is Python 3. +- Pair every public `cdef class` / `cpdef` method with a `.pxd` declaration. +- New extension files **must be added to `ext_modules` in `setup.py`** or they will silently not be built. +- The DASPK/DASSL solver is selected at compile time via `rmgpy/solver/settings.pxi` (auto-written by `utilities.py check-pydas` from whatever PyDAS variant is installed). Do not commit changes to `settings.pxi`. +- macOS-specific: `setup.py` deduplicates `-Wl,-rpath` flags from sysconfig before invoking Cython, to work around an LC_RPATH issue with conda-forge's Python on darwin. Don't remove that block. + +## Tests + +Configured in [pytest.ini](pytest.ini): `testpaths = test`, `python_files = *Test.py`, `python_classes = *Test Test*`. Tests live under `test/` mirroring `rmgpy/` and `arkane/`. + +Default pytest flags include `-s -vv --keep-duplicates` and coverage (`--cov=arkane --cov=rmgpy --cov-report html`). `test/regression/` is excluded. + +Markers (from `pytest.ini`): +- `@pytest.mark.functional` — slower functional tests +- `@pytest.mark.database` — tests that require RMG-database to be cloned and loaded +- Unmarked = unit tests + +Make targets: +```bash +make test # unit tests only (excludes functional, database) +make test-functional +make test-database +make test-all # everything +``` + +Run a subset directly: +```bash +pytest test/rmgpy/molecule/atomtypeTest.py +pytest -k "test_pattern" +pytest -m "functional" +``` + +`pytest-xdist` (`-n auto`) is supported but **incompatible with RMS/Julia** — only use when RMS is not installed. + +`test/conftest.py` forces `multiprocessing.set_start_method('fork')` and silences OpenBabel error logging. Be aware of the `fork` start method when adding tests that touch multiprocessing. + +### Regression tests + +Separate from pytest. Each `test/regression//` has an `input.py`. CI runs `python rmg.py test/regression//input.py` and diffs core/edge models against artifacts produced on `main`. Locally you can reproduce a single one: +```bash +python rmg.py test/regression/superminimal/input.py +python scripts/checkModels.py ... # (see .github/workflows/CI.yml for arg shape) +``` +Adding a new regression test means editing the **two lists** in [.github/workflows/CI.yml](.github/workflows/CI.yml) (Execution + Comparison steps); the first PR will fail CI until baseline artifacts exist on `main`. + +The `Makefile` also has `eg0`-`eg10` targets that copy example inputs into `testing//` and run `rmg.py` — useful for ad-hoc end-to-end smoke testing (`eg0` is fastest). + +## Linting / formatting / typing + +There is **no configured linter, formatter, or type checker** in this repo (no `pyproject.toml`, `ruff.toml`, `.flake8`, `mypy.ini`, or `pre-commit` config). The only style guidance is "follow PEP 8 for new code, but don't churn existing code just for style." Don't run `black`/`ruff format`/`isort` over the tree as part of unrelated changes — diffs balloon and reviews stall. + +## Database integration + +RMG looks up `database.directory` in this order: +1. `database.load(path=...)` arg in code +2. `rmgrc` in cwd +3. `~/.rmg/rmgrc` +4. `rmgpy/rmgrc` (alongside the package) +5. Default: `../RMG-database/input` relative to RMG-Py source + +Template: [rmgpy/rmgrc_template](rmgpy/rmgrc_template). Copy it (don't edit in place — it's overwritten on install). In CI, the database is checked out at the branch named in `RMG_DATABASE_BRANCH` (env var in [.github/workflows/CI.yml](.github/workflows/CI.yml)); change that line if your PR depends on an unmerged database branch. + +## Conventions + +- **Python API uses `snake_case`**. +- **Input file DSL keeps `camelCase`** (`thermoLibraries`, `simpleReactor`, `terminationConversion`, ...) for backward compatibility. When adding a new input keyword, follow camelCase and update [documentation/source/users/rmg/input.rst](documentation/source/users/rmg/input.rst). +- All source files require the MIT license header (template lives in [LICENSE.txt](LICENSE.txt); `python utilities.py update-headers` re-applies it across `.py`/`.pyx`/`.pxd` in `rmgpy/`, `scripts/`, and the root). +- Use `logging` not `print`. +- Don't reach for `__init__.py`-as-namespace imports across cython modules; use `cimport rmgpy.constants as constants` etc. +- Git commit messages should include a short summary (one line), followed by a blank line, then a more detailed description that explains the motivation and rationale for the change, so that a human code reviewer can understand without the context of the conversation. + +## Documentation + +Sphinx docs in `documentation/source/`. Build with `make documentation` (calls `make -C documentation html`). Output: `documentation/build/html/index.html`. Built with the standard `rmg_env` (no separate doc env). + +When changing things, also update: +- **Input file syntax / new options** → [documentation/source/users/rmg/input.rst](documentation/source/users/rmg/input.rst) (this is treated as required by reviewers). +- **New public API** → ensure docstrings exist; add module to a toctree under `documentation/source/reference/` if the module is new. API docs are auto-generated via `sphinx.ext.autodoc`. +- **New user-facing feature** → mention in `documentation/source/users/rmg/features.rst` or a sibling `.rst`. +- **Behavior change** → relevant section of the user guide (`users/rmg/` or `users/arkane/`). + +You should keep this documentation (CLAUDE.md) up to date as needed. +Always make changes to this file in a separate commit for clarity, and explain in detail to the user why changes were necessary. + +The `gh-pages` branch hosts the live site; CI publishes on push to `main`. + +## CI + +- [.github/workflows/CI.yml](.github/workflows/CI.yml): build + tests on Linux (ubuntu-latest, all Python versions, with and without RMS) and macOS (latest Python only). Linux runs `make test-all`; other matrix entries run only unit tests. Regression job runs separately on `ubuntu-latest`. +- [.github/workflows/conda_build.yml](.github/workflows/conda_build.yml): builds the conda package from [.conda/meta.yaml](.conda/meta.yaml). +- [.github/workflows/docs.yml](.github/workflows/docs.yml): Sphinx build + publish to `gh-pages`. + +## Quick gotchas + +- **Edits to `.pyx`/`.pxd`/cythonized `.py` won't take effect until you rebuild** (`make build`). Mysterious unchanged behavior is almost always a stale `.so`. +- **`.so` files persist across branch switches.** When chasing a weird bug after a checkout, `make clean && make` before debugging. +- **Don't use `--no-verify` or skip Cython rebuilds** to make a commit go through; the underlying issue will resurface in CI. +- **Functional/database tests need RMG-database checked out** at a compatible branch in `../RMG-database`. +- **RMS reactor types in input files require Julia** — without `install_rms.sh` they'll fail at runtime, not import.