def test_mb_modules_monthly(gdir): # check if massbalance.PastMassBalance equal to mb_modules with cte # gradient and mb_monthly as options for lapse rate mb_type mu_star_opt_cte_var = 195.5484547754791 # if I use ERA5dr in PastMassBalance, it applies automatically the # gradient that changes with time and location mu_opts = [mu_star_opt_cte['mb_monthly'], mu_star_opt_cte_var] grads = ['cte', 'var'] for k, clim in zip([0, 1], ['ERA5', 'ERA5dr']): mu_opt = mu_opts[k] grad_type = grads[k] cfg.PARAMS['baseline_climate'] = clim oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset=clim) mb_mod = mb_modules(gdir, mu_opt, mb_type='mb_monthly', prcp_fac=2.5, 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() mbdf = gdir.get_ref_mb_data() tot_mb = mb_mod.get_specific_mb(heights=hgts, widths=widths, year=mbdf.index.values) cfg.PARAMS['temp_default_gradient'] = -0.0065 cfg.PARAMS['prcp_scaling_factor'] = 2.5 cfg.PARAMS['temp_all_solid'] = 0 cfg.PARAMS['temp_all_liq'] = 2 cfg.PARAMS['temp_melt'] = 0 # check if the default OGGM monthly mass balance with cte gradient # gives the same result as the new mb_modules with the options # mb_monthly and constant lapse rate gradient! mb_mod_default = massbalance.PastMassBalance(gdir, mu_star=mu_opt, bias=0, check_calib_params=False) tot_mb_default = mb_mod_default.get_specific_mb(heights=hgts, widths=widths, year=mbdf.index.values) assert_allclose(tot_mb, tot_mb_default, rtol=1e-4)
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_N(gdir): # tests whether modelled mb_daily massbalances of different values of N # is similar to observed mass balances # this could be optimised and included in the above tests climate = 'ERA5dr' mb_type = 'mb_daily' cfg.PARAMS['baseline_climate'] = 'ERA5dr' oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset="ERA5dr") 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 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: mbdf = gdir.get_ref_mb_data() hgts, widths = gdir.get_inversion_flowline_hw() tot_mb_N = {} for N in [10000, 5000, 1000, 500, 100]: mb_mod = mb_modules(gdir, mu_star_opt[mb_type], mb_type=mb_type, prcp_fac=pf, N=N, t_solid=0, t_liq=2, t_melt=0, default_grad=-0.0065, bias=0, grad_type=grad_type) tot_mb_N[N] = mb_mod.get_specific_mb(heights=hgts, widths=widths, year=mbdf.index.values) assert np.abs(utils.md(tot_mb_N[N], mbdf['ANNUAL_BALANCE'])) < 10 # %% # something like that could also be included later on # bbut only if I somehow get the data from the climate files .... # or can I use these things with the ELA... without the climate files... # in the moment oggm.core.climate works only with default OGGM mass balance # def test_mb_modules(self, hef_gdir): # rho = cfg.PARAMS['ice_density'] # F = SEC_IN_YEAR * rho # gdir = hef_gdir # init_present_time_glacier(gdir) # df = gdir.read_json('local_mustar') # mu_star = df['mu_star_glacierwide'] # bias = df['bias'] # # Climate period # yrp = [1851, 2000] # # Flowlines height # h, w = gdir.get_inversion_flowline_hw() # mb_mod = massbalance.PastMassBalance(gdir, bias=0) # for i, yr in enumerate(np.arange(yrp[0], yrp[1]+1)): # ref_mb_on_h = p[:, i] - mu_star * t[:, i] # my_mb_on_h = mb_mod.get_annual_mb(h, yr) * F # np.testing.assert_allclose(ref_mb_on_h, my_mb_on_h, # atol=1e-2) # ela_z = mb_mod.get_ela(year=yr) # totest = mb_mod.get_annual_mb([ela_z], year=yr) * F # assert_allclose(totest[0], 0, atol=1) # mb_mod = massbalance.PastMassBalance(gdir) # for i, yr in enumerate(np.arange(yrp[0], yrp[1]+1)): # ref_mb_on_h = p[:, i] - mu_star * t[:, i] # my_mb_on_h = mb_mod.get_annual_mb(h, yr) * F # np.testing.assert_allclose(ref_mb_on_h, my_mb_on_h + bias, # atol=1e-2) # ela_z = mb_mod.get_ela(year=yr) # totest = mb_mod.get_annual_mb([ela_z], year=yr) * F # assert_allclose(totest[0], 0, atol=1) # for i, yr in enumerate(np.arange(yrp[0], yrp[1]+1)): # ref_mb_on_h = p[:, i] - mu_star * t[:, i] # my_mb_on_h = ref_mb_on_h*0. # for m in np.arange(12): # yrm = utils.date_to_floatyear(yr, m + 1) # tmp = mb_mod.get_monthly_mb(h, yrm) * SEC_IN_MONTH * rho # my_mb_on_h += tmp # np.testing.assert_allclose(ref_mb_on_h, # my_mb_on_h + bias, # atol=1e-2) # # real data # h, w = gdir.get_inversion_flowline_hw() # mbdf = gdir.get_ref_mb_data() # mbdf.loc[yr, 'MY_MB'] = np.NaN # mb_mod = massbalance.PastMassBalance(gdir) # for yr in mbdf.index.values: # my_mb_on_h = mb_mod.get_annual_mb(h, yr) * SEC_IN_YEAR * rho # mbdf.loc[yr, 'MY_MB'] = np.average(my_mb_on_h, weights=w) # np.testing.assert_allclose(mbdf['ANNUAL_BALANCE'].mean(), # mbdf['MY_MB'].mean(), # atol=1e-2) # mbdf['MY_ELA'] = mb_mod.get_ela(year=mbdf.index.values) # assert mbdf[['MY_ELA', 'MY_MB']].corr().values[0, 1] < -0.9 # assert mbdf[['MY_ELA', 'ANNUAL_BALANCE']].corr().values[0, 1] < -0.7 # mb_mod = massbalance.PastMassBalance(gdir, bias=0) # for yr in mbdf.index.values: # my_mb_on_h = mb_mod.get_annual_mb(h, yr) * SEC_IN_YEAR * rho # mbdf.loc[yr, 'MY_MB'] = np.average(my_mb_on_h, weights=w) # np.testing.assert_allclose(mbdf['ANNUAL_BALANCE'].mean() + bias, # mbdf['MY_MB'].mean(), # atol=1e-2) # mb_mod = massbalance.PastMassBalance(gdir) # for yr in mbdf.index.values: # my_mb_on_h = mb_mod.get_annual_mb(h, yr) * SEC_IN_YEAR * rho # mbdf.loc[yr, 'MY_MB'] = np.average(my_mb_on_h, weights=w) # mb_mod.temp_bias = 1 # my_mb_on_h = mb_mod.get_annual_mb(h, yr) * SEC_IN_YEAR * rho # mbdf.loc[yr, 'BIASED_MB'] = np.average(my_mb_on_h, weights=w) # mb_mod.temp_bias = 0 # np.testing.assert_allclose(mbdf['ANNUAL_BALANCE'].mean(), # mbdf['MY_MB'].mean(), # atol=1e-2) # assert mbdf.ANNUAL_BALANCE.mean() > mbdf.BIASED_MB.mean() # # Repeat # mb_mod = massbalance.PastMassBalance(gdir, repeat=True, # ys=1901, ye=1950) # yrs = np.arange(100) + 1901 # mb = mb_mod.get_specific_mb(h, w, year=yrs) # assert_allclose(mb[50], mb[-50])
def test_loop(gdir): # tests whether ERA5dr works better with or without the loop in mb_daily # tests that both option give same results and in case that default option # (no loop) is 30% slower, it raises an error # this could be optimised and included in the above tests cfg.initialize() climate = 'ERA5dr' mb_type = 'mb_daily' cfg.PARAMS['baseline_climate'] = 'ERA5dr' oggm.shop.ecmwf.process_ecmwf_data(gdir, dataset="ERA5dr") 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 fail_err_4: with pytest.raises(InvalidParamsError): 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: mbdf = gdir.get_ref_mb_data() ys = mbdf.index.values hgts, widths = gdir.get_inversion_flowline_hw() ex_t = time.time() for t in np.arange(10): mb_mod_noloop = mb_modules(gdir, mu_star_opt[mb_type], mb_type=mb_type, prcp_fac=pf, loop=False, t_solid=0, t_liq=2, t_melt=0, default_grad=-0.0065, bias=0, grad_type=grad_type) tot_mb_noloop = mb_mod_noloop.get_specific_mb(heights=hgts, widths=widths, year=ys) ex_noloop = time.time() - ex_t ex_t = time.time() for t in np.arange(10): mb_mod_loop = mb_modules(gdir, mu_star_opt[mb_type], mb_type=mb_type, prcp_fac=pf, loop=True, t_solid=0, t_liq=2, t_melt=0, default_grad=-0.0065, bias=0, grad_type=grad_type) tot_mb_loop = mb_mod_loop.get_specific_mb(heights=hgts, widths=widths, year=ys) ex_loop = time.time() - ex_t # both should give the same results!!! assert_allclose(tot_mb_loop, tot_mb_noloop, atol=1e-2) # if the loop would be at least 30% faster than not using the loop # raise an error assert (ex_loop - ex_noloop) / ex_noloop > -0.3
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