Source code for climada.entity.impact_funcs.trop_cyclone

"""
This file is part of CLIMADA.

Copyright (C) 2017 ETH Zurich, CLIMADA contributors listed in AUTHORS.

CLIMADA is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free
Software Foundation, version 3.

CLIMADA is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.  See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with CLIMADA. If not, see <https://www.gnu.org/licenses/>.

---

Define impact functions for tropical cyclnes .
"""

__all__ = ['ImpfTropCyclone', 'ImpfSetTropCyclone', 'IFTropCyclone']

import logging
from deprecation import deprecated
import numpy as np
import pandas as pd

from climada.entity.impact_funcs.base import ImpactFunc
from climada.entity.impact_funcs.impact_func_set import ImpactFuncSet
from climada.util.constants import SYSTEM_DIR

LOGGER = logging.getLogger(__name__)

[docs] class ImpfTropCyclone(ImpactFunc): """Impact functions for tropical cyclones."""
[docs] def __init__(self): ImpactFunc.__init__(self) self.haz_type = 'TC'
[docs] def set_emanuel_usa(self, *args, **kwargs): """This function is deprecated, use from_emanuel_usa() instead.""" LOGGER.warning("The use of ImpfTropCyclone.set_emanuel_usa is deprecated." "Use ImpfTropCyclone.from_emanuel_usa instead.") self.__dict__ = ImpfTropCyclone.from_emanuel_usa(*args, **kwargs).__dict__
[docs] @classmethod def from_emanuel_usa(cls, impf_id=1, intensity=np.arange(0, 121, 5), v_thresh=25.7, v_half=74.7, scale=1.0): """ Init TC impact function using the formula of Kerry Emanuel, 2011: 'Global Warming Effects on U.S. Hurricane Damage', https://doi.org/10.1175/WCAS-D-11-00007.1 Parameters ---------- impf_id : int, optional impact function id. Default: 1 intensity : np.array, optional intensity array in m/s. Default: 5 m/s step array from 0 to 120m/s v_thresh : float, optional first shape parameter, wind speed in m/s below which there is no damage. Default: 25.7(Emanuel 2011) v_half : float, optional second shape parameter, wind speed in m/s at which 50% of max. damage is expected. Default: v_threshold + 49 m/s (mean value of Sealy & Strobl 2017) scale : float, optional scale parameter, linear scaling of MDD. 0<=scale<=1. Default: 1.0 Raises ------ ValueError Returns ------- impf : ImpfTropCyclone TC impact function instance based on formula by Emanuel (2011) """ if v_half <= v_thresh: raise ValueError('Shape parameters out of range: v_half <= v_thresh.') if v_thresh < 0 or v_half < 0: raise ValueError('Negative shape parameter.') if scale > 1 or scale <= 0: raise ValueError('Scale parameter out of range.') impf = cls() impf.name = 'Emanuel 2011' impf.id = impf_id impf.intensity_unit = 'm/s' impf.intensity = intensity impf.paa = np.ones(intensity.shape) v_temp = (impf.intensity - v_thresh) / (v_half - v_thresh) v_temp[v_temp < 0] = 0 impf.mdd = v_temp**3 / (1 + v_temp**3) impf.mdd *= scale return impf
[docs] class ImpfSetTropCyclone(ImpactFuncSet): """Impact function set (ImpfS) for tropical cyclones."""
[docs] def __init__(self): ImpactFuncSet.__init__(self)
[docs] def set_calibrated_regional_ImpfSet(self, *args, **kwargs): """This function is deprecated, use from_calibrated_regional_ImpfSet() instead.""" LOGGER.warning("ImpfSetTropCyclone.set_calibrated_regional_ImpfSet is deprecated." "Use ImpfSetTropCyclone.from_calibrated_regional_ImpfSet instead.") self.__dict__ = \ ImpfSetTropCyclone.from_calibrated_regional_ImpfSet(*args, **kwargs).__dict__ return ImpfSetTropCyclone.calibrated_regional_vhalf(*args, **kwargs)
[docs] @classmethod def from_calibrated_regional_ImpfSet(cls, calibration_approach='TDR', q=.5, input_file_path=None, version=1): """Calibrated regional TC wind impact functions Based on Eberenz et al. 2021: https://doi.org/10.5194/nhess-21-393-2021 Parameters ---------- calibration_approach : str, optional The following values are supported: 'TDR' (default) Total damage ratio (TDR) optimization with TDR=1.0 (simulated damage = reported damage from EM-DAT) 'TDR1.5' Total damage ratio (TDR) optimization with TDR=1.5 (simulated damage = 1.5*reported damage from EM-DAT) 'RMSF' Root-mean-squared fraction (RMSF) optimization 'EDR' quantile from individually fitted v_half per event, i.e. v_half fitted to get EDR=1.0 for each event q : float, optional Quantile between 0 and 1.0 to select (EDR only). Default: 0.5, i.e. median v_half input_file_path : str or DataFrame, optional full path to calibration result file to be used instead of default file in repository (expert users only) Returns ------- impf_set : ImpfSetTropCyclone TC Impact Function Set based on Eberenz et al, 2021. """ reg_v_half = ImpfSetTropCyclone.calibrated_regional_vhalf( calibration_approach=calibration_approach, q=q, input_file_path=input_file_path, version=version, ) # define regions and parameters: v_0 = 25.7 # v_threshold based on Emanuel (2011) scale = 1.0 regions_long = dict() regions_long['NA1'] = 'Caribbean and Mexico (NA1)' regions_long['NA2'] = 'USA and Canada (NA2)' regions_long['NI'] = 'North Indian (NI)' regions_long['OC'] = 'Oceania (OC)' regions_long['SI'] = 'South Indian (SI)' regions_long['WP1'] = 'South East Asia (WP1)' regions_long['WP2'] = 'Philippines (WP2)' regions_long['WP3'] = 'China Mainland (WP3)' regions_long['WP4'] = 'North West Pacific (WP4)' regions_long['ROW'] = 'Global' # init impact function set impf_set = cls() for idx, region in enumerate(reg_v_half.keys()): impf_tc = ImpfTropCyclone.from_emanuel_usa(impf_id=int(idx + 1), v_thresh=v_0, v_half=reg_v_half[region], scale=scale) impf_tc.name = regions_long[region] impf_set.append(impf_tc) return impf_set
[docs] @staticmethod def calibrated_regional_vhalf(calibration_approach='TDR', q=.5, input_file_path=None, version=1): """Calibrated TC wind impact function slope parameter v_half per region Based on Eberenz et al., 2021: https://doi.org/10.5194/nhess-21-393-2021 Parameters ---------- calibration_approach : str, optional The following values are supported: 'TDR' (default) Total damage ratio (TDR) optimization with TDR=1.0 (simulated damage = reported damage from EM-DAT) 'TDR1.5' Total damage ratio (TDR) optimization with TDR=1.5 (simulated damage = 1.5*reported damage from EM-DAT) 'RMSF' Root-mean-squared fraction (RMSF) optimization 'EDR' quantile from individually fitted v_half per event, i.e. v_half fitted to get EDR=1.0 for each event q : float, optional Quantile between 0 and 1.0 to select (EDR only). Default: 0.5, i.e. median v_half input_file_path : str or DataFrame, optional full path to calibration result file to be used instead of default file in repository (expert users only) Raises ------ ValueError Returns ------- v_half : dict TC impact function slope parameter v_half per region """ calibration_approach = calibration_approach.upper() if calibration_approach not in ['TDR', 'TDR1.0', 'TDR1.5', 'RMSF', 'EDR']: raise ValueError('calibration_approach is invalid') if 'EDR' in calibration_approach and (q < 0. or q > 1.): raise ValueError('Quantile q out of range [0, 1]') if calibration_approach == 'TDR': calibration_approach = 'TDR1.0' # load calibration results depending on approach: if isinstance(input_file_path, str): df_calib_results = pd.read_csv(input_file_path, encoding="ISO-8859-1", header=0) elif isinstance(input_file_path, pd.DataFrame): df_calib_results = input_file_path else: df_calib_results = pd.read_csv( SYSTEM_DIR.joinpath( 'tc_impf_cal_v%02.0f_%s.csv' % (version, calibration_approach)), encoding="ISO-8859-1", header=0) regions_short = ['NA1', 'NA2', 'NI', 'OC', 'SI', 'WP1', 'WP2', 'WP3', 'WP4'] # loop over calibration regions (column cal_region2 in df): reg_v_half = dict() for region in regions_short: df_reg = df_calib_results.loc[df_calib_results.cal_region2 == region] df_reg = df_reg.reset_index(drop=True) reg_v_half[region] = np.round(df_reg['v_half'].quantile(q=q), 5) # rest of the world (ROW), calibrated by all data: regions_short = regions_short + ['ROW'] if calibration_approach == 'EDR': reg_v_half[regions_short[-1]] = np.round(df_calib_results['v_half'].quantile(q=q), 5) else: df_reg = df_calib_results.loc[df_calib_results.cal_region2 == 'GLB'] df_reg = df_reg.reset_index(drop=True) reg_v_half[regions_short[-1]] = np.round(df_reg['v_half'].values[0], 5) return reg_v_half
[docs] @staticmethod def get_countries_per_region(region=None): """Returns dictionaries with numerical and alphabetical ISO3 codes of all countries associated to a calibration region. Only contains countries that were affected by tropical cyclones between 1980 and 2017 according to EM-DAT. Parameters ---------- region : str regional abbreviation (default='all'), either 'NA1', 'NA2', 'NI', 'OC', 'SI', 'WP1', 'WP2', 'WP3', 'WP4', or 'all'. Returns ------- region_name : dict or str long name per region impf_id : dict or int impact function ID per region iso3n : dict or list numerical ISO3codes (=region_id) per region iso3a : dict or list numerical ISO3codes (=region_id) per region """ if not region: region = 'all' iso3n = {'NA1': [660, 28, 32, 533, 44, 52, 84, 60, 68, 132, 136, 152, 170, 188, 192, 212, 214, 218, 222, 238, 254, 308, 312, 320, 328, 332, 340, 388, 474, 484, 500, 558, 591, 600, 604, 630, 654, 659, 662, 670, 534, 740, 780, 796, 858, 862, 92, 850], 'NA2': [124, 840], 'NI': [4, 51, 31, 48, 50, 64, 262, 232, 231, 268, 356, 364, 368, 376, 400, 398, 414, 417, 422, 462, 496, 104, 524, 512, 586, 634, 682, 706, 144, 760, 762, 795, 800, 784, 860, 887], 'OC': [16, 36, 184, 242, 258, 316, 296, 584, 583, 520, 540, 554, 570, 574, 580, 585, 598, 612, 882, 90, 626, 772, 776, 798, 548, 876], 'SI': [174, 180, 748, 450, 454, 466, 480, 508, 710, 834, 716], 'WP1': [116, 360, 418, 458, 764, 704], 'WP2': [608], 'WP3': [156], 'WP4': [344, 392, 410, 446, 158], 'ROW': [8, 12, 20, 24, 10, 40, 112, 56, 204, 535, 70, 72, 74, 76, 86, 96, 100, 854, 108, 120, 140, 148, 162, 166, 178, 191, 531, 196, 203, 384, 208, 818, 226, 233, 234, 246, 250, 260, 266, 270, 276, 288, 292, 300, 304, 831, 324, 624, 334, 336, 348, 352, 372, 833, 380, 832, 404, 408, 983, 428, 426, 430, 434, 438, 440, 442, 470, 478, 175, 498, 492, 499, 504, 516, 528, 562, 566, 807, 578, 275, 616, 620, 642, 643, 646, 638, 652, 663, 666, 674, 678, 686, 688, 690, 694, 702, 703, 705, 239, 728, 724, 729, 744, 752, 756, 768, 788, 792, 804, 826, 581, 732, 894, 248]} iso3a = {'NA1': ['AIA', 'ATG', 'ARG', 'ABW', 'BHS', 'BRB', 'BLZ', 'BMU', 'BOL', 'CPV', 'CYM', 'CHL', 'COL', 'CRI', 'CUB', 'DMA', 'DOM', 'ECU', 'SLV', 'FLK', 'GUF', 'GRD', 'GLP', 'GTM', 'GUY', 'HTI', 'HND', 'JAM', 'MTQ', 'MEX', 'MSR', 'NIC', 'PAN', 'PRY', 'PER', 'PRI', 'SHN', 'KNA', 'LCA', 'VCT', 'SXM', 'SUR', 'TTO', 'TCA', 'URY', 'VEN', 'VGB', 'VIR'], 'NA2': ['CAN', 'USA'], 'NI': ['AFG', 'ARM', 'AZE', 'BHR', 'BGD', 'BTN', 'DJI', 'ERI', 'ETH', 'GEO', 'IND', 'IRN', 'IRQ', 'ISR', 'JOR', 'KAZ', 'KWT', 'KGZ', 'LBN', 'MDV', 'MNG', 'MMR', 'NPL', 'OMN', 'PAK', 'QAT', 'SAU', 'SOM', 'LKA', 'SYR', 'TJK', 'TKM', 'UGA', 'ARE', 'UZB', 'YEM'], 'OC': ['ASM', 'AUS', 'COK', 'FJI', 'PYF', 'GUM', 'KIR', 'MHL', 'FSM', 'NRU', 'NCL', 'NZL', 'NIU', 'NFK', 'MNP', 'PLW', 'PNG', 'PCN', 'WSM', 'SLB', 'TLS', 'TKL', 'TON', 'TUV', 'VUT', 'WLF'], 'SI': ['COM', 'COD', 'SWZ', 'MDG', 'MWI', 'MLI', 'MUS', 'MOZ', 'ZAF', 'TZA', 'ZWE'], 'WP1': ['KHM', 'IDN', 'LAO', 'MYS', 'THA', 'VNM'], 'WP2': ['PHL'], 'WP3': ['CHN'], 'WP4': ['HKG', 'JPN', 'KOR', 'MAC', 'TWN'], 'ROW': ['ALB', 'DZA', 'AND', 'AGO', 'ATA', 'AUT', 'BLR', 'BEL', 'BEN', 'BES', 'BIH', 'BWA', 'BVT', 'BRA', 'IOT', 'BRN', 'BGR', 'BFA', 'BDI', 'CMR', 'CAF', 'TCD', 'CXR', 'CCK', 'COG', 'HRV', 'CUW', 'CYP', 'CZE', 'CIV', 'DNK', 'EGY', 'GNQ', 'EST', 'FRO', 'FIN', 'FRA', 'ATF', 'GAB', 'GMB', 'DEU', 'GHA', 'GIB', 'GRC', 'GRL', 'GGY', 'GIN', 'GNB', 'HMD', 'VAT', 'HUN', 'ISL', 'IRL', 'IMN', 'ITA', 'JEY', 'KEN', 'PRK', 'XKX', 'LVA', 'LSO', 'LBR', 'LBY', 'LIE', 'LTU', 'LUX', 'MLT', 'MRT', 'MYT', 'MDA', 'MCO', 'MNE', 'MAR', 'NAM', 'NLD', 'NER', 'NGA', 'MKD', 'NOR', 'PSE', 'POL', 'PRT', 'ROU', 'RUS', 'RWA', 'REU', 'BLM', 'MAF', 'SPM', 'SMR', 'STP', 'SEN', 'SRB', 'SYC', 'SLE', 'SGP', 'SVK', 'SVN', 'SGS', 'SSD', 'ESP', 'SDN', 'SJM', 'SWE', 'CHE', 'TGO', 'TUN', 'TUR', 'UKR', 'GBR', 'UMI', 'ESH', 'ZMB', 'ALA']} impf_id = {'NA1': 1, 'NA2': 2, 'NI': 3, 'OC': 4, 'SI': 5, 'WP1': 6, 'WP2': 7, 'WP3': 8, 'WP4': 9, 'ROW': 10} region_name = dict() region_name['NA1'] = 'Caribbean and Mexico' region_name['NA2'] = 'USA and Canada' region_name['NI'] = 'North Indian' region_name['OC'] = 'Oceania' region_name['SI'] = 'South Indian' region_name['WP1'] = 'South East Asia' region_name['WP2'] = 'Philippines' region_name['WP3'] = 'China Mainland' region_name['WP4'] = 'North West Pacific' if region == 'all': return region_name, impf_id, iso3n, iso3a return region_name[region], impf_id[region], iso3n[region], iso3a[region]
[docs] @deprecated(details="The class name IFTropCyclone is deprecated and won't be supported in a future " +"version. Use ImpfTropCyclone instead") class IFTropCyclone(ImpfTropCyclone): """Is ImpfTropCyclone now"""