terraflow.hazard¶
WMO/ETCCDI-aligned hazard indicators introduced in v0.5.0 (#138d).
Backs four of the TemporalAggregation.kind values that
terraflow.temporal.aggregate_per_station dispatches to.
Overview¶
growing_degree_days(df, base_temp_c)— per-station cumulative sum ofmax(0, T_d - base)across every row in the (scenario-filtered) DataFrame. Note: this is a window-cumulative total, not a per-year average — a 30-year scenario window yields ~30× the value of a 1-year window. Divide by(year_max - year_min + 1)if you need an annualised GDD.frost_days(df, threshold_c)— per-station cumulative count of days whereT ≤ thresholdacross every row in the (scenario-filtered) DataFrame. Maps to WMO ETCCDI FD0 when threshold = 0 °C, but note the WMO definition is per-year — TerraFlow's implementation returns the window total. Divide by the window's year count for the canonical annual FD0.heat_stress_days(df, threshold_c)— per-station cumulative count of days whereT ≥ thresholdacross every row in the (scenario-filtered) DataFrame. Maps to WMO ETCCDI TX35 when threshold = 35 °C; same per-year vs window-total caveat asfrost_daysabove.spei(df, timescale_months)— simplified Thornthwaite-PET-based Standardised Precipitation-Evapotranspiration Index at the final month of the input window.
SPEI simplifications¶
Documented honestly so a user can decide whether the simplification is acceptable for their analysis:
| Aspect | Canonical SPEI (R package) | TerraFlow spei() |
|---|---|---|
| Standardisation | Log-logistic CDF fit | Z-score |
| Daylight-hour correction | Latitude-dependent in PET | Omitted |
| Heat-index reference | Multi-decade climatology | Per-station fit on input window |
For relative scenario comparisons (e.g. "is SSP5-8.5 drier than
historical?") these simplifications are typically acceptable. For
absolute SPEI claims against published thresholds (e.g. "moderate
drought" at SPEI < -1) prefer the canonical R package via reticulate or
a pre-computed SPEI column passed through precip_percentile as a
substitute.
Quick example¶
import pandas as pd
from terraflow.hazard import growing_degree_days, frost_days, heat_stress_days, spei
df = pd.read_csv("data/demo_timeseries.csv", parse_dates=["date"])
gdd = growing_degree_days(df, base_temp_c=10.0)
fd = frost_days(df, threshold_c=0.0)
ts = heat_stress_days(df, threshold_c=35.0)
spei3 = spei(df, timescale_months=3)
API Reference¶
hazard
¶
Climate-induced crop-hazard indicators (flagship #138d).
Implements the four hazard kinds dispatched from :mod:terraflow.temporal:
growing_degree_days: GDD accumulation above a crop-specific base temperature.GDD = sum_d max(0, daily_mean_temp - base_temp_c).frost_days: count of days with daily mean temperature at or below a threshold (typically 0 °C).heat_stress_days: count of days with daily mean temperature at or above a threshold (typically 30-35 °C for major C3 crops).spei: Standardised Precipitation-Evapotranspiration Index using a simplified Thornthwaite PET. Returns the SPEI value at the final month of the input window.
All four functions take the same long-format station time-series
DataFrame shape used elsewhere in the climate-impact pipeline
(station_id, date, temperature_c, precipitation_mm) and
return a :class:pandas.Series indexed by station_id with float
scalar values. Stations with no rows after upstream scenario filtering
yield NaN rather than raising — consistent with the rest of the
engine.
Simplified-SPEI caveats (documented for reviewers):
- PET is computed via Thornthwaite (monthly temperature only); no
daylight-hour or latitude correction (assumes 12 h days, 30-day
months). Standard SPEI implementations (e.g. R's
SPEIpackage) add a latitude-aware daylight factor. - The annual heat index
Iis fitted on each station's own monthly means within the input window. Standard practice fitsIon a long-run climatology. - Standardisation is a per-station z-score of the rolling
timescale_monthswater-balance sum. Standard SPEI uses a fitted log-logistic distribution; the simplification preserves sign and relative ordering but not the canonical CDF mapping.
frost_days(df, threshold_c)
¶
Per-station count of days with mean temperature ≤ threshold_c.
A daily mean of exactly threshold_c counts as a frost day —
matches the WMO convention for ETCCDI FD0 when threshold = 0 °C.
Source code in terraflow/hazard.py
growing_degree_days(df, base_temp_c)
¶
Per-station GDD accumulation above base_temp_c.
GDD for one day = max(0, daily_mean_temp_c - base_temp_c). The
per-station total is the sum across all rows in the (already
scenario-filtered) DataFrame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df
|
DataFrame
|
Long-format station time-series. Must contain |
required |
base_temp_c
|
float
|
Crop-specific base temperature in °C (e.g. 10 °C for maize, 4 °C for winter wheat). |
required |
Returns:
| Type | Description |
|---|---|
pd.Series:
|
Indexed by |
Source code in terraflow/hazard.py
heat_stress_days(df, threshold_c)
¶
Per-station count of days with mean temperature ≥ threshold_c.
A daily mean of exactly threshold_c counts as a heat-stress day —
consistent with the WMO ETCCDI TX35 convention when the threshold
matches.
Source code in terraflow/hazard.py
spei(df, timescale_months)
¶
Per-station simplified SPEI at the final month of the input window.
Drought index combining precipitation and evapotranspiration into a standardised metric. Values near zero indicate normal conditions; negative values indicate drought (more negative = more severe); positive values indicate wet anomalies. The scalar returned is the SPEI at the last month covered by the input data, computed over a rolling timescale_months window.
See module docstring for the documented simplifications relative to the canonical R-package SPEI implementation.