William.Hatheway
Active member
Using the ECMWF Climate Data Store (CDS) to Download ERA5 Data in a Conda Environment
This guide shows you how to:- Create a Conda environment called CDS with pip and cdsapi
- Activate the environment
- Set up your CDS API token (.cdsapirc)
- Use the Python script Download_CDS_ERA5_Data_Hourly.py to download hourly ERA5 pressure-level and surface data
1. Create the Conda Environment CDS
Make sure you have conda (Anaconda or Miniconda) installed.1.1 Create the environment (with Python and pip)
conda create -n CDS python=3.10 pip- -n CDS → environment name is CDS
- python=3.10 → sets Python version
- pip → ensures pip is available in the environment
1.2 Activate the environment
conda activate CDSYour shell prompt should now show (CDS) at the beginning.
1.3 Install cdsapi inside CDS
pip install "cdsapi>=0.7.7"This installs the official Climate Data Store API client library.
2. Get and Set Up Your CDS API Token
The script uses the cdsapi client, which reads your credentials from a file called ~/.cdsapirc.2.1 Get your token from the CDS website
- Log in to the Copernicus Climate Data Store (CDS).
- Go to the CDS API / personal access token page.
- You will see something like:
url: https://cds.climate.copernicus.eu/api
key: YOUR_PERSONAL_ACCESS_TOKEN
Keep your key secret. Treat it like a password.
2.2 Create the .cdsapirc file
On Linux/macOS (or WSL / Git Bash on Windows):nano ~/.cdsapirc
Paste in:
url: https://cds.climate.copernicus.eu/api
key: YOUR_PERSONAL_ACCESS_TOKEN
Save and exit.
2.3 Quick test: can cdsapi see your token?
With the CDS environment active:python - << 'EOF'
import cdsapi
c = cdsapi.Client()
print("CDS client initialized successfully.")
EOF
If no error appears, your token and URL are configured correctly.
3. Overview of Download_CDS_ERA5_Data_Hourly.py
The main script is:Download_CDS_ERA5_Data_Hourly.py
It does four main things:
- Imports & description
"""
Downloads hourly ERA5 pressure-level and surface-level data from CDS.
- pressure-level files → ./pressure/
- surface-level files → ./surface/
"""
import os
from datetime import date, timedelta
from pathlib import Path
import cdsapi- Uses cdsapi for downloads, Path for directories, date/timedelta for looping over days.
- CDS config helpers
- _parse_cds_config(path)
- Reads a .cdsapirc-style file and extracts url and key.
- get_cds_client()
- Looks for:
- ~/.cdsapirc (home directory), or
- .cdsapirc in the script directory
- If found, returns a configured cdsapi.Client.
- If not, interactively asks for:
- URL and key or
- Path to an existing .cdsapirc.
- Looks for:
- _parse_cds_config(path)
- User input helpers
- prompt_int(prompt_text, default)
- Prompts for an integer with a default (for year/month/day).
- prompt_float(prompt_text, default)
- Prompts for a float with a default (for lat/lon).
- prompt_int(prompt_text, default)
- Main download logic
- download_era5_data(start_year, start_month, start_day, end_year, end_month, end_day, north_latitude, south_latitude, west_longitude, east_longitude, https_proxy=None)
- Inside this function:
- Optional proxy support via HTTPS_PROXY / https_proxy env vars.
- Calls get_cds_client() to get an authenticated cdsapi.Client.
- Creates output folders next to the script:
- pressure/
- surface/
- Builds a list of all 24 hours:
times = [
"00:00", "01:00", "02:00", "03:00",
"04:00", "05:00", "06:00", "07:00",
"08:00", "09:00", "10:00", "11:00",
"12:00", "13:00", "14:00", "15:00",
"16:00", "17:00", "18:00", "19:00",
"20:00", "21:00", "22:00", "23:00",
] - Loops from the start date to the end dateand for each day/hour:
- Builds file names like:
- pressure/preslev_YYYYMMDD_HHMM.grib
- surface/surface_YYYYMMDD_HHMM.grib
- Issues two CDS requests per hour:
- (a) Pressure levels
"reanalysis-era5-pressure-levels",
{
"product_type": "reanalysis",
"format": "grib",
"year": stryear,
"month": strmonth,
"day": strday,
"time": [hour],
"variable": [
"divergence", "fraction_of_cloud_cover", "geopotential",
"ozone_mass_mixing_ratio", "potential_vorticity",
"relative_humidity",
"specific_cloud_ice_water_content",
"specific_cloud_liquid_water_content",
"specific_humidity",
"specific_rain_water_content",
"specific_snow_water_content",
"temperature",
"u_component_of_wind",
"v_component_of_wind",
"vertical_velocity",
"vorticity",
],
"pressure_level": [
"10", "20", "30", "50", "70", "100", "125", "150", "175",
"200", "225", "250", "300", "350", "400", "450", "500",
"550", "600", "650", "700", "750", "775", "800", "825",
"850", "875", "900", "925", "950", "975", "1000",
],
"area": [
north_latitude, west_longitude,
south_latitude, east_longitude,
],
"grid": [0.25, 0.25],
},
str(pressure_filename),
)
(b) Single (surface) levels
c.retrieve(
"reanalysis-era5-single-levels",
{
"product_type": "reanalysis",
"format": "grib",
"year": stryear,
"month": strmonth,
"day": strday,
"time": [hour],
"variable": [
"10m_u_component_of_wind",
"10m_v_component_of_wind",
"2m_dewpoint_temperature",
"2m_temperature",
"land_sea_mask",
"mean_sea_level_pressure",
"sea_ice_cover",
"sea_surface_temperature",
"skin_temperature",
"snow_density",
"snow_depth",
"soil_temperature_level_1",
"soil_temperature_level_2",
"soil_temperature_level_3",
"soil_temperature_level_4",
"surface_pressure",
"volumetric_soil_water_layer_1",
"volumetric_soil_water_layer_2",
"volumetric_soil_water_layer_3",
"volumetric_soil_water_layer_4",
],
"area": [
north_latitude, west_longitude,
south_latitude, east_longitude,
],
"grid": [0.25, 0.25],
},
str(surface_filename),
) - Builds file names like:
- After all downloads:
print("Hourly ERA5 downloads complete.")
print(f"Pressure files saved in: {pressure_dir}")
print(f"Surface files saved in: {surface_dir}")
4. Interactive Main Block
At the bottom of the script:if __name__ == "__main__":
print("=== ERA5 Download Configuration ===")
print("Press Enter to accept the default value shown in [brackets].\n")
# Default values
default_start_year = 2024
default_start_month = 9
default_start_day = 25
default_end_year = 2024
default_end_month = 9
default_end_day = 29
default_north_lat = 45.0
default_south_lat = 5.0
default_west_lon = 60.0
default_east_lon = 100.0
The script then:
- Prompts for start/end year, month, day using prompt_int.
- Prompts for north/south latitude and west/east longitude using prompt_float.
- Optionally asks for an HTTPS proxy.
- Prints a summary of your choices.
- Calls download_era5_data(...) with the values you entered.
- Run the script.
- Accept defaults or enter your own values.
- Files appear in pressure/ and surface/ directories next to the script.
5. How to Run the Script in the CDS Conda Environment
Assuming:- Script path:
/media/yourdisk/Download_CDS_ERA5_Data_Hourly.py - CDS environment is set up.
- .cdsapirc is configured.
5.1 Activate the environment
conda activate CDS5.2 Run the script
python "/media/yourdisk/Download_CDS_ERA5_Data_Hourly.py"5.3 Follow the prompts
You’ll see something like:=== ERA5 Download Configuration ===
Press Enter to accept the default value shown in [brackets].
Start date:
Start year [2024]:
Start month [9]:
Start day [25]:
End date:
End year [2024]:
End month [9]:
End day [29]:
Geographic bounding box (latitudes/longitudes):
Note: North > South; longitudes in degrees (West/East, can be negative).
North latitude [45.0]:
South latitude [5.0]:
West longitude [60.0]:
East longitude [100.0]:
HTTPS proxy (optional).
Example: http://user: password@proxy-server: port
Enter HTTPS proxy (or leave blank for none):
Press Enter to accept defaults or type your own values. The script will print messages like:
Requesting data for 20240925 00:00
and will write the GRIB files into:
- pressure/
- surface/
Pytthon Code attached in Zip Files
Attachments
Last edited: