bloc.reactors.pfr_networks#

Homogeneous-shell PFR network, marching helpers, and RefractoryReactor.

Attributes#

Classes#

PFRHomogeneousShellNet

ReactorNet subclass implementing Forward-Backward Sweep for a PFR stage.

RefractoryReactor

Industrial Carbon Growth Reactor (CGR) / refractory-lined vessel.

PFRThinShellNet

Single-pass PFR network for the thin-shell hypothesis.

QuartzTubeReactor

Industrial quartz-tube / lab-tube reactor.

PFRGasTemperatureProfileNet

Stage network driving a PFRGasTemperatureProfile.

Functions#

residence_states_to_series(states)

Serialize a closed CSTR residence-time profile for the Plots tab.

states_to_series(states[, fbs_convergence])

Serialize a spatial SolutionArray profile to a JSON-compatible dict.

is_pfr_profile_kind(kind)

Return True when kind is a registered STONE kind for any PFR/CGR profile reactor.

Module Contents#

bloc.reactors.pfr_networks.HeatFluxFactory#
bloc.reactors.pfr_networks.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_spatial is intentionally absent so Boulder does not label the axis as position [m].

Return type:

dict

bloc.reactors.pfr_networks.states_to_series(states, fbs_convergence=None)#

Serialize a spatial SolutionArray profile to a JSON-compatible dict.

Parameters:
  • states – Converged spatial profile with custom x (position, m) and t (residence time, s) extra columns set by _march_pfr_to_length().

  • fbs_convergence – Per-FBS-iteration list of Phi_kW values, or None.

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.reactors.pfr_networks.PFRHomogeneousShellNet(reactors, meta=None)#

Bases: cantera.ReactorNet

ReactorNet 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 the PFRHomogeneousShell reactor directly as the ODE carrier — no auxiliary gas or reactor objects are created. For each pass, a fresh ReactorNet wraps the PFRHomogeneousShell so CVODE always starts from the correct (heat-loss-corrected) inlet state. The converged spatial profile is stored on the reactor as _states for 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#
role: ClassVar[str] = 'reactor'#
advance_to_steady_state()#

Advance to the tube outlet (one nominal time unit).

solve_steady()#

Delegate to advance_to_steady_state() for Boulder solve_steady kind.

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 or MAX_ITER is 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._states and the scalar to reactor._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.

property scalars: Dict[str, Any]#

heat loss, geometry, and outlet-state physics quantities.

Outlet T/P/density are read from reactor.phase, which the integrator leaves at the converged outlet after advance().

Type:

FBS scalar outputs

class bloc.reactors.pfr_networks.RefractoryReactor(gas, *args, **kwargs)#

Bases: bloc.reactors.plug_flow.PFRHomogeneousShell

Industrial 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

PFRHomogeneousShell

underlying numerical engine.

QuartzTubeReactor

thin-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 _meta geometry 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, including heat_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_length in the x extra 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 x extra column (axial position [m]).

Returns:

Length-weighted mean temperature in °C. Falls back to the unweighted mean only if states.x is 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 PFRHomogeneousShellNet and delegates to its _spatial_ode_pass. This is the single-shot entry point for standalone use and tests; the FBS convergence loop in PFRHomogeneousShellNet.advance calls _spatial_ode_pass directly.

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]) and x (axial position [m]).

Return type:

ct.SolutionArray

before_update_state(y)#

Inject a pending initial state into CVODE’s y before 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 None for 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.

bloc.reactors.pfr_networks.is_pfr_profile_kind(kind)#

Return True when kind is a registered STONE kind for any PFR/CGR profile reactor.

“Any PFR/CGR profile reactor” means PFRHomogeneousShell or a subclass — e.g. the SPRING RefractoryReactor (CGR) kind. Resolved via Boulder’s schema registry (reactor_class passed to register_reactor_builder), the same mechanism is_torch_reactor_kind() uses — so a new homogeneous-shell PFR subclass is recognized automatically; no hardcoded kind-name list to maintain.

class bloc.reactors.pfr_networks.PFRThinShellNet(reactors, meta=None)#

Bases: cantera.ReactorNet

Single-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-time ct.Wall, whose heat_flux is wired to a callable that reads reactor.phase.T each CVODE eval.

After advance() the wall flux is pinned to the integrated scalar Phi_kW so 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 as PFRHomogeneousShellNet).

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.

property scalars: Dict[str, Any]#

heat loss, geometry, and outlet-state physics quantities.

Outlet T/P/density are read from reactor.phase, which the integrator leaves at the outlet after advance().

Type:

Scalar outputs

class bloc.reactors.pfr_networks.QuartzTubeReactor(gas, *args, **kwargs)#

Bases: bloc.reactors.plug_flow.PFRThinShell

Industrial 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

PFRThinShell

underlying numerical engine.

RefractoryReactor

thick-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 PFRThinShellNet and runs one advance pass.

Returns:

Spatial profile with extra columns t and x.

Return type:

ct.SolutionArray

before_update_state(y)#

Inject a pending initial state into CVODE’s y before 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 None for 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.pfr_networks.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 to T_gas(x) at every spatial checkpoint, so only the kinetics evolve. This is the Dirichlet-on-gas counterpart of the wall-driven PFRWallProfileNet.

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 PFRGasTemperatureProfile reactor.

  • meta – Geometry/profile meta dict (populated by _build_pfr_gas_temperature_profile()). Must contain total_length and the trapezoidal-profile keys (T_gas_K, T_ambient_K, entry_leg, exit_leg, entry_zone, plateau_zone) or an explicit T_gas_profile dict.

  • 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.plug_flow.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 Boulder solve_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 species is None, the six species with the highest peak mole fraction (≥ 0.1 %) are selected automatically.