SWMMVis  6.0.0-alpha.4
Qt6/C++ GIS-based graphical user interface for the SWMMVis engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
mesh::CflStats Struct Reference

The 2D marcher's CFL characteristic length, per cell and summarised. More...

#include <meshcellstats.h>

Collaboration diagram for mesh::CflStats:

Public Attributes

double min = 0.0
 The cell that sets dt0.
 
double p10 = 0.0
 
double p50 = 0.0
 
double p90 = 0.0
 
double max = 0.0
 
double ratio = 0.0
 p50 / min. Reportable, not a gate — see ltsWork.
 
int impliedTiers = 0
 
double ltsWork = 0.0
 
int count = 0
 Cells measured; 0 = stats invalid.
 
int interiorFaces = 0
 
int isolatedCells = 0
 No interior face; used the 2A/xi_max fallback.
 

Detailed Description

The 2D marcher's CFL characteristic length, per cell and summarised.

This is the quantity that actually sets the explicit timestep, and it is NOT triangle area: a thin triangle can carry a respectable area and still have a tiny L_char. The engine computes

L_char[t] = sqrt( 2*A_t / SUM_f( xi_f * inv_dx_normal_f ) )

over that cell's INTERIOR faces, where xi_f is the shared edge length and inv_dx_normal_f is 1 / max(|dc . n|, 0.3*|dc|) with dc the centroid offset to the neighbour. Then dt = alpha * L_char / (sqrt(g*h) + |u|).

Mirrored from openswmm.engine src/engine/2d/solver/InertialEdges.cpp:41-135 (edge assembly and cell_lchar) and src/engine/2d/mesh/MeshBuilder.cpp:44-175 (edge-vertex convention, centroid, area, unit normal). The engine's derivation of that formula is dated 2026-08-03 and has changed once already, so a divergence check against the engine's own arrays belongs in the test, not in a comment.

Caveats, because this is a geometric proxy and not a runtime prediction: dt0 is taken over WET cells only, depth enters as 1/sqrt(g*h), and coupling and boundary cells pin to LTS tier 0 regardless of their size.

Units are the project CRS's, which may be feet.

Member Data Documentation

◆ count

int mesh::CflStats::count = 0

Cells measured; 0 = stats invalid.

◆ impliedTiers

int mesh::CflStats::impliedTiers = 0

Tiers local timestepping would need to cover the spread, versus the project's LTS_TIERS (default 4, so 8x is all it can hide).

◆ interiorFaces

int mesh::CflStats::interiorFaces = 0

◆ isolatedCells

int mesh::CflStats::isolatedCells = 0

No interior face; used the 2A/xi_max fallback.

◆ ltsWork

double mesh::CflStats::ltsWork = 0.0

Work proxy: relative marcher cost per unit simulated time at uniform depth, (1/min) * SUM_t 2^-tier(t) with the engine's tier rule min(K-1, floor(log2(L_t/min))). Runtime is a PRODUCT of cell count and 1/min, so this is the honest single number — a spread ratio alone is blind to a refinement explosion, which lowers the median and so improves the ratio while making the mesh strictly worse. Lower is better; compare conditioned against unconditioned.

◆ max

double mesh::CflStats::max = 0.0

◆ min

double mesh::CflStats::min = 0.0

The cell that sets dt0.

◆ p10

double mesh::CflStats::p10 = 0.0

◆ p50

double mesh::CflStats::p50 = 0.0

◆ p90

double mesh::CflStats::p90 = 0.0

◆ ratio

double mesh::CflStats::ratio = 0.0

p50 / min. Reportable, not a gate — see ltsWork.


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