Skip to content

Commit 8895be3

Browse files
authored
Merge pull request #1200 from CLIMADA-project/feature/static-risk-traj
Risk Trajectory Split 4 : Non-interpolated (Static) trajectories
2 parents 99703d3 + ea8e9b6 commit 8895be3

15 files changed

+2632
-0
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
"""
2+
This file is part of CLIMADA.
3+
4+
Copyright (C) 2017 ETH Zurich, CLIMADA contributors listed in AUTHORS.
5+
6+
CLIMADA is free software: you can redistribute it and/or modify it under the
7+
terms of the GNU General Public License as published by the Free
8+
Software Foundation, version 3.
9+
10+
CLIMADA is distributed in the hope that it will be useful, but WITHOUT ANY
11+
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
12+
PARTICULAR PURPOSE. See the GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License along
15+
with CLIMADA. If not, see <https://www.gnu.org/licenses/>.
16+
---
17+
18+
A set of reusable objects for testing purpose.
19+
20+
The objective of this file is to provide minimalistic, understandable and consistent
21+
default objects for unit and integration testing.
22+
23+
"""
24+
25+
import geopandas as gpd
26+
import numpy as np
27+
from scipy.sparse import csr_matrix
28+
from shapely.geometry import Point
29+
30+
from climada.entity import Exposures, ImpactFunc, ImpactFuncSet
31+
from climada.hazard import Centroids, Hazard
32+
from climada.trajectories.snapshot import Snapshot
33+
34+
# ---------------------------------------------------------------------------
35+
# Coordinate system and metadata
36+
# ---------------------------------------------------------------------------
37+
CRS_WGS84 = "EPSG:4326"
38+
39+
# ---------------------------------------------------------------------------
40+
# Exposure attributes
41+
# ---------------------------------------------------------------------------
42+
EXP_DESC = "Test exposure dataset"
43+
EXP_DESC_LATLON = "Test exposure dataset (lat/lon)"
44+
EXPOSURE_REF_YEAR = 2020
45+
EXPOSURE_VALUE_UNIT = "USD"
46+
VALUES = np.array([0, 1000, 2000, 3000])
47+
REGIONS = np.array(["A", "A", "B", "B"])
48+
CATEGORIES = np.array([1, 1, 2, 1])
49+
50+
# Exposure coordinates
51+
EXP_LONS = np.array([4, 4.5, 4, 4.5])
52+
EXP_LATS = np.array([45, 45, 45.5, 45.5])
53+
54+
# ---------------------------------------------------------------------------
55+
# Hazard definition
56+
# ---------------------------------------------------------------------------
57+
HAZARD_TYPE = "TEST_HAZARD_TYPE"
58+
HAZARD_UNIT = "TEST_HAZARD_UNIT"
59+
60+
# Hazard centroid positions
61+
HAZ_JITTER = 0.1 # To test centroid matching
62+
HAZ_LONS = EXP_LONS + HAZ_JITTER
63+
HAZ_LATS = EXP_LATS + HAZ_JITTER
64+
65+
# Hazard events
66+
EVENT_IDS = np.array([1, 2, 3, 4])
67+
EVENT_NAMES = ["ev1", "ev2", "ev3", "ev4"]
68+
DATES = np.array([1, 2, 3, 4])
69+
70+
# Frequency are choosen so that they cumulate nicely
71+
# to correspond to 100, 50, and 20y return periods (for impacts)
72+
FREQUENCY = np.array([0.1, 0.03, 0.01, 0.01])
73+
FREQUENCY_UNIT = "1/year"
74+
75+
# Hazard maximum intensity
76+
# 100 to match 0 to 100% idea
77+
# also in line with linear 1:1 impact function
78+
# for easy mental calculus
79+
HAZARD_MAX_INTENSITY = 100
80+
81+
# ---------------------------------------------------------------------------
82+
# Impact function
83+
# ---------------------------------------------------------------------------
84+
IMPF_ID = 1
85+
IMPF_NAME = "IMPF_1"
86+
87+
# ---------------------------------------------------------------------------
88+
# Future years
89+
# ---------------------------------------------------------------------------
90+
EXPOSURE_FUTURE_YEAR = 2040
91+
92+
93+
def reusable_minimal_exposures(
94+
values=VALUES,
95+
regions=REGIONS,
96+
group_id=None,
97+
lon=EXP_LONS,
98+
lat=EXP_LATS,
99+
crs=CRS_WGS84,
100+
desc=EXP_DESC,
101+
ref_year=EXPOSURE_REF_YEAR,
102+
value_unit=EXPOSURE_VALUE_UNIT,
103+
assign_impf=IMPF_ID,
104+
increase_value_factor=1,
105+
) -> Exposures:
106+
data = gpd.GeoDataFrame(
107+
{
108+
"value": values * increase_value_factor,
109+
"region_id": regions,
110+
f"impf_{HAZARD_TYPE}": assign_impf,
111+
"geometry": [Point(lon, lat) for lon, lat in zip(lon, lat)],
112+
},
113+
crs=crs,
114+
)
115+
if group_id is not None:
116+
data["group_id"] = group_id
117+
return Exposures(
118+
data=data,
119+
description=desc,
120+
ref_year=ref_year,
121+
value_unit=value_unit,
122+
)
123+
124+
125+
def reusable_intensity_mat(max_intensity=HAZARD_MAX_INTENSITY):
126+
# Choosen such that:
127+
# - 1st event has 0 intensity
128+
# - 2nd event has max intensity in first exposure point (defaulting to 0 value)
129+
# - 3rd event has 1/2* of max intensity in second centroid
130+
# - 4th event has 1/4* of max intensity everywhere
131+
# *: So that you can double intensity of the hazard and expect double impacts
132+
return csr_matrix(
133+
[
134+
[0, 0, 0, 0],
135+
[max_intensity, 0, 0, 0],
136+
[0, max_intensity / 2, 0, 0],
137+
[
138+
max_intensity / 4,
139+
max_intensity / 4,
140+
max_intensity / 4,
141+
max_intensity / 4,
142+
],
143+
]
144+
)
145+
146+
147+
def reusable_minimal_hazard(
148+
haz_type=HAZARD_TYPE,
149+
units=HAZARD_UNIT,
150+
lat=HAZ_LATS,
151+
lon=HAZ_LONS,
152+
crs=CRS_WGS84,
153+
event_id=EVENT_IDS,
154+
event_name=EVENT_NAMES,
155+
date=DATES,
156+
frequency=FREQUENCY,
157+
frequency_unit=FREQUENCY_UNIT,
158+
intensity=None,
159+
intensity_factor=1,
160+
) -> Hazard:
161+
intensity = reusable_intensity_mat() if intensity is None else intensity
162+
intensity *= intensity_factor
163+
return Hazard(
164+
haz_type=haz_type,
165+
units=units,
166+
centroids=Centroids(lat=lat, lon=lon, crs=crs),
167+
event_id=event_id,
168+
event_name=event_name,
169+
date=date,
170+
frequency=frequency,
171+
frequency_unit=frequency_unit,
172+
intensity=intensity,
173+
)
174+
175+
176+
def reusable_minimal_impfset(
177+
hazard=None, name=IMPF_NAME, impf_id=IMPF_ID, max_intensity=HAZARD_MAX_INTENSITY
178+
):
179+
hazard = reusable_minimal_hazard() if hazard is None else hazard
180+
return ImpactFuncSet(
181+
[
182+
ImpactFunc(
183+
haz_type=hazard.haz_type,
184+
intensity_unit=hazard.units,
185+
name=name,
186+
intensity=np.array([0, max_intensity / 2, max_intensity]),
187+
mdd=np.array([0, 0.5, 1]),
188+
paa=np.array([1, 1, 1]),
189+
id=impf_id,
190+
)
191+
]
192+
)
193+
194+
195+
def reusable_snapshot(
196+
hazard_intensity_increase_factor=1,
197+
exposure_value_increase_factor=1,
198+
date=EXPOSURE_REF_YEAR,
199+
):
200+
exposures = reusable_minimal_exposures(
201+
increase_value_factor=exposure_value_increase_factor
202+
)
203+
hazard = reusable_minimal_hazard(intensity_factor=hazard_intensity_increase_factor)
204+
impfset = reusable_minimal_impfset()
205+
return Snapshot(exposure=exposures, hazard=hazard, impfset=impfset, date=str(date))

0 commit comments

Comments
 (0)