OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
SurfaceStateData.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
31
32#ifndef OPENSWMM_ENGINE_2D_SURFACE_STATE_DATA_HPP
33#define OPENSWMM_ENGINE_2D_SURFACE_STATE_DATA_HPP
34
35#include <vector>
36#include <cstring>
37#include <cmath>
38#include <limits>
39#include <algorithm>
40#include <vector>
41
44#include "SurfaceTransportState.hpp" // S1 — species mass per cell
45#include "../heat/MeshHeat.hpp"
46#include "MeshData.hpp" // kMaxCellVerts edge-slot stride
47
48namespace openswmm {
49struct NodeData;
50} // 1D node data (held during a 2D advance)
51
52namespace openswmm::twoD {
53
54struct CouplingPoint; // fwd decl — 1D↔2D coupling descriptor (NodeCoupling.hpp)
55
62struct BoundaryData; // fwd decl — per-edge boundary conditions (BoundaryData.hpp)
63
65
66 // -----------------------------------------------------------------------
67 // State variables — per triangle [0, n_triangles)
68 // -----------------------------------------------------------------------
69
77 const BoundaryData* boundary = nullptr;
78
83 const NodeData* nodes_1d = nullptr;
88 const std::vector<double>* node_row_conc = nullptr;
89 const std::vector<CouplingPoint>* node_coupling = nullptr;
95 const std::vector<double>* node_pond_base = nullptr;
98 const std::vector<int>* coupling_head_cells = nullptr;
102 const std::vector<double>* node_pond_area_m2 = nullptr;
103 double coupling_window_s = 0.0;
104
112
113 std::vector<double> depth;
114 std::vector<double> head;
115 std::vector<double> volume;
116
117 // Gradient fields (per triangle)
118 std::vector<double> grad_hx;
119 std::vector<double> grad_hy;
120 std::vector<double> grad_hx_lim;
121 std::vector<double> grad_hy_lim;
122
123 // Reconstructed head at vertices — [0, n_vertices)
124 std::vector<double> vert_head;
125
134 std::vector<double> vert_depth_signed;
135
136 // Output-only cell velocity: native FULL_SWE or wetted-edge reconstruction.
137 // Paired NaNs mark an unresolved wet-cell vector; dry cells carry zero.
138 std::vector<double> face_vx;
139 std::vector<double> face_vy;
140
141 // Per-cell continuity residual — per triangle (m³/s, ≈0 when conservative)
142 std::vector<double> cell_continuity_err;
143
144 // Fluxes — flat 2D: [cell * kMaxCellVerts + edge]
145 std::vector<double> edge_flux;
146
147 // Source/sink terms — per triangle
148 // Snow owns precipitation only on its resolved weather footprints. The
149 // context is a non-owning forcing view, like nodes_1d; it is never archived.
152 std::vector<double> snow_catch;
162 double liquidRainfall(int i) const {
163 return snow.owns(i) ? snow.liquidRates()[i] : runtime_forcings.rate(1, i, rainfall[i]);
164 }
165
173 double exposedEvaporation(int i) const {
174 return runtime_forcings.rate(2, i, evap_rate[i]) *
175 (snow.owns(i) ? snow.exposedFractions()[i] : 1.);
176 }
177 std::vector<double> rainfall;
178 std::vector<double> evap_rate;
179
187 std::vector<double> infil_rate;
188
198 std::vector<double> infil_applied;
199
200 std::vector<double> coupling_flux;
201
219 std::vector<double> coupling_applied;
220
221 // Plugin boundary transfers (m³), compacted in boundary_receipt_slots order. Allocated
222 // only by plugin solvers; additive until the router drains them into its
223 // engine-owned receipts after advance(). Separate directions preserve
224 // reversals within a window. CPU solvers book their receipts directly.
225 std::vector<int> boundary_receipt_slots;
226 std::vector<double> boundary_in_applied;
227 std::vector<double> boundary_out_applied;
228 std::vector<double> boundary_requested;
229 std::vector<double> boundary_last_flow;
230 std::vector<double> boundary_last_dt;
231
232 std::vector<double> net_source;
233
234 // -----------------------------------------------------------------------
235 // Forcing overrides (optional external control)
236 // -----------------------------------------------------------------------
237
238 std::vector<int8_t> rainfall_forced;
239 std::vector<int8_t> rainfall_persist;
240 std::vector<double> rainfall_force_val;
241 std::vector<int8_t> evap_forced;
242 std::vector<int8_t> evap_persist;
243 std::vector<double> evap_force_val;
244 std::vector<int8_t> coupling_forced;
245 std::vector<int8_t> coupling_persist;
246 std::vector<double> coupling_force_val;
247
253 // Unforced coupling is restored before each batch; ADD never compounds.
256 std::vector<double> coupling_native;
257 bool forcing_dirty = false;
258
264 bool forcing_ever_set = false;
265
266 // -----------------------------------------------------------------------
267 // Previous step state
268 // -----------------------------------------------------------------------
269
270 std::vector<double> old_depth;
271 std::vector<double> old_volume;
272
273 // -----------------------------------------------------------------------
274 // Cumulative statistics
275 // -----------------------------------------------------------------------
276
277 std::vector<double> stat_max_depth;
278 std::vector<double> stat_max_velocity;
279 std::vector<double> stat_max_cont_err;
280 std::vector<double> stat_cum_volume;
281
285 double evap_loss_total = 0.0;
288 std::vector<double> rk2_rain_pending;
289
290 // -----------------------------------------------------------------------
291 // Lifecycle
292 // -----------------------------------------------------------------------
293
306 void resize(int n_triangles, int n_vertices) {
307 heat.clear();
308 snow = {};
309 snow_context = nullptr;
310 snow_catch.clear();
311 auto nt = static_cast<std::size_t>(n_triangles);
312 auto nv = static_cast<std::size_t>(n_vertices);
313 auto n3 = nt * static_cast<std::size_t>(kMaxCellVerts);
314
315 depth.assign(nt, 0.0);
316 head.assign(nt, 0.0);
317 volume.assign(nt, 0.0);
318 grad_hx.assign(nt, 0.0);
319 grad_hy.assign(nt, 0.0);
320 grad_hx_lim.assign(nt, 0.0);
321 grad_hy_lim.assign(nt, 0.0);
322 vert_head.assign(nv, 0.0);
323 vert_depth_signed.assign(nv, 0.0);
324 face_vx.assign(nt, 0.0);
325 face_vy.assign(nt, 0.0);
326 cell_continuity_err.assign(nt, 0.0);
327 edge_flux.assign(n3, 0.0);
328 rainfall.assign(nt, 0.0);
329 evap_rate.assign(nt, 0.0);
330 infil_rate.assign(nt, 0.0);
331 infil_applied.assign(nt, 0.0);
332 coupling_applied.assign(nt, 0.0);
334 boundary_in_applied.clear();
335 boundary_out_applied.clear();
336 boundary_requested.clear();
337 boundary_last_flow.clear();
338 boundary_last_dt.clear();
339 coupling_flux.assign(nt, 0.0);
340 coupling_native.clear();
341 runtime_sources = {};
342 runtime_forcings = {};
343 rk2_rain_pending.clear();
344 net_source.assign(nt, 0.0);
345
346 rainfall_forced.assign(nt, 0);
347 rainfall_persist.assign(nt, 0);
348 rainfall_force_val.assign(nt, 0.0);
349 evap_forced.assign(nt, 0);
350 evap_persist.assign(nt, 0);
351 evap_force_val.assign(nt, 0.0);
352 coupling_forced.assign(nt, 0);
353 coupling_persist.assign(nt, 0);
354 coupling_force_val.assign(nt, 0.0);
355
356 old_depth.assign(nt, 0.0);
357 old_volume.assign(nt, 0.0);
358 stat_max_depth.assign(nt, 0.0);
359 stat_max_velocity.assign(nt, std::numeric_limits<double>::quiet_NaN());
360 stat_max_cont_err.assign(nt, 0.0);
361 stat_cum_volume.assign(nt, 0.0);
362 evap_loss_total = 0.0;
363 }
364
372 void save_state() noexcept {
373 std::memcpy(old_depth.data(), depth.data(), depth.size() * sizeof(double));
374 std::memcpy(old_volume.data(), volume.data(), volume.size() * sizeof(double));
375 }
376
384 void reset_state() noexcept {
385 std::memcpy(depth.data(), old_depth.data(), old_depth.size() * sizeof(double));
386 std::memcpy(volume.data(), old_volume.data(), old_volume.size() * sizeof(double));
387 }
388
399 void clear_reset_forcings() noexcept {
400 if (!forcing_ever_set)
401 return;
402 for (std::size_t i = 0; i < rainfall_forced.size(); ++i) {
403 if (rainfall_persist[i] == 0 && rainfall_forced[i] != 0) {
404 rainfall_forced[i] = 0;
405 rainfall_force_val[i] = 0.0;
406 forcing_dirty = true;
407 }
408 if (evap_persist[i] == 0 && evap_forced[i] != 0) {
409 evap_forced[i] = 0;
410 evap_force_val[i] = 0.0;
411 forcing_dirty = true;
412 }
413 if (coupling_persist[i] == 0 && coupling_forced[i] != 0) {
414 coupling_forced[i] = 0;
415 coupling_force_val[i] = 0.0;
416 forcing_dirty = true;
417 }
418 }
419 }
420
440 void update_statistics([[maybe_unused]] const std::vector<double>& tri_area, double dt,
441 [[maybe_unused]] int nthreads = 1) noexcept {
442 // Each cell updates only its own envelope slots (max/cum into [i]);
443 // schedule(static) keeps this bit-identical to serial for any thread
444 // count. int loop index for OpenMP canonical-loop form.
445 const int n = static_cast<int>(depth.size());
446#if defined(SWMM_USE_OPENMP)
447#pragma omp parallel for schedule(static) num_threads(nthreads)
448#endif
449 for (int i = 0; i < n; ++i) {
450 if (depth[i] > stat_max_depth[i])
451 stat_max_depth[i] = depth[i];
452
453 const double speed = std::sqrt(face_vx[i] * face_vx[i] + face_vy[i] * face_vy[i]);
454 if (std::isfinite(speed) &&
455 (!std::isfinite(stat_max_velocity[i]) || speed > stat_max_velocity[i]))
456 stat_max_velocity[i] = speed;
457
458 const double aerr = std::abs(cell_continuity_err[i]);
459 if (aerr > stat_max_cont_err[i])
460 stat_max_cont_err[i] = aerr;
461
462 // Cell water volume × dt (VFR: V is the integrated state, not h̄·A).
463 stat_cum_volume[i] += volume[i] * dt;
464 }
465 }
466};
467
468} // namespace openswmm::twoD
469
470#endif // OPENSWMM_ENGINE_2D_SURFACE_STATE_DATA_HPP
Structure-of-Arrays (SoA) storage for 2D triangular mesh geometry.
Mesh thermal state, including bed energy retained through surface drying.
Snow state and advancement for mesh cells.
Runtime coupling state and canonical transport exchange quantities.
Overland transport S1 — per-cell species MASS on the 2D surface.
Owned mixed degree-day/UEB snow on remaining mesh weather footprints. Geometry area is horizontal m2;...
Definition MeshSnow.hpp:54
Definition ExchangeLaw.hpp:60
constexpr int kMaxCellVerts
Definition MeshData.hpp:49
Definition ExchangeLaw.hpp:60
Structure-of-Arrays storage for all nodes.
Definition NodeData.hpp:125
Central, reentrant simulation context.
Definition SimulationContext.hpp:390
SoA storage for per-edge boundary conditions.
Definition BoundaryData.hpp:73
Descriptor for a single coupling point between 2D and 1D.
Definition NodeCoupling.hpp:59
Definition MeshHeat.hpp:27
Definition RuntimeCoupling.hpp:226
Definition RuntimeCoupling.hpp:44
Definition SurfaceStateData.hpp:64
std::vector< double > rk2_rain_pending
Definition SurfaceStateData.hpp:288
std::vector< double > grad_hy_lim
Limited gradient Y.
Definition SurfaceStateData.hpp:121
std::vector< double > infil_rate
Definition SurfaceStateData.hpp:187
std::vector< double > grad_hy
∂h/∂y (unlimited gradient)
Definition SurfaceStateData.hpp:119
void save_state() noexcept
Save the current depth and conserved-volume arrays for local rollback.
Definition SurfaceStateData.hpp:372
std::vector< int8_t > coupling_forced
0=computed, 1=override, 2=add
Definition SurfaceStateData.hpp:244
std::vector< double > coupling_flux
Exchange with SWMM node (m/s, + = into 2D)
Definition SurfaceStateData.hpp:200
bool forcing_ever_set
Definition SurfaceStateData.hpp:264
std::vector< double > vert_depth_signed
Definition SurfaceStateData.hpp:134
MeshHeatState heat
Definition SurfaceStateData.hpp:111
std::vector< int8_t > rainfall_forced
0=computed, 1=override, 2=add
Definition SurfaceStateData.hpp:238
RuntimeSources runtime_sources
Definition SurfaceStateData.hpp:254
double evap_loss_total
Definition SurfaceStateData.hpp:285
std::vector< double > stat_max_depth
Maximum depth ψ_o seen at each cell (m)
Definition SurfaceStateData.hpp:277
std::vector< double > cell_continuity_err
Definition SurfaceStateData.hpp:142
std::vector< double > net_source
Net source/sink per cell (m/s)
Definition SurfaceStateData.hpp:232
SurfaceTransportState transport
Definition SurfaceStateData.hpp:110
SimulationContext * snow_context
Definition SurfaceStateData.hpp:151
std::vector< double > rainfall_force_val
Forced rainfall value.
Definition SurfaceStateData.hpp:240
std::vector< double > stat_max_cont_err
Max |cell_continuity_err| (m³/s)
Definition SurfaceStateData.hpp:279
std::vector< double > stat_cum_volume
Cumulative volume through cell (m³)
Definition SurfaceStateData.hpp:280
std::vector< int8_t > evap_persist
0=reset, 1=persist
Definition SurfaceStateData.hpp:242
void clear_reset_forcings() noexcept
Clear RESET forcings after each step.
Definition SurfaceStateData.hpp:399
bool forcing_dirty
Definition SurfaceStateData.hpp:257
const std::vector< double > * node_row_conc
Definition SurfaceStateData.hpp:88
std::vector< double > depth
Mean wetted depth h̄ = V/A_wet (m) [reconstructed].
Definition SurfaceStateData.hpp:113
std::vector< double > boundary_requested
signed cumulative request pending receipt drain
Definition SurfaceStateData.hpp:228
std::vector< double > face_vx
Cell velocity X component (m/s)
Definition SurfaceStateData.hpp:138
std::vector< double > grad_hx
∂h/∂x (unlimited gradient)
Definition SurfaceStateData.hpp:118
const std::vector< CouplingPoint > * node_coupling
Definition SurfaceStateData.hpp:89
const std::vector< int > * coupling_head_cells
Definition SurfaceStateData.hpp:98
std::vector< double > rainfall
Raw precipitation intensity (m/s)
Definition SurfaceStateData.hpp:177
std::vector< double > volume
Cell water volume V (m³) — the integrated state.
Definition SurfaceStateData.hpp:115
double exposedEvaporation(int i) const
Resolve atmospheric evaporation demand over the snow-exposed surface.
Definition SurfaceStateData.hpp:173
std::vector< double > coupling_force_val
Forced coupling value.
Definition SurfaceStateData.hpp:246
std::vector< double > evap_force_val
Forced evaporation value.
Definition SurfaceStateData.hpp:243
std::vector< double > vert_head
Head reconstructed at vertices.
Definition SurfaceStateData.hpp:124
std::vector< int8_t > evap_forced
0=computed, 1=override, 2=add
Definition SurfaceStateData.hpp:241
std::vector< double > snow_catch
Definition SurfaceStateData.hpp:152
void reset_state() noexcept
Restore only the saved depth and conserved-volume arrays.
Definition SurfaceStateData.hpp:384
std::vector< double > boundary_out_applied
Definition SurfaceStateData.hpp:227
std::vector< int > boundary_receipt_slots
padded edge slot for each transfer entry
Definition SurfaceStateData.hpp:225
std::vector< double > head
Free-surface elevation η (m) [reconstructed].
Definition SurfaceStateData.hpp:114
std::vector< double > grad_hx_lim
Limited gradient X.
Definition SurfaceStateData.hpp:120
const NodeData * nodes_1d
Definition SurfaceStateData.hpp:83
std::vector< int8_t > coupling_persist
0=reset, 1=persist
Definition SurfaceStateData.hpp:245
void resize(int n_triangles, int n_vertices)
Reset main surface hydraulic arrays to a new mixed-cell/vertex extent.
Definition SurfaceStateData.hpp:306
surface::MeshSnow snow
Definition SurfaceStateData.hpp:150
std::vector< double > boundary_last_flow
last applied substep flow (m³/s)
Definition SurfaceStateData.hpp:229
std::vector< double > face_vy
Cell velocity Y component (m/s)
Definition SurfaceStateData.hpp:139
std::vector< double > coupling_applied
Definition SurfaceStateData.hpp:219
std::vector< double > evap_rate
Evaporation demand rate (m/s, >= 0)
Definition SurfaceStateData.hpp:178
std::vector< double > stat_max_velocity
Max cell speed |v| = √(vx²+vy²) (m/s)
Definition SurfaceStateData.hpp:278
const BoundaryData * boundary
Definition SurfaceStateData.hpp:77
std::vector< double > old_depth
Mean depth at start of coupling interval.
Definition SurfaceStateData.hpp:270
std::vector< int8_t > rainfall_persist
0=reset, 1=persist
Definition SurfaceStateData.hpp:239
RuntimeForcings runtime_forcings
Definition SurfaceStateData.hpp:255
std::vector< double > old_volume
Volume at start of coupling interval (m³)
Definition SurfaceStateData.hpp:271
const std::vector< double > * node_pond_area_m2
Definition SurfaceStateData.hpp:102
const std::vector< double > * node_pond_base
Definition SurfaceStateData.hpp:95
void update_statistics(const std::vector< double > &tri_area, double dt, int nthreads=1) noexcept
Update cumulative statistics / rendering envelopes.
Definition SurfaceStateData.hpp:440
std::vector< double > boundary_in_applied
Definition SurfaceStateData.hpp:226
std::vector< double > coupling_native
Definition SurfaceStateData.hpp:256
std::vector< double > edge_flux
Normal flux through each edge.
Definition SurfaceStateData.hpp:145
std::vector< double > boundary_last_dt
last boundary substep duration (s)
Definition SurfaceStateData.hpp:230
double liquidRainfall(int i) const
Resolve the liquid-water precipitation source for one cell.
Definition SurfaceStateData.hpp:162
std::vector< double > infil_applied
Definition SurfaceStateData.hpp:198
double coupling_window_s
Definition SurfaceStateData.hpp:103
Definition SurfaceTransportState.hpp:70