45#ifndef OPENSWMM_QUALITY_LARD_SEGMENT_STORE_HPP
46#define OPENSWMM_QUALITY_LARD_SEGMENT_STORE_HPP
83 a.fixed(head_, count_, vol_, conc_);
84 for (
int l = 0; l < nl_; ++l)
85 if (head_[l] < 0 || head_[l] >= cap_ || count_[l] < 0 || count_[l] > cap_)
86 throw std::runtime_error(
"Invalid LARD checkpoint ring.");
88 if (!std::isfinite(v) || v < 0)
89 throw std::runtime_error(
"Invalid LARD checkpoint water volume.");
90 for (
double v : conc_)
91 if (!std::isfinite(v))
92 throw std::runtime_error(
"Nonfinite LARD checkpoint concentration.");
110 const std::size_t slab =
static_cast<std::size_t
>(nl_) *
static_cast<std::size_t
>(cap_);
111 head_.assign(
static_cast<std::size_t
>(nl_), 0);
112 count_.assign(
static_cast<std::size_t
>(nl_), 0);
113 vol_.assign(slab, 0.0);
114 conc_.assign(slab *
static_cast<std::size_t
>(ns_ > 0 ? ns_ : 1), 0.0);
122 int count(
int l)
const {
return count_[
static_cast<std::size_t
>(l)]; }
142 for (
int i = 0; i <
count(l); ++i)
143 v += vol_[phys(l, i)];
153 double seg_volume(
int l,
int i)
const {
return vol_[phys(l, i)]; }
162 double seg_conc(
int l,
int i,
int s)
const {
return conc_[cidx(l, i, s)]; }
175 void set_seg_conc(
int l,
int i,
int s,
double c) { conc_[cidx(l, i, s)] = c; }
189 for (
int s = 0; s < ns_; ++s)
192 for (
int i = 0; i <
count(l); ++i) {
193 const double sv = vol_[phys(l, i)];
195 for (
int s = 0; s < ns_; ++s)
196 out[s] += sv * conc_[cidx(l, i, s)];
199 for (
int s = 0; s < ns_; ++s)
212 head_[
static_cast<std::size_t
>(l)] = 0;
213 count_[
static_cast<std::size_t
>(l)] = 0;
235 double drain_back(
int l,
double vol_target,
double* mass_out) {
236 double drained = 0.0;
237 while (vol_target - drained > 0.0 &&
count(l) > 0) {
238 const int i =
count(l) - 1;
239 const std::size_t p = phys(l, i);
240 const double take = std::min(vol_[p], vol_target - drained);
241 for (
int s = 0; s < ns_; ++s)
242 mass_out[s] += take * conc_[cidx(l, i, s)];
246 count_[
static_cast<std::size_t
>(l)] -= 1;
268 double drained = 0.0;
269 while (vol_target - drained > 0.0 &&
count(l) > 0) {
270 const std::size_t p = phys(l, 0);
271 const double take = std::min(vol_[p], vol_target - drained);
272 for (
int s = 0; s < ns_; ++s)
273 mass_out[s] += take * conc_[cidx(l, 0, s)];
276 if (vol_[p] <= 0.0) {
277 head_[
static_cast<std::size_t
>(l)] =
278 (head_[
static_cast<std::size_t
>(l)] + 1) % cap_;
279 count_[
static_cast<std::size_t
>(l)] -= 1;
308 if (
count(l) > 0 && mergeable(l, 0, c)) {
309 merge_into(l, 0, volume, c);
312 if (
count(l) >= cap_) {
316 head_[
static_cast<std::size_t
>(l)] = (head_[
static_cast<std::size_t
>(l)] - 1 + cap_) % cap_;
317 count_[
static_cast<std::size_t
>(l)] += 1;
318 const std::size_t p = phys(l, 0);
320 for (
int s = 0; s < ns_; ++s)
321 conc_[cidx(l, 0, s)] = c[s];
334 const int n =
count(l);
335 for (
int i = 0, j = n - 1; i < j; ++i, --j) {
336 std::swap(vol_[phys(l, i)], vol_[phys(l, j)]);
337 for (
int s = 0; s < ns_; ++s)
338 std::swap(conc_[cidx(l, i, s)], conc_[cidx(l, j, s)]);
358 for (
int l = 0; l < nl_; ++l)
359 for (
int i = 0; i <
count(l); ++i)
360 conc_[cidx(l, i, s)] += delta;
380 double removed = 0.0;
381 for (
int l = 0; l < nl_; ++l)
382 for (
int i = 0; i <
count(l); ++i) {
383 const std::size_t ci = cidx(l, i, s);
384 removed += vol_[phys(l, i)] * conc_[ci] * (1.0 - factor);
400 std::size_t phys(
int l,
int i)
const {
401 const int slot = (head_[
static_cast<std::size_t
>(l)] + i) % cap_;
402 return static_cast<std::size_t
>(l) *
static_cast<std::size_t
>(cap_) +
403 static_cast<std::size_t
>(slot);
415 std::size_t cidx(
int l,
int i,
int s)
const {
416 return static_cast<std::size_t
>(s) *
static_cast<std::size_t
>(nl_) *
417 static_cast<std::size_t
>(cap_) +
431 bool mergeable(
int l,
int i,
const double* c)
const {
432 for (
int s = 0; s < ns_; ++s) {
433 const double cf = conc_[cidx(l, i, s)];
452 void merge_into(
int l,
int i,
double volume,
const double* c) {
453 const std::size_t p = phys(l, i);
454 const double v0 = vol_[p];
455 const double vt = v0 +
volume;
458 for (
int s = 0; s < ns_; ++s) {
459 const std::size_t ci = cidx(l, i, s);
460 conc_[ci] = (conc_[ci] * v0 + c[s] *
volume) / vt;
473 void merge_front_pair(
int l) {
478 const std::size_t p0 = phys(l, 0);
479 const std::size_t p1 = phys(l, 1);
480 const double v0 = vol_[p0], v1 = vol_[p1], vt = v0 + v1;
482 for (
int s = 0; s < ns_; ++s) {
483 const std::size_t c0 = cidx(l, 0, s);
484 const std::size_t c1 = cidx(l, 1, s);
485 conc_[c1] = (conc_[c0] * v0 + conc_[c1] * v1) / vt;
488 head_[
static_cast<std::size_t
>(l)] = (head_[
static_cast<std::size_t
>(l)] + 1) % cap_;
489 count_[
static_cast<std::size_t
>(l)] -= 1;
493 std::vector<int> head_, count_;
494 std::vector<double> vol_;
495 std::vector<double> conc_;
Versioned archives of completed source-boundary state.
Definition CompletedSourceArchive.hpp:25
Definition SegmentStore.hpp:67
double drain_front(int l, double vol_target, double *mass_out)
Same as drain_back but from the FRONT (upstream end) — the volume- reconciliation path for a link tha...
Definition SegmentStore.hpp:267
double seg_conc(int l, int i, int s) const
Read one species concentration in a live segment.
Definition SegmentStore.hpp:162
double decay_species(int s, double factor)
Exact-exponential decay on one species over every LIVE segment.
Definition SegmentStore.hpp:379
int count(int l) const
Read the number of live segments in one ring.
Definition SegmentStore.hpp:122
void resize(int n_links, int n_species, int cap=kMaxSegmentsPerLink)
Replace all segment storage with empty rings at new dimensions.
Definition SegmentStore.hpp:106
double drain_back(int l, double vol_target, double *mass_out)
Drain up to vol_target from the BACK (downstream end).
Definition SegmentStore.hpp:235
void checkpoint(detail::CompletedSourceArchive &a)
Serialize or restore fixed-sized segment ring arrays and validate restored numerical state.
Definition SegmentStore.hpp:82
void push_front(int l, double volume, const double *c)
Release a new segment at the FRONT (upstream end).
Definition SegmentStore.hpp:305
void mean_conc(int l, double *out) const
Volume-weighted mean concentration over the link's segments. out has ns_ entries; an empty link repor...
Definition SegmentStore.hpp:188
void set_seg_conc(int l, int i, int s, double c)
X3b: the RWPT exchange rewrites segment concentrations in place (mass-conserving by its own construct...
Definition SegmentStore.hpp:175
void add_species(int s, double delta)
Add a constant to one species on every LIVE segment.
Definition SegmentStore.hpp:357
void reverse(int l)
§4.4 flow reversal: front becomes back, in place.
Definition SegmentStore.hpp:333
double total_volume(int l) const
Sum live segment water volumes for one link.
Definition SegmentStore.hpp:140
int capacity() const
Read slots reserved per link ring.
Definition SegmentStore.hpp:132
void clear_link(int l)
Remove one whole link's contents (init/re-seed).
Definition SegmentStore.hpp:211
double seg_volume(int l, int i) const
Read a live segment's stored water volume.
Definition SegmentStore.hpp:153
int species() const
Read initialized concentration row count.
Definition SegmentStore.hpp:127
Definition LagrangianSolver.hpp:125
constexpr double kMergeAtol
Definition SegmentStore.hpp:64
constexpr double kMergeRtol
Definition SegmentStore.hpp:65
constexpr int kMaxSegmentsPerLink
Definition SegmentStore.hpp:58
OPENSWMM_POND_HD double volume(double x, double a_eq, double band)
Pond volume held between the rim and depth x above it.
Definition PondModel.hpp:72
Definition ExchangeLaw.hpp:60