def test_append_equal_same(self): """Appends an other tag correctly.""" tag1 = Tag('file_name1.mat', 'dummy file 1') tag2 = Tag('file_name1.mat', 'dummy file 1') tag1.append(tag2) self.assertEqual('file_name1.mat', tag1.file_name) self.assertEqual('dummy file 1', tag1.description)
def test_append_different_increase(self): """Appends an other tag correctly.""" tag1 = Tag('file_name1.mat', 'dummy file 1') self.assertEqual('file_name1.mat', tag1.file_name) self.assertEqual('dummy file 1', tag1.description) tag2 = Tag('file_name2.mat', 'dummy file 2') tag1.append(tag2) self.assertEqual('file_name1.mat + file_name2.mat', tag1.file_name) self.assertEqual('dummy file 1 + dummy file 2', tag1.description)
class MeasureSet(): """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. """ def __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) """ self.clear() def clear(self): """Reinitialize attributes.""" self.tag = Tag() self._data = dict() # {hazard_type : {name: Measure()}} def append(self, meas): """Append an Measure. Override if same name and haz_type. Parameters: meas (Measure): Measure instance Raises: ValueError """ if not isinstance(meas, Measure): LOGGER.error("Input value is not of type Measure.") raise ValueError if not meas.haz_type: LOGGER.warning("Input Measure's hazard type not set.") if not meas.name: LOGGER.warning("Input Measure's name not set.") if meas.haz_type not in self._data: self._data[meas.haz_type] = dict() self._data[meas.haz_type][meas.name] = meas def 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 """ if (haz_type is not None) and (name is not None): try: del self._data[haz_type][name] except KeyError: LOGGER.info("No Measure with hazard %s and id %s.", haz_type, name) elif haz_type is not None: try: del self._data[haz_type] except KeyError: LOGGER.info("No Measure with hazard %s.", haz_type) elif name is not None: haz_remove = self.get_hazard_types(name) if not haz_remove: LOGGER.info("No Measure with name %s.", name) for haz in haz_remove: del self._data[haz][name] else: self._data = dict() def 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) """ if (haz_type is not None) and (name is not None): try: return self._data[haz_type][name] except KeyError: LOGGER.info("No Measure with hazard %s and id %s.", haz_type, name) return list() elif haz_type is not None: try: return list(self._data[haz_type].values()) except KeyError: LOGGER.info("No Measure with hazard %s.", haz_type) return list() elif name is not None: haz_return = self.get_hazard_types(name) if not haz_return: LOGGER.info("No Measure with name %s.", name) meas_return = [] for haz in haz_return: meas_return.append(self._data[haz][name]) return meas_return else: return self._data def 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) """ if meas is None: return list(self._data.keys()) haz_return = [] for haz, haz_dict in self._data.items(): if meas in haz_dict: haz_return.append(haz) return haz_return def 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) """ if haz_type is None: out_dict = dict() for haz, haz_dict in self._data.items(): out_dict[haz] = list(haz_dict.keys()) return out_dict try: return list(self._data[haz_type].keys()) except KeyError: LOGGER.info("No Measure with hazard %s.", haz_type) return list() def 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 """ if (haz_type is not None) and (name is not None) and \ (isinstance(self.get_measure(haz_type, name), Measure)): return 1 if (haz_type is not None) or (name is not None): return len(self.get_measure(haz_type, name)) return sum(len(meas_list) for meas_list in self.get_names().values()) def check(self): """Check instance attributes. Raises: ValueError """ for key_haz, meas_dict in self._data.items(): def_color = plt.cm.get_cmap('Greys', len(meas_dict)) for i_meas, (name, meas) in enumerate(meas_dict.items()): if (name != meas.name) | (name == ''): LOGGER.error("Wrong Measure.name: %s != %s.", name, meas.name) raise ValueError if key_haz != meas.haz_type: LOGGER.error("Wrong Measure.haz_type: %s != %s.", key_haz, meas.haz_type) raise ValueError # set default color if not set if np.array_equal(meas.color_rgb, np.zeros(3)): meas.color_rgb = def_color(i_meas) meas.check() def 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 """ meas_set.check() if self.size() == 0: self.__dict__ = copy.deepcopy(meas_set.__dict__) return self.tag.append(meas_set.tag) new_func = meas_set.get_measure() for _, meas_dict in new_func.items(): for _, meas in meas_dict.items(): self.append(meas) def read_mat(self, file_name, description='', var_names=DEF_VAR_MAT): """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 """ def read_att_mat(measures, data, file_name, var_names): """Read MATLAB measures attributes""" num_mes = len(data[var_names['var_name']['name']]) for idx in range(0, num_mes): meas = Measure() meas.name = hdf5.get_str_from_ref( file_name, data[var_names['var_name']['name']][idx][0]) color_str = hdf5.get_str_from_ref( file_name, data[var_names['var_name']['color']][idx][0]) meas.color_rgb = np.fromstring(color_str, dtype=float, sep=' ') meas.cost = data[var_names['var_name']['cost']][idx][0] meas.haz_type = hdf5.get_str_from_ref( file_name, data[var_names['var_name']['haz']][idx][0]) meas.hazard_freq_cutoff = data[var_names['var_name'] ['haz_frq']][idx][0] meas.hazard_set = hdf5.get_str_from_ref( file_name, data[var_names['var_name']['haz_set']][idx][0]) try: meas.hazard_inten_imp = ( data[var_names['var_name']['haz_int_a']][idx][0], data[var_names['var_name']['haz_int_b']][0][idx]) except KeyError: meas.hazard_inten_imp = ( data[var_names['var_name']['haz_int_a'][:-2]][idx][0], 0) # different convention of signes followed in MATLAB! meas.mdd_impact = ( data[var_names['var_name']['mdd_a']][idx][0], data[var_names['var_name']['mdd_b']][idx][0]) meas.paa_impact = ( data[var_names['var_name']['paa_a']][idx][0], data[var_names['var_name']['paa_b']][idx][0]) meas.imp_fun_map = hdf5.get_str_from_ref( file_name, data[var_names['var_name']['fun_map']][idx][0]) meas.exposures_set = hdf5.get_str_from_ref( file_name, data[var_names['var_name']['exp_set']][idx][0]) exp_region_id = data[var_names['var_name']['exp_reg']][idx][0] if exp_region_id: meas.exp_region_id = [exp_region_id] meas.risk_transf_attach = data[var_names['var_name'] ['risk_att']][idx][0] meas.risk_transf_cover = data[var_names['var_name'] ['risk_cov']][idx][0] measures.append(meas) data = hdf5.read(file_name) self.clear() self.tag.file_name = file_name self.tag.description = description try: data = data[var_names['sup_field_name']] except KeyError: pass try: data = data[var_names['field_name']] read_att_mat(self, data, file_name, var_names) except KeyError as var_err: LOGGER.error("Not existing variable %s", str(var_err)) raise var_err def read_excel(self, file_name, description='', var_names=DEF_VAR_EXCEL): """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 """ def read_att_excel(measures, dfr, var_names): """Read Excel measures attributes""" num_mes = len(dfr.index) for idx in range(0, num_mes): meas = Measure() meas.name = dfr[var_names['col_name']['name']][idx] try: meas.haz_type = dfr[var_names['col_name']['haz']][idx] except KeyError: pass meas.color_rgb = np.fromstring( dfr[var_names['col_name']['color']][idx], dtype=float, sep=' ') meas.cost = dfr[var_names['col_name']['cost']][idx] meas.hazard_freq_cutoff = dfr[var_names['col_name'] ['haz_frq']][idx] meas.hazard_set = dfr[var_names['col_name']['haz_set']][idx] # Search for (a, b) values, put a = 1 otherwise try: meas.hazard_inten_imp = ( dfr[var_names['col_name']['haz_int_a']][idx], dfr[var_names['col_name']['haz_int_b']][idx]) except KeyError: meas.hazard_inten_imp = ( 1, dfr['hazard intensity impact'][idx]) try: meas.exposures_set = dfr[var_names['col_name'] ['exp_set']][idx] meas.exp_region_id = ast.literal_eval( dfr[var_names['col_name']['exp_reg']][idx]) except KeyError: pass except ValueError: meas.exp_region_id = dfr[var_names['col_name'] ['exp_reg']][idx] meas.mdd_impact = (dfr[var_names['col_name']['mdd_a']][idx], dfr[var_names['col_name']['mdd_b']][idx]) meas.paa_impact = (dfr[var_names['col_name']['paa_a']][idx], dfr[var_names['col_name']['paa_b']][idx]) meas.imp_fun_map = dfr[var_names['col_name']['fun_map']][idx] meas.risk_transf_attach = dfr[var_names['col_name'] ['risk_att']][idx] meas.risk_transf_cover = dfr[var_names['col_name'] ['risk_cov']][idx] try: meas.risk_transf_cost_factor = dfr[var_names['col_name'] ['risk_fact']][idx] except KeyError: pass measures.append(meas) dfr = pd.read_excel(file_name, var_names['sheet_name']) dfr = dfr.fillna('') self.clear() self.tag.file_name = file_name self.tag.description = description try: read_att_excel(self, dfr, var_names) except KeyError as var_err: LOGGER.error("Not existing variable: %s", str(var_err)) raise var_err def write_excel(self, file_name, var_names=DEF_VAR_EXCEL): """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 """ def write_meas(row_ini, imp_ws, xls_data): """Write one measure""" for icol, col_dat in enumerate(xls_data): imp_ws.write(row_ini, icol, col_dat) meas_wb = xlsxwriter.Workbook(file_name) mead_ws = meas_wb.add_worksheet(var_names['sheet_name']) header = [ var_names['col_name']['name'], var_names['col_name']['color'], var_names['col_name']['cost'], var_names['col_name']['haz_int_a'], var_names['col_name']['haz_int_b'], var_names['col_name']['haz_frq'], var_names['col_name']['haz_set'], var_names['col_name']['mdd_a'], var_names['col_name']['mdd_b'], var_names['col_name']['paa_a'], var_names['col_name']['paa_b'], var_names['col_name']['fun_map'], var_names['col_name']['exp_set'], var_names['col_name']['exp_reg'], var_names['col_name']['risk_att'], var_names['col_name']['risk_cov'], var_names['col_name']['haz'] ] for icol, head_dat in enumerate(header): mead_ws.write(0, icol, head_dat) for row_ini, (_, haz_dict) in enumerate(self._data.items(), 1): for meas_name, meas in haz_dict.items(): xls_data = [ meas_name, ' '.join(list(map(str, meas.color_rgb))), meas.cost, meas.hazard_inten_imp[0], meas.hazard_inten_imp[1], meas.hazard_freq_cutoff, meas.hazard_set, meas.mdd_impact[0], meas.mdd_impact[1], meas.paa_impact[0], meas.paa_impact[1], meas.imp_fun_map, meas.exposures_set, str(meas.exp_region_id), meas.risk_transf_attach, meas.risk_transf_cover, meas.haz_type ] write_meas(row_ini, mead_ws, xls_data) meas_wb.close()
class ImpactFuncSet(): """Contains impact functions of type ImpactFunc. Loads from files with format defined in FILE_EXT. Attributes: tag (Tag): information about the source data _data (dict): contains ImpactFunc classes. It's not suppossed to be directly accessed. Use the class methods instead. """ def __init__(self): """Empty initialization. Examples: Fill impact functions with values and check consistency data: >>> fun_1 = ImpactFunc() >>> fun_1.haz_type = 'TC' >>> fun_1.id = 3 >>> fun_1.intensity = np.array([0, 20]) >>> fun_1.paa = np.array([0, 1]) >>> fun_1.mdd = np.array([0, 0.5]) >>> imp_fun = ImpactFuncSet() >>> imp_fun.append(fun_1) >>> imp_fun.check() Read impact functions from file and checks consistency data. >>> imp_fun = ImpactFuncSet() >>> imp_fun.read(ENT_TEMPLATE_XLS) """ self.clear() def clear(self): """Reinitialize attributes.""" self.tag = Tag() self._data = dict() # {hazard_type : {id:ImpactFunc}} def append(self, func): """Append a ImpactFunc. Overwrite existing if same id and haz_type. Parameters: func (ImpactFunc): ImpactFunc instance Raises: ValueError """ if not isinstance(func, ImpactFunc): LOGGER.error("Input value is not of type ImpactFunc.") raise ValueError if not func.haz_type: LOGGER.warning("Input ImpactFunc's hazard type not set.") if not func.id: LOGGER.warning("Input ImpactFunc's id not set.") if func.haz_type not in self._data: self._data[func.haz_type] = dict() self._data[func.haz_type][func.id] = func def remove_func(self, haz_type=None, fun_id=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 fun_id (int, optional): all impact functions with this id """ if (haz_type is not None) and (fun_id is not None): try: del self._data[haz_type][fun_id] except KeyError: LOGGER.warning("No ImpactFunc with hazard %s and id %s.", haz_type, fun_id) elif haz_type is not None: try: del self._data[haz_type] except KeyError: LOGGER.warning("No ImpactFunc with hazard %s.", haz_type) elif fun_id is not None: haz_remove = self.get_hazard_types(fun_id) if not haz_remove: LOGGER.warning("No ImpactFunc with id %s.", fun_id) for vul_haz in haz_remove: del self._data[vul_haz][fun_id] else: self._data = dict() def get_func(self, haz_type=None, fun_id=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 fun_id (int, optional): ImpactFunc id Returns: ImpactFunc (if haz_type and fun_id), list(ImpactFunc) (if haz_type or fun_id), {ImpactFunc.haz_type: {ImpactFunc.id : ImpactFunc}} (if None) """ if (haz_type is not None) and (fun_id is not None): try: return self._data[haz_type][fun_id] except KeyError: return list() elif haz_type is not None: try: return list(self._data[haz_type].values()) except KeyError: return list() elif fun_id is not None: haz_return = self.get_hazard_types(fun_id) vul_return = [] for vul_haz in haz_return: vul_return.append(self._data[vul_haz][fun_id]) return vul_return else: return self._data def get_hazard_types(self, fun_id=None): """Get impact functions hazard types contained for the id provided. Return all hazard types if no input id. Parameters: fun_id (int, optional): id of an impact function Returns: list(str) """ if fun_id is None: return list(self._data.keys()) haz_types = [] for vul_haz, vul_dict in self._data.items(): if fun_id in vul_dict: haz_types.append(vul_haz) return haz_types def get_ids(self, haz_type=None): """Get impact functions ids contained for the hazard type provided. Return all ids for each hazard type if no input hazard type. Parameters: haz_type (str, optional): hazard type from which to obtain the ids Returns: list(ImpactFunc.id) (if haz_type provided), {ImpactFunc.haz_type : list(ImpactFunc.id)} (if no haz_type) """ if haz_type is None: out_dict = dict() for vul_haz, vul_dict in self._data.items(): out_dict[vul_haz] = list(vul_dict.keys()) return out_dict try: return list(self._data[haz_type].keys()) except KeyError: return list() def size(self, haz_type=None, fun_id=None): """Get number of impact functions 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 fun_id (int, optional): ImpactFunc id Returns: int """ if (haz_type is not None) and (fun_id is not None) and \ (isinstance(self.get_func(haz_type, fun_id), ImpactFunc)): return 1 if (haz_type is not None) or (fun_id is not None): return len(self.get_func(haz_type, fun_id)) return sum(len(vul_list) for vul_list in self.get_ids().values()) def check(self): """Check instance attributes. Raises: ValueError """ for key_haz, vul_dict in self._data.items(): for fun_id, vul in vul_dict.items(): if (fun_id != vul.id) | (fun_id == ''): LOGGER.error("Wrong ImpactFunc.id: %s != %s.", fun_id, vul.id) raise ValueError if (key_haz != vul.haz_type) | (key_haz == ''): LOGGER.error("Wrong ImpactFunc.haz_type: %s != %s.", key_haz, vul.haz_type) raise ValueError vul.check() def extend(self, impact_funcs): """Append impact functions of input ImpactFuncSet to current ImpactFuncSet. Overwrite ImpactFunc if same id and haz_type. Parameters: impact_funcs (ImpactFuncSet): ImpactFuncSet instance to extend Raises: ValueError """ impact_funcs.check() if self.size() == 0: self.__dict__ = copy.deepcopy(impact_funcs.__dict__) return self.tag.append(impact_funcs.tag) new_func = impact_funcs.get_func() for _, vul_dict in new_func.items(): for _, vul in vul_dict.items(): self.append(vul) def plot(self, haz_type=None, fun_id=None, axis=None, **kwargs): """Plot impact functions of selected hazard (all if not provided) and selected function id (all if not provided). Parameters: haz_type (str, optional): hazard type fun_id (int, optional): id of the function Returns: matplotlib.axes._subplots.AxesSubplot """ num_plts = self.size(haz_type, fun_id) num_row, num_col = u_plot._get_row_col_size(num_plts) # Select all hazard types to plot if haz_type is not None: hazards = [haz_type] else: hazards = self._data.keys() if not axis: _, axis = plt.subplots(num_row, num_col) if num_plts > 1: axes = axis.flatten() else: axes = [axis] i_axis = 0 for sel_haz in hazards: if fun_id is not None: self._data[sel_haz][fun_id].plot(axis=axes[i_axis], **kwargs) i_axis += 1 else: for sel_id in self._data[sel_haz].keys(): self._data[sel_haz][sel_id].plot(axis=axes[i_axis], **kwargs) i_axis += 1 return axis def read_excel(self, file_name, description='', var_names=DEF_VAR_EXCEL): """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 """ dfr = pd.read_excel(file_name, var_names['sheet_name']) self.clear() self.tag.file_name = str(file_name) self.tag.description = description self._fill_dfr(dfr, var_names) def read_mat(self, file_name, description='', var_names=DEF_VAR_MAT): """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 """ def _get_hdf5_funcs(imp, file_name, var_names): """Get rows that fill every impact function and its name.""" func_pos = dict() for row, (fun_id, fun_type) in enumerate( zip(imp[var_names['var_name']['fun_id']].squeeze(), imp[var_names['var_name']['peril']].squeeze())): type_str = u_hdf5.get_str_from_ref(file_name, fun_type) key = (type_str, int(fun_id)) if key not in func_pos: func_pos[key] = list() func_pos[key].append(row) return func_pos def _get_hdf5_str(imp, idxs, file_name, var_name): """Get rows with same string in var_name.""" prev_str = "" for row in idxs: cur_str = u_hdf5.get_str_from_ref(file_name, imp[var_name][row][0]) if prev_str == "": prev_str = cur_str elif prev_str != cur_str: LOGGER.error("Impact function with two different %s.", var_name) raise ValueError return prev_str imp = u_hdf5.read(file_name) self.clear() self.tag.file_name = str(file_name) self.tag.description = description try: imp = imp[var_names['sup_field_name']] except KeyError: pass try: imp = imp[var_names['field_name']] funcs_idx = _get_hdf5_funcs(imp, file_name, var_names) for imp_key, imp_rows in funcs_idx.items(): func = ImpactFunc() func.haz_type = imp_key[0] func.id = imp_key[1] # check that this function only has one intensity unit, if provided try: func.intensity_unit = _get_hdf5_str(imp, imp_rows, file_name, var_names['var_name']['unit']) except KeyError: pass # check that this function only has one name try: func.name = _get_hdf5_str(imp, imp_rows, file_name, var_names['var_name']['name']) except KeyError: func.name = str(func.id) func.intensity = np.take(imp[var_names['var_name']['inten']], imp_rows) func.mdd = np.take(imp[var_names['var_name']['mdd']], imp_rows) func.paa = np.take(imp[var_names['var_name']['paa']], imp_rows) self.append(func) except KeyError as err: LOGGER.error("Not existing variable: %s", str(err)) raise err def write_excel(self, file_name, var_names=DEF_VAR_EXCEL): """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 """ def write_if(row_ini, imp_ws, xls_data): """Write one impact function""" for icol, col_dat in enumerate(xls_data): for irow, data in enumerate(col_dat, row_ini): imp_ws.write(irow, icol, data) imp_wb = xlsxwriter.Workbook(file_name) imp_ws = imp_wb.add_worksheet(var_names['sheet_name']) header = [var_names['col_name']['func_id'], var_names['col_name']['inten'], var_names['col_name']['mdd'], var_names['col_name']['paa'], var_names['col_name']['peril'], var_names['col_name']['unit'], var_names['col_name']['name']] for icol, head_dat in enumerate(header): imp_ws.write(0, icol, head_dat) row_ini = 1 for fun_haz_id, fun_haz in self._data.items(): for fun_id, fun in fun_haz.items(): n_inten = fun.intensity.size xls_data = [repeat(fun_id, n_inten), fun.intensity, fun.mdd, fun.paa, repeat(fun_haz_id, n_inten), repeat(fun.intensity_unit, n_inten), repeat(fun.name, n_inten)] write_if(row_ini, imp_ws, xls_data) row_ini += n_inten imp_wb.close() def _fill_dfr(self, dfr, var_names): def _get_xls_funcs(dfr, var_names): """Parse individual impact functions.""" dist_func = [] for (haz_type, imp_id) in zip(dfr[var_names['col_name']['peril']], dfr[var_names['col_name']['func_id']]): if (haz_type, imp_id) not in dist_func: dist_func.append((haz_type, imp_id)) return dist_func try: dist_func = _get_xls_funcs(dfr, var_names) for haz_type, imp_id in dist_func: df_func = dfr[dfr[var_names['col_name']['peril']] == haz_type] df_func = df_func[df_func[var_names['col_name']['func_id']] == imp_id] func = ImpactFunc() func.haz_type = haz_type func.id = imp_id # check that the unit of the intensity is the same try: if len(df_func[var_names['col_name']['name']].unique()) != 1: raise ValueError('Impact function with two different names.') func.name = df_func[var_names['col_name']['name']].values[0] except KeyError: func.name = str(func.id) # check that the unit of the intensity is the same, if provided try: if len(df_func[var_names['col_name']['unit']].unique()) != 1: raise ValueError('Impact function with two different \ intensity units.') func.intensity_unit = \ df_func[var_names['col_name']['unit']].values[0] except KeyError: pass func.intensity = df_func[var_names['col_name']['inten']].values func.mdd = df_func[var_names['col_name']['mdd']].values func.paa = df_func[var_names['col_name']['paa']].values self.append(func) except KeyError as err: LOGGER.error("Not existing variable: %s", str(err)) raise err
class DiscRates(): """Defines discount rates and basic methods. Loads from files with format defined in FILE_EXT. Attributes: tag (Tag): information about the source data years (np.array): years rates (np.array): discount rates for each year (between 0 and 1) """ def __init__(self): """Empty initialization. Examples: Fill discount rates with values and check consistency data: >>> disc_rates = DiscRates() >>> disc_rates.years = np.array([2000, 2001]) >>> disc_rates.rates = np.array([0.02, 0.02]) >>> disc_rates.check() Read discount rates from year_2050.mat and checks consistency data. >>> disc_rates = DiscRates(ENT_TEMPLATE_XLS) """ self.clear() def clear(self): """Reinitialize attributes.""" self.tag = Tag() # Following values are given for each defined year self.years = np.array([], int) self.rates = np.array([], float) def check(self): """Check attributes consistency. Raises: ValueError """ check.size(len(self.years), self.rates, 'DiscRates.rates') def select(self, year_range): """Select discount rates in given years. Parameters: year_range (np.array): continuous sequence of selected years. Returns: DiscRates """ pos_year = np.isin(year_range, self.years) if not np.all(pos_year): LOGGER.info('No discount rates for given years.') return None pos_year = np.isin(self.years, year_range) sel_disc = self.__class__() sel_disc.tag = self.tag sel_disc.years = self.years[pos_year] sel_disc.rates = self.rates[pos_year] return sel_disc def append(self, disc_rates): """Check and append discount rates to current DiscRates. Overwrite discount rate if same year. Parameters: disc_rates (DiscRates): DiscRates instance to append Raises: ValueError """ disc_rates.check() if self.years.size == 0: self.__dict__ = copy.deepcopy(disc_rates.__dict__) return self.tag.append(disc_rates.tag) new_year = array('l') new_rate = array('d') for year, rate in zip(disc_rates.years, disc_rates.rates): found = np.where(year == self.years)[0] if found.size > 0: self.rates[found[0]] = rate else: new_year.append(year) new_rate.append(rate) self.years = np.append(self.years, new_year).astype(int, copy=False) self.rates = np.append(self.rates, new_rate) def net_present_value(self, ini_year, end_year, val_years): """Compute net present value between present year and future year. Parameters: ini_year (float): initial year end_year (float): end year val_years (np.array): cash flow at each year btw ini_year and end_year (both included) Returns: float """ year_range = np.arange(ini_year, end_year + 1) if year_range.size != val_years.size: LOGGER.error('Wrong size of yearly values.') raise ValueError sel_disc = self.select(year_range) if sel_disc is None: LOGGER.error('No information of discount rates for provided years:'\ ' %s - %s', ini_year, end_year) raise ValueError return u_fin.net_present_value(sel_disc.years, sel_disc.rates, val_years) def plot(self, axis=None, **kwargs): """Plot discount rates per year. Parameters: axis (matplotlib.axes._subplots.AxesSubplot, optional): axis to use kwargs (optional): arguments for plot matplotlib function, e.g. marker='x' Returns: matplotlib.axes._subplots.AxesSubplot """ if not axis: _, axis = plt.subplots(1, 1) axis.set_title('Discount rates') axis.set_xlabel('Year') axis.set_ylabel('discount rate (%)') axis.plot(self.years, self.rates * 100, **kwargs) axis.set_xlim((self.years.min(), self.years.max())) return axis def read_mat(self, file_name, description='', var_names=DEF_VAR_MAT): """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 """ disc = hdf5.read(file_name) self.clear() self.tag.file_name = file_name self.tag.description = description try: disc = disc[var_names['sup_field_name']] except KeyError: pass try: disc = disc[var_names['field_name']] self.years = np.squeeze(disc[var_names['var_name']['year']]). \ astype(int, copy=False) self.rates = np.squeeze(disc[var_names['var_name']['disc']]) except KeyError as err: LOGGER.error("Not existing variable: %s", str(err)) raise err def read_excel(self, file_name, description='', var_names=DEF_VAR_EXCEL): """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 """ dfr = pd.read_excel(file_name, var_names['sheet_name']) self.clear() self.tag.file_name = file_name self.tag.description = description try: self.years = dfr[var_names['col_name']['year']].values. \ astype(int, copy=False) self.rates = dfr[var_names['col_name']['disc']].values except KeyError as err: LOGGER.error("Not existing variable: %s", str(err)) raise err def write_excel(self, file_name, var_names=DEF_VAR_EXCEL): """ 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 """ disc_wb = xlsxwriter.Workbook(file_name) disc_ws = disc_wb.add_worksheet(var_names['sheet_name']) header = [var_names['col_name']['year'], var_names['col_name']['disc']] for icol, head_dat in enumerate(header): disc_ws.write(0, icol, head_dat) for i_yr, (disc_yr, disc_rt) in enumerate(zip(self.years, self.rates), 1): disc_ws.write(i_yr, 0, disc_yr) disc_ws.write(i_yr, 1, disc_rt) disc_wb.close()
class DiscRates(): """ Defines discount rates and basic methods. Loads from files with format defined in FILE_EXT. Attributes --------- tag: Tag information about the source data years: np.array list of years rates: np.array list of discount rates for each year (between 0 and 1) """ def __init__(self, years=None, rates=None, tag=None): """ Fill discount rates with values and check consistency data Parameters ---------- years : numpy.ndarray(int) Array of years. Default is numpy.array([]). rates : numpy.ndarray(float) Discount rates for each year in years. Default is numpy.array([]). Note: rates given in float, e.g., to set 1% rate use 0.01 tag : climate.entity.tag Metadata. Default is None. """ years = np.array([]) if years is None else years rates = np.array([]) if rates is None else rates self.years = years self.rates = rates tag = Tag() if tag is None else tag self.tag = tag def clear(self): """Reinitialize attributes.""" self.tag = Tag() # Following values are given for each defined year self.years = np.array([], int) self.rates = np.array([], float) def check(self): """ Check attributes consistency. Raises ------ ValueError """ u_check.size(len(self.years), self.rates, 'DiscRates.rates') def select(self, year_range): """ Select discount rates in given years. Parameters ---------- year_range: np.array(int) continuous sequence of selected years. Returns: climada.entity.DiscRates The selected discrates in the year_range """ pos_year = np.isin(year_range, self.years) if not np.all(pos_year): LOGGER.info('No discount rates for given years.') return None pos_year = np.isin(self.years, year_range) return DiscRates(years=self.years[pos_year], rates=self.rates[pos_year], tag=self.tag) def append(self, disc_rates): """ Check and append discount rates to current DiscRates. Overwrite discount rate if same year. Parameters ---------- disc_rates: climada.entity.DiscRates DiscRates instance to append Raises ------ ValueError """ disc_rates.check() if self.years.size == 0: self.__dict__ = copy.deepcopy(disc_rates.__dict__) return self.tag.append(disc_rates.tag) new_year = array('l') new_rate = array('d') for year, rate in zip(disc_rates.years, disc_rates.rates): found = np.where(year == self.years)[0] if found.size > 0: self.rates[found[0]] = rate else: new_year.append(year) new_rate.append(rate) self.years = np.append(self.years, new_year).astype(int, copy=False) self.rates = np.append(self.rates, new_rate) def net_present_value(self, ini_year, end_year, val_years): """ Compute net present value between present year and future year. Parameters ---------- ini_year: float initial year end_year: float end year val_years: np.array cash flow at each year btw ini_year and end_year (both included) Returns ------- net_present_value: float net present value between present year and future year. """ year_range = np.arange(ini_year, end_year + 1) if year_range.size != val_years.size: raise ValueError('Wrong size of yearly values.') sel_disc = self.select(year_range) if sel_disc is None: raise ValueError( 'No information of discount rates for provided years:' f' {ini_year} - {end_year}') return u_fin.net_present_value(sel_disc.years, sel_disc.rates, val_years) def plot(self, axis=None, figsize=(6, 8), **kwargs): """ Plot discount rates per year. Parameters ---------- axis: matplotlib.axes._subplots.AxesSubplot, optional axis to use figsize: tuple(int, int), optional size of the figure. The default is (6,8) kwargs: optional keyword arguments passed to plotting function axis.plot Returns ------- axis: matplotlib.axes._subplots.AxesSubplot axis handles of the plot """ if not axis: _, axis = plt.subplots(1, 1, figsize=figsize) axis.set_title('Discount rates') axis.set_xlabel('Year') axis.set_ylabel('discount rate (%)') axis.plot(self.years, self.rates * 100, **kwargs) axis.set_xlim((self.years.min(), self.years.max())) return axis @classmethod def from_mat(cls, file_name, description='', var_names=None): """ Read MATLAB file generated with previous MATLAB CLIMADA version. Parameters ---------- file_name: str filename including path and extension description: str, optional description of the data. The default is '' var_names: dict, optional name of the variables in the file. The Default is DEF_VAR_MAT = {'sup_field_name': 'entity', 'field_name': 'discount', 'var_name': {'year': 'year', 'disc': 'discount_rate'}} Returns ------- climada.entity.DiscRates : The disc rates from matlab """ if var_names is None: var_names = DEF_VAR_MAT disc = u_hdf5.read(file_name) tag = Tag(file_name=str(file_name), description=description) try: disc = disc[var_names['sup_field_name']] except KeyError: pass try: disc = disc[var_names['field_name']] years = np.squeeze(disc[var_names['var_name']['year']]). \ astype(int, copy=False) rates = np.squeeze(disc[var_names['var_name']['disc']]) except KeyError as err: raise KeyError("Not existing variable: %s" % str(err)) from err return cls(years=years, rates=rates, tag=tag) def read_mat(self, *args, **kwargs): """This function is deprecated, use DiscRates.from_mats instead.""" LOGGER.warning("The use of DiscRates.read_mats is deprecated." "Use DiscRates.from_mats instead.") self.__dict__ = DiscRates.from_mat(*args, **kwargs).__dict__ @classmethod def from_excel(cls, file_name, description='', var_names=None): """ Read excel file following template and store variables. Parameters ---------- file_name: str filename including path and extension description: str, optional description of the data. The default is '' var_names: dict, optional name of the variables in the file. The Default is DEF_VAR_EXCEL = {'sheet_name': 'discount', 'col_name': {'year': 'year', 'disc': 'discount_rate'}} Returns ------- climada.entity.DiscRates : The disc rates from excel """ if var_names is None: var_names = DEF_VAR_EXCEL dfr = pd.read_excel(file_name, var_names['sheet_name']) tag = Tag(file_name=str(file_name), description=description) try: years = dfr[var_names['col_name']['year']].values. \ astype(int, copy=False) rates = dfr[var_names['col_name']['disc']].values except KeyError as err: raise KeyError("Not existing variable: %s" % str(err)) from err return cls(years=years, rates=rates, tag=tag) def read_excel(self, *args, **kwargs): """This function is deprecated, use DiscRates.from_excel instead.""" LOGGER.warning("The use of DiscRates.read_excel is deprecated." "Use DiscRates.from_excel instead.") self.__dict__ = DiscRates.from_mat(*args, **kwargs).__dict__ def write_excel(self, file_name, var_names=None): """ Write excel file following template. Parameters ---------- file_name: str filename including path and extension var_names: dict, optional name of the variables in the file. The Default is DEF_VAR_EXCEL = {'sheet_name': 'discount', 'col_name': {'year': 'year', 'disc': 'discount_rate'}} """ if var_names is None: var_names = DEF_VAR_EXCEL disc_wb = xlsxwriter.Workbook(file_name) disc_ws = disc_wb.add_worksheet(var_names['sheet_name']) header = [var_names['col_name']['year'], var_names['col_name']['disc']] for icol, head_dat in enumerate(header): disc_ws.write(0, icol, head_dat) for i_yr, (disc_yr, disc_rt) in enumerate(zip(self.years, self.rates), 1): disc_ws.write(i_yr, 0, disc_yr) disc_ws.write(i_yr, 1, disc_rt) disc_wb.close()