OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
SurfaceRouter2D.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2//
3// Copyright 2026 Caleb Buahin
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
37
38#ifndef OPENSWMM_ENGINE_2D_SURFACE_ROUTER_HPP
39#define OPENSWMM_ENGINE_2D_SURFACE_ROUTER_HPP
40
41#include "data/MeshData.hpp"
44#include "data/BoundaryData.hpp"
47#include "gw/GwTransportData.hpp" // U4
48#include "subsurface/SubsurfaceSolver.hpp" // G1: the two-zone GW kernel
49#include "infil/Infil2D.hpp"
51
52#include <memory>
53#include <unordered_map>
54#include <unordered_set>
55#include <string>
56#include <vector>
57#ifdef OPENSWMM_HAS_2D
59#endif
60
61namespace openswmm {
63}
64
65namespace openswmm::twoD {
66
71public:
72 SurfaceRouter2D() = default;
73 ~SurfaceRouter2D() = default;
74
75 // Non-copyable, movable
80
90
106 void step(SimulationContext& ctx, double dt, double t);
107
116
126 void advancePostRouting(SimulationContext& ctx, double dt, double t);
127
136
147
154 double reportWeight(double report_ms) const noexcept;
155
158 const std::vector<double>& reportOldDepth() const noexcept {
159 return report_old_depth_;
160 }
161
162 const std::vector<double>& reportOldHead() const noexcept {
163 return report_old_head_;
164 }
165
175 void finalize(SimulationContext& ctx);
176
178 bool isActive() const noexcept { return active_; }
179
183 const std::vector<std::string>& threadWarnings() const noexcept { return thread_warnings_; }
184
190 const SimulationContext& ctx,
191 std::vector<std::pair<int, double>>& out) const;
192
204 void prepareForEdit();
205
207 const MeshData& mesh() const noexcept { return mesh_; }
208
210 MeshData& mesh() noexcept { return mesh_; }
211
213 const SurfaceStateData& state() const noexcept { return state_; }
214
216 SurfaceStateData& state() noexcept { return state_; }
217
219 const SolverOptions2D& options() const noexcept { return options_; }
220
222 SolverOptions2D& options() noexcept { return options_; }
223
225 const BoundaryData& boundary() const noexcept { return boundary_; }
226
228 BoundaryData& boundary() noexcept { return boundary_; }
229
233 void invalidateBoundaryIndex() noexcept { bc_nonwall_dirty_ = true; }
234
241 if (render_dirty_) refreshRenderFields();
242 }
243
252 Infil2D& infil() noexcept { return infil_; }
253 const Infil2D& infil() const noexcept { return infil_; }
254
258 GwTransportData& gwTransport() noexcept { return gw_; }
259 const GwTransportData& gwTransport() const noexcept { return gw_; }
260
264 SubsurfaceConfig& aquiferConfig() noexcept { return aquifer_cfg_; }
265 const SubsurfaceConfig& aquiferConfig() const noexcept { return aquifer_cfg_; }
266 std::vector<std::string>& aquiferNodeNames() noexcept {
267 return aquifer_node_names_;
268 }
269 const std::vector<std::string>& aquiferNodeNames() const noexcept {
270 return aquifer_node_names_;
271 }
272
273 SubsurfaceSolver& subsurface() noexcept { return subsurface_; }
274 const SubsurfaceSolver& subsurface() const noexcept { return subsurface_; }
275
300 const std::vector<double>& subcatchRecharge() const noexcept {
301 return subcatch_recharge_;
302 }
303
306 void drainSubcatchRecharge(std::vector<double>& out) {
307 out = subcatch_recharge_;
308 std::fill(subcatch_recharge_.begin(), subcatch_recharge_.end(), 0.0);
309 }
310
312 const std::vector<int>& cellSubcatchment() const noexcept {
313 return cell_subcatch_;
314 }
315
316 const std::vector<double>& infilCumulative() const noexcept {
317 return infil_cum_applied_;
318 }
319
329 const std::vector<double>& couplingCumulative() const noexcept {
330 return coupling_cum_applied_;
331 }
332
341 const std::vector<double>& rainCumulative() const noexcept {
342 return rain_cum_;
343 }
344
359 std::vector<PendingInitialQualityRow>& pendingInitialQualityRows() noexcept {
360 return pending_iq_rows_;
361 }
362 std::vector<PendingBoundaryQualityRow>& pendingBoundaryQualityRows() noexcept {
363 return pending_bq_rows_;
364 }
365 std::vector<PendingBoundaryRow>& pendingBCRows() noexcept { return pending_bc_rows_; }
366 const std::vector<PendingBoundaryRow>& pendingBCRows() const noexcept { return pending_bc_rows_; }
367
379 std::vector<PendingEdgeConveyanceRow>& pendingEdgeConveyanceRows() noexcept {
380 return pending_edge_conveyance_rows_;
381 }
382 const std::vector<PendingEdgeConveyanceRow>& pendingEdgeConveyanceRows() const noexcept {
383 return pending_edge_conveyance_rows_;
384 }
385
387 double totalVolume() const;
388
390 double totalExchangeFlow() const;
391#ifdef OPENSWMM_HAS_2D
393 long lastSolverSteps() const {
394 return solver_ ? solver_->last_num_steps() : 0;
395 }
396 double lastSolverStepSize() const {
397 return solver_ ? solver_->last_step_size() : 0.0;
398 }
402 ISurfaceSolver::RunStats runStats() const {
403 return solver_ ? solver_->run_stats() : ISurfaceSolver::RunStats{};
404 }
405#else
406 long lastSolverSteps() const { return 0; }
407 double lastSolverStepSize() const { return 0.0; }
408#endif
411 const std::string& backendName() const noexcept { return backend_name_; }
412
413private:
417 void drainPendingRows();
418
419 MeshData mesh_;
420 SurfaceStateData state_;
421 SolverOptions2D options_;
422 BoundaryData boundary_;
423 std::vector<std::string> thread_warnings_;
424 std::string backend_name_;
425
429 Infil2D infil_;
430
434 double infil_elapsed_ = 0.0;
435
441 std::vector<double> infil_cum_applied_;
442
447 std::vector<double> coupling_cum_applied_;
448
452 std::vector<int> cell_subcatch_;
453 std::vector<double> subcatch_recharge_;
454
456 GwTransportData gw_;
457
462 SubsurfaceConfig aquifer_cfg_;
463 std::vector<std::string> aquifer_node_names_;
464 SubsurfaceSolver subsurface_;
465
468 std::vector<double> rain_cum_;
469
471 std::vector<PendingBoundaryRow> pending_bc_rows_;
472 std::vector<PendingInitialQualityRow> pending_iq_rows_;
473 std::vector<PendingBoundaryQualityRow> pending_bq_rows_;
474
478 std::vector<PendingEdgeConveyanceRow> pending_edge_conveyance_rows_;
479
480 std::vector<CouplingPoint> coupling_points_;
484 std::vector<CouplingPoint> node_coupling_points_;
488 std::vector<double> node_row_conc_;
489 void publishNodeRows(const SimulationContext& ctx);
492 void applyAgingAndReactions(SimulationContext& ctx, double dt);
493 std::vector<double> react_phi_, react_a_, react_dx_;
494
496 double co_refresh_elapsed_ = 0.0;
502 double co_render_elapsed_ = 0.0;
503 bool render_dirty_ = false;
506 std::vector<double> render_eta_;
511 std::vector<int> bc_nonwall_slots_;
514 bool bc_nonwall_dirty_ = true;
517 std::unordered_set<int> mb_seen_nodes_;
519 double co_forcing_elapsed_ = 0.0;
520 bool co_forcing_first_ = true;
525 void coAdvanceStep(SimulationContext& ctx, double dt, double t);
529 bool refreshDue(const SimulationContext& ctx, double dt) const;
531 void refreshRenderFields();
532
533 bool active_ = false;
534 double sim_time_ = 0.0;
536 double pending_dt_ = 0.0;
537
545 std::vector<double> report_old_depth_;
546 std::vector<double> report_old_head_;
547 double report_window_old_ms_ = 0.0;
548 double report_window_new_ms_ = 0.0;
549 bool report_old_valid_ = false;
550
554 std::vector<double> ramp_prev_head_;
555 double ramp_prev_span_ = 0.0;
556
559 double prev_boundary_cum_ = 0.0;
560
564 std::vector<double> window_outfall_accum_;
569 std::vector<double> window_avail_budget_;
570
573 void resetWindowAccumulators();
576 long outfall_clamp_windows_ = 0;
577
579 double last_t_ = 0.0;
580
584 bool boundary_names_resolved_ = false;
585
591 double bc_stage_scale_ = 1.0;
592
600 double bc_stage_ts_scale_ = 1.0;
601
606 double bc_flow_scale_ = 1.0;
607#ifdef OPENSWMM_HAS_2D
611 std::unique_ptr<ISurfaceSolver> solver_;
612#endif
613
616 void updateRainfall(SimulationContext& ctx);
617
621 RainfallInterpolator interp_;
622
625 std::vector<double> rain_si_;
626
632 void resolveBoundaryValues(SimulationContext& ctx, double t);
633
639 void accumulateMassBalance(SimulationContext& ctx, double dt);
640};
641
642} // namespace openswmm::twoD
643
644#endif // OPENSWMM_ENGINE_2D_SURFACE_ROUTER_HPP
Structure-of-Arrays (SoA) storage for 2D mesh boundary conditions.
U4 (2026-09-07) — authoring state for subsurface (groundwater) transport: [GW_TRANSPORT_OPTIONS],...
Backend-neutral interface for the 2D surface-routing time integrator.
Per-cell infiltration for the 2D overland-flow mesh (track I).
Structure-of-Arrays (SoA) storage for 2D triangular mesh geometry.
Orifice-equation exchange between 2D surface and SWMM nodes.
Parse-time scratch rows for [2D_BOUNDARY_CONDITIONS] and [2D_EDGE_CONVEYANCE] input sections.
Static per-cell weights mapping raingage rainfall onto the 2D mesh.
Configuration options for the 2D surface routing solver.
G-steps 3, 6-12, 16 — the two-zone groundwater kernel: saturated FV update, lateral Darcy,...
Structure-of-Arrays (SoA) storage for 2D surface routing state.
Owns per-cell infiltration parameters, kernel state and held rates.
Definition Infil2D.hpp:181
Builds and applies static rainfall-interpolation weights for the mesh.
Definition RainfallInterpolator.hpp:60
The two-zone kernel. Owned by SurfaceRouter2D; driven by the marcher's tier hooks.
Definition SubsurfaceSolver.hpp:97
const SolverOptions2D & options() const noexcept
Access solver options (read-only).
Definition SurfaceRouter2D.hpp:219
void computeCouplingConductances(const SimulationContext &ctx, std::vector< std::pair< int, double > > &out) const
Definition SurfaceRouter2D.cpp:1564
void advancePostRouting(SimulationContext &ctx, double dt, double t)
Post-routing hook: compute coupling exchange and advance 2D solver.
Definition SurfaceRouter2D.cpp:1580
SurfaceRouter2D & operator=(const SurfaceRouter2D &)=delete
SurfaceRouter2D & operator=(SurfaceRouter2D &&)=default
const std::vector< std::string > & threadWarnings() const noexcept
Definition SurfaceRouter2D.hpp:183
twoD::PendingBoundaryRow PendingBoundaryRow
Per-row buffer for [2D_BOUNDARY_CONDITIONS] parse output.
Definition SurfaceRouter2D.hpp:355
std::vector< PendingEdgeConveyanceRow > & pendingEdgeConveyanceRows() noexcept
Definition SurfaceRouter2D.hpp:379
const std::vector< double > & infilCumulative() const noexcept
Definition SurfaceRouter2D.hpp:316
GwTransportData & gwTransport() noexcept
Definition SurfaceRouter2D.hpp:258
BoundaryData & boundary() noexcept
Access per-edge boundary-condition data (mutable, for forcing/parsing).
Definition SurfaceRouter2D.hpp:228
double reportWeight(double report_ms) const noexcept
Definition SurfaceRouter2D.cpp:1634
const SubsurfaceConfig & aquiferConfig() const noexcept
Definition SurfaceRouter2D.hpp:265
void invalidateBoundaryIndex() noexcept
Definition SurfaceRouter2D.hpp:233
SubsurfaceConfig & aquiferConfig() noexcept
Definition SurfaceRouter2D.hpp:264
long lastSolverSteps() const
Definition SurfaceRouter2D.hpp:406
const std::vector< double > & reportOldDepth() const noexcept
Definition SurfaceRouter2D.hpp:158
std::vector< PendingBoundaryRow > & pendingBCRows() noexcept
Definition SurfaceRouter2D.hpp:365
void step(SimulationContext &ctx, double dt, double t)
Advance the 2D surface routing by one SWMM routing step.
Definition SurfaceRouter2D.cpp:1170
void drainSubcatchRecharge(std::vector< double > &out)
Definition SurfaceRouter2D.hpp:306
SubsurfaceSolver & subsurface() noexcept
The running kernel. active() is false until [2D_AQUIFER] resolves.
Definition SurfaceRouter2D.hpp:273
void refreshRenderFieldsIfStale()
Definition SurfaceRouter2D.hpp:240
MeshData & mesh() noexcept
Access mesh data (mutable, for input parsing).
Definition SurfaceRouter2D.hpp:210
const std::vector< double > & rainCumulative() const noexcept
Ledger-consistent cumulative rainfall volume per cell (m³).
Definition SurfaceRouter2D.hpp:341
const std::vector< std::string > & aquiferNodeNames() const noexcept
Definition SurfaceRouter2D.hpp:269
const std::vector< double > & couplingCumulative() const noexcept
Signed cumulative coupling exchange per cell (m³).
Definition SurfaceRouter2D.hpp:329
const std::vector< double > & reportOldHead() const noexcept
Cell head (m) at the start of that batch.
Definition SurfaceRouter2D.hpp:162
const std::vector< double > & subcatchRecharge() const noexcept
Ledger-consistent cumulative infiltrated depth per cell (m).
Definition SurfaceRouter2D.hpp:300
const SurfaceStateData & state() const noexcept
Access surface state (read-only).
Definition SurfaceRouter2D.hpp:213
const Infil2D & infil() const noexcept
Definition SurfaceRouter2D.hpp:253
std::vector< PendingInitialQualityRow > & pendingInitialQualityRows() noexcept
S1/S2: raw [2D_INITIAL_QUALITY] rows, resolved at initialize().
Definition SurfaceRouter2D.hpp:359
double totalExchangeFlow() const
Get total exchange flow (sum of coupling flows, m³/s).
Definition SurfaceRouter2D.cpp:1815
const SubsurfaceSolver & subsurface() const noexcept
Definition SurfaceRouter2D.hpp:274
twoD::PendingInitialQualityRow PendingInitialQualityRow
Definition SurfaceRouter2D.hpp:356
std::vector< std::string > & aquiferNodeNames() noexcept
Definition SurfaceRouter2D.hpp:266
std::vector< PendingBoundaryQualityRow > & pendingBoundaryQualityRows() noexcept
Definition SurfaceRouter2D.hpp:362
double totalVolume() const
Get total 2D surface volume (sum of depth * area).
Definition SurfaceRouter2D.cpp:1803
const std::string & backendName() const noexcept
Definition SurfaceRouter2D.hpp:411
void initialize(SimulationContext &ctx)
Initialize the 2D module after input parsing is complete.
Definition SurfaceRouter2D.cpp:202
void flushPendingBatch(SimulationContext &ctx)
Flush the pending (partial) sync batch, if any.
Definition SurfaceRouter2D.cpp:1624
SurfaceStateData & state() noexcept
Access surface state (mutable, for forcing).
Definition SurfaceRouter2D.hpp:216
const std::vector< PendingBoundaryRow > & pendingBCRows() const noexcept
Definition SurfaceRouter2D.hpp:366
Infil2D & infil() noexcept
Access the per-cell infiltration model (plan §5.5, track I).
Definition SurfaceRouter2D.hpp:252
void updateOutfallsPreRouting(SimulationContext &ctx)
Pre-routing hook: update outfall boundaries from 2D surface heads.
Definition SurfaceRouter2D.cpp:1183
SurfaceRouter2D(const SurfaceRouter2D &)=delete
void finalize(SimulationContext &ctx)
Finalize the 2D module at simulation end.
Definition SurfaceRouter2D.cpp:1746
SurfaceRouter2D(SurfaceRouter2D &&)=default
double lastSolverStepSize() const
Definition SurfaceRouter2D.hpp:407
twoD::PendingBoundaryQualityRow PendingBoundaryQualityRow
Definition SurfaceRouter2D.hpp:357
const MeshData & mesh() const noexcept
Access mesh data (read-only).
Definition SurfaceRouter2D.hpp:207
void prepareOneShotForcing(SimulationContext &ctx)
Prepare a RESET 2D forcing to apply on the next routing step.
Definition SurfaceRouter2D.cpp:1645
bool isActive() const noexcept
Check if the 2D module is active.
Definition SurfaceRouter2D.hpp:178
const GwTransportData & gwTransport() const noexcept
Definition SurfaceRouter2D.hpp:259
SolverOptions2D & options() noexcept
Access solver options (mutable).
Definition SurfaceRouter2D.hpp:222
const BoundaryData & boundary() const noexcept
Access per-edge boundary-condition data (read-only).
Definition SurfaceRouter2D.hpp:225
twoD::PendingEdgeConveyanceRow PendingEdgeConveyanceRow
Per-row buffer for [2D_EDGE_CONVEYANCE] parse output (§11A).
Definition SurfaceRouter2D.hpp:378
const std::vector< int > & cellSubcatchment() const noexcept
Definition SurfaceRouter2D.hpp:312
const std::vector< PendingEdgeConveyanceRow > & pendingEdgeConveyanceRows() const noexcept
Definition SurfaceRouter2D.hpp:382
void prepareForEdit()
Make the parsed mesh editable without a full initialize().
Definition SurfaceRouter2D.cpp:193
Definition NodeCoupling.cpp:16
Definition NodeCoupling.cpp:16
Central, reentrant simulation context.
Definition SimulationContext.hpp:353
SoA storage for per-edge boundary conditions.
Definition BoundaryData.hpp:71
Every [GW_*] authoring row of one model.
Definition GwTransportData.hpp:180
SoA storage for 2D mixed triangle/quad mesh geometry and topology.
Definition MeshData.hpp:67
Definition PendingRows2D.hpp:101
Per-row buffer for [2D_BOUNDARY_CONDITIONS] parse output.
Definition PendingRows2D.hpp:53
Per-row buffer for [2D_EDGE_CONVEYANCE] parse output (§11A).
Definition PendingRows2D.hpp:72
One [2D_INITIAL_QUALITY] row (overland transport S1/S2).
Definition PendingRows2D.hpp:89
Configuration for the 2D surface routing solver.
Definition SolverOptions2D.hpp:208
Everything the parser fills, before resolution onto cells.
Definition SubsurfaceData.hpp:234
Definition SurfaceStateData.hpp:59