OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
DynamicWave.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
43
44#ifndef OPENSWMM_DYNAMIC_WAVE_HPP
45#define OPENSWMM_DYNAMIC_WAVE_HPP
46
47#include "XSectBatch.hpp"
48#include "../core/Constants.hpp"
50#include "../data/NodeData.hpp"
51#include "../data/LinkData.hpp"
52#include <cstdint>
53#include <functional>
54#include <string>
55#include <vector>
56
57namespace openswmm {
58
60
61namespace dynwave {
62
63// ============================================================================
64// Constants — imported from global Constants.hpp
65// ============================================================================
66
77
78// ============================================================================
79// Dynamic Preissmann Slot (DPS) configuration and per-link state
80// Sharior, Hodges & Vasconcelos (2023), J. Hydraul. Eng. 149(11)
81// ============================================================================
82
84struct DPSConfig {
85 double c_pT = 25.0;
86 double alpha = 3.0;
87 double r = 0.5;
88 double c_pT_sq = 625.0;
89};
90
103 std::vector<double> As;
104 std::vector<double> hs;
105 std::vector<double> hs_prev_iter;
106 std::vector<double> P;
107 std::vector<double> P_hat;
108 std::vector<double> P_hat_0;
109 std::vector<double> T_s_target;
110 std::vector<double> t_s;
111 std::vector<uint8_t> surcharged;
112
113 void resize(std::size_t n) {
114 As.assign(n, 0.0);
115 hs.assign(n, 0.0);
116 hs_prev_iter.assign(n, 0.0);
117 P.assign(n, 1.0);
118 P_hat.assign(n, 1.0);
119 P_hat_0.assign(n, 1.0);
120 T_s_target.assign(n, 0.0);
121 t_s.assign(n, 0.0);
122 surcharged.assign(n, 0);
123 }
124};
125
126// ============================================================================
127// Per-node extended state for DW iterations
128// ============================================================================
129
133 std::vector<double> new_surf_area;
134 std::vector<double> old_surf_area;
135 std::vector<double> sumdqdh;
136 std::vector<double> dYdT;
137 std::vector<uint8_t> converged;
138 std::vector<uint8_t> is_surcharged;
139
140 void resize(std::size_t n) {
141 new_surf_area.assign(n, 0.0);
142 old_surf_area.assign(n, 0.0);
143 sumdqdh.assign(n, 0.0);
144 dYdT.assign(n, 0.0);
145 converged.assign(n, 0);
146 is_surcharged.assign(n, 0);
147 }
148};
149
150// ============================================================================
151// DW solver — batch-oriented
152// ============================================================================
153
158enum class SurchargeMethod : int {
159 EXTRAN = 0,
160 SLOT = 1,
162 TPA = 3
166};
167
184
193class DWSolver {
194public:
195 void init(int n_nodes, int n_links, const XSectGroups& groups,
196 const SimulationContext& ctx);
197
212 void setNumThreads(int n, std::vector<std::string>* warnings = nullptr);
213
216 using NonConduitFlowFunc = std::function<void(SimulationContext&, double, int)>;
217
227 int execute(SimulationContext& ctx, double dt,
228 NonConduitFlowFunc non_conduit_fn = nullptr);
229
234 bool lastConverged() const { return last_converged_; }
235
242 double fixed_step, double courant_factor);
243
246 double omega = OMEGA;
249 bool anderson_accel = false;
250
256 double uf_k3 = 0.015;
257
261 double tpa_celerity = 100.0;
262
272 std::vector<int> uf_nb_up_, uf_nb_dn_;
273 std::vector<int8_t> uf_sg_up_, uf_sg_dn_;
274
277 double evap_rate = 0.0;
278
279private:
280 int n_nodes_ = 0;
281 int n_links_ = 0;
282 int n_conduits_ = 0;
283 int num_threads_ = 1;
284 const XSectGroups* groups_ = nullptr;
285
289 bool any_conduit_seep_ = false;
290
295 bool losses_all_zero_ = true;
296
297 // Pre-built conduit index list for skipping non-conduits in inner loops
298 std::vector<int> conduit_idx_;
299
300 // Pre-computed per-link invariants (populated once at first execute, reused)
301 // Using uint8_t instead of bool to allow .data() pointer access for SIMD/restrict
302 std::vector<uint8_t> is_open_;
303 std::vector<uint8_t> is_force_main_;
304 std::vector<uint8_t> has_losses_;
305 std::vector<double> barrels_d_;
306 std::vector<double> cached_length_;
307 std::vector<double> inv_length_;
308
309 // ------------------------------------------------------------------------
310 // Phase A — Conduit-dense "hot tile" of timestep-invariant data.
311 //
312 // Sized n_conduits_, accessed by ci (0..n_conduits_-1) for dense linear
313 // memory access pattern. This replaces sparse `links.X[uj]` /
314 // `nodes.X[un]` reads inside the Picard inner loops, where uj/un are
315 // sparse-indexed via conduit_idx_ + links.node1/node2. Each ci-indexed
316 // read maps to one contiguous cache line that holds 8+ conduits' data,
317 // versus the sparse pattern where each uj read can miss into a new line.
318 //
319 // All fields below are populated once in init() (or refreshConduitTile
320 // when a hot-start changes invariants) and remain constant for the rest
321 // of the simulation. None of these change per Picard iter, per
322 // timestep, or per outfall update.
323 // ------------------------------------------------------------------------
324 std::vector<int> tile_uj_;
325 std::vector<int> tile_n1_;
326 std::vector<int> tile_n2_;
327 std::vector<double> tile_inv1_elev_;
328 std::vector<double> tile_inv2_elev_;
329 std::vector<double> tile_z1_off_;
330 std::vector<double> tile_z2_off_;
331 std::vector<double> tile_y_full_;
332 std::vector<double> tile_a_full_;
333 std::vector<double> tile_r_full_;
334 std::vector<double> tile_w_max_;
335 std::vector<double> tile_length_;
336 std::vector<double> tile_inv_length_;
337 std::vector<double> tile_links_length_;
338 std::vector<double> tile_beta_;
339 std::vector<double> tile_q_max_;
340 std::vector<double> tile_rough_factor_;
341 std::vector<double> tile_barrels_d_;
342 std::vector<uint8_t> tile_is_open_;
343 std::vector<uint8_t> tile_is_force_main_;
344 std::vector<uint8_t> tile_is_closed_;
345 std::vector<uint8_t> tile_has_losses_;
346 std::vector<int> tile_xsect_batch_shape_;
347 std::vector<XsectShape> tile_shape_;
354 std::vector<uint8_t> tile_has_offset_;
359 std::vector<int> tile_uj_to_ci_;
362 std::vector<int> tile_culvert_code_;
363 std::vector<double> tile_slope_;
364 std::vector<double> tile_q_limit_;
365 std::vector<double> tile_loss_inlet_;
366 std::vector<double> tile_loss_outlet_;
367 std::vector<double> tile_loss_avg_;
368 std::vector<double> tile_roughness_;
369 std::vector<double> tile_fm_sbot_;
370 std::vector<double> tile_fm_rbot_;
371 std::vector<uint8_t> tile_has_flap_gate_;
372 std::vector<int8_t> tile_direction_;
373
377 void refreshConduitTile(const SimulationContext& ctx);
378
379 // Per-timestep constants
380 double dt_gravity_ = 0.0;
381
382 bool last_converged_ = false;
383
393 double min_surf_area_ = constants::MIN_SURFAREA;
394
395 // Pre-allocated width-capping buffers (avoids thread_local per-call allocation)
396 std::vector<double> wcap_d1_, wcap_d2_, wcap_dm_;
397
398 // Variable timestep state (matching legacy VariableStep in dynwave.c)
399 mutable double variable_step_ = 0.0;
400
401 // Per-node working state (SoA)
402 DWNodeArrays xnode_;
403
404 // Per-link pre-computed geometry (batch-filled by XSectGroups each iteration)
405 std::vector<double> area1_;
406 std::vector<double> area2_;
407 std::vector<double> area_mid_;
408 std::vector<double> hrad_mid_;
409 std::vector<double> width_mid_;
410 std::vector<double> depth1_;
411 std::vector<double> depth2_;
412 std::vector<double> depth_mid_;
413
414 // Per-link momentum working arrays
415 std::vector<double> velocity_;
416 std::vector<double> froude_;
417 std::vector<double> sigma_;
418 std::vector<double> dqdh_;
419 std::vector<double> new_flow_;
420
421 // Per-link area from previous iteration (for unsteady term)
422 std::vector<double> area_old_;
423
424 // Per-link bypass flag (true when both end nodes converged; skip momentum solve)
425 // uint8_t instead of bool: avoids std::vector<bool> bit-packing overhead
426 std::vector<uint8_t> bypassed_;
427
428 // ------------------------------------------------------------------------
429 // B2 threading — CSR node→incident-conduit adjacency for the parallel
430 // node-centric flow gather (see gatherConduitNodeFlows). Built once in
431 // init() from static topology.
432 //
433 // PROOF OF BIT-EXACTNESS vs the serial per-link scatter: legacy
434 // findLinkFlows (dynwave.c:385-388) scatters conduits one link at a time
435 // in ascending link index; each link updates node1's accumulators, then
436 // node2's. For a given NODE, the projection of that global order is
437 // simply its incident conduit links in ascending link index (node1-end
438 // entry before node2-end entry when both ends touch the same node). CSR
439 // entries are stored per node in exactly that order, so the per-node
440 // gather performs the identical FP accumulation sequence on each
441 // accumulator (inflow, outflow, sumdqdh, new_surf_area) — bit-exact at
442 // any thread count, since each node is owned by exactly one thread.
443 // ------------------------------------------------------------------------
444 std::vector<int> csr_row_;
445 std::vector<int32_t> csr_link_;
446 std::vector<uint8_t> csr_is_n2_;
447 std::vector<uint8_t> csr_other_outfall_;
448
449 // ------------------------------------------------------------------------
450 // Virtual junctions — zero-storage, momentum-transmitting pair nodes
451 // (see plans/VIRTUAL_JUNCTION_IMPLEMENTATION_PLAN.md). vjunc_ is empty for
452 // models without [VIRTUAL_JUNCTIONS]; every hot-loop hook below is gated
453 // on that emptiness so VJ-free models compile down to the original paths.
454 // ------------------------------------------------------------------------
455 struct VJuncPair {
456 int node = -1;
457 int link_a = -1, link_b = -1;
458 int up_link = -1, dn_link = -1;
459 uint8_t through = 0;
460 double lambda = 0.0;
461
462 // Per-Picard-iteration cache (filled by vjPrepareIteration):
463 double sigma_j = 1.0;
464 double a_up_mid = 0.0;
465 double r_up_mid = 0.0;
466 double dq4j = 0.0;
467 uint8_t active = 0;
468 int8_t dirn = 0;
469
470 // Momentum-residual diagnostic accumulators (whole run):
471 double resid_max = 0.0;
472 double resid_sum = 0.0;
473 long long resid_n = 0;
474 };
475 std::vector<VJuncPair> vjunc_;
479 std::vector<int32_t> vj_pair_n1_;
480 std::vector<int32_t> vj_pair_n2_;
481
490 static constexpr double kVjWetSeedFrac = 0.02;
491 std::vector<double> vj_wet_floor_;
492
494 void buildVirtualJunctionPairs(const SimulationContext& ctx);
497 void vjPrepareIteration(const SimulationContext& ctx, double dt);
499 void vjAccumulateResiduals(SimulationContext& ctx);
500
501 // Node-dense tile of the per-node invariants setNodeDepth touches every
502 // Picard iteration. setNodeDepth reads ~20 SoA arrays per node; the seven
503 // step-invariant ones below otherwise cost seven separate cache streams
504 // (legacy's AoS TNode record pays 1-2 lines per node for the same reads).
505 // Rebuilt once per routing step in execute() — amortised over the Picard
506 // iterations and automatically correct even if the editing API mutates
507 // node geometry mid-run. y_crown pre-evaluates crownElev − invertElev
508 // with the identical operands the per-call subtraction used, so the
509 // value is bit-identical (legacy setNodeDepth recomputes it per call).
510 struct NodeTile {
511 double full_depth;
512 double y_crown;
513 double invert_elev;
514 double ponded_area;
515 double sur_depth;
516 double full_volume;
517 int32_t degree;
518 uint8_t is_storage;
519 uint8_t is_outfall;
520 uint8_t is_virtual;
521 };
522 std::vector<NodeTile> node_tile_;
523 // Unit system for node volume/surf-area table dispatch, hoisted from the
524 // per-call ucf::getUnitSystem(options.flow_units) (options are fixed
525 // during a run).
526 int unit_sys_ = 0;
527
528 // Per-link surface area contributions to upstream/downstream nodes
529 // (matching legacy Link[].surfArea1/surfArea2 from dwflow.c findSurfArea)
530 std::vector<double> surf_area1_;
531 std::vector<double> surf_area2_;
532
533 // Per-link upstream geometry (for proper weighted hyd. radius)
534 std::vector<double> hrad1_;
535 std::vector<double> width1_;
536 std::vector<double> width2_;
537
538 // Per-link head values (persisted from computeLinkGeometry for solveMomentumBatch,
539 // may be modified by flow classification for UP_CRITICAL/DN_CRITICAL cases)
540 std::vector<double> h1_;
541 std::vector<double> h2_;
542 std::vector<double> fasnh_;
543
544 // Anderson acceleration state (per-node, depth-2 mixing)
545 std::vector<double> aa_y_prev_;
546 std::vector<double> aa_g_prev_;
547 std::vector<double> aa_r_prev_;
548 std::vector<uint8_t> aa_skip_;
549
550
551 // Per-conduit momentum category (rebuilt each Picard iteration).
552 // solveMomentumBatch dispatches on category_[uj] inline — no auxiliary
553 // per-category index list is needed.
554 std::vector<MomentumCategory> category_;
555
556 // Internal methods
557 void initNodeStates(SimulationContext& ctx);
558 void findBypassedLinks(const SimulationContext& ctx);
559 void computeLinkGeometry(SimulationContext& ctx);
568 void recomputeConduitLossOne(SimulationContext& ctx, double dt, int ci);
576 void momentumKernels(SimulationContext& ctx, double dt, int step);
577
582 void processDryLink(SimulationContext& ctx, double dt, std::size_t uj);
583 void processManningLink(SimulationContext& ctx, double dt, int step,
584 std::size_t uj, MomentumCategory cat);
585 void processForceMainLink(SimulationContext& ctx, double dt, int step,
586 std::size_t uj, MomentumCategory cat);
587 void applyFlowLimits(SimulationContext& ctx, double dt, int step,
588 std::size_t uj, double& q, double qLast,
589 double barrels_d, bool isFull);
594 void updateNodeFlows(SimulationContext& ctx);
596 void buildConduitNodeCSR(const SimulationContext& ctx);
602 void gatherConduitNodeFlows(SimulationContext& ctx);
603 void computeAASkipFlags(const SimulationContext& ctx);
610 void updateNodeDepthsTeam(SimulationContext& ctx, double dt, int step,
611 int& unconv_shared);
612 void setNodeDepth(SimulationContext& ctx, int node_idx, double dt, int step);
620 void commitNodeDepthState(SimulationContext& ctx, int node_idx,
621 double y_new, double dV, double dt);
622 double getLinkStep(const SimulationContext& ctx, int link_idx) const;
623
624public:
633 bool isInitialized() const noexcept { return !xnode_.sumdqdh.empty(); }
634
636 uint8_t& nodeSurchargedFlag(int idx) { return xnode_.is_surcharged[static_cast<std::size_t>(idx)]; }
637
640 double* nodeNewSurfAreaDataMut() { return xnode_.new_surf_area.data(); }
641
649 bool isBypassed(int j) const {
650 const auto uj = static_cast<std::size_t>(j);
651 return uj < bypassed_.size() && bypassed_[uj] != 0;
652 }
653
657 double& nodeSumDqdh(int n) { return xnode_.sumdqdh[static_cast<std::size_t>(n)]; }
658
663 void setNodeDepthForTest(SimulationContext& ctx, int node_idx, double dt,
664 int step) {
665 setNodeDepth(ctx, node_idx, dt, step);
666 }
667
669 const std::vector<uint8_t>& aaSkipFlags() const { return aa_skip_; }
670
672 const DPSLinkArrays& dpsState() const { return dps_; }
674 const DPSConfig& dpsConfig() const { return dps_config_; }
676 DPSLinkArrays& dpsStateMut() { return dps_; }
677private:
678
679 // Preissmann slot helpers (matching legacy dwflow.c)
680 double getSlotWidth(double y, double y_full, double w_max, XsectShape shape) const;
681 double getCrownCutoff() const;
682
683 // Dynamic Preissmann Slot (DPS) state and methods
684 DPSConfig dps_config_;
685 DPSLinkArrays dps_;
686 double sim_time_ = 0.0;
687
689 void applyDPSGeometry(SimulationContext& ctx);
690
691 // -- TPA (SurchargeMethod::TPA, issue #156 Phase 5) ----------------------
693 std::vector<double> tpa_w_;
698 std::vector<uint8_t> tpa_latch_;
700 std::vector<uint8_t> tpa_latch_changed_;
701
706 void updateTpaLatch(SimulationContext& ctx);
707
712 void applyTpaGeometry(SimulationContext& ctx);
713
715 void updateDPSState(SimulationContext& ctx, double dt);
716
718 void spatialSmoothP(const SimulationContext& ctx);
719};
720
721} // namespace dynwave
722} // namespace openswmm
723
724#endif // OPENSWMM_DYNAMIC_WAVE_HPP
Global physical, numerical, and model constants for OpenSWMM Engine.
Structure-of-Arrays (SoA) storage for all node types.
Simulation options parsed from the [OPTIONS] section.
Cross-section geometry — unified batch + per-element API.
Shape-grouped cross-section manager for batch computation.
Definition XSectBatch.hpp:243
Dynamic wave solver — operates on entire link/node system.
Definition DynamicWave.hpp:193
double tpa_celerity
Definition DynamicWave.hpp:261
double evap_rate
Definition DynamicWave.hpp:277
std::vector< int > uf_nb_dn_
Definition DynamicWave.hpp:272
void setNumThreads(int n, std::vector< std::string > *warnings=nullptr)
Set the number of OpenMP threads for parallel loops.
Definition DynamicWave.cpp:1209
SurchargeMethod surcharge_method
Definition DynamicWave.hpp:247
void init(int n_nodes, int n_links, const XSectGroups &groups, const SimulationContext &ctx)
Definition DynamicWave.cpp:491
double uf_k3
Brunone-type k3; consumed only when active.
Definition DynamicWave.hpp:256
bool isBypassed(int j) const
Definition DynamicWave.hpp:649
DPSLinkArrays & dpsStateMut()
Mutable access to DPS state for tests that need to seed slot conditions.
Definition DynamicWave.hpp:676
std::vector< int8_t > uf_sg_up_
Definition DynamicWave.hpp:273
std::vector< int > uf_nb_up_
Definition DynamicWave.hpp:272
const DPSLinkArrays & dpsState() const
Read-only access to DPS per-conduit state arrays (for tests/diagnostics).
Definition DynamicWave.hpp:672
bool lastConverged() const
Definition DynamicWave.hpp:234
double head_tol
Definition DynamicWave.hpp:244
int unsteady_friction
Definition DynamicWave.hpp:255
NodeContinuity node_continuity
Definition DynamicWave.hpp:248
const DPSConfig & dpsConfig() const
Read-only access to DPS configuration (for tests/diagnostics).
Definition DynamicWave.hpp:674
bool anderson_accel
Enable Anderson acceleration.
Definition DynamicWave.hpp:249
double omega
Definition DynamicWave.hpp:246
int execute(SimulationContext &ctx, double dt, NonConduitFlowFunc non_conduit_fn=nullptr)
Execute one DW routing timestep.
Definition DynamicWave.cpp:1240
std::vector< int8_t > uf_sg_dn_
+1 same sense, -1 opposed
Definition DynamicWave.hpp:273
double & nodeSumDqdh(int n)
Definition DynamicWave.hpp:657
uint8_t & nodeSurchargedFlag(int idx)
Direct write access to the per-node is_surcharged flag (for tests/non-conduit scatter).
Definition DynamicWave.hpp:636
void setNodeDepthForTest(SimulationContext &ctx, int node_idx, double dt, int step)
Definition DynamicWave.hpp:663
double * nodeNewSurfAreaDataMut()
Definition DynamicWave.hpp:640
int max_trials
Definition DynamicWave.hpp:245
double getRoutingStep(SimulationContext &ctx, double fixed_step, double courant_factor)
Compute CFL-based variable timestep.
Definition DynamicWave.cpp:4007
std::function< void(SimulationContext &, double, int)> NonConduitFlowFunc
Definition DynamicWave.hpp:216
const std::vector< uint8_t > & aaSkipFlags() const
Access per-node AA skip flags (read-only, for testing/diagnostics).
Definition DynamicWave.hpp:669
bool isInitialized() const noexcept
Definition DynamicWave.hpp:633
constexpr double MIN_SURFAREA
Definition Constants.hpp:95
constexpr double DEFAULT_HEAD_TOL
Definition Constants.hpp:121
constexpr double FUDGE
Definition Constants.hpp:91
constexpr double EXTRAN_CROWN_CUTOFF
Definition Constants.hpp:137
constexpr double MAX_VELOCITY
Definition Constants.hpp:129
constexpr double SLOT_WIDTH_FACTOR
Preissmann slot width factor (slot_width = y_full * this factor).
Definition Constants.hpp:143
constexpr double OMEGA
Definition Constants.hpp:117
constexpr int DEFAULT_MAX_TRIALS
Definition Constants.hpp:125
constexpr double MIN_TIMESTEP
Definition Constants.hpp:133
constexpr double SLOT_CROWN_CUTOFF
Preissmann slot crown cutoff fraction.
Definition Constants.hpp:140
Definition DynamicWave.cpp:97
constexpr double DEFAULT_HEAD_TOL
Definition Constants.hpp:121
constexpr double OMEGA
Definition Constants.hpp:117
constexpr int DEFAULT_MAX_TRIALS
Definition Constants.hpp:125
SurchargeMethod
Surcharge method: EXTRAN (classic) or SLOT (Preissmann).
Definition DynamicWave.hpp:158
@ SLOT
Preissmann slot — fictitious narrow slot above crown.
Definition DynamicWave.hpp:160
@ TPA
Definition DynamicWave.hpp:162
@ DYNAMIC_SLOT
Dynamic slot — slot width varies with flow conditions (experimental) Sharior, S., Hodges,...
Definition DynamicWave.hpp:161
@ EXTRAN
Classic EXTRAN approach — dQ/dH for surcharged nodes.
Definition DynamicWave.hpp:159
MomentumCategory
Momentum category for branch-free per-category kernel dispatch.
Definition DynamicWave.hpp:175
@ MANNING_OPEN
Standard Manning, open channel (Froude-based sigma)
Definition DynamicWave.hpp:177
@ MANNING_CLOSED_FULL
Manning, closed conduit, surcharged (fr=0, sig=0)
Definition DynamicWave.hpp:179
@ FORCE_MAIN_HW
Force main, Hazen-Williams friction.
Definition DynamicWave.hpp:180
@ FORCE_MAIN_DW
Force main, Darcy-Weisbach friction.
Definition DynamicWave.hpp:181
@ MANNING_CLOSED_FS
Manning, closed conduit, free surface.
Definition DynamicWave.hpp:178
@ N_CATEGORIES
Definition DynamicWave.hpp:182
@ SKIP_DRY
DRY/UP_DRY/DN_DRY, aMid<=FUDGE, or is_closed.
Definition DynamicWave.hpp:176
Definition Node.cpp:38
Definition NodeCoupling.cpp:16
NodeContinuity
Node continuity formulation for depth update.
Definition SimulationOptions.hpp:143
@ EXPLICIT
Classic explicit two-branch (default)
Definition SimulationOptions.hpp:144
XsectShape
Conduit cross-section shape code.
Definition LinkData.hpp:70
double * y
Definition odesolve.c:28
Central, reentrant simulation context.
Definition SimulationContext.hpp:353
DPS configuration parameters (derived from SimulationOptions at init).
Definition DynamicWave.hpp:84
double alpha
Surcharge shock parameter (>= 2)
Definition DynamicWave.hpp:86
double c_pT_sq
c_pT^2 (pre-computed)
Definition DynamicWave.hpp:88
double c_pT
Target pressure celerity (ft/s, internal units)
Definition DynamicWave.hpp:85
double r
Decay time scale for P → 1 (seconds)
Definition DynamicWave.hpp:87
Definition DynamicWave.hpp:132
std::vector< double > dYdT
Definition DynamicWave.hpp:136
std::vector< double > old_surf_area
Surface area from last non-surcharged state.
Definition DynamicWave.hpp:134
std::vector< double > new_surf_area
Definition DynamicWave.hpp:133
void resize(std::size_t n)
Definition DynamicWave.hpp:140
std::vector< uint8_t > is_surcharged
TRUE when node depth > crown elevation.
Definition DynamicWave.hpp:138
std::vector< double > sumdqdh
Definition DynamicWave.hpp:135
std::vector< uint8_t > converged
Definition DynamicWave.hpp:137