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

Species mass in both aquifer zones, and where mass crossed a boundary. More...

#include <SubsurfaceTransportState.hpp>

Collaboration diagram for openswmm::twoD::SubsurfaceTransportState:

Public Member Functions

bool signedRow (int s) const noexcept
 A row whose mass may legitimately be negative — the temperature row (°C·m³ below zero is a state, not an error), so no clamp applies.
 
int rowIndex (std::string_view name) const noexcept
 Row index of a species by name, or −1 — the [GW_*] sections address species by name and resolve through this.
 
std::size_t layerIdx (int s, int j, int c) const noexcept
 < layerIdx
 
void refreshUnsat (int s, int c) noexcept
 Refresh one derived unsaturated bulk inventory from canonical layers.
 
double dissolvedFraction (int s, int c, double theta) const noexcept
 The share of a cell's stored mass that is DISSOLVED and therefore mobile: 1 / R with the retardation factor R = 1 + ρ_b·K_d/θ. Age and temperature never sorb — they are properties of the water, not solutes — so they are always fully mobile.
 
bool active () const noexcept
 Test whether the subsurface transport layout is nonempty.
 
std::size_t idx (int s, int c) const noexcept
 Map a species/cell pair into bulk species-major storage.
 
std::size_t lateralIndex (int species, std::size_t edge) const noexcept
 Index a lateral species packet in edge-major owned storage. Requires valid species/edge indices and coherent model-derived extents. No ordering, inventory, allocation or validation side effect.
 
void resize (int n_spec, int n_cell, int n_edges)
 Allocate/reset the core two-zone transport arrays and ledgers.
 
void clear ()
 Reset the complete subsurface transport state to empty defaults.
 
double inFlight1D (int s) const noexcept
 T7.4: mass in flight on the two 1D seams — booked by the producer, not yet taken by the owner. Part of storage, for the same reason the surface accumulators are.
 
double storage (int s) const noexcept
 Everything the aquifer HOLDS of one species, including mass in flight in a side accumulator (the water's liveStorage rule).
 
double ledgeredStorage (int s) const noexcept
 The storage the LEDGER can account for: holdings less the two surface accumulators, which are always one firing out of phase with gained_infil (booked when the cell gathers) and lost_dunne (booked when the cell pushes). The water side's ledgeredStorage makes the identical exclusion for the identical reason — the two pending terms cancel on both sides of the balance.
 
double continuityDenominator (int s) const noexcept
 T7.4 (2026-09-21): the scale a residual is judged against — what the aquifer started with plus every route mass can arrive by. It lives here, beside residual(), because the two must name the same channels: T7.4 added the node and link seams as routes and the .rpt block's own copy of this sum was not updated, so a deck fed only through its beds divided a machine-precision residual by a machine-precision denominator and printed 6 198 889.840 % beside an exact balance. One definition, one place to add a channel to.
 
double residual (int s) const noexcept
 T7.1's conservation statement, the twin of SurfaceTransportState::totalIncludingLedgers: what the aquifer holds now, plus everything that left, minus everything that arrived, equals what it started with. Zero to machine precision for a conserving kernel — GW plan gate 6's stub.
 

Public Attributes

double c_diff = 0.4
 explicit solute diffusion safety factor
 
int n_species = 0
 
int n_cells = 0
 
int n_pollut = 0
 
int n_msx = 0
 
int age_row = -1
 
int temp_row = -1
 
std::vector< std::string > row_names
 
std::vector< double > sat_mass
 [s*n_cells+c] in the saturated water
 
std::vector< double > unsat_mass
 [s*n_cells+c] in the column store
 
int n_layers = 0
 
std::vector< double > layer_mass
 [(s*n_cells+c)*n_layers+j]
 
std::vector< double > contact_water
 [j*n_cells+c], SI m3
 
std::vector< double > contact_node_out
 
std::vector< double > contact_link_out
 gross promised water, per bed/cell
 
std::vector< double > contact_node_mass
 
std::vector< double > contact_link_mass
 
std::vector< double > alpha_L
 [GW_TRANSPORT_PARAMS] per cell, after * < TAG < CELL resolution.
 
std::vector< double > alpha_T
 transverse dispersivity (m)
 
std::vector< double > D_m
 molecular diffusivity (m²/s)
 
std::vector< double > rho_b
 
std::vector< double > kd
 
std::vector< double > decay
 
bool dispersion_on = true
 Whether dispersion runs at all ([GW_TRANSPORT_OPTIONS] DISPERSION).
 
long dispersion_limiter_binds = 0
 
std::vector< double > sacc_L
 
std::vector< double > sacc_R
 
std::vector< double > xacc_from_surface
 
std::vector< double > xacc_to_surface
 
std::vector< double > nacc_mass
 
std::vector< double > lacc_mass
 
std::vector< double > lout_mass
 
std::vector< double > link_gain_shortfall
 
std::vector< double > node_out_mass
 
std::vector< double > lost_deep
 deep percolation
 
std::vector< double > lost_node
 to a 1D node through its bed
 
std::vector< double > lost_link
 to a gaining conduit (G-X4)
 
std::vector< double > lost_dunne
 saturation excess + rejection, to the surface
 
std::vector< double > lost_et
 the intensive rows ET carried off
 
std::vector< double > gained_infil
 from the surface's infiltration
 
std::vector< double > gained_node
 from a recharging node (T7.4 seam)
 
std::vector< double > gained_link
 from a leaking conduit (T7.4 seam)
 
std::vector< double > net_lateral
 net across the domain edge (0 on a closed mesh)
 
std::vector< double > gained_source
 
std::vector< double > lost_source
 wells, native concentration x m3
 
std::vector< double > boundary_in
 
std::vector< double > boundary_out
 
std::vector< double > boundary_flux_in
 
std::vector< double > boundary_flux_out
 gross split of net_lateral
 
std::vector< double > lost_reaction
 T7.2: first-order decay.
 
std::vector< double > generated_age
 
std::vector< double > gained_contact
 
std::vector< double > init_mass
 
std::vector< double > internal_recharge
 

Detailed Description

Species mass in both aquifer zones, and where mass crossed a boundary.

Member Function Documentation

◆ active()

bool openswmm::twoD::SubsurfaceTransportState::active ( ) const
inlinenoexcept

Test whether the subsurface transport layout is nonempty.

Returns
True when n_species and n_cells are positive; does not verify vector extents or owner activation. Read-only, allocation-free.

◆ clear()

void openswmm::twoD::SubsurfaceTransportState::clear ( )
inline

Reset the complete subsurface transport state to empty defaults.

Postcondition
Releases all bulk/layered inventories, accumulators, parameters, names and ledgers; invalidates borrowed storage. Requires exclusive state access.

◆ continuityDenominator()

double openswmm::twoD::SubsurfaceTransportState::continuityDenominator ( int s) const
inlinenoexcept

T7.4 (2026-09-21): the scale a residual is judged against — what the aquifer started with plus every route mass can arrive by. It lives here, beside residual(), because the two must name the same channels: T7.4 added the node and link seams as routes and the .rpt block's own copy of this sum was not updated, so a deck fed only through its beds divided a machine-precision residual by a machine-precision denominator and printed 6 198 889.840 % beside an exact balance. One definition, one place to add a channel to.

Parameters
[in]sValid zero-based species row with coherently sized mandatory and enabled optional arrays.
Returns
Nonnegative absolute initial/inflow scale in native concentration*m3; includes net-lateral magnitude and optional generated-age/contact receipts.
Precondition
LAYERED callers have refreshed derived unsat_mass; nacc_mass extent is species-major, and generated_age/gained_contact are enabled/sized together.
Note
Read-only accepted-state snapshot; no bounds/finite checks, allocation or mutation. Serialize with producer/gather/ledger updates so pending inventories are sampled consistently.

◆ dissolvedFraction()

double openswmm::twoD::SubsurfaceTransportState::dissolvedFraction ( int s,
int c,
double theta ) const
inlinenoexcept

The share of a cell's stored mass that is DISSOLVED and therefore mobile: 1 / R with the retardation factor R = 1 + ρ_b·K_d/θ. Age and temperature never sorb — they are properties of the water, not solutes — so they are always fully mobile.

Parameters
[in]sValid zero-based species row, unchecked.
[in]cValid zero-based cell with rho_b and kd storage when sorption is active.
[in]thetaFinite volumetric water content, dimensionless.
Returns
Dissolved share 1/R in (0,1] for valid physical data; one for age/temperature, absent kd, nonpositive theta/kd, or R <= 1.
Note
rho_b uses kg/m3 and kd m3/kg. This does not multiply/move stored inventory; stable read-only arrays are required. No allocation or bounds validation.
Here is the call graph for this function:

◆ idx()

std::size_t openswmm::twoD::SubsurfaceTransportState::idx ( int s,
int c ) const
inlinenoexcept

Map a species/cell pair into bulk species-major storage.

Parameters
[in]sValid nonnegative species row in [0,n_species).
[in]cValid nonnegative cell in [0,n_cells).
Returns
size_t offset s*n_cells+c; bounds and arithmetic overflow are unchecked. No allocation/mutation.
Here is the caller graph for this function:

◆ inFlight1D()

double openswmm::twoD::SubsurfaceTransportState::inFlight1D ( int s) const
inlinenoexcept

T7.4: mass in flight on the two 1D seams — booked by the producer, not yet taken by the owner. Part of storage, for the same reason the surface accumulators are.

Parameters
[in]sValid zero-based species row with coherently sized mandatory and enabled optional arrays.
Returns
Pending node/conduit arrival and layer-contact inventory in native concentration*m3; excludes node-out already delivered to the network.
Precondition
LAYERED callers have refreshed derived unsat_mass; nacc_mass extent is species-major, and generated_age/gained_contact are enabled/sized together.
Note
Read-only accepted-state snapshot; no bounds/finite checks, allocation or mutation. Serialize with producer/gather/ledger updates so pending inventories are sampled consistently.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ lateralIndex()

std::size_t openswmm::twoD::SubsurfaceTransportState::lateralIndex ( int species,
std::size_t edge ) const
inlinenoexcept

Index a lateral species packet in edge-major owned storage. Requires valid species/edge indices and coherent model-derived extents. No ordering, inventory, allocation or validation side effect.

Here is the caller graph for this function:

◆ layerIdx()

std::size_t openswmm::twoD::SubsurfaceTransportState::layerIdx ( int s,
int j,
int c ) const
inlinenoexcept

< layerIdx

Map a species/layer/cell triple into owned species/cell/layer storage. Layer mass and its paired node/link contact masses share this index.

Parameters
[in]sValid zero-based species row.
[in]jValid zero-based unsaturated layer in [0,n_layers), surface first.
[in]cValid zero-based cell in [0,n_cells).
Returns
size_t offset (s*n_cells+c)*n_layers+j; no bounds/overflow checks, allocation or mutation.
Here is the caller graph for this function:

◆ ledgeredStorage()

double openswmm::twoD::SubsurfaceTransportState::ledgeredStorage ( int s) const
inlinenoexcept

The storage the LEDGER can account for: holdings less the two surface accumulators, which are always one firing out of phase with gained_infil (booked when the cell gathers) and lost_dunne (booked when the cell pushes). The water side's ledgeredStorage makes the identical exclusion for the identical reason — the two pending terms cancel on both sides of the balance.

Parameters
[in]sValid zero-based species row with coherently sized mandatory and enabled optional arrays.
Returns
Bulk inventories plus lateral and 1D/contact pending receipts, excluding both surface cross-cadence accumulators, native concentration*m3.
Precondition
LAYERED callers have refreshed derived unsat_mass; nacc_mass extent is species-major, and generated_age/gained_contact are enabled/sized together.
Note
Read-only accepted-state snapshot; no bounds/finite checks, allocation or mutation. Serialize with producer/gather/ledger updates so pending inventories are sampled consistently.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ refreshUnsat()

void openswmm::twoD::SubsurfaceTransportState::refreshUnsat ( int s,
int c )
inlinenoexcept

Refresh one derived unsaturated bulk inventory from canonical layers.

Parameters
[in]sValid zero-based species row.
[in]cValid zero-based cell index.
Postcondition
Writes unsat_mass[idx(s,c)] as the sum over all layer_mass entries; zero when n_layers == 0. Units are native concentration*m3, age s*m3, temperature degrees C*m3.
Precondition
Corresponding arrays are coherently sized; this operation belongs to LAYERED ownership and must not replace an independently owned BULK inventory. Exclusive state access, no allocation or ledger changes.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ residual()

double openswmm::twoD::SubsurfaceTransportState::residual ( int s) const
inlinenoexcept

T7.1's conservation statement, the twin of SurfaceTransportState::totalIncludingLedgers: what the aquifer holds now, plus everything that left, minus everything that arrived, equals what it started with. Zero to machine precision for a conserving kernel — GW plan gate 6's stub.

Parameters
[in]sValid zero-based species row with coherently sized mandatory and enabled optional arrays.
Returns
Signed ledgered storage + cumulative outputs - cumulative inputs - initial inventory, native concentration*m3; age s*m3 and temperature degrees C*m3.
Precondition
LAYERED callers have refreshed derived unsat_mass; nacc_mass extent is species-major, and generated_age/gained_contact are enabled/sized together.
Note
Read-only accepted-state snapshot; no bounds/finite checks, allocation or mutation. Serialize with producer/gather/ledger updates so pending inventories are sampled consistently.
Here is the call graph for this function:

◆ resize()

void openswmm::twoD::SubsurfaceTransportState::resize ( int n_spec,
int n_cell,
int n_edges )
inline

Allocate/reset the core two-zone transport arrays and ledgers.

Parameters
[in]n_specRequested species count; nonpositive clamps to zero.
[in]n_cellRequested cell count; nonpositive clamps to zero.
[in]n_edgesRequested lateral-face count; nonpositive clamps to zero.
Postcondition
Zeroes bulk inventories, face/surface/conduit accumulators and cumulative ledgers; resets parameter defaults. Solver separately sizes node-bed/node outputs and layered/contact stores and refines row layout.
Note
Existing n_layers, row names/layout fields and those separately owned arrays are not reset here. Allocations may throw after partial resizing, invalidating references. Requires exclusive state access; no rollback or unit conversion.

◆ rowIndex()

int openswmm::twoD::SubsurfaceTransportState::rowIndex ( std::string_view name) const
inlinenoexcept

Row index of a species by name, or −1 — the [GW_*] sections address species by name and resolve through this.

Parameters
[in]nameBorrowed nonowning exact species name view, not retained.
Returns
First case-sensitive row index or -1 for no match. Read-only linear search; no allocation.
Here is the caller graph for this function:

◆ signedRow()

bool openswmm::twoD::SubsurfaceTransportState::signedRow ( int s) const
inlinenoexcept

A row whose mass may legitimately be negative — the temperature row (°C·m³ below zero is a state, not an error), so no clamp applies.

Parameters
[in]sValid zero-based species index; caller excludes the -1 unset sentinel.
Returns
True exactly when s == temp_row. Read-only and unchecked; no allocation.

◆ storage()

double openswmm::twoD::SubsurfaceTransportState::storage ( int s) const
inlinenoexcept

Everything the aquifer HOLDS of one species, including mass in flight in a side accumulator (the water's liveStorage rule).

Parameters
[in]sValid zero-based species row with coherently sized mandatory and enabled optional arrays.
Returns
Live bulk inventories plus pending surface, lateral and 1D/contact receipts, native concentration*m3.
Precondition
LAYERED callers have refreshed derived unsat_mass; nacc_mass extent is species-major, and generated_age/gained_contact are enabled/sized together.
Note
Read-only accepted-state snapshot; no bounds/finite checks, allocation or mutation. Serialize with producer/gather/ledger updates so pending inventories are sampled consistently.
Here is the call graph for this function:

Member Data Documentation

◆ age_row

int openswmm::twoD::SubsurfaceTransportState::age_row = -1

◆ alpha_L

std::vector<double> openswmm::twoD::SubsurfaceTransportState::alpha_L

[GW_TRANSPORT_PARAMS] per cell, after * < TAG < CELL resolution.

longitudinal dispersivity (m)

◆ alpha_T

std::vector<double> openswmm::twoD::SubsurfaceTransportState::alpha_T

transverse dispersivity (m)

◆ boundary_flux_in

std::vector<double> openswmm::twoD::SubsurfaceTransportState::boundary_flux_in

◆ boundary_flux_out

std::vector<double> openswmm::twoD::SubsurfaceTransportState::boundary_flux_out

gross split of net_lateral

◆ boundary_in

std::vector<double> openswmm::twoD::SubsurfaceTransportState::boundary_in

◆ boundary_out

std::vector<double> openswmm::twoD::SubsurfaceTransportState::boundary_out

◆ c_diff

double openswmm::twoD::SubsurfaceTransportState::c_diff = 0.4

explicit solute diffusion safety factor

◆ contact_link_mass

std::vector<double> openswmm::twoD::SubsurfaceTransportState::contact_link_mass

◆ contact_link_out

std::vector<double> openswmm::twoD::SubsurfaceTransportState::contact_link_out

gross promised water, per bed/cell

◆ contact_node_mass

std::vector<double> openswmm::twoD::SubsurfaceTransportState::contact_node_mass

◆ contact_node_out

std::vector<double> openswmm::twoD::SubsurfaceTransportState::contact_node_out

◆ contact_water

std::vector<double> openswmm::twoD::SubsurfaceTransportState::contact_water

[j*n_cells+c], SI m3

◆ D_m

std::vector<double> openswmm::twoD::SubsurfaceTransportState::D_m

molecular diffusivity (m²/s)

◆ decay

std::vector<double> openswmm::twoD::SubsurfaceTransportState::decay

◆ dispersion_limiter_binds

long openswmm::twoD::SubsurfaceTransportState::dispersion_limiter_binds = 0

T7.2 telemetry: faces whose dispersive exchange hit the limiter. A bind is not an error — it is the face telling the modeller the dispersion is under-resolved at this Δt, which is the surface's rule too (dispersion_limiter_binds).

◆ dispersion_on

bool openswmm::twoD::SubsurfaceTransportState::dispersion_on = true

Whether dispersion runs at all ([GW_TRANSPORT_OPTIONS] DISPERSION).

◆ gained_contact

std::vector<double> openswmm::twoD::SubsurfaceTransportState::gained_contact

explicit finite-porewater model only; empty in compatibility mode

◆ gained_infil

std::vector<double> openswmm::twoD::SubsurfaceTransportState::gained_infil

from the surface's infiltration

◆ gained_link

std::vector<double> openswmm::twoD::SubsurfaceTransportState::gained_link

from a leaking conduit (T7.4 seam)

◆ gained_node

std::vector<double> openswmm::twoD::SubsurfaceTransportState::gained_node

from a recharging node (T7.4 seam)

◆ gained_source

std::vector<double> openswmm::twoD::SubsurfaceTransportState::gained_source

◆ generated_age

std::vector<double> openswmm::twoD::SubsurfaceTransportState::generated_age

◆ init_mass

std::vector<double> openswmm::twoD::SubsurfaceTransportState::init_mass

Mass in both stores at the start of the run — the conservation gate's reference (the aquifer is seeded from [GW_INITIAL_QUALITY]).

◆ internal_recharge

std::vector<double> openswmm::twoD::SubsurfaceTransportState::internal_recharge

Internal, informational: the unsaturated ⇄ saturated handover. Not in the balance — both ends are inside the same cell.

◆ kd

std::vector<double> openswmm::twoD::SubsurfaceTransportState::kd

[GW_SORPTION] per cell and species, [s*n_cells+c]: the linear partition coefficient (m³/kg — the row is L/kg and converts once) and the first-order decay constant (1/s).

◆ lacc_mass

std::vector<double> openswmm::twoD::SubsurfaceTransportState::lacc_mass

[s * n_cells + c] mass a LEAKING conduit delivered, at the conduit's own concentration — the twin of the water's lacc.

◆ layer_mass

std::vector<double> openswmm::twoD::SubsurfaceTransportState::layer_mass

[(s*n_cells+c)*n_layers+j]

◆ link_gain_shortfall

std::vector<double> openswmm::twoD::SubsurfaceTransportState::link_gain_shortfall

[s] informational: gain mass the 1D received that the cell could not supply at its firing (its store had already been drawn below it).

◆ lost_deep

std::vector<double> openswmm::twoD::SubsurfaceTransportState::lost_deep

deep percolation

◆ lost_dunne

std::vector<double> openswmm::twoD::SubsurfaceTransportState::lost_dunne

saturation excess + rejection, to the surface

◆ lost_et

std::vector<double> openswmm::twoD::SubsurfaceTransportState::lost_et

the intensive rows ET carried off

◆ lost_link

std::vector<double> openswmm::twoD::SubsurfaceTransportState::lost_link

to a gaining conduit (G-X4)

◆ lost_node

std::vector<double> openswmm::twoD::SubsurfaceTransportState::lost_node

to a 1D node through its bed

◆ lost_reaction

std::vector<double> openswmm::twoD::SubsurfaceTransportState::lost_reaction

T7.2: first-order decay.

◆ lost_source

std::vector<double> openswmm::twoD::SubsurfaceTransportState::lost_source

wells, native concentration x m3

◆ lout_mass

std::vector<double> openswmm::twoD::SubsurfaceTransportState::lout_mass

[s * n_cells + c] mass a GAINING conduit already delivered to its end nodes (review, 2026-10-15), debited from the saturated store when the cell fires — the twin of the water's negative lacc. Booked into lost_link at that debit, so the aquifer ledger is unchanged in form.

◆ n_cells

int openswmm::twoD::SubsurfaceTransportState::n_cells = 0

◆ n_layers

int openswmm::twoD::SubsurfaceTransportState::n_layers = 0

◆ n_msx

int openswmm::twoD::SubsurfaceTransportState::n_msx = 0

◆ n_pollut

int openswmm::twoD::SubsurfaceTransportState::n_pollut = 0

◆ n_species

int openswmm::twoD::SubsurfaceTransportState::n_species = 0

◆ nacc_mass

std::vector<double> openswmm::twoD::SubsurfaceTransportState::nacc_mass

[s * n_beds + b] mass a RECHARGING node pushed down its bed, sampled at the node's own concentration at tier-0 cadence and gathered by the cell when it fires — the twin of the water's nacc.

◆ net_lateral

std::vector<double> openswmm::twoD::SubsurfaceTransportState::net_lateral

net across the domain edge (0 on a closed mesh)

◆ node_out_mass

std::vector<double> openswmm::twoD::SubsurfaceTransportState::node_out_mass

[s * n_nodes] mass the aquifer owes each 1D node, booked at the cell's firing and flushed by the router into the node's coupling queues. Reset per routing batch, exactly as node_exchange_vol_ is.

◆ rho_b

std::vector<double> openswmm::twoD::SubsurfaceTransportState::rho_b

bulk density ρ_s(1 − θ_s) (kg/m³)

◆ row_names

std::vector<std::string> openswmm::twoD::SubsurfaceTransportState::row_names

◆ sacc_L

std::vector<double> openswmm::twoD::SubsurfaceTransportState::sacc_L

Lateral Darcy face sides, [e*n_species + s] — the twin of eacc_L/eacc_R, gathered by the owning cell at ITS firing (GW plan §3.1).

◆ sacc_R

std::vector<double> openswmm::twoD::SubsurfaceTransportState::sacc_R

◆ sat_mass

std::vector<double> openswmm::twoD::SubsurfaceTransportState::sat_mass

[s*n_cells+c] in the saturated water

◆ temp_row

int openswmm::twoD::SubsurfaceTransportState::temp_row = -1

◆ unsat_mass

std::vector<double> openswmm::twoD::SubsurfaceTransportState::unsat_mass

[s*n_cells+c] in the column store

◆ xacc_from_surface

std::vector<double> openswmm::twoD::SubsurfaceTransportState::xacc_from_surface

[s*n_cells+c] mass the SURFACE handed down with its infiltration, gathered when the GW cell fires — the twin of xacc_from_surface.

◆ xacc_to_surface

std::vector<double> openswmm::twoD::SubsurfaceTransportState::xacc_to_surface

…and the mass owed back to the surface with saturation excess and column rejection — the twin of xacc_to_surface, drained by the surface cell.


The documentation for this struct was generated from the following file: