bloc.reactors#
Extension of Cantera Reactor classes to include new features.
Implementation is based on the examples given in https://cantera.org/3.1/examples/python/reactors/custom2.html
Classes#
IdealGasReactor with additional features for carbon quality calculations. |
|
IdealGasConstPressureReactor with additional features for carbon quality calculations. |
|
IdealGasMoleReactor with additional features for carbon quality calculations. |
|
Perfectly Stirred Reactor (PSR) engine — well-mixed, constant-pressure. |
|
Plug Flow Reactor (PFR) engine — closed Lagrangian parcel march. |
|
PFR engine with a prescribed wall-temperature profile. |
|
PFR engine with homogeneous-shell radial heat loss. |
|
PFR engine with thin-shell local-temperature radial heat loss. |
|
PFR engine with a prescribed GAS temperature profile T_gas(x). |
|
Unified network driver for any |
Functions#
|
Build a fresh CLOSED carrier reactor (no flow devices) and a bare ReactorNet. |
|
Copy outlet TPX from src_phase back onto the stage dst_reactor. |
|
Single forward pass of a CLOSED Lagrangian parcel from inlet to outlet. |
|
Compute the H2 yield of the process from the states object. |
|
Compute carbon yield (solid C mass / total C mass in feed). |
|
Return the temperature in °C for a given enthalpy in J/kg and for a given gas composition and pressure. |
|
Switch the mechanism of a gas object. |
|
Solve the kinetics in an isothermal isobaric reactor at T_reactor_C (°C) and P_bar (bar) for a residence time t_res (s). |
|
Solve the kinetics in an adiabatic isobaric reactor at P_bar (bar) for a residence time t_res (s). |
|
Solve kinetics in a PFR with a prescribed temperature profile T(x). |
|
Solve kinetics in a PFR with a prescribed temperature profile T(t). |
|
Mix two streams of gases and return the resulting cantera.Quantity object. |
|
qm_in = v * S_in * density <=> v = qm_in / (S_in*density). |
|
|
|
Compute the mass of the reactor based on its dimensions and the insulation layers. |
|
Compute the power recovered from the preheating of the torch and the second injection. |
|
Compute residual heat after recovery in the exchanger. |
Module Contents#
- class bloc.reactors.CarbonBlackIdealGasReactor(*args, **kwargs)#
Bases:
cantera.ExtensibleIdealGasReactorIdealGasReactor with additional features for carbon quality calculations.
This class extends the
cantera.IdealGasReactorclass to include additional features for carbon quality calculations. The class is intended to be used in Reactor Networks.Examples
- residence_time#
Residence time in (s). Residence time must be set by the user during simulation.
- after_initialize(t0)#
- guess_specific_surface(Model=KirkOthmer2004SurfaceArea)#
Evaluate the specific surface of the carbon based on temperature and residence time.
Note
The residence time must be calculated before calling this method; for instance with:
reactor.residence_time = reactor.volume / volumetric_flow_rate
Or:
for t in logspace(0.001, 1, 50): # s sim.advance(t) reactor.residence_time = t
- Parameters:
Model (
class) – Surface area model to use. Default isKirkOthmer2004SurfaceArea.
Examples
- class bloc.reactors.CarbonBlackIdealGasConstPressureReactor(*args, **kwargs)#
Bases:
cantera.ExtensibleIdealGasConstPressureReactorIdealGasConstPressureReactor with additional features for carbon quality calculations.
This class extends the
cantera.IdealGasReactorclass to include additional features for carbon quality calculations. The class is intended to be used in Reactor Networks.Examples
- residence_time#
Residence time in (s). Residence time must be set by the user during simulation.
- after_initialize(t0)#
- guess_specific_surface(Model=KirkOthmer2004SurfaceArea)#
Evaluate the specific surface of the carbon based on temperature and residence time.
Note
The residence time must be calculated before calling this method; for instance with:
reactor.residence_time = reactor.volume / flow_rate
Or:
for t in logspace(0.001, 1, 50): # s sim.advance(t) reactor.residence_time = t
- Parameters:
Model (
class) – Surface area model to use. Default isKirkOthmer2004SurfaceArea.
Examples
- class bloc.reactors.CarbonBlackIdealGasMoleReactor(*args, **kwargs)#
Bases:
cantera.ExtensibleIdealGasMoleReactorIdealGasMoleReactor with additional features for carbon quality calculations.
This class extends the
cantera.IdealGasMoleReactorclass to include additional features for carbon quality calculations. The class is intended to be used in Reactor Networks.Examples
- residence_time#
Residence time in (s). Residence time must be set by the user during simulation.
- after_initialize(t0)#
- guess_specific_surface(Model=KirkOthmer2004SurfaceArea)#
Evaluate the specific surface of the carbon based on temperature and residence time.
Note
The residence time must be calculated before calling this method; for instance with:
reactor.residence_time = reactor.volume / flow_rate
Or:
for t in logspace(0.001, 1, 50): # s sim.advance(t) reactor.residence_time = t
- Parameters:
Model (
class) – Surface area model to use. Default isKirkOthmer2004SurfaceArea.
Examples
- bloc.reactors.build_closed_carrier_net(reactor, T, P, X, volume, *, reactor_kwargs=None, use_preconditioner=True, max_steps=None)#
Build a fresh CLOSED carrier reactor (no flow devices) and a bare ReactorNet.
Both reactor families share this constructor so the closed-parcel guarantee (“no mass flow in/out during the inner integration”) has a single named home and cannot silently drift between the tube-furnace and PFRHomogeneousShell paths.
The fresh carrier is built by cloning the mechanism source from
reactor._mech_source(present on bothPFRWallProfileandDesignIdealGasConstPressureMoleReactor) and constructing a new instance oftype(reactor). Because the carrier is a freshly created object it carries no process flow devices (MFC/PC), so CVODE only sees the closed-system ODEs.- Parameters:
reactor – Template reactor whose type and mechanism source are reused.
T – Inlet thermodynamic state (K, Pa, mole fractions).
P – Inlet thermodynamic state (K, Pa, mole fractions).
X – Inlet thermodynamic state (K, Pa, mole fractions).
volume – Initial reactor volume [m³].
reactor_kwargs – Extra keyword arguments passed to
type(reactor)(gas, clone=False, **reactor_kwargs).use_preconditioner – Attach a
cantera.AdaptivePreconditionerto the network.max_steps – If provided, set
net.max_stepson the ReactorNet.
- Returns:
carrier— the fresh closed reactor,gas— thecantera.Solutionused to initialise it,net— the barecantera.ReactorNet.- Return type:
(carrier,gas,net)
- bloc.reactors.copy_state(src_phase, dst_reactor)#
Copy outlet TPX from src_phase back onto the stage dst_reactor.
Called after the inner closed-carrier integration completes so that the original stage reactor (which may carry process flow devices) reflects the converged outlet state. Both
phaseand the reactor’s internal CVODE state vector are updated.
- bloc.reactors.march_lagrangian_parcel(reactor, T_in, P_in, X_in, *, length, diameter, mdot, heat_flux_factory=None, on_position=None, recorder=None, reactor_kwargs=None, n_points=200, max_steps=200000, use_preconditioner=True, rtol=None, atol=None, max_time_step=None, energy_off=False)#
Single forward pass of a CLOSED Lagrangian parcel from inlet to outlet.
This is the shared march engine used by both the tube-furnace path (
PFRWallProfileNet) and the PFRHomogeneousShell / PFRThinShell family (_march_pfr_to_length()). It always builds a fresh closed carrier reactor (viabuild_closed_carrier_net()) so the parcel integrates independently of any process flow devices (MFC/PC) that may be attached to the stage reactor. The converged outlet state is copied back to reactor viacopy_state().Integration proceeds in n_points equal spatial checkpoints
x = i * dx,dx = length / n_points. At each checkpoint:on_position(carrier, x_prev)is called (if provided) so the caller can update position-dependent state (e.g.T_wall(x)).The carrier is advanced to the next time point via
net.advance(t + dt)wheredt = dx / vandv = mdot / (rho * S).recorder(carrier, x, net.time)is called (if provided).
A
ct.Wall(ambient, carrier)witharea = 1 m²is built when a heat_flux_factory is provided. The factory receives carrier and must return a callableheat_flux(t) -> float [W/m²](Cantera Wall convention: positive = heat from ambient to carrier).The ambient reservoir uses a throwaway
gri30gas — it is never advanced, so its thermodynamic state is irrelevant.- Parameters:
reactor – Template / stage reactor.
type(reactor)and_mech_sourceare used to build the fresh carrier; the outlet state is copied back here after the march.T_in – Inlet state (K, Pa, mole fractions).
P_in – Inlet state (K, Pa, mole fractions).
X_in – Inlet state (K, Pa, mole fractions).
length – Tube length [m].
diameter – Tube inner diameter [m].
mdot – Mass flow rate [kg/s].
heat_flux_factory –
factory(carrier) -> callablethat builds theWall.heat_fluxfunction. PassNonefor adiabatic.on_position –
on_position(carrier, x)called before each checkpoint advance. Use to setcarrier.T_wall_K,carrier.x_position, etc.recorder –
recorder(carrier, x, t)called after each checkpoint.reactor_kwargs – Forwarded to
build_closed_carrier_net().n_points – Number of spatial checkpoints. Default 200.
max_steps – CVODE maximum steps per checkpoint. Default 200 000.
use_preconditioner – Attach
cantera.AdaptivePreconditioner. Default True.energy_off – When True the carrier’s energy equation is disabled (
carrier.energy_enabled = False) so the gas temperature is held constant during each checkpoint advance. The temperature is then a Dirichlet condition imposed by on_position (seePFRGasTemperatureProfile). Default False.
- Returns:
Spatial profile with extra columns
t(residence time [s]) andx(axial position [m]). The outlet state is also copied back to reactor.- Return type:
ct.SolutionArray
- class bloc.reactors.PSR(gas, *args, **kwargs)#
Bases:
cantera.ExtensibleIdealGasConstPressureMoleReactorPerfectly Stirred Reactor (PSR) engine — well-mixed, constant-pressure.
Physics#
The gas is assumed spatially uniform at every instant. The governing equations are the standard constant-pressure mole-balance ODEs:
\[\frac{dn_i}{dt} = V \dot{\omega}_i\]where \(n_i\) is moles of species i, \(V\) is the reactor volume, and \(\dot{\omega}_i\) is the net molar production rate [mol/(m³·s)]. Energy is either solved (
energy='on', the default) or held fixed (energy='off').Use cases#
Torch Mixing Reactor (TMR): turbulent mixing of two streams at nearly constant residence time.
Any well-mixed stage where spatial gradients are negligible.
Network topology#
Stage YAML (SPRING ``ContinuousMixingReactor``): OPEN — inlet
MassFlowController``(s), outlet ``PressureController/MassFlowController; continuous feed and discharge in the stageReactorNet.Inner physics: OPEN — CVODE integrates the stirred tank with inlet/outlet mass exchange. Volume is sized from
t_res_s(\(V = \\tau \\dot m / \\rho\)) by Boulder at build time; useadvance_to_steady_stateon the stage.Not intended for#
Plug-flow (axial gradients): use
PFRor a subclass.
Why not
ct.IdealGasConstPressureMoleReactor?#This class inherits from the extensible variant so that subclasses can intercept Cantera’s ODE callbacks (
before_update_state,after_eval, etc.) without modifying C++ code. Concrete subclasses such asContinuousMixingReactoradd industrial defaults and KPI helpers on top of this numerical base.- before_update_state(y)#
Inject a pending initial state into CVODE’s
ybefore the first eval.Cantera’s
Reactor::initialize()restoresm_state(the state snapshot taken at construction time) via a direct C++ call that bypasses all Python delegates. The only reliable interception point is here: CVODE callsupdateState(y)just before its firsteval, andyis writable.If
_pending_initis set, this method overwritesywith values derived from the HP-corrected gas state and clears the flag. All subsequentupdateStatecalls (driven by CVODE’s own stepping) are unaffected.
- class bloc.reactors.PFR(gas, *args, **kwargs)#
Bases:
cantera.ExtensibleIdealGasConstPressureMoleReactorPlug Flow Reactor (PFR) engine — closed Lagrangian parcel march.
Physics#
A fixed mass of gas is tracked as it travels axially through a tube. The parcel is modelled as a closed constant-pressure system: no mass enters or leaves during the inner CVODE integration. At every spatial checkpoint the outlet state is written back to the stage reactor via
copy_state().The common invariant shared by all PFR subclasses is:
A fresh carrier reactor is built by
build_closed_carrier_net()from the stage reactor’s mechanism (_mech_source) and type.The carrier is marched from inlet to outlet.
The outlet TPX is copied back to the stage reactor.
Subclasses override
heat_flux_factory()and/orSOLVER_MODEto express the wall heat-transfer hypothesis:PFRWallProfile— prescribedT_wall(x)with forced-convection + grey-gas radiation, adaptivenet.stepmarch.PFRHomogeneousShell— radial insulation stack, spatial-mean temperature, Forward-Backward Sweep.PFRThinShell— radial insulation stack, localT(z), single forward pass.
Why not
ct.FlowReactor?#Cantera’s
FlowReactoris a steady-state plug-flow model that is integrated byReactorNetover axial distance (DAE / IDAS), not over residence time (CVODES). It is adiabatic and frictionless by construction and has no hook for our wall heat-transfer laws. Cantera also enforces that aFlowReactormust run alone in its network — it cannot share aReactorNetwith time-dependent ODE reactors (MFC/PC stages, mixing vessels, recycle loops) because the two formulations use different independent variables and different integrators.We therefore march a closed Lagrangian parcel on an extensible const-pressure mole reactor, which preserves wall heat injection via
after_eval/heat_flux_factoryand full compatibility with Boulder’s time-based stage networks.See also: https://cantera.org/dev/python/zerodim.html#cantera.FlowReactor
- param gas:
Cantera
Solutionat the initial thermodynamic state.
Notes
_metamust be populated by the network or builder before marching. Required keys depend on the subclass heat law; at minimum:length,diameter,mass_flow_rate.- SOLVER_MODE: ClassVar[str] = 'fixed_checkpoint'#
- NETWORK_CLASS: ClassVar[type | None] = None#
- before_update_state(y)#
Inject a pending initial state into CVODE’s
ybefore the first eval.
- heat_flux_factory(carrier)#
Return a heat-flux callable
Q(t) [W/m²]for this wall model.Override in subclasses to provide the wall heat-transfer law. Return
Nonefor an adiabatic parcel.- Parameters:
carrier – The fresh closed-carrier instance created by
build_closed_carrier_net(). Subclasses may read carrier attributes (diameter,phase,_meta, …) to build the closure.
- class bloc.reactors.PFRWallProfile(gas, *args, clone=False, diameter=0.1, kappa_grey=0.0, mass_flow_rate=0.0, **kwargs)#
Bases:
PFRPFR engine with a prescribed wall-temperature profile.
Physics#
The tube wall temperature
T_wall(x)is provided as a callable. At each spatial position the network setsreactor.T_wall_Kandreactor.x_position; theafter_evalhook then injects the combined forced-convection and grey-gas-radiation flux directly into the energy ODE RHS:\[Q_{wall} = h_{conv}\,A_{int}\,(T_{wall} - T_{gas}) - q_{rad}\,A_{int}\]where \(A_{int} = (4/D)\,V\) is the internal surface area and \(h_{conv}\) is computed from the Nusselt correlation (
internal_convection_h(), Baehr-Stephan / Hausen / Churchill-Zajic depending on the flow regime).The parcel is marched with an adaptive
net.step()loop so the integrator controls step size according to local stiffness.Use cases#
Electrically or externally heated tube furnace with a known wall temperature profile.
Any reactor where the wall temperature is prescribed rather than computed from an insulation model.
See also
PFRHomogeneousShellthick-shell radial loss.
PFRThinShellthin-shell local-T radial loss.
- SOLVER_MODE: ClassVar[str] = 'adaptive'#
- diameter = 0.1#
- kappa_grey = 0.0#
- mass_flow_rate = 0.0#
- T_wall_K: float | None = None#
- x_position: float = 0.0#
- after_eval(t, LHS, RHS)#
Inject wall convection + radiation into the energy ODE RHS.
- NETWORK_CLASS: ClassVar[type | None] = None#
- before_update_state(y)#
Inject a pending initial state into CVODE’s
ybefore the first eval.
- heat_flux_factory(carrier)#
Return a heat-flux callable
Q(t) [W/m²]for this wall model.Override in subclasses to provide the wall heat-transfer law. Return
Nonefor an adiabatic parcel.- Parameters:
carrier – The fresh closed-carrier instance created by
build_closed_carrier_net(). Subclasses may read carrier attributes (diameter,phase,_meta, …) to build the closure.
- class bloc.reactors.PFRHomogeneousShell(gas, *args, **kwargs)#
Bases:
PFRPFR engine with homogeneous-shell radial heat loss.
Physics#
Radial heat loss is modelled via a spatial-mean gas temperature and a lumped thermal resistance stack (insulation layers + external natural-convection / radiation). The total loss
Phi_kWis converged by a Forward-Backward Sweep (FBS): an adiabatic predictor pass gives the mean T, which yields a firstPhi_kWestimate; the corrector repeats with the updated wall flux until|ΔΦ| / Φ < 1 %.The heat loss enters the Cantera ODE via a
ct.Wall(area = 1 m²) whoseheat_fluxcallable distributesPhi_kWuniformly in space (i.e. proportional to local velocity).Use cases#
Insulated, thick-shell industrial vessels where axial wall conduction smears temperature gradients (e.g. the SPRING Carbon Growth Reactor).
Any reactor where the dominant resistance to heat loss is in the insulation layer rather than the gas film.
Not intended for#
Reactors with large axial temperature gradients and thin walls: use
PFRThinShellinstead.
See also
PFRWallProfileprescribed wall-temperature profile.
PFRThinShellthin-shell local-T radial loss.
- SOLVER_MODE: ClassVar[str] = 'fixed_checkpoint'#
- thermal_resistance_stack()#
Build the radial-conduction + external-convection resistance list.
Uses
_metageometry and insulation layers. Returns a list of thermal resistances [K/W] from inner wall to ambient, ordered from innermost insulation layer to external convection/radiation.
- wall_thermal_report(T_mean_C)#
Return the wall heat-transfer breakdown at a mean gas temperature.
Single source of truth for the SPRING wall KPIs: the external film coefficients (
h_CC,h_rad,h_eff[W/m²/K]), the external wall temperature (T_wall_ext[°C]) and the resulting wall heat loss (heat_loss_kW, includingheat_loss_corr_factor). When_meta["adiabatic"]is set the loss is zero and the wall sits at ambient.- Parameters:
T_mean_C – Spatial-mean gas temperature in °C.
- Returns:
{"h_CC", "h_rad", "h_eff", "T_wall_ext", "heat_loss_kW"}.- Return type:
dict
- spatial_mean_temperature(states)#
Compute the spatial-mean gas temperature [°C] from a PFR profile.
Integrates T over the axial position recorded by
_march_pfr_to_lengthin thexextra column, using the trapezoid rule (trapezoid(states.T, states.x) / states.x[-1]) so the FBS heat-loss estimate is identical between the staged and standalone paths.- Parameters:
states – SolutionArray with an
xextra column (axial position [m]).- Returns:
Length-weighted mean temperature in °C. Falls back to the unweighted mean only if
states.xis missing or zero.- Return type:
float
- heat_loss(T_mean_C)#
Compute total wall heat loss [kW] for a given mean gas temperature.
Uses the linearized thermal resistance stack from
thermal_resistance_stack()and multiplies by_meta["heat_loss_corr_factor"](default 1.0) to account for thermal bridges and other unmodelled loss paths. Returns 0 when_meta["adiabatic"]is True.- Parameters:
T_mean_C – Spatial-mean gas temperature in °C.
- Returns:
Heat loss in kW (positive = loss to ambient).
- Return type:
float
- solve_forward(Phi_kW)#
Integrate the PFR with a fixed heat-loss power and return the spatial profile.
Builds a
PFRHomogeneousShellNetand delegates to its_spatial_ode_pass. This is the single-shot entry point for standalone use and tests; the FBS convergence loop inPFRHomogeneousShellNet.advancecalls_spatial_ode_passdirectly.- Parameters:
Phi_kW – Total wall heat loss to subtract from the inlet enthalpy [kW]. Positive value = heat removed from the gas.
- Returns:
Spatial profile with extra columns
t(residence time [s]) andx(axial position [m]).- Return type:
ct.SolutionArray
- NETWORK_CLASS: ClassVar[type | None] = None#
- before_update_state(y)#
Inject a pending initial state into CVODE’s
ybefore the first eval.
- heat_flux_factory(carrier)#
Return a heat-flux callable
Q(t) [W/m²]for this wall model.Override in subclasses to provide the wall heat-transfer law. Return
Nonefor an adiabatic parcel.- Parameters:
carrier – The fresh closed-carrier instance created by
build_closed_carrier_net(). Subclasses may read carrier attributes (diameter,phase,_meta, …) to build the closure.
- class bloc.reactors.PFRThinShell(gas, *args, **kwargs)#
Bases:
PFRPFR engine with thin-shell local-temperature radial heat loss.
Physics#
Heat loss depends on the local gas temperature
T(z)rather than the spatial mean. The local loss per unit length is:\[q'(z) = -\frac{T_{gas}(z) - T_{amb}}{R_{tot} \cdot L}\quad [W/m]\]Because the flux is evaluated at each checkpoint via a callable that reads
reactor.phase.T, a single forward pass is sufficient — no Forward-Backward Sweep is needed.Use cases#
Quartz-tube / lab-tube reactors where axial wall conduction is negligible (thin, low-conductivity walls).
Scenarios where the gas temperature profile is steep and a spatial-mean-T hypothesis would over-predict the loss in the hot inlet zone.
See also
PFRWallProfileprescribed wall-temperature profile.
PFRHomogeneousShellthick-shell homogeneous loss.
- SOLVER_MODE: ClassVar[str] = 'fixed_checkpoint'#
- thermal_resistance_stack#
- wall_thermal_report#
- spatial_mean_temperature#
- heat_loss#
- solve_forward()#
Integrate the PFR with the local-T heat loss and return the spatial profile.
Single-shot entry point for standalone use and tests. Builds a
PFRThinShellNetand runs oneadvancepass.- Returns:
Spatial profile with extra columns
tandx.- Return type:
ct.SolutionArray
- NETWORK_CLASS: ClassVar[type | None] = None#
- before_update_state(y)#
Inject a pending initial state into CVODE’s
ybefore the first eval.
- heat_flux_factory(carrier)#
Return a heat-flux callable
Q(t) [W/m²]for this wall model.Override in subclasses to provide the wall heat-transfer law. Return
Nonefor an adiabatic parcel.- Parameters:
carrier – The fresh closed-carrier instance created by
build_closed_carrier_net(). Subclasses may read carrier attributes (diameter,phase,_meta, …) to build the closure.
- class bloc.reactors.PFRGasTemperatureProfile(gas, *args, clone=False, diameter=0.1, mass_flow_rate=0.0, **kwargs)#
Bases:
PFRPFR engine with a prescribed GAS temperature profile T_gas(x).
Physics#
This is the Dirichlet-on-gas boundary condition: the gas temperature itself is prescribed as a callable
T_gas(x)and the energy equation is switched off. Only the kinetics evolve; at every spatial checkpoint the network resets the parcel temperature toT_gas(x):\[T_{gas}(x) = T_{prescribed}(x), \qquad \frac{dY_k}{dt} = \frac{\dot\omega_k W_k}{\rho}\]No wall film, no radiation and no resistance stack are involved — the temperature is imposed, not computed from a heat balance. Contrast with
PFRWallProfile, which prescribes the wall temperature and lets the gas lag behind it through a convective + radiative film.Numerically the parcel is marched by the shared
march_lagrangian_parcel()withenergy_off=True; the temperature is re-imposed before each checkpoint advance so the stepwise-constant history converges to the continuous profile asn_pointsgrows. This is the closed-parcel / OO counterpart of the proceduralsolve_fixed_position_temperature_profile_pfr().Use cases#
Kinetics validation against a measured in-stream gas temperature (thermocouple trace) where you want predicted species, not a predicted temperature.
Decoupling chemistry from the energy balance to isolate mechanism behaviour under a known thermal history.
See also
PFRWallProfileprescribed wall temperature with convective + radiative coupling (gas temperature is free).
solve_fixed_position_temperature_profile_pfr()procedural equivalent.
- SOLVER_MODE: ClassVar[str] = 'fixed_checkpoint'#
- IMPOSED_GAS_T: ClassVar[bool] = True#
- diameter = 0.1#
- mass_flow_rate = 0.0#
- T_gas_K: float | None = None#
- x_position: float = 0.0#
- NETWORK_CLASS: ClassVar[type | None] = None#
- before_update_state(y)#
Inject a pending initial state into CVODE’s
ybefore the first eval.
- heat_flux_factory(carrier)#
Return a heat-flux callable
Q(t) [W/m²]for this wall model.Override in subclasses to provide the wall heat-transfer law. Return
Nonefor an adiabatic parcel.- Parameters:
carrier – The fresh closed-carrier instance created by
build_closed_carrier_net(). Subclasses may read carrier attributes (diameter,phase,_meta, …) to build the closure.
- class bloc.reactors.PFRNetwork(reactor)#
Unified network driver for any
PFRsubclass.A generic single-pass driver that runs the fixed-checkpoint
_march_pfr_to_length()spatial march for anyPFRsubclass. Specialised stage networks (PFRWallProfileNetfor the tube furnace,PFRHomogeneousShellNet/PFRThinShellNetfor the shell models) wrap the same marcher with their wall-loss specifics; this class is the minimal fallback driver.The network is Boulder-compatible: it exposes
timeand anadvance()method, and wires into theNETWORK_CLASSattribute on eachPFRsubclass.- Parameters:
reactor – A
PFR(or subclass) instance that has been fully configured (_metapopulated by the STONE builder).
- reactor#
- property time: float#
Residence time [s] after the last advance.
- advance(time=0.0)#
Run the spatial march and update the stage reactor outlet state.
The
timeargument is ignored (Boulder callsadvance(1.0)by convention); the actual integration length is taken fromreactor._meta['length'].
- bloc.reactors.get_H2_yield(states)#
Compute the H2 yield of the process from the states object.
- Parameters:
states (
ct.SolutionArray) – Solution array with the states of the reactor at each time step. states[0] and states[-1] must be the initial and final states of the reactor. Mass is assumed to be conserved between states[0] and states[-1].as (The H2 yield is defined)
subtracted (The initial amount of H2 in the feedstock must be)
produced. (because it is not)
Thus (
H2_yield = (Y_H2_final - Y_H2_initial) / (Y_H_tot - Y_H2_initial))math:: (..) – H2_yield = \frac{Y_{H2,final} - Y_{H2,initial}}{Y_{H,total} - Y_{H2,initial}}
- bloc.reactors.get_carbon_yield(gas, n_C_min=300)#
Compute carbon yield (solid C mass / total C mass in feed).
Assumes no solid carbon in the input gas. Carbon yield = mass fraction of solid carbon / total mass fraction of carbon element in the input gas.
- Parameters:
gas (
cantera.Solutionorcantera.SolutionArray) – Gas object with composition set.n_C_min (
int, optional) – Minimum number of carbon atoms to treat a species as solid carbon. Default 300. Use 24 for mechanisms that represent soot as large PAH only.
- bloc.reactors.find_temperature_from_enthalpy(h_mass, X, P_bar, mechanism)#
Return the temperature in °C for a given enthalpy in J/kg and for a given gas composition and pressure.
- Parameters:
h_mass (-) – Specific enthalpy target in J/kg
X (-) – Composition of the gas in mole fraction
P_bar (-) – Pressure in bar
mechanism (-) – Path to the mechanism file
- bloc.reactors.switch_mechanism(gas, new_mechanism, htol=0.0001, Xtol=0.0001, verbose=False)#
Switch the mechanism of a gas object.
Useful to switch from plasma to reactor simulation for instance. As some species may not be present in the new mechanism, we compute the adjust the temperature of the new gas object to match the enthalpy of the old gas object, so that energy is conserved. Still, if the chemical enthalpy variation exceed htol, an error is raised. Similarly, if the mole fraction variation exceed Xtol, a error is raised.
- Parameters:
gas (
ct.Solution) – Gas objectnew_mechanism (
str) – Path to the new mechanism filehtol (
float) – Tolerance for the chemical enthalpy variation between the two mechanisms. Default is 1e-4.Xtol (
float) – Tolerance for the mole fraction variation between the two mechanisms. Default is 1e-4.verbose (
bool) – If True, print information about the process. Default is False.
- Returns:
gas_new – Gas object with the new mechanism
- Return type:
ct.Solution
- bloc.reactors.solve_isothermal_reactor(qm_kgs, T_reactor_C, t_res, X0, T0_C, P_bar, mechanism=None, dt_short=1e-09, rtolT_prevention=0.0001, rtolT_fatal=0.01, heat_recycling=True, conversion_target=None, H2_yield_target=None, name=None, verbose=2, termination='residence_time', L_r=None, S_r=None)#
Solve the kinetics in an isothermal isobaric reactor at T_reactor_C (°C) and P_bar (bar) for a residence time t_res (s).
- Parameters:
qm_kgs (-) – Mass flow rate of the input gas in kg/s
T_reactor_C (-) – Temperature of the reactor in °C
t_res (-) – Residence time in the reactor in s
X0 (-) – Composition of the input gas in mole fraction
T0_C (-) – Temperature of the input gas in °C
P_bar (-) – Pressure in the reactor in bar
mechanism (-) – Path to the mechanism file
dt_short (-) – Short time step for the simulation. A short time step is used to prevent temperature variations.
rtolT_prevention (-) – Relative tolerance for temperature variations. If the relative variation of the temperature exceed rtolT_prevention, the time step is reduced.
rtolT_fatal (-) – Relative tolerance for temperature variations. If the relative variation of the temperature exceed rtolT_fatal, the simulation is stopped.
heat_recycling (-) – If True, the energy released in exothermic reactions is used in later endothermic reactions. Default is True.
conversion_target (-) – Target for the conversion of the input gas. Default is None.
H2_yield_target (-) – Target for the H2 yield. Default is None.
name (-) – Name of the reactor. Default is None.
verbose (
int) – if >0, print infos. If >=2, add calculation progress bar.
Notes
Energy calculation: Two terms are computed: - Ecost_init: the energy required to heat the input gas from T0_C to T_reactor_C. Multiplying it by the mass flow
yields the heating power
- delta_h: the energy required to compensate for the endothermic reactions and maintain the temperature constant in the reactor.
If heat_recycling is True, the energy released in exothermic reactions is used in later endothermic reactions. Multiplying it by the mass flow yields the chemical power.
To compute delta_h, we use ‘energy = on’ in the reactor object definition, and evaluate the enthalpy variation at each time step. The time step is choosed so that the relative variation of the temperature is less than rtolT_prevention.
- bloc.reactors.solve_adiabatic_reactor(qm_kgs, P_in_kW, t_res, X0, T0_C, P_bar, mechanism, dt_short=1e-09, conversion_target=None, H2_yield_target=None, termination='residence_time', L_reactor=0.0, S_reactor=1.0, P_in_kW_avg=0.0, name=None, verbose=2)#
Solve the kinetics in an adiabatic isobaric reactor at P_bar (bar) for a residence time t_res (s).
- Parameters:
qm_kgs (-) – Mass flow rate of the input gas in kg/s
P_in_kW (-) – Instantaneous power input in kW. Applied once at t = 0 as an inlet specific-enthalpy pulse
P_in_kW * 1e3 / qm_kgs(J/kg), before time integration starts.t_res (-) – Residence time in the reactor in s
X0 (-) – Composition of the input gas in mole fraction
T0_C (-) – Temperature of the input gas in °C
P_bar (-) – Pressure in the reactor in bar
mechanism (-) – Name of the mechanism file
dt_short (-) – Short time step for the simulation
conversion_target (-) – Target for the conversion of the input gas. Default is None.
H2_yield_target (-) – Target for the H2 yield. Default is None.
termination (-) – Termination condition for the simulation. Default is ‘residence_time’. Can be ‘residence_time’ or ‘reactor_length’.
L_reactor (-) – Length of the reactor in m. Default is 0. If termination is ‘reactor_length’, L_reactor must be defined.
S_reactor (-) – Section of the reactor in m2. Default is 1. If termination is ‘reactor_length’, S_reactor must be defined.
P_in_kW_avg (-) – Average power input/removal in kW distributed uniformly over
t_res. At each integration stepdt, the specific enthalpy is adjusted bydh = P_in_kW_avg * 1e3 / qm_kgs * dt / t_res(J/kg). Positive values add heat; negative values remove heat.name (-) – Name of the reactor. Default is None.
verbose (
int) – if >0, print infos. If >=2, add calculation progress bar.
- Returns:
- “gas”: ct.Solution
Gas object with the final state of the reactor
- ”states”: ct.SolutionArray
Solution array with the states of the reactor at each time step
- Return type:
a dictionary
- bloc.reactors.solve_fixed_position_temperature_profile_pfr(qm_kgs, inlet_composition, P_bar, mechanism, temperature_profile_position, dx=0.01, L_reactor=0.0, d_reactor=1.0, name=None, verbose=2)#
Solve kinetics in a PFR with a prescribed temperature profile T(x).
Integrates along the reactor axis with fixed spatial step dx. At each step, the reactor advances by dt = dx / velocity (from mass flow and cross-section), then temperature is set from the profile. No energy equation; T is imposed.
- Parameters:
qm_kgs (
float) – Mass flow rate (kg/s).inlet_composition (
str) – Inlet composition (Cantera format, mole fractions).P_bar (
float) – Pressure (bar).mechanism (
str, optional) – Mechanism name or path; must not be None.temperature_profile_position (
np.ndarray) – Shape (2, n): row 0 = axial positions (m), row 1 = temperature (K).dx (
float, optional) – Spatial integration step (m). Default 0.01.L_reactor (
float, optional) – Reactor length (m); used for reporting. Default 0.0.d_reactor (
float, optional) – Reactor diameter (m); used for velocity and cross-section. Default 1.0.name (
str, optional) – Reactor name for logging.verbose (
int, optional) – Logging level. Default 2.
- Returns:
“gas”: Cantera Solution; “states”: SolutionArray with extra “t”, “x”. If mechanism is CRECK_Nobili2024.yaml, also “reaction_rates_by_class” and “mass_carbon_rates_by_class”.
- Return type:
dict
- bloc.reactors.solve_fixed_time_temperature_profile_pfr(inlet_composition, P_bar, mechanism, temperature_profile_time, dt=1e-06, name=None, verbose=2)#
Solve kinetics in a PFR with a prescribed temperature profile T(t).
Integrates in time with fixed step dt. At each step the reactor advances by dt, then temperature is set from the profile. No energy equation; T is imposed. No reactor geometry or velocity; purely time-residence integration.
- Parameters:
inlet_composition (
str) – Inlet composition (Cantera format, mole fractions).P_bar (
float) – Pressure (bar).mechanism (
str, optional) – Mechanism name or path; must not be None.temperature_profile_time (
np.ndarray) – Shape (2, n): row 0 = residence times (s), row 1 = temperature (K).dt (
float, optional) – Time integration step (s). Default 1e-6.name (
str, optional) – Reactor name for logging.verbose (
int, optional) – Logging level. Default 2.
- Returns:
“gas”: Cantera Solution; “states”: SolutionArray with extra “t”. If mechanism is CRECK_Nobili2024.yaml, also “reaction_rates_by_class” and “mass_carbon_rates_by_class”.
- Return type:
dict
- bloc.reactors.mix_two_streams(gas_1, qm_1, gas_2, qm_2)#
Mix two streams of gases and return the resulting cantera.Quantity object.
- bloc.reactors.compute_reactor_length(qm_in, S_in, states)#
qm_in = v * S_in * density <=> v = qm_in / (S_in*density).
- qm_in: float
Mass flow rate of the input gas in kg/s
- S_in: float
Section of the reactor in m2
- states: ct.SolutionArray
contains the results of the kinetic simulation
- bloc.reactors.compute_reactor_dimensions_with_form_factor(qm_in, f_factor, states)#
- bloc.reactors.get_reactor_mass(L_reactor, d_reactor, e_insul_layers, rho_insul_layers, verbose=False)#
Compute the mass of the reactor based on its dimensions and the insulation layers.
- Parameters:
L_reactor (
float) – Length of the reactor in m.d_reactor (
float) – Diameter of the reactor in m.e_insul_layers (
listoffloat) – Thickness of the insulation layers in m.rho_insul_layers (
listoffloat) – Density of the insulation layers in kg/m3.verbose (
bool) – If True, print detailed information about the function call.
- Returns:
Mass of the reactor in kg.
- Return type:
float
- bloc.reactors.compute_recovered_power(qm_torch, T_torch_input_C, X_torch_input, qm_2nd_inj, T_2nd_inj_C, X_2nd_inj, P_bar, T_amb, gas_reac, verbose=False)#
Compute the power recovered from the preheating of the torch and the second injection.
\[P_{\mathrm{recovered}} = P_{\mathrm{preheat,torch}} + P_{\mathrm{preheat,2nd}} P_{\mathrm{preheat}} = \dot{m} \, (h_{\mathrm{in}} - h_0)\]
- bloc.reactors.compute_residual_heat(P_recovered, gas, qm_tot, T_amb_C, verbose=False)#
Compute residual heat after recovery in the exchanger.
\[P_{\mathrm{heat,tot}} = \dot{m}_{\mathrm{tot}} \, (h_{\mathrm{reactor\,out}} - h_{\mathrm{cold\,out}}) P_{\mathrm{residual}} = P_{\mathrm{heat,tot}} - P_{\mathrm{recovered}}\]