Runtime objects¶
The live objects build_network hands back, and the state you read off
a pipe inside an on_step callback. This page pins the public
members — the fields and accessors you compose against — not every
internal attribute the solver hangs off these classes.
NetworkBundle¶
The return value of build_network.
Carries the materialised pipes, junctions, and boundary conditions, plus
the coupling lists dispatch_advance consumes. It also unpacks as the
legacy 3-tuple pipes, junctions, bcs = build_network(case).
aeolus1d.io.build.NetworkBundle ¶
Return value of build_network.
Supports the legacy 3-tuple unpack pipes, junctions, bcs = build_network(case)
via iter, and exposes .controllers for callers that want them.
Phase Coolant-3: coolant_pipes and coolant_couplings carry
the parsed-and-instantiated coolant network. coolant_couplings
is the list of (gas_pipe, ThermalWall, CoolantPipe) triples
that advance_network(coolant_couplings=...) consumes directly.
Default-empty so existing callers are unaffected.
Pipe¶
One discretised duct: the gas state on an N-cell finite-volume mesh
plus any species, surface, and source-closure state attached to it.
net.pipes is a dict[str, Pipe] keyed by the pipe id. The members
below are the ones you read or set from user code — the conserved-state
array, the species stack, and the per-cell surface / heat-release state
a chemistry case evolves.
primitives()returns(rho, u, p)arrays over the interior cells — the usual readout in a sampler.Y/Y_extras/species_namesare the species stack:Yis the primary mass fraction (lengthN),Y_extrasis the(N, n_extra)block of additional advected species, andspecies_nameslabels the extra columns in order (the primary's label isspecies_name, singular).surface_stateis a nameddict[str, np.ndarray]of per-cell solid-phase arrays — adsorbed coverages such astheta_Ce/theta_NH3live here, each shape(N,).q_rxnis the per-cell reaction heat-release rate (W/m³), populated by the chemistry sub-step; zero-length on non-reacting pipes.
aeolus1d.components.pipe.Pipe
dataclass
¶
One uniform-dx 1D pipe: geometry, the ghost-padded state, and the switches that select a residual kernel.
A plain dataclass: assigning a field the solver does not read succeeds
without a word and changes nothing (a bug shipped that way once, so this
lists what is read; contract sweep 2026-09-30, from the readers under
solver/, closures/ and bc/).
Fixed at construction (__post_init__ derives them once; assigning
the source field later does not re-derive them): L and N give
dx = L / N, x (cell centres) and the U_pad allocation;
Ng sizes U_pad; A gives A_cell and A_face. The
kernels read dx, N, Ng, A_cell, A_face and
is_uniform_area; they never read L, x or A. pipe.A
after construction is read only by diagnostics (the cylinder port area,
energy_audit), so pipe.A = new_area moves no result. To retaper a
built pipe set A_cell (its setter refreshes is_uniform_area) and
A_face together.
Shapes. U_pad is (N + 2 Ng, 3) = (rho, rho u, rho E)
per cell with Ng ghost rows each side; U is a view of its
N interior rows. A_cell is (N,) [m^2], A_face (N + 1,)
[m^2] (face i is the left face of cell i), both finite and
positive at construction. gamma_pad is (N + 2 Ng,) when set (the
ghost slots hold the boundary cell's gamma) and is read only while
use_per_cell_gamma is true; gamma is the cell mean on such a
pipe. Y is (N,) and Y_extras (N, n_extra) mass
fractions (size 0 = no species). catalyst.T_solid, filter.T_wall
and filter.T_cake are (N,) per-cell solid temperatures, size 0 =
that inertia is off. The per-cell wall temperature of a ThermalWall
or CoolantPipe lives on that object; _thermal_wall and
_coolant_pipe are back-references read only by io.snapshot and
io.resume, never by a kernel.
Who guarantees the shapes. __post_init__ checks and allocates
U_pad, x, A_cell and A_face once, and nothing re-checks them
afterwards (a later direct assignment can put a wrong-shaped array there:
the A_cell setter refreshes only is_uniform_area). set_species
and add_extra_species check the (N,) shape; the Y and
Y_extras property setters do not. update_per_cell_gamma builds
gamma_pad (reallocating on a shape change). io.build sizes the
per-cell solid temperatures and the reaction / surface arrays; the pipe
does not.
Read by the residual kernels (timeloop.make_pipe_residual_fn and
the network / implicit / quasi-steady drivers): U_pad, gamma,
gamma_pad with use_per_cell_gamma, eos_kind / eos_params,
scheme, muscl_limiter_code, hllc_low_mach,
friction_kind / friction_params, heat_kind / heat_params,
porous, catalyst, filter, and the py_* closure seams.
needs_quasi1d (derived from those) selects the area-weighted kernel.
R_gas is read by the closures and the chemistry, not by the flux.
gamma is overwritten by :meth:update_per_cell_gamma and
:meth:update_mixture_gamma, so assigning it on a pipe those drivers
refresh is undone at the next step. mixture_species_db,
gamma_T_from_energy and use_caloric_thermo are read only inside
this class; use_mixture_gamma only by the network drivers'
refresh_network_gamma and by packed_pipes.
Y
property
writable
¶
Y: ndarray
The primary species' mass fractions.
Inputs
none.
Returns:
the live array, shape (N,) (size 0 when no species is tracked).
It is the pipe's own storage, not a copy: an in-place edit
changes the state.
Refuses:
none.
Edges:
the live array is returned, not a copy
(test_the_y_setter_keeps_has_species_coherent).
Y_extras
property
writable
¶
Y_extras: ndarray
The extra species' mass fractions.
Inputs
none.
Returns:
the live array, shape (N, n_extra) (shape (0, 0) when none);
not a copy.
Refuses:
none.
Edges:
starts as shape (0, 0)
(test_the_y_extras_setter_keeps_the_extra_count_coherent).
species_names
class-attribute
instance-attribute
¶
species_names: list[str] = field(default_factory=list)
surface_state
class-attribute
instance-attribute
¶
surface_state: dict[str, ndarray] = field(
default_factory=dict
)
q_rxn
class-attribute
instance-attribute
¶
q_rxn: ndarray = field(default_factory=lambda: np.empty(0))
n_extra_species
property
¶
n_extra_species: int
Number of extra species columns.
Inputs
none.
Returns:
the count cached by the Y_extras setter (0 by default).
Refuses:
none.
Edges:
follows the Y_extras setter
(test_the_y_extras_setter_keeps_the_extra_count_coherent).
primitives ¶
primitives() -> tuple[np.ndarray, np.ndarray, np.ndarray]
Return (rho, u, p) arrays over the interior, the pressure as the solver holds it: through the EOS on a real-gas pipe, with each cell's own gamma on a per-cell-gamma pipe, else the scalar gamma.
Until 2026-09-25 it always used the scalar gamma, so the HDF5
p, snapshots, wall / coolant gas temperatures and the implicit
helpers read a pressure the solver did not hold (+9.7 / -8.1 % on
examples/87's halves; 1.0e6 against 7.5e5 Pa on examples/19). The
one decode timeloop.interior_primitives now delegates to.
Inputs
none (reads U, gamma, and gamma_pad when
use_per_cell_gamma is set, or eos_kind / eos_params
on a real-gas pipe). A valid state has rho > 0 in every cell.
Returns:
(rho, u, p), each shape (N,): [kg/m^3], [m/s], [Pa]. rho
is a VIEW of U[:, 0] (writing to it changes the state);
u and p are new arrays. p is (gamma - 1) rho e
with the scalar gamma, or with each cell's gamma_pad
entry when use_per_cell_gamma and gamma_pad is set, or
the EOS pressure on a real-gas pipe.
Refuses:
none by design: a dead cell is the driver's to diagnose. rho == 0
on the ideal path gives NaN u and p with numpy
RuntimeWarnings and no exception; on the real-gas path it
raises ZeroDivisionError. A negative rho or p is returned as
it is.
Edges:
rho aliases the state, u and p do not
(test_primitives_rho_is_a_view_and_u_p_are_copies).
an uninitialised pipe (all zero) gives NaN, not an error
(test_primitives_of_an_uninitialised_pipe_is_nan_not_an_error).
use_per_cell_gamma without a gamma_pad falls back to the
scalar gamma without a word, and gamma_pad without the
flag is ignored
(test_primitives_uses_gamma_pad_only_when_the_flag_is_set).
a real-gas pipe with a dead cell raises
(test_a_real_gas_dead_cell_raises_in_primitives).
set_species ¶
set_species(
Y_init: float | ndarray, name: str = ""
) -> None
Enable single-species transport. Y_init is a scalar (uniform)
or a length-N array of per-cell mass fractions.
Inputs
Y_init: primary mass fraction, a scalar or an array of shape (N,).
Range (0 <= Y <= 1) is NOT checked here.
name: the species label ("" allowed: an unnamed primary is
skipped by iter_pipe_species and cannot be looked up in a
mixture database).
Returns:
None. Sets Y (a fresh array; an input array is copied, so
later edits to it do not reach the pipe) and species_name.
Y_extras and species_names are left as they were.
Refuses:
an array whose shape is not (N,) -> ValueError naming both
shapes; nothing is changed.
Edges:
scalar -> uniform fill; array -> copied
(test_set_species_fills_copies_and_checks_the_shape).
wrong shape refused
(test_set_species_fills_copies_and_checks_the_shape).
the extras columns are untouched
(test_set_species_fills_copies_and_checks_the_shape).
add_extra_species ¶
add_extra_species(
name: str, Y_init: float | ndarray = 0.0
) -> None
Phase-22: add another advected species column to Y_extras.
Each call appends one column. The primary species (self.Y)
must already be set via set_species first — the extra-species
machinery rides alongside the primary.
Inputs
name: the extra species' label, appended to species_names.
Unique among the extras (a repeat is refused: extras_column
would answer the last column and list.index the first).
The primary's name is NOT compared: it is not an extras column.
Y_init: mass fraction, a scalar or an array of shape (N,); range
NOT checked.
Returns:
None. Appends one column to Y_extras (shape (N, n_extra + 1),
via its setter, so n_extra_species follows) and name to
species_names. An input array is copied.
Refuses:
no primary species yet -> RuntimeError (call set_species
first); a name already among the extras -> ValueError
naming it; an array not of shape (N,) -> ValueError. Nothing
is appended in any case.
Edges:
no primary -> RuntimeError
(test_add_extra_species_needs_a_primary_and_appends_columns).
columns append in call order and the array is copied
(test_add_extra_species_needs_a_primary_and_appends_columns).
wrong shape refused, nothing appended
(test_add_extra_species_needs_a_primary_and_appends_columns).
a repeated name refused, nothing appended
(test_backlog_add_extra_species_refuses_a_duplicate_name).
Junctions¶
net.junctions is a list of junction component objects — one per
[[junction]] in the case. Their concrete classes
(Junction, CorberanJunction, EHRJunction,
PassthroughJunction, …) live under aeolus1d.components, and the
mapping from each kind to its model and theory section is tabulated in
the Component index — start
there rather than against the classes, which are coupling internals.
In normal use you do not construct or mutate junctions directly: you
pass the list straight from net.junctions into
dispatch_advance, which
steps them as part of the network solve.