Guidance for AI agents working in this repo. Also read .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.
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 <input.py>— runs RMG on a Python-style input file (seeexamples/rmg/minimal/input.py)Arkane.py <input.py>— runs Arkane- Both are also installed as console scripts (
rmg.py,Arkane.py) viasetup.py. They thin-wraprmgpy.__main__:main/arkane.__main__:main. - Scripts under
scripts/are also installed (e.g.simulate.py,diffModels.py,mergeModels.py,rmg2to3.py).
The conda env is the only supported install path. Python is pinned >=3.9,<3.12.
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 installmake install runs python utilities.py check-pydas (which writes 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 and .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 forrms*reactor types in input files. HonorsRMS_INSTALLER={continuous,standard,developer}andRMS_BRANCH(defaultfor_rmg).make q2dtor— clones Q2DTor intoexternal/for 2D rotor calculations in Arkane.
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-placesetup.py build_ext --inplace. Fast. Use this after editing.pyx/.pxd/cythonized.py.make(defaultall) — checks deps, ensures.installedsentinel, thenmake build. Safe go-to.make clean— removes.so,.pyc, generated.c,build/, and.installed. Alsopip uninstalls the package.make decython— deletes most.sofiles (keeps_statmech.so,quantity.so, andrmgpy/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/cpdefmethod with a.pxddeclaration. - New extension files must be added to
ext_modulesinsetup.pyor they will silently not be built. - The DASPK/DASSL solver is selected at compile time via
rmgpy/solver/settings.pxi(auto-written byutilities.py check-pydasfrom whatever PyDAS variant is installed). Do not commit changes tosettings.pxi. - macOS-specific:
setup.pydeduplicates-Wl,-rpathflags from sysconfig before invoking Cython, to work around an LC_RPATH issue with conda-forge's Python on darwin. Don't remove that block.
Configured in 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:
make test # unit tests only (excludes functional, database)
make test-functional
make test-database
make test-all # everythingRun a subset directly:
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.
Separate from pytest. Each test/regression/<name>/ has an input.py. CI runs python rmg.py test/regression/<name>/input.py and diffs core/edge models against artifacts produced on main. Locally you can reproduce a single one:
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 (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/<name>/ and run rmg.py — useful for ad-hoc end-to-end smoke testing (eg0 is fastest).
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.
RMG looks up database.directory in this order:
database.load(path=...)arg in codermgrcin cwd~/.rmg/rmgrcrmgpy/rmgrc(alongside the package)- Default:
../RMG-database/inputrelative to RMG-Py source
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); change that line if your PR depends on an unmerged database branch.
- 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. - All source files require the MIT license header (template lives in LICENSE.txt;
python utilities.py update-headersre-applies it across.py/.pyx/.pxdinrmgpy/,scripts/, and the root). - Use
loggingnotprint. - Don't reach for
__init__.py-as-namespace imports across cython modules; usecimport rmgpy.constants as constantsetc. - 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.
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 (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 viasphinx.ext.autodoc. - New user-facing feature → mention in
documentation/source/users/rmg/features.rstor a sibling.rst. - Behavior change → relevant section of the user guide (
users/rmg/orusers/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.
- .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 onubuntu-latest. - .github/workflows/conda_build.yml: builds the conda package from .conda/meta.yaml.
- .github/workflows/docs.yml: Sphinx build + publish to
gh-pages.
- Edits to
.pyx/.pxd/cythonized.pywon't take effect until you rebuild (make build). Mysterious unchanged behavior is almost always a stale.so. .sofiles persist across branch switches. When chasing a weird bug after a checkout,make clean && makebefore debugging.- Don't use
--no-verifyor 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.shthey'll fail at runtime, not import.