Group project¶
Instructions¶
Objectives
In this final project, you should pick two glacierized basins and analyse the projected future of glaciers for different climate scenarios, and compare them to each other. For this you should use tools and knowledge you gained during the practical sessions in the last weeks.
Deadline
Please submit your project via OLAT before Monday June 17 at 00H (in the night from Monday to Tuesday).
Formal requirements
You will work in groups of two. If we are an odd number of students, one group can have three participants. (Tip: I recommend that students who have not followed a programming class to team up with students who have).
Each group will submit one (executed) jupyter notebook containing the code, plots, and answers to the questions (text in the markdown format) on OLAT. Please also submit an HTML version of the notebook. Please ensure that your HTML file is smaller than 10 MB. This helps us provide you with more detailed and readable feedback.
Each group member must contribute to the notebook. The notebook should be self-contained and the answers must be well structured. The plots must be as understandable as possible (title, units, x and y axis labels, appropriate colors…).
Please be concise in your answer. We expect a few sentences per answer at most - there is no need to write a new text book in this project! Use links and references to the literature or your class slides where appropriate.
Grading
We will give one grade per project, according to the following table (total 10 points):
- correctness of the code and the plots: content, legends, colors, units, etc. (3 points)
- quality of the answers: correctness, preciseness, appropriate use of links and references to literature or external resources (5 points)
- contextualise your findings with literature (2 points)
1 2 3 4 5 6 7 8 9 10 11 12 | # Imports import os import urllib.request from oggm import utils from oggm import tasks import xarray as xr import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns sns.set_context('notebook') |
International Network for Alpine Research Catchment Hydrology INARCH¶
We aim, with this group project, to contribute to the INARCH initiative. The goal of INARCH is to better understand hydrological processes in alpine cold regions, improve their prediction, diagnose their sensitivity to global change, and develop consistent measurement strategies. You can find more information on the INARCH website.
In this project, our focus will be on glacier projections from OGGM in glacierized basins of INARCH. You are expected to analyze how glaciers are evolving and how their contribution to total runoff is changing. The final outcome will be a dataset of OGGM projections for all CMIP5 and CMIP6 scenarios (which I have prepared), along with a first analysis of this dataset, this is the core of your work in the group project.
For your individual group analysis, you should compare two basins. As a whole class, we aim to ensure that each basin is covered by at least one group. The selection of basins is up to each group and should be done using the link to the spreadsheet shared in the presentation (first come, first served).
In your analysis, make sure to incorporate the background knowledge about how OGGM is working and how the data was generated, as we discussed during the practical sessions.
Selecting Temperature Scenarios for Analysis¶
To analyze how glaciers are evolving, we will group the projections by temperature warming levels, as done in a previous session. For this, you will again need the table containing the actual warming levels for each climate model realization. You can download it here and save it at the same location as this notebook.
Below is the code used to select the model realizations based on temperature targets. Our analysis focuses on three temperature goals: 1.5°C, 2.7°C, and 4.0°C, each with a tolerance of ±0.2°C.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # reading the csv file df_warming_levels = pd.read_csv('cmip5_and_cmip6_warming_compared_to_preindustrial.csv', index_col=0) # the function takes a target temperature and a range, e.g. 2.7+/-0.2°C def get_models_from_temp(temp, temp_range): pi_l = temp - temp_range # our lower temperature limit pi_u = temp + temp_range # our higher temperature limit # select only those which are inside of our temperature limit pd_cmip_sel = df_warming_levels.loc[ # select all which have a larger temperature as our lower limit AND (df_warming_levels['global_temp_ch_2071-2100_preindustrial']>=pi_l) & # those having a smaller temperature as our higher limit (df_warming_levels['global_temp_ch_2071-2100_preindustrial']<=pi_u) ] return pd_cmip_sel # define the models for each temperature goal in a dictionary temp_scenarios = { '4°C': get_models_from_temp(4, 0.2), '2.7°C': get_models_from_temp(2.7, 0.2), '1.5°C': get_models_from_temp(1.5, 0.2), } |
1 2 3 4 5 6 7 8 9 10 | # Evaluate model selection for each temperature target for temp, df in temp_scenarios.items(): mean_val = df['global_temp_ch_2071-2100_preindustrial'].mean() median_val = df['global_temp_ch_2071-2100_preindustrial'].median() count_val = df.shape[0] print(f"--- {temp} scenario ---") print(f"Number of realizations: {count_val}") print(f"Mean temperature: {mean_val:.2f}°C") print(f"Median temperature: {median_val:.2f}°C\n") |
--- 4°C scenario --- Number of realizations: 9 Mean temperature: 4.06°C Median temperature: 4.08°C --- 2.7°C scenario --- Number of realizations: 14 Mean temperature: 2.71°C Median temperature: 2.72°C --- 1.5°C scenario --- Number of realizations: 11 Mean temperature: 1.56°C Median temperature: 1.58°C
All three groups show a close match to the target temperature, with both the mean and median well within the ±0.2°C tolerance range. The 2.7°C scenario has the highest number of realizations (14), indicating better coverage of that warming level among the available models. The 4.0°C scenario has the fewest (9), which is still acceptable but may result in slightly higher uncertainty due to the smaller sample. Overall, the selections appear robust and well-distributed for each temperature goal, supporting reliable comparative analysis in the glacier projections.
Getting the Data for Your Basins¶
To begin your analysis, you need to load the glacier and runoff projection data for your assigned basins. Make sure you know which basins your group is working on (as selected in the shared spreadsheet). The data for each basin is stored in individual files, which you can load using the provided code template. You can choose where to store the data locally by setting the variable local_data_dir. By default, this will create a new folder called glacier_projection_data in the same location as your notebook.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # add here your the basin_id of your selected basins (e.g. ['basin_1', 'basin_2']) basin_ids = ['zugspitze', 'brewster'] # you can select here a location on your computer to store the glacier data local_data_dir = 'glacier_projection_data' # create the directory, if it does not exist os.makedirs(local_data_dir, exist_ok=True) # the url where all the data is stored base_url = 'https://cluster.klima.uni-bremen.de/~pschmitt/teaching/cryo_in_climate/INARCH/data/' # in this structure we will save the opened data ds_all = {} # Code for downloading the data, if data already downloaded this will be skipped for basin in basin_ids: # create a directory for each basin basin_url = os.path.join(base_url, basin, '2100') local_basin_dir = os.path.join(local_data_dir, basin) os.makedirs(local_basin_dir, exist_ok=True) ds_all[basin] = {} for temp_level in temp_scenarios: ds_tmp_all = [] for i, realization in temp_scenarios[temp_level].iterrows(): # depending on the CMIP, different names for scenarios scenario_column = 'ssp' if realization['cmip'] == 'CMIP6' else 'rcp' filename = f"basin_{basin}_run_hydro_w5e5_gcm_merged_bc_2000_2019_{realization['gcm']}_{realization[scenario_column]}.nc" # only download if file not already downloaded if os.path.isfile(os.path.join(local_basin_dir, filename)): print(f"File already downloaded: {filename}") else: print(f"Downloading {filename}") urllib.request.urlretrieve( os.path.join(basin_url, filename), os.path.join(local_basin_dir, filename)) # open individual dataset and combine gcma and scenario in new variable with xr.open_dataset(os.path.join(local_basin_dir, filename)) as ds: ds_stacked = ds.stack(gcm_scenario=("gcm", "scenario")) ds_tmp_all.append(ds_stacked) print(f'{basin}: combining data for {temp_level}') ds_all[basin][temp_level] = xr.combine_by_coords(ds_tmp_all, fill_value=np.nan) |
Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp85.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM-LR_rcp85.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CNRM-CM5_rcp85.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_NorESM2-MM_ssp585.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_BCC-CSM2-MR_ssp585.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_FGOALS-f3-L_ssp585.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2-WACCM_ssp370.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2_ssp370.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_EC-Earth3-Veg_ssp370.nc zugspitze: combining data for 4°C Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CNRM-CM5_rcp45.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CSIRO-Mk3-6-0_rcp45.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_IPSL-CM5A-LR_rcp45.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp60.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-CM3_rcp26.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_ACCESS-CM2_ssp126.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CanESM5_ssp126.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CAMS-CSM1-0_ssp370.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2-WACCM_ssp534-over.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_IPSL-CM6A-LR_ssp534-over.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp245.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_BCC-CSM2-MR_ssp245.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_FGOALS-f3-L_ssp245.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp434.nc zugspitze: combining data for 2.7°C Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM2G_rcp45.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_NorESM1-M_rcp26.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM-LR_rcp26.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp26.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM1-2-HR_ssp126.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM4_ssp126.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_INM-CM4-8_ssp126.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_INM-CM5-0_ssp126.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_CAMS-CSM1-0_ssp126.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM4_ssp119.nc Downloading basin_zugspitze_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp119.nc zugspitze: combining data for 1.5°C Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp85.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM-LR_rcp85.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CNRM-CM5_rcp85.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_NorESM2-MM_ssp585.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_BCC-CSM2-MR_ssp585.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_FGOALS-f3-L_ssp585.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2-WACCM_ssp370.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2_ssp370.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_EC-Earth3-Veg_ssp370.nc brewster: combining data for 4°C Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CNRM-CM5_rcp45.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CSIRO-Mk3-6-0_rcp45.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_IPSL-CM5A-LR_rcp45.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp60.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-CM3_rcp26.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_ACCESS-CM2_ssp126.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CanESM5_ssp126.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CAMS-CSM1-0_ssp370.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2-WACCM_ssp534-over.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_IPSL-CM6A-LR_ssp534-over.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp245.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_BCC-CSM2-MR_ssp245.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_FGOALS-f3-L_ssp245.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp434.nc brewster: combining data for 2.7°C Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM2G_rcp45.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_NorESM1-M_rcp26.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM-LR_rcp26.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp26.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM1-2-HR_ssp126.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM4_ssp126.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_INM-CM4-8_ssp126.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_INM-CM5-0_ssp126.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_CAMS-CSM1-0_ssp126.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM4_ssp119.nc Downloading basin_brewster_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp119.nc brewster: combining data for 1.5°C
After downloading and processing the data, everything will be stored in the variable ds_all. You can access the data for a specific basin and temperature level using the syntax ds_all[basin_name][temperature_level]. Below you can find one example:
1 | ds_all[basin_ids[0]]['1.5°C'] |
<xarray.Dataset> Size: 925kB
Dimensions: (time: 101, rgi_id: 3, gcm_scenario: 11,
month_2d: 12)
Coordinates:
* time (time) float64 808B 2e+03 ... 2.1e+03
* rgi_id (rgi_id) <U14 168B 'RGI60-11.03246' ... 'RG...
hydro_year (time) int64 808B 2000 2001 2002 ... 2099 2100
hydro_month (time) int64 808B 4 4 4 4 4 4 ... 4 4 4 4 4 4
calendar_year (time) int64 808B 2000 2001 2002 ... 2099 2100
calendar_month (time) int64 808B 1 1 1 1 1 1 ... 1 1 1 1 1 1
* month_2d (month_2d) int64 96B 1 2 3 4 5 ... 9 10 11 12
calendar_month_2d (month_2d) int64 96B 1 2 3 4 5 ... 9 10 11 12
* gcm_scenario (gcm_scenario) object 88B MultiIndex
* gcm (gcm_scenario) <U13 572B 'CAMS-CSM1-0' ... ...
* scenario (gcm_scenario) <U6 264B 'ssp126' ... 'rcp26'
Data variables: (12/14)
volume (time, rgi_id, gcm_scenario) float32 13kB 1...
area (time, rgi_id, gcm_scenario) float32 13kB 4...
on_area (time, rgi_id, gcm_scenario) float32 13kB 4...
off_area (time, rgi_id, gcm_scenario) float32 13kB 1...
melt_off_glacier (time, rgi_id, gcm_scenario) float32 13kB 0...
melt_on_glacier (time, rgi_id, gcm_scenario) float32 13kB 9...
... ...
melt_off_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 160kB ...
melt_on_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 160kB ...
liq_prcp_off_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 160kB ...
liq_prcp_on_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 160kB ...
runoff_monthly (time, month_2d, rgi_id, gcm_scenario) float32 160kB ...
runoff (time, rgi_id, gcm_scenario) float32 13kB 2...
Attributes:
description: OGGM model output
oggm_version: 1.6.1.dev26+gf8a1745
calendar: 365-day no leap
creation_date: 2025-05-07 20:14:15
bias_correction: bc_2000_2019
basin_name: Zugspitze
basin_area_km2: 13.321712660800962
glaciers_in_basin: 3
glacierised_area_perc: 3.0026169321081135
glacierised_area_km2: 0.4Based on the example of the Zugspitze basin under a 1.5°C global warming scenario we can explore and discuss the available data generated by the OGGM. The data is stored in a structured xarray Dataset format.
Dimensions:
- time: 101 values (years 2000–2100)
- rgi_id: 3 glacier IDs (individual glaciers in basin)
- gcm_scenario: 11 combinations (GCM × climate scenario)
- month_2d: 12 months (used for monthly-resolved variables)
Variables:
- volume | Glacier volume | m^3
- area | Glacier surface area | m^2
- on_area, off_area | Area on/off glacier | m^2
- melt_on_glacier, melt_off_glacier | Annual melt volumes | kg y^-1
- liq_prcp_on/off_glacier | Annual liquid precipitation | kg y^-1
- runoff | Annual runoff from glacierized areas | kg y^-1
melt_on/off_glacier, liq_prcp_on/off_glacier and runoff are available as monthly variables as well with the unit kg month^-1
Some variables contain NaN values near the end of the simulation period, likely due to full glacier melt or model limits.
All projections use bias-corrected inputs based on the 2000–2019 climatology, ensuring realistic input forcing.
Common running glaciers¶
Some individual glacier projections may be missing or not available for certain scenarios. To avoid introducing errors due to differing glacier counts across scenarios, we will first extract only those glaciers that are available in all scenarios:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # in this variable the common running glaciers will be saved for each basin not_nan_rgi_ids_all = {} # loop through your basins for basin in basin_ids: not_nan_rgi_ids = None # loop though the temperature scenarios, only glaciers which are available in all temperature scenarios are selected for temp in temp_scenarios: not_nan_rgi_ids_temp = ~ds_all[basin][temp].volume.isnull().any(dim=["time", "gcm_scenario"]) if not_nan_rgi_ids is None: not_nan_rgi_ids = not_nan_rgi_ids_temp else: not_nan_rgi_ids &= not_nan_rgi_ids_temp # save the working rgi_ids for each basin not_nan_rgi_ids_all[basin] = not_nan_rgi_ids.rgi_id[not_nan_rgi_ids].values |
We can now use this list of valid rgi_ids to filter our data and include only those glaciers that are available across all scenarios.
1 2 | basin_example = basin_ids[0] ds_all[basin_example]['1.5°C'].sel(rgi_id=not_nan_rgi_ids_all[basin_example]) |
<xarray.Dataset> Size: 925kB
Dimensions: (time: 101, rgi_id: 3, gcm_scenario: 11,
month_2d: 12)
Coordinates:
* time (time) float64 808B 2e+03 ... 2.1e+03
* rgi_id (rgi_id) <U14 168B 'RGI60-11.03246' ... 'RG...
hydro_year (time) int64 808B 2000 2001 2002 ... 2099 2100
hydro_month (time) int64 808B 4 4 4 4 4 4 ... 4 4 4 4 4 4
calendar_year (time) int64 808B 2000 2001 2002 ... 2099 2100
calendar_month (time) int64 808B 1 1 1 1 1 1 ... 1 1 1 1 1 1
* month_2d (month_2d) int64 96B 1 2 3 4 5 ... 9 10 11 12
calendar_month_2d (month_2d) int64 96B 1 2 3 4 5 ... 9 10 11 12
* gcm_scenario (gcm_scenario) object 88B MultiIndex
* gcm (gcm_scenario) <U13 572B 'CAMS-CSM1-0' ... ...
* scenario (gcm_scenario) <U6 264B 'ssp126' ... 'rcp26'
Data variables: (12/14)
volume (time, rgi_id, gcm_scenario) float32 13kB 1...
area (time, rgi_id, gcm_scenario) float32 13kB 4...
on_area (time, rgi_id, gcm_scenario) float32 13kB 4...
off_area (time, rgi_id, gcm_scenario) float32 13kB 1...
melt_off_glacier (time, rgi_id, gcm_scenario) float32 13kB 0...
melt_on_glacier (time, rgi_id, gcm_scenario) float32 13kB 9...
... ...
melt_off_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 160kB ...
melt_on_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 160kB ...
liq_prcp_off_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 160kB ...
liq_prcp_on_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 160kB ...
runoff_monthly (time, month_2d, rgi_id, gcm_scenario) float32 160kB ...
runoff (time, rgi_id, gcm_scenario) float32 13kB 2...
Attributes:
description: OGGM model output
oggm_version: 1.6.1.dev26+gf8a1745
calendar: 365-day no leap
creation_date: 2025-05-07 20:14:15
bias_correction: bc_2000_2019
basin_name: Zugspitze
basin_area_km2: 13.321712660800962
glaciers_in_basin: 3
glacierised_area_perc: 3.0026169321081135
glacierised_area_km2: 0.41 2 | basin_example = basin_ids[1] ds_all[basin_example]['1.5°C'].sel(rgi_id=not_nan_rgi_ids_all[basin_example]) |
<xarray.Dataset> Size: 2MB
Dimensions: (time: 101, rgi_id: 5, gcm_scenario: 11,
month_2d: 12)
Coordinates:
* time (time) float64 808B 2e+03 ... 2.1e+03
* rgi_id (rgi_id) <U14 280B 'RGI60-18.01116' ... 'RG...
hydro_year (time) int64 808B 2000 2001 2002 ... 2099 2100
hydro_month (time) int64 808B 10 10 10 10 ... 10 10 10 10
calendar_year (time) int64 808B 2000 2001 2002 ... 2099 2100
calendar_month (time) int64 808B 1 1 1 1 1 1 ... 1 1 1 1 1 1
* month_2d (month_2d) int64 96B 1 2 3 4 5 ... 9 10 11 12
calendar_month_2d (month_2d) int64 96B 1 2 3 4 5 ... 9 10 11 12
* gcm_scenario (gcm_scenario) object 88B MultiIndex
* gcm (gcm_scenario) <U13 572B 'CAMS-CSM1-0' ... ...
* scenario (gcm_scenario) <U6 264B 'ssp126' ... 'rcp26'
Data variables: (12/14)
volume (time, rgi_id, gcm_scenario) float32 22kB 1...
area (time, rgi_id, gcm_scenario) float32 22kB 6...
on_area (time, rgi_id, gcm_scenario) float32 22kB 6...
off_area (time, rgi_id, gcm_scenario) float32 22kB 2...
melt_off_glacier (time, rgi_id, gcm_scenario) float32 22kB 1...
melt_on_glacier (time, rgi_id, gcm_scenario) float32 22kB 1...
... ...
melt_off_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 267kB ...
melt_on_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 267kB ...
liq_prcp_off_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 267kB ...
liq_prcp_on_glacier_monthly (time, month_2d, rgi_id, gcm_scenario) float32 267kB ...
runoff_monthly (time, month_2d, rgi_id, gcm_scenario) float32 267kB ...
runoff (time, rgi_id, gcm_scenario) float32 22kB 2...
Attributes:
description: OGGM model output
oggm_version: 1.6.1.dev26+gf8a1745
calendar: 365-day no leap
creation_date: 2025-05-07 20:14:15
bias_correction: bc_2000_2019
basin_name: Brewster Glacier
basin_area_km2: 6.000116492103946
glaciers_in_basin: 5
glacierised_area_perc: 46.71575966381155
glacierised_area_km2: 2.803In both the Zugspitze basin and the Brewster basin no glaciers were excluded.
Describe your basins¶
Before starting your data analysis, take some time to explore your selected basins and do a bit of background research. You can download all basin shapefiles here to examine them more closely.
- Where are the basins located, and what are their climate conditions?
- How large is each basin, and what proportion of the area is glacierized? (Tip: check the Attribues of ds_all for the individual basins)
Zugspitze basin
- region: Northern Alps at the border of Germany and Austria
- Temperature: Cold, with significant seasonal variation and subzero winter averages
- Precipitation: High annual precipitation, primarily snow in winter, contributing to glacier mass balance
- Seasonality: Strongly seasonal snowmelt and runoff cycles, with peak glacier melt during summer months
- Basin area: 13.32 km^2
- Glacierized area: 0.4 km^2 (~ 3.0%)
Brewster basin
- region: Southern Alps of New Zealand
- Temperature: Cool temperatures with relatively mild winters due to maritime influence; minimal seasonal extremes
- Precipitation: Very high annual precipitation, often exceeding 5,000 mm, more than half of it as rain
- Seasonality: Less pronounced than continental glaciers — glacier melt is significant in summer, but rain events contribute to runoff year-round
- Basin area: 6.00 km^2
- Glacierized area: 2.80 km^2 (~ 46,7%)
Volume and area evolution¶
Analyze the volume and area evolution of all glaciers in your basin. Tip: use ds.sum(dim='rgi_id') to sum over all glaciers.
For each basin, create:
- One plot showing total glacier volume evolution (in km³) from 2020 to 2100
- One plot showing total glacier area evolution (in km²) from 2020 to 2100
Each plot should include all three temperature scenarios, displayed as the median with interquartile range (17th to 83rd percentile). The title of each plot should include the name of the basin and the glacierized area fraction (in percent).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | # Function to plot volume and area evolution def plot_glacier_evolution(ds_all, basin_ids, temp_scenarios): for basin in basin_ids: ds_basin = ds_all[basin] sample_ds = list(ds_basin.values())[0] glac_area_pct = sample_ds.attrs.get('glacierised_area_perc', 'N/A') fig, axs = plt.subplots(1, 2, figsize=(14, 5), sharex=True) for temp in ['1.5°C', '2.7°C', '4°C']: ds = ds_basin[temp].sum(dim='rgi_id') years = ds.time vol = ds.volume / 1e9 # m3 to km3 area = ds.area / 1e6 # m2 to km2 # percentiles across GCMs vol_median = np.percentile(vol, 50, axis=1) vol_low = np.percentile(vol, 17, axis=1) vol_high = np.percentile(vol, 83, axis=1) area_median = np.percentile(area, 50, axis=1) area_low = np.percentile(area, 17, axis=1) area_high = np.percentile(area, 83, axis=1) axs[0].plot(years, vol_median, label=temp) axs[0].fill_between(years, vol_low, vol_high, alpha=0.3) axs[1].plot(years, area_median, label=temp) axs[1].fill_between(years, area_low, area_high, alpha=0.3) axs[0].set_title(f"{basin} - Volume Evolution\nGlacierized Area: {glac_area_pct:.2f}%") axs[0].set_ylabel("Volume [km³]") axs[1].set_title(f"{basin} - Area Evolution\nGlacierized Area: {glac_area_pct:.2f}%") axs[1].set_ylabel("Area [km²]") axs[0].legend() axs[1].legend() axs[0].set_xlabel("Year") axs[1].set_xlabel("Year") plt.tight_layout() plt.show() # Example usage plot_glacier_evolution(ds_all, basin_ids, temp_scenarios) |
- What do you observe when comparing the different scenarios within each basin?
- Do the two basins react similarly or differently?
- Is there a noticeable difference in the behavior between glacier area and volume?
The higher the temperature increase the faster the decline in volume and area for both basins. Additionally we see that the uncertainty (the interquartile range) is higher for the lower temperature scenario. For the Zugspitze basin we can see that for the 1.5°C scenario the volume is decreasing till 2100 with a stabilising area even though there is a lot of variability. So this means that there is thinning of the glacier with a more or less stable area. For the Brewster we first see a steep decline for both the volume and the area with a stabilising effect for both from the year 2050/2060 for the 1.5°C scenario and also for the 2.7°C scenario and a less steep decline for the 4.0°C scenario. To compare the both basins with each other we can see that the Zugspitze glaciers are unlikely to survive in the warmer two scenarios, whereas the Brewster glaciers show that they are in a new equilibrium even with the 2.7°C scenario. So the area and volume are declining, but they have a higher chance of surviving. Both areas show similiar decline rates between 2020 and 2060.
Hydrological output¶
Analyze the hydrological output of your basins. For guidance, you can refer to the plots of this tutorial.
For each basin, create the following plots:
- Total runoff for all temperature scenarios in one plot (showing median and interquartile range)
- Runoff components (only median), one plot per temperature scenario
- Monthly runoff (median only), as a 2D plot (x-axis: Months, y-axis: Years), one plot per temperature scenario
- Annual runoff at three time steps (e.g. 2020, 2060, 2100), showing median and interquartile range, one plot per temperature scenario
The title of each plot should include the name of the basin and the glacierized area fraction (in percent), and, if needed, the temperature scenario.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | import numpy as np import matplotlib.pyplot as plt def analyze_hydrology(ds_all, basin_ids): for basin in basin_ids: ds_b = ds_all[basin] sample = next(iter(ds_b.values())) basin_name = sample.attrs.get('basin_name', basin) glac_pct = sample.attrs.get('glacierised_area_perc', 0) for scenario, ds in ds_b.items(): # Sum over glaciers ds_sum = ds.sum(dim='rgi_id') # Convert units to km³ (annual) and Mt (monthly) annual = ds_sum[['melt_off_glacier', 'melt_on_glacier', 'liq_prcp_off_glacier', 'liq_prcp_on_glacier', 'runoff']].copy() annual_km3 = annual * 1e-9 # Monthly runoff monthly = (ds_sum['melt_off_glacier_monthly'] + ds_sum['melt_on_glacier_monthly'] + ds_sum['liq_prcp_off_glacier_monthly'] + ds_sum['liq_prcp_on_glacier_monthly']) * 1e-9 # 1. Total annual runoff plot (median + IQR) run = annual_km3['runoff'] run_np = run.transpose('time','gcm_scenario').values years = ds_sum.time.values med = np.percentile(run_np, 50, axis=1) p17 = np.percentile(run_np, 17, axis=1) p83 = np.percentile(run_np, 83, axis=1) plt.figure(figsize=(8,4)) plt.plot(years[0:99], med[0:99], label='Total runoff') plt.fill_between(years[0:99], p17[0:99], p83[0:99], alpha=0.3) plt.title(f"{basin_name} - Total Runoff ({scenario})\nGlacierized Area: {glac_pct:.2f}%") plt.ylabel("Runoff [km³]") plt.xlabel("Year") plt.tight_layout() plt.show() # 2. Runoff components (median only) comps = ['melt_on_glacier','melt_off_glacier','liq_prcp_on_glacier','liq_prcp_off_glacier'] plt.figure(figsize=(8,4)) area_plot = pd.DataFrame({'year': years[0:99]}) for c in comps: arr = annual_km3[c].transpose('time','gcm_scenario').values med_c = np.percentile(arr, 50, axis=1) area_plot[c] = med_c[0:99] area_plot.plot.area(x='year') plt.title(f"{basin_name} - Runoff Components ({scenario})") plt.ylabel("Runoff [km³]") plt.xlabel("Year") plt.legend() plt.tight_layout() plt.show() # 3. Monthly runoff (2D median heatmap) monthly_np = monthly.transpose('time','month_2d','gcm_scenario').values med_mon = np.percentile(monthly_np,50,axis=2) plt.figure(figsize=(8,6)) plt.imshow(med_mon, aspect='auto', origin='lower', extent=[1,12,years.min(), years.max()], cmap='Blues') plt.colorbar(label='Monthly Runoff [km³]') plt.title(f"{basin_name} - Monthly Runoff Median ({scenario})") plt.xlabel("Month") plt.ylabel("Year") plt.tight_layout() plt.show() # 4. Annual runoff at 2020, 2060, 2099 sel_years = [2020, 2060, 2099] indices = [np.where(years==yr)[0][0] for yr in sel_years] run_np = run_np # % from above meds = [np.median(run_np[i]) for i in indices] lows = [np.percentile(run_np[i],17) for i in indices] highs = [np.percentile(run_np[i],83) for i in indices] plt.figure(figsize=(6,4)) plt.bar([str(yr) for yr in sel_years], meds, yerr=[np.array(meds)-np.array(lows), np.array(highs)-np.array(meds)], capsize=5) plt.title(f"{basin_name} - Annual Runoff Snapshots ({scenario})") plt.ylabel("Runoff [km³]") plt.tight_layout() plt.show() # Example call analyze_hydrology(ds_all, basin_ids) |
<Figure size 800x400 with 0 Axes>
<Figure size 800x400 with 0 Axes>
<Figure size 800x400 with 0 Axes>
<Figure size 800x400 with 0 Axes>
<Figure size 800x400 with 0 Axes>
<Figure size 800x400 with 0 Axes>
- What do you observe when comparing the different scenarios within each basin?
- Do the two basins react similarly or differently?
- Can you identify any evidence of peak water?
First a little explaination from the OGGM Documentation (https://edu-notebooks.oggm.org/oggm-edu/glacier_water_resources_projections.html):
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)
With that in mind, we first look at the glacier at Zugspitze.
In the 1.5°C scenario, the total runoff as well as the components constributing to the runoff does not change a lot during the simulation period.
At 2.7°C the total runoff is slightly smaller towards the end of the century, compared to 1.5°C. There is a significant change in the runoff components, starting at mid-century, with the on-glacier components vanishing almost completely from ca. 2080, when the glacier area is almost all gone (see area and volume plots).
At the most extreme (4.0°C) scenario the glacier will be gone by 2070. Also in this scenario the total runoff is not as impacted by the drastic change as one would think and the off-glacier components mostly make up for the missing on-glaicer components.
Now for the Brewster glacier.
In this basin for all scenarios, the total runoff increased from 2000 until now and is simulated to then decrease until roughly mid-century where there is a significant decrease in runoff in all scenarios which is mostly pronounced in the on-glacier components. In the second half of the century the overall runoff is mostly stable for the 1.5°C and 2.7°C scenarios with a slight decrease in the 4.0°C scenario. In the 4.0°C scenario the glaicer is gone by 2100.
Both basins have quite different runoff characteristics which is most likely associated with their very different geographical and climatological environment. The peak water in the Zugspitze basin is typically in the months June-August with a slight shift towards May/June in the 4.0°C scenario. The Brewster glaciers, located on the souther heimsphere, has its peak water typically from December to Febuary, wiht a slight shift of the peak melting season starting already in late November for the higher temperature scenarios.
Contextualize your results with the literature¶
Glacier area and volume respond differently to climate change. Both glacier area and volume are projected to decline significantly this century as visible in our figures, with volume generally decreasing faster than area, especially under high-emission scenarios. -According to literature on volume loss: Glacier volume is highly sensitive to warming, with projections indicating global glacier volume losses of 41–64% by 2100 under high-end scenarios (RCP8.5), and 29% under moderate scenarios (RCP4.5)(Shannon et al., 2019; Radic et al., 2013) In some regions, such as the Southern Alps and the French Alps, volume losses could reach 75–92% by the end of this century, depending on the scenario (Anderson et al., 2023; Bolibar et al., 2022). -According to literature on area loss: Glacier area also declines, but often at a slower rate than volume. For example, in the Tianshan Mountains, area reductions of 18–28% are projected by 2100, with more intense retreat under higher emissions (Wang et al., 2021). The area loss lags behind volume loss because thinning can occur before significant retreat of glacier margins (Wal & Wild, 2001; Radic et al., 2013), which we also saw in the Zugspitze and Brewster glacial basins. Other literature suggested a non-linearity in glacier response that is more prominent the flatter the glacier is (Bolibar et al., 2022).
Zugspitze¶
According to the OGGM simulations for the Zugspitze basin, glacier ice volume decreases steadily across all temperature scenarios, with a near-complete loss of glacier mass projected by approximately 2070 for the higher temperature scenarios. This result, while alarming, shows a slightly slower retreat compared to earlier studies such as Marowsky (2010) and the Bayerischer Gletscherbericht 2021. In general, literature on the Zugspitze basin is very scarce and there is no data about hydrological output. However, these sources suggested that the main glaciers in the area—such as the Nördlicher Schneeferner and Höllentalferner—could largely disappear as early as 2030, particularly under conditions modeled using the REMO regional climate model and continued warming trends. The differences in these projections can be attributed to several factors. First, OGGM uses more recent climate scenarios based on CMIP6 (e.g., SSP1-2.6, SSP5-8.5), whereas older studies relied on CMIP3 or CMIP5-era inputs. Secondly, OGGM applies a simplified ice dynamics model, which may not fully capture complex melt processes and rapid degradation observed in steep, debris-free alpine glaciers. Lastly, the initial ice thickness data and glacier geometry used in OGGM are more up-to-date, potentially reflecting slightly greater resilience than older datasets used in previous studies.
Despite these methodological differences, both OGGM results and observational data agree on the broader trajectory: the glaciers of the Zugspitze massif are in terminal decline and will likely vanish entirely within the 21st century. The OGGM projection of a later disappearance underscores the importance of model choice and climate scenario assumptions.
Brewster¶
Brewster Glacier, located in New Zealand’s Southern Alps, demonstrates a highly climate-sensitive hydrological and mass balance response due to its maritime setting and high annual precipitation.
Less studies about the hydrological characteristics and projections for the Brewster basin can be found than for the Zugspitze basin. According to Anderson et al. (2010), the glacier receives abundant snowfall and rainfall, with rain alone contributing nearly 50% of the total annual runoff—an unusually high proportion compared to continental glaciers. This leads to a strong seasonal buffering effect, where up to half of the annual precipitation is temporarily stored as snow and firn before being released as meltwater during warmer months. Energy balance modeling shows that the glacier’s mass balance is strongly negative in response to even modest warming: a 1 °C temperature increase results in a dramatic increase in melt energy and a mass loss of approximately 1.5 m water equivalent per year. This rapid mass loss drives a substantial, but short-lived, increase in runoff—up to 60% higher per °C of warming—as ice melt accelerates. However, the model simulations reveal that this intensified melt is unsustainable over the long term. As the glacier thins and its storage capacity diminishes, annual runoff declines sharply after several decades, particularly under higher warming scenarios. Thus, while short-term warming may temporarily enhance water availability, it simultaneously undermines the glacier’s long-term viability.
Literature¶
Anderson, B., Mackintosh, A., Dadić, R., Oerlemans, J., Zammit, C., Doughty, A., Sood, A., & Mullan, B. (2021). Modelled response of debris-covered and lake-calving glaciers to climate change, Kā Tiritiri o te Moana/Southern Alps, New Zealand. Global and Planetary Change, 205, 103593. https://doi.org/10.1016/J.GLOPLACHA.2021.103593.
Bolibar, J., Rabatel, A., Gouttevin, I., Zekollari, H., & Galiez, C. (2022). Nonlinear sensitivity of glacier mass balance to future climate change unveiled by deep learning. Nature Communications, 13. https://doi.org/10.1038/s41467-022-28033-0.
Radic, V., Bliss, A., Beedlow, A., Hock, R., Miles, E., Miles, E., & Cogley, J. (2013). Regional and global projections of twenty-first century glacier mass changes in response to climate scenarios from global climate models. Climate Dynamics, 42, 37-58. https://doi.org/10.1007/s00382-013-1719-7.
Shannon, S., Smith, R., Wiltshire, A., Payne, T., Huss, M., Betts, R., Caesar, J., Koutroulis, A., Jones, D., & Harrison, S. (2019). Global glacier volume projections under high-end climate change scenarios. The Cryosphere. https://doi.org/10.5194/TC-13-325-2019.
Wang, T., Zhang, Z., Liu, L., Li, Z., Wang, P., Xu, L., Zhao, G., Tian, H., Kang, Z., Chen, H., & Zhang, X. (2021). Simulation of the Potential Distribution of the Glacier Based on Maximum Entropy Model in the Tianshan Mountains, China. Water, 13, 1541. https://doi.org/10.3390/W13111541.
Marowsky, K. (2010). Die Validierung des Gletschermodells Surges am Beispiel von Vernagtferner sowie Nördlichem und Südlichem Schneeferner [Unveröffentlichte Diplomarbeit]. Universität München. http://www.vernagtferner.de/Download/DA_Marowsky.pdf
Mayer, C., Hagg, W., Weber, M., & Lambrecht, A. (2021). Zweiter Bayerischer Gletscherbericht: Klimawandel in den Alpen. Bayerische Akademie der Wissenschaften & Bayerisches Staatsministerium für Umwelt und Verbraucherschutz. https://badw.de/fileadmin/user_upload/Files/BADW/Neuigkeiten/2021/04-21/Bayerischer_Gletscherbericht_2021_bf_low-DS_n.pdf
Anderson B, Mackintosh A, Stumm D, et al. Climate sensitivity of a high-precipitation glacier in New Zealand. Journal of Glaciology. 2010;56(195):114-128. doi:10.3189/002214310791190929