Create local topography maps from different DEM sources with OGGM#

There are a number of datasets available out-of-the box in OGGM. This Notebook will show you how to download the original sources and create the local glacier centered map. It is also possible to use your own DEM data in OGGM.

Set-up#

import rioxarray as rioxr
import matplotlib.pyplot as plt
import oggm
from oggm import cfg, utils, workflow, tasks, graphics
from oggm.core import gis
cfg.initialize(logging_level='WARNING')
cfg.PARAMS['border'] = 10
2026-03-09 23:10:21: oggm.cfg: Reading default parameters from the OGGM `params.cfg` configuration file.
2026-03-09 23:10:21: oggm.cfg: Multiprocessing switched OFF according to the parameter file.
2026-03-09 23:10:21: oggm.cfg: Multiprocessing: using all available processors (N=4)
2026-03-09 23:10:21: oggm.cfg: PARAMS['border'] changed from `80` to `10`.

RGI outlines#

We use the RGI outlines to identify the necessary DEM tiles. If you haven’t downloaded the RGI files yet, this will also download them. Feel free to use your desired RGI-ID here, otherwise let’s use the Hintereisferner glacier as an example.

entity = utils.get_rgi_glacier_entities(['RGI60-11.00897'])
entity.plot();
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[2], line 1
----> 1 entity = utils.get_rgi_glacier_entities(['RGI60-11.00897'])
      2 entity.plot();

File /usr/local/pyenv/versions/3.13.12/lib/python3.13/site-packages/oggm/utils/_downloads.py:1925, in get_rgi_glacier_entities(rgi_ids, version)
   1923 selection = []
   1924 for reg in sorted(np.unique(regions)):
-> 1925     sh = gpd.read_file(get_rgi_region_file(reg, version=version))
   1926     try:
   1927         selection.append(sh.loc[sh.RGIId.isin(rgi_ids)])

File /usr/local/pyenv/versions/3.13.12/lib/python3.13/site-packages/oggm/utils/_downloads.py:1882, in get_rgi_region_file(region, version, reset)
   1862 def get_rgi_region_file(region, version=None, reset=False):
   1863     """Path to the RGI region file.
   1864 
   1865     If the RGI files are not present, download them.
   (...)   1879         path to the RGI shapefile
   1880     """
-> 1882     rgi_dir = get_rgi_dir(version=version, reset=reset)
   1883     if version in ['70G', '70C']:
   1884         f = list(glob.glob(rgi_dir + f"/*/*-{region}_*.shp"))

File /usr/local/pyenv/versions/3.13.12/lib/python3.13/site-packages/oggm/utils/_downloads.py:1791, in get_rgi_dir(version, reset)
   1772 """Path to the RGI directory.
   1773 
   1774 If the RGI files are not present, download them.
   (...)   1787     path to the RGI directory
   1788 """
   1790 with get_lock():
-> 1791     return _get_rgi_dir_unlocked(version=version, reset=reset)

File /usr/local/pyenv/versions/3.13.12/lib/python3.13/site-packages/oggm/utils/_downloads.py:1839, in _get_rgi_dir_unlocked(version, reset)
   1837 ofile = file_downloader(dfile, reset=reset)
   1838 if ofile is None:
-> 1839     raise RuntimeError(f'Could not download RGI file: {dfile}')
   1840 # Extract root
   1841 try:

RuntimeError: Could not download RGI file: http://www.glims.org/RGI/rgi60_files/00_rgi60.zip

Choose a DEM source (e.g. SRTM)#

If not specifying anything, OGGM will use its default settings, i.e. NASADEM for mid- and low-latitudes (60°S-60°N). However, this needs registration at NASA Earthdata (see “Register” below). Here, we choose the SRTM source as example DEM (no registration necessary).

# Let's make a working directory for this DEM 
cfg.PATHS['working_dir'] = utils.gettempdir('default', reset=True)
gdir = workflow.init_glacier_directories(entity)[0]
tasks.define_glacier_region(gdir, source='SRTM')
# if not yet installed, you have to install rasterio
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[3], line 3
      1 # Let's make a working directory for this DEM 
      2 cfg.PATHS['working_dir'] = utils.gettempdir('default', reset=True)
----> 3 gdir = workflow.init_glacier_directories(entity)[0]
      4 tasks.define_glacier_region(gdir, source='SRTM')
      5 # if not yet installed, you have to install rasterio

NameError: name 'entity' is not defined

You can access the (reprojected and interpolated) DEM file in the working directory:

dem_path = gdir.get_filepath('dem')
dem_path
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[4], line 1
----> 1 dem_path = gdir.get_filepath('dem')
      2 dem_path

NameError: name 'gdir' is not defined

It is a geotiff file. Xarray can open them thanks to rasterio:

da = rioxr.open_rasterio(dem_path)
f, ax = plt.subplots()
da.plot(cmap='terrain', ax=ax)
# Add the outlines
gdir.read_shapefile('outlines').plot(ax=ax, color='none', edgecolor='black');
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 da = rioxr.open_rasterio(dem_path)
      2 f, ax = plt.subplots()
      3 da.plot(cmap='terrain', ax=ax)

NameError: name 'dem_path' is not defined

The source of the DEM is documented in the directory itself:

with open(gdir.get_filepath('dem_source'), 'r') as f:
    print(f.read())
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[6], line 1
----> 1 with open(gdir.get_filepath('dem_source'), 'r') as f:
      2     print(f.read())

NameError: name 'gdir' is not defined

OGGM is neither the owner nor the distributor of these datasets! OGGM only provides tools to access it. It is your responsibility as the data user to read the individual usage requirements and cite and acknowledge the original data sources accordingly.

OGGM provided datasets#

At the moment OGGM is able to download and process the following DEM sources:

for src in utils.DEM_SOURCES:
    print('{:<10}: {}'.format(src, gis.DEM_SOURCE_INFO[src].split('\n')[0]))
GIMP      : GIMP V1.1
ARCTICDEM : ARCTICDEM V3
RAMP      : RAMP V2
TANDEM    : TanDEM-X 90m
AW3D30    : AW3D30 V1804
MAPZEN    : MAPZEN TERRAIN TILES
DEM3      : VIEWFINDER PANORAMAS DEMs
ASTER     : ASTGTMV3
SRTM      : SRTM V4
REMA      : REMA V1.1
ALASKA    : ALASKA V3
COPDEM30  : Copernicus DEM GLO-30
COPDEM90  : Copernicus DEM GLO-90
NASADEM   : NASADEM Merged DEM Global

Register for online datasets#

The default DEM source for low and mid-latitudes (60°S-60°N), NASADEM, requires a user account to download data, so you need to register at NASA Earthdata. There are other DEM sources where a registration is necessary; for ASTGTMV3 at NASA Earthdata, for TanDEM-X at DLR, and for COPDEM at spacedata.copernicus.eu/.

After that you can use the command line functionality oggm_netrc_credentials to store your user credentials in a local ~/.netrc file. Your user credentials are only stored locally and are only used by the download function for authentification with the original DEM source. Credentials are not needed if you use the RGI-TOPO data (see below).

Use pre-processed DEMs from RGI-TOPO#

The RGI-TOPO dataset is an RGI-provided dataset in beta release. These data are available for everyone, and were created with OGGM. Of course, you can easily use these data in OGGM as well:

# use NASADEM, the default DEM for low and mid-latitudes in OGGM, you can also change to e.g. 'COPDEM'
from oggm.shop import rgitopo
cfg.PATHS['working_dir'] = utils.gettempdir('rgitopo', reset=True)
gdir = rgitopo.init_glacier_directories_from_rgitopo(['RGI60-11.00897'], dem_source='NASADEM')[0]
graphics.plot_domain(gdir)
2026-03-09 23:10:22: oggm.workflow: init_glacier_directories from prepro level 1 on 1 glaciers.
2026-03-09 23:10:22: oggm.workflow: Execute entity tasks [gdir_from_prepro] on 1 glaciers
2026-03-09 23:10:22: oggm.workflow: Execute entity tasks [select_dem_from_dir] on 1 glaciers
../../_images/61ef024576c11e7b43e0f703fb2b3a309061dd928de8a4e9071bb6f9ce11755c.png

Use another DEM source#

Using RGI-TOPO DEMs is by far the easiest since all data is prepared for you and ready to use. But if you really want, you can go back to the original data sources:

# Let's make a working directory for this DEM 
cfg.PATHS['working_dir'] = utils.gettempdir('alternative')
try:
    gdir = workflow.init_glacier_directories(entity)[0]
    tasks.define_glacier_region(gdir, source='DEM3')
except oggm.exceptions.InvalidDEMError as err:
    print(err)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[9], line 4
      2 cfg.PATHS['working_dir'] = utils.gettempdir('alternative')
      3 try:
----> 4     gdir = workflow.init_glacier_directories(entity)[0]
      5     tasks.define_glacier_region(gdir, source='DEM3')
      6 except oggm.exceptions.InvalidDEMError as err:

NameError: name 'entity' is not defined

Let’s check that the source text is updated as well:

with open(gdir.get_filepath('dem_source'), 'r') as f:
    print(f.read())
NASADEM Merged DEM Global

Original resolution: 1 arcsec (~30m)
Date of acquisition: February 2000
Date range: 2000-2000

# Data Citation

NASADEM Merged DEM Global 1 arc second - NASADEM_HGT
NASA JPL (2020). NASADEM Merged DEM Global 1 arc second V001 [Data set]. NASA
EOSDIS Land Processes DAAC. Accessed YYYY-MM-DD from
https://doi.org/10.5067/MEaSUREs/NASADEM/NASADEM_HGT.001

# Data files

n46e010.hgt
f, ax = plt.subplots()
da_dem3 = rioxr.open_rasterio(gdir.get_filepath('dem'))
da_dem3.plot(cmap='terrain', ax=ax)
gdir.read_shapefile('outlines').plot(ax=ax, color='none', edgecolor='black');
../../_images/806d99b35e5d4d5896ad54a2d6e53f60d72f2abc63c43be7f145fd303fb215c7.png

There might not be much difference a first sight, but by subtracting them the difference become clear:

f, ax = plt.subplots()
(da_dem3 - da).plot(ax=ax)
plt.title('DEM3 - SRTM')
gdir.read_shapefile('outlines').plot(ax=ax, color='none', edgecolor='black');
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[12], line 2
      1 f, ax = plt.subplots()
----> 2 (da_dem3 - da).plot(ax=ax)
      3 plt.title('DEM3 - SRTM')
      4 gdir.read_shapefile('outlines').plot(ax=ax, color='none', edgecolor='black');

NameError: name 'da' is not defined
../../_images/b116d57a62f73100763cfd98956c774aff52846104e7aa97c2cb75189e8d31a0.png

Regional DEMs / DEM availability#

Of course not all sources are available for every glacier as some of the DEMs are regional only. If we for example try the GIMP DEM, which is a Greenland specific DEM, it will not work for glaciers outside that region:

# Let's make a working directory for this DEM 
cfg.PATHS['working_dir'] = utils.gettempdir('gimp', reset=True)
try:
    gdir = workflow.init_glacier_directories(entity)[0]
    tasks.define_glacier_region(gdir, source='GIMP')
except oggm.exceptions.InvalidWorkflowError as err:
    print(err)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[13], line 4
      2 cfg.PATHS['working_dir'] = utils.gettempdir('gimp', reset=True)
      3 try:
----> 4     gdir = workflow.init_glacier_directories(entity)[0]
      5     tasks.define_glacier_region(gdir, source='GIMP')
      6 except oggm.exceptions.InvalidWorkflowError as err:

NameError: name 'entity' is not defined

User provided DEM#

Users should be able to use any DEM file which can be opened by rasterio (i.e. geotiff). Here, we use a subset SRTM file shipped with OGGM as an example:

custom_dem_path = utils.get_demo_file('hef_srtm.tif')
custom_dem_path
'/github/home/.oggm/oggm-sample-data-905430969c704c3ccd459c153f25bc1b9340af5b/test-files/hef_srtm.tif'

We tell OGGM to use it by changing the entry in the RGI table and by giving the path to the file:

cfg.PATHS['dem_file'] = custom_dem_path
cfg.PATHS['working_dir'] = utils.gettempdir('user', reset=True)
gdir = workflow.init_glacier_directories(entity)[0]
tasks.define_glacier_region(gdir, source='USER')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[16], line 2
      1 cfg.PATHS['working_dir'] = utils.gettempdir('user', reset=True)
----> 2 gdir = workflow.init_glacier_directories(entity)[0]
      3 tasks.define_glacier_region(gdir, source='USER')

NameError: name 'entity' is not defined

Now the user provided DEM is used:

f, ax = plt.subplots()
da_user = rioxr.open_rasterio(gdir.get_filepath('dem'))
da_user.plot(cmap='terrain', ax=ax)
gdir.read_shapefile('outlines').plot(ax=ax, color='none', edgecolor='black');
../../_images/806d99b35e5d4d5896ad54a2d6e53f60d72f2abc63c43be7f145fd303fb215c7.png

The border value, or how to choose the size of the topographic map#

It is possible to specify the extent of the local topographic map. All maps are centered on the glacier and the size of the map is determined in grid points around the glacier. The number of grid points that was used in this example are 10 in order to save storage. But depending on your study you might need a larger topographic map.

OGGM’s pre-processed directories come in 4 border sizes: 10, 40, 80 and 160. But if you process the topography yourself you can choose every value.

# print the currently used number of gridpoints around a glacier
cfg.PARAMS['border']
10
cfg.PARAMS['border'] = 1
2026-03-09 23:10:23: oggm.cfg: PARAMS['border'] changed from `10` to `1`.
# Let's make a working directory for this DEM 
cfg.PATHS['working_dir'] = utils.gettempdir('border1')
gdir = workflow.init_glacier_directories(entity)[0]
tasks.define_glacier_region(gdir)
da = rioxr.open_rasterio(gdir.get_filepath('dem'))
f, ax = plt.subplots()
da.plot(cmap='terrain', ax=ax)
# Add the outlines
gdir.read_shapefile('outlines').plot(ax=ax, color='none', edgecolor='black');
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[20], line 3
      1 # Let's make a working directory for this DEM 
      2 cfg.PATHS['working_dir'] = utils.gettempdir('border1')
----> 3 gdir = workflow.init_glacier_directories(entity)[0]
      4 tasks.define_glacier_region(gdir)
      5 da = rioxr.open_rasterio(gdir.get_filepath('dem'))

NameError: name 'entity' is not defined
cfg.PARAMS['border'] = 100
2026-03-09 23:10:23: oggm.cfg: PARAMS['border'] changed from `1` to `100`.
# Let's make a working directory for this DEM 
cfg.PATHS['working_dir'] = utils.gettempdir('border100')
gdir = workflow.init_glacier_directories(entity)[0]
tasks.define_glacier_region(gdir)
da = rioxr.open_rasterio(gdir.get_filepath('dem'))
f, ax = plt.subplots()
da.plot(cmap='terrain', ax=ax)
# Add the outlines
gdir.read_shapefile('outlines').plot(ax=ax, color='none', edgecolor='black');
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[22], line 3
      1 # Let's make a working directory for this DEM 
      2 cfg.PATHS['working_dir'] = utils.gettempdir('border100')
----> 3 gdir = workflow.init_glacier_directories(entity)[0]
      4 tasks.define_glacier_region(gdir)
      5 da = rioxr.open_rasterio(gdir.get_filepath('dem'))

NameError: name 'entity' is not defined

What’s next?#