Skip to content

Commit

Permalink
update ecmwf from @blaylockbk
Browse files Browse the repository at this point in the history
  • Loading branch information
alcoat committed Mar 1, 2024
1 parent 2749b2c commit d9389ad
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 18 deletions.
56 changes: 45 additions & 11 deletions herbie/models/ecmwf.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
## Added by Brian Blaylock
## January 26, 2022

"""
A Herbie template for the ECMWF Open Data GRIB2 files.
Expand All @@ -11,20 +8,25 @@
- License Statement: This data is published under a Creative Commons Attribution 4.0 International (CC BY 4.0). https://creativecommons.org/licenses/by/4.0/
- Disclaimer: ECMWF does not accept any liability whatsoever for any error or omission in the data, their availability, or for any loss or damage arising from their use.
https://confluence.ecmwf.int/display/DAC/ECMWF+open+data%3A+real-time+forecasts
https://confluence.ecmwf.int/display/DAC/ECMWF+open+data%3A+real-time+forecasts+from+IFS+and+AIFS
Update 2024-02-29: ECMWF changes from 0.4 degree resolution to 0.25 plus adds artificial IFS
https://www.ecmwf.int/en/about/media-centre/news/2024/ecmwf-releases-much-larger-open-dataset
"""


class ecmwf:
class ifs:
def template(self):
# TODO: This will need to be updated someday
model = "ifs"
resol = "0p25"
# Allow a user to select the deprecated 0p4-beta resolution,
# but default to the 0p25 product if resolution is not specified.
# Sounds like the 0p4-beta product will be deprecated in May 2024.
if not hasattr(self, "resolution") or self.resolution is None:
self.resolution = "0p25"

self.DESCRIPTION = "ECMWF open data"
self.DESCRIPTION = "ECMWF Open Data - Integrated Forecast System"
self.DETAILS = {
"ECMWF": "https://confluence.ecmwf.int/display/DAC/ECMWF+open+data%3A+real-time+forecasts",
"ECMWF": "https://confluence.ecmwf.int/display/DAC/ECMWF+open+data%3A+real-time+forecasts+from+IFS+and+AIFS",
}
self.PRODUCTS = {
"oper": "operational high-resolution forecast, atmospheric fields",
Expand All @@ -46,7 +48,7 @@ def template(self):
product_suffix = "fc"

post_root = (
f"{self.date:%Y%m%d/%Hz}/{model}/{resol}/{self.product}"
f"{self.date:%Y%m%d/%Hz}/ifs/{self.resolution}/{self.product}"
f"/{self.date:%Y%m%d%H%M%S}-{self.fxx}h-{self.product}-{product_suffix}.grib2"
)

Expand All @@ -61,3 +63,35 @@ def template(self):
self.IDX_SUFFIX = [".index"]
self.IDX_STYLE = "eccodes" # 'wgrib2' or 'eccodes'
self.LOCALFILE = f"{self.get_remoteFileName}"


class aifs:
def template(self):
self.DESCRIPTION = (
"ECMWF Open Data - Artificial Inteligence Integrated Forecast System"
)
self.DETAILS = {
"ECMWF": "https://confluence.ecmwf.int/display/DAC/ECMWF+open+data%3A+real-time+forecasts+from+IFS+and+AIFS",
}
self.PRODUCTS = {
"oper": "operational high-resolution forecast, atmospheric fields",
}

# example file
# https://data.ecmwf.int/forecasts/20240229/00z/aifs/0p25/oper/20240229000000-0h-oper-fc.grib2

product_suffix = "fc"

post_root = (
f"{self.date:%Y%m%d/%Hz}/aifs/0p25/{self.product}"
f"/{self.date:%Y%m%d%H%M%S}-{self.fxx}h-{self.product}-{product_suffix}.grib2"
)

self.SOURCES = {
"azure": f"https://ai4edataeuwest.blob.core.windows.net/ecmwf/{post_root}",
"aws": f"https://ecmwf-forecasts.s3.eu-central-1.amazonaws.com/{post_root}",
"ecmwf": f"https://data.ecmwf.int/forecasts/{post_root}",
}
self.IDX_SUFFIX = [".index"]
self.IDX_STYLE = "eccodes" # 'wgrib2' or 'eccodes'
self.LOCALFILE = f"{self.get_remoteFileName}"
31 changes: 24 additions & 7 deletions tests/test_ecmwf.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
## Brian Blaylock
## October 13, 2021
"""Tests for downloading ECMWF model."""

"""
Tests for downloading ECMWF model
"""
from datetime import datetime, timedelta

from herbie import Herbie
Expand All @@ -14,10 +10,10 @@
save_dir = "$TMPDIR/Herbie-Tests/"


def test_ecmwf():
def test_ifs():
H = Herbie(
yesterday,
model="ecmwf",
model="ifs",
product="oper",
save_dir=save_dir,
)
Expand All @@ -34,3 +30,24 @@ def test_ecmwf():
# Test partial file xarray
H.xarray(":10(?:u|v):", remove_grib=False)
assert H.get_localFilePath(":10(?:u|v):").exists()


def test_aifs():
H = Herbie(
yesterday,
model="aifs",
save_dir=save_dir,
)

# Test full file download
H.download()
assert H.get_localFilePath().exists()

# Test partial file download
# temperature at all levels
H.download(":t:")
assert H.get_localFilePath(":t:").exists()

# Test partial file xarray
H.xarray(":10(?:u|v):", remove_grib=False)
assert H.get_localFilePath(":10(?:u|v):").exists()

0 comments on commit d9389ad

Please sign in to comment.