def get_TIModel_clim_model_type(gd, mb_type='mb_monthly', grad_type='cte', pd_geodetic_loc=None, # pd_geodetic_comp ): rho_geodetic = 850 # get volume estimates dV = pd.read_hdf(utils.get_demo_file('rgi62_itmix_df.h5')) # for potential restricting total ice melt V_gd_m3 = dV.loc[gd.rgi_id]['vol_itmix_m3'] # m3 volume of HEF total_mass_gd = V_gd_m3 * rho_geodetic # this is the area from 2000, could use another estimate (e.g. mean between 2000 and 2020...) gd_area = pd_geodetic_loc.loc[gd.rgi_id]['area'] # in km2 # convert kg --> kg/km2 max_allowed_specificMB = - total_mass_gd / 1e6 / gd_area h, w = gd.get_inversion_flowline_hw() if mb_type != 'mb_real_daily': cfg.PARAMS['baseline_climate'] = 'ERA5dr' oggm.shop.ecmwf.process_ecmwf_data(gd, dataset='ERA5dr') else: cfg.PARAMS['baseline_climate'] = 'ERA5_daily' process_era5_daily_data(gd) ref_df = gd.get_ref_mb_data() # at instantiation use prcp_fac = 2.5, change this in def_get_mb later on gd_mb = TIModel(gd, 150, mb_type=mb_type, N=100, prcp_fac=2.5, grad_type=grad_type) gd_mb.historical_climate_qc_mod(gd) return gd_mb, ref_df, h, w, max_allowed_specificMB
def test_optimize_std_quot_brentq(gdir): # check if double optimisation of bias and std_quotient works grad_type = 'cte' N = 2000 loop = False cfg.PARAMS['baseline_climate'] = 'ERA5dr' oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset='ERA5dr') for mb_type in ['mb_monthly', 'mb_daily', 'mb_real_daily']: if mb_type != 'mb_real_daily': cfg.PARAMS['baseline_climate'] = 'ERA5dr' oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset='ERA5dr') else: cfg.PARAMS['baseline_climate'] = 'ERA5_daily' process_era5_daily_data(gdir) hgts, widths = gdir.get_inversion_flowline_hw() mbdf = gdir.get_ref_mb_data() pf_opt = scipy.optimize.brentq(optimize_std_quot_brentq, 0.01, 20, args=(mb_type, grad_type, gdir, N, loop), xtol=0.01) DDF_opt_pf = scipy.optimize.brentq(minimize_bias, 1, 10000, args=(mb_type, grad_type, gdir, N, pf_opt, loop, False), disp=True, xtol=0.1) gd_mb = mb_modules(gdir, DDF_opt_pf, prcp_fac=pf_opt, mb_type=mb_type, grad_type=grad_type) mb_specific = gd_mb.get_specific_mb(heights=hgts, widths=widths, year=mbdf.index.values) RMSD, bias, rcor, quot_std = compute_stat(mb_specific=mb_specific, mbdf=mbdf) # check if the bias is optimised assert bias.round() == 0 # check if the std_quotient is optimised assert quot_std.round(1) == 1
def test_minimize_bias(gdir): # important to initialize again, otherwise hydro_month_nh=1 # from test_hydro_years_HEF... # just checks if minimisation gives always same results grad_type = 'cte' N = 2000 loop = False for mb_type in ['mb_real_daily', 'mb_monthly', 'mb_daily']: if mb_type != 'mb_real_daily': cfg.PARAMS['baseline_climate'] = 'ERA5dr' oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset='ERA5dr') else: cfg.PARAMS['baseline_climate'] = 'ERA5_daily' process_era5_daily_data(gdir) DDF_opt = scipy.optimize.brentq(minimize_bias, 1, 10000, disp=True, xtol=0.1, args=(mb_type, grad_type, gdir, N, pf, loop, False)) hgts, widths = gdir.get_inversion_flowline_hw() mbdf = gdir.get_ref_mb_data() # check if they give the same optimal DDF # print(mu_star_opt_cte[mb_type], DDF_opt) assert np.round(mu_star_opt_cte[mb_type] / DDF_opt, 3) == 1 gd_mb = mb_modules(gdir, DDF_opt, mb_type=mb_type, grad_type=grad_type) mb_specific = gd_mb.get_specific_mb(heights=hgts, widths=widths, year=mbdf.index.values) RMSD, bias, rcor, quot_std = compute_stat(mb_specific=mb_specific, mbdf=mbdf) # check if the bias is optimised assert bias.round() == 0
def test_hydro_years_HEF(gdir): # only very basic test, the other stuff is done in oggm man basis # test if it also works for hydro_month ==1, necessary for geodetic mb # if hydro_month ==1, and msm start in 1979, then hydro_year should also # be 1979, this works only with the newest OGGM dev version... cfg.PARAMS['hydro_month_nh'] = 1 h, w = gdir.get_inversion_flowline_hw() cfg.PARAMS['baseline_climate'] = 'ERA5dr' oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset='ERA5dr') f = gdir.get_filepath('climate_historical', filesuffix='') test_climate = xr.open_dataset(f) assert test_climate.time[0] == np.datetime64('1979-01-01') assert test_climate.time[-1] == np.datetime64('2018-12-01') # now test it for ERA5_daily cfg.PARAMS['baseline_climate'] = 'ERA5_daily' process_era5_daily_data(gdir) f = gdir.get_filepath('climate_historical', filesuffix='_daily') test_climate = xr.open_dataset(f) assert test_climate.time[0] == np.datetime64('1979-01-01') assert test_climate.time[-1] == np.datetime64('2018-12-31')
def test_process_era5_daily_data(self, gdir): process_era5_daily_data(gdir, y0=1979, y1=2018) fs = '_daily_ERA5' fpath = gdir.get_filepath('climate_historical', filesuffix=fs) # check the climate files of an individual glacier (Hintereisferner) xr_nc = xr.open_dataset(fpath) assert np.all(xr_nc.prcp) >= 0 # daily precipitation amount in kg m-2 (not in kg m-2 s-1) assert xr_nc.prcp.max() > 1 # to be sure that there are no erroneaous filling values inside assert np.all(xr_nc.prcp) < 10000 # temperature values are in °C and in the right range assert np.all(xr_nc.temp) > -100 assert np.all(xr_nc.temp) < 100 # temperature gradient should be in the following range assert np.all(xr_nc.gradient > -0.015) assert np.all(xr_nc.gradient < -0.002) # all lapse rates/ precipitation values in one month should be equal # because only temperature is on daily basis np.testing.assert_allclose(xr_nc.resample(time='1M').std().prcp, 0, atol=1e-3) np.testing.assert_allclose(xr_nc.resample(time='1M').std().gradient, 0, atol=1e-3) # summed up monthly precipitation from daily dataset xr_nc_prcp_m = xr_nc.prcp.resample(time='1M').sum() oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset="ERA5", y0=1979, y1=2018) filename = 'climate_historical' fpath = gdir.get_filepath(filename) xr_nc_monthly = xr.open_dataset(fpath) # check if summed up monthly precipitation from daily # dataset equals approx. to the ERA5 monthly prcp np.testing.assert_allclose(xr_nc_prcp_m.values, xr_nc_monthly.prcp.values, rtol=1e-4) xr_nc_temp_m = xr_nc.temp.resample(time='1M').mean() # check if mean temperature from daily dataset equals # approx. to the ERA5 monthly temp. np.testing.assert_allclose(xr_nc_temp_m.values, xr_nc_monthly.temp.values, atol=0.05) with pytest.raises(InvalidParamsError): # dataset only goes from 1979--2018 process_era5_daily_data(gdir, y0=1979, y1=2019) # in cfg.PARAMS that is initiated during testing, # cfg.PARAMS[hydro_month_nh = 10], this is in conflict with 8 process_era5_daily_data(gdir, y0=1979, y1=2018, hydro_month_nh=8)
gdirs = workflow.init_glacier_directories( pd_geodetic_comp_alps.dropna().index[start_ind:end_ind].values, from_prepro_level=2, prepro_border=10, prepro_base_url=base_url, prepro_rgi_version='62') if mb_type != 'mb_real_daily': cfg.PARAMS['baseline_climate'] = 'ERA5dr' workflow.execute_entity_task(tasks.process_ecmwf_data, gdirs, dataset='ERA5dr') else: cfg.PARAMS['baseline_climate'] = 'ERA5_daily' for gd in pd_geodetic_comp_alps.index[start_ind:end_ind]: process_era5_daily_data(gd) elif compute_missing: #raise NotImplementedError('this has to be adapted') path_samples = '/home/users/lschuster/bayesian_calibration/WFDE5_ISIMIP/burned_trace_plus200samples/' miss_samples = {} exist_samples = {} typ = '{}_{}'.format(mb_type, grad_type) miss_samples[typ] = [] exist_samples[typ] = [] geod_ind = pd_geodetic_comp_alps.dropna().index path_dir = '/home/users/lschuster/oggm_files/all/per_glacier/RGI60-11/' for t in os.listdir(path_dir): path_t = path_dir + t + '/' for rgi_id in os.listdir(path_t):
def test_all_at_once(self, gdir): # Init exps = ['CRU', 'HISTALP', 'ERA5', 'ERA5L', 'CERA', 'ERA5_daily', 'WFDE5_CRU_daily', 'W5E5_daily', 'WFDE5_CRU_monthly', 'W5E5_monthly'] ref_hgts = [] dft = [] dfp = [] for base in exps: if base not in ['ERA5_daily', 'WFDE5_CRU_daily', 'W5E5_daily', 'WFDE5_CRU_monthly', 'W5E5_monthly']: cfg.PARAMS['baseline_climate'] = base tasks.process_climate_data(gdir, output_filesuffix=base) elif base == 'ERA5_daily': cfg.PARAMS['baseline_climate'] = base process_era5_daily_data(gdir, output_filesuffix=base) elif base == 'WFDE5_CRU_daily' or base == 'W5E5_daily': process_w5e5_data(gdir, output_filesuffix=base, temporal_resol='daily') elif '_monthly' in base: # wfde5_cru and w5e5 process_w5e5_data(gdir, output_filesuffix=base, temporal_resol='monthly') f = gdir.get_filepath('climate_historical', filesuffix=base) with xr.open_dataset(f) as ds: ref_hgts.append(ds.ref_hgt) assert ds.ref_pix_dis < 30000 dft.append(ds.temp.to_series()) dfp.append(ds.prcp.to_series()) dft = pd.concat(dft, axis=1, keys=exps) dfp = pd.concat(dfp, axis=1, keys=exps) # compare daily mean temperatures of ERA5 and WFDE5 assert dft[['ERA5_daily', 'WFDE5_CRU_daily']].corr().min().min() > 0.95 assert dft[['W5E5_daily', 'WFDE5_CRU_daily']].corr().min().min() > 0.95 # want to compare mean monthly temperatures # (daily resolution datasets have to be resampled) dft = dft.resample('MS').mean() print(dft) # Common period #dft = dft.resample(time='1M').mean() dfy = dft.resample('AS').mean().dropna().iloc[1:] dfm = dft.groupby(dft.index.month).mean() assert dfy.corr().min().min() > 0.44 # ERA5L and CERA do not correlate assert dfm.corr().min().min() > 0.97 dfavg = dfy.describe() # Correct for hgt ref_h = ref_hgts[0] for h, d in zip(ref_hgts, exps): dfy[d] = dfy[d] - 0.0065 * (ref_h - h) dfm[d] = dfm[d] - 0.0065 * (ref_h - h) dfavg_cor = dfy.describe() # After correction less spread assert dfavg_cor.loc['mean'].std() < 0.8 * dfavg.loc['mean'].std() print(dfavg_cor) # with ERA5_daily and WFDE5_daily, smaller std (from <2.1 -> <1.7) assert dfavg_cor.loc['mean'].std() < 1.7 # PRECIP # want to compare summed up monthly precipitation # (daily resolution datasets, so far only wfde5, have to resample) dfp = dfp.resample('MS').sum(min_count =1) # Common period dfy = dfp.resample('AS').mean().dropna().iloc[1:] * 12 dfm = dfp.groupby(dfp.index.month).mean() assert dfy.corr().min().min() > 0.5 # monthly prcp of WFDE5 is quite different > 0.8 -> > 0.75 assert dfm.corr().min().min() > 0.73 # 0.8 dfavg = dfy.describe() assert dfavg.loc['mean'].std() / dfavg.loc['mean'].mean() < 0.28 # %
def test_process_w5e5_data(self, gdir): # first with daily resolution cfg.PARAMS['hydro_month_nh'] = 1 process_w5e5_data(gdir, y0=1979, y1=2019, temporal_resol='daily', climate_type='W5E5') process_w5e5_data(gdir, y0=1979, y1=2018, temporal_resol='daily', climate_type='WFDE5_CRU') filename = 'climate_historical' fpath = gdir.get_filepath(filename, filesuffix='_daily_WFDE5_CRU') # check the climate files of an individual glacier (Hintereisferner) xr_nc = xr.open_dataset(fpath) fpath_w5e5 = gdir.get_filepath(filename, filesuffix='_daily_W5E5') # check the climate files of an individual glacier (Hintereisferner) xr_nc_w5e5 = xr.open_dataset(fpath_w5e5) assert np.all(xr_nc.prcp) >= 0 assert np.all(xr_nc_w5e5.prcp) >= 0 # daily precipitation amount in kg m-2 (not in kg m-2 s-1) assert xr_nc.prcp.max() > 1 assert xr_nc_w5e5.prcp.max() > 1 # to be sure that there are no erroneous filling values inside assert np.all(xr_nc.prcp) < 10000 assert np.all(xr_nc_w5e5.prcp) < 10000 # temperature values are in °C and in the right range assert np.all(xr_nc.temp) > -100 assert np.all(xr_nc.temp) < 100 assert np.all(xr_nc_w5e5.temp) > -100 assert np.all(xr_nc_w5e5.temp) < 100 # temperature gradient should be in the following range assert np.all(xr_nc.gradient > -0.015) assert np.all(xr_nc.gradient < -0.002) assert np.all(xr_nc_w5e5.gradient > -0.015) assert np.all(xr_nc_w5e5.gradient < -0.002) # all lapse rates values in one month should be equal # because only temperature and prcp is on daily basis #np.testing.assert_allclose(xr_nc.resample(time='1M').std().prcp, # 0, atol=1e-3) np.testing.assert_allclose(xr_nc.resample(time='MS').std().gradient, 0, atol=1e-3) np.testing.assert_allclose(xr_nc_w5e5.resample(time='MS').std().gradient, 0, atol=1e-3) # summed up monthly precipitation from daily dataset xr_nc_prcp_m = xr_nc.prcp.resample(time='MS').sum() xr_nc_prcp_m_w5e5 = xr_nc_w5e5.prcp.resample(time='MS').sum() oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset="ERA5", y0=1979, y1=2018) filename = 'climate_historical' fpath = gdir.get_filepath(filename) xr_nc_monthly_ERA5 = xr.open_dataset(fpath) # check if summed up monthly precipitation from daily # dataset equals approx to the WFDE5 monthly prcp # first with daily resolution process_w5e5_data(gdir, y0=1979, y1=2018, temporal_resol='monthly', climate_type='WFDE5_CRU') process_w5e5_data(gdir, y0=1979, y1=2019, temporal_resol='monthly', climate_type='W5E5') # an output filesuffix is needed, otherwise the # ERA5 dataset from above is used as it has the same name ... fpath_monthly = gdir.get_filepath(filename, filesuffix='_monthly_WFDE5_CRU') xr_nc_monthly = xr.open_dataset(fpath_monthly) fpath_monthly = gdir.get_filepath(filename, filesuffix='_monthly_W5E5') xr_nc_monthly_W5E5 = xr.open_dataset(fpath_monthly) assert np.all(xr_nc_monthly.prcp) > 0 assert np.all(xr_nc_monthly_W5E5.prcp) > 0 assert xr_nc_monthly.prcp.max() > 1 assert xr_nc_monthly_W5E5.prcp.max() > 1 # to be sure that there are no erroneous filling values inside assert np.all(xr_nc_monthly.prcp) < 10000 assert np.all(xr_nc_monthly_W5E5) < 10000 # temperature values are in °C and in the right range assert np.all(xr_nc_monthly.temp) > -100 assert np.all(xr_nc_monthly.temp) < 100 assert np.all(xr_nc_monthly_W5E5.temp) > -100 assert np.all(xr_nc_monthly_W5E5.temp) < 100 # temperature gradient should be in the following range assert np.all(xr_nc_monthly.gradient > -0.015) assert np.all(xr_nc_monthly.gradient < -0.002) assert np.all(xr_nc_monthly_W5E5.gradient > -0.015) assert np.all(xr_nc_monthly_W5E5.gradient < -0.002) assert_allclose(xr_nc_prcp_m.values, xr_nc_monthly.prcp.values, rtol=1e-4) assert_allclose(xr_nc_prcp_m_w5e5.values, xr_nc_monthly_W5E5.prcp.values, rtol=1e-4) # check if summed up monthly precipitation from daily # dataset correlate for prpc ... assert np.corrcoef(xr_nc_prcp_m.values, xr_nc_monthly_ERA5.prcp.values)[0][1] > 0.75 xr_nc_prcp_m_w5e5 = xr_nc_prcp_m_w5e5.sel(time=slice('1979', '2018')) assert np.corrcoef(xr_nc_prcp_m.values, xr_nc_prcp_m_w5e5)[0][1] > 0.75 #np.testing.assert_allclose(xr_nc_prcp_m.values, # xr_nc_monthly.prcp.values, rtol=1e-4) xr_nc_temp_m = xr_nc.temp.resample(time='MS').mean() xr_nc_temp_m_w5e5 = xr_nc_w5e5.temp.resample(time='MS').mean() # check if mean temperature from daily dataset equals # approx. the WFDE5 monthly temp. assert_allclose(xr_nc_temp_m.values, xr_nc_monthly.temp.values, atol=1e-4) assert_allclose(xr_nc_temp_m_w5e5.values, xr_nc_monthly_W5E5.temp.values, atol=1e-4) # check if mean temperature from daily dataset equals # approx. to the ERA5 monthly temp. assert np.corrcoef(xr_nc_monthly_ERA5.temp.values, xr_nc_temp_m.values)[0][1] > 0.75 xr_nc_temp_m = xr_nc_temp_m.sel(time=slice('1979', '2018')) assert np.corrcoef(xr_nc_monthly_ERA5.temp.values, xr_nc_temp_m.values)[0][1] > 0.75 with pytest.raises(InvalidParamsError): # dataset only goes from 1979--2018 process_era5_daily_data(gdir, y0=1979, y1=2019) # in cfg.PARAMS that is initiated during testing, # cfg.PARAMS[hydro_month_nh = 1], this is in conflict with 8 process_era5_daily_data(gdir, y0=1979, y1=2018, hydro_month_nh=8)
def test_process_era5_daily_data(): cfg.initialize() test_dir = '/home/lilianschuster/Schreibtisch/PhD/oggm_files/tests' if not os.path.exists(test_dir): test_dir = utils.gettempdir(dirname='OGGM_era5_daily_test', reset=True) cfg.PATHS['working_dir'] = test_dir b_url_ = 'https://cluster.klima.uni-bremen.de/~fmaussion' base_url = b_url_ + '/gdirs/prepro_l2_202010/elevbands_fl_with_consensus' df = utils.get_rgi_glacier_entities(['RGI60-11.00897']) gdirs = workflow.init_glacier_directories(df, from_prepro_level=2, prepro_border=40, prepro_base_url=base_url, prepro_rgi_version='62') gdir = gdirs[0] process_era5_daily_data(gdir, y0=1979, y1=2018) filename = 'climate_historical_daily' fpath = gdir.get_filepath(filename) # check the climate files of an individual glacier (Hintereisferner) xr_nc = xr.open_dataset(fpath) assert np.all(xr_nc.prcp) > 0 # to be sure that there are no erroneaous filling values inside assert np.all(xr_nc.prcp) < 10000 # temperature values are in °C and in the right range assert np.all(xr_nc.temp) > -100 assert np.all(xr_nc.temp) < 100 # temperature gradient should be in the following range assert np.all(xr_nc.gradient > -0.015) assert np.all(xr_nc.gradient < -0.002) # all lapse rates/ precipitation values in one month should be equal # because only temperature is on daily basis np.testing.assert_allclose(xr_nc.resample(time='1M').std().prcp, 0, atol=1e-3) np.testing.assert_allclose(xr_nc.resample(time='1M').std().gradient, 0, atol=1e-3) # summed up monthly precipitation from daily dataset xr_nc_prcp_m = xr_nc.prcp.resample(time='1M').sum() oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset="ERA5", y0=1979, y1=2018) filename = 'climate_historical' fpath = gdir.get_filepath(filename) xr_nc_monthly = xr.open_dataset(fpath) # check if summed up monthly precipitation from daily # dataset equals approx. to the ERA5 monthly prcp np.testing.assert_allclose(xr_nc_prcp_m.values, xr_nc_monthly.prcp.values, rtol=1e-4) xr_nc_temp_m = xr_nc.temp.resample(time='1M').mean() # check if mean temperature from daily dataset equals # approx. to the ERA5 monthly temp. np.testing.assert_allclose(xr_nc_temp_m.values, xr_nc_monthly.temp.values, atol=0.05) with pytest.raises(InvalidParamsError): # dataset only goes from 1979--2018 process_era5_daily_data(gdir, y0=1979, y1=2019) # in cfg.PARAMS that is initiated during testing, # cfg.PARAMS[hydro_month_nh = 10], this is in conflict with 8 process_era5_daily_data(gdir, y0=1979, y1=2018, hydro_month_nh=8)
def get_opt_pf_melt_f(gd, mb_type='mb_monthly', grad_type='cte', pd_calib_opt=None, pd_geodetic=None, dataset='ERA5'): if type(pd_calib_opt) == pd.core.frame.DataFrame: pass else: pd_calib_opt = pd.DataFrame(columns=[ 'pf_opt', 'melt_f_opt_pf', 'mb_geodetic', 'mb_geodetic_err', 'mb_glaciological_mean', 'mb_glaciological_std', 'stats_calib', # 'stats_valid', 'amount_glacmsm', # 'glacmsm_after_2000', 'glacmsm_before_2000', 'temp std', 'temp for melt std (mean)', 'tempfmelt_std_quot_hdiff', 'prcp std', 'solid prcp std (mean)', 'prcpsols_std_hstd', 'prcp std valid', 'solid prcp std valid', 'prcp mean', 'solid prcp mean', 'temp mean', 'temp for melt mean', 'prcp mean nopf', 'prcp mean nopf weighted', 'solid prcp mean nopf', 'solid prcp mean nopf weighted', 'solid prcp std nopf' ]) pd_calib_opt.loc[gd.rgi_id] = np.NaN if mb_type != 'mb_real_daily': if dataset == 'ERA5': baseline_climate = 'ERA5dr' oggm.shop.ecmwf.process_ecmwf_data(gd, dataset='ERA5dr') input_fs = '' elif dataset == 'WFDE5_CRU_monthly': baseline_climate = 'WFDE5_CRU' process_w5e5_data(gd, climate_type=baseline_climate, temporal_resol='monthly') input_fs = '_monthly_WFDE5_CRU' elif mb_type == 'mb_real_daily': if dataset == 'ERA5': baseline_climate = 'ERA5dr' process_era5_daily_data(gd) input_fs = '' elif dataset == 'WFDE5_CRU_monthly': baseline_climate = 'WFDE5_CRU' process_w5e5_data(gd, climate_type=baseline_climate, temporal_resol='daily') input_fs = '_daily_WFDE5_CRU' mbdf = gd.get_ref_mb_data(input_filesuffix=input_fs) mb_glaciological = mbdf['ANNUAL_BALANCE'] ys_glac = mbdf.index.values # print(ys_glac) gd_mb = TIModel(gd, None, mb_type=mb_type, N=100, prcp_fac=2.5, grad_type=grad_type, baseline_climate=baseline_climate) gd_mb.historical_climate_qc_mod(gd) h, w = gd.get_inversion_flowline_hw() mb_geodetic = pd_geodetic.loc[gd.rgi_id].dmdtda * 1000 mb_geodetic_err = pd_geodetic.loc[gd.rgi_id].err_dmdtda * 1000 if len(ys_glac) > 1: try: pf_opt = scipy.optimize.brentq(optimize_std_quot_brentq_geod, 0.01, 20, xtol=0.01, args=(gd_mb, mb_geodetic, mb_glaciological, h, w, ys_glac), disp=True) except ValueError: # (' f(a) and f(b) must have different signs'): print('{}: try out with 0.1 and 10 as pf boundaries'.format( gd.rgi_id)) try: pf_opt = scipy.optimize.brentq(optimize_std_quot_brentq_geod, 0.1, 10, xtol=0.01, args=(gd_mb, mb_geodetic, mb_glaciological, h, w, ys_glac), disp=True) except ValueError: # (' f(a) and f(b) must have different signs'): print('{}: try out with 0.5 and 3 as pf boundaries'.format( gd.rgi_id)) # try: pf_opt = scipy.optimize.brentq(optimize_std_quot_brentq_geod, 0.5, 3, xtol=0.01, args=(gd_mb, mb_geodetic, mb_glaciological, h, w, ys_glac), disp=True) # except: # pf_opt = 2.5 melt_f_opt_pf = scipy.optimize.brentq(minimize_bias_geodetic, 1, 10000, xtol=0.01, args=(gd_mb, mb_geodetic, h, w, pf_opt), disp=True) gd_mb.melt_f = melt_f_opt_pf gd_mb.prcp_fac = pf_opt mb_specific_optstd = gd_mb.get_specific_mb(heights=h, widths=w, year=ys_glac) stats_calib = compute_stat(mb_specific=mb_specific_optstd, mbdf=mbdf, return_dict=True) cs = [ 'pf_opt', 'melt_f_opt_pf', 'mb_geodetic', 'mb_geodetic_err', 'mb_glaciological_mean', 'mb_glaciological_std', 'stats_calib', # 'stats_valid', 'amount_glacmsm' ] var = [ pf_opt, melt_f_opt_pf, mb_geodetic, mb_geodetic_err, mb_glaciological.mean(), mb_glaciological.std(), str(stats_calib), # str(stats_valid), len(ys_glac) ] # len(ys_glac[ys_glac < 2000])] for c, v in zip(cs, var): # print(c, v) pd_calib_opt.loc[gd.rgi_id, c] = v pd_calib_opt.loc[gd.rgi_id, 'optimisation_possible'] = True ### understand which glaciers need a high pf_opt as # they have a high mb_glaciological_std gd_mb.prcp_fac = 1 prcps_nofac = pd.DataFrame() prcpsols_nofac = pd.DataFrame() # I take only those years where measurements are available!!!! for y in ys_glac: t, tfmelt, prcp, prcpsol = gd_mb.get_annual_climate(h, year=y) prcps_nofac[y] = prcp prcpsols_nofac[y] = prcpsol prcp_mean_nopf = prcps_nofac.mean(axis=1).mean() prcp_mean_nopf_weight = (prcps_nofac.mean(axis=1) * w).mean() / w.mean() solid_prcp_mean_nopf = prcpsols_nofac.mean(axis=1).mean() solid_prcp_mean_nopf_weight = (prcpsols_nofac.mean(axis=1) * w).mean() / w.mean() prcpsols_std_nopf = prcpsols_nofac.std(axis=1).mean() # back to calibrated value gd_mb.prcp_fac = pf_opt # other climate data ts = pd.DataFrame() tfmelts = pd.DataFrame() prcps = pd.DataFrame() prcpsols = pd.DataFrame() # I take only those years where measurements are available!!!! for y in ys_glac: t, tfmelt, prcp, prcpsol = gd_mb.get_annual_climate(h, year=y) ts[y] = t tfmelts[y] = tfmelt prcps[y] = prcp prcpsols[y] = prcpsol # ts.index = h ts_std = ts.std( axis=1).mean() # this is everywhere the same because of lapse rate ts_mean = ts.mean( axis=1).mean() # this is everywhere the same because of lapse rate prcp_mean = prcps.mean(axis=1).mean() solid_prcp_mean = prcpsols.mean(axis=1).mean() tfmelts_std = tfmelts.std(axis=1).mean() tfmelts_mean = tfmelts.mean(axis=1).mean() tfmelts_std_quot_hdiff = tfmelts.std(axis=1).iloc[0] / \ tfmelts.std(axis=1).iloc[-1] # this is everywhere the same because no prcp changes with height! prcps_std = prcps.std(axis=1).mean() # print(prcp_mean) # this changes with height prcpsols_std = prcpsols.std(axis=1).mean() prcpsols_std_hstd = prcpsols.std(axis=1).std() var = [ ts_std, tfmelts_std, tfmelts_std_quot_hdiff, prcps_std, prcpsols_std, prcpsols_std_hstd, prcp_mean, solid_prcp_mean, ts_mean, tfmelts_mean, prcp_mean_nopf, prcp_mean_nopf_weight, solid_prcp_mean_nopf, solid_prcp_mean_nopf_weight, prcpsols_std_nopf ] cs = [ 'temp std', 'temp for melt std (mean)', 'tempfmelt_std_quot_hdiff', 'prcp std', 'solid prcp std (mean)', 'prcpsols_std_hstd', 'prcp mean', 'solid prcp mean', 'temp mean', 'temp for melt mean', 'prcp mean nopf', 'prcp mean nopf weighted', 'solid prcp mean nopf', 'solid prcp mean nopf weighted', 'solid prcp std nopf' ] for c, v in zip(cs, var): pd_calib_opt.loc[gd.rgi_id, c] = v ### # validation: no validation right no pd_calib_opt.loc[gd.rgi_id, 'prcp std valid'] = np.NaN pd_calib_opt.loc[gd.rgi_id, 'solid prcp std valid'] = np.NaN else: pd_calib_opt.loc[gd.rgi_id] = np.NaN pd_calib_opt.loc[gd.rgi_id, 'amount_glacmsm'] = len(ys_glac) pd_calib_opt.loc[gd.rgi_id, 'optimisation_possible'] = 'only 1 or less msm>=1979' return pd_calib_opt, gd_mb
def test_monthly_glacier_massbalance(gdir): # TODO: problem with that, monthly and annual MB not exactly the same!!! # I think there is a problem with SEC_IN_MONTH/SEC_IN_YEAR ... # do this for all model types # ONLY TEST it for ERA5dr or ERA5_daily!!! for climate in ['ERA5dr', 'ERA5_daily']: for mb_type in ['mb_monthly', 'mb_daily', 'mb_real_daily']: for grad_type in ['cte', 'var_an_cycle']: if grad_type == 'var_an_cycle': fail_err_4 = ((mb_type == 'mb_monthly') and (climate == 'CRU')) mu_star_opt = mu_star_opt_var else: fail_err_4 = False mu_star_opt = mu_star_opt_cte if climate == 'ERA5dr': cfg.PARAMS['baseline_climate'] = 'ERA5dr' oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset="ERA5dr") elif climate == 'ERA5_daily': process_era5_daily_data(gdir) cfg.PARAMS['baseline_climate'] = 'ERA5_daily' else: tasks.process_climate_data(gdir) pass # mb_type ='mb_daily' fail_err_1 = (mb_type == 'mb_daily') and (climate != 'ERA5dr') fail_err_2 = ((mb_type == 'mb_monthly') and (climate == 'ERA5_daily')) fail_err_3 = ((mb_type == 'mb_real_daily') and (climate != 'ERA5_daily')) if fail_err_1 or fail_err_2 or fail_err_3 or fail_err_4: with pytest.raises(InvalidParamsError): mb_mod = mb_modules(gdir, mu_star_opt[mb_type], mb_type=mb_type, prcp_fac=pf, t_solid=0, t_liq=2, t_melt=0, default_grad=-0.0065, bias=0, grad_type=grad_type) else: # but this is just a test for reproducibility! mb_mod = mb_modules(gdir, mu_star_opt[mb_type], mb_type=mb_type, prcp_fac=pf, t_solid=0, t_liq=2, t_melt=0, default_grad=-0.0065, bias=0, grad_type=grad_type) hgts, widths = gdir.get_inversion_flowline_hw() rho = 900 # ice density yrp = [1980, 2018] for i, yr in enumerate(np.arange(yrp[0], yrp[1] + 1)): my_mon_mb_on_h = 0. dayofyear = 0 for m in np.arange(12): yrm = utils.date_to_floatyear(yr, m + 1) _, dayofmonth = monthrange(yr, m + 1) dayofyear += dayofmonth tmp = (mb_mod.get_monthly_mb(hgts, yrm) * dayofmonth * SEC_IN_DAY * rho) my_mon_mb_on_h += tmp my_an_mb_on_h = (mb_mod.get_annual_mb(hgts, yr) * dayofyear * SEC_IN_DAY * rho) # these large errors might come from the problematic of # different amount of days in a year? # or maybe it just does not fit ... assert_allclose(np.mean(my_an_mb_on_h - my_mon_mb_on_h), 0, atol=100)
def test_present_time_glacier_massbalance(gdir): # check if area of HUSS flowlines corresponds to the rgi area h, w = gdir.get_inversion_flowline_hw() fls = gdir.read_pickle('inversion_flowlines') assert_allclose(gdir.rgi_area_m2, np.sum(w * gdir.grid.dx * fls[0].dx)) # do this for all model types # ONLY TEST it for ERA5dr or ERA5_daily!!! for climate in ['ERA5dr', 'ERA5_daily']: for mb_type in ['mb_monthly', 'mb_daily', 'mb_real_daily']: for grad_type in ['cte', 'var_an_cycle']: if grad_type == 'var_an_cycle': fail_err_4 = ((mb_type == 'mb_monthly') and (climate == 'CRU')) mu_star_opt = mu_star_opt_var else: fail_err_4 = False mu_star_opt = mu_star_opt_cte if climate == 'ERA5dr': cfg.PARAMS['baseline_climate'] = 'ERA5dr' oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset="ERA5dr") elif climate == 'ERA5_daily': cfg.PARAMS['baseline_climate'] = 'ERA5_daily' process_era5_daily_data(gdir) else: tasks.process_climate_data(gdir) pass fail_err_1 = (mb_type == 'mb_daily') and (climate != 'ERA5dr') fail_err_2 = ((mb_type == 'mb_monthly') and (climate == 'ERA5_daily')) fail_err_3 = ((mb_type == 'mb_real_daily') and (climate != 'ERA5_daily')) if fail_err_1 or fail_err_2 or fail_err_3 or fail_err_4: with pytest.raises(InvalidParamsError): mb_mod = mb_modules(gdir, mu_star_opt[mb_type], mb_type=mb_type, prcp_fac=pf, t_solid=0, t_liq=2, t_melt=0, default_grad=-0.0065, bias=0, grad_type=grad_type) else: # this is just a test for reproducibility! mb_mod = mb_modules(gdir, mu_star_opt[mb_type], mb_type=mb_type, prcp_fac=pf, t_solid=0, t_liq=2, t_melt=0, default_grad=-0.0065, bias=0, grad_type=grad_type) mbdf = gdir.get_ref_mb_data() hgts, widths = gdir.get_inversion_flowline_hw() tot_mb = [] refmb = [] grads = hgts * 0 for yr, mb in mbdf.iterrows(): refmb.append(mb['ANNUAL_BALANCE']) mbh = (mb_mod.get_annual_mb(hgts, yr) * SEC_IN_YEAR * cfg.PARAMS['ice_density']) grads += mbh tot_mb.append(np.average(mbh, weights=widths)) grads /= len(tot_mb) # check if calibrated total mass balance similar # to observe mass balance time series assert np.abs(utils.md(tot_mb, refmb)) < 50