Methodology Reference#

All indicators must be calculated for the same season, spatial grid, and reference climatology (default: 1991–2020, configurable — for the live Ethiopia project this is 1993–2025, see project-context.md). Dry day: rainfall < 1 mm/day (configurable). Wet day: rainfall ≥ 1 mm/day (configurable).

Update note: The drought-hazard formula below is unchanged from the original spec. The excess-wetness formula, the standardization equations, and the hazard-combination rule have since been refined (Rx1day/Rx5day promoted from “add later” to primary wetness indicators) — see “Excess-wetness hazard (H_wet) — updated formula” and the two new sections after it. Use the updated versions for new code; the original wetness formula is kept below only for history.

Core climate indicators#

  • Seasonal rainfall total

  • Standardized Precipitation Index (SPI-3 initially)

  • Consecutive Dry Days (CDD)

  • Consecutive Wet Days (CWD)

Designed to be extended later with Rx1day, Rx5day, soil moisture, runoff, and river discharge — add these as new indicator modules, not by modifying the core four.

Drought hazard (H_drought)#

Normalize each indicator to a 0–1 drought score:

  • Low rainfall percentile → increases drought hazard

  • Negative SPI → increases drought hazard

  • High CDD percentile → increases drought hazard

  • Low CWD percentile → increases drought hazard

H_drought = 0.20 × rainfall_deficit_score
          + 0.35 × SPI_drought_score
          + 0.30 × CDD_drought_score
          + 0.15 × CWD_drought_score

Excess-wetness hazard (H_wet) — original formula (superseded, kept for history)#

Normalize each indicator to a 0–1 wetness score:

  • High rainfall percentile → increases wetness hazard

  • Positive SPI → increases wetness hazard

  • High CWD percentile → increases wetness hazard

  • Low CDD percentile → supporting evidence only, low weight

H_wet = 0.25 × high_rainfall_score
      + 0.30 × positive_SPI_score
      + 0.35 × CWD_wetness_score
      + 0.10 × low_CDD_score

Normalize rainfall total, CDD, and CWD using percentile-based normalization (not map-specific min-max) so results are comparable across years and forecast initializations.

Excess-wetness hazard (H_wet) — updated formula (use this one)#

CWD measures persistence but not intensity — it won’t catch a flood-producing short, intense burst of rain. Rx1day (max 1-day rainfall) and Rx5day (max consecutive 5-day rainfall) are now primary indicators instead of a later extension. CDD is dropped from the wetness formula (a low CDD isn’t strong independent evidence of wetness once CWD, SPI, and rainfall percentile are already included — keeping it risked padding the score with a redundant signal).

H_wet = 0.20 × SPI_wet_score
      + 0.20 × rainfall_percentile_wet_score
      + 0.20 × CWD_wet_score
      + 0.15 × Rx1day_wet_score
      + 0.25 × Rx5day_wet_score

Weights sum to 1.00. Rx5day gets the largest single weight because accumulated multi-day rainfall is particularly relevant to soil saturation and waterlogging. Rx1day and Rx5day should not be used for drought (a low value there isn’t meaningful evidence of dryness) — keep them wetness-only.

Drought hazard (H_dry) — same formula, just renamed for consistency#

The project now refers to this as H_dry (equivalent to H_drought above) to pair naturally with H_wet. The formula and weights are unchanged:

H_dry = 0.35 × SPI_dry_score
      + 0.20 × rainfall_percentile_dry_score
      + 0.30 × CDD_dry_score
      + 0.15 × CWD_dry_score

Do not add Rx1day/Rx5day to the drought formula — a low value in either isn’t meaningful evidence of dryness, so they stay wetness-only.

Standardization formulas#

Use local, calendar-period-specific historical distributions — June 2026 compares against historical Junes, JJAS 2026 against historical JJAS seasons, etc. Never mix calendar periods when computing a percentile rank.

Rainfall percentile (P = rainfall percentile, 0–100, at that grid cell for that calendar period):

S_rain_dry = clip((50 − P) / 40, 0, 1)   # 10th percentile or below → max drought score
S_rain_wet = clip((P − 50) / 40, 0, 1)   # 90th percentile or above → max wetness score

Near the 50th percentile, both scores are ~0 (no hazard contribution).

SPI (standardized value, roughly −3 to +3):

S_SPI_dry = clip(−SPI / 2, 0, 1)
S_SPI_wet = clip(SPI / 2, 0, 1)

Reference points: SPI = −2.0 → dry score 1.00; SPI = −1.0 → dry score 0.50; SPI = +1.0 → wet score 0.50; SPI = +2.0 → wet score 1.00.

CDD, CWD, Rx1day, Rx5day — use each index’s own historical percentile rank p at that grid cell for that calendar period (not the raw value, not map-wide min-max):

S_CDD_dry   = clip((p_CDD − 50) / 40, 0, 1)   # high CDD percentile → dry
S_CWD_dry   = clip((50 − p_CWD) / 40, 0, 1)   # low CWD percentile → dry
S_CWD_wet   = clip((p_CWD − 50) / 40, 0, 1)   # high CWD percentile → wet
S_Rx1day_wet = clip((p_Rx1day − 50) / 40, 0, 1)
S_Rx5day_wet = clip((p_Rx5day − 50) / 40, 0, 1)

Combining drought and wetness into overall hazard — use max, not average#

Never average H_dry and H_wet — opposite hazard signals would cancel each other and mask a real hazard. Instead:

H_overall = max(H_dry, H_wet)

Dominant-hazard categorical layer T (same codes as the R_dominant categorical layer used later in the risk step — keep them consistent):

T = 0   if neither H_dry nor H_wet is substantial (below the high-hazard threshold)
T = 1   if H_dry > H_wet  (drought-dominated)
T = 2   if H_wet > H_dry  (wetness-dominated)
T = 3   if both hazards are substantial (mixed/compound)

Hazard probability#

Input data has either year × lat × lon (historical) or ensemble_member × lat × lon (forecast) dimensions. High-hazard threshold: configurable, default 0.60.

P_drought = count(H_drought ≥ 0.60) / total_valid_realizations
P_wet     = count(H_wet ≥ 0.60) / total_valid_realizations
P_any     = count(H_drought ≥ 0.60 OR H_wet ≥ 0.60) / total_valid_realizations

With a 25-member ensemble (this project’s default), probability moves in increments of 1/25 = 0.04 = 4% — don’t report finer precision than that implies.

Caveat: don’t confuse a pre-existing “SPI drought probability” or “SPI wet probability” product (P(SPI ≤ −1.0) or P(SPI ≥ +1.0), computed from SPI alone) with the full composite P_dry/P_wet defined here. The composite probability must be computed from the member-level H_dry/H_wet hazard scores (which blend SPI with rainfall percentile, CDD/CWD, and Rx1day/Rx5day), not from SPI in isolation. If an existing GeoTIFF is named like a probability product, check what it was actually computed from before wiring it into P_dry/P_wet.

Also calculate the probability of joint drought+wetness events within the selected assessment period when both can occur, and conditional severity:

S_drought = mean(H_drought among realizations classified as drought events)
S_wet     = mean(H_wet among realizations classified as wetness events)

Exposure#

Separate maps for: population, rainfed cropland, irrigated cropland, crop production, livestock, roads, health facilities, water infrastructure, settlements, economic assets.

Maintain both:

  • Absolute exposure (people, hectares, livestock head, etc.)

  • Normalized exposure index (0–1), using robust 5th/95th-percentile normalization

Do not combine incompatible physical units into one index unless a clearly documented composite exposure index is explicitly requested by the user.

Drought vulnerability (V_drought)#

Sensitivity indicators: rainfed-agriculture dependence, drought-sensitive crop area, historical yield variability, low soil water-holding capacity, land degradation, water scarcity, poverty, food insecurity, livestock dependence.

Adaptive-capacity indicators: irrigation access, water storage, functional water points, climate-information access, agricultural extension access, drought-tolerant seed access, credit, insurance, livelihood diversification, market access, social protection.

Normalize all to 0–1; reverse beneficial indicators so higher = more vulnerable.

V_drought = 0.60 × drought_sensitivity + 0.40 × adaptive_capacity_deficit

Excess-wetness vulnerability (V_wet)#

Sensitivity indicators: poorly drained soils, low-lying terrain, topographic wetness, proximity to rivers, waterlogging-sensitive crops, historical wetness losses, erosion susceptibility, landslide susceptibility, poor housing, unpaved-road dependence, weak sanitation.

Adaptive-capacity indicators: agricultural drainage, urban drainage, flood-protection structures, all-weather roads, improved storage, short-range forecast access, emergency-response capacity, health-service access, crop insurance, disease surveillance.

V_wet = 0.60 × wetness_sensitivity + 0.40 × adaptive_capacity_deficit

Risk calculation#

R_drought = 100 × P_drought × S_drought × E_drought × V_drought
R_wet     = 100 × P_wet × S_wet × E_wet × V_wet

These are relative 0–100 risk scores, not probability percentages.

R_dominant = max(R_drought, R_wet)

Categorical dominant-risk layer:

  • 0 = insignificant / no identified risk

  • 1 = drought-dominated risk

  • 2 = excess-wetness-dominated risk

  • 3 = mixed / compound risk (where applicable)

Member-wise (ensemble) risk#

When ensemble data are available:

member_drought_risk = drought_event × drought_severity × drought_exposure × drought_vulnerability
member_wetness_risk = wetness_event × wetness_severity × wetness_exposure × wetness_vulnerability

Per member, overall risk = max(member_drought_risk, member_wetness_risk) unless cumulative impacts are explicitly requested. Average the member-wise overall risk across all members for the final ensemble risk map.

Risk classes (configurable)#

Range

Class

0–19.9

Very low

20–39.9

Low

40–59.9

Moderate

60–79.9

High

80–100

Very high

The architecture must support later calibration against observed crop losses, livestock mortality, water shortages, waterlogging, and infrastructure-damage records — keep calibration as a pluggable step, not baked into the risk formula.