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.ERA5 — Function
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
~/.cdsapircwithurl: https://cds.climate.copernicus.eu/apiandkey: <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.
Setup
CDS API Key
To download ERA5 data automatically, you need a free CDS account:
- Register at https://cds.climate.copernicus.eu/
- Accept the ERA5 data licence
- Create
~/.cdsapircwith:
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]
)| Row | Name | Units | Description |
|---|---|---|---|
| String | Dimensio… | String | |
| 1 | pl₊v | m s⁻¹ | V component of wind |
| 2 | pl₊w | m⁻¹ kg s⁻³ | Vertical velocity |
| 3 | pl₊r | Relative humidity | |
| 4 | pl₊cc | Fraction of cloud cover | |
| 5 | pl₊clwc | Specific cloud liquid water content | |
| 6 | pl₊ciwc | Specific cloud ice water content | |
| 7 | pl₊vo | s⁻¹ | Vorticity (relative) |
| 8 | pl₊o3 | Ozone mass mixing ratio | |
| 9 | pl₊pv | m² kg⁻¹ s⁻¹ K | Potential vorticity |
| 10 | pl₊cswc | Specific snow water content | |
| 11 | pl₊t | K | Temperature |
| 12 | pl₊u | m s⁻¹ | U component of wind |
| 13 | pl₊q | Specific humidity | |
| 14 | pl₊z | m² s⁻² | Geopotential |
| 15 | pl₊crwc | Specific rain water content | |
| 16 | pl₊d | s⁻¹ | Divergence |
| 17 | P | m⁻¹ kg s⁻² | Pressure |
| 18 | δxδlon | m | X gradient with respect to longitude |
| 19 | δyδlat | m | Y gradient with respect to latitude |
| 20 | δPδlev | m⁻¹ 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 Name | Long Name | Units |
|---|---|---|
| t | Temperature | K |
| u | U component of wind | m s⁻¹ |
| v | V component of wind | m s⁻¹ |
| w | Vertical velocity | Pa s⁻¹ |
| q | Specific humidity | kg kg⁻¹ |
| r | Relative humidity | % |
| z | Geopotential | m² s⁻² |
| d | Divergence | s⁻¹ |
| vo | Vorticity | s⁻¹ |
| o3 | Ozone mass mixing ratio | kg kg⁻¹ |
| cc | Fraction of cloud cover | (0-1) |
| ciwc | Specific cloud ice water content | kg kg⁻¹ |
| clwc | Specific cloud liquid water content | kg kg⁻¹ |
| crwc | Specific rain water content | kg kg⁻¹ |
| cswc | Specific snow water content | kg kg⁻¹ |
| pv | Potential vorticity | K 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:
| Index | Pressure (hPa) | Index | Pressure (hPa) |
|---|---|---|---|
| 1 | 1000 | 20 | 300 |
| 2 | 975 | 21 | 250 |
| 3 | 950 | 22 | 225 |
| 4 | 925 | 23 | 200 |
| 5 | 900 | 24 | 175 |
| 6 | 875 | 25 | 150 |
| 7 | 850 | 26 | 125 |
| 8 | 825 | 27 | 100 |
| 9 | 800 | 28 | 70 |
| 10 | 775 | 29 | 50 |
| 11 | 750 | 30 | 30 |
| 12 | 700 | 31 | 20 |
| 13 | 650 | 32 | 10 |
| 14 | 600 | 33 | 7 |
| 15 | 550 | 34 | 5 |
| 16 | 500 | 35 | 3 |
| 17 | 450 | 36 | 2 |
| 18 | 400 | 37 | 1 |
| 19 | 350 |