RDPS πŸ…±#

BETA Requires MetPy >=1.6

This demonstrates using data from Canada’s GEM Regional or Regional Deterministic Prediction System (RDPS).

RDPS Model Description

Data Sources

prioriy=

Data source

Archive Duration

"mcs"

Meteorological Service of Canada

Last 24 hours

Model Initialization

Model cyles every six hours.

Forecast Hour

For the most recent version of RDPS…

fxx=

Forecast lead time

0 through 84, step=1

hourly forecasts available

Products

product=

Product Description

"10km/grib2"

Regional domain

Variable and Level

You will need to specify the variable and level for each request.

NOTE: The organization of these files is different than other NWP products.

  1. There are no index files provided.

  2. Each GRIB2 file only contains one message. The variable name and level is in the file’s name.

Herbie requires you provide a keyword argument for both variable and level. Pay special attention to model description (linked above) to understand how the model data is organized. If you don’t provide input for variable or level, Herbie will give you some ideas. For example, variable=TMP and level=TGL_2 will give you the filename that contains

TMP_TGL_2

Note: This requires MetPy version 1.6 or greater which has the capability to parse the rotated latitude longitude map projection type (see MetPy/#3123).

[1]:
from herbie import Herbie
import xarray as xr
import numpy as np

import matplotlib.pyplot as plt
from herbie.toolbox import EasyMap, pc
import cartopy.crs as ccrs
import cartopy.feature as feature
import pandas as pd

recent = pd.Timestamp("now").floor("12h") - pd.Timedelta("12h")
[3]:
# Some examples

H = Herbie(
    recent,  # Datetime
    model="rdps",
    fxx=3,
    variable="AirTemp",
    level="AGL-2m",
)
H.grib
βœ… Found β”Š model=rdps β”Š product=10km/grib2 β”Š 2026-Apr-16 12:00 UTC F03 β”Š GRIB2 @ local β”Š IDX @ None
[3]:
PosixPath('/home/meteo/kps5442/data/rdps/20260416/20260416T12Z_MSC_RDPS_AirTemp_AGL-2m_RLatLon0.09_PT003H.grib2')
[4]:
H = Herbie(
    recent,  # Datetime
    model="rdps",
    fxx=12,
    variable="GeopotentialHeight",
    level="IsbL-0500",
)
H.grib
βœ… Found β”Š model=rdps β”Š product=10km/grib2 β”Š 2026-Apr-16 12:00 UTC F12 β”Š GRIB2 @ msc β”Š IDX @ None
[4]:
'https://dd.weather.gc.ca/20260416/WXO-DD/model_rdps/10km/12/012/20260416T12Z_MSC_RDPS_GeopotentialHeight_IsbL-0500_RLatLon0.09_PT012H.grib2'
[6]:
# View variable names
H.AVAILABLE_VARIABLES
[6]:
['AbsoluteVorticity',
 'AirTemp',
 'Albedo',
 'CAPE',
 'CIN',
 'CloudWater',
 'DewPoint',
 'DewPointDepression',
 'DownwardLongwaveRadiationFlux-Accum',
 'DownwardShortwaveRadiationFlux-Accum',
 'GeopotentialHeight',
 'Humidex',
 'KIndex',
 'LandWaterProportion',
 'LatentHeatNetFlux',
 'LiftedIndex-MU-VT',
 'NetLongwaveRadiationFlux-Accum',
 'NetShortwaveRadiationFlux-Accum',
 'PlanetaryBoundaryLayerHeight',
 'PrecipType-Instant',
 'Pressure',
 'RadiativeTemp',
 'RelativeHumidity',
 'Runoff-Accum',
 'SWEATIndex',
 'SeaIceFraction',
 'SeaWaterTemp',
 'SensibleHeatNetFlux',
 'ShowalterIndex',
 'SkyTransparencyIndex',
 'SnowDensity',
 'SnowDepth',
 'SoilTemp',
 'SoilVolumetricWaterContent',
 'SpecificHumidity',
 'StormRelativeHelicity',
 'StormSeverityIndex',
 'Thickness',
 'TotalCloudCover',
 'TotalTotalsIndex',
 'UVIndex',
 'UVIndex-ClearSky',
 'UVIndex-ClearSky-Max24h',
 'UVIndex-Max24h',
 'UpwardLongwaveRadiationFlux',
 'UpwardShortwaveRadiationFlux',
 'VerticalVelocity',
 'VerticalWindShear',
 'WindChill',
 'WindDir',
 'WindGust',
 'WindGust-Max',
 'WindGust-Min',
 'WindSpeed',
 'WindU',
 'WindV']
[7]:
# View level names
H.AVAILABLE_LEVELS
[7]:
['AGL-10m',
 'AGL-120m',
 'AGL-2m',
 'AGL-40m',
 'AGL-80m',
 'DBS-0to10cm',
 'DBS-0to1cm',
 'EAtm',
 'EtaL-10000',
 'EtaL-6500',
 'IsbL-0001',
 'IsbL-0005',
 'IsbL-0010',
 'IsbL-0020',
 'IsbL-0030',
 'IsbL-0050',
 'IsbL-0100',
 'IsbL-0150',
 'IsbL-0175',
 'IsbL-0200',
 'IsbL-0225',
 'IsbL-0250',
 'IsbL-0275',
 'IsbL-0300',
 'IsbL-0350',
 'IsbL-0400',
 'IsbL-0450',
 'IsbL-0500',
 'IsbL-0550',
 'IsbL-0600',
 'IsbL-0650',
 'IsbL-0700',
 'IsbL-0750',
 'IsbL-0800',
 'IsbL-0850',
 'IsbL-0850to0700',
 'IsbL-0875',
 'IsbL-0900',
 'IsbL-0925',
 'IsbL-0950',
 'IsbL-0970',
 'IsbL-0985',
 'IsbL-1000',
 'IsbL-1000to0500',
 'IsbL-1000to0850',
 'IsbL-1015',
 'MSL',
 'NTAtm',
 'PVU-1',
 'PVU-1.5',
 'PVU-2',
 'Sfc',
 'TGL-10',
 'TGL-120',
 'TGL-2',
 'TGL-40',
 'TGL-80']

Get the 2-metre temperature#

[4]:
H = Herbie(
    recent,  # Datetime
    model="rdps",
    fxx=3,
    variable="AirTemp",
    level="AGL-2m",
)
ds = H.xarray()
ds
βœ… Found β”Š model=rdps β”Š product=10km/grib2 β”Š 2026-Apr-16 12:00 UTC F03 β”Š GRIB2 @ local β”Š IDX @ None
/home/kps5442/mapwall_dev/herbie-dev/src/herbie/core.py:1301: UserWarning: Will not remove GRIB file because it previously existed.
  warnings.warn("Will not remove GRIB file because it previously existed.")
[4]:
<xarray.Dataset> Size: 24MB
Dimensions:              (y: 1045, x: 1140)
Coordinates:
    latitude             (y, x) float64 10MB ...
    longitude            (y, x) float64 10MB ...
    time                 datetime64[ns] 8B 2026-04-16T12:00:00
    step                 timedelta64[ns] 8B 03:00:00
    heightAboveGround    float64 8B 2.0
    valid_time           datetime64[ns] 8B ...
    gribfile_projection  object 8B None
Dimensions without coordinates: y, x
Data variables:
    t2m                  (y, x) float32 5MB ...
Attributes:
    GRIB_edition:            2
    GRIB_centre:             cwao
    GRIB_centreDescription:  Canadian Meteorological Service - Montreal
    GRIB_subCentre:          0
    Conventions:             CF-1.7
    institution:             Canadian Meteorological Service - Montreal
    model:                   rdps
    product:                 10km/grib2
    description:             Canada's Regional Deterministic Prediction Syste...
    remote_grib:             /home/meteo/kps5442/data/rdps/20260416/20260416T...
    local_grib:              /home/meteo/kps5442/data/rdps/20260416/20260416T...
    search:                  None

Plot data on Plate Carree projection#

[5]:
ax = EasyMap("50m").BORDERS().STATES(alpha=0.5).ax
p = ax.pcolormesh(ds.longitude, ds.latitude, ds.t2m, transform=pc, cmap="Spectral_r")
plt.colorbar(p, ax=ax, orientation="horizontal", pad=0.01, shrink=0.8)
ax.set_title(
    f"2-m Temperature\nValid {ds.valid_time.dt.strftime('%Y-%m-%d %H:%M').item()} UTC",
    loc="right",
    fontsize=10,
)
ax.set_title(f"{ds.model.upper()}: {H.product_description}", loc="left")
ax.gridlines()
[5]:
<cartopy.mpl.gridliner.Gridliner at 0x73a5af9674d0>
../../_images/gallery_eccc_models_rdps_9_1.png

Get 10-m U and 10-m V wind#

[7]:
H.VARIABLES
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[7], line 1
----> 1 H.VARIABLES

AttributeError: 'Herbie' object has no attribute 'VARIABLES'
[9]:
# loading more than one variable requires a loop, because the
# data is stored in multiple files (and a Herbie object only
# represents a single file).

store = []
for var, lev in zip(["WindU", "WindV"], ["AGL-10m", "AGL-10m"]):
    _ds = Herbie(
        recent,
        model="rdps",
        fxx=3,
        variable=var,
        level=lev,
    ).xarray()
    store.append(_ds)

ds = xr.merge(store)
ds
βœ… Found β”Š model=rdps β”Š product=10km/grib2 β”Š 2026-Apr-16 12:00 UTC F03 β”Š GRIB2 @ msc β”Š IDX @ None
βœ… Found β”Š model=rdps β”Š product=10km/grib2 β”Š 2026-Apr-16 12:00 UTC F03 β”Š GRIB2 @ msc β”Š IDX @ None
/home/kps5442/mapwall_dev/herbie-dev/src/herbie/core.py:1306: UserWarning: Will not remove GRIB file because Herbie will only remove subsetted files (not full files).
  warnings.warn(
/tmp/ipykernel_1523756/2064047288.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_1523756/2064047288.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_1523756/2064047288.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_1523756/2064047288.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_1523756/2064047288.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_1523756/2064047288.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_1523756/2064047288.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
[9]:
<xarray.Dataset> Size: 29MB
Dimensions:              (y: 1045, x: 1140)
Coordinates:
    latitude             (y, x) float64 10MB -3.772 -3.731 -3.69 ... 50.1 50.04
    longitude            (y, x) float64 10MB -124.6 -124.6 ... 32.11 32.11
    time                 datetime64[ns] 8B 2026-04-16T12:00:00
    step                 timedelta64[ns] 8B 03:00:00
    heightAboveGround    float64 8B 10.0
    valid_time           datetime64[ns] 8B 2026-04-16T15:00:00
    gribfile_projection  object 8B None
Dimensions without coordinates: y, x
Data variables:
    u10                  (y, x) float32 5MB ...
    v10                  (y, x) float32 5MB ...
Attributes:
    GRIB_edition:            2
    GRIB_centre:             cwao
    GRIB_centreDescription:  Canadian Meteorological Service - Montreal
    GRIB_subCentre:          0
    Conventions:             CF-1.7
    institution:             Canadian Meteorological Service - Montreal
    model:                   rdps
    product:                 10km/grib2
    description:             Canada's Regional Deterministic Prediction Syste...
    remote_grib:             /home/meteo/kps5442/data/rdps/20260416/20260416T...
    local_grib:              /home/meteo/kps5442/data/rdps/20260416/20260416T...
    search:                  None
[10]:
# MetPy version >= 1.6 is required to parse the map projection
ds.herbie.crs
[10]:
2026-04-17T10:59:54.557790 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/
<cartopy.crs.RotatedPole object at 0x73a5b4b84f50>
[11]:
ax = (
    EasyMap("50m", crs=ds.herbie.crs, figsize=8, linewidth=1, theme="dark")
    .BORDERS()
    .STATES(alpha=0.5)
    .ax
)
p = ax.pcolormesh(
    ds.longitude,
    ds.latitude,
    np.hypot(ds.u10, ds.v10),  # Wind Speed
    transform=pc,
)
plt.colorbar(
    p, ax=ax, orientation="horizontal", pad=0.01, shrink=0.8, label="Wind speed (m/s)"
)

ax.set_title(
    f"10-m Wind Speed\nValid {ds.valid_time.dt.strftime('%Y-%m-%d %H:%M').item()} UTC",
    loc="center",
    fontsize=10,
)
ax.set_title(f"{ds.model.upper()}", loc="left")
ax.EasyMap.INSET_GLOBE()
[11]:
<GeoAxes: label='inset_axes'>
../../_images/gallery_eccc_models_rdps_14_1.png

500 hPa Humidity and Geopotential Height#

(some weirdness in the data I don’t understand)

[8]:
# loading more than one variable requires a loop, because the
# data is stored in multiple files (and a Herbie object only
# represents a single file).

store = []
for var, lev in zip(["GeopotentialHeight", "RelativeHumidity"], ["IsbL-0500", "IsbL-0500"]):
    _ds = Herbie(
        recent,
        model="rdps",
        fxx=3,
        variable=var,
        level=lev,
    ).xarray()
    store.append(_ds)

ds = xr.merge(store)
ds
βœ… Found β”Š model=rdps β”Š product=10km/grib2 β”Š 2026-Apr-16 12:00 UTC F03 β”Š GRIB2 @ msc β”Š IDX @ None
/home/kps5442/mapwall_dev/herbie-dev/src/herbie/core.py:1306: UserWarning: Will not remove GRIB file because Herbie will only remove subsetted files (not full files).
  warnings.warn(
βœ… Found β”Š model=rdps β”Š product=10km/grib2 β”Š 2026-Apr-16 12:00 UTC F03 β”Š GRIB2 @ msc β”Š IDX @ None
/home/kps5442/mapwall_dev/herbie-dev/src/herbie/core.py:1306: UserWarning: Will not remove GRIB file because Herbie will only remove subsetted files (not full files).
  warnings.warn(
/tmp/ipykernel_2164550/923645496.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_2164550/923645496.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_2164550/923645496.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_2164550/923645496.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_2164550/923645496.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_2164550/923645496.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
/tmp/ipykernel_2164550/923645496.py:16: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge(store)
[8]:
<xarray.Dataset> Size: 29MB
Dimensions:              (y: 1045, x: 1140)
Coordinates:
    latitude             (y, x) float64 10MB -3.772 -3.731 -3.69 ... 50.1 50.04
    longitude            (y, x) float64 10MB -124.6 -124.6 ... 32.11 32.11
    time                 datetime64[ns] 8B 2026-04-16T12:00:00
    step                 timedelta64[ns] 8B 03:00:00
    isobaricInhPa        float64 8B 500.0
    valid_time           datetime64[ns] 8B 2026-04-16T15:00:00
    gribfile_projection  object 8B None
Dimensions without coordinates: y, x
Data variables:
    gh                   (y, x) float32 5MB ...
    r                    (y, x) float32 5MB ...
Attributes:
    GRIB_edition:            2
    GRIB_centre:             cwao
    GRIB_centreDescription:  Canadian Meteorological Service - Montreal
    GRIB_subCentre:          0
    Conventions:             CF-1.7
    institution:             Canadian Meteorological Service - Montreal
    model:                   rdps
    product:                 10km/grib2
    description:             Canada's Regional Deterministic Prediction Syste...
    remote_grib:             /home/meteo/kps5442/data/rdps/20260416/20260416T...
    local_grib:              /home/meteo/kps5442/data/rdps/20260416/20260416T...
    search:                  None
[12]:
ax = (
    EasyMap("50m", crs=ds.herbie.crs, figsize=8, linewidth=1, theme="dark")
    .BORDERS()
    .STATES(alpha=0.5)
    .ax
)

# Draw Relative Humidity
p = ax.pcolormesh(
    ds.longitude, ds.latitude, ds.r, transform=pc, cmap="BrBG", vmin=0, vmax=100
)
plt.colorbar(
    p,
    ax=ax,
    orientation="horizontal",
    pad=0.01,
    shrink=0.8,
    label="Relative Humidity (%)",
)

# Draw Geopential Height Contours
ax.contour(
    ds.longitude,
    ds.latitude,
    ds.gh,
    colors="k",
    transform=pc,
    levels=range(0, 6000, 80),
)

ax.set_title(
    f"500 hPa RH and Geopotential height\nValid {ds.valid_time.dt.strftime('%Y-%m-%d %H:%M').item()} UTC",
    loc="center",
    fontsize=10,
)
ax.set_title(f"{ds.model.upper()}", loc="left")
[12]:
Text(0.0, 1.0, 'RDPS')
../../_images/gallery_eccc_models_rdps_17_1.png
[ ]: