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)
In [2]:
# Imports
import os
import urllib.request

import xarray as xr
import pandas as pd
import numpy as np

import matplotlib.pyplot as plt # added by Jakob
import seaborn as sns
from scipy.stats import scoreatpercentile

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.

In [3]:
# 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),
}
print(temp_scenarios)
{'4°C':                        cmip            gcm    rcp     ssp  \
CCSM4_RCP85           CMIP5          CCSM4  rcp85     NaN   
MPI-ESM-LR_RCP85      CMIP5     MPI-ESM-LR  rcp85     NaN   
CNRM-CM5_RCP85        CMIP5       CNRM-CM5  rcp85     NaN   
NORESM2-MM_SSP585     CMIP6     NorESM2-MM    NaN  ssp585   
BCC-CSM2-MR_SSP585    CMIP6    BCC-CSM2-MR    NaN  ssp585   
FGOALS-F3-L_SSP585    CMIP6    FGOALS-f3-L    NaN  ssp585   
CESM2-WACCM_SSP370    CMIP6    CESM2-WACCM    NaN  ssp370   
CESM2_SSP370          CMIP6          CESM2    NaN  ssp370   
EC-EARTH3-VEG_SSP370  CMIP6  EC-Earth3-Veg    NaN  ssp370   

                      global_temp_ch_2071-2100_preindustrial  
CCSM4_RCP85                                         4.101378  
MPI-ESM-LR_RCP85                                    4.058044  
CNRM-CM5_RCP85                                      3.960476  
NORESM2-MM_SSP585                                   3.873557  
BCC-CSM2-MR_SSP585                                  4.035788  
FGOALS-F3-L_SSP585                                  4.197179  
CESM2-WACCM_SSP370                                  4.081607  
CESM2_SSP370                                        4.125652  
EC-EARTH3-VEG_SSP370                                4.143629  , '2.7°C':                            cmip            gcm    rcp          ssp  \
CNRM-CM5_RCP45            CMIP5       CNRM-CM5  rcp45          NaN   
CSIRO-MK3-6-0_RCP45       CMIP5  CSIRO-Mk3-6-0  rcp45          NaN   
IPSL-CM5A-LR_RCP45        CMIP5   IPSL-CM5A-LR  rcp45          NaN   
CCSM4_RCP60               CMIP5          CCSM4  rcp60          NaN   
GFDL-CM3_RCP26            CMIP5       GFDL-CM3  rcp26          NaN   
ACCESS-CM2_SSP126         CMIP6     ACCESS-CM2    NaN       ssp126   
CANESM5_SSP126            CMIP6        CanESM5    NaN       ssp126   
CAMS-CSM1-0_SSP370        CMIP6    CAMS-CSM1-0    NaN       ssp370   
CESM2-WACCM_SSP534-OVER   CMIP6    CESM2-WACCM    NaN  ssp534-over   
IPSL-CM6A-LR_SSP534-OVER  CMIP6   IPSL-CM6A-LR    NaN  ssp534-over   
MRI-ESM2-0_SSP245         CMIP6     MRI-ESM2-0    NaN       ssp245   
BCC-CSM2-MR_SSP245        CMIP6    BCC-CSM2-MR    NaN       ssp245   
FGOALS-F3-L_SSP245        CMIP6    FGOALS-f3-L    NaN       ssp245   
MRI-ESM2-0_SSP434         CMIP6     MRI-ESM2-0    NaN       ssp434   

                          global_temp_ch_2071-2100_preindustrial  
CNRM-CM5_RCP45                                          2.544987  
CSIRO-MK3-6-0_RCP45                                     2.870632  
IPSL-CM5A-LR_RCP45                                      2.783992  
CCSM4_RCP60                                             2.706795  
GFDL-CM3_RCP26                                          2.626000  
ACCESS-CM2_SSP126                                       2.781735  
CANESM5_SSP126                                          2.646456  
CAMS-CSM1-0_SSP370                                      2.731656  
CESM2-WACCM_SSP534-OVER                                 2.853885  
IPSL-CM6A-LR_SSP534-OVER                                2.792142  
MRI-ESM2-0_SSP245                                       2.844054  
BCC-CSM2-MR_SSP245                                      2.641109  
FGOALS-F3-L_SSP245                                      2.568657  
MRI-ESM2-0_SSP434                                       2.609334  , '1.5°C':                        cmip            gcm    rcp     ssp  \
GFDL-ESM2G_RCP45      CMIP5     GFDL-ESM2G  rcp45     NaN   
NORESM1-M_RCP26       CMIP5      NorESM1-M  rcp26     NaN   
MPI-ESM-LR_RCP26      CMIP5     MPI-ESM-LR  rcp26     NaN   
CCSM4_RCP26           CMIP5          CCSM4  rcp26     NaN   
MPI-ESM1-2-HR_SSP126  CMIP6  MPI-ESM1-2-HR    NaN  ssp126   
GFDL-ESM4_SSP126      CMIP6      GFDL-ESM4    NaN  ssp126   
INM-CM4-8_SSP126      CMIP6      INM-CM4-8    NaN  ssp126   
INM-CM5-0_SSP126      CMIP6      INM-CM5-0    NaN  ssp126   
CAMS-CSM1-0_SSP126    CMIP6    CAMS-CSM1-0    NaN  ssp126   
GFDL-ESM4_SSP119      CMIP6      GFDL-ESM4    NaN  ssp119   
MRI-ESM2-0_SSP119     CMIP6     MRI-ESM2-0    NaN  ssp119   

                      global_temp_ch_2071-2100_preindustrial  
GFDL-ESM2G_RCP45                                    1.666789  
NORESM1-M_RCP26                                     1.545585  
MPI-ESM-LR_RCP26                                    1.487504  
CCSM4_RCP26                                         1.579428  
MPI-ESM1-2-HR_SSP126                                1.669876  
GFDL-ESM4_SSP126                                    1.692323  
INM-CM4-8_SSP126                                    1.534266  
INM-CM5-0_SSP126                                    1.589314  
CAMS-CSM1-0_SSP126                                  1.510336  
GFDL-ESM4_SSP119                                    1.307174  
MRI-ESM2-0_SSP119                                   1.619736  }
In [4]:
df_warming_levels.gcm.unique()  # print the unique RCPs in the dataframe
Out[4]:
array(['CCSM4', 'MPI-ESM-LR', 'CNRM-CM5', 'GFDL-ESM2G', 'CSIRO-Mk3-6-0',
       'IPSL-CM5A-LR', 'GFDL-CM3', 'NorESM1-M', 'GISS-E2-R', 'CanESM2',
       'CESM1-CAM5', 'CESM2-WACCM', 'MPI-ESM1-2-HR', 'GFDL-ESM4',
       'NorESM2-MM', 'ACCESS-ESM1-5', 'ACCESS-CM2', 'INM-CM4-8',
       'CanESM5', 'IPSL-CM6A-LR', 'INM-CM5-0', 'MRI-ESM2-0', 'CESM2',
       'EC-Earth3', 'EC-Earth3-Veg', 'CAMS-CSM1-0', 'BCC-CSM2-MR',
       'FGOALS-f3-L', 'CMCC-CM2-SR5', 'TaiESM1'], dtype=object)
Task: For each temperature target (1.5°C, 2.7°C, and 4.0°C), evaluate the selection of climate model realizations by calculating the mean, median, and number of realizations included in each group. Briefly discuss your findings.
In [5]:
# Evaluate and plot the selection of climate model realizations for each temperature target
stats = []
for temp, df in temp_scenarios.items():
    temps = df['global_temp_ch_2071-2100_preindustrial']
    mean_val = temps.mean()
    median_val = temps.median()
    std_val = temps.std()
    count_val = temps.count()
    stats.append({'Scenario': temp, 'Mean': mean_val, 'Median': median_val, 'Std': std_val, 'Count': count_val})
    print(f"{temp}:")
    print(f"  Number of realizations: {count_val}")
    print(f"  Mean warming: {mean_val:.2f}°C")
    print(f"  Median warming: {median_val:.2f}°C")
4°C:
  Number of realizations: 9
  Mean warming: 4.06°C
  Median warming: 4.08°C
2.7°C:
  Number of realizations: 14
  Mean warming: 2.71°C
  Median warming: 2.72°C
1.5°C:
  Number of realizations: 11
  Mean warming: 1.56°C
  Median warming: 1.58°C
In [6]:
fig, axes = plt.subplots(2, 4, figsize=(24, 12), sharey=True)
df_warming_levels.iloc[0:15].plot(x='gcm', y='global_temp_ch_2071-2100_preindustrial', kind='bar', ax=axes[0, 0])
df_warming_levels.iloc[15:30].plot(x='gcm', y='global_temp_ch_2071-2100_preindustrial', kind='bar', ax=axes[0, 1])
df_warming_levels.iloc[30:45].plot(x='gcm', y='global_temp_ch_2071-2100_preindustrial', kind='bar', ax=axes[0, 2])
df_warming_levels.iloc[45:60].plot(x='gcm', y='global_temp_ch_2071-2100_preindustrial', kind='bar', ax=axes[0, 3])
df_warming_levels.iloc[60:75].plot(x='gcm', y='global_temp_ch_2071-2100_preindustrial', kind='bar', ax=axes[1, 0])
df_warming_levels.iloc[75:90].plot(x='gcm', y='global_temp_ch_2071-2100_preindustrial', kind='bar', ax=axes[1, 1])
df_warming_levels.iloc[90:105].plot(x='gcm', y='global_temp_ch_2071-2100_preindustrial', kind='bar', ax=axes[1, 2])
df_warming_levels.iloc[105:].plot(x='gcm', y='global_temp_ch_2071-2100_preindustrial', kind='bar', ax=axes[1, 3])


for ax in axes.flatten():
    ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha='right')
    ax.set_xlabel('GCM')
    ax.set_ylabel('Warming (°C)')
    ax.grid(axis='y')
axes[0, 0].set_title('Projected Warming by GCM (Part 1)')
axes[0, 1].set_title('Projected Warming by GCM (Part 2)')
axes[0, 2].set_title('Projected Warming by GCM (Part 3)')
axes[1, 0].set_title('Projected Warming by GCM (Part 4)')
plt.tight_layout()
plt.show()
No description has been provided for this image

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.

In [7]:
# add here your the basin_id of your selected basins (e.g. ['basin_1', 'basin_2'])
basin_ids = ['rofental', 'langtang' ]

# 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)
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp85.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM-LR_rcp85.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CNRM-CM5_rcp85.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_NorESM2-MM_ssp585.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_BCC-CSM2-MR_ssp585.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_FGOALS-f3-L_ssp585.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2-WACCM_ssp370.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2_ssp370.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_EC-Earth3-Veg_ssp370.nc
rofental: combining data for 4°C
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CNRM-CM5_rcp45.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CSIRO-Mk3-6-0_rcp45.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_IPSL-CM5A-LR_rcp45.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp60.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-CM3_rcp26.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_ACCESS-CM2_ssp126.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CanESM5_ssp126.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CAMS-CSM1-0_ssp370.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2-WACCM_ssp534-over.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_IPSL-CM6A-LR_ssp534-over.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp245.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_BCC-CSM2-MR_ssp245.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_FGOALS-f3-L_ssp245.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp434.nc
rofental: combining data for 2.7°C
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM2G_rcp45.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_NorESM1-M_rcp26.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM-LR_rcp26.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp26.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM1-2-HR_ssp126.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM4_ssp126.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_INM-CM4-8_ssp126.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_INM-CM5-0_ssp126.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_CAMS-CSM1-0_ssp126.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM4_ssp119.nc
File already downloaded: basin_rofental_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp119.nc
rofental: combining data for 1.5°C
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp85.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM-LR_rcp85.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CNRM-CM5_rcp85.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_NorESM2-MM_ssp585.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_BCC-CSM2-MR_ssp585.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_FGOALS-f3-L_ssp585.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2-WACCM_ssp370.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2_ssp370.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_EC-Earth3-Veg_ssp370.nc
langtang: combining data for 4°C
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CNRM-CM5_rcp45.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CSIRO-Mk3-6-0_rcp45.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_IPSL-CM5A-LR_rcp45.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp60.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-CM3_rcp26.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_ACCESS-CM2_ssp126.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CanESM5_ssp126.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CAMS-CSM1-0_ssp370.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CESM2-WACCM_ssp534-over.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_IPSL-CM6A-LR_ssp534-over.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp245.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_BCC-CSM2-MR_ssp245.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_FGOALS-f3-L_ssp245.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp434.nc
langtang: combining data for 2.7°C
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM2G_rcp45.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_NorESM1-M_rcp26.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM-LR_rcp26.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CCSM4_rcp26.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_MPI-ESM1-2-HR_ssp126.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM4_ssp126.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_INM-CM4-8_ssp126.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_INM-CM5-0_ssp126.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_CAMS-CSM1-0_ssp126.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_GFDL-ESM4_ssp119.nc
File already downloaded: basin_langtang_run_hydro_w5e5_gcm_merged_bc_2000_2019_MRI-ESM2-0_ssp119.nc
langtang: 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:

In [8]:
print(ds_all)
{'rofental': {'4°C': <xarray.Dataset> Size: 6MB
Dimensions:                       (time: 101, rgi_id: 23, gcm_scenario: 9,
                                   month_2d: 12)
Coordinates:
  * time                          (time) float64 808B 2e+03 ... 2.1e+03
  * rgi_id                        (rgi_id) <U14 1kB 'RGI60-11.00719' ... 'RGI...
    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 72B MultiIndex
  * gcm                           (gcm_scenario) <U13 468B 'BCC-CSM2-MR' ... ...
  * scenario                      (gcm_scenario) <U6 216B 'ssp585' ... 'ssp585'
Data variables: (12/14)
    volume                        (time, rgi_id, gcm_scenario) float32 84kB 4...
    area                          (time, rgi_id, gcm_scenario) float32 84kB 8...
    on_area                       (time, rgi_id, gcm_scenario) float32 84kB 8...
    off_area                      (time, rgi_id, gcm_scenario) float32 84kB 3...
    melt_off_glacier              (time, rgi_id, gcm_scenario) float32 84kB 3...
    melt_on_glacier               (time, rgi_id, gcm_scenario) float32 84kB 1...
    ...                            ...
    melt_off_glacier_monthly      (time, month_2d, rgi_id, gcm_scenario) float32 1MB ...
    melt_on_glacier_monthly       (time, month_2d, rgi_id, gcm_scenario) float32 1MB ...
    liq_prcp_off_glacier_monthly  (time, month_2d, rgi_id, gcm_scenario) float32 1MB ...
    liq_prcp_on_glacier_monthly   (time, month_2d, rgi_id, gcm_scenario) float32 1MB ...
    runoff_monthly                (time, month_2d, rgi_id, gcm_scenario) float32 1MB ...
    runoff                        (time, rgi_id, gcm_scenario) float32 84kB 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:             Rofental
    basin_area_km2:         98.64030351364737
    glaciers_in_basin:      23
    glacierised_area_perc:  35.36384090218637
    glacierised_area_km2:   34.883, '2.7°C': <xarray.Dataset> Size: 9MB
Dimensions:                       (time: 101, rgi_id: 23, gcm_scenario: 14,
                                   month_2d: 12)
Coordinates:
  * time                          (time) float64 808B 2e+03 ... 2.1e+03
  * rgi_id                        (rgi_id) <U14 1kB 'RGI60-11.00719' ... 'RGI...
    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 112B MultiIndex
  * gcm                           (gcm_scenario) <U13 728B 'ACCESS-CM2' ... '...
  * scenario                      (gcm_scenario) <U11 616B 'ssp126' ... 'ssp434'
Data variables: (12/14)
    volume                        (time, rgi_id, gcm_scenario) float32 130kB ...
    area                          (time, rgi_id, gcm_scenario) float32 130kB ...
    on_area                       (time, rgi_id, gcm_scenario) float32 130kB ...
    off_area                      (time, rgi_id, gcm_scenario) float32 130kB ...
    melt_off_glacier              (time, rgi_id, gcm_scenario) float32 130kB ...
    melt_on_glacier               (time, rgi_id, gcm_scenario) float32 130kB ...
    ...                            ...
    melt_off_glacier_monthly      (time, month_2d, rgi_id, gcm_scenario) float32 2MB ...
    melt_on_glacier_monthly       (time, month_2d, rgi_id, gcm_scenario) float32 2MB ...
    liq_prcp_off_glacier_monthly  (time, month_2d, rgi_id, gcm_scenario) float32 2MB ...
    liq_prcp_on_glacier_monthly   (time, month_2d, rgi_id, gcm_scenario) float32 2MB ...
    runoff_monthly                (time, month_2d, rgi_id, gcm_scenario) float32 2MB ...
    runoff                        (time, rgi_id, gcm_scenario) float32 130kB ...
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:             Rofental
    basin_area_km2:         98.64030351364737
    glaciers_in_basin:      23
    glacierised_area_perc:  35.36384090218637
    glacierised_area_km2:   34.883, '1.5°C': <xarray.Dataset> Size: 7MB
Dimensions:                       (time: 101, rgi_id: 23, gcm_scenario: 11,
                                   month_2d: 12)
Coordinates:
  * time                          (time) float64 808B 2e+03 ... 2.1e+03
  * rgi_id                        (rgi_id) <U14 1kB 'RGI60-11.00719' ... 'RGI...
    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 102kB ...
    area                          (time, rgi_id, gcm_scenario) float32 102kB ...
    on_area                       (time, rgi_id, gcm_scenario) float32 102kB ...
    off_area                      (time, rgi_id, gcm_scenario) float32 102kB ...
    melt_off_glacier              (time, rgi_id, gcm_scenario) float32 102kB ...
    melt_on_glacier               (time, rgi_id, gcm_scenario) float32 102kB ...
    ...                            ...
    melt_off_glacier_monthly      (time, month_2d, rgi_id, gcm_scenario) float32 1MB ...
    melt_on_glacier_monthly       (time, month_2d, rgi_id, gcm_scenario) float32 1MB ...
    liq_prcp_off_glacier_monthly  (time, month_2d, rgi_id, gcm_scenario) float32 1MB ...
    liq_prcp_on_glacier_monthly   (time, month_2d, rgi_id, gcm_scenario) float32 1MB ...
    runoff_monthly                (time, month_2d, rgi_id, gcm_scenario) float32 1MB ...
    runoff                        (time, rgi_id, gcm_scenario) float32 102kB ...
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:             Rofental
    basin_area_km2:         98.64030351364737
    glaciers_in_basin:      23
    glacierised_area_perc:  35.36384090218637
    glacierised_area_km2:   34.883}, 'langtang': {'4°C': <xarray.Dataset> Size: 26MB
Dimensions:                       (time: 101, rgi_id: 102, gcm_scenario: 9,
                                   month_2d: 12)
Coordinates:
  * time                          (time) float64 808B 2e+03 ... 2.1e+03
  * rgi_id                        (rgi_id) <U14 6kB 'RGI60-15.03954' ... 'RGI...
    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 72B MultiIndex
  * gcm                           (gcm_scenario) <U13 468B 'BCC-CSM2-MR' ... ...
  * scenario                      (gcm_scenario) <U6 216B 'ssp585' ... 'ssp585'
Data variables: (12/14)
    volume                        (time, rgi_id, gcm_scenario) float32 371kB ...
    area                          (time, rgi_id, gcm_scenario) float32 371kB ...
    on_area                       (time, rgi_id, gcm_scenario) float32 371kB ...
    off_area                      (time, rgi_id, gcm_scenario) float32 371kB ...
    melt_off_glacier              (time, rgi_id, gcm_scenario) float32 371kB ...
    melt_on_glacier               (time, rgi_id, gcm_scenario) float32 371kB ...
    ...                            ...
    melt_off_glacier_monthly      (time, month_2d, rgi_id, gcm_scenario) float32 4MB ...
    melt_on_glacier_monthly       (time, month_2d, rgi_id, gcm_scenario) float32 4MB ...
    liq_prcp_off_glacier_monthly  (time, month_2d, rgi_id, gcm_scenario) float32 4MB ...
    liq_prcp_on_glacier_monthly   (time, month_2d, rgi_id, gcm_scenario) float32 4MB ...
    runoff_monthly                (time, month_2d, rgi_id, gcm_scenario) float32 4MB ...
    runoff                        (time, rgi_id, gcm_scenario) float32 371kB ...
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:             Langtang
    basin_area_km2:         583.8048947612463
    glaciers_in_basin:      102
    glacierised_area_perc:  21.129661828280465
    glacierised_area_km2:   123.356, '2.7°C': <xarray.Dataset> Size: 40MB
Dimensions:                       (time: 101, rgi_id: 102, gcm_scenario: 14,
                                   month_2d: 12)
Coordinates:
  * time                          (time) float64 808B 2e+03 ... 2.1e+03
  * rgi_id                        (rgi_id) <U14 6kB 'RGI60-15.03954' ... 'RGI...
    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 112B MultiIndex
  * gcm                           (gcm_scenario) <U13 728B 'ACCESS-CM2' ... '...
  * scenario                      (gcm_scenario) <U11 616B 'ssp126' ... 'ssp434'
Data variables: (12/14)
    volume                        (time, rgi_id, gcm_scenario) float32 577kB ...
    area                          (time, rgi_id, gcm_scenario) float32 577kB ...
    on_area                       (time, rgi_id, gcm_scenario) float32 577kB ...
    off_area                      (time, rgi_id, gcm_scenario) float32 577kB ...
    melt_off_glacier              (time, rgi_id, gcm_scenario) float32 577kB ...
    melt_on_glacier               (time, rgi_id, gcm_scenario) float32 577kB ...
    ...                            ...
    melt_off_glacier_monthly      (time, month_2d, rgi_id, gcm_scenario) float32 7MB ...
    melt_on_glacier_monthly       (time, month_2d, rgi_id, gcm_scenario) float32 7MB ...
    liq_prcp_off_glacier_monthly  (time, month_2d, rgi_id, gcm_scenario) float32 7MB ...
    liq_prcp_on_glacier_monthly   (time, month_2d, rgi_id, gcm_scenario) float32 7MB ...
    runoff_monthly                (time, month_2d, rgi_id, gcm_scenario) float32 7MB ...
    runoff                        (time, rgi_id, gcm_scenario) float32 577kB ...
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:             Langtang
    basin_area_km2:         583.8048947612463
    glaciers_in_basin:      102
    glacierised_area_perc:  21.129661828280465
    glacierised_area_km2:   123.356, '1.5°C': <xarray.Dataset> Size: 31MB
Dimensions:                       (time: 101, rgi_id: 102, gcm_scenario: 11,
                                   month_2d: 12)
Coordinates:
  * time                          (time) float64 808B 2e+03 ... 2.1e+03
  * rgi_id                        (rgi_id) <U14 6kB 'RGI60-15.03954' ... 'RGI...
    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 453kB ...
    area                          (time, rgi_id, gcm_scenario) float32 453kB ...
    on_area                       (time, rgi_id, gcm_scenario) float32 453kB ...
    off_area                      (time, rgi_id, gcm_scenario) float32 453kB ...
    melt_off_glacier              (time, rgi_id, gcm_scenario) float32 453kB ...
    melt_on_glacier               (time, rgi_id, gcm_scenario) float32 453kB ...
    ...                            ...
    melt_off_glacier_monthly      (time, month_2d, rgi_id, gcm_scenario) float32 5MB ...
    melt_on_glacier_monthly       (time, month_2d, rgi_id, gcm_scenario) float32 5MB ...
    liq_prcp_off_glacier_monthly  (time, month_2d, rgi_id, gcm_scenario) float32 5MB ...
    liq_prcp_on_glacier_monthly   (time, month_2d, rgi_id, gcm_scenario) float32 5MB ...
    runoff_monthly                (time, month_2d, rgi_id, gcm_scenario) float32 5MB ...
    runoff                        (time, rgi_id, gcm_scenario) float32 453kB ...
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:             Langtang
    basin_area_km2:         583.8048947612463
    glaciers_in_basin:      102
    glacierised_area_perc:  21.129661828280465
    glacierised_area_km2:   123.356}}
Task: Explore and discuss the available data (data structure, variables, units, temporal resolution, ...).

Summarize key points for discussion

  • Data is stored as an xarray.Dataset with dimensions: time, rgi_id, gcm_scenario (or scenario/gcm)
  • Variables include glacier volume, area, runoff, melt, precipitation, etc.
  • Units are typically km³ for volume, km² for area, mm or m³ for runoff, etc.
  • Temporal resolution: yearly (time from 2000 to 2100) and monthly (month_2d)
  • Attributes provide basin metadata: name, area, glacierized fraction, etc.

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:

In [9]:
# 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

for id in basin_ids:
    print('for the basin: ', id)
    for temp in temp_scenarios:
        print(f"{temp}: {not_nan_rgi_ids_all[id].size} glaciers available")
for the basin:  rofental
4°C: 23 glaciers available
2.7°C: 23 glaciers available
1.5°C: 23 glaciers available
for the basin:  langtang
4°C: 102 glaciers available
2.7°C: 102 glaciers available
1.5°C: 102 glaciers available

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.

In [10]:
basin_example = basin_ids[1]
ds_all[basin_example]['4°C'].sel(rgi_id=not_nan_rgi_ids_all[basin_example]).coords['rgi_id']

#########see if the 23 and 102 glacies fromt the file are available in the data for all scenarios
for id in basin_ids:
    print('for the basin: ', id)
    for temp in temp_scenarios:
        print(f"{temp}: {not_nan_rgi_ids_all[id].size} glaciers available")
for the basin:  rofental
4°C: 23 glaciers available
2.7°C: 23 glaciers available
1.5°C: 23 glaciers available
for the basin:  langtang
4°C: 102 glaciers available
2.7°C: 102 glaciers available
1.5°C: 102 glaciers available
Important: For all subsequent analyses, make sure to include only the glaciers that are available across all scenarios to ensure consistency!

When comparing the number of glaciers with the one given in the slides we can see that all are avaliable 23 for Rofental and 102 for LangTang

Task: For each of your basins, check whether any glaciers were excluded during the filtering process, and if so, calculate the total glacier area in 2000 of the excluded glaciers (in km²) and what percentage this represents of the total 2000 glacier area in the basin.

Your answer here:

  • since all galciers are all available in all scenarios skip this task

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.

Please answer at least the following questions:
  • 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)

Your answer here: Rofental is located in the Ötztal Alps in Austria, Central Europe. The climate is temperate alpine, characterized by cold winters, cool summers, and significant precipitation, much of it as snow at higher elevations.

  • Basin area: 98.64 km²
  • Glacierized area: 34.88 km²
  • Glacierized fraction: 35.36%

Langtang is situated in the Himalayas of Nepal. The climate is high-mountain continental, with cold winters, a pronounced monsoon season (June–September), and dry winters.

  • Basin area: 583.80 km²
  • Glacierized area: 123.36 km²
  • Glacierized fraction: 21.13%

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).

In [11]:
# Plot glacier volume and area evolution for each basin and scenario
years = ds_all[basin_ids[0]]['1.5°C'].time.values
start_idx = np.where(years >= 2020)[0][0]
years = years[start_idx:]

percentiles = [17, 50, 83]

for basin in basin_ids:
    attrs = ds_all[basin]['1.5°C'].attrs
    frac = attrs['glacierised_area_perc']
    basin_name = attrs['basin_name']

    fig, axes = plt.subplots(1, 2, figsize=(14, 5), sharex=True)
    for var, ax, ylabel in zip(['volume', 'area'], axes, ['Glacier Volume (km³)', 'Glacier Area (km²)']):
        for scenario, color in zip(['1.5°C', '2.7°C', '4°C'], ['tab:blue', 'tab:orange', 'tab:red']):
            ds = ds_all[basin][scenario].sel(rgi_id=not_nan_rgi_ids_all[basin])
            # Sum over glaciers, then compute percentiles over gcm_scenario
            data = ds[var].sum(dim='rgi_id').transpose('time', 'gcm_scenario').values[start_idx:]
            p17 = np.percentile(data, percentiles[0], axis=1)
            p50 = np.percentile(data, percentiles[1], axis=1)
            p83 = np.percentile(data, percentiles[2], axis=1)
            ax.plot(years, p50, label=scenario, color=color)
            ax.fill_between(years, p17, p83, color=color, alpha=0.2)
        ax.set_ylabel(ylabel)
        ax.set_xlabel('Year')
        ax.grid(True)
        ax.set_xlim([2020, 2100])
    axes[0].set_title(f"{basin_name}: Glacier Volume\nGlacierized Fraction: {frac:.1f}%")
    axes[1].set_title(f"{basin_name}: Glacier Area\nGlacierized Fraction: {frac:.1f}%")
    axes[1].legend(title='Scenario')
    plt.tight_layout()
    plt.show()
No description has been provided for this image
No description has been provided for this image
Questions:
  • 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?

Your answers here:

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.

In [12]:
# ---------- variable preparation --------- # 
ds_rofental = ds_all['rofental']
ds_langtang = ds_all['langtang']
temperatures = ['1.5°C', '2.7°C', '4°C']
runoff_vars = ['melt_off_glacier', 'melt_on_glacier', 'liq_prcp_off_glacier', 'liq_prcp_on_glacier']
years = [2020, 2060, 2099]
In [17]:
# ############ Plot 1) #############
# Time setup
years = ds_all[basin_ids[0]]['1.5°C'].time.values
start_idx = np.where(years >= 2020)[0][0]
years = years[start_idx:]

percentiles = [17, 50, 83]
colors = {'1.5°C': 'tab:blue', '2.7°C': 'tab:orange', '4°C': 'tab:red'}

for basin in basin_ids:
    attrs = ds_all[basin]['1.5°C'].attrs
    basin_name = attrs['basin_name']

    fig, ax = plt.subplots(figsize=(10, 4))

    for scenario in ['1.5°C', '2.7°C', '4°C']:
        ds = ds_all[basin][scenario].sel(rgi_id=not_nan_rgi_ids_all[basin])

        # Sum all runoff components and convert from m³ to Gt (1e9 m³)
        runoff = sum(ds[comp] for comp in runoff_vars) * 1e-9  # Gt

        # Sum over rgi_ids
        total_runoff = runoff.sum(dim='rgi_id')  # Dimensions: time, gcm_scenario

        # Convert to numpy array and trim to 2020 onward
        data = total_runoff.values[start_idx:]  # shape: (years, gcm_scenario)

        # Compute percentiles across GCMs
        p17 = np.percentile(data, percentiles[0], axis=1)
        p50 = np.percentile(data, percentiles[1], axis=1)
        p83 = np.percentile(data, percentiles[2], axis=1)

        ax.plot(years, p50, label=scenario, color=colors[scenario])
        ax.fill_between(years, p17, p83, color=colors[scenario], alpha=0.2)

    ax.set_title(f"{basin_name}: Total Annual Runoff (2020–2100)\nGlaciered Fraction: {attrs['glacierised_area_perc']:.1f}%")
    ax.set_ylabel("Total Runoff [Mt/year]")
    ax.set_xlabel("Year")
    ax.grid(True)
    ax.set_xlim([2020, 2100])
    ax.legend(title="Scenario")

    plt.tight_layout()
    plt.show()
No description has been provided for this image
No description has been provided for this image
In [31]:
############# Plot 2) ############
# --------- variable preparation --------- #

df_annual_r = {}
df_annual_l = {}

for temp in temperatures:
    # Only use glaciers available in all scenarios
    sel_vars_r = [v for v in ds_rofental[temp].data_vars if 'month_2d' not in ds_rofental[temp][v].dims]
    sel_vars_l = [v for v in ds_langtang[temp].data_vars if 'month_2d' not in ds_langtang[temp][v].dims]
    df_annual_r[temp] = ds_rofental[temp][sel_vars_r].sel(rgi_id=not_nan_rgi_ids_all['rofental']).sum(dim='rgi_id').to_dataframe()
    df_annual_l[temp] = ds_langtang[temp][sel_vars_l].sel(rgi_id=not_nan_rgi_ids_all['langtang']).sum(dim='rgi_id').to_dataframe()

# Convert to Gt if not already done
for temp in temperatures:
    df_annual_r[temp] = df_annual_r[temp][runoff_vars] * 1e-9
    df_annual_l[temp] = df_annual_l[temp][runoff_vars] * 1e-9

frac_rofental = ds_rofental['1.5°C'].attrs['glacierised_area_perc']
frac_langtang = ds_langtang['1.5°C'].attrs['glacierised_area_perc']

# Plot 1: Median only (no running mean)
fig1, axs1 = plt.subplots(2, 3, figsize=(18, 10), sharex=True, sharey=False)
colors = sns.color_palette("mako", n_colors=len(runoff_vars))

for col, temp in enumerate(temperatures):
    # --- Rofental ---
    ax_r = axs1[0, col]
    df_r = df_annual_r[temp].reset_index()
    df_r_median = df_r.groupby('time')[runoff_vars].median()
    df_r_median.plot.area(ax=ax_r, color=colors, alpha=0.95)
    ax_r.set_title(f'Rofental - {temp}\nGlacierized Fraction: {frac_rofental:.1f}%')
    ax_r.set_ylabel('Runoff [Mt]')
    ax_r.set_xlabel('Year')
    ax_r.set_ylim(0, 250)
    if col == 2:
        ax_r.legend(loc='upper right', fontsize='small')
    else:
        ax_r.get_legend().remove()

    # --- Langtang ---
    ax_l = axs1[1, col]
    df_l = df_annual_l[temp].reset_index()
    df_l_median = df_l.groupby('time')[runoff_vars].median()
    df_l_median.plot.area(ax=ax_l, color=colors, alpha=0.95)
    ax_l.set_title(f'Langtang - {temp}\nGlacierized Fraction: {frac_langtang:.1f}%')
    ax_l.set_ylabel('Runoff [Mt]')
    ax_l.set_xlabel('Year')
    # Do not set ylim for Langtang
    if col == 2:
        ax_l.legend(loc='upper right', fontsize='small')
    else:
        ax_l.get_legend().remove()

plt.suptitle("Annual runoff components (median, no smoothing)", y=1.02, fontsize=16)
plt.tight_layout()
plt.show()

# Plot 2: Median with running mean
fig2, axs2 = plt.subplots(2, 3, figsize=(18, 10), sharex=True, sharey=False)

for col, temp in enumerate(temperatures):
    # --- Rofental ---
    ax_r = axs2[0, col]
    df_r = df_annual_r[temp].reset_index()
    df_r_median = df_r.groupby('time')[runoff_vars].median()
    df_r_median_smooth = df_r_median.rolling(window=24, min_periods=1, center=True).mean()
    df_r_median_smooth.plot.area(ax=ax_r, color=colors, alpha=0.95)
    ax_r.set_title(f'Rofental - {temp}\nGlacierized Fraction: {frac_rofental:.1f}%')
    ax_r.set_ylabel('Runoff [Mt]')
    ax_r.set_xlabel('Year')
    ax_r.set_ylim(0, 250)
    if col == 2:
        ax_r.legend(loc='upper right', fontsize='small')
    else:
        ax_r.get_legend().remove()

    # --- Langtang ---
    ax_l = axs2[1, col]
    df_l = df_annual_l[temp].reset_index()
    df_l_median = df_l.groupby('time')[runoff_vars].median()
    df_l_median_smooth = df_l_median.rolling(window=24, min_periods=1, center=True).mean()
    df_l_median_smooth.plot.area(ax=ax_l, color=colors, alpha=0.95)
    ax_l.set_title(f'Langtang - {temp}\nGlacierized Fraction: {frac_langtang:.1f}%')
    ax_l.set_ylabel('Runoff [Mt]')
    ax_l.set_xlabel('Year')
    # Do not set ylim for Langtang
    if col == 2:
        ax_l.legend(loc='upper right', fontsize='small')
    else:
        ax_l.get_legend().remove()

plt.suptitle("Annual runoff components (median, 24-year running mean)", y=1.02, fontsize=16)
plt.tight_layout()
plt.show()
No description has been provided for this image
No description has been provided for this image
In [25]:
############ Plot 3) ############
# 1. Extract DataFrames
for temp in temperatures:
    df_annual_r[temp] = ds_rofental[temp].sel(rgi_id=not_nan_rgi_ids_all['rofental']).sum(dim='rgi_id').to_dataframe()
    df_annual_l[temp] = ds_langtang[temp].sel(rgi_id=not_nan_rgi_ids_all['langtang']).sum(dim='rgi_id').to_dataframe()

# 2. Calculate monthly medians
for temp in temperatures:
    var = 'runoff_monthly'
    df_annual_r[temp] = (
        df_annual_r[temp]
        .groupby(['calendar_year', 'calendar_month_2d'])[var]
        .median()
        .unstack()
        * 1e-9
    )
    df_annual_l[temp] = (
        df_annual_l[temp]
        .groupby(['calendar_year', 'calendar_month_2d'])[var]
        .median()
        .unstack()
        * 1e-9
    )

# Get glacierized area fractions for titles
frac_rofental = ds_rofental['1.5°C'].attrs['glacierised_area_perc']
frac_langtang = ds_langtang['1.5°C'].attrs['glacierised_area_perc']

# 3. Plotting heatmaps
fig, axs = plt.subplots(2, 3, figsize=(18, 12), sharex=True, sharey=True)

for col, temp in enumerate(temperatures):
    # Rofental
    ax_r = axs[0, col]
    sns.heatmap(
        df_annual_r[temp], ax=ax_r, cmap=sns.color_palette("vlag", as_cmap=True), cbar=col == 2,
        linewidths=0.1, linecolor='gray'
    )
    ax_r.set_title(f'Rofental - {temp}\nGlacierized Fraction: {frac_rofental:.1f}%')
    ax_r.set_xlabel('Month')
    ax_r.set_ylabel('Year')

    # Langtang
    ax_l = axs[1, col]
    sns.heatmap(
        df_annual_l[temp], ax=ax_l, cmap=sns.color_palette("vlag", as_cmap=True), cbar=col == 2,
        linewidths=0.1, linecolor='gray'
    )
    ax_l.set_title(f'Langtang - {temp}\nGlacierized Fraction: {frac_langtang:.1f}%')
    ax_l.set_xlabel('Month')
    ax_l.set_ylabel('Year')

plt.tight_layout()
plt.show()
No description has been provided for this image
In [27]:
############## Plot 4 ##############
# Constants
month_labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 
                'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
key_years = [2020, 2060, 2099]
colors = ['tab:blue', 'tab:orange', 'tab:green']

# Get glacierized fractions for titles
frac_rofental = ds_rofental['1.5°C'].attrs['glacierised_area_perc']
frac_langtang = ds_langtang['1.5°C'].attrs['glacierised_area_perc']

for temp in temperatures:
    df_annual_r[temp] = ds_rofental[temp].sel(rgi_id=not_nan_rgi_ids_all['rofental']).sum(dim='rgi_id').to_dataframe()
    df_annual_l[temp] = ds_langtang[temp].sel(rgi_id=not_nan_rgi_ids_all['langtang']).sum(dim='rgi_id').to_dataframe()

def get_monthly_stats(df, year):
    monthly = df[df['calendar_year'] == year].groupby('calendar_month_2d')['runoff_monthly']
    median = monthly.median().values * 1e-9
    q17 = monthly.quantile(0.17).values * 1e-9
    q83 = monthly.quantile(0.83).values * 1e-9
    return median, q17, q83

fig, axs = plt.subplots(2, 3, figsize=(18, 10), sharex=True, sharey=False)

for row, (basin, dfs, frac) in enumerate(zip(['rofental', 'langtang'], [df_annual_r, df_annual_l], [frac_rofental, frac_langtang])):
    for col, temp in enumerate(temperatures):
        ax = axs[row, col]
        for idx, year in enumerate(key_years):
            median, q17, q83 = get_monthly_stats(dfs[temp], year)
            ax.plot(range(1, 13), median, label=f'{year}', color=colors[idx])
            ax.fill_between(range(1, 13), q17, q83, color=colors[idx], alpha=0.2)

        ax.set_title(f"{basin.capitalize()} - {temp}\nGlacierized Fraction: {frac:.1f}%")
        ax.set_xticks(range(1, 13))
        ax.set_xticklabels(month_labels)
        if col == 0:
            ax.set_ylabel('Runoff [Mt]')
        if row == 1:
            ax.set_xlabel('Month')
        if row == 0:
            ax.set_ylim(0, 100)
        else: 
            ax.set_ylim(0, 500)
        if row == 0 and col == 2:
            ax.legend(title="Year")

plt.tight_layout()
plt.show()


        
No description has been provided for this image
Questions:
  • 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?

Comparison of scenarios within each basin:
For both Rofental and Langtang, higher warming scenarios (2.7°C and 4°C) lead to a much stronger and faster decline in glacier volume and area, as well as a more pronounced reduction in glacier melt contribution to runoff. Under the 1.5°C scenario, glacier loss is slower and a larger glacierized area persists by 2100, resulting in a more sustained glacier melt contribution to runoff.

Similarities and differences between basins:
Both basins show qualitatively similar responses to warming: accelerated glacier loss and declining glacier melt runoff with increasing temperature. However, Langtang (with a lower glacierized fraction) shows a larger absolute runoff and a more pronounced shift from glacier melt to liquid precipitation as the dominant runoff source. Rofental, being more glacierized, exhibits a steeper decline in glacier melt runoff and a more rapid transition to rainfall-dominated runoff under high warming.

Evidence of peak water:
Yes, both basins show evidence of "peak water": annual runoff initially increases or remains stable as glacier melt accelerates due to warming, but then declines in the second half of the century as glacier area shrinks and meltwater supply diminishes. This is especially clear in the 2.7°C and 4°C scenarios, where peak runoff is reached before 2050, followed by a steady decrease towards 2100. The timing and magnitude of peak water differ between basins and scenarios, but the pattern is consistent. For better visibility of the 'peak water' we additionally plotted the running mean in the second plot

Contextualize your results with the literature¶

Task: Compare your findings with existing studies or reports. For each basin, find at least one relevant source from the scientific literature. Compare your results to those presented in the literature, and discuss any similarities or differences. Use the knowledge you have gained during the practical sessions, particularly about OGGM and how the data is generated, to help interpret and explain any contrasts between your findings and those in other studies.

Your answer here:

Cites for Rofental¶

  1. Hanzer, F., Förster, K., Nemec, J., & Strasser, U. (2018). Projected cryospheric and hydrological impacts of 21st century climate change in the Ötztal Alps (Austria) simulated using a physically based approach. Hydrology and Earth System Sciences, 22(2), 1593-1614. https://doi.org/10.5194/hess-22-1593-2018

  2. Strasser, U., Marke, T., Braun, L., Escher-Vetter, H., Juen, I., Kuhn, M., ... & Kaser, G. (2018). The Rofental: a high Alpine research basin (1890–3770 m asl) in the Ötztal Alps (Austria) with over 150 years of hydrometeorological and glaciological observations. Earth System Science Data, 10(1), 151-171. https://doi.org/10.5194/essd-10-151-2018

Together, these two articles provide a comprehensive overview of the current state of the Rofental basin and projections for its future development. Strasser et al. present an extensive and unique dataset spanning 150 years of observations, offering a robust foundation for conducting cryospheric, hydrological, and atmospheric research. Hanzer et al. focus on future projections, specifically assessing the anticipated impacts of climate change on the cryosphere and hydrology of the Ötztal Alps (Austria) through the year 2100.

For the projections, Hanzer et.al uses the a physically based hydroclimatological model (AMUNDSEN) to assess future climate change impacts on the cryosphere and hydrology. The model is run in 100 m spatial and 3 h temporal resolution using in total 31 down-scaled, bias-corrected, and temporally disaggregated EURO-CORDEX climate projections for the representative concentration pathways (RCPs) 2.6, 4.5, and 8.5 scenarios as forcing data.

Mains findings Hanzer et.al

  1. RCP2.6 snow amounts then stay relatively constant during the remainder of the century at 6 mm (−31 %), while RCP4.5 and RCP8.5 snow amounts continue to decrease strongly, amounting to −63 and −80 %, respectively, at the end of the century.
  2. Until 2050, glacier volume will de-cline by approx. 60–65 % largely independent of the emission scenario, whereas by the end of the century 80–96 %.
  3. Temperature is projected to increase by all models and for all seasons, with average values of 1.1 (RCP2.6) to 3.8 ∘C (RCP8.5) in the annual mean and a maximum spread of 2.2 ∘C between individual models for a given scenario. The highest warming is projected for the winter season, with up to 4.5 ∘C in the RCP8.5 scenario, while the smallest increases are projected for spring.
  4. Projected multi-model average increases in winter precipitation are between 8 % (RCP2.6) and 21 % (RCP8.5), with individual models projecting increases of up to 57 %.
  5. Summer runoff strongly decreases with simultaneously increasing spring runoff, indicating a shift from glacial/glacio-nival to nivo-glacial runoff regimes
  6. While in the RCP2.6 scenario the month of peak runoff remains unchanged, in the RCP4.5 and RCP8.5 scenarios the peak gradually shifts from July towards June for all catchments, with the exception of Vernagtbach in the RCP4.5 scenario

Although this article does not focus specifically on our study basin, but rather on the Ötztal Alps region as a whole, it serves as a valuable comparison for our results, since the climatic conditions and the glaciers analyzed are relatively similar to those in our area. In addition, the article presents its results in a very clear and structured form, organized into distinct categories: changes in snow cover, glaciers, and hydrology.

When comparing the results from both models, it is evident that, although the projected temperatures differ between the simulations, this does not significantly affect the overall conclusion regarding glacier loss. Regardless of the climate scenario, both models project an almost complete disappearance of glaciers by the end of the century. In our project, we did not explicitly analyze seasonal variations in runoff, but we concur with the findings of the referenced article that a shift in the timing of peak runoff is expected. Specifically, the current summer peak in runoff is projected to move toward the spring months, reflecting earlier snowmelt and glacier melt as a consequence of rising temperatures.

It is particularly interesting to compare the results from both models, as they are designed for different scales and purposes. OGGM is a model developed primarily for regional to global applications, focusing on the long-term evolution of glacier geometry, including changes in area, volume, and length under varying climate scenarios. In contrast, AMUNDSEN is a high-resolution, physically based model tailored for mountainous catchments, particularly in the Alpine region, where complex topography and microclimatic effects play a significant role.

While OGGM simplifies surface processes by using a temperature-index approach calibrated individually for each glacier, AMUNDSEN simulates the full surface energy and mass balance, including detailed representations of radiation fluxes, turbulent heat exchange, snow accumulation and redistribution, and meltwater runoff. This allows AMUNDSEN to capture fine-scale spatial and temporal variability, which is essential in small, glacierized catchments with heterogeneous terrain such as Rofental. While OGGM require precipitation and temperature as a input, AMUNDSEN require temperature, precipitatio, relative humidity, radiation and wind speed. Another key distinction is that OGGM includes a dynamic ice flow model (or flux based model), enabling projections of glacier advance or retreat over decades to centuries. AMUNDSEN, on the other hand, focuses more on short- to medium-term hydrological and cryospheric processes, and requires coupling with external models (e.g., OGGM or GloGEM) if long-term glacier geometry changes are to be simulated.

Cites for Langtang¶

  1. Immerzeel, W.W., van Beek, L.P.H., Konz, M. et al. Hydrological response to climate change in a glacierized catchment in the Himalayas. Climatic Change 110, 721–736 (2012). https://doi.org/10.1007/s10584-011-0143-4

  2. Pradhananga, N. S., Kayastha, R. B., Bhattarai, B. C., Adhikari, T. R., Pradhan, S. C., Devkota, L. P., ... & Mool, P. K. (2014). Estimation of discharge from Langtang River basin, Rasuwa, Nepal, using a glacio-hydrological model. Annals of Glaciology, 55(66), 223-230. DOI 10.3189/2014AoG66A123

Although Immerzel et.al was published more than 10 years ago, we consider it a good example and a starting point for comparing our results. The authors conducted their study following the striking findings of the IPCC Fourth Assessment Report, which suggested that glaciers in the Himalayas could disappear by 2035.

To begin with, we will summarize their main findings and then compare them with our own results, highlighting the similarities and differences between the two models.

Mains findings Immerzzel, et al:

  1. By 2035 the glacier area has decreased by 32%, by 50% in 2055 and by 75% in 2088.
  2. From 2075 onwards permanent ice can only be found at the highest elevations in the catchment.
  3. On average a positive precipitation trend is predicted of 1.9 mm y-1 consistent with the acceleration of the hydrological cycle due to the increased atmospheric temperature.
  4. Annual ensemble discharge increases by 0.05 m³/s (~4 mm), reaching a 32% rise by 2050, though the rate slows by century’s end. This is due to increased precipitation and a shift from meltwater- to rainfall-dominated runoff, raising the runoff coefficient from 50% to 65%.
  5. After 2040 the decrease in glacier area becomes dominant leading to runoff decline

In terms of glacier area decrease, our results are very similar for the 2.7 °C and 4 °C scenarios, both showing a strong reduction in glacier surface area—approaching nearly 100% loss under the 4 °C scenario and around 75% under the 2.7 °C scenario. Under the 1.5 °C scenario, approximately 50% of the glacier area is projected to persist. Regarding runoff, our findings also align closely with those presented in the article. Runoff tends to decline by mid-century due to the reduced contribution from glacier melt. Meanwhile, precipitation shows an increasing trend, consistent with the patterns reported by the authors. For the seasonal runoff, our results shows that from April to August runoff increase until a maximun, this is also show in the article where it explains by peak of the melt and moonson season.

The article employed the older climate scenario framework (A1B SRES), using data from five different models provided by the IPCC to simulate future temperature and precipitation. This scenario projects a likely temperature increase of about 2.8 °C by the end of the century, which is comparable to our intermediate scenario.In our project, we used three projections based on different global temperature targets, derived from carbon emission pathways. The model used in the article incorporates key glacio-hydrological processes, including glacier dynamics (assuming basal sliding), snow and ice ablation using a degree-day approach influenced by aspect and debris cover, evapotranspiration (both reference and actual), surface runoff (via the curve number method), and baseflow (groundwater contribution) thougth a downscaling process. OGGM differs in some aspect, use geometrical centerlines and uses temperature and precipitation as mains input.

Pradhananga et.al points out the contribution of the glacier and ice melting in terms of discharge to the Langtang basin, projection until 2050. "The main objective is to estimate the present and future discharge from the glacierized Langtang River basin using a PDD model (PDDM) " --> The contribution of snow and ice melt from glaciers and snowmelt from rocks and vegetation will decrease in the future: in 2040– 50 it will be just 50% of the total discharge. The PDDM is sensitive to monthly average temperature, as a 28C temperature increase will increase the discharge by 31.9%. Changes in glacier area are less sensitive, as glacier area decreases of 25% and 50% result in a change in the total discharge of –5.7% and –11.4%, respectively. Our results shows similarities, due to increased temperature, more rain than snow is observed in precipitation, and melting of snow and ice from glaciers also increases. Despite the similarities in the results, both model has some differences. WEhile PDD, whe main output is ice melting, where it requires only temperature as a input, OGGM has more details in terms on mass balance and geometry (area, volume) where precipitation is also a require input.

In [ ]: