![]() |
OpenSWMM Engine
6.0.0-alpha.3
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.3)
|
Namespaces | |
| namespace | gpu |
Classes | |
| struct | ActiveSetData |
| struct | BoundaryData |
| SoA storage for per-edge boundary conditions. More... | |
| struct | CouplingPoint |
| Descriptor for a single coupling point between 2D and 1D. More... | |
| class | HypreAmgPreconditioner |
| BoomerAMG preconditioner over the 2D diffusion Newton matrix. More... | |
| struct | InertialEdges |
| Canonical unique interior-edge layout + per-cell incidence for the local-inertial scheme. More... | |
| class | ISurfaceSolver |
| Abstract time integrator for the 2D surface-routing ODE system. More... | |
| struct | MeshData |
| SoA storage for 2D triangular mesh geometry and topology. More... | |
| struct | PendingBoundaryRow |
Per-row buffer for [2D_BOUNDARY_CONDITIONS] parse output. More... | |
| struct | PendingEdgeConveyanceRow |
Per-row buffer for [2D_EDGE_CONVEYANCE] parse output (§11A). More... | |
| class | RainfallInterpolator |
| Builds and applies static rainfall-interpolation weights for the mesh. More... | |
| struct | SolverOptions2D |
| Configuration for the 2D surface routing CVODE solver. More... | |
| class | SurfaceJacobian |
| Assembles M = I − γ·J (diffusion stencil) in CSR for AMG. More... | |
| class | SurfaceRouter2D |
| Top-level orchestrator for the 2D surface routing module. More... | |
| struct | SurfaceStateData |
Enumerations | |
| enum class | BoundaryType : int8_t { WALL = 0 , NORMAL_FLOW = 1 , SPECIFIED_STAGE = 2 , SPECIFIED_FLOW = 3 , RATING_CURVE = 4 } |
| Boundary condition types for 2D mesh edges. More... | |
| enum class | LinearSolverType : int8_t { GMRES = 0 , BICGSTAB = 1 , TFQMR = 2 } |
| Krylov linear solver selector for the BDF + Newton + Krylov stack. More... | |
| enum class | PreconditionerType : int8_t { NONE = 0 , JACOBI = 1 , ILU = 2 , AMG = 3 } |
| Preconditioner selector for the Krylov inner solver. More... | |
| enum class | IntegratorType : int8_t { CVODE = 0 , ARKODE = 1 } |
| Time-integrator selector for the 2D surface ODE. More... | |
| enum class | MomentumType : int8_t { DW = 0 , INERTIAL = 1 } |
| Surface-momentum closure for the 2D flux. More... | |
| enum class | RainfallMode : int8_t { NATURAL_NEIGHBOUR = 0 , SYSTEM = 1 , NONE = 2 } |
| How raingage rainfall is mapped onto the 2D mesh cells. More... | |
Functions | |
| double | computeNodeCouplingQ (const CouplingPoint &cp, const MeshData &mesh, const SurfaceStateData &state, const NodeData &nodes, const SolverOptions2D &opts) noexcept |
| Live node-coupling orifice flux for ONE non-outfall coupling point. | |
| void | scatterCouplingToYdot (const MeshData &mesh, const SurfaceStateData &state, const CouplingPoint &cp, double Q, double *ydot) noexcept |
| Scatter a signed volumetric exchange Q (m³/s) directly onto the cell derivatives ydot[] of the 2D volume ODE (for the live-RHS path). | |
| std::vector< CouplingPoint > | buildCouplingPoints (const MeshData &mesh, const SimulationContext &ctx) |
| Build the list of coupling points from mesh coupling maps. | |
| void | computeCouplingExchange (const std::vector< CouplingPoint > &cps, const MeshData &mesh, SurfaceStateData &state, SimulationContext &ctx, const SolverOptions2D &opts, double dt) |
| Compute exchange flows at all coupling points and inject into forcing API. | |
| void | updateOutfallBoundaries (const std::vector< CouplingPoint > &cps, const MeshData &mesh, const SurfaceStateData &state, SimulationContext &ctx, const SolverOptions2D &opts) |
| Update outfall boundary depths from 2D surface heads. | |
| int | transferOutfallDischarges (const std::vector< CouplingPoint > &cps, const MeshData &mesh, SurfaceStateData &state, const SimulationContext &ctx, const SolverOptions2D &opts, double dt, std::unordered_map< int, double > &applied_q) |
| Transfer outfall discharges into 2D coupling cells. | |
| std::vector< PendingBoundaryRow > | collectBCRows (const std::vector< PendingBoundaryRow > *pending, const BoundaryData *boundary, bool drained) |
Collect [2D_BOUNDARY_CONDITIONS]-shaped rows for serialization. | |
| std::vector< PendingEdgeConveyanceRow > | collectConveyanceRows (const std::vector< PendingEdgeConveyanceRow > *pending, const MeshData *mesh, bool drained) |
Collect [2D_EDGE_CONVEYANCE]-shaped rows for serialization. | |
| std::string | parse2DOptionsLine (const std::vector< std::string > &tokens, SolverOptions2D &opts) |
| Parse a single line from the [2D_OPTIONS] section. | |
| bool | is2DOptionKey (const std::string &key) |
True when key (case-insensitive) is a [2D_OPTIONS] parameter accepted by parse2DOptionsLine. | |
| std::string | format2DOptionValue (const SolverOptions2D &opts, const std::string &key) |
| Format the current value of a [2D_OPTIONS] parameter as the string token parse2DOptionsLine accepts (round-trip safe). | |
| std::string | parse2DVertexLine (const std::vector< std::string > &tokens, MeshData &mesh) |
| Parse a single line from the [2D_VERTICES] section. | |
| std::string | parse2DTriangleLine (const std::vector< std::string > &tokens, MeshData &mesh) |
| Parse a single line from the [2D_TRIANGLES] section. | |
| std::string | parse2DVertexNodeMapLine (const std::vector< std::string > &tokens, MeshData &mesh) |
| Parse a single line from the [2D_VERTEX_NODE_MAP] section. | |
| std::string | parse2DTriangleNodeMapLine (const std::vector< std::string > &tokens, MeshData &mesh) |
| Parse a single line from the [2D_TRIANGLE_NODE_MAP] section. | |
| std::string | parse2DBoundaryConditionsLine (const std::vector< std::string > &tokens, std::vector< SurfaceRouter2D::PendingBoundaryRow > &pending_rows) |
V-E3 — parse a single line from the [2D_BOUNDARY_CONDITIONS] section into a SurfaceRouter2D::PendingBoundaryRow appended to pending_rows. | |
| std::string | parse2DEdgeConveyanceLine (const std::vector< std::string > &tokens, std::vector< SurfaceRouter2D::PendingEdgeConveyanceRow > &pending_rows) |
§11A — parse a single [2D_EDGE_CONVEYANCE] line. | |
| void | register2DSections (MeshData &mesh, SolverOptions2D &options, std::vector< SurfaceRouter2D::PendingBoundaryRow > &pending_bc_rows, std::vector< SurfaceRouter2D::PendingEdgeConveyanceRow > &pending_ec_rows, input::SectionRegistry ®istry) |
| Register all 2D input section handlers with the section registry. | |
| std::string | load2DMeshExternalFile (MeshData &mesh, SolverOptions2D &opts, std::vector< SurfaceRouter2D::PendingBoundaryRow > &pending_bc_rows, std::vector< SurfaceRouter2D::PendingEdgeConveyanceRow > &pending_ec_rows, const std::string &mesh_file, const std::string &inp_base_dir) |
| Load 2D mesh sections from an external file. | |
| void | prescan2DUnitsHeader (const std::string &inp_path, SolverOptions2D &opts) |
Scan inp_path for a ;; UNITS: <value> comment header and set opts.mesh_units_si to true when the value names metres. | |
| void | buildMeshTopology (MeshData &mesh) |
| Build mesh topology and precompute geometry from raw vertex/triangle data. | |
| std::string | validateMesh (const MeshData &mesh) |
| Validate mesh data for consistency. | |
| void | recomputeVertexZDependents (MeshData &mesh, int vidx) |
| Recompute Z-derived per-triangle / per-edge geometry for triangles incident to a vertex whose Z just changed. | |
| void | buildVertexStencils (MeshData &mesh) |
| Build pseudo-Laplacian reconstruction stencils for all vertices. | |
| void | reconstructVertexHeads (const MeshData &mesh, SurfaceStateData &state, int nthreads=1) |
| Reconstruct head values at vertices from cell-centred heads. | |
| void | seedInactiveState (const MeshData &mesh, SurfaceStateData &state, const SolverOptions2D &opts) |
| void | rebuildActiveSet (const MeshData &mesh, SurfaceStateData &state, const BoundaryData *boundary, const std::vector< CouplingPoint > *coupling_pts, const SolverOptions2D &opts, ActiveSetData &as, bool live_coupling) |
| bool | activeSetBreached (const MeshData &mesh, const SurfaceStateData &state, const ActiveSetData &as) |
| void | computeUnlimitedGradients (const MeshData &mesh, SurfaceStateData &state, int nthreads=1) |
| Compute unlimited gradients for all triangles via Green-Gauss theorem. | |
| void | computeLimitedGradients (const MeshData &mesh, SurfaceStateData &state, double epsilon, int nthreads=1) |
| Apply Jawahar-Kamath slope limiter (Eq. [23]–[24]). | |
| void | computeEdgeFluxes (const MeshData &mesh, SurfaceStateData &state, const SolverOptions2D &opts) |
| Compute edge fluxes for all triangles. | |
| void | assembleRHS (const MeshData &mesh, const SurfaceStateData &state, const SolverOptions2D &opts, double *ydot) |
| Assemble the RHS of the ODE system: dψ/dt for each triangle. | |
| void | assembleImplicitRHS (const MeshData &mesh, const SurfaceStateData &state, const SolverOptions2D &opts, double *ydot) |
| Implicit half of the IMEX split: the flux divergence only (ARKODE F_I). | |
| void | assembleExplicitRHS (const MeshData &mesh, const SurfaceStateData &state, const SolverOptions2D &opts, const double *y, double *ydot) |
| Explicit half of the IMEX split: source/sink forcing (ARKODE F_E). | |
| void | computeCellContinuity (const MeshData &mesh, SurfaceStateData &state, const SolverOptions2D &opts, double dt) |
| Compute the per-cell continuity residual (local mass-balance check). | |
| void | computeFaceVelocity (const MeshData &mesh, SurfaceStateData &state, const SolverOptions2D &opts) |
| Reconstruct cell-centred velocity (vx, vy) from edge fluxes (RT0). | |
| double | evapSink (double rate, double depth, double dry_depth) noexcept |
| Depth-limited evaporation sink rate (m/s) for one cell. | |
| std::unique_ptr< ISurfaceSolver > | makeSurfaceSolver (const SolverOptions2D &opts, std::string *chosen=nullptr, int n_cells=0) |
| Construct the 2D surface solver per the runtime backend policy. | |
|
strong |
Boundary condition types for 2D mesh edges.
SPECIFIED_FLOW (3) and RATING_CURVE (4) added per GUI plan §V V-E4 / V-E5. Storage + C API only at this revision — the FV-SWE flux integration for non-Wall BCs is deferred to a follow-up slice (V-E-FLUX). Today the solver treats every boundary edge as Wall regardless of type (see SurfaceFluxCalculator::computeEdgeFluxes line 131).
|
strong |
Time-integrator selector for the 2D surface ODE.
CVODE is the default fully-implicit BDF integrator (CvodeSurfaceSolver). ARKODE selects the ARKStep additive-Runge–Kutta IMEX integrator (ArkodeSurfaceSolver) — the diffusion flux is integrated implicitly while the non-stiff source forcing is explicit. See docs/IMEX_LOCAL_INERTIAL_IMPLEMENTATION_PLAN.md. Orthogonal to the serial/omp/gpu backend selector; ARKODE is CPU-only. The env var OPENSWMM_2D_INTEGRATOR (cvode|arkode) overrides this field.
| Enumerator | |
|---|---|
| CVODE | Default: fully-implicit BDF (CvodeSurfaceSolver). |
| ARKODE | ARKStep IMEX additive-RK (ArkodeSurfaceSolver). |
|
strong |
Krylov linear solver selector for the BDF + Newton + Krylov stack.
Phase 1 wires GMRES only; BICGSTAB and TFQMR are kept as enum values to preserve the input-file parsing surface and to mark slots reserved for possible Phase 2 work, but selecting them today triggers a clear runtime error in CvodeSurfaceSolver::initialize().
GMRES is the canonical choice for the elliptic-flavoured diffusive-wave Jacobian and pairs cleanly with multigrid preconditioners (the Phase 2 BoomerAMG path); the other two Krylov methods would only earn their keep for problem classes we do not currently solve.
| Enumerator | |
|---|---|
| GMRES | Phase 1: WIRED (SUNLinSol_SPGMR). |
| BICGSTAB | Reserved; rejected at initialize() in Phase 1. |
| TFQMR | Reserved; rejected at initialize() in Phase 1. |
|
strong |
Surface-momentum closure for the 2D flux.
DW (default) is the Manning diffusive wave (no inertia; state = cell volume only). INERTIAL adds the LISFLOOD-FP local-inertial momentum: a prognostic per-edge discharge q with implicit gravity + friction, integrated by the ARKStep IMEX solver. See docs/IMEX_LOCAL_INERTIAL_IMPLEMENTATION_PLAN.md §2. Only honored by ArkodeSurfaceSolver; env OPENSWMM_2D_MOMENTUM (dw|inertial) overrides this field.
| Enumerator | |
|---|---|
| DW | Manning diffusive wave (default). |
| INERTIAL | Local-inertial (LISFLOOD-FP) with per-edge q. |
|
strong |
Preconditioner selector for the Krylov inner solver.
NONE (no preconditioning) and JACOBI (per-cell diagonal approximation rebuilt each Jacobian refresh) are always available. AMG (hypre BoomerAMG) is wired only when the engine is built with OPENSWMM_WITH_HYPRE; selecting it otherwise triggers a clear runtime error in the solver's initialize(). ILU remains a reserved-but-rejected slot.
Tier rationale (see also the Phase 1/2 discussion in docs/2D_KNOWN_STIFFNESS_ISSUE.md):
| Enumerator | |
|---|---|
| NONE | WIRED (no preconditioning). |
| JACOBI | WIRED (diagonal heuristic). |
| ILU | Reserved; rejected at initialize(). |
| AMG | WIRED when built with OPENSWMM_WITH_HYPRE (BoomerAMG). |
|
strong |
How raingage rainfall is mapped onto the 2D mesh cells.
NATURAL_NEIGHBOUR (default) spatially interpolates the located raingages onto every cell centroid — natural-neighbour (Laplace) weights inside the convex hull of the gages, inverse-distance (power 2) extrapolation outside it. The weights are precomputed once in SurfaceRouter2D::initialize() (gage positions are static for a run) and applied each step as a sparse weighted sum.
SYSTEM applies one uniform value to all cells: the arithmetic mean of every gage's current rainfall. It is also the automatic fallback when no gage has a map location (no [SYMBOLS] coordinate), since interpolation is then undefined.
Parsed from [2D_OPTIONS] RAINFALL_MODE; env OPENSWMM_2D_RAINFALL_MODE (natural|system) overrides at initialize().
| bool openswmm::twoD::activeSetBreached | ( | const MeshData & | mesh, |
| const SurfaceStateData & | state, | ||
| const ActiveSetData & | as ) |
Post-advance safety check: true if any OUTER-ring cell got wet (volume > eps·A) — the front crossed the whole halo within one window and the advance must be discarded and redone with a wider halo.
| void openswmm::twoD::assembleExplicitRHS | ( | const MeshData & | mesh, |
| const SurfaceStateData & | state, | ||
| const SolverOptions2D & | opts, | ||
| const double * | y, | ||
| double * | ydot ) |
Explicit half of the IMEX split: source/sink forcing (ARKODE F_E).
Writes ydot_i = A_i·(rainfall_i + coupling_flux_i − evapSink_i). Cell depth is reconstructed locally from the stage volume y (depth = max(V,0)/A) so the callback is free of side effects on the shared state arrays the implicit half and the preconditioner read.
| mesh | Mesh geometry (tri_area). |
| state | Surface state (reads rainfall, coupling_flux, evap_rate). |
| opts | Solver options (dry_depth, num_threads). |
| y | Stage cell volumes (m³), one per triangle. |
| ydot | Output: explicit dV/dt per triangle (size = n_triangles). |
| void openswmm::twoD::assembleImplicitRHS | ( | const MeshData & | mesh, |
| const SurfaceStateData & | state, | ||
| const SolverOptions2D & | opts, | ||
| double * | ydot ) |
Implicit half of the IMEX split: the flux divergence only (ARKODE F_I).
Writes ydot_i = Σ_e edge_flux[i·3+e] — the stiff parabolic diffusion operator that drives the implicit solve. The source/sink forcing is handled separately by assembleExplicitRHS; together they reproduce assembleRHS exactly. Requires state.edge_flux to be current (computeEdgeFluxes already called this stage).
| mesh | Mesh geometry. |
| state | Surface state (reads edge_flux). |
| opts | Solver options (num_threads). |
| ydot | Output: implicit dV/dt per triangle (size = n_triangles). |
| void openswmm::twoD::assembleRHS | ( | const MeshData & | mesh, |
| const SurfaceStateData & | state, | ||
| const SolverOptions2D & | opts, | ||
| double * | ydot ) |
Assemble the RHS of the ODE system: dψ/dt for each triangle.
Combines edge fluxes, rainfall, evaporation, and coupling fluxes into the net rate of change of depth for each cell: dψ_i/dt = (1/A_i) Σ_j F_j + rainfall_i + coupling_flux_i − evapSink(evap_rate_i, ψ_i, dry_depth)
| mesh | Mesh geometry. |
| state | Surface state. |
| opts | Solver options (dry_depth for the evaporation ramp). |
| ydot | Output: dψ/dt for each triangle (size = n_triangles). |
| std::vector< CouplingPoint > openswmm::twoD::buildCouplingPoints | ( | const MeshData & | mesh, |
| const SimulationContext & | ctx ) |
Build the list of coupling points from mesh coupling maps.
Resolves vertex/triangle → node mappings into CouplingPoint descriptors. Must be called after node names are resolved to indices.
| mesh | Mesh data with coupling maps populated. |
| ctx | Simulation context (for node type and outfall queries). |
| void openswmm::twoD::buildMeshTopology | ( | MeshData & | mesh | ) |
Build mesh topology and precompute geometry from raw vertex/triangle data.
Must be called after parsing is complete and before solver initialization. Populates: tri_nbr*, tri_area, tri_c*, edge_length, edge_n*, edge_m*.
| mesh | The mesh data with vx/vy/vz and tri_v0/v1/v2 already populated. |
| void openswmm::twoD::buildVertexStencils | ( | MeshData & | mesh | ) |
Build pseudo-Laplacian reconstruction stencils for all vertices.
For each vertex, collects all triangles sharing that vertex, computes moments (I_xx, I_yy, I_xy, R_x, R_y), Lagrange multipliers (λ_x, λ_y), and weights. Stores results in mesh.vert_stencil_ptr/idx/wt (CSR format).
| mesh | The mesh (must have topology already built). |
|
inline |
Collect [2D_BOUNDARY_CONDITIONS]-shaped rows for serialization.
| pending | Parse-time pending rows (may be null/empty). |
| boundary | Drained per-edge BC storage (may be null/unsized). |
| drained | SolverOptions2D::pending_rows_drained — true once initialize() moved the pending rows into boundary. |
|
inline |
Collect [2D_EDGE_CONVEYANCE]-shaped rows for serialization.
| pending | Parse-time pending rows (may be null/empty). |
| mesh | Mesh whose edge_conveyance slots hold the drained values (may be null). |
| drained | SolverOptions2D::pending_rows_drained — true once initialize() moved the pending rows into the mesh slots. |
| void openswmm::twoD::computeCellContinuity | ( | const MeshData & | mesh, |
| SurfaceStateData & | state, | ||
| const SolverOptions2D & | opts, | ||
| double | dt ) |
Compute the per-cell continuity residual (local mass-balance check).
Evaluates the discrete semi-discrete balance for each cell: residual_i = (ψ_i − ψ_old_i)·A_i/dt − ( Σ_e F_e + (rainfall_i + coupling_flux_i − evapSink_i)·A_i ) where F_e = edge_flux[i·3+e] is the inflow-positive volumetric edge flux (m³/s). A perfectly conservative step yields ~0 (first-order diagnostic, not the solver's internal error). Reads old_depth, depth, edge_flux, rainfall, evap_rate, coupling_flux; writes cell_continuity_err (m³/s).
Call AFTER the solver advance, with old_depth holding the start-of-step depths (i.e. after save_state() but before the next save_state()).
| mesh | Mesh geometry (tri_area). |
| state | Surface state (writes cell_continuity_err). |
| opts | Solver options (dry_depth for the evaporation ramp). |
| dt | Step over which old_depth→depth evolved (s). |
| void openswmm::twoD::computeCouplingExchange | ( | const std::vector< CouplingPoint > & | cps, |
| const MeshData & | mesh, | ||
| SurfaceStateData & | state, | ||
| SimulationContext & | ctx, | ||
| const SolverOptions2D & | opts, | ||
| double | dt ) |
Compute exchange flows at all coupling points and inject into forcing API.
For each coupling point:
| cps | Coupling points. |
| mesh | Mesh data. |
| state | 2D surface state. |
| ctx | Simulation context (node heads, forcing API, mass balance). |
| opts | 2D solver options (uses dry_depth as the wet/dry threshold). |
| dt | Current SWMM routing timestep (s). |
| void openswmm::twoD::computeEdgeFluxes | ( | const MeshData & | mesh, |
| SurfaceStateData & | state, | ||
| const SolverOptions2D & | opts ) |
Compute edge fluxes for all triangles.
For each edge, reconstructs head at the edge from the upstream cell using the limited gradient, computes diffusive conductance, and evaluates the normal flux. Boundary edges use zero-flux (wall) condition.
| mesh | Mesh geometry. |
| state | Surface state (reads depth, head, limited gradients; writes edge_flux). |
| opts | Solver options (dry_depth). |
| void openswmm::twoD::computeFaceVelocity | ( | const MeshData & | mesh, |
| SurfaceStateData & | state, | ||
| const SolverOptions2D & | opts ) |
Reconstruct cell-centred velocity (vx, vy) from edge fluxes (RT0).
For each wet cell, solves the 3×2 least-squares system N·q ≈ b in closed form via the normal equations (NᵀN)·q = Nᵀb, where each row of N is the outward edge normal and b_e = edge_flux_e / edge_length_e is the depth-integrated normal speed (m²/s). The resulting specific-discharge vector is divided by cell depth to give velocity (m/s). Dry cells (depth < dry_depth) get zero velocity. Mirrors the GUI RT0 reconstruction (swmm2dresultslayer.cpp applyCurrentFlux_) without its scene-space Y-flip.
| mesh | Mesh geometry (edge normals, lengths). |
| state | Surface state (reads edge_flux, depth; writes face_vx/face_vy). |
| opts | Solver options (dry_depth). |
| void openswmm::twoD::computeLimitedGradients | ( | const MeshData & | mesh, |
| SurfaceStateData & | state, | ||
| double | epsilon, | ||
| int | nthreads = 1 ) |
Apply Jawahar-Kamath slope limiter (Eq. [23]–[24]).
Computes continuously differentiable limited gradients from the unlimited gradients of a cell and its neighbours.
| mesh | Mesh geometry (for neighbour lookup). |
| state | Surface state (reads grad_hx/hy, writes grad_hx_lim/hy_lim). |
| epsilon | Limiter epsilon (small positive, typically 1e-6). |
| nthreads | OpenMP thread count for the per-cell loop (1 = serial). |
|
noexcept |
Live node-coupling orifice flux for ONE non-outfall coupling point.
Evaluates the bidirectional capped-pipe orifice exchange Q (m³/s; > 0 drains 2D → 1D, < 0 spills 1D → 2D) from the CURRENT 2D state (head/depth/vert_head, reconstructed live inside the CVODE RHS) against the 1D node head, which is frozen for the duration of a 2D advance() window. Unlike computeCouplingExchange (which pre-computes a HELD flux per window and caps it by available volume / dt to stop a held drain overshooting), this is the continuous form for use inside the RHS: the orifice + capped-pipe gate + the wet/dry Hermite ramp on the LIVE source-side depth make Q self-limit smoothly as the cell drains, so CVODE integrates the stiff coupling implicitly and stably across a large macro-window — no discrete avail/dt cap needed.
Booking/conservation is handled by the caller integrating ∫Q dt (a per-point accumulator carried in the augmented state vector) over the window.
| void openswmm::twoD::computeUnlimitedGradients | ( | const MeshData & | mesh, |
| SurfaceStateData & | state, | ||
| int | nthreads = 1 ) |
Compute unlimited gradients for all triangles via Green-Gauss theorem.
For each triangle, the gradient is the area-weighted average of edge contributions: ∇h_i = (1/A_i) Σ_j h_edge_j * n_j * ξ_j
| mesh | Mesh geometry. |
| state | Surface state (reads head[], writes grad_hx[], grad_hy[]). |
| nthreads | OpenMP thread count for the per-cell loop (1 = serial). |
|
inlinenoexcept |
Depth-limited evaporation sink rate (m/s) for one cell.
Reuses the cubic Hermite wet/dry ramp applied to edge fluxes: the full demand rate applies for depth ≥ dry_depth and shuts off smoothly (C¹) as the cell dries, so evaporation can never drive a depth negative. Negative rates are treated as zero (no condensation source — use rainfall).
| rate | Evaporation demand rate (m/s). |
| depth | Current cell depth (m). |
| dry_depth | Dry-depth threshold (m). |
| std::string openswmm::twoD::format2DOptionValue | ( | const SolverOptions2D & | opts, |
| const std::string & | key ) |
Format the current value of a [2D_OPTIONS] parameter as the string token parse2DOptionsLine accepts (round-trip safe).
| opts | Solver options to read. |
| key | Parameter name (case-insensitive). |
| bool openswmm::twoD::is2DOptionKey | ( | const std::string & | key | ) |
True when key (case-insensitive) is a [2D_OPTIONS] parameter accepted by parse2DOptionsLine.
Used by the swmm_options_get_ext / swmm_options_set_ext C API to route these keys to the live SolverOptions2D (via SimulationContext::twod_io) instead of the generic ext_options map — that routing is what makes GUI/API edits of 2D options reach the solver and persist through the InpWriter [2D_OPTIONS] emission and the GeoPackage 2D_* option keys.
| std::string openswmm::twoD::load2DMeshExternalFile | ( | MeshData & | mesh, |
| SolverOptions2D & | opts, | ||
| std::vector< SurfaceRouter2D::PendingBoundaryRow > & | pending_bc_rows, | ||
| std::vector< SurfaceRouter2D::PendingEdgeConveyanceRow > & | pending_ec_rows, | ||
| const std::string & | mesh_file, | ||
| const std::string & | inp_base_dir ) |
Load 2D mesh sections from an external file.
Opens the file referenced by mesh_file (resolved relative to inp_base_dir if it is a relative path) and parses any [2D_OPTIONS], [2D_VERTICES], [2D_TRIANGLES], [2D_VERTEX_NODE_MAP], and [2D_TRIANGLE_NODE_MAP] sections found in it.
| mesh | Mesh data to populate. |
| opts | Solver options to populate. |
| mesh_file | Path from the [2D_MESH_FILE] FILE token. |
| inp_base_dir | Directory of the parent .inp file (may be empty). |
| std::unique_ptr< ISurfaceSolver > openswmm::twoD::makeSurfaceSolver | ( | const SolverOptions2D & | opts, |
| std::string * | chosen = nullptr, | ||
| int | n_cells = 0 ) |
Construct the 2D surface solver per the runtime backend policy.
Never throws on plugin absence or load failure — it resolves to the serial CPU solver instead. A successfully loaded GPU plugin is reported on stderr; the default CPU path is silent so ordinary runs produce no extra output.
| opts | Solver options (reserved for future per-model backend hints). |
| chosen | Optional out-param; receives a human-readable backend label (e.g. "cpu (serial CVODE)" or "cuda (NVIDIA A100)"). |
| n_cells | Triangle count of the mesh (0 = unknown). Under the default auto policy a mesh below the parallel-worthwhile threshold (env OPENSWMM_2D_MIN_PARALLEL_CELLS, default 20000) selects the serial CPU solver even when a GPU/OpenMP plugin is present — Kokkos' per-kernel launch overhead makes the accelerated path slower than serial on small meshes. An explicit OPENSWMM_2D_BACKEND always wins (no size gate). |
| std::string openswmm::twoD::parse2DBoundaryConditionsLine | ( | const std::vector< std::string > & | tokens, |
| std::vector< SurfaceRouter2D::PendingBoundaryRow > & | pending_rows ) |
V-E3 — parse a single line from the [2D_BOUNDARY_CONDITIONS] section into a SurfaceRouter2D::PendingBoundaryRow appended to pending_rows.
Format: TRI EDGE TYPE [PARAM_1 [PARAM_2 [GROUP]]] TYPE ∈ WALL / NORMAL_FLOW / SPECIFIED_STAGE / TS_STAGE / SPECIFIED_FLOW / TS_FLOW / RATING_CURVE PARAM_1 = slope / head / TS name / flow / TS name / curve name (by type) PARAM_2 reserved, always "*" GROUP optional named group ("*" = none)
Rows are drained into BoundaryData inside SurfaceRouter2D::initialize() after boundary_.resize() has sized the per-edge slots.
| std::string openswmm::twoD::parse2DEdgeConveyanceLine | ( | const std::vector< std::string > & | tokens, |
| std::vector< SurfaceRouter2D::PendingEdgeConveyanceRow > & | pending_rows ) |
§11A — parse a single [2D_EDGE_CONVEYANCE] line.
Format: FROM_VERTEX TO_VERTEX CONVEYANCE FROM_VERTEX, TO_VERTEX : non-negative integer mesh-vertex indices. Must differ. The pair is undirected. CONVEYANCE : double in [0, 1] (strict, clamped at parse).
Rows are accumulated into pending (a scratch buffer on SurfaceRouter2D) and resolved against the mesh topology in SurfaceRouter2D::initialize() after buildMeshTopology populates the neighbour table.
| std::string openswmm::twoD::parse2DOptionsLine | ( | const std::vector< std::string > & | tokens, |
| SolverOptions2D & | opts ) |
Parse a single line from the [2D_OPTIONS] section.
| tokens | Whitespace-split tokens from the line. |
| opts | Output solver options to populate. |
| std::string openswmm::twoD::parse2DTriangleLine | ( | const std::vector< std::string > & | tokens, |
| MeshData & | mesh ) |
Parse a single line from the [2D_TRIANGLES] section.
Format: V1 V2 V3 MANNINGS_N [TAG]
| tokens | Whitespace-split tokens from the line. |
| mesh | Mesh data to append triangle to. |
| std::string openswmm::twoD::parse2DTriangleNodeMapLine | ( | const std::vector< std::string > & | tokens, |
| MeshData & | mesh ) |
Parse a single line from the [2D_TRIANGLE_NODE_MAP] section.
Format: TRIANGLE_INDEX_OR_TAG SWMM_NODE_NAME [CD] [AREA]
| tokens | Whitespace-split tokens from the line. |
| mesh | Mesh data to update coupling map. |
| std::string openswmm::twoD::parse2DVertexLine | ( | const std::vector< std::string > & | tokens, |
| MeshData & | mesh ) |
Parse a single line from the [2D_VERTICES] section.
Format: X Y Z [TAG]
| tokens | Whitespace-split tokens from the line. |
| mesh | Mesh data to append vertex to. |
| std::string openswmm::twoD::parse2DVertexNodeMapLine | ( | const std::vector< std::string > & | tokens, |
| MeshData & | mesh ) |
Parse a single line from the [2D_VERTEX_NODE_MAP] section.
Format: VERTEX_INDEX_OR_TAG SWMM_NODE_NAME [CD] [AREA]
| tokens | Whitespace-split tokens from the line. |
| mesh | Mesh data to update coupling map. |
| void openswmm::twoD::prescan2DUnitsHeader | ( | const std::string & | inp_path, |
| SolverOptions2D & | opts ) |
Scan inp_path for a ;; UNITS: <value> comment header and set opts.mesh_units_si to true when the value names metres.
Recognised SI markers (case-insensitive): SI (m), m, metre, metres, meter, meters. Any other value (or absent header) leaves the flag unchanged.
Safe to call multiple times; e.g. once on the inline .inp and again on the resolved .2dm — the most recent observation wins, which is the intended precedence (external file overrides inline).
Quietly does nothing if the file cannot be opened — the caller already reports the missing-file error via the normal read path.
| void openswmm::twoD::rebuildActiveSet | ( | const MeshData & | mesh, |
| SurfaceStateData & | state, | ||
| const BoundaryData * | boundary, | ||
| const std::vector< CouplingPoint > * | coupling_pts, | ||
| const SolverOptions2D & | opts, | ||
| ActiveSetData & | as, | ||
| bool | live_coupling = false ) |
Rebuild the mask from the CURRENT wet set + sources. O(nt + nv), once per advance window (never per RHS evaluation). Seeds = wet cells (V > eps·A) ∪ nonzero rainfall/coupling sources (runtime forcings must already be folded into those arrays) ∪ cells with a non-WALL boundary edge. With live_coupling set, ALL coupling-point stencils are additionally force-activated: the live exchange is evaluated inside the RHS against the moving 2D head, so coupling_flux alone cannot reveal them. On the held path a zero-flux stencil contributes nothing this window by construction, so the flux seeds above are exact — and skipping the blanket activation is what keeps the active set near the wet front instead of pinning every coupled node's neighbourhood hot for the whole run. Cells that leave the active set get their edge-flux slots zeroed so stale values cannot linger in diagnostics or boundary integration.
| void openswmm::twoD::recomputeVertexZDependents | ( | MeshData & | mesh, |
| int | vidx ) |
Recompute Z-derived per-triangle / per-edge geometry for triangles incident to a vertex whose Z just changed.
Updates tri_cz (centroid Z = mean of vertex Zs) and edge_mz (per-edge midpoint Z) for every triangle that references vertex vidx. XY-derived fields (tri_area, tri_cx, tri_cy, edge_length, edge_nx, edge_ny, edge_mx, edge_my) are not affected.
Used by swmm_2d_set_vertex_z and exposed here so tests can verify the recompute logic without spinning up a full engine.
| mesh | The mesh; mesh.vz[vidx] is assumed to already hold the new Z. |
| vidx | Index of the vertex whose Z just changed. |
| void openswmm::twoD::reconstructVertexHeads | ( | const MeshData & | mesh, |
| SurfaceStateData & | state, | ||
| int | nthreads = 1 ) |
Reconstruct head values at vertices from cell-centred heads.
Evaluates: h_vertex[b] = Σ_i ω_i * h_cell[stencil_idx[i]] Uses the CSR stencil built by buildVertexStencils().
| mesh | The mesh (with stencils built). |
| state | Surface state (reads head[], writes vert_head[]). |
| nthreads | OpenMP thread count for the per-vertex loop (1 = serial). |
| void openswmm::twoD::register2DSections | ( | MeshData & | mesh, |
| SolverOptions2D & | options, | ||
| std::vector< SurfaceRouter2D::PendingBoundaryRow > & | pending_bc_rows, | ||
| std::vector< SurfaceRouter2D::PendingEdgeConveyanceRow > & | pending_ec_rows, | ||
| input::SectionRegistry & | registry ) |
Register all 2D input section handlers with the section registry.
Call during input reader setup (conditional on OPENSWMM_HAS_2D). The handlers will populate the mesh and options data in SimulationContext.
| mesh | Mesh data to populate. |
| options | Solver options to populate. |
| registry | Section registry to register handlers into. |
|
noexcept |
Scatter a signed volumetric exchange Q (m³/s) directly onto the cell derivatives ydot[] of the 2D volume ODE (for the live-RHS path).
Same upwind-HGL stencil distribution as the held-flux scatterCouplingFlux, but adds the per-cell share Q·w (Σw = 1) straight into ydot (m³/s) rather than into a coupling_flux rate, so the exchange is conservative across the stencil. Sign convention matches ydot: positive Q = source INTO the cells, negative = sink OUT of them (so the RHS passes −Q_drain for a 2D → 1D drain).
| void openswmm::twoD::seedInactiveState | ( | const MeshData & | mesh, |
| SurfaceStateData & | state, | ||
| const SolverOptions2D & | opts ) |
One-time seed: run the FULL vertex-head, gradient, limiter and edge-flux passes so every cell/vertex holds its frozen-correct dry value (dry-cell head = bed, terrain gradients, zero fluxes) before masking starts — the limiter reads inactive neighbours' gradients and the vertex reconstruction reads inactive stencil heads, so those must be exact, not initial zeros. Call from SurfaceRouter2D::initialize() and after every reinitialize().
| int openswmm::twoD::transferOutfallDischarges | ( | const std::vector< CouplingPoint > & | cps, |
| const MeshData & | mesh, | ||
| SurfaceStateData & | state, | ||
| const SimulationContext & | ctx, | ||
| const SolverOptions2D & | opts, | ||
| double | dt, | ||
| std::unordered_map< int, double > & | applied_q ) |
Transfer outfall discharges into 2D coupling cells.
After 1D routing, the outfall discharge is a source for the 2D cell at the outfall coupling point. Withdrawal (net backflow into the pipe) is capped at the water actually available in the receiving cell(s) so the held sink cannot pull cell volumes negative over the window.
| cps | Coupling points. |
| mesh | Mesh data. |
| state | 2D surface state. |
| ctx | Simulation context. |
| opts | 2D solver options (for unit-system coupling factors). |
| dt | 2D advance window (s); used for the withdrawal cap. |
| applied_q | Out: net SI exchange (m³/s, +into 2D) actually applied per outfall node index — the mass-balance ledger must book exactly these (clamped) values, not the raw 1D rates. |
| void openswmm::twoD::updateOutfallBoundaries | ( | const std::vector< CouplingPoint > & | cps, |
| const MeshData & | mesh, | ||
| const SurfaceStateData & | state, | ||
| SimulationContext & | ctx, | ||
| const SolverOptions2D & | opts ) |
Update outfall boundary depths from 2D surface heads.
For each outfall coupled to the 2D domain, sets the outfall depth to max(h_standard, h_2d) to account for dynamic tailwater from 2D flooding. Must be called before 1D routing step.
| cps | Coupling points. |
| mesh | Mesh data. |
| state | 2D surface state. |
| ctx | Simulation context. |
| opts | 2D solver options (for unit-system coupling factors). |
| std::string openswmm::twoD::validateMesh | ( | const MeshData & | mesh | ) |
Validate mesh data for consistency.
Checks: vertex indices in bounds, positive areas, no degenerate triangles.
| mesh | The mesh to validate. |