bloc.reactor_models#
Industrial reactor models and STONE YAML builders for Bloc.
This module connects Bloc’s domain-specific reactor formulations to the
YAML with STONE standard used by Boulder. It registers custom reactor builders
so that STONE component types like PlasmaTorchInstantaneousHeating,
ContinuousMixingReactor, RefractoryReactor, QuartzTubeReactor and
TubeFurnace declared in configuration files are instantiated as concrete
Cantera reactors inside a ReactorNet.
Each industrial model subclasses a numerical engine defined in
bloc.reactors (PFRHomogeneousShell, PFRThinShell,
PFRWallProfile, PSR) and adds industrial defaults and KPI helpers.
Registration is handled by bloc.boulder_plugins.register.register_plugins()
function called via entry point.
Key responsibilities#
Register custom STONE builders via
register_reactor_builder()and install a post-build hook viaregister_post_build_hook(). Builders are invoked byCanteraConverterwhen converting a normalized STONE config to a running Cantera network.Provide design-oriented reactor subclasses that expose convenient solver and utility methods (mixing, energy accounting, heat transfer estimates) used by higher-level workflows.
Interoperate with Bloc utilities and models (
bloc.reactors,bloc.utils,bloc.models) while remaining fully compatible withReactorandReactorNet.
PFR thermal hypotheses#
Bloc ships two PFR variants which differ only in how they map gas
temperature to wall heat loss; both attach a ct.Wall between the
reactor and an ambient ct.Reservoir, and both surface that wall
in the post-solve visualization network.
PFRHomogeneousShell— homogeneous shell hypothesis (industrial model:RefractoryReactor). The wall is assumed isothermal because axial conduction through a thick shell smears local gradients. Total radial loss is driven by the spatial-mean gas temperature, so the network class resolves it with a Forward-Backward Sweep (FBS) iteration.PFRThinShell— thin shell hypothesis (industrial model:QuartzTubeReactor). Axial conduction is negligible (e.g. quartz tubes used in lab tube furnaces), so heat loss is computed locally fromT(z). No FBS is required; the network solves the spatial ODE in a single pass with awall.heat_fluxcallable that closes overreactor.phase.T.
Use RefractoryReactor for insulated, thick-shell configurations where
axial wall conduction smears local gradients. Use QuartzTubeReactor
only when the reactor shell is genuinely thin and axially non-conducting.
Example
Given a STONE component
- id: torch
PlasmaTorchInstantaneousHeating:
t_res_s: 1.0e-4
electric_power_kW: 55.0
torch_eff: 0.8
gen_eff: 0.8
the converter will call this module’s registered builder and
inject an instance into the network under the torch id.
Attributes#
Classes#
ReactorNet subclass implementing torch adiabatic integration. |
|
Torch physics engine with instantaneous enthalpy jump (plasma / simplified). |
|
Design-oriented constant-pressure mole reactor with helper APIs. |
|
Stage network driving a |
|
Stage network driving a |
|
ReactorNet subclass implementing Forward-Backward Sweep for a PFR stage. |
|
Single-pass PFR network for the thin-shell hypothesis. |
|
Industrial Tube Furnace model. |
|
Industrial Carbon Growth Reactor (CGR) / refractory-lined vessel. |
|
Industrial quartz-tube / lab-tube reactor. |
|
Industrial Torch Mixing Reactor (TMR) / multi-inlet well-mixed vessel. |
|
ReactorNet subclass for instantaneous-mix + closed-τ chemistry. |
|
Engine: instantaneous HP mix of two inlet streams + closed-τ chemistry. |
|
Industrial model: instantaneous mix + closed chemical residence time. |
|
Industrial Plasma Torch model — instantaneous-heating variant. |
Functions#
|
Serialize a closed CSTR residence-time profile for the Plots tab. |
|
Serialize a spatial |
Compute tube-furnace engineering KPIs from a solved STONE Simulation. |
Module Contents#
- class bloc.reactor_models.TorchInstantaneousHeatingNet(reactors, meta=None)#
Bases:
cantera.ReactorNetReactorNet subclass implementing torch adiabatic integration.
Mirrors the
PFRHomogeneousShellNetpattern: overridesadvance()so the torch stage runs the same physics as the legacysimulation_non_isothermal_reactorspath — instantaneous enthalpy addition followed by adiabatic kinetics fort_res_s.- Parameters:
reactors – List of reactors for this stage. Must contain exactly one
TorchInstantaneousHeating.meta (
dict, optional) – Parameters injected by_build_torch_instantaneous()and enriched by_post_build_design_volumes():effective_power_kW,mass_flow_rate,t_res_s,mechanism.
- advance_to_steady_state()#
Validate that precomputed torch outlet data is available.
This stage does not integrate dynamics here; the outlet profile is precomputed in
_post_build_design_volumes().
- solve_steady()#
Delegate steady solve to
advance_to_steady_state().Base
ReactorNetwould run on an empty reactor list and raise.
- advance(time)#
Validate and expose the precomputed torch outlet.
_post_build_design_volumes()pre-computes a torch outlet profile and stores_statesbefore thisTorchInstantaneousHeatingNetis instantiated. Downstream extraction readstorch.phaseaftersolve_adiabatic()writeback.- Parameters:
time – Nominal advance time [s], unused and kept for API compatibility.
- property states: cantera.SolutionArray | None#
Adiabatic post-enthalpy profile (satisfies
CustomStageNetwork).
- property scalars: Dict[str, Any]#
Torch build parameters and outlet-state physics quantities.
- class bloc.reactor_models.TorchInstantaneousHeating(gas, *args, **kwargs)#
Bases:
cantera.IdealGasConstPressureMoleReactorTorch physics engine with instantaneous enthalpy jump (plasma / simplified).
Boulder’s
build_sub_networkdetectsNETWORK_CLASSand instantiatesTorchInstantaneousHeatingNetfor the torch stage. That class uses the same physics as the legacysimulation_non_isothermal_reactorspath: instantaneous enthalpy addition (gas.HP += Q/mdot) followed by adiabatic kinetics fort_res_s.- _meta#
Torch parameters populated by
_build_torch_instantaneous()and enriched by_post_build_design_volumes().- Type:
dict
- _states#
Residence-time profile written by
solve_adiabatic()(extrat[s]).- Type:
ct.SolutionArrayorNone
See also
- NETWORK_CLASS: ClassVar[type | None]#
- solve_adiabatic(mdot, power_kW, t_res_s, verbose=True)#
Solve adiabatic kinetics using this reactor’s current inlet state.
Adds torch power as an enthalpy jump and integrates one adiabatic pass for
t_res_susing a freshtype(self)(gas, clone=False)carrier.
- class bloc.reactor_models.DesignIdealGasConstPressureMoleReactor(gas, *args, **kwargs)#
Bases:
cantera.ExtensibleIdealGasConstPressureMoleReactorDesign-oriented constant-pressure mole reactor with helper APIs.
Inherits from
ExtensibleIdealGasConstPressureMoleReactorso that subclasses can intercept Cantera’s ODE callbacks without modifying C++ code.The key hook used here is
before_update_state(): CVODE callsupdateState(y)before its very firsteval, at which pointyis still writable. By storing a pending initial condition in_pending_initand writing it intoyon the first call, any subclass can override CVODE’s starting point — even thoughm_state(the C++ snapshot taken at construction) cannot be changed from Python.- Parameters:
gas – Cantera
Solutionobject used to initialise the reactor.
- before_update_state(y)#
Inject a pending initial state into CVODE’s y before 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.
- solve_adiabatic(mdot, power_kW, t_res_s, verbose=False)#
Solve an adiabatic constant-pressure reactor segment.
Uses this reactor as the ODE owner: applies an enthalpy jump from
power_kW / mdotand integrates with a freshtype(self)(gas, clone=False)carrier fort_res_s.
- switch_mechanism(gas, mechanism_path, htol, Xtol)#
Switch the active mechanism while conserving chemical enthalpy.
See
switch_mechanism()for details.
- external_coeffs(D_ext, L_reac, eps_wall, T_wall_hyp_C, T_amb_C)#
Return convective and radiative heat transfer coefficients at the wall.
- heat_losses_linear(T_mean_C, T_amb_C, R_list)#
Compute linearized heat losses across a thermal resistance stack.
- thermal_resistance(d_reac, L_reac, e_insul_list, cond_list, h_tot, S_ext)#
Build a radial-conduction plus external heat transfer resistance list.
- mass_and_power(qm_torch, T_torch_input_C, X_torch, qm_2nd_inj, T_2nd_inj_C, X_2nd_inj, P_bar, T_amb_C, gas)#
Compute preheat recovery and residual heat based on reactor states.
- mass_reactor(L_reac, d_reac, e_insul_list, density_list, verbose=False)#
Estimate reactor mass and volume from geometry and insulation layers.
- class bloc.reactor_models.PFRWallProfileNet(reactors, meta=None, *, wall_T_fn=None, total_length=None, n_points=200, rtol=0.0001, atol=1e-12, cap_time_step=True)#
Stage network driving a
TubeFurnacethrough a prescribed wall profile.Replaces the legacy
LagrangianPFRReactor+LagrangianPFRNetwork+DesignTubeFurnaceNettrio with a single driver built on the unifiedPFRWallProfileengine and the sharedmarch_lagrangian_parcel()marcher.Physics#
A closed Lagrangian gas parcel is marched from inlet to outlet. At each spatial checkpoint the wall temperature
T_wall(x)and the entry-length positionx_position = max(x - heating_start, 0)are pushed onto the carrier; theafter_eval()hook then injects forced-convection + grey-gas-radiation flux into the energy ODE.Numerics#
Unlike the retired adaptive
net.steploop, this driver uses the fixed-checkpointnet.advancemarch (n_pointsdefault 200), which yields a uniform spatial grid and reproduces the experimentally-validated (Mei 2019) profiles within < 1 %.The public surface is duck-typed to Boulder’s
CustomStageNetwork(time,states,scalars,advance,advance_to_steady_state) and exposes the tube-furnace diagnostics (E_conv,E_rad,n_steps,h_conv_avg,Fo_D_minand the recorded*_arrprofiles) consumed bycompute_tube_furnace_kpis(),report_detailsandyaml_utils.- param reactors:
Iterable containing exactly one
TubeFurnace(PFRWallProfile) reactor.- param meta:
Geometry / wall-profile parameters produced by
_build_design_tube_furnace()(total_length,T_wall_K,T_ambient_K,entry_leg,exit_leg,entry_zone,plateau_zone,T_wall_profile,diameter,kappa_grey).- type meta:
dict, optional
- NETWORK_DIAGRAM_NOTE: str = 'Node temperatures in this diagram reflect the outlet gas state of the Lagrangian simulation...#
- reactors#
- E_conv: float = 0.0#
- E_rad: float = 0.0#
- n_steps: int = 0#
- h_conv_avg: float#
- Fo_D_min: float#
- x_arr: numpy.ndarray | None = None#
- t_arr: numpy.ndarray | None = None#
- T_wall_arr: numpy.ndarray | None = None#
- T_gas_arr: numpy.ndarray | None = None#
- Y_Cs_arr: numpy.ndarray | None = None#
- X_arr: numpy.ndarray | None = None#
- species_names: list[str] | None = None#
- Fo_D_arr: numpy.ndarray | None = None#
- h_conv_arr: numpy.ndarray | None = None#
- alpha_arr: numpy.ndarray | None = None#
- u_arr: numpy.ndarray | None = None#
- k_arr: numpy.ndarray | None = None#
- Re_arr: numpy.ndarray | None = None#
- Pr_arr: numpy.ndarray | None = None#
- property reactor: bloc.reactors.PFRWallProfile#
The single PFRWallProfile/TubeFurnace reactor (used by plot helpers).
- property mass_flow_rate: float#
Mass flow rate [kg/s] of the driven reactor.
- property network#
Self-reference kept for backward compatibility with diagnostics readers.
- property time: float#
Residence time [s] of the Lagrangian march (0 before advance).
- property preconditioner#
Preconditioner is managed inside march_lagrangian_parcel; exposed for symmetry.
- solve_steady()#
Delegate to
advance_to_steady_state()for Bouldersolve_steady.
- advance(t=1.0)#
Advance to
t; for a Lagrangian tube this runs to the outlet.
- advance_to_steady_state()#
Run the fixed-checkpoint parcel march from inlet to outlet.
The full axial
cantera.SolutionArrayis attached to the reactor as_states(consumed by Boulder’s stage-state collector andspatial_series_fn). Idempotent: a second call is a no-op.
- property states: cantera.SolutionArray | None#
Axial Lagrangian profile (satisfies Boulder’s stage-state collector).
- property scalars: Dict[str, Any]#
Tube-furnace scalars (wall energy budget, residence time, meta).
- draw(title='Tube Furnace — Wall Temperature Profile', n_points=200)#
Return a schematic matplotlib Figure of the tube-furnace geometry.
Upper panel: colour-coded tube rectangle (cold→hot→cold). Lower panel: wall (and, post-advance, gas) temperature profile. Does not require
advance()— relies only onwall_T_fn/total_length.
- plot_temperature_profile(title='Temperature Profile — Tube Furnace')#
Plot gas + wall temperature vs position with a residence-time axis.
Requires
advance_to_steady_state()to have been called.
- plot_species_profiles(species=None, title='Species Profile — Tube Furnace')#
Plot mole-fraction profiles vs position with a residence-time axis.
Requires
advance_to_steady_state()to have been called. WhenspeciesisNone, the six species with the highest peak mole fraction (≥ 0.1 %) are selected automatically.
- class bloc.reactor_models.PFRGasTemperatureProfileNet(reactors, meta=None, *, T_gas_fn=None, total_length=None, n_points=200, rtol=0.0001, atol=1e-12)#
Stage network driving a
PFRGasTemperatureProfile.Imposes a prescribed gas temperature profile
T_gas(x)on a closed Lagrangian parcel: the energy equation is disabled and the temperature is reset toT_gas(x)at every spatial checkpoint, so only the kinetics evolve. This is the Dirichlet-on-gas counterpart of the wall-drivenPFRWallProfileNet.The public surface is duck-typed to Boulder’s
CustomStageNetwork(time,states,scalars,advance,advance_to_steady_state) and records the axial temperature and species profiles consumed by the calculation note and the plot helpers.- Parameters:
reactors – Iterable containing exactly one
PFRGasTemperatureProfilereactor.meta – Geometry/profile meta dict (populated by
_build_pfr_gas_temperature_profile()). Must containtotal_lengthand the trapezoidal-profile keys (T_gas_K,T_ambient_K,entry_leg,exit_leg,entry_zone,plateau_zone) or an explicitT_gas_profiledict.T_gas_fn – Standalone API: pass an explicit
T_gas(x)callable and tube length instead of the STONE meta dict (used by examples and tests).total_length – Standalone API: pass an explicit
T_gas(x)callable and tube length instead of the STONE meta dict (used by examples and tests).n_points – Standalone API: pass an explicit
T_gas(x)callable and tube length instead of the STONE meta dict (used by examples and tests).rtol – Integrator tolerances forwarded to
march_lagrangian_parcel().atol – Integrator tolerances forwarded to
march_lagrangian_parcel().
- reactors#
- x_arr: numpy.ndarray | None = None#
- t_arr: numpy.ndarray | None = None#
- T_gas_arr: numpy.ndarray | None = None#
- Y_Cs_arr: numpy.ndarray | None = None#
- X_arr: numpy.ndarray | None = None#
- species_names: list | None = None#
- property reactor: bloc.reactors.PFRGasTemperatureProfile#
The single PFRGasTemperatureProfile reactor (used by plot helpers).
- property mass_flow_rate: float#
Mass flow rate [kg/s] of the driven reactor.
- property network#
Self-reference kept for symmetry with PFRWallProfileNet readers.
- property time: float#
Residence time [s] of the Lagrangian march (0 before advance).
- property preconditioner#
Preconditioner is managed inside march_lagrangian_parcel.
- solve_steady()#
Delegate to
advance_to_steady_state()for Bouldersolve_steady.
- advance(t=1.0)#
Advance to
t; for a Lagrangian tube this runs to the outlet.
- advance_to_steady_state()#
Run the fixed-checkpoint parcel march with the gas temperature imposed.
Idempotent: a second call is a no-op.
- property states: cantera.SolutionArray | None#
Axial Lagrangian profile (satisfies Boulder’s stage-state collector).
- property scalars: Dict[str, Any]#
Imposed-gas-T scalars (residence time + meta).
- plot_temperature_profile(title='Imposed Gas Temperature Profile')#
Plot the imposed gas temperature
T_gas(x)vs position [degC].
- plot_species_profiles(species=None, title='Species Profiles (imposed gas T)')#
Plot mole-fraction profiles vs position with a residence-time axis.
When
speciesisNone, the six species with the highest peak mole fraction (≥ 0.1 %) are selected automatically.
- bloc.reactor_models.HeatFluxFactory#
- bloc.reactor_models.residence_states_to_series(states)#
Serialize a closed CSTR residence-time profile for the Plots tab.
- Parameters:
states – Profile with extra
t[s] (physical residence time, not axial position).- Returns:
Keys:
t,T,P,X,Y,is_residence. Arrays are plain Python lists for JSON safety.is_spatialis intentionally absent so Boulder does not label the axis as position [m].- Return type:
dict
- bloc.reactor_models.states_to_series(states, fbs_convergence=None)#
Serialize a spatial
SolutionArrayprofile to a JSON-compatible dict.- Parameters:
states – Converged spatial profile with custom
x(position, m) andt(residence time, s) extra columns set by_march_pfr_to_length().fbs_convergence – Per-FBS-iteration list of
Phi_kWvalues, orNone.
- Returns:
Keys:
x,t,T,P,X,Y,is_spatial,fbs_convergence. All arrays are plain Python lists for JSON safety.- Return type:
dict
- class bloc.reactor_models.PFRHomogeneousShellNet(reactors, meta=None)#
Bases:
cantera.ReactorNetReactorNet subclass implementing Forward-Backward Sweep for a PFR stage.
Overrides
advance()to run the FBS heat-loss convergence loop. The spatial integration is performed by_spatial_ode_pass(), which uses thePFRHomogeneousShellreactor directly as the ODE carrier — no auxiliary gas or reactor objects are created. For each pass, a freshReactorNetwraps thePFRHomogeneousShellso CVODE always starts from the correct (heat-loss-corrected) inlet state. The converged spatial profile is stored on the reactor as_statesfor downstream trajectory collection.- Parameters:
reactors – List of reactors to integrate. Must contain exactly one
PFRHomogeneousShell.meta (
dict, optional) – Geometry and insulation parameters for the FBS loop, as produced by_build_pfr_homogeneous_shell().
- MAX_ITER: int = 10#
- CONVERGENCE_TOL: float = 0.01#
- advance_to_steady_state()#
Advance to the tube outlet (one nominal time unit).
- solve_steady()#
Delegate to
advance_to_steady_state()for Bouldersolve_steadykind.Cantera’s default would use the empty reactor list from
super().__init__and fail.
- advance(time)#
Run Forward-Backward Sweep and update the PFR reactor state.
Reads the inlet state from
self._pfr_reactor.phase(set by the staged solver before this call), then iterates_spatial_ode_pass()with updated heat-loss estimates until convergence orMAX_ITERis reached. In the adiabatic branch a single pass with zero heat flux is performed.After convergence the wall flux is pinned to the converged scalar value so a downstream visualization network sees the actual radial loss. The spatial profile is written to
reactor._statesand the scalar toreactor._heat_loss_kW.- Parameters:
time – Nominal advance time [s]. Not used by the length-terminated PFR integration; kept for API compatibility with
ReactorNet.
- property states: cantera.SolutionArray | None#
Converged FBS spatial profile (satisfies
CustomStageNetwork).
- property states_as_series: dict | None#
Return the spatial profile as a JSON-serializable dict for the frontend.
- class bloc.reactor_models.PFRThinShellNet(reactors, meta=None)#
Bases:
cantera.ReactorNetSingle-pass PFR network for the thin-shell hypothesis.
Heat loss depends on the local gas temperature
T(z)so a single forward pass is sufficient — there is no Forward-Backward Sweep. The radial loss enters the ODE through the build-timect.Wall, whoseheat_fluxis wired to a callable that readsreactor.phase.Teach CVODE eval.After
advance()the wall flux is pinned to the integrated scalarPhi_kWso the post-solve visualization network shows a Wall carrying the actual radial loss.- Parameters:
reactors – Stage reactors; must contain exactly one
PFRThinShell.meta (
dict, optional) – Geometry and thermal parameters (length,diameter,insulation,T_amb…) as produced by_build_pfr_thin_shell().
- advance_to_steady_state()#
Advance through the single-pass thin-shell solve.
- solve_steady()#
Delegate to
advance_to_steady_state()(same pattern asPFRHomogeneousShellNet).
- advance(time)#
Run a single-pass thin-shell solve and update the reactor state.
- Parameters:
time – Nominal advance time [s]. Not used by the length-terminated integration; kept for API compatibility with
ReactorNet.
- property states: cantera.SolutionArray | None#
Spatial profile (satisfies
CustomStageNetwork).
- property states_as_series: dict | None#
Return the spatial profile as a JSON-serializable dict for the frontend.
- bloc.reactor_models.compute_tube_furnace_kpis(sim)#
Compute tube-furnace engineering KPIs from a solved STONE Simulation.
Bridges the STONE/Boulder path to the same output key set as
bloc.yaml_utils._tf_kpi_extractor()(the ctwrap path), so thatrun_yaml_scenarios.pyand the legacy ctwrap runner produce the same Calculation Note Excel.Looks for a
PFRWallProfileNetinsim.network.networks(the stage solver mapping). All scalars are read from that network, which is populated duringadvance_to_steady_state.- Parameters:
sim (
bloc.simulation_builder.Simulation) – Solved STONE simulation returned bybloc.simulation_builder.build_simulation_from_yaml().- Returns:
Flat scalar dict with keys matching
bloc.yaml_utils.TF_OUTPUT_VARIABLE_MAP(T_outlet_C,E_conv_J,E_rad_J,P_conv_avg_W,P_rad_avg_W,SEO_MJ_kg,n_steps,h_conv_avg_W_m2_K,Fo_D_min,diameter_mm,t_res_s) plus per-species mole (X_*) and mass (Y_*) fractions. Returns an empty dict when noPFRWallProfileNetis found insim.network.networks.- Return type:
dict
- class bloc.reactor_models.TubeFurnace(gas, *args, clone=False, diameter=0.1, kappa_grey=0.0, mass_flow_rate=0.0, **kwargs)#
Bases:
bloc.reactors.PFRWallProfileIndustrial Tube Furnace model.
A plug-flow reactor heated by an externally prescribed wall-temperature profile
T_wall(x)using forced convection and grey-gas radiation (seePFRWallProfile).STONE kind:
TubeFurnace. For the STONE YAML schema seeTubeFurnaceSchema.Use this kind for any electrically or indirectly heated tube where the wall temperature profile is known or measured. The Carbon-Black tube furnace (Mei-2019 validation) is the canonical example.
See also
PFRWallProfileunderlying numerical engine.
RefractoryReactorinsulated thick-shell reactor (SPRING CGR).
- NETWORK_CLASS: ClassVar[type | None] = None#
- 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.
- 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.reactor_models.RefractoryReactor(gas, *args, **kwargs)#
Bases:
bloc.reactors.PFRHomogeneousShellIndustrial Carbon Growth Reactor (CGR) / refractory-lined vessel.
A plug-flow reactor with homogeneous-shell radial heat loss through an insulation resistance stack, converged by Forward-Backward Sweep (see
PFRHomogeneousShell).STONE kind:
RefractoryReactor. Node id in SPRING YAML:cgr(the CGR in SPRING A3/A4).Use this kind for thick-walled insulated industrial reactors where axial wall conduction smears temperature gradients.
See also
PFRHomogeneousShellunderlying numerical engine.
QuartzTubeReactorthin-shell variant for lab reactors.
- NETWORK_CLASS: ClassVar[type | None] = None#
- mass_and_power(qm_torch, T_torch_input_C, X_torch, qm_2nd_inj, T_2nd_inj_C, X_2nd_inj, P_bar, T_amb_C, gas)#
Compute preheat recovery and residual heat based on reactor states.
Industrial-design helper for SPRING thermal-recovery KPIs (consumed by
bloc.spring_kpi.compute_spring_kpis()).
- 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
- 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.reactor_models.QuartzTubeReactor(gas, *args, **kwargs)#
Bases:
bloc.reactors.PFRThinShellIndustrial quartz-tube / lab-tube reactor.
A plug-flow reactor with thin-shell local-temperature radial heat loss (see
PFRThinShell). Single forward pass; no Forward-Backward Sweep.STONE kind:
QuartzTubeReactor.Use this kind for quartz, fused-silica, or other thin-walled lab reactors where axial wall conduction is negligible.
See also
PFRThinShellunderlying numerical engine.
RefractoryReactorthick-shell variant for industrial vessels.
- NETWORK_CLASS: ClassVar[type | None] = None#
- 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
- 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.reactor_models.ContinuousMixingReactor(gas, *args, **kwargs)#
Bases:
bloc.reactors.PSRIndustrial Torch Mixing Reactor (TMR) / multi-inlet well-mixed vessel.
A perfectly stirred reactor (see
PSR) used to model the turbulent mixing of two or more streams at the outlet of a plasma torch.STONE kind:
ContinuousMixingReactor. Node id in SPRING YAML:tmr(the TMR in SPRING A3/A4).Use this kind for any well-mixed stage where axial gradients are negligible. Assume Da_mix ≫ 1: mixing inside the vessel is faster than chemistry so the CSTR approximation holds.
Network topology#
Stage YAML: OPEN — multi-inlet MFCs, outlet PC/MFC; solved with
ReactorNetandadvance_to_steady_state(default).Inner physics: OPEN CSTR.
t_res_ssizes volume via Bloc post-build (_post_build_design_volumes(),V = τ·ṁ/ρ); it is the design residence time, not the stageadvance_time.See also
PSRunderlying numerical engine.
InstantaneousMixingReactorclosed-parcel alternative when inlet streams are pre-mixed algebraically before chemistry.
- NETWORK_CLASS = None#
- 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.reactor_models.InstantaneousMixingNet(reactors, meta=None)#
Bases:
cantera.ReactorNetReactorNet subclass for instantaneous-mix + closed-τ chemistry.
Mirrors
TorchInstantaneousHeatingNet: the stage network holds no live ODE reactors.advance()only validates that_post_build_design_volumes()has pre-computed the outlet profile.- Parameters:
reactors – Stage reactor list. Must contain exactly one
InstantaneousMixinginstance.meta (
dict, optional) – Parameters from the STONE builder, enriched by_post_build_design_volumes():t_res_s,mass_flow_rate.
- advance_to_steady_state()#
Validate precomputed outlet and delegate.
- solve_steady()#
Delegate steady solve to
advance_to_steady_state().
- advance(time)#
Validate precomputed outlet profile from post-build.
- Parameters:
time – Nominal advance time [s]; unused, kept for API compatibility.
- property states: cantera.SolutionArray | None#
Closed-τ residence-time profile (satisfies
CustomStageNetwork).
- property scalars: Dict[str, Any]#
Build parameters and outlet-state scalars.
- class bloc.reactor_models.InstantaneousMixing(gas, *args, **kwargs)#
Bases:
bloc.reactors.PSREngine: instantaneous HP mix of two inlet streams + closed-τ chemistry.
Step 1 — inlet streams are combined with constant-HP algebraic mixing (
mix_two_streams()), reproducing theDa_mix ≫ 1assumption (turbulent mixing much faster than chemistry).Step 2 — a closed constant-pressure parcel integrates the ODE from
t = 0tot = t_res_swith no inlet/outlet mass exchange.This formalises the legacy pattern:
gas_mixed = mix_two_streams(gas_1, qm_1, gas_2, qm_2) PSR_simu = solve_adiabatic_reactor(qm_total, 0, t_res_s, ...)
- _states#
Residence-time profile recorded by
solve_premixed().- Type:
ct.SolutionArrayorNone
- NETWORK_CLASS: ClassVar[type | None] = None#
- solve_premixed(gas_1, qm_1, gas_2, qm_2, t_res_s, *, verbose=True)#
HP-mix two inlet streams then integrate closed chemistry for t_res_s.
- Parameters:
gas_1 – Cantera Solution objects for the two inlet streams (same or different mechanisms; both must be on the stage mechanism before calling — species mapping is the caller’s responsibility).
gas_2 – Cantera Solution objects for the two inlet streams (same or different mechanisms; both must be on the stage mechanism before calling — species mapping is the caller’s responsibility).
qm_1 – Mass flow rates [kg/s] of each stream.
qm_2 – Mass flow rates [kg/s] of each stream.
t_res_s – Chemical residence time [s]; CVODE integrates 0 → t_res_s on a closed parcel (no MFC flux during integration).
verbose – Print outlet state summary.
- Returns:
- 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.reactor_models.InstantaneousMixingReactor(gas, *args, **kwargs)#
Bases:
InstantaneousMixingIndustrial model: instantaneous mix + closed chemical residence time.
Two inlet streams (e.g. torch primary + secondary injection) are combined with constant-HP algebraic mixing (
mix_two_streams()), then chemistry runs fort_res_sin a closed well-mixed parcel.STONE kind:
InstantaneousMixingReactor.Use when Da_mix ≫ 1 (turbulent mixing time ≪ chemical timescale) and the workflow is a one-shot feedforward chain (not a continuously-fed vessel). For a continuously-fed open CSTR, use
ContinuousMixingReactorinstead.Network topology#
Stage YAML: OPEN — two inlet MFCs (source reservoirs or upstream reactor outlets), outlet MFC/PressureController for downstream handoff.
Inner physics: CLOSED parcel.
_post_build_design_volumes()gathers both inlet states, callssolve_premixed(), and writes back toreactor.phase+syncState(). No live ODE in the stage ReactorNet.See also
ContinuousMixingReactoropen CSTR alternative (continuous feed/discharge).
mix_two_streamsalgebraic HP mixer used in step 1.
- NETWORK_CLASS: ClassVar[type | None] = None#
- solve_premixed(gas_1, qm_1, gas_2, qm_2, t_res_s, *, verbose=True)#
HP-mix two inlet streams then integrate closed chemistry for t_res_s.
- Parameters:
gas_1 – Cantera Solution objects for the two inlet streams (same or different mechanisms; both must be on the stage mechanism before calling — species mapping is the caller’s responsibility).
gas_2 – Cantera Solution objects for the two inlet streams (same or different mechanisms; both must be on the stage mechanism before calling — species mapping is the caller’s responsibility).
qm_1 – Mass flow rates [kg/s] of each stream.
qm_2 – Mass flow rates [kg/s] of each stream.
t_res_s – Chemical residence time [s]; CVODE integrates 0 → t_res_s on a closed parcel (no MFC flux during integration).
verbose – Print outlet state summary.
- Returns:
- 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.reactor_models.PlasmaTorchInstantaneousHeating(gas, *args, **kwargs)#
Bases:
TorchInstantaneousHeatingIndustrial Plasma Torch model — instantaneous-heating variant.
Instantaneous enthalpy jump (plasma power input at
eta * P_torch) followed by adiabatic constant-pressure kinetics fort_res_s(seeTorchInstantaneousHeating).STONE kind:
PlasmaTorchInstantaneousHeating.The
InstantaneousHeatingsuffix distinguishes this model from future plasma-torch implementations that may use a different heating model (e.g., arc-discharge, spatially-resolved, or multi-temperature).Use this kind for all plasma torch stages where the heating is quasi-instantaneous compared to the chemical relaxation time.
See also
TorchInstantaneousHeatingunderlying physics class.
- NETWORK_CLASS: ClassVar[type | None] = None#
- solve_adiabatic(mdot, power_kW, t_res_s, verbose=True)#
Solve adiabatic kinetics using this reactor’s current inlet state.
Adds torch power as an enthalpy jump and integrates one adiabatic pass for
t_res_susing a freshtype(self)(gas, clone=False)carrier.