Skip to content

Commit 8c2f69d

Browse files
Merge branch 'develop' into feature/geo_pandas_upgrade
2 parents affd2f3 + 5d0a1d7 commit 8c2f69d

File tree

16 files changed

+150
-192
lines changed

16 files changed

+150
-192
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Code freeze date: YYYY-MM-DD
1313
Removed:
1414

1515
- `pandas-datareader`
16+
- `intensity_thres` of `Hazard`, `StormEurope`, and `TropCyclones` object [#1065](https://github.com/CLIMADA-project/climada_python/pull/1065)
17+
- Deprecated method `climada.hazard.trop_cyclone.trop_cyclone.TropCyclone.set_from_tracks` [#1065](https://github.com/CLIMADA-project/climada_python/pull/1065)
1618

1719
### Added
1820
- Added optional parameter to `geo_im_from_array`, `plot_from_gdf`, `plot_rp_imp`, `plot_rp_intensity`,
@@ -22,7 +24,8 @@ Removed:
2224
- `ImpactFunc` and `ImpactFuncSet` now support equality comparisons via `==` [#1027](https://github.com/CLIMADA-project/climada_python/pull/1027)
2325

2426
### Changed
25-
27+
- Changed the default mask_distance in `util.plot.geo_im_from_array` to 0.03 to avoid white gaps in gridded hazard data with comparably low resolution (>80 centroids per axis) [#1073](https://github.com/CLIMADA-project/climada_python/pull/1073)
28+
- Increased speed of `util.plot.add_shapes` by avoiding for loops, substantially speeding up `Hazard.plot_intensity` and other functions. [#1073](https://github.com/CLIMADA-project/climada_python/pull/1073)
2629
- `Hazard.local_exceedance_intensity`, `Hazard.local_return_period` and `Impact.local_exceedance_impact`, `Impact.local_return_period`, using the `climada.util.interpolation` module: New default (no binning), binning on decimals, and faster implementation [#1012](https://github.com/CLIMADA-project/climada_python/pull/1012)
2730
- World Bank indicator data is now downloaded directly from their API via the function `download_world_bank_indicator`, instead of relying on the `pandas-datareader` package [#1033](https://github.com/CLIMADA-project/climada_python/pull/1033)
2831
- `Exposures.write_hdf5` pickles geometry data in WKB format, which is faster and more sustainable. [#1051](https://github.com/CLIMADA-project/climada_python/pull/1051)

climada/engine/cost_benefit.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,9 +1079,7 @@ def _calc_impact_measures(
10791079
# compute impact for each measure
10801080
for measure in meas_set.get_measure(hazard.haz_type):
10811081
LOGGER.debug("%s impact of measure %s.", when, measure.name)
1082-
imp_tmp, risk_transf = measure.calc_impact(
1083-
exposures, imp_fun_set, hazard, assign_centroids=False
1084-
)
1082+
imp_tmp, risk_transf = measure.calc_impact(exposures, imp_fun_set, hazard)
10851083
impact_meas[measure.name] = dict()
10861084
impact_meas[measure.name]["cost"] = (
10871085
measure.cost,

climada/engine/impact.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,7 +1178,7 @@ def plot_rp_imp(
11781178
return_periods=(25, 50, 100, 250),
11791179
log10_scale=True,
11801180
axis=None,
1181-
mask_distance=0.01,
1181+
mask_distance=0.03,
11821182
kwargs_local_exceedance_impact=None,
11831183
**kwargs,
11841184
):
@@ -1198,8 +1198,8 @@ def plot_rp_imp(
11981198
mask_distance: float, optional
11991199
Only regions are plotted that are closer to any of the data points than this distance,
12001200
relative to overall plot size. For instance, to only plot values
1201-
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
1202-
Default is 0.01.
1201+
at the centroids, use mask_distance=0.03. If None, the plot is not masked.
1202+
Default is 0.03.
12031203
kwargs_local_exceedance_impact: dict
12041204
Dictionary of keyword arguments for the method impact.local_exceedance_impact.
12051205
kwargs : dict, optional

climada/engine/test/test_cost_benefit.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
)
3636
from climada.entity.disc_rates import DiscRates
3737
from climada.entity.entity_def import Entity
38+
from climada.entity.measures import Measure
39+
from climada.entity.measures.base import LOGGER as ILOG
3840
from climada.hazard.base import Hazard
3941
from climada.test import get_test_file
4042
from climada.util.api_client import Client
@@ -1119,6 +1121,66 @@ def test_remove_measure(self):
11191121
self.assertEqual(len(cost_ben.cost_ben_ratio), 3)
11201122
self.assertEqual(len(cost_ben.benefit), 3)
11211123

1124+
def test_measure_exposure_no_centroids(self):
1125+
"""Test centroids assigned if no centroids were assigned in Measure Exposures object"""
1126+
hazard = Hazard.from_hdf5(HAZ_TEST_TC)
1127+
entity = Entity.from_excel(ENT_DEMO_TODAY)
1128+
entity.check()
1129+
entity.exposures.ref_year = 2018
1130+
1131+
# test that warning is not raised when centroid are assigned
1132+
try:
1133+
with self.assertLogs(ILOG, level="WARNING") as logs:
1134+
cost_ben = CostBenefit()
1135+
cost_ben.calc(
1136+
hazard,
1137+
entity,
1138+
future_year=2040,
1139+
risk_func=risk_aai_agg,
1140+
imp_time_depen=None,
1141+
save_imp=True,
1142+
)
1143+
for log in logs.output:
1144+
self.assertNotIn(
1145+
"No assigned hazard centroids in exposure object after",
1146+
log,
1147+
"Centroids are already assinged in Measure Exposure object"
1148+
"and should not be reassigned.",
1149+
)
1150+
except AssertionError as e:
1151+
if "no logs" in str(e).lower():
1152+
pass
1153+
else:
1154+
raise
1155+
1156+
# add measure with exposure without assigned centroids
1157+
exp_no_assigned_centroids = entity.exposures.copy()
1158+
exp_no_assigned_centroids.data = entity.exposures.data.drop(
1159+
columns=["centr_TC"]
1160+
)
1161+
entity.measures.append(
1162+
Measure(
1163+
name="no centroids",
1164+
haz_type="TC",
1165+
exposures_set=exp_no_assigned_centroids,
1166+
)
1167+
)
1168+
1169+
# test if warning is raised
1170+
with self.assertLogs(ILOG, level="WARNING") as logs:
1171+
cost_ben = CostBenefit()
1172+
cost_ben.calc(
1173+
hazard,
1174+
entity,
1175+
future_year=2040,
1176+
risk_func=risk_aai_agg,
1177+
imp_time_depen=None,
1178+
save_imp=True,
1179+
)
1180+
self.assertIn(
1181+
"No assigned hazard centroids in exposure object after", logs.output[0]
1182+
)
1183+
11221184

11231185
class TestCalc(unittest.TestCase):
11241186
"""Test calc"""

climada/entity/measures/base.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def check(self):
179179
u_check.size(2, self.mdd_impact, "Measure.mdd_impact")
180180
u_check.size(2, self.paa_impact, "Measure.paa_impact")
181181

182-
def calc_impact(self, exposures, imp_fun_set, hazard, assign_centroids=True):
182+
def calc_impact(self, exposures, imp_fun_set, hazard):
183183
"""
184184
Apply measure and compute impact and risk transfer of measure
185185
implemented over inputs.
@@ -192,12 +192,6 @@ def calc_impact(self, exposures, imp_fun_set, hazard, assign_centroids=True):
192192
impact function set instance
193193
hazard : climada.hazard.Hazard
194194
hazard instance
195-
assign_centroids : bool, optional
196-
indicates whether centroids are assigned to the self.exposures object.
197-
Centroids assignment is an expensive operation; set this to ``False`` to save
198-
computation time if the hazards' centroids are already assigned to the exposures
199-
object.
200-
Default: True
201195
202196
Returns
203197
-------
@@ -206,7 +200,17 @@ def calc_impact(self, exposures, imp_fun_set, hazard, assign_centroids=True):
206200
"""
207201

208202
new_exp, new_impfs, new_haz = self.apply(exposures, imp_fun_set, hazard)
209-
return self._calc_impact(new_exp, new_impfs, new_haz, assign_centroids)
203+
# assign centroids if missing
204+
if new_haz.centr_exp_col not in new_exp.gdf.columns:
205+
LOGGER.warning(
206+
"No assigned hazard centroids in exposure object after the "
207+
"application of the measure. The centroids will be assigned during impact "
208+
"calculation. This is potentiall costly. To silence this warning, make sure "
209+
"that centroids are assigned to all exposures."
210+
)
211+
new_exp.assign_centroids(new_haz)
212+
213+
return self._calc_impact(new_exp, new_impfs, new_haz)
210214

211215
def apply(self, exposures, imp_fun_set, hazard):
212216
"""
@@ -246,7 +250,7 @@ def apply(self, exposures, imp_fun_set, hazard):
246250

247251
return new_exp, new_impfs, new_haz
248252

249-
def _calc_impact(self, new_exp, new_impfs, new_haz, assign_centroids):
253+
def _calc_impact(self, new_exp, new_impfs, new_haz):
250254
"""Compute impact and risk transfer of measure implemented over inputs.
251255
252256
Parameters
@@ -267,7 +271,7 @@ def _calc_impact(self, new_exp, new_impfs, new_haz, assign_centroids):
267271
)
268272

269273
imp = ImpactCalc(new_exp, new_impfs, new_haz).impact(
270-
save_mat=False, assign_centroids=assign_centroids
274+
save_mat=False, assign_centroids=False
271275
)
272276
return imp.calc_risk_transfer(self.risk_transf_attach, self.risk_transf_cover)
273277

climada/hazard/base.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,6 @@ class Hazard(HazardIO, HazardPlot):
101101
(i.e., is equivalent to fraction is 1 everywhere).
102102
"""
103103

104-
intensity_thres = 10
105-
"""Intensity threshold per hazard used to filter lower intensities. To be
106-
set for every hazard type"""
107-
108104
vars_oblig = {
109105
"units",
110106
"centroids",
@@ -485,7 +481,7 @@ def local_exceedance_intensity(
485481
self,
486482
return_periods=(25, 50, 100, 250),
487483
method="interpolate",
488-
min_intensity=None,
484+
min_intensity=0,
489485
log_frequency=True,
490486
log_intensity=True,
491487
bin_decimals=None,
@@ -512,8 +508,7 @@ def local_exceedance_intensity(
512508
periods and extends the interpolation between these points to the given return period
513509
(similar for small return periods). Defauls to "interpolate".
514510
min_intensity : float, optional
515-
Minimum threshold to filter the hazard intensity. If set to None, self.intensity_thres
516-
will be used. Defaults to None.
511+
Minimum threshold to filter the hazard intensity. Defaults to 0.
517512
log_frequency : bool, optional
518513
If set to True, (cummulative) frequency values are converted to log scale before
519514
inter- and extrapolation. Defaults to True.
@@ -554,8 +549,6 @@ def local_exceedance_intensity(
554549
intensities range from 1e6 to 1e9, you could use bin_decimals=-5, if your intensities
555550
range from 0.0001 to .01, you could use bin_decimals=5.
556551
"""
557-
if not min_intensity and min_intensity != 0:
558-
min_intensity = self.intensity_thres
559552
# check frequency unit
560553
return_period_unit = u_dt.convert_frequency_unit_to_time_unit(
561554
self.frequency_unit
@@ -639,7 +632,7 @@ def local_return_period(
639632
self,
640633
threshold_intensities=(10.0, 20.0),
641634
method="interpolate",
642-
min_intensity=None,
635+
min_intensity=0,
643636
log_frequency=True,
644637
log_intensity=True,
645638
bin_decimals=None,
@@ -667,8 +660,7 @@ def local_return_period(
667660
points to the given threshold intensity (similar for small threshold intensites).
668661
Defaults to "interpolate".
669662
min_intensity : float, optional
670-
Minimum threshold to filter the hazard intensity. If set to None, self.intensity_thres
671-
will be used. Defaults to None.
663+
Minimum threshold to filter the hazard intensity. Defaults to 0.
672664
log_frequency : bool, optional
673665
If set to True, (cummulative) frequency values are converted to log scale before
674666
inter- and extrapolation. Defaults to True.
@@ -710,8 +702,6 @@ def local_return_period(
710702
intensities range from 1e6 to 1e9, you could use bin_decimals=-5, if your intensities
711703
range from 0.0001 to .01, you could use bin_decimals=5.
712704
"""
713-
if not min_intensity and min_intensity != 0:
714-
min_intensity = self.intensity_thres
715705
# check frequency unit
716706
return_period_unit = u_dt.convert_frequency_unit_to_time_unit(
717707
self.frequency_unit

climada/hazard/plot.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def plot_rp_intensity(
4040
self,
4141
return_periods=(25, 50, 100, 250),
4242
axis=None,
43-
mask_distance=0.01,
43+
mask_distance=0.03,
4444
kwargs_local_exceedance_intensity=None,
4545
**kwargs,
4646
):
@@ -60,8 +60,8 @@ def plot_rp_intensity(
6060
mask_distance: float, optional
6161
Only regions are plotted that are closer to any of the data points than this distance,
6262
relative to overall plot size. For instance, to only plot values
63-
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
64-
Default is 0.01.
63+
at the centroids, use mask_distance=0.03. If None, the plot is not masked.
64+
Default is 0.03.
6565
kwargs: optional
6666
arguments for pcolormesh matplotlib function used in event plots
6767
@@ -111,7 +111,7 @@ def plot_intensity(
111111
smooth=True,
112112
axis=None,
113113
adapt_fontsize=True,
114-
mask_distance=0.01,
114+
mask_distance=0.03,
115115
**kwargs,
116116
):
117117
"""Plot intensity values for a selected event or centroid.
@@ -138,8 +138,8 @@ def plot_intensity(
138138
mask_distance: float, optional
139139
Only regions are plotted that are closer to any of the data points than this distance,
140140
relative to overall plot size. For instance, to only plot values
141-
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
142-
Default is 0.01.
141+
at the centroids, use mask_distance=0.03. If None, the plot is not masked.
142+
Default is 0.03.
143143
kwargs: optional
144144
arguments for pcolormesh matplotlib function
145145
used in event plots or for plot function used in centroids plots
@@ -181,7 +181,7 @@ def plot_fraction(
181181
centr=None,
182182
smooth=True,
183183
axis=None,
184-
mask_distance=0.01,
184+
mask_distance=0.03,
185185
**kwargs,
186186
):
187187
"""Plot fraction values for a selected event or centroid.
@@ -208,8 +208,8 @@ def plot_fraction(
208208
mask_distance: float, optional
209209
Relative distance (with respect to maximal map extent in longitude or latitude) to data
210210
points above which plot should not display values. For instance, to only plot values
211-
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
212-
Default is None.
211+
at the centroids, use mask_distance=0.03. If None, the plot is not masked.
212+
Default is 0.03.
213213
kwargs: optional
214214
arguments for pcolormesh matplotlib function
215215
used in event plots or for plot function used in centroids plots
@@ -252,7 +252,7 @@ def _event_plot(
252252
axis=None,
253253
figsize=(9, 13),
254254
adapt_fontsize=True,
255-
mask_distance=0.01,
255+
mask_distance=0.03,
256256
**kwargs,
257257
):
258258
"""Plot an event of the input matrix.
@@ -277,8 +277,8 @@ def _event_plot(
277277
mask_distance: float, optional
278278
Only regions are plotted that are closer to any of the data points than this distance,
279279
relative to overall plot size. For instance, to only plot values
280-
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
281-
Default is None.
280+
at the centroids, use mask_distance=0.03. If None, the plot is not masked.
281+
Default is 0.03.
282282
kwargs: optional
283283
arguments for pcolormesh matplotlib function
284284

0 commit comments

Comments
 (0)