Landslide debris flow (Voellmy–Salm depth-averaged)
Full description: Read the full narrative
Slope failure begins with a Mohr–Coulomb infinite-slope assessment over a susceptibility field (with Newmark-style seismic, effective-stress rainfall, and lahar triggers), converts susceptible steep cells into an initial debris mass, and routes it with the depth-averaged Voellmy–Salm equations using Rusanov mass fluxes and a semi-implicit momentum update. μ and ξ are free calibration parameters — the platform ships an endpoint to fit them against an observed runout.
- Execution mode
- Kaggle kernel (numpy, CPU instance); local in-process for calibration & Monte-Carlo server/kaggle/simRunner.ts:126-141 server/kaggle/localRunner.ts:1-15
- Verification
- MEASURED locally — convergence/conservation script PASS re-executed
- Wire scenario type
landslide— 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):
Voellmy-Salm friction law: τ_b/ρ = μ_c·g·h·cos²θ + g·u·|u|/ξ where μ_c = tan φ_res is the residual (dynamic) basal friction and ξ (m/s²) is Voellmy's turbulent coefficient. Debris: φ_res ≈ 14°, ξ ≈ 300.
Coefficients and named constants
| Name | Value | Meaning | Source |
|---|---|---|---|
| G | 9.81 m/s² | Gravity | kaggle-kernels/landslide-sim/main.py:54 |
| RHO_DEBRIS | 2000 kg/m³ | Bulk debris density (sediment + water) | kaggle-kernels/landslide-sim/main.py:55 |
| φ_res / μ_default | 14° / tan φ ≈ 0.249 | Residual friction angle (μ = 0.25 UI default) | kaggle-kernels/landslide-sim/main.py:68-69 |
| ξ_default | 300 m/s² | Turbulent coefficient (range 100–1000 in comment: "ξ=300 gives ~6–11 m/s on realistic slopes") | kaggle-kernels/landslide-sim/main.py:59-70 |
| φ / c defaults | 35° / 500 Pa | Mohr–Coulomb strength (overridable per run) | kaggle-kernels/landslide-sim/main.py:73-74 |
| PGA / rain thresholds | 0.15 g / 150 mm | Trigger defaults | kaggle-kernels/landslide-sim/main.py:77-78 |
| V_MAX / CFL | 30 m/s / 0.15 | Velocity cap and inner substep criterion | kaggle-kernels/landslide-sim/main.py:326-327,503-509 |
| Source construction | sus > 0.4, slope > 25°, radius 0.32·gs, h = sus·(slope/30)·6 ∈ [2,15] m, capped at 5 % of grid | Localized failure mass (rationale comments for each guard) | kaggle-kernels/landslide-sim/main.py:391-421 |
Parameter contract
Landslide 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 |
|---|---|---|---|---|---|---|
| Trigger Type select | trigger_type | enum | earthquake | rainfall | volcanic | earthquake | Which failure mechanism maps rainfall/PGA fields to susceptibility | src/components/scenarios/ScenarioEditor.tsx:114-134 src/services/kaggleSim.ts:211 kaggle-kernels/landslide-sim/main.py:298 |
| Earthquake Magnitude slider | magnitude | M | UI 4–9.5; wire 3–9.7 | UI 6.5 · kernel 6.5 | Feeds the PGA field only under earthquake trigger | src/components/scenarios/ScenarioEditor.tsx:114-134 src/services/kaggleSim.ts:212 kaggle-kernels/landslide-sim/main.py:299 |
| PGA Threshold slider | pga_threshold | g | UI 0.05–0.5 (auto-lowered with M); wire 0.01–1 | UI 0.15 · kernel 0.15 | Cell activates when local PGA exceeds it | src/components/scenarios/ScenarioEditor.tsx:114-134 src/services/kaggleSim.ts:213,625 kaggle-kernels/landslide-sim/main.py:300 |
| Total Rainfall slider | rainfall_mm | mm | UI 50–2000; wire 0–3000 | UI 200 · kernel 200 | Rain-trigger susceptibility via effective-stress loss (≤ 70 %) | src/components/scenarios/ScenarioEditor.tsx:114-134 src/services/kaggleSim.ts:214 kaggle-kernels/landslide-sim/main.py:302,252-260 |
| Friction Angle / Cohesion sliders | friction_angle, cohesion | °; Pa | UI 20–50 / 0–2000; wire 10–60 / 0–5000 | 35° / 500 Pa | Mohr–Coulomb strength in the FS criterion | src/components/scenarios/ScenarioEditor.tsx:114-134 src/services/kaggleSim.ts:215-216 kaggle-kernels/landslide-sim/main.py:304-305 |
| Voellmy μ slider | mu | — | UI 0.05–0.5; wire 0.01–1 | UI 0.25 · kernel tan 14° ≈ 0.249 | Dry (dynamic) Coulomb friction — free calibration parameter | src/components/scenarios/ScenarioEditor.tsx:114-134 src/services/kaggleSim.ts:230 kaggle-kernels/landslide-sim/main.py:311 |
| Voellmy ξ slider | xi | m/s² | UI 50–1500; wire 10–5000 | UI 300 · kernel 300 | Turbulent friction coefficient — free calibration parameter | src/components/scenarios/ScenarioEditor.tsx:114-134 src/services/kaggleSim.ts:232 kaggle-kernels/landslide-sim/main.py:312 |
| Bed Entrainment Rate / Erodible Depth sliders | entrainment_rate, erodible_depth_m | 1/s; m | UI 0–0.01 / 0–20; wire 0–0.1 / 0–50 | UI 0 / 5 · kernel 0 / 0 (off) | Velocity-proportional growth of the flow by bed erosion (default disabled) | src/components/scenarios/ScenarioEditor.tsx:114-134 src/services/kaggleSim.ts:233-236 kaggle-kernels/landslide-sim/main.py:314-315,556-577 |
| Duration slider | duration_hours | h | UI 0.5–48; wire ≤ 720; kernel also caps simulated time at 300 s | UI 2 · kernel 2 | Flow routing window | src/components/scenarios/ScenarioEditor.tsx:114-134 src/services/kaggleSim.ts:217 kaggle-kernels/landslide-sim/main.py:303,435-442 |
| Terrain (optional) | terrain(+_gs) | m | ≤ 65,536 cells | — | Real relief; otherwise a deterministic synthetic ridge (seed 42) | src/services/kaggleSim.ts:218-224 kaggle-kernels/landslide-sim/main.py:81-103 |
Outputs
| Field | Unit | Meaning | Source |
|---|---|---|---|
landslide_depth.npy | m | Final debris thickness | kaggle-kernels/landslide-sim/main.py:875-895 |
landslide_velocity.npy, velocity_x/y.npy | m/s | Speed and components | kaggle-kernels/landslide-sim/main.py:875-895 |
runout_distance.npy | km field | Distance from the depth-weighted source centroid | kaggle-kernels/landslide-sim/main.py:457-463 |
susceptibility.npy / trigger_map.npy / slope.npy | 0–1 / g or mm / ° | Failure susceptibility and trigger field (PGA in g for earthquake runs, else rainfall mm) | kaggle-kernels/landslide-sim/main.py:744,875-895 |
snapshots_depth/velocity/vx/vy.npy + snapshot_times.npy | —; s | Animation series | kaggle-kernels/landslide-sim/main.py:875-895 |
metadata.json | — | model "depth_averaged_debris_flow", friction_law "voellmy", solver "lax_friedrichs", total volume + outflow ledger | kaggle-kernels/landslide-sim/main.py:772-775,756-761 |
Spatial-origin semantics
Square domain; row 0 = north. Documented axis-naming quirk: internally dz_dx is the north–south (row-axis) gradient and dz_dy the east–west (column-axis) gradient; the code comment records that the old mapping was swapped and would have driven debris across slopes on real terrain. Runout is measured from the depth-weighted source centroid. kaggle-kernels/landslide-sim/main.py:147-148,465-475,457-463
Documented validity limits (verbatim from the code)
'The genuine conservation proof is the closed-box test (verify_closed_box) and the grid-convergence script, not this algebraic bookkeeping.' · axis-mapping note: 'The old mapping was swapped, which on *real* terrain would drive debris across the slope instead of down it' · susceptibility raw mask note: 'The raw mask (susceptibility > 0.3) covers ~99% of the grid, so the "pile" is a grid-wide slab that blows up and renders as a hollow rim.' · "Certified-grade" debris-flow modelling requires the free parameters to be fit to a real slide, not guessed … Sample runout resources: Hungr et al. (2001) runout databases
The closed-box verifier exists in main.py but is NOT invoked by main() (unlike flood/tsunami/volcano); the authoritative gates are validate_convergence.py (conservation 1e-8, runout refinement ≤ 0.25, upsampling RMSE ≤ max(10 %, 30 m)) and the /api/kaggle/calibrate grid fit. kaggle-kernels/landslide-sim/main.py:808-857 kaggle-kernels/landslide-sim/validate_convergence.py:19-21,35-98
Measured runs and timings
| Run / check | Measured result |
|---|---|
| Grid-convergence script re-executed | PASS — conservation |Δ| = 0 with and without entrainment; runout 3.74→2.87→2.95 km over gs 64→128→256 (fixed 5.12 km domain, dx 80→40→20 m); area refinement Δ1 = 1.386 → Δ2 = 0.050 (gate ≤ 0.25); terrain upsample RMSE 20.6 m = 1.5 % of 1,381 m relief; exit 0 |
| Representative quake-trigger run (128², M 6.5, μ 0.25, ξ 300, 5 min sim) | max depth 157 m (coarse-grid pooling), max velocity 26.2 m/s, runout 4.0 km, affected 5.1 km², volume 24.5 M m³; in-domain mass ledger drift 1.56 % (boundary exchange ledger reported separately); wall 2.7 s |
| Rain + entrainment run (96², 300 mm, rate 0.005/s, bed 4 m) | max depth 216 m, velocity 21.6 m/s, runout 6.2 km, affected 25.5 km²; entrained +126 M m³ accounted; mass drift 0.0000 %; wall 2.0 s |
| Calibration endpoint semantics | μ×ξ grid search {0.15…0.40}×{100…800} minimising |runout − observed| (calibrate.py:24-25,64) — exercised by the server localRunner (spawned python3, in-process) |
Reproduction
Commands
# Convergence/conservation gates (in-process, no Kaggle):
cd <repo>/kaggle-kernels/landslide-sim && python3 validate_convergence.py
# → 'PASS — all gates OK'
# Calibrate μ×ξ to an observed runout (documented-event value required):
python3 calibrate.py --observed-runout-km 2.9 --grid-size 128
# Server-side UQ:
curl -s -X POST http://localhost:3001/api/kaggle/landslide/quantify \
-H 'Content-Type: application/json' -d '{ "request": {…landslide params…}, "samples": 16 }'