Filter the glacier length and area time series

In this short tutorial, we show how to deal with unwanted “spikes” in the length and area time series of individual glaciers. These happen because OGGM currently doesn’t differentiate between snow and ice, i.e. occasional years with large snowfall can artificially increase the glacier area.

While the best solution would be to deal with this in OGGM, this is currently not possible because we do not have a generally applicable solution to this problem. In the meantime, we recommend a simple workaround.

Set-up

import matplotlib.pyplot as plt
import xarray as xr
import os
from oggm import cfg, utils, workflow, tasks
cfg.initialize()
Downloading salem-sample-data...
2022-10-07 12:44:15: oggm.cfg: Reading default parameters from the OGGM `params.cfg` configuration file.
2022-10-07 12:44:15: oggm.cfg: Multiprocessing switched OFF according to the parameter file.
2022-10-07 12:44:15: oggm.cfg: Multiprocessing: using all available processors (N=2)
2022-10-07 12:44:15: oggm.utils: Downloading https://github.com/OGGM/oggm-sample-data/archive/8a3c41a36d190c6c78029b5032648ce94ee2026c.zip to /github/home/OGGM/download_cache/github.com/OGGM/oggm-sample-data/archive/8a3c41a36d190c6c78029b5032648ce94ee2026c.zip...
2022-10-07 12:44:17: oggm.utils: Checking the download verification file checksum...
2022-10-07 12:44:17: oggm.utils: Downloading https://cluster.klima.uni-bremen.de/data/downloads.sha256.hdf to /github/home/.oggm/downloads.sha256.hdf...
2022-10-07 12:44:31: oggm.utils: Done downloading.
2022-10-07 12:44:31: oggm.utils: Checking the download verification file checksum...
2022-10-07 12:44:31: oggm.utils: No known hash for github.com/OGGM/oggm-sample-data/archive/8a3c41a36d190c6c78029b5032648ce94ee2026c.zip
cfg.PATHS['working_dir'] = utils.gettempdir(dirname='OGGM-Filter')

Define the glaciers for the run

We take the Kesselwandferner in the Austrian Alps:

rgi_ids = ['RGI60-11.00787']

Glacier directories

gdirs = workflow.init_glacier_directories(rgi_ids, from_prepro_level=4, prepro_border=80)
---------------------------------------------------------------------------
InvalidParamsError                        Traceback (most recent call last)
Cell In [5], line 1
----> 1 gdirs = workflow.init_glacier_directories(rgi_ids, from_prepro_level=4, prepro_border=80)

File /usr/local/pyenv/versions/3.10.7/lib/python3.10/site-packages/oggm/workflow.py:351, in init_glacier_directories(rgidf, reset, force, from_prepro_level, prepro_border, prepro_rgi_version, prepro_base_url, from_tar, delete_tar)
    348     reset = utils.query_yes_no('Delete all glacier directories?')
    350 if from_prepro_level:
--> 351     url = utils.get_prepro_base_url(base_url=prepro_base_url,
    352                                     border=prepro_border,
    353                                     prepro_level=from_prepro_level,
    354                                     rgi_version=prepro_rgi_version)
    355     if cfg.PARAMS['has_internet'] and not utils.url_exists(url):
    356         raise InvalidParamsError("base url seems unreachable with these "
    357                                  "parameters: {}".format(url))

File /usr/local/pyenv/versions/3.10.7/lib/python3.10/site-packages/oggm/utils/_downloads.py:1278, in get_prepro_base_url(base_url, rgi_version, border, prepro_level)
   1275 """Extended base url where to find the desired gdirs."""
   1277 if base_url is None:
-> 1278     raise InvalidParamsError('Starting with v1.6, users now have to '
   1279                              'explicitly indicate the url they want '
   1280                              'to start from.')
   1282 if not base_url.endswith('/'):
   1283     base_url += '/'

InvalidParamsError: Starting with v1.6, users now have to explicitly indicate the url they want to start from.

Run

We can step directly to a new experiment! This runs under a random climate representative for the recent climate (1985-2015) and a warm temperature bias:

workflow.execute_entity_task(tasks.run_random_climate, gdirs,
                             nyears=200, y0=2000, seed=5,
                             output_filesuffix='_commitment');

The problem

ds = utils.compile_run_output(gdirs, filesuffix='_commitment')
ds = ds.isel(rgi_id=0)  # take just the one glacier
ds.area.plot();
ds.length.plot();

For small areas, the glacier has the unrealistic “spikes” described above.

Workaround

A good way to deal with the issue is to run a moving filter which keeps the smallest area or length in a given window size:

roll_yrs = 5
# Take the minimum out of 5 years
ts = ds.area.to_series()
ts = ts.rolling(roll_yrs).min()
ts.iloc[0:roll_yrs] = ts.iloc[roll_yrs]
# Plot
ds.area.plot(label='Original');
ts.plot(label='Filtered');
plt.legend();

It works the same with length:

# Take the minimum out of 5 years
ts = ds.length.to_series()
ts = ts.rolling(roll_yrs).min()
ts.iloc[0:roll_yrs] = ts.iloc[roll_yrs]
# Plot
ds.length.plot(label='Original');
ts.plot(label='Filtered');
plt.legend();

What’s next?