![]() |
OpenSWMM Engine
6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
|
Structure-of-Arrays storage for all nodes. More...
#include <NodeData.hpp>
Public Member Functions | |
| int | count () const noexcept |
| Number of nodes. | |
| void | resize (int n) |
Resize all arrays to hold exactly n nodes. | |
| void | grow_to (int n) |
Grow all arrays to hold at least n nodes, preserving existing data. | |
| void | reserve_to (int n) |
Reserve capacity for n nodes without changing count(). | |
| void | erase_at (int idx) |
Erase the node at index idx from every parallel array. | |
| void | resize_loads (int n_pollutants) |
| Resize pollutant load arrays after pollutant count is known. | |
| void | resize_quality (int n_pollutants) |
| Resize per-node quality arrays after pollutant count is known. | |
| void | shrink_to_fit () |
| Release excess vector capacity accumulated during parsing. | |
| void | save_state () noexcept |
| Snapshot current state into old-step arrays before solving. | |
| void | reset_state () noexcept |
| Reset state variables, applying init_depth from input. | |
| void | clearInflowSources () noexcept |
| Zero routing-phase inflow source arrays. | |
Public Attributes | |
| std::vector< NodeType > | type |
| Node type for each node. | |
| std::vector< double > | invert_elev |
| Invert elevation (project length units). | |
| std::vector< double > | full_depth |
| Full depth of the node (project length units). | |
| std::vector< double > | init_depth |
| Initial water depth (project length units). | |
| std::vector< double > | sur_depth |
| Maximum depth allowed at the node (ponding or surcharge limit). | |
| std::vector< double > | ponded_area |
| Ponding area at the surface (sq project length units). | |
| std::vector< uint8_t > | is_virtual |
| Virtual-junction flag (0 = regular node, 1 = virtual junction). | |
| std::vector< uint8_t > | is_inlet |
| Inlet-junction flag (0 = plain node, 1 = inlet junction). | |
| std::vector< double > | rim_depth |
| Rendering-only rim (ground) depth above the invert, project length units. 0 = unset. | |
| std::vector< double > | depth |
| Current water depth above invert (project length units). | |
| std::vector< double > | head |
| Current water surface head (project length units = invert + depth). | |
| std::vector< double > | volume |
| Current water volume (project volume units). | |
| std::vector< double > | lat_flow |
| Current lateral inflow (project flow units). | |
| std::vector< double > | user_lat_flow |
| User-forced lateral inflow set via the API (project flow units). | |
| std::vector< double > | runoff_inflow |
| Interpolated surface runoff from subcatchments (project flow units). | |
| std::vector< double > | gw_inflow |
| Interpolated groundwater flow from subcatchments (project flow units). | |
| std::vector< double > | ext_inflow |
| External (timeseries/baseline) inflows (project flow units). | |
| std::vector< double > | dwf_inflow |
| Dry weather flow inflows (project flow units). | |
| std::vector< double > | rdii_inflow |
| RDII unit hydrograph inflows (project flow units). | |
| std::vector< double > | iface_inflow |
| Interface file (upstream model coupling) inflows (project flow units). | |
| std::vector< double > | coupling_inflow |
| 2D ↔ 1D coupling exchange flow at the node (project flow units). | |
| std::vector< double > | coupling_volume |
| Pending 1D↔2D exchange VOLUME for the next routing step (1D units, ft³). | |
| std::vector< double > | coupling_queue |
| Delivery queue for the 1D↔2D junction exchange (1D units, ft³). | |
| std::vector< double > | coupling_qual_queue |
| S3 — species MASS queue for the 2D→1D junction drain, per (node, pollutant), 1D mass units (conc × ft³). | |
| std::vector< double > | coupling_qual_inflow |
| S3 — this step's delivered 2D→1D species mass RATE per (node, pollutant) (mass/sec); read by QualitySolver::addCouplingLoads(). | |
| std::vector< double > | coupling_age_vol_queue |
S4 — the tuple's age-volume and temperature-volume halves, per node (age·ft³ / °C·ft³ queued; age·ft³/s / °C·ft³/s delivered). Same queue/drain rule as coupling_qual_queue; consumed by addCouplingLoads into node_age_vol_in / node_temp_vol_in when the 2D surface carries the row (coupling_tuple_age / coupling_tuple_temp), which replaces the EXTERNAL_INFLOW stand-in S3 used. Sized with the node count (cheap); untouched on decks without a 2D surface. | |
| std::vector< double > | coupling_temp_vol_queue |
| std::vector< double > | coupling_age_vol_inflow |
| std::vector< double > | coupling_temp_vol_inflow |
| bool | coupling_tuple_age = false |
| set by SurfaceRouter2D at initialize | |
| bool | coupling_tuple_temp = false |
| std::vector< double > | qual_mass_in |
| Accumulated quality mass inflow rate per (node, pollutant). | |
| std::vector< double > | qual_vol_in |
| Accumulated volume inflow rate per node (ft3/sec). | |
| std::vector< double > | iface_qual_mass |
| Routing interface file quality mass rate per (node, pollutant) (mass/sec). | |
| std::vector< double > | ext_qual_mass |
| Direct external inflow quality mass rate per (node, pollutant) (mass/sec). | |
| std::vector< double > | dwf_qual_mass |
| Per-node DWF pollutant mass-rate ADJUSTMENT (mass/sec), net of the global default: row mass (q·pattern-adjusted value) minus q·Pollut.dwfConcen when the global default is set. Adding it on top of the global-default DWF load reproduces legacy addDryWeatherInflows' add-row-then-subtract-default exactly. Flat 2D: [node * n_pollutants + pollutant]. | |
| std::vector< double > | lid_drain_qual_load |
| LID drain quality mass rate per (node, pollutant) (mass/sec). | |
| std::vector< double > | lid_drain_qual_vol |
| LID drain volume inflow rate per node (ft3/sec). | |
| std::vector< double > | lid_drain_inflow |
LID drain WATER inflow rate per node (ft3/sec) — the routing twin of lid_drain_qual_vol. | |
| std::vector< double > | conc |
| Current quality concentration at each node. | |
| std::vector< double > | conc_old |
| Previous-step quality at each node. | |
| std::vector< double > | hrt |
| Hydraulic residence time for storage nodes (seconds). | |
| std::vector< double > | user_conc_mass_flux |
| User-forced quality mass flux at each node (mass/sec). | |
| int | conc_n_pollutants = 0 |
| Number of pollutants in the quality arrays. | |
| std::vector< double > | inflow |
| Current total inflow to the node (project flow units). | |
| std::vector< double > | outflow |
| Current total outflow from the node (project flow units). | |
| std::vector< double > | overflow |
| Current overflow / ponded flow (project flow units). | |
| std::vector< double > | losses |
| Node losses (evaporation + seepage) (project flow units). | |
| std::vector< double > | crown_elev |
| Crown elevation — top of highest connecting conduit (project length units). | |
| std::vector< int > | degree |
| Node degree — number of connecting links (+ve downstream, -ve upstream terminal). | |
| std::vector< double > | old_net_inflow |
| Net inflow from previous timestep (inflow - outflow) for averaging. | |
| std::vector< double > | full_volume |
| Full volume at node (project volume units). | |
| std::vector< double > | old_depth |
| Depth at the previous timestep. | |
| std::vector< double > | old_volume |
| Volume at the previous timestep. | |
| std::vector< double > | old_lat_flow |
| Lateral flow at the previous timestep. | |
| std::vector< double > | old_inflow |
| Total inflow at the previous timestep (for output interpolation). | |
| std::vector< std::string > | comments |
| Object comment from the INP file (lines with a single ';' prefix immediately above this object's data row). | |
| std::vector< std::string > | tags |
Per-object tag from the INP [TAGS] section. | |
| std::vector< char > | rpt_flag |
| Whether this node is included in report/output (0=no, 1=yes). | |
| std::vector< double > | stat_vol_flooded |
| Total volume of water lost as overflow (project volume units). | |
| std::vector< double > | stat_time_flooded |
| Total duration the node was flooded (seconds). | |
| std::vector< double > | stat_max_depth |
| Maximum reported depth (project length units). | |
| std::vector< double > | stat_max_overflow |
| Maximum reported overflow rate (project flow units). | |
| std::vector< double > | stat_max_overflow_date |
| Date/time when maximum overflow occurred (OADate (days since 12/30/1899)). | |
| std::vector< double > | stat_sum_depth |
| std::vector< double > | stat_sum_volume |
| std::vector< double > | stat_max_depth_date |
| std::vector< double > | stat_max_rpt_depth |
| std::vector< double > | stat_max_inflow_date |
| std::vector< double > | stat_time_surcharged |
| std::vector< double > | stat_max_surcharge_height |
| std::vector< double > | stat_outfall_avg_flow |
| Outfall cumulative average flow (flow units × reporting periods). | |
| std::vector< double > | stat_max_lat_inflow |
| std::vector< double > | stat_max_total_inflow |
| std::vector< double > | stat_storage_max_outflow |
| std::vector< double > | stat_lat_inflow_vol |
| std::vector< double > | stat_total_inflow_vol |
| Cumulative total inflow volume at each node (ft3). | |
| std::vector< double > | stat_total_outflow_vol |
| std::vector< double > | stat_outfall_max_flow |
| Outfall maximum flow (project flow units). | |
| std::vector< long > | stat_outfall_periods |
| Outfall number of non-zero flow periods. | |
| std::vector< int > | stat_non_converged_count |
| Count of non-converging steps per node. | |
| std::vector< double > | stat_time_courant_critical |
| CFL time-step critical count per node. | |
| std::vector< double > | stat_total_load |
| Cumulative pollutant loads at each node. | |
| int | stat_n_pollutants = 0 |
Structure-of-Arrays storage for all nodes.
All parallel arrays are indexed by node index [0, count). Use SimulationContext::node_names to translate name → index.
Fields are divided into:
|
inlinenoexcept |
Zero routing-phase inflow source arrays.
Called at the start of each routing step before processes write to their respective source arrays.
NOTE: runoff_inflow and gw_inflow are zeroed in stepRunoff() Phase 2 before subcatchment accumulation (matching legacy initSystemInflows which zeros newLatFlow each routing step).
|
inlinenoexcept |
Number of nodes.
|
inline |
Erase the node at index idx from every parallel array.
Removes the element at idx from every SoA vector. For flat-2D quality arrays indexed as [node * n_pollutants + p], the full stride for idx is removed. Spatial arrays are NOT touched here; ObjectDeleter erases spatial data separately after calling this. Only call in BUILDING or OPENED state.
|
inline |
Grow all arrays to hold at least n nodes, preserving existing data.
Called by ensure_node_capacity() during incremental INP parsing. Uses vector::resize() (not assign) so existing elements are preserved. New elements get the same defaults as resize().
|
inline |
Reserve capacity for n nodes without changing count().
Parsing grows these arrays one row at a time via grow_to(), so each of the ~60 parallel vectors reallocates and copies O(log n) times over a section — the dominant memory traffic in handler dispatch on a large model.
This reserves capacity only. It deliberately does NOT resize: count() is the vector size, and PostParseResolver compares it against the final name count and calls resize() when they differ — a call with destructive assign semantics. Growing the SIZE speculatively here would trip that path and wipe parsed data. Capacity is invisible to all of it.
Over-reserving is harmless, so callers pass the section's row count as an upper bound.
|
inlinenoexcept |
Reset state variables, applying init_depth from input.
Matches legacy node_initState() which sets oldDepth = initDepth and computes initial volume from depth. Flows and inflows are zeroed for a cold start.
|
inline |
Resize all arrays to hold exactly n nodes.
Called once during input parsing after the total node count is known. All numeric arrays are zero-initialized; type arrays use JUNCTION as the default.
|
inline |
Resize pollutant load arrays after pollutant count is known.
|
inline |
Resize per-node quality arrays after pollutant count is known.
|
inlinenoexcept |
Snapshot current state into old-step arrays before solving.
|
inline |
Release excess vector capacity accumulated during parsing.
Called once after final sizing is complete. Each vector's capacity is reduced to match its size, freeing memory that was over-allocated by geometric growth during incremental parsing.
| std::vector<std::string> openswmm::NodeData::comments |
Object comment from the INP file (lines with a single ';' prefix immediately above this object's data row).
Multiple comment lines are joined by the literal two-character token "\\n" (backslash + n). Empty string means no comment. Written back to INP by InpWriter as one ';'-prefixed row per part. Also stored verbatim in the GeoPackage 'comment' column.
| std::vector<double> openswmm::NodeData::conc |
Current quality concentration at each node.
Size = n_nodes * n_pollutants.
| int openswmm::NodeData::conc_n_pollutants = 0 |
Number of pollutants in the quality arrays.
| std::vector<double> openswmm::NodeData::conc_old |
Previous-step quality at each node.
| std::vector<double> openswmm::NodeData::coupling_age_vol_inflow |
| std::vector<double> openswmm::NodeData::coupling_age_vol_queue |
S4 — the tuple's age-volume and temperature-volume halves, per node (age·ft³ / °C·ft³ queued; age·ft³/s / °C·ft³/s delivered). Same queue/drain rule as coupling_qual_queue; consumed by addCouplingLoads into node_age_vol_in / node_temp_vol_in when the 2D surface carries the row (coupling_tuple_age / coupling_tuple_temp), which replaces the EXTERNAL_INFLOW stand-in S3 used. Sized with the node count (cheap); untouched on decks without a 2D surface.
| std::vector<double> openswmm::NodeData::coupling_inflow |
2D ↔ 1D coupling exchange flow at the node (project flow units).
Signed: positive = 2D → 1D (surface drainage into the node), negative = 1D → 2D (surcharge spill onto the surface). Written by SurfaceRouter2D::advancePostRouting at the end of step N; read by assembleLateralInflows at the start of step N+1 (so the value persists across the step boundary and is consumed exactly once by the DW solver).
For mass-balance accounting the signed value is split:
This replaces the earlier scheme of routing coupling Q through forcing.node_lat_inflow_value, which conflated user forcing with 2D coupling and dropped the negative (1D→2D) volume from the mass balance entirely.
| std::vector<double> openswmm::NodeData::coupling_qual_inflow |
S3 — this step's delivered 2D→1D species mass RATE per (node, pollutant) (mass/sec); read by QualitySolver::addCouplingLoads().
| std::vector<double> openswmm::NodeData::coupling_qual_queue |
S3 — species MASS queue for the 2D→1D junction drain, per (node, pollutant), 1D mass units (conc × ft³).
Filled by SurfaceRouter2D from the marcher's per-point exch_mass (2D→1D drains only, at the CELL's concentration); drained by assembleLateralInflows with the SAME rule as coupling_queue (uniform rate over the remaining delivery span, flushed when remaining ≤ dt) so mass and water arrive in the same proportions. Flat 2D [node * n_pollutants + pollutant]. Never negative: a 1D→2D spill removes mass from the node IMPLICITLY through the reduced mixing volume (the CSTR takes every outflow at the mixed concentration), so no debit is queued for it. In-memory only.
| std::vector<double> openswmm::NodeData::coupling_queue |
Delivery queue for the 1D↔2D junction exchange (1D units, ft³).
SurfaceRouter2D::fireAdvanceWindow moves each fired window's coupling_volume here after the 2D mass-balance ledger books it; assembleLateralInflows drains the queue at the uniform rate queue / SimulationContext::coupling_delivery_remaining, so a multi-step advance window's exchange volume arrives spread over the following routing steps instead of as a single-step pulse (window/routing-step × the physical rate — which flooded small junctions instantly and drove a per-window drain/spill churn). Degenerates exactly to the legacy one-step delivery when the 2D advance fires every routing step (delivery window ≤ routing step). Signed like coupling_volume: + = 2D→1D drain, − = 1D→2D spill. In-memory only (not serialized to hotstart).
| std::vector<double> openswmm::NodeData::coupling_temp_vol_inflow |
| std::vector<double> openswmm::NodeData::coupling_temp_vol_queue |
| bool openswmm::NodeData::coupling_tuple_age = false |
set by SurfaceRouter2D at initialize
| bool openswmm::NodeData::coupling_tuple_temp = false |
| std::vector<double> openswmm::NodeData::coupling_volume |
Pending 1D↔2D exchange VOLUME for the next routing step (1D units, ft³).
The exchange is carried across the staggered-coupling step boundary as a volume (not a rate) so it stays mass-conservative under VARIABLE_STEP: the producer (computeCouplingExchange / the live-RHS booking) writes Q·dt here at the end of step N; the consumer (assembleLateralInflows) re-derives the rate coupling_inflow = coupling_volume/dt at the start of step N+1 and clears this, so the 1D node receives exactly the volume 2D exchanged regardless of how the timestep changes. Signed: + = 2D→1D drain, − = 1D→2D spill. In-memory only (not serialized to hotstart). See plan / review §11.
| std::vector<double> openswmm::NodeData::crown_elev |
Crown elevation — top of highest connecting conduit (project length units).
| std::vector<int> openswmm::NodeData::degree |
| std::vector<double> openswmm::NodeData::depth |
Current water depth above invert (project length units).
| std::vector<double> openswmm::NodeData::dwf_inflow |
Dry weather flow inflows (project flow units).
| std::vector<double> openswmm::NodeData::dwf_qual_mass |
Per-node DWF pollutant mass-rate ADJUSTMENT (mass/sec), net of the global default: row mass (q·pattern-adjusted value) minus q·Pollut.dwfConcen when the global default is set. Adding it on top of the global-default DWF load reproduces legacy addDryWeatherInflows' add-row-then-subtract-default exactly. Flat 2D: [node * n_pollutants + pollutant].
| std::vector<double> openswmm::NodeData::ext_inflow |
External (timeseries/baseline) inflows (project flow units).
| std::vector<double> openswmm::NodeData::ext_qual_mass |
Direct external inflow quality mass rate per (node, pollutant) (mass/sec).
Written by inflow::InflowSolver::evaluate() each routing step from the [INFLOWS] CONCEN/MASS rows (cleared in clearInflowSources()); read by QualitySolver::addExtInflowLoads() → added to qual_mass_in. Flat 2D: [node * n_pollutants + pollutant]. CONCEN rows are already multiplied by the node's external flow inflow, so this is a mass rate for either row type.
| std::vector<double> openswmm::NodeData::full_depth |
Full depth of the node (project length units).
| std::vector<double> openswmm::NodeData::full_volume |
Full volume at node (project volume units).
| std::vector<double> openswmm::NodeData::gw_inflow |
Interpolated groundwater flow from subcatchments (project flow units).
| std::vector<double> openswmm::NodeData::head |
Current water surface head (project length units = invert + depth).
| std::vector<double> openswmm::NodeData::hrt |
Hydraulic residence time for storage nodes (seconds).
| std::vector<double> openswmm::NodeData::iface_inflow |
Interface file (upstream model coupling) inflows (project flow units).
| std::vector<double> openswmm::NodeData::iface_qual_mass |
Routing interface file quality mass rate per (node, pollutant) (mass/sec).
Written by iface::InterfaceManager::readInflows() each routing step (cleared in clearInflowSources()); read by QualitySolver::addIfaceLoads() → added to qual_mass_in. Flat 2D: [node * n_pollutants + pollutant].
| std::vector<double> openswmm::NodeData::inflow |
| std::vector<double> openswmm::NodeData::init_depth |
Initial water depth (project length units).
| std::vector<double> openswmm::NodeData::invert_elev |
Invert elevation (project length units).
| std::vector<uint8_t> openswmm::NodeData::is_inlet |
Inlet-junction flag (0 = plain node, 1 = inlet junction).
An inlet junction is a virtual junction (is_virtual is always set alongside this flag) that additionally carries a street inlet: it sits between two STREET conduits and diverts captured gutter flow to a separate capture node through the usage row InletUsageStore::find_by_node_host(idx) (INP section [INLET_JUNCTIONS]). Refactored engine only.
| std::vector<uint8_t> openswmm::NodeData::is_virtual |
Virtual-junction flag (0 = regular node, 1 = virtual junction).
A virtual junction is a zero-storage, momentum-transmitting JUNCTION connecting exactly two conduits of identical cross section (INP section [VIRTUAL_JUNCTIONS]). The NodeType stays JUNCTION so the binary .out type-code space is unchanged. Refactored engine only — the legacy engine has no support.
| std::vector<double> openswmm::NodeData::lat_flow |
Current lateral inflow (project flow units).
| std::vector<double> openswmm::NodeData::lid_drain_inflow |
LID drain WATER inflow rate per node (ft3/sec) — the routing twin of lid_drain_qual_vol.
Set once per runoff step by the LID block in stepRunoff() and read by assembleLateralInflows() every routing step until the next runoff step overwrites it. It is NOT ext_inflow: that array is cleared by clearInflowSources() at the top of every routing step, i.e. AFTER stepRunoff has added to it, so a drain booked there never reached the network (LID fix round, 2026-08-30 — every drain-to-node case, not only the target-less one). Legacy books it as Node.newLatFlow + EXTERNAL_INFLOW.
| std::vector<double> openswmm::NodeData::lid_drain_qual_load |
LID drain quality mass rate per (node, pollutant) (mass/sec).
Set once per runoff step (cleared at runoff step start); read each routing step by addWetWeatherLoads() → added to qual_mass_in. Flat 2D: [node * n_pollutants + pollutant]. Covers drain-to-node and drain-to-subcatch (routed to outlet node). Matches legacy lid_addDrainInflow() / lid_addDrainRunon() quality.
| std::vector<double> openswmm::NodeData::lid_drain_qual_vol |
LID drain volume inflow rate per node (ft3/sec).
Set once per runoff step; read each routing step by addWetWeatherLoads() → added to qual_vol_in (denominator for mixing).
| std::vector<double> openswmm::NodeData::losses |
| std::vector<double> openswmm::NodeData::old_depth |
Depth at the previous timestep.
| std::vector<double> openswmm::NodeData::old_inflow |
Total inflow at the previous timestep (for output interpolation).
| std::vector<double> openswmm::NodeData::old_lat_flow |
Lateral flow at the previous timestep.
| std::vector<double> openswmm::NodeData::old_net_inflow |
Net inflow from previous timestep (inflow - outflow) for averaging.
| std::vector<double> openswmm::NodeData::old_volume |
Volume at the previous timestep.
| std::vector<double> openswmm::NodeData::outflow |
| std::vector<double> openswmm::NodeData::overflow |
| std::vector<double> openswmm::NodeData::ponded_area |
Ponding area at the surface (sq project length units).
| std::vector<double> openswmm::NodeData::qual_mass_in |
Accumulated quality mass inflow rate per (node, pollutant).
Flat 2D: [node * n_pollutants + pollutant]. Units: mass/sec.
| std::vector<double> openswmm::NodeData::qual_vol_in |
Accumulated volume inflow rate per node (ft3/sec).
| std::vector<double> openswmm::NodeData::rdii_inflow |
RDII unit hydrograph inflows (project flow units).
| std::vector<double> openswmm::NodeData::rim_depth |
Rendering-only rim (ground) depth above the invert, project length units. 0 = unset.
Optional third token of a [VIRTUAL_JUNCTIONS] row. A virtual junction's full_depth is derived — it is always the shared pipe crown — which makes every ground/terrain line a viewer draws collapse to the crown at the break point. This field carries the surface elevation for those drawings and nothing else: it is written by the input and edit paths and read only by renderers. No hydraulics, routing, reporting or output-file code may read it, so a model produces bit-identical results whether or not it is supplied.
| std::vector<char> openswmm::NodeData::rpt_flag |
Whether this node is included in report/output (0=no, 1=yes).
| std::vector<double> openswmm::NodeData::runoff_inflow |
Interpolated surface runoff from subcatchments (project flow units).
| std::vector<double> openswmm::NodeData::stat_lat_inflow_vol |
Cumulative lateral inflow volume at each node (ft3).
| std::vector<double> openswmm::NodeData::stat_max_depth |
Maximum reported depth (project length units).
| std::vector<double> openswmm::NodeData::stat_max_depth_date |
Date/time when maximum depth occurred (OADate (days since 12/30/1899)).
| std::vector<double> openswmm::NodeData::stat_max_inflow_date |
Date/time when maximum total inflow occurred (OADate (days since 12/30/1899)).
| std::vector<double> openswmm::NodeData::stat_max_lat_inflow |
Maximum lateral inflow at each node (project flow units).
| std::vector<double> openswmm::NodeData::stat_max_overflow |
Maximum reported overflow rate (project flow units).
| std::vector<double> openswmm::NodeData::stat_max_overflow_date |
Date/time when maximum overflow occurred (OADate (days since 12/30/1899)).
| std::vector<double> openswmm::NodeData::stat_max_rpt_depth |
Maximum reported depth (used for output-step max tracking).
| std::vector<double> openswmm::NodeData::stat_max_surcharge_height |
| std::vector<double> openswmm::NodeData::stat_max_total_inflow |
Maximum total inflow at each node (project flow units).
| int openswmm::NodeData::stat_n_pollutants = 0 |
| std::vector<int> openswmm::NodeData::stat_non_converged_count |
Count of non-converging steps per node.
Incremented when a routing step fails to converge and the node itself did not converge (matching legacy NodeStats[i].nonConvergedCount).
| std::vector<double> openswmm::NodeData::stat_outfall_avg_flow |
Outfall cumulative average flow (flow units × reporting periods).
| std::vector<double> openswmm::NodeData::stat_outfall_max_flow |
Outfall maximum flow (project flow units).
| std::vector<long> openswmm::NodeData::stat_outfall_periods |
Outfall number of non-zero flow periods.
| std::vector<double> openswmm::NodeData::stat_storage_max_outflow |
Peak outflow released by a storage unit (project flow units). Storage only; stays zero elsewhere. Tracked separately from inflow because a pond's whole purpose is that the two differ.
| std::vector<double> openswmm::NodeData::stat_sum_depth |
Cumulative depth for computing average (project length units × seconds).
| std::vector<double> openswmm::NodeData::stat_sum_volume |
Cumulative stored volume for computing average (internal ft³), storage nodes only. Accumulated per routing step alongside stat_sum_depth so the Storage Volume Summary's average is the true time-average of the node's nonlinear volume, not volume-of-the-average-depth (which understates a convex curve).
| std::vector<double> openswmm::NodeData::stat_time_courant_critical |
CFL time-step critical count per node.
Incremented when the node's depth-change rate produces the smallest CFL-limited timestep (matching legacy NodeStats[i].timeCourantCritical).
| std::vector<double> openswmm::NodeData::stat_time_flooded |
Total duration the node was flooded (seconds).
| std::vector<double> openswmm::NodeData::stat_time_surcharged |
Total time node was surcharged (seconds).
| std::vector<double> openswmm::NodeData::stat_total_inflow_vol |
Cumulative total inflow volume at each node (ft3).
| std::vector<double> openswmm::NodeData::stat_total_load |
Cumulative pollutant loads at each node.
Flat 2D: [node * n_pollutants + p]. Only meaningful for outfall nodes. Resized by resize_loads() after pollutant count is known.
| std::vector<double> openswmm::NodeData::stat_total_outflow_vol |
Cumulative total outflow volume at each node (ft3).
| std::vector<double> openswmm::NodeData::stat_vol_flooded |
Total volume of water lost as overflow (project volume units).
| std::vector<double> openswmm::NodeData::sur_depth |
Maximum depth allowed at the node (ponding or surcharge limit).
| std::vector<std::string> openswmm::NodeData::tags |
Per-object tag from the INP [TAGS] section.
Free-form string label, used by GUIs for filtering and grouping (e.g. catchment-name labels, asset IDs, user-defined groups). Empty string means no tag. Written back to INP by InpWriter as a Node <name> <tag> row in [TAGS]. Index-keyed (per-NodeData field) so swmm_node_rename keeps the tag attached — the earlier name-keyed SimulationContext::node_tags map lost tags on rename.
| std::vector<NodeType> openswmm::NodeData::type |
Node type for each node.
| std::vector<double> openswmm::NodeData::user_conc_mass_flux |
User-forced quality mass flux at each node (mass/sec).
Flat 2D: [node * n_pollutants + pollutant]. Unlike the transient forcing in ForcingData, this persists until the user explicitly changes it and is applied as an additive mass source at each routing step (analogous to user_lat_flow for flow).
| std::vector<double> openswmm::NodeData::user_lat_flow |
User-forced lateral inflow set via the API (project flow units).
Unlike lat_flow, this is not cleared between routing steps. The value persists until the user explicitly changes it and is added to lat_flow at each routing step.
| std::vector<double> openswmm::NodeData::volume |
Current water volume (project volume units).