Metadata-Version: 2.4
Name: floodpath
Version: 0.2.0
Summary: Modular Python pipeline for HAND-based flood inundation and damage estimation.
Author-email: Reza Ehsani <rezaa.ehsaani@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/rehsani/floodpath
Project-URL: Repository, https://github.com/rehsani/floodpath
Project-URL: Issues, https://github.com/rehsani/floodpath/issues
Keywords: flood,hydrology,geospatial,DEM,HAND,inundation,damage,remote-sensing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Topic :: Scientific/Engineering :: Hydrology
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Requires-Dist: rasterio>=1.3
Requires-Dist: pyflwdir>=0.5
Dynamic: license-file

# floodpath

[![PyPI version](https://img.shields.io/pypi/v/floodpath.svg)](https://pypi.org/project/floodpath/)
[![tests](https://github.com/rehsani/floodpath/actions/workflows/tests.yml/badge.svg)](https://github.com/rehsani/floodpath/actions/workflows/tests.yml)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

**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

```bash
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:

```bash
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?").

```python
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.

```python
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.

```python
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:

```bash
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](https://www.bristol.ac.uk/geography/research/hydrology/models/lisflood/), [HEC-RAS 2D](https://www.hec.usace.army.mil/software/hec-ras/), or [WFlow](https://github.com/Deltares/Wflow.jl).

### 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](LICENSE).
