Source code for simulator.thermo.reactor0d

from __future__ import annotations
from dataclasses import dataclass

import math

from .thermo_state import ThermoState


[docs] @dataclass class ProgressVariableReactor: """Very simple 0-D reactor based on a single progress variable. This is *not* a detailed chemical-kinetics model. It is meant as a drop-in replacement for a Wiebe function when you want the burn shape x_b(θ) to come from an ODE rather than a closed form. State variables --------------- * lam : float Progress variable in [0, 1], analogous to mass fraction burned. * state : :class:`ThermoState` Thermodynamic state of the zone (typically the burned or unburned gas). In this first version we keep T fixed and only evolve lam. """ lam: float state: ThermoState
[docs] def rhs(self, t: float) -> float: """Right-hand side dλ/dt for the progress variable ODE. We use a simple Arrhenius-like law modulated by (1−λ): dλ/dt = A * exp(−E / (R T)) * λ^m * (1 − λ) All parameters are set through attributes and can be tuned to roughly match a desired CA10/50/90 at a given operating point. """ A = getattr(self, "A", 1.0e3) # 1/s E = getattr(self, "E", 1.5e5) # J/mol m = getattr(self, "m", 1.0) R = 8.314462618 T = self.state.T k = A * math.exp(-E / (R * max(T, 300.0))) return k * (self.lam ** m) * (1.0 - self.lam)
[docs] def step(self, dt: float) -> None: """Advance the reactor by a small time step ``dt`` using RK4.""" lam0 = self.lam k1 = self.rhs(0.0) k2 = self.rhs(0.0) + 0.5 * dt * k1 k3 = self.rhs(0.0) + 0.5 * dt * k2 k4 = self.rhs(0.0) + dt * k3 self.lam = max(0.0, min(1.0, lam0 + dt * (k1 + 2 * k2 + 2 * k3 + k4) / 6.0))