Skip to content

Commit e66cb6c

Browse files
Merge branch 'develop' into feature/interpolate_exceedance
2 parents 0b1c2a4 + 60d3957 commit e66cb6c

45 files changed

Lines changed: 4089 additions & 118 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Code freeze date: YYYY-MM-DD
2727

2828
### Removed
2929
- `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)
30-
- `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)
30+
- `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)
3131

3232
## 6.1.0
3333

@@ -160,9 +160,9 @@ Removed:
160160
- `climada.entity.impact_funcs.trop_cyclone.ImpfSetTropCyclone.get_impf_id_regions_per_countries` function [#1034](https://github.com/CLIMADA-project/climada_python/pull/1034)
161161
- `climada.hazard.tc_tracks.BasinBoundsStorm` Enum class `climada.hazard.tc_tracks.subset_by_basin` function [#1031](https://github.com/CLIMADA-project/climada_python/pull/1031)
162162
- `climada.hazard.tc_tracks.TCTracks.subset_years` function [#1023](https://github.com/CLIMADA-project/climada_python/pull/1023)
163-
-`climada.hazard.tc_tracks.compute_track_density` function, `climada.hazard.tc_tracks.compute_genesis_density` function, `climada.hazard.plot.plot_track_density` function
163+
- `climada.hazard.tc_tracks.compute_track_density` function, `climada.hazard.tc_tracks.compute_genesis_density` function, `climada.hazard.plot.plot_track_density` function
164164
[#1003](https://github.com/CLIMADA-project/climada_python/pull/1003)
165-
-`climada.hazard.tc_tracks.TCTracks.from_FAST` function, add Australia basin (AU) [#993](https://github.com/CLIMADA-project/climada_python/pull/993)
165+
- `climada.hazard.tc_tracks.TCTracks.from_FAST` function, add Australia basin (AU) [#993](https://github.com/CLIMADA-project/climada_python/pull/993)
166166
- Add `osm-flex` package to CLIMADA core [#981](https://github.com/CLIMADA-project/climada_python/pull/981)
167167
- `doc.tutorial.climada_entity_Exposures_osm.ipynb` tutorial explaining how to use `osm-flex` with CLIMADA
168168
- `climada.util.coordinates.bounding_box_global` function [#980](https://github.com/CLIMADA-project/climada_python/pull/980)
-335 Bytes
Binary file not shown.

climada/engine/unsequa/test/test_unsequa.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,18 @@
4141
from climada.entity import Exposures, ImpactFunc, ImpactFuncSet
4242
from climada.entity.entity_def import Entity
4343
from climada.hazard import Hazard
44-
from climada.util.api_client import Client
44+
from climada.test import get_test_file
4545
from climada.util.constants import (
4646
ENT_DEMO_FUTURE,
4747
ENT_DEMO_TODAY,
48-
EXP_DEMO_H5,
4948
HAZ_DEMO_H5,
5049
TEST_UNC_OUTPUT_COSTBEN,
5150
TEST_UNC_OUTPUT_IMPACT,
5251
)
5352

54-
test_unc_output_impact = Client().get_dataset_file(
55-
name=TEST_UNC_OUTPUT_IMPACT, status="test_dataset"
56-
)
57-
test_unc_output_costben = Client().get_dataset_file(
58-
name=TEST_UNC_OUTPUT_COSTBEN, status="test_dataset"
59-
)
53+
EXP_DEMO_H5 = get_test_file("exp_demo_today", file_format="hdf5")
54+
test_unc_output_impact = get_test_file(TEST_UNC_OUTPUT_IMPACT)
55+
test_unc_output_costben = get_test_file(TEST_UNC_OUTPUT_COSTBEN)
6056

6157

6258
def impf_dem(x_paa=1, x_mdd=1):
@@ -578,7 +574,7 @@ def test_calc_sensitivity_all_pass(self):
578574
"sensitivity_kwargs": {"S": 10, "seed": 12345},
579575
"test_param_name": ["x_exp", 0],
580576
"test_si_name": ["CV", 16],
581-
"test_si_value": [0.25000, 2],
577+
"test_si_value": [0.250000, 2],
582578
},
583579
"hdmr": {
584580
"sampling_method": "saltelli",
@@ -587,7 +583,7 @@ def test_calc_sensitivity_all_pass(self):
587583
"sensitivity_kwargs": {},
588584
"test_param_name": ["x_exp", 2],
589585
"test_si_name": ["Sa", 4],
590-
"test_si_value": [0.004658, 3],
586+
"test_si_value": [0.004649, 3],
591587
},
592588
"ff": {
593589
"sampling_method": "ff",
@@ -618,7 +614,7 @@ def test_calc_sensitivity_all_pass(self):
618614
},
619615
"test_param_name": ["x_exp", 0],
620616
"test_si_name": ["dgsm", 8],
621-
"test_si_value": [1.697516e-01, 9],
617+
"test_si_value": [0.1697516, 9],
622618
},
623619
"fast": {
624620
"sampling_method": "fast_sampler",
@@ -627,7 +623,7 @@ def test_calc_sensitivity_all_pass(self):
627623
"sensitivity_kwargs": {"M": 4, "seed": 12345},
628624
"test_param_name": ["x_exp", 0],
629625
"test_si_name": ["S1_conf", 8],
630-
"test_si_value": [0.671396, 1],
626+
"test_si_value": [0.671546, 1],
631627
},
632628
"rbd_fast": {
633629
"sampling_method": "saltelli",
@@ -636,7 +632,7 @@ def test_calc_sensitivity_all_pass(self):
636632
"sensitivity_kwargs": {"M": 4, "seed": 12345},
637633
"test_param_name": ["x_exp", 0],
638634
"test_si_name": ["S1_conf", 4],
639-
"test_si_value": [0.152609, 4],
635+
"test_si_value": [0.129919, 4],
640636
},
641637
"morris": {
642638
"sampling_method": "morris",
@@ -645,7 +641,7 @@ def test_calc_sensitivity_all_pass(self):
645641
"sensitivity_kwargs": {},
646642
"test_param_name": ["x_exp", 0],
647643
"test_si_name": ["mu", 1],
648-
"test_si_value": [5066460029.63911, 8],
644+
"test_si_value": [7935400297.813827, 8],
649645
},
650646
}
651647

@@ -700,7 +696,7 @@ def test_sensitivity_method(
700696
haz_unc,
701697
sensitivity_method,
702698
method_params,
703-
places=2 if sensitivity_method == "rbd_fast" else 5,
699+
places=5,
704700
)
705701

706702

climada/entity/exposures/base.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,9 @@ def __init__(
403403

404404
self.description = self._consolidate(meta, "description", description)
405405
self.ref_year = self._consolidate(meta, "ref_year", ref_year, DEF_REF_YEAR)
406+
407+
if geodata.shape[0] > 0:
408+
value_unit = self._consolidate(geodata.iloc[0], "value_unit", value_unit)
406409
self.value_unit = self._consolidate(
407410
meta, "value_unit", value_unit, DEF_VALUE_UNIT
408411
)
@@ -644,15 +647,17 @@ def assign_centroids(
644647
645648
Caution: nearest neighbourg matching can introduce serious artefacts
646649
such as:
647-
- exposure and hazard centroids with shifted grids can lead
648-
to systematically wrong assignements.
649-
- hazard centroids covering larger areas than exposures may lead
650-
to sub-optimal matching if the threshold is too large
651-
- projected crs often diverge at the anti-meridian and close points
652-
on either side will be at a large distance. For proper handling
653-
of the anti-meridian please use degree coordinates in EPSG:4326.
654-
This might be relevant for countries like the Fidji or the US that
655-
cross the anti-meridian.
650+
651+
- exposure and hazard centroids with shifted grids can lead
652+
to systematically wrong assignements.
653+
- hazard centroids covering larger areas than exposures may lead
654+
to sub-optimal matching if the threshold is too large
655+
- projected crs often diverge at the anti-meridian and close points
656+
on either side will be at a large distance. For proper handling
657+
of the anti-meridian please use degree coordinates in EPSG:4326.
658+
This might be relevant for countries like the Fidji or the US that
659+
cross the anti-meridian.
660+
656661
657662
Users are free to implement their own matching alrogithm and save the
658663
matching centroid index in the appropriate column ``centr_[hazard.HAZ_TYPE]``.

climada/entity/exposures/test/test_base.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def test__init__mda_in_kwargs(self):
182182
def test_read_raster_pass(self):
183183
"""from_raster"""
184184
exp = Exposures.from_raster(
185-
HAZ_DEMO_FL, window=Window(10, 20, 50, 60), attrs={"value_unit": "USD"}
185+
HAZ_DEMO_FL, window=Window(10, 20, 50, 60), attrs={"value_unit": "PKR"}
186186
)
187187
exp.check()
188188
self.assertTrue(u_coord.equal_crs(exp.crs, DEF_CRS))
@@ -204,7 +204,7 @@ def test_read_raster_pass(self):
204204
self.assertAlmostEqual(
205205
exp.gdf["value"].values.reshape((60, 50))[25, 12], 0.056825936
206206
)
207-
self.assertEqual(exp.value_unit, "USD")
207+
self.assertEqual(exp.value_unit, "PKR")
208208

209209
def test_assign_raster_pass(self):
210210
"""Test assign_centroids with raster hazard"""
@@ -429,16 +429,23 @@ def test_read_template_pass(self):
429429
exp_df = Exposures(df)
430430
# set metadata
431431
exp_df.ref_year = 2020
432-
exp_df.value_unit = "XSD"
432+
exp_df.value_unit = "PAK"
433433
exp_df.check()
434434

435+
def test_handling_unit_conflicts_pass(self):
436+
"""Check that the value_unit is correctly set when there are conflicting value_unit definitions in the data frame and the meta attribute."""
437+
df = pd.read_excel(ENT_TEMPLATE_XLS)
438+
exp_df = Exposures(df, meta={"value_unit": "XSD"}, value_unit="XSD")
439+
exp_df.check()
440+
self.assertEqual(exp_df.value_unit, "XSD")
441+
with self.assertRaises(ValueError) as cm:
442+
exp_df = Exposures(df, meta={"value_unit": "XSD"}, value_unit="PAK")
443+
435444
def test_io_hdf5_pass(self):
436445
"""write and read hdf5"""
437-
exp = Exposures(pd.read_excel(ENT_TEMPLATE_XLS), crs="epsg:32632")
438-
439-
# set metadata
440-
exp.ref_year = 2020
441-
exp.value_unit = "XSD"
446+
exp = Exposures(
447+
pd.read_excel(ENT_TEMPLATE_XLS), crs="epsg:32632", ref_year=2020
448+
)
442449

443450
# add another geometry column
444451
exp.data["geocol2"] = exp.data.geometry.copy(deep=True)

climada/entity/measures/test/test_base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
from climada.entity.measures.measure_set import MeasureSet
3737
from climada.hazard.base import Hazard
3838
from climada.test import get_test_file
39-
from climada.util.constants import EXP_DEMO_H5, HAZ_DEMO_H5
39+
from climada.util.constants import HAZ_DEMO_H5
4040

4141
DATA_DIR = CONFIG.measures.test_data.dir()
4242

43+
EXP_DEMO_H5 = get_test_file("exp_demo_today", file_format="hdf5")
44+
4345
HAZ_TEST_TC: Path = get_test_file("test_tc_florida", file_format="hdf5")
4446
"""
4547
Hazard test file from Data API: Hurricanes from 1851 to 2011 over Florida with 100 centroids.

climada/hazard/tc_tracks.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2281,7 +2281,9 @@ def compute_track_density(
22812281
wind_min: float = None,
22822282
wind_max: float = None,
22832283
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
2284-
"""Compute tropical cyclone track density. Before using this function,
2284+
"""Compute tropical cyclone track density.
2285+
2286+
Before using this function,
22852287
apply the same temporal resolution to all tracks by calling :py:meth:`equal_timestep` on
22862288
the TCTrack object. Due to the computational cost of the this function, it is not
22872289
recommended to use a grid resolution higher tha 0.1°. Also note that the time step (in hours)
@@ -2291,7 +2293,7 @@ def compute_track_density(
22912293
it returns the absolute count per bin. To plot the output of this function,
22922294
use :py:meth:`plot_track_density`.
22932295
2294-
Parameters:
2296+
Parameters
22952297
----------
22962298
tc_track: TCTracks object
22972299
track object containing a list of all tracks
@@ -2310,7 +2312,8 @@ def compute_track_density(
23102312
wind_max: float (optional), default: None
23112313
Maximal wind speed below which to select tracks (exclusive if wind_min is also provided,
23122314
otherwise inclusive).
2313-
Returns:
2315+
2316+
Returns
23142317
-------
23152318
hist_count: np.ndarray
23162319
2D matrix containing the absolute count per grid cell of track point.
@@ -2319,8 +2322,8 @@ def compute_track_density(
23192322
lon_bins: np.ndarray
23202323
longitude bins in which the point were counted
23212324
2322-
Example:
2323-
--------
2325+
Example
2326+
-------
23242327
>>> tc_tracks = TCTrack.from_ibtracs_netcdf("path_to_file")
23252328
>>> tc_tracks.equal_timestep(time_step_h = 1)
23262329
>>> hist_count, _, _ = compute_track_density(tc_track = tc_tracks, res = 2)

climada/hazard/tc_tracks_synth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,7 @@ def _apply_decay_coeffs(track, v_rel, p_rel, land_geom, s_rel):
10491049
# if there is no further landfall, correct until the end of
10501050
# the track
10511051
end_cor = track["time"].size
1052-
rndn = 0.1 * float(np.abs(np.random.normal(size=1) * 5) + 6)
1052+
rndn = 0.1 * float(np.abs(np.random.default_rng().normal() * 5) + 6)
10531053
r_diff = (
10541054
track["central_pressure"][land_sea].values
10551055
- track["central_pressure"][land_sea - 1].values

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

0 commit comments

Comments
 (0)