Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ECMWF Open Data download and conversion functions #2975

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions modules/data.atmosphere/R/download.ECMWF.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#' Download ECMWF Open Data 15 day forecast data products
#'
swarnaleem marked this conversation as resolved.
Show resolved Hide resolved
#' @author Swarnalee Mazumder
#'

library(reticulate)
swarnaleem marked this conversation as resolved.
Show resolved Hide resolved
# py_install("ecmwf-opendata",pip = TRUE)

download.ECMWF <- function(outfolder,
fchour,
swarnaleem marked this conversation as resolved.
Show resolved Hide resolved
stream,
type = "pf",
parameters = "all",
overwrite = FALSE,
reticulate_python = NULL,...)

{
if (!file.exists(outfolder)) {
dir.create(outfolder, showWarnings = FALSE, recursive = TRUE)
}


istfer marked this conversation as resolved.
Show resolved Hide resolved
tryCatch({
ecmwfod <- reticulate::import("ecmwf.opendata")
}, error = function(e) {
PEcAn.logger::logger.severe(
"Failed to load `ecmwfod` Python library. ",
"Please make sure it is installed to a location accessible to `reticulate`.",
"You should be able to install it with the following command: ",
"`pip install --user ecmwf-opendata`.",
"The following error was thrown by `reticulate::import(\"ecmwf.opendata\")`: ",
conditionMessage(e)
)
})

hour <- fchour

all_hours <- c(00, 12)

if (any(!hour %in% all_hours)) {
bad_hours <- setdiff(hour, all_hours)
PEcAn.logger::logger.severe(sprintf(
"Invalid forecast hours %s. 15 day forecast hours must be one of the following: %s",
paste0("`", bad_hours, "`", collapse = ", "),
paste0("`", all_hours, "`", collapse = ", ")
))
}

if (fchour == 00){
time <- 0
} else if (fchour == 12){
time <- 12
}

all_parameters <- c("2t", "tp", "10u", "10v", "q", "r", "sp")
istfer marked this conversation as resolved.
Show resolved Hide resolved

if (tolower(parameters) == "all") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this condition is not met there will be no parameter_types, then line 61 will most likely throw a 'parameter_types' not found error, should there be an else to this if?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added else to show what can be given as an input, here all.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is remains to be the case, please add an else to make sure parameter_types are assigned something in case tolower(parameters) != "all"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If tolower(parameters) != "all" should the parameter_types still be "all"?

parameter_types <- all_parameters
}

if (any(!parameter_types %in% all_parameters)) {
bad_parameters <- setdiff(parameter_types, all_parameters)
PEcAn.logger::logger.severe(sprintf(
"Invalid parameter types %s. Products must be one of the following: %s",
paste0("`", bad_parameters, "`", collapse = ", "),
paste0("`", all_parameters, "`", collapse = ", ")
))
}


if (stream == "enfo"){
time <- time
step <- 360
type <- type
swarnaleem marked this conversation as resolved.
Show resolved Hide resolved
} else{
PEcAn.logger::logger.severe(sprintf(
"Invalid data stream."
swarnaleem marked this conversation as resolved.
Show resolved Hide resolved
))
}

# Python script "download_ecmwf.py" to get latest forecast date and download forecast datasets
source_python("download_ecmwf.py")
swarnaleem marked this conversation as resolved.
Show resolved Hide resolved

date_latestdata <- ecmwflatest(time, step, stream, type, all_parameters)
Copy link
Contributor

@istfer istfer Sep 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
date_latestdata <- ecmwflatest(time, step, stream, type, all_parameters)
date_latestdata <- ecmwflatest(time, step_15day, stream, type, all_parameters)

there is no step variable, was this supposed to be step_15day?

latest_filedate <- strtoi(gsub("-", "", substr(as.character.Date(date_latestdata), 1, 10)))

current_date <- strtoi(gsub("-", "", Sys.Date()))

date <- if (latest_filedate == current_date){
# today
0
} else if ((latest_filedate - current_date) == -1){
# yesterday
-1
} else if ((latest_filedate - current_date) == -2){
# the day before yesterday
-2
} else { PEcAn.logger::logger.severe(sprintf(
"Invalid file download date."
))
}

fname <- paste(latest_filedate, time, step, stream, type, sep = "_")
swarnaleem marked this conversation as resolved.
Show resolved Hide resolved

grib_fname <- paste0(fname, ".grib2")
data_download <- ecmwfdownload(date, time, step, stream, type, all_parameters, grib_fname)

# Python script "ecmwf_grib2nc.py" to convert grib2 to netCDF
# Converting Grib2 file to ensemble wise NetCDF file
source_python("ecmwf_grib2nc.py")
swarnaleem marked this conversation as resolved.
Show resolved Hide resolved
nc_ecmwf <- grib2nc_ecmwf(grib_fname)

swarnaleem marked this conversation as resolved.
Show resolved Hide resolved
}

### code to reproduce
# date <- -1
# time <- 0
# step <- 360
# stream <- "enfo"
# type <- "pf"
#
# all_parameters <- c("tp", "10u", "10v", "q", "r", "sp")
# grib_fname <- "trial_ecmwfod.grib2"
#
# source_python("download_ecmwf.py")
# data_download <- ecmwfdownload(date, time, step, stream, type, all_parameters, grib_fname)
#
# source_python("ecmwf_grib2nc.py")
# nc_ecmwf <- grib2nc_ecmwf(grib_fname)
44 changes: 44 additions & 0 deletions modules/data.atmosphere/inst/ECMWF/download_ecmwf_opendata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# !pip install ecmwf-opendata

def ecmwflatest(time, step, stream, type, params):
from ecmwf.opendata import Client

client = Client("ecmwf", beta=True)

if stream == "mmsf":
latest= client.latest(
time = int(time),
step= step,
stream= stream,
type= type,
param= params,
)

elif stream == "enfo":
latest= client.latest(
time = int(time),
step= int(step),
stream= stream,
type= type,
param= params,
)

return latest


def ecmwfdownload(date, time, step, stream, type, params, filename):
from ecmwf.opendata import Client

client = Client("ecmwf", beta=True)

file = client.retrieve(
date= int(date),
time= int(time),
step= int(step),
stream= stream,
type= type,
param= params,
target= filename
)

return file
22 changes: 22 additions & 0 deletions modules/data.atmosphere/inst/ECMWF/ecmwf_grib2nc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# !pip install xarray
# !pip install cfgrib

def grib2nc_ecmwf(grib_fname):
import xarray
import cfgrib

grib_fname = str(grib_fname)

dataset = xarray.open_dataset(grib_fname, engine='cfgrib')

fname = str(grib_fname[:-6])

for i in range(50):

ens = dataset.isel(number=i)

fname = fname+"ens_"+str(i+1)+".nc"

ens.to_netcdf(fname)

fname = str(grib_fname[:-6])