Flood inundation (local-inertial shallow water)
Full description: Read the full narrative
Rainfall-runoff inundation over real (or, when no terrain is supplied, procedurally generated) topography. The solver is the local-inertial (diffusive-inertial) form of the 2D shallow-water equations with a uniform rainfall source — the approach family of LISFLOOD-FP, SFINCS and RIM2D — discretised with Rusanov (local Lax–Friedrichs) fluxes with Audusse hydrostatic reconstruction and a semi-implicit Bates-2010 Manning friction update.
- Execution mode
- Kaggle kernel push→poll→download (numpy-only code; the kernel metadata requests the GPU accelerator) server/kaggle/simRunner.ts:126-141 (not in LOCAL_SIM_TYPES) kaggle-kernels/flood-sim/kernel-metadata.json:enable_gpu=true
- Verification
- PHYSICS MEASURED locally (solver completed; mass balance closure 0.0000 %)
- Wire scenario type
flood_inundation— contract at src/services/kaggleSim.ts:28-240; job API at Simulation job API
MEASURED marks values produced by executing the actual code on this machine (commands in Reproduction; raw logs summarised in Methodology → Evidence runs).
Governing equations and coefficients
Source attribution as stated in the kernel header (verbatim):
Solves the 2D local-inertial (diffusive-inertial) shallow water equations with a spatially uniform rainfall source term — the approach used by LISFLOOD-FP, SFINCS, and RIM2D. … Solver: Rusanov (local Lax-Friedrichs) for continuity with hydrostatic reconstruction (Audusse et al. 2004), semi-implicit Bates (2010) formulation for Manning friction.
Coefficients and named constants
| WorldCover class | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 95 | 100 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| n | 0.100 | 0.070 | 0.035 | 0.040 | 0.015 | 0.025 | 0.025 | 0.030 | 0.060 | 0.150 | 0.050 |
Parameter contract
Flood parameters. Shared request envelope (validated at the client boundary before dispatch).
| UI control | Wire field | Unit | Valid range (UI · wire · kernel) | Default | Physical meaning | Source |
|---|---|---|---|---|---|---|
| Total Rainfall slider | rainfall_mm | mm (event total) | UI 50–2000; wire 10–3000; kernel applies unvalidated | UI 500 · kernel 400 | Spatially uniform rain depth | src/components/scenarios/ScenarioEditor.tsx:102-108 src/services/kaggleSim.ts:34 kaggle-kernels/flood-sim/main.py:372 |
| Soil Saturation slider | soil_saturation | fraction | 0–1 | UI 0.8 · kernel 0.8 | Scales infiltration loss and initial ponded depth (h_init = 0.02·S) | src/components/scenarios/ScenarioEditor.tsx:102-108 src/services/kaggleSim.ts:36 kaggle-kernels/flood-sim/main.py:374,485-486 |
| Duration slider | duration_hours | h | UI 1–168 (auto-derived from rainfall/catchment); wire ≤ 720 | UI 72 · kernel 12 | Rain event length | src/components/scenarios/ScenarioEditor.tsx:102-108 src/services/kaggleSim.ts:35,640 kaggle-kernels/flood-sim/main.py:373 |
| Wind Speed slider | wind_speed_ms (optional) = km/h÷3.6 | m/s | UI 0–100 km/h; wire 0–60 | UI 40 km/h | Advisory field — not used in the solver momentum terms | src/components/scenarios/ScenarioEditor.tsx:102-108 src/services/kaggleSim.ts:38,434 |
| Catchment Area slider | — (not sent) | km² | UI 100–20,000 | 2000 | UI-only hint for derived runoff/duration suggestions | src/components/scenarios/ScenarioEditor.tsx:102-108 src/services/kaggleSim.ts:631-641 |
| dam_breach | dam_breach | — | literal true required by the schema | true | Contract constant only — the kernel contains no dam-breach hydrograph; inundation is rainfall-driven | src/services/kaggleSim.ts:37 |
| terrain / landcover (server-sampled) | terrain(+_gs), landcover(+_gs) | m; WorldCover codes | ≤ 65,536 cells each | auto | Server auto-samples land cover for flood runs when absent | src/services/kaggleSim.ts:41-55 server/kaggle/simRunner.ts:520-563 |
Outputs
| Field | Unit | Meaning | Source |
|---|---|---|---|
water_depth_final.npy | m | Final flood depth | kaggle-kernels/flood-sim/main.py:789-807 |
velocity_x/y.npy | m/s | Depth-averaged velocity | kaggle-kernels/flood-sim/main.py:789-807 |
terrain.npy | m | Elevation used | kaggle-kernels/flood-sim/main.py:789-807 |
snapshots_depth.npy + snapshot_times.npy | m; hours | Animation series | kaggle-kernels/flood-sim/main.py:789-807 |
metadata.json | — | model "local_inertial_swe", solver "bates_2010_semi_implicit", mass_balance block | kaggle-kernels/flood-sim/main.py:702-722,809-819 |
Spatial-origin semantics
Cell-centred (NY, NX) square grid, uniform dx from extent; row 0 = north (bilinear-upsample docstring shared across kernels); east face = roll(z_b, −1, axis=1), south face = roll(z_b, −1, axis=0). lat/lon are decorative (metadata/printing). kaggle-kernels/flood-sim/main.py:16,476-478,525-530,91-92,387,375-381
Documented validity limits (verbatim from the code)
'covers the entire DEM domain (not just valleys downstream of a breach)' · solver attribution: 'Rusanov (local Lax-Friedrichs) for continuity with hydrostatic reconstruction (Audusse et al. 2004), semi-implicit Bates (2010) formulation for Manning friction.' · boundary: 'the boundary can remove water but can never create it. (np.minimum = drain only.)' · truncation warning: '[WARNING] Simulation truncated at t=…h — results are partial'
Two fatal conservation gates run before the simulation (each raises and aborts): a closed-box mass-conservation test (tol 1e-9) and a lake-at-rest well-balanced test (tol 1e-6, 10 % sloped bed): "Water would spontaneously flow on sloped terrain." kaggle-kernels/flood-sim/main.py:121-366,771-783
Measured runs and timings
| Run / check | Measured result |
|---|---|
| Local direct run (64², 300 mm rain, 4 h, sat 0.8, 20 km box) | Solver completed: max depth 4.01 m, flooded 78.2 % of grid; mass balance rainfall 120.0 M m³, infiltration 7.04 M, outflow 7.73 M, clip-loss 0.000 M, closure error 0.0000 %; wall 7.5 s. Both conservation gates ran first (stdout). |
| Minimum-rain edge (10 mm, 1 h) | max depth 0.00 m, flooded 0 % — infiltration absorbed all rainfall; closure 0.0000 % |
| Output limitation observed | The npy/metadata write step fails off-Kaggle with "Read-only file system: '/kaggle'" because the output dir is hard-coded (main.py:786) — this is why flood is NOT in LOCAL_SIM_TYPES; the web pipeline runs it on Kaggle where /kaggle/working exists |
Reproduction
Commands
# Physics (computation) locally — output writing intentionally fails off-Kaggle:
cd /tmp && mkdir fl && cp <repo>/kaggle-kernels/flood-sim/main.py fl/ && cd fl && \
echo '{"grid_size":64,"rainfall_mm":300,"duration_hours":4,"soil_saturation":0.8,"extent_km":20,"wallclock_max_sec":120}' > params.json && \
python3 main.py | grep -E "VERIFY|MASS BALANCE|DONE"
# Full pipeline requires ~/.kaggle/kaggle.json (see deployment page):
curl -s -X POST http://localhost:3001/api/kaggle/simulate \
-H 'Content-Type: application/json' -d '{"type":"flood_inundation","lat":29.76,"lon":-95.37,"grid_size":256,"extent_km":20,"rainfall_mm":300,"duration_hours":4,"soil_saturation":0.8,"dam_breach":true}'