Skip to content

stoiver/Simple_SW_Inlets

Repository files navigation

Simple SW Inlets

License Python Built with ANUGA Tests

A small ANUGA hydrodynamic experiment that models stormwater inlets (pits / grates / lintels) capturing water from a 2-D shallow-water surface flow, plus a Tkinter GUI for inspecting the resulting hydrographs.

The simulation places a row of inlets down a sloping channel, drives a steady inflow over them, and records how much water each inlet captures versus how much bypasses it. Each inlet captures water according to a dual-regime weir/orifice capture law driven by the local ponded depth. See docs/HYDRAULICS.md for the equations and their basis.


Contents

File Purpose
stormwater_inlets.py Reusable toolkit: inlet spec + catalogue, TOML loaders, the depth-driven capture operators (serial + MPI), and the inlet network manager. Imported by the simulation and the tests.
stormwater_inlet_simulation.py Runnable, follow-along experiment built on the toolkit; writes one hydrograph_<Asset_ID>.csv per inlet plus sloped_inlet_experiment.sww.
stormwater_inlet_viewer.py Standalone Tkinter dashboard that scans a folder for the hydrograph CSVs; a View menu switches between per-inlet diagnostic plots and a folder-combined hydrograph.
test_inlet_hydraulics.py Fast unit tests for the asset/hydraulics logic and the CSV schema (no ANUGA domain built).
test_inlet_operator_integration.py Integration tests that evolve/query a real ANUGA domain (capture law ↔ live update_Q, and mass balance).
test_parallel_inlet_mass_balance.py MPI test: shells out to mpiexec -np 2 and checks the parallel operator's global mass balance (skipped if MPI is unavailable).
config/*.toml Example TOML config (inlet catalogue + pit placements) mirroring the built-in defaults.
docs/HYDRAULICS.md The capture-law theory, equations, transition depth, and references.

The simulation and the viewer are coupled only by the CSV schema (below), not by imports; the simulation imports the toolkit.


Requirements

  • Python 3
  • anuga (the main setup hurdle — not pip-trivial)
  • numpy, pandas, matplotlib
  • tkinter (for the viewer GUI; needs a display / X server)
  • pytest (to run the tests)

ANUGA is assumed already installed in the environment; there is no package manifest or build step for this project.


Usage

Run the simulation

python stormwater_inlet_simulation.py

This builds the domain, registers the six inlets, evolves for 120 s, prints a results summary, and writes hydrograph_*.csv (one per inlet) and sloped_inlet_experiment.sww into the working directory.

By default the inlet catalogue and pit placements come from the built-in INLET_LIBRARY / PIT_PLACEMENTS. You can instead load them from TOML:

python stormwater_inlet_simulation.py \
    --library config/inlet_library.toml \
    --placements config/pit_placements.toml

The example files in config/ mirror the defaults — edit a copy to define your own inlet types ([inlets.<name>] with clear_area/effective_perimeter; quote names containing a dot, e.g. [inlets."Lintel_1.2m"]) or pit layout ([[pits]] with required id/x/y/spec and optional radius/blockage). Reading uses the stdlib tomllib (Python 3.11+); load_inlet_library() / load_pit_placements() are also importable.

The runtime is guarded by if __name__ == "__main__", so importing the module (e.g. from a notebook or the tests) does not start a simulation. You can also drive it programmatically:

import stormwater_inlet_simulation as sim

network = sim.run_experiment(yieldstep=10, finaltime=120, write_csv=True)
df = network.to_dataframe("Pit_01_SmallGrate")

Launch the hydrograph viewer

python stormwater_inlet_viewer.py

A sidebar lists the hydrograph CSVs found in the chosen directory. The View menu offers two modes:

  • Pit Hydrograph (default; shown when you select a file) — four stacked plots for that single inlet:
    1. Approach vs captured discharge over time
    2. Accumulated captured / bypassed volumes
    3. Flows with ponded depth on a twin axis
    4. A time-coloured depth-vs-discharge hysteresis loop
  • Combined Hydrograph — sums captured/bypass across every CSV in the folder onto a common time axis, plotting instantaneous flows (L/s, left axis) with the cumulative captured / bypassed / combined volumes (m³, right axis).

The viewer is HiDPI-aware (it reads the configured Xft.dpi rather than the DPI Tk reports, which is unreliable on Wayland/XWayland) and has live UI Font Size and Plot Font Size sliders. Per-machine slider values and window geometry are saved to ~/.stormwater_inlet_viewer.json.

Run the tests

python -m pytest

Tests use pytest. test_inlet_hydraulics.py is fast (no domain); test_inlet_operator_integration.py builds a small ANUGA pond and is a little slower but still runs in well under a second. test_parallel_inlet_mass_balance.py shells out to mpiexec -np 2 to exercise the parallel inlet operator; it is automatically skipped if mpi4py / mpiexec are not available.


The experiment

build_domain() creates a 100 m × 20 m channel meshed with maximum_triangle_area = 2.0, with:

  • a 1 % slope bed: elevation = 1.0 − 0.01·x (falls left → right),
  • an initially dry stage (stage = elevation), Manning friction 0.015,
  • a Dirichlet inflow on the left at stage = 1.35 (≈ 0.35 m deep entering at x = 0), a Transmissive right boundary, and Reflective side walls.

build_network() then places six inlets along the centreline (y = 10 m), each with a circular sampling footprint (default radius 1.5 m):

Asset ID x (m) Spec
Pit_01_SmallGrate 15 Grate_600x600
Pit_02_LargeGrate 28 Grate_900x900
Pit_03_ShortLintel 42 Lintel_1.2m
Pit_04_LongLintel 56 Lintel_2.4m
Pit_05_ComboSmall 70 Combo_1.2m_G600
Pit_06_ComboLarge 85 Combo_2.4m_G900

Each entry also takes an optional blockage (0.0 = clear, 1.0 = fully blocked) that derates the inlet's clear area and perimeter — e.g. add "blockage": 0.5 to a pit to model a half-clogged grate. It defaults to 0.0 and is shown in the results table.

domain.evolve(yieldstep=10, finaltime=120) runs the simulation, then print_summary() prints the steady-state table and dumps the CSVs.

Note: capture resolves over the inlet footprint, which can be a small number of triangles, so mesh density (maximum_triangle_area) at the pit location materially affects results.


Code overview

The reusable pieces live in stormwater_inlets.py (the simulation script imports them as si); the hydraulics use an asset-library + operator design (see docs/HYDRAULICS.md for the physics):

  • Inlet_specification — geometry of a standard inlet (clear_area, effective_perimeter) plus a blockage_factor. operational_area and operational_perimeter derate the geometry by blockage. INLET_LIBRARY is the catalogue of named standard inlets.
  • Depth_driven_inlet_operator(anuga.Inlet_operator) — the core. Its update_Q(t) returns the capture discharge as a negative value (water leaving the domain), computed from the inlet's region-averaged depth via the dual-regime law. The pure hydraulics are factored into the static methods transition_depth(...) and capture_discharge(...) so they can be tested without a domain. The parent Inlet_operator distributes that discharge over the inlet region and enforces mass balance.
  • Stormwater_inlet_network — registers inlets onto the domain (one small circular anuga.Region per pit), owns the per-asset capture logs, and exposes to_dataframe() for export.
  • build_network / print_summary — generic helpers: register a list of placements onto a domain, and print the steady-state results table (with an all-asset TOTAL row) while dumping the per-inlet CSVs.

The viewer is a single class, Stormwater_inlet_viewer_app, in stormwater_inlet_viewer.py.


CSV contract (the integration point)

Both scripts depend on this exact column set, written by the operator's capture log and validated by the viewer's required_headers:

Time_s, Depth_m, Approach_Q_cms, Captured_Q_cms, Bypass_Q_cms, Cum_Inflow_m3, Cum_Captured_m3, Cum_Bypassed_m3

Flows are stored in m³/s (cms) and converted to L/s only at display time. The exported per-inlet DataFrame additionally prepends an Asset_ID column. The viewer requires only the original seven columns (it ignores the extra Cum_Inflow_m3), so it still opens older CSVs.

If you rename a column in the simulation, update required_headers in stormwater_inlet_viewer.py or the GUI will reject the file.


Generated / artifact files

Running the simulation or tests produces files in the working directory that are outputs, not source: hydrograph_*.csv, sloped_inlet_experiment.sww, and the test ponds (inlet_integration_test.sww, etc.). They can be deleted and regenerated at any time.

About

ANUGA shallow-water experiment modelling depth-driven stormwater inlet (pit/grate/lintel) capture via dual-regime weir/orifice hydraulics, with a Tkinter hydrograph viewer and a pytest suite.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages