OpenSWMM Engine  6.0.0-alpha.1
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.1)
Loading...
Searching...
No Matches
NodeSubtypes.hpp
Go to the documentation of this file.
1
37
38#ifndef OPENSWMM_ENGINE_NODE_SUBTYPES_HPP
39#define OPENSWMM_ENGINE_NODE_SUBTYPES_HPP
40
41#include <algorithm>
42#include <vector>
43#include <cstdint>
44#include <string>
45
46#include "NodeData.hpp"
47
48namespace openswmm {
49
50// ============================================================================
51// StorageData — side-table for STORAGE nodes
52// ============================================================================
53
61 std::vector<int> node_idx;
62
64 std::vector<int> curve;
66 std::vector<std::string> curve_name;
68 std::vector<double> a;
70 std::vector<double> b;
72 std::vector<double> c;
74 std::vector<double> seep_rate;
76 std::vector<double> evap_frac;
78 std::vector<double> evap_loss;
80 std::vector<double> exfil_loss;
82 std::vector<double> exfil_suction;
84 std::vector<double> exfil_ksat;
86 std::vector<double> exfil_imd;
87
89 int count() const noexcept { return static_cast<int>(node_idx.size()); }
90
92 void clear() noexcept {
93 node_idx.clear(); curve.clear(); curve_name.clear();
94 a.clear(); b.clear(); c.clear();
95 seep_rate.clear(); evap_frac.clear(); evap_loss.clear(); exfil_loss.clear();
96 exfil_suction.clear(); exfil_ksat.clear(); exfil_imd.clear();
97 }
98
100 void reserve(int n) {
101 const auto un = static_cast<std::size_t>(n);
102 node_idx.reserve(un); curve.reserve(un); curve_name.reserve(un);
103 a.reserve(un); b.reserve(un); c.reserve(un);
104 seep_rate.reserve(un); evap_frac.reserve(un);
105 evap_loss.reserve(un); exfil_loss.reserve(un);
106 exfil_suction.reserve(un); exfil_ksat.reserve(un); exfil_imd.reserve(un);
107 }
108
112 int add_default(int i) {
113 const auto p = static_cast<std::ptrdiff_t>(
114 std::lower_bound(node_idx.begin(), node_idx.end(), i) - node_idx.begin());
115 node_idx.insert(node_idx.begin() + p, i);
116 curve.insert(curve.begin() + p, -1);
117 curve_name.insert(curve_name.begin() + p, std::string{});
118 a.insert(a.begin() + p, 0.0);
119 b.insert(b.begin() + p, 0.0);
120 c.insert(c.begin() + p, 0.0);
121 seep_rate.insert(seep_rate.begin() + p, 0.0);
122 evap_frac.insert(evap_frac.begin() + p, 0.0);
123 evap_loss.insert(evap_loss.begin() + p, 0.0);
124 exfil_loss.insert(exfil_loss.begin() + p, 0.0);
125 exfil_suction.insert(exfil_suction.begin() + p, 0.0);
126 exfil_ksat.insert(exfil_ksat.begin() + p, 0.0);
127 exfil_imd.insert(exfil_imd.begin() + p, 0.0);
128 return static_cast<int>(p);
129 }
130
132 void erase_at(int r) {
133 const auto p = static_cast<std::ptrdiff_t>(r);
134 node_idx.erase(node_idx.begin() + p);
135 curve.erase(curve.begin() + p);
136 curve_name.erase(curve_name.begin() + p);
137 a.erase(a.begin() + p);
138 b.erase(b.begin() + p);
139 c.erase(c.begin() + p);
140 seep_rate.erase(seep_rate.begin() + p);
141 evap_frac.erase(evap_frac.begin() + p);
142 evap_loss.erase(evap_loss.begin() + p);
143 exfil_loss.erase(exfil_loss.begin() + p);
144 exfil_suction.erase(exfil_suction.begin() + p);
145 exfil_ksat.erase(exfil_ksat.begin() + p);
146 exfil_imd.erase(exfil_imd.begin() + p);
147 }
148};
149
150// ============================================================================
151// OutfallData — side-table for OUTFALL nodes
152// ============================================================================
153
160 std::vector<int> node_idx;
161
163 std::vector<OutfallType> bc_type;
165 std::vector<double> param;
167 std::vector<uint8_t> has_flap_gate;
169 std::vector<int> route_to;
171 std::vector<int> link_idx;
173 std::vector<double> link_offset;
175 std::vector<double> head_2d;
178 std::vector<double> ramp_2d;
179
181 int count() const noexcept { return static_cast<int>(node_idx.size()); }
182
184 void clear() noexcept {
185 node_idx.clear(); bc_type.clear(); param.clear();
186 has_flap_gate.clear(); route_to.clear();
187 link_idx.clear(); link_offset.clear(); head_2d.clear();
188 ramp_2d.clear();
189 }
190
192 void reserve(int n) {
193 const auto un = static_cast<std::size_t>(n);
194 node_idx.reserve(un); bc_type.reserve(un); param.reserve(un);
195 has_flap_gate.reserve(un); route_to.reserve(un);
196 link_idx.reserve(un); link_offset.reserve(un); head_2d.reserve(un);
197 ramp_2d.reserve(un);
198 }
199
202 int add_default(int i) {
203 const auto p = static_cast<std::ptrdiff_t>(
204 std::lower_bound(node_idx.begin(), node_idx.end(), i) - node_idx.begin());
205 node_idx.insert(node_idx.begin() + p, i);
206 bc_type.insert(bc_type.begin() + p, OutfallType::FREE);
207 param.insert(param.begin() + p, 0.0);
208 has_flap_gate.insert(has_flap_gate.begin() + p, uint8_t{0});
209 route_to.insert(route_to.begin() + p, -1);
210 link_idx.insert(link_idx.begin() + p, -1);
211 link_offset.insert(link_offset.begin() + p, 0.0);
212 head_2d.insert(head_2d.begin() + p, -1.0e30);
213 ramp_2d.insert(ramp_2d.begin() + p, 0.0);
214 return static_cast<int>(p);
215 }
216
218 void erase_at(int r) {
219 const auto p = static_cast<std::ptrdiff_t>(r);
220 node_idx.erase(node_idx.begin() + p);
221 bc_type.erase(bc_type.begin() + p);
222 param.erase(param.begin() + p);
223 has_flap_gate.erase(has_flap_gate.begin() + p);
224 route_to.erase(route_to.begin() + p);
225 link_idx.erase(link_idx.begin() + p);
226 link_offset.erase(link_offset.begin() + p);
227 head_2d.erase(head_2d.begin() + p);
228 ramp_2d.erase(ramp_2d.begin() + p);
229 }
230};
231
232// ============================================================================
233// DividerData — side-table for DIVIDER nodes
234// ============================================================================
235
242 std::vector<int> node_idx;
243
245 std::vector<DividerType> method;
247 std::vector<double> cutoff;
249 std::vector<double> cd;
251 std::vector<double> max_depth;
253 std::vector<int> curve;
255 std::vector<int> link;
257 std::vector<std::string> link_name;
259 std::vector<std::string> curve_name;
260
262 int count() const noexcept { return static_cast<int>(node_idx.size()); }
263
265 void clear() noexcept {
266 node_idx.clear(); method.clear(); cutoff.clear();
267 cd.clear(); max_depth.clear(); curve.clear(); link.clear();
268 link_name.clear(); curve_name.clear();
269 }
270
272 void reserve(int n) {
273 const auto un = static_cast<std::size_t>(n);
274 node_idx.reserve(un); method.reserve(un); cutoff.reserve(un);
275 cd.reserve(un); max_depth.reserve(un); curve.reserve(un); link.reserve(un);
276 link_name.reserve(un); curve_name.reserve(un);
277 }
278
281 int add_default(int i) {
282 const auto p = static_cast<std::ptrdiff_t>(
283 std::lower_bound(node_idx.begin(), node_idx.end(), i) - node_idx.begin());
284 node_idx.insert(node_idx.begin() + p, i);
285 method.insert(method.begin() + p, DividerType::CUTOFF);
286 cutoff.insert(cutoff.begin() + p, 0.0);
287 cd.insert(cd.begin() + p, 0.0);
288 max_depth.insert(max_depth.begin() + p, 0.0);
289 curve.insert(curve.begin() + p, -1);
290 link.insert(link.begin() + p, -1);
291 link_name.insert(link_name.begin() + p, std::string{});
292 curve_name.insert(curve_name.begin() + p, std::string{});
293 return static_cast<int>(p);
294 }
295
297 void erase_at(int r) {
298 const auto p = static_cast<std::ptrdiff_t>(r);
299 node_idx.erase(node_idx.begin() + p);
300 method.erase(method.begin() + p);
301 cutoff.erase(cutoff.begin() + p);
302 cd.erase(cd.begin() + p);
303 max_depth.erase(max_depth.begin() + p);
304 curve.erase(curve.begin() + p);
305 link.erase(link.begin() + p);
306 link_name.erase(link_name.begin() + p);
307 curve_name.erase(curve_name.begin() + p);
308 }
309};
310
311// ============================================================================
312// NodeSubtypes — container + reverse map + build/verify
313// ============================================================================
314
327
329 std::vector<int> subtype_row;
330
332 void clear() noexcept {
333 storages.clear();
334 outfalls.clear();
335 dividers.clear();
336 subtype_row.clear();
337 }
338
349 void rebuild_index(int n_nodes) {
350 subtype_row.assign(static_cast<std::size_t>(n_nodes), -1);
351 for (int r = 0; r < storages.count(); ++r)
352 subtype_row[static_cast<std::size_t>(storages.node_idx[static_cast<std::size_t>(r)])] = r;
353 for (int r = 0; r < outfalls.count(); ++r)
354 subtype_row[static_cast<std::size_t>(outfalls.node_idx[static_cast<std::size_t>(r)])] = r;
355 for (int r = 0; r < dividers.count(); ++r)
356 subtype_row[static_cast<std::size_t>(dividers.node_idx[static_cast<std::size_t>(r)])] = r;
357 }
358
372 int set_node_type(NodeData& nodes, int i, NodeType t) {
373 const auto ui = static_cast<std::size_t>(i);
374 if (i >= static_cast<int>(subtype_row.size()))
375 subtype_row.resize(static_cast<std::size_t>(i) + 1, -1);
376
377 const NodeType old = nodes.type[ui];
378 const int existing = subtype_row[ui];
379 if (old == t && existing >= 0)
380 return existing; // already this subtype with a row — idempotent.
381
382 bool shifted = false;
383 if (existing >= 0) { // remove the old subtype row (real re-type/convert).
384 switch (old) {
385 case NodeType::STORAGE: storages.erase_at(existing); break;
386 case NodeType::OUTFALL: outfalls.erase_at(existing); break;
387 case NodeType::DIVIDER: dividers.erase_at(existing); break;
388 default: break;
389 }
390 shifted = true;
391 }
392
393 nodes.type[ui] = t;
394
395 int row = -1;
396 switch (t) {
397 case NodeType::STORAGE: row = storages.add_default(i);
398 if (row != storages.count() - 1) shifted = true; break;
399 case NodeType::OUTFALL: row = outfalls.add_default(i);
400 if (row != outfalls.count() - 1) shifted = true; break;
401 case NodeType::DIVIDER: row = dividers.add_default(i);
402 if (row != dividers.count() - 1) shifted = true; break;
404 default: break; // no subtype row
405 }
406
407 if (shifted) {
408 rebuild_index(nodes.count());
409 return (t == NodeType::JUNCTION) ? -1 : subtype_row[ui];
410 }
411 subtype_row[ui] = row; // O(1) ascending-parse / end-insert path
412 return row;
413 }
414
420 void erase_node(int i, int n_after) {
421 // Erase the row whose node_idx == i (in whichever table holds it).
422 auto drop = [i](auto& tbl) -> bool {
423 for (int r = 0; r < tbl.count(); ++r)
424 if (tbl.node_idx[static_cast<std::size_t>(r)] == i) { tbl.erase_at(r); return true; }
425 return false;
426 };
427 drop(storages) || drop(outfalls) || drop(dividers);
428
429 auto shift = [i](std::vector<int>& keys) {
430 for (auto& k : keys) if (k > i) --k;
431 };
432 shift(storages.node_idx);
433 shift(outfalls.node_idx);
434 shift(dividers.node_idx);
435
436 rebuild_index(n_after);
437 }
438
441 int storage_row(int i) const noexcept {
442 if (i >= 0 && i < static_cast<int>(subtype_row.size())) {
443 const int r = subtype_row[static_cast<std::size_t>(i)];
444 if (r >= 0 && r < storages.count() &&
445 storages.node_idx[static_cast<std::size_t>(r)] == i)
446 return r;
447 }
448 return -1;
449 }
450
453 int outfall_row(int i) const noexcept {
454 if (i >= 0 && i < static_cast<int>(subtype_row.size())) {
455 const int r = subtype_row[static_cast<std::size_t>(i)];
456 if (r >= 0 && r < outfalls.count() &&
457 outfalls.node_idx[static_cast<std::size_t>(r)] == i)
458 return r;
459 }
460 return -1;
461 }
462
465 int divider_row(int i) const noexcept {
466 if (i >= 0 && i < static_cast<int>(subtype_row.size())) {
467 const int r = subtype_row[static_cast<std::size_t>(i)];
468 if (r >= 0 && r < dividers.count() &&
469 dividers.node_idx[static_cast<std::size_t>(r)] == i)
470 return r;
471 }
472 return -1;
473 }
474};
475
476} // namespace openswmm
477
478#endif // OPENSWMM_ENGINE_NODE_SUBTYPES_HPP
Structure-of-Arrays (SoA) storage for all node types.
Definition NodeCoupling.cpp:15
@ FREE
Definition NodeData.hpp:55
NodeType
Node type codes.
Definition NodeData.hpp:43
@ JUNCTION
Definition NodeData.hpp:44
@ DIVIDER
Definition NodeData.hpp:46
@ STORAGE
Definition NodeData.hpp:47
@ OUTFALL
Definition NodeData.hpp:45
@ CUTOFF
Definition NodeData.hpp:67
Dense SoA for flow-divider properties (one row per DIVIDER node).
Definition NodeSubtypes.hpp:240
std::vector< double > cd
Weir discharge coefficient for WEIR dividers.
Definition NodeSubtypes.hpp:249
std::vector< std::string > link_name
Diversion link name (deferred resolution).
Definition NodeSubtypes.hpp:257
std::vector< int > curve
Diversion curve index for TABULAR dividers (-1 = none).
Definition NodeSubtypes.hpp:253
std::vector< double > cutoff
Cutoff flow for CUTOFF dividers.
Definition NodeSubtypes.hpp:247
void clear() noexcept
Drop all rows (capacity retained).
Definition NodeSubtypes.hpp:265
std::vector< DividerType > method
Diversion method (CUTOFF/OVERFLOW/TABULAR/WEIR).
Definition NodeSubtypes.hpp:245
int count() const noexcept
Number of divider rows.
Definition NodeSubtypes.hpp:262
int add_default(int i)
Insert a default divider row for base node i, keeping node_idx ascending; returns the inserted row in...
Definition NodeSubtypes.hpp:281
std::vector< double > max_depth
Weir max depth for WEIR dividers.
Definition NodeSubtypes.hpp:251
void reserve(int n)
Reserve capacity for n rows.
Definition NodeSubtypes.hpp:272
std::vector< int > link
Diversion link index (-1 = not set).
Definition NodeSubtypes.hpp:255
std::vector< std::string > curve_name
Diversion curve name (deferred resolution, TABULAR only).
Definition NodeSubtypes.hpp:259
void erase_at(int r)
Erase divider row r from every column.
Definition NodeSubtypes.hpp:297
std::vector< int > node_idx
Base NodeData index this row belongs to (the join key).
Definition NodeSubtypes.hpp:242
Structure-of-Arrays storage for all nodes.
Definition NodeData.hpp:90
int count() const noexcept
Number of nodes.
Definition NodeData.hpp:537
std::vector< NodeType > type
Node type for each node.
Definition NodeData.hpp:97
Owns the three node subtype side-tables plus the reverse index map.
Definition NodeSubtypes.hpp:323
int divider_row(int i) const noexcept
Divider side-table row for base node i, or -1 if not a divider (or the side-table is unbuilt)....
Definition NodeSubtypes.hpp:465
DividerData dividers
Definition NodeSubtypes.hpp:326
int storage_row(int i) const noexcept
Storage side-table row for base node i, or -1 if i is not a storage node (or the side-table is unbuil...
Definition NodeSubtypes.hpp:441
int set_node_type(NodeData &nodes, int i, NodeType t)
Set node i to t, creating/removing/moving its subtype row so the side-table stays the single source o...
Definition NodeSubtypes.hpp:372
void erase_node(int i, int n_after)
Drop node i's subtype row and renumber the join keys after a base node erase. Call after NodeData::er...
Definition NodeSubtypes.hpp:420
void rebuild_index(int n_nodes)
Recompute the reverse map (subtype_row) from the side-table rows.
Definition NodeSubtypes.hpp:349
void clear() noexcept
Drop all rows and the reverse map.
Definition NodeSubtypes.hpp:332
OutfallData outfalls
Definition NodeSubtypes.hpp:325
std::vector< int > subtype_row
base node index → row in its subtype table (-1 for junctions).
Definition NodeSubtypes.hpp:329
int outfall_row(int i) const noexcept
Outfall side-table row for base node i, or -1 if not an outfall (or the side-table is unbuilt)....
Definition NodeSubtypes.hpp:453
StorageData storages
Definition NodeSubtypes.hpp:324
Dense SoA for outfall boundary-condition properties (one row per OUTFALL).
Definition NodeSubtypes.hpp:158
std::vector< OutfallType > bc_type
Boundary condition type (FREE/NORMAL/FIXED/TIDAL/TIMESERIES).
Definition NodeSubtypes.hpp:163
void erase_at(int r)
Erase outfall row r from every column.
Definition NodeSubtypes.hpp:218
std::vector< int > link_idx
Cached connected-conduit index (-1 = none).
Definition NodeSubtypes.hpp:171
std::vector< uint8_t > has_flap_gate
Flap gate present (0/1).
Definition NodeSubtypes.hpp:167
void reserve(int n)
Reserve capacity for n rows.
Definition NodeSubtypes.hpp:192
std::vector< int > route_to
Subcatchment index to route discharge to (-1 = none).
Definition NodeSubtypes.hpp:169
int count() const noexcept
Number of outfall rows.
Definition NodeSubtypes.hpp:181
void clear() noexcept
Drop all rows (capacity retained).
Definition NodeSubtypes.hpp:184
std::vector< double > ramp_2d
Cached wet/dry ramp factor [0,1] for the 2D tailwater override (0 = dry → free discharge,...
Definition NodeSubtypes.hpp:178
int add_default(int i)
Insert a default outfall row for base node i, keeping node_idx ascending; returns the inserted row in...
Definition NodeSubtypes.hpp:202
std::vector< double > param
Fixed stage, or tidal/timeseries table index (per bc_type).
Definition NodeSubtypes.hpp:165
std::vector< double > head_2d
Cached 2D surface head at the coupling point (sentinel -1e30).
Definition NodeSubtypes.hpp:175
std::vector< double > link_offset
Conduit offset at the outfall end.
Definition NodeSubtypes.hpp:173
std::vector< int > node_idx
Base NodeData index this row belongs to (the join key).
Definition NodeSubtypes.hpp:160
Dense SoA for storage-unit properties (one row per STORAGE node).
Definition NodeSubtypes.hpp:59
void clear() noexcept
Drop all rows (capacity retained).
Definition NodeSubtypes.hpp:92
int add_default(int i)
Insert a default storage row for base node i, keeping node_idx ascending; returns the inserted row in...
Definition NodeSubtypes.hpp:112
int count() const noexcept
Number of storage rows.
Definition NodeSubtypes.hpp:89
void reserve(int n)
Reserve capacity for n rows.
Definition NodeSubtypes.hpp:100
std::vector< double > exfil_imd
Green-Ampt initial moisture deficit for exfiltration (0-1).
Definition NodeSubtypes.hpp:86
std::vector< double > evap_frac
Fraction of potential evaporation realized (0-1).
Definition NodeSubtypes.hpp:76
std::vector< double > exfil_suction
Green-Ampt suction head for exfiltration.
Definition NodeSubtypes.hpp:82
std::vector< double > a
Functional area parameter A.
Definition NodeSubtypes.hpp:68
std::vector< double > b
Functional area parameter B.
Definition NodeSubtypes.hpp:70
std::vector< double > seep_rate
Seepage rate (project units/day).
Definition NodeSubtypes.hpp:74
std::vector< int > node_idx
Base NodeData index this row belongs to (the join key).
Definition NodeSubtypes.hpp:61
std::vector< int > curve
Storage curve index into TableData (-1 = functional A·d^B + C).
Definition NodeSubtypes.hpp:64
std::vector< double > exfil_ksat
Green-Ampt saturated conductivity for exfiltration.
Definition NodeSubtypes.hpp:84
std::vector< double > c
Functional area parameter C (baseline area).
Definition NodeSubtypes.hpp:72
std::vector< std::string > curve_name
Curve name for deferred resolution.
Definition NodeSubtypes.hpp:66
std::vector< double > evap_loss
Evaporation loss this timestep (ft3).
Definition NodeSubtypes.hpp:78
std::vector< double > exfil_loss
Exfiltration loss this timestep (ft3).
Definition NodeSubtypes.hpp:80
void erase_at(int r)
Erase storage row r from every column.
Definition NodeSubtypes.hpp:132