Esempio n. 1
0
def load_glacier_data(glac_no=None, rgi_regionsO1=None, rgi_regionsO2='all', rgi_glac_number='all',
                      load_caldata=0, startyear=2000, endyear=2018, option_wateryear=3):
    """
    Load glacier data (main_glac_rgi, hyps, and ice thickness)
    """
    # Load glaciers
    main_glac_rgi_all = modelsetup.selectglaciersrgitable(
            rgi_regionsO1=rgi_regionsO1, rgi_regionsO2 =rgi_regionsO2, rgi_glac_number=rgi_glac_number,  
            glac_no=glac_no)

    # Glacier hypsometry [km**2], total area
    main_glac_hyps_all = modelsetup.import_Husstable(main_glac_rgi_all, pygem_prms.hyps_filepath, pygem_prms.hyps_filedict,
                                                     pygem_prms.hyps_colsdrop)
    # Ice thickness [m], average
    main_glac_icethickness_all = modelsetup.import_Husstable(main_glac_rgi_all, pygem_prms.thickness_filepath,
                                                             pygem_prms.thickness_filedict, pygem_prms.thickness_colsdrop)
    
    # Additional processing
    main_glac_hyps_all[main_glac_icethickness_all == 0] = 0
    main_glac_hyps_all = main_glac_hyps_all.fillna(0)
    main_glac_icethickness_all = main_glac_icethickness_all.fillna(0)
    
    # Add degree groups to main_glac_rgi_all
    # Degrees
    main_glac_rgi_all['CenLon_round'] = np.floor(main_glac_rgi_all.CenLon.values/degree_size) * degree_size
    main_glac_rgi_all['CenLat_round'] = np.floor(main_glac_rgi_all.CenLat.values/degree_size) * degree_size
    deg_groups = main_glac_rgi_all.groupby(['CenLon_round', 'CenLat_round']).size().index.values.tolist()
    deg_dict = dict(zip(deg_groups, np.arange(0,len(deg_groups))))
    main_glac_rgi_all.reset_index(drop=True, inplace=True)
    cenlon_cenlat = [(main_glac_rgi_all.loc[x,'CenLon_round'], main_glac_rgi_all.loc[x,'CenLat_round']) 
                     for x in range(len(main_glac_rgi_all))]
    main_glac_rgi_all['CenLon_CenLat'] = cenlon_cenlat
    main_glac_rgi_all['deg_id'] = main_glac_rgi_all.CenLon_CenLat.map(deg_dict)
    
    if load_caldata == 1:
        cal_datasets = ['shean']
        startyear=2000
        dates_table = modelsetup.datesmodelrun(startyear=startyear, endyear=endyear, spinupyears=0, 
                                               option_wateryear=option_wateryear)
        # Calibration data
        cal_data_all = pd.DataFrame()
        for dataset in cal_datasets:
            cal_subset = class_mbdata.MBData(name=dataset)
            cal_subset_data = cal_subset.retrieve_mb(main_glac_rgi_all, main_glac_hyps_all, dates_table)
            cal_data_all = cal_data_all.append(cal_subset_data, ignore_index=True)
        cal_data_all = cal_data_all.sort_values(['glacno', 't1_idx'])
        cal_data_all.reset_index(drop=True, inplace=True)
    
    if load_caldata == 0:
        return main_glac_rgi_all, main_glac_hyps_all, main_glac_icethickness_all
    else:
        return main_glac_rgi_all, main_glac_hyps_all, main_glac_icethickness_all, cal_data_all
Esempio n. 2
0
elev_bins = main_glac_hyps.columns.values.astype(int)
# Ice thickness [m], average
main_glac_icethickness = modelsetup.import_Husstable(
    main_glac_rgi, pygem_prms.thickness_filepath,
    pygem_prms.thickness_filedict, pygem_prms.thickness_colsdrop)
main_glac_hyps[main_glac_icethickness == 0] = 0
# Width [km], average
main_glac_width = modelsetup.import_Husstable(main_glac_rgi,
                                              pygem_prms.width_filepath,
                                              pygem_prms.width_filedict,
                                              pygem_prms.width_colsdrop)
# Add volume [km**3] and mean elevation [m a.s.l.] to the main glaciers table
main_glac_rgi['Volume'], main_glac_rgi['Zmean'] = modelsetup.hypsometrystats(
    main_glac_hyps, main_glac_icethickness)
# Model time frame
dates_table = modelsetup.datesmodelrun(startyear, endyear, spinupyears)
# Quality control - if ice thickness = 0, glacier area = 0 (problem identified by glacier RGIV6-15.00016 03/06/2018)
main_glac_hyps[main_glac_icethickness == 0] = 0

#%% ===== LOAD CLIMATE DATA =====
gcm = class_climate.GCM(name=gcm_name)
if option_gcm_downscale == 1:
    # Air Temperature [degC] and GCM dates
    gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(
        gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table)
    # Precipitation [m] and GCM dates
    gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(
        gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table)
    # Elevation [m a.s.l] associated with air temperature  and precipitation data
    gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn,
                                                     main_glac_rgi)
Esempio n. 3
0
def vars_mon2annualseasonal(gcm_name):
    netcdf_fp_prefix = input.output_sim_fp + 'spc_vars/'
    vns = ['acc_glac_monthly', 'melt_glac_monthly', 'refreeze_glac_monthly', 'frontalablation_glac_monthly', 
           'massbaltotal_glac_monthly', 'temp_glac_monthly', 'prec_glac_monthly', 'runoff_glac_monthly']

    for vn in vns:
        netcdf_fp = netcdf_fp_prefix + vn + '/'
        for i in os.listdir(netcdf_fp):
            if i.endswith('.nc') and gcm_name in i:
                print(i)
                               
                # Open dataset and extract annual values
                ds = xr.open_dataset(netcdf_fp + i)      
                ds_mean = ds[vn].values[:,:,0]
                ds_std = ds[vn].values[:,:,1]
                ds_var = ds_std**2
                
                # Compute annual/seasonal mean/sum and standard deviation for the variable of interest
                if vn is 'temp_glac_monthly':
                    output_list = ['annual']
                    # Mean annual temperature, standard deviation, and variance
                    ds_mean_annual = ds_mean.reshape(-1,12).mean(axis=1).reshape(-1,int(ds_mean.shape[1]/12))
                    ds_var_annual = ds_var.reshape(-1,12).mean(axis=1).reshape(-1,int(ds_std.shape[1]/12))
                    ds_std_annual = ds_var_annual**0.5
                    ds_values_annual = np.concatenate((ds_mean_annual[:,:,np.newaxis], ds_std_annual[:,:,np.newaxis]), 
                                                      axis=2)
                elif vn in ['prec_glac_monthly', 'runoff_glac_monthly']:
                    output_list = ['annual']
                    # Total annual precipitation, standard deviation, and variance
                    ds_sum_annual = ds_mean.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_mean.shape[1]/12))
                    ds_var_annual = ds_var.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_std.shape[1]/12))
                    ds_std_annual = ds_var_annual**0.5
                    ds_values_annual = np.concatenate((ds_sum_annual[:,:,np.newaxis], ds_std_annual[:,:,np.newaxis]), 
                                                      axis=2)
                elif vn in ['acc_glac_monthly', 'melt_glac_monthly', 'refreeze_glac_monthly', 
                            'frontalablation_glac_monthly', 'massbaltotal_glac_monthly']:
                    output_list = ['annual', 'summer', 'winter']
                    # Annual total, standard deviation, and variance
                    ds_sum_annual = ds_mean.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_mean.shape[1]/12))
                    ds_var_annual = ds_var.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_std.shape[1]/12))
                    ds_std_annual = ds_var_annual**0.5
                    ds_values_annual = np.concatenate((ds_sum_annual[:,:,np.newaxis], ds_std_annual[:,:,np.newaxis]), 
                                                      axis=2)
                    # Seasonal total, standard deviation, and variance
                    if ds.time.year_type == 'water year':
                        option_wateryear = 1
                    elif ds.time.year_type == 'calendar year':
                        option_wateryear = 2
                    else:
                        option_wateryear = 3
                    
                    print('CHANGE BACK OPTION WATER YEAR HERE - DUE TO MANUAL ERROR')
                    option_wateryear=input.gcm_wateryear
                    
                    dates_table = modelsetup.datesmodelrun(startyear=ds.year.values[0], endyear=ds.year.values[-1], 
                                                           spinupyears=0, option_wateryear=option_wateryear)
                    
                    # For seasonal calculations copy monthly values and remove the other season's values
                    ds_mean_summer = ds_mean.copy()
                    ds_var_summer = ds_var.copy()                    
                    ds_mean_summer[:,dates_table.season.values == 'winter'] = 0
                    ds_sum_summer = ds_mean_summer.reshape(-1,12).sum(axis=1).reshape(-1, int(ds_mean.shape[1]/12))
                    ds_var_summer = ds_var_summer.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_std.shape[1]/12))
                    ds_std_summer = ds_var_summer**0.5
                    ds_values_summer = np.concatenate((ds_sum_summer[:,:,np.newaxis], ds_std_summer[:,:,np.newaxis]), 
                                                      axis=2)
                    ds_mean_winter = ds_mean.copy()
                    ds_var_winter = ds_var.copy()                    
                    ds_mean_winter[:,dates_table.season.values == 'summer'] = 0
                    ds_sum_winter = ds_mean_winter.reshape(-1,12).sum(axis=1).reshape(-1, int(ds_mean.shape[1]/12))
                    ds_var_winter = ds_var_winter.reshape(-1,12).sum(axis=1).reshape(-1,int(ds_std.shape[1]/12))
                    ds_std_winter = ds_var_winter**0.5
                    ds_values_winter = np.concatenate((ds_sum_winter[:,:,np.newaxis], ds_std_winter[:,:,np.newaxis]), 
                                                      axis=2)
                # Create modified dataset
                for temporal_res in output_list:
                    vn_new = vn.split('_')[0] + '_glac_' + temporal_res
                    output_fp = netcdf_fp_prefix + vn_new + '/'
                    output_fn = i.split('.nc')[0][:-7] + temporal_res + '.nc'                
                    output_coords_dict, output_attrs_dict, encoding = coords_attrs_dict(ds, vn_new)
                    if temporal_res is 'annual':
                        ds_new = xr.Dataset({vn_new: (list(output_coords_dict[vn_new].keys()), ds_values_annual)},
                                             coords=output_coords_dict[vn_new])
                    elif temporal_res is 'summer':
                        ds_new = xr.Dataset({vn_new: (list(output_coords_dict[vn_new].keys()), ds_values_summer)},
                                             coords=output_coords_dict[vn_new])
                    elif temporal_res is 'winter':
                        ds_new = xr.Dataset({vn_new: (list(output_coords_dict[vn_new].keys()), ds_values_winter)},
                                             coords=output_coords_dict[vn_new])
                    ds_new[vn_new].attrs = output_attrs_dict[vn_new]
                    # Merge new dataset into the old to retain glacier table and other attributes
                    output_ds = xr.merge((ds, ds_new))
                    output_ds = output_ds.drop(vn)
                    # Export netcdf
                    if not os.path.exists(output_fp):
                        os.makedirs(output_fp)
                    output_ds.to_netcdf(output_fp + output_fn, encoding=encoding)
Esempio n. 4
0
def load_masschange_monthly(regions,
                            ds_ending,
                            netcdf_fp=sim_netcdf_fp,
                            option_add_caldata=0):
    """ Load monthly mass change data """
    count = 0
    for region in regions:
        count += 1

        # Load datasets
        ds_fn = 'R' + str(region) + ds_ending
        ds = xr.open_dataset(netcdf_fp + ds_fn)

        main_glac_rgi_region_ds = pd.DataFrame(ds.glacier_table.values,
                                               columns=ds.glac_attrs)
        glac_wide_massbaltotal_region = ds.massbaltotal_glac_monthly.values[:, :,
                                                                            0]
        glac_wide_area_annual_region = ds.area_glac_annual.values[:, :, 0]
        time_values = pd.Series(
            ds.massbaltotal_glac_monthly.coords['time'].values)

        # ===== GLACIER DATA =====
        main_glac_rgi_region = modelsetup.selectglaciersrgitable(
            rgi_regionsO1=[region], rgi_regionsO2='all', rgi_glac_number='all')
        if (main_glac_rgi_region['glacno'] -
                main_glac_rgi_region_ds['glacno']).sum() == 0:
            print('Region', str(region), ': number of glaciers match')
        # Glacier hypsometry
        main_glac_hyps_region = modelsetup.import_Husstable(
            main_glac_rgi_region, pygem_prms.hyps_filepath,
            pygem_prms.hyps_filedict, pygem_prms.hyps_colsdrop)
        # Ice thickness [m], average
        main_glac_icethickness_region = modelsetup.import_Husstable(
            main_glac_rgi_region, input.thickness_filepath,
            input.thickness_filedict, input.thickness_colsdrop)
        main_glac_hyps_region[main_glac_icethickness_region == 0] = 0
        # ===== CALIBRATION DATA =====
        if option_add_caldata == 1:
            dates_table_nospinup = modelsetup.datesmodelrun(
                startyear=input.startyear,
                endyear=input.endyear,
                spinupyears=0)
            cal_data_region = pd.DataFrame()
            for dataset in cal_datasets:
                cal_subset = class_mbdata.MBData(name=dataset)
                cal_subset_data = cal_subset.retrieve_mb(
                    main_glac_rgi_region, main_glac_hyps_region,
                    dates_table_nospinup)
                cal_data_region = cal_data_region.append(cal_subset_data,
                                                         ignore_index=True)
            cal_data_region = cal_data_region.sort_values(['glacno', 't1_idx'])
            cal_data_region.reset_index(drop=True, inplace=True)

        # ===== APPEND DATASETS =====
        if count == 1:
            main_glac_rgi = main_glac_rgi_region
            main_glac_hyps = main_glac_hyps_region
            main_glac_icethickness = main_glac_icethickness_region
            glac_wide_massbaltotal = glac_wide_massbaltotal_region
            glac_wide_area_annual = glac_wide_area_annual_region

            if option_add_caldata == 1:
                cal_data = cal_data_region

        else:
            main_glac_rgi = main_glac_rgi.append(main_glac_rgi_region)

            glac_wide_massbaltotal = np.concatenate(
                [glac_wide_massbaltotal, glac_wide_massbaltotal_region])
            glac_wide_area_annual = np.concatenate(
                [glac_wide_area_annual, glac_wide_area_annual_region])

            if option_add_caldata == 1:
                cal_data = cal_data.append(cal_data_region)

            # If more columns in region, then need to expand existing dataset
            if main_glac_hyps_region.shape[1] > main_glac_hyps.shape[1]:
                all_col = list(main_glac_hyps.columns.values)
                reg_col = list(main_glac_hyps_region.columns.values)
                new_cols = [item for item in reg_col if item not in all_col]
                for new_col in new_cols:
                    main_glac_hyps[new_col] = 0
                    main_glac_icethickness[new_col] = 0
            elif main_glac_hyps_region.shape[1] < main_glac_hyps.shape[1]:
                all_col = list(main_glac_hyps.columns.values)
                reg_col = list(main_glac_hyps_region.columns.values)
                new_cols = [item for item in all_col if item not in reg_col]
                for new_col in new_cols:
                    main_glac_hyps_region[new_col] = 0
                    main_glac_icethickness_region[new_col] = 0
            main_glac_hyps = main_glac_hyps.append(main_glac_hyps_region)
            main_glac_icethickness = main_glac_icethickness.append(
                main_glac_icethickness_region)

    # reset index
    main_glac_rgi.reset_index(inplace=True, drop=True)
    main_glac_hyps.reset_index(inplace=True, drop=True)
    main_glac_icethickness.reset_index(inplace=True, drop=True)
    if option_add_caldata == 1:
        cal_data.reset_index(inplace=True, drop=True)

    # Volume [km**3] and mean elevation [m a.s.l.]
    main_glac_rgi['Volume'], main_glac_rgi[
        'Zmean'] = modelsetup.hypsometrystats(main_glac_hyps,
                                              main_glac_icethickness)

    # ===== MASS CHANGE CALCULATIONS =====
    # Compute glacier volume change for every time step and use this to compute mass balance
    glac_wide_area = np.repeat(glac_wide_area_annual[:, :-1], 12, axis=1)

    # Mass change [km3 mwe]
    #  mb [mwea] * (1 km / 1000 m) * area [km2]
    glac_wide_masschange = glac_wide_massbaltotal / 1000 * glac_wide_area

    if option_add_caldata == 1:
        return main_glac_rgi, glac_wide_masschange, glac_wide_area, time_values, cal_data
    else:
        return main_glac_rgi, glac_wide_masschange, glac_wide_area, time_values
Esempio n. 5
0
gcm_list = ['CSIRO-Mk3-6-0', 'CNRM-CM5', 'GISS-E2-R', 'GFDL-ESM2M', 'CCSM4', 'MPI-ESM-LR', 'NorESM1-M', 'CanESM2', 'GFDL-CM3', 'IPSL-CM5A-LR']

#gcm_list = ['CanESM2']

rcp_list = ['rcp26', 'rcp45', 'rcp85']
RCP_list = ['RCP 2.6', 'RCP 4.5', 'RCP 8.5']

fig, ax = plt.subplots(2, 3, squeeze=False, sharex='col', sharey='row', 
             gridspec_kw = {'wspace':0.1, 'hspace':0.15})

for j in range(len(rcp_list)):
    for i in range(len(gcm_list)):
        gcm = class_climate.GCM(name=gcm_list[i], rcp_scenario=rcp_list[j])
        main_glac_rgi = modelsetup.selectglaciersrgitable(rgi_regionsO1=input.rgi_regionsO1, rgi_regionsO2 = 'all',
                                                      rgi_glac_number = 'all')
        dates_table = modelsetup.datesmodelrun(startyear=2000, endyear=2100, spinupyears=0)
        time = np.linspace(2000, 2100, 101, dtype=int)
        
        gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table)
        gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table)
        
        gcm_temp_annual = pygemfxns.annual_avg_2darray(gcm_temp)
        gcm_prec_annual = pygemfxns.annual_sum_2darray(gcm_prec)
        
        x_values = time
        y_values = gcm_temp_annual[0]
        y2_values = gcm_prec_annual[0]
        
        ax[0,j].xaxis.set_tick_params(labelsize=20)
        ax[0,j].xaxis.set_major_locator(plt.MultipleLocator(40))
        ax[0,j].xaxis.set_minor_locator(plt.MultipleLocator(5))
Esempio n. 6
0
def main(list_packed_vars):
    """
    Climate data bias adjustment
    
    Parameters
    ----------
    list_packed_vars : list
        list of packed variables that enable the use of parallels
        
    Returns
    -------
    csv files of bias adjustment output
        The bias adjustment parameters are output instead of the actual temperature and precipitation to reduce file
        sizes.  Additionally, using the bias adjustment will cause the GCM climate data to use the reference elevation
        since the adjustments were made from the GCM climate data to be consistent with the reference dataset.
    """
    # Unpack variables    
    count = list_packed_vars[0]
    chunk = list_packed_vars[1]
    main_glac_rgi_all = list_packed_vars[2]
    chunk_size = list_packed_vars[3]
    gcm_name = list_packed_vars[4]

    time_start = time.time()
    parser = getparser()
    args = parser.parse_args()
    
    if (gcm_name != pygem_prms.ref_gcm_name) and (args.rcp is None):
        rcp_scenario = os.path.basename(args.gcm_list_fn).split('_')[1]
    elif args.rcp is not None:
        rcp_scenario = args.rcp
#    rcp_scenario = os.path.basename(args.gcm_file).split('_')[1]

    # ===== LOAD OTHER GLACIER DATA =====
    main_glac_rgi = main_glac_rgi_all.iloc[chunk:chunk + chunk_size, :]
    # Glacier hypsometry [km**2], total area
    main_glac_hyps = modelsetup.import_Husstable(main_glac_rgi, pygem_prms.hyps_filepath,
                                                 pygem_prms.hyps_filedict, pygem_prms.hyps_colsdrop)
    # Ice thickness [m], average
    main_glac_icethickness = modelsetup.import_Husstable(main_glac_rgi, pygem_prms.thickness_filepath,
                                                         pygem_prms.thickness_filedict, pygem_prms.thickness_colsdrop)
    main_glac_hyps[main_glac_icethickness == 0] = 0
    # Width [km], average
    main_glac_width = modelsetup.import_Husstable(main_glac_rgi, pygem_prms.width_filepath,
                                                  pygem_prms.width_filedict, pygem_prms.width_colsdrop)
    elev_bins = main_glac_hyps.columns.values.astype(int)

    # Select dates including future projections
    # If reference climate data starts or ends before or after the GCM data, then adjust reference climate data such
    # that the reference and GCM span the same period of time.
    if pygem_prms.startyear >= pygem_prms.gcm_startyear:
        ref_startyear = pygem_prms.startyear
    else:
        ref_startyear = pygem_prms.gcm_startyear
    if pygem_prms.endyear <= pygem_prms.gcm_endyear:
        ref_endyear = pygem_prms.endyear
    else:
        ref_endyear = pygem_prms.gcm_endyear
    dates_table_ref = modelsetup.datesmodelrun(startyear=ref_startyear, endyear=ref_endyear, 
                                               spinupyears=pygem_prms.ref_spinupyears, 
                                               option_wateryear=pygem_prms.ref_wateryear)
    dates_table = modelsetup.datesmodelrun(startyear=pygem_prms.gcm_startyear, endyear=pygem_prms.gcm_endyear, 
                                           spinupyears=pygem_prms.gcm_spinupyears, 
                                           option_wateryear=pygem_prms.gcm_wateryear)

    # ===== LOAD CLIMATE DATA =====
    # Reference climate data
    ref_gcm = class_climate.GCM(name=pygem_prms.ref_gcm_name)
    # Air temperature [degC], Precipitation [m], Elevation [masl], Lapse rate [K m-1]
    ref_temp, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.temp_fn, ref_gcm.temp_vn, main_glac_rgi, 
                                                                     dates_table_ref)
    ref_prec, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.prec_fn, ref_gcm.prec_vn, main_glac_rgi, 
                                                                     dates_table_ref)
    ref_elev = ref_gcm.importGCMfxnearestneighbor_xarray(ref_gcm.elev_fn, ref_gcm.elev_vn, main_glac_rgi)
    ref_lr, ref_dates = ref_gcm.importGCMvarnearestneighbor_xarray(ref_gcm.lr_fn, ref_gcm.lr_vn, main_glac_rgi, 
                                                                   dates_table_ref)
    ref_lr_monthly_avg = (ref_lr.reshape(-1,12).transpose().reshape(-1,int(ref_temp.shape[1]/12)).mean(1)
                          .reshape(12,-1).transpose())
    
    # GCM climate data
    if gcm_name == 'ERA-Interim' or gcm_name == 'COAWST':
        gcm = class_climate.GCM(name=gcm_name)
    else:
        gcm = class_climate.GCM(name=gcm_name, rcp_scenario=rcp_scenario)
    # Air temperature [degC], Precipitation [m], Elevation [masl], Lapse rate [K m-1]
    gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table)
    gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table)
    gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn, main_glac_rgi)
    if gcm_name == 'ERA-Interim':
        gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table)
    else:
        gcm_lr = monthly_avg_array_rolled(ref_lr, dates_table_ref, dates_table)

    # COAWST data has two domains, so need to merge the two domains
    if gcm_name == 'COAWST':
        gcm_temp_d01, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.temp_fn_d01, gcm.temp_vn, main_glac_rgi, 
                                                                         dates_table)
        gcm_prec_d01, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(gcm.prec_fn_d01, gcm.prec_vn, main_glac_rgi, 
                                                                         dates_table)
        gcm_elev_d01 = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn_d01, gcm.elev_vn, main_glac_rgi)
        # Check if glacier outside of high-res (d02) domain
        for glac in range(main_glac_rgi.shape[0]):
            glac_lat = main_glac_rgi.loc[glac,pygem_prms.rgi_lat_colname]
            glac_lon = main_glac_rgi.loc[glac,pygem_prms.rgi_lon_colname]
            if (~(pygem_prms.coawst_d02_lat_min <= glac_lat <= pygem_prms.coawst_d02_lat_max) or 
                ~(pygem_prms.coawst_d02_lon_min <= glac_lon <= pygem_prms.coawst_d02_lon_max)):
                gcm_prec[glac,:] = gcm_prec_d01[glac,:]
                gcm_temp[glac,:] = gcm_temp_d01[glac,:]
                gcm_elev[glac] = gcm_elev_d01[glac]

    #%% ===== BIAS CORRECTIONS =====     
    # OPTION 1: Adjust temp and prec similar to Huss and Hock (2015) but limit maximum precipitation
    #  - temperature accounts for means and interannual variability
    #  - precipitation corrects
    if pygem_prms.option_bias_adjustment == 1:
        # Temperature bias correction
        gcm_temp_biasadj, gcm_elev_biasadj = temp_biasadj_HH2015(ref_temp, ref_elev, gcm_temp, dates_table_ref, 
                                                                 dates_table)
        # Precipitation bias correction
        gcm_prec_biasadj, gcm_elev_biasadj = prec_biasadj_opt1(ref_prec, ref_elev, gcm_prec, dates_table_ref, 
                                                               dates_table)
    
    # OPTION 2: Adjust temp and prec according to Huss and Hock (2015) accounts for means and interannual variability
    elif pygem_prms.option_bias_adjustment == 2:
        # Temperature bias correction
        gcm_temp_biasadj, gcm_elev_biasadj = temp_biasadj_HH2015(ref_temp, ref_elev, gcm_temp, dates_table_ref, 
                                                                 dates_table)
        # Precipitation bias correction
        gcm_prec_biasadj, gcm_elev_biasadj = prec_biasadj_HH2015(ref_prec, ref_elev, gcm_prec, dates_table_ref, 
                                                                 dates_table)
 
    if gcm_prec_biasadj.max() > 10:
        print('precipitation bias too high, needs to be modified')
        print(np.where(gcm_prec_biasadj > 10))
    elif gcm_prec_biasadj.min() < 0:
        print('Negative precipitation value')
        print(np.where(gcm_prec_biasadj < 0))
        
    #%% PLOT BIAS ADJUSTED DATA
    if option_plot_adj:
        print('plotting')
        plot_biasadj(ref_temp, gcm_temp_biasadj, ref_prec, gcm_prec, gcm_prec_biasadj, dates_table_ref, dates_table)

    #%% Export variables as global to view in variable explorer
    if args.option_parallels == 0:
        global main_vars
        main_vars = inspect.currentframe().f_locals

    print('\nProcessing time of', gcm_name, 'for', count,':',time.time()-time_start, 's')
def main(list_packed_vars):
    """
    Model calibration

    Parameters
    ----------
    list_packed_vars : list
        list of packed variables that enable the use of parallels

    Returns
    -------
    netcdf files of the calibration output
        Depending on the calibration scheme additional output may be exported as well
    """
    #%%
    # Unpack variables
    main_glac_rgi = list_packed_vars[0]
    gcm_name = list_packed_vars[1]

    time_start = time.time()
    parser = getparser()
    args = parser.parse_args()

    if args.debug == 1:
        debug = True
    else:
        debug = False

    # ===== MASS BALANCE DATA AND DATES TABLE =====
    data_source = 'regional'
    #    data_source = 'individual_glaciers'

    if data_source in ['individual_glaciers']:
        dates_table = modelsetup.datesmodelrun(startyear=2000,
                                               endyear=2018,
                                               spinupyears=0)
        mb_shean_fullfn = pygem_prms.shean_fp + pygem_prms.shean_fn
        mb_shean_df = pd.read_csv(mb_shean_fullfn)
        mb_shean_df['RGIId'] = [
            'RGI60-' + str(int(x)) + '.' +
            str(int(np.round((x - int(x)) * 1e5, 0))).zfill(5)
            for x in mb_shean_df.RGIId.values
        ]
    elif data_source in ['regional']:
        dates_table = modelsetup.datesmodelrun(startyear=2006,
                                               endyear=2015,
                                               spinupyears=0)
        roi_mbobs_dict = {
            '01': [-0.70, 0.18],
            '02': [-0.50, 0.91],
            '03': [-0.38, 0.80],
            '04': [-0.80, 0.22],
            '05': [-0.57, 0.20],
            '06': [-0.69, 0.26],
            '07': [-0.27, 0.17],
            '08': [-0.66, 0.27],
            '09': [-0.30, 0.27],
            '10': [-0.40, 0.31],
            '11': [-0.91, 0.70],
            '12': [-0.88, 0.57],
            '13': [-0.19, 0.15],
            '14': [-0.11, 0.15],
            '15': [-0.44, 0.15],
            '16': [-0.59, 0.58],
            '17': [-0.86, 0.17],
            '18': [-0.59, 1.14]
        }

    # ===== LOAD CLIMATE DATA =====
    gcm = class_climate.GCM(name=gcm_name)
    # Air temperature [degC], Air temperature Std [K], Precipitation [m], Elevation [masl], Lapse rate [K m-1]
    gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(
        gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table)
    gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(
        gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table)
    gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn,
                                                     main_glac_rgi)
    # Air temperature standard deviation [K]
    if pygem_prms.option_ablation != 2 or gcm_name not in ['ERA5']:
        gcm_tempstd = np.zeros(gcm_temp.shape)
    elif gcm_name in ['ERA5']:
        gcm_tempstd, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(
            gcm.tempstd_fn, gcm.tempstd_vn, main_glac_rgi, dates_table)
    # Lapse rate [K m-1]
    if gcm_name in ['ERA-Interim', 'ERA5']:
        gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(
            gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table)
    else:
        # Mean monthly lapse rate
        ref_lr_monthly_avg = np.genfromtxt(gcm.lr_fp + gcm.lr_fn,
                                           delimiter=',')
        gcm_lr = np.tile(ref_lr_monthly_avg, int(gcm_temp.shape[1] / 12))

    # Huss and Hock (2015) parameters and bounds
    tempchange_init = 0
    tempchange_bndlow = -10
    tempchange_bndhigh = 10
    precfactor_init = 1.5
    precfactor_bndlow = 0.8
    precfactor_bndhigh = 2
    ddfsnow_init = 0.003
    ddfsnow_bndlow = 0.00175
    ddfsnow_bndhigh = 0.0045
    ddfsnow_iceratio = 0.5

    # Area change rate dictionary to account for clean ice retreat scenario
    area_chg_rate_dict = {
        '01': [-0.42, 0.23],
        '02': [-0.54, 0.24],
        '03': [-0.07, 0.03],
        '04': [-0.08, 0.05],
        '05': [-0.18, 0.23],
        '06': [-0.58, 0.23],
        '07': [-0.26, 0.23],
        '08': [-0.18, 0.11],
        '09': [-0.18, 0.23],
        '10': [-0.52, 0.67],
        '11': [-0.93, 0.47],
        '12': [-0.18, 0.23],
        '13': [-0.18, 0.17],
        '14': [-0.36, 0.08],
        '15': [-0.47, 0.13],
        '16': [-1.19, 0.54],
        '17': [-0.20, 0.08],
        '18': [-0.69, 0.23]
    }

    for nglac, rgiid in enumerate(main_glac_rgi.rgino_str):
        if debug:
            print(nglac, rgiid)

        # ===== LOAD GLACIER DATA =====
        binnedcsv = pd.read_csv(main_glac_rgi.loc[nglac, 'binned_fullfn'])

        if prescribe_retreat:
            roi = rgiid.split('.')[0].zfill(2)
            dc_perc_min = area_chg_rate_dict[roi][0] * (
                main_glac_rgi.loc[nglac, 'RefYear'] - 2015)
            binnedcsv['area_cumsum_%'] = (
                np.cumsum(binnedcsv.z1_bin_area_valid_km2) /
                binnedcsv.z1_bin_area_valid_km2.sum() * 100)
            binnedcsv = binnedcsv[
                binnedcsv['area_cumsum_%'] > dc_perc_min].copy()
            binnedcsv.reset_index(inplace=True, drop=True)

        # Elevation bin statistics
        elev_bins = binnedcsv['bin_center_elev_m'].values
        bins_area = binnedcsv['z1_bin_area_valid_km2'].values

        main_glac_rgi['Zmed'] = weighted_percentile(elev_bins, bins_area, 0.5)
        main_glac_rgi['Zmin'] = elev_bins.min()
        main_glac_rgi['Zmax'] = elev_bins.max()

        # Set model parameters
        modelparameters = [
            pygem_prms.lrgcm, pygem_prms.lrglac, precfactor_init,
            pygem_prms.precgrad, ddfsnow_init, ddfsnow_init / ddfsnow_iceratio,
            pygem_prms.tempsnow, tempchange_init
        ]

        # Select subsets of data
        glacier_rgi_table = main_glac_rgi.loc[
            main_glac_rgi.index.values[nglac], :]
        glacier_gcm_elev = gcm_elev[nglac]
        glacier_gcm_prec = gcm_prec[nglac, :]
        glacier_gcm_temp = gcm_temp[nglac, :]
        glacier_gcm_tempstd = gcm_tempstd[nglac, :]
        glacier_gcm_lrgcm = gcm_lr[nglac, :]
        glacier_gcm_lrglac = glacier_gcm_lrgcm.copy()
        glacier_area_initial = binnedcsv['z1_bin_area_valid_km2'].values
        icethickness_initial = binnedcsv['H_mean']
        glacier_debrismf = binnedcsv[mf_cn].values

        # Glacier widths (from OGGM)
        oggm_widths_fp = (pygem_prms.main_directory + '/../oggm_widths/' +
                          main_glac_rgi.loc[nglac, 'RGIId'].split('.')[0] +
                          '/')
        widths_fn = main_glac_rgi.loc[nglac, 'RGIId'] + '_widths_m.csv'
        try:
            # Add width (km) to each elevation bin
            widths_df = pd.read_csv(oggm_widths_fp + widths_fn)
            elev_nearidx = (np.abs(
                np.array(elev_bins)[:, np.newaxis] -
                widths_df['elev'].values).argmin(axis=1))
            width_initial = widths_df.loc[elev_nearidx,
                                          'width_m'].values / 1000
        except:
            width_initial = np.zeros(glacier_area_initial.shape[0])

        # Mass balance data
        if data_source in ['individual_glaciers']:
            assert glacier_rgi_table.O1Region in [
                13, 14, 15
            ], 'Individual mb data not available'
            mb_shean_idx = np.where(
                glacier_rgi_table.RGIId == mb_shean_df.RGIId.values)[0][0]
            observed_massbal = mb_shean_df.loc[mb_shean_idx, 'mb_mwea']
            observed_massbal_std = mb_shean_df.loc[mb_shean_idx,
                                                   'mb_mwea_sigma']
        elif data_source in ['regional']:
            observed_massbal = roi_mbobs_dict[str(
                glacier_rgi_table.O1Region).zfill(2)][0]
            observed_massbal_std = roi_mbobs_dict[str(
                glacier_rgi_table.O1Region).zfill(2)][1]

        t1_idx = 0
        t2_idx = dates_table.shape[0]

        if debug:
            print('obs_mwea:', np.round(observed_massbal, 2), '+/-',
                  np.round(observed_massbal_std, 2))

#        #%%
##        dates_table = dates_table.loc[0:11,:]
##        glacier_gcm_temp = glacier_gcm_temp[0:12]
##        glacier_gcm_tempstd = glacier_gcm_tempstd[0:12]
##        glacier_gcm_prec = glacier_gcm_prec[0:12]
##        glacier_gcm_lrgcm = glacier_gcm_lrgcm[0:12]
##        glacier_gcm_lrglac = glacier_gcm_lrglac[0:12]
#        option_areaconstant = 1
#        (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze, glac_bin_snowpack, glac_bin_melt,
#         glac_bin_frontalablation, glac_bin_massbalclim, glac_bin_massbalclim_annual, glac_bin_area_annual,
#         glac_bin_icethickness_annual, glac_bin_width_annual, glac_bin_surfacetype_annual,
#         glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline, glac_wide_snowpack,
#         glac_wide_area_annual, glac_wide_volume_annual, glac_wide_ELA_annual, offglac_wide_prec,
#         offglac_wide_refreeze, offglac_wide_melt, offglac_wide_snowpack, offglac_wide_runoff) = (
#            massbalance.runmassbalance(modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial,
#                                       width_initial, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec,
#                                       glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table,
#                                       option_areaconstant=option_areaconstant, glacier_debrismf=glacier_debrismf,
#                                       debug=True))
#
#        # Compute glacier volume change for every time step and use this to compute mass balance
#        glac_wide_area = glac_wide_area_annual[:-1].repeat(12)
#        # Mass change [km3 mwe]
#        #  mb [mwea] * (1 km / 1000 m) * area [km2]
#        glac_wide_masschange = glac_wide_massbaltotal[t1_idx:t2_idx+1] / 1000 * glac_wide_area[t1_idx:t2_idx+1]
#        # Mean annual mass balance [mwea]
#        mb_mwea = (glac_wide_masschange.sum() / glac_wide_area[0] * 1000 / (glac_wide_masschange.shape[0] / 12))
#
##        mb_mwea = mb_mwea_calc(modelparameters, glacier_rgi_table, glacier_area_initial, icethickness_initial,
##                               width_initial, elev_bins, glacier_gcm_temp, glacier_gcm_tempstd, glacier_gcm_prec,
##                               glacier_gcm_elev, glacier_gcm_lrgcm, glacier_gcm_lrglac, dates_table, t1_idx, t2_idx,
##                               option_areaconstant=1, glacier_debrismf=glacier_debrismf)
#        print(np.round(mb_mwea,2))

#%%
# Huss and Hock (2015) model calibration steps
        if pygem_prms.option_calibration == 3:

            def objective(modelparameters_subset):
                """ Objective function for mass balance data.
                
                Parameters
                ----------
                modelparameters_subset : list of model parameters to calibrate
                    [precipitation factor, precipitation gradient, degree-day factor of snow, temperature bias]
                    
                Returns
                -------
                mb_dif_mwea : difference in modeled vs observed mass balance [mwea]
                """
                # Use a subset of model parameters to reduce number of constraints required
                modelparameters[2] = modelparameters_subset[0]
                modelparameters[3] = modelparameters_subset[1]
                modelparameters[4] = modelparameters_subset[2]
                modelparameters[5] = modelparameters[4] / ddfsnow_iceratio
                modelparameters[7] = modelparameters_subset[3]
                mb_mwea = mb_mwea_calc(modelparameters,
                                       glacier_rgi_table,
                                       glacier_area_initial,
                                       icethickness_initial,
                                       width_initial,
                                       elev_bins,
                                       glacier_gcm_temp,
                                       glacier_gcm_tempstd,
                                       glacier_gcm_prec,
                                       glacier_gcm_elev,
                                       glacier_gcm_lrgcm,
                                       glacier_gcm_lrglac,
                                       dates_table,
                                       t1_idx,
                                       t2_idx,
                                       option_areaconstant=1,
                                       glacier_debrismf=glacier_debrismf)
                # Differnece [mwea] = Observed mass balance [mwea] - mb_mwea
                mb_dif_mwea_abs = abs(observed_massbal - mb_mwea)
                return mb_dif_mwea_abs

        def run_objective(modelparameters_init,
                          observed_massbal,
                          precfactor_bnds=(0.33, 3),
                          tempchange_bnds=(-10, 10),
                          ddfsnow_bnds=(0.0026, 0.0056),
                          precgrad_bnds=(0.0001, 0.0001),
                          run_opt=True,
                          ftol_opt=pygem_prms.ftol_opt):
            """ Run the optimization for the single glacier objective function.
            
            Parameters
            ----------
            modelparams_init : list
                List of model parameters to calibrate
                [precipitation factor, precipitation gradient, degree day factor of snow, temperature change]
            precfactor_bnds, tempchange_bnds, ddfsnow_bnds, precgrad_bnds : tuples
                Lower and upper bounds for various model parameters
            run_opt : boolean
                Boolean statement allowing one to bypass the optimization and run through with initial parameters
                (default is True - run the optimization)
                
            Returns
            -------
            modelparams : list of model parameters
            mb_mwea : optimized modeled mass balance (mwea)
            """
            # Bounds
            modelparameters_bnds = (precfactor_bnds, precgrad_bnds,
                                    ddfsnow_bnds, tempchange_bnds)
            # Run the optimization
            #  'L-BFGS-B' - much slower
            #  'SLSQP' did not work for some geodetic measurements using the sum_abs_zscore.  One work around was to
            #    divide the sum_abs_zscore by 1000, which made it work in all cases.  However, methods were switched
            #    to 'L-BFGS-B', which may be slower, but is still effective.
            # note: switch enables running through with given parameters
            if run_opt:
                modelparameters_opt = minimize(objective,
                                               modelparameters_init,
                                               method=pygem_prms.method_opt,
                                               bounds=modelparameters_bnds,
                                               options={'ftol': ftol_opt})
                # Record the optimized parameters
                modelparameters_subset = modelparameters_opt.x
            else:
                modelparameters_subset = modelparameters_init.copy()
            modelparams = ([
                modelparameters[0], modelparameters[1],
                modelparameters_subset[0], modelparameters_subset[1],
                modelparameters_subset[2],
                modelparameters_subset[2] / ddfsnow_iceratio,
                modelparameters[6], modelparameters_subset[3]
            ])
            # Re-run the optimized parameters in order to see the mass balance
            mb_mwea = mb_mwea_calc(modelparameters,
                                   glacier_rgi_table,
                                   glacier_area_initial,
                                   icethickness_initial,
                                   width_initial,
                                   elev_bins,
                                   glacier_gcm_temp,
                                   glacier_gcm_tempstd,
                                   glacier_gcm_prec,
                                   glacier_gcm_elev,
                                   glacier_gcm_lrgcm,
                                   glacier_gcm_lrglac,
                                   dates_table,
                                   t1_idx,
                                   t2_idx,
                                   option_areaconstant=1,
                                   glacier_debrismf=glacier_debrismf)
            return modelparams, mb_mwea

        continue_param_search = True
        # ===== ROUND 1: PRECIPITATION FACTOR ======
        if debug:
            print('Round 1:')
        # Lower bound
        modelparameters[2] = precfactor_bndlow
        mb_mwea_kp_low = mb_mwea_calc(modelparameters,
                                      glacier_rgi_table,
                                      glacier_area_initial,
                                      icethickness_initial,
                                      width_initial,
                                      elev_bins,
                                      glacier_gcm_temp,
                                      glacier_gcm_tempstd,
                                      glacier_gcm_prec,
                                      glacier_gcm_elev,
                                      glacier_gcm_lrgcm,
                                      glacier_gcm_lrglac,
                                      dates_table,
                                      t1_idx,
                                      t2_idx,
                                      option_areaconstant=1,
                                      glacier_debrismf=glacier_debrismf)
        # Upper bound
        modelparameters[2] = precfactor_bndhigh
        mb_mwea_kp_high = mb_mwea_calc(modelparameters,
                                       glacier_rgi_table,
                                       glacier_area_initial,
                                       icethickness_initial,
                                       width_initial,
                                       elev_bins,
                                       glacier_gcm_temp,
                                       glacier_gcm_tempstd,
                                       glacier_gcm_prec,
                                       glacier_gcm_elev,
                                       glacier_gcm_lrgcm,
                                       glacier_gcm_lrglac,
                                       dates_table,
                                       t1_idx,
                                       t2_idx,
                                       option_areaconstant=1,
                                       glacier_debrismf=glacier_debrismf)
        # Optimimum precipitation factor
        if observed_massbal < mb_mwea_kp_low:
            precfactor_opt = precfactor_bndlow
            mb_mwea = mb_mwea_kp_low
        elif observed_massbal > mb_mwea_kp_high:
            precfactor_opt = precfactor_bndhigh
            mb_mwea = mb_mwea_kp_high
        else:
            modelparameters[2] = precfactor_init
            modelparameters_subset = [
                modelparameters[2], modelparameters[3], modelparameters[4],
                modelparameters[7]
            ]
            precfactor_bnds = (precfactor_bndlow, precfactor_bndhigh)
            ddfsnow_bnds = (ddfsnow_init, ddfsnow_init)
            tempchange_bnds = (tempchange_init, tempchange_init)
            modelparams, mb_mwea = run_objective(
                modelparameters_subset,
                observed_massbal,
                precfactor_bnds=precfactor_bnds,
                tempchange_bnds=tempchange_bnds,
                ddfsnow_bnds=ddfsnow_bnds,
                ftol_opt=1e-3)
            precfactor_opt = modelparams[2]
            continue_param_search = False

        # Update parameter values
        modelparameters[2] = precfactor_opt

        if debug:
            print('  kp:', np.round(precfactor_opt, 2), 'mb_mwea:',
                  np.round(mb_mwea, 2))

        # ===== ROUND 2: DEGREE-DAY FACTOR OF SNOW ======
        if continue_param_search:
            if debug:
                print('Round 2:')
            # Lower bound
            modelparameters[4] = ddfsnow_bndlow
            modelparameters[5] = modelparameters[4] / ddfsnow_iceratio
            mb_mwea_ddflow = mb_mwea_calc(modelparameters,
                                          glacier_rgi_table,
                                          glacier_area_initial,
                                          icethickness_initial,
                                          width_initial,
                                          elev_bins,
                                          glacier_gcm_temp,
                                          glacier_gcm_tempstd,
                                          glacier_gcm_prec,
                                          glacier_gcm_elev,
                                          glacier_gcm_lrgcm,
                                          glacier_gcm_lrglac,
                                          dates_table,
                                          t1_idx,
                                          t2_idx,
                                          option_areaconstant=1,
                                          glacier_debrismf=glacier_debrismf)
            # Upper bound
            modelparameters[4] = ddfsnow_bndhigh
            modelparameters[5] = modelparameters[4] / ddfsnow_iceratio
            mb_mwea_ddfhigh = mb_mwea_calc(modelparameters,
                                           glacier_rgi_table,
                                           glacier_area_initial,
                                           icethickness_initial,
                                           width_initial,
                                           elev_bins,
                                           glacier_gcm_temp,
                                           glacier_gcm_tempstd,
                                           glacier_gcm_prec,
                                           glacier_gcm_elev,
                                           glacier_gcm_lrgcm,
                                           glacier_gcm_lrglac,
                                           dates_table,
                                           t1_idx,
                                           t2_idx,
                                           option_areaconstant=1,
                                           glacier_debrismf=glacier_debrismf)
            # Optimimum degree-day factor of snow
            if observed_massbal < mb_mwea_ddfhigh:
                ddfsnow_opt = ddfsnow_bndhigh
                mb_mwea = mb_mwea_ddfhigh
            elif observed_massbal > mb_mwea_ddflow:
                ddfsnow_opt = ddfsnow_bndlow
                mb_mwea = mb_mwea_ddflow
            else:
                modelparameters_subset = [
                    precfactor_opt, modelparameters[3], modelparameters[4],
                    modelparameters[7]
                ]
                precfactor_bnds = (precfactor_opt, precfactor_opt)
                ddfsnow_bnds = (ddfsnow_bndlow, ddfsnow_bndhigh)
                tempchange_bnds = (tempchange_init, tempchange_init)
                modelparams, mb_mwea = run_objective(
                    modelparameters_subset,
                    observed_massbal,
                    precfactor_bnds=precfactor_bnds,
                    tempchange_bnds=tempchange_bnds,
                    ddfsnow_bnds=ddfsnow_bnds,
                    ftol_opt=1e-5)
                ddfsnow_opt = modelparams[4]
                continue_param_search = False

            # Update parameter values
            modelparameters[4] = ddfsnow_opt
            modelparameters[5] = modelparameters[4] / ddfsnow_iceratio

            if debug:
                print('  ddfsnow:', np.round(ddfsnow_opt, 4), 'mb_mwea:',
                      np.round(mb_mwea, 2))
        else:
            ddfsnow_opt = modelparams[4]

        # ===== ROUND 3: TEMPERATURE BIAS ======
        if continue_param_search:
            if debug:
                print('Round 3:')

            tc_step = 0.5

            # ----- TEMPBIAS: max accumulation -----
            # Lower temperature bound based on no positive temperatures
            # Temperature at the lowest bin
            #  T_bin = T_gcm + lr_gcm * (z_ref - z_gcm) + lr_glac * (z_bin - z_ref) + tempchange
            lowest_bin = np.where(glacier_area_initial > 0)[0][0]
            tempchange_max_acc = (
                -1 * (glacier_gcm_temp + glacier_gcm_lrgcm *
                      (elev_bins[lowest_bin] - glacier_gcm_elev)).max())
            tempchange_bndlow = tempchange_max_acc

            modelparameters[7] = tempchange_bndlow
            mb_mwea = mb_mwea_calc(modelparameters,
                                   glacier_rgi_table,
                                   glacier_area_initial,
                                   icethickness_initial,
                                   width_initial,
                                   elev_bins,
                                   glacier_gcm_temp,
                                   glacier_gcm_tempstd,
                                   glacier_gcm_prec,
                                   glacier_gcm_elev,
                                   glacier_gcm_lrgcm,
                                   glacier_gcm_lrglac,
                                   dates_table,
                                   t1_idx,
                                   t2_idx,
                                   option_areaconstant=1,
                                   glacier_debrismf=glacier_debrismf)

            if debug:
                print('  tc_bndlow:', np.round(tempchange_bndlow, 2),
                      'mb_mwea:', np.round(mb_mwea, 2))

            while mb_mwea > observed_massbal and modelparameters[7] < 20:

                modelparameters[7] = modelparameters[7] + tc_step
                mb_mwea = mb_mwea_calc(modelparameters,
                                       glacier_rgi_table,
                                       glacier_area_initial,
                                       icethickness_initial,
                                       width_initial,
                                       elev_bins,
                                       glacier_gcm_temp,
                                       glacier_gcm_tempstd,
                                       glacier_gcm_prec,
                                       glacier_gcm_elev,
                                       glacier_gcm_lrgcm,
                                       glacier_gcm_lrglac,
                                       dates_table,
                                       t1_idx,
                                       t2_idx,
                                       option_areaconstant=1,
                                       glacier_debrismf=glacier_debrismf)
                if debug:
                    print('  tc:', np.round(modelparameters[7], 2), 'mb_mwea:',
                          np.round(mb_mwea, 2))

                tempchange_bndhigh = modelparameters[7]

            modelparameters_subset = [
                precfactor_opt, modelparameters[3], ddfsnow_opt,
                modelparameters[7] - tc_step / 2
            ]
            precfactor_bnds = (precfactor_opt, precfactor_opt)
            ddfsnow_bnds = (ddfsnow_opt, ddfsnow_opt)
            tempchange_bnds = (tempchange_bndlow, tempchange_bndhigh)

            modelparams, mb_mwea = run_objective(
                modelparameters_subset,
                observed_massbal,
                precfactor_bnds=precfactor_bnds,
                tempchange_bnds=tempchange_bnds,
                ddfsnow_bnds=ddfsnow_bnds,
                ftol_opt=1e-3)

            # Update parameter values
            tc_opt = modelparams[7]
            modelparameters[7] = tc_opt

            if debug:
                print('  tc:', np.round(tc_opt, 3), 'mb_mwea:',
                      np.round(mb_mwea, 2))

        else:
            tc_opt = modelparams[7]

        #%%

        mb_mwea = mb_mwea_calc(modelparameters,
                               glacier_rgi_table,
                               glacier_area_initial,
                               icethickness_initial,
                               width_initial,
                               elev_bins,
                               glacier_gcm_temp,
                               glacier_gcm_tempstd,
                               glacier_gcm_prec,
                               glacier_gcm_elev,
                               glacier_gcm_lrgcm,
                               glacier_gcm_lrglac,
                               dates_table,
                               t1_idx,
                               t2_idx,
                               option_areaconstant=1,
                               glacier_debrismf=glacier_debrismf)
        mb_mwea_nodebris = mb_mwea_calc(modelparameters,
                                        glacier_rgi_table,
                                        glacier_area_initial,
                                        icethickness_initial,
                                        width_initial,
                                        elev_bins,
                                        glacier_gcm_temp,
                                        glacier_gcm_tempstd,
                                        glacier_gcm_prec,
                                        glacier_gcm_elev,
                                        glacier_gcm_lrgcm,
                                        glacier_gcm_lrglac,
                                        dates_table,
                                        t1_idx,
                                        t2_idx,
                                        option_areaconstant=1,
                                        glacier_debrismf=None)

        if debug:
            print('mod_mwea:', np.round(mb_mwea, 2), 'no debris:',
                  np.round(mb_mwea_nodebris, 2))

        if abs(mb_mwea - observed_massbal) > observed_massbal_std:
            print(rgiid, ' check as observed mass balance not close')
            # Skip and replace with observation for both to not skew results
            #  ex. 3.02860 - frontal ablation appears too much causing far too negative mass balance
            troubleshoot_fp = pygem_prms.output_fp_cal + '_4debrispaper/' + data_source + '/errors/'
            if not os.path.exists(troubleshoot_fp):
                os.makedirs(troubleshoot_fp)
            txt_fn = rgiid + "-mb_agreement_notfound.txt"
            with open(troubleshoot_fp + txt_fn, "w") as text_file:
                text_file.write(rgiid +
                                ' mass balance not close to observation (' +
                                str(np.round(mb_mwea, 2)) + ' vs. ' +
                                str(np.round(observed_massbal, 2)) +
                                '), so replaced with observed mb')
            mb_mwea = observed_massbal
            mb_mwea_nodebris = observed_massbal

        # ===== EXPORT RESULTS =====
        output_cns = [
            'RGIId', 'area_km2', 'kp', 'ddfsnow', 'ddfice', 'tc', 'tsnow',
            'obs_mwea', 'obs_mwea_std', 'mod_mwea', 'mod_mwea_nodebris'
        ]
        output_df = pd.DataFrame(np.zeros((1, len(output_cns))),
                                 columns=output_cns)
        output_df['RGIId'] = rgiid
        output_df['area_km2'] = binnedcsv.z1_bin_area_valid_km2.sum()
        print(binnedcsv.z1_bin_area_valid_km2.sum(), bins_area.sum(),
              main_glac_rgi.loc[nglac, 'Area'])
        output_df['kp'] = precfactor_opt
        output_df['ddfsnow'] = ddfsnow_opt
        output_df['ddfice'] = ddfsnow_opt / ddfsnow_iceratio
        output_df['tc'] = tc_opt
        output_df['tsnow'] = pygem_prms.tempsnow
        output_df['obs_mwea'] = observed_massbal
        output_df['obs_mwea_std'] = observed_massbal_std
        output_df['mod_mwea'] = mb_mwea
        output_df['mod_mwea_nodebris'] = mb_mwea_nodebris

        # EXPORT TO NETCDF
        if mf_cn == 'mf_ts_mean_bndlow':
            mf_str = 'bndlow_'
        elif mf_cn == 'mf_ts_mean_bndhigh':
            mf_str = 'bndhigh_'
        else:
            mf_str = ''
        output_fp = (pygem_prms.output_fp_cal + '_4debrispaper/' + mf_str +
                     data_source + '/' +
                     str(glacier_rgi_table.O1Region).zfill(2) + '/')
        if not os.path.exists(output_fp):
            os.makedirs(output_fp)
        output_fn = rgiid + '_HH2015_wdebris.csv'
        output_df.to_csv(output_fp + output_fn, index=False)

        #%% ===== CALCULATE MASS BALANCE WITH AND WITHOUT DEBRIS =====
        #        modelparameters = [-0.0065, -0.0065, 0.8, 0.0001, 0.0045, 0.009, 1.0, 1.067748599396429]
        #        print(modelparameters)
        (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze,
         glac_bin_snowpack, glac_bin_melt, glac_bin_frontalablation,
         glac_bin_massbalclim, glac_bin_massbalclim_annual,
         glac_bin_area_annual, glac_bin_icethickness_annual,
         glac_bin_width_annual, glac_bin_surfacetype_annual,
         glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline,
         glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual,
         glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze,
         offglac_wide_melt, offglac_wide_snowpack,
         offglac_wide_runoff) = (massbalance.runmassbalance(
             modelparameters,
             glacier_rgi_table,
             glacier_area_initial,
             icethickness_initial,
             width_initial,
             elev_bins,
             glacier_gcm_temp,
             glacier_gcm_tempstd,
             glacier_gcm_prec,
             glacier_gcm_elev,
             glacier_gcm_lrgcm,
             glacier_gcm_lrglac,
             dates_table,
             option_areaconstant=1,
             glacier_debrismf=glacier_debrismf,
             debug=False))
        glac_bin_massbalclim_annual_mean_wdebris = glac_bin_massbalclim_annual.mean(
            axis=1)

        (glac_bin_temp, glac_bin_prec, glac_bin_acc, glac_bin_refreeze,
         glac_bin_snowpack, glac_bin_melt, glac_bin_frontalablation,
         glac_bin_massbalclim, glac_bin_massbalclim_annual,
         glac_bin_area_annual, glac_bin_icethickness_annual,
         glac_bin_width_annual, glac_bin_surfacetype_annual,
         glac_wide_massbaltotal, glac_wide_runoff, glac_wide_snowline,
         glac_wide_snowpack, glac_wide_area_annual, glac_wide_volume_annual,
         glac_wide_ELA_annual, offglac_wide_prec, offglac_wide_refreeze,
         offglac_wide_melt, offglac_wide_snowpack,
         offglac_wide_runoff) = (massbalance.runmassbalance(
             modelparameters,
             glacier_rgi_table,
             glacier_area_initial,
             icethickness_initial,
             width_initial,
             elev_bins,
             glacier_gcm_temp,
             glacier_gcm_tempstd,
             glacier_gcm_prec,
             glacier_gcm_elev,
             glacier_gcm_lrgcm,
             glacier_gcm_lrglac,
             dates_table,
             option_areaconstant=1,
             glacier_debrismf=None,
             debug=False))
        glac_bin_massbalclim_annual_mean_nodebris = glac_bin_massbalclim_annual.mean(
            axis=1)

        mbclim_output_cns = [
            'elev', 'area', 'mf', 'mbclim_mwea_wdebris',
            'mbclim_mwea_nodebris', 'frontalablation'
        ]
        mbclim_output_df = pd.DataFrame(np.zeros(
            (len(elev_bins), len(mbclim_output_cns))),
                                        columns=mbclim_output_cns)
        mbclim_output_df['elev'] = elev_bins
        mbclim_output_df['area'] = bins_area
        mbclim_output_df['mf'] = glacier_debrismf
        mbclim_output_df[
            'mbclim_mwea_wdebris'] = glac_bin_massbalclim_annual_mean_wdebris
        mbclim_output_df[
            'mbclim_mwea_nodebris'] = glac_bin_massbalclim_annual_mean_nodebris
        mbclim_output_df['frontalablation'] = glac_bin_frontalablation.mean(1)
        mbclim_output_fn = rgiid + '_mbclim_data.csv'
        mbclim_output_fp = (pygem_prms.output_fp_cal + '_4debrispaper/' +
                            mf_str + data_source + '-mbclim' + '/' +
                            str(glacier_rgi_table.O1Region).zfill(2) + '/')
        if not os.path.exists(mbclim_output_fp):
            os.makedirs(mbclim_output_fp)
        mbclim_output_df.to_csv(mbclim_output_fp + mbclim_output_fn,
                                index=False)

    if debug:
        return main_glac_rgi

#    # Export variables as global to view in variable explorers
#    if args.option_parallels == 0:
#        global main_vars
#        main_vars = inspect.currentframe().f_locals

    print('\nProcessing time of', gcm_name, ':', time.time() - time_start, 's')
Esempio n. 8
0
        return glac_variable_series, time_series


#%% Testing
if __name__ == '__main__':
    #    gcm = GCM(name='CanESM2', rcp_scenario='rcp85')
    gcm = GCM(name='ERA5')
    #    gcm = GCM(name='ERA-Interim')

    main_glac_rgi = modelsetup.selectglaciersrgitable(
        rgi_regionsO1=input.rgi_regionsO1,
        rgi_regionsO2='all',
        rgi_glac_number=input.rgi_glac_number)
    dates_table = modelsetup.datesmodelrun(
        startyear=1980,
        endyear=2017,
        spinupyears=0,
        option_wateryear=input.gcm_wateryear)

    # Air temperature [degC], Precipitation [m], Elevation [masl], Lapse rate [K m-1]
    gcm_temp, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(
        gcm.temp_fn, gcm.temp_vn, main_glac_rgi, dates_table)
    gcm_prec, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(
        gcm.prec_fn, gcm.prec_vn, main_glac_rgi, dates_table)
    gcm_elev = gcm.importGCMfxnearestneighbor_xarray(gcm.elev_fn, gcm.elev_vn,
                                                     main_glac_rgi)
    if gcm.name == 'ERA-Interim' or gcm.name == 'ERA5':
        gcm_lr, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(
            gcm.lr_fn, gcm.lr_vn, main_glac_rgi, dates_table)
    if gcm.name == 'ERA5':
        gcm_tempstd, gcm_dates = gcm.importGCMvarnearestneighbor_xarray(