Dynamic wave solver — operates on entire link/node system.
More...
#include <DynamicWave.hpp>
|
| void | init (int n_nodes, int n_links, const XSectGroups &groups, const SimulationContext &ctx) |
| | Allocate and initialize dynamic-wave working state for a resolved network.
|
| |
| void | setNumThreads (int n, std::vector< std::string > *warnings=nullptr) |
| | Set the number of OpenMP threads for parallel loops.
|
| |
| int | execute (SimulationContext &ctx, double dt, NonConduitFlowFunc non_conduit_fn=nullptr) |
| | Advance one dynamic-wave routing interval through the bounded Picard loop.
|
| |
| bool | lastConverged () const |
| | Report the final Picard convergence flag from the most recent execute.
|
| |
| double | getRoutingStep (SimulationContext &ctx, double fixed_step, double courant_factor) |
| | Compute the next native routing interval from link/node/virtual-pair constraints.
|
| |
| void | accumulateLinkStepStats (SimulationContext &ctx, double dt, double fixed_step, double courant_factor) const |
| | Record convergence and timestep summaries for conduit reporting.
|
| |
| bool | isInitialized () const noexcept |
| | Check whether the node head-sensitivity working array is nonempty.
|
| |
| uint8_t & | nodeSurchargedFlag (int idx) |
| | Borrow mutable per-node surcharge diagnostic state.
|
| |
| double * | nodeNewSurfAreaDataMut () |
| | Borrow writable per-node Picard surface-area accumulation storage.
|
| |
| bool | isBypassed (int j) const |
| | Check whether a link holds its previous Picard flow/geometry this iteration.
|
| |
| double & | nodeSumDqdh (int n) |
| | Borrow mutable node flow/head sensitivity accumulation.
|
| |
| void | setNodeDepthForTest (SimulationContext &ctx, int node_idx, double dt, int step) |
| | Apply the private continuity update directly for a test fixture.
|
| |
| const std::vector< uint8_t > & | aaSkipFlags () const |
| | Access per-node AA skip flags (read-only, for testing/diagnostics).
|
| |
| const DPSLinkArrays & | dpsState () const |
| | Read-only access to DPS per-conduit state arrays (for tests/diagnostics).
|
| |
| const DPSConfig & | dpsConfig () const |
| | Read-only access to DPS configuration (for tests/diagnostics).
|
| |
| DPSLinkArrays & | dpsStateMut () |
| | Mutable access to DPS state for tests that need to seed slot conditions.
|
| |
Dynamic wave solver — operates on entire link/node system.
Working arrays are allocated once at init and reused each timestep. The solver pre-computes all cross-section geometry via XSectGroups batch API before entering the momentum arithmetic loop, ensuring the inner loop is branch-free and vectorisable.
◆ NonConduitFlowFunc
Callback for computing non-conduit link flows inside the Picard loop. Parameters: (ctx, dt, picard_step) where step=0 is first iteration.
◆ aaSkipFlags()
| const std::vector< uint8_t > & openswmm::dynwave::DWSolver::aaSkipFlags |
( |
| ) |
const |
|
inline |
Access per-node AA skip flags (read-only, for testing/diagnostics).
◆ accumulateLinkStepStats()
| void openswmm::dynwave::DWSolver::accumulateLinkStepStats |
( |
SimulationContext & | ctx, |
|
|
double | dt, |
|
|
double | fixed_step, |
|
|
double | courant_factor ) const |
Record convergence and timestep summaries for conduit reporting.
Requires a completed execute with node tile/convergence flags. Both ends must converge, counting outfalls as always converged for this statistic. No-flow/unconstrained sentinel links add no CFL sample. No hydraulic solver state is changed.
- Parameters
-
| [in,out] | ctx | Matching initialized context; only conduit reporting counters/step distributions are updated. |
| [in] | dt | Weight of this completed routing interval in seconds; <=0 is a no-op. |
| [in] | fixed_step | Positive nominal route interval in seconds, used as a sample cap/reference. |
| [in] | courant_factor | Positive CFL multiplier; nonpositive values use one for reporting. |
◆ dpsConfig()
| const DPSConfig & openswmm::dynwave::DWSolver::dpsConfig |
( |
| ) |
const |
|
inline |
Read-only access to DPS configuration (for tests/diagnostics).
◆ dpsState()
| const DPSLinkArrays & openswmm::dynwave::DWSolver::dpsState |
( |
| ) |
const |
|
inline |
Read-only access to DPS per-conduit state arrays (for tests/diagnostics).
◆ dpsStateMut()
Mutable access to DPS state for tests that need to seed slot conditions.
◆ execute()
Advance one dynamic-wave routing interval through the bounded Picard loop.
Requires completed init with the same live XSectGroups and topology. Refreshes node tiles, snapshots previous midpoint areas, advances TPA latches once, then performs team geometry/momentum, surface/LID limits, flow gather/structures, outfall boundaries and bounded/optional-Anderson node updates. Updates current link/node hydraulic fields and nonconvergence diagnostics. DPS time/history and virtual diagnostics advance after the loop, including non-converged intervals; no rollback or convergence exception is supplied. Mutable group scratch and this solver cannot serve simultaneous executes. Caller owns clock advancement and run-level mass/report ledgers.
- Parameters
-
| [in,out] | ctx | Matching initialized native-unit context with fixed validated topology/side tables, current and previous routing state and prepared external forcing. No context pointer is retained. |
| [in] | dt | Positive finite routing interval in seconds, consistent with cached dt_gravity_ and old-state snapshot. |
| [in] | non_conduit_fn | Optional copied synchronous callback(ctx,dt,zero-based-iteration). Invoked once per Picard iteration on the team single thread after conduit gather; it computes/scatters structure flow and sensitivity, honors bypass flags and must not throw, retain mutable borrowed references or reenter this solver. |
- Returns
- Number of Picard iterations performed, at most max_trials; use lastConverged() for actual convergence.
◆ getRoutingStep()
| double openswmm::dynwave::DWSolver::getRoutingStep |
( |
SimulationContext & | ctx, |
|
|
double | fixed_step, |
|
|
double | courant_factor ) |
Compute the next native routing interval from link/node/virtual-pair constraints.
The first variable-step call seeds the minimum interval without counting a critical element. Subsequent calls use current midpoint geometry/Froude and dYdT, with a virtual-pair bound. Requires matching init and current state from execute. Optional OPENSWMM_DT_TRACE emits diagnostics; no finite-input validation or general non-convergence status is supplied.
- Parameters
-
| [in,out] | ctx | Matching initialized context; increments the selected critical node/link counter when a limiting element is identified. |
| [in] | fixed_step | Positive fixed routing interval in seconds; values below MIN_TIMESTEP bypass variable-step machinery. |
| [in] | courant_factor | Dimensionless positive factor enabling CFL selection; <=0 returns fixed_step unchanged. |
- Returns
- Routing interval in seconds, floored to the configured minimum then truncated to whole milliseconds on subsequent variable-step calls.
◆ init()
Allocate and initialize dynamic-wave working state for a resolved network.
Builds true-conduit tiles/maps, node adjacency, virtual pairs, momentum/geometry work arrays and optional UF/DPS/TPA state. Solver option fields (surcharge/UF/celerity etc.) must be configured before init. Converts display-unit minimum surface area/celerities to native ft units. Retains groups by address; moving/destroying/rebuilding it requires reinitialization. No context state is changed. Allocation exceptions propagate and can leave partial initialization; serialize lifecycle/execute calls on an instance.
- Parameters
-
| [in] | n_nodes | Nonnegative global node count matching ctx node arrays. |
| [in] | n_links | Nonnegative global link count matching ctx link arrays; topology/side-table indices must already be valid. |
| [in] | groups | Borrowed built cross-section groups whose mutable scratch/profile tables must remain valid and exclusively available throughout solver use. |
| [in] | ctx | Resolved immutable context supplying native geometry, topology, initial state and options; not retained as a pointer. |
◆ isBypassed()
| bool openswmm::dynwave::DWSolver::isBypassed |
( |
int | j | ) |
const |
|
inline |
Check whether a link holds its previous Picard flow/geometry this iteration.
A shared structure callback uses this to hold a converged link. Uninitialized storage returns false; read only after the corresponding Picard barrier.
- Parameters
-
| [in] | j | Global link index; negative or out-of-range values return false after size conversion. |
- Returns
- True for a nonzero initialized bypass flag, otherwise false.
◆ isInitialized()
| bool openswmm::dynwave::DWSolver::isInitialized |
( |
| ) |
const |
|
inlinenoexcept |
Check whether the node head-sensitivity working array is nonempty.
This is an allocation-state guard for shared structure callbacks, not a full initialization-validity or convergence check.
- Returns
- True when sumdqdh has elements; false before init and also for a zero-node initialization.
◆ lastConverged()
| bool openswmm::dynwave::DWSolver::lastConverged |
( |
| ) |
const |
|
inline |
Report the final Picard convergence flag from the most recent execute.
Iteration count alone does not indicate failure; an exhausted trial budget is non-converged only when this flag is false.
- Returns
- True only when the final iteration satisfied node convergence, including convergence on the last allowed trial.
◆ nodeNewSurfAreaDataMut()
| double * openswmm::dynwave::DWSolver::nodeNewSurfAreaDataMut |
( |
| ) |
|
|
inline |
Borrow writable per-node Picard surface-area accumulation storage.
No ownership transfers. Pointer/contents can be invalidated by init or destruction; coordinate writes with the solver scatter/gather phase. The C++ empty-vector data() value is not guaranteed to be null.
- Returns
- data() pointer to n_nodes entries in ft2; an empty vector pointer must not be dereferenced.
◆ nodeSumDqdh()
| double & openswmm::dynwave::DWSolver::nodeSumDqdh |
( |
int | n | ) |
|
|
inline |
Borrow mutable node flow/head sensitivity accumulation.
Meaningful inside the implicit continuity/Picard scatter. No ownership transfers; reinit/destruction invalidates it. Serialize external writes with the owning node/team phase.
- Parameters
-
| [in] | n | Valid nonnegative initialized node index, unchecked. |
- Returns
- Reference to the current sumdqdh entry in ft2/s.
◆ nodeSurchargedFlag()
| uint8_t & openswmm::dynwave::DWSolver::nodeSurchargedFlag |
( |
int | idx | ) |
|
|
inline |
Borrow mutable per-node surcharge diagnostic state.
Caller must serialize access with the Picard team. Changes affect diagnostics/AA logic and must preserve solver invariants.
- Parameters
-
| [in] | idx | Valid nonnegative initialized node index, unchecked. |
- Returns
- Reference to the flag; valid until reinitialization/reallocation or destruction.
◆ setNodeDepthForTest()
| void openswmm::dynwave::DWSolver::setNodeDepthForTest |
( |
SimulationContext & | ctx, |
|
|
int | node_idx, |
|
|
double | dt, |
|
|
int | step ) |
|
inline |
Apply the private continuity update directly for a test fixture.
Requires execute to have built the node invariant tile, and current solver accumulators. Commits depth/head/volume/overflow/dYdT through the production node path, including special LID handling. Does not independently check convergence or prepare boundary/link flows.
- Parameters
-
| [in,out] | ctx | Matching initialized context with valid current/old node state and prepared flow/surface-area inputs. |
| [in] | node_idx | Valid non-outfall node index. |
| [in] | dt | Positive timestep in seconds. |
| [in] | step | Zero-based Picard iteration; >0 enables under-relaxation paths. |
◆ setNumThreads()
| void openswmm::dynwave::DWSolver::setNumThreads |
( |
int | n, |
|
|
std::vector< std::string > * | warnings = nullptr ) |
Set the number of OpenMP threads for parallel loops.
Called after init() when the thread count is finalized. Resolution (threadinfo::dwThreads): 0 = auto — omp_get_max_threads(), the conduits-per-thread gate and the Apple Silicon P-core clamp; N > 0 = honoured exactly, subject only to the conduits-per-thread gate, with warnings when N exceeds the machine / runtime limits. SWMM_DW_THREADS forces the count outright (warned).
- Parameters
-
| n | Requested thread count ([OPTIONS] THREADS). |
| warnings | Optional sink for human-readable warnings. |
◆ ::openswmm::Router
◆ anderson_accel
| bool openswmm::dynwave::DWSolver::anderson_accel = false |
Enable Anderson acceleration.
◆ evap_rate
| double openswmm::dynwave::DWSolver::evap_rate = 0.0 |
Evaporation rate (ft/s) — set by Router::step() each timestep so that solveMomentumBatch can recompute dq6 per Picard iteration (Gap #14).
◆ head_tol
◆ max_trials
◆ node_continuity
◆ omega
| double openswmm::dynwave::DWSolver::omega = OMEGA |
◆ surcharge_method
◆ tpa_celerity
| double openswmm::dynwave::DWSolver::tpa_celerity = 100.0 |
TPA acoustic celerity a (PROJECT length units per second, converted to ft/s at init like FV_SLOT_CELERITY). Sets the constant slot width w_tpa = g·A_full/a² per conduit (TPA plan §B1). Issue #156.
◆ uf_k3
| double openswmm::dynwave::DWSolver::uf_k3 = 0.015 |
Brunone-type k3; consumed only when active.
◆ uf_nb_dn_
| std::vector<int> openswmm::dynwave::DWSolver::uf_nb_dn_ |
◆ uf_nb_up_
| std::vector<int> openswmm::dynwave::DWSolver::uf_nb_up_ |
Cross-link ∂V/∂x stencil for UF (issue #156). A full link has equal end areas, so the within-link |v2−v1| estimator is structurally ZERO in exactly the pressurized cases UF exists for (measured: pure added inertia, slight ANTI-damping). The gradient therefore comes from the neighboring conduits' in-place velocities across simple degree-2 conduit junctions. Momentum runs in serial conduit order when UF is active, preserving the existing serial stencil at every team size. Built once in init() when unsteady_friction != 0; -1 = no simple neighbor on that side (falls back one-sided / within-link).
◆ uf_sg_dn_
| std::vector<int8_t> openswmm::dynwave::DWSolver::uf_sg_dn_ |
+1 same sense, -1 opposed
◆ uf_sg_up_
| std::vector<int8_t> openswmm::dynwave::DWSolver::uf_sg_up_ |
◆ unsteady_friction
| int openswmm::dynwave::DWSolver::unsteady_friction = 0 |
Unsteady friction (issue #156 Phase 3): 0 = NONE (default, bit-inert), 1 = VITKOVSKY. Folded into the momentum denominator (so dqdh_ stays consistent with the surcharge Jacobian) with the same dead-band and half-momentum clamp as kernels::ufUpdate on the FV side.
The documentation for this class was generated from the following files:
- /home/runner/work/openswmm.engine/openswmm.engine/src/engine/hydraulics/DynamicWave.hpp
- /home/runner/work/openswmm.engine/openswmm.engine/src/engine/hydraulics/DynamicWave.cpp