def call_hazard(directory_hazard, scenario, year, uncertainty_variable='all', kanton=None):
    """Compute heat hazard for the CH2018 data, considered as any day where the T_max is higher than 22 degrees celsius

            Parameters:
                directory_hazard (str): directory to a folder containing one tasmax folder with all the data files
                scenario (str): scenario for which to compute the hazards
                year(str): year for which to compute the hazards
                uncertainty_variable (str): variable for which to consider the uncertainty. Default: 'all'
                kanton (str or None): Name of canton. Default: None (all of Switzerland)

            Returns:
                hazards(dict): dictionary containing the hazard heat
                  """
    if uncertainty_variable == 'all' or uncertainty_variable == 'years':
        ny = random.randint(-3, 3)  # to be added to the year, so that any year in the +5 to -5 range can be picked
    else:  # if we are testing the sensitivity to the change in variables, we always want to be taking
        # the same year and therefore add 0
        ny = 0

    if uncertainty_variable == 'simulations' or uncertainty_variable == 'all':
        nc_max_temp = np.random.choice(list(set(glob.glob(''.join([directory_hazard, '/tasmax/', '*', scenario, '*'])))))
    else:
        nc_max_temp = glob.glob(directory_hazard + '/tasmax/' + '*SMHI-RCA_NORESM_EUR44*')[0]

    tasmax = xr.open_dataset(nc_max_temp).sel(time=slice(''.join([str(year + ny), '-01-01']),
                                                         ''.join([str(year + 1 + ny), '-01-01'])))  # open as xr dataset

    if kanton:  # if a canton is specified, we mask the values outside of this canton using a day_startapefile
        shp_dir = '../../input_data/shapefiles/KANTONS_projected_epsg4326/' \
                  'swissBOUNDARIES3D_1_3_TLM_KANTONSGEBIET_epsg4326.shp'

        tasmax = add_shape_coord_from_data_array(tasmax, shp_dir, kanton)
        tasmax = tasmax.where(tasmax[kanton] == 0, other=np.nan)

    # replace all values where the maximum
    # temperature does not reach 22 degrees by nas in TASMAX and drop time steps that only have NAs
    # for the entire area: (21.5 because of rounding that happens later)
    tasmax = tasmax.where(tasmax['tasmax'] > 21.5).dropna(dim='time', how='all')

    nlats = len(tasmax.lat)  # number of latitudes
    nlons = len(tasmax.lon)  # number of longitudes

    # variables needed for the model

    number_days = len(tasmax.time)
    temp = np.zeros([number_days, nlats, nlons]) # array where we save the data for the heat hazard
    day = 0  # start at day 0
    dates = np.zeros(number_days)

    # create an array with the maximum temperature of the day

    for t in range(number_days):  # loop over the number of days in a year

        dates[t] = Timestamp(tasmax.time.values[day]).toordinal()
        temp[t,:,:] = (tasmax.tasmax.values[day])
            
        day = day + 1

    nevents = [len(temp)]  # number of events
    events = [range(len(temp))]  # number of each event
    event_dates = [dates]
    temp_data = [temp]
    hazard_types =['heat']

    hazards = {}

    for w_ in range(len(temp_data)):  # write down the events in Hazard class

        grid_x, grid_y = np.meshgrid(tasmax.lon.values, tasmax.lat.values)
        heat = Hazard('heat')
        heat.centroids.set_lat_lon(grid_y.flatten(), grid_x.flatten(), crs={'init': 'epsg:4326'})
        heat.units = 'degrees C'
        heat_data = temp_data[w_]
        heat_data[np.isnan(heat_data)] = 0.  # replace NAs by 0
        heat.intensity = sparse.csr_matrix(heat_data.reshape(nevents[w_], nlons * nlats))
        heat.event_id = np.array(events[w_])
        heat.event_name = heat.event_id
        heat.frequency = np.ones(nevents[w_])
        heat.fraction = heat.intensity.copy()
        heat.fraction.data.fill(1)
        heat.date = event_dates[w_]
        hazards[hazard_types[w_]] = heat
        heat.check()

    tasmax.close()
    del tasmax
    del temp

    return hazards  # return the hazards
Example #2
0
def generate_haz(name_haz, name_hdf5_file, input_folder, years):
    """
    Generates new CLIMADA Hazard class
    
    Parameters
    ----------
    name_haz : str
        name of hazard ["haz_real", "haz_synth", "haz_dur"].
    name_hdf5_file : dict
        names of corresponding hdf5 files.
    input_folder : str
        Path to input folder.
    years : list of str
        years for which data will be loaded.

    Returns
    -------
    haz : climada.hazard.base.Hazard
        CLIMADA hazard.

    """
    # here it gets a bit ugly
    

    if name_haz == "haz_real":
        haz = Hazard("HL")
        haz.units = "mm"
        haz.fraction, haz.intensity, duration, haz.event_name, \
                lat, lon, haz.date = get_hail_data(
                years = years,  
                input_folder = input_folder)
        haz.intensity_thres = 20

    elif name_haz == "haz_synth":
        haz = Hazard("HL")
        haz.units = "mm"
        haz.fraction, haz.intensity, haz.event_name, \
                lat, lon, haz.date = get_hail_data_synth(
                years = years,  
                input_folder = input_folder)
        haz.intensity_thres = 20

    else:
        haz = Hazard("HL")
        haz.units = "min"
        haz.fraction, placeholder, haz.intensity, haz.event_name, \
                lat, lon, haz.date = get_hail_data(
                years = years,  
                input_folder = input_folder)
        haz.intensity_thres = 0

    #set frequency
    haz.frequency = np.ones(haz.intensity.shape[0])/len(years)        
    haz.event_id = np.arange(1, haz.intensity.shape[0]+1, dtype = int)
    #set coordinates
    haz.centroids.set_lat_lon(lat, lon)
    save_haz = input("you forced a new generation of {}. Do you want to save it as hdf5 [True, False]? ".format(name_haz))
    if save_haz == "True":
        print("writing new Hazard to hdf5")
        haz.write_hdf5(input_folder + "/" + name_haz + ".hdf5")
    return haz
Example #3
0
def call_hazard(directory_hazard,
                scenario,
                year,
                uncertainty_variable='all',
                kanton=None,
                sun_protection=False,
                working_hours=[8, 12, 13, 17],
                only_outside=False):
    """Compute heat inside and heat outside hazards for the ch2018 data, considered as any hour where the WBGT is higher
        than 22 degrees celsius

            Parameters:
                directory_hazard (str): directory to a folder containing one tasmax and one tasmin folder with all the
                                        data files
                scenario (str): scenario for which to compute the hazards
                year(str): year for which to compute the hazards
                uncertainty_variable (str): variable for which to consider the uncertainty. Default: 'all'
                kanton (str or None): Name of canton. Default: None (all of Switzerland)
                sun_protection (bool): rather to consider the adaptation measure sun_protection. Default: False
                working_hours (list): hours where people are working. list with the first number being when they
                        start in the day, the second when they start their midday break,
                        third when they start in the afternoon and last when they finished in the evening
                        Default:[8,12,13,17]
                only_outside (bool): rather damage occurs only outside (buildings are well insulated from heat)
                        Default: False

            Returns:
                hazards(dict): dictionary containing the hazard 'heat outside' and 'heat inside'
                  """

    if not sun_protection:
        ones_zero_random = np.random.choice(
            [0, 1], size=(8, )
        )  # randomly pick the number of hours where people working outside are in the sun
    else:
        ones_zero_random = np.ones(8, dtype=int)

    rmse_hourly_t = 0.028530743129040116  # Root mean square error from the hourly T transformation
    error_hourly_t = np.random.normal(
        0, rmse_hourly_t)  # distribution for the transformation from
    # min T and max T to hourly T
    error_temp_in = np.random.triangular(
        0, 1, 1.2)  # distribution for the inside temperature estimation.
    error_wbgt = np.random.normal(
        0, 2 / 3.92)  # error for the transformation between T and WBGT

    if uncertainty_variable == 'all' or uncertainty_variable == 'years':
        ny = random.randint(
            -3, 3
        )  # to be added to the year, so that any year in the +5 to -5 range can be picked
    else:  # if we are testing the sensitivity to the change in variables, we always want to be taking
        # the same year and therefore add 0
        ny = 0

    if uncertainty_variable == 'simulations' or uncertainty_variable == 'all':
        nc_max_temp = np.random.choice(
            list(
                set(
                    glob.glob(''.join(
                        [directory_hazard, '/tasmax/', '*', scenario, '*'])))))
    else:
        nc_max_temp = glob.glob(directory_hazard + '/tasmax/' +
                                '*SMHI-RCA_NORESM_EUR44*')[0]

    nc_min_temp = nc_max_temp.replace('max',
                                      'min')  # take equivalent tasmin file
    tasmax = xr.open_dataset(nc_max_temp).sel(time=slice(
        ''.join([str(year + ny), '-01-01']),
        ''.join([str(year + 1 + ny), '-01-01'])))  # open as xr dataset
    tasmin = xr.open_dataset(nc_min_temp).sel(time=slice(
        ''.join([str(year +
                     ny), '-01-01']), ''.join([str(year + 1 + ny), '-01-01'])))

    if kanton:  # if a canton is specified, we mask the values outside of this canton using a day_startapefile
        shp_dir = '../../input_data/shapefiles/KANTONS_projected_epsg4326/' \
                  'swissBOUNDARIES3D_1_3_TLM_KANTONSGEBIET_epsg4326.shp'

        tasmax = add_shape_coord_from_data_array(tasmax, shp_dir, kanton)
        tasmax = tasmax.where(tasmax[kanton] == 0, other=np.nan)
        tasmin = add_shape_coord_from_data_array(tasmin, shp_dir, kanton)
        tasmin = tasmin.where(tasmin[kanton] == 0, other=np.nan)

    # replace all values where the maximum
    # temperature does not reach 22 degrees by nas in both TASMIN and TASMAX and drop time steps that only have NAs
    # for the entire area:
    tasmin = tasmin.where(tasmax['tasmax'] > 22).dropna(dim='time', how='all')
    tasmax = tasmax.where(tasmax['tasmax'] > 22).dropna(dim='time', how='all')

    nlats = len(tasmax.lat)  # number of latitudes
    nlons = len(tasmax.lon)  # number of longitudes
    day_start = working_hours[0]  # beginning of working day
    day_end = working_hours[3]  # End of working day
    daily_working_hours = day_end - day_start  # length of working day

    # variables needed for the model (h_max is the hour at which the temperature is highest, h_min lowest)

    number_days = len(tasmax.time)

    n_hours = number_days * daily_working_hours
    h_max = 15  # set 15 as the warmest hour of the day
    h_min = 5  # set 5 as the coldest hour
    pi = math.pi
    cos = math.cos
    temp = np.zeros([n_hours, nlats, nlons])
    wbgt_out = np.zeros(
        [n_hours, nlats,
         nlons])  # array where we save the data for the heat outside hazard
    wbgt_in = np.zeros(
        [n_hours, nlats,
         nlons])  # array where we save the data for the heat inside hazard
    temp_in = np.zeros([n_hours, nlats, nlons])
    day = 0  # start at day 0
    h = day_start + 1  # the first temperature that we want to consider is at the end of the hour 8 on the first day
    # where the temperature reached 22 degress
    week_day = day  # also start at 0
    dates = np.zeros(n_hours)

    # create an array with the maximum, the minimum, the average and the amplitude of the day

    for t in range(
            n_hours
    ):  # loop over the number of working hours in a year, everyone is considered to have the same

        if week_day < 6:  # ignores 2 out of 7 days because it is the weekend, do not really correspond to real days
            # in the week

            dates[t] = Timestamp(tasmax.time.values[day]).toordinal()

            if day < (len(tasmax.tasmax.values) -
                      1):  # if day is not the last day of the dataset
                next_day = day + 1  # next days, needed to calculate the hourly temperature.
            else:
                next_day = day  # when the last day of the year is reached, we just consider that the next day
                # has the same temperature curve as itself

            if h <= working_hours[1] or h > working_hours[
                    2]:  # continue if not the midday break

                # model to give the hourly temperature based on the maximum and minimum temperature of this day,
                # as well as the min temperature of the next. Here as we removed some data, the following or next day
                # may not always be the same

                if h_min <= h < h_max:  # between 5 and 15, the last known temperature is the minimum temperature of
                    # the day at 5 and the next is the maximum which is considered to happens at 15
                    temp[t, :, :] = (
                        (tasmax.tasmax.values[day] + tasmin.tasmin.values[day])
                        / 2 -
                        (tasmax.tasmax.values[day] - tasmin.tasmin.values[day])
                        / 2 * cos(pi * (h - h_min) / (h_max - h_min)))

                if h_max <= h:  # after 15h, the next known temperature is the one of the next day
                    temp[t, :, :] = (tasmin.tasmin.values[next_day] + tasmax.tasmax.values[next_day]) \
                                    / 2 - (tasmin.tasmin.values[next_day] - tasmax.tasmax.values[day]) \
                                    / 2 * cos(pi * (h - h_max) / (h_min - h_max))
                # here we would have to add conditions if we wanted to have the temperature before 5:00 but it is not
                # needed in hour model

                if uncertainty_variable == 'hourly_temperature' or uncertainty_variable == 'all':
                    temp[t, :, :] = temp[
                        t, :, :] + error_hourly_t  # if we consider the error,
                    # the temperature is the temperature as calculate + the error for the transformation

                # in the case that the wbgt for any of the points on the map is larger then 22,
                # save the temperature transformed to a wbgt

                sun_or_shadow_functions = [
                    t_to_wbgt_sun, t_to_wbgt
                ]  # list of the two possible function for the
                # transformation to WBGT
                sun_or_shadow_sd = [sd_mean_sun, sd_mean]

                if uncertainty_variable == 'sun_or_shadow' or uncertainty_variable == 'all':
                    one_zero = np.random.choice(
                        ones_zero_random
                    )  # randomly chose if people outside are working in
                    # the sun or shadow for the current hour from the distribution set at the beginning of the file
                    sun_or_shadow = sun_or_shadow_functions[
                        one_zero]  # then take the corresponding function
                    sd = sun_or_shadow_sd[one_zero]

                else:
                    sun_or_shadow = sun_or_shadow_functions[
                        1]  # if we do not consider this uncertainty, just fix
                    # that people are protected from the sun at all times
                    sd = sun_or_shadow_sd[1]

                if uncertainty_variable == 't_to_wbgt' or uncertainty_variable == 'all':  # uncertainty from the
                    # transformation to wbgt
                    wbgt_out[t, :, :] = np.random.normal(
                        sun_or_shadow(temp[t, :, :]), sd) + error_wbgt
                else:
                    wbgt_out[t, :, :] = np.random.normal(
                        sun_or_shadow(temp[t, :, :]), sd)

                if not only_outside:  # only_outside is set when we have the adaptation measure 'efficient buildings'
                    # meaning that there is only impacts outside

                    if uncertainty_variable == 'temp_in' or uncertainty_variable == 'all':

                        temp_in[t, :, :] = temp[t, :, :] * (1 + (np.array(
                            t_diff_fit(h, *Tin_est))) * error_temp_in)
                        # transform to inside temperature to make the wbgt>22 test for inside events

                    else:  # without considering the uncertainty
                        temp_in[t, :, :] = temp[t, :, :] * (
                            1 + np.array(t_diff_fit(h, *Tin_est)))

                        # transformation to wbgt for the inside temperature:

                    if uncertainty_variable == 't_to_wbgt' or uncertainty_variable == 'all':
                        wbgt_in[t, :, :] = (np.random.normal(
                            t_to_wbgt(temp_in[t, :, :]), sd_mean)) + error_wbgt

                    else:  # without uncertainty
                        wbgt_in[t, :, :] = (np.random.normal(
                            t_to_wbgt(temp_in[t, :, :]), sd_mean))

        h = h + 1  # add +1 to the hour
        if h == day_end + 1:  # if this is the end of the day add 1 to day and go back to hour=1
            h = day_start + 1  # go back to the hour where the day starts
            day = day + 1
            week_day = week_day + 1
            if week_day == 8:  # if it is the end of the week, go back to the start
                week_day = 0

    # again, we get rid this time of the hours where the wbgt is lower than 22 everywhere:
    hours_in = np.zeros(len(wbgt_in), dtype=bool)
    hours_out = np.zeros(len(wbgt_out), dtype=bool)

    for i_ in range(len(wbgt_in)):
        hours_out[i_] = np.any(wbgt_out[i_, :, :] > 22)
        hours_in[i_] = np.any(wbgt_in[i_, :, :] > 22)

    hours_in[0] = True
    hours_out[
        0] = True  # I here set the first hour as being a hazard, whatever the real wbgt. this is because it
    # happens maybe once in a 1000 times that there are 0 hazards inside, which further leads to an error and to the
    # model to fail

    wbgt_out = wbgt_out[hours_out == True]
    wbgt_in = wbgt_in[hours_in == True]
    dates_out = dates[hours_out == True].astype('int')
    dates_in = dates[hours_in == True].astype('int')

    nevents = [len(wbgt_out),
               len(wbgt_in)]  # number of events inside and outside
    events = [range(len(wbgt_out)),
              range(len(wbgt_in))]  # number of each event
    event_dates = [dates_out, dates_in]
    wbgt_data = [wbgt_out, wbgt_in]
    hazard_types = ['heat outside', 'heat inside']

    hazards = {}

    for w_ in range(len(wbgt_data)):  # write down the events in Hazard class

        grid_x, grid_y = np.meshgrid(tasmax.lon.values, tasmax.lat.values)
        heat = Hazard('heat')
        heat.centroids.set_lat_lon(grid_y.flatten(),
                                   grid_x.flatten(),
                                   crs={'init': 'epsg:4326'})
        heat.units = 'degrees c'
        heat_data = wbgt_data[w_]
        heat_data[np.isnan(heat_data)] = 0.  # replace NAs by 0
        heat.intensity = sparse.csr_matrix(
            heat_data.reshape(nevents[w_], nlons * nlats))
        heat.event_id = np.array(events[w_])
        heat.event_name = heat.event_id
        heat.frequency = np.ones(nevents[w_])
        heat.fraction = heat.intensity.copy()
        heat.fraction.data.fill(1)
        heat.date = event_dates[w_]
        hazards[hazard_types[w_]] = heat
        heat.check()

    tasmax.close()
    tasmin.close()
    del tasmax
    del tasmin
    del wbgt_in
    del wbgt_out
    del temp_in
    del temp

    return hazards  # return the hazards