OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
RuntimeCoupling.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2
11
12#ifndef OPENSWMM_RUNTIME_COUPLING_HPP
13#define OPENSWMM_RUNTIME_COUPLING_HPP
14#include <algorithm>
15#include <array>
16#include <unordered_map>
17#include <cmath>
18#include <limits>
19#include <string>
20#include <vector>
21
22namespace openswmm::twoD {
23// Transport rows store concentration * SI volume, including temperature-volume.
24// Heat receipts use sensible energy relative to 0 C; no soil energy is implied.
25inline constexpr double runtimeWaterHeatCapacity = 4186000.0; // J/(m3 K)
27 double requested = 0.0, applied = 0.0;
28 double water_in = 0.0, water_out = 0.0;
29 double heat_requested = 0.0, heat_applied = 0.0;
30 double last_flow = 0.0, last_dt = 0.0;
31 std::vector<double> requested_mass, applied_mass;
32};
34 std::string id, owner;
35 int cell = -1;
36 double flow = 0.0, heat = 0.0;
37 int boundary_edge = -1;
38 double boundary_head = std::numeric_limits<double>::quiet_NaN();
39 double until = std::numeric_limits<double>::infinity();
40 bool enabled = true;
41 std::vector<double> concentrations, rates;
43};
45 std::vector<RuntimeSource> rows;
46 std::vector<std::vector<std::size_t>> cells;
47 std::unordered_map<std::string, std::unordered_map<int, std::size_t>> index;
56 RuntimeSource* find(const std::string& id, int cell) {
57 const auto a = index.find(id);
58 if (a == index.end())
59 return nullptr;
60 const auto b = a->second.find(cell);
61 return b == a->second.end() ? nullptr : &rows[b->second];
62 }
63
71 const RuntimeSource* find(const std::string& id, int cell) const {
72 return const_cast<RuntimeSources*>(this)->find(id, cell);
73 }
74
85 void rebuild(int count) {
86 cells.assign(count, {});
87 for (std::size_t k = 0; k < rows.size(); ++k)
88 if (rows[k].enabled)
89 cells.at(rows[k].cell).push_back(k);
90 }
91
102 void replace(RuntimeSource value) {
103 if (auto* row = find(value.id, value.cell)) {
104 value.receipt = std::move(row->receipt);
105 *row = std::move(value);
106 return;
107 }
108 index[value.id][value.cell] = rows.size();
109 value.receipt.requested_mass.assign(value.concentrations.size(), 0.0);
110 value.receipt.applied_mass.assign(value.concentrations.size(), 0.0);
111 rows.push_back(std::move(value));
112 }
113
119 void prune() noexcept {
120 for (auto& cell : cells)
121 cell.erase(std::remove_if(cell.begin(), cell.end(),
122 [this](auto k) { return !rows[k].enabled; }),
123 cell.end());
124 }
125
135 bool clear(const std::string& id, int cell = -1) noexcept {
136 const auto found = index.find(id);
137 if (found == index.end())
138 return false;
139 if (cell >= 0) {
140 auto* row = find(id, cell);
141 if (!row)
142 return false;
143 row->enabled = false;
144 if (cell < static_cast<int>(cells.size())) {
145 auto& active = cells[cell];
146 active.erase(std::remove_if(active.begin(), active.end(),
147 [this](auto k) { return !rows[k].enabled; }),
148 active.end());
149 }
150 return true;
151 } else
152 for (const auto& entry : found->second)
153 rows[entry.second].enabled = false;
154 prune();
155 return true;
156 }
157
166 void syncReceipts(const RuntimeSources& old) {
167 for (auto& row : rows)
168 if (const auto* previous = old.find(row.id, row.cell))
169 row.receipt = previous->receipt;
170 }
171
177 bool active() const {
178 for (const auto& r : rows)
179 if (r.enabled)
180 return true;
181 return false;
182 }
183
191 double nextTime(double now) const {
192 double next = std::numeric_limits<double>::infinity();
193 for (const auto& r : rows)
194 if (r.enabled && r.until > now)
195 next = std::min(next, r.until);
196 return next;
197 }
198
205 bool expire(double now) {
206 bool changed = false;
207 for (auto& r : rows)
208 if (r.enabled && r.until <= now) {
209 r.enabled = false;
210 changed = true;
211 }
212 if (changed)
213 prune();
214 return changed;
215 }
216};
217// Runtime forcing channels: rain, evaporation, paired infiltration, rain quality.
219 int channel = 0, cell = -1, mode = 1;
220 double rate = 0.0, until = std::numeric_limits<double>::infinity();
221 bool enabled = true;
222 std::string owner;
223 std::vector<double> concentrations;
225};
227 std::vector<RuntimeForcing> rows;
228 std::vector<std::array<int, 4>> cells;
229 std::array<int, 4> uniform{{-1, -1, -1, -1}};
230 std::unordered_map<int, std::unordered_map<int, std::size_t>> index;
239 RuntimeForcing* find(int channel, int cell) {
240 auto a = index.find(channel);
241 if (a == index.end())
242 return nullptr;
243 auto b = a->second.find(cell);
244 return b == a->second.end() ? nullptr : &rows[b->second];
245 }
246
256 const RuntimeForcing* get(int channel, int cell) const noexcept {
257 int k = cell >= 0 && cell < static_cast<int>(cells.size()) ? cells[cell][channel - 1] : -1;
258 if (k < 0 || !rows[k].enabled)
259 k = uniform[channel - 1];
260 return k >= 0 && rows[k].enabled ? &rows[k] : nullptr;
261 }
262
271 double rate(int channel, int cell, double native) const noexcept {
272 const auto* row = get(channel, cell);
273 return !row ? native : row->mode == 2 ? native + row->rate : row->rate;
274 }
275
286 if (auto* old = find(row.channel, row.cell)) {
287 row.receipt = std::move(old->receipt);
288 *old = std::move(row);
289 } else {
290 index[row.channel][row.cell] = rows.size();
291 rows.push_back(std::move(row));
292 }
293 }
294
304 void rebuild(int count) {
305 cells.assign(count, {{-1, -1, -1, -1}});
306 uniform = {{-1, -1, -1, -1}};
307 for (std::size_t k = 0; k < rows.size(); ++k)
308 if (rows[k].enabled) {
309 const auto& row = rows[k];
310 if (row.cell < 0)
311 uniform[row.channel - 1] = static_cast<int>(k);
312 else
313 cells.at(row.cell)[row.channel - 1] = static_cast<int>(k);
314 }
315 }
316
322 bool active() const noexcept {
323 for (const auto& row : rows)
324 if (row.enabled)
325 return true;
326 return false;
327 }
328
336 double nextTime(double now) const noexcept {
337 double time = std::numeric_limits<double>::infinity();
338 for (const auto& row : rows)
339 if (row.enabled && row.until > now)
340 time = std::min(time, row.until);
341 return time;
342 }
343
350 void expire(double now) noexcept {
351 for (auto& row : rows)
352 if (row.enabled && row.until <= now)
353 row.enabled = false;
354 }
355};
356} // namespace openswmm::twoD
357#endif
Definition ExchangeLaw.hpp:60
constexpr double runtimeWaterHeatCapacity
Definition RuntimeCoupling.hpp:25
Definition RuntimeCoupling.hpp:218
int cell
Definition RuntimeCoupling.hpp:219
std::vector< double > concentrations
Definition RuntimeCoupling.hpp:223
double until
Definition RuntimeCoupling.hpp:220
std::string owner
Definition RuntimeCoupling.hpp:222
RuntimeReceipt receipt
Definition RuntimeCoupling.hpp:224
int mode
Definition RuntimeCoupling.hpp:219
double rate
Definition RuntimeCoupling.hpp:220
bool enabled
Definition RuntimeCoupling.hpp:221
int channel
Definition RuntimeCoupling.hpp:219
Definition RuntimeCoupling.hpp:226
std::vector< std::array< int, 4 > > cells
Definition RuntimeCoupling.hpp:228
double rate(int channel, int cell, double native) const noexcept
Resolve a forced scalar rate from a native value.
Definition RuntimeCoupling.hpp:271
const RuntimeForcing * get(int channel, int cell) const noexcept
Resolve enabled cell-specific forcing with uniform fallback.
Definition RuntimeCoupling.hpp:256
std::vector< RuntimeForcing > rows
Definition RuntimeCoupling.hpp:227
void expire(double now) noexcept
Disable all enabled prescriptions whose expiry has been reached.
Definition RuntimeCoupling.hpp:350
bool active() const noexcept
Test whether any retained runtime prescription is enabled.
Definition RuntimeCoupling.hpp:322
void rebuild(int count)
Rebuild channel/cell and uniform forcing gather indices.
Definition RuntimeCoupling.hpp:304
std::unordered_map< int, std::unordered_map< int, std::size_t > > index
Definition RuntimeCoupling.hpp:230
std::array< int, 4 > uniform
Definition RuntimeCoupling.hpp:229
double nextTime(double now) const noexcept
Find the next enabled prescription expiry strictly after now.
Definition RuntimeCoupling.hpp:336
RuntimeForcing * find(int channel, int cell)
Find an exact channel/cell forcing row, including disabled retained rows.
Definition RuntimeCoupling.hpp:239
void replace(RuntimeForcing row)
Upsert one forcing prescription while retaining its accumulated receipt.
Definition RuntimeCoupling.hpp:285
Definition RuntimeCoupling.hpp:26
double last_dt
Definition RuntimeCoupling.hpp:30
double last_flow
Definition RuntimeCoupling.hpp:30
std::vector< double > requested_mass
Definition RuntimeCoupling.hpp:31
double requested
Definition RuntimeCoupling.hpp:27
double applied
Definition RuntimeCoupling.hpp:27
double heat_requested
Definition RuntimeCoupling.hpp:29
double water_out
Definition RuntimeCoupling.hpp:28
double heat_applied
Definition RuntimeCoupling.hpp:29
double water_in
Definition RuntimeCoupling.hpp:28
std::vector< double > applied_mass
Definition RuntimeCoupling.hpp:31
Definition RuntimeCoupling.hpp:33
double flow
Definition RuntimeCoupling.hpp:36
bool enabled
Definition RuntimeCoupling.hpp:40
double boundary_head
Definition RuntimeCoupling.hpp:38
int boundary_edge
Definition RuntimeCoupling.hpp:37
std::vector< double > rates
Definition RuntimeCoupling.hpp:41
RuntimeReceipt receipt
Definition RuntimeCoupling.hpp:42
int cell
Definition RuntimeCoupling.hpp:35
std::vector< double > concentrations
Definition RuntimeCoupling.hpp:41
std::string owner
Definition RuntimeCoupling.hpp:34
double until
Definition RuntimeCoupling.hpp:39
std::string id
Definition RuntimeCoupling.hpp:34
double heat
Definition RuntimeCoupling.hpp:36
Definition RuntimeCoupling.hpp:44
bool clear(const std::string &id, int cell=-1) noexcept
Disable one source-cell key or every cell belonging to a source id.
Definition RuntimeCoupling.hpp:135
std::unordered_map< std::string, std::unordered_map< int, std::size_t > > index
Definition RuntimeCoupling.hpp:47
const RuntimeSource * find(const std::string &id, int cell) const
Find a source prescription by its exact registry key.
Definition RuntimeCoupling.hpp:71
bool expire(double now)
Disable all enabled prescriptions whose expiry has been reached.
Definition RuntimeCoupling.hpp:205
void syncReceipts(const RuntimeSources &old)
Copy matching accepted receipts into a staged source registry.
Definition RuntimeCoupling.hpp:166
bool active() const
Test whether any retained runtime prescription is enabled.
Definition RuntimeCoupling.hpp:177
void rebuild(int count)
Recreate enabled source-to-cell gather indices.
Definition RuntimeCoupling.hpp:85
void replace(RuntimeSource value)
Upsert a source prescription while preserving accumulated receipts.
Definition RuntimeCoupling.hpp:102
double nextTime(double now) const
Find the next enabled prescription expiry strictly after now.
Definition RuntimeCoupling.hpp:191
RuntimeSource * find(const std::string &id, int cell)
Find a source prescription by its exact registry key.
Definition RuntimeCoupling.hpp:56
std::vector< std::vector< std::size_t > > cells
Definition RuntimeCoupling.hpp:46
std::vector< RuntimeSource > rows
Definition RuntimeCoupling.hpp:45
void prune() noexcept
Remove disabled row offsets from every cell gather list.
Definition RuntimeCoupling.hpp:119