OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
openswmm::transport Namespace Reference

Namespaces

namespace  fvkernels
 
namespace  heat
 

Classes

class  ArdEngine
 
struct  Cell
 
struct  ClassEnables
 Allocation-free class enables for one domain — what the engines size from. n_msx is the reactions component's species count when MSX is on for the domain; msx_has_wall tells ARD / 2D that the component declares WALL species (their own fallback / warning). More...
 
struct  Donors
 
struct  Draft
 Build the full matrix (states + reasons). Pure: never writes warnings. More...
 
struct  Matrix
 
class  ReactionIntegrator
 
struct  RowLayout
 
struct  RxEvalEnv
 Evaluation environment: pre-gathered pointers, no lookups. More...
 
struct  RxExprSpan
 Compiled expression = span into the shared pool. len 0 ⇒ no expression. More...
 
struct  RxRateContext
 
struct  RxStepReport
 
struct  RxSymbols
 
struct  RxToken
 
class  RxWorkspace
 
class  Tokenizer
 Stateless multi-delimiter tokenizer for SWMM input lines. More...
 

Enumerations

enum class  Domain : int {
  RUNOFF = 0 ,
  GROUNDWATER = 1 ,
  NETWORK_1D = 2 ,
  SURFACE_2D = 3 ,
  COUNT = 4
}
 Rows of the matrix. Values are the C API's SWMM_TRANSPORT_DOMAIN_* codes. More...
 
enum class  SpeciesClass : int {
  POLLUTANTS = 0 ,
  MSX = 1 ,
  AGE = 2 ,
  TEMPERATURE = 3 ,
  COUNT = 4
}
 Columns of the matrix. Values are the C API's SWMM_TRANSPORT_CLASS_* codes. More...
 
enum class  CellState : int {
  ENABLED = 0 ,
  DISABLED_BY_USER = 1 ,
  UNAVAILABLE = 2
}
 One cell's state. Values are the C API's SWMM_TRANSPORT_* state codes. More...
 
enum class  RxHydVar
 

Functions

void warnIfFvDispersionKeyIgnored (SimulationContext &ctx)
 Warn when FV_DISPERSION is set while EULERIAN_ARD reads its own component coefficients.
 
bool ardBoundariesNeedExternalVolumes (const SimulationContext &ctx)
 Test whether resolved ARD boundary rows need shared external carrier assembly.
 
void resolveArdTransportRows (SimulationContext &ctx, std::vector< std::string > &errors)
 Resolve deferred MSX boundary/source rows to native element/species/time-series arrays.
 
void registerArdComponent ()
 Register built-in ARD parser/serializer callbacks in process singleton.
 
bool heatAttrValueOk (HeatAttr attr, double value) noexcept
 Validate a public numeric heat attribute value with parser-equivalent range policy.
 
void registerHeatComponent ()
 Register built-in heat configuration parser and serializer callbacks.
 
void routeLegacyHeat (SimulationContext &ctx, double dt)
 Apply heat flux then legacy complete-mix transport of node/link temperatures.
 
double lidLayerHeatCapacity (const SimulationContext &ctx, const lid::LIDGroupSoA &g, std::size_t unit, int layer) noexcept
 Compute current areal thermal capacity of a conventional-LID layer.
 
void initLidLayerTemperature (SimulationContext &ctx, const lid::LIDSolver &solver)
 Size shared layer scalar state and seed all conventional-LID temperatures.
 
void setLidInflowTemperature (SimulationContext &ctx, int type_index, int unit, int subcatch, double rain_rate, double q_imperv, double q_perv, double q_runon, double lid_area)
 Set one LID unit's incoming degC from rainfall and captured/run-on surface water.
 
void routeLidLayerTemperature (SimulationContext &ctx, const lid::LIDSolver &solver, double dt)
 Mix accepted layer inflows then solve optional LID heat conduction/atmospheric exchange.
 
void addRunonTemperature (SimulationContext &ctx, int donor_sc, int receiver_sc, double q)
 Add donor runoff temperature times routed flow to receiver thermal run-on assembly.
 
void addRunonTemperatureAt (SimulationContext &ctx, int receiver_sc, double q, double temp_c)
 Add a known-temperature positive run-on carrier to one receiver's thermal numerator.
 
void routeSubcatchmentTemperature (SimulationContext &ctx, const runoff::RunoffSoA &soa, double dt)
 Mix snow-adjusted precipitation/run-on and atmospheric heat into subarea thermal stores.
 
Donors donorsFor (lid::LIDType t, bool has_soil)
 Resolve immediate inflow donors/physical vertical adjacency for each LID layer.
 
void layerVolumes (const lid::LIDGroupSoA &g, std::size_t ui, double(&v)[kNL])
 Void-weighted water held in each layer, as a depth per unit area (ft). The four terms are exactly those LIDSolver::storedVolume() sums, so a layer's age is weighted by the same water the mass balance counts.
 
std::vector< int > buildOffsets (const lid::LIDSolver &solver)
 Build flattened conventional-LID group/unit prefix offsets.
 
void armMsxRoutingLedger (SimulationContext &ctx)
 Initialize native network species continuity ledger when absent or row shape changes.
 
void routeLegacyMsx (SimulationContext &ctx, double dt)
 Transport native BULK species through legacy node/link complete-mix routing and LID ports.
 
void drainMsxCouplingQueue (SimulationContext &ctx, double dt)
 Convert accepted queued coupling inventory into native external mass rate for this substep.
 
void bookMsxSystemOutflow (SimulationContext &ctx, int node, double q, bool flooding, double dt)
 Add native BULK species inventory carried by accepted system discharge to continuity ledger.
 
bool ardReactionsActive (const SimulationContext &ctx)
 Test configured/compiled native reaction flags for ARD binding.
 
bool ardHasWallSpecies (const SimulationContext &ctx)
 Test whether any configured reaction species is marked WALL.
 
void reactArdStage (SimulationContext &ctx, double dt, double *cell_phi, const double *cell_a, const double *cell_dx, int n_cells, double *node_mass, const double *node_vol, int n_nodes, int n_pollut, int ns_total, double min_store_vol, int temp_row, const int *cell_conduit, const int *conduit_link)
 Decay pollutant rows and integrate native reaction rows in ARD cell/node stores.
 
std::string compileReactionExpression (const std::string &src, const RxSymbols &symbols, std::vector< RxToken > &pool, RxExprSpan &out, int &error_col)
 Compile an infix scalar reaction expression into appended stack-machine tokens.
 
double evalReactionExpression (const std::vector< RxToken > &pool, const RxExprSpan &span, const RxEvalEnv &env) noexcept
 Evaluate a validated compiled reaction span with stack-local scratch.
 
int reactionFunctionCount ()
 Read number of supported compiled scalar function entries.
 
bool reactionFunctionInfo (int idx, const char **name, int *arity)
 Read name and argument count of one supported expression function.
 
int reactionHydVarCount ()
 Read number of declared hydraulic/thermal/groundwater expression variables.
 
bool reactionHydVarInfo (int idx, const char **name, const char **description)
 Read canonical variable name and description including its declared units/support.
 
std::string reactionContextDiagnostic (const ReactionData &rx, const std::vector< RxToken > &pool, const RxExprSpan &span, int context)
 Recursively reject hydraulic/species/pollutant references unavailable in one reactor context.
 
bool reactionHydVarPopulated (int idx)
 Test the network-quality variable range currently populated by native routing.
 
std::string unpopulatedHydVarDiagnostic (const std::string &src, const std::vector< RxToken > &pool, const RxExprSpan &span, int &error_col)
 Report first compiled hydraulic variable not in the network-populated range.
 
double reactionAreaFactor (ReactionAreaUnits units)
 Convert native square feet to configured reaction wall/dry-store area units.
 
double reactionWallArea (const SimulationContext &c, bool link_element, int e, bool reference=false)
 Resolve explicit or hydraulic wetted reaction wall area for an element.
 
double reactionAreaVolume (const SimulationContext &c, bool link_element, int e, double volume)
 Compute active wetted reaction wall area per litre of water.
 
void reactionWallScales (const SimulationContext &c, bool link_element, int e, double volume, std::vector< double > &scales)
 Build per-species active-to-reference wall coverage multipliers.
 
void ensureMsxState (SimulationContext &ctx)
 Lazily size + seed the MSX element state; warn once about the R4b transport limitation when any RATE MSX species exists in either scope (LEGACY only — under LARD the species ride the segments as of L3).
 
void noteNegativeClamp (SimulationContext &ctx, const char *where)
 Review A2: one warning per run when the reaction step had to clamp a negative concentration. The LEGACY binding also books the mass the clamp added (msx_ledger.clamped); the other engines report it here only.
 
double clampRateSpecies (const ReactionData &rx, bool tank, double *block, double *added)
 Floor negative RATE species only and optionally report each concentration addition.
 
void reactSpeciesBlock (SimulationContext &ctx, bool tank, double dt, double *species_block, const double *pollut, double hrt_seconds, double temp_c, int element)
 React one LARD-owned tuple with held HRT/temperature and optional element geometry.
 
bool legacyReactionsActive (const SimulationContext &ctx)
 Test configured and compiled native reaction readiness.
 
void reactLegacyNodes (SimulationContext &ctx, double dt)
 Run legacy-bound exact pollutant decay and native node kinetics once.
 
void reactLegacyLinks (SimulationContext &ctx, double dt)
 Run legacy-bound exact pollutant decay and native link kinetics once.
 
void warnIfLegacyBindingBypassed (SimulationContext &ctx)
 Warn when configured compiled reactions are bypassed by IGNORE_QUALITY.
 
const std::vector< std::string > & reactionSectionTags ()
 Borrow the complete fixed set of supported embedded/external reaction section names.
 
void applyReactionSections (SimulationContext &ctx, const components::ComponentConfigSections &config, std::vector< std::string > &errors)
 Parse, validate, compile and register one native multispecies reaction system.
 
void applyEmbeddedReactionSections (SimulationContext &ctx, bool external_component_registered, std::vector< std::string > &errors)
 Apply retained INP reaction sections unless an external component has precedence.
 
void registerReactionsComponent ()
 Register native reaction parser/serializer callbacks under the built-in component ID.
 
bool recompileReactionSystem (SimulationContext &ctx, std::vector< std::string > &errors)
 Rebuild all compiled reaction expressions and validate scoped availability/profile constraints.
 
double reactionSourceFactor (const ReactionData &r, const ReactionData::Source &source, double seconds)
 Read a periodic reaction-source pattern factor at an elapsed simulation time.
 
double reactionBoosterMass (SimulationContext &ctx, int node, int species, double mass, double mixed_volume, double arriving_volume)
 Compute and book the first matching node/species booster inventory addition.
 
std::string serializeReactionSystem (const SimulationContext &ctx)
 Serialize configured native reaction metadata and scoped laws to INP section text.
 
std::string serializeWaterAgeConfig (const SimulationContext &ctx)
 Serialize configured constant water-age source rows to canonical component text.
 
void registerWaterAgeComponent ()
 Register the built-in water-age configuration parser and serializer callbacks.
 
void routeLegacyAge (SimulationContext &ctx, double dt)
 Advance age seconds through legacy node/conduit mixing without altering pollutants.
 
void initLidLayerAge (SimulationContext &ctx, const lid::LIDSolver &solver)
 Size shared conventional-LID scalar storage and seed retained-water layer ages.
 
void setLidInflowAge (SimulationContext &ctx, int type_index, int unit, int subcatch, double rain_rate, double q_imperv, double q_perv, double q_runon, double lid_area)
 Set one unit's scalar inflow age from rainfall and captured/run-on surface water.
 
void routeLidLayerAge (SimulationContext &ctx, const lid::LIDSolver &solver, double dt)
 Advance and mix conventional-LID layer ages after accepted layer hydraulics.
 
void addRunonAge (SimulationContext &ctx, int donor_sc, int receiver_sc, double q)
 Add donor subcatchment runoff-age rate to receiver run-on numerator.
 
void routeSubcatchmentAge (SimulationContext &ctx, const runoff::RunoffSoA &soa, double dt)
 Age/mix subarea water stores with snow-adjusted precipitation and assembled run-on.
 
double arrivingPrecipRate (const SimulationContext &ctx, std::size_t ui, int subarea) noexcept
 Read arriving liquid precipitation after optional snowpack storage/melt.
 
double arrivingMeltFraction (const SimulationContext &ctx, std::size_t ui, int subarea) noexcept
 Read the melt fraction of arriving liquid precipitation.
 
double arrivingPrecipTemperature (const SimulationContext &ctx, std::size_t ui, int subarea) noexcept
 Mix rain and zero-degree meltwater temperatures by arriving melt fraction.
 
double arrivingPrecipAge (const SimulationContext &ctx, std::size_t ui, int subarea) noexcept
 Mix configured rain age with retained meltwater age by arriving melt fraction.
 
double initialAgeSecondsFor (const SimulationContext &ctx, bool is_link, int idx, double fallback)
 Per-element initial age (SECONDS) for one node/link, falling back to fallback (normally the INITIAL_STATE global) when no [INITIAL_QUALITY] row targets the element. Later rows win.
 
double initialTempFor (const SimulationContext &ctx, bool is_link, int idx, double fallback)
 Per-element initial temperature (degC) for one node/link, falling back to fallback (normally the INITIAL_STATE global).
 
void applyInitialAgeOverrides (SimulationContext &ctx)
 Apply WATER_AGE rows onto water_age_state.node_age/link_age (hours -> seconds). No-op when a hotstart state is loaded (D-IQ7) or the arrays are unsized.
 
void applyInitialTempOverrides (SimulationContext &ctx)
 Apply TEMPERATURE rows onto heat_state.node_temp/link_temp (degC). No-op on unsized arrays.
 
bool initialQualityHasMsxRow (const SimulationContext &ctx, bool is_link, int elem_idx, int species)
 Test whether a resolved initial-quality table already owns an element/reaction species seed.
 
std::vector< std::string > mirrorInitialQualityMsxRows (SimulationContext &ctx)
 Mirror resolved MSX initial seeds into the native reaction component's element seed table.
 
ClassEnables network1DEnables (const SimulationContext &ctx) noexcept
 Resolve allocation-free native network class counts from current project policy.
 
ClassEnables surface2DEnables (const SimulationContext &ctx) noexcept
 Resolve allocation-free surface native class eligibility from project and 2D opt-outs.
 
ClassEnables groundwaterEnables (const SimulationContext &ctx) noexcept
 Resolve allocation-free canonical aquifer class eligibility for an active integrated kernel.
 
RowLayout canonicalRows (const SimulationContext &ctx, const ClassEnables &e)
 Build an owned canonical pollutant/MSX/age/temperature row layout for supplied enables.
 
Matrix resolve (const SimulationContext &ctx, const Draft *draft)
 Build a domain-by-species transport capability matrix with explicit reasons and counts.
 
const char * domainName (Domain d) noexcept
 Format a transport matrix domain as a human-readable label.
 
const char * speciesClassName (SpeciesClass c) noexcept
 Format a transport species class as a human-readable label.
 
const char * cellStateName (CellState s) noexcept
 Format a transport capability state as its canonical uppercase label.
 
std::string formatReportBlock (const Matrix &m)
 Format a capability matrix as a readable fixed-column report and unavailable explanations.
 

Variables

constexpr int kNL = LidLayerSpeciesState::kLayerCount
 
constexpr int kExternal = -1
 -1 means "external to the unit"; -2 means "this type has no such layer".
 
constexpr int kAbsent = -2
 
constexpr int kSurf = static_cast<int>(LidLayer::SURFACE)
 
constexpr int kPave = static_cast<int>(LidLayer::PAVEMENT)
 
constexpr int kSoil = static_cast<int>(LidLayer::SOIL)
 
constexpr int kStor = static_cast<int>(LidLayer::STORAGE)
 
constexpr int kSubIMPERV0 = 0
 
constexpr int kSubIMPERV1 = 1
 
constexpr int kSubPERV = 2
 
constexpr double kMeltwaterTempC = 0.0
 
constexpr double ZERO_DEPTH
 
constexpr double LEGACY_ZERO
 
constexpr double ZERO_DEPTH
 
constexpr double LEGACY_ZERO
 
constexpr int kRxMaxStackDepth
 
constexpr double ZERO_DEPTH
 
constexpr double LEGACY_ZERO
 

Enumeration Type Documentation

◆ CellState

enum class openswmm::transport::CellState : int
strong

One cell's state. Values are the C API's SWMM_TRANSPORT_* state codes.

Enumerator
ENABLED 

rows are carried in this domain

DISABLED_BY_USER 

a key turned it off — reason names the key

UNAVAILABLE 

nothing to carry, or the solver lacks it — reason says which

◆ Domain

enum class openswmm::transport::Domain : int
strong

Rows of the matrix. Values are the C API's SWMM_TRANSPORT_DOMAIN_* codes.

Enumerator
RUNOFF 

subcatchment runoff + LID

GROUNDWATER 

legacy per-subcatchment aquifers

NETWORK_1D 

LEGACY / EULERIAN_ARD / LAGRANGIAN routing.

SURFACE_2D 

the 2D mesh

COUNT 

◆ RxHydVar

enum class openswmm::RxHydVar : int
strong

Hydraulic variables available in reaction expressions (reactions plan §2; engines populate the evaluation environment at R6). Order is the ABI of the evaluator's hydvar array.

◆ SpeciesClass

enum class openswmm::transport::SpeciesClass : int
strong

Columns of the matrix. Values are the C API's SWMM_TRANSPORT_CLASS_* codes.

Enumerator
POLLUTANTS 

[POLLUTANTS]

MSX 

reactions component species

AGE 

WATER_AGE

TEMPERATURE 

TEMPERATURE

COUNT 

Function Documentation

◆ addRunonAge()

void openswmm::transport::addRunonAge ( SimulationContext & ctx,
int donor_sc,
int receiver_sc,
double q )

Add donor subcatchment runoff-age rate to receiver run-on numerator.

Parameters
[in,out]ctxEnabled water-age state with prepared donor and receiver arrays.
[in]donor_scValid nonnegative donor subcatchment ID; uncovered returns.
[in]receiver_scValid nonnegative receiver ID; uncovered returns.
[in]qRouted run-on ft3/s, not interval volume; finite sign is not checked.
Note
Adds q*donor age seconds, does not clear numerator, transfer water or advance clock. Allocation-free; caller serializes cleared run-on assembly and subsequent watershed mix.

Accumulate run-on age-volume from a donor subcatchment to its receiver. Called from the run-on assembly beside the flow it mirrors.

◆ addRunonTemperature()

void openswmm::transport::addRunonTemperature ( SimulationContext & ctx,
int donor_sc,
int receiver_sc,
double q )

Add donor runoff temperature times routed flow to receiver thermal run-on assembly.

Accumulate run-on temperature from donor_sc onto receiver_sc.

Parameters
[in,out]ctxEnabled thermal state with covered donor runoff and receiver numerator/rate arrays.
[in]donor_scValid nonnegative donor subcatchment identity; uncovered returns.
[in]receiver_scValid nonnegative receiver identity; uncovered returns.
[in]qRouted run-on ft3/s; addRunonTemperatureAt accepts only positive values.
Note
No queue clearing, water/clock update or allocation; caller owns exclusive run-on assembly.

The RATE convention every loader uses: donors add q · T, the consumer divides by the total rate. Mirrors addRunonAge, and must be called at every contributor to runon_inflow — the subcatchment cascade, the LID underdrain return, and the outfall return. A3 filled this numerator from one of the three and divided by all three, which produced arriving water younger than anything entering the model. The temperature analogue of that defect is quieter and worse: a missing contributor pulls the arriving temperature toward 0 °C, which is a plausible number.

  • Argument q: Volumetric flow rate, ft³/s.
Here is the call graph for this function:

◆ addRunonTemperatureAt()

void openswmm::transport::addRunonTemperatureAt ( SimulationContext & ctx,
int receiver_sc,
double q,
double temp_c )

Add a known-temperature positive run-on carrier to one receiver's thermal numerator.

Accumulate run-on at an explicitly supplied temperature.

Parameters
[in,out]ctxEnabled thermal state; writes matching receiver rate and temperature-rate arrays.
[in]receiver_scValid nonnegative subcatchment ID; uncovered returns.
[in]qPositive finite ft3/s; nonpositive/NaN returns.
[in]temp_cFlow temperature degC, copied without finite/range validation.
Note
Adds q*temp and q without clearing prior receipts. No physical water/clock/global-ledger change, allocation or source consumption; exclusive source-assembly phase.

For contributors whose donor is not another subcatchment: the outfall return (which carries heat_state.node_temp) and, from H5b, the LID underdrain. Adds to the numerator and the rate together — the pairing is why this is one function and not two array writes at each call site.

  • Argument q: Volumetric flow rate, ft³/s.
  • Argument temp_c: Temperature of that flow, °C.
Here is the caller graph for this function:

◆ applyEmbeddedReactionSections()

void openswmm::transport::applyEmbeddedReactionSections ( SimulationContext & ctx,
bool external_component_registered,
std::vector< std::string > & errors )

Apply retained INP reaction sections unless an external component has precedence.

Parameters
[in,out]ctxEmbedded component rows and final reaction/name state, warnings/config updated.
[in]external_component_registeredTrue warns/ignores embedded sections; external owner wins.
[in,out]errorsPassed to applyReactionSections, append-only except underlying reaction metadata reset.
Note
No embedded rows returns. Otherwise appends style/precedence warning each invocation; not once-latched. Builds copied synthetic section set then parses/compiles. Allocation can leave warnings or partial metadata; no water/clock advance, exclusive initial configuration chronology.

Embedded fallback (called from SWMMEngine::open after component resolution): if [REACTION_*] sections were found in the legacy .inp, apply them with a style warning — unless an external reactions component was registered, in which case the external file wins wholesale and the embedded sections are reported ignored.

Here is the call graph for this function:

◆ applyInitialAgeOverrides()

void openswmm::transport::applyInitialAgeOverrides ( SimulationContext & ctx)
inline

Apply WATER_AGE rows onto water_age_state.node_age/link_age (hours -> seconds). No-op when a hotstart state is loaded (D-IQ7) or the arrays are unsized.

Parameters
[in,out]ctxStable resolved initial-quality rows and already-sized native node/link age arrays in s. Matching in-range age targets receive authored hours*3600 in row order, last wins.
Note
Hotstart-loaded age is preserved. Negative/out-of-array targets ignored, unrelated kinds skipped; no resize/finite/sign validation. Call after owner's final resize/initial fallback seed, before evolution; repeated call reapplies seeds, not an incremental age operator. Exclusive state, no allocation/water/engine-clock change.
Here is the caller graph for this function:

◆ applyInitialTempOverrides()

void openswmm::transport::applyInitialTempOverrides ( SimulationContext & ctx)
inline

Apply TEMPERATURE rows onto heat_state.node_temp/link_temp (degC). No-op on unsized arrays.

Parameters
[in,out]ctxStable resolved initial-quality rows and already-sized native node/link degC arrays, overwritten at matching valid targets in row order (last wins).
Note
Skips negative/out-of-array indices and other kinds; no hotstart guard, resize or finite validation. Caller enforces temperature hotstart precedence and invokes only at correct seed phase, after final state resize. Repeated call reapplies initial values; no water/clock mutation, serial use.
Here is the caller graph for this function:

◆ applyReactionSections()

void openswmm::transport::applyReactionSections ( SimulationContext & ctx,
const components::ComponentConfigSections & config,
std::vector< std::string > & errors )

Parse, validate, compile and register one native multispecies reaction system.

Parameters
[in,out]ctxFinal native node/link/subcatch/landuse/LID names and pollutant registry; replaces reaction metadata, installs compiled tokens/spans and successful native registry species.
[in]configSupported REACTION_* sections and source path used in diagnostics; read synchronously.
[in,out]errorsAppends parse/profile/compile diagnostics; any nonempty vector at final parse check (including preexisting caller errors) clears reaction metadata and prevents registration.
Note
Already configured refuses duplicate without clearing existing state. Otherwise clears at entry, parses declarations before scoped laws/seeds/patterns/sources/walls/LIDs, then rejects LAGRANGIAN WALL profile. Requires at least one species; zero-species early return can retain partially parsed options. Final parse/compile refusal clears reaction metadata; warnings remain. Successful registry insertion can allocate/throw after earlier species registrations, no transactional rollback. Does not seed evolved runtime species arrays, resolve hydraulic ownership or advance physical water/clock. Exclusive startup, matching name tables and correctly built parallel model arrays required.

Parse + validate a set of reaction sections into ctx.reactions and the species registry. Shared by the component apply hook (external file) and the embedded fallback. Diagnostics are appended to errors (fatal).

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ardBoundariesNeedExternalVolumes()

bool openswmm::transport::ardBoundariesNeedExternalVolumes ( const SimulationContext & ctx)

Test whether resolved ARD boundary rows need shared external carrier assembly.

Parameters
[in]ctxStable selected quality solver, ignore flag and resolved boundary-node array.
Returns
True for EULERIAN_ARD with quality enabled and nonempty bc_node, independent of pollutant count/configured/resolved flag. No mutation/allocation or implicit binding.

True when the external-load loaders must run even though the model has no pollutants: a [TRANSPORT_BOUNDARIES] row injects qual_vol_in * concentration, and qual_vol_in is accumulated by those loaders. Without this an MSX-ONLY model — the nh2cl shape, and the one E5a exists to enable — assembles no inflow volume and its boundary delivers exactly nothing.

◆ ardHasWallSpecies()

bool openswmm::transport::ardHasWallSpecies ( const SimulationContext & ctx)

Test whether any configured reaction species is marked WALL.

Parameters
[in]ctxStable species_is_wall vector.
Returns
True for any nonzero flag, independent of configured/compiled/active state. Pure/no allocation.

True when any declared MSX species is WALL — unsupported under the ARD engine (no transport semantics for attached species yet); the engine falls back to LEGACY, whose R4 binding runs them element-locally.

◆ ardReactionsActive()

bool openswmm::transport::ardReactionsActive ( const SimulationContext & ctx)

Test configured/compiled native reaction flags for ARD binding.

Parameters
[in]ctxStable reaction metadata.
Returns
configured and compiled, without species/quality/profile/shape validation or mutation.

True when the reactions component is active (configured + compiled) — the ARD engine's condition for carrying MSX species on the mesh.

Here is the caller graph for this function:

◆ armMsxRoutingLedger()

void openswmm::transport::armMsxRoutingLedger ( SimulationContext & ctx)

Initialize native network species continuity ledger when absent or row shape changes.

Parameters
[in,out]ctxPrepared old native water volumes, reaction initial state and native LID held inventories; ensures MSX concentration state then arms/resets matching ledger as needed.
Note
Initial BULK inventory is node concentration*old ft3 plus held native LID mass, and link concentration*old ft3. WALL rows excluded. Already armed matching ledger preserved. Concentration*ft3 convention, no28.317/user-mass conversion. Requires covered species flags/volumes/seeds; allocation can partially reset. Exclusive initial accepted-routing phase, no water/clock advance.

Advect the MSX element state one routing step on the LEGACY CSTR path. No-op unless a reaction system with at least one species is configured.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ arrivingMeltFraction()

double openswmm::transport::arrivingMeltFraction ( const SimulationContext & ctx,
std::size_t ui,
int subarea )
noexcept

Read the melt fraction of arriving liquid precipitation.

Fraction of the arriving water that is MELTWATER, in [0, 1].

Parameters
[in]ctxStable configured source scalars and prepared subcatchment snow/rain/melt receipt arrays.
[in]uiZero-based subcatchment index; missing optional per-subcatch arrays use fallback.
[in]subareakSubPERV selects pervious snow data; any other value selects impervious.
Returns
Melt/net clamped0..1 when snow enabled and both covered nonnegative with positive net; otherwise0.
Note
No source consumption, physical water/clock change or allocation. Caller supplies finite configuration/hydraulic rates; only explicit fallback/ratio guards repair missing/invalid inputs.

Under a pack the arriving water is two different waters: meltwater, and rain that reached the ground through the snow-free fraction. arrivingPrecipRate returns their sum, and a sum cannot say what either is worth — this is the split.

Returns 0 wherever there is no pack, IGNORE_SNOWMELT is on, or nothing arrived, so a caller can blend unconditionally and a bare deck is bit-identical to its pre-S2 behaviour.

Here is the caller graph for this function:

◆ arrivingPrecipAge()

double openswmm::transport::arrivingPrecipAge ( const SimulationContext & ctx,
std::size_t ui,
int subarea )
noexcept

Mix configured rain age with retained meltwater age by arriving melt fraction.

Water age of the water arriving at one subarea [seconds] (S2b).

Parameters
[in]ctxStable configured source scalars and prepared subcatchment snow/rain/melt receipt arrays.
[in]uiZero-based subcatchment index; missing optional per-subcatch arrays use fallback.
[in]subareakSubPERV selects pervious snow data; any other value selects impervious.
Returns
Age seconds; missing/negative/NaN melt age uses configured rainfall age; otherwise flow-fraction blend.
Note
No source consumption, physical water/clock change or allocation. Caller supplies finite configuration/hydraulic rates; only explicit fallback/ratio guards repair missing/invalid inputs.

The age analogue of arrivingPrecipTemperature, and it uses the same arrivingMeltFraction — not an equivalent expression, the same call. Under a pack the arriving water is meltwater carrying the pack's residence time plus rain that reached the ground through the snow-free fraction carrying the configured WaterAgeSource::RAINFALL age:

a = (1 − f)·a_rain + f·a_pack

If the two tracks ever computed f separately they could drift, and the drift would be invisible: both answers stay inside their brackets, and only a deck comparing arriving age against arriving temperature could see it. One call is what makes that unrepresentable.

Where a_pack comes from snow_melt_age_*, published beside snow_melt_* under the
identical area blend. It is NOT the age of the water still in the pack — a pack that empties this step publishes the age its water HAD, which the remaining-water age cannot express because there is none.
The no-pack answer Returns the configured RAINFALL age wherever there is no pack,
IGNORE_SNOWMELT is on, nothing arrived, or the pack published no melt — so a caller blends unconditionally and a bare deck is bit-identical to its pre-S2b behaviour.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ arrivingPrecipRate()

double openswmm::transport::arrivingPrecipRate ( const SimulationContext & ctx,
std::size_t ui,
int subarea )
noexcept

Read arriving liquid precipitation after optional snowpack storage/melt.

Net precipitation actually reaching one subarea this step [ft/s].

Parameters
[in]ctxStable configured source scalars and prepared subcatchment snow/rain/melt receipt arrays.
[in]uiZero-based subcatchment index; missing optional per-subcatch arrays use fallback.
[in]subareakSubPERV selects pervious snow data; any other value selects impervious.
Returns
Native depth rate ft/s: pervious snow-net array for subarea==kSubPERV, impervious otherwise; missing/disabled snow or negative net uses gage rainfall (missing gage0).
Note
No source consumption, physical water/clock change or allocation. Caller supplies finite configuration/hydraulic rates; only explicit fallback/ratio guards repair missing/invalid inputs.

This is the mixing volume, and it is not always the rainfall.

ctx.subcatches.rainfall is set once, at Runoff.cpp:294-295, to rain + SNOWFALL, and never updated. On a subcatchment with a snowpack the runoff solver does not use it: it uses snow_net_imperv for IMPERV0/IMPERV1 and snow_net_perv for PERV (Runoff.cpp:548-552), each built as imelt + rainfall·(1 − asc) — melt, plus the rain falling on the snow-free fraction (SWMMEngine.cpp:1608-1616).

Reading the rainfall field on such a deck is wrong twice over:

  • snowfall is counted as arriving liquid, so water being stored in the pack is mixed into the surface as though it had landed, and
  • snowmelt is not counted at all, so the water that genuinely arrives is invisible to the mixing volume and the surface ages as if nothing arrived.

The second of those is A3's own net-gain failure (lessons 64, 68) reappearing through a different field: the mixing volume is again not the arriving volume. They do not cancel — they are displaced by the whole residence time of the pack, which is precisely the quantity a snow-aware age model exists to measure.

The -1.0 sentinel is the whole guard snow_net_* initialise to -1.0
(SubcatchData.hpp:642), and the solver's own test is >= 0.0 (Runoff.cpp:551-552). A subcatchment with a pack but no melt this step publishes 0.0, which is a real rate; only the negative sentinel means "no pack, use the gage". This function mirrors that test exactly rather than inventing its own.
IGNORE_SNOWMELT Falls back to the gage value, matching Runoff.cpp:548's
!ctx.options.ignore_snow_melt and legacy subcatch.c:784.
  • Argument subarea: One of kSubIMPERV0 / kSubIMPERV1 / kSubPERV.
Here is the caller graph for this function:

◆ arrivingPrecipTemperature()

double openswmm::transport::arrivingPrecipTemperature ( const SimulationContext & ctx,
std::size_t ui,
int subarea )
noexcept

Mix rain and zero-degree meltwater temperatures by arriving melt fraction.

Temperature of the water arriving at one subarea [°C] (S2).

Parameters
[in]ctxStable configured source scalars and prepared subcatchment snow/rain/melt receipt arrays.
[in]uiZero-based subcatchment index; missing optional per-subcatch arrays use fallback.
[in]subareakSubPERV selects pervious snow data; any other value selects impervious.
Returns
degC: configured global rainfall temperature blended with kMeltwaterTempC (0degC).
Note
No source consumption, physical water/clock change or allocation. Caller supplies finite configuration/hydraulic rates; only explicit fallback/ratio guards repair missing/invalid inputs.

Meltwater is at 0 °C essentially by definition — that is what melting means — so the arriving temperature is the melt fraction blended against the configured HeatSource::RAINFALL value:

T = (1 − f)·T_rain + f·0

On a winter deck this is not a small approximation to make: it is the difference between a stream fed by snowmelt and one fed by rain. Unlike the age half, it needs no pack state at all — the freezing point is not something the pack has to remember.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ bookMsxSystemOutflow()

void openswmm::transport::bookMsxSystemOutflow ( SimulationContext & ctx,
int node,
double q,
bool flooding,
double dt )

Add native BULK species inventory carried by accepted system discharge to continuity ledger.

Parameters
[in,out]ctxArmed native MSX ledger and stable node concentrations/species flags.
[in]nodeNative node ID; negative/uncovered returns.
[in]qPositive finite outflow ft3/s; nonpositive/NaN returns.
[in]floodingTrue books flooding row, false regular outflow.
[in]dtMatching accepted positive finite duration s, not independently checked.
Note
Adds q*c*dt concentration*ft3, skips WALL. Requires flooding/outflow row consistency (only outflow shape explicitly checked). No node inventory/water removal, queue consumption, allocation or clock advance; caller owns exactly-once accepted flux ledger booking.

Review B14: book species leaving the system at node at flow q (ft³/s, > 0) for dt into the routing ledger's outflow or flooding row, at the node's published concentration. No-op until the LEGACY ledger is armed. Called from the same classification that books pollutants.

◆ buildOffsets()

std::vector< int > openswmm::transport::buildOffsets ( const lid::LIDSolver & solver)

Build flattened conventional-LID group/unit prefix offsets.

Flat index of each per-type group's first unit; back() == n_units.

Parameters
[in]solverStable group counts/order; nonnegative counts and signed-int sum must fit.
Returns
Owning numGroups()+1 offsets starting0 and ending total units; no units still returns[0]. No context mutation or count/overflow validation; vector allocation can throw.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ canonicalRows()

RowLayout openswmm::transport::canonicalRows ( const SimulationContext & ctx,
const ClassEnables & e )

Build an owned canonical pollutant/MSX/age/temperature row layout for supplied enables.

Parameters
[in]ctxStable pollutant and reaction names/flags covering supplied counts.
[in]eNonnegative qualified class counts and optional age/temperature/BULK-only flags, consistent with available native name/flag arrays.
Returns
Owned layout with counts, names and age/temp index (-1 when absent), order pollutants, selected reaction species, WATER_AGE, TEMPERATURE. BULK-only skips WALL species.
Note
Allocates/copies names and may throw; does not repair inconsistent counts or guarantee names extent equals advertised ns for invalid enables. No registry/owner/physical/clock mutation.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cellStateName()

const char * openswmm::transport::cellStateName ( CellState s)
noexcept

Format a transport capability state as its canonical uppercase label.

Parameters
[in]sState enum, invalid values permitted for fallback.
Returns
Static nonowned ENABLED/DISABLED_BY_USER/UNAVAILABLE literal or '?'. No mutation/allocation.

◆ clampRateSpecies()

double openswmm::transport::clampRateSpecies ( const ReactionData & rx,
bool tank,
double * block,
double * added )

Floor negative RATE species only and optionally report each concentration addition.

Parameters
[in]rxStable n_species and selected pipe/tank form arrays.
[in]tankTrue selects tank forms, false pipe.
[in,out]blockWritable n_species concentrations, finite expected; negative RATE becomes0, EQUIL/FORMULA/NONE remain unchanged even if negative.
[out]addedOptional n_species tuple replaced with added concentration per row (not inventory).
Returns
Sum of concentration additions across rows, not a unit-homogeneous physical mass when row units differ. No ledger/clock/warning, finite repair or allocation; caller supplies nonaliasing output.

Review A2: set every negative RATE species in block (scope tank) to zero; writes the concentration added per species to added when it is non-null, returns the sum.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compileReactionExpression()

std::string openswmm::transport::compileReactionExpression ( const std::string & src,
const RxSymbols & symbols,
std::vector< RxToken > & pool,
RxExprSpan & out,
int & error_col )

Compile an infix scalar reaction expression into appended stack-machine tokens.

Compile src into the shared pool.

Parameters
[in]srcStable expression text; space/tab whitespace only. Supports unary signs, arithmetic, parentheses and fixed-arity functions; identifiers are case-sensitive except functions/hydraulic vars.
[in]symbolsBorrowed optional species/coefficient/term/pollutant name vectors, alive through call. Resolution priority follows that order then hydraulic names; max_term excludes later term rows.
[in,out]poolExisting compiled token pool; appended only after complete syntax/stack validation. Products/span indices must fit int32_t; no rollback guarantee for unexpected allocation exception.
[out]outInitially {original pool end,0}; on success appended token span. May hold planned span if final insertion throws. No ownership of pool transferred.
[out]error_col0 on success, otherwise1-based source column (some malformed/stack failures1).
Returns
Empty on success, descriptive parse/undefined symbol/arity/depth error on failure. Ordinary refusal leaves pool unchanged and out empty. Does not evaluate finite/domain behavior or reject all nonfinite numeric literals; caller later validates context and solve results.
Note
Allocates temporary token/operator vectors and strings. No configuration/clock mutation; exclusive pool append and stable symbol metadata required.
  • Argument error_col: [out] 1-based column of the offending token on failure.
    Returns
    empty on success, else the diagnostic ("undefined identifier 'x'", "expression too deep", "term 'T' references later term", …).
Here is the caller graph for this function:

◆ domainName()

const char * openswmm::transport::domainName ( Domain d)
noexcept

Format a transport matrix domain as a human-readable label.

Parameters
[in]dDomain enum; COUNT/invalid values are permitted for fallback.
Returns
Static nonowned null-terminated label or '?' for unknown. No allocation/mutation.
Here is the caller graph for this function:

◆ donorsFor()

Donors openswmm::transport::donorsFor ( lid::LIDType t,
bool has_soil )

Resolve immediate inflow donors/physical vertical adjacency for each LID layer.

Parameters
[in]tConventional LID type; unknown value uses surface external and other layers absent.
[in]has_soilFor permeable pavement, storage donor is soil when true, pavement otherwise.
Returns
Four selectors surface/pavement/soil/storage: layer ID, kExternal or kAbsent; no allocation, context mutation or runtime geometry validation.
Here is the caller graph for this function:

◆ drainMsxCouplingQueue()

void openswmm::transport::drainMsxCouplingQueue ( SimulationContext & ctx,
double dt )

Convert accepted queued coupling inventory into native external mass rate for this substep.

Parameters
[in,out]ctxReaction queue [node*species+m], external native rate array and held coupling_delivery_remaining seconds; remaining duration is read, not decremented here.
[in]dtPositive finite accepted routing subinterval s; empty/no species/nonpositive/NaN returns.
Note
Queue shape mismatch returns untouched. External shape mismatch resets destination0. When remaining>dt releases queued/remaining rate and subtracts rate*dt; otherwise drains all queued/dt. Signed inventory supported, no finite clamp. Native concentration*ft3 units, no litre conversion, physical water/clock/ledger mutation. Allocation can partially reset; exclusive exactly-once receipt consumption.

Review D1/F21: drain ReactionData::msx_coupling_queue (species mass handed to nodes by the 2D surface and the aquifer) into msx_ext_mass_in, by the coupling-volume queue's remaining-span rule. Call after msxsurf::deliver, before assembleLateralInflows.

Here is the call graph for this function:

◆ ensureMsxState()

void openswmm::transport::ensureMsxState ( SimulationContext & ctx)

Lazily size + seed the MSX element state; warn once about the R4b transport limitation when any RATE MSX species exists in either scope (LEGACY only — under LARD the species ride the segments as of L3).

Seed native node/link species state when node-shaped storage differs from current model.

Parameters
[in,out]ctxStable species/global/element initial rows and model counts; mismatch replaces node/link concentration vectors and applies covered element overrides after global seeds.
Note
Only node vector shape triggers reset; matching node shape with wrong link shape is not repaired. Requires covered parallel seed arrays. No configured/compiled/quality flag check, ledger, water or clock advance. Allocation may partially reset; exclusive initial lifecycle before routing.

L3: lazily size + seed the MSX element state (GLOBAL fill + [REACTION_QUALITY] overrides). Shared by the LEGACY dispatch and the LARD engine's init — one seeding spelling for both engines.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ evalReactionExpression()

double openswmm::transport::evalReactionExpression ( const std::vector< RxToken > & pool,
const RxExprSpan & span,
const RxEvalEnv & env )
noexcept

Evaluate a validated compiled reaction span with stack-local scratch.

Tier-1 evaluation: one pass, fixed-depth stack, allocation-free.

Parameters
[in]poolStable compiled token storage, span fully covered and validated by compiler.
[in]spanNonnegative begin/len, valid opcode/stack shape and max depth<=kRxMaxStackDepth; len<=0 returns0 without pool/environment access.
[in]envBorrowed species/coefficient/term/hydraulic/pollutant tuples covering every referenced index; each pointer may be null only when that category is not referenced. Units follow expression.
Returns
Scalar result; domain/division/overflow propagate NaN/inf, not an error status. STEP(0)=0, SGN(0)=0; no positivity clipping. Caller tests finite/admissible output.
Note
Allocation-free/noexcept, but malformed spans/indices/stack or null referenced input are unchecked invalid access. No model/clock mutation; stable pool/inputs allow independent concurrent evaluation.
Here is the caller graph for this function:

◆ formatReportBlock()

std::string openswmm::transport::formatReportBlock ( const Matrix & m)

Format a capability matrix as a readable fixed-column report and unavailable explanations.

Parameters
[in]mStable fully initialized4x4matrix; reason strings and counts already resolved.
Returns
Owned text ending newline, each enabled cell 'on(n)', disabled 'off:KEY', unavailable 'n/a'; then one explanation per unavailable nonempty cell. Enabled advisory reasons are not emitted here.
Note
Fixed256-byte formatting buffer can truncate long individual rows/reasons; no wrap/reflow or matrix repair. Allocates and may throw; no file I/O, warnings, model/physics/clock changes.

The .rpt block: a fixed-width table, one line per domain, one column per class, each cell "on(n)" / "off:KEY" / "n/a:reason". Ends with '
'.

Here is the call graph for this function:

◆ groundwaterEnables()

ClassEnables openswmm::transport::groundwaterEnables ( const SimulationContext & ctx)
noexcept

Resolve allocation-free canonical aquifer class eligibility for an active integrated kernel.

Parameters
[in]ctxStable twod_io aquifer state/options and complete native reaction/pollutant metadata.
Returns
Empty enables without active positive-cell aquifer. Otherwise pollutants and BULK-only compiled MSX obey !ignore_quality and GW opt-outs; age/temperature obey independent project flags and GW enables. Sets msx_bulk_only, retains WALL-presence diagnostic and counts zero wall flags.
Note
Uses GW options directly, independently of surface opt-outs. No owner creation, validation, reaction/physical advance or clock mutation; consistent metadata extents required.

T7.1: two-zone groundwater enables — the 2D surface rule plus the [GW_TRANSPORT_OPTIONS] TRANSPORT_* keys. Like the surface, age and temperature are not gated by IGNORE_QUALITY. Every row is 0 unless a [2D_AQUIFER] actually resolved: the sections are authorable on a deck with no kernel, and they transport nothing there.

Here is the caller graph for this function:

◆ heatAttrValueOk()

bool openswmm::transport::heatAttrValueOk ( HeatAttr attr,
double value )
noexcept

Validate a public numeric heat attribute value with parser-equivalent range policy.

Parameters
[in]attrSupported HeatAttr selector; unknown returnsfalse.
[in]valueFinite scalar in stored SI/degC/dimensionless attribute units.
Returns
True for known finite range-valid value; false otherwise. Does not install value, check scope/element compatibility or invalidate caches.
Note
Invalid-range diagnostic is built into a discarded vector; allocation can occur inside noexcept and terminate on failure. No model/clock mutation; do not assume allocation-free validation.

The parser's per-attribute value rule (fractions in [0,1], strictly positive lengths and material properties, non-negative diffusivity and velocity), shared so the C API and the deck refuse the same values.

Here is the caller graph for this function:

◆ initialAgeSecondsFor()

double openswmm::transport::initialAgeSecondsFor ( const SimulationContext & ctx,
bool is_link,
int idx,
double fallback )
inline

Per-element initial age (SECONDS) for one node/link, falling back to fallback (normally the INITIAL_STATE global) when no [INITIAL_QUALITY] row targets the element. Later rows win.

Parameters
[in]ctxStable resolved initial_quality parallel arrays, each covering count().
[in]is_linkTrue for a link seed, false for node.
[in]idxResolved zero-based element index to match; not dereferenced or bounds-checked here.
[in]fallbackAlready-internal default age s, retained when no matching row.
Returns
Last matching age row value*3600 (authored hours to s), otherwise fallback. Does not check hotstart/finite/sign itself; callers determine seed precedence. Read-only, allocation-free.
Here is the caller graph for this function:

◆ initialQualityHasMsxRow()

bool openswmm::transport::initialQualityHasMsxRow ( const SimulationContext & ctx,
bool is_link,
int elem_idx,
int species )

Test whether a resolved initial-quality table already owns an element/reaction species seed.

Parameters
[in]ctxStable resolved initial-quality parallel arrays covering count().
[in]is_linkTrue selects links, false nodes.
[in]elem_idxResolved zero-based element identity, compared without dereference.
[in]speciesValid nonnegative native reaction species index encoded as MSX initial-quality kind.
Returns
True for any matching element/kind, independent of seed value or current reaction enable.
Note
Read-only/no allocation; writer uses this to avoid duplicate emission. No seed/clock change.

True when ctx.initial_quality carries an MSX row for (is_link, elem, species) — the ReactionsWriter's "already written elsewhere" test.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ initialTempFor()

double openswmm::transport::initialTempFor ( const SimulationContext & ctx,
bool is_link,
int idx,
double fallback )
inline

Per-element initial temperature (degC) for one node/link, falling back to fallback (normally the INITIAL_STATE global).

Parameters
[in]ctxStable resolved initial_quality arrays covering count().
[in]is_linkTrue for link, false node.
[in]idxZero-based resolved element index used only for equality.
[in]fallbackDefault Celsius temperature.
Returns
Last matching temperature row in degC or fallback; no finite/sign/hotstart check.
Note
Read-only/no allocation/physical/clock change; caller applies at prepared seed phase.
Here is the caller graph for this function:

◆ initLidLayerAge()

void openswmm::transport::initLidLayerAge ( SimulationContext & ctx,
const lid::LIDSolver & solver )

Size shared conventional-LID scalar storage and seed retained-water layer ages.

Parameters
[in,out]ctxWATER_AGE option/config and shared layer species state. Ensures unit/row shapes, writes previous layer water depth ft and initial age seconds for layers holding>1e-12ft.
[in]solverFinal stable grouped LID geometry/order with covered layer arrays.
Note
Disabled/no units returns. Repeated call overwrites wet-layer age with initial value even if shape is unchanged, so use initial lifecycle only. Shared ensureSized can reset heat rows on shape change. No water/clock advance or mass ledger; allocations may partially reset, exclusive state.

Size the per-layer block against the model's LID units and seed the layers that already hold water at t = 0. Call after the LID manager has built its groups; repeating reseeds existing wet-layer ages.

Here is the call graph for this function:

◆ initLidLayerTemperature()

void openswmm::transport::initLidLayerTemperature ( SimulationContext & ctx,
const lid::LIDSolver & solver )

Size shared layer scalar state and seed all conventional-LID temperatures.

Parameters
[in,out]ctxEnabled thermal config/shared layer state; ensures shapes and writes initial degC plus previous water depths ft, including currently dry/absent layers.
[in]solverFinal stable grouped unit order and parallel geometry arrays.
Note
Disabled/no units returns; repeating overwrites evolved temperature. Shape changes may reset other shared scalar rows. No water/clock/global-ledger change; allocation can partially reset, exclusive initial lifecycle after group build required.

Size the shared layer block if needed and seed the TEMPERATURE row from HeatSource::INITIAL_STATE. Independent of initLidLayerAge: either may run first, neither wipes the other (LidLayerSpeciesState::ensureSized).

Here is the call graph for this function:

◆ layerVolumes()

void openswmm::transport::layerVolumes ( const lid::LIDGroupSoA & g,
std::size_t ui,
double(&) v[kNL] )

Void-weighted water held in each layer, as a depth per unit area (ft). The four terms are exactly those LIDSolver::storedVolume() sums, so a layer's age is weighted by the same water the mass balance counts.

Compute four void-weighted retained layer water depths per unit footprint area.

Parameters
[in]gPrepared parallel LID depth, porosity, thickness and moisture arrays.
[in]uiValid unit index covered by all accessed arrays, unchecked.
[out]vExactly kNL depths ft: surface, pavement, soil, storage. These are not total ft3; caller multiplies by footprint area if absolute water volume is required.
Note
Allocation-free, no finite/sign checks or geometry/clock mutation; output must not alias inputs.

Void-weighted water held in each layer, as a depth per unit area (ft). The four terms are exactly those LIDSolver::storedVolume() sums.

Here is the caller graph for this function:

◆ legacyReactionsActive()

bool openswmm::transport::legacyReactionsActive ( const SimulationContext & ctx)

Test configured and compiled native reaction readiness.

Parameters
[in]ctxStable reaction flags.
Returns
configured and compiled; no species-count/quality-option/shape validation or mutation.

True when the reactions component is active (configured + compiled) — the QualitySolver's branch condition.

Here is the caller graph for this function:

◆ lidLayerHeatCapacity()

double openswmm::transport::lidLayerHeatCapacity ( const SimulationContext & ctx,
const lid::LIDGroupSoA & g,
std::size_t unit,
int layer )
noexcept

Compute current areal thermal capacity of a conventional-LID layer.

Heat capacity of one layer, J/m²/K over the layer's footprint.

Parameters
[in]ctxStable conduction material and water density/specific heat SI configuration.
[in]gPrepared unit layer geometry/moisture arrays.
[in]unitValid zero-based unit covered by every accessed array.
[in]layerLayer selector0..kNL-1; invalid returns0.
Returns
J/(m2*K) using water/solid capacity and physical thickness; nonpositive thickness yields0. No footprint multiplication, finite validation, state change or allocation.

Exported so a gate can sum a column's heat content and assert conservation WITHOUT restating the water/matrix mixture — a second copy of it in the test would make the gate agree with itself rather than with the code. Zero for an absent layer.

Here is the call graph for this function:

◆ mirrorInitialQualityMsxRows()

std::vector< std::string > openswmm::transport::mirrorInitialQualityMsxRows ( SimulationContext & ctx)

Mirror resolved MSX initial seeds into the native reaction component's element seed table.

Parameters
[in,out]ctxPrepared configured reaction names/counts and resolved initial_quality rows; appends missing parallel init_elem kind/index/species/value entries, preserving existing values.
Returns
Owned list of differing-value conflicts for same element/species; empty on no conflicts or unconfigured reaction component. Equal existing values are accepted, no duplicate append.
Note
Skips invalid reaction kind/index and negative element indices; does not validate element upper bounds, finite concentration or array shapes. Uses exact double equality for conflict. May append other rows despite diagnostics. Allocation can leave partial parallel-array appends, so stage context data for transactional edits. No runtime native inventory/physics/clock mutation; exclusive post-parse/reparse phase required, caller preserves provenance for writer deduplication.

Mirror every MSX-kind [INITIAL_QUALITY] row into ctx.reactions.init_elem_* (upsert; a conflicting .rxn row is reported). Returns the diagnostics (empty on success).

Here is the call graph for this function:
Here is the caller graph for this function:

◆ network1DEnables()

ClassEnables openswmm::transport::network1DEnables ( const SimulationContext & ctx)
noexcept

Resolve allocation-free native network class counts from current project policy.

1D network enables: LEGACY / ARD / LARD all size from this.

Parameters
[in]ctxStable prepared pollutant/reaction counts and process flags.
Returns
Pollutants/MSX only when !ignore_quality, MSX requires configured+compiled; age and thermal flags also gated by !ignore_quality. Reports WALL presence even when quality disabled.
Note
Does not apply actual solver-specific fallback, validate native layout or create rows. Read-only/no allocation/physics/clock update; consistent reaction metadata required.
Here is the caller graph for this function:

◆ noteNegativeClamp()

void openswmm::transport::noteNegativeClamp ( SimulationContext & ctx,
const char * where )

Review A2: one warning per run when the reaction step had to clamp a negative concentration. The LEGACY binding also books the mass the clamp added (msx_ledger.clamped); the other engines report it here only.

Append one context-wide diagnostic after a negative RATE result is floored.

Parameters
[in,out]ctxReaction warning latch and warnings list; latch set before string append.
[in]whereNonnull null-terminated element category, read synchronously/copied into warning.
Note
Does not clamp inventories or book mass itself. Once-latched returns; allocation failure can leave latch set without warning. Exclusive context diagnostic access, no water/clock change.

Review A2: record (once per run) that a reaction step clamped a negative concentration to zero at where.

Here is the caller graph for this function:

◆ reactArdStage()

void openswmm::transport::reactArdStage ( SimulationContext & ctx,
double dt,
double * cell_phi,
const double * cell_a,
const double * cell_dx,
int n_cells,
double * node_mass,
const double * node_vol,
int n_nodes,
int n_pollut,
int ns_total,
double min_store_vol,
int temp_row,
const int * cell_conduit,
const int * conduit_link )

Decay pollutant rows and integrate native reaction rows in ARD cell/node stores.

The E4 reaction stage over one routing step.

Parameters
[in,out]ctxCompiled reaction metadata/coefficients and node HRT/geometry, pollutant decay and reacted ledger plus once-only native reaction diagnostics. No hydraulic or engine clock advance.
[in]dtPositive finite accepted stage duration s; nonpositive returns (NaN not explicitly rejected).
[in,out]cell_phiSpecies-major [row*n_cells+cell] concentrations, writable n_cells*ns_total.
[in]cell_aPer-cell water area ft2.
[in]cell_dxPer-cell length ft, product with area yields represented native volume.
[in]n_cellsNonnegative cell count.
[in,out]node_massNode-major [node*ns_total+row] concentration*ft3 inventories.
[in]node_volPer-node retained native ft3, n_nodes entries.
[in]n_nodesMatching native node count, nonnegative.
[in]n_pollutNumber of leading pollutant rows, matching ctx pollutant decay arrays.
[in]ns_totalTotal flattened row count; native n_species follow pollutant rows for this binding.
[in]min_store_volNative ft3 threshold below/equal which node native kinetics skip.
[in]temp_rowOptional valid thermal row, negative uses default reaction degC.
[in]cell_conduitOptional n_cells conduit indices, must be valid with conduit_link.
[in]conduit_linkOptional conduit->native-link IDs; both mapping pointers required for geometry/overrides.
Note
Exact pollutant decay occurs even when native reactions inactive, books signed concentration-volume loss and floors negatives. Native solve uses private scratch; failure preserves that cell/node's native tuple and warns, accepted RATE negatives floor0. No native reacted/clamped mass ledger booking here. Requires BULK-compatible ARD profile, valid compiled spans/extents and stable row layout; this routine itself does not reject WALL systems. Static scratch makes cross-model calls nonconcurrent. Allocation and diagnostics may leave earlier stages/elements changed; no global rollback.
  • Argument cell_phi: ARD cell state, species-major [s * n_cells + c]; rows 0..n_pollut-1 are pollutants, rows n_pollut.. are the MSX species in ReactionData order.
  • Argument cell_a: Cell areas (read-only; dry cells still react — their carried concentration evolves like LEGACY's, and holds negligible mass).
  • Argument cell_dx: Cell lengths (read-only; E5b — with cell_a they give the water volume each kdecay concentration change acts on, so the removed pollutant mass books into the qual_routing_reacted ledger row).
  • Argument node_mass: Node-store species MASS [nd * ns_total + s].
  • Argument node_vol: Node-store water volume [nd].
  • Argument n_pollut: Pollutant row count (may be 0 — MSX-only model).
  • Argument ns_total: Total species rows (n_pollut + rx.n_species() when the component is active, else n_pollut).
  • Argument min_store_vol: Below this volume a store has no meaningful concentration: MSX tank integration is skipped there (mass-form kdecay still applies).
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reactionAreaFactor()

double openswmm::transport::reactionAreaFactor ( ReactionAreaUnits units)
inline

Convert native square feet to configured reaction wall/dry-store area units.

Parameters
[in]unitsM2, CM2 or FT2/other selector.
Returns
.09290304 for m2/ft2,929.0304 for cm2/ft2, otherwise1. Pure/allocation-free.
Here is the caller graph for this function:

◆ reactionAreaVolume()

double openswmm::transport::reactionAreaVolume ( const SimulationContext & c,
bool link_element,
int e,
double volume )
inline

Compute active wetted reaction wall area per litre of water.

Parameters
[in]cStable prepared wall/geometry configuration.
[in]link_elementTrue link, false node identity.
[in]eValid element ID for geometry resolution.
[in]volumeNative water ft3; only>.0353147 triggers geometry lookup.
Returns
Declared area units/L using28.317L/ft3, else0. No state/clock change or physical validation.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reactionBoosterMass()

double openswmm::transport::reactionBoosterMass ( SimulationContext & ctx,
int node,
int species,
double mass,
double mixed_volume,
double arriving_volume )
inline

Compute and book the first matching node/species booster inventory addition.

Parameters
[in,out]ctxResolved reaction source patterns and current elapsed clock (read only); updates booster_mass and armed MSX inflow ledger, never physical concentration directly.
[in]nodeNative node ID matched against source rows.
[in]speciesValid native species row with covered ledger arrays.
[in]massExisting mixed native concentration*ft3 inventory.
[in]mixed_volumeTotal mixed water ft3; <=1e-12/NaN returns0.
[in]arriving_volumePositive arriving water ft3; <=1e-12/NaN returns0 even for setpoint.
Returns
FLOWPACED strength*arrival or SETPOINT max(strength*mixed-existing,0), concentration*ft3; 0 if no matching nonzero booster. Pattern/source strength is not finite/sign-clamped here.
Note
May resize/reset booster totals when shape differs. Books only first matching booster, no water/clock advance; caller adds returned inventory exactly once. Allocation can partially reset, exclusive context/ledger ownership required.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reactionContextDiagnostic()

std::string openswmm::transport::reactionContextDiagnostic ( const ReactionData & rx,
const std::vector< RxToken > & pool,
const RxExprSpan & span,
int context )

Recursively reject hydraulic/species/pollutant references unavailable in one reactor context.

context: 0=network, 1=shared term definition, 2=groundwater, 3=wet subcatchment.

Parameters
[in]rxStable compiled species wall flags, wall-geometry switch and acyclic forward term graph.
[in]poolToken storage covering supplied span; recursive term spans use rx.token_pool.
[in]spanCompiled expression span with fitting integer extent and valid species indices.
[in]context0 pipe,1 tank (ground variables permitted),2 groundwater,>=3 wet/LID contexts.
Returns
First descriptive refusal, or empty. Checks token extent and term index, AV wall-geometry requirement, context hydraulic mask, WALL species in GW/wet and pollutant access in wet/LID. Does not validate all opcode/species/hydvar indices or solve readiness; cyclic term graphs can recurse unbounded. No state mutation; diagnostic strings/recursion may allocate/throw.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reactionFunctionCount()

int openswmm::transport::reactionFunctionCount ( )

Read number of supported compiled scalar function entries.

Number of built-in functions.

Returns
Fixed function-table length, no mutation/allocation.
Here is the caller graph for this function:

◆ reactionFunctionInfo()

bool openswmm::transport::reactionFunctionInfo ( int idx,
const char ** name,
int * arity )

Read name and argument count of one supported expression function.

Name + arity of function idx; false when out of range.

Parameters
[in]idxZero-based table row; invalid returnsfalse without touching outputs.
[out]nameOptional pointer receiving static nonowned null-terminated function name.
[out]arityOptional pointer receiving required operand count.
Returns
True for valid row, including both outputs null. No allocation, ownership transfer or mutation.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reactionHydVarCount()

int openswmm::transport::reactionHydVarCount ( )

Read number of declared hydraulic/thermal/groundwater expression variables.

Number of built-in hydraulic variables.

Returns
RxHydVar::COUNT_ integer, independent of actual context population. Pure/allocation-free.
Here is the caller graph for this function:

◆ reactionHydVarInfo()

bool openswmm::transport::reactionHydVarInfo ( int idx,
const char ** name,
const char ** description )

Read canonical variable name and description including its declared units/support.

Name + one-line description of hydraulic variable idx.

Parameters
[in]idxZero-based RxHydVar row; invalid returnsfalse and preserves outputs.
[out]nameOptional pointer receiving static borrowed variable name.
[out]descriptionOptional pointer receiving static borrowed unit/population description.
Returns
True for valid variable, including both outputs null. No dynamic context eligibility check, allocation, ownership transfer or state mutation.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reactionHydVarPopulated()

bool openswmm::transport::reactionHydVarPopulated ( int idx)

Test the network-quality variable range currently populated by native routing.

Parameters
[in]idxInteger RxHydVar identity.
Returns
True for AV through TEMP inclusive (AV,HRT,DT,TEMP), false otherwise including GW variables; other context validators may allow additional scoped variables. Pure/allocation-free.

Physics review A1 (2026-10-15): whether any engine fills hydraulic variable idx. D, Q, U, RE, US and FF remain unavailable. AV requires WALL_GEOMETRY; HRT, DT and TEMP have their documented reactor contexts.

Here is the caller graph for this function:

◆ reactionSectionTags()

const std::vector< std::string > & openswmm::transport::reactionSectionTags ( )

Borrow the complete fixed set of supported embedded/external reaction section names.

Returns
Const static owning-vector reference, process lifetime; caller must not mutate/retain mutable aliases. First initialization allocates and may throw; subsequent access no model/clock change.

The recognised [REACTION_*] tags (upper-case, no brackets) — shared by the embedded-fallback handlers and the config parser.

Here is the caller graph for this function:

◆ reactionSourceFactor()

double openswmm::transport::reactionSourceFactor ( const ReactionData & r,
const ReactionData::Source & source,
double seconds )
inline

Read a periodic reaction-source pattern factor at an elapsed simulation time.

Parameters
[in]rStable source_patterns, positive finite pattern_timestep seconds and nonempty factor arrays.
[in]sourceResolved source; pattern<0 means unpatterned, otherwise valid pattern index.
[in]secondsFinite elapsed seconds; negatives floor0 before phase wrap.
Returns
Pattern multiplier, or1 without pattern. Uses tiny timestep-scaled epsilon at boundaries; periodic floor index wraps factor count. No shape/finite validation, source consumption, allocation or clock mutation; empty factors/nonpositive timestep violate preconditions.
Here is the caller graph for this function:

◆ reactionWallArea()

double openswmm::transport::reactionWallArea ( const SimulationContext & c,
bool link_element,
int e,
bool reference = false )
inline

Resolve explicit or hydraulic wetted reaction wall area for an element.

Parameters
[in]cStable wall override rows and prepared native conduit geometry/subtype tables.
[in]link_elementTrue identifies a link, false a node.
[in]eNative element ID; explicit matching override returned before generic validity check.
[in]referenceTrue uses full section depth, false accepted current link depth. Explicit area overrides use same fixed value for reference and active requests.
Returns
Declared AREA_UNITS area; first explicit row wins verbatim, otherwise conduit wetted perimeter*true/nominal length*max(barrels,1) converted from ft2. No implicit node geometry; returns0 for absent/nonconduit/invalid/nonpositive depth or radius. No finite/range repair, allocation or mutation.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reactionWallScales()

void openswmm::transport::reactionWallScales ( const SimulationContext & c,
bool link_element,
int e,
double volume,
std::vector< double > & scales )
inline

Build per-species active-to-reference wall coverage multipliers.

Parameters
[in]cStable configured species wall flags and prepared wall/geometry arrays.
[in]link_elementTrue selects link identity, false node.
[in]eValid native element ID.
[in]volumeWater ft3; <=one litre/NaN uses active area0.
[out]scalesResized/reset n_species to1 for BULK and clamp(active/reference,0,1) for WALL; reference<=0 gives WALL0. Owns no geometry pointers after return.
Note
Allocation can throw; no physical/clock mutation. Caller owns exclusive output and stable inputs.
Here is the call graph for this function:

◆ reactLegacyLinks()

void openswmm::transport::reactLegacyLinks ( SimulationContext & ctx,
double dt )

Run legacy-bound exact pollutant decay and native link kinetics once.

Parameters
[in,out]ctxConfigured/compiled reactions and matching prepared native species/pollutant, hydraulic, thermal/geometry and mass-ledger arrays; seeds species only if node-shaped state mismatches.
[in]dtPositive finite accepted routing duration s; inactive/nonpositive returns.
Note
Exact pollutant decay runs before native laws; nodes skip tiny nonstorage pools, native node reactions also skip separately reactive LID ownership. Failed native element solve retains species and warns, pollutant decay remains applied. No water/clock advance, cross-element rollback or concurrent static workspace access. Allocation/warning failures can leave partial context changes.

Link-side step: exact-exponential pollutant decay + MSX pipe-scope integration. Runs AFTER updateLinkQuality() (whose internal linear decay is zeroed when reactions are active), so the reacted concentrations are not overwritten by the mixing pass.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reactLegacyNodes()

void openswmm::transport::reactLegacyNodes ( SimulationContext & ctx,
double dt )

Run legacy-bound exact pollutant decay and native node kinetics once.

Parameters
[in,out]ctxConfigured/compiled reactions and matching prepared native species/pollutant, hydraulic, thermal/geometry and mass-ledger arrays; seeds species only if node-shaped state mismatches.
[in]dtPositive finite accepted routing duration s; inactive/nonpositive returns.
Note
Exact pollutant decay runs before native laws; nodes skip tiny nonstorage pools, native node reactions also skip separately reactive LID ownership. Failed native element solve retains species and warns, pollutant decay remains applied. No water/clock advance, cross-element rollback or concurrent static workspace access. Allocation/warning failures can leave partial context changes.

Node-side step: exact-exponential pollutant decay + MSX tank-scope integration. Runs where applyDecay() ran (before updateLinkQuality).

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reactSpeciesBlock()

void openswmm::transport::reactSpeciesBlock ( SimulationContext & ctx,
bool tank,
double dt,
double * species_block,
const double * pollut,
double hrt_seconds,
double temp_c,
int element )

React one LARD-owned tuple with held HRT/temperature and optional element geometry.

Parameters
[in,out]ctxStable compiled reaction data/coefficients and once-only diagnostic flags/list.
[in]tankTrue tank laws, false pipe laws.
[in]dtAccepted positive finite reaction duration s, forwarded to integrator.
[in,out]species_blockWritable n_species local tuple, retained unchanged on returned solve failure; accepted RATE negatives floor0. Must not alias private static workspace/pollutant input.
[in]pollutOptional stable np current concentrations required by referenced tokens.
[in]hrt_secondsHeld reactor HRT seconds.
[in]temp_cHeld degC; nonfinite selects reaction default.
[in]elementMatching native node/link ID or negative for no element geometry/override lookup; when wall geometry enabled nonnegative ID must be valid.
Note
Unlike reactElements, does not book MSX reacted/clamped inventory or apply wall coverage kinetic scaling. Copies through shared static scratch; failure warns once, no water/clock mutation. Allocation/diagnostic exceptions propagate and all bindings across contexts require serialization.

L3: integrate ONE species block in place over dt through the shared integrator. pollut may be null (no pollutant context); tank selects tank-scope expressions; hrt_seconds feeds RxHydVar::HRT and temp_c feeds RxHydVar::TEMP (NaN ⇒ the [REACTION_OPTIONS] TEMPERATURE constant). On an integrator failure the block is left unchanged and the once-per-run failure warning fires — the reactElements contract.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ recompileReactionSystem()

bool openswmm::transport::recompileReactionSystem ( SimulationContext & ctx,
std::vector< std::string > & errors )

Rebuild all compiled reaction expressions and validate scoped availability/profile constraints.

Parameters
[in,out]ctxInternally consistent species/coefficient/term/source form arrays and final native geometry/control/name tables; clears compiled flag/token pool and replaces spans before compilation.
[in,out]errorsAppends qualified source/column diagnostics; prior errors alone do not make this routine fail (success tests only newly appended count).
Returns
True and compiled=true when no new errors; false with partial rebuilt token pool/spans and compiled=false. Does not restore previous compiled state on refusal.
Note
Compiles terms in declaration order allowing earlier terms only; law contexts enforce readable hydraulic/pollutant/BULK references. Checks LID layer count, wall geometry+FULL coupling, required storage-node wall areas and RATE/NONE WALL forms. Trusts prepared parallel source/form extents; not a general geometry/index validator. Does not reseed inventories, refresh existing workspaces, book physical mass or advance clock. Token relocation invalidates prior spans/views/callers; exclusive configuration barrier required. Allocation/diagnostic errors propagate with partial metadata retained.

Recompile every reaction expression (terms, pipes, tanks) into a fresh flat token pool from the sources in ctx.reactions (E-C2: the one compile path, shared by the file apply and the CRUD API's eager validation — D-RC4, no second compiler). Returns true and sets rx.compiled on success; on failure appends diagnostics and leaves rx.compiled false (the pool/spans hold the partial result — callers roll back or clear).

Here is the call graph for this function:
Here is the caller graph for this function:

◆ registerArdComponent()

void openswmm::transport::registerArdComponent ( )

Register built-in ARD parser/serializer callbacks in process singleton.

Note
Installs org.hydrocouple.openswmm.transport.ard; duplicate policy is registry-owned. No context configuration, mesh/state seeding or clock mutation. Registration may allocate/throw; serialize startup before lookup.

Register org.hydrocouple.openswmm.transport.ard with the process-component registry (idempotent; called from SWMMEngine::open before resolution, next to registerReactionsComponent).

Here is the call graph for this function:

◆ registerHeatComponent()

void openswmm::transport::registerHeatComponent ( )

Register built-in heat configuration parser and serializer callbacks.

Note
Installs org.hydrocouple.openswmm.heat in singleton component registry; duplicate policy is registry-owned. No context configuration/thermal seeding or physical/clock advance. Registration allocates and may throw; caller serializes registry startup before lookup/application.

Register org.hydrocouple.openswmm.heat with the process-component registry (idempotent; called from SWMMEngine::open before resolution).

Here is the call graph for this function:

◆ registerReactionsComponent()

void openswmm::transport::registerReactionsComponent ( )

Register native reaction parser/serializer callbacks under the built-in component ID.

Note
Installs org.hydrocouple.openswmm.reactions in process singleton; duplicate policy is registry-owned. Does not instantiate a reaction system or advance clock. Registration may allocate/throw and must be serialized during startup before process component lookup/application.

Register org.hydrocouple.openswmm.reactions with the process-component registry (idempotent; called from SWMMEngine::open before resolution).

Here is the call graph for this function:

◆ registerWaterAgeComponent()

void openswmm::transport::registerWaterAgeComponent ( )

Register the built-in water-age configuration parser and serializer callbacks.

Note
Installs org.hydrocouple.openswmm.waterage in singleton registry; registry duplicate policy applies. No context configuration/state seeding or physical clock advance. Registration allocates and may throw; caller serializes registry startup before component lookup.

Register org.hydrocouple.openswmm.waterage with the process-component registry (idempotent; called from SWMMEngine::open before resolution).

Here is the call graph for this function:

◆ resolve()

Matrix openswmm::transport::resolve ( const SimulationContext & ctx,
const Draft * draft )

Build a domain-by-species transport capability matrix with explicit reasons and counts.

Parameters
[in]ctxStable complete model/process, native reaction/surface-loading, optional 2D mesh, aquifer and domain policy metadata. Read only, including warnings.
[in]draftOptional borrowed preview overrides for quality/age/heat/mesh/groundwater/2D ignore and four surface class flags; null resolves current configuration. No pointer retained.
Returns
Owned 4x4matrix (runoff/LID, groundwater, network, surface) by pollutant/MSX/age/temperature, with ENABLED counts, DISABLED_BY_USER key or UNAVAILABLE reason. Preview does not qualify actual solver physics or promise successful initialization.
Note
Integrated authored/active aquifer can carry groundwater native rows, legacy per-subcatch seam does not. Runoff MSX requires active surface loading and reports no surface reactions; surface WALL MSX unavailable, network WALL marks fallback advisory. Age/temperature ignore-quality gating differs between network/runoff and integrated surface/GW. Checks feature availability before domain opt-outs in defined branch order; no emitted warnings or model mutation. Allocations may throw; requires stable serial/const-consistent model views, no clock/physical advancement.
Here is the call graph for this function:

◆ resolveArdTransportRows()

void openswmm::transport::resolveArdTransportRows ( SimulationContext & ctx,
std::vector< std::string > & errors )

Resolve deferred MSX boundary/source rows to native element/species/time-series arrays.

Parameters
[in,out]ctxFinal native node/conduit names and reaction species/series registry; clears dense BC/source arrays, binds accepted unique element/species tuples and sets transport_rows_resolved true at normal return, even with appended errors.
[in,out]errorsAppends unknown element/species/series or duplicate errors; preserves prior entries.
Note
Unconfigured/no rows marks resolved and returns. Pollutant target refused; native species lookup does not itself reject WALL profile. Sources require conduits; constant source mass/s divided by kLitersPerFt3 into native concentration*ft3/s, signed extraction warns. Original raw row units retained for serialization. No mesh build/runtime state seeding/water/clock change; allocation can leave partial arrays and unresolved flag. Exclusive configuration barrier and later error check required.

E5a: resolve the raw [TRANSPORT_BOUNDARIES]/[TRANSPORT_SOURCES] rows to node/link/species/timeseries indices. Called from SWMMEngine::open AFTER all process components (and the embedded reactions fallback) have applied, because the rows name MSX species and the reactions component may apply before or after transport.ard in file order. Pushes fatal diagnostics into errors; pollutant species are refused (their loading surface is the legacy pathways). Source VALUE rates convert from species mass/s to internal conc·ft³/s here (kLitersPerFt3).

Here is the call graph for this function:

◆ routeLegacyAge()

void openswmm::transport::routeLegacyAge ( SimulationContext & ctx,
double dt )

Advance age seconds through legacy node/conduit mixing without altering pollutants.

Parameters
[in,out]ctxEnabled age config/state, completed old/new hydraulics and assembled qual_vol_in ft3 plus external age-volume rate (age seconds*ft3/s); writes node/link ages and clamp diagnostics.
[in]dtPositive finite accepted routing interval s; disabled/nonpositive returns.
Note
Shape mismatch resizes age state. First legacy call seeds global positive initial age and initial overrides; then adds dt to old node/link values, routes old-link loads and mixes with source numerators. Shared quality reactor/dry/conduit inflow thresholds apply; age has no evaporation concentration multiplier. Negative age-volume extraction floors available inventory and records clamp; STEADY conduit uses geometric node1 upstream age. No physical water/clock or pollutant ledger mutation. Static shared scratch makes calls across all contexts nonconcurrent. Allocations and warnings may leave partial seeding/ages; requires prepared finite arrays and exactly-once step.

One LEGACY age routing step (call at the END of QualitySolver::execute, after qual_vol_in is fully accumulated). No-op when WATER_AGE is off.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ routeLegacyHeat()

void openswmm::transport::routeLegacyHeat ( SimulationContext & ctx,
double dt )

Apply heat flux then legacy complete-mix transport of node/link temperatures.

Parameters
[in,out]ctxEnabled thermal config/state, completed old/new native hydraulics and assembled qual_vol_in ft3 plus external temperature-volume rate degC*ft3/s; writes node/link degC and heat/bed state.
[in]dtPositive finite accepted routing interval s; disabled/nonpositive returns.
Note
First call seeds all temperatures plus overrides; shape mismatch resizes thermal state. Applies atmospheric/bed heat before snapshotting old concentrations, then accumulates old-link heat rates and mixes nodes bounded by donor extrema. No pollutant-style evaporation multiplier or zero dry-node reset; dry conduit uses upstream temperature, STEADY uses geometric node1. No hydraulic water/clock/pollutant-ledger advance. Static scratch prohibits concurrent calls across models; allocation/dependency failures can leave partial seeding, heat flux and temperatures without rollback.

One LEGACY temperature routing step (call at the END of QualitySolver::execute, after qual_vol_in is fully accumulated). No-op when HEAT_TRANSPORT is off.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ routeLegacyMsx()

void openswmm::transport::routeLegacyMsx ( SimulationContext & ctx,
double dt )

Transport native BULK species through legacy node/link complete-mix routing and LID ports.

Parameters
[in,out]ctxPrepared old/current native hydraulics, matching reaction stores and assembled qual_vol_in ft3/external native concentration*ft3/s; updates native node/link concentrations, LID captures, source boosters and network inflow/seep/dry continuity ledger.
[in]dtPositive finite accepted routing interval s; nonpositive/no species returns.
Note
Ensures initial state/arms ledger, snapshots old species then routes absolute-flow downstream rates, subtracting separately captured native LID mass. Node mobile water/history, storage evaporation and exfiltration corrections, backflow/dry tests follow shared rules. WALL rows remain local and are neither advected nor booked; kinetics is a separate stage. Link STEADY uses geometric node1, others shared mixing inflow/dry tests; RATE extraction floors0 without an added-mass continuity entry here. Not guarded by configured/compiled/IGNORE_QUALITY flags; caller owns dispatch policy. No hydraulic water/engine clock advance. Static scratch prohibits concurrent models; allocation and booster/dependency exceptions can leave partial stores/ledgers. Exactly-once accepted phase required.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ routeLidLayerAge()

void openswmm::transport::routeLidLayerAge ( SimulationContext & ctx,
const lid::LIDSolver & solver,
double dt )

Advance and mix conventional-LID layer ages after accepted layer hydraulics.

Advance the per-layer ages one runoff step, after LIDSolver::execute.

Parameters
[in,out]ctxEnabled active shared layer scalar state with initialized old water depth ft, inflow age seconds, writable age/old-water/drain rows and matching group offsets.
[in]solverCompleted grouped layer inflows ft/s and current water depths/void fractions; exact initialized group/unit order, parallel arrays covered.
[in]dtPositive finite accepted runoff interval s; nonpositive/NaN returns.
Note
Uses explicit donors and OLD donor ages+dt, not newly mixed upstream age. Negative inflow floors0; absent/empty layers reset age0; other ages clipped nonnegative. Stores current water depth for next interval, drain age from storage except roof-disconnect uses surface. No water/clock or mass-ledger changes, allocation or shape refresh; exclusive exactly-once accepted hydraulic phase.
Here is the call graph for this function:

◆ routeLidLayerTemperature()

void openswmm::transport::routeLidLayerTemperature ( SimulationContext & ctx,
const lid::LIDSolver & solver,
double dt )

Mix accepted layer inflows then solve optional LID heat conduction/atmospheric exchange.

Parameters
[in,out]ctxEnabled active shared layer thermal state, initialized old water depths and inflow temperatures, material/weather/override configuration; writes layer/drain degC and old-water depths.
[in]solverCompleted layer inflow ft/s, new retained depths ft and configured thickness/porosity, exact matching initialized group/unit order and covered parallel arrays.
[in]dtPositive finite accepted runoff duration s; disabled/inactive/nonpositive/NaN returns.
Note
Uses old donor temperatures, positive inflow only. Dry solids retain heat when physical layer exists; other dry layers follow policy. Optional implicit SI conduction couples present thermal masses and linearized atmospheric flux acts on top mass. Nonfinite solve outputs retain mixed value; zero pivot fallback can be finite raw RHS. Drain uses storage except roof-disconnect surface. No hydraulic/clock/global-ledger mutation or shape refresh. Updates solar forcing and state progressively; dependency allocation/errors may leave earlier changes, exclusive exactly-once phase.

Advance every LID column one runoff step: advective mixing per layer, then one coupled thermal solve over the stack. Publishes the underdrain temperature, retiring HeatSource::RAINFALL's "(and LID drains until H5)" marker.

< holds or receives WATER → advection

< has THERMAL MASS → conduction, policy

Here is the call graph for this function:

◆ routeSubcatchmentAge()

void openswmm::transport::routeSubcatchmentAge ( SimulationContext & ctx,
const runoff::RunoffSoA & soa,
double dt )

Age/mix subarea water stores with snow-adjusted precipitation and assembled run-on.

Parameters
[in,out]ctxEnabled age config/state and prepared rainfall/snow/run-on receipts; writes subarea ages seconds, old water volumes ft3 and runoff age.
[in]soaCompleted runoff area ft2, area fractions and new subarea depths ft, matching source order.
[in]dtPositive finite accepted runoff interval s; disabled/nonpositive or no sources returns.
Note
Shape mismatch calls full age-state resize, potentially resetting unrelated node/link histories. Adds dt to stored age, mixes arriving rain/melt+run-on volume, clips age nonnegative. Publishes new-retained-volume-weighted subarea mean (not outgoing-flow-weighted); dry fallback configured rain age. Does not clear run-on numerator, book water/global mass or change clock. Parallel extents must cover area count; allocation may partially reset and NaN dt is not explicitly rejected.

One runoff-step update of the subarea ages and the published runoff age. Call immediately AFTER the runoff solver has stepped, so the depths are this step's. No-op when WATER_AGE is off.

Here is the call graph for this function:

◆ routeSubcatchmentTemperature()

void openswmm::transport::routeSubcatchmentTemperature ( SimulationContext & ctx,
const runoff::RunoffSoA & soa,
double dt )

Mix snow-adjusted precipitation/run-on and atmospheric heat into subarea thermal stores.

Advance ponded subarea temperatures one runoff step.

Parameters
[in,out]ctxEnabled thermal configuration and prepared rain/snow/run-on receipts/weather; updates subarea degC, old volume ft3, runoff degC and solar forcing.
[in]soaCompleted runoff geometry: native ft2 area, fractions and new depth ft, matching sources.
[in]dtPositive finite accepted runoff interval s; disabled/nonpositive/no sources returns.
Note
Missing watershed shape reseeds that thermal block. Run-on uses known temperature carrier ratio when available else rain temperature; accepted hydraulic run-on still sets mixed volume. Atmospheric exchange acts on old retained water in SI before inflow mixing; dry policy applies when old and arriving water negligible. Publishes retained-volume-weighted mean, dry fallback rain (not outgoing-flow-weighted). Does not clear run-on queues or advance water/clock. Allocation and forcing/dependencies can leave partial updates; exclusive state and complete parallel extents required.

Per subarea, in order: apply the surface energy balance to the water that was already there, mix in what arrived by GROSS inflow volume, then publish the subcatchment's runoff temperature as the volume-weighted mean of the subareas holding water. Outflow leaves at the subarea's own temperature, so only the inflow is needed — the same complete-mix argument A3 arrived at after its net-gain estimate proved to be a 6.3× defect.

  • Argument soa: The solver's own SoA. ctx.subcatches.ponded_depth is declared but written by nobody; reading it would give zeros.
  • Argument dt: Runoff timestep, seconds.
Here is the call graph for this function:

◆ serializeReactionSystem()

std::string openswmm::transport::serializeReactionSystem ( const SimulationContext & ctx)

Serialize configured native reaction metadata and scoped laws to INP section text.

Parameters
[in]ctxStable internally consistent reaction arrays/enums, species/coefficient/element/control names, initial-quality ownership and retained expression source strings.
Returns
Owning REACTION_OPTIONS/SPECIES plus nonempty coefficient/pattern/source/LID/wall/parameter/ report/term/pipe/tank/subcatch/buildup/subsurface/rain/initial sections; unconfigured zero-species empty.
Note
Emits stored declared units and elapsed timestep seconds, preserves source expressions and scoped row order. Element initial rows owned by INITIAL_QUALITY are omitted to avoid duplicates; invalid own seed IDs use wildcard, invalid species seeds skip. Most resolved indices/enums/parallel arrays are trusted, not generically checked. Fixed row helper can truncate long lines; names generally verbatim, subsurface TAG quoted. No compiled token regeneration, cache change, physical/clock advance or output-file IO; string allocation can throw. Caller provides stable exclusive configuration snapshot.

Canonical .rxn text for the current reaction system (empty system -> a header comment plus an empty [REACTION_SPECIES] shell is NOT emitted; the result is an empty string when nothing is configured).

Here is the call graph for this function:
Here is the caller graph for this function:

◆ serializeWaterAgeConfig()

std::string openswmm::transport::serializeWaterAgeConfig ( const SimulationContext & ctx)

Serialize configured constant water-age source rows to canonical component text.

Parameters
[in]ctxStable config, node names and covered parallel override arrays.
Returns
Owning WATER_AGE_SOURCES section in hours; unconfigured yields empty, zero globals omitted, invalid node IDs skipped, remaining node overrides preserve stored order. Unknown source uses?. No context mutation, state seeding or clock change; string allocation/formatting may throw.

Render [WATER_AGE_SOURCES] from the live config in FILE units (HOURS, shortest-exact) — the single spelling shared by the ComponentConfigSave hook and swmm_water_age_save (IO3c), the same sharing the reactions component has with serializeReactionSystem. Empty when the component never applied (save DECLINES → the carry-alongside copy runs).

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setLidInflowAge()

void openswmm::transport::setLidInflowAge ( SimulationContext & ctx,
int type_index,
int unit,
int subcatch,
double rain_rate,
double q_imperv,
double q_perv,
double q_runon,
double lid_area )

Set one unit's scalar inflow age from rainfall and captured/run-on surface water.

Parameters
[in,out]ctxEnabled active layer scalar store and current subcatchment runoff age/config.
[in]type_indexValid group index; absent offset pair returns.
[in]unitUnit within that group; flattened global bound checked, not group-specific extent.
[in]subcatchSource subcatch ID; missing/nonpositive runoff age uses rainfall age.
[in]rain_rateArriving rainfall depth ft/s, caller-qualified finite value.
[in]q_impervCaptured impervious runoff ft3/s.
[in]q_pervCaptured pervious runoff ft3/s.
[in]q_runonCaptured whole-subcatchment run-on ft3/s.
[in]lid_areaUnit footprint ft2, converts rain_rate to carrier flow.
Note
Stores seconds weighted by positive total flow, otherwise rainfall age; surface inputs share one subcatch age. No finite/sign repair, allocation, water/clock advance or receipt consumption; exclusive inflow assembly before routeLidLayerAge.

Flow-weighted age of the water arriving at each LID unit this step, stored into ctx.lid_layer_state.inflow_value. Called where LIDGroupSoA::inflow is assembled, because that is the only place the contributing rates (rain, captured impervious and pervious runoff, whole-subcatchment run-on) exist together.

◆ setLidInflowTemperature()

void openswmm::transport::setLidInflowTemperature ( SimulationContext & ctx,
int type_index,
int unit,
int subcatch,
double rain_rate,
double q_imperv,
double q_perv,
double q_runon,
double lid_area )

Set one LID unit's incoming degC from rainfall and captured/run-on surface water.

Parameters
[in,out]ctxEnabled active shared layer store and subcatchment thermal runoff/config values.
[in]type_indexValid group ID; absent offset pair returns.
[in]unitValid unit in group; only flattened global bounds checked.
[in]subcatchSource ID; missing runoff temperature uses rainfall default.
[in]rain_rateArriving precipitation depth ft/s.
[in]q_impervCaptured impervious runoff ft3/s.
[in]q_pervCaptured pervious runoff ft3/s.
[in]q_runonCaptured whole-subcatchment run-on ft3/s.
[in]lid_areaFootprint ft2 multiplying rain_rate.
Note
Positive total flow mixes rainfall and single source-surface degC; otherwise rain default. No sign/finite validation, receipt consumption, allocation or water/clock update; exclusive inflow assembly.

Temperature of the water arriving at one unit this step, flow-weighted over the same four rates setLidInflowAge weights. Mirrors it exactly, including its hard-won choice to take the SUBCATCHMENT's published runoff value rather than reconstructing a mean from the subarea rows.

◆ speciesClassName()

const char * openswmm::transport::speciesClassName ( SpeciesClass c)
noexcept

Format a transport species class as a human-readable label.

Parameters
[in]cClass enum; COUNT/invalid values use fallback.
Returns
Static nonowned Pollutants/MSX/Age/Temperature literal or '?'. No mutation/allocation.
Here is the caller graph for this function:

◆ surface2DEnables()

ClassEnables openswmm::transport::surface2DEnables ( const SimulationContext & ctx)
noexcept

Resolve allocation-free surface native class eligibility from project and 2D opt-outs.

Parameters
[in]ctxStable process/reaction/pollutant metadata and optional borrowed 2D options.
Returns
Pollutants/MSX gated by !ignore_quality and respective domain enable; MSX requires compiled reaction and no WALL species. Age/temperature use project process flags and domain opt-outs, independent of ignore_quality. Null options mean domain classes inherit on.
Note
Does not require a present/active mesh or initialize solver rows; read-only/no allocation. No warnings, kinetic execution or clock mutation; runtime owner performs profile qualification.

2D surface enables: the 1D rule plus the [2D_OPTIONS] TRANSPORT_* keys. Age and temperature are NOT gated by IGNORE_QUALITY here (pre-E2 rule: "IGNORE_QUALITY turns off the pollutant and MSX rows only").

◆ unpopulatedHydVarDiagnostic()

std::string openswmm::transport::unpopulatedHydVarDiagnostic ( const std::string & src,
const std::vector< RxToken > & pool,
const RxExprSpan & span,
int & error_col )

Report first compiled hydraulic variable not in the network-populated range.

Parameters
[in]srcOriginal expression used only to recover case-insensitive token-boundary column.
[in]poolStable valid compiled token pool.
[in]spanCovered compiled span with valid hydraulic indices; out-of-range token extent stops scan.
[out]error_col1-based first source spelling match for refused variable, otherwise-1; reset on entry.
Returns
Descriptive refusal for first direct unpopulated PUSH_HYDVAR, or empty. Does not recurse term references or distinguish groundwater/wet context; reactionContextDiagnostic handles scoped policy. String allocation may throw; no model/pool/clock mutation.

Diagnostic for the first unpopulated hydraulic variable the compiled expression span reads, or empty. error_col is its 1-based column in src (or -1). The evaluator still accepts every variable; this is the contract check that the system-level compile and the validator apply.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ warnIfFvDispersionKeyIgnored()

void openswmm::transport::warnIfFvDispersionKeyIgnored ( SimulationContext & ctx)

Warn when FV_DISPERSION is set while EULERIAN_ARD reads its own component coefficients.

Parameters
[in,out]ctxStable shared dispersion/quality options and writable warning list.
Note
Nonzero key plus ARD solver appends each call, no once-latch or IGNORE_QUALITY guard. Does not change dispersion/state/clock; diagnostic allocation can throw, exclusive setup warning phase.

Warn when [OPTIONS] FV_DISPERSION is set under QUALITY_SOLVER EULERIAN_ARD. The component's own bypass warnings only cover models that HAVE a transport.ard file; this is the reverse case — the user spelled dispersion the familiar way, selected the engine that now supports it, and got nothing. FV_DISPERSION reaches no solver today (WARN 105 says so under FLOW_ROUTING FV, and nothing says it under DYNWAVE), so E3's arrival is what makes the silence misleading rather than merely inert.

◆ warnIfLegacyBindingBypassed()

void openswmm::transport::warnIfLegacyBindingBypassed ( SimulationContext & ctx)

Warn when configured compiled reactions are bypassed by IGNORE_QUALITY.

Parameters
[in,out]ctxReaction readiness and option flags; appends explanatory warning each qualifying call.
Note
No once-only latch, state seeding or clock change. Warning string may allocate; exclusive setup diagnostics.

Warn (once, at open) when a reactions component is configured but no engine will run it this simulation. As of E4/R6 the only remaining bypass is IGNORE_QUALITY — EULERIAN_ARD now runs its own binding (ReactionArdBinding) with MSX species transported on the mesh. Without this a user who wrote a .rxn file gets a run in which nothing reacted and nothing said so.

Here is the call graph for this function:

Variable Documentation

◆ kAbsent

int openswmm::transport::kAbsent = -2
constexpr

◆ kExternal

int openswmm::transport::kExternal = -1
constexpr

-1 means "external to the unit"; -2 means "this type has no such layer".

◆ kMeltwaterTempC

double openswmm::transport::kMeltwaterTempC = 0.0
inlineconstexpr

The temperature meltwater leaves a pack at, °C. Zero, and named rather than written as a literal so a gate can assert against the constant the code uses instead of against a number a reader hopes it uses.

◆ kNL

int openswmm::transport::kNL = LidLayerSpeciesState::kLayerCount
constexpr

◆ kPave

int openswmm::transport::kPave = static_cast<int>(LidLayer::PAVEMENT)
constexpr

◆ kRxMaxStackDepth

int openswmm::kRxMaxStackDepth
inlineconstexpr

Maximum operand-stack depth; the compiler rejects deeper expressions so the evaluator's fixed stack can never overflow.

◆ kSoil

int openswmm::transport::kSoil = static_cast<int>(LidLayer::SOIL)
constexpr

◆ kStor

int openswmm::transport::kStor = static_cast<int>(LidLayer::STORAGE)
constexpr

◆ kSubIMPERV0

int openswmm::transport::kSubIMPERV0 = 0
constexpr

Subarea ordering shared by SubArea (A3) and HeatSubArea (H5a). Both enums are deliberately separate types; this is the ordinal they agree on.

◆ kSubIMPERV1

int openswmm::transport::kSubIMPERV1 = 1
constexpr

◆ kSubPERV

int openswmm::transport::kSubPERV = 2
constexpr

◆ kSurf

int openswmm::transport::kSurf = static_cast<int>(LidLayer::SURFACE)
constexpr

◆ LEGACY_ZERO [1/3]

double openswmm::quality::LEGACY_ZERO
constexpr

Legacy's effective-zero flow (ZERO in src/legacy/engine/consts.h). The mixing kernels test the inflow RATE against this, not against 0.0. Published here because the water-age, heat and MSX transport mirrors run the same kernels and must not drift from them.

◆ LEGACY_ZERO [2/3]

double openswmm::quality::LEGACY_ZERO
constexpr

Legacy's effective-zero flow (ZERO in src/legacy/engine/consts.h). The mixing kernels test the inflow RATE against this, not against 0.0. Published here because the water-age, heat and MSX transport mirrors run the same kernels and must not drift from them.

◆ LEGACY_ZERO [3/3]

double openswmm::quality::LEGACY_ZERO
constexpr

Legacy's effective-zero flow (ZERO in src/legacy/engine/consts.h). The mixing kernels test the inflow RATE against this, not against 0.0. Published here because the water-age, heat and MSX transport mirrors run the same kernels and must not drift from them.

◆ ZERO_DEPTH [1/3]

double openswmm::quality::ZERO_DEPTH
constexpr

The quality path's own thresholds — one litre and one millimetre, the numbers legacy qualrout.c routes on. This mirror previously carried a local 1e-10, so it dispatched differently from the family it mirrors.

◆ ZERO_DEPTH [2/3]

double openswmm::quality::ZERO_DEPTH
constexpr

The quality path's own thresholds — one litre and one millimetre, the numbers legacy qualrout.c routes on. This mirror previously carried a local 1e-10, so it dispatched differently from the family it mirrors.

◆ ZERO_DEPTH [3/3]

double openswmm::quality::ZERO_DEPTH
constexpr

The quality path's own thresholds — one litre and one millimetre, the numbers legacy qualrout.c routes on. This mirror previously carried a local 1e-10 under a comment claiming it matched the quality path; it did not, and the two families dispatched differently as a result.