discopt-mkm
Describe a catalytic mechanism as data (a spec) and get structured results.
Use from discopt.mkm import agent (each function takes a spec dict, returns
JSON-able data) or the MCP tools of the same names. Do not hand-write the
operator DSL (m.step(CO + s >> COs)); always pass a spec.
Spec
name: co_oxidation
T: 500 # temperature
R: 8.617e-5 # gas constant — MUST match your energy units (see Units)
Tref: 298.15
sites: [{name: "*", density: 1.0}]
gas: [{name: CO, H: 0.0, S: 0.0020}, {name: O2, H: 0.0, S: 0.0021}, {name: CO2, H: -3.0, S: 0.0023}]
adsorbates: [{name: "CO*", site: "*", H: -0.8, S: 0.0005}, {name: "O*", site: "*", H: -0.3, S: 0.0005}]
reactions:
- {equation: "CO + * <=> CO*", A: 1e4, Ea: 0.0} # Arrhenius; reverse from thermo
- {equation: "O2 + 2 * <=> 2 O*", A: 1e4, Ea: 0.0}
- {equation: "CO* + O* -> CO2 + 2 *", A: 1e8, Ea: 0.7} # '->' = irreversible
reactor: {type: differential, pressures: {CO: 1.0, O2: 0.5, CO2: 0.0}}
Equations: <=> reversible, -> irreversible; terms are coeff species
(coefficient optional), site/adsorbate * allowed.
Per-reaction kinetics (choose one): A+Ea (Arrhenius, reverse from species
thermo) · kf+Keq (explicit constants) · equilibrated: true (quasi-
equilibrium for fast steps; give Keq or rely on thermo). Add irreversible: true to force kr=0, alpha: <0..1> for a BEP coverage-dependent barrier.
Optional: interactions: [{a: "CO*", b: "O*", eps: 0.1}], per-species
composition: {C: 1, O: 1} (else inferred from the name), per-species thermo: {type: nasa7, low: [...], high: [...]} or {type: shomate, coeffs: [A..H]}.
Reactor types: differential (fixed pressures), cstr (inlet, tau,
cat_density), batch.
Tools / functions (spec in, JSON out)
validate(spec) → {ok, errors, warnings, info}. Call first: parses and
checks element + site mass balance; fix errors before solving.
structure(spec) → overall reaction, independent reactions, conservation laws.
solve(spec, coordinates="linear") → coverages, gas, rates, status.
degree_of_rate_control(spec, target) → {step: X_RC} (sums to ~1).
apparent_kinetics(spec, target) → apparent orders + apparent activation energy.
analyze(spec, target) → all of the above in one call. Prefer this.
report(spec, target, path=...) → self-contained HTML report.
target is a gas-product species name; defaults to a net-produced gas species.
Decision guide
- Reactor: fixed-condition rate/DRC →
differential; conversion with flow →
cstr; time evolution → batch (use solve_transient, not these tools).
coordinates: default "linear"; use "log" for stiff near-equilibrium
mechanisms (e.g. water-gas shift) — solve/analyze auto-warm-start it.
- Fast steps you want to assume equilibrated →
equilibrated: true (removes
stiffness; reports degree of rate control = 0 for those steps by construction).
- If
degree_of_rate_control returns drc: null, a coverage is pinned near 0/1
— retry with coordinates="log".
Units (important)
Unit-agnostic — keep H, S, Cp, Ea, R consistent: eV & eV/K → R = 8.617e-5;
J/mol & J/(mol·K) → R = 8.314. Apparent Ea returns in the energy units of R.
1---2name: discopt-mkm3description: Build and analyze heterogeneous-catalysis microkinetic models — steady-state coverages, turnover frequency, Campbell degree of rate control, apparent reaction orders / activation energy, reaction routes and the overall reaction, lumped (Langmuir-Hinshelwood) rate laws, and HTML reports. Use whenever the user describes a catalytic reaction mechanism, surface kinetics, adsorbates and sites, coverages, rate-determining or rate-controlling steps, or asks to solve or analyze a microkinetic model.4---56# discopt-mkm78Describe a catalytic mechanism as **data** (a spec) and get **structured** results.9Use `from discopt.mkm import agent` (each function takes a spec dict, returns10JSON-able data) or the MCP tools of the same names. Do **not** hand-write the11operator DSL (`m.step(CO + s >> COs)`); always pass a spec.1213## Spec1415```yaml16name: co_oxidation17T: 500 # temperature18R: 8.617e-5 # gas constant — MUST match your energy units (see Units)19Tref: 298.1520sites: [{name: "*", density: 1.0}]21gas: [{name: CO, H: 0.0, S: 0.0020}, {name: O2, H: 0.0, S: 0.0021}, {name: CO2, H: -3.0, S: 0.0023}]22adsorbates: [{name: "CO*", site: "*", H: -0.8, S: 0.0005}, {name: "O*", site: "*", H: -0.3, S: 0.0005}]23reactions:24 - {equation: "CO + * <=> CO*", A: 1e4, Ea: 0.0} # Arrhenius; reverse from thermo25 - {equation: "O2 + 2 * <=> 2 O*", A: 1e4, Ea: 0.0}26 - {equation: "CO* + O* -> CO2 + 2 *", A: 1e8, Ea: 0.7} # '->' = irreversible27reactor: {type: differential, pressures: {CO: 1.0, O2: 0.5, CO2: 0.0}}28```2930Equations: `<=>` reversible, `->` irreversible; terms are `coeff species`31(coefficient optional), site/adsorbate `*` allowed.3233Per-reaction kinetics (choose one): `A`+`Ea` (Arrhenius, reverse from species34thermo) · `kf`+`Keq` (explicit constants) · `equilibrated: true` (quasi-35equilibrium for fast steps; give `Keq` or rely on thermo). Add `irreversible:36true` to force `kr=0`, `alpha: <0..1>` for a BEP coverage-dependent barrier.3738Optional: `interactions: [{a: "CO*", b: "O*", eps: 0.1}]`, per-species39`composition: {C: 1, O: 1}` (else inferred from the name), per-species `thermo:40{type: nasa7, low: [...], high: [...]}` or `{type: shomate, coeffs: [A..H]}`.41Reactor types: `differential` (fixed `pressures`), `cstr` (`inlet`, `tau`,42`cat_density`), `batch`.4344## Tools / functions (spec in, JSON out)4546- `validate(spec)` → `{ok, errors, warnings, info}`. **Call first**: parses and47 checks element + site mass balance; fix `errors` before solving.48- `structure(spec)` → overall reaction, independent reactions, conservation laws.49- `solve(spec, coordinates="linear")` → coverages, gas, rates, status.50- `degree_of_rate_control(spec, target)` → `{step: X_RC}` (sums to ~1).51- `apparent_kinetics(spec, target)` → apparent orders + apparent activation energy.52- `analyze(spec, target)` → all of the above in one call. **Prefer this.**53- `report(spec, target, path=...)` → self-contained HTML report.5455`target` is a gas-product species name; defaults to a net-produced gas species.5657## Decision guide5859- Reactor: fixed-condition rate/DRC → `differential`; conversion with flow →60 `cstr`; time evolution → `batch` (use `solve_transient`, not these tools).61- `coordinates`: default `"linear"`; use `"log"` for stiff near-equilibrium62 mechanisms (e.g. water-gas shift) — `solve`/`analyze` auto-warm-start it.63- Fast steps you want to assume equilibrated → `equilibrated: true` (removes64 stiffness; reports degree of rate control = 0 for those steps by construction).65- If `degree_of_rate_control` returns `drc: null`, a coverage is pinned near 0/166 — retry with `coordinates="log"`.6768## Units (important)6970Unit-agnostic — keep `H, S, Cp, Ea, R` consistent: eV & eV/K → `R = 8.617e-5`;71J/mol & J/(mol·K) → `R = 8.314`. Apparent `Ea` returns in the energy units of `R`.