Skip to content

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.

pipes instance-attribute

pipes = pipes

junctions instance-attribute

junctions = junctions

bcs instance-attribute

bcs = bcs

controllers instance-attribute

controllers: list[Any] = controllers or []

coolant_couplings instance-attribute

coolant_couplings: list[tuple[Pipe, Any, Any]] = (
    coolant_couplings or []
)

wall_thermal_pairs instance-attribute

wall_thermal_pairs: list[tuple[Pipe, Any]] = (
    wall_thermal_pairs or []
)

coolant_pipes instance-attribute

coolant_pipes: dict[str, Any] = coolant_pipes or {}

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_names are the species stack: Y is the primary mass fraction (length N), Y_extras is the (N, n_extra) block of additional advected species, and species_names labels the extra columns in order (the primary's label is species_name, singular).
  • surface_state is a named dict[str, np.ndarray] of per-cell solid-phase arrays — adsorbed coverages such as theta_Ce / theta_NH3 live here, each shape (N,).
  • q_rxn is 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.

L instance-attribute

L: float

N instance-attribute

N: int

gamma class-attribute instance-attribute

gamma: float = 1.4

A class-attribute instance-attribute

A: float | ndarray = 1.0

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)

species_name class-attribute instance-attribute

species_name: str = ''

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.