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

Top-level orchestrator for the 2D surface routing module. More...

#include <SurfaceRouter2D.hpp>

Collaboration diagram for openswmm::twoD::SurfaceRouter2D:

Public Types

using PendingBoundaryRow = twoD::PendingBoundaryRow
 Per-row buffer for [2D_BOUNDARY_CONDITIONS] parse output.
 
using PendingInitialQualityRow = twoD::PendingInitialQualityRow
 
using PendingBoundaryQualityRow = twoD::PendingBoundaryQualityRow
 
using PendingEdgeConveyanceRow = twoD::PendingEdgeConveyanceRow
 Per-row buffer for [2D_EDGE_CONVEYANCE] parse output (§11A).
 

Public Member Functions

 SurfaceRouter2D ()=default
 
 ~SurfaceRouter2D ()=default
 
 SurfaceRouter2D (const SurfaceRouter2D &)=delete
 
SurfaceRouter2Doperator= (const SurfaceRouter2D &)=delete
 
 SurfaceRouter2D (SurfaceRouter2D &&)=default
 
SurfaceRouter2Doperator= (SurfaceRouter2D &&)=default
 
void initialize (SimulationContext &ctx)
 Initialize the 2D module after input parsing is complete.
 
void step (SimulationContext &ctx, double dt, double t)
 Advance the 2D surface routing by one SWMM routing step.
 
void updateOutfallsPreRouting (SimulationContext &ctx)
 Pre-routing hook: update outfall boundaries from 2D surface heads.
 
void advancePostRouting (SimulationContext &ctx, double dt, double t)
 Post-routing hook: compute coupling exchange and advance 2D solver.
 
void prepareOneShotForcing (SimulationContext &ctx)
 Prepare a RESET 2D forcing to apply on the next routing step.
 
void flushPendingBatch (SimulationContext &ctx)
 Flush the pending (partial) sync batch, if any.
 
double reportWeight (double report_ms) const noexcept
 
const std::vector< double > & reportOldDepth () const noexcept
 
const std::vector< double > & reportOldHead () const noexcept
 Cell head (m) at the start of that batch.
 
void finalize (SimulationContext &ctx)
 Finalize the 2D module at simulation end.
 
bool isActive () const noexcept
 Check if the 2D module is active.
 
const std::vector< std::string > & threadWarnings () const noexcept
 
void computeCouplingConductances (const SimulationContext &ctx, std::vector< std::pair< int, double > > &out) const
 
void prepareForEdit ()
 Make the parsed mesh editable without a full initialize().
 
const MeshDatamesh () const noexcept
 Access mesh data (read-only).
 
MeshDatamesh () noexcept
 Access mesh data (mutable, for input parsing).
 
const SurfaceStateDatastate () const noexcept
 Access surface state (read-only).
 
SurfaceStateDatastate () noexcept
 Access surface state (mutable, for forcing).
 
const SolverOptions2Doptions () const noexcept
 Access solver options (read-only).
 
SolverOptions2Doptions () noexcept
 Access solver options (mutable).
 
const BoundaryDataboundary () const noexcept
 Access per-edge boundary-condition data (read-only).
 
BoundaryDataboundary () noexcept
 Access per-edge boundary-condition data (mutable, for forcing/parsing).
 
void invalidateBoundaryIndex () noexcept
 
void refreshRenderFieldsIfStale ()
 
Infil2Dinfil () noexcept
 Access the per-cell infiltration model (plan §5.5, track I).
 
const Infil2Dinfil () const noexcept
 
GwTransportDatagwTransport () noexcept
 
const GwTransportDatagwTransport () const noexcept
 
SubsurfaceConfigaquiferConfig () noexcept
 
const SubsurfaceConfigaquiferConfig () const noexcept
 
std::vector< std::string > & aquiferNodeNames () noexcept
 
const std::vector< std::string > & aquiferNodeNames () const noexcept
 
SubsurfaceSolversubsurface () noexcept
 The running kernel. active() is false until [2D_AQUIFER] resolves.
 
const SubsurfaceSolversubsurface () const noexcept
 
const std::vector< double > & subcatchRecharge () const noexcept
 Ledger-consistent cumulative infiltrated depth per cell (m).
 
void drainSubcatchRecharge (std::vector< double > &out)
 
const std::vector< int > & cellSubcatchment () const noexcept
 
const std::vector< double > & infilCumulative () const noexcept
 
const std::vector< double > & couplingCumulative () const noexcept
 Signed cumulative coupling exchange per cell (m³).
 
const std::vector< double > & rainCumulative () const noexcept
 Ledger-consistent cumulative rainfall volume per cell (m³).
 
std::vector< PendingInitialQualityRow > & pendingInitialQualityRows () noexcept
 S1/S2: raw [2D_INITIAL_QUALITY] rows, resolved at initialize().
 
std::vector< PendingBoundaryQualityRow > & pendingBoundaryQualityRows () noexcept
 
std::vector< PendingBoundaryRow > & pendingBCRows () noexcept
 
const std::vector< PendingBoundaryRow > & pendingBCRows () const noexcept
 
std::vector< PendingEdgeConveyanceRow > & pendingEdgeConveyanceRows () noexcept
 
const std::vector< PendingEdgeConveyanceRow > & pendingEdgeConveyanceRows () const noexcept
 
double totalVolume () const
 Get total 2D surface volume (sum of depth * area).
 
double totalExchangeFlow () const
 Get total exchange flow (sum of coupling flows, m³/s).
 
long lastSolverSteps () const
 
double lastSolverStepSize () const
 
const std::string & backendName () const noexcept
 

Detailed Description

Top-level orchestrator for the 2D surface routing module.

Member Typedef Documentation

◆ PendingBoundaryQualityRow

◆ PendingBoundaryRow

Per-row buffer for [2D_BOUNDARY_CONDITIONS] parse output.

V-E3. Populated by the input parser during reading (before the mesh is finalized), drained into boundary_ during initialize() after boundary_.resize() allocates the per-edge slots. Retained after the drain so serialization (InpWriter / GeoPackage) can re-emit the authored rows (group label, TS-vs-constant choice). Hoisted to data/PendingRows2D.hpp; alias kept for call sites.

◆ PendingEdgeConveyanceRow

Per-row buffer for [2D_EDGE_CONVEYANCE] parse output (§11A).

Populated by the input parser during reading (vertices known but mesh topology not yet built), drained into mesh_.edge_conveyance during initialize() after buildMeshTopology has populated the neighbour table. Mirrored to both slots of an interior edge so antisymmetric FV flux integration stays mass-conservative. Retained after the drain for faithful re-serialization.

◆ PendingInitialQualityRow

Constructor & Destructor Documentation

◆ SurfaceRouter2D() [1/3]

openswmm::twoD::SurfaceRouter2D::SurfaceRouter2D ( )
default
Here is the caller graph for this function:

◆ ~SurfaceRouter2D()

openswmm::twoD::SurfaceRouter2D::~SurfaceRouter2D ( )
default

◆ SurfaceRouter2D() [2/3]

openswmm::twoD::SurfaceRouter2D::SurfaceRouter2D ( const SurfaceRouter2D & )
delete
Here is the call graph for this function:

◆ SurfaceRouter2D() [3/3]

openswmm::twoD::SurfaceRouter2D::SurfaceRouter2D ( SurfaceRouter2D && )
default
Here is the call graph for this function:

Member Function Documentation

◆ advancePostRouting()

void openswmm::twoD::SurfaceRouter2D::advancePostRouting ( SimulationContext & ctx,
double dt,
double t )

Post-routing hook: compute coupling exchange and advance 2D solver.

Must be called AFTER the 1D routing step.

Parameters
ctxSimulation context.
dtSWMM routing timestep (seconds).
tCurrent simulation time (seconds from start).
Here is the caller graph for this function:

◆ aquiferConfig() [1/2]

const SubsurfaceConfig & openswmm::twoD::SurfaceRouter2D::aquiferConfig ( ) const
inlinenoexcept

◆ aquiferConfig() [2/2]

SubsurfaceConfig & openswmm::twoD::SurfaceRouter2D::aquiferConfig ( )
inlinenoexcept

G1: the authored [2D_AQUIFER*] rows, in the user's own units. Reached by the section handlers and the InpWriter through SimulationContext::twod_io.aquifer.

◆ aquiferNodeNames() [1/2]

const std::vector< std::string > & openswmm::twoD::SurfaceRouter2D::aquiferNodeNames ( ) const
inlinenoexcept

◆ aquiferNodeNames() [2/2]

std::vector< std::string > & openswmm::twoD::SurfaceRouter2D::aquiferNodeNames ( )
inlinenoexcept

◆ backendName()

const std::string & openswmm::twoD::SurfaceRouter2D::backendName ( ) const
inlinenoexcept

Backend label chosen by SurfaceSolverFactory at initialize() ("cpu (explicit marcher)", "omp (…)", …); empty before that.

◆ boundary() [1/2]

const BoundaryData & openswmm::twoD::SurfaceRouter2D::boundary ( ) const
inlinenoexcept

Access per-edge boundary-condition data (read-only).

◆ boundary() [2/2]

BoundaryData & openswmm::twoD::SurfaceRouter2D::boundary ( )
inlinenoexcept

Access per-edge boundary-condition data (mutable, for forcing/parsing).

◆ cellSubcatchment()

const std::vector< int > & openswmm::twoD::SurfaceRouter2D::cellSubcatchment ( ) const
inlinenoexcept

Cell → containing subcatchment index (-1 = none). Empty unless the SUBCATCH_AQUIFER destination resolved.

◆ computeCouplingConductances()

void openswmm::twoD::SurfaceRouter2D::computeCouplingConductances ( const SimulationContext & ctx,
std::vector< std::pair< int, double > > & out ) const

Windowless-coupling stabilizer: per coupled node, the exchange head sensitivity G = Σ_points −∂Q/∂h_1d ≥ 0 converted to 1D units (ft³/s per ft), for the caller to add into the dynamic-wave sumdqdh each Picard iteration. Appends (node_idx, G) pairs; cheap (O(points)).

Here is the call graph for this function:

◆ couplingCumulative()

const std::vector< double > & openswmm::twoD::SurfaceRouter2D::couplingCumulative ( ) const
inlinenoexcept

Signed cumulative coupling exchange per cell (m³).

Positive = water the 1D node delivered INTO this cell (spill, submerged-outfall discharge); negative = water the node abstracted FROM it (drain). Summing the vector gives coupling_1d_to_2d_in − coupling_2d_to_1d_out, which is the check that ties this series to the domain totals.

◆ drainSubcatchRecharge()

void openswmm::twoD::SurfaceRouter2D::drainSubcatchRecharge ( std::vector< double > & out)
inline

Move the pending recharge into out (m³ per subcatchment) and zero the accumulator. out is sized to the accumulator (empty when the destination is not in use).

◆ finalize()

void openswmm::twoD::SurfaceRouter2D::finalize ( SimulationContext & ctx)

Finalize the 2D module at simulation end.

Flushes any partial macro-step window (routing time accumulated since the last 2D advance) so the 2D clock ends at the simulation end instead of up to one window short, then releases the solver.

Parameters
ctxSimulation context (needed for the flush advance).

◆ flushPendingBatch()

void openswmm::twoD::SurfaceRouter2D::flushPendingBatch ( SimulationContext & ctx)

Flush the pending (partial) sync batch, if any.

Closes the accumulated routing span with one co-advance so the 2D clock reaches the current routing time. A no-op under default per-routing-step coupling (the batch closes every step). Used before a report snapshot — so the report-time blend brackets the report instant — and before a one-shot forcing.

Here is the caller graph for this function:

◆ gwTransport() [1/2]

const GwTransportData & openswmm::twoD::SurfaceRouter2D::gwTransport ( ) const
inlinenoexcept

◆ gwTransport() [2/2]

GwTransportData & openswmm::twoD::SurfaceRouter2D::gwTransport ( )
inlinenoexcept

U4 (2026-09-07): the [GW_*] subsurface-transport authoring rows. Reached by the parser, the writer and the C API through SimulationContext::twod_io.gw. Authoring-only in this release.

◆ infil() [1/2]

const Infil2D & openswmm::twoD::SurfaceRouter2D::infil ( ) const
inlinenoexcept

◆ infil() [2/2]

Infil2D & openswmm::twoD::SurfaceRouter2D::infil ( )
inlinenoexcept

Access the per-cell infiltration model (plan §5.5, track I).

Mutable so SWMMEngine can publish it on ctx.twod_io.infil — the [2D_INFILTRATION*] section handlers and the InpWriter reach it there. The router owns the object, resolves it against the mesh in initialize(), and drives its INFIL_STEP cadence in coAdvanceStep().

◆ infilCumulative()

const std::vector< double > & openswmm::twoD::SurfaceRouter2D::infilCumulative ( ) const
inlinenoexcept

◆ initialize()

void openswmm::twoD::SurfaceRouter2D::initialize ( SimulationContext & ctx)

Initialize the 2D module after input parsing is complete.

Builds mesh topology, vertex stencils, resolves coupling names, and initializes the explicit 2D solver.

Parameters
ctxSimulation context (must have mesh_2d populated from parsing).
Here is the call graph for this function:

◆ invalidateBoundaryIndex()

void openswmm::twoD::SurfaceRouter2D::invalidateBoundaryIndex ( )
inlinenoexcept

Announce that a boundary slot's TYPE changed (the API BC-type setter), so the compact non-WALL slot list the per-step boundary passes walk is rebuilt before it is next used.

◆ isActive()

bool openswmm::twoD::SurfaceRouter2D::isActive ( ) const
inlinenoexcept

Check if the 2D module is active.

◆ lastSolverSteps()

long openswmm::twoD::SurfaceRouter2D::lastSolverSteps ( ) const
inline

◆ lastSolverStepSize()

double openswmm::twoD::SurfaceRouter2D::lastSolverStepSize ( ) const
inline

◆ mesh() [1/2]

const MeshData & openswmm::twoD::SurfaceRouter2D::mesh ( ) const
inlinenoexcept

Access mesh data (read-only).

◆ mesh() [2/2]

MeshData & openswmm::twoD::SurfaceRouter2D::mesh ( )
inlinenoexcept

Access mesh data (mutable, for input parsing).

◆ operator=() [1/2]

SurfaceRouter2D & openswmm::twoD::SurfaceRouter2D::operator= ( const SurfaceRouter2D & )
delete
Here is the call graph for this function:

◆ operator=() [2/2]

SurfaceRouter2D & openswmm::twoD::SurfaceRouter2D::operator= ( SurfaceRouter2D && )
default
Here is the call graph for this function:

◆ options() [1/2]

const SolverOptions2D & openswmm::twoD::SurfaceRouter2D::options ( ) const
inlinenoexcept

Access solver options (read-only).

◆ options() [2/2]

SolverOptions2D & openswmm::twoD::SurfaceRouter2D::options ( )
inlinenoexcept

Access solver options (mutable).

◆ pendingBCRows() [1/2]

const std::vector< PendingBoundaryRow > & openswmm::twoD::SurfaceRouter2D::pendingBCRows ( ) const
inlinenoexcept

◆ pendingBCRows() [2/2]

std::vector< PendingBoundaryRow > & openswmm::twoD::SurfaceRouter2D::pendingBCRows ( )
inlinenoexcept

◆ pendingBoundaryQualityRows()

std::vector< PendingBoundaryQualityRow > & openswmm::twoD::SurfaceRouter2D::pendingBoundaryQualityRows ( )
inlinenoexcept

◆ pendingEdgeConveyanceRows() [1/2]

const std::vector< PendingEdgeConveyanceRow > & openswmm::twoD::SurfaceRouter2D::pendingEdgeConveyanceRows ( ) const
inlinenoexcept

◆ pendingEdgeConveyanceRows() [2/2]

std::vector< PendingEdgeConveyanceRow > & openswmm::twoD::SurfaceRouter2D::pendingEdgeConveyanceRows ( )
inlinenoexcept

◆ pendingInitialQualityRows()

std::vector< PendingInitialQualityRow > & openswmm::twoD::SurfaceRouter2D::pendingInitialQualityRows ( )
inlinenoexcept

S1/S2: raw [2D_INITIAL_QUALITY] rows, resolved at initialize().

◆ prepareForEdit()

void openswmm::twoD::SurfaceRouter2D::prepareForEdit ( )

Make the parsed mesh editable without a full initialize().

The GUI keeps the engine in OPENED (not INITIALIZED) state so 1D property edits stay legal. In that state the 2D mesh is parsed but the [2D_BOUNDARY_CONDITIONS] / [2D_EDGE_CONVEYANCE] rows still live in the pending-row buffers, which the serializer prefers over live state. This drains those rows into BoundaryData / mesh edge slots (the same drain initialize() performs) so per-edge API edits take effect and are written on save. No-op once drained or when no mesh is loaded.

◆ prepareOneShotForcing()

void openswmm::twoD::SurfaceRouter2D::prepareOneShotForcing ( SimulationContext & ctx)

Prepare a RESET 2D forcing to apply on the next routing step.

Flushes any already accumulated macro-window before the new one-shot is recorded, then forces the next routing step to fire a 2D advance so the prescription applies to future time only and is cleared after use.

Here is the call graph for this function:

◆ rainCumulative()

const std::vector< double > & openswmm::twoD::SurfaceRouter2D::rainCumulative ( ) const
inlinenoexcept

Ledger-consistent cumulative rainfall volume per cell (m³).

Booked in accumulateMassBalance() from the SAME per-cell rainfall term that feeds MassBalance2D::rainfall_in, so sum(rainCumulative()[i]) == rainfall_in holds by construction. Sized [n_triangles] from initialize(); zero-filled when no rain.

◆ refreshRenderFieldsIfStale()

void openswmm::twoD::SurfaceRouter2D::refreshRenderFieldsIfStale ( )
inline

Bring the render fields (vertex heads, output gradients, vertex render depths) up to date with the current solver state if a batch has run since they were last computed. The API getters that expose those fields call this so a reader arriving between reports is never served a stale field; it is a no-op at a report instant, where the refresh already ran.

◆ reportOldDepth()

const std::vector< double > & openswmm::twoD::SurfaceRouter2D::reportOldDepth ( ) const
inlinenoexcept

Cell depth (m) at the start of the sync batch that crossed the current report instant (meaningful when reportWeight() < 1).

◆ reportOldHead()

const std::vector< double > & openswmm::twoD::SurfaceRouter2D::reportOldHead ( ) const
inlinenoexcept

Cell head (m) at the start of that batch.

◆ reportWeight()

double openswmm::twoD::SurfaceRouter2D::reportWeight ( double report_ms) const
noexcept

Report-time interpolation weight for the 2D snapshot blend: f = (report_ms − window_old_ms)/(window_new_ms − window_old_ms), clamped to [0,1]; returns 1.0 (pure current state) when no batch has crossed a report instant yet. Unlike the 1D weight there is no legacy bit pattern to reproduce, so the clamp simply absorbs ulp-level clock skew between the router's and the engine's ms accumulators.

◆ state() [1/2]

const SurfaceStateData & openswmm::twoD::SurfaceRouter2D::state ( ) const
inlinenoexcept

Access surface state (read-only).

◆ state() [2/2]

SurfaceStateData & openswmm::twoD::SurfaceRouter2D::state ( )
inlinenoexcept

Access surface state (mutable, for forcing).

◆ step()

void openswmm::twoD::SurfaceRouter2D::step ( SimulationContext & ctx,
double dt,
double t )

Advance the 2D surface routing by one SWMM routing step.

Sequence:

  1. Update outfall boundary heads from 2D state (before 1D routing)
  2. After 1D routing: compute coupling exchange flows
  3. Update 2D rainfall from system gages
  4. Advance the explicit 2D solver by dt_swmm
  5. Transfer outfall discharges into 2D cells
  6. Update statistics
Parameters
ctxSimulation context.
dtSWMM routing timestep (seconds).
tCurrent simulation time (seconds from start).
Here is the call graph for this function:

◆ subcatchRecharge()

const std::vector< double > & openswmm::twoD::SurfaceRouter2D::subcatchRecharge ( ) const
inlinenoexcept

Ledger-consistent cumulative infiltrated depth per cell (m).

Drains the SAME SurfaceStateData::infil_applied accumulator that MassBalance2D::infil_out books — the depth the marcher actually removed, summed as it was removed — so sum(infilCumulative()[i] * tri_area[i]) == infil_out holds by construction. Prefer this over Infil2D::cumulative(), which is the unramped capacity the kernels offered and therefore exceeds the applied loss on drying cells. Empty when no [2D_INFILTRATION*] model resolved.

U3 (track I-b) — per-subcatchment 2D infiltration recharge pending delivery to the legacy aquifer, in m³.

Filled in accumulateMassBalance() for every cell whose resolved row says SUBCATCH_AQUIFER and that a subcatchment contains. drainSubcatchRecharge() hands it to the runoff step (which adds it to that subcatchment's infiltration rate for GWSolver::execute) and zeroes it, so the accumulator is drained exactly once per runoff step. Empty when the destination is not in use.

◆ subsurface() [1/2]

const SubsurfaceSolver & openswmm::twoD::SurfaceRouter2D::subsurface ( ) const
inlinenoexcept

◆ subsurface() [2/2]

SubsurfaceSolver & openswmm::twoD::SurfaceRouter2D::subsurface ( )
inlinenoexcept

The running kernel. active() is false until [2D_AQUIFER] resolves.

◆ threadWarnings()

const std::vector< std::string > & openswmm::twoD::SurfaceRouter2D::threadWarnings ( ) const
inlinenoexcept

Thread-count advisories produced by initialize() (THREADS above the machine limits, triangle gate reducing an explicit request). The engine forwards them to the report warnings and the host warning callback.

◆ totalExchangeFlow()

double openswmm::twoD::SurfaceRouter2D::totalExchangeFlow ( ) const

Get total exchange flow (sum of coupling flows, m³/s).

◆ totalVolume()

double openswmm::twoD::SurfaceRouter2D::totalVolume ( ) const

Get total 2D surface volume (sum of depth * area).

Here is the caller graph for this function:

◆ updateOutfallsPreRouting()

void openswmm::twoD::SurfaceRouter2D::updateOutfallsPreRouting ( SimulationContext & ctx)

Pre-routing hook: update outfall boundaries from 2D surface heads.

Must be called BEFORE the 1D routing step, after setOutfallDepths().

Parameters
ctxSimulation context.
Here is the call graph for this function:
Here is the caller graph for this function:

The documentation for this class was generated from the following files: