diff --git a/oggm/core/dynamic_spinup.py b/oggm/core/dynamic_spinup.py index 2ded5cf28..d952527fd 100644 --- a/oggm/core/dynamic_spinup.py +++ b/oggm/core/dynamic_spinup.py @@ -40,7 +40,7 @@ def run_dynamic_spinup(gdir, init_model_filesuffix=None, init_model_yr=None, store_model_geometry=True, store_fl_diagnostics=None, store_model_evolution=True, ignore_errors=False, return_t_bias_best=False, ye=None, - model_flowline_filesuffix='', + model_flowline_filesuffix='', make_compatible=False, **kwargs): """Dynamically spinup the glacier to match area or volume at the RGI date. @@ -178,6 +178,13 @@ def run_dynamic_spinup(gdir, init_model_filesuffix=None, init_model_yr=None, suffix to the model_flowlines filename to use (if no other flowlines are provided with init_model_filesuffix or init_model_fls). Default is '' + make_compatible : bool + if set to true this will add all variables to the resulting dataset + so it could be combined with any other one. This is necessary if + different spinup methods are used. For example if using the dynamic + spinup and setting fixed geoemtry spinup as fallback, the variable + 'is_fixed_geometry_spinup' must be added to the dynamic spinup so + it is possible to compile both glaciers together. kwargs : dict kwargs to pass to the evolution_model instance @@ -305,7 +312,8 @@ def save_model_without_dynamic_spinup(): yr_run, geom_path=geom_path, diag_path=diag_path, - fl_diag_path=fl_diag_path) + fl_diag_path=fl_diag_path, + make_compatible=make_compatible) return model_dynamic_spinup_end @@ -395,7 +403,8 @@ def run_model_with_spinup_to_rgi_date(t_bias): geom_path=geom_path, diag_path=diag_path, fl_diag_path=fl_diag_path, - dynamic_spinup_min_ice_thick=min_ice_thickness) + dynamic_spinup_min_ice_thick=min_ice_thickness, + make_compatible=make_compatible) if type(ds) == tuple: ds = ds[0] model_area_km2 = ds.area_m2_min_h.loc[yr_rgi].values * 1e-6 @@ -882,10 +891,11 @@ def define_new_mu_star_in_gdir(gdir, new_mu_star, bias=0): def dynamic_mu_star_run_with_dynamic_spinup( gdir, mu_star, yr0_ref_mb, yr1_ref_mb, fls_init, ys, ye, output_filesuffix='', evolution_model=FluxBasedModel, + mb_model_historical=None, mb_model_spinup=None, minimise_for='area', climate_input_filesuffix='', spinup_period=20, - min_spinup_period=10, yr_rgi=None, precision_percent_dyn_spinup=1, - precision_absolute_dyn_spinup=1, min_ice_thickness=None, - first_guess_t_bias=-2, t_bias_max_step_length=2, maxiter_dyn_spinup=30, + min_spinup_period=10, yr_rgi=None, precision_percent=1, + precision_absolute=1, min_ice_thickness=None, + first_guess_t_bias=-2, t_bias_max_step_length=2, maxiter=30, store_model_geometry=True, store_fl_diagnostics=None, local_variables=None, set_local_variables=False, do_inversion=True, **kwargs): @@ -924,6 +934,15 @@ def dynamic_mu_star_run_with_dynamic_spinup( evolution_model : class:oggm.core.FlowlineModel Evolution model to use. Default is FluxBasedModel + mb_model_historical : :py:class:`core.MassBalanceModel` + User-povided MassBalanceModel instance for the historical run. Default + is to use a PastMassBalance model together with the provided + parameter climate_input_filesuffix. + mb_model_spinup : :py:class:`core.MassBalanceModel` + User-povided MassBalanceModel instance for the spinup before the + historical run. Default is to use a ConstantMassBalance model together + with the provided parameter climate_input_filesuffix and during the + period of spinup_start_yr until rgi_year (e.g. 1979 - 2000). minimise_for : str The variable we want to match at yr_rgi. Options are 'area' or 'volume'. Default is 'area'. @@ -947,18 +966,18 @@ def dynamic_mu_star_run_with_dynamic_spinup( The rgi date, at which we want to match area or volume. If None, gdir.rgi_date + 1 is used (the default). Default is None - precision_percent_dyn_spinup : float + precision_percent : float Gives the precision we want to match for the selected variable ('minimise_for') at rgi_date in percent. The algorithm makes sure that the resulting relative mismatch is smaller than precision_percent, but also that the absolute value is smaller than precision_absolute. Default is 1, meaning the difference must be within 1% of the given value (area or volume). - precision_absolute_dyn_spinup : float + precision_absolute : float Gives an minimum absolute value to match. The algorithm makes sure that the resulting relative mismatch is smaller than - precision_percent_dyn_spinup, but also that the absolute value is - smaller than precision_absolute_dyn_spinup. + precision_percent, but also that the absolute value is + smaller than precision_absolute. The unit of precision_absolute depends on minimise_for (if 'area' in km2, if 'volume' in km3) Default is 1. @@ -978,7 +997,7 @@ def dynamic_mu_star_run_with_dynamic_spinup( Defines the maximums allowed change of t_bias between two iteratons. Is needed to avoid to large changes. Default is 2 - maxiter_dyn_spinup : int + maxiter : int Maximum number of minimisation iterations per dynamic spinup where area or volume is tried to be matched. If reached and 'ignore_errors=False' an error is raised. @@ -1042,14 +1061,7 @@ def dynamic_mu_star_run_with_dynamic_spinup( spinup_period = yr_rgi - ys min_ice_thickness = 0 - # Here we start with the actual model run - define_new_mu_star_in_gdir(gdir, mu_star) - - # this variable is used if an inverison is conducted to keep the original - # model_flowline unchanged (-> to be able to conduct different dynamic - # calibration runs in the same gdir) - model_flowline_filesuffix = '' - + # check that inversion is only possible without providing own fls if do_inversion: if not np.all([np.all(getattr(fl_prov, 'surface_h') == getattr(fl_orig, 'surface_h')) and @@ -1063,15 +1075,26 @@ def dynamic_mu_star_run_with_dynamic_spinup( 'provide your own flowlines! (fls_init ' 'should be None or ' 'the original model_flowlines)') + + # Here we start with the actual model run + if mu_star == gdir.read_json('local_mustar')['mu_star_glacierwide']: + # we do not need to define a new mu_star or do an inversion + do_inversion = False + else: + define_new_mu_star_in_gdir(gdir, mu_star) + + if do_inversion: apparent_mb_from_any_mb(gdir) # do inversion with A calibration to current volume calibrate_inversion_from_consensus( [gdir], apply_fs_on_mismatch=True, error_on_mismatch=False, filter_inversion_output=True, volume_m3_reference=local_variables['vol_m3_ref']) - # And finally initialise the new model flowlines - model_flowline_filesuffix = '_dyn_mu_calib' - init_present_time_glacier(gdir, filesuffix=model_flowline_filesuffix) + + # this is used to keep the original model_flowline unchanged (-> to be able + # to conduct different dynamic calibration runs in the same gdir) + model_flowline_filesuffix = '_dyn_mu_calib' + init_present_time_glacier(gdir, filesuffix=model_flowline_filesuffix) # Now do a dynamic spinup to match area # do not ignore errors in dynamic spinup, so all 'bad' files are @@ -1079,17 +1102,21 @@ def dynamic_mu_star_run_with_dynamic_spinup( try: model, last_best_t_bias = run_dynamic_spinup( gdir, + continue_on_error=False, # force to raise an error in @entity_task init_model_fls=fls_init, climate_input_filesuffix=climate_input_filesuffix, - evolution_model=evolution_model, spinup_period=spinup_period, + evolution_model=evolution_model, + mb_model_historical=mb_model_historical, + mb_model_spinup=mb_model_spinup, + spinup_period=spinup_period, spinup_start_yr=ys, spinup_start_yr_max=yr0_ref_mb, min_spinup_period=min_spinup_period, yr_rgi=yr_rgi, - precision_percent=precision_percent_dyn_spinup, - precision_absolute=precision_absolute_dyn_spinup, + precision_percent=precision_percent, + precision_absolute=precision_absolute, min_ice_thickness=min_ice_thickness, t_bias_max_step_length=t_bias_max_step_length, - maxiter=maxiter_dyn_spinup, + maxiter=maxiter, minimise_for=minimise_for, first_guess_t_bias=local_variables['t_bias'][-1], output_filesuffix=output_filesuffix, @@ -1098,6 +1125,7 @@ def dynamic_mu_star_run_with_dynamic_spinup( store_model_geometry=store_model_geometry, store_fl_diagnostics=store_fl_diagnostics, model_flowline_filesuffix=model_flowline_filesuffix, + make_compatible=True, **kwargs) # save the temperature bias which was successful in the last iteration # as we expect we are not so far away in the next iteration (only @@ -1122,10 +1150,11 @@ def dynamic_mu_star_run_with_dynamic_spinup( def dynamic_mu_star_run_with_dynamic_spinup_fallback( gdir, mu_star, fls_init, ys, ye, local_variables, output_filesuffix='', evolution_model=FluxBasedModel, minimise_for='area', + mb_model_historical=None, mb_model_spinup=None, climate_input_filesuffix='', spinup_period=20, min_spinup_period=10, - yr_rgi=None, precision_percent_dyn_spinup=1, - precision_absolute_dyn_spinup=1, min_ice_thickness=10, - first_guess_t_bias=-2, t_bias_max_step_length=2, maxiter_dyn_spinup=30, + yr_rgi=None, precision_percent=1, + precision_absolute=1, min_ice_thickness=10, + first_guess_t_bias=-2, t_bias_max_step_length=2, maxiter=30, store_model_geometry=True, store_fl_diagnostics=None, do_inversion=True, **kwargs): """ @@ -1157,6 +1186,15 @@ def dynamic_mu_star_run_with_dynamic_spinup_fallback( evolution_model : class:oggm.core.FlowlineModel Evolution model to use. Default is FluxBasedModel + mb_model_historical : :py:class:`core.MassBalanceModel` + User-povided MassBalanceModel instance for the historical run. Default + is to use a PastMassBalance model together with the provided + parameter climate_input_filesuffix. + mb_model_spinup : :py:class:`core.MassBalanceModel` + User-povided MassBalanceModel instance for the spinup before the + historical run. Default is to use a ConstantMassBalance model together + with the provided parameter climate_input_filesuffix and during the + period of spinup_start_yr until rgi_year (e.g. 1979 - 2000). minimise_for : str The variable we want to match at yr_rgi. Options are 'area' or 'volume'. Default is 'area'. @@ -1180,18 +1218,18 @@ def dynamic_mu_star_run_with_dynamic_spinup_fallback( The rgi date, at which we want to match area or volume. If None, gdir.rgi_date + 1 is used (the default). Default is None - precision_percent_dyn_spinup : float + precision_percent : float Gives the precision we want to match for the selected variable ('minimise_for') at rgi_date in percent. The algorithm makes sure that the resulting relative mismatch is smaller than precision_percent, but also that the absolute value is smaller than precision_absolute. Default is 1, meaning the difference must be within 1% of the given value (area or volume). - precision_absolute_dyn_spinup : float + precision_absolute : float Gives an minimum absolute value to match. The algorithm makes sure that the resulting relative mismatch is smaller than - precision_percent_dyn_spinup, but also that the absolute value is - smaller than precision_absolute_dyn_spinup. + precision_percent, but also that the absolute value is + smaller than precision_absolute. The unit of precision_absolute depends on minimise_for (if 'area' in km2, if 'volume' in km3) Default is 1. @@ -1211,7 +1249,7 @@ def dynamic_mu_star_run_with_dynamic_spinup_fallback( Defines the maximums allowed change of t_bias between two iteratons. Is needed to avoid to large changes. Default is 2 - maxiter_dyn_spinup : int + maxiter : int Maximum number of minimisation iterations per dynamic spinup where area or volume is tried to be matched. If reached and 'ignore_errors=False' an error is raised. @@ -1270,23 +1308,30 @@ def dynamic_mu_star_run_with_dynamic_spinup_fallback( try: model_end = run_dynamic_spinup( gdir, + continue_on_error=False, # force to raise an error in @entity_task init_model_fls=fls_init, climate_input_filesuffix=climate_input_filesuffix, evolution_model=evolution_model, + mb_model_historical=mb_model_historical, + mb_model_spinup=mb_model_spinup, spinup_period=spinup_period, spinup_start_yr=ys, - min_spinup_period=min_spinup_period, yr_rgi=yr_rgi, + min_spinup_period=min_spinup_period, + yr_rgi=yr_rgi, minimise_for=minimise_for, - precision_percent=precision_percent_dyn_spinup, - precision_absolute=precision_absolute_dyn_spinup, + precision_percent=precision_percent, + precision_absolute=precision_absolute, min_ice_thickness=min_ice_thickness, first_guess_t_bias=first_guess_t_bias, t_bias_max_step_length=t_bias_max_step_length, - maxiter=maxiter_dyn_spinup, + maxiter=maxiter, output_filesuffix=output_filesuffix, store_model_geometry=store_model_geometry, store_fl_diagnostics=store_fl_diagnostics, - ignore_errors=False, ye=ye, **kwargs) + ignore_errors=False, + ye=ye, + make_compatible=True, + **kwargs) gdir.add_to_diagnostics('used_spinup_option', 'dynamic spinup only') @@ -1390,7 +1435,10 @@ def dynamic_mu_star_run( # conduct model run try: - model = run_from_climate_data(gdir, ys=ys, ye=ye, + model = run_from_climate_data(gdir, + # force to raise an error in @entity_task + continue_on_error=False, + ys=ys, ye=ye, output_filesuffix=output_filesuffix, init_model_fls=fls_init, evolution_model=evolution_model, @@ -1458,7 +1506,10 @@ def dynamic_mu_star_run_fallback( # conduct model run try: - model = run_from_climate_data(gdir, ys=ys, ye=ye, + model = run_from_climate_data(gdir, + # force to raise an error in @entity_task + continue_on_error=False, + ys=ys, ye=ye, output_filesuffix=output_filesuffix, init_model_fls=fls_init, evolution_model=evolution_model, @@ -1475,7 +1526,7 @@ def dynamic_mu_star_run_fallback( def run_dynamic_mu_star_calibration( gdir, ref_dmdtda=None, err_ref_dmdtda=None, ref_period='', ignore_hydro_months=False, min_mu_star=None, - max_mu_star=None, mu_star_max_step_length=5, maxiter_mu_star=20, + max_mu_star=None, mu_star_max_step_length=5, maxiter=20, ignore_errors=False, output_filesuffix='_dynamic_mu_star', ys=None, ye=None, run_function=dynamic_mu_star_run_with_dynamic_spinup, @@ -1530,7 +1581,7 @@ def run_dynamic_mu_star_calibration( Defines the maximum allowed change of mu_star between two iteratons. Is needed to avoid to large changes. Default is 5 - maxiter_mu_star : int + maxiter : int Maximum number of minimisation iterations of minimising mismatch to dmdtda by changing mu_star. Each of this iterations conduct a complete run defined in the 'run_function'. If maxiter_mu_star reached and @@ -1883,6 +1934,7 @@ def get_mismatch(mu_star): # in this loop if an error at the limits is raised we go step by # step away from the limits until we are at the initial guess or we # found an error free run + tmp_mismatch = None while ((current_min_error | current_max_error | iteration == 0) & (iteration < max_iterations)): try: @@ -1961,6 +2013,10 @@ def get_mismatch(mu_star): elif current_max_error: mu_star_limits[1] = copy.deepcopy(mu_star) + if tmp_mismatch is None: + raise RuntimeError('Not able to find a new mismatch for ' + 'dmdtda!') + return float(tmp_mismatch), float(mu_star) # first guess @@ -1990,7 +2046,7 @@ def get_mismatch(mu_star): return mismatch[-1], new_mu_star # Now start with splin fit for guessing - while len(mu_star_guess) < maxiter_mu_star: + while len(mu_star_guess) < maxiter: # get next guess from splin (fit partial linear function to # previously calculated (mismatch, mu_star) pairs and get mu_star # value where mismatch=0 from this fitted curve) @@ -2024,7 +2080,7 @@ def get_mismatch(mu_star): raise RuntimeError(f'Could not find mismatch smaller ' f'{err_ref_dmdtda} kg m-2 yr-1 (only ' f'{np.min(np.abs(mismatch))} kg m-2 yr-1) in ' - f'{maxiter_mu_star} Iterations!') + f'{maxiter} Iterations!') # wrapper to get values for intermediate (mismatch, mu_star) guesses if an # error is raised @@ -2066,16 +2122,16 @@ def minimiser(fct_to_minimise): log.workflow('Dynamic mu star calibration not successful. Error ' f'message: {e}') - only_first_guess = False - # if we only conducted one successful run: only the first guess - # worked without an error - if len(mismatch_dmdtda) == 1: - only_first_guess = True - # there where some successful runs so we return the one with the # smallest mismatch of dmdtda min_mismatch_index = np.argmin(np.abs(mismatch_dmdtda)) mu_star_best = np.array(mu_star_guesses)[min_mismatch_index] + + # check if the first guess was the best guess + only_first_guess = False + if min_mismatch_index == 1: + only_first_guess = True + model_return = fallback_run( mu_star=mu_star_best, reset=False, best_mismatch=np.array(mismatch_dmdtda)[min_mismatch_index], diff --git a/oggm/core/flowline.py b/oggm/core/flowline.py index 224479e22..429f30432 100644 --- a/oggm/core/flowline.py +++ b/oggm/core/flowline.py @@ -933,6 +933,7 @@ def run_until_and_store(self, y1, stop_criterion=None, fixed_geometry_spinup_yr=None, dynamic_spinup_min_ice_thick=None, + make_compatible=False ): """Runs the model and returns intermediate steps in xarray datasets. @@ -991,6 +992,13 @@ def run_until_and_store(self, y1, area or the total volume. This is useful to smooth out yearly fluctuations when matching to observations. The names of this new variables include the suffix _min_h (e.g. 'area_m2_min_h') + make_compatible : bool + if set to true this will add all variables to the resulting dataset + so it could be combined with any other one. This is necessary if + different spinup methods are used. For example if using the dynamic + spinup and setting fixed geoemtry spinup as fallback, the variable + 'is_fixed_geometry_spinup' must be added to the dynamic spinup so + it is possible to compile both glaciers together. Returns ------- geom_ds : xarray.Dataset or None @@ -1161,6 +1169,12 @@ def run_until_and_store(self, y1, desc = 'Part of the series which are spinup' diag_ds['is_fixed_geometry_spinup'].attrs['description'] = desc diag_ds['is_fixed_geometry_spinup'].attrs['unit'] = '-' + elif make_compatible: + is_spinup_time = np.full(len(monthly_time), False, dtype=np.bool) + diag_ds['is_fixed_geometry_spinup'] = ('time', is_spinup_time) + desc = 'Part of the series which are spinup' + diag_ds['is_fixed_geometry_spinup'].attrs['description'] = desc + diag_ds['is_fixed_geometry_spinup'].attrs['unit'] = '-' fl_diag_dss = None if do_fl_diag: diff --git a/oggm/tests/test_models.py b/oggm/tests/test_models.py index ed74a6bd5..0b56f3cd9 100644 --- a/oggm/tests/test_models.py +++ b/oggm/tests/test_models.py @@ -3774,13 +3774,13 @@ def test_run_dynamic_mu_star_calibration_with_dynamic_spinup(self, gdir, max_mu_star=1000., run_function=dynamic_mu_star_run_with_dynamic_spinup, kwargs_run_function={'minimise_for': minimise_for, - 'precision_percent_dyn_spinup': precision_percent, - 'precision_absolute_dyn_spinup': precision_absolute, + 'precision_percent': precision_percent, + 'precision_absolute': precision_absolute, 'do_inversion': do_inversion}, fallback_function=dynamic_mu_star_run_with_dynamic_spinup_fallback, kwargs_fallback_function={'minimise_for': minimise_for, - 'precision_percent_dyn_spinup': precision_percent, - 'precision_absolute_dyn_spinup': precision_absolute, + 'precision_percent': precision_percent, + 'precision_absolute': precision_absolute, 'do_inversion': do_inversion}, output_filesuffix='_dyn_mu_calib_spinup_inversion', ys=1979, ye=ye) @@ -3834,13 +3834,13 @@ def test_run_dynamic_mu_star_calibration_with_dynamic_spinup(self, gdir, max_mu_star=1000., run_function=dynamic_mu_star_run_with_dynamic_spinup, kwargs_run_function={'minimise_for': minimise_for, - 'precision_percent_dyn_spinup': precision_percent, - 'precision_absolute_dyn_spinup': precision_absolute, + 'precision_percent': precision_percent, + 'precision_absolute': precision_absolute, 'do_inversion': do_inversion}, fallback_function=dynamic_mu_star_run_with_dynamic_spinup_fallback, kwargs_fallback_function={'minimise_for': minimise_for, - 'precision_percent_dyn_spinup': precision_percent, - 'precision_absolute_dyn_spinup': precision_absolute, + 'precision_percent': precision_percent, + 'precision_absolute': precision_absolute, 'do_inversion': do_inversion}, output_filesuffix='_dyn_mu_calib_spinup_inversion', ys=1979, ye=ye, init_model_fls=fls) @@ -3860,13 +3860,13 @@ def test_run_dynamic_mu_star_calibration_with_dynamic_spinup(self, err_ref_dmdtda=err_ref_dmdtda + delta_err_ref_dmdtda, run_function=dynamic_mu_star_run_with_dynamic_spinup, kwargs_run_function={'minimise_for': minimise_for, - 'precision_percent_dyn_spinup': precision_percent, - 'precision_absolute_dyn_spinup': precision_absolute, + 'precision_percent': precision_percent, + 'precision_absolute': precision_absolute, 'do_inversion': do_inversion}, fallback_function=dynamic_mu_star_run_with_dynamic_spinup_fallback, kwargs_fallback_function={'minimise_for': minimise_for, - 'precision_percent_dyn_spinup': precision_percent, - 'precision_absolute_dyn_spinup': precision_absolute, + 'precision_percent': precision_percent, + 'precision_absolute': precision_absolute, 'do_inversion': do_inversion}, output_filesuffix='_dyn_mu_calib_spinup_inversion_user_dmdtda', ys=1979, ye=ye) @@ -3902,25 +3902,25 @@ def test_run_dynamic_mu_star_calibration_with_dynamic_spinup(self, output_filesuffix='_dyn_mu_calib_spinup_inversion_error', ignore_errors=False, ref_dmdtda=ref_dmdtda, err_ref_dmdtda=0.000001, - maxiter_mu_star=2) + maxiter=2) # test that fallback function works as expected if ignore_error=True and # if the first guess can improve (but not enough) model_fallback = run_dynamic_mu_star_calibration( gdir, max_mu_star=1000., run_function=dynamic_mu_star_run_with_dynamic_spinup, kwargs_run_function={'minimise_for': minimise_for, - 'precision_percent_dyn_spinup': precision_percent, - 'precision_absolute_dyn_spinup': precision_absolute, + 'precision_percent': precision_percent, + 'precision_absolute': precision_absolute, 'do_inversion': do_inversion}, fallback_function=dynamic_mu_star_run_with_dynamic_spinup_fallback, kwargs_fallback_function={'minimise_for': minimise_for, - 'precision_percent_dyn_spinup': precision_percent, - 'precision_absolute_dyn_spinup': precision_absolute, + 'precision_percent': precision_percent, + 'precision_absolute': precision_absolute, 'do_inversion': do_inversion}, output_filesuffix='_dyn_mu_calib_spinup_inversion_error', ignore_errors=True, ref_dmdtda=ref_dmdtda, err_ref_dmdtda=0.000001, - maxiter_mu_star=2) + maxiter=2) assert isinstance(model_fallback, oggm.core.flowline.FluxBasedModel) assert gdir.get_diagnostics()['used_spinup_option'] == \ 'dynamic mu_star calibration (part success)' @@ -3944,20 +3944,20 @@ def test_run_dynamic_mu_star_calibration_with_dynamic_spinup(self, gdir, max_mu_star=1000., run_function=dynamic_mu_star_run_with_dynamic_spinup, kwargs_run_function={'minimise_for': minimise_for, - 'precision_percent_dyn_spinup': 0.1, - 'precision_absolute_dyn_spinup': 0.0001, - 'maxiter_dyn_spinup': 2, + 'precision_percent': 0.1, + 'precision_absolute': 0.0001, + 'maxiter': 2, 'do_inversion': do_inversion}, fallback_function=dynamic_mu_star_run_with_dynamic_spinup_fallback, kwargs_fallback_function={'minimise_for': minimise_for, - 'precision_percent_dyn_spinup': 0.1, - 'precision_absolute_dyn_spinup': 0.0001, - 'maxiter_dyn_spinup': 2, + 'precision_percent': 0.1, + 'precision_absolute': 0.0001, + 'maxiter': 2, 'do_inversion': do_inversion}, output_filesuffix='_dyn_mu_calib_spinup_inversion_error', ignore_errors=True, ref_dmdtda=ref_dmdtda, err_ref_dmdtda=0.000001, - maxiter_mu_star=2) + maxiter=2) assert isinstance(model_fallback, oggm.core.flowline.FluxBasedModel) assert gdir.get_diagnostics()['used_spinup_option'] == \ 'fixed geometry spinup' @@ -4151,7 +4151,7 @@ def test_run_dynamic_mu_star_calibration_without_dynamic_spinup(self): output_filesuffix='_dyn_mu_calib_error', ignore_errors=False, ref_dmdtda=ref_dmdtda, err_ref_dmdtda=0.000001, - maxiter_mu_star=2) + maxiter=2) # test that fallback function works as expected if ignore_error=True and # if the first guess can improve (but not enough) model_fallback = run_dynamic_mu_star_calibration( @@ -4161,7 +4161,7 @@ def test_run_dynamic_mu_star_calibration_without_dynamic_spinup(self): output_filesuffix='_dyn_mu_calib_spinup_inversion_error', ignore_errors=True, ref_dmdtda=ref_dmdtda, err_ref_dmdtda=0.000001, - maxiter_mu_star=2) + maxiter=2) assert isinstance(model_fallback, oggm.core.flowline.FluxBasedModel) assert gdir.get_diagnostics()['used_spinup_option'] == \ 'dynamic mu_star calibration (part success)' @@ -4176,7 +4176,7 @@ def test_run_dynamic_mu_star_calibration_without_dynamic_spinup(self): output_filesuffix='_dyn_mu_calib_error', ignore_errors=True, ref_dmdtda=ref_dmdtda, err_ref_dmdtda=0.000001, - maxiter_mu_star=2) + maxiter=2) assert isinstance(model_fallback, oggm.core.flowline.FluxBasedModel) assert gdir.get_diagnostics()['used_spinup_option'] == 'no spinup' diff --git a/oggm/tests/test_utils.py b/oggm/tests/test_utils.py index bd2bac588..c424ffe72 100644 --- a/oggm/tests/test_utils.py +++ b/oggm/tests/test_utils.py @@ -1247,7 +1247,7 @@ def test_elev_bands_and_spinup_run(self): # Around RGI date they are close # have to exclude rgi_id 'RGI60-11.00719_d02', because no dmdtda data assert_allclose(dss.sel(time=2004).area[1:], dse.sel(time=2004).area[1:], rtol=0.01) - assert_allclose(dss.sel(time=2004).length[1:], dse.sel(time=2004).length[1:], atol=805) + assert_allclose(dss.sel(time=2004).length[1:], dse.sel(time=2004).length[1:], atol=940) assert_allclose(dss.sel(time=2004).volume[1:], dse.sel(time=2004).volume[1:], rtol=0.21) # Over the period they are... close enough diff --git a/oggm/tests/test_workflow.py b/oggm/tests/test_workflow.py index f6a325610..0c49377fb 100644 --- a/oggm/tests/test_workflow.py +++ b/oggm/tests/test_workflow.py @@ -223,7 +223,6 @@ def test_calibrate_inversion_from_consensus(self): gdirs, ignore_missing=True, volume_m3_reference=user_provided_volume_m3) - df = df.dropna() np.testing.assert_allclose(user_provided_volume_m3, df.vol_oggm_m3.sum(), rtol=0.01) diff --git a/oggm/workflow.py b/oggm/workflow.py index 06a7ae681..995b79519 100644 --- a/oggm/workflow.py +++ b/oggm/workflow.py @@ -740,7 +740,12 @@ def compute_vol(x): filter_inversion_output=filter_inversion_output) odf = df.copy() odf['oggm'] = execute_entity_task(tasks.get_inversion_volume, gdirs) - return odf.dropna() + # if the user provides a glacier volume all glaciers are considered, + # dropna() below exclude glaciers where no ITMIX volume is available + if volume_m3_reference is None: + return odf.dropna() + else: + return odf def to_minimize(x): log.workflow('Consensus estimate optimisation with '