bloc.reactors.tube_furnace#

Tube furnace Lagrangian model, wall profile network, and KPI bridge.

Classes#

PFRWallProfileNet

Stage network driving a TubeFurnace through a prescribed wall profile.

TubeFurnace

Industrial Tube Furnace model.

SootRadiatingTubeFurnace

Tube furnace with soot-augmented grey-gas radiation.

Functions#

compute_tube_furnace_kpis(sim)

Compute tube-furnace engineering KPIs from a solved STONE Simulation.

Module Contents#

class bloc.reactors.tube_furnace.PFRWallProfileNet(reactors, meta=None, *, wall_T_fn=None, total_length=None, n_points=200, rtol=0.0001, atol=1e-12)#

Bases: bloc.reactors.pfr_networks._LagrangianDuckTypedNetMixin

Stage network driving a TubeFurnace through a prescribed wall profile.

Replaces the legacy LagrangianPFRReactor + LagrangianPFRNetwork + DesignTubeFurnaceNet trio with a single driver built on the unified PFRWallProfile engine and the shared march_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 position x_position = max(x - heating_start, 0) are pushed onto the carrier; the after_eval() hook then injects forced-convection + grey-gas-radiation flux into the energy ODE.

Numerics#

Unlike the retired adaptive net.step loop, this driver uses the fixed-checkpoint net.advance march (n_points default 200), which yields a uniform spatial grid and reproduces the experimentally-validated (Mei 2019) profiles within < 1 %. Spatial resolution is controlled by n_points alone; inner CVODE step size is left to the integrator.

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_min and the recorded *_arr profiles) consumed by compute_tube_furnace_kpis(), report_details and yaml_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

role: ClassVar[str] = 'furnace'#
report_states: ClassVar[bool] = False#
FO_PROFILE_KEYS: ClassVar[tuple[str, ...]] = ('x_arr', 'T_wall_arr', 'T_gas_arr', 'alpha_arr', 'k_arr', 'u_arr', 'Re_arr', 'Pr_arr',...#
NETWORK_DIAGRAM_NOTE: str = 'Node temperatures in this diagram reflect the outlet gas state of the Lagrangian simulation...#
model_notes()#

Return the physical models and numerics this stage used, one line each.

Consumed by the calculation note’s Notes sheet (see bloc.reporting.orchestrator_stone._stone_model_notes_from_sim()). States what was actually used: the convection correlations are the ones the march recorded checkpoint by checkpoint, with the Reynolds range over which each applied, not a static description.

fo_profile()#

Return the axial thermal-homogeneity profile as plain float lists.

JSON-safe, so the profile survives the Calculation Note’s cached bundle. The Excel table used to be rendered straight off a live network object, which only the retired ctwrap path ever provided, so it never appeared in a STONE export.

Returns None before the march has run.

reactors#
E_conv: float = 0.0#
E_rad: float = 0.0#
E_total: 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.plug_flow.PFRWallProfile#

The single PFRWallProfile/TubeFurnace reactor (used by plot helpers).

advance_to_steady_state()#

Run the fixed-checkpoint parcel march from inlet to outlet.

The full axial cantera.SolutionArray is attached to the reactor as _states (consumed by Boulder’s stage-state collector and spatial_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).

export_cfd_conditions()#

Export the tube-furnace trajectory as CFD initial/boundary conditions.

Returns a dict with all the state arrays and scalars needed by Avalanche to render the OpenFOAM case: inlet T, p, composition, mass flow rate, wall T profile (x, T_wall), axial velocity, Re, residence time, diameter, and length.

The node must already have been solved (via advance_to_steady_state() or build_simulation_from_yaml()). This method does not re-run the 1-D solve; it only reads the cached trajectory arrays.

Returns:

CFD-relevant state from the solved tube-furnace trajectory.

Return type:

dict

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 on wall_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_reynolds_profile(title='Reynolds Number — Tube Furnace')#

Plot the local Reynolds number vs position, with the laminar limit.

Re = mdot D / (A mu), evaluated at the local gas state along the march, so it tracks the viscosity rise as the gas heats. Re = 2300 is drawn for reference: below it the flow is laminar and the convection correlation falls back to a constant Nusselt number.

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

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 Boulder solve_steady.

advance(t=1.0)#

Advance to t; for a Lagrangian tube this runs to the outlet.

bloc.reactors.tube_furnace.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 that run_yaml_scenarios.py and the legacy ctwrap runner produce the same Calculation Note Excel.

Looks for a PFRWallProfileNet in sim.network.networks (the stage solver mapping). All scalars are read from that network, which is populated during advance_to_steady_state.

Parameters:

sim (bloc.simulation_builder.Simulation) – Solved STONE simulation returned by bloc.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 gas-phase mole (X_*) and mass (Y_*) fractions (solid carbon excluded and renormalised, reported separately as X_C(s) / Y_C(s)) and, when the feed carries H or C, the performance KPIs shared with the SPRING calc note (H2_yield, C(s)_yield, CH4_conversion, H2_production, C(s)_production, Ecost_H2 (kWh/kgH2)). With a torch stage upstream the performance KPIs are referenced to the process feed and the torch energy rows are added (G_PW_IN (kW), TP_PW_OUT (kW), SEI_torch (MJ/kg), SEO_torch (MJ/kg)); Ecost_H2 then uses the generator electric power as in the SPRING calc note. Returns an empty dict when no PFRWallProfileNet is found in sim.network.networks.

Return type:

dict

class bloc.reactors.tube_furnace.TubeFurnace(gas, *args, clone=False, diameter=0.1, kappa_grey=0.0, mass_flow_rate=0.0, **kwargs)#

Bases: bloc.reactors.plug_flow.PFRWallProfile

Industrial 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 (see PFRWallProfile).

STONE kind: TubeFurnace. For the STONE YAML schema see TubeFurnaceSchema.

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

PFRWallProfile

underlying numerical engine.

RefractoryReactor

insulated 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#
wall_heat_terms()#

Return (Q_conv, Q_rad, h_conv, kappa) for the current phase state.

after_eval is an ODE right-hand-side hook, so the solver also calls it for trial steps it later rejects and for every finite-difference Jacobian column. _last_Q_conv therefore holds whatever perturbed state was evaluated last, which is not the accepted solution and is not reproducible across machines. Anything reporting these terms must recompute them from the accepted state by calling this.

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

add_energy_stream(stream)#

Attach an EnergyStream record to this reactor.

property energy_inlets: list[EnergyStream]#

Energy streams currently flowing into this reactor (power_w > 0).

property energy_outlets: list[EnergyStream]#

Energy streams currently flowing out of this reactor (power_w < 0).

class bloc.reactors.tube_furnace.SootRadiatingTubeFurnace(gas, *args, clone=False, diameter=0.1, kappa_grey=0.0, mass_flow_rate=0.0, soot_density=1800.0, n_C_min=None, **kwargs)#

Bases: TubeFurnace

Tube furnace with soot-augmented grey-gas radiation.

Overrides the energy-balance hook so the radiative flux uses an effective absorption coefficient kappa = kappa_grey + kappa_soot evaluated from the local gas state, instead of the fixed self.kappa_grey used by the base class. kappa_grey therefore carries the clean-gas baseline.

Soot contribution uses the Planck-mean grey-gas correlation (Rodrigues):

\[\kappa_{soot} = 3.83\,\frac{C_0}{C_2}\,f_v\,T\]

where:

  • \(f_v = Y_{soot}\,\rho_{gas}/\rho_{soot}\) is the local soot volume fraction, with \(Y_{soot}\) the summed solid-carbon mass fraction, \(\rho_{gas}\) the gas density, and \(\rho_{soot}\) the soot particle density (soot_density, default 1800 kg/m³).

  • \(C_0 = 6\pi\,E(m)\) is the soot optical constant, with \(E(m) \approx 0.260\) the soot absorption function (dimensionless). Implemented as _SOOT_C0 = 6 * pi * 0.260.

  • \(C_2 = hc/k_B\) is the second radiation constant (Planck law), \(C_2 \approx 0.014388\) m·K. Implemented as _SOOT_C2.

The prefactor 3.83 and the \(C_0/C_2\) grouping are folded into _SOOT_KAPPA_COEFF in code.

References

Rodrigues, P. Modélisation multiphysique de flammes turbulentes suitées avec la prise en compte des transferts radiatifs et des transferts de chaleur pariétaux.

soot_density#
n_C_min = None#
wall_heat_terms()#

Return (Q_conv, Q_rad, h_conv, kappa_eff) for the current state.

See PFRWallProfile.wall_heat_terms(): after_eval runs inside the solver’s right-hand-side evaluations, so _last_Q_conv is whichever trial or Jacobian-perturbation state came last. Reporting code must call this instead.

after_eval(t, LHS, RHS)#

Inject wall convection + soot-augmented grey-gas radiation.

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#
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.

add_energy_stream(stream)#

Attach an EnergyStream record to this reactor.

property energy_inlets: list[EnergyStream]#

Energy streams currently flowing into this reactor (power_w > 0).

property energy_outlets: list[EnergyStream]#

Energy streams currently flowing out of this reactor (power_w < 0).