Adaptation Measures

Adaptation measures are defined by parameters that alter the exposures, hazard or impact functions. Risk transfer options are also considered. Single measures are defined in the Measure class, which can be aggregated to a MeasureSet.

Measure class

A measure is characterized by the following attributes:

Related to measure’s description: * name (str): name of the action * haz_type (str): related hazard type (peril), e.g. TC * color_rgb (np.array): integer array of size 3. Gives color code of this measure in RGB * cost (float): discounted cost (in same units as assets). Needs to be provided by the user. See the example provided in climada_python/data/system/entity_template.xlsx sheets _measures_details and _discounting_sheet to see how the discounting is done.

Related to a measure’s impact: * hazard_set (str): file name of hazard to use * hazard_freq_cutoff (float): hazard frequency cutoff * exposure_set (str): file name of exposure to use * hazard_inten_imp (tuple): parameter a and b of hazard intensity change * mdd_impact (tuple): parameter a and b of the impact over the mean damage degree * paa_impact (tuple): parameter a and b of the impact over the percentage of affected assets * imp_fun_map (str): change of impact function id, e.g. ‘1to3’ * exp_region_id (int): region id of the selected exposures to consider ALL the previous parameters * risk_transf_attach (float): risk transfer attachment. Applies to the whole exposure. * risk_transf_cover (float): risk transfer cover. Applies to the whole exposure.

Paramters description:

hazard_set and exposures_set provide the file names in h5 format (generated by CLIMADA) of the hazard and exposures to use as a result of the implementation of the measure. These might be further modified when applying the other parameters.

hazard_inten_imp, mdd_impact and paa_impact transform the impact functions linearly as follows:

intensity = intensity*hazard_inten_imp[0] + hazard_inten_imp[1]
mdd = mdd*mdd_impact[0] + mdd_impact[1]
paa = paa*paa_impact[0] + paa_impact[1]

hazard_freq_cutoff modifies the hazard by putting 0 intensities to the events whose impact exceedance frequency are greater than hazard_freq_cutoff.

imp_fun_map indicates the ids of the impact function to replace and its replacement. The if_XX variable of Exposures with the affected impact function id will be correspondingly modified (XX refers to the haz_type of the measure).

exp_region_id will apply all the previous changes only to the region_id indicated. This means that only the exposures with that region_id and the hazard’s centroids close to them will be modified with the previous changes, the other regions will remain unaffected to the measure.

risk_transf_attach and risk_transf_cover are the deductible and coverage of any event to happen.

Methods description:

The method check() validates the attibutes. apply() applies the measure to a given exposure, impact function and hazard, returning their modified values. The parameters related to insurability (risk_transf_attach and risk_transf_cover) affect the resulting impact and are therefore not applied in the apply() method yet.

calc_impact() calls to apply(), applies the insurance parameters and returns the final impact and risk transfer of the measure. This method is called from the CostBenefit class.

The method apply() allows to visualize the effect of a measure. Here are some examples:

[5]:
# effect of mdd_impact, paa_impact, hazard_inten_imp
%matplotlib inline
import numpy as np
from climada.entity import ImpactFuncSet, IFTropCyclone, Exposures
from climada.entity.measures import Measure
from climada.hazard import Hazard

# define measure
meas = Measure()
meas.name = 'Mangrove'
meas.haz_type = 'TC'
meas.color_rgb = np.array([1, 1, 1])
meas.cost = 500000000
meas.mdd_impact = (1, 0)
meas.paa_impact = (1, -0.15)
meas.hazard_inten_imp = (1, -10) # reduces intensity by 10

# impact functions
if_tc = IFTropCyclone()
if_tc.set_emanuel_usa()
if_all = ImpactFuncSet()
if_all.append(if_tc)
if_all.plot()

# dummy Hazard and Exposures
haz = Hazard('TC') # this measure does not change hazard
exp = Exposures() # this measure does not change exposures

# new impact functions
new_exp, new_ifs, new_haz = meas.apply(exp, if_all, haz)
axes = new_ifs.plot()
axes.set_title('TC: Modified impact function')
2021-03-05 13:21:37,745 - climada.entity.exposures.base - INFO - meta set to default value {}
2021-03-05 13:21:37,746 - climada.entity.exposures.base - INFO - tag set to default value  File:
 Description:
2021-03-05 13:21:37,748 - climada.entity.exposures.base - INFO - ref_year set to default value 2018
2021-03-05 13:21:37,748 - climada.entity.exposures.base - INFO - value_unit set to default value USD
2021-03-05 13:21:37,750 - climada.entity.exposures.base - INFO - crs set to default value: EPSG:4326
[5]:
Text(0.5, 1.0, 'TC: Modified impact function')
../_images/tutorial_climada_entity_MeasureSet_4_2.png
../_images/tutorial_climada_entity_MeasureSet_4_3.png
[6]:
# effect of hazard_freq_cutoff
import numpy as np
from climada.entity import ImpactFuncSet, IFTropCyclone, Exposures
from climada.entity.measures import Measure
from climada.hazard import Hazard
from climada.engine import Impact

from climada.util import HAZ_DEMO_H5, EXP_DEMO_H5

# define measure
meas = Measure()
meas.name = 'Mangrove'
meas.haz_type = 'TC'
meas.color_rgb = np.array([1, 1, 1])
meas.cost = 500000000
meas.hazard_freq_cutoff = 0.0255

# impact functions
if_tc = IFTropCyclone()
if_tc.set_emanuel_usa()
if_all = ImpactFuncSet()
if_all.append(if_tc)

# Hazard
haz = Hazard('TC')
haz.read_hdf5(HAZ_DEMO_H5)
haz.check()

# Exposures
exp = Exposures()
exp.read_hdf5(EXP_DEMO_H5)
exp.check()

# new hazard
new_exp, new_ifs, new_haz = meas.apply(exp, if_all, haz)
# if you look at the maximum intensity per centroid: new_haz does not contain the event with smaller impact (the most frequent)
haz.plot_intensity(0)
new_haz.plot_intensity(0)
# you might also compute the exceedance frequency curve of both hazard
imp = Impact()
imp.calc(exp, if_all, haz)
ax = imp.calc_freq_curve().plot(label='original')

new_imp = Impact()
new_imp.calc(new_exp, new_ifs, new_haz)
new_imp.calc_freq_curve().plot(axis=ax, label='measure') # the damages for events with return periods > 1/0.0255 ~ 40 are 0
ax.legend()
2021-03-05 13:21:55,826 - climada.hazard.base - INFO - Reading /Users/ckropf/climada/demo/data/tc_fl_1990_2004.h5
2021-03-05 13:21:55,857 - climada.entity.exposures.base - INFO - meta set to default value {}
2021-03-05 13:21:55,857 - climada.entity.exposures.base - INFO - tag set to default value  File:
 Description:
2021-03-05 13:21:55,858 - climada.entity.exposures.base - INFO - ref_year set to default value 2018
2021-03-05 13:21:55,858 - climada.entity.exposures.base - INFO - value_unit set to default value USD
2021-03-05 13:21:55,859 - climada.entity.exposures.base - INFO - crs set to default value: EPSG:4326
2021-03-05 13:21:55,860 - climada.entity.exposures.base - INFO - Reading /Users/ckropf/climada/demo/data/exp_demo_today.h5
2021-03-05 13:21:55,934 - climada.entity.exposures.base - INFO - meta set to default value {}
2021-03-05 13:21:55,935 - climada.entity.exposures.base - INFO - tag set to default value  File:
 Description:
2021-03-05 13:21:55,935 - climada.entity.exposures.base - INFO - ref_year set to default value 2018
2021-03-05 13:21:55,935 - climada.entity.exposures.base - INFO - value_unit set to default value USD
2021-03-05 13:21:55,937 - climada.entity.exposures.base - INFO - crs set to default value: EPSG:4326
2021-03-05 13:21:55,939 - climada.entity.exposures.base - INFO - centr_ not set.
2021-03-05 13:21:55,941 - climada.entity.exposures.base - INFO - Matching 50 exposures with 2500 centroids.
2021-03-05 13:21:55,955 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 216 events.
/Users/ckropf/Documents/Climada/climada_python/climada/util/plot.py:326: UserWarning: Tight layout not applied. The left and right margins cannot be made large enough to accommodate all axes decorations.
  fig.tight_layout()
2021-03-05 13:21:56,883 - climada.engine.impact - INFO - Exposures matching centroids found in centr_TC
2021-03-05 13:21:56,884 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 216 events.
2021-03-05 13:21:56,897 - climada.engine.impact - INFO - Exposures matching centroids found in centr_TC
2021-03-05 13:21:56,898 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 216 events.
[6]:
<matplotlib.legend.Legend at 0x7fbd057e0bd0>
/Users/ckropf/opt/anaconda3/envs/climada_uncertainty/lib/python3.7/site-packages/cartopy/mpl/feature_artist.py:225: MatplotlibDeprecationWarning: Using a string of single character colors as a color sequence is deprecated. Use an explicit list instead.
  **dict(style))
../_images/tutorial_climada_entity_MeasureSet_5_5.png
../_images/tutorial_climada_entity_MeasureSet_5_6.png
../_images/tutorial_climada_entity_MeasureSet_5_7.png
[7]:
# effect of exp_region_id
import numpy as np
from climada.entity import ImpactFuncSet, IFTropCyclone, Exposures
from climada.entity.measures import Measure
from climada.hazard import Hazard
from climada.engine import Impact

from climada.util import HAZ_DEMO_H5, EXP_DEMO_H5

# define measure
meas = Measure()
meas.name = 'Building code'
meas.haz_type = 'TC'
meas.color_rgb = np.array([1, 1, 1])
meas.cost = 500000000
meas.hazard_freq_cutoff = 0.00455
meas.exp_region_id = [1] # apply measure to points close to exposures with region_id=1

# impact functions
if_tc = IFTropCyclone()
if_tc.set_emanuel_usa()
if_all = ImpactFuncSet()
if_all.append(if_tc)

# Hazard
haz = Hazard('TC')
haz.read_hdf5(HAZ_DEMO_H5)
haz.check()

# Exposures
exp = Exposures()
exp.read_hdf5(EXP_DEMO_H5)
#exp['region_id'] = np.ones(exp.shape[0])
exp.check()
# all exposures have region_id=1
exp.plot_hexbin(buffer=1.0)

# new hazard
new_exp, new_ifs, new_haz = meas.apply(exp, if_all, haz)
# the cutoff has been apllied only in the region of the exposures
haz.plot_intensity(0)
new_haz.plot_intensity(0)

# the exceddance frequency has only been computed for the selected exposures before doing the cutoff.
# since we have removed the hazard of the places with exposure, the new exceedance frequency curve is zero.
imp = Impact()
imp.calc(exp, if_all, haz)
imp.calc_freq_curve().plot()

new_imp = Impact()
new_imp.calc(new_exp, new_ifs, new_haz)
new_imp.calc_freq_curve().plot()
2021-03-05 13:22:11,124 - climada.hazard.base - INFO - Reading /Users/ckropf/climada/demo/data/tc_fl_1990_2004.h5
2021-03-05 13:22:11,147 - climada.entity.exposures.base - INFO - meta set to default value {}
2021-03-05 13:22:11,147 - climada.entity.exposures.base - INFO - tag set to default value  File:
 Description:
2021-03-05 13:22:11,148 - climada.entity.exposures.base - INFO - ref_year set to default value 2018
2021-03-05 13:22:11,148 - climada.entity.exposures.base - INFO - value_unit set to default value USD
2021-03-05 13:22:11,149 - climada.entity.exposures.base - INFO - crs set to default value: EPSG:4326
2021-03-05 13:22:11,150 - climada.entity.exposures.base - INFO - Reading /Users/ckropf/climada/demo/data/exp_demo_today.h5
2021-03-05 13:22:11,167 - climada.entity.exposures.base - INFO - meta set to default value {}
2021-03-05 13:22:11,167 - climada.entity.exposures.base - INFO - tag set to default value  File:
 Description:
2021-03-05 13:22:11,168 - climada.entity.exposures.base - INFO - ref_year set to default value 2018
2021-03-05 13:22:11,168 - climada.entity.exposures.base - INFO - value_unit set to default value USD
2021-03-05 13:22:11,169 - climada.entity.exposures.base - INFO - crs set to default value: EPSG:4326
2021-03-05 13:22:11,170 - climada.entity.exposures.base - INFO - centr_ not set.
/Users/ckropf/Documents/Climada/climada_python/climada/util/plot.py:326: UserWarning: Tight layout not applied. The left and right margins cannot be made large enough to accommodate all axes decorations.
  fig.tight_layout()
2021-03-05 13:22:11,657 - climada.entity.exposures.base - INFO - meta set to default value {}
2021-03-05 13:22:11,657 - climada.entity.exposures.base - INFO - tag set to default value  File:
 Description:
2021-03-05 13:22:11,658 - climada.entity.exposures.base - INFO - ref_year set to default value 2018
2021-03-05 13:22:11,659 - climada.entity.exposures.base - INFO - value_unit set to default value USD
2021-03-05 13:22:11,660 - climada.entity.exposures.base - INFO - Matching 50 exposures with 2500 centroids.
2021-03-05 13:22:11,667 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 216 events.
2021-03-05 13:22:11,679 - climada.entity.exposures.base - INFO - Matching 50 exposures with 2500 centroids.
/Users/ckropf/Documents/Climada/climada_python/climada/util/plot.py:326: UserWarning: Tight layout not applied. The left and right margins cannot be made large enough to accommodate all axes decorations.
  fig.tight_layout()
2021-03-05 13:22:12,607 - climada.engine.impact - INFO - Exposures matching centroids found in centr_TC
2021-03-05 13:22:12,609 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 216 events.
2021-03-05 13:22:12,623 - climada.entity.exposures.base - INFO - Matching 50 exposures with 2500 centroids.
2021-03-05 13:22:12,628 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 216 events.
[7]:
<matplotlib.axes._subplots.AxesSubplot at 0x7fbd06882d10>
/Users/ckropf/opt/anaconda3/envs/climada_uncertainty/lib/python3.7/site-packages/cartopy/mpl/feature_artist.py:225: MatplotlibDeprecationWarning: Using a string of single character colors as a color sequence is deprecated. Use an explicit list instead.
  **dict(style))
../_images/tutorial_climada_entity_MeasureSet_6_7.png
../_images/tutorial_climada_entity_MeasureSet_6_8.png
../_images/tutorial_climada_entity_MeasureSet_6_9.png
../_images/tutorial_climada_entity_MeasureSet_6_10.png
../_images/tutorial_climada_entity_MeasureSet_6_11.png
[8]:
# effect of risk_transf_attach and risk_transf_cover
import numpy as np
from climada.entity import ImpactFuncSet, IFTropCyclone, Exposures
from climada.entity.measures import Measure
from climada.hazard import Hazard
from climada.engine import Impact

from climada.util import HAZ_DEMO_H5, EXP_DEMO_H5

# define measure
meas = Measure()
meas.name = 'Insurance'
meas.haz_type = 'TC'
meas.color_rgb = np.array([1, 1, 1])
meas.cost = 500000000
meas.risk_transf_attach = 5.0e8
meas.risk_transf_cover = 1.0e9

# impact functions
if_tc = IFTropCyclone()
if_tc.set_emanuel_usa()
if_all = ImpactFuncSet()
if_all.append(if_tc)

# Hazard
haz = Hazard('TC')
haz.read_hdf5(HAZ_DEMO_H5)
haz.check()

# Exposures
exp = Exposures()
exp.read_hdf5(EXP_DEMO_H5)
exp.check()

# impact before
imp = Impact()
imp.calc(exp, if_all, haz)
imp.calc_freq_curve().plot()

# impact after. risk_transf will be added to the cost of the measure
imp_new, risk_transf = meas.calc_impact(exp, if_all, haz)
imp_new.calc_freq_curve().plot()
print('risk_transfer {:.3}'.format(risk_transf.aai_agg))
2021-03-05 13:22:25,141 - climada.hazard.base - INFO - Reading /Users/ckropf/climada/demo/data/tc_fl_1990_2004.h5
2021-03-05 13:22:25,165 - climada.entity.exposures.base - INFO - meta set to default value {}
2021-03-05 13:22:25,166 - climada.entity.exposures.base - INFO - tag set to default value  File:
 Description:
2021-03-05 13:22:25,167 - climada.entity.exposures.base - INFO - ref_year set to default value 2018
2021-03-05 13:22:25,167 - climada.entity.exposures.base - INFO - value_unit set to default value USD
2021-03-05 13:22:25,169 - climada.entity.exposures.base - INFO - crs set to default value: EPSG:4326
2021-03-05 13:22:25,169 - climada.entity.exposures.base - INFO - Reading /Users/ckropf/climada/demo/data/exp_demo_today.h5
2021-03-05 13:22:25,186 - climada.entity.exposures.base - INFO - meta set to default value {}
2021-03-05 13:22:25,187 - climada.entity.exposures.base - INFO - tag set to default value  File:
 Description:
2021-03-05 13:22:25,187 - climada.entity.exposures.base - INFO - ref_year set to default value 2018
2021-03-05 13:22:25,188 - climada.entity.exposures.base - INFO - value_unit set to default value USD
2021-03-05 13:22:25,190 - climada.entity.exposures.base - INFO - crs set to default value: EPSG:4326
2021-03-05 13:22:25,192 - climada.entity.exposures.base - INFO - centr_ not set.
2021-03-05 13:22:25,193 - climada.entity.exposures.base - INFO - Matching 50 exposures with 2500 centroids.
2021-03-05 13:22:25,200 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 216 events.
2021-03-05 13:22:25,220 - climada.engine.impact - INFO - Exposures matching centroids found in centr_TC
2021-03-05 13:22:25,221 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 216 events.
risk_transfer 2.7e+07
../_images/tutorial_climada_entity_MeasureSet_7_1.png
../_images/tutorial_climada_entity_MeasureSet_7_2.png

MeasureSet class

Similarly to the ImpactFuncSet, MeasureSet is a container which handles Measure instances through the methods append(), extend(), remove_measure()and get_measure(). Use the check() method to make sure all the measures have been propoerly set.

MeasureSet contains the attribute tag of type Tag, which stores information about the data: the original file name and a description.

[ ]:
from climada.entity import MeasureSet
help(MeasureSet)
[9]:
# build measures
import numpy as np
import matplotlib.pyplot as plt
from climada.entity.measures import Measure, MeasureSet

meas_1 = Measure()
meas_1.haz_type = 'TC'
meas_1.name = 'Mangrove'
meas_1.color_rgb = np.array([1, 1, 1])
meas_1.cost = 500000000
meas_1.mdd_impact = (1, 2)
meas_1.paa_impact = (1, 2)
meas_1.hazard_inten_imp = (1, 2)
meas_1.risk_transf_cover = 500

meas_2 = Measure()
meas_2.haz_type = 'TC'
meas_2.name = 'Sandbags'
meas_2.color_rgb = np.array([1, 1, 1])
meas_2.cost = 22000000
meas_2.mdd_impact = (1, 2)
meas_2.paa_impact = (1, 3)
meas_2.hazard_inten_imp = (1, 2)
meas_2.exp_region_id = 2

# gather all measures
meas_set = MeasureSet()
meas_set.append(meas_1)
meas_set.append(meas_2)
meas_set.check()

# select one measure
meas_sel = meas_set.get_measure(name='Sandbags')
print(meas_sel[0].name, meas_sel[0].cost)
Sandbags 22000000

Read measures of an Excel file

Measures defined in an excel file following the template provided in sheet measures of climada_python/data/system/entity_template.xlsx can be ingested directly using the method read_excel().

[10]:
from climada.entity.measures import MeasureSet
from climada.util import ENT_TEMPLATE_XLS

# Fill DataFrame from Excel file
file_name = ENT_TEMPLATE_XLS # provide absolute path of the excel file
meas_set = MeasureSet()
meas_set.read_excel(file_name)
print('Read file:', meas_set.tag.file_name)
Read file: /Users/ckropf/climada/data/entity_template.xlsx

Write measures

Measures can be writen in Excel format using write_excel() method.

[ ]:
from climada.entity.measures import MeasureSet
from climada.util import ENT_TEMPLATE_XLS

# Fill DataFrame from Excel file
file_name = ENT_TEMPLATE_XLS # provide absolute path of the excel file
meas_set = MeasureSet()
meas_set.read_excel(file_name)

# write file
meas_set.write_excel('results/tutorial_meas_set.xlsx')

Pickle can always be used as well:

[ ]:
from climada.util.save import save
# this generates a results folder in the current path and stores the output there
save('tutorial_meas_set.p', meas_set)