From 52adc2cb2e5bf9102b40ab26fc7ba026f72fe58a Mon Sep 17 00:00:00 2001 From: Fabien Maussion Date: Tue, 6 Sep 2022 17:32:26 +0200 Subject: [PATCH] Allow special MB models to work even without t* --- oggm/core/climate.py | 20 ++++---------------- oggm/core/massbalance.py | 24 +++++++++++++++++++----- oggm/tests/test_models.py | 6 ++++++ oggm/utils/_workflow.py | 15 ++++++++++++--- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/oggm/core/climate.py b/oggm/core/climate.py index 6051b0f19..21a55dadb 100644 --- a/oggm/core/climate.py +++ b/oggm/core/climate.py @@ -541,10 +541,7 @@ def mb_climate_on_height(gdir, heights, *, time_range=None, year_range=None): "None if using a winter_prcp_factor") # Have we decided on a factor yet? - try: - df = gdir.read_json('local_mustar') - except FileNotFoundError: - df = {} + df = gdir.read_json('local_mustar', allow_empty=True) prcp_fac = df.get('glacier_prcp_scaling_factor') if prcp_fac is None: # Then decide and store @@ -924,10 +921,7 @@ def _fallback_local_t_star(gdir): """ # Scalars in a small dict for later - try: - df = gdir.read_json('local_mustar') - except FileNotFoundError: - df = {} + df = gdir.read_json('local_mustar', allow_empty=True) df['rgi_id'] = gdir.rgi_id df['t_star'] = np.nan df['bias'] = np.nan @@ -1062,10 +1056,7 @@ def local_t_star(gdir, *, ref_df=None, tstar=None, bias=None, '{:.2f}'.format(gdir.rgi_id, mustar)) # Scalars in a small dict for later - try: - df = gdir.read_json('local_mustar') - except FileNotFoundError: - df = {} + df = gdir.read_json('local_mustar', allow_empty=True) df['rgi_id'] = gdir.rgi_id df['t_star'] = int(tstar) df['bias'] = bias @@ -1574,10 +1565,7 @@ def mu_star_calibration_from_geodetic_mb(gdir, gdir.write_json(out, 'climate_info') # Store diagnostics - try: - df = gdir.read_json('local_mustar') - except FileNotFoundError: - df = {} + df = gdir.read_json('local_mustar', allow_empty=True) df['rgi_id'] = gdir.rgi_id df['t_star'] = np.nan df['bias'] = 0 diff --git a/oggm/core/massbalance.py b/oggm/core/massbalance.py index cf1f266bf..c2856656e 100644 --- a/oggm/core/massbalance.py +++ b/oggm/core/massbalance.py @@ -633,7 +633,8 @@ def __init__(self, gdir, mu_star=None, bias=None, you want to use (the default is to use the calibrated value) y0 : int, optional, default: tstar the year at the center of the period of interest. The default - is to use tstar as center. + is to use tstar as center. If t_star is not available, raises + an error. halfsize : int, optional the half-size of the time window (window size = 2 * halfsize + 1) filename : str, optional @@ -651,7 +652,10 @@ def __init__(self, gdir, mu_star=None, bias=None, if y0 is None: df = gdir.read_json('local_mustar') - y0 = df['t_star'] + y0 = df.get('t_star', np.NaN) + if not np.isfinite(y0): + raise InvalidParamsError('t_star has not been set for this ' + 'glacier. Please set `y0` explicitly') # This is a quick'n dirty optimisation try: @@ -851,7 +855,10 @@ def __init__(self, gdir, mu_star=None, bias=None, if y0 is None: df = gdir.read_json('local_mustar') - y0 = df['t_star'] + y0 = df.get('t_star', np.NaN) + if not np.isfinite(y0): + raise InvalidParamsError('t_star has not been set for this ' + 'glacier. Please set `y0` explicitly') self.mbmod = PastMassBalance(gdir, mu_star=mu_star, bias=bias, filename=filename, @@ -950,7 +957,10 @@ def __init__(self, gdir, mu_star=None, bias=None, else: if y0 is None: df = gdir.read_json('local_mustar') - y0 = df['t_star'] + y0 = df.get('t_star', np.NaN) + if not np.isfinite(y0): + raise InvalidParamsError('t_star has not been set for this ' + 'glacier. Please set `y0` explicitly') self.years = np.arange(y0 - halfsize, y0 + halfsize + 1) else: self.rng = None @@ -1247,7 +1257,11 @@ def __init__(self, gdir, fls=None, mu_star=None, fl.rgi_id != gdir.rgi_id) and (_y0 is None): df = gdir.read_json('local_mustar', filesuffix='_' + fl.rgi_id) - kwargs['y0'] = df['t_star'] + y0 = df.get('t_star', np.NaN) + if not np.isfinite(y0): + raise InvalidParamsError('t_star has not been set for this ' + 'glacier. Please set `y0` explicitly') + kwargs['y0'] = y0 self.flowline_mb_models.append( mb_model_class(gdir, mu_star=fl.mu_star, bias=fl_bias, diff --git a/oggm/tests/test_models.py b/oggm/tests/test_models.py index 4bb246638..c5b66288c 100644 --- a/oggm/tests/test_models.py +++ b/oggm/tests/test_models.py @@ -1065,10 +1065,16 @@ def test_hef_mu_star_calibration_from_geodetic_mb(self, hef_gdir): np.testing.assert_allclose(ref_mb_geodetic, mb_modelled.mean()) np.testing.assert_allclose(pf, 3.35713, rtol=1e-4) + + with pytest.raises(InvalidParamsError): + # This does not work + mb = massbalance.ConstantMassBalance(gdir) + cfg.PARAMS['use_winter_prcp_factor'] = False cfg.PARAMS['prcp_scaling_factor'] = prev_fac + class TestModelFlowlines(): def test_rectangular(self): diff --git a/oggm/utils/_workflow.py b/oggm/utils/_workflow.py index 0bcf64834..75689fd6b 100644 --- a/oggm/utils/_workflow.py +++ b/oggm/utils/_workflow.py @@ -3067,7 +3067,7 @@ def write_pickle(self, var, filename, use_compression=None, filesuffix=''): with _open(fp, 'wb') as f: pickle.dump(var, f, protocol=4) - def read_json(self, filename, filesuffix=''): + def read_json(self, filename, filesuffix='', allow_empty=False): """Reads a JSON file located in the directory. Parameters @@ -3076,6 +3076,8 @@ def read_json(self, filename, filesuffix=''): file name (must be listed in cfg.BASENAME) filesuffix : str append a suffix to the filename (useful for experiments). + allow_empty : bool + if True, does not raise an error if the file is not there. Returns ------- @@ -3087,8 +3089,15 @@ def read_json(self, filename, filesuffix=''): return self._read_deprecated_climate_info() fp = self.get_filepath(filename, filesuffix=filesuffix) - with open(fp, 'r') as f: - out = json.load(f) + if allow_empty: + try: + with open(fp, 'r') as f: + out = json.load(f) + except FileNotFoundError: + out = {} + else: + with open(fp, 'r') as f: + out = json.load(f) return out def write_json(self, var, filename, filesuffix=''):