|
| 1 | +# RMG-Py Copilot Instructions |
| 2 | + |
| 3 | +## Project Overview |
| 4 | +RMG-Py is the Reaction Mechanism Generator - an automatic chemical kinetics mechanism generator. It consists of two main components: |
| 5 | +- **RMG** (`rmgpy/`): Core mechanism generation engine |
| 6 | +- **Arkane** (`arkane/`): Statistical mechanics and transition state theory calculations |
| 7 | + |
| 8 | +## Architecture |
| 9 | + |
| 10 | +### Core Packages |
| 11 | +- `rmgpy/molecule/` - Molecular graph representation (`Molecule`, `Atom`, `Bond`, `Group`) |
| 12 | +- `rmgpy/thermo/` - Thermodynamic models (NASA, Wilhoit, ThermoData) |
| 13 | +- `rmgpy/kinetics/` - Rate coefficient models (Arrhenius, Chebyshev, pressure-dependent) |
| 14 | +- `rmgpy/solver/` - ODE solvers for reactor simulations |
| 15 | +- `rmgpy/rmg/` - Main RMG algorithm (`main.py`, `model.py`, `react.py`) |
| 16 | +- `rmgpy/data/` - Database interfaces for thermo, kinetics, transport |
| 17 | + |
| 18 | +### Key Base Classes |
| 19 | +- `RMGObject` (in `rmgpy/rmgobject.pyx`) - Base class providing `as_dict()`/`make_object()` for YAML serialization |
| 20 | +- `Graph`/`Vertex`/`Edge` (in `rmgpy/molecule/graph.pyx`) - Graph isomorphism via VF2 algorithm |
| 21 | +- `Species` and `Reaction` are central objects connecting molecules to thermodynamics and kinetics |
| 22 | + |
| 23 | +### Cython Architecture |
| 24 | +Performance-critical code uses Cython (`.pyx` files) with declaration files (`.pxd`): |
| 25 | +- 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. |
| 26 | +- Always pair `.pyx` (or cythonized `.py`) with `.pxd` for public cdef classes/methods |
| 27 | +- Use `cpdef` for methods callable from both Python and Cython |
| 28 | +- Use `cimport` for Cython-level imports (e.g., `cimport rmgpy.constants as constants`) |
| 29 | +- Register new Cython modules in `setup.py` `ext_modules` list |
| 30 | +- 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. |
| 31 | + |
| 32 | +## Development Commands |
| 33 | +```bash |
| 34 | +make install # First-time pip editable install + Cython build. Writes a .installed sentinel; subsequent `make install` is a no-op until `make clean`. |
| 35 | +make build # Incremental in-place Cython rebuild (`setup.py build_ext --inplace`). Fast — use this after editing .pyx/.pxd/cythonized .py. |
| 36 | +make # Default target: dep check, install if needed (via sentinel), then `make build`. Safe go-to. |
| 37 | +make test # Run unit tests (excludes functional/database tests) |
| 38 | +make test-functional # Run functional tests |
| 39 | +make test-database # Run database tests |
| 40 | +make test-all # Run all tests |
| 41 | +make clean # Remove .so/.pyc/.c build artifacts, the build/ dir, the .installed sentinel, and pip-uninstall the package. |
| 42 | +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. |
| 43 | +make documentation # Build Sphinx docs |
| 44 | +``` |
| 45 | + |
| 46 | +## Testing Conventions |
| 47 | +- Tests live in `test/` mirroring `rmgpy/` and `arkane/` structure |
| 48 | +- Test files: `*Test.py` (e.g., `speciesTest.py`, `reactionTest.py`) |
| 49 | +- Test classes: `class TestClassName:` or `class ClassNameTest:` |
| 50 | +- Use `pytest` with fixtures (`@pytest.fixture(autouse=True)` for setup) |
| 51 | +- Markers: `@pytest.mark.functional`, `@pytest.mark.database` |
| 52 | +- Run specific tests: `pytest -k "test_name_pattern"` |
| 53 | + |
| 54 | +## Code Patterns |
| 55 | + |
| 56 | +### Molecular Representations |
| 57 | +```python |
| 58 | +from rmgpy.molecule import Molecule |
| 59 | +mol = Molecule().from_smiles("CC") # From SMILES |
| 60 | +mol = Molecule().from_adjacency_list("""...""") # From adjacency list |
| 61 | +mol.is_isomorphic(other_mol) # Graph isomorphism check |
| 62 | +``` |
| 63 | + |
| 64 | +### Species and Reactions |
| 65 | +```python |
| 66 | +from rmgpy.species import Species |
| 67 | +species = Species(label='ethane', molecule=[Molecule().from_smiles("CC")]) |
| 68 | +species.generate_resonance_structures() |
| 69 | +``` |
| 70 | + |
| 71 | +```python |
| 72 | +from rmgpy.reaction import Reaction |
| 73 | +from rmgpy.kinetics import Arrhenius |
| 74 | + |
| 75 | +# Reaction with Arrhenius kinetics |
| 76 | +rxn = Reaction( |
| 77 | + reactants=[Species(label='CH3', molecule=[Molecule(smiles='[CH3]')]), |
| 78 | + Species(label='O2', molecule=[Molecule(smiles='[O][O]')])], |
| 79 | + products=[Species(label='CH3OO', molecule=[Molecule(smiles='CO[O]')])], |
| 80 | + kinetics=Arrhenius(A=(2.65e12, 'cm^3/(mol*s)'), n=0.0, Ea=(0.0, 'kJ/mol'), T0=(1, 'K')), |
| 81 | +) |
| 82 | + |
| 83 | +# Reaction without kinetics (e.g. for isomorphism checks) |
| 84 | +rxn2 = Reaction( |
| 85 | + reactants=[Species().from_smiles('[O]'), Species().from_smiles('O=S=O')], |
| 86 | + products=[Species().from_smiles('O=S(=O)=O')], |
| 87 | +) |
| 88 | +``` |
| 89 | + |
| 90 | + |
| 91 | +## Input Files |
| 92 | +- RMG inputs: Python scripts defining `database()`, `species()`, `simpleReactor()`, etc. |
| 93 | +- See `examples/rmg/minimal/input.py` for structure and `examples/rmg/commented/input.py` for a file with detailed comments |
| 94 | +- Arkane inputs: Python scripts with `species()`, `transitionState()`, `reaction()` blocks |
| 95 | +- See `examples/arkane/` for examples |
| 96 | + |
| 97 | +## RMG-database Integration |
| 98 | +The **RMG-database** is a separate repository containing all thermodynamic, kinetics, and transport data. It's typically cloned alongside RMG-Py in a sibling folder named `RMG-database`. |
| 99 | + |
| 100 | +### Database Structure (in RMG-database `input/` directory, eg. `RMG-database/input/thermo/`) |
| 101 | +- `thermo/` - Thermodynamic libraries and group additivity data |
| 102 | +- `kinetics/families/` - Reaction family templates with rate rules (e.g., `H_Abstraction`, `R_Addition_MultipleBond`) |
| 103 | +- `kinetics/libraries/` - Curated rate coefficient libraries |
| 104 | +- `solvation/` - Solvent and solute parameters |
| 105 | +- `transport/` - Transport properties |
| 106 | + |
| 107 | +### How RMG-Py Loads the Database |
| 108 | +The `RMGDatabase` class (`rmgpy/data/rmg.py`) is the central interface: |
| 109 | +```python |
| 110 | +from rmgpy.data.rmg import RMGDatabase |
| 111 | +database = RMGDatabase() |
| 112 | +database.load( |
| 113 | + path='/path/to/RMG-database/input', |
| 114 | + thermo_libraries=['primaryThermoLibrary'], |
| 115 | + kinetics_families='default', |
| 116 | + reaction_libraries=[], |
| 117 | +) |
| 118 | +``` |
| 119 | + |
| 120 | +### Key Database Classes |
| 121 | +- `ThermoDatabase` (`rmgpy/data/thermo.py`) - Estimates thermo via group additivity or libraries |
| 122 | +- `KineticsDatabase` (`rmgpy/data/kinetics/database.py`) - Manages reaction families and libraries |
| 123 | +- `KineticsFamily` (`rmgpy/data/kinetics/family.py`) - Template-based reaction generation using `Group` pattern matching |
| 124 | +- `Entry` (`rmgpy/data/base.py`) - Base class for database entries with metadata |
| 125 | + |
| 126 | +### Data Flow for Species Thermodynamics |
| 127 | +1. `Species.get_thermo_data()` → `rmgpy.thermo.thermoengine.submit(species)` |
| 128 | +2. `thermoengine.submit()` generates resonance structures, then dispatches to `ThermoDatabase.get_thermo_data(species)` |
| 129 | +3. `ThermoDatabase` first checks thermo libraries for an exact match (via graph isomorphism) |
| 130 | +4. If no library match is found, `ThermoDatabase` falls back to group additivity estimation using functional group contributions |
| 131 | +5. The resolved result is returned as a `ThermoData`, `NASA`, or `Wilhoit` object |
| 132 | + |
| 133 | + |
| 134 | +### Data Flow for Reaction Kinetics |
| 135 | +1. `KineticsFamily.generate_reactions(reactants)` - Matches reactant molecules to family templates |
| 136 | +2. Creates `TemplateReaction` objects with labeled atoms from template matching |
| 137 | +3. `KineticsFamily.get_kinetics()` - Estimates rate using rate rules or training reactions |
| 138 | +4. Returns `Arrhenius` or pressure-dependent kinetics model |
| 139 | + |
| 140 | +## External Dependencies |
| 141 | +- **RMG-database**: In CI, `RMG_DATABASE_BRANCH` controls which RMG-database branch is cloned. Locally, the database location is set via `settings['database.directory']` (default `../RMG-database/input`) or `database.directory` in an `rmgrc` file; you may also pass an explicit path to `database.load()`. |
| 142 | +- **Julia/RMS**: Optional (recommended) reactor simulation backend (install via `./install_rms.sh`) |
| 143 | +- Environment managed via `environment.yml` (conda/mamba) |
| 144 | + |
| 145 | +## Documentation |
| 146 | +Documentation lives in `documentation/source/` and is built with Sphinx (`make documentation`). |
| 147 | + |
| 148 | +### User Documentation (`documentation/source/users/`) |
| 149 | +- `users/rmg/` - RMG user guide (how to run, configure, interpret output) |
| 150 | +- `users/arkane/` - Arkane user guide |
| 151 | +- **Critical file**: `users/rmg/input.rst` - Documents all input file options. **Must be updated when changing input file syntax or adding new features.** |
| 152 | + |
| 153 | +### API Reference (`documentation/source/reference/`) |
| 154 | +- Auto-generated from docstrings using `sphinx.ext.autodoc` |
| 155 | +- Each module has a corresponding `.rst` file (e.g., `documentation/source/reference/species/index.rst` → `rmgpy/species.py`) |
| 156 | +- **Maintenance**: Add new modules to the appropriate `index.rst` toctree. Docstrings in code are automatically extracted. |
| 157 | +- Uses reStructuredText format with `.. automodule::` directives |
| 158 | + |
| 159 | +### When to Update Documentation |
| 160 | +- **New input file options**: Update `documentation/source/users/rmg/input.rst` |
| 161 | +- **New public API**: Ensure docstrings exist; add module to `documentation/source/reference/` if new |
| 162 | +- **Changed behavior**: Update relevant user guide section |
| 163 | +- **New features**: Add to `documentation/source/users/rmg/features.rst` or create and link to new `.rst` file |
| 164 | + |
| 165 | +## Pull Request Review Guidance |
| 166 | +### Review Priorities |
| 167 | +- Verify changed behavior is covered by tests, or request targeted tests for uncovered paths. |
| 168 | +- Check that user-facing changes include required documentation updates (especially input syntax in `documentation/source/users/rmg/input.rst`). |
| 169 | +- Confirm Cython changes are complete (`.pyx`/`.pxd` parity, required setup wiring, and likely rebuild impact). |
| 170 | +- Watch for performance regressions in hot paths (`rmgpy/molecule/`, `rmgpy/solver/`, kinetics generation loops). |
| 171 | + |
| 172 | +### Other checks |
| 173 | +- If `environment.yml` or `.conda/meta.yaml` change, verify they are consistent. |
| 174 | +- For changes that affect data loading or estimators, verify assumptions against RMG-database integration points in `rmgpy/data/rmg.py` and related loaders. |
| 175 | + |
| 176 | +## Style Guidelines |
| 177 | +- Follow PEP 8 for new or modified code, but don't modify code just to fix style |
| 178 | +- Docstrings describe purpose, not implementation |
| 179 | +- Use `logging` module (not print statements) |
| 180 | +- MIT license header required on all source files |
0 commit comments