Skip to content

Commit 231087d

Browse files
committed
Merge branch 'develop' into fix-haz-creation-with-attrs
2 parents b452bb0 + 3c54792 commit 231087d

34 files changed

Lines changed: 2273 additions & 1746 deletions

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,29 @@ Release date: 2025-09-30
66

77
### Dependency Changes
88

9+
### Added
10+
11+
- Better type hints and overloads signatures for ImpactFuncSet [#1250](https://github.com/CLIMADA-project/climada_python/pull/1250)
12+
13+
### Changed
14+
- Updated Impact Calculation Tutorial (`doc.climada_engine_Impact.ipynb`) [#1095](https://github.com/CLIMADA-project/climada_python/pull/1095).
15+
16+
### Fixed
17+
18+
- Fixed asset count in impact logging message [#1195](https://github.com/CLIMADA-project/climada_python/pull/1195).
19+
20+
### Deprecated
21+
22+
### Removed
23+
- `climada.util.earth_engine.py` Google Earth Engine methods did not facilitate direct use of GEE data in CLIMADA. Code was relocated to [climada-snippets](https://github.com/CLIMADA-project/climada-snippets). [#1109](https://github.com/CLIMADA-project/climada_python/pull/1109)
24+
- `doc.climada_util_earth_engine.ipynb` Tutorial about GEE not relevant to CLIMADA Core. Tutorial notebook was relocated to [climada-snippets](https://github.com/CLIMADA-project/climada-snippets).[#1109](https://github.com/CLIMADA-project/climada_python/pull/1109)
25+
26+
## 6.1.0
27+
28+
Release date: 2025-09-30
29+
30+
### Dependency Changes
31+
932
Added:
1033

1134
- `bayesian-optimization` >=1.5,<2.0

climada/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "6.1.0"
1+
__version__ = "6.1.1-dev"

climada/engine/impact_calc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def impact(
186186
return self._return_empty(save_mat)
187187
LOGGER.info(
188188
"Calculating impact for %s assets (>0) and %s events.",
189-
exp_gdf.size,
189+
len(exp_gdf),
190190
self.n_events,
191191
)
192192
imp_mat_gen = self.imp_mat_gen(exp_gdf, impf_col)

climada/engine/test/test_impact_calc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ def test_calc_insured_impact_no_insurance(self):
441441
self.assertEqual(
442442
logs.output,
443443
[
444-
"INFO:climada.engine.impact_calc:Calculating impact for 150 assets (>0) and 14450 events."
444+
"INFO:climada.engine.impact_calc:Calculating impact for 50 assets (>0) and 14450 events."
445445
],
446446
)
447447
self.assertEqual(icalc.n_events, len(impact.at_event))

climada/engine/unsequa/input_var.py

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,8 @@ def haz(haz_list, n_ev=None, bounds_int=None, bounds_frac=None, bounds_freq=None
246246
The frequency of all events is multiplied by a number
247247
sampled uniformly from a distribution with (min, max) = bounds_freq
248248
HL: sample uniformly from hazard list
249-
From the provided list of hazard is elements are uniformly
250-
sampled. For example, Hazards outputs from dynamical models
251-
for different input factors.
249+
For each sample, one element is drawn uniformly from the provided list of hazards.
250+
For example, Hazards outputs from dynamical models for different input factors.
252251
253252
If a bounds is None, this parameter is assumed to have no uncertainty.
254253
@@ -310,8 +309,8 @@ def exp(exp_list, bounds_totval=None, bounds_noise=None):
310309
with (min, max) = bounds_noise. EN is the value of the seed
311310
for the uniform random number generator.
312311
EL: sample uniformly from exposure list
313-
From the provided list of exposure is elements are uniformly
314-
sampled. For example, LitPop instances with different exponents.
312+
For each sample, one element is drawn uniformly from the provided list of exposures.
313+
For example, LitPop instances with different exponents.
315314
316315
If a bounds is None, this parameter is assumed to have no uncertainty.
317316
@@ -376,9 +375,8 @@ def impfset(
376375
sampled uniformly from a distribution with
377376
(min, max) = bounds_int
378377
IL: sample uniformly from impact function set list
379-
From the provided list of impact function sets elements are uniformly
380-
sampled. For example, impact functions obtained from different
381-
calibration methods.
378+
For each sample, one element is drawn uniformly from the provided list of impact function sets.
379+
For example, impact functions obtained from different calibration methods.
382380
383381
384382
If a bounds is None, this parameter is assumed to have no uncertainty.
@@ -468,8 +466,8 @@ def ent(
468466
with (min, max) = bounds_noise. EN is the value of the seed
469467
for the uniform random number generator.
470468
EL: sample uniformly from exposure list
471-
From the provided list of exposure is elements are uniformly
472-
sampled. For example, LitPop instances with different exponents.
469+
For each sample, one element is drawn uniformly from the provided list of exposures.
470+
For example, LitPop instances with different exponents.
473471
MDD: scale the mdd (homogeneously)
474472
The value of mdd at each intensity is multiplied by a number
475473
sampled uniformly from a distribution with
@@ -483,9 +481,8 @@ def ent(
483481
sampled uniformly from a distribution with
484482
(min, max) = bounds_int
485483
IL: sample uniformly from impact function set list
486-
From the provided list of impact function sets elements are uniformly
487-
sampled. For example, impact functions obtained from different
488-
calibration methods.
484+
For each sample, one element is drawn uniformly from the provided list of impact function sets.
485+
For example, impact functions obtained from different calibration methods.
489486
490487
If a bounds is None, this parameter is assumed to have no uncertainty.
491488
@@ -566,7 +563,7 @@ def ent(
566563
bounds_noise=bounds_noise,
567564
exp_list=exp_list,
568565
meas_set=meas_set,
569-
**kwargs
566+
**kwargs,
570567
),
571568
_ent_unc_dict(
572569
bounds_totval=bounds_totval,
@@ -616,8 +613,8 @@ def entfut(
616613
with (min, max) = bounds_noise. EN is the value of the seed
617614
for the uniform random number generator.
618615
EL: sample uniformly from exposure list
619-
From the provided list of exposure is elements are uniformly
620-
sampled. For example, LitPop instances with different exponents.
616+
For each sample, one element is drawn uniformly from the provided list of exposures.
617+
For example, LitPop instances with different exponents.
621618
MDD: scale the mdd (homogeneously)
622619
The value of mdd at each intensity is multiplied by a number
623620
sampled uniformly from a distribution with
@@ -631,9 +628,8 @@ def entfut(
631628
sampled uniformly from a distribution with
632629
(min, max) = bounds_impfi
633630
IL: sample uniformly from impact function set list
634-
From the provided list of impact function sets elements are uniformly
635-
sampled. For example, impact functions obtained from different
636-
calibration methods.
631+
For each sample, one element is drawn uniformly from the provided list of impact function sets.
632+
For example, impact functions obtained from different calibration methods.
637633
638634
If a bounds is None, this parameter is assumed to have no uncertainty.
639635
@@ -706,7 +702,7 @@ def entfut(
706702
impf_set_list=impf_set_list,
707703
exp_list=exp_list,
708704
meas_set=meas_set,
709-
**kwargs
705+
**kwargs,
710706
),
711707
_entfut_unc_dict(
712708
bounds_eg=bounds_eg,

climada/entity/impact_funcs/base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ def from_step_impf(
189189
haz_type: str,
190190
mdd: tuple[float, float] = (0, 1),
191191
paa: tuple[float, float] = (1, 1),
192-
impf_id: int = 1,
192+
impf_id: int | str = 1,
193193
**kwargs,
194194
):
195195
"""Step function type impact function.
@@ -207,7 +207,7 @@ def from_step_impf(
207207
(min, max) mdd values. The default is (0, 1)
208208
paa: tuple(float, float)
209209
(min, max) paa values. The default is (1, 1)
210-
impf_id : int, optional, default=1
210+
impf_id : int|str, optional, default=1
211211
impact function id
212212
kwargs :
213213
keyword arguments passed to ImpactFunc()
@@ -250,7 +250,7 @@ def from_sigmoid_impf(
250250
k: float,
251251
x0: float,
252252
haz_type: str,
253-
impf_id: int = 1,
253+
impf_id: int | str = 1,
254254
**kwargs,
255255
):
256256
r"""Sigmoid type impact function hinging on three parameter.
@@ -320,7 +320,7 @@ def from_poly_s_shape(
320320
scale: float,
321321
exponent: float,
322322
haz_type: str,
323-
impf_id: int = 1,
323+
impf_id: int | str = 1,
324324
**kwargs,
325325
):
326326
r"""S-shape polynomial impact function hinging on four parameter.

climada/entity/impact_funcs/impact_func_set.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import copy
2525
import logging
2626
from itertools import repeat
27-
from typing import Iterable, Optional
27+
from typing import Iterable, Optional, Union, overload
2828

2929
import matplotlib.pyplot as plt
3030
import numpy as np
@@ -119,7 +119,7 @@ def clear(self):
119119
"""Reinitialize attributes."""
120120
self._data = dict() # {hazard_type : {id:ImpactFunc}}
121121

122-
def append(self, func):
122+
def append(self, func: ImpactFunc):
123123
"""Append a ImpactFunc. Overwrite existing if same id and haz_type.
124124
125125
Parameters
@@ -141,7 +141,9 @@ def append(self, func):
141141
self._data[func.haz_type] = dict()
142142
self._data[func.haz_type][func.id] = func
143143

144-
def remove_func(self, haz_type=None, fun_id=None):
144+
def remove_func(
145+
self, haz_type: Optional[str] = None, fun_id: Optional[str | int] = None
146+
):
145147
"""Remove impact function(s) with provided hazard type and/or id.
146148
If no input provided, all impact functions are removed.
147149
@@ -173,7 +175,29 @@ def remove_func(self, haz_type=None, fun_id=None):
173175
else:
174176
self._data = dict()
175177

176-
def get_func(self, haz_type=None, fun_id=None):
178+
@overload
179+
def get_func(
180+
self, haz_type: None = None, fun_id: None = None
181+
) -> dict[str, dict[Union[int, str], ImpactFunc]]: ...
182+
183+
@overload
184+
def get_func(
185+
self, haz_type: None = ..., fun_id: int | str = ...
186+
) -> list[ImpactFunc]: ...
187+
188+
@overload
189+
def get_func(
190+
self, haz_type: str = ..., fun_id: None = None
191+
) -> list[ImpactFunc]: ...
192+
193+
@overload
194+
def get_func(self, haz_type: str = ..., fun_id: int | str = ...) -> ImpactFunc: ...
195+
196+
def get_func(
197+
self, haz_type: Optional[str] = None, fun_id: Optional[int | str] = None
198+
) -> Union[
199+
ImpactFunc, list[ImpactFunc], dict[str, dict[Union[int, str], ImpactFunc]]
200+
]:
177201
"""Get ImpactFunc(s) of input hazard type and/or id.
178202
If no input provided, all impact functions are returned.
179203
@@ -209,7 +233,7 @@ def get_func(self, haz_type=None, fun_id=None):
209233
else:
210234
return self._data
211235

212-
def get_hazard_types(self, fun_id=None):
236+
def get_hazard_types(self, fun_id: Optional[str | int] = None) -> list[str]:
213237
"""Get impact functions hazard types contained for the id provided.
214238
Return all hazard types if no input id.
215239
@@ -231,7 +255,15 @@ def get_hazard_types(self, fun_id=None):
231255
haz_types.append(vul_haz)
232256
return haz_types
233257

234-
def get_ids(self, haz_type=None):
258+
@overload
259+
def get_ids(self, haz_type: None = None) -> dict[str, list[str | int]]: ...
260+
261+
@overload
262+
def get_ids(self, haz_type: str) -> list[int | str]: ...
263+
264+
def get_ids(
265+
self, haz_type: Optional[str] = None
266+
) -> dict[str, list[str | int]] | list[int | str]:
235267
"""Get impact functions ids contained for the hazard type provided.
236268
Return all ids for each hazard type if no input hazard type.
237269
@@ -256,7 +288,9 @@ def get_ids(self, haz_type=None):
256288
except KeyError:
257289
return list()
258290

259-
def size(self, haz_type=None, fun_id=None):
291+
def size(
292+
self, haz_type: Optional[str] = None, fun_id: Optional[str | int] = None
293+
) -> int:
260294
"""Get number of impact functions contained with input hazard type and
261295
/or id. If no input provided, get total number of impact functions.
262296
@@ -279,6 +313,7 @@ def size(self, haz_type=None, fun_id=None):
279313
return 1
280314
if (haz_type is not None) or (fun_id is not None):
281315
return len(self.get_func(haz_type, fun_id))
316+
282317
return sum(len(vul_list) for vul_list in self.get_ids().values())
283318

284319
def check(self):
@@ -300,7 +335,7 @@ def check(self):
300335
)
301336
vul.check()
302337

303-
def extend(self, impact_funcs):
338+
def extend(self, impact_funcs: "ImpactFuncSet"):
304339
"""Append impact functions of input ImpactFuncSet to current
305340
ImpactFuncSet. Overwrite ImpactFunc if same id and haz_type.
306341
@@ -323,7 +358,13 @@ def extend(self, impact_funcs):
323358
for _, vul in vul_dict.items():
324359
self.append(vul)
325360

326-
def plot(self, haz_type=None, fun_id=None, axis=None, **kwargs):
361+
def plot(
362+
self,
363+
haz_type: Optional[str] = None,
364+
fun_id: Optional[str | int] = None,
365+
axis=None,
366+
**kwargs,
367+
):
327368
"""Plot impact functions of selected hazard (all if not provided) and
328369
selected function id (all if not provided).
329370

climada/hazard/test/test_xarray.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import numpy as np
2929
import xarray as xr
3030
from pyproj import CRS
31-
from scipy.sparse import csr_matrix
31+
from scipy.sparse import csr_array, csr_matrix
3232

3333
from climada.hazard.base import Hazard
3434
from climada.util.constants import DEF_CRS
@@ -104,8 +104,8 @@ def _assert_default_types(self, hazard):
104104
self.assertIsInstance(hazard.event_id, np.ndarray)
105105
self.assertIsInstance(hazard.event_name, list)
106106
self.assertIsInstance(hazard.frequency, np.ndarray)
107-
self.assertIsInstance(hazard.intensity, csr_matrix)
108-
self.assertIsInstance(hazard.fraction, csr_matrix)
107+
self.assertIsInstance(hazard.intensity, csr_matrix | csr_array)
108+
self.assertIsInstance(hazard.fraction, csr_matrix | csr_array)
109109
self.assertIsInstance(hazard.date, np.ndarray)
110110

111111
def test_load_path(self):
@@ -149,8 +149,11 @@ def _load_and_assert(**kwargs):
149149
def test_type_error(self):
150150
"""Calling 'from_xarray_raster' with wrong data type should throw"""
151151
# Passing a DataArray
152-
with xr.open_dataset(self.netcdf_path) as dset, self.assertRaisesRegex(
153-
TypeError, "This method only supports passing xr.Dataset"
152+
with (
153+
xr.open_dataset(self.netcdf_path) as dset,
154+
self.assertRaisesRegex(
155+
TypeError, "This method only supports passing xr.Dataset"
156+
),
154157
):
155158
Hazard.from_xarray_raster(dset["intensity"], "", "")
156159

climada/hazard/xarray.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def _to_csr_matrix(array: xr.DataArray) -> sparse.csr_matrix:
5858
output_dtypes=[array.dtype],
5959
)
6060
sparse_coo = array.compute().data # Load into memory
61-
return sparse_coo.tocsr() # Convert sparse.COO to scipy.sparse.csr_matrix
61+
return sparse_coo.tocsr() # Convert sparse.COO to scipy.sparse.csr_array
6262

6363

6464
# Define accessors for xarray DataArrays

climada/trajectories/__init__.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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+
19+
This module implements risk trajectory objects which enable computation and
20+
possibly interpolation of risk metric over multiple dates.
21+
22+
"""
23+
24+
from .interpolation import AllLinearStrategy, ExponentialExposureStrategy
25+
from .snapshot import Snapshot
26+
27+
__all__ = [
28+
"AllLinearStrategy",
29+
"ExponentialExposureStrategy",
30+
"Snapshot",
31+
]

0 commit comments

Comments
 (0)