Glaciers as water resources: part 2 (projections) - OGGM versions pre 1.6#

Goals of this notebook:

  • run simulations using climate projections to explore the role of glaciers as water resources

This version of the notebook works for OGGM versions before 1.6. We will keep this notebook here for a while longer (e.g.: for classroom.oggm.org). If you are running OGGM 1.6, you can visit the updated notebook at glacier_water_resources_projections.ipynb.

Setting the scene: glacier runoff and “peak water”#

We strongly recommend to run Part 1 of this notebook before going on!

Setup#

import matplotlib.pyplot as plt
import seaborn as sns
sns.set_context('notebook')  # plot defaults
# Temporarily ignore warnings from shapely
import warnings
from shapely.errors import ShapelyDeprecationWarning
warnings.filterwarnings('ignore', category=ShapelyDeprecationWarning)
warnings.filterwarnings('ignore', message='Unpickling a shapely <2.0 geometry')
import xarray as xr
import salem
import numpy as np
import pandas as pd
import oggm.cfg
from oggm import utils, workflow, tasks, graphics
# OGGM options
oggm.cfg.initialize(logging_level='WARNING')
oggm.cfg.PATHS['working_dir'] = utils.gettempdir(dirname='WaterResources-Proj')
oggm.cfg.PARAMS['min_ice_thick_for_length'] = 1  # a glacier is when ice thicker than 1m
oggm.cfg.PARAMS['store_model_geometry'] = True
2023-08-27 22:05:37: oggm.cfg: Reading default parameters from the OGGM `params.cfg` configuration file.
2023-08-27 22:05:37: oggm.cfg: Multiprocessing switched OFF according to the parameter file.
2023-08-27 22:05:37: oggm.cfg: Multiprocessing: using all available processors (N=2)
2023-08-27 22:05:38: oggm.cfg: PARAMS['min_ice_thick_for_length'] changed from `0.0` to `1`.
2023-08-27 22:05:38: oggm.cfg: PARAMS['store_model_geometry'] changed from `False` to `True`.

Define the glacier we will play with#

For this notebook we use the Hintereisferner, Austria. Some other possibilities to play with:

  • Hintereisferner, Austria: RGI60-11.00897

  • Artesonraju, Peru: RGI60-16.02444

  • Rikha Samba, Nepal: RGI60-15.04847

  • Parlung No. 94, China: RGI60-15.11693

And virtually any glacier you can find the RGI Id from, e.g. in the GLIMS viewer! Large glaciers may need longer simulations to see changes though. For less uncertain calibration parameters, we also recommend to pick one of the many reference glaciers in this list, where we make sure that observations of mass-balance are better matched.

Let’s start with Hintereisferner first and you’ll be invited to try out your favorite glacier at the end of this notebook.

# Hintereisferner
rgi_id = 'RGI60-11.00897'

Preparing the glacier data#

This can take up to a few minutes on the first call because of the download of the required data:

# We pick the elevation-bands glaciers because they run a bit faster - but they create more step changes in the area outputs
base_url = 'https://cluster.klima.uni-bremen.de/~oggm/gdirs/oggm_v1.4/L3-L5_files/CRU/elev_bands/qc3/pcp2.5/no_match'
gdir = workflow.init_glacier_directories([rgi_id], from_prepro_level=5, prepro_border=80, prepro_base_url=base_url)[0]
2023-08-27 22:05:39: oggm.workflow: You seem to be using v1.4 directories with a more recent version of OGGM. While this is possible, be aware that some defaults parameters have changed. See the documentation for details: http://docs.oggm.org/en/stable/whats-new.html
2023-08-27 22:05:39: oggm.workflow: init_glacier_directories from prepro level 5 on 1 glaciers.
2023-08-27 22:05:39: oggm.workflow: Execute entity tasks [gdir_from_prepro] on 1 glaciers

Interactive glacier map#

A first glimpse on the glacier of interest.

Tip: You can use the mouse to pan and zoom in the map

# One interactive plot below requires Bokeh
# The rest of the notebook works without this dependency - comment if needed
import holoviews as hv
hv.extension('bokeh')
import geoviews as gv
import geoviews.tile_sources as gts

sh = salem.transform_geopandas(gdir.read_shapefile('outlines'))
(gv.Polygons(sh).opts(fill_color=None, color_index=None) *
 gts.tile_sources['EsriImagery'] * gts.tile_sources['StamenLabels']).opts(width=800, height=500, active_tools=['pan', 'wheel_zoom'])

For OGGM, glaciers are “1.5” dimensional along their flowline:

fls = gdir.read_pickle('model_flowlines')
graphics.plot_modeloutput_section(fls);
../../_images/e204e34d46b1593500fd68478e8e34321696c616db09d387480c976517df3e0e.png

“Commitment run”#

We are now ready to run our first simulation. This is a so called “commitment run”: how much ice loss is “already committed” for this glacier, even if climate change would stop today? This is a useful but purely theoretical experiment: climate change won’t stop today, unfortunately. To learn more about committed mass-loss at the global scale, read Marzeion et al., 2018.

Here, we run a simulation for 100 years with a constant climate based on the last 11 years:

# file identifier where the model output is saved
file_id = '_ct'

# We are using the task run_with_hydro to store hydrological outputs along with the usual glaciological outputs
tasks.run_with_hydro(gdir,
                     run_task=tasks.run_constant_climate,  # which climate? See below for other examples
                     nyears=100,  # length of the simulation
                     y0=2014, halfsize=5,  # For the constant climate, period over which the climate is taken from
                     store_monthly_hydro=True,  # Monthly ouptuts provide additional information
                     output_filesuffix=file_id);  # an identifier for the output file to read it later
2023-08-27 22:05:46: oggm.core.flowline: FileNotFoundError occurred during task run_constant_climate_ct on RGI60-11.00897: [Errno 2] No such file or directory: '/tmp/OGGM/WaterResources-Proj/per_glacier/RGI60-11/RGI60-11.00/RGI60-11.00897/mb_calib.json'
2023-08-27 22:05:46: oggm.core.flowline: FileNotFoundError occurred during task run_with_hydro_ct on RGI60-11.00897: [Errno 2] No such file or directory: '/tmp/OGGM/WaterResources-Proj/per_glacier/RGI60-11/RGI60-11.00/RGI60-11.00897/mb_calib.json'
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
Cell In[10], line 5
      2 file_id = '_ct'
      4 # We are using the task run_with_hydro to store hydrological outputs along with the usual glaciological outputs
----> 5 tasks.run_with_hydro(gdir,
      6                      run_task=tasks.run_constant_climate,  # which climate? See below for other examples
      7                      nyears=100,  # length of the simulation
      8                      y0=2014, halfsize=5,  # For the constant climate, period over which the climate is taken from
      9                      store_monthly_hydro=True,  # Monthly ouptuts provide additional information
     10                      output_filesuffix=file_id);  # an identifier for the output file to read it later

File /usr/local/pyenv/versions/3.10.12/lib/python3.10/site-packages/oggm/utils/_workflow.py:492, in entity_task.__call__.<locals>._entity_task(gdir, reset, print_log, return_value, continue_on_error, add_to_log_file, **kwargs)
    490     signal.alarm(cfg.PARAMS['task_timeout'])
    491 ex_t = time.time()
--> 492 out = task_func(gdir, **kwargs)
    493 ex_t = time.time() - ex_t
    494 if cfg.PARAMS['task_timeout'] > 0:

File /usr/local/pyenv/versions/3.10.12/lib/python3.10/site-packages/oggm/core/flowline.py:3759, in run_with_hydro(gdir, run_task, store_monthly_hydro, fixed_geometry_spinup_yr, ref_area_from_y0, ref_area_yr, ref_geometry_filesuffix, **kwargs)
   3756 if fixed_geometry_spinup_yr is not None:
   3757     kwargs['fixed_geometry_spinup_yr'] = fixed_geometry_spinup_yr
-> 3759 out = run_task(gdir, **kwargs)
   3761 if out is None:
   3762     raise InvalidWorkflowError('The run task ({}) did not run '
   3763                                'successfully.'.format(run_task.__name__))

File /usr/local/pyenv/versions/3.10.12/lib/python3.10/site-packages/oggm/utils/_workflow.py:492, in entity_task.__call__.<locals>._entity_task(gdir, reset, print_log, return_value, continue_on_error, add_to_log_file, **kwargs)
    490     signal.alarm(cfg.PARAMS['task_timeout'])
    491 ex_t = time.time()
--> 492 out = task_func(gdir, **kwargs)
    493 ex_t = time.time() - ex_t
    494 if cfg.PARAMS['task_timeout'] > 0:

File /usr/local/pyenv/versions/3.10.12/lib/python3.10/site-packages/oggm/core/flowline.py:3513, in run_constant_climate(gdir, nyears, y0, halfsize, ys, ye, bias, temperature_bias, precipitation_factor, store_monthly_step, store_model_geometry, store_fl_diagnostics, init_model_filesuffix, init_model_yr, output_filesuffix, climate_filename, mb_model_class, climate_input_filesuffix, init_model_fls, zero_initial_glacier, **kwargs)
   3428 @entity_task(log)
   3429 def run_constant_climate(gdir, nyears=1000, y0=None, halfsize=15,
   3430                          ys=None, ye=None,
   (...)
   3443                          zero_initial_glacier=False,
   3444                          **kwargs):
   3445     """Runs the constant mass balance model for a given number of years.
   3446 
   3447     This will initialize a
   (...)
   3510         kwargs to pass to the FluxBasedModel instance
   3511     """
-> 3513     mb_model = MultipleFlowlineMassBalance(gdir,
   3514                                            mb_model_class=partial(
   3515                                                ConstantMassBalance,
   3516                                                mb_model_class=mb_model_class),
   3517                                            y0=y0, halfsize=halfsize,
   3518                                            bias=bias,
   3519                                            filename=climate_filename,
   3520                                            input_filesuffix=climate_input_filesuffix)
   3522     if temperature_bias is not None:
   3523         mb_model.temp_bias += temperature_bias

File /usr/local/pyenv/versions/3.10.12/lib/python3.10/site-packages/oggm/core/massbalance.py:1199, in MultipleFlowlineMassBalance.__init__(self, gdir, fls, mb_model_class, use_inversion_flowlines, input_filesuffix, **kwargs)
   1195     else:
   1196         rgi_filesuffix = input_filesuffix
   1198     self.flowline_mb_models.append(
-> 1199         mb_model_class(gdir, input_filesuffix=rgi_filesuffix,
   1200                        **kwargs))
   1202 self.valid_bounds = self.flowline_mb_models[-1].valid_bounds
   1203 self.hemisphere = gdir.hemisphere

File /usr/local/pyenv/versions/3.10.12/lib/python3.10/site-packages/oggm/core/massbalance.py:712, in ConstantMassBalance.__init__(self, gdir, mb_model_class, y0, halfsize, **kwargs)
    695 """Initialize
    696 
    697 Parameters
   (...)
    708     keyword arguments to pass to the mb_model_class
    709 """
    711 super().__init__()
--> 712 self.mbmod = mb_model_class(gdir,
    713                             **kwargs)
    715 if y0 is None:
    716     raise InvalidParamsError('Please set `y0` explicitly')

File /usr/local/pyenv/versions/3.10.12/lib/python3.10/site-packages/oggm/core/massbalance.py:384, in MonthlyTIModel.__init__(self, gdir, filename, input_filesuffix, fl_id, melt_f, temp_bias, prcp_fac, bias, ys, ye, repeat, check_calib_params)
    381 self.gdir = gdir
    383 if melt_f is None:
--> 384     melt_f = self.calib_params['melt_f']
    386 if temp_bias is None:
    387     temp_bias = self.calib_params['temp_bias']

File /usr/local/pyenv/versions/3.10.12/lib/python3.10/site-packages/oggm/utils/_workflow.py:299, in lazy_property.<locals>._lazy_property(self)
    295 @property
    296 @wraps(fn)
    297 def _lazy_property(self):
    298     if not hasattr(self, attr_name):
--> 299         setattr(self, attr_name, fn(self))
    300     return getattr(self, attr_name)

File /usr/local/pyenv/versions/3.10.12/lib/python3.10/site-packages/oggm/core/massbalance.py:546, in MonthlyTIModel.calib_params(self)
    543 @lazy_property
    544 def calib_params(self):
    545     if self.fl_id is None:
--> 546         return self.gdir.read_json('mb_calib')
    547     else:
    548         try:

File /usr/local/pyenv/versions/3.10.12/lib/python3.10/site-packages/oggm/utils/_workflow.py:3222, in GlacierDirectory.read_json(self, filename, filesuffix, allow_empty)
   3220         out = {}
   3221 else:
-> 3222     with open(fp, 'r') as f:
   3223         out = json.load(f)
   3224 return out

FileNotFoundError: [Errno 2] No such file or directory: '/tmp/OGGM/WaterResources-Proj/per_glacier/RGI60-11/RGI60-11.00/RGI60-11.00897/mb_calib.json'

Then we can take a look at the output:

with xr.open_dataset(gdir.get_filepath('model_diagnostics', filesuffix=file_id)) as ds:
    # The last step of hydrological output is NaN (we can't compute it for this year)
    ds = ds.isel(time=slice(0, -1)).load()

There are plenty of variables in this dataset! We can list them with:

ds

Tip: you can click on a variable and show it’s attribute with the “page” button on the right.

The time and month_2d variables are coordinates, and the other variables are either provided as additional information (e.g. calendar_month, we will get back to this), or they are providing the actual data. For instance, we can plot the annual evolution of the volume and length of our glacier:

fig, axs = plt.subplots(nrows=2, figsize=(10, 7), sharex=True)
ds.volume_m3.plot(ax=axs[0]);
ds.length_m.plot(ax=axs[1]);
axs[0].set_xlabel(''); axs[0].set_title(f'{rgi_id}'); axs[1].set_xlabel('Years');

The glacier length and volume decrease during the first ~40 years of the simulation - this is the glacier retreat phase. Afterwards, both length and volume oscillate around a more or less constant value indicating that the glacier has reached equilibrium. The difference between the starting volume and the equilibrium volume is called the committed mass loss. It can be quite high in the Alps, and depends on many factors (such as glacier size, location, and the reference climate period),

Annual runoff#

As glaciers retreat, they contribute to sea-level rise (visit the World Glaciers Explorer OGGM-Edu app for more information!). This is not what we are interested in here. Indeed, they will also have important local impacts: in this notebook, we will have a look at their impact on streamflow.

Let’s take a look at some of the hydrological outputs computed by OGGM. We start by creating a pandas DataFrame of all “1D” (annual) variables:

sel_vars = [v for v in ds.variables if 'month_2d' not in ds[v].dims]
df_annual = ds[sel_vars].to_dataframe()

Then we can select the hydrological varialbes and sum them to get the total annual runoff:

# Select only the runoff variables
runoff_vars = ['melt_off_glacier', 'melt_on_glacier', 'liq_prcp_off_glacier', 'liq_prcp_on_glacier']
# Convert them to megatonnes (instead of kg)
df_runoff = df_annual[runoff_vars] * 1e-9
fig, ax = plt.subplots(figsize=(10, 3.5), sharex=True)
df_runoff.sum(axis=1).plot(ax=ax);
plt.ylabel('Mt'); plt.xlabel('Years'); plt.title(f'Total annual runoff for {rgi_id}');

The hydrological variables are computed on the largest possible area that was covered by glacier ice during the simulation. This is equivalent to the runoff that would be measured at a fixed-gauge hydrological station at the glacier terminus.

The total annual runoff consists of the following components:

  • melt off-glacier: snow melt on areas that are now glacier free (i.e. 0 in the year of largest glacier extent, in this example at the start of the simulation)

  • melt on-glacier: ice + seasonal snow melt on the glacier

  • liquid precipitaton on- and off-glacier (the latter being zero at the year of largest glacial extent, in this example at start of the simulation)

f, ax = plt.subplots(figsize=(10, 6));
df_runoff.plot.area(ax=ax, color=sns.color_palette("rocket")); plt.xlabel('Years'); plt.ylabel('Runoff (Mt)'); plt.title(rgi_id);

Before we continue, let’s remember ourselves the expected contribution of glaciers to runoff.

Fig 1 from https://www.nature.com/articles/s41558-017-0049-x

Graphic from Huss & Hock (2018)

Questions to explore:

  • where approximately on this graph is the studied glacier?

  • can you explain the relative contribution of each component, based on the previous notebook?

The total runoff out of a glacier basin is the sum of the four contributions above. To show that the glacier total contribution is indeed zero (\(\Delta M = 0\)) when in equilibrium, we can compute it from the glacier mass change:

glacier_mass = ds.volume_m3.to_series() * oggm.cfg.PARAMS['ice_density'] * 1e-9  # In Megatonnes, Mt

glacier_mass.diff().plot()
plt.axhline(y=0, color='k', ls=':')
plt.ylabel('Annual glacier mass change (Mt yr$^{-1}$)')
plt.xlabel('Years'); plt.title('Glacier contribution to annual runoff');

Note that this doesn’t mean that ice is not melting! At equilibrium, this means that the ice that melts each year over the glacier is replaced by snowfall in the accumulation area of the glacier. This illustrates well that glaciers in equilibrium are not net water resources on the annual average: in the course of the year they gain as much mass as they release.

Monthly runoff#

The “2D” variables contain the same data but at monthly resolution, with the dimension (time, month). For example, runoff can be computed the same way:

# Select only the runoff variables and convert them to megatonnes (instead of kg)
monthly_runoff = (ds['melt_off_glacier_monthly'] + ds['melt_on_glacier_monthly'] +
                  ds['liq_prcp_off_glacier_monthly'] + ds['liq_prcp_on_glacier_monthly'])
monthly_runoff *= 1e-9
monthly_runoff.clip(0).plot(cmap='Blues', cbar_kwargs={'label': 'Mt'}); plt.xlabel('Months'); plt.ylabel('Years');

But be aware, something is a bit wrong with this: the coordinates are hydrological months - let’s make this better:

# This should work in both hemispheres maybe?
ds_roll = ds.roll(month_2d=ds['calendar_month_2d'].data[0] - 1, roll_coords=True)
ds_roll['month_2d'] = ds_roll['calendar_month_2d']

# Select only the runoff variables and convert them to megatonnes (instead of kg)
monthly_runoff = (ds_roll['melt_off_glacier_monthly'] + ds_roll['melt_on_glacier_monthly'] +
                  ds_roll['liq_prcp_off_glacier_monthly'] + ds_roll['liq_prcp_on_glacier_monthly'])
monthly_runoff *= 1e-9
monthly_runoff.clip(0).plot(cmap='Blues', cbar_kwargs={'label': 'Mt'}); plt.xlabel('Months'); plt.ylabel('Years');

As we can see, the runoff is approximately zero during the winter months, while relatively high during the summer months. This implies that the glacier is a source of water in the summer when it releases the water accumulated in the winter.

The annual cycle changes as the glacier retreats:

monthly_runoff.sel(time=[0, 30, 99]).plot(hue='time');
plt.title('Annual cycle');
plt.xlabel('Month');
plt.ylabel('Runoff (Mt)');

Not only does the total runoff during the summer months decrease as the simulation progresses, the month of maximum runoff is also shifted to earlier in the summer.

CMIP5 projection runs#

You have now learned how to simulate and analyse a specific glacier under a constant climate. We will now take this a step further and simulate two different glaciers, located in different climatic regions, forced with CMIP5 climate projections.

We begin by initializing the glacier directories:

# We keep Hintereisferner from earlier, but also add a new glacier
rgi_ids = [rgi_id, 'RGI60-15.02420']
gdirs = workflow.init_glacier_directories(rgi_ids, from_prepro_level=5, prepro_border=80, prepro_base_url=base_url)

gdirs now contain two glaciers, one in Central Europe and one in the Eastern Himlayas:

gdirs

We can take a quick look at the new glacier:

sh = salem.transform_geopandas(gdirs[1].read_shapefile('outlines'))
(gv.Polygons(sh).opts(fill_color=None, color_index=None) *
 gts.tile_sources['EsriImagery'] * gts.tile_sources['StamenLabels']).opts(width=800, height=500, active_tools=['pan', 'wheel_zoom'])

Climate downscaling#

Before we run our simulation we have to process the climate data for the glaicer i.e. downscale it: (This can take some time)

from oggm.shop import gcm_climate
bp = 'https://cluster.klima.uni-bremen.de/~oggm/cmip5-ng/pr/pr_mon_CCSM4_{}_r1i1p1_g025.nc'
bt = 'https://cluster.klima.uni-bremen.de/~oggm/cmip5-ng/tas/tas_mon_CCSM4_{}_r1i1p1_g025.nc'
for rcp in ['rcp26', 'rcp45', 'rcp60', 'rcp85']:
    # Download the files
    ft = utils.file_downloader(bt.format(rcp))
    fp = utils.file_downloader(bp.format(rcp))
    workflow.execute_entity_task(gcm_climate.process_cmip_data, gdirs,
                                 # Name file to recognize it later
                                 filesuffix='_CCSM4_{}'.format(rcp),
                                 # temperature projections
                                 fpath_temp=ft,
                                 # precip projections
                                 fpath_precip=fp,
                                 );

Projection run#

With the downscaling complete, we can run the forced simulations:

for rcp in ['rcp26', 'rcp45', 'rcp60', 'rcp85']:
    rid = '_CCSM4_{}'.format(rcp)
    workflow.execute_entity_task(tasks.run_with_hydro, gdirs,
                                 run_task=tasks.run_from_climate_data, ys=2020,
                                 # use gcm_data, not climate_historical
                                 climate_filename='gcm_data',
                                 # use the chosen scenario
                                 climate_input_filesuffix=rid,
                                 # this is important! Start from 2020 glacier
                                 init_model_filesuffix='_historical',
                                 # recognize the run for later
                                 output_filesuffix=rid,
                                 # add monthly diagnostics
                                 store_monthly_hydro=True);
# Create the figure
f, ax = plt.subplots(figsize=(18, 7), sharex=True)
# Loop over all scenarios
for i, rcp in enumerate(['rcp26', 'rcp45', 'rcp60', 'rcp85']):
    file_id = f'_CCSM4_{rcp}'
    # Open the data, gdirs[0] correspond to Hintereisferner.
    with xr.open_dataset(gdirs[0].get_filepath('model_diagnostics', filesuffix=file_id)) as ds:
        # Load the data into a dataframe
        ds = ds.isel(time=slice(0, -1)).load()

    # Select annual variables
    sel_vars = [v for v in ds.variables if 'month_2d' not in ds[v].dims]
    # And create a dataframe
    df_annual = ds[sel_vars].to_dataframe()

    # Select the variables relevant for runoff.
    runoff_vars = ['melt_off_glacier', 'melt_on_glacier', 'liq_prcp_off_glacier', 'liq_prcp_on_glacier']
    # Convert to mega tonnes instead of kg.
    df_runoff = df_annual[runoff_vars].clip(0) * 1e-9
    # Sum the variables each year "axis=1", take the 11 year rolling mean and plot it.
    df_roll = df_runoff.sum(axis=1).rolling(window=11, center=True).mean()
    df_roll.plot(ax=ax, label=rcp, color=sns.color_palette("rocket")[i])

ax.set_ylabel('Annual runoff (Mt)'); ax.set_xlabel('Year'); plt.title(gdirs[0].rgi_id); plt.legend();

For Hintereisferner, runoff continues to decrease throughout the 21st-century for all scenarios, indicating that peak water has already been reached sometime in the past. This is the case for many European glaciers. What about our unnamed glacier in the Himalayas?

# Create the figure
f, ax = plt.subplots(figsize=(18, 7), sharex=True)
# Loop over all scenarios
for i, rcp in enumerate(['rcp26', 'rcp45', 'rcp60', 'rcp85']):
    file_id = f'_CCSM4_{rcp}'
    # Open the data, gdirs[1] correspond to the unnamed glacier.
    with xr.open_dataset(gdirs[1].get_filepath('model_diagnostics', filesuffix=file_id)) as ds:
        # Load the data into a dataframe
        ds = ds.isel(time=slice(0, -1)).load()

    # Select annual variables
    sel_vars = [v for v in ds.variables if 'month_2d' not in ds[v].dims]
    # And create a dataframe
    df_annual = ds[sel_vars].to_dataframe()

    # Select the variables relevant for runoff.
    runoff_vars = ['melt_off_glacier', 'melt_on_glacier',
                   'liq_prcp_off_glacier', 'liq_prcp_on_glacier']
    # Convert to mega tonnes instead of kg.
    df_runoff = df_annual[runoff_vars].clip(0) * 1e-9
    # Sum the variables each year "axis=1", take the 11 year rolling mean and plot it.
    df_roll = df_runoff.sum(axis=1).rolling(window=11, center=True).mean()
    df_roll.plot(ax=ax, label=rcp, color=sns.color_palette("rocket")[i])

ax.set_ylabel('Annual runoff (Mt)'); ax.set_xlabel('Year'); plt.title(gdirs[1].rgi_id); plt.legend();

Unlike for Hintereisferner, these projections indicate that the annual runoff will increase in all the scenarios for the first half of the century. The higher RCP scenarios can reach peak water later in the century, since the excess melt can continue to increase. For the lower RCP scenarios on the other hand, the glacier might be approaching a new equilibirum, which reduces the runoff earlier in the century (Rounce et. al., 2020). After peak water is reached (RCP2.6: ~2055, RCP8.5: ~2070 in these projections), the annual runoff begins to decrease. This decrease occurs because the shrinking glacier is no longer able to support the high levels of melt.

Another projection run with temperature bias, or precipitation?#

TODO: include something about how temperature bias affect the size of the glacier and the meltwater output.

Take home points#

  • Glaciers in equilibrium are not net water resources: they gain as much mass as they release over a year.

    • However, they have a seasonal buffer role: they release water during the melt months.

    • The size of a glacier has an influence on the water availability downstream during the dry season. The impact is most important if the (warm) melt season coincides with the dry season (see Kaser et al., 2010).

  • When glaciers melt, they become net water resources over the year. “Peak water” is the point in time when glacier melt supply reaches its maximum, i.e. when the maximum runoff occurs.

References#

  • Kaser, G., Großhauser, M., and Marzeion, B.: Contribution potential of glaciers to water availability in different climate regimes, PNAS, 07 (47) 20223-20227, doi:10.1073/pnas.1008162107, 2010

  • Huss, M. and Hock, R.: Global-scale hydrological response to future glacier mass loss, Nat. Clim. Chang., 8(2), 135–140, doi:10.1038/s41558-017-0049-x, 2018.

  • Marzeion, B., Kaser, G., Maussion, F. and Champollion, N.: Limited influence of climate change mitigation on short-term glacier mass loss, Nat. Clim. Chang., 8, doi:10.1038/s41558-018-0093-1, 2018.

  • Rounce, D. R., Hock, R., McNabb, R. W., Millan, R., Sommer, C., Braun, M. H., Malz, P., Maussion, F., Mouginot, J., Seehaus, T. C. and Shean, D. E.: Distributed global debris thickness estimates reveal debris significantly impacts glacier mass balance, Geophys. Res. Lett., doi:10.1029/2020GL091311, 2021.

What’s next?#

Back to the table of contents