OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
ExplicitFvSolver.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
38
39#ifndef OPENSWMM_ENGINE_FV_EXPLICIT_FV_SOLVER_HPP
40#define OPENSWMM_ENGINE_FV_EXPLICIT_FV_SOLVER_HPP
41
43#include <array>
44#include <cstdint>
45#include <vector>
46
47#include "FvKernels.hpp"
48#include "FvOptions.hpp"
49#include "INetworkSolver.hpp"
50#include "NetworkMeshData.hpp"
52
54struct SpeciesKernelView; // transport/fvkernels/SpeciesTransportKernels.hpp
55}
56
57namespace openswmm::fv {
58
60public:
66 ExplicitFvSolver() = default;
73 ~ExplicitFvSolver() override = default;
74
83
95 pressure_candidate_ = true;
96 pressure_controls_ = controls;
97 }
98
104 return pressure_result_;
105 }
106
111 long pressureCandidateRejections() const noexcept { return pressure_rejections_; }
112
131 void initialize(NetworkMeshData& mesh, NetworkStateData& state, const FvOptions& opts) override;
152 double advance(double t_current, double t_target, const FvStepForcing& forcing) override;
163 void reinitialize(double t0) override;
171 void finalize() override;
172
173 long last_num_steps() const noexcept override { return last_nsteps_; }
174 double last_step_size() const noexcept override { return last_h_; }
175 double suggested_step() const noexcept override { return suggested_h_; }
176 RunStats run_stats() const noexcept override;
177 bool is_initialized() const noexcept override { return mesh_ != nullptr; }
178 bool divergence(Divergence& d) const noexcept override {
179 if (div_link_ < 0)
180 return false;
181 d.link = div_link_;
182 d.value = div_value_;
183 d.what = div_what_;
184 return true;
185 }
186
192 using ConduitStepSink = void (*)(void* user, int conduit, double dt, double dur);
206 void setConduitStepSink(ConduitStepSink fn, void* user) noexcept {
207 step_sink_ = fn;
208 step_sink_user_ = user;
209 }
210
219 const std::vector<double>& node_exchange() const noexcept { return node_exch_; }
220
223 void trackAcceptedWater(bool enabled) {
224 water_tracking_ = enabled;
225 if (enabled && mesh_)
226 water_.resize(mesh_->n_faces(), mesh_->struct_link.size(), mesh_->n_cells(), mesh_->n_nodes());
227 else water_ = {};
228 save_water_ = water_; rk_water_ = water_;
229 }
230 const AcceptedWaterVolumes& acceptedWater() const noexcept { return water_; }
231 void requireConservativeNodeBalance(bool enabled) noexcept {conservative_node_balance_=enabled;}
232 std::vector<double>& withdrawalRates() noexcept { return withdrawal_rates_; }
233 const std::vector<double>& withdrawalRates() const noexcept { return withdrawal_rates_; }
234 const std::vector<double>& unmetWithdrawalVolumes() const noexcept { return unmet_withdrawal_; }
235
236
237
246 const std::vector<double>& node_continuity_carry() const noexcept { return node_carry_; }
247
256 const std::vector<std::uint8_t>& pressure_folded_nodes() const noexcept {
257 return press_.foldedNodes();
258 }
259
268 const std::vector<double>& node_inflow_volume() const noexcept { return node_in_; }
277 const std::vector<double>& node_outflow_volume() const noexcept { return node_out_; }
289 void bookDivertedLateral(std::size_t un, double dt, const FvStepForcing& forcing) noexcept {
290 if (node_lat_div_.empty() || !node_lat_div_[un] || !forcing.node_lateral)
291 return;
292 const double lat = forcing.node_lateral[un];
293 if (lat > 0.0)
294 node_out_[un] += lat * dt;
295 }
296
305 const std::vector<uint8_t>& inlet_control() const noexcept { return inlet_control_; }
306
308 const std::vector<double>& node_flood_volume() const noexcept { return flood_vol_; }
309
318 const std::vector<double>& dummy_volume() const noexcept { return dummy_vol_; }
319
328 const std::vector<std::uint8_t>& node_passthrough() const noexcept { return node_pass_; }
329
338 const std::vector<std::uint8_t>& node_publish_stage() const noexcept { return node_pub_; }
339
348 const std::vector<double>& cell_flow_integral() const noexcept { return cell_q_int_; }
349
363 double nodeVolumeFromDepth(int node, double depth) const;
364
369 int lts_tiers() const noexcept { return lts_tiers_; }
370
379 const std::array<long, kMaxLtsTiers>& tier_occupancy() const noexcept {
380 return tier_occupancy_;
381 }
382
383private:
399 double advanceImpl(double t_current, double t_target, const FvStepForcing& forcing);
410 void validatePressureCandidate(const FvStepForcing& forcing) const;
411 // -- substep pipeline ---------------------------------------------------
421 void refreshDepths();
430 void refreshNodeAreas();
440 void rebuildActiveLists();
455 double censusDt(bool press_edit = false) const;
456 void reconstructState();
472 void computeFaceFlux(int face, bool mass_only = false);
484 void reconstructScalars(double dt);
495 transport::fvkernels::SpeciesKernelView speciesKernelView();
504 void computeFluxes();
518 void limitPositivity(double dt);
519
533 void relaxNodeFluxes(double dt, const FvStepForcing& forcing);
549 template <class DtOf>
550 void solveNodes(const std::vector<int>& nodes, DtOf&& dt_of, const FvStepForcing& forcing);
551 std::vector<int> node_solve_list_;
552 std::vector<int>
553 node_heavy_;
554 std::vector<int> node_light_;
555
571 void relaxOneNode(int node, double dt, const FvStepForcing& forcing);
572
591 void solveAlgebraicNode(int node, double dt, const FvStepForcing& forcing);
592
609 void settleAlgebraicNode(int node, double carry);
610
613 std::vector<std::uint8_t> node_alg_;
616 std::vector<std::uint8_t> node_pass_static_;
622 std::vector<std::uint8_t> node_pass_;
629 std::vector<std::uint8_t> node_pub_static_;
630 std::vector<std::uint8_t> node_pub_;
634 std::vector<double> node_carry_;
643 std::vector<double> cell_qlat_;
644 std::vector<std::uint8_t> node_lat_div_;
655 double nodeLateral(const FvStepForcing& forcing, std::size_t un) const noexcept {
656 if (!node_lat_div_.empty() && node_lat_div_[un])
657 return 0.0;
658 return forcing.node_lateral ? forcing.node_lateral[un] : 0.0;
659 }
680 std::vector<double> face_a_rim_;
681 std::vector<double> face_lat_spill_;
697 double injectDivertedLateral(std::size_t uc, double a_new, double dt, double inv_dx);
708 void bookLateralSpills(const std::vector<int>* nodes);
710 std::vector<double> node_vfull_;
711
722 bool algebraicActive(int n) const noexcept {
723 const auto un = static_cast<std::size_t>(n);
724 if (!node_alg_[un])
725 return false;
726 if (mesh_->node_can_pond[un] && state_->node_volume[un] > node_vfull_[un])
727 return false;
728 return true;
729 }
730
741 bool incidentPressurized(std::size_t un) const noexcept {
742 for (int p = mesh_->node_face_ptr[un]; p < mesh_->node_face_ptr[un + 1]; ++p) {
743 const auto uf =
744 static_cast<std::size_t>(mesh_->node_face_idx[static_cast<std::size_t>(p)]);
745 const int c = (mesh_->face_cl[uf] >= 0) ? mesh_->face_cl[uf] : mesh_->face_cr[uf];
746 if (c < 0)
747 continue;
748 const auto uc = static_cast<std::size_t>(c);
749 if (tpaCell(uc))
750 return true;
751 const FvGeometry& g = mesh_->geom[static_cast<std::size_t>(mesh_->cell_geom[uc])];
752 if (!g.is_open && state_->cell_h[uc] >= g.y_crown)
753 return true;
754 }
755 return false;
756 }
772 void updateCells(double dt, const FvStepForcing& forcing);
787 void updateNodes(double dt, const FvStepForcing& forcing);
798 void dispersionSolve(double dt);
799
813 void refreshStructFlows(const FvStepForcing& forcing);
814 std::vector<double> node_qstruct_;
815
824 std::vector<double> node_qdummy_;
825
829 std::vector<double> dummy_vol_;
830
847 template <class ArrivedFn>
848 void refreshDummyFlows(double dt, const FvStepForcing& forcing, ArrivedFn&& arrived, bool book_receipts = true);
849
856 double nodeQDummy(std::size_t un) const noexcept {
857 return node_qdummy_.empty() ? 0.0 : node_qdummy_[un];
858 }
859
871 double nodeDepthFromVolume(int node, double volume) const;
872
880 bool ltsEligible() const noexcept {
881 return opts_.lts && opts_.time_integration != TimeIntegration::RK2 && state_ &&
882 state_->n_species == 0;
883 }
884
894 bool faceIsLive(int f) const noexcept {
895 return all_faces_live_ ||
896 (!live_stamp_.empty() && live_stamp_[static_cast<std::size_t>(f)] == live_gen_);
897 }
898
901 std::vector<std::uint32_t> live_stamp_;
902 std::uint32_t live_gen_ = 0;
907 bool all_faces_live_ = true;
908
919 double algebraicNodeStableDt(int n) const noexcept;
920
939 double frictionFor(const FvGeometry& g, double roughness, double rough_factor, double q,
940 double u, double h, double dt, double radius) const;
941
957 void applyNodeCapacity(int node, double v_prev, double& vol, double& depth);
958
959 // -- local time stepping (plan §3.3) ------------------------------------
970 double cellStableDt(int cell) const;
981 double nodeStableDt(int node) const;
982
999 int assignTiers(double& dt0, int k_cap_override = 0);
1000
1013 void fireFaces(const std::vector<int>& faces, double dt0);
1029 void fireCells(const std::vector<int>& cells, double dt0, const FvStepForcing& forcing);
1044 void fireNodes(const std::vector<int>& nodes, double dt0, const FvStepForcing& forcing);
1059 void runMacroCycle(double dt0, int nsub, const FvStepForcing& forcing);
1060
1070 void settleAccumulators();
1071
1080 void saveState();
1090 void restoreState();
1091
1108 bool takeSubstep(double dt, const FvStepForcing& forcing);
1109
1110 // -- implicit pressurized head update (slot program R2a) ----------------
1120 bool anyPressurizedCell() const;
1131 bool nodePressFolded(int n) const;
1143 PressurizedView pressView(const FvStepForcing& forcing);
1144 PressurizedHeadSolver press_;
1146 bool press_step_ = false;
1147 bool pressure_candidate_ = false;
1148 NonlinearPressureStorage::Controls pressure_controls_;
1149 NonlinearPressureStorage::Result pressure_result_;
1150 long pressure_rejections_ = 0;
1151
1159 void rkSave();
1172 void rkAverage(const FvStepForcing& forcing);
1173
1196 void faceSide(int face, int cell, int node, double zstar, int dir, double u_interior,
1197 kernels::FaceState& out, double& i1_unreconstructed, double& z_side,
1198 bool measure_only) const;
1199
1200 NetworkMeshData* mesh_ = nullptr;
1201 NetworkStateData* state_ = nullptr;
1202
1206 const FvStepForcing* forcing_ = nullptr;
1207 FvOptions opts_{};
1208
1209 // Face scratch. corr_l/corr_r are the Audusse well-balanced corrections
1210 // g·(I₁(h_K) − I₁(h*_K)) — per-cell, not per-face, which is why they are
1211 // stored separately from the shared flux.
1212 std::vector<double> f_mass_, f_mom_, f_sstar_, f_corr_l_, f_corr_r_;
1213
1219 std::vector<double> f_phi_l_, f_phi_r_;
1220
1222 std::vector<double> f_phi_flux_;
1223
1226 std::vector<double> lo_flux_, anti_flux_, td_, anew_, rplus_, rminus_;
1227
1231 std::vector<kernels::FaceState> f_state_l_, f_state_r_;
1232 std::vector<kernels::FaceFlux> f_flux_;
1233 bool hllc_ = true;
1234
1236 std::vector<double> cell_slope_;
1237
1244 std::vector<double> cell_eta_slope_, cell_u_slope_;
1245
1251 std::vector<char> cell_ho2_;
1252
1253 // Cell scratch.
1254 std::vector<double> cell_eta_;
1255 std::vector<double> cell_u_;
1256
1264 std::vector<double> cell_ah_;
1265 std::vector<double> cell_t_;
1266 std::vector<double> cell_i1_;
1280 void cacheClosure(std::size_t uc, const FvGeometry& g, double h,
1281 double* radius = nullptr) noexcept;
1282
1287 std::vector<double> uf_grad_;
1288
1301 void computeUfGradients(const std::vector<int>* cells);
1302
1303 // -- TPA pressure closure (issue #156 Phase 4) ---------------------------
1304 bool tpa_ = false;
1305 bool mixed_wave_ = true;
1306 bool mw_rh_ = true;
1307 bool deg1_guard_slot_ =
1308 true;
1309 bool census_pass_far_ =
1310 true;
1311 bool lts_fit_ =
1312 false;
1324 int passThroughFarCell(int face, int nd) const noexcept;
1325 std::vector<uint8_t> tpa_scratch_;
1326 std::vector<uint8_t> save_tpa_;
1327
1338 void updateTpaFlags();
1339
1347 bool tpaCell(std::size_t uc) const noexcept { return tpa_ && state_->cell_tpa[uc] != 0; }
1348 std::vector<double> cell_q_int_;
1352
1353 bool water_tracking_ = false;
1354 bool conservative_node_balance_ = false;
1355 std::vector<double> withdrawal_rates_, unmet_withdrawal_, save_unmet_, rk_unmet_;
1356 void bookFaceWater(int face, double dt);
1357 void bookSpliceReceipt(std::size_t vj, double flux, double dt);
1358 double capWithdrawal(std::size_t node, double balance, double dt, const FvStepForcing& forcing);
1359
1360 AcceptedWaterVolumes water_, save_water_, rk_water_;
1361 void bookStructureWater(double dt, const FvStepForcing& forcing);
1362 double algebraicAvailableWater(std::size_t node, double dt, double pending,
1363 const std::vector<double>& cell_scales) const;
1364
1365 // Node scratch.
1366 std::vector<double> node_exch_;
1367 std::vector<double> node_in_, node_out_;
1368 std::vector<double> flood_vol_;
1369 std::vector<uint8_t> inlet_control_;
1370
1371 // Step-rejection snapshot. A cell can cross the crown INSIDE a substep,
1372 // taking its celerity from the free-surface value to the slot value — a
1373 // factor of ~20 on a 3 ft pipe — so a step sized on the pre-step state can
1374 // violate CFL by more than an order of magnitude exactly when the model is
1375 // doing something interesting. Re-censusing the POST-step state and rolling
1376 // back when it disagrees is the principled fix; a heuristic fill-rate cap
1377 // is not, because the stiffness ratio depends on FV_SLOT_CELERITY.
1378 std::vector<double> save_dummy_, rk_dummy_;
1379 std::vector<double> save_cell_a_, save_cell_q_, save_cell_phi_;
1380 std::vector<double> save_node_vol_, save_node_head_;
1381 std::vector<double> save_exch_, save_in_, save_out_, save_flood_, save_qint_, save_carry_;
1382
1383 // SSP-RK2 stage-1 snapshot. Separate from the rejection snapshot above:
1384 // a rejected RK2 step has to roll back to Uⁿ, and Uⁿ must survive the
1385 // stage-1 save that the rejection machinery performs.
1386 std::vector<double> rk_cell_a_, rk_cell_q_, rk_cell_phi_;
1387 std::vector<double> rk_node_vol_, rk_node_head_;
1388 std::vector<double> rk_exch_, rk_in_, rk_out_, rk_flood_, rk_qint_, rk_carry_;
1389 std::vector<uint8_t> rk_tpa_;
1390
1393 static constexpr double kStepAcceptRatio = 0.5;
1394 static constexpr int kMaxStepRetries = 8;
1395
1403 static constexpr double kMinSubstep = 1.0e-6;
1404
1405 // Divergence guard (issue #156 R3). The retry loop above is sound for CFL
1406 // violations, which shrink away with dt — but a dt-INDEPENDENT
1407 // amplification (measured: RK2 x TPA on the study's e3 siphon grows the
1408 // crown head x20-40 per millisecond at FV_CFL 0.9, 0.45 and 0.25 alike)
1409 // fails all 8 retries identically and the loop then ACCEPTS the diverged
1410 // step silently. These bounds are physical absurdities, not tolerances: no
1411 // water transient carries particle velocity past 1000 ft/s (celerity is
1412 // not particle speed), and 10,000 ft of pressure head is 300 bar. A run
1413 // that crosses either has left the physics and must say so instead of
1414 // scoring OK (P6 finding F3). Checked once per routing step, O(cells).
1415 static constexpr double kDivergedVelocity = 1000.0;
1416 static constexpr double kDivergedDepth = 10000.0;
1417 int div_link_ = -1;
1418 double div_value_ = 0.0;
1419 const char* div_what_ = nullptr;
1420
1421 // Work lists (plan §5.2.1). `halo_` is the compaction safety margin: a wet
1422 // front advances at most CFL cells per substep, so a halo of `rebuild_
1423 // interval_` cells keeps a stale list conservative between rebuilds.
1424 std::vector<int> active_faces_;
1425 std::vector<char> cell_active_;
1426 std::vector<char> halo_prev_;
1427 bool lists_valid_ = false;
1428 int since_rebuild_ = 0;
1429 static constexpr int kRebuildInterval = 8;
1430
1431 // Local time stepping (plan §3.3). Tiers are assigned only at a
1432 // synchronisation point — never mid-cycle — because a cell re-tiered
1433 // between firings would either skip a flux it owes or drain one twice.
1434 std::vector<std::uint8_t> cell_tier_, face_tier_, node_tier_;
1435
1436 ConduitStepSink step_sink_ = nullptr;
1437 void* step_sink_user_ = nullptr;
1450 void emitConduitSteps(double dt0, double dur, bool tiered) const;
1451 std::vector<std::vector<int>> cells_by_tier_, faces_by_tier_, nodes_by_tier_;
1452
1458 std::vector<std::vector<int>> due_f_upto_, due_c_upto_, due_n_upto_;
1459
1464 bool lts_valid_ = false;
1465 int lts_countdown_ = 0;
1466 double lts_dt0_ = 0.0;
1467 static constexpr int kRetierEveryCycles = 8;
1468
1472 std::vector<double> acc_a_, acc_q_, acc_nvol_;
1473
1478 int lts_tiers_ = 1;
1479 std::array<long, kMaxLtsTiers> tier_occupancy_{};
1480
1481 // Statistics.
1482 long last_nsteps_ = 0;
1483 double last_h_ = 0.0;
1484 double suggested_h_ = 0.0;
1485 long total_steps_ = 0;
1486 long total_flux_ = 0;
1487 double min_h_ = 0.0;
1488 double sim_time_ = 0.0;
1492 long n_macro_cycles_ = 0;
1493 long n_macro_rejected_ = 0;
1494
1503 bool state_clean_ = false;
1509 bool acc_dirty_ = false;
1512 std::vector<double> relax_beta_;
1513
1514 // dt-argmin attribution (slot program R0): who owned the binding CFL
1515 // element, counted once per censusDt (global path) / assignTiers (LTS
1516 // path). `mutable` because censusDt is const; these are telemetry.
1517 mutable long dt_argmin_pressurized_ = 0;
1518 mutable long dt_argmin_band_ = 0;
1519 mutable long dt_argmin_free_ = 0;
1520 mutable long dt_argmin_node_ = 0;
1521 double active_sum_ = 0.0;
1522 double active_min_ = -1.0;
1523 double active_max_ = -1.0;
1524 long active_n_ = 0;
1525
1529 double dt_cache_ = 0.0;
1530
1536 double dt_census_ = 0.0;
1537
1540 int census_count_ = 0;
1541};
1542
1543} // namespace openswmm::fv
1544
1545#endif // OPENSWMM_ENGINE_FV_EXPLICIT_FV_SOLVER_HPP
Single-source scalar kernels for the explicit FV 1D network solver.
Option struct for the explicit finite-volume 1D network solver.
Backend-neutral interface for the explicit FV 1D network integrator.
SoA storage for the 1D finite-volume network mesh and its state.
Implicit acoustic/slot head update on the pressurized subset (slot program R2a, Strategy E).
ExplicitFvSolver(const ExplicitFvSolver &)=delete
Disallow copying a solver and its borrowed state/scratch ownership.
void enablePressureStorageCandidate(const NonlinearPressureStorage::Controls &controls={})
Enable the restricted native nonlinear pressure-storage experiment.
Definition ExplicitFvSolver.hpp:94
const std::array< long, kMaxLtsTiers > & tier_occupancy() const noexcept
Borrow the run tier-occupancy histogram.
Definition ExplicitFvSolver.hpp:379
int lts_tiers() const noexcept
Read the most recent local-time-stepping tier count.
Definition ExplicitFvSolver.hpp:369
const std::vector< uint8_t > & inlet_control() const noexcept
Borrow culvert inlet-control occurrence flags for the last window.
Definition ExplicitFvSolver.hpp:305
bool is_initialized() const noexcept override
True once initialize() has completed and the solver is ready.
Definition ExplicitFvSolver.hpp:177
void(*)(void *user, int conduit, double dt, double dur) ConduitStepSink
Definition ExplicitFvSolver.hpp:192
const NonlinearPressureStorage::Result & pressureCandidateResult() const noexcept
Borrow the most recently attempted nonlinear pressure candidate diagnostics.
Definition ExplicitFvSolver.hpp:103
const std::vector< double > & node_flood_volume() const noexcept
Per-node flooding VOLUME (ft³) over the last advance().
Definition ExplicitFvSolver.hpp:308
void setConduitStepSink(ConduitStepSink fn, void *user) noexcept
Set an optional synchronous per-conduit accepted-step reporting observer.
Definition ExplicitFvSolver.hpp:206
ExplicitFvSolver()=default
Construct an unbound solver with no borrowed mesh/state.
long last_num_steps() const noexcept override
Substep count used by the last advance() call.
Definition ExplicitFvSolver.hpp:173
double last_step_size() const noexcept override
Last internal substep size (s).
Definition ExplicitFvSolver.hpp:174
std::vector< double > & withdrawalRates() noexcept
Definition ExplicitFvSolver.hpp:232
void requireConservativeNodeBalance(bool enabled) noexcept
Definition ExplicitFvSolver.hpp:231
void reinitialize(double t0) override
Invalidate stepping caches and refresh derived state after external restoration.
Definition ExplicitFvSolver.cpp:309
double nodeVolumeFromDepth(int node, double depth) const
Evaluate native node storage volume from depth.
Definition ExplicitFvSolver.cpp:365
bool divergence(Divergence &d) const noexcept override
Report the last advance's worst physical-bound/nonfinite offender when supported.
Definition ExplicitFvSolver.hpp:178
const std::vector< double > & node_continuity_carry() const noexcept
Borrow the signed numerical node-continuity carry.
Definition ExplicitFvSolver.hpp:246
ExplicitFvSolver & operator=(const ExplicitFvSolver &)=delete
Disallow copy assignment of a live solver.
RunStats run_stats() const noexcept override
Read cumulative statistics. Default: zeros (backend has no counters).
Definition ExplicitFvSolver.cpp:327
const std::vector< double > & dummy_volume() const noexcept
Borrow per-structure-entry DUMMY pass-through receipts.
Definition ExplicitFvSolver.hpp:318
long pressureCandidateRejections() const noexcept
Read the current restricted-candidate routing-window rejection count.
Definition ExplicitFvSolver.hpp:111
void finalize() override
Detach the borrowed mesh and state.
Definition ExplicitFvSolver.cpp:322
double advance(double t_current, double t_target, const FvStepForcing &forcing) override
Advance the borrowed native state over one requested routing window.
Definition ExplicitFvSolver.cpp:4673
void trackAcceptedWater(bool enabled)
Definition ExplicitFvSolver.hpp:223
const std::vector< std::uint8_t > & node_passthrough() const noexcept
Borrow the current direct-face algebraic-node bypass mask.
Definition ExplicitFvSolver.hpp:328
const std::vector< double > & withdrawalRates() const noexcept
Definition ExplicitFvSolver.hpp:233
double suggested_step() const noexcept override
Read the next CFL step suggestion from the latest backend census.
Definition ExplicitFvSolver.hpp:175
const std::vector< double > & unmetWithdrawalVolumes() const noexcept
Definition ExplicitFvSolver.hpp:234
const std::vector< double > & node_exchange() const noexcept
Borrow the last-window signed node exchange receipt.
Definition ExplicitFvSolver.hpp:219
const std::vector< double > & node_outflow_volume() const noexcept
Borrow accumulated departing conduit-face/diverted-lateral volume magnitudes.
Definition ExplicitFvSolver.hpp:277
const std::vector< double > & node_inflow_volume() const noexcept
Borrow accumulated arriving conduit-face volume magnitudes.
Definition ExplicitFvSolver.hpp:268
~ExplicitFvSolver() override=default
Destroy owned solver scratch without deleting borrowed mesh/state.
void bookDivertedLateral(std::size_t un, double dt, const FvStepForcing &forcing) noexcept
Book positive node lateral volume that entered cells without crossing node faces.
Definition ExplicitFvSolver.hpp:289
const std::vector< std::uint8_t > & pressure_folded_nodes() const noexcept
Borrow the most recent pressure-classification folded-node mask.
Definition ExplicitFvSolver.hpp:256
const std::vector< double > & cell_flow_integral() const noexcept
Borrow the last-window time integral of mean face through-flow per cell.
Definition ExplicitFvSolver.hpp:348
const AcceptedWaterVolumes & acceptedWater() const noexcept
Definition ExplicitFvSolver.hpp:230
void initialize(NetworkMeshData &mesh, NetworkStateData &state, const FvOptions &opts) override
Bind a mesh/state and initialize native solver scratch and static eligibility.
Definition ExplicitFvSolver.cpp:85
const std::vector< std::uint8_t > & node_publish_stage() const noexcept
Borrow eligibility for reconstructing reported node stage from adjacent wet cells.
Definition ExplicitFvSolver.hpp:338
Abstract time integrator for the explicit FV 1D network.
Definition INetworkSolver.hpp:135
Definition Controls.cpp:47
Definition AcceptedWaterVolumes.hpp:8
@ RK2
SSP-RK2 (Heun) — strong-stability-preserving.
Definition FvOptions.hpp:77
Definition Node.cpp:38
Definition ExplicitFvSolver.hpp:53
Definition AcceptedWaterVolumes.hpp:14
Knobs for FLOW_ROUTING FV.
Definition FvOptions.hpp:123
Definition INetworkSolver.hpp:58
Definition INetworkSolver.hpp:246
SoA mesh geometry and topology for the FV network solver.
Definition NetworkMeshData.hpp:123
std::vector< int > cell_geom
index into geom
Definition NetworkMeshData.hpp:129
std::vector< int > node_face_idx
face indices
Definition NetworkMeshData.hpp:346
std::vector< int > face_cl
left cell (-1 ⇒ node on the left)
Definition NetworkMeshData.hpp:161
std::vector< uint8_t > node_can_pond
Definition NetworkMeshData.hpp:366
std::vector< int > node_face_ptr
[n_nodes + 1] row pointers
Definition NetworkMeshData.hpp:345
std::vector< FvGeometry > geom
Definition NetworkMeshData.hpp:401
Mutable solver state — the conserved variables and the node volumes.
Definition NetworkMeshData.hpp:519
std::vector< double > cell_h
depth (ft)
Definition NetworkMeshData.hpp:527
std::vector< double > node_volume
stored volume (ft³)
Definition NetworkMeshData.hpp:532
Definition NonlinearPressureStorage.hpp:44
Definition NonlinearPressureStorage.hpp:65
Non-owning view over everything the species kernels read and write.
Definition SpeciesTransportKernels.hpp:103