Skip to main content

Modular Python pipeline for HAND-based flood inundation and damage estimation.

Project description

floodpath

PyPI version tests Python 3.10+ License: MIT

A modular Python pipeline for HAND-based flood inundation and damage estimation.

floodpath chains together everything you need to go from a (lat, lon) point to a per-cell flood damage estimate. As of v0.2 the pipeline is end-to-end physically grounded — it accepts precipitation directly, runs SCS-CN runoff partitioning + Manning channel hydraulics, and produces a rainfall-driven flood map (the static-water-level path remains supported):

                Precipitation (uniform synthetic, or your own grid)
                                  ↓ SCS-CN
                          runoff Q (mm/cell)
                                  ↓ flow accumulation (pyflwdir)
                  accumulated upstream volume + peak discharge
                                  ↓ Manning normal-depth at streams
                          stream water levels h (m)
                                  ↓ HAND broadcast (per-stream → per-cell)
DEM → flow direction → streams → HAND → flood depth (m) per cell
                                  ↓
                  + GHSL built-up + WorldPop + OSM buildings
                                  ↓
              + JRC Huizinga 2017 depth-damage curves
                                  ↓
                          → 2D damage map

Each layer is a small, well-tested module. Plug in the parts you need, swap in your own data, or extend with new sources.

Install

pip install floodpath

floodpath depends on rasterio and pyflwdir, both of which install cleanly via pip on Linux. On macOS arm64, conda-forge is the smoother path:

conda install -c conda-forge rasterio pyflwdir numpy
pip install floodpath

Quickstart — static water-level scenario

The original v0.1 pipeline. Useful as a what-if tool ("if water rose to 5 m everywhere, where would it go?").

from floodpath.dem import get_dem
from floodpath.hydrology import build_flow_grid, extract_streams, compute_hand
from floodpath.exposure import get_ghsl_built
from floodpath.damage import (
    JRC_AFRICA_RESIDENTIAL,
    compute_inundation_depth,
    compute_damage,
)

# 1. Fetch a DEM patch (Copernicus GLO-30, ~30 m, no auth)
dem = get_dem(lat=11.805, lon=37.5625, buffer_deg=0.0375)

# 2. Terrain hydrology
grid = build_flow_grid(dem)
streams = extract_streams(grid, threshold=200)
hand = compute_hand(grid, streams, dem)

# 3. Exposure (GHS-BUILT-S, ~90 m built-up surface per cell)
exposure = get_ghsl_built(lat=11.805, lon=37.5625, buffer_deg=0.0375, epoch=2020)

# 4. Damage at a 5 m water level
depth = compute_inundation_depth(hand, water_level=5.0)
damage = compute_damage(depth, exposure, JRC_AFRICA_RESIDENTIAL)

print(f"Total damaged built-up: {damage.values.sum():,.0f} m²")

Quickstart — rainfall-driven scenario (new in v0.2)

Drives the same HAND machinery from a real rainfall event. Replaces the user-supplied "5 m water level" with a per-cell water depth field computed from precipitation → SCS-CN → flow accumulation → Manning normal-depth.

from floodpath.dem import get_dem
from floodpath.hydrology import build_flow_grid, extract_streams, compute_hand
from floodpath.exposure import get_ghsl_built
from floodpath.landuse import get_worldcover_landuse, landuse_to_roughness
from floodpath.soil import get_soilgrids_texture, texture_to_hsg
from floodpath.precip import uniform_precip_like
from floodpath.runoff import compute_curve_number, apply_scs_cn
from floodpath.routing import (
    accumulate_runoff,
    peak_discharge,
    compute_water_level,
    compute_rainfall_inundation,
)
from floodpath.damage import JRC_AFRICA_RESIDENTIAL, compute_damage

LAT, LON, BUF = 11.805, 37.5625, 0.0375

# 1. Terrain + hydrology
dem = get_dem(lat=LAT, lon=LON, buffer_deg=BUF)
grid = build_flow_grid(dem)
streams = extract_streams(grid, threshold=200)
hand = compute_hand(grid, streams, dem)

# 2. Land surface inputs
landuse = get_worldcover_landuse(lat=LAT, lon=LON, buffer_deg=BUF, year=2021)
roughness = landuse_to_roughness(landuse)
texture = get_soilgrids_texture(lat=LAT, lon=LON, buffer_deg=BUF)
hsg = texture_to_hsg(texture)
exposure = get_ghsl_built(lat=LAT, lon=LON, buffer_deg=BUF, epoch=2020)

# 3. Rainfall → runoff (any PrecipGrid works; uniform 100 mm here)
cn = compute_curve_number(landuse, hsg)
precip = uniform_precip_like(cn, depth_mm=100.0)
runoff = apply_scs_cn(cn, precip)

# 4. Steady-state routing → discharge → Manning water level
acc = accumulate_runoff(runoff, grid)
discharge = peak_discharge(acc, duration_s=6 * 3600.0)  # 6-hour design storm
water_level = compute_water_level(discharge, roughness, grid, streams, dem)

# 5. Rainfall-driven flood + damage
flood = compute_rainfall_inundation(water_level, hand, grid, streams)
damage = compute_damage(flood, exposure, JRC_AFRICA_RESIDENTIAL)

print(f"Flooded fraction: {100*flood.flooded_fraction():.1f}% of patch")
print(f"Outlet peak Q: {discharge.outlet_peak():.1f} m³/s")
print(f"Total rainfall-driven damage: {damage.values.sum():,.0f} m² built-up")

Modules

Module Source What it provides
floodpath.dem Copernicus GLO-30 (AWS Open Data, COG) Elevation patch around any (lat, lon)
floodpath.hydrology derived from DEM via pyflwdir Flow direction + accumulation, stream networks (with Strahler order), basin delineation, HAND
floodpath.exposure GHSL R2023A, WorldPop, OpenStreetMap (Overpass) Built-up surface, population, building footprints
floodpath.landuse ESA WorldCover (10 m, AWS Open Data, COG) 11-class land-cover raster (2020 v100, 2021 v200), Manning's roughness derivation
floodpath.soil ISRIC SoilGrids 2.0 (250 m, COG) Sand/silt/clay topsoil composition + USDA texture-triangle classification + NEH 630 Ch7 hydrologic soil group (A/B/C/D)
floodpath.precip Synthetic uniform (real fetchers later: ERA5 / IMERG / CHIRPS) Precipitation depth raster (mm) — pluggable input to the runoff equation
floodpath.runoff NEH 630 Ch9 + Ch10 + landuse + HSG + precip SCS Curve Number raster + SCS-CN runoff equation Q = (P-0.2S)²/(P+0.8S)
floodpath.routing runoff + flow direction (pyflwdir) + roughness + HAND Hydrologic routing (accumulation + peak discharge) + hydraulic closure (Manning normal-depth at streams, Leopold-Maddock width) + rainfall-driven HAND flood depth
floodpath.damage JRC Huizinga 2017 + DEM/HAND/GHSL/routing Per-cell flood depth and damage in m² of built-up surface — accepts either a static water-level scenario or a rainfall-driven flood from floodpath.routing

Depth-damage curves

floodpath.damage ships 26 continental-average curves from JRC's Huizinga et al. 2017 Global flood depth-damage functions report — covering residential, commerce, industry, transport, infrastructure and agriculture asset classes across up to six continents.

from floodpath.damage import jrc_curve

curve = jrc_curve(asset_class="residential", continent="north_america")
fractions = curve(depths_m=np.array([0.0, 0.5, 1.0, 2.0, 5.0]))

Coverage gaps from the original report are preserved: jrc_curve("commerce", "africa") raises KeyError rather than fabricating data.

Test fixtures and offline development

floodpath ships with a small set of committed test fixtures (Robit Bata watershed, northern Ethiopia) so contributors can iterate without hitting the network:

pytest -m "not integration"   # ~0.1 s, no network
pytest                        # full suite, ~1 minute (downloads ~25 MB)

The fixtures (committed binaries totalling ~330 KB) are regenerated by scripts under tests/fixtures/_generate_*.py whenever an upstream source changes.

Status

floodpath is beta (v0.2). The pipeline produces sensible flood/damage maps for both:

  • Static water-level scenarios (the v0.1 path)
  • Rainfall-driven scenarios with SCS-CN runoff partitioning, steady-state flow accumulation, and Manning normal-depth at stream cells (new in v0.2)

It does not yet model:

  • Time-resolved hydraulics or hydrographs (no unit hydrograph or kinematic-wave routing — steady-state only; planned for v0.3)
  • 2D shallow-water dynamics or Saint-Venant solver (not planned)
  • Subgrid stochastic uncertainty / ensemble flood mapping (not planned)

The steady-state routing assumption is appropriate for small basins under intense storms; larger basins where peak attenuation along the channel matters will see biased-high peak Q and biased-high flood depths. If you need full physics, look at LISFLOOD-FP, HEC-RAS 2D, or WFlow.

What's new in v0.2

  • New modules: floodpath.landuse (ESA WorldCover + Manning's roughness), floodpath.soil (SoilGrids 2.0 + NEH 630 Ch7 hydrologic soil group), floodpath.precip (uniform synthetic; pluggable for any user-supplied grid), floodpath.runoff (NEH 630 Ch9 SCS Curve Number + Ch10 SCS-CN equation), floodpath.routing (steady-state hydrologic + Manning hydraulic closure)
  • compute_damage now accepts either kind of inundation depth (static or rainfall-driven) — same numerics, different scenario metadata
  • 332 offline unit tests + 16 integration tests; smoke test runs 19 stages from DEM through rainfall-driven damage

Citation

If you use floodpath in academic work, please cite the underlying datasets too:

  • DEM: Copernicus DEM GLO-30, ESA / Airbus, doi:10.5270/ESA-c5d3d65
  • Built-up surface: GHSL Data Package 2023, JRC, doi:10.2760/098587
  • Population: WorldPop, University of Southampton, doi:10.5258/SOTON/WP00674
  • Land cover: ESA WorldCover 2020/2021, ESA, doi:10.5281/zenodo.7254221
  • Soil texture: ISRIC SoilGrids 2.0, doi:10.5194/soil-7-217-2021
  • Hydrologic soil group + Curve Number: USDA NRCS National Engineering Handbook Part 630, Chapter 7 (Hydrologic Soil Groups, 2009) and Chapter 9 (Hydrologic Soil-Cover Complexes, 2009)
  • Channel hydraulic geometry: Leopold, L. B. and Maddock, T. (1953). The hydraulic geometry of stream channels and some physiographic implications. USGS Professional Paper 252
  • Damage curves: Huizinga, J., de Moel, H. and Szewczyk, W. (2017). Global flood depth-damage functions: Methodology and the database with guidelines. JRC Technical Report EUR 28552 EN, doi:10.2760/16510

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

floodpath-0.2.0.tar.gz (56.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

floodpath-0.2.0-py3-none-any.whl (74.9 kB view details)

Uploaded Python 3

File details

Details for the file floodpath-0.2.0.tar.gz.

File metadata

  • Download URL: floodpath-0.2.0.tar.gz
  • Upload date:
  • Size: 56.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for floodpath-0.2.0.tar.gz
Algorithm Hash digest
SHA256 a812502947740d3fbbfe5575794b15a3593cd40e3f14382adf4ac25eccc7deb1
MD5 49e7d027c540cb72aafae177dac19c1a
BLAKE2b-256 8206750fcd959c9f11ea3ad32e9254c8d71dba32748b8197e7c633fe54a48abe

See more details on using hashes here.

File details

Details for the file floodpath-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: floodpath-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 74.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for floodpath-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9ff6b56d9480f9f40e90e25488befb8fd836301a8d0404e07f6f1e54bfa22b69
MD5 ccf7e8e7ad48a303c729c1b05278d8ba
BLAKE2b-256 aa3445194edb2acf943e9c163a22438ecda0e6329a95ffd5f0c09112729991b3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page