OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
GwSourceForcing.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2
11
12#ifndef OPENSWMM_GW_SOURCE_FORCING_HPP
13#define OPENSWMM_GW_SOURCE_FORCING_HPP
14#include <algorithm>
15#include <cmath>
16#include <memory>
17#include <string>
18#include <utility>
19#include <vector>
20namespace openswmm::twoD {
21// Immutable linear series in elapsed simulation seconds. Endpoint hold matches
22// the standard SWMM continuous table lookup. Empty times denotes a constant.
24 std::vector<double> times, values;
25 bool hasNegative = false;
26};
28 double constant = 0.0;
29 // Inline vectors support small programmatic signals; resolved named
30 // series share one immutable allocation across all cell source rows.
31 std::vector<double> times, values;
32 std::shared_ptr<const GwSourceSeries> series;
40 const std::vector<double>& timePoints() const noexcept {
41 return series ? series->times : times;
42 }
43
50 const std::vector<double>& ordinates() const noexcept {
51 return series ? series->values : values;
52 }
53
63 double at(double t) const noexcept {
64 const auto& times = timePoints();
65 const auto& values = ordinates();
66 if (times.empty())
67 return constant;
68 if (t <= times.front())
69 return values.front();
70 if (t >= times.back())
71 return values.back();
72 const auto hi = std::upper_bound(times.begin(), times.end(), t);
73 const auto i = static_cast<std::size_t>(hi - times.begin());
74 const double f = (t - times[i - 1]) / (times[i] - times[i - 1]);
75 return values[i - 1] + f * (values[i] - values[i - 1]);
76 }
77};
79 int row = -1;
80 bool massRate = false; // pollutant native mass/s, converted by massScale
81 double massScale = 1.0;
83};
85 std::string name;
86 double scale = 1.0;
88 std::vector<std::pair<int, double>> cells; // active cell, share of TOTAL source
89 std::vector<GwResolvedSourceTerm> terms;
90};
92 double in = 0.0, out = 0.0; // separately integrated positive/negative flow
93 std::vector<double> mass;
94};
95// Exact integral on each common linear interval, including sign changes in
96// flow. CONC only enters on injection; extraction carries in-situ dissolved
97// quality. MASS is an independent nonnegative mass loading (also at Q=0).
119inline void integrateGwSource(const GwResolvedSource& s, double t, double dt, double weight,
120 GwSourcePulse& pulse) {
121 if (!(dt > 0) || !(weight > 0) || !(s.scale > 0))
122 return;
123 const double end = t + dt, scale = weight * s.scale;
124 std::vector<double> knots{t, end};
125 auto add = [&](const GwSourceSignal& v) {
126 const auto& times = v.timePoints();
127 for (auto it = std::upper_bound(times.begin(), times.end(), t);
128 it != times.end() && *it < end; ++it)
129 knots.push_back(*it);
130 };
131 add(s.flow);
132 for (const auto& term : s.terms)
133 add(term.signal);
134 std::sort(knots.begin(), knots.end());
135 knots.erase(std::unique(knots.begin(), knots.end()), knots.end());
136 for (std::size_t i = 1; i < knots.size(); ++i) {
137 const double a = knots[i - 1], b = knots[i], qa = s.flow.at(a), qb = s.flow.at(b);
138 std::vector<double> cuts{a, b};
139 if ((qa < 0 && qb > 0) || (qa > 0 && qb < 0))
140 cuts.insert(cuts.begin() + 1, a + (b - a) * (-qa) / (qb - qa));
141 for (std::size_t k = 1; k < cuts.size(); ++k) {
142 const double lo = cuts[k - 1], hi = cuts[k], h = hi - lo, q0 = s.flow.at(lo),
143 q1 = s.flow.at(hi);
144 const double volume = .5 * (q0 + q1) * h * scale;
145 if (volume >= 0)
146 pulse.in += volume;
147 else
148 pulse.out -= volume;
149 for (const auto& term : s.terms) {
150 if (term.row < 0 || static_cast<std::size_t>(term.row) >= pulse.mass.size())
151 continue;
152 const double c0 = term.signal.at(lo), c1 = term.signal.at(hi);
153 double m = 0;
154 if (term.massRate)
155 m = .5 * (c0 + c1) * h * term.massScale;
156 else if (volume > 0)
157 m = h * (2 * q0 * c0 + q0 * c1 + q1 * c0 + 2 * q1 * c1) / 6;
158 pulse.mass[static_cast<std::size_t>(term.row)] += m * scale;
159 }
160 }
161 }
162}
163} // namespace openswmm::twoD
164#endif
Definition ExchangeLaw.hpp:60
void integrateGwSource(const GwResolvedSource &s, double t, double dt, double weight, GwSourcePulse &pulse)
Accumulate signed water and injection/load species forcing over linear intervals.
Definition GwSourceForcing.hpp:119
Definition GwSourceForcing.hpp:84
std::string name
Definition GwSourceForcing.hpp:85
std::vector< std::pair< int, double > > cells
Definition GwSourceForcing.hpp:88
GwSourceSignal flow
Definition GwSourceForcing.hpp:87
double scale
Definition GwSourceForcing.hpp:86
std::vector< GwResolvedSourceTerm > terms
Definition GwSourceForcing.hpp:89
Definition GwSourceForcing.hpp:78
bool massRate
Definition GwSourceForcing.hpp:80
double massScale
Definition GwSourceForcing.hpp:81
int row
Definition GwSourceForcing.hpp:79
GwSourceSignal signal
Definition GwSourceForcing.hpp:82
Definition GwSourceForcing.hpp:91
std::vector< double > mass
Definition GwSourceForcing.hpp:93
double out
Definition GwSourceForcing.hpp:92
double in
Definition GwSourceForcing.hpp:92
Definition GwSourceForcing.hpp:23
std::vector< double > values
Definition GwSourceForcing.hpp:24
bool hasNegative
Definition GwSourceForcing.hpp:25
std::vector< double > times
Definition GwSourceForcing.hpp:24
Definition GwSourceForcing.hpp:27
double at(double t) const noexcept
Evaluate a constant or piecewise-linear signal with endpoint hold.
Definition GwSourceForcing.hpp:63
const std::vector< double > & timePoints() const noexcept
Borrow the signal's elapsed-second knot vector.
Definition GwSourceForcing.hpp:40
double constant
Definition GwSourceForcing.hpp:28
const std::vector< double > & ordinates() const noexcept
Borrow ordinates associated with timePoints().
Definition GwSourceForcing.hpp:50
std::shared_ptr< const GwSourceSeries > series
Definition GwSourceForcing.hpp:32
std::vector< double > values
Definition GwSourceForcing.hpp:31
std::vector< double > times
Definition GwSourceForcing.hpp:31