How the model works (water-balance technical reference)¶
This page explains what the DSS is actually computing: how water is routed in space, how supply and demand are reconciled per sub-watershed per month, and what each number on the dashboard physically means.
The Flask app does none of this at request time. All hydrological computation happens offline in app/data_prep/prepare_hydrosheds.py, which converts the GeoPackages and Excel from the modelling team into the CSVs and GeoJSONs that the dashboard reads. The app just slices and aggregates those pre-computed tables.
1. The spatial unit: sub-watersheds¶
The modelled area is partitioned into small drainage cells, one per sub-watershed (1,847 across the 110 modelled WRUAs). Each cell:
- Is derived from a 30 m SRTM-based DEM via flow accumulation.
- Has a stable
band_id(the sub-watershed polygon identifier). - Belongs to exactly one parent WRUA. Water never crosses a WRUA boundary (Rule 1).
- Has a mean elevation, a polygon area, and an adjacency list (which cells share an edge).
- The modelled deployment uses a 10000-pixel flow-accumulation threshold (~9 km² per cell, 1847 cells across the 110 modelled WRUAs).
See Modelling unit for per-polygon attribute details.
2. The monthly water balance per sub-watershed¶
For each sub-watershed i and each month m the model computes a balance:
available(i, m) = runoff_local(i, m) + inflow_from_upstream(i, m)
demand(i, m) = CWR(i, m) # crop water requirement
gross_deficit = max(0, demand - available)
surplus = max(0, available - demand)
The five years of input data (2019 to 2023) are aggregated into a single 12-month climatology that the dashboard plots. The 48-month time series used by the SAT pond simulation preserves the original monthly sequence.
Where each term comes from¶
| Term | Source | Resolution |
|---|---|---|
runoff_local |
Model-derived (basin hydrological model), summarized monthly | Subbasin, climatology |
CWR (crop water requirement) |
FAO-56 Kc × WaPOR evapotranspiration over cropland |
100 m, 2019 to 2023 |
| Cropland mask | WaPOR land-cover | 100 m |
| Precipitation | CHIRPS | 5 km, 2019 to 2023 |
The gross deficit is the demand the irrigation system has to deliver. The net deficit is what crops actually need at the field gate, before factoring in irrigation losses.
Gross vs net deficit (irrigation efficiency)¶
The model uses two efficiencies (constant across the basin):
- Conveyance efficiency
Ec = 0.85(water lost between source and field) - Application efficiency
Ea = 0.70(water lost during application to the crop) - Overall efficiency
E = Ec * Ea = 0.595
So:
A 1 Mm³ net crop deficit needs ~1.68 Mm³ of gross water to actually deliver. The map's color ramp keys on total_deficit_Mm3 which is the gross value.
3. Scenario 1: Reallocation (gravity transfer)¶

Reallocation tries to move surplus water from upstream sub-watersheds to downstream ones using gravity only, with no new infrastructure. The algorithm walks each WRUA top-down by elevation and for every surplus cell decides where its surplus goes.
Routing rules (in priority order)¶
- Stay within the same WRUA. Water never crosses a WRUA boundary, even if a neighbour has surplus to share.
- Local reallocation only on slope < 3%. If the donor's mean slope is steeper than 3% (percent grade, not degrees), no local reallocation is attempted; deficit stays accounted for at source.
- Flow downhill to adjacent watersheds. Candidate receivers must share a polygon edge with the donor AND lie at lower mean elevation. Uphill transfer is disallowed.
- Lowest-friction path. Among eligible downhill neighbours, pick the one with the lowest cumulative friction along the connecting flow path (per-pixel landcover and slope cost surface).
- Tie-break by greatest elevation drop. When two candidates tie on friction, the steeper drop wins.
After routing, each sub-watershed has:
inflow_surplus_Mm3 # surplus received from upstream
total_available_Mm3 # = local available + inflow_surplus
deficit_met_gross_Mm3 # how much of gross deficit was closed by transfers
unmet_deficit_gross_Mm3 # residual gross deficit
surplus_transferred_down # surplus passed further downstream
Across the modelled WRUAs most have small total surplus, so reallocation alone typically closes only single-digit % of the deficit. Reallocation is the cheapest scenario but rarely sufficient.
4. Scenario 2: Storage (SAT farm ponds)¶

SAT = Storage Attenuation Technology. Each pond is a fixed 1000 m³ tank that captures wet-season runoff and releases it during dry-season irrigation.
Pond count per sub-watershed¶
The 1.1 multiplier is a design factor (over-provision so a pond drained early in the dry season still has buffer). NP_needed is the unconstrained count assuming the basin can absorb all the runoff capture.
Environmental check (the 20% rule)¶
If every needed pond were built, the basin might capture so much runoff that downstream flows collapse. To prevent this, the model simulates 48 months of pond operation and checks the basin-annual retained fraction:
basin_annual_retained_frac =
sum(R_captured over all ponds, all months over a year)
/ sum(natural_runoff over the whole basin, same year)
If this fraction exceeds 0.20 (20%), pond counts are scaled down per sub-watershed until the basin-annual cap holds. The resulting count is NP_built. The dashboard always shows both:
NP_needed(unconstrained, what the deficit asks for)NP_built(constrained, what passes the 20% environmental check)
The 48-month simulation¶
For each sub-watershed and each of 48 months the pipeline writes:
| Field | Meaning |
|---|---|
H |
Pond water level at month end (fraction of pond capacity) |
R |
Runoff inflow into ponds that month |
overflow |
Spillover when ponds reached capacity |
balance |
Net balance (R, ET losses, irrigation withdrawals) |
Deficit |
Residual unmet demand that month, even with ponds operating |
retainedfrac |
Per-watershed annual retained share, recomputed monthly |
/api/simulation/<wrua>?scenario=sat returns the timeseries for any WRUA (optionally filtered to a single band_id). The dashboard does not yet plot it, but the data is there.
5. Scenario 3: Combined¶

Combined runs reallocation first, then builds ponds only for the residual unmet deficit:
combined_deficit_to_pond = unmet_deficit_after_reallocation
NP_combined = ceil( combined_deficit_to_pond / 1000 * 1.1 )
Typically Combined uses ~40% fewer ponds than pure SAT for the same deficit coverage, because gravity has already done the easy work.
6. What each dashboard chart actually shows¶
| Chart | Underlying quantity | Aggregation |
|---|---|---|
| Map polygon color | total_deficit_Mm3 per sub-watershed (annual gross deficit) |
Single sub-watershed |
| Monthly Water Balance (right panel bars) | vol_surplus_Mm3 (green, up) and vol_deficit_gross_Mm3 (orange, down) |
Summed across all sub-watersheds in the selected WRUA (or all modelled WRUAs in basin mode) |
| Deficit Intensity heatmap | vol_deficit_gross_Mm3 per (sub-watershed, month) |
Top 10 sub-watersheds in the WRUA by peak monthly deficit |
| Recommended Interventions | max_deficit_m3 (single-month peak in m³, not Mm³) and NP_needed, NP_built |
Top 15 sub-watersheds by max_deficit_m3 |
| Comparison view bars | Annual total_deficit, deficit_met, unmet, ponds, % addressed |
Per scenario, per WRUA |
7. Constants and assumptions¶
| Constant | Value | Source |
|---|---|---|
| Pond volume | 1,000 m³ | Reviewer convention; matches typical farm-pond size in Kenya |
| Pond design factor | 1.1× | Empirical over-provision |
Conveyance efficiency Ec |
0.85 | Pipeline transmission |
Application efficiency Ea |
0.70 | Surface irrigation |
Overall efficiency E |
0.595 | Ec × Ea |
| Basin-annual retained-fraction cap | 0.20 | Environmental flow protection |
| Local reallocation slope cap | 3% | Reviewer rule |
| Years aggregated | 2019 to 2023 (5y) | Input data window |
| Simulation length | 48 months | Reviewer convention |
8. What the model does not do¶
- It does not route water across WRUA boundaries, even when one WRUA has surplus and a neighbour has deficit. This is a policy choice baked into the rules.
- It does not account for groundwater. All transfers are surface.
- It does not model crop choice. CWR is taken as observed from WaPOR ET; the question "what if farmers grew a less thirsty crop?" is out of scope.
- It does not dynamically recompute as you change scenarios in the UI. Every scenario's outputs are pre-computed offline and stored as static CSV.
9. Where to look in the code¶
| Concern | File |
|---|---|
| Data pipeline (Excel and GPKG → CSV and GeoJSON) | app/data_prep/prepare_hydrosheds.py |
| Authoritative routing rules | Reallocation rules |
| Flask aggregation endpoints | app/app.py |
| Per-WRUA data on disk | app/data/reallocation.csv, sat_bands.csv, combined_bands.csv, simulation_*.csv |
| GeoJSON polygons | app/data/elevation_bands.geojson (sub-watershed polygons) |