ERA5 Reanalysis

Overview

ERA5 is the fifth generation ECMWF atmospheric reanalysis of the global climate, covering 1940 to the present with hourly temporal resolution and 0.25° x 0.25° spatial resolution on 37 pressure levels.

This data loader provides access to ERA5 pressure-level data via the Copernicus Climate Data Store (CDS) API or from pre-downloaded local NetCDF files.

Reference: Hersbach, H., et al. (2020). The ERA5 global reanalysis. Quarterly Journal of the Royal Meteorological Society, 146(730), 1999-2049. doi:10.1002/qj.3803

EarthSciData.ERA5Function
ERA5(domaininfo; name, mirror, variables, stream)

A data loader for ERA5 reanalysis data on pressure levels from the Copernicus Climate Data Store (CDS).

ERA5 is the fifth generation ECMWF atmospheric reanalysis of the global climate, covering 1940 to present with hourly temporal resolution and 0.25deg x 0.25deg spatial resolution on 37 pressure levels.

Authentication: Requires a CDS API key. Either:

  • Set ENV["CDSAPI_KEY"]
  • Create ~/.cdsapirc with url: https://cds.climate.copernicus.eu/api and key: <your-key>

Pre-downloaded data: Pass mirror="file:///path/to/data" to use local NetCDF files. Expected filenames: era5_pl_YYYY_MM.nc containing all variables for that month.

Available variables (all on pressure levels): temperature, u/v wind, vertical velocity, specific/relative humidity, geopotential, divergence, vorticity, ozone, cloud fractions, potential vorticity.

The native data type for this dataset is Float32.

stream specifies whether the data should be streamed in as needed or loaded all at once.

source

Setup

CDS API Key

To download ERA5 data automatically, you need a free CDS account:

  1. Register at https://cds.climate.copernicus.eu/
  2. Accept the ERA5 data licence
  3. Create ~/.cdsapirc with:
url: https://cds.climate.copernicus.eu/api
key: <your-api-key>

Alternatively, set the CDSAPI_KEY environment variable.

Pre-downloaded Data

If you already have ERA5 data as NetCDF files, use mirror="file:///path/to/data". Files should be named era5_pl_YYYY_MM.nc (one file per month, containing all variables).

Implementation

To use ERA5 data in production, you will need a CDS API key (see Setup above). The example below uses a small synthetic dataset to demonstrate the API.

using EarthSciData, EarthSciMLBase
using ModelingToolkit, DataFrames
using ModelingToolkit: t
using Dates
using DynamicQuantities
using DynamicQuantities: dimension

domain = DomainInfo(DateTime(2022, 1, 1), DateTime(2022, 1, 3);
    latrange = deg2rad(20.0f0):deg2rad(5.0):deg2rad(50.0f0),
    lonrange = deg2rad(-130.0f0):deg2rad(5.0):deg2rad(-60.0f0),
    levrange = 1:4,
)

era5 = ERA5(domain; mirror="file://$(era5_dir)")

\[ \begin{align} \mathtt{pl.v}\left( t \right) &= \mathtt{pl.v\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.w}\left( t \right) &= \mathtt{pl.w\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.r}\left( t \right) &= \mathtt{pl.r\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.cc}\left( t \right) &= \mathtt{pl.cc\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.clwc}\left( t \right) &= \mathtt{pl.clwc\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.ciwc}\left( t \right) &= \mathtt{pl.ciwc\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.vo}\left( t \right) &= \mathtt{pl.vo\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.o3}\left( t \right) &= \mathtt{pl.o3\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.pv}\left( t \right) &= \mathtt{pl.pv\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.cswc}\left( t \right) &= \mathtt{pl.cswc\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.t}\left( t \right) &= \mathtt{pl.t\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.u}\left( t \right) &= \mathtt{pl.u\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.q}\left( t \right) &= \mathtt{pl.q\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.z}\left( t \right) &= \mathtt{pl.z\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.crwc}\left( t \right) &= \mathtt{pl.crwc\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.d}\left( t \right) &= \mathtt{pl.d\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ P\left( t \right) &= \mathtt{hPa2Pa} ~ DataInterpolations.LinearInterpolation{Vector{Float64}, UnitRange{Int64}, Vector{Float64}, Vector{Float64}, Float64}([1000.0, 975.0, 950.0, 925.0, 900.0, 875.0, 850.0, 825.0, 800.0, 775.0, 750.0, 700.0, 650.0, 600.0, 550.0, 500.0, 450.0, 400.0, 350.0, 300.0, 250.0, 225.0, 200.0, 175.0, 150.0, 125.0, 100.0, 70.0, 50.0, 30.0, 20.0, 10.0, 7.0, 5.0, 3.0, 2.0, 1.0], 1:37, Float64[], DataInterpolations.LinearParameterCache{Vector{Float64}}(Float64[]), DataInterpolations.ExtrapolationType.None, DataInterpolations.ExtrapolationType.None, FindFirstFunctions.Guesser{UnitRange{Int64}}(1:37, Base.RefValue{Int64}(1), true), false, false)\left( \mathtt{lev} \right) \\ \mathtt{{\delta}x{\delta}lon}\left( t \right) &= \mathtt{lon2m} ~ \cos\left( \mathtt{lat} \right) \\ \mathtt{{\delta}y{\delta}lat}\left( t \right) &= \mathtt{lat2meters} \\ \mathtt{{\delta}P{\delta}lev}\left( t \right) &= \mathtt{hPa2Pa} ~ derivative\left( Interpolation\_interp, \mathtt{lev}, 1 \right) \end{align} \]

State Variables

vars = unknowns(era5)
DataFrame(
    :Name => [string(Symbolics.tosymbol(v, escape = false)) for v in vars],
    :Units => [dimension(ModelingToolkit.get_unit(v)) for v in vars],
    :Description => [ModelingToolkit.getdescription(v) for v in vars]
)
20×3 DataFrame
RowNameUnitsDescription
StringDimensio…String
1pl₊vm s⁻¹V component of wind
2pl₊wm⁻¹ kg s⁻³Vertical velocity
3pl₊rRelative humidity
4pl₊ccFraction of cloud cover
5pl₊clwcSpecific cloud liquid water content
6pl₊ciwcSpecific cloud ice water content
7pl₊vos⁻¹Vorticity (relative)
8pl₊o3Ozone mass mixing ratio
9pl₊pvm² kg⁻¹ s⁻¹ KPotential vorticity
10pl₊cswcSpecific snow water content
11pl₊tKTemperature
12pl₊um s⁻¹U component of wind
13pl₊qSpecific humidity
14pl₊zm² s⁻²Geopotential
15pl₊crwcSpecific rain water content
16pl₊ds⁻¹Divergence
17Pm⁻¹ kg s⁻²Pressure
18δxδlonmX gradient with respect to longitude
19δyδlatmY gradient with respect to latitude
20δPδlevm⁻¹ kg s⁻²Pressure gradient with respect to level index

Equations

eqs = equations(era5)

\[ \begin{align} \mathtt{pl.v}\left( t \right) &= \mathtt{pl.v\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.w}\left( t \right) &= \mathtt{pl.w\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.r}\left( t \right) &= \mathtt{pl.r\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.cc}\left( t \right) &= \mathtt{pl.cc\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.clwc}\left( t \right) &= \mathtt{pl.clwc\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.ciwc}\left( t \right) &= \mathtt{pl.ciwc\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.vo}\left( t \right) &= \mathtt{pl.vo\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.o3}\left( t \right) &= \mathtt{pl.o3\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.pv}\left( t \right) &= \mathtt{pl.pv\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.cswc}\left( t \right) &= \mathtt{pl.cswc\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.t}\left( t \right) &= \mathtt{pl.t\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.u}\left( t \right) &= \mathtt{pl.u\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.q}\left( t \right) &= \mathtt{pl.q\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.z}\left( t \right) &= \mathtt{pl.z\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.crwc}\left( t \right) &= \mathtt{pl.crwc\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ \mathtt{pl.d}\left( t \right) &= \mathtt{pl.d\_itp}\left( t + \mathtt{t\_ref}, \mathtt{lon}, \mathtt{lat}, \mathtt{lev} \right) \\ P\left( t \right) &= \mathtt{hPa2Pa} ~ DataInterpolations.LinearInterpolation{Vector{Float64}, UnitRange{Int64}, Vector{Float64}, Vector{Float64}, Float64}([1000.0, 975.0, 950.0, 925.0, 900.0, 875.0, 850.0, 825.0, 800.0, 775.0, 750.0, 700.0, 650.0, 600.0, 550.0, 500.0, 450.0, 400.0, 350.0, 300.0, 250.0, 225.0, 200.0, 175.0, 150.0, 125.0, 100.0, 70.0, 50.0, 30.0, 20.0, 10.0, 7.0, 5.0, 3.0, 2.0, 1.0], 1:37, Float64[], DataInterpolations.LinearParameterCache{Vector{Float64}}(Float64[]), DataInterpolations.ExtrapolationType.None, DataInterpolations.ExtrapolationType.None, FindFirstFunctions.Guesser{UnitRange{Int64}}(1:37, Base.RefValue{Int64}(1), true), false, false)\left( \mathtt{lev} \right) \\ \mathtt{{\delta}x{\delta}lon}\left( t \right) &= \mathtt{lon2m} ~ \cos\left( \mathtt{lat} \right) \\ \mathtt{{\delta}y{\delta}lat}\left( t \right) &= \mathtt{lat2meters} \\ \mathtt{{\delta}P{\delta}lev}\left( t \right) &= \mathtt{hPa2Pa} ~ derivative\left( Interpolation\_interp, \mathtt{lev}, 1 \right) \end{align} \]

Available Variables

ERA5 pressure-level variables include:

Short NameLong NameUnits
tTemperatureK
uU component of windm s⁻¹
vV component of windm s⁻¹
wVertical velocityPa s⁻¹
qSpecific humiditykg kg⁻¹
rRelative humidity%
zGeopotentialm² s⁻²
dDivergences⁻¹
voVorticitys⁻¹
o3Ozone mass mixing ratiokg kg⁻¹
ccFraction of cloud cover(0-1)
ciwcSpecific cloud ice water contentkg kg⁻¹
clwcSpecific cloud liquid water contentkg kg⁻¹
crwcSpecific rain water contentkg kg⁻¹
cswcSpecific snow water contentkg kg⁻¹
pvPotential vorticityK m² kg⁻¹ s⁻¹

Pressure Levels

ERA5 provides data on 37 pressure levels from 1000 hPa (surface) to 1 hPa (stratosphere). The level index maps to pressure as follows:

IndexPressure (hPa)IndexPressure (hPa)
1100020300
297521250
395022225
492523200
590024175
687525150
785026125
882527100
98002870
107752950
117503030
127003120
136503210
14600337
15550345
16500353
17450362
18400371
19350