![]() |
OpenSWMM Engine
6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
|
Configuration for the 2D surface routing solver. More...
#include <SolverOptions2D.hpp>
Public Attributes | |
| Momentum2D | momentum = Momentum2D::LOCAL_INERTIAL |
| [2D_OPTIONS] MOMENTUM_EQUATION — momentum closure (see Momentum2D). | |
| int | front_rebuild = -1 |
| int | reconstruction_order = 1 |
| double | max_timestep = 10.0 |
| double | dry_depth = 0.001 |
| Dry cell threshold (m) | |
| double | limiter_epsilon = 1.0e-6 |
| double | flux_dh_eps = 0.004 |
| double | coupling_sync = 0.0 |
| double | coupling_cd = 0.65 |
| Default discharge coefficient. | |
| bool | report_2d = true |
| Write 2D results to output. | |
| OutputPrecision2D | output_precision = OutputPrecision2D::FLOAT32 |
| int | output_compression = 4 |
| unsigned | report_2d_vars = report2d::DEFAULT_MASK |
| std::vector< std::string > | report_2d_species |
| double | report_2d_step = 0.0 |
| int8_t | infiltration = -1 |
| double | infil_step = 0.0 |
| std::string | infil_default_method |
| std::string | infil_destination |
| int8_t | evaporation = 1 |
| bool | transport_pollutants = true |
| bool | transport_msx = true |
| bool | transport_age = true |
| bool | transport_temperature = true |
| int8_t | groundwater = -1 |
| std::string | gw_et |
| RainfallMode | rainfall_mode = RainfallMode::NATURAL_NEIGHBOUR |
| CellClosure2D | cell_closure = CellClosure2D::FLAT |
| FaceDepth2D | face_reconstruction = FaceDepth2D::MEAN |
| double | vfr_min_wet_frac = 0.01 |
| double | theta = 0.8 |
| [2D_OPTIONS] THETA, (0, 1] | |
| double | cfl_number = 0.7 |
| double | h_move = 0.003 |
| int | lts_tiers = 4 |
| [2D_OPTIONS] LTS_TIERS, 1..8 (1 = global dt) | |
| double | froude_max = 1.5 |
| bool | advection = false |
| double | exchange_beta = 0.8 |
| double | dispersion = 0.0 |
| double | exchange_relax = 1.0 |
| Optional EMA sub-relaxation of per-substep coupling exchange (1 = off). | |
| bool | coupling_area_auto = false |
| bool | coupling_in_flooding = false |
| Backend2D | backend = Backend2D::AUTO |
| openswmm::FilePathPair | mesh_file |
| openswmm::FilePathPair | output_file |
| double | len_1d_to_2d = 1.0 |
| 1D length → 2D length (ft→m, 0.3048) | |
| double | len_2d_to_1d = 1.0 |
| 2D length → 1D length (m→ft, 3.2808) | |
| double | vol_1d_to_2d = 1.0 |
| 1D volume → 2D volume (ft³→m³, 0.02832) | |
| double | flow_1d_to_2d = 1.0 |
| 1D flow → 2D flow (ft³/s→m³/s, 0.02832) | |
| double | flow_2d_to_1d = 1.0 |
| 2D flow → 1D flow (m³/s→ft³/s, 35.315) | |
| int | num_threads = 1 |
| int | requested_threads = 0 |
| bool | mesh_units_si = false |
| bool | mesh_scaled_to_si = false |
| double | mesh_to_si_factor = 1.0 |
| bool | pending_rows_drained = false |
| double | bc_flow_to_si_applied = 1.0 |
Configuration for the 2D surface routing solver.
Populated from [2D_OPTIONS] input section. Defaults are chosen for typical urban drainage surface routing problems.
| bool openswmm::twoD::SolverOptions2D::advection = false |
Convective momentum flux ∂(u·q)/∂n at interior faces, in Stelling–Duinmeijer staggered upwind form on the Perot cell vectors. This is the term the pure local-inertial formulation drops, and without it the scheme has no velocity head: a transcritical reach holds a FLAT free surface upstream of a control (measured on the SWASHES bump: η = 0.59 m against an analytic backwater of 1.02 m) and bores land on the wrong Rankine–Hugoniot states. Vanishes identically at rest and in uniform flow, so lake-at-rest exactness is untouched. OPT-IN while the 2D validation ladder is re-graded against it: the default reproduces the established local-inertial results exactly. [2D_OPTIONS] ADVECTION YES|NO
| Backend2D openswmm::twoD::SolverOptions2D::backend = Backend2D::AUTO |
[2D_OPTIONS] BACKEND: which marcher implementation runs the mesh. See Backend2D. Read once, at SurfaceRouter2D::initialize() (the solver is constructed there), so a mid-run edit takes effect on the next open.
| double openswmm::twoD::SolverOptions2D::bc_flow_to_si_applied = 1.0 |
Runtime-only: the display-flow-units → m³/s factor initialize() has applied IN PLACE to the constant SPECIFIED_FLOW values in BoundaryData (1.0 until it runs, and for CMS projects). The [2D_BOUNDARY_CONDITIONS] file contract is display flow units per metre — there is no SI header for flows, unlike lengths — so the writers divide edge_bc_flow by this before emitting. Never parsed/persisted.
| CellClosure2D openswmm::twoD::SolverOptions2D::cell_closure = CellClosure2D::FLAT |
| double openswmm::twoD::SolverOptions2D::cfl_number = 0.7 |
[2D_OPTIONS] CFL_NUMBER — α in dt = α·L_char/(√(gh)+|u|). L_char is derived from the discrete wave operator (InertialEdges), so α is a TRUE Courant fraction: 1.0 = linear stability limit, 0.7 default = 30% margin on any mesh.
| bool openswmm::twoD::SolverOptions2D::coupling_area_auto = false |
[2D_OPTIONS] COUPLING_AREA AUTO: derive exchange area at coupling-point resolve from the largest connected conduit (clamp(1.25·A_conduit, 0.05, 2.0) m²) for rows that did not author an explicit area.
| double openswmm::twoD::SolverOptions2D::coupling_cd = 0.65 |
Default discharge coefficient.
| bool openswmm::twoD::SolverOptions2D::coupling_in_flooding = false |
[2D_OPTIONS] COUPLING_IN_FLOODING: book the 1D→2D spill into the 1D report's "Flooding Loss" row instead of its own "2D Coupling Outflow" row. Default NO — the split row is the accurate reporting, since a coupling transfer is not flooding.
YES exists for one reason: comparing a run against a build from before the split, where the spill was inside Flooding Loss. It changes the report only; the continuity error and every routed volume are identical either way.
| double openswmm::twoD::SolverOptions2D::coupling_sync = 0.0 |
[2D_OPTIONS] COUPLING_SYNC (s): 1D↔2D co-advance sync-batch span. 0 (default) couples every routing step — exchange volumes reach the 1D with at most one routing step of lag, which keeps fill-and-spill coupling (weir/culvert ponds) free of batch-delay ringing. > 0 batches the 2D advance over ~SPAN seconds (clamped to [routing_step, 60]) — the wall-clock lever for large meshes where per-step advances degenerate to the global-dt tail; expect the held-exchange error to grow with the span.
| double openswmm::twoD::SolverOptions2D::dispersion = 0.0 |
Overland transport S2 — [2D_OPTIONS] DISPERSION <m²/s>: isotropic species dispersion coefficient (D-2DT7). 0 (default) means the dispersive face term is never entered, so pre-S2 answers are bit-identical by construction rather than by a zero coefficient multiplying through. Refused negative at parse: anti-diffusion is not a modelling case.
| double openswmm::twoD::SolverOptions2D::dry_depth = 0.001 |
Dry cell threshold (m)
| int8_t openswmm::twoD::SolverOptions2D::evaporation = 1 |
[2D_OPTIONS] EVAPORATION NO | YES | CLIMATE. 1 = YES (default, the pre-E2 sink: per-cell forcing only — swmm_2d_force_evap*). 0 = NO: the evaporation sink is zero for the run (forcing ignored). 2 = CLIMATE: unforced cells evaporate at the project [EVAPORATION] rate (climate_state.evap_rate, ft/s → m/s); forcing still overrides/adds.
| double openswmm::twoD::SolverOptions2D::exchange_beta = 0.8 |
Positivity/exchange availability fraction β: max share of a cell's volume that outgoing fluxes (or a coupling drain) may take per own-step.
| double openswmm::twoD::SolverOptions2D::exchange_relax = 1.0 |
Optional EMA sub-relaxation of per-substep coupling exchange (1 = off).
| FaceDepth2D openswmm::twoD::SolverOptions2D::face_reconstruction = FaceDepth2D::MEAN |
| double openswmm::twoD::SolverOptions2D::flow_1d_to_2d = 1.0 |
1D flow → 2D flow (ft³/s→m³/s, 0.02832)
| double openswmm::twoD::SolverOptions2D::flow_2d_to_1d = 1.0 |
2D flow → 1D flow (m³/s→ft³/s, 35.315)
| double openswmm::twoD::SolverOptions2D::flux_dh_eps = 0.004 |
Head-difference regularization (m) for the diffusive-wave flux √|Δη|. Below this gradient the flux is linearized (C¹) so the transmissivity stays bounded as the water surface flattens — without it, deep near-level ponding (e.g. a large design storm draining) makes the flux Jacobian blow up and the implicit step collapse. Only affects millimeter-scale gradients, so bulk flow is preserved; raise it for extra robustness on very deep problems. Default 4 mm; 0 = bare √. Parsed from [2D_OPTIONS] FLUX_DH_EPS; env OPENSWMM_2D_FLUX_DH_EPS overrides. Diffusive-flux gradient floor (m)
| int openswmm::twoD::SolverOptions2D::front_rebuild = -1 |
[2D_OPTIONS] FRONT_REBUILD AUTO|YES|NO — rebuild the flux-active set as soon as a wetting front reaches the edge of the active halo instead of waiting for the fixed rebuild cadence (kRebuildEveryCycles macro cycles). Without it a dry-bed front can advance at most one cell ring per cadence — the stall that pins the SWASHES Ritter/Thacker results. AUTO (default): YES for FULL_SWE / DIFFUSIVE_WAVE, NO for LOCAL_INERTIAL (which stays bit-identical to its pre-2026-09 results). -1 AUTO, 0 NO, 1 YES
| double openswmm::twoD::SolverOptions2D::froude_max = 1.5 |
[2D_OPTIONS] FROUDE_MAX face |u| clamp
| int8_t openswmm::twoD::SolverOptions2D::groundwater = -1 |
[2D_OPTIONS] GROUNDWATER YES|NO. -1 = AUTO (unset): the kernel runs iff any [2D_AQUIFER*] row was authored — exactly what it did before this key existed, so a deck without it is unchanged. NO keeps the rows (they still save) and runs without the subsurface; YES with no rows is a deck that expects groundwater and has none, and says so.
| std::string openswmm::twoD::SolverOptions2D::gw_et |
[2D_OPTIONS] GW_ET NONE | CAPILLARY_RISE | BOUNDARY_ET | BOTH — an ALIAS of the [2D_AQUIFER_OPTIONS] key of the same name, which is the single source of truth (GwOptions::gw_et is what the kernel reads and what the writer emits). Empty = not spelled here; SWMMEngine::open folds a spelled value into GwOptions and clears this, so the value is never stored — or written — in two places.
| double openswmm::twoD::SolverOptions2D::h_move = 0.003 |
Flux-activation depth (m): cells below it are source-only (lazy rain accumulation, no face flux). Hysteresis band ±1 mm around it. [2D_OPTIONS] H_MOVE (m) — flux-active cell threshold; the marcher's on/off hysteresis band is min(1 mm, h_move/2), so thin-depth models (H_MOVE ≪ 1 mm) activate near h_move as requested.
| std::string openswmm::twoD::SolverOptions2D::infil_default_method |
[2D_OPTIONS] INFIL_DEFAULT_METHOD token (NONE | HORTON | MOD_HORTON | GREEN_AMPT | MOD_GREEN_AMPT | CURVE_NUMBER | CONSTANT). Empty = unset: the '' row of [2D_INFILTRATION_DEFAULTS] governs. NONE drops the '' row for the run; a method must match the '*' row (its parameters live there) — a mismatch is an initialize error, a missing row a warning.
| std::string openswmm::twoD::SolverOptions2D::infil_destination |
[2D_OPTIONS] INFIL_DESTINATION token (LOST | SUBCATCH_AQUIFER | AQUIFER_2D). Empty = LOST. Applied at initialize to every [2D_INFILTRATION*] row that did not spell its own DEST column. SUBCATCH_AQUIFER routes to the containing subcatchment's legacy aquifer (U3); AQUIFER_2D is authoring-only until the G1 kernel.
| double openswmm::twoD::SolverOptions2D::infil_step = 0.0 |
[2D_OPTIONS] INFIL_STEP (seconds). The canonical home of the [2D_INFILTRATION_OPTIONS] INFIL_STEP value; the old section is still read. 0 = unset (the section value, else the project WET_STEP). When both are present this one wins.
| int8_t openswmm::twoD::SolverOptions2D::infiltration = -1 |
[2D_OPTIONS] INFILTRATION YES|NO. -1 = AUTO (unset): infiltration is on iff any [2D_INFILTRATION*] row resolved (the pre-E2 rule). 0 = NO: rows are kept in the model but Infil2D is deactivated for the run. 1 = YES: explicit; warns when no row resolves.
| double openswmm::twoD::SolverOptions2D::len_1d_to_2d = 1.0 |
1D length → 2D length (ft→m, 0.3048)
| double openswmm::twoD::SolverOptions2D::len_2d_to_1d = 1.0 |
2D length → 1D length (m→ft, 3.2808)
| double openswmm::twoD::SolverOptions2D::limiter_epsilon = 1.0e-6 |
Slope limiter epsilon
| int openswmm::twoD::SolverOptions2D::lts_tiers = 4 |
[2D_OPTIONS] LTS_TIERS, 1..8 (1 = global dt)
| double openswmm::twoD::SolverOptions2D::max_timestep = 10.0 |
Max marcher step (s): caps film-cell CFL steps (and thus the LTS tier spread) and the co-advance sync-batch span.
| openswmm::FilePathPair openswmm::twoD::SolverOptions2D::mesh_file |
Path from [2D_MESH_FILE] FILE token. Empty = mesh is inline in main .inp. .absolute is filled by resolve_external_file_slots() against the source .inp directory, which is what lets the writer re-anchor a RELATIVE token when saving to a different folder (without it, a Save-As left the .2dm reference pointing at the old directory).
| bool openswmm::twoD::SolverOptions2D::mesh_scaled_to_si = false |
Runtime-only: true after SurfaceRouter2D::initialize() applied the FLOW_UNITS ft→m in-place mesh scaling (vx/vy/vz, coupling areas). Lets serialization (InpWriter, GeoPackage) un-scale back to the authored units, and makes a repeated initialize() idempotent against double-scaling. Never parsed from input, never persisted.
| double openswmm::twoD::SolverOptions2D::mesh_to_si_factor = 1.0 |
Runtime-only: the linear factor SurfaceRouter2D::initialize() applied to the authored mesh coordinates to reach the solver's SI metres — 0.3048 for US FLOW_UNITS, 1.0 for SI projects and for meshes that declared ;; UNITS: SI (m). Equivalently: metres per model-CRS linear unit. Georeferenced output (Default2DOutputPlugin) writes this into the /crs variable so a consumer can return the stored metric coordinates to the model CRS's own unit exactly. Never parsed/persisted.
| bool openswmm::twoD::SolverOptions2D::mesh_units_si = false |
When true, the inline .inp or referenced .2dm declared ;; UNITS: SI (m) (or an equivalent metric keyword). The mesh on disk is already in SI metres, so SurfaceRouter2D::initialize SKIPS the FLOW_UNITS-based mesh scaling (vx/vy/vz and the coupling areas). The 1D⇄2D coupling factors (len_1d_to_2d, vol_1d_to_2d, flow_*) are unaffected — they are always the feet⇄metres conversion (the 1D side is always feet), not the mesh scaling.
| Momentum2D openswmm::twoD::SolverOptions2D::momentum = Momentum2D::LOCAL_INERTIAL |
[2D_OPTIONS] MOMENTUM_EQUATION — momentum closure (see Momentum2D).
| int openswmm::twoD::SolverOptions2D::num_threads = 1 |
Runtime-only: resolved OpenMP thread count for the embarrassingly- parallel 2D per-cell / per-vertex loops (RHS pipeline, Jacobi preconditioner, post-step diagnostics). Set in SurfaceRouter2D::initialize() from SimulationOptions::num_threads (the global THREADS option) using the same min(N,max) + size-gate DWSolver::setNumThreads applies. 1 = serial. The parallelised loops use schedule(static) and write only their own cell/vertex slot, so any thread count is bit-identical to serial. Never parsed/persisted.
| int openswmm::twoD::SolverOptions2D::output_compression = 4 |
[2D_OPTIONS] OUTPUT_COMPRESSION 0..9 — zlib level on chunked datasets; the byte-shuffle filter precedes it whenever level > 0. 0 = none.
| openswmm::FilePathPair openswmm::twoD::SolverOptions2D::output_file |
HDF5 output file path from [2D_OPTIONS] OUTPUT_FILE token. Empty = no 2D output is written. Resolved relative to the parent .inp directory at the point of use (SWMMEngine::open) and re-anchored on save from .absolute, same as mesh_file.
| OutputPrecision2D openswmm::twoD::SolverOptions2D::output_precision = OutputPrecision2D::FLOAT32 |
[2D_OPTIONS] OUTPUT_PRECISION FLOAT32|FLOAT64 — storage type of the time-varying datasets and envelopes (geometry stays float64).
| bool openswmm::twoD::SolverOptions2D::pending_rows_drained = false |
Runtime-only: true after SurfaceRouter2D::initialize() drained the pending [2D_BOUNDARY_CONDITIONS] / [2D_EDGE_CONVEYANCE] rows into BoundaryData / MeshData::edge_conveyance. Serialization collectors (Serialize2D.hpp) switch to the drained arrays once this is set — they are the live state that post-initialize API mutations edit; the retained pending rows would be stale. Never parsed/persisted.
| RainfallMode openswmm::twoD::SolverOptions2D::rainfall_mode = RainfallMode::NATURAL_NEIGHBOUR |
| int openswmm::twoD::SolverOptions2D::reconstruction_order = 1 |
[2D_OPTIONS] RECONSTRUCTION_ORDER 1|2 — FULL_SWE only: 1 = piecewise constant (first-order Godunov, forward Euler); 2 = MUSCL on (η, u, v) with the Barth–Jespersen-limited Green-Gauss gradient + SSP-RK2 (global-dt mode; LTS_TIERS > 1 is reduced to 1 with a warning).
| bool openswmm::twoD::SolverOptions2D::report_2d = true |
Write 2D results to output.
| std::vector<std::string> openswmm::twoD::SolverOptions2D::report_2d_species |
[2D_OPTIONS] REPORT_2D_SPECIES — species row names to write; empty = every row the transport layout carries.
| double openswmm::twoD::SolverOptions2D::report_2d_step = 0.0 |
[2D_OPTIONS] REPORT_2D_STEP — 2D-only report interval (seconds); 0 = follow [OPTIONS] REPORT_STEP. Validated at start to be a positive multiple of REPORT_STEP.
| unsigned openswmm::twoD::SolverOptions2D::report_2d_vars = report2d::DEFAULT_MASK |
[2D_OPTIONS] REPORT_2D_VARIABLES — bitmask of report2d::Var groups (tokens, or presets DEFAULT | MINIMAL | ALL).
| int openswmm::twoD::SolverOptions2D::requested_threads = 0 |
Runtime-only: the RAW [OPTIONS] THREADS value (0 = auto) copied in SurfaceRouter2D::initialize(), handed to the Kokkos OpenMP plugin as OpenSwmmGpuProbe::requested_threads (ABI v4) so the 2D host backend follows THREADS like the 1D solvers. Never parsed/persisted.
| double openswmm::twoD::SolverOptions2D::theta = 0.8 |
[2D_OPTIONS] THETA, (0, 1]
Face-update θ weighting (de Almeida & Bates 2013): 1 = pure Bates 2010 (no numerical diffusion), <1 blends the Perot-reconstructed neighbour discharge to damp thin-film checkerboarding on steep faces.
| bool openswmm::twoD::SolverOptions2D::transport_age = true |
| bool openswmm::twoD::SolverOptions2D::transport_msx = true |
| bool openswmm::twoD::SolverOptions2D::transport_pollutants = true |
[2D_OPTIONS] TRANSPORT_POLLUTANTS | TRANSPORT_MSX | TRANSPORT_AGE | TRANSPORT_TEMPERATURE YES|NO — the 2D column of the Domain × Species matrix (transport::resolve). NO drops that class's rows from the surface transport state; the 1D side is unaffected.
| bool openswmm::twoD::SolverOptions2D::transport_temperature = true |
| double openswmm::twoD::SolverOptions2D::vfr_min_wet_frac = 0.01 |
Wetted-area-fraction floor ε of the regularized VFR closure: below wet fraction ε the η(V) relation continues linearly (slope 1/(εA)), bounding dη/dV for the implicit solvers' Newton/Jacobian path. Exact elsewhere. Only used when CELL_CLOSURE = VFR. Parsed from [2D_OPTIONS] VFR_MIN_WET_FRAC; valid range (0, 0.5].
| double openswmm::twoD::SolverOptions2D::vol_1d_to_2d = 1.0 |
1D volume → 2D volume (ft³→m³, 0.02832)