Skip to content

Commit e270e1a

Browse files
committed
Merge branch 'develop' into calibrate-impact-functions
2 parents 2326db2 + 7ce9484 commit e270e1a

Some content is hidden

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

44 files changed

+2587
-3224
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: bug
6+
assignees: ''
7+
8+
---
9+
10+
**Describe the bug**
11+
A clear and concise description of what the bug is.
12+
13+
**To Reproduce**
14+
Steps to reproduce the behavior/error:
15+
1.
16+
17+
Code example:
18+
```python
19+
# Your code here
20+
```
21+
22+
**Expected behavior**
23+
A clear and concise description of what you expected to happen.
24+
25+
**Screenshots**
26+
If applicable, add screenshots to help explain your problem.
27+
28+
**Climada Version:** [Version or branch]
29+
30+
**System Information (please complete the following information):**
31+
- Operating system and version: [e.g. Ubuntu 22.04, macOS 14.3.1, Windows 10]
32+
- Python version: [e.g. 3.10]
33+
(to obtain this information execute > import sys >print(sys.version))
34+
35+
**Additional context**
36+
Add any other context about the problem here.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
name: Code feature request
3+
about: Suggest an idea to improve the code
4+
title: ''
5+
labels: enhancement
6+
assignees: ''
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12+
13+
**Describe the solution you'd like**
14+
A clear and concise description of what you want to happen.
15+
16+
**Describe alternatives you've considered**
17+
A clear and concise description of any alternative solutions or features you've considered.
18+
19+
**Additional context**
20+
Add any other context or screenshots about the feature request here.

.readthedocs.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ build:
55
tools:
66
python: "mambaforge-4.10"
77

8+
# Append fixed Python version to requirements
9+
jobs:
10+
pre_create_environment:
11+
- echo " - python=3.9" >> requirements/env_climada.yml
12+
813
conda:
9-
environment: requirements/env_docs.yml
14+
environment: requirements/env_climada.yml
1015

1116
python:
1217
install:

AUTHORS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,5 @@
3333
* Kam Lam Yeung
3434
* Sarah Hülsen
3535
* Timo Schmid
36+
* Luca Severino
37+
* Samuel Juhel

CHANGELOG.md

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,65 @@ Code freeze date: YYYY-MM-DD
1010

1111
### Dependency Changes
1212

13-
### Added
14-
1513
### Changed
1614

15+
- Centroids complete overhaul. Most function should be backward compatible. Internal data is stored in a geodataframe attribute. Raster are now stored as points, and the meta attribute is removed. Several methds were deprecated or removed. [#787](https://github.com/CLIMADA-project/climada_python/pull/787)
16+
- Improved error messages produced by `ImpactCalc.impact()` in case impact function in the exposures is not found in impf_set [#863](https://github.com/CLIMADA-project/climada_python/pull/863)
17+
1718
### Fixed
1819

20+
- Avoid an issue where a Hazard subselection would have a fraction matrix with only zeros as entries by throwing an error [#866](https://github.com/CLIMADA-project/climada_python/pull/866)
21+
22+
### Added
23+
24+
- climada.hazard.centroids.centr.Centroids.get_area_pixel
25+
- climada.hazard.centroids.centr.Centroids.get_dist_coast
26+
- climada.hazard.centroids.centr.Centroids.get_elevation
27+
- climada.hazard.centroids.centr.Centroids.get_meta
28+
- climada.hazard.centroids.centr.Centroids.get_pixel_shapes
29+
- climada.hazard.centroids.centr.Centroids.to_crs
30+
- climada.hazard.centroids.centr.Centroids.to_default_crs
31+
- climada.hazard.centroids.centr.Centroids.write_csv
32+
- climada.hazard.centroids.centr.Centroids.write_excel
33+
1934
### Deprecated
2035

36+
- climada.hazard.centroids.centr.Centroids.from_lat_lon
37+
- climada.hazard.centroids.centr.Centroids.def set_area_pixel
38+
- climada.hazard.centroids.centr.Centroids.def set_area_approx
39+
- climada.hazard.centroids.centr.Centroids.set_dist_coast
40+
- climada.hazard.centroids.centr.Centroids.empty_geometry_points
41+
- climada.hazard.centroids.centr.Centroids.set_meta_to_lat_lon
42+
- climada.hazard.centroids.centr.Centroids.set_lat_lon_to_meta
43+
2144
### Removed
2245

46+
- climada.hazard.base.Hazard.clear
47+
- climada.hazard.base.Hazard.raster_to_vector
48+
- climada.hazard.base.Hazard.read_mat
49+
- climada.hazard.base.Hazard.reproject_raster
50+
- climada.hazard.base.Hazard.set_vector
51+
- climada.hazard.base.Hazard.vector_to_raster
52+
- climada.hazard.centroids.centr.Centroids.calc_pixels_polygons
53+
- climada.hazard.centroids.centr.Centroids.check
54+
- climada.hazard.centroids.centr.Centroids.clear
55+
- climada.hazard.centroids.centr.Centroids.equal
56+
- climada.hazard.centroids.centr.Centroids.from_mat
57+
- climada.hazard.centroids.centr.Centroids.from_base_grid
58+
- climada.hazard.centroids.centr.Centroids.read_excel
59+
- climada.hazard.centroids.centr.Centroids.read_hdf5
60+
- climada.hazard.centroids.centr.Centroids.read_mat
61+
- climada.hazard.centroids.centr.Centroids.set_elevation
62+
- climada.hazard.centroids.centr.Centroids.set_geometry_points
63+
- climada.hazard.centroids.centr.Centroids.set_lat_lon
64+
- climada.hazard.centroids.centr.Centroids.set_raster_file
65+
- climada.hazard.centroids.centr.Centroids.set_raster_from_pnt_bounds
66+
- climada.hazard.centroids.centr.Centroids.set_vector_file
67+
- climada.hazard.centroids.centr.Centroids.values_from_raster_files
68+
- climada.hazard.centroids.centr.Centroids.values_from_vector_files
69+
- climada.hazard.centroids.centr.generate_nat_earth_centroids
70+
- `requirements/env_docs.yml`. The regular environment specs are now used to build the online documentation [#687](https://github.com/CLIMADA-project/climada_python/pull/687)
71+
2372
## 4.1.1
2473

2574
Release date: 2024-02-21

climada/conf/climada.conf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"cache_db": "{local_data.system}/.downloads.db",
6868
"cache_enabled": true,
6969
"cache_dir": "{local_data.system}/.apicache",
70-
"supported_hazard_types": ["river_flood", "tropical_cyclone", "storm_europe", "relative_cropyield", "wildfire", "earthquake", "flood"],
71-
"supported_exposures_types": ["litpop", "crop_production", "ssp_population"]
70+
"supported_hazard_types": ["river_flood", "tropical_cyclone", "storm_europe", "relative_cropyield", "wildfire", "earthquake", "flood", "hail"],
71+
"supported_exposures_types": ["litpop", "crop_production", "ssp_population", "crops"]
7272
}
7373
}

climada/engine/forecast.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from matplotlib.ticker import PercentFormatter, ScalarFormatter
3232
from matplotlib.colors import ListedColormap, BoundaryNorm
3333
import cartopy.crs as ccrs
34+
from matplotlib import colormaps as cm
3435
import pyproj
3536
import shapely
3637
from cartopy.io import shapereader
@@ -88,7 +89,7 @@
8889
warnprob_colors_extended = np.repeat(warnprob_colors, 10, axis=0)
8990
CMAP_WARNPROB = ListedColormap(warnprob_colors_extended)
9091
# colors for impact forecast
91-
color_map_pre = plt.get_cmap("plasma", 90)
92+
color_map_pre = cm.get_cmap("plasma").resampled(90)
9293
impact_colors = color_map_pre(np.linspace(0, 1, 90))
9394
white_extended = np.repeat([[255 / 255, 255 / 255, 255 / 255, 1]], 10, axis=0)
9495
impact_colors_extended = np.append(white_extended, impact_colors, axis=0)

climada/engine/impact_calc.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def impact(self, save_mat=True, assign_centroids=True,
112112
apply_deductible_to_mat : apply deductible to impact matrix
113113
apply_cover_to_mat : apply cover to impact matrix
114114
"""
115-
# check for compability of exposures and hazard type
115+
# check for compatibility of exposures and hazard type
116116
if all(name not in self.exposures.gdf.columns for
117117
name in ['if_', f'if_{self.hazard.haz_type}',
118118
'impf_', f'impf_{self.hazard.haz_type}']):
@@ -121,14 +121,28 @@ def impact(self, save_mat=True, assign_centroids=True,
121121
f"for hazard type {self.hazard.haz_type} in exposures."
122122
)
123123

124-
# check for compability of impact function and hazard type
124+
# check for compatibility of impact function and hazard type
125125
if not self.impfset.get_func(haz_type=self.hazard.haz_type):
126126
raise AttributeError(
127127
"Impact calculation not possible. No impact functions found "
128128
f"for hazard type {self.hazard.haz_type} in impf_set."
129129
)
130130

131131
impf_col = self.exposures.get_impf_column(self.hazard.haz_type)
132+
known_impact_functions = self.impfset.get_ids(haz_type=self.hazard.haz_type)
133+
134+
# check for compatibility of impact function id between impact function set and exposure
135+
if not all(self.exposures.gdf[impf_col].isin(known_impact_functions)):
136+
unknown_impact_functions = list(self.exposures.gdf[
137+
~self.exposures.gdf[impf_col].isin(known_impact_functions)
138+
][impf_col].drop_duplicates().astype(int).astype(str))
139+
raise ValueError(
140+
f"The associated impact function(s) with id(s) "
141+
f"{', '.join(unknown_impact_functions)} have no match in impact function set for"
142+
f" hazard type \'{self.hazard.haz_type}\'.\nPlease make sure that all exposure "
143+
"points are associated with an impact function that is included in the impact "
144+
"function set.")
145+
132146
exp_gdf = self.minimal_exp_gdf(impf_col, assign_centroids, ignore_cover, ignore_deductible)
133147
if exp_gdf.size == 0:
134148
return self._return_empty(save_mat)

climada/engine/test/test_cost_benefit.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,15 @@
3535
from climada.test import get_test_file
3636

3737

38-
HAZ_TEST_MAT = get_test_file('atl_prob_no_name', file_format='matlab')
3938
ENT_TEST_MAT = get_test_file('demo_today', file_format='MAT-file')
40-
39+
HAZ_TEST_TC :Path = get_test_file('test_tc_florida')
4140

4241
class TestSteps(unittest.TestCase):
4342
"""Test intermediate steps"""
4443
def test_calc_impact_measures_pass(self):
4544
"""Test _calc_impact_measures against reference value"""
46-
self.assertTrue(HAZ_TEST_MAT.is_file(), "{} is not a file".format(HAZ_TEST_MAT))
47-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
45+
self.assertTrue(HAZ_TEST_TC.is_file(), "{} is not a file".format(HAZ_TEST_TC))
46+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
4847

4948
self.assertTrue(ENT_TEST_MAT.is_file(), "{} is not a file".format(ENT_TEST_MAT))
5049
entity = Entity.from_mat(ENT_TEST_MAT)
@@ -230,7 +229,7 @@ def test_cb_one_meas_fut_pass(self):
230229

231230
def test_calc_cb_no_change_pass(self):
232231
"""Test _calc_cost_benefit without present value against reference value"""
233-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
232+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
234233
entity = Entity.from_mat(ENT_TEST_MAT)
235234
entity.measures._data['TC'] = entity.measures._data.pop('XX')
236235
for meas in entity.measures.get_measure('TC'):
@@ -267,7 +266,7 @@ def test_calc_cb_no_change_pass(self):
267266

268267
def test_calc_cb_change_pass(self):
269268
"""Test _calc_cost_benefit with present value against reference value"""
270-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
269+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
271270
entity = Entity.from_mat(ENT_TEST_MAT)
272271
entity.measures._data['TC'] = entity.measures._data.pop('XX')
273272
for meas in entity.measures.get_measure('TC'):
@@ -438,7 +437,7 @@ def test_norm_value(self):
438437

439438
def test_combine_fut_pass(self):
440439
"""Test combine_measures with present and future"""
441-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
440+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
442441
entity = Entity.from_excel(ENT_DEMO_TODAY)
443442
entity.check()
444443
entity.exposures.ref_year = 2018
@@ -498,7 +497,7 @@ def test_combine_fut_pass(self):
498497

499498
def test_combine_current_pass(self):
500499
"""Test combine_measures with only future"""
501-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
500+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
502501
entity = Entity.from_excel(ENT_DEMO_TODAY)
503502
entity.check()
504503
entity.exposures.ref_year = 2018
@@ -538,7 +537,7 @@ def test_combine_current_pass(self):
538537

539538
def test_apply_transf_current_pass(self):
540539
"""Test apply_risk_transfer with only future"""
541-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
540+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
542541
entity = Entity.from_excel(ENT_DEMO_TODAY)
543542
entity.check()
544543
entity.exposures.ref_year = 2018
@@ -588,7 +587,7 @@ def test_apply_transf_current_pass(self):
588587

589588
def test_apply_transf_cost_fact_pass(self):
590589
"""Test apply_risk_transfer with only future annd cost factor"""
591-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
590+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
592591
entity = Entity.from_excel(ENT_DEMO_TODAY)
593592
entity.check()
594593
entity.exposures.ref_year = 2018
@@ -636,7 +635,7 @@ def test_apply_transf_cost_fact_pass(self):
636635

637636
def test_apply_transf_future_pass(self):
638637
"""Test apply_risk_transfer with present and future"""
639-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
638+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
640639
entity = Entity.from_excel(ENT_DEMO_TODAY)
641640
entity.check()
642641
entity.exposures.ref_year = 2018
@@ -692,7 +691,7 @@ def test_apply_transf_future_pass(self):
692691

693692
def test_remove_measure(self):
694693
"""Test remove_measure method"""
695-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
694+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
696695
entity = Entity.from_excel(ENT_DEMO_TODAY)
697696
entity.check()
698697
entity.exposures.ref_year = 2018
@@ -720,7 +719,7 @@ class TestCalc(unittest.TestCase):
720719
def test_calc_change_pass(self):
721720
"""Test calc with future change"""
722721
# present
723-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
722+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
724723
entity = Entity.from_excel(ENT_DEMO_TODAY)
725724
entity.exposures.gdf.rename(columns={'impf_': 'impf_TC'}, inplace=True)
726725
entity.check()
@@ -777,7 +776,7 @@ def test_calc_change_pass(self):
777776

778777
def test_calc_no_change_pass(self):
779778
"""Test calc without future change"""
780-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
779+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
781780
entity = Entity.from_excel(ENT_DEMO_TODAY)
782781
entity.check()
783782
entity.exposures.ref_year = 2018
@@ -808,7 +807,7 @@ class TestRiskFuncs(unittest.TestCase):
808807
def test_impact(self):
809808
ent = Entity.from_excel(ENT_DEMO_TODAY)
810809
ent.check()
811-
hazard = Hazard.from_mat(HAZ_TEST_MAT)
810+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
812811
impact = ImpactCalc(ent.exposures, ent.impact_funcs, hazard).impact()
813812
return impact
814813

climada/engine/test/test_forecast.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,12 @@ def test_Forecast_plot(self):
110110
HAZ_DIR.joinpath('storm_europe_cosmoe_forecast_vmax_testfile.nc'),
111111
run_datetime=dt.datetime(2018,1,1),
112112
event_date=dt.datetime(2018,1,3))
113-
haz1.centroids.lat += 0.6
114-
haz1.centroids.lon -= 1.2
113+
haz1.centroids.gdf.geometry = haz1.centroids.gdf.geometry.translate(-1.2, 0.6)
115114
haz2 = StormEurope.from_cosmoe_file(
116115
HAZ_DIR.joinpath('storm_europe_cosmoe_forecast_vmax_testfile.nc'),
117116
run_datetime=dt.datetime(2018,1,1),
118117
event_date=dt.datetime(2018,1,3))
119-
haz2.centroids.lat += 0.6
120-
haz2.centroids.lon -= 1.2
118+
haz2.centroids.gdf.geometry = haz2.centroids.gdf.geometry.translate(-1.2, 0.6)
121119
#exposure
122120
data = {}
123121
data['latitude'] = haz1.centroids.lat

0 commit comments

Comments
 (0)