Source code for climada.engine.unsequa.input_var

"""
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 InputVar class.
"""

import copy
from functools import partial
from itertools import zip_longest
import logging
from typing import Dict

import scipy as sp
import numpy as np
import matplotlib.pyplot as plt

from climada.entity import Entity, DiscRates

LOGGER = logging.getLogger(__name__)

__all__ = ['InputVar']

FIG_W, FIG_H = 8, 5 #default figize width/heigh column/work multiplicators

[docs] class InputVar(): """ Input variable for the uncertainty analysis An uncertainty input variable requires a single or multi-parameter function. The parameters must follow a given distribution. The uncertainty input variables are the input parameters of the model. Attributes ---------- distr_dict : dict Distribution of the uncertainty parameters. Keys are uncertainty parameters names and Values are probability density distribution from the scipy.stats package https://docs.scipy.org/doc/scipy/reference/stats.html labels : list Names of the uncertainty parameters (keys of distr_dict) func : function User defined python fucntion with the uncertainty parameters as keyword arguements and which returns a climada object. Notes ----- A few default Variables are defined for Hazards, Exposures, Impact Fucntions, Measures and Entities. Examples -------- Categorical variable function: LitPop exposures with m,n exponents in [0,5] >>> import scipy as sp >>> def litpop_cat(m, n): ... exp = Litpop.from_countries('CHE', exponent=[m, n]) ... return exp >>> distr_dict = { ... 'm': sp.stats.randint(low=0, high=5), ... 'n': sp.stats.randint(low=0, high=5) ... } >>> iv_cat = InputVar(func=litpop_cat, distr_dict=distr_dict) Continuous variable function: Impact function for TC >>> import scipy as sp >>> def imp_fun_tc(G, v_half, vmin, k, _id=1): ... intensity = np.linspace(0, 150, num=100) ... mdd = np.repeat(1, len(intensity)) ... paa = np.array([sigmoid_function(v, G, v_half, vmin, k) ... for v in intensity]) ... imp_fun = ImpactFunc(haz_type='TC', ... id=_id, ... intensity_unit='m/s', ... intensity=intensity, ... mdd=mdd, ... paa=paa) ... imp_fun.check() ... impf_set = ImpactFuncSet([imp_fun]) ... return impf_set >>> distr_dict = {"G": sp.stats.uniform(0.8, 1), ... "v_half": sp.stats.uniform(50, 100), ... "vmin": sp.stats.norm(loc=15, scale=30), ... "k": sp.stats.randint(low=1, high=9) ... } >>> iv_cont = InputVar(func=imp_fun_tc, distr_dict=distr_dict) """
[docs] def __init__( self, func: callable, distr_dict: Dict, ): """ Initialize InputVar Parameters ---------- func : function Variable defined as a function of the uncertainty parameters distr_dict : dict Dictionary of the probability density distributions of the uncertainty parameters, with keys matching the keyword arguments (i.e. uncertainty parameters) of the func function. The distribution must be of type scipy.stats https://docs.scipy.org/doc/scipy/reference/stats.html """ self.labels = list(distr_dict.keys()) self.distr_dict = distr_dict self.func = func
[docs] def evaluate(self, **params): """ Return the value of uncertainty input variable. By default, the value of the average is returned. Parameters ---------- **params : optional Input parameters will be passed to self.func. Returns ------- unc_func(**params) : climada object Output of the uncertainty variable. """ if not params: params = { param: distr.mean() for param, distr in self.distr_dict.items() } return self.func(**params)
[docs] def plot(self, figsize=None): """ Plot the distributions of the parameters of the uncertainty variable. Parameters ---------- figsize: tuple(int or float, int or float), optional The figsize argument of matplotlib.pyplot.subplots() The default is derived from the total number of plots (nplots) as: >>> nrows, ncols = int(np.ceil(nplots / 3)), min(nplots, 3) >>> figsize = (ncols * FIG_W, nrows * FIG_H) Returns ------- axes: matplotlib.pyplot.figure, matplotlib.pyplot.axes The figure and axes handle of the plot. """ nplots = len(self.distr_dict) nrows, ncols = int(np.ceil(nplots / 3)), min(nplots, 3) if figsize is None: figsize = (ncols * FIG_W, nrows * FIG_H) _fig, axes = plt.subplots(nrows=nrows, ncols=ncols, figsize=figsize) if nplots > 1: flat_axes = axes.flatten() else: flat_axes = np.array([axes]) for ax, name_distr in zip_longest(flat_axes, self.distr_dict.items(), fillvalue=None): if name_distr is None: ax.remove() continue (param_name, distr) = name_distr low = distr.ppf(1e-10) high = distr.ppf(1-1e-10) n = 100 try: x = np.linspace(low, high, n) ax.plot(x, distr.pdf(x), label=param_name) except AttributeError: if (high - low) > n: x = np.arange(low, high, int((high-low) / n)) else: x = np.arange(low, high+1) ax.vlines(x, 0, distr.pmf(x), label=param_name) ax.legend() return axes
[docs] @staticmethod def var_to_inputvar(var): """ Returns an uncertainty variable with no distribution if var is not an InputVar. Else, returns var. Parameters ---------- var : climada.uncertainty.InputVar or any other CLIMADA object Returns ------- InputVar var if var is InputVar, else InputVar with var and no distribution. """ if isinstance(var, InputVar): return var return InputVar(func=lambda: var, distr_dict={})
[docs] @staticmethod def haz(haz_list, n_ev=None, bounds_int=None, bounds_frac=None, bounds_freq=None): """ Helper wrapper for basic hazard uncertainty input variable The following types of uncertainties can be added: HE: sub-sampling events from the total event set For each sub-sample, n_ev events are sampled with replacement. HE is the value of the seed for the uniform random number generator. HI: scale the intensity of all events (homogeneously) The instensity of all events is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_int HA: scale the fraction of all events (homogeneously) The fraction of all events is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_frac HF: scale the frequency of all events (homogeneously) The frequency of all events is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_freq HL: sample uniformly from hazard list From the provided list of hazard is elements are uniformly sampled. For example, Hazards outputs from dynamical models for different input factors. If a bounds is None, this parameter is assumed to have no uncertainty. Parameters ---------- haz : List of climada.hazard.Hazard The list of base hazard. Can be one or many to uniformly sample from. n_ev : int, optional Number of events to be subsampled per sample. Can be equal or larger than haz.size. The default is None. bounds_int : (float, float), optional Bounds of the uniform distribution for the homogeneous intensity scaling. The default is None. bounds_frac : (float, float), optional Bounds of the uniform distribution for the homogeneous fraction scaling. The default is None. bounds_freq : (float, float), optional Bounds of the uniform distribution for the homogeneous frequency scaling. The default is None. Returns ------- climada.engine.unsequa.input_var.InputVar Uncertainty input variable for a hazard object. """ n_haz = len(haz_list) kwargs = {'haz_list': haz_list, 'n_ev': n_ev} if n_ev is None: kwargs['HE'] = None if bounds_int is None: kwargs['HI'] = None if bounds_frac is None: kwargs['HA'] = None if bounds_freq is None: kwargs['HF'] = None if n_haz == 1: kwargs['HL'] = 0 return InputVar( partial(_haz_uncfunc, **kwargs), _haz_unc_dict(n_ev, bounds_int, bounds_frac, bounds_freq, n_haz) )
[docs] @staticmethod def exp(exp_list, bounds_totval=None, bounds_noise=None): """ Helper wrapper for basic exposure uncertainty input variable The following types of uncertainties can be added: ET: scale the total value (homogeneously) The value at each exposure point is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_totvalue EN: mutliplicative noise (inhomogeneous) The value of each exposure point is independently multiplied by a random number sampled uniformly from a distribution with (min, max) = bounds_noise. EN is the value of the seed for the uniform random number generator. EL: sample uniformly from exposure list From the provided list of exposure is elements are uniformly sampled. For example, LitPop instances with different exponents. If a bounds is None, this parameter is assumed to have no uncertainty. Parameters ---------- exp_list : list of climada.entity.exposures.Exposures The list of base exposure. Can be one or many to uniformly sample from. bounds_totval : (float, float), optional Bounds of the uniform distribution for the homogeneous total value scaling.. The default is None. bounds_noise : (float, float), optional Bounds of the uniform distribution to scale each exposure point independently. The default is None. Returns ------- climada.engine.unsequa.input_var.InputVar Uncertainty input variable for an exposure object. """ n_exp = len(exp_list) kwargs = {'exp_list': exp_list, 'bounds_noise': bounds_noise} if bounds_noise is None: kwargs['EN'] = None if bounds_totval is None: kwargs['ET'] = None if n_exp == 1: kwargs['EL'] = 0 return InputVar( partial(_exp_uncfunc, **kwargs), _exp_unc_dict(bounds_totval=bounds_totval, bounds_noise=bounds_noise, n_exp=n_exp) )
[docs] @staticmethod def impfset(impf_set_list, haz_id_dict= None, bounds_mdd=None, bounds_paa=None, bounds_impfi=None): """ Helper wrapper for basic impact function set uncertainty input variable. One impact function (chosen with haz_type and fun_id) is characterized. The following types of uncertainties can be added: MDD: scale the mdd (homogeneously) The value of mdd at each intensity is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_mdd PAA: scale the paa (homogeneously) The value of paa at each intensity is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_paa IFi: shift the intensity (homogeneously) The value intensity are all summed with a random number sampled uniformly from a distribution with (min, max) = bounds_int IL: sample uniformly from impact function set list From the provided list of impact function sets elements are uniformly sampled. For example, impact functions obtained from different calibration methods. If a bounds is None, this parameter is assumed to have no uncertainty. Parameters ---------- impf_set_list : list of ImpactFuncSet The list of base impact function set. Can be one or many to uniformly sample from. The impact function ids must identical for all impact function sets. bounds_mdd : (float, float), optional Bounds of the uniform distribution for the homogeneous mdd scaling. The default is None. bounds_paa : (float, float), optional Bounds of the uniform distribution for the homogeneous paa scaling. The default is None. bounds_impfi : (float, float), optional Bounds of the uniform distribution for the homogeneous shift of intensity. The default is None. haz_id_dict : dict(), optional Dictionary of the impact functions affected by uncertainty. Keys are hazard types (str), values are a list of impact function id (int). Default is impsf_set.get_ids() i.e. all impact functions in the set Returns ------- climada.engine.unsequa.input_var.InputVar Uncertainty input variable for an impact function set object. """ n_impf_set = len(impf_set_list) kwargs = {'impf_set_list': impf_set_list} if bounds_mdd is None: kwargs['MDD'] = None if bounds_paa is None: kwargs['PAA'] = None if bounds_impfi is None: kwargs['IFi'] = None if haz_id_dict is None: haz_id_dict = impf_set_list[0].get_ids() if n_impf_set == 1: kwargs['IL'] = 0 return InputVar( partial( _impfset_uncfunc, haz_id_dict=haz_id_dict, **kwargs ), _impfset_unc_dict(bounds_impfi, bounds_mdd, bounds_paa, n_impf_set) )
[docs] @staticmethod def ent(impf_set_list, disc_rate, exp_list, meas_set, haz_id_dict, bounds_disc=None, bounds_cost=None, bounds_totval=None, bounds_noise=None, bounds_mdd=None, bounds_paa=None, bounds_impfi=None): """ Helper wrapper for basic entity set uncertainty input variable. Important: only the impact function defined by haz_type and fun_id will be affected by bounds_impfi, bounds_mdd, bounds_paa. The following types of uncertainties can be added: DR: value of constant discount rate (homogeneously) The value of the discounts in each year is sampled uniformly from a distribution with (min, max) = bounds_disc CO: scale the cost (homogeneously) The cost of all measures is multiplied by the same number sampled uniformly from a distribution with (min, max) = bounds_cost ET: scale the total value (homogeneously) The value at each exposure point is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_totval EN: mutliplicative noise (inhomogeneous) The value of each exposure point is independently multiplied by a random number sampled uniformly from a distribution with (min, max) = bounds_noise. EN is the value of the seed for the uniform random number generator. EL: sample uniformly from exposure list From the provided list of exposure is elements are uniformly sampled. For example, LitPop instances with different exponents. MDD: scale the mdd (homogeneously) The value of mdd at each intensity is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_mdd PAA: scale the paa (homogeneously) The value of paa at each intensity is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_paa IFi: shift the intensity (homogeneously) The value intensity are all summed with a random number sampled uniformly from a distribution with (min, max) = bounds_int IL: sample uniformly from impact function set list From the provided list of impact function sets elements are uniformly sampled. For example, impact functions obtained from different calibration methods. If a bounds is None, this parameter is assumed to have no uncertainty. Parameters ---------- bounds_disk : (float, float), optional Bounds of the uniform distribution for the homogeneous discount rate scaling. The default is None. bounds_cost :(float, float), optional Bounds of the uniform distribution for the homogeneous cost of all measures scaling. The default is None. bounds_totval : (float, float), optional Bounds of the uniform distribution for the homogeneous total exposure value scaling. The default is None. bounds_noise : (float, float), optional Bounds of the uniform distribution to scale each exposure point independently. The default is None. bounds_mdd : (float, float), optional Bounds of the uniform distribution for the homogeneous mdd scaling. The default is None. bounds_paa : (float, float), optional Bounds of the uniform distribution for the homogeneous paa scaling. The default is None. bounds_impfi : (float, float), optional Bounds of the uniform distribution for the homogeneous shift of intensity. The default is None. impf_set_list : list of ImpactFuncSet The list of base impact function set. Can be one or many to uniformly sample from. The impact function ids must identical for all impact function sets. disc_rate : climada.entity.disc_rates.base.DiscRates The base discount rates. exp_list : [climada.entity.exposures.base.Exposure] The list of base exposure. Can be one or many to uniformly sample from. meas_set : climada.entity.measures.measure_set.MeasureSet The base measures. haz_id_dict : dict Dictionary of the impact functions affected by uncertainty. Keys are hazard types (str), values are a list of impact function id (int). Returns ------- climada.engine.unsequa.input_var.InputVar Entity uncertainty input variable """ n_exp = len(exp_list) n_impf_set = len(impf_set_list) kwargs = {} if bounds_mdd is None: kwargs['MDD'] = None if bounds_paa is None: kwargs['PAA'] = None if bounds_impfi is None: kwargs['IFi'] = None if n_impf_set== 1: kwargs['IL'] = 0 if bounds_disc is None: kwargs['DR'] = None if bounds_cost is None: kwargs['CO'] = None if bounds_totval is None: kwargs['ET'] = None if bounds_noise is None: kwargs['EN'] = None if n_exp == 1: kwargs['EL'] = 0 return InputVar( partial(_ent_unc_func, impf_set_list=impf_set_list, haz_id_dict=haz_id_dict, disc_rate=disc_rate, bounds_noise=bounds_noise, exp_list=exp_list, meas_set=meas_set, **kwargs ), _ent_unc_dict(bounds_totval=bounds_totval, bounds_noise=bounds_noise, bounds_impfi=bounds_impfi, n_impf_set=n_impf_set, bounds_mdd=bounds_mdd, bounds_paa=bounds_paa, bounds_disc=bounds_disc, bounds_cost=bounds_cost, n_exp=n_exp,) )
[docs] @staticmethod def entfut(impf_set_list, exp_list, meas_set, haz_id_dict, bounds_cost=None, bounds_eg=None, bounds_noise=None, bounds_impfi=None, bounds_mdd=None, bounds_paa=None, ): """ Helper wrapper for basic future entity set uncertainty input variable. Important: only the impact function defined by haz_type and fun_id will be affected by bounds_impfi, bounds_mdd, bounds_paa. The following types of uncertainties can be added: CO: scale the cost (homogeneously) The cost of all measures is multiplied by the same number sampled uniformly from a distribution with (min, max) = bounds_cost EG: scale the exposures growth (homogeneously) The value at each exposure point is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_eg EN: mutliplicative noise (inhomogeneous) The value of each exposure point is independently multiplied by a random number sampled uniformly from a distribution with (min, max) = bounds_noise. EN is the value of the seed for the uniform random number generator. EL: sample uniformly from exposure list From the provided list of exposure is elements are uniformly sampled. For example, LitPop instances with different exponents. MDD: scale the mdd (homogeneously) The value of mdd at each intensity is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_mdd PAA: scale the paa (homogeneously) The value of paa at each intensity is multiplied by a number sampled uniformly from a distribution with (min, max) = bounds_paa IFi: shift the impact function intensity (homogeneously) The value intensity are all summed with a random number sampled uniformly from a distribution with (min, max) = bounds_impfi IL: sample uniformly from impact function set list From the provided list of impact function sets elements are uniformly sampled. For example, impact functions obtained from different calibration methods. If a bounds is None, this parameter is assumed to have no uncertainty. Parameters ---------- bounds_cost :(float, float), optional Bounds of the uniform distribution for the homogeneous cost of all measures scaling. The default is None. bounds_eg : (float, float), optional Bounds of the uniform distribution for the homogeneous total exposure growth scaling. The default is None. bounds_noise : (float, float), optional Bounds of the uniform distribution to scale each exposure point independently. The default is None. bounds_mdd : (float, float), optional Bounds of the uniform distribution for the homogeneous mdd scaling. The default is None. bounds_paa : (float, float), optional Bounds of the uniform distribution for the homogeneous paa scaling. The default is None. bounds_impfi : (float, float), optional Bounds of the uniform distribution for the homogeneous shift of intensity. The default is None. impf_set_list : list of ImpactFuncSet The list of base impact function set. Can be one or many to uniformly sample from. The impact function ids must identical for all impact function sets. exp_list : [climada.entity.exposures.base.Exposure] The list of base exposure. Can be one or many to uniformly sample from. meas_set : climada.entity.measures.measure_set.MeasureSet The base measures. haz_id_dict : dict Dictionary of the impact functions affected by uncertainty. Keys are hazard types (str), values are a list of impact function id (int). Returns ------- climada.engine.unsequa.input_var.InputVar Entity uncertainty input variable """ n_exp = len(exp_list) n_impf_set = len(impf_set_list) kwargs = {} if bounds_mdd is None: kwargs['MDD'] = None if bounds_paa is None: kwargs['PAA'] = None if bounds_impfi is None: kwargs['IFi'] = None if n_impf_set == 1: kwargs['IL'] = 0 if bounds_cost is None: kwargs['CO'] = None if bounds_eg is None: kwargs['EG'] = None if bounds_noise is None: kwargs['EN'] = None if n_exp == 1: kwargs['EL'] = 0 return InputVar( partial(_entfut_unc_func, haz_id_dict=haz_id_dict, bounds_noise=bounds_noise, impf_set_list=impf_set_list, exp_list=exp_list, meas_set=meas_set, **kwargs), _entfut_unc_dict(bounds_eg=bounds_eg, bounds_noise=bounds_noise, bounds_impfi=bounds_impfi, n_impf_set=n_impf_set, bounds_paa=bounds_paa, bounds_mdd=bounds_mdd, bounds_cost=bounds_cost, n_exp=n_exp) )
#Hazard def _haz_uncfunc(HE, HI, HA, HF, HL, haz_list, n_ev): haz_tmp = copy.deepcopy(haz_list[int(HL)]) if HE is not None: rng = np.random.RandomState(int(HE)) event_id = list(rng.choice(haz_tmp.event_id, int(n_ev))) haz_tmp = haz_tmp.select(event_id=event_id) if HI is not None: haz_tmp.intensity = haz_tmp.intensity.multiply(HI) if HA is not None: haz_tmp.fraction = haz_tmp.fraction.multiply(HA) if HF is not None: haz_tmp.frequency = np.multiply(haz_tmp.frequency, HF) return haz_tmp def _haz_unc_dict(n_ev, bounds_int, bounds_frac, bounds_freq, n_haz): hud = {} if n_ev is not None: hud['HE'] = sp.stats.randint(0, 2**32 - 1) #seed for rnd generator if bounds_int is not None: imin, idelta = bounds_int[0], bounds_int[1] - bounds_int[0] hud['HI'] = sp.stats.uniform(imin, idelta) if bounds_frac is not None: amin, adelta = bounds_frac[0], bounds_frac[1] - bounds_frac[0] hud['HA'] = sp.stats.uniform(amin, adelta) if bounds_freq is not None: fmin, fdelta = bounds_freq[0], bounds_freq[1] - bounds_freq[0] hud['HF'] = sp.stats.uniform(fmin, fdelta) if n_haz > 1: hud['HL'] = sp.stats.randint(0, n_haz) return hud #Exposure def _exp_uncfunc(EN, ET, EL, exp_list, bounds_noise): exp_tmp = exp_list[int(EL)].copy(deep=True) if EN is not None: rng = np.random.RandomState(int(EN)) rnd_vals = rng.uniform(bounds_noise[0], bounds_noise[1], size = len(exp_tmp.gdf)) exp_tmp.gdf.value *= rnd_vals if ET is not None: exp_tmp.gdf.value *= ET return exp_tmp def _exp_unc_dict(bounds_totval, bounds_noise, n_exp): eud = {} if bounds_totval is not None: tmin, tmax = bounds_totval[0], bounds_totval[1] - bounds_totval[0] eud['ET'] = sp.stats.uniform(tmin, tmax) if bounds_noise is not None: eud['EN'] = sp.stats.randint(0, 2**32 - 1) #seed for rnd generator if n_exp > 1: eud['EL'] = sp.stats.randint(0, n_exp) return eud #Impact function set def _impfset_uncfunc(IFi, MDD, PAA, IL, impf_set_list, haz_id_dict): impf_set_tmp = copy.deepcopy(impf_set_list[int(IL)]) for haz_type, fun_id_list in haz_id_dict.items(): for fun_id in fun_id_list: if MDD is not None: new_mdd = np.minimum( impf_set_tmp.get_func(haz_type=haz_type, fun_id=fun_id).mdd * MDD, 1.0 ) impf_set_tmp.get_func(haz_type=haz_type, fun_id=fun_id).mdd = new_mdd if PAA is not None: new_paa = np.minimum( impf_set_tmp.get_func(haz_type=haz_type, fun_id=fun_id).paa * PAA, 1.0 ) impf_set_tmp.get_func(haz_type=haz_type, fun_id=fun_id).paa = new_paa if IFi is not None: new_int = np.maximum( impf_set_tmp.get_func(haz_type=haz_type, fun_id=fun_id).intensity + IFi, 0.0 ) impf_set_tmp.get_func(haz_type=haz_type, fun_id=fun_id).intensity = new_int return impf_set_tmp def _impfset_unc_dict(bounds_impfi, bounds_mdd, bounds_paa, n_impf_set): iud = {} if bounds_impfi is not None: xmin, xdelta = bounds_impfi[0], bounds_impfi[1] - bounds_impfi[0] iud['IFi'] = sp.stats.uniform(xmin, xdelta) if bounds_paa is not None: xmin, xdelta = bounds_paa[0], bounds_paa[1] - bounds_paa[0] iud['PAA'] = sp.stats.uniform(xmin, xdelta) if bounds_mdd is not None: xmin, xdelta = bounds_mdd[0], bounds_mdd[1] - bounds_mdd[0] iud['MDD'] = sp.stats.uniform(xmin, xdelta) if n_impf_set > 1: iud['IL'] = sp.stats.randint(0, n_impf_set) return iud #Entity def _disc_uncfunc(DR, disc_rate): disc = copy.deepcopy(disc_rate) if DR is not None: disc.rates = np.ones(disc.years.size) * DR return disc def _disc_unc_dict(bounds_disk): if bounds_disk is None: return {} dmin, ddelta = bounds_disk[0], bounds_disk[1] - bounds_disk[0] return {'DR': sp.stats.uniform(dmin, ddelta)} def _meas_set_uncfunc(CO, meas_set): meas_set_tmp = copy.deepcopy(meas_set) if CO is not None: for haz_type in meas_set_tmp.get_hazard_types(): for meas in meas_set_tmp.get_measure(haz_type=haz_type): meas.cost *= CO return meas_set_tmp def _meas_set_unc_dict(bounds_cost): cmin, cdelta = bounds_cost[0], bounds_cost[1] - bounds_cost[0] return {'CO': sp.stats.uniform(cmin, cdelta)} def _ent_unc_func(EN, ET, EL, IFi, IL, MDD, PAA, CO, DR, bounds_noise, impf_set_list, haz_id_dict, disc_rate, exp_list, meas_set): exposures = _exp_uncfunc(EN, ET, EL, exp_list, bounds_noise) impact_func_set = _impfset_uncfunc(IFi, MDD, PAA, IL, impf_set_list=impf_set_list, haz_id_dict=haz_id_dict) measure_set = _meas_set_uncfunc(CO, meas_set=meas_set) disc_rates = _disc_uncfunc(DR, disc_rate) return Entity(exposures, disc_rates, impact_func_set, measure_set) def _ent_unc_dict(bounds_totval, bounds_noise, bounds_impfi, bounds_mdd, bounds_paa, n_impf_set, bounds_disc, bounds_cost, n_exp): ent_unc_dict = _exp_unc_dict(bounds_totval, bounds_noise, n_exp) ent_unc_dict.update(_impfset_unc_dict(bounds_impfi, bounds_mdd, bounds_paa, n_impf_set)) ent_unc_dict.update(_disc_unc_dict(bounds_disc)) ent_unc_dict.update(_meas_set_unc_dict(bounds_cost)) return ent_unc_dict def _entfut_unc_func(EN, EG, EL, IFi, IL, MDD, PAA, CO, bounds_noise, impf_set_list, haz_id_dict, exp_list, meas_set): exposures = _exp_uncfunc(EN=EN, ET=EG, EL=EL, exp_list=exp_list, bounds_noise=bounds_noise) impact_funcs = _impfset_uncfunc(IFi, MDD, PAA, IL, impf_set_list=impf_set_list, haz_id_dict=haz_id_dict) measures = _meas_set_uncfunc(CO, meas_set=meas_set) disc_rates = DiscRates() #Disc rate of future entity ignored in cost_benefit.calc() return Entity(exposures, disc_rates, impact_funcs, measures) def _entfut_unc_dict(bounds_impfi, bounds_mdd, bounds_paa, n_impf_set, bounds_eg, bounds_noise, bounds_cost, n_exp): eud = {} if bounds_eg is not None: gmin, gmax = bounds_eg[0], bounds_eg[1] - bounds_eg[0] eud['EG'] = sp.stats.uniform(gmin, gmax) if bounds_noise is not None: eud['EN'] = sp.stats.randint(0, 2**32 - 1) #seed for rnd generator if n_exp > 1: eud['EL'] = sp.stats.randint(0, n_exp) eud.update(_impfset_unc_dict(bounds_impfi, bounds_mdd, bounds_paa, n_impf_set)) if bounds_cost is not None: eud.update(_meas_set_unc_dict(bounds_cost)) return eud