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:

[1]:
# effect of mdd_impact, paa_impact, hazard_inten_imp
%matplotlib inline
import numpy as np
from climada.entity import Measure, ImpactFuncSet, IFTropCyclone, Exposures
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)
fig, axes = new_ifs.plot()
axes[0].set_title('TC: Modified impact function')
2019-05-15 08:06:23,597 - climada - DEBUG - Loading default config file: /Users/aznarsig/Documents/Python/climada_python/climada/conf/defaults.conf
2019-05-15 08:06:26,031 - climada.entity.measures.base - DEBUG - Transforming impact functions.
[1]:
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
[2]:
# effect of hazard_freq_cutoff
import numpy as np
from climada.entity import Measure, ImpactFuncSet, IFTropCyclone, Exposures
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)
imp.calc_freq_curve().plot()

new_imp = Impact()
new_imp.calc(new_exp, new_ifs, new_haz)
new_imp.calc_freq_curve().plot() # the damages for events with return periods > 1/0.0255 ~ 40 are 0

2019-05-15 08:06:26,490 - climada.entity.exposures.base - INFO - centr_ not set.
2019-05-15 08:06:26,492 - climada.entity.measures.base - DEBUG - Transforming impact functions.
2019-05-15 08:06:26,492 - climada.entity.measures.base - DEBUG - Cutting events whose damage have a frequency > 0.0255.
2019-05-15 08:06:26,493 - climada.entity.exposures.base - INFO - Matching 50 exposures with 2500 centroids.
2019-05-15 08:06:26,499 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 2405 events.
/Users/aznarsig/anaconda3/envs/climada_up/lib/python3.7/site-packages/h5py/_hl/dataset.py:313: H5pyDeprecationWarning: dataset.value has been deprecated. Use dataset[()] instead.
  "Use dataset[()] instead.", H5pyDeprecationWarning)
/Users/aznarsig/anaconda3/envs/climada_up/lib/python3.7/site-packages/matplotlib/tight_layout.py:176: UserWarning: Tight layout not applied. The left and right margins cannot be made large enough to accommodate all axes decorations.
  warnings.warn('Tight layout not applied. The left and right margins '
2019-05-15 08:06:27,483 - climada.engine.impact - INFO - Exposures matching centroids found in centr_TC
2019-05-15 08:06:27,484 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 2405 events.
2019-05-15 08:06:27,503 - climada.engine.impact - INFO - Exposures matching centroids found in centr_TC
2019-05-15 08:06:27,505 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 2405 events.
[2]:
(<Figure size 288x288 with 1 Axes>,
 [<matplotlib.axes._subplots.AxesSubplot at 0x1a24968940>])
../_images/tutorial_climada_entity_MeasureSet_5_4.png
../_images/tutorial_climada_entity_MeasureSet_5_5.png
../_images/tutorial_climada_entity_MeasureSet_5_6.png
../_images/tutorial_climada_entity_MeasureSet_5_7.png
[3]:
# effect of exp_region_id
import numpy as np
from climada.entity import Measure, ImpactFuncSet, IFTropCyclone, Exposures
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()
2019-05-15 08:06:30,045 - climada.entity.exposures.base - INFO - centr_ not set.
/Users/aznarsig/anaconda3/envs/climada_up/lib/python3.7/site-packages/h5py/_hl/dataset.py:313: H5pyDeprecationWarning: dataset.value has been deprecated. Use dataset[()] instead.
  "Use dataset[()] instead.", H5pyDeprecationWarning)
2019-05-15 08:06:30,366 - climada.entity.measures.base - DEBUG - Transforming impact functions.
2019-05-15 08:06:30,367 - climada.entity.measures.base - DEBUG - Cutting events whose damage have a frequency > 0.00455.
2019-05-15 08:06:30,369 - climada.entity.exposures.base - INFO - Matching 50 exposures with 2500 centroids.
2019-05-15 08:06:30,374 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 2405 events.
2019-05-15 08:06:30,759 - climada.entity.exposures.base - INFO - Matching 50 exposures with 2500 centroids.
/Users/aznarsig/anaconda3/envs/climada_up/lib/python3.7/site-packages/matplotlib/tight_layout.py:176: UserWarning: Tight layout not applied. The left and right margins cannot be made large enough to accommodate all axes decorations.
  warnings.warn('Tight layout not applied. The left and right margins '
2019-05-15 08:06:31,795 - climada.engine.impact - INFO - Exposures matching centroids found in centr_TC
2019-05-15 08:06:31,798 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 2405 events.
2019-05-15 08:06:31,818 - climada.entity.exposures.base - INFO - Matching 50 exposures with 2500 centroids.
2019-05-15 08:06:31,823 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 2405 events.
[3]:
(<Figure size 288x288 with 1 Axes>,
 [<matplotlib.axes._subplots.AxesSubplot at 0x1a296a0dd8>])
../_images/tutorial_climada_entity_MeasureSet_6_6.png
../_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
[4]:
# effect of risk_transf_attach and risk_transf_cover
import numpy as np
from climada.entity import Measure, ImpactFuncSet, IFTropCyclone, Exposures
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))
2019-05-15 08:06:34,753 - climada.entity.exposures.base - INFO - centr_ not set.
2019-05-15 08:06:34,754 - climada.entity.exposures.base - INFO - Matching 50 exposures with 2500 centroids.
2019-05-15 08:06:34,760 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 2405 events.
2019-05-15 08:06:34,778 - climada.entity.measures.base - DEBUG - Transforming impact functions.
2019-05-15 08:06:34,779 - climada.engine.impact - INFO - Exposures matching centroids found in centr_TC
2019-05-15 08:06:34,780 - climada.engine.impact - INFO - Calculating damage for 50 assets (>0) and 2405 events.
risk_transfer 1.11e+08
/Users/aznarsig/anaconda3/envs/climada_up/lib/python3.7/site-packages/h5py/_hl/dataset.py:313: H5pyDeprecationWarning: dataset.value has been deprecated. Use dataset[()] instead.
  "Use dataset[()] instead.", H5pyDeprecationWarning)
../_images/tutorial_climada_entity_MeasureSet_7_2.png
../_images/tutorial_climada_entity_MeasureSet_7_3.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.

[5]:
from climada.entity import MeasureSet
help(MeasureSet)
Help on class MeasureSet in module climada.entity.measures.measure_set:

class MeasureSet(builtins.object)
 |  Contains measures of type Measure. Loads from
 |  files with format defined in FILE_EXT.
 |
 |  Attributes:
 |      tag (Tag): information about the source data
 |      _data (dict): cotains Measure classes. It's not suppossed to be
 |          directly accessed. Use the class methods instead.
 |
 |  Methods defined here:
 |
 |  __init__(self)
 |      Empty initialization.
 |
 |      Examples:
 |          Fill MeasureSet with values and check consistency data:
 |
 |          >>> act_1 = Measure()
 |          >>> act_1.name = 'Seawall'
 |          >>> act_1.color_rgb = np.array([0.1529, 0.2510, 0.5451])
 |          >>> act_1.hazard_intensity = (1, 0)
 |          >>> act_1.mdd_impact = (1, 0)
 |          >>> act_1.paa_impact = (1, 0)
 |          >>> meas = MeasureSet()
 |          >>> meas.append(act_1)
 |          >>> meas.tag.description = "my dummy MeasureSet."
 |          >>> meas.check()
 |
 |          Read measures from file and checks consistency data:
 |
 |          >>> meas = MeasureSet()
 |          >>> meas.read_excel(ENT_TEMPLATE_XLS)
 |
 |  append(self, meas)
 |      Append an Measure. Override if same name and haz_type.
 |
 |      Parameters:
 |          meas (Measure): Measure instance
 |
 |      Raises:
 |          ValueError
 |
 |  check(self)
 |      Check instance attributes.
 |
 |      Raises:
 |          ValueError
 |
 |  clear(self)
 |      Reinitialize attributes.
 |
 |  extend(self, meas_set)
 |      Extend measures of input MeasureSet to current
 |      MeasureSet. Overwrite Measure if same name and haz_type.
 |
 |      Parameters:
 |          impact_funcs (MeasureSet): ImpactFuncSet instance to extend
 |
 |      Raises:
 |          ValueError
 |
 |  get_hazard_types(self, meas=None)
 |      Get measures hazard types contained for the name provided.
 |      Return all hazard types if no input name.
 |
 |      Parameters:
 |          name (str, optional): measure name
 |
 |      Returns:
 |          list(str)
 |
 |  get_measure(self, haz_type=None, name=None)
 |      Get ImpactFunc(s) of input hazard type and/or id.
 |      If no input provided, all impact functions are returned.
 |
 |      Parameters:
 |          haz_type (str, optional): hazard type
 |          name (str, optional): measure name
 |
 |      Returns:
 |          Measure (if haz_type and name),
 |          list(Measure) (if haz_type or name),
 |          {Measure.haz_type: {Measure.name : Measure}} (if None)
 |
 |  get_names(self, haz_type=None)
 |      Get measures names contained for the hazard type provided.
 |      Return all names for each hazard type if no input hazard type.
 |
 |      Parameters:
 |          haz_type (str, optional): hazard type from which to obtain the names
 |
 |      Returns:
 |          list(Measure.name) (if haz_type provided),
 |          {Measure.haz_type : list(Measure.name)} (if no haz_type)
 |
 |  read_excel(self, file_name, description='', var_names={'sheet_name': 'measures', 'col_name': {'name': 'name', 'color': 'color', 'cost': 'cost', 'haz_int_a': 'hazard intensity impact a', 'haz_int_b': 'hazard intensity impact b', 'haz_frq': 'hazard high frequency cutoff', 'haz_set': 'hazard event set', 'mdd_a': 'MDD impact a', 'mdd_b': 'MDD impact b', 'paa_a': 'PAA impact a', 'paa_b': 'PAA impact b', 'fun_map': 'damagefunctions map', 'exp_set': 'assets file', 'exp_reg': 'Region_ID', 'risk_att': 'risk transfer attachement', 'risk_cov': 'risk transfer cover', 'haz': 'peril_ID'}})
 |      Read excel file following template and store variables.
 |
 |      Parameters:
 |          file_name (str): absolute file name
 |          description (str, optional): description of the data
 |          var_names (dict, optional): name of the variables in the file
 |
 |  read_mat(self, file_name, description='', var_names={'sup_field_name': 'entity', 'field_name': 'measures', 'var_name': {'name': 'name', 'color': 'color', 'cost': 'cost', 'haz_int_a': 'hazard_intensity_impact_a', 'haz_int_b': 'hazard_intensity_impact_b', 'haz_frq': 'hazard_high_frequency_cutoff', 'haz_set': 'hazard_event_set', 'mdd_a': 'MDD_impact_a', 'mdd_b': 'MDD_impact_b', 'paa_a': 'PAA_impact_a', 'paa_b': 'PAA_impact_b', 'fun_map': 'damagefunctions_map', 'exp_set': 'assets_file', 'exp_reg': 'Region_ID', 'risk_att': 'risk_transfer_attachement', 'risk_cov': 'risk_transfer_cover', 'haz': 'peril_ID'}})
 |      Read MATLAB file generated with previous MATLAB CLIMADA version.
 |
 |      Parameters:
 |          file_name (str): absolute file name
 |          description (str, optional): description of the data
 |          var_names (dict, optional): name of the variables in the file
 |
 |  remove_measure(self, haz_type=None, name=None)
 |      Remove impact function(s) with provided hazard type and/or id.
 |      If no input provided, all impact functions are removed.
 |
 |      Parameters:
 |          haz_type (str, optional): all impact functions with this hazard
 |          name (str, optional): measure name
 |
 |  size(self, haz_type=None, name=None)
 |      Get number of measures contained with input hazard type and
 |      /or id. If no input provided, get total number of impact functions.
 |
 |      Parameters:
 |          haz_type (str, optional): hazard type
 |          name (str, optional): measure name
 |
 |      Returns:
 |          int
 |
 |  write_excel(self, file_name, var_names={'sheet_name': 'measures', 'col_name': {'name': 'name', 'color': 'color', 'cost': 'cost', 'haz_int_a': 'hazard intensity impact a', 'haz_int_b': 'hazard intensity impact b', 'haz_frq': 'hazard high frequency cutoff', 'haz_set': 'hazard event set', 'mdd_a': 'MDD impact a', 'mdd_b': 'MDD impact b', 'paa_a': 'PAA impact a', 'paa_b': 'PAA impact b', 'fun_map': 'damagefunctions map', 'exp_set': 'assets file', 'exp_reg': 'Region_ID', 'risk_att': 'risk transfer attachement', 'risk_cov': 'risk transfer cover', 'haz': 'peril_ID'}})
 |      Write excel file following template.
 |
 |      Parameters:
 |          file_name (str): absolute file name to write
 |          var_names (dict, optional): name of the variables in the file
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

[6]:
# build measures
import numpy as np
import matplotlib.pyplot as plt
from climada.entity 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().

[7]:
from climada.entity 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/aznarsig/Documents/Python/climada_python/data/system/entity_template.xlsx

 Write measures

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

[8]:
from climada.entity 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:

[9]:
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)
2019-05-15 08:06:35,192 - climada.util.save - INFO - Written file /Users/aznarsig/Documents/Python/climada_python/doc/tutorial/results/tutorial_meas_set.p