|
| 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 | +- Always pair `.pyx` with `.pxd` for public cdef classes/methods |
| 26 | +- Use `cpdef` for methods callable from both Python and Cython |
| 27 | +- Use `cimport` for Cython-level imports (e.g., `cimport rmgpy.constants as constants`) |
| 28 | +- Register new Cython modules in `setup.py` `ext_modules` list |
| 29 | + |
| 30 | +## Development Commands |
| 31 | +```bash |
| 32 | +make install # Build Cython extensions and install in editable mode |
| 33 | +make test # Run unit tests (excludes functional/database tests) |
| 34 | +make test-functional # Run functional tests |
| 35 | +make test-database # Run database tests |
| 36 | +make test-all # Run all tests |
| 37 | +make clean # Remove build artifacts |
| 38 | +make decython # Remove .so files for "pure Python" debugging. Pure python mode is not reliably tested and might not work. |
| 39 | +make documentation # Build Sphinx docs |
| 40 | +``` |
| 41 | + |
| 42 | +## Testing Conventions |
| 43 | +- Tests live in `test/` mirroring `rmgpy/` and `arkane/` structure |
| 44 | +- Test files: `*Test.py` (e.g., `speciesTest.py`, `reactionTest.py`) |
| 45 | +- Test classes: `class TestClassName:` or `class ClassNameTest:` |
| 46 | +- Use `pytest` with fixtures (`@pytest.fixture(autouse=True)` for setup) |
| 47 | +- Markers: `@pytest.mark.functional`, `@pytest.mark.database` |
| 48 | +- Run specific tests: `pytest -k "test_name_pattern"` |
| 49 | + |
| 50 | +## Code Patterns |
| 51 | + |
| 52 | +### Molecular Representations |
| 53 | +```python |
| 54 | +from rmgpy.molecule import Molecule |
| 55 | +mol = Molecule().from_smiles("CC") # From SMILES |
| 56 | +mol = Molecule().from_adjacency_list("""...""") # From adjacency list |
| 57 | +mol.is_isomorphic(other_mol) # Graph isomorphism check |
| 58 | +``` |
| 59 | + |
| 60 | +### Species and Reactions |
| 61 | +```python |
| 62 | +from rmgpy.species import Species |
| 63 | +species = Species(label='ethane', molecule=[Molecule().from_smiles("CC")]) |
| 64 | +species.generate_resonance_structures() |
| 65 | +``` |
| 66 | + |
| 67 | +```python |
| 68 | +from rmgpy.reaction import Reaction |
| 69 | +from rmgpy.kinetics import Arrhenius |
| 70 | + |
| 71 | +# Reaction with Arrhenius kinetics |
| 72 | +rxn = Reaction( |
| 73 | + reactants=[Species(label='CH3', molecule=[Molecule(smiles='[CH3]')]), |
| 74 | + Species(label='O2', molecule=[Molecule(smiles='[O][O]')])], |
| 75 | + products=[Species(label='CH3OO', molecule=[Molecule(smiles='CO[O]')])], |
| 76 | + kinetics=Arrhenius(A=(2.65e12, 'cm^3/(mol*s)'), n=0.0, Ea=(0.0, 'kJ/mol'), T0=(1, 'K')), |
| 77 | +) |
| 78 | + |
| 79 | +# Reaction without kinetics (e.g. for isomorphism checks) |
| 80 | +rxn2 = Reaction( |
| 81 | + reactants=[Species().from_smiles('[O]'), Species().from_smiles('O=S=O')], |
| 82 | + products=[Species().from_smiles('O=S(=O)=O')], |
| 83 | +) |
| 84 | +``` |
| 85 | + |
| 86 | + |
| 87 | +## Input Files |
| 88 | +- RMG inputs: Python scripts defining `database()`, `species()`, `simpleReactor()`, etc. |
| 89 | +- See `examples/rmg/minimal/input.py` for structure and `examples/rmg/commented/input.py` for a file with detailed comments |
| 90 | +- Arkane inputs: Python scripts with `species()`, `transitionState()`, `reaction()` blocks |
| 91 | +- See `examples/arkane/` for examples |
| 92 | + |
| 93 | +## RMG-database Integration |
| 94 | +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`. |
| 95 | + |
| 96 | +### Database Structure (in RMG-database `input/` directory, eg. `RMG-database/input/thermo/`) |
| 97 | +- `thermo/` - Thermodynamic libraries and group additivity data |
| 98 | +- `kinetics/families/` - Reaction family templates with rate rules (e.g., `H_Abstraction`, `R_Addition_MultipleBond`) |
| 99 | +- `kinetics/libraries/` - Curated rate coefficient libraries |
| 100 | +- `solvation/` - Solvent and solute parameters |
| 101 | +- `transport/` - Transport properties |
| 102 | + |
| 103 | +### How RMG-Py Loads the Database |
| 104 | +The `RMGDatabase` class (`rmgpy/data/rmg.py`) is the central interface: |
| 105 | +```python |
| 106 | +from rmgpy.data.rmg import RMGDatabase |
| 107 | +database = RMGDatabase() |
| 108 | +database.load( |
| 109 | + path='/path/to/RMG-database/input', |
| 110 | + thermo_libraries=['primaryThermoLibrary'], |
| 111 | + kinetics_families='default', |
| 112 | + reaction_libraries=[], |
| 113 | +) |
| 114 | +``` |
| 115 | + |
| 116 | +### Key Database Classes |
| 117 | +- `ThermoDatabase` (`rmgpy/data/thermo.py`) - Estimates thermo via group additivity or libraries |
| 118 | +- `KineticsDatabase` (`rmgpy/data/kinetics/database.py`) - Manages reaction families and libraries |
| 119 | +- `KineticsFamily` (`rmgpy/data/kinetics/family.py`) - Template-based reaction generation using `Group` pattern matching |
| 120 | +- `Entry` (`rmgpy/data/base.py`) - Base class for database entries with metadata |
| 121 | + |
| 122 | +### Data Flow for Species Thermodynamics |
| 123 | +1. `Species.get_thermo_data()` → `rmgpy.thermo.thermoengine.submit(species)` |
| 124 | +2. `thermoengine.submit()` generates resonance structures, then dispatches to `ThermoDatabase.get_thermo_data(species)` |
| 125 | +3. `ThermoDatabase` first checks thermo libraries for an exact match (via graph isomorphism) |
| 126 | +4. If no library match is found, `ThermoDatabase` falls back to group additivity estimation using functional group contributions |
| 127 | +5. The resolved result is returned as a `ThermoData`, `NASA`, or `Wilhoit` object |
| 128 | + |
| 129 | + |
| 130 | +### Data Flow for Reaction Kinetics |
| 131 | +1. `KineticsFamily.generate_reactions(reactants)` - Matches reactant molecules to family templates |
| 132 | +2. Creates `TemplateReaction` objects with labeled atoms from template matching |
| 133 | +3. `KineticsFamily.get_kinetics()` - Estimates rate using rate rules or training reactions |
| 134 | +4. Returns `Arrhenius` or pressure-dependent kinetics model |
| 135 | + |
| 136 | +## External Dependencies |
| 137 | +- **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()`. |
| 138 | +- **Julia/RMS**: Optional (recommended) reactor simulation backend (install via `./install_rms.sh`) |
| 139 | +- Environment managed via `environment.yml` (conda/mamba) |
| 140 | + |
| 141 | +## Documentation |
| 142 | +Documentation lives in `documentation/source/` and is built with Sphinx (`make documentation`). |
| 143 | + |
| 144 | +### User Documentation (`documentation/source/users/`) |
| 145 | +- `users/rmg/` - RMG user guide (how to run, configure, interpret output) |
| 146 | +- `users/arkane/` - Arkane user guide |
| 147 | +- **Critical file**: `users/rmg/input.rst` - Documents all input file options. **Must be updated when changing input file syntax or adding new features.** |
| 148 | + |
| 149 | +### API Reference (`documentation/source/reference/`) |
| 150 | +- Auto-generated from docstrings using `sphinx.ext.autodoc` |
| 151 | +- Each module has a corresponding `.rst` file (e.g., `documentation/source/reference/species/index.rst` → `rmgpy/species.py`) |
| 152 | +- **Maintenance**: Add new modules to the appropriate `index.rst` toctree. Docstrings in code are automatically extracted. |
| 153 | +- Uses reStructuredText format with `.. automodule::` directives |
| 154 | + |
| 155 | +### When to Update Documentation |
| 156 | +- **New input file options**: Update `documentation/source/users/rmg/input.rst` |
| 157 | +- **New public API**: Ensure docstrings exist; add module to `documentation/source/reference/` if new |
| 158 | +- **Changed behavior**: Update relevant user guide section |
| 159 | +- **New features**: Add to `documentation/source/users/rmg/features.rst` or create and link to new `.rst` file |
| 160 | + |
| 161 | +## Style Guidelines |
| 162 | +- Follow PEP 8 for new or modified code, but don't modify code just to fix style |
| 163 | +- Docstrings describe purpose, not implementation |
| 164 | +- Use `logging` module (not print statements) |
| 165 | +- MIT license header required on all source files |
0 commit comments