Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5efad83
cherry pick snapshots from feature/risk_trajectories
spjuhel Dec 17, 2025
ecae36e
Cherrypicks from risk traj
spjuhel Dec 17, 2025
da997e7
Cherrypick from risk traj
spjuhel Dec 17, 2025
a734bfa
cherrypick from risk_traj
spjuhel Dec 18, 2025
6147507
Merge branch 'feature/interpolation-strategies' into feature/static-r…
spjuhel Dec 18, 2025
245d13c
Merge branch 'feature/impact-computation-strategies' into feature/sta…
spjuhel Dec 18, 2025
40f37b0
cherry pick, renaming
spjuhel Dec 18, 2025
bf00262
adds __init__
spjuhel Dec 18, 2025
50ab78b
cherry picks __init__
spjuhel Dec 18, 2025
68d63ea
Merge branch 'feature/snapshots' into feature/impact-computation-stra…
spjuhel Dec 18, 2025
c0e5e55
Merge branch 'feature/impact-computation-strategies' into feature/sta…
spjuhel Dec 18, 2025
6be5e6c
namespace fixes
spjuhel Dec 18, 2025
0e99117
cherry picks dataframe handling
spjuhel Dec 18, 2025
7e53650
Merge remote-tracking branch 'origin/develop' into feature/snapshots
spjuhel Dec 18, 2025
dd63bf4
Introduces on/off option for caching
spjuhel Dec 18, 2025
a6932e8
removes redondant code
spjuhel Dec 18, 2025
49e1cad
Clarifies docstring
spjuhel Dec 18, 2025
cc74d4a
Cherry picks tests
spjuhel Dec 18, 2025
6bf3416
Initial data
spjuhel Dec 18, 2025
d44f377
Merge branch 'feature/common_test_fixtures' into feature/static-risk-…
spjuhel Dec 18, 2025
7ec7db1
cleanups test
spjuhel Dec 18, 2025
7349bc7
cleansup
spjuhel Dec 18, 2025
2708f9a
Merge branch 'feature/common_test_fixtures' into feature/static-risk-…
spjuhel Dec 18, 2025
e12e014
Adds option to have references instead of deep copies of members
spjuhel Dec 19, 2025
b4f05e1
Pylint fix
spjuhel Jan 5, 2026
4e1772e
Merge branch 'feature/snapshots' into feature/impact-computation-stra…
spjuhel Jan 5, 2026
4a8c770
Fixes pylint
spjuhel Jan 5, 2026
430903f
Merge branch 'feature/snapshots' into feature/impact-computation-stra…
spjuhel Jan 5, 2026
87332be
Complies with pylint
spjuhel Jan 5, 2026
e01c330
Pylint compliance
spjuhel Jan 5, 2026
1ec88bf
Fixes type hints
spjuhel Jan 5, 2026
ad2e774
ref only for apply measure
spjuhel Jan 6, 2026
25fbcda
adds API references rst files
spjuhel Jan 6, 2026
5df73e0
Merge branch 'feature/snapshots' into feature/impact-computation-stra…
spjuhel Jan 6, 2026
cf40e8f
API references files
spjuhel Jan 6, 2026
1511994
Merge branch 'feature/snapshots' into feature/static-risk-traj
spjuhel Jan 6, 2026
595fb55
Merge branch 'feature/impact-computation-strategies' into feature/sta…
spjuhel Jan 6, 2026
183783f
API references files
spjuhel Jan 6, 2026
b8ef41a
On The Dangers of Copy Pasting (Juhel 2026)
spjuhel Jan 6, 2026
30e2d0e
Adds warnings for direct __init__ call
spjuhel Jan 6, 2026
ffbf31e
Shifts tests to pytest format (and updates them)
spjuhel Jan 6, 2026
59ba291
updates tests
spjuhel Jan 6, 2026
77b76c4
apply_measure already makes copies
spjuhel Jan 6, 2026
2da5952
Removes remaining global risk transfer code
spjuhel Jan 6, 2026
a4e0e0c
Shifts test to pytest
spjuhel Jan 6, 2026
3a262c8
Merge branch 'feature/snapshots' into feature/static-risk-traj
spjuhel Jan 6, 2026
3902daa
Merge branch 'feature/impact-computation-strategies' into feature/sta…
spjuhel Jan 6, 2026
ca8ca6e
Wrong merge somewhere pbly
spjuhel Jan 6, 2026
46e089a
cleanup from wrong merge
spjuhel Jan 6, 2026
a9ebdb5
fixes type hint annoyance
spjuhel Jan 6, 2026
e69794f
Shifts tests to pytest
spjuhel Jan 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 205 additions & 0 deletions climada/test/common_test_fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
"""
This file is part of CLIMADA.

Copyright (C) 2017 ETH Zurich, CLIMADA contributors listed in AUTHORS.

CLIMADA is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free
Software Foundation, version 3.

CLIMADA is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with CLIMADA. If not, see <https://www.gnu.org/licenses/>.
---

A set of reusable objects for testing purpose.

The objective of this file is to provide minimalistic, understandable and consistent
default objects for unit and integration testing.

"""

import geopandas as gpd
import numpy as np
from scipy.sparse import csr_matrix
from shapely.geometry import Point

from climada.entity import Exposures, ImpactFunc, ImpactFuncSet
from climada.hazard import Centroids, Hazard
from climada.trajectories.snapshot import Snapshot

# ---------------------------------------------------------------------------
# Coordinate system and metadata
# ---------------------------------------------------------------------------
CRS_WGS84 = "EPSG:4326"

# ---------------------------------------------------------------------------
# Exposure attributes
# ---------------------------------------------------------------------------
EXP_DESC = "Test exposure dataset"
EXP_DESC_LATLON = "Test exposure dataset (lat/lon)"
EXPOSURE_REF_YEAR = 2020
EXPOSURE_VALUE_UNIT = "USD"
VALUES = np.array([0, 1000, 2000, 3000])
REGIONS = np.array(["A", "A", "B", "B"])
CATEGORIES = np.array([1, 1, 2, 1])

# Exposure coordinates
EXP_LONS = np.array([4, 4.5, 4, 4.5])
EXP_LATS = np.array([45, 45, 45.5, 45.5])

# ---------------------------------------------------------------------------
# Hazard definition
# ---------------------------------------------------------------------------
HAZARD_TYPE = "TEST_HAZARD_TYPE"
HAZARD_UNIT = "TEST_HAZARD_UNIT"

# Hazard centroid positions
HAZ_JITTER = 0.1 # To test centroid matching
HAZ_LONS = EXP_LONS + HAZ_JITTER
HAZ_LATS = EXP_LATS + HAZ_JITTER

# Hazard events
EVENT_IDS = np.array([1, 2, 3, 4])
EVENT_NAMES = ["ev1", "ev2", "ev3", "ev4"]
DATES = np.array([1, 2, 3, 4])

# Frequency are choosen so that they cumulate nicely
# to correspond to 100, 50, and 20y return periods (for impacts)
FREQUENCY = np.array([0.1, 0.03, 0.01, 0.01])
FREQUENCY_UNIT = "1/year"

# Hazard maximum intensity
# 100 to match 0 to 100% idea
# also in line with linear 1:1 impact function
# for easy mental calculus
HAZARD_MAX_INTENSITY = 100

# ---------------------------------------------------------------------------
# Impact function
# ---------------------------------------------------------------------------
IMPF_ID = 1
IMPF_NAME = "IMPF_1"

# ---------------------------------------------------------------------------
# Future years
# ---------------------------------------------------------------------------
EXPOSURE_FUTURE_YEAR = 2040


def reusable_minimal_exposures(
values=VALUES,
regions=REGIONS,
group_id=None,
lon=EXP_LONS,
lat=EXP_LATS,
crs=CRS_WGS84,
desc=EXP_DESC,
ref_year=EXPOSURE_REF_YEAR,
value_unit=EXPOSURE_VALUE_UNIT,
assign_impf=IMPF_ID,
increase_value_factor=1,
) -> Exposures:
data = gpd.GeoDataFrame(
{
"value": values * increase_value_factor,
"region_id": regions,
f"impf_{HAZARD_TYPE}": assign_impf,
"geometry": [Point(lon, lat) for lon, lat in zip(lon, lat)],
},
crs=crs,
)
if group_id is not None:
data["group_id"] = group_id
return Exposures(
data=data,
description=desc,
ref_year=ref_year,
value_unit=value_unit,
)


def reusable_intensity_mat(max_intensity=HAZARD_MAX_INTENSITY):
# Choosen such that:
# - 1st event has 0 intensity
# - 2nd event has max intensity in first exposure point (defaulting to 0 value)
# - 3rd event has 1/2* of max intensity in second centroid
# - 4th event has 1/4* of max intensity everywhere
# *: So that you can double intensity of the hazard and expect double impacts
return csr_matrix(
[
[0, 0, 0, 0],
[max_intensity, 0, 0, 0],
[0, max_intensity / 2, 0, 0],
[
max_intensity / 4,
max_intensity / 4,
max_intensity / 4,
max_intensity / 4,
],
]
)


def reusable_minimal_hazard(
haz_type=HAZARD_TYPE,
units=HAZARD_UNIT,
lat=HAZ_LATS,
lon=HAZ_LONS,
crs=CRS_WGS84,
event_id=EVENT_IDS,
event_name=EVENT_NAMES,
date=DATES,
frequency=FREQUENCY,
frequency_unit=FREQUENCY_UNIT,
intensity=None,
intensity_factor=1,
) -> Hazard:
intensity = reusable_intensity_mat() if intensity is None else intensity
intensity *= intensity_factor
return Hazard(
haz_type=haz_type,
units=units,
centroids=Centroids(lat=lat, lon=lon, crs=crs),
event_id=event_id,
event_name=event_name,
date=date,
frequency=frequency,
frequency_unit=frequency_unit,
intensity=intensity,
)


def reusable_minimal_impfset(
hazard=None, name=IMPF_NAME, impf_id=IMPF_ID, max_intensity=HAZARD_MAX_INTENSITY
):
hazard = reusable_minimal_hazard() if hazard is None else hazard
return ImpactFuncSet(
[
ImpactFunc(
haz_type=hazard.haz_type,
intensity_unit=hazard.units,
name=name,
intensity=np.array([0, max_intensity / 2, max_intensity]),
mdd=np.array([0, 0.5, 1]),
paa=np.array([1, 1, 1]),
id=impf_id,
)
]
)


def reusable_snapshot(
hazard_intensity_increase_factor=1,
exposure_value_increase_factor=1,
date=EXPOSURE_REF_YEAR,
):
exposures = reusable_minimal_exposures(
increase_value_factor=exposure_value_increase_factor
)
hazard = reusable_minimal_hazard(intensity_factor=hazard_intensity_increase_factor)
impfset = reusable_minimal_impfset()
return Snapshot(exposure=exposures, hazard=hazard, impfset=impfset, date=date)
Loading
Loading