Skip to content

Commit 537630b

Browse files
committed
add risk functions for 100 and 250 return periods
1 parent 4f5aa2c commit 537630b

File tree

2 files changed

+87
-14
lines changed

2 files changed

+87
-14
lines changed

climada/engine/cost_benefit.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
Define CostBenefit class.
2020
"""
2121

22-
__all__ = ['CostBenefit', 'risk_aai_agg']
22+
__all__ = ['CostBenefit', 'risk_aai_agg', 'risk_rp_100', 'risk_rp_250']
2323

2424
import logging
2525
import numpy as np
@@ -52,6 +52,30 @@ def risk_aai_agg(impact):
5252
"""
5353
return impact.aai_agg
5454

55+
def risk_rp_100(impact):
56+
"""Risk measurement as exceedance impact at 100 years return period.
57+
58+
Parameters:
59+
impact (Impact): an Impact instance
60+
61+
Returns:
62+
float
63+
"""
64+
efc = impact.calc_freq_curve([100])
65+
return efc.impact[0]
66+
67+
def risk_rp_250(impact):
68+
"""Risk measurement as exceedance impact at 250 years return period.
69+
70+
Parameters:
71+
impact (Impact): an Impact instance
72+
73+
Returns:
74+
float
75+
"""
76+
efc = impact.calc_freq_curve([250])
77+
return efc.impact[0]
78+
5579
class CostBenefit():
5680
"""Impact definition. Compute from an entity (exposures and impact
5781
functions) and hazard.
@@ -140,7 +164,7 @@ def calc(self, hazard, entity, haz_future=None, ent_future=None, \
140164
self.unit = entity.exposures.value_unit
141165

142166
# save measure colors
143-
for meas in entity.measures.get_measure():
167+
for meas in entity.measures.get_measure(hazard.tag.haz_type):
144168
self.color_rgb[meas.name] = meas.color_rgb
145169

146170
if not haz_future and not ent_future:
@@ -295,6 +319,8 @@ def plot_waterfall(self, hazard, entity, haz_future, ent_future,
295319
time_dep = self._time_dependency_array()
296320
risk_curr = self._npv_unaverted_impact(risk_future, entity.disc_rates,
297321
time_dep)
322+
LOGGER.info('Risk function at {:d}: {:.3e}'.format(self.present_year,
323+
risk_future))
298324

299325
# changing future
300326
time_dep = self._time_dependency_array(imp_time_depen)
@@ -308,6 +334,8 @@ def plot_waterfall(self, hazard, entity, haz_future, ent_future,
308334
risk_future = fut_risk
309335
risk_tot = self._npv_unaverted_impact(risk_future, entity.disc_rates,
310336
time_dep, curr_risk)
337+
LOGGER.info('Risk function at {:d}: {:.3e}'.format(self.future_year,
338+
risk_future))
311339

312340
axis.bar(1, risk_curr/norm_fact)
313341
axis.text(1, risk_curr/norm_fact, str(int(round(risk_curr/norm_fact))), \
@@ -328,6 +356,8 @@ def plot_waterfall(self, hazard, entity, haz_future, ent_future,
328356
plt.xticks(np.arange(4)+1, ['Risk ' + str(self.present_year), \
329357
'Economic \ndevelopment', 'Climate \nchange', 'Risk ' + str(self.future_year)])
330358
axis.set_ylabel('Impact (' + self.unit + ' ' + norm_name + ')')
359+
axis.set_title('Total accumulated damage from {:d} to {:d}'.format(
360+
self.present_year, self.future_year))
331361

332362
return fig, axis
333363

@@ -362,7 +392,7 @@ def _calc_impact_measures(self, hazard, exposures, meas_set, imp_fun_set, \
362392
impact_meas['no measure']['impact'] = imp_tmp
363393

364394
# compute impact for each measure
365-
for measure in meas_set.get_measure():
395+
for measure in meas_set.get_measure(hazard.tag.haz_type):
366396
imp_tmp, risk_transf = measure.calc_impact(exposures, imp_fun_set, hazard)
367397
impact_meas[measure.name] = dict()
368398
impact_meas[measure.name]['cost'] = measure.cost
@@ -443,6 +473,9 @@ def _time_dependency_array(self, imp_time_depen=None):
443473
Parameters:
444474
imp_time_depen (float, optional): parameter which represent time
445475
evolution of impact. Time array is all ones if not provided
476+
477+
Returns:
478+
np.array
446479
"""
447480
n_years = self.future_year - self.present_year + 1
448481
if imp_time_depen:

climada/engine/test/test_cost_benefit.py

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
from climada.entity.entity_def import Entity
2727
from climada.entity.disc_rates import DiscRates
2828
from climada.hazard.base import Hazard
29-
from climada.engine.cost_benefit import CostBenefit, risk_aai_agg, DEF_RP
29+
from climada.engine.cost_benefit import CostBenefit, risk_aai_agg, DEF_RP, \
30+
risk_rp_100, risk_rp_250
31+
from climada.engine import Impact
3032
from climada.util.constants import ENT_DEMO_FUTURE, ENT_DEMO_TODAY
3133

3234
HAZ_DATA_DIR = os.path.join(os.path.dirname(__file__), '../../hazard/test/data')
@@ -45,10 +47,11 @@ def test_calc_impact_measures_pass(self):
4547
hazard.read_mat(HAZ_TEST_MAT)
4648
entity = Entity()
4749
entity.read_mat(ENT_TEST_MAT)
48-
entity.exposures.rename(columns={'if_': 'if_TC'}, inplace=True)
4950
entity.check()
50-
for meas in entity.measures.get_measure():
51+
entity.measures._data['TC'] = entity.measures._data.pop('XX')
52+
for meas in entity.measures.get_measure('TC'):
5153
meas.haz_type = 'TC'
54+
entity.check()
5255

5356
cost_ben = CostBenefit()
5457
cost_ben._calc_impact_measures(hazard, entity.exposures, entity.measures,
@@ -112,10 +115,10 @@ def test_calc_cb_no_change_pass(self):
112115
hazard.read_mat(HAZ_TEST_MAT)
113116
entity = Entity()
114117
entity.read_mat(ENT_TEST_MAT)
115-
entity.exposures.rename(columns={'if_': 'if_TC'}, inplace=True)
116-
entity.check()
117-
for meas in entity.measures.get_measure():
118+
entity.measures._data['TC'] = entity.measures._data.pop('XX')
119+
for meas in entity.measures.get_measure('TC'):
118120
meas.haz_type = 'TC'
121+
entity.check()
119122

120123
cost_ben = CostBenefit()
121124
cost_ben._calc_impact_measures(hazard, entity.exposures, entity.measures,
@@ -148,10 +151,10 @@ def test_calc_cb_change_pass(self):
148151
hazard.read_mat(HAZ_TEST_MAT)
149152
entity = Entity()
150153
entity.read_mat(ENT_TEST_MAT)
151-
entity.exposures.rename(columns={'if_': 'if_TC'}, inplace=True)
152-
entity.check()
153-
for meas in entity.measures.get_measure():
154+
entity.measures._data['TC'] = entity.measures._data.pop('XX')
155+
for meas in entity.measures.get_measure('TC'):
154156
meas.haz_type = 'TC'
157+
entity.check()
155158

156159
cost_ben = CostBenefit()
157160
cost_ben._calc_impact_measures(hazard, entity.exposures, entity.measures,
@@ -160,8 +163,6 @@ def test_calc_cb_change_pass(self):
160163
ent_future = Entity()
161164
ent_future.read_excel(ENT_DEMO_FUTURE)
162165
ent_future.check()
163-
for meas in ent_future.measures.get_measure():
164-
meas.haz_type = 'TC'
165166

166167
haz_future = copy.deepcopy(hazard)
167168
haz_future.intensity.data += 25
@@ -369,7 +370,46 @@ def test_calc_no_change_pass(self):
369370

370371
self.assertEqual(cost_ben.tot_climate_risk, 1.2150496306913972e+11)
371372

373+
class TestRiskFuncs(unittest.TestCase):
374+
'''Test risk functions definitions'''
375+
376+
def test_impact():
377+
ent = Entity()
378+
ent.read_excel(ENT_DEMO_TODAY)
379+
ent.check()
380+
hazard = Hazard('TC')
381+
hazard.read_mat(HAZ_TEST_MAT)
382+
impact = Impact()
383+
ent.exposures.assign_centroids(hazard)
384+
impact.calc(ent.exposures, ent.impact_funcs, hazard)
385+
return impact
386+
387+
def test_risk_aai_agg_pass(self):
388+
"""Test risk_aai_agg"""
389+
impact = self.test_impact()
390+
risk = risk_aai_agg(impact)
391+
self.assertAlmostEqual(6.512201157564421e+09, risk, 5)
392+
self.assertTrue(np.isclose(6.512201157564421e+09, risk))
393+
394+
def test_risk_rp_100_pass(self):
395+
"""Test risk_rp_100"""
396+
impact = self.test_impact()
397+
exc_freq = impact.calc_freq_curve([100])
398+
399+
risk = risk_rp_100(impact)
400+
self.assertAlmostEqual(exc_freq.impact[0], risk)
401+
402+
def test_risk_rp_200_pass(self):
403+
"""Test risk_rp_200"""
404+
impact = self.test_impact()
405+
exc_freq = impact.calc_freq_curve([250])
406+
407+
risk = risk_rp_250(impact)
408+
self.assertAlmostEqual(exc_freq.impact[0], risk)
409+
372410
# Execute Tests
411+
TESTS = unittest.TestLoader().loadTestsFromTestCase(TestRiskFuncs)
373412
TESTS = unittest.TestLoader().loadTestsFromTestCase(TestCalc)
374413
TESTS.addTests(unittest.TestLoader().loadTestsFromTestCase(TestSteps))
414+
TESTS.addTests(unittest.TestLoader().loadTestsFromTestCase(TestRiskFuncs))
375415
unittest.TextTestRunner(verbosity=2).run(TESTS)

0 commit comments

Comments
 (0)