OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
openswmm::fv::FvOptions Struct Reference

Knobs for FLOW_ROUTING FV. More...

#include <FvOptions.hpp>

Collaboration diagram for openswmm::fv::FvOptions:

Public Attributes

double cell_length = 0.0
 
int min_cells = 4
 
int pressure_closure = 0
 
int unsteady_friction = 0
 0 = NONE (default, bit-inert), 1 = VITKOVSKY.
 
double uf_k3 = 0.015
 Brunone-type k3 coefficient; consumed only when unsteady_friction != 0.
 
double cfl = 0.5
 
RiemannSolver riemann = RiemannSolver::HLLC
 
int order = 1
 1 | 2 (MUSCL-Hancock)
 
Limiter limiter = Limiter::MINMOD
 
ScalarScheme scalar_scheme = ScalarScheme::MUSCL
 
TimeIntegration time_integration = TimeIntegration::EULER
 
double slot_celerity = 100.0
 
bool pressurized_implicit = false
 
StructureCoupling structure_coupling = StructureCoupling::SUBSTEP
 
Backend backend = Backend::AUTO
 
long min_parallel_cells = 20000
 
bool compaction = true
 
bool lts = true
 
bool node_feedback_dt = false
 
int lts_max_tiers = 6
 Maximum LTS tier count (tier k advances at 2^k·dt₀). 6 ⇒ 64× spread.
 
int cfl_census_interval = 1
 
double dispersion = 0.0
 

Detailed Description

Knobs for FLOW_ROUTING FV.

Length-dimensioned members (cell_length, slot_celerity) are stored in INTERNAL units (feet, ft/s) — OptionsHandler converts from the project's display units on parse, exactly as HEAD_TOLERANCE is handled for DW.

Member Data Documentation

◆ backend

Backend openswmm::fv::FvOptions::backend = Backend::AUTO

◆ cell_length

double openswmm::fv::FvOptions::cell_length = 0.0

Target Δx. 0 ⇒ no length target, and each conduit gets min_cells.

0 ⇒ each conduit is cut into max(min_cells, ceil(L/cell_length)) cells. Internal units (ft).

◆ cfl

double openswmm::fv::FvOptions::cfl = 0.5

◆ cfl_census_interval

int openswmm::fv::FvOptions::cfl_census_interval = 1

Recompute the global CFL min-reduction every k substeps instead of every substep. 1 = every substep (exact).

INERT BEFORE 2026-08-20. The accepted-substep tail wrote the step it had just taken into the census cache and forced the countdown to zero, so the pre-step census ran every substep for every value of k. The step taken and the Courant bound are now separate quantities (dt_cache_ vs dt_census_) and the countdown survives; a retry — the post-step census proving the bound inadmissible — still resets it. The default of 1 is bit-identical across the change.

NOT YET SWEPT. k > 1 throttles only the PRE-step census; the post-step acceptance census still runs every substep and is the safety net that makes skipping the pre-step one defensible at all. The ceiling on this option is therefore ~2× on census cost, not k×. Measure before raising the default (Phase 1, FV1D_PERF_PLAN_REVISED_2026-08-20.md).

◆ compaction

bool openswmm::fv::FvOptions::compaction = true

Dry/inactive work-list compaction. Results-transparent by contract: a compacted run must reproduce the non-compacted run bit-for-bit on the same backend (§6.10).

◆ dispersion

double openswmm::fv::FvOptions::dispersion = 0.0

Longitudinal dispersion coefficient (ft²/s). 0 disables the parabolic term entirely (advection only). Treated implicitly per D-FV1 so the Δx²/(2·D_L) constraint never binds.

◆ limiter

Limiter openswmm::fv::FvOptions::limiter = Limiter::MINMOD

◆ lts

bool openswmm::fv::FvOptions::lts = true

Local time stepping — stiff cells (short Δx, pressurized) substep at their own dt while the rest advance at the macro step. When tiering finds nothing to separate the solver falls through to the global-dt path bit-for-bit, so this is on by default (plan §3.3).

◆ lts_max_tiers

int openswmm::fv::FvOptions::lts_max_tiers = 6

Maximum LTS tier count (tier k advances at 2^k·dt₀). 6 ⇒ 64× spread.

◆ min_cells

int openswmm::fv::FvOptions::min_cells = 4

Floor on cells per conduit. A FLOOR, not a FINE-mode detail: it applies with or without a cell_length target.

Four, not one. A conduit meshed as a single cell has no interior gradient of its own and presents an artificial bed step of half its fall at every manhole (§8.3), so it under-conveys and backs water up. Measured on Example1 — mean absolute peak-flow deviation from DYNWAVE, and wall-clock relative to one cell:

cells      1       2       4       8
deviation  37.1 %  25.7 %  15.3 %   7.6 %
worst     -75.8 % -58.1 % -43.2 % -22.6 %
time       1.0x    1.4x    2.2x    5.4x

Four is the knee: it more than halves the one-cell error for about twice the cost, and convergence past it is slower than its price. One cell was the default and should not have been — it is a known-wrong setting, not a cheap-but-approximate one. Raise this (or set cell_length) where peak flows or in-conduit profiles matter.

◆ min_parallel_cells

long openswmm::fv::FvOptions::min_parallel_cells = 20000

Small-problem gate: below this cell count AUTO stays on the CPU because per-kernel launch overhead dominates. Carried over from the 2D marcher's measured recalibration (plan §2 guardrails).

◆ node_feedback_dt

bool openswmm::fv::FvOptions::node_feedback_dt = false

Bound the explicit step by the ALGEBRAIC JUNCTION feedback limit. Opt-in: correct but costly (see the wall-time note below).

An algebraic junction has no volume state, so it carries no storage bound and was exempted from the step census on both paths. But its head is solved from the instantaneous flux balance and then handed to the incident cells as a ghost, so the neighbours integrate against a boundary state that can travel a long way inside one step. That feedback is explicit and has its own limit (algebraicNodeStableDt):

tau = min_i(0.5*dx_i*T_i) / sum_j(T_j*c_j)

min in the numerator, not sum: every incident conduit pushes flux (the sum), but the solved head must resolve on the TIGHTEST incident storage. Summing – what legacy DW does for its own node continuity – makes the bound LOOSER at exactly the junctions that need it (a 12 ft barrel meeting a 3 ft one gives a 2123 ft effective length against a 250 ft cell). Gated on the junction being pressurized, so open-channel networks pay nothing.

Relative to the cell bound this is 1/(2n) * (T_min/T_max) – purely geometric: 4x for two equal barrels, 32x across a 16:1 area step. Those are the factors the EPA QA decks were measured to need, and they are CELERITY-INVARIANT (T ~ 1/c^2 cancels), which is why lowering FV_SLOT_CELERITY suppresses the symptom without fixing the bound.

The constraint is applied to the junction's INCIDENT CELLS in assignTiers, not to dt_node: a plain junction integrates no state and is pinned to its finest incident cell, so routing it through dt_node discards the tier while still dragging dt0 down. On the cells it is an ordinary local CFL number and tiering localises it normally.

Measured at stock FV_CFL 0.5 with LTS on (zigzag = total variation / range of the worst link, against dynamic wave): test5 37.95 -> 4.97 (DW 5.08), peak Q 1.06x -> 1.01x, 8.5 s -> 121 s test2 52.01 -> 2.99 (DW 6.87), peak Q 11.9x -> 0.99x, 1.0 s -> 9.7 s It also closes an accuracy hole unrelated to oscillation: on the culvert fixture the un-tiered path floods 0.885 acre-ft against DW's 0.003, and 0.001 with this on.

Default OFF because of that 10-14x wall cost on pressurized networks. The cost is the bound doing its job – a stiff junction genuinely needs a small step – but it is the user's call whether to pay it. It does NOT disable tiering (an earlier revision did): LTS still localises the cost, and turning LTS off instead costs 376 s / 38 s on the same decks.

◆ order

int openswmm::fv::FvOptions::order = 1

1 | 2 (MUSCL-Hancock)

◆ pressure_closure

int openswmm::fv::FvOptions::pressure_closure = 0

[OPTIONS] FV_PRESSURE_CLOSURE SLOT|TPA. 0 = SLOT (default, parity-preserving), 1 = TPA (Vasconcelos/Wright/Roe 2006): a per-cell regime flag extends the slot line to ΔA < 0 (sub-atmospheric full-pipe flow), with venting governed by atmosphere contact. FV_SLOT_CELERITY doubles as the TPA acoustic celerity a (same physical dial). Plan: plans/TPA_TWO_COMPONENT_PRESSURE_PLAN.md + MIXED_FLOW §2.2.

◆ pressurized_implicit

bool openswmm::fv::FvOptions::pressurized_implicit = false

Integrate the acoustic/slot pair implicitly on the pressurized subset (slot program R2a, Strategy E). Above the taper band the closure is linear in head, so cells at/above band entry solve an SPD head system per substep (Thomas on chains, Jacobi-CG past folded junctions) whose back-substituted face discharges overwrite f_mass_ — a pure flux predictor: conservation, rollback and hot start are untouched, and a run that never pressurizes is bit-identical with the option on.

With it, pressurized cells are advection-bound in the step census — FV_SLOT_CELERITY leaves the dt law entirely, making the slot width a pure accuracy parameter (a narrow slot no longer costs runtime). Default OFF while the R2 gates land; the R4 default flip is a separate, deliberate commit.

◆ riemann

RiemannSolver openswmm::fv::FvOptions::riemann = RiemannSolver::HLLC

◆ scalar_scheme

ScalarScheme openswmm::fv::FvOptions::scalar_scheme = ScalarScheme::MUSCL

◆ slot_celerity

double openswmm::fv::FvOptions::slot_celerity = 100.0

Pressurized wave speed (ft/s internal). Sets the Preissmann slot top width through T_slot = g·A_full/c², so it is a direct accuracy/cost dial: physical acoustic speeds would crush the global CFL step. Default 100 ft/s is the same order DW's SLOT surcharge method produces.

◆ structure_coupling

StructureCoupling openswmm::fv::FvOptions::structure_coupling = StructureCoupling::SUBSTEP

◆ time_integration

TimeIntegration openswmm::fv::FvOptions::time_integration = TimeIntegration::EULER

◆ uf_k3

double openswmm::fv::FvOptions::uf_k3 = 0.015

Brunone-type k3 coefficient; consumed only when unsteady_friction != 0.

◆ unsteady_friction

int openswmm::fv::FvOptions::unsteady_friction = 0

0 = NONE (default, bit-inert), 1 = VITKOVSKY.


The documentation for this struct was generated from the following file: