Mass balance#

Note

Engine: OpenSWMM 6 — refactored.

Continuity errors, flux totals, and routing diagnostics for a completed simulation. Reach the view via Solver.mass_balance:

with Solver("model.inp") as s:
    for _ in s.steps():
        pass

    mb = s.mass_balance
    print(mb.runoff_continuity_error)        # %
    print(mb.routing_continuity_error)       # %

Reference: openswmm_massbalance.h.


Continuity errors#

Property / method

Type

Meaning

runoff_continuity_error

float

Runoff continuity error (%).

routing_continuity_error

float

Flow routing continuity error (%).

quality_continuity_error(pollutant)

float

Per-pollutant quality continuity error (%); accepts id or index.


Flux totals#

The flux total accessors are enum-typed: passing an int still works (IntEnum), but the enum gives you discoverability and type checking:

from openswmm.engine import RunoffTotal, RoutingTotal

mb.runoff_total(RunoffTotal.RAINFALL)
mb.runoff_total(RunoffTotal.EVAP)
mb.routing_total(RoutingTotal.OUTFLOW)
mb.routing_total(RoutingTotal.FLOODING)

Quality mass losses#

mb.quality_seep_loss("TSS")       # cumulative mass lost to seepage
mb.quality_evap_loss("TSS")       # cumulative mass lost to evaporation

Pollutant argument accepts id (str) or integer index.


Routing diagnostics#

The combined routing-solver diagnostics are exposed as a single RoutingDiagnostics dataclass — typed and attribute-keyed rather than a free-form dict:

diag = mb.routing_diagnostics
print(diag.avg_time_step, diag.max_courant)
print(diag.n_steps, diag.n_steps_not_converged)
print(diag.pct_not_converged, diag.avg_iterations)

For the bare maximum Courant number on its own:

print(mb.max_courant)

When the values are meaningful#

Mass-balance results are only finalised after Solver.end() (equivalently: after the simulation loop terminates). Reading them before that gives partial / zero values without raising.


See also#