Differences between the “elevation band” and “centerline” flowlines#
In version 1.4, OGGM introduced a new way to compute flowlines: the so-called “elevation-band flowlines” (after Huss & Farinotti, 2012). These elevation bands complement the already available “multiple centerlines” glacier representation.
In OGGM 1.6 and above, the “elevation band” representation is the most commonly used representation for large scale simulations.
This notebook allows you to compare the two representations. It shows that the difference between the two are small for projections of glacier change, but each representation comes with pros and cons when it comes to single glacier simulations.
Tags: beginner, workflow, dynamics, flowlines
from oggm import cfg, utils, workflow, graphics, tasks
import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
cfg.initialize(logging_level='WARNING')
2026-07-20 13:01:35: oggm.cfg: Reading default parameters from the OGGM `params.cfg` configuration file.
2026-07-20 13:01:35: oggm.cfg: Multiprocessing switched OFF according to the parameter file.
2026-07-20 13:01:35: oggm.cfg: Multiprocessing: using all available processors (N=4)
# Pick the glacier you want! We use Baltoro here
rgi_ids = ['RGI60-14.06794']
Get ready#
In order to open the same glacier on two different glacier directories, we apply a trick: we set a new working directory for each case! This trick is not recommended for real runs: if you have a use case for such a workflow (the same glacier with different flowline types, please get in touch with us).
# Geometrical centerline
# Where to store the data
cfg.PATHS['working_dir'] = utils.gettempdir(dirname='OGGM-centerlines', reset=True)
# We start from prepro level 3 with all data ready - note the url here
base_url = 'https://cluster.klima.uni-bremen.de/~oggm/gdirs/oggm_v1.6/L3-L5_files/2025.6/centerlines/W5E5/per_glacier_spinup'
gdirs = workflow.init_glacier_directories(rgi_ids, from_prepro_level=3, prepro_border=80, prepro_base_url=base_url)
gdir_cl = gdirs[0]
gdir_cl
2026-07-20 13:01:36: oggm.workflow: init_glacier_directories from prepro level 3 on 1 glaciers.
2026-07-20 13:01:36: oggm.workflow: Execute entity tasks [gdir_from_prepro] on 1 glaciers
<oggm.GlacierDirectory>
RGI id: RGI60-14.06794
Region: 14: South Asia West
Subregion: 14-02: Karakoram
Name: Baltoro Glacier
Glacier type: Glacier
Terminus type: Land-terminating
Status: Glacier or ice cap
Area: 809.109 km2
Lon, Lat: (76.4047, 35.7416)
Grid (nx, ny): (481, 348)
Grid (dx, dy): (200.0, -200.0)
# Elevation band flowline
# New working directory
cfg.PATHS['working_dir'] = utils.gettempdir(dirname='OGGM-elevbands', reset=True)
# Note the new url
base_url = 'https://cluster.klima.uni-bremen.de/~oggm/gdirs/oggm_v1.6/L3-L5_files/2025.6/elev_bands/W5E5/per_glacier_spinup'
gdirs = workflow.init_glacier_directories(rgi_ids, from_prepro_level=3, prepro_border=80, prepro_base_url=base_url)
gdir_eb = gdirs[0]
gdir_eb
2026-07-20 13:01:58: oggm.workflow: init_glacier_directories from prepro level 3 on 1 glaciers.
2026-07-20 13:01:58: oggm.workflow: Execute entity tasks [gdir_from_prepro] on 1 glaciers
<oggm.GlacierDirectory>
RGI id: RGI60-14.06794
Region: 14: South Asia West
Subregion: 14-02: Karakoram
Name: Baltoro Glacier
Glacier type: Glacier
Terminus type: Land-terminating
Status: Glacier or ice cap
Area: 809.109 km2
Lon, Lat: (76.4047, 35.7416)
Grid (nx, ny): (481, 348)
Grid (dx, dy): (200.0, -200.0)
Some reading first#
We wrote a bit of information about the differences between these two. First, go to the glacier flowlines documentation where you can find detailed information about the two flowline types and also a guideline when to use which flowline method.
The examples below illustrate these differences, without much text for now because of lack of time:
Glacier length and cross-section#
fls_cl = gdir_cl.read_pickle('model_flowlines')
fls_eb = gdir_eb.read_pickle('model_flowlines')
f, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 14), sharex=True, sharey=True)
graphics.plot_modeloutput_section(fls_cl, ax=ax1)
ax1.set_title('Geometrical centerline')
graphics.plot_modeloutput_section(fls_eb, ax=ax2)
ax2.set_title('Elevation band flowline');
Note that the elevation band flowline length is shorter than the geometrical centerline!
Projections: generally small differences in volume, but larger differences in geometry (length and area)#
Thanks to OGGM’s modular workflow, a simulation with each geometry is fairly similar in terms of code. For example, we can process the climate data for both representations with the same command:
gdirs = [gdir_cl, gdir_eb]
from oggm.shop import gcm_climate
# you can choose for example one of these 5 primary ISIMIP3b GCMs:
# 'gfdl-esm4_r1i1p1f1', 'mpi-esm1-2-hr_r1i1p1f1', 'mri-esm2-0_r1i1p1f1' ("low sensitivity" models, within typical ranges from AR6)
# 'ipsl-cm6a-lr_r1i1p1f1', 'ukesm1-0-ll_r1i1p1f2' ("hotter" models, especially ukesm1-0-ll)
member = 'mri-esm2-0_r1i1p1f1'
for ssp in ['ssp126', 'ssp370','ssp585']:
# bias correct them
workflow.execute_entity_task(gcm_climate.process_monthly_isimip_data, gdirs,
ssp = ssp,
# gcm member -> you can choose another one
member=member,
# recognize the climate file for later
output_filesuffix=f'_ISIMIP3b_{member}_{ssp}'
);
2026-07-20 13:02:20: oggm.workflow: Execute entity tasks [process_monthly_isimip_data] on 2 glaciers
2026-07-20 13:02:22: oggm.workflow: Execute entity tasks [process_monthly_isimip_data] on 2 glaciers
2026-07-20 13:02:24: oggm.workflow: Execute entity tasks [process_monthly_isimip_data] on 2 glaciers
For the ice dynamics simulations, the commands are exactly the same as well. The only difference is that centerlines require the more flexible “FluxBased” numerical model, while the elevation bands can also use the more robust “SemiImplicit” one. The runs are considerably faster with the elevation bands flowlines.
# add additional outputs to default OGGM
cfg.PARAMS['store_model_geometry'] = True
cfg.PARAMS['store_fl_diagnostics'] = True
for gdir in gdirs:
if gdir is gdir_cl:
cfg.PARAMS['evolution_model'] = 'FluxBased'
else:
cfg.PARAMS['evolution_model'] = 'SemiImplicit'
workflow.execute_entity_task(tasks.run_from_climate_data, [gdir],
output_filesuffix='_historical',
)
for ssp in ['ssp126', 'ssp370', 'ssp585']:
rid = f'_ISIMIP3b_{member}_{ssp}'
workflow.execute_entity_task(tasks.run_from_climate_data, [gdir],
climate_filename='gcm_data', # use gcm_data, not climate_historical
climate_input_filesuffix=rid, # use the chosen scenario
init_model_filesuffix='_historical', # this is important! Start from 2020 glacier
output_filesuffix=rid, # recognize the run for later
);
2026-07-20 13:02:26: oggm.cfg: PARAMS['store_model_geometry'] changed from `False` to `True`.
2026-07-20 13:02:26: oggm.cfg: PARAMS['store_fl_diagnostics'] changed from `False` to `True`.
2026-07-20 13:02:26: oggm.cfg: PARAMS['evolution_model'] changed from `SemiImplicit` to `FluxBased`.
2026-07-20 13:02:26: oggm.workflow: Execute entity tasks [run_from_climate_data] on 1 glaciers
2026-07-20 13:02:42: oggm.workflow: Execute entity tasks [run_from_climate_data] on 1 glaciers
2026-07-20 13:02:44: oggm.core.flowline: InvalidWorkflowError occurred during task run_from_climate_data_ISIMIP3b_mri-esm2-0_r1i1p1f1_ssp126 on RGI60-14.06794: You seem to have calibrated with the GSWP3_W5E5 climate data while this gdir was calibrated with _ISIMIP3b_mri-esm2-0_r1i1p1f1_ssp126_no_OGGM_bias_correction. Set `check_calib_params=False` to ignore this warning.
---------------------------------------------------------------------------
InvalidWorkflowError Traceback (most recent call last)
Cell In[10], line 18
14
15 for ssp in ['ssp126', 'ssp370', 'ssp585']:
16 rid = f'_ISIMIP3b_{member}_{ssp}'
17
---> 18 workflow.execute_entity_task(tasks.run_from_climate_data, [gdir],
19 climate_filename='gcm_data', # use gcm_data, not climate_historical
20 climate_input_filesuffix=rid, # use the chosen scenario
21 init_model_filesuffix='_historical', # this is important! Start from 2020 glacier
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/workflow.py:208, in execute_entity_task(task, gdirs, **kwargs)
204 if ng > 3:
205 log.workflow('WARNING: you are trying to run an entity task on '
206 '%d glaciers with multiprocessing turned off. OGGM '
207 'will run faster with multiprocessing turned on.', ng)
--> 208 out = [pc(gdir) for gdir in gdirs]
210 return out
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/workflow.py:125, in _pickle_copier.__call__(self, arg)
123 for func in self.call_func:
124 func, kwargs = func
--> 125 res = self._call_internal(func, arg, kwargs)
126 return res
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/workflow.py:119, in _pickle_copier._call_internal(self, call_func, gdir, kwargs)
116 gdir, gdir_kwargs = gdir
117 kwargs.update(gdir_kwargs)
--> 119 return call_func(gdir, **kwargs)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/utils/_workflow.py:522, in entity_task.__call__.<locals>._entity_task(gdir, reset, print_log, return_value, continue_on_error, add_to_log_file, **kwargs)
520 signal.alarm(gdir.settings['task_timeout'])
521 ex_t = time.time()
--> 522 out = task_func(gdir, **kwargs)
523 ex_t = time.time() - ex_t
524 if gdir.settings['task_timeout'] > 0:
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/core/flowline.py:4480, in run_from_climate_data(gdir, settings_filesuffix, ys, ye, min_ys, max_ys, fixed_geometry_spinup_yr, store_monthly_step, store_model_geometry, store_fl_diagnostics, climate_filename, mb_model, mb_model_class, climate_input_filesuffix, output_filesuffix, init_model_filesuffix, init_model_yr, init_model_fls, zero_initial_glacier, bias, temperature_bias, precipitation_factor, mb_diagnostics_filesuffix, save_mb_diagnostics_filesuffix, **kwargs)
4473 mb_model = MultipleFlowlineMassBalance.load_from_file(
4474 gdir,
4475 filesuffix=mb_diagnostics_filesuffix,
4476 climate_filename=_branch_fn,
4477 climate_input_filesuffix=_branch_isuf,
4478 )
4479 else:
-> 4480 mb_model = MultipleFlowlineMassBalance(
4481 gdir,
4482 mb_model_class=mb_model_class,
4483 filename=climate_filename,
4484 bias=bias,
4485 input_filesuffix=climate_input_filesuffix,
4486 settings_filesuffix=settings_filesuffix,
4487 )
4489 if temperature_bias is not None:
4490 mb_model.temp_bias += temperature_bias
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/core/massbalance.py:3494, in MultipleFlowlineMassBalance.__init__(self, gdir, settings_filesuffix, fls, mb_model_class, use_inversion_flowlines, flowlines_filesuffix, input_filesuffix, **kwargs)
3490 if rgi_filesuffix is not None:
3491 kwargs['input_filesuffix'] = rgi_filesuffix
3493 self.flowline_mb_models.append(
-> 3494 mb_model_class(
3495 gdir=gdir,
3496 settings_filesuffix=settings_filesuffix,
3497 **kwargs,
3498 )
3499 )
3501 self.valid_bounds = self.flowline_mb_models[-1].valid_bounds
3502 self.hemisphere = gdir.hemisphere
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/core/massbalance.py:594, in MonthlyTIModel.__init__(self, gdir, filename, input_filesuffix, settings_filesuffix, fl_id, melt_f, temp_bias, prcp_fac, bias, temp_melt, ys, ye, repeat, check_calib_params, check_climate_data, use_leap_years)
589 if src != src_calib:
590 msg = (f'You seem to have calibrated with the {src} '
591 f"climate data while this gdir was calibrated with "
592 f"{src_calib}. Set `check_calib_params=False` to "
593 f"ignore this warning.")
--> 594 raise InvalidWorkflowError(msg)
596 self.melt_f = melt_f
597 self.bias = bias
InvalidWorkflowError: You seem to have calibrated with the GSWP3_W5E5 climate data while this gdir was calibrated with _ISIMIP3b_mri-esm2-0_r1i1p1f1_ssp126_no_OGGM_bias_correction. Set `check_calib_params=False` to ignore this warning.
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 4))
# Pick some colors for the lines
color_dict={'ssp126':'blue', 'ssp370':'orange', 'ssp585':'red'}
for ssp in ['ssp126','ssp370', 'ssp585']:
rid = f'_ISIMIP3b_{member}_{ssp}'
with xr.open_dataset(gdir_cl.get_filepath('model_diagnostics', filesuffix=rid)) as ds:
ds.volume_m3.plot(ax=ax1, label=ssp, c=color_dict[ssp])
for ssp in ['ssp126','ssp370', 'ssp585']:
rid = f'_ISIMIP3b_{member}_{ssp}'
with xr.open_dataset(gdir_eb.get_filepath('model_diagnostics', filesuffix=rid)) as ds:
ds.volume_m3.plot(ax=ax1, label=ssp, c=color_dict[ssp], ls='--')
ax1.set_title('Glacier volume')
ax1.set_xlim([2020,2100])
ax1.set_ylim([0, ds.volume_m3.max().max()*1.1])
for ssp in ['ssp126','ssp370', 'ssp585']:
rid = f'_ISIMIP3b_{member}_{ssp}'
with xr.open_dataset(gdir_cl.get_filepath('model_diagnostics', filesuffix=rid)) as ds:
ds.length_m.plot(ax=ax2, label=ssp, c=color_dict[ssp])
ax2.set_ylim([0, ds.length_m.max().max()*1.1])
for ssp in ['ssp126','ssp370', 'ssp585']:
rid = f'_ISIMIP3b_{member}_{ssp}'
with xr.open_dataset(gdir_eb.get_filepath('model_diagnostics', filesuffix=rid)) as ds:
ds.length_m.plot(ax=ax2, label=ssp, c=color_dict[ssp], ls='--');
ax2.set_title('Glacier length')
ax2.set_xlim([2020,2100])
plt.legend();
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/file_manager.py:219, in CachingFileManager._acquire_with_cache_info(self, needs_lock)
218 try:
--> 219 file = self._cache[self._key]
220 except KeyError:
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/lru_cache.py:56, in LRUCache.__getitem__(self, key)
55 with self._lock:
---> 56 value = self._cache[key]
57 self._cache.move_to_end(key)
KeyError: [<class 'netCDF4._netCDF4.Dataset'>, ('/tmp/OGGM/OGGM-centerlines/per_glacier/RGI60-14/RGI60-14.06/RGI60-14.06794/model_diagnostics_ISIMIP3b_mri-esm2-0_r1i1p1f1_ssp126.nc',), 'r', (('clobber', True), ('diskless', False), ('format', 'NETCDF4'), ('persist', False)), '26ab5223-5edc-43a3-bcd0-08aaf345c4dc']
During handling of the above exception, another exception occurred:
FileNotFoundError Traceback (most recent call last)
Cell In[11], line 8
4 color_dict={'ssp126':'blue', 'ssp370':'orange', 'ssp585':'red'}
5
6 for ssp in ['ssp126','ssp370', 'ssp585']:
7 rid = f'_ISIMIP3b_{member}_{ssp}'
----> 8 with xr.open_dataset(gdir_cl.get_filepath('model_diagnostics', filesuffix=rid)) as ds:
9 ds.volume_m3.plot(ax=ax1, label=ssp, c=color_dict[ssp])
10 for ssp in ['ssp126','ssp370', 'ssp585']:
11 rid = f'_ISIMIP3b_{member}_{ssp}'
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/api.py:607, in open_dataset(filename_or_obj, engine, chunks, cache, decode_cf, mask_and_scale, decode_times, decode_timedelta, use_cftime, concat_characters, decode_coords, drop_variables, create_default_indexes, inline_array, chunked_array_type, from_array_kwargs, backend_kwargs, **kwargs)
595 decoders = _resolve_decoders_kwargs(
596 decode_cf,
597 open_backend_dataset_parameters=backend.open_dataset_parameters,
(...) 603 decode_coords=decode_coords,
604 )
606 overwrite_encoded_chunks = kwargs.pop("overwrite_encoded_chunks", None)
--> 607 backend_ds = backend.open_dataset(
608 filename_or_obj,
609 drop_variables=drop_variables,
610 **decoders,
611 **kwargs,
612 )
613 ds = _dataset_from_backend_dataset(
614 backend_ds,
615 filename_or_obj,
(...) 626 **kwargs,
627 )
628 return ds
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:771, in NetCDF4BackendEntrypoint.open_dataset(self, filename_or_obj, mask_and_scale, decode_times, concat_characters, decode_coords, drop_variables, use_cftime, decode_timedelta, group, mode, format, clobber, diskless, persist, auto_complex, lock, autoclose)
749 def open_dataset(
750 self,
751 filename_or_obj: T_PathFileOrDataStore,
(...) 768 autoclose=False,
769 ) -> Dataset:
770 filename_or_obj = _normalize_path(filename_or_obj)
--> 771 store = NetCDF4DataStore.open(
772 filename_or_obj,
773 mode=mode,
774 format=format,
775 group=group,
776 clobber=clobber,
777 diskless=diskless,
778 persist=persist,
779 auto_complex=auto_complex,
780 lock=lock,
781 autoclose=autoclose,
782 )
784 store_entrypoint = StoreBackendEntrypoint()
785 with close_on_error(store):
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:529, in NetCDF4DataStore.open(cls, filename, mode, format, group, clobber, diskless, persist, auto_complex, lock, lock_maker, autoclose)
525 else:
526 manager = CachingFileManager(
527 netCDF4.Dataset, filename, mode=mode, kwargs=kwargs, lock=lock
528 )
--> 529 return cls(manager, group=group, mode=mode, lock=lock, autoclose=autoclose)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:429, in NetCDF4DataStore.__init__(self, manager, group, mode, lock, autoclose)
427 self._group = group
428 self._mode = mode
--> 429 self.format = self.ds.data_model
430 self._filename = self.ds.filepath()
431 self.is_remote = is_remote_uri(self._filename)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:538, in NetCDF4DataStore.ds(self)
536 @property
537 def ds(self):
--> 538 return self._acquire()
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:532, in NetCDF4DataStore._acquire(self, needs_lock)
531 def _acquire(self, needs_lock=True):
--> 532 with self._manager.acquire_context(needs_lock) as root:
533 ds = _nc4_require_group(root, self._group, self._mode)
534 return ds
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/contextlib.py:141, in _GeneratorContextManager.__enter__(self)
139 del self.args, self.kwds, self.func
140 try:
--> 141 return next(self.gen)
142 except StopIteration:
143 raise RuntimeError("generator didn't yield") from None
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/file_manager.py:207, in CachingFileManager.acquire_context(self, needs_lock)
204 @contextmanager
205 def acquire_context(self, needs_lock: bool = True) -> Iterator[T_File]:
206 """Context manager for acquiring a file."""
--> 207 file, cached = self._acquire_with_cache_info(needs_lock)
208 try:
209 yield file
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/file_manager.py:225, in CachingFileManager._acquire_with_cache_info(self, needs_lock)
223 kwargs = kwargs.copy()
224 kwargs["mode"] = self._mode
--> 225 file = self._opener(*self._args, **kwargs)
226 if self._mode == "w":
227 # ensure file doesn't get overridden when opened again
228 self._mode = "a"
File src/netCDF4/_netCDF4.pyx:2521, in netCDF4._netCDF4.Dataset.__init__()
-> 2521 'Could not get source, probably due dynamically evaluated source code.'
File src/netCDF4/_netCDF4.pyx:2158, in netCDF4._netCDF4._ensure_nc_success()
-> 2158 'Could not get source, probably due dynamically evaluated source code.'
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/OGGM/OGGM-centerlines/per_glacier/RGI60-14/RGI60-14.06/RGI60-14.06794/model_diagnostics_ISIMIP3b_mri-esm2-0_r1i1p1f1_ssp126.nc'
As you can see, for this disappearing glacier, the representations create slightly different volume projections. The differences can be quite a bit larger at times, for example for length projections.
Graphical representation: centerlines win by short margin (for now)#
rid = f'_ISIMIP3b_{member}_ssp126'
Both models can be represented with a cross-section, like this:
sel_years = np.linspace(2020, 2100, 17).astype(int)
colors = sns.color_palette('rocket', len(sel_years))
with plt.rc_context({'axes.prop_cycle': plt.cycler(color=colors)}):
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5.5), sharey=True, sharex=True)
n_lines = len(gdir_cl.read_pickle('model_flowlines'))
with xr.open_dataset(gdir_cl.get_filepath('fl_diagnostics', filesuffix=rid), group=f'fl_{n_lines-1}') as ds:
(ds.bed_h + ds.sel(time=sel_years).thickness_m).plot(ax=ax1, hue='time')
ds.bed_h.plot(ax=ax1, c='k')
ax1.set_title('Centerlines')
with xr.open_dataset(gdir_eb.get_filepath('fl_diagnostics', filesuffix=rid), group='fl_0') as ds:
(ds.bed_h + ds.sel(time=sel_years).thickness_m).plot(ax=ax2, hue='time')
ds.bed_h.plot(ax=ax2, c='k')
ax2.set_ylabel('')
ax2.set_title('Elevation bands')
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/file_manager.py:219, in CachingFileManager._acquire_with_cache_info(self, needs_lock)
218 try:
--> 219 file = self._cache[self._key]
220 except KeyError:
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/lru_cache.py:56, in LRUCache.__getitem__(self, key)
55 with self._lock:
---> 56 value = self._cache[key]
57 self._cache.move_to_end(key)
KeyError: [<class 'netCDF4._netCDF4.Dataset'>, ('/tmp/OGGM/OGGM-centerlines/per_glacier/RGI60-14/RGI60-14.06/RGI60-14.06794/fl_diagnostics_ISIMIP3b_mri-esm2-0_r1i1p1f1_ssp126.nc',), 'r', (('clobber', True), ('diskless', False), ('format', 'NETCDF4'), ('persist', False)), 'fa103ff4-2af2-4771-b275-b054e3d0fb38']
During handling of the above exception, another exception occurred:
FileNotFoundError Traceback (most recent call last)
Cell In[13], line 6
2 colors = sns.color_palette('rocket', len(sel_years))
3 with plt.rc_context({'axes.prop_cycle': plt.cycler(color=colors)}):
4 f, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5.5), sharey=True, sharex=True)
5 n_lines = len(gdir_cl.read_pickle('model_flowlines'))
----> 6 with xr.open_dataset(gdir_cl.get_filepath('fl_diagnostics', filesuffix=rid), group=f'fl_{n_lines-1}') as ds:
7 (ds.bed_h + ds.sel(time=sel_years).thickness_m).plot(ax=ax1, hue='time')
8 ds.bed_h.plot(ax=ax1, c='k')
9 ax1.set_title('Centerlines')
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/api.py:607, in open_dataset(filename_or_obj, engine, chunks, cache, decode_cf, mask_and_scale, decode_times, decode_timedelta, use_cftime, concat_characters, decode_coords, drop_variables, create_default_indexes, inline_array, chunked_array_type, from_array_kwargs, backend_kwargs, **kwargs)
595 decoders = _resolve_decoders_kwargs(
596 decode_cf,
597 open_backend_dataset_parameters=backend.open_dataset_parameters,
(...) 603 decode_coords=decode_coords,
604 )
606 overwrite_encoded_chunks = kwargs.pop("overwrite_encoded_chunks", None)
--> 607 backend_ds = backend.open_dataset(
608 filename_or_obj,
609 drop_variables=drop_variables,
610 **decoders,
611 **kwargs,
612 )
613 ds = _dataset_from_backend_dataset(
614 backend_ds,
615 filename_or_obj,
(...) 626 **kwargs,
627 )
628 return ds
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:771, in NetCDF4BackendEntrypoint.open_dataset(self, filename_or_obj, mask_and_scale, decode_times, concat_characters, decode_coords, drop_variables, use_cftime, decode_timedelta, group, mode, format, clobber, diskless, persist, auto_complex, lock, autoclose)
749 def open_dataset(
750 self,
751 filename_or_obj: T_PathFileOrDataStore,
(...) 768 autoclose=False,
769 ) -> Dataset:
770 filename_or_obj = _normalize_path(filename_or_obj)
--> 771 store = NetCDF4DataStore.open(
772 filename_or_obj,
773 mode=mode,
774 format=format,
775 group=group,
776 clobber=clobber,
777 diskless=diskless,
778 persist=persist,
779 auto_complex=auto_complex,
780 lock=lock,
781 autoclose=autoclose,
782 )
784 store_entrypoint = StoreBackendEntrypoint()
785 with close_on_error(store):
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:529, in NetCDF4DataStore.open(cls, filename, mode, format, group, clobber, diskless, persist, auto_complex, lock, lock_maker, autoclose)
525 else:
526 manager = CachingFileManager(
527 netCDF4.Dataset, filename, mode=mode, kwargs=kwargs, lock=lock
528 )
--> 529 return cls(manager, group=group, mode=mode, lock=lock, autoclose=autoclose)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:429, in NetCDF4DataStore.__init__(self, manager, group, mode, lock, autoclose)
427 self._group = group
428 self._mode = mode
--> 429 self.format = self.ds.data_model
430 self._filename = self.ds.filepath()
431 self.is_remote = is_remote_uri(self._filename)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:538, in NetCDF4DataStore.ds(self)
536 @property
537 def ds(self):
--> 538 return self._acquire()
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:532, in NetCDF4DataStore._acquire(self, needs_lock)
531 def _acquire(self, needs_lock=True):
--> 532 with self._manager.acquire_context(needs_lock) as root:
533 ds = _nc4_require_group(root, self._group, self._mode)
534 return ds
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/contextlib.py:141, in _GeneratorContextManager.__enter__(self)
139 del self.args, self.kwds, self.func
140 try:
--> 141 return next(self.gen)
142 except StopIteration:
143 raise RuntimeError("generator didn't yield") from None
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/file_manager.py:207, in CachingFileManager.acquire_context(self, needs_lock)
204 @contextmanager
205 def acquire_context(self, needs_lock: bool = True) -> Iterator[T_File]:
206 """Context manager for acquiring a file."""
--> 207 file, cached = self._acquire_with_cache_info(needs_lock)
208 try:
209 yield file
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/file_manager.py:225, in CachingFileManager._acquire_with_cache_info(self, needs_lock)
223 kwargs = kwargs.copy()
224 kwargs["mode"] = self._mode
--> 225 file = self._opener(*self._args, **kwargs)
226 if self._mode == "w":
227 # ensure file doesn't get overridden when opened again
228 self._mode = "a"
File src/netCDF4/_netCDF4.pyx:2521, in netCDF4._netCDF4.Dataset.__init__()
-> 2521 'Could not get source, probably due dynamically evaluated source code.'
File src/netCDF4/_netCDF4.pyx:2158, in netCDF4._netCDF4._ensure_nc_success()
-> 2158 'Could not get source, probably due dynamically evaluated source code.'
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/OGGM/OGGM-centerlines/per_glacier/RGI60-14/RGI60-14.06/RGI60-14.06794/fl_diagnostics_ISIMIP3b_mri-esm2-0_r1i1p1f1_ssp126.nc'
However, only centerlines can be plotted as a map:
# this can take some time
# if you want to see more thickness differences you can use ssp585 instead of ssp126
# by uncomment the following line
# rid = f'_ISIMIP3b_{member}_ssp585'
f, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(14, 6))
# let's have the same colorbar for every subplot for better comparability
graphics.plot_modeloutput_map(gdir_cl, filesuffix=rid, modelyr=2020, ax=ax1, vmax=600)
graphics.plot_modeloutput_map(gdir_cl, filesuffix=rid, modelyr=2050, ax=ax2, vmax=600)
graphics.plot_modeloutput_map(gdir_cl, filesuffix=rid, modelyr=2100, ax=ax3, vmax=600)
plt.tight_layout();
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/file_manager.py:219, in CachingFileManager._acquire_with_cache_info(self, needs_lock)
218 try:
--> 219 file = self._cache[self._key]
220 except KeyError:
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/lru_cache.py:56, in LRUCache.__getitem__(self, key)
55 with self._lock:
---> 56 value = self._cache[key]
57 self._cache.move_to_end(key)
KeyError: [<class 'netCDF4._netCDF4.Dataset'>, ('/tmp/OGGM/OGGM-centerlines/per_glacier/RGI60-14/RGI60-14.06/RGI60-14.06794/model_geometry_ISIMIP3b_mri-esm2-0_r1i1p1f1_ssp126.nc',), 'r', (('clobber', True), ('diskless', False), ('format', 'NETCDF4'), ('persist', False)), 'ff615fe3-776d-440a-972d-ae79290e37f6']
During handling of the above exception, another exception occurred:
FileNotFoundError Traceback (most recent call last)
Cell In[14], line 7
3 # by uncomment the following line
4 # rid = f'_ISIMIP3b_{member}_ssp585'
5 f, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(14, 6))
6 # let's have the same colorbar for every subplot for better comparability
----> 7 graphics.plot_modeloutput_map(gdir_cl, filesuffix=rid, modelyr=2020, ax=ax1, vmax=600)
8 graphics.plot_modeloutput_map(gdir_cl, filesuffix=rid, modelyr=2050, ax=ax2, vmax=600)
9 graphics.plot_modeloutput_map(gdir_cl, filesuffix=rid, modelyr=2100, ax=ax3, vmax=600)
10 plt.tight_layout();
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/graphics.py:158, in _plot_map.<locals>.newplotfunc(gdirs, ax, smap, add_colorbar, title, title_comment, horizontal_colorbar, lonlat_contours_kwargs, cbar_ax, autosave, add_scalebar, figsize, savefig, savefig_kwargs, extend_plot_limit, **kwargs)
156 if add_scalebar:
157 mp.set_scale_bar()
--> 158 out = plotfunc(gdirs, ax=ax, smap=mp, **kwargs)
160 if add_colorbar and 'cbar_label' in out:
161 cbprim = out.get('cbar_primitive', mp)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/graphics.py:710, in plot_modeloutput_map(gdirs, ax, smap, model, vmax, linewidth, filesuffix, modelyr, plotting_var)
708 models = []
709 for gdir in gdirs:
--> 710 model = FileModel(gdir.get_filepath('model_geometry',
711 filesuffix=filesuffix))
712 model.run_until(modelyr)
713 models.append(model)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/core/flowline.py:3109, in FileModel.__init__(self, path)
3106 def __init__(self, path):
3107 """ Instantiate."""
-> 3109 self.fls = glacier_from_netcdf(path)
3111 fl_tss = []
3112 for flid, fl in enumerate(self.fls):
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/oggm/core/flowline.py:3610, in glacier_from_netcdf(path)
3607 def glacier_from_netcdf(path):
3608 """Instantiates a list of flowlines from an xarray Dataset."""
-> 3610 with xr.open_dataset(path) as ds:
3611 fls = []
3612 for flid in ds['flowlines'].values:
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/api.py:607, in open_dataset(filename_or_obj, engine, chunks, cache, decode_cf, mask_and_scale, decode_times, decode_timedelta, use_cftime, concat_characters, decode_coords, drop_variables, create_default_indexes, inline_array, chunked_array_type, from_array_kwargs, backend_kwargs, **kwargs)
595 decoders = _resolve_decoders_kwargs(
596 decode_cf,
597 open_backend_dataset_parameters=backend.open_dataset_parameters,
(...) 603 decode_coords=decode_coords,
604 )
606 overwrite_encoded_chunks = kwargs.pop("overwrite_encoded_chunks", None)
--> 607 backend_ds = backend.open_dataset(
608 filename_or_obj,
609 drop_variables=drop_variables,
610 **decoders,
611 **kwargs,
612 )
613 ds = _dataset_from_backend_dataset(
614 backend_ds,
615 filename_or_obj,
(...) 626 **kwargs,
627 )
628 return ds
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:771, in NetCDF4BackendEntrypoint.open_dataset(self, filename_or_obj, mask_and_scale, decode_times, concat_characters, decode_coords, drop_variables, use_cftime, decode_timedelta, group, mode, format, clobber, diskless, persist, auto_complex, lock, autoclose)
749 def open_dataset(
750 self,
751 filename_or_obj: T_PathFileOrDataStore,
(...) 768 autoclose=False,
769 ) -> Dataset:
770 filename_or_obj = _normalize_path(filename_or_obj)
--> 771 store = NetCDF4DataStore.open(
772 filename_or_obj,
773 mode=mode,
774 format=format,
775 group=group,
776 clobber=clobber,
777 diskless=diskless,
778 persist=persist,
779 auto_complex=auto_complex,
780 lock=lock,
781 autoclose=autoclose,
782 )
784 store_entrypoint = StoreBackendEntrypoint()
785 with close_on_error(store):
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:529, in NetCDF4DataStore.open(cls, filename, mode, format, group, clobber, diskless, persist, auto_complex, lock, lock_maker, autoclose)
525 else:
526 manager = CachingFileManager(
527 netCDF4.Dataset, filename, mode=mode, kwargs=kwargs, lock=lock
528 )
--> 529 return cls(manager, group=group, mode=mode, lock=lock, autoclose=autoclose)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:429, in NetCDF4DataStore.__init__(self, manager, group, mode, lock, autoclose)
427 self._group = group
428 self._mode = mode
--> 429 self.format = self.ds.data_model
430 self._filename = self.ds.filepath()
431 self.is_remote = is_remote_uri(self._filename)
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:538, in NetCDF4DataStore.ds(self)
536 @property
537 def ds(self):
--> 538 return self._acquire()
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/netCDF4_.py:532, in NetCDF4DataStore._acquire(self, needs_lock)
531 def _acquire(self, needs_lock=True):
--> 532 with self._manager.acquire_context(needs_lock) as root:
533 ds = _nc4_require_group(root, self._group, self._mode)
534 return ds
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/contextlib.py:141, in _GeneratorContextManager.__enter__(self)
139 del self.args, self.kwds, self.func
140 try:
--> 141 return next(self.gen)
142 except StopIteration:
143 raise RuntimeError("generator didn't yield") from None
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/file_manager.py:207, in CachingFileManager.acquire_context(self, needs_lock)
204 @contextmanager
205 def acquire_context(self, needs_lock: bool = True) -> Iterator[T_File]:
206 """Context manager for acquiring a file."""
--> 207 file, cached = self._acquire_with_cache_info(needs_lock)
208 try:
209 yield file
File /usr/local/pyenv/versions/3.13.13/lib/python3.13/site-packages/xarray/backends/file_manager.py:225, in CachingFileManager._acquire_with_cache_info(self, needs_lock)
223 kwargs = kwargs.copy()
224 kwargs["mode"] = self._mode
--> 225 file = self._opener(*self._args, **kwargs)
226 if self._mode == "w":
227 # ensure file doesn't get overridden when opened again
228 self._mode = "a"
File src/netCDF4/_netCDF4.pyx:2521, in netCDF4._netCDF4.Dataset.__init__()
-> 2521 'Could not get source, probably due dynamically evaluated source code.'
File src/netCDF4/_netCDF4.pyx:2158, in netCDF4._netCDF4._ensure_nc_success()
-> 2158 'Could not get source, probably due dynamically evaluated source code.'
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/OGGM/OGGM-centerlines/per_glacier/RGI60-14/RGI60-14.06/RGI60-14.06794/model_geometry_ISIMIP3b_mri-esm2-0_r1i1p1f1_ssp126.nc'
We are however working on a better representation of retreating glaciers for outreach. Have a look at this tutorial!
Take home messages#
in the absence of additional data to better calibrate the mass balance model, using multiple centerlines is considered not useful: indeed, the distributed representation offers little advantages if the mass balance is only a function of elevation.
elevation band flowlines are now the default of most OGGM applications. It is faster, much cheaper, and more robust to use these simplified glaciers.
elevation band flowlines cannot be represented on a map “out of the box”. We have however developed a tool to display the changes by redistributing them on a map: have a look at this tutorial!
multiple centerlines can be useful for growing glacier cases and use cases where geometry plays an important role (e.g. lakes, paleo applications).
What’s next?#
return to the OGGM documentation
back to the table of contents