39#ifndef OPENSWMM_ENGINE_FV_EXPLICIT_FV_SOLVER_HPP
40#define OPENSWMM_ENGINE_FV_EXPLICIT_FV_SOLVER_HPP
54struct SpeciesKernelView;
95 pressure_candidate_ =
true;
104 return pressure_result_;
176 RunStats
run_stats() const noexcept override;
182 d.value = div_value_;
208 step_sink_user_ = user;
219 const std::vector<double>&
node_exchange() const noexcept {
return node_exch_; }
224 water_tracking_ = enabled;
225 if (enabled && mesh_)
226 water_.resize(mesh_->n_faces(), mesh_->struct_link.size(), mesh_->n_cells(), mesh_->n_nodes());
228 save_water_ = water_; rk_water_ = water_;
233 const std::vector<double>&
withdrawalRates() const noexcept {
return withdrawal_rates_; }
257 return press_.foldedNodes();
290 if (node_lat_div_.empty() || !node_lat_div_[un] || !forcing.node_lateral)
292 const double lat = forcing.node_lateral[un];
294 node_out_[un] += lat * dt;
305 const std::vector<uint8_t>&
inlet_control() const noexcept {
return inlet_control_; }
318 const std::vector<double>&
dummy_volume() const noexcept {
return dummy_vol_; }
380 return tier_occupancy_;
399 double advanceImpl(
double t_current,
double t_target,
const FvStepForcing& forcing);
410 void validatePressureCandidate(
const FvStepForcing& forcing)
const;
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);
504 void computeFluxes();
518 void limitPositivity(
double dt);
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_;
554 std::vector<int> node_light_;
609 void settleAlgebraicNode(
int node,
double carry);
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])
658 return forcing.node_lateral ? forcing.node_lateral[un] : 0.0;
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_;
722 bool algebraicActive(
int n)
const noexcept {
723 const auto un =
static_cast<std::size_t
>(n);
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) {
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];
748 const auto uc =
static_cast<std::size_t
>(c);
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)
772 void updateCells(
double dt,
const FvStepForcing& forcing);
787 void updateNodes(
double dt,
const FvStepForcing& forcing);
798 void dispersionSolve(
double dt);
813 void refreshStructFlows(
const FvStepForcing& forcing);
814 std::vector<double> node_qstruct_;
824 std::vector<double> node_qdummy_;
829 std::vector<double> dummy_vol_;
847 template <
class ArrivedFn>
848 void refreshDummyFlows(
double dt,
const FvStepForcing& forcing, ArrivedFn&& arrived,
bool book_receipts =
true);
856 double nodeQDummy(std::size_t un)
const noexcept {
857 return node_qdummy_.empty() ? 0.0 : node_qdummy_[un];
871 double nodeDepthFromVolume(
int node,
double volume)
const;
880 bool ltsEligible() const noexcept {
882 state_->n_species == 0;
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_);
901 std::vector<std::uint32_t> live_stamp_;
902 std::uint32_t live_gen_ = 0;
907 bool all_faces_live_ =
true;
919 double algebraicNodeStableDt(
int n)
const noexcept;
939 double frictionFor(
const FvGeometry& g,
double roughness,
double rough_factor,
double q,
940 double u,
double h,
double dt,
double radius)
const;
957 void applyNodeCapacity(
int node,
double v_prev,
double& vol,
double& depth);
970 double cellStableDt(
int cell)
const;
981 double nodeStableDt(
int node)
const;
999 int assignTiers(
double& dt0,
int k_cap_override = 0);
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);
1070 void settleAccumulators();
1090 void restoreState();
1108 bool takeSubstep(
double dt,
const FvStepForcing& forcing);
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;
1172 void rkAverage(
const FvStepForcing& forcing);
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;
1200 NetworkMeshData* mesh_ =
nullptr;
1201 NetworkStateData* state_ =
nullptr;
1206 const FvStepForcing* forcing_ =
nullptr;
1212 std::vector<double> f_mass_, f_mom_, f_sstar_, f_corr_l_, f_corr_r_;
1219 std::vector<double> f_phi_l_, f_phi_r_;
1222 std::vector<double> f_phi_flux_;
1226 std::vector<double> lo_flux_, anti_flux_, td_, anew_, rplus_, rminus_;
1231 std::vector<kernels::FaceState> f_state_l_, f_state_r_;
1232 std::vector<kernels::FaceFlux> f_flux_;
1236 std::vector<double> cell_slope_;
1244 std::vector<double> cell_eta_slope_, cell_u_slope_;
1251 std::vector<char> cell_ho2_;
1254 std::vector<double> cell_eta_;
1255 std::vector<double> cell_u_;
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;
1287 std::vector<
double> uf_grad_;
1301 void computeUfGradients(const std::vector<
int>* cells);
1305 bool mixed_wave_ = true;
1307 bool deg1_guard_slot_ =
1309 bool census_pass_far_ =
1324 int passThroughFarCell(
int face,
int nd) const noexcept;
1325 std::vector<uint8_t> tpa_scratch_;
1326 std::vector<uint8_t> save_tpa_;
1338 void updateTpaFlags();
1347 bool tpaCell(std::
size_t uc) const noexcept {
return tpa_ && state_->cell_tpa[uc] != 0; }
1348 std::vector<double> cell_q_int_;
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);
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;
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_;
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_;
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_;
1393 static constexpr double kStepAcceptRatio = 0.5;
1394 static constexpr int kMaxStepRetries = 8;
1403 static constexpr double kMinSubstep = 1.0e-6;
1415 static constexpr double kDivergedVelocity = 1000.0;
1416 static constexpr double kDivergedDepth = 10000.0;
1418 double div_value_ = 0.0;
1419 const char* div_what_ =
nullptr;
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;
1434 std::vector<std::uint8_t> cell_tier_, face_tier_, node_tier_;
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_;
1458 std::vector<std::vector<int>> due_f_upto_, due_c_upto_, due_n_upto_;
1464 bool lts_valid_ =
false;
1465 int lts_countdown_ = 0;
1466 double lts_dt0_ = 0.0;
1467 static constexpr int kRetierEveryCycles = 8;
1472 std::vector<double> acc_a_, acc_q_, acc_nvol_;
1479 std::array<long, kMaxLtsTiers> tier_occupancy_{};
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;
1503 bool state_clean_ =
false;
1509 bool acc_dirty_ =
false;
1512 std::vector<double> relax_beta_;
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;
1529 double dt_cache_ = 0.0;
1536 double dt_census_ = 0.0;
1540 int census_count_ = 0;
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 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