diff --git a/.gitignore b/.gitignore index 764c476c0..ce29038a1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,9 @@ __pycache__ # asv stuff .asv/ -# PyCharm stuffs +# IDE stuffs .idea/ +.vscode/ # coverage stuffs .coverage @@ -42,3 +43,4 @@ docs/_sources docs/_images docs/.doctrees oggm/version.py +oggm/ignore diff --git a/oggm/core/massbalance.py b/oggm/core/massbalance.py index c25e787c4..eab32d705 100644 --- a/oggm/core/massbalance.py +++ b/oggm/core/massbalance.py @@ -1,7 +1,9 @@ """Mass-balance models""" # Built ins +import logging # External libs import numpy as np +import pandas as pd import netCDF4 from scipy.interpolate import interp1d from scipy import optimize as optimization @@ -12,7 +14,10 @@ date_to_floatyear, monthly_timeseries, ncDataset, tolist, clip_min, clip_max, clip_array) from oggm.exceptions import InvalidWorkflowError +from oggm import entity_task +# Module logger +log = logging.getLogger(__name__) class MassBalanceModel(object, metaclass=SuperclassMeta): """Common logic for the mass balance models. @@ -1122,3 +1127,60 @@ def get_ela(self, year=None, **kwargs): areas = np.append(areas, np.sum(fl.widths)) return np.average(elas, weights=areas) + + +@entity_task(log) +def fixed_geometry_mass_balance(gdir, ys=None, ye=None, years=None, + monthly_step=False, + climate_filename='climate_historical', + climate_input_filesuffix=''): + """Runs a glacier with climate input from e.g. CRU or a GCM. + + This will initialize a + :py:class:`oggm.core.massbalance.MultipleFlowlineMassBalance`, + and run a :py:func:`oggm.core.flowline.robust_model_run`. + + Parameters + ---------- + gdir : :py:class:`oggm.GlacierDirectory` + the glacier directory to process + ys : int + start year of the model run (default: from the climate file) + date) + ye : int + end year of the model run (default: from the climate file) + years : array of ints + override ys and ye with the years of your choice + monthly_step : bool + whether to store the diagnostic data at a monthly time step or not + (default is yearly) + climate_filename : str + name of the climate file, e.g. 'climate_historical' (default) or + 'gcm_data' + climate_input_filesuffix: str + filesuffix for the input climate file + """ + + if monthly_step: + raise NotImplementedError('monthly_step not implemented yet') + + try: + mb = MultipleFlowlineMassBalance(gdir, mb_model_class=PastMassBalance, + filename=climate_filename, + input_filesuffix=climate_input_filesuffix) + except InvalidWorkflowError: + mb = MultipleFlowlineMassBalance(gdir, mb_model_class=PastMassBalance, + filename=climate_filename, + use_inversion_flowlines=True, + input_filesuffix=climate_input_filesuffix) + + if years is None: + if ys is None: + ys = mb.flowline_mb_models[0].ys + if ye is None: + ye = mb.flowline_mb_models[0].ye + years = np.arange(ys, ye + 1) + + odf = pd.Series(data=mb.get_specific_mb(year=years), + index=years) + return odf diff --git a/oggm/tasks.py b/oggm/tasks.py index d4e258bc1..90917a3fa 100644 --- a/oggm/tasks.py +++ b/oggm/tasks.py @@ -35,6 +35,7 @@ from oggm.core.climate import local_t_star from oggm.core.climate import mu_star_calibration from oggm.core.climate import apparent_mb_from_linear_mb +from oggm.core.massbalance import fixed_geometry_mass_balance from oggm.core.inversion import prepare_for_inversion from oggm.core.inversion import mass_conservation_inversion from oggm.core.inversion import filter_inversion_output diff --git a/oggm/tests/test_benchmarks.py b/oggm/tests/test_benchmarks.py index d5d68b990..0d7d81a7e 100644 --- a/oggm/tests/test_benchmarks.py +++ b/oggm/tests/test_benchmarks.py @@ -425,6 +425,9 @@ def test_workflow(self): df = utils.compile_glacier_statistics(gdirs) assert df.inv_thickness_m[0] < 100 + df = utils.compile_fixed_geometry_mass_balance(gdirs) + assert len(df) > 100 + if do_plot: import matplotlib.pyplot as plt from oggm.graphics import plot_inversion diff --git a/oggm/tests/test_models.py b/oggm/tests/test_models.py index d541d3098..0ddd7a541 100644 --- a/oggm/tests/test_models.py +++ b/oggm/tests/test_models.py @@ -336,6 +336,19 @@ def test_past_mb_model(self, hef_gdir): mb_gw = mb_gw_mod.get_specific_mb(year=yrs) assert_allclose(mb, mb_gw) + # Test massbalance task + s = massbalance.fixed_geometry_mass_balance(gdir) + assert s.index[0] == 1802 + assert s.index[-1] == 2003 + + s = massbalance.fixed_geometry_mass_balance(gdir, ys=1990, ye=2000) + assert s.index[0] == 1990 + assert s.index[-1] == 2000 + + s = massbalance.fixed_geometry_mass_balance(gdir, + years=mbdf.index.values) + assert_allclose(s, mbdf['MY_MB']) + @pytest.mark.parametrize("cl", [massbalance.PastMassBalance, massbalance.ConstantMassBalance, massbalance.RandomMassBalance]) diff --git a/oggm/utils/_workflow.py b/oggm/utils/_workflow.py index ea173fd33..bcb4b9170 100644 --- a/oggm/utils/_workflow.py +++ b/oggm/utils/_workflow.py @@ -1266,6 +1266,49 @@ def compile_glacier_statistics(gdirs, filesuffix='', path=True, return out +def compile_fixed_geometry_mass_balance(gdirs, filesuffix='', path=True, + ys=None, ye=None, years=None): + """Compiles a table of specific mass-balance timeseries for all glaciers. + + Parameters + ---------- + gdirs : list of :py:class:`oggm.GlacierDirectory` objects + the glacier directories to process + filesuffix : str + add suffix to output file + path : str, bool + Set to "True" in order to store the info in the working directory + Set to a path to store the file to your chosen location + ys : int + start year of the model run (default: from the climate file) + date) + ye : int + end year of the model run (default: from the climate file) + years : array of ints + override ys and ye with the years of your choice + """ + from oggm.workflow import execute_entity_task + from oggm.core.massbalance import fixed_geometry_mass_balance + + out_df = execute_entity_task(fixed_geometry_mass_balance, gdirs, + ys=ys, ye=ye, years=years) + + for idx, s in enumerate(out_df): + if s is None: + out_df[idx] = pd.Series(np.NaN) + + out = pd.concat(out_df, axis=1, keys=[gd.rgi_id for gd in gdirs]) + + if path: + if path is True: + out.to_csv(os.path.join(cfg.PATHS['working_dir'], + ('fixed_geometry_mass_balance' + + filesuffix + '.csv'))) + else: + out.to_csv(path) + return out + + @entity_task(log) def climate_statistics(gdir, add_climate_period=1995): """Gather as much statistics as possible about this glacier.