Test data fixture generator¶
tests/fixtures/generator.py provides deterministic, in-memory fixture
generators for climate risk test data. Every function accepts a seed
parameter so that identical inputs always produce identical byte-level output.
Nothing is written to disk; callers receive plain numpy arrays plus a metadata
dict.
Why a shared generator?¶
Without a shared generator, each test file rolls its own hazard/exposure arrays by hand. This leads to:
- Inconsistent intensity ranges — some tests accidentally use intensities below the curve threshold (silent zero-damage) or above saturation.
- Fragile SHA256 references — no easy way to assert a test dataset is stable across code changes.
- Copy-paste amplification — adding a new hazard type means touching a dozen test files.
The generator centralises the calibration knowledge (intensity ranges, units, curve shapes) in one place.
API¶
make_hazard_fixture¶
from tests.fixtures.generator import make_hazard_fixture
result = make_hazard_fixture(
hazard_type="RF", # "RF" | "TC" | "WF" | "WS"
n_events=3,
bbox=(23.0, 37.0, 24.0, 38.0), # (lon_min, lat_min, lon_max, lat_max)
seed=42,
)
Returned keys:
| Key | Type | Description |
|---|---|---|
hazard_type |
str |
Two-letter engine code passed in |
n_events |
int |
Number of events |
n_centroids |
int |
Number of centroids (≥ n_events) |
intensity |
ndarray (n_events, n_centroids) |
Float32 intensity values |
frequency |
ndarray (n_events,) |
Marginal event frequency |
centroids_lon |
ndarray (n_centroids,) |
Centroid longitudes |
centroids_lat |
ndarray (n_centroids,) |
Centroid latitudes |
intensity_unit |
str |
Physical unit (m, m/s, K) |
bbox |
tuple |
As passed |
make_exposure_fixture¶
from tests.fixtures.generator import make_exposure_fixture
result = make_exposure_fixture(
n_points=5,
bbox=(23.0, 37.0, 24.0, 38.0),
seed=42,
)
Returned keys:
| Key | Type | Description |
|---|---|---|
n_points |
int |
Number of assets |
lons |
ndarray (n_points,) |
Longitudes inside bbox |
lats |
ndarray (n_points,) |
Latitudes inside bbox |
values |
ndarray (n_points,) |
Asset values in EUR (100 k – 10 M) |
value_unit |
str |
"EUR" |
bbox |
tuple |
As passed |
make_impact_function_fixture¶
from tests.fixtures.generator import make_impact_function_fixture
result = make_impact_function_fixture(
hazard_type="RF",
curve_shape="linear", # "linear" | "step" | "sigmoid"
seed=42,
)
Returned keys:
| Key | Type | Description |
|---|---|---|
hazard_type |
str |
Two-letter engine code |
curve_shape |
str |
Shape used |
intensity_unit |
str |
Physical unit |
n_points |
int |
Number of breakpoints (6) |
mdd_x |
ndarray (n_points,) |
Intensity breakpoints |
mdd_y |
ndarray (n_points,) |
Mean damage degree (0–1) |
paa_x |
ndarray (n_points,) |
Same breakpoints as mdd_x |
paa_y |
ndarray (n_points,) |
Percentage of assets affected |
Hazard-type worked examples¶
The calibrated intensity ranges ensure that produced fixtures return
positive but non-saturating damage against the built-in impact curves
seeded by src/climate_lama/core/impact_function_seeder.py.
RF — River flood¶
haz = make_hazard_fixture("RF", n_events=2, seed=0)
# intensity in metres (0.5 – 3.0 m)
# Sits above the JRC flood-Europe threshold and below the 6 m saturation tail.
impf = make_impact_function_fixture("RF", curve_shape="linear", seed=0)
TC — Tropical cyclone¶
haz = make_hazard_fixture("TC", n_events=2, seed=0)
# intensity in m/s gust (35 – 75 m/s)
# Above Emanuel 2011 v_thresh=25.7, below v_half=110.1 where MDD → 1.
impf = make_impact_function_fixture("TC", curve_shape="sigmoid", seed=0)
WF — Wildfire¶
haz = make_hazard_fixture("WF", n_events=2, seed=0)
# intensity in K brightness temperature (305 – 320 K)
# Above Lüthi 2021 I_thresh=295 K; values stay just above threshold.
impf = make_impact_function_fixture("WF", curve_shape="linear", seed=0)
WS — Storm Europe¶
haz = make_hazard_fixture("WS", n_events=2, seed=0)
# intensity in m/s gust (25 – 45 m/s)
# Above Klawa-Ulbrich 2003 v98=20 m/s, below saturation plateau.
impf = make_impact_function_fixture("WS", curve_shape="sigmoid", seed=0)
Reproducibility and SHA256 assertions¶
Because the generator is deterministic, you can pin expected checksums:
import hashlib
import numpy as np
from tests.fixtures.generator import make_hazard_fixture
result = make_hazard_fixture("RF", seed=42)
digest = hashlib.sha256(result["intensity"].tobytes()).hexdigest()
assert digest == "..." # pinned at fixture creation time
This catches unintended changes to the generation logic (e.g. a NumPy RNG API change) without requiring large binary fixtures committed to the repo.
Design constraints¶
- No disk I/O — all data lives in memory. No fixture files are committed.
- No external dependencies — only NumPy; no CLIMADA, no engine imports.
- Deterministic across platforms —
numpy.random.default_rngguarantees identical output on any OS and NumPy ≥1.17.