diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 74badb7..0000000 Binary files a/.DS_Store and /dev/null differ diff --git a/.Rbuildignore b/.Rbuildignore index 3783119..2dafdb6 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -3,3 +3,5 @@ ^packrat/ ^\.Rprofile$ ^LICENSE\.md$ +^data-raw$ +^metadata$ diff --git a/.gitignore b/.gitignore index 8a435a4..9222578 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,14 @@ .Ruserdata packrat/ -**/Test/* + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db diff --git a/DESCRIPTION b/DESCRIPTION index ebf3e6a..d0c3b9f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,36 +1,33 @@ Package: KrigR Type: Package -Title: Downloading, Aggregating, and Kriging of ERA5(Land)-Data -Version: 0.1.3 +Title: Downloading, Aggregating, and Kriging of ECMWF CDS-Data +Version: 0.3.0 Authors@R: as.person(c( "Erik Kusch [aut, cre]", "Richard Davy [aut]" )) -Description: An R Package for downloading, preprocessing, and statistical downscaling of the European Centre for Medium-range Weather Forecasts ReAnalysis 5 (ERA5) family provided by the European Centre for Medium‐Range Weather Forecasts (ECMWF). +Description: An R Package for downloading, preprocessing, and statistical downscaling of data provided by the European Centre for Medium‐Range Weather Forecasts (ECMWF). KrigR contains functions for: - - Downloading Era5(Land) data directly from within R - - Downloading USGS GMTED 2010 elevation data + - Downloading ECMWF data directly from within R + - Downloading USGS GMTED 2010 elevation data - Working towards also implementing support for HWSD data + - Preparing covariate data for Kriging - Kriging spatial input to desired output using user-specified covariates - - Downloading and Kriging Era5(Land) data using USGS GMTED 2010 elevation as coviariate data in one function call License: MIT + file LICENSE Encoding: UTF-8 LazyData: true -RoxygenNote: 7.2.3 -Depends: - ncdf4, +RoxygenNote: 7.3.1 +Imports: ecmwfr, - keyring, - stringr, - raster, - rgdal, - doParallel, - foreach, - doSNOW, - automap, + httr, + stringr, lubridate, - sp, sf, - fasterize, - stars, - httr, - terra + terra, + ncdf4, + automap, + foreach, + tools, + progress, + doSNOW, + pbapply +Depends: R (>= 4.0.0) diff --git a/NAMESPACE b/NAMESPACE index 8bad4fa..ca020df 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,10 +1,75 @@ # Generated by roxygen2: do not edit by hand export(BioClim) +export(Buffer.pts) +export(CDownloadS) +export(Check.File) +export(CovariateSetup) +export(Ext.Check) +export(Handle.Spatial) +export(Kriging) +export(Make.SpatialPoints) +export(Make.UTC) +export(Meta.DOI) +export(Meta.List) +export(Meta.QuickFacts) +export(Meta.Read) +export(Meta.Variables) export(SummarizeRaster) export(buffer_Points) -export(check_Krig) export(download_DEM) export(download_ERA) export(krigR) export(mask_Shape) +importFrom(automap,autoKrige) +importFrom(doSNOW,registerDoSNOW) +importFrom(ecmwfr,wf_get_key) +importFrom(ecmwfr,wf_request) +importFrom(ecmwfr,wf_set_key) +importFrom(ecmwfr,wf_transfer) +importFrom(foreach,"%dopar%") +importFrom(foreach,foreach) +importFrom(httr,DELETE) +importFrom(httr,GET) +importFrom(httr,add_headers) +importFrom(httr,authenticate) +importFrom(httr,progress) +importFrom(httr,write_disk) +importFrom(lubridate,days_in_month) +importFrom(methods,getClass) +importFrom(ncdf4,nc_close) +importFrom(ncdf4,nc_open) +importFrom(ncdf4,ncatt_get) +importFrom(ncdf4,ncatt_put) +importFrom(parallel,makeCluster) +importFrom(parallel,stopCluster) +importFrom(pbapply,pblapply) +importFrom(progress,progress_bar) +importFrom(sf,st_as_sf) +importFrom(sf,st_bbox) +importFrom(sf,st_buffer) +importFrom(sf,st_coordinates) +importFrom(sf,st_drop_geometry) +importFrom(sf,st_union) +importFrom(stringr,str_c) +importFrom(stringr,str_pad) +importFrom(terra,aggregate) +importFrom(terra,app) +importFrom(terra,crop) +importFrom(terra,crs) +importFrom(terra,ext) +importFrom(terra,mask) +importFrom(terra,metags) +importFrom(terra,nlyr) +importFrom(terra,rast) +importFrom(terra,res) +importFrom(terra,resample) +importFrom(terra,subset) +importFrom(terra,tapp) +importFrom(terra,time) +importFrom(terra,units) +importFrom(terra,values) +importFrom(terra,varnames) +importFrom(terra,writeCDF) +importFrom(terra,writeRaster) +importFrom(tools,file_path_sans_ext) diff --git a/R/BioClim.R b/R/BioClim.R index 480c460..0e4212d 100644 --- a/R/BioClim.R +++ b/R/BioClim.R @@ -60,6 +60,8 @@ BioClim <- function(Water_Var = "volumetric_soil_water_layer_1", # could also be TimeOut = 36000, SingularDL = FALSE){ + stop("Function currently deprecated as KrigR undergoes major re-development. Please use the stable release to gain access to this functionality.") + Vars <- c("2m_temperature", Water_Var) if(Y_end == year(Sys.Date())){ diff --git a/R/CDSAPI.R b/R/CDSAPI.R new file mode 100644 index 0000000..c0f03d1 --- /dev/null +++ b/R/CDSAPI.R @@ -0,0 +1,205 @@ +### CDS API Credentials ======================================================== +#' Register CDS API Credentials +#' +#' Just checks if provided API user and Key have already been added to keychain and adds them if necessary. +#' +#' @param API_User Character. CDS API User +#' @param API_Key Character. CDS API Key +#' +#' @importFrom ecmwfr wf_get_key +#' @importFrom ecmwfr wf_set_key +#' +#' @return No R object. An addition to the keychain if necessary. +#' +#' @seealso \code{\link{Make.Request}}, \code{\link{Execute.Requests}}. +#' +Register.Credentials <- function(API_User, API_Key){ + API_Service = "cds" + KeyRegisterCheck <- tryCatch(ecmwfr::wf_get_key(user = API_User, service = API_Service), + error = function(e){e}) + if(any(class(KeyRegisterCheck) == "simpleError")){ + ecmwfr::wf_set_key(user = API_User, + key = as.character(API_Key), + service = API_Service) + } +} +### FORMING CDS Requests ======================================================= +#' Form CDS Requests +#' +#' Loops over time windows of defined size and creates a list of CDS requests. +#' +#' @param QueryTimeWindows List. List of date ranges created by \code{\link{Make.RequestWindows}}. +#' @param QueryDataSet Character. Dataset specified by user. +#' @param QueryType Character. Dataset type specified by user. +#' @param QueryVariable Character. CDS internal variable name. +#' @param QueryTimes Character. Layers of data in the raw data set +#' @param QueryExtent Character. Extent object created by Check.Ext(Extent)[c(4,1,3,2)] +#' @param QueryFormat Character. File format queried by user +#' @param Dir Directory pointer. Where to store CDS request outcomes. +#' @param verbose Logical. Whether to print/message function progress in console or not. +#' @param API_User Character. CDS API User +#' @param API_Key Character. CDS API Key +#' +#' @importFrom ecmwfr wf_request +#' +#' @return List. Each element holding either (1) a list object representing a CDS request or (2) the value NA indicating that a file of this name is already present. +#' +#' @seealso \code{\link{Make.RequestWindows}}, \code{\link{Register.Credentials}}, \code{\link{Execute.Requests}}. +#' +Make.Request <- function(QueryTimeWindows, QueryDataSet, QueryType, QueryVariable, + QueryTimes, QueryExtent, QueryFormat, Dir = getwd(), verbose = TRUE, + API_User, API_Key){ + #' Make list of CDS Requests + Requests_ls <- lapply(1:length(QueryTimeWindows), FUN = function(requestID){ + FName <- paste("TEMP", QueryVariable, stringr::str_pad(requestID, 5, "left", "0"), sep = "_") + if(grepl("month", QueryType)){ # monthly data needs to be specified with year, month fields + list('dataset_short_name' = QueryDataSet, + 'product_type' = QueryType, + 'variable' = QueryVariable, + 'year' = unique(as.numeric(format(as.POSIXct(QueryTimeWindows[[requestID]]), "%Y"))), + 'month' = unique(as.numeric(format(QueryTimeWindows[[requestID]], "%m"))), + 'time' = QueryTimes, + 'area' = QueryExtent, + 'format' = QueryFormat, + 'target' = FName + # , + # 'grid' = QueryGrid + ) + }else{ + list('dataset_short_name' = QueryDataSet, + 'product_type' = QueryType, + 'variable' = QueryVariable, + 'date' = paste0( + head(QueryTimeWindows[[requestID]], n = 1), + "/", + tail(QueryTimeWindows[[requestID]], n = 1)), + 'time' = QueryTimes, + 'area' = QueryExtent, + 'format' = QueryFormat, + 'target' = FName + # , + # 'grid' = QueryGrid + ) + } + + }) + ## making list names useful for request execution updates to console + Iterators <- paste0("[", 1:length(Requests_ls), "/", length(Requests_ls), "] ") + FNames <- unlist(lapply(Requests_ls, "[[", "target")) + Dates <- unlist(lapply(lapply(Requests_ls, "[[", "date"), gsub, pattern = "/", replacement = " - ")) + if(length(Dates) == 0){ # this happens for monthly data queries + Dates <- unlist(lapply(lapply(Requests_ls, "[[", "year"), FUN = function(x){ + paste0(head(x, 1), " - ", tail(x, 1)) + })) + } + names(Requests_ls) <- paste0(Iterators, FNames, " (UTC: ", Dates, ")") + ## check if files are already present + FCheck <- sapply(FNames, Check.File, Dir = Dir, loadFun = "terra::rast", load = FALSE, + verbose = FALSE) + if(length(names(unlist(FCheck))) > 0){ + Requests_ls[match(names(unlist(FCheck)), FNames)] <- NA + } + Requests_ls + + if(verbose){print("## Staging CDS Requests")} + for(requestID in 1:length(Requests_ls)){ ## looping over CDS requests + if(verbose){print(names(Requests_ls)[requestID])} + if(class(Requests_ls[[requestID]]) == "logical"){ + # if(verbose){print("File with this name is already present.")} + next() + } + API_request <- suppressMessages({ + ecmwfr::wf_request(user = API_User, + request = Requests_ls[[requestID]], + transfer = FALSE, + path = Dir, + verbose = verbose, + time_out = TimeOut) + }) + Requests_ls[[requestID]]$API_request <- API_request + } + Requests_ls +} + +### EXECUTING CDS REQUESTS ==================================================== +#' Execute CDS Requests +#' +#' Loops over list of fully formed ecmwfr requests and executes these on CDS. +#' +#' @param Requests_ls List. ecmwfr-ready CDS requests formed with \code{\link{Make.Request}}. +#' @param Dir Character. Directory where to save raw data. +#' @param API_User Character. CDS API User +#' @param API_Key Character. CDS API Key +#' @param TryDown Numeric. How often to retry a failing request/download +#' @param verbose Logical. Whether to print/message function progress in console or not. +#' +#' @importFrom ecmwfr wf_transfer +#' @importFrom httr DELETE +#' @importFrom httr authenticate +#' @importFrom httr add_headers +#' +#' @return No R object. Resulting files of CDS query/queries in signated directory. +#' +#' @seealso \code{\link{Register.Credentials}}, \code{\link{Make.Request}}. +#' +Execute.Requests <- function(Requests_ls, Dir, API_User, API_Key, TryDown, verbose = TRUE){ + if(verbose){print("## Listening for CDS Requests")} + for(requestID in 1:length(Requests_ls)){ ## looping over CDS requests + if(verbose){print(names(Requests_ls)[requestID])} + if(class(Requests_ls[[requestID]]) == "logical"){ + if(verbose){print("File with this name is already present.")} + next() + } + API_request <- Requests_ls[[requestID]]$API_request + FileDown <- list(state = "queued") + Down_try <- 0 + while(FileDown$state != "completed" & Down_try <= TryDown){ + ## console output that shows the status of the request on CDS + if(verbose){ + if(FileDown$state == "queued"){ + for(rep_iter in 1:10){ + cat(rep(" ", 100)) + flush.console() + cat('\r', "Waiting for CDS to start processing the query", rep(".", rep_iter)) + flush.console() + Sys.sleep(0.5) + } + } + if(FileDown$state == "running"){ + for(rep_iter in 1:10){ + cat(rep(" ", 100)) + flush.console() + cat('\r', "CDS is processing the query", rep(".", rep_iter)) + flush.console() + Sys.sleep(0.5) + } + } + } + ## download file for current request when ready + FileDown <- tryCatch(ecmwfr::wf_transfer(url = API_request$get_url(), + user = API_User, + service = "cds", + verbose = TRUE, + path = Dir, + filename = API_request$get_request()$target), + error = function(e){e} + ) + if(Down_try == TryDown){ + stop("Download of CDS query result continues to fail after ", Down_try, " trys. The most recent error message is: \n", FileDown, "Assess issues at https://cds.climate.copernicus.eu/cdsapp#!/yourrequests.") + } + if(any(class(FileDown) == "simpleError")){ + FileDown <- list(state = "queued") + Down_try <- Down_try+1 + } + } + if(FileDown$state == "completed"){ + delete <- httr::DELETE( + API_request$get_url(), + httr::authenticate(API_User, API_Key), + httr::add_headers( + "Accept" = "application/json", + "Content-Type" = "application/json") + ) + } + } +} diff --git a/R/CDownloadS.R b/R/CDownloadS.R new file mode 100644 index 0000000..1ed6150 --- /dev/null +++ b/R/CDownloadS.R @@ -0,0 +1,353 @@ +#' Downloading Data from ECMWF Climate Data Store +#' +#' This function is used to obtain data from the \href{https://cds.climate.copernicus.eu/#!/home}{Climate Data Store (CDS)} hosted by the \href{https://cds.climate.copernicus.eu/about-c3s}{Copernicus Climate Change Service (C3S)}. By default, this function breaks down download calls into intervals so as to avoid submitting queries which fail, downloads queried data from \href{https://www.ecmwf.int/}{ECMWF} servers according to user-specification, and fuses the downloaded files together according to user-demands. The actual time to download is dependent on ECMWF download queues. Users need an \href{https://cds.climate.copernicus.eu/api-how-to}{API key} for download staging and accept terms and conditions for the specific queried dataset(s). +#' +#' @param Variable Character. Desired variable from queried dataset. See \code{\link{Meta.Variables}} for options per dataset. +#' @param CumulVar Logical. Some ECMWF CDS data is recorded in cumulative steps per hour/month from the 00:00 time mark per day. Setting CumulVar to TRUE converts these into records which represent the total records per hour using the \code{\link{Temporal.Cumul}} function. Monthly cumulative records express the average daily total value. Setting this argument to TRUE multiplies monthly records by the number of days per the respective month(s) to get to total records instead of average. Default is FALSE. This argument can only be set to TRUE for cumulatively recorded variables. See \code{\link{Meta.Variables}} for an overview of which variables at recorded cumulatively per dataset. +#' @param DataSet Character. Which dataset to query data from. See currently supported datasets by calling \code{\link{Meta.List}}. +#' @param Type Either NA or Character. Which kind of sub-type to query per data set. See \code{\link{Meta.QucikFacts}} for options per dataset. +#' @param DateStart Character. Date ('YYYY-MM-DD HH:SS') at which to start time series of downloaded data. +#' @param DateStop Character. Date ('YYYY-MM-DD HH:SS') at which to stop time series of downloaded data. +#' @param TZone Character. Time zone in which to represent and evaluate time dimension of data. See the output of OlsonNames() for a full overview of supported specifications. Default is UTC. +#' @param TResolution Character. Temporal resolution of final product. 'hour', 'day', 'month', or 'year'. +#' @param TStep Numeric. Which time steps to consider for temporal resolution. For example, specify bi-monthly data records by setting TResolution to 'month' and TStep to 2. +#' @param FUN A raster calculation argument as passed to `terra::tapp()`. This controls what kind of data to obtain for temporal aggregates of reanalysis data. Specify 'mean' (default) for mean values, 'min' for minimum values, and 'max' for maximum values, among others. +#' @param Extent Optional, download data according to desired spatial specification. If missing/unspecified, total area of queried data set is used. Can be specified either as a raster object, an sf object, a terra object, or a data.frame. If Extent is a raster or terra object, data will be queried according to rectangular extent thereof. If Extent is an sf (MULTI-)POLYGON object, this will be treated as a shapefile and the output will be cropped and masked to this shapefile. If Extent is a data.frame of geo-referenced point records, it needs to contain Lat and Lon columns around which a buffered shapefile will be created using the Buffer argument. +#' @param Buffer Optional, Numeric. Identifies how big a circular buffer to draw around points if Extent is a data.frame of points. Buffer is expressed as centessimal degrees. +#' @param Dir Character/Directory Pointer. Directory specifying where to download data to. +#' @param FileName Character. A file name for the produced file. +#' @param FileExtension Character. A file extension for the produced file. Supported values are ".nc" (default) and ".tif" (better support for metadata). +#' @param API_Key Character; ECMWF cds API key. +#' @param API_User Character; ECMWF cds user number. +#' @param TryDown Optional, numeric. How often to attempt the download of each individual file that the function queries from the CDS. This is to circumvent having to restart the entire function when encountering connectivity issues. +#' @param TimeOut Numeric. The timeout for each download in seconds. Default 36000 seconds (10 hours). +#' @param TChunkSize Numeric. Number of layers to bundle in each individual download. Default is 6000 to adhere to most restrictive CDS limits: https://cds.climate.copernicus.eu/live/limits. +#' @param Cores Numeric. How many cores to use when carrying out temporal aggregation. Default is 1. +#' @param verbose Logical. Whether to print/message function progress in console or not. +#' @param Keep_Raw Logical. Whether to retain raw downloaded data or not. Default is FALSE. +#' @param Save_Final Logical. Whether to write the final SpatRaster to the hard drive. Default is TRUE. +#' +#' @importFrom tools file_path_sans_ext +#' @importFrom terra rast +#' @importFrom terra ext +#' @importFrom terra time +#' @importFrom terra nlyr +#' @importFrom terra varnames +#' @importFrom terra units +#' @importFrom terra metags +#' @importFrom terra writeRaster +#' +#' @return A SpatRaster object containing the downloaded, cropped/masked, and subsequently temporally aggregated data, and a file (either .nc or .tif) in the specified directory. +#' +#' The SpatRaster contains metadata/attributes as a named vector that can be retrieved with terra::metags(...): +#' \itemize{ +#' \item{Citation}{ - A string which to use for in-line citation of the data product obtained with CDownloadS}. +#' \item{KrigRCall.X}{ - Arguments passed to the CDownloadS function that produced the file (API credentials are omitted from these metadata)}. +#' } +#' +#' \strong{ATTENTION:} If data is loaded again from disk at a later point with a different function, take note that the time zone will have to be set anew and existing time parameters in the .nc contents will need to be converted to the desired time zone. Likewise, citation and KrigR-call metadata will not be loaded properly from a .nc when loading data through a different function. CDownloads() handles these .nc specific issues when loading .nc files created previously with CDownloadS from disk. +#' +#' @seealso \code{\link{Meta.List}}, \code{\link{Meta.Variables}}, \code{\link{Meta.QuickFacts}}. +#' +#' @examples +#' \dontrun{ +#' ## Raw data for one month of full globe +#' RawGlobe_rast <- CDownloadS( +#' Variable = "2m_temperature", +#' DataSet = "reanalysis-era5-land-monthly-means", +#' Type = "monthly_averaged_reanalysis", +#' # time-window, default set to range of dataset-type +#' DateStart = "1995-01-01 00:00", +#' DateStop = "1995-01-01 23:00", +#' TZone = "CET", +#' # temporal aggregation +#' TResolution = "month", +#' TStep = 1, +#' # file storing +#' FileName = "RawGlobe", +#' # API credentials +#' API_User = API_User, +#' API_Key = API_Key +#' ) +#' terra::plot(RawGlobe_rast) +#' +#' ## Monthly air temperature aggregated to bi-annual maximum by SpatRaster +#' CDS_rast <- terra::rast(system.file("extdata", "CentralNorway.nc", package="KrigR")) +#' BiAnnAirTemp_rast <- CDownloadS( +#' Variable = "2m_temperature", +#' DataSet = "reanalysis-era5-land-monthly-means", +#' Type = "monthly_averaged_reanalysis", +#' # time-window, default set to range of dataset-type +#' DateStart = "1995-01-01 00:00", +#' DateStop = "1996-12-31 23:00", +#' TZone = "EET", +#' # temporal aggregation +#' TResolution = "year", +#' TStep = 2, +#' # spatial +#' Extent = CDS_rast, +#' # file storing +#' FileName = "BiAnnAirTemp", +#' # API credentials +#' API_User = API_User, +#' API_Key = API_Key +#' ) +#' terra::plot(BiAnnAirTemp_rast) +#' +#' ## Hourly back-calculated precipitation aggregated to daily averages by shapefiles +#' data("Jotunheimen_poly") +#' Jotunheimen_poly +#' DailyBackCPrecip_rast <- CDownloadS( +#' Variable = "total_precipitation", +#' CumulVar = TRUE, +#' # time-window, default set to range of dataset-type +#' DateStart = "1995-01-01 00:00", +#' DateStop = "1995-01-03 23:00", +#' TZone = "CET", +#' # temporal aggregation +#' TResolution = "day", +#' # spatial +#' Extent = Jotunheimen_poly, +#' # file storing +#' FileName = "DailyBackCPrecip", +#' # API credentials +#' API_User = API_User, +#' API_Key = API_Key +#' ) +#' terra::plot(DailyBackCPrecip_rast) +#' +#' ## 6-hourly ensemble member spread sum for air temperature by buffered points +#' data("Mountains_df") +#' EnsembleSpreadSum6hour_rast <- CDownloadS( +#' Variable = "2m_temperature", +#' DataSet = "reanalysis-era5-single-levels", +#' Type = "ensemble_spread", +#' # time-window, default set to range of dataset-type +#' DateStart = "1995-01-01 00:00:00", +#' DateStop = "1995-01-01 21:00:00", +#' TZone = "UTC", +#' # temporal aggregation +#' TResolution = "hour", +#' TStep = 6, +#' FUN = sum, +#' # spatial +#' Extent = Mountains_df, +#' Buffer = 0.2, +#' # file storing +#' FileName = "EnsembleSpreadSum6hour", +#' FileExtension = ".tif", +#' # API credentials +#' API_User = API_User, +#' API_Key = API_Key, +#' Keep_Raw = TRUE +#' ) +#' terra::plot(EnsembleSpreadSum6hour_rast) +#' } +#' @export +CDownloadS <- function(Variable = NULL, # which variable + CumulVar = FALSE, # cumulative variable? + DataSet = "reanalysis-era5-land", # data set + Type = NA, # type of data set + DateStart, DateStop, TZone = "UTC", # time-window, default set to range of dataset-type + TResolution = "month", TStep = 1, FUN = 'mean', # temporal aggregation + Extent, # spatial limitation, default set to range of dataset-type + Buffer = 0.5, # point buffering if desired + Dir = getwd(), FileName, FileExtension = ".nc", # file storing + API_User, API_Key, # API credentials + TryDown = 10, TimeOut = 36000, # Calls to CDS + TChunkSize = 6000, + Cores = 1, # parallelisation + verbose = TRUE, # verbosity + Keep_Raw = FALSE, + Save_Final = TRUE + ){ + ## Catching Most Frequent Issues =============== + #--- API Credentials + ### checking if API User and Key have been supplied + if(exists("API_User") + exists("API_Key") != 2){ + stop("Please provide a value for the API_User and API_Key arguments.") + } + ### making API_User into a character string + API_User <- as.character(API_User) + #--- Data set & Type + ### checking if a supported data set has been queried + if(!(DataSet %in% Meta.List())){ + stop("Please specify a supported dataset as the DataSet argument. Your options are:", + "\n", paste(Meta.List(), collapse = (" \n"))) + } + if(!(Type %in% Meta.QuickFacts(dataset = DataSet)$Type)){ + stop("Please specify a Type argument that is supported by your chosen data set. Your options are:", + "\n", paste(Meta.QuickFacts(dataset = DataSet)$Type, collapse = (" \n")), + "\n !! If you are seeing an NA on the above line, note that this is not an error. Please specify NA as the Type.") + } + #--- File Name and Extension + ### check if file name has been specified + if(!exists("FileName")){stop("Please provide a value for the FileName argument.")} + FileName <- paste0(file_path_sans_ext(FileName), FileExtension) + if(!(FileExtension %in% c(".nc", ".tif"))){stop("Please specify a FileExtension of either '.tif' or '.nc'")} + + #--- Time Zone + if(!(TZone %in% OlsonNames())){stop("The TZone argument you have specified is not supported. Please refer to OlsonNames() for an overview of all supported specifications.")} + + ## The Request ================================= + if(verbose){message("###### CDS Request & Data Download")} + + ### Building ===== + if(verbose){print("Building request")} + + #--- Name resolving + VarPos <- which(rowSums(Meta.Variables(dataset = DataSet)[,1:2] == Variable) != 0) + QueryVariable <- Meta.Variables(dataset = DataSet)[VarPos,"CDSname"] + + #--- Extent resolving; formatting as SpatExtent object + if(missing(Extent)){Extent <- ext(Meta.QuickFacts(dataset = DataSet)$CDSArguments$area)} ## assign maximum extent for dataset if not specified + if(class(Extent)[1] == "data.frame"){ + Extent <- Buffer.pts(USER_pts = Make.SpatialPoints(USER_df = Extent), + USER_buffer = Buffer) + } + QuerySpace <- Ext.Check(Extent) + QueryExtent <- QuerySpace$Ext[c(4,1,3,2)] #N,W,S,E + Extent <- QuerySpace$SpatialObj # terra/sf version of input extent to be used for easy cropping and masking + + #--- Base Dataset Information + BaseResolution <- Meta.QuickFacts(dataset = DataSet)$TResolution + BaseStep <- Meta.QuickFacts(dataset = DataSet)$TStep[ + na.omit(match(Type, Meta.QuickFacts(dataset = DataSet)$Type))] + BaseStart <- Meta.QuickFacts(dataset = DataSet)$TStart + + if(BaseResolution == "hour" & CumulVar){ + DateStop <- as.character(as.POSIXct(DateStop, tz = TZone)+1*60*60*24) # add one day to hourly pulls when cumulVar is turned on as an extra layer of data is needed for proper backcalculation + } + + #--- Time windows + Dates_df <- Make.UTC(DatesVec = c( + as.POSIXct(DateStart, tz = TZone), + as.POSIXct(DateStop, tz = TZone)) + ) + QueryTimeWindows <- Make.RequestWindows(Dates_df = Dates_df, + BaseTResolution = BaseResolution, + BaseTStep = 24/BaseStep, + BaseTStart = BaseStart, + TChunkSize = TChunkSize, + DataSet = DataSet + ) + QueryTimes <- QueryTimeWindows$QueryTimes + QueryTimeWindows <- QueryTimeWindows$QueryTimeWindows + + #--- Aggregation Check + QueryTargetSteps <- TemporalAggregation.Check( + QuerySeries = paste(unlist(lapply(QueryTimeWindows, as.character)), QueryTimes), + DateStart = Dates_df$UTC[1], + DateStop = Dates_df$UTC[2], + TResolution = TResolution, + BaseTResolution = BaseResolution, + TStep = TStep, + BaseTStep = BaseStep + ) + + ### Checking ===== + if(verbose){print("Checking request validity")} + + #--- Metadata check - can the queried dataset-type deliver the queried data? + MetaCheck_ls <- Meta.Check(DataSet = DataSet, + Type = Type, + VariableCheck = QueryVariable, + CumulativeCheck = CumulVar, + ExtentCheck = QueryExtent, + DateCheck = Dates_df, + AggrCheck = list(TStep, TResolution), + QueryTimes = QueryTimes) + + ## File/Call metadata + KrigRCall <- match.call() + KrigRCall <- KrigRCall[!(names(KrigRCall) %in% c("API_Key", "API_User"))] + Meta_vec <- as.character(KrigRCall) + names(Meta_vec) <- names(KrigRCall) + Meta_vec <- c( + "Citation" = paste0(MetaCheck_ls$QueryDataSet, " data (DOI:", Meta.DOI("reanalysis-era5-land-monthly-means"), ") obtained with KrigR (DOI:10.1088/1748-9326/ac48b3) on ", Sys.time()), + "KrigRCall" = Meta_vec + ) + + #--- File check, if already a file with this name present then load from disk + FCheck <- Check.File(FName = FileName, Dir = Dir, loadFun = terra::rast, load = TRUE, verbose = TRUE) + if(!is.null(FCheck)){ + if(FileExtension == ".nc"){ + FCheck <- Meta.NC(NC = FCheck, FName = file.path(Dir, FileName), Attrs = Meta_vec, Read = TRUE) + } + terra::time(FCheck) <- as.POSIXct(terra::time(FCheck), tz = TZone) # assign the correct time zone, when loading from disk, time zone is set to UTC + return(FCheck) + } + + ### Executing ===== + if(verbose){print("Executing request - Notice that time windows may vary slightly at this step due to timezone conversions. This will be resolved automatically.")} + #--- API credentials + Register.Credentials(API_User, API_Key) + #--- Make list of CDS Requests + Requests_ls <- Make.Request(QueryTimeWindows, + MetaCheck_ls$QueryDataSet, MetaCheck_ls$QueryType, MetaCheck_ls$QueryVariable, + QueryTimes, QueryExtent, MetaCheck_ls$QueryFormat, + Dir, verbose = TRUE, API_User, API_Key) + ## work an on.exit in here to allow restarting downloads themselves without new queries + #--- Execution of requests + Execute.Requests(Requests_ls, Dir, API_User, API_Key, TryDown, verbose = TRUE) + + ## The Data ================================= + if(verbose){message("###### Data Checking & Limitting & Aggregating")} + TempFs <- file.path(Dir, unlist(lapply(strsplit(names(Requests_ls), " "), "[[", 2))) + ## Checking ===== + if(verbose){print("Checking for known data issues")} + #--- layers + NLyrCheck <- unlist(lapply(TempFs, FUN = function(LayerCheckIter){ + nlyr(rast(LayerCheckIter)) + })) + NLyrIssue <- which(NLyrCheck != unlist(lapply(QueryTimeWindows, length))) + if(length(NLyrIssue) > 0){ + stop("Download of ", paste(basename(TempFs[NLyrIssue]), collapse = ", "), " produced file(s) of incorrect amount of layers. You may want to delete these files and try again. If the error persists. Please consult your queue on CDS: https://cds.climate.copernicus.eu/cdsapp#!/yourrequests. Alternatively, you may want to consult the corresponding download query/queries used behind the scenes:", paste(capture.output(str(Requests_ls[NLyrIssue])), collapse = "\n")) + } + + #--- Loading data + CDS_rast <- rast(TempFs) + terra::time(CDS_rast) <- as.POSIXct(terra::time(CDS_rast), tz = TZone) # assign time in queried timezone + ## subset to desired time + CDS_rast <- CDS_rast[[which(!(terra::time(CDS_rast) < Dates_df$IN[1] | terra::time(CDS_rast) > Dates_df$IN[2]))]] + + ## Spatial ===== + if(verbose){print("Spatial Limiting")} + CDS_rast <- Handle.Spatial(CDS_rast, Extent) + + ## Temporal ===== + if(verbose){print("Temporal Aggregation")} + #--- Cumulative Fix + CDS_rast <- Temporal.Cumul(CDS_rast, CumulVar, BaseResolution, BaseStep, TZone) + + #--- Temporal aggregation + CDS_rast <- Temporal.Aggr(CDS_rast, BaseResolution, BaseStep, + TResolution, TStep, FUN, Cores, QueryTargetSteps, TZone) + + ## Exports ================================= + if(verbose){message("###### Data Export & Return")} + + ### Assign additional information + terra::varnames(CDS_rast) <- MetaCheck_ls$QueryVariable + terra::units(CDS_rast) <- MetaCheck_ls$QueryUnit + terra::metags(CDS_rast) <- Meta_vec + + ### write file + if(Save_Final){ + if(FileExtension == ".tif"){ + terra::writeRaster(CDS_rast, filename = file.path(Dir, FileName)) + } + if(FileExtension == ".nc"){ + CDS_rast <- Meta.NC(NC = CDS_rast, FName = file.path(Dir, FileName), + Attrs = terra::metags(CDS_rast), Write = TRUE) + } + } + + ### unlink temporary files + if(!Keep_Raw){ + unlink(TempFs) + } + + ### return object + return(CDS_rast) +} diff --git a/R/Checks.R b/R/Checks.R new file mode 100644 index 0000000..0213ba7 --- /dev/null +++ b/R/Checks.R @@ -0,0 +1,121 @@ +### FILE EXISTENCE CHECKING ==================================================== +#' Checking if a file already exists +#' +#' If a file already exists in a given place, load that file +#' +#' @param FName File name +#' @param Dir Directory where to look for file +#' @param loadFun function with which to load filetype of FName +#' @param load Logical. Whether to load the data or not +#' @param verbose Logical. Whether to print/message function progress in console or not. +#' +#' @return Either a data object or NULL +#' +#' @examples +#' KrigR::Check.File( +#' FName = basename(system.file("extdata", "CentralNorway.nc", package="KrigR")), +#' Dir = dirname(system.file("extdata", "CentralNorway.nc", package="KrigR")), +#' loadFun = terra::rast +#' ) +#' @export +Check.File <- function(FName, Dir = getwd(), loadFun, load = TRUE, verbose = TRUE){ + FNAME <- file.path(Dir, FName) + file <- NULL + if(file.exists(FNAME)){ + if(verbose){print(paste0("A file with the name ", FName, " already exists in ", Dir, + "."))} + if(load){ + if(verbose){print("Loading this file for you from the disk.")} + file <- sapply(FNAME, loadFun)[[1]] + }else{ + file <- "Present. Not Loaded." + } + } + return(file) +} + +### KRIGING SANITY CHECK ======================================================= +#' Sanity checks before Kriging commences +#' +#' This function is called upon in the Kriging function and performs sanity checks for some of the most common error sources in kriging thereby attempting to return more sensible error messages to the user than what is returned by default. +#' +#' @param Data A SpatRaster object containing the data to be kriged. +#' @param CovariatesCoarse A SpatRaster object containing covariates for kriging at training resolution. +#' @param CovariatesFine A SPatRaster object containing covariates for kriging at target resolution. +#' @param KrigingEquation A formula object obtained from a character vector via as.formula() specifying the covariates to be used in kriging. The covariates used have to be present and named as layers in CovariatesCoarse and CovariatesFine. +#' +#' @importFrom terra res +#' @importFrom terra ext +#' @importFrom terra nlyr +#' @importFrom terra values +#' @importFrom terra varnames +#' +#' @return A list containing a potentially altered KrigingEquation if needed as well as an identifier for data layers which need to be skipped when kriging due to a variety of reasons. +#' +#' @seealso \code{\link{Kriging}}, \code{\link{KrigingCovariateSetup}}. +#' +Check.Krig <- function(Data, CovariatesCoarse, CovariatesFine, KrigingEquation){ + ## Resolutions =============== + if(terra::res(CovariatesFine)[1] < terra::res(Data)[1]/10){ + warning("It is not recommended to use kriging for statistical downscaling of more than one order of magnitude. You are currently attempting this. Kriging will proceed.") + } + if(all.equal(terra::res(CovariatesCoarse)[1], terra::res(Data)[1]) != TRUE){ + stop(paste0("The resolution of your data (", terra::res(Data)[1], ") does not match the resolution of your covariate data (", terra::res(CovariatesCoarse)[1], ") used for training the kriging model. Kriging can't be performed!" )) + } + ## Extent =============== + if(terra::ext(Data) == terra::ext(-180, 180, -90, 90)){ + stop("You are attempting to use kriging at a global extent. For reasons of computational expense and identity of relationships between covariates and variables not being homogenous across the globe, this is not recommended. Instead, try kriging of latitude bands if global kriging is really your goal.") + } + if(!all.equal(terra::ext(CovariatesCoarse), terra::ext(Data))){ + stop("The extents of your data and training covariates don't match. Kriging can't be performed!") + } + + ## Data Availability =============== + DataSkips <- NULL # data layers without enough data to be skipped in kriging + Data_vals <- base::colSums(matrix(!is.na(terra::values(Data)), ncol = terra::nlyr(Data))) # a value of 0 indicates a layer only made of NAs + if(length(which(Data_vals < 2)) > 0){ + if(length(which(Data_vals < 2)) != terra::nlyr(Data)){ + stop(paste0("Layer(s) ", paste(which(Data_vals == 0), collapse=", "), " of your data do(es) not contain enough data. Kriging cannot be performed. Usually, increasing the extent of kriging can fix this issue.")) + DataSkips <- which(Data_vals < 2) + }else{ + stop("Your Data does not contain enough values. Kriging cannot be performed. Usually, increasing the extent of kriging can fix this issue.") + } + } + CovCo_vals <- base::colSums(matrix(!is.na(terra::values(CovariatesCoarse)), ncol = terra::nlyr(CovariatesCoarse))) # a value of 0 indicates a layer only made of NAs + if(length(which(CovCo_vals < 2)) > 0){ + if(length(which(CovCo_vals < 2)) != terra::nlyr(CovariatesCoarse)){ + warning(paste0("Layer(s) ", paste(which(CovCo_vals < 2), collapse=", "), " of your covariates at training resolution do(es) not contain enough data. This/these layer(s) is/are dropped. The Kriging equation might get altered.")) + CovariatesCoarse <- CovariatesCoarse[[-which(CovCo_vals < 2)]] + }else{ + stop("Your covariate data at training resolution does not contain enough values. Kriging can't be performed!") + } + } + CovFin_vals <- base::colSums(matrix(!is.na(terra::values(CovariatesFine)), ncol = terra::nlyr(CovariatesFine))) # a value of 0 indicates a layer only made of NAs + if(length(which(CovFin_vals < 2)) > 0){ + if(length(which(CovFin_vals < 2)) != terra::nlyr(CovariatesFine)){ + warning(paste0("Layer(s) ", paste(which(CovFin_vals == 0), collapse=", "), " of your covariates at target resolution do(es) not contain enough data. This/these layer(s) is/are dropped.")) + CovariatesFine <- CovariatesFine[[-which(CovFin_vals < 2)]] + }else{ + stop("Your covariate data at target resolution does not contain enough values. Kriging can't be performed!") + } + } + ## Kriging Equation =============== + Terms <- unlist(strsplit(labels(terms(KrigingEquation)), split = ":")) # identify parameters called to in formula + Terms_Required <- unique(Terms) # isolate double-references (e.g. due to ":" indexing for interactions) + Terms_Present <- Reduce(intersect, list(Terms_Required, terra::varnames(CovariatesCoarse), terra::varnames(CovariatesFine))) # identify the terms that are available and required + if(sum(Terms_Required %in% Terms_Present) != length(Terms_Required)){ + if(length(Terms_Present) == 0){ # if none of the specified terms were found + KrigingEquation <- paste0("Data ~ ", paste(terra::varnames(CovariatesCoarse), collapse = "+")) + warn <- paste("None of the terms specified in your KrigingEquation are present in the covariate data sets. The KrigingEquation has been altered to include all available terms in a linear model:", "\n\n", KrigingEquation) + }else{ # at least some of the specified terms were found + KrigingEquation <- paste0("Data ~ ", paste(Terms_Present, collapse = "+")) + warn <- paste("Not all of the terms specified in your KrigingEquation are present in the covariate data sets. The KrigingEquation has been altered to include all available and specified terms in a linear model:", "\n\n", KrigingEquation) + } + Cotinue <- menu(c("Yes", "No"), title=paste0(warn, ". \n\nDo you wish to continue using the new formula?")) + if(Cotinue == 2){ # break operation if user doesn't want this + stop("Kriging terminated by user due to formula issues.") + } + } + ## Return data =============== + return(list(as.formula(KrigingEquation), DataSkips)) +} diff --git a/R/CovariateSetup.R b/R/CovariateSetup.R new file mode 100644 index 0000000..e84c4ef --- /dev/null +++ b/R/CovariateSetup.R @@ -0,0 +1,252 @@ +#' Preparing Covariate Data for Use in Kriging +#' +#' This function is used to setup products of covariate data ready for use in Kriging. This functiuonality can either be applied to user-supplied covariate data or ready-made data products such as the Harmised World Soil Data Base and the median statistic of the Global Multi-resolution Terrain Elevation Data (GMTED2010; available at \url{https://topotools.cr.usgs.gov/gmted_viewer/gmted2010_global_grids.php}). In case of the latter, the data is downloaded at 30 arc-sec latitude/longitude grid cells and subsequently resampled to match training and target resolutions specified by the user. +#' +#' @param Training A SpatRaster file containing the data which is to be downscaled. Covariate data will be resampled to match this. +#' @param Target Either numeric or a SpatRaster. If numeric, a single number representing the target resolution for the kriging step (i.e. wich resolution to downscale to). If a SpatRaster, data that the covariates and kriged products should align with. In case of a numeric input, covariate data is aggregated as closely as possible to desired resolution. If a SpatRaster, covariate data is resampled to match desired output directly. +#' @param Covariates Either character or a SpatRaster. If character, obtain frequently used and provably useful covariate data (i.e., GMTED2010 and HWSD) and prepare for use in Kriging. Supported character values are "GMTED2010" and "HWSD". Note that currently, HWSD data download is not functional. If a SpatRaster, a user-supplied set of covariate data to be prepared for use in Kriging. +#' @param Source Character. Only comes into effect when Covariates argument is specified as a character. Whether to attempt download of covariate data from the official sources (Source = "Origin") or a static copy of the data set on a private drive (Source = "Drive"). Default is "Origin". +#' @param Extent Optional, prepare covariate data according to desired spatial specification. If missing/unspecified, maximal area of supplied data and covariat sets is used. Can be specified either as a raster object, an sf object, a terra object, or a data.frame. If Extent is a raster or terra object, covariates will be prepared according to rectangular extent thereof. If Extent is an sf (MULTI-)POLYGON object, this will be treated as a shapefile and the output will be cropped and masked to this shapefile. If Extent is a data.frame of geo-referenced point records, it needs to contain Lat and Lon columns around which a buffered shapefile will be created using the Buffer argument. +#' @param Buffer Optional, Numeric. Identifies how big a circular buffer to draw around points if Extent is a data.frame of points. Buffer is expressed as centessimal degrees. +#' @param Dir Character/Directory Pointer. Directory specifying where to download data to. +#' @param Keep_Global Logical. Only comes into effect when Covariates argument is specified as a character. Whether to retain raw downloaded covariate data or not. Default is FALSE. +#' @param FileExtension Character. A file extension for the produced files. Supported values are ".nc" (default) and ".tif" (better support for metadata). +#' +#' @importFrom httr GET +#' @importFrom httr write_disk +#' @importFrom httr progress +#' @importFrom terra rast +#' @importFrom terra res +#' @importFrom terra ext +#' @importFrom terra values +#' @importFrom terra metags +#' @importFrom terra resample +#' @importFrom terra aggregate +#' @importFrom terra writeRaster +#' @importFrom terra writeCDF +#' @importFrom terra varnames +#' +#' @return A list containing two SpatRaster objects (Training and Target) ready to be used as covariates for kriging, and two files called Covariates_Target and Covariates_Train in the specified directory. +#' +#' The SpatRasters produced and stored when specifying the Covariates argument as a character string and setting the Keep_Global argument to TRUE contain metadata/attributes as a named vector that can be retrieved with terra::metags(...): +#' \itemize{ +#' \item{Citation}{ - A string which to use for in-line citation of the data product.} +#' } +#' +#' @seealso \code{\link{Kriging}}. +#' +#' @examples +#' \dontrun{ +#' ## Rectangular Covariate data according to input data +#' CDS_rast <- terra::rast(system.file("extdata", "CentralNorway.nc", package="KrigR")) +#' Covariates_ls <- CovariateSetup(Training = CDS_rast, +#' Target = 0.01, +#' Covariates = "GMTED2010", +#' Keep_Global = TRUE, +#' FileExtension = ".nc") +#' terra::plot(Covariates_ls[[1]]) +#' terra::plot(Covariates_ls[[2]]) +#' +#' ## Shapefile-limited covariate data +#' data("Jotunheimen_poly") +#' CDS_rast <- terra::rast(system.file("extdata", "CentralNorway.nc", package="KrigR")) +#' Covariates_ls <- CovariateSetup(Training = CDS_rast, +#' Target = 0.01, +#' Covariates = "GMTED2010", +#' Extent = Jotunheimen_poly, +#' Keep_Global = TRUE, +#' FileExtension = ".nc") +#' terra::plot(Covariates_ls[[1]]) +#' terra::plot(Covariates_ls[[2]]) +#' +#' ## buffered-point-limited covariate data +#' data("Mountains_df") +#' CDS_rast <- terra::rast(system.file("extdata", "CentralNorway.nc", package="KrigR")) +#' Covariates_ls <- CovariateSetup(Training = CDS_rast, +#' Target = 0.01, +#' Covariates = "GMTED2010", +#' Extent = Mountains_df, +#' Buffer = 0.2, +#' Keep_Global = TRUE, +#' FileExtension = ".nc") +#' terra::plot(Covariates_ls[[1]]) +#' terra::plot(Covariates_ls[[2]]) +#' } +#' @export +CovariateSetup <- function(Training, + Target, + Covariates = "GMTED2010", + Source = "Origin", + Extent, + Buffer = 0.5, + Dir = getwd(), + Keep_Global = FALSE, + FileExtension = ".nc" + ){ + ## Catching Most Frequent Issues =============== + if(class(Covariates) == "character"){ + if(sum(!(Covariates %in% c("GMTED2010", "HWSD"))) > 0){ + stop("Please specify a valid covariate data set. You may supply either the character string 'GMTED2010' or 'HWSD', or a SpatRaster object.") + } + if("HWSD" %in% Covariates){ + stop("HWSD download currently not supported. We are working on it.") + } + if(length(Source) > 1){ + stop("Please specify only one source type for the covariate data that will be downloaded. You may specify either 'Origin' or 'Drive'.") + } + if(!(Source %in% c("Origin", "Drive"))){ + stop("Please specify a valid source type for the covariate data that will be downloaded. You may specify either 'Origin' or 'Drive'.") + } + } + + ## Links for Data download =============== + Links_df <- data.frame( + Cov = rep(c("GMTED2010", "HWSD"), each = 2), + Source = rep(c("Origin", "Drive")), + UnzippedFile = rep(c("mn30_grd/w001001.adf", "NULL"), each = 2), + DOI = rep(c("10.3133/ofr20111073", "NULL"), each = 2), + Link = c( + "https://edcintl.cr.usgs.gov/downloads/sciweb1/shared/topo/downloads/GMTED/Grid_ZipFiles/mn30_grd.zip", # Link to GMTED2010 + "https://www.dropbox.com/s/whkje7jc401xuwx/GMTED2010.zip?raw=1", # Link to DropBox with GMTED2010 + NULL, # Link to Harmonized World Soil Database v2.0 + NULL # Link to DropBox with GMTED2010 + ) + ) + + ## Data Download (skipped if own SpatRaster supplied) =============== + if(class(Covariates) == "character"){ + CovariatesIn <- Covariates + ### Directory for raw files + Dir.Covs <- file.path(Dir, "CovariateSetup") + if(!dir.exists(Dir.Covs)){dir.create(Dir.Covs)} + + ### Data downloads + Data_ls <- lapply(Covariates, FUN = function(Cov_iter){ + + #### Figure out which link to use + Match_vec <- sapply(1:nrow(Links_df), FUN = function(x){ + sum(Links_df$Cov[x] == Cov_iter, Links_df$Source[x] == Source) + }) + + #### Store link and name for download + Link <- Links_df$Link[Match_vec == 2] + Name <- Links_df$Cov[Match_vec == 2] + UnzippedFile <- Links_df$UnzippedFile[Match_vec == 2] + DOI <- Links_df$DOI[Match_vec == 2] + FName <- paste0(Name, FileExtension) + + #### Metadata + Meta_vec <- paste0(Name, " data (DOI: ", DOI, ") downloaded: ", Sys.time(), " using KrigR from ", Source) + names(Meta_vec) <- "Citation" + + #### Check if data is already present + Data <- Check.File(FName = FName, Dir = Dir, loadFun = terra::rast, load = TRUE, verbose = FALSE) + if(!is.null(Data) & FileExtension == ".nc"){ + Data <- Meta.NC(NC = Data, FName = file.path(Dir, FName), Attrs = Meta_vec, Read = TRUE) + } + + if(is.null(Data)){ + #### Downloading data + message("Downloading ", Name, " covariate data.") # inform user of download in console + httr::GET(Link, + httr::write_disk(file.path(Dir.Covs, paste0(Name, ".zip"))), + httr::progress(), overwrite = TRUE) + + #### Unzipping data + unzip(file.path(Dir.Covs, paste0(Name, ".zip")), # which file to unzip + exdir = Dir.Covs) # where to unzip to + + #### Loading data + Data <- terra::rast(file.path(Dir.Covs, UnzippedFile)) + if(class(terra::values(Data)[,1]) == "integer"){ + print("Reformatting integer data into continuous numeric data.") + Data <- Data+0 # +0 to avoid integer reading in faulty way, https://gis.stackexchange.com/questions/398061/reading-rasters-in-r-using-terra-package + } + terra::metags(Data) <- Meta_vec + terra::varnames(Data) <- Name + + #### Saving data as single file + if(FileExtension == ".tif"){ + terra::writeRaster(Data, filename = file.path(Dir, FName)) + } + if(FileExtension == ".nc"){ + Data <- Meta.NC(NC = Data, FName = file.path(Dir, FName), + Attrs = terra::metags(Data), Write = TRUE) + } + + }else{ + message("Raw ", Name, " covariate data already downloaded.") + } + Data + }) + Covariates <- do.call(c, Data_ls) + unlink(Dir.Covs, recursive = TRUE) + } + VarNames <- terra::varnames(Covariates) + + ## Spatial Limitting =============== + ### Extent Handling + if(missing("Extent")){ ## assign maximum extent of supplied data and covariates (only when no extent is specified) + Extent <-terra::ext( + ifelse(terra::ext(Training)[1] > terra::ext(Covariates)[1], terra::ext(Training)[1], terra::ext(Covariates)[1]), + ifelse(terra::ext(Training)[2] < terra::ext(Covariates)[2], terra::ext(Training)[2], terra::ext(Covariates)[2]), + ifelse(terra::ext(Training)[3] > terra::ext(Covariates)[3], terra::ext(Training)[3], terra::ext(Covariates)[3]), + ifelse(terra::ext(Training)[4] < terra::ext(Covariates)[4], terra::ext(Training)[4], terra::ext(Covariates)[4]) + ) + } + if(class(Extent)[1] == "data.frame"){ + Extent <- Buffer.pts(USER_pts = Make.SpatialPoints(USER_df = Extent), + USER_buffer = Buffer) + } + QuerySpace <- Ext.Check(Extent) + Extent <- QuerySpace$SpatialObj # terra/sf version of input extent to be used for easy cropping and masking + + ## Spatial Aggregation/Resampling =============== + ### Sanity Check + if(class(Target) == "numeric"){ + Target_res <- Target[1] + }else{ + Target_res <- terra::res(Target) + } + if(Target_res < terra::res(Covariates)[1]){ + stop(paste0("You have specified resolution(s) to be finer than ", res(GMTED2010_ras), " (native GMTED2010 reslution). Please download higher-resolution DEM data instead.")) + } + ### Resampling + Cov_train <- terra::resample(Covariates, Training) + if(class(Extent)[1] == "SpatRaster"){ + Cov_target <- terra::resample(Covariates, Extent) + }else{ + Cov_target <- suppressWarnings(terra::aggregate(Covariates, fact = Target_res[1]/terra::res(Covariates)[1])) + } + ### Cropping and Masking + Training <- Handle.Spatial(BASE = Training, Shape = Extent) + Cov_train <- Handle.Spatial(Cov_train, Extent) + Cov_target <- Handle.Spatial(Cov_target, Extent) + + ## Data Saving & Export =============== + TrainName <- file.path(Dir, paste0("Covariates_Train", FileExtension)) + TargetName <- file.path(Dir, paste0("Covariates_Target", FileExtension)) + if(FileExtension == ".tif"){ + terra::writeRaster(x = Cov_train, filename = TrainName, overwrite = TRUE) + terra::writeRaster(x = Cov_target, filename = TargetName, overwrite = TRUE) + } + if(FileExtension == ".nc"){ + terra::writeCDF(x = Cov_train, filename = TrainName, overwrite = TRUE) + terra::writeCDF(x = Cov_target, filename = TargetName, overwrite = TRUE) + } + + ## Cleaning up files =============== + if(!Keep_Global){ # cleanup check + unlink(list.files(Dir, pattern = paste0(CovariatesIn, FileExtension), full.names = TRUE)) + } + + ## Return data =============== + TrainRet <- terra::rast(TrainName) + TargetRet <- terra::rast(TargetName) + terra::varnames(TrainRet) <- terra::varnames(TargetRet) <- VarNames + + return( + list(Training = TrainRet, + Target = TargetRet) + ) +} diff --git a/R/Kriging.R b/R/Kriging.R index 3a673a0..fd5ad48 100644 --- a/R/Kriging.R +++ b/R/Kriging.R @@ -1,305 +1,316 @@ #' (multi-core) Kriging #' -#' This function statistically downscales input data using covariate data and the kriging methodology. The function can be run in two ways: -#' \enumerate{ -#' \item \strong{By Itself}: Use the arguments Data, Covariates_coarse, Covariates_fine when you already have raster files for your data which is to be downscaled as well as covariate raster data. -#' \item \strong{From Scratch}: Use the arguments Variable, Type, DataSet, DateStart, DateStop, TResolution, TStep, Extent, Dir, FileName, API_Key, API_User, and arget_res. By doing so, krigR will call the functions download_ERA() and download_DEM() for one coherent kriging workflow. Note that this process does not work when targetting UERRA data. -#' } -#' Use optional arguments such as Dir, FileName, Keep_Temporary, SingularTry, KrigingEquation and Cores for ease of use, substitution of non-GMTED2010 covariates, and parallel processing. +#' This function statistically downscales input data using covariate data and the kriging methodology. +#' Use optional arguments such as Dir, Keep_Temporary, KrigingEquation, nmax and Cores for ease of use, substitution of non-default covariates, localisation of kriging, and parallel processing. #' -#' @param Data Raster file which is to be downscaled. -#' @param Covariates_coarse Raster file containing covariates at training resolution. -#' @param Covariates_fine Raster file containing covariates at target resolution. -#' @param KrigingEquation Formula or character string specifying which covariates to use and how. Layer names in Covariates_coarse and Covariates_fine need to match Parameters in this formula. Needs to start with "X ~ ". X can read anything you like. -#' @param Dir Optional. Directory specifying where to place final kriged product. Default is current working directory. -#' @param FileName Optional. A file name for the netcdf produced. Default is a combination parameters in the function call. -#' @param Keep_Temporary Logical, whether to delete individual kriging products of layers in Data after processing. Default is TRUE. -#' @param Cores Numeric. How many cores to use. If you want output to your console during the process, use Cores == 1. Parallel processing is carried out when Cores is bigger than 1. Default is detecting all cores of your machine. -#' @param SingularTry Numeric. How often to try kriging of each layer of the input. This usually gets around issues of singular covariance matrices in the kriging process, but takes some time. Default is 10 -#' @param Variable Optional, calls download_ERA(). ERA5(Land)-contained climate variable. -#' @param PrecipFix Optional. Era5(-land) total precipitation is recorded in cumulative steps per hour from the 00:00 time mark per day. Setting PrecipFix to TRUE converts these into records which represent the total precipitation per hour. Monthly records in Era5(-land) express the average daily total precipitation. Setting this argument to TRUE multiplies monthly records by the number of days per the respective month(s) to get to total precipitation records instead of average. Default is FALSE. -#' @param Type Optional. Whether to download reanalysis ('reanalysis') or ensemble ('ensemble_members', 'ensemble_mean', or 'ensemble_spread') data. Passed on to download_ERA. -#' @param DataSet Optional. Which ERA5 data set to download data from. 'era5' or 'era5-land'. Passed on to download_ERA. -#' @param DateStart Optional. Date ('YYYY-MM-DD') at which to start time series of downloaded data. Passed on to download_ERA. -#' @param DateStop Optional. Date ('YYYY-MM-DD') at which to stop time series of downloaded data. Passed on to download_ERA. -#' @param TResolution Optional. Temporal resolution of final product. hour', 'day', 'month'. Passed on to download_ERA. -#' @param TStep Optional. Which time steps (numeric) to consider for temporal resolution. Passed on to download_ERA. -#' @param FUN Optional. A raster calculation argument as passed to `raster::stackApply()`. This controls what kind of data to obtain for temporal aggregates of reanalysis data. Specify 'mean' (default) for mean values, 'min' for minimum values, and 'max' for maximum values, among others. -#' @param Extent Optional, download data according to rectangular bounding box. specify as extent() object or as a raster, a SpatialPolygonsDataFrame object, or a data.frame object. If Extent is a SpatialPolygonsDataFrame, this will be treated as a shapefile and the output will be cropped and masked to this shapefile. If Extent is a data.frame of geo-referenced point records, it needs to contain Lat and Lon columns as well as a non-repeating ID-column. Passed on to download_ERA and download_DEM. -#' @param Buffer Optional. Identifies how big a rectangular buffer to draw around points if Extent is a data frame of points. Buffer is expressed as centessimal degrees. Passed on to download_ERA and download_DEM. -#' @param ID Optional. Identifies which column in Extent to use for creation of individual buffers if Extent is a data.frame. Passed on to download_ERA and download_DEM. -#' @param Target_res Optional. The target resolution for the kriging step (i.e. which resolution to downscale to). An object as specified/produced by raster::res(). Passed on to download_DEM. -#' @param Source Optional, character. Whether to attempt download from the official USGS data viewer (Source = "USGS") or a static copy of the data set on a private drive (Source = "Drive"). Default is "USGS". Use this if the USGS viewer is unavailable. Passed on to download_DEM. -#' @param API_Key Optional. ECMWF cds API key. Passed on to download_ERA. -#' @param API_User Optional. ECMWF cds user number. Passed on to download_ERA. -#' @param nmax Optional. Controls local kriging. Number of nearest observations to be used kriging of each observation. Default is to use all available (Inf). You can specify as a number (numeric). -#' @param TryDown Optional, numeric. How often to attempt the download of each individual file (if querying data download) that the function queries from the server. This is to circumvent having to restart the entire function when encountering connectivity issues. +#' @param Data SpatRaster which is to be downscaled. +#' @param Covariates_training SpatRaster containing covariates at training resolution. +#' @param Covariates_target SpatRaster containing covariates at target resolution. +#' @param Equation Formula or character string specifying which covariates to use and how. Layer names in Covariates_training and Covariates_target need to match parameters in this formula. Do not include ". ~", just supply the righthand side of this formula like so: "Covariate1+Covariate2" or "Covariate1*Covariate2", etc. +#' @param Cores Numeric. How many cores to use. Parallel processing is carried out when Cores is bigger than 1. Default is detecting all cores of your machine. +#' @param nmax NUmeric. Controls local kriging. Number of nearest observations to be used kriging of each observation. Default is to use all available (Inf). You can specify as a number (numeric). +#' @param Dir Character/Directory Pointer. Directory specifying where to place final kriged product. Default is current working directory. +#' @param FileName Character. A file name for the produced files. +#' @param FileExtension Character. A file extension for the produced file. Supported values are ".nc" (default) and ".tif" (better support for metadata). +#' @param Keep_Temporary Logical, whether to delete individual kriging products of layers in Data after processing. Default is TRUE. These temporary files are stored in a newly created directory in Dir which is pre-pended with "TEMP-" and is deleted if Keep_Temporary = FALSE upon completion. #' @param verbose Optional, logical. Whether to report progress of data download (if queried) in the console or not. -#' @param TimeOut Numeric. The timeout for each download in seconds. Default 36000 seconds (10 hours). -#' @param SingularDL Logical. Whether to force download of data in one call to CDS or automatically break download requests into individual monthly downloads. Default is FALSE. -#' @return A list object containing the downscaled data as well as the standard error for downscaling as well as the call to the krigR function, and two NETCDF (.nc) file in the specified directory which are the two data contents of the aforementioned list. A temporary directory is populated with individual NETCDF (.nc) files throughout the runtime of krigR which is deleted upon completion if Keep_Temporary = TRUE and all layers in the Data raster object were kriged successfully. +#' +#' @importFrom progress progress_bar +#' @importFrom terra nlyr +#' @importFrom terra crs +#' @importFrom terra varnames +#' @importFrom tools file_path_sans_ext +#' @importFrom terra rast +#' @importFrom terra units +#' @importFrom terra metags +#' @importFrom terra writeRaster +#' @importFrom terra writeCDF +#' @importFrom terra time +#' @importFrom sf st_as_sf +#' @importFrom sf st_drop_geometry +#' @importFrom sf st_coordinates +#' @importFrom sf st_as_sf +#' @importFrom automap autoKrige +#' @importFrom stringr str_pad +#' @importFrom doSNOW registerDoSNOW +#' @importFrom parallel makeCluster +#' @importFrom parallel stopCluster +#' @importFrom foreach %dopar% +#' @importFrom foreach foreach +#' +#' @return A list object containing SpatRasters reporting (1) the downscaled data as well as (2) the standard deviation for downscaling. Also produces two files of specified extension in the specified directory which are the two data contents of the aforementioned list. A temporary directory is populated with individual files during the execution of this function which is deleted upon completion if Keep_Temporary = FALSE and all layers in the Data raster object were kriged successfully. +#' +#' The produced SpatRasters contains metadata/attributes as a named vector that can be retrieved with terra::metags(...): +#' \itemize{ +#' \item{Citation}{ - A string which to use for in-line citation of the data product obtained with Kriging}. +#' \item{KrigRCall.X}{ - Arguments passed to the Kriging function that produced the file}. +#' } +#' +#' \strong{ATTENTION:} If data is loaded again from disk at a later point with a different function, take note that citation and KrigR-call metadata will not be loaded properly from a .nc when loading data through a different function. Kriging() handles these .nc specific issues when loading .nc files created previously with Kriging() from disk. +#' +#' @seealso \code{\link{CovariateSetup}}. +#' #' @examples #' \dontrun{ -#' ## THREE-STEP PROCESS (By Itself) -#' # Downloading ERA5-Land air temperature reanalysis data in 12-hour intervals for 02/01/1995 - 04/01/1995 (DD/MM/YYYY). API User and Key in this example are non-functional. Substitute with your user number and key to run this example. -#' Extent <- extent(c(11.8,15.1,50.1,51.7)) # roughly the extent of Saxony -#' API_User <- "..." -#' API_Key <- "..." -#' State_Raw <- download_ERA( -#' Variable = "2m_temperature", -#' DataSet = "era5-land", -#' DateStart = "1995-01-02", -#' DateStop = "1995-01-04", -#' TResolution = "hour", -#' TStep = 12, -#' Extent = Extent, -#' API_User = API_User, -#' API_Key = API_Key +#' ## Kriging using pre-fab data with a rectangular extent and a fives layers of data with parallel processing +#' ### Loading data +#' CDS_rast <- terra::rast(system.file("extdata", "CentralNorway.nc", package="KrigR")) +#' Cov_train <- terra::rast(system.file("extdata", "Covariates_Train.nc", package="KrigR")) +#' Cov_target <- terra::rast(system.file("extdata", "Covariates_Target.nc", package="KrigR")) +#' terra::varnames(Cov_train) <- terra::varnames(Cov_target) <- "GMTED2010" # we must ensure that the varnames in the Covariate file match +#' ### kriging itself +#' ExtentKrig <- Kriging( +#' Data = CDS_rast, +#' Covariates_training = Cov_train, +#' Covariates_target = Cov_target, +#' Equation = "GMTED2010", +#' Cores = 2, +#' FileName = "KrigTest1", +#' FileExtension = ".nc", +#' Keep_Temporary = TRUE, +#' nmax = 40, +#' verbose = TRUE #' ) -#' State_Raw # a raster brick with 6 layers at resolution of ~0.1° -#' # Downloading GMTED2010-data at resolution and extent obtained by a call to download_ERA and a target resolution of .02. -#' Covs_ls <- download_DEM( -#' Train_ras = State_Raw, -#' Target_res = .02, -#' Keep_Temporary = TRUE -#' ) -#' Covs_ls # a list with two elements: (1) GMTED 2010 data at training resolution, and (2) GMTED 2010 data aggregated as close as possible to a resolution of 0.02 -#' # Kriging the data sets prepared with the previous functions. -#' State_Krig <- krigR( -#' Data = State_Raw, # data we want to krig as a raster object -#' Covariates_coarse = Covs_ls[[1]], # training covariate as a raster object -#' Covariates_fine = Covs_ls[[2]], # target covariate as a raster object +#' +#' ## Kriging using full KrigR pipeline with shapefile data +#' ### Shapefile loading +#' data("Jotunheimen_poly") +#' ### CDS data download +#' Qsoil_rast <- CDownloadS( +#' Variable = "Volumetric soil water layer 1", # can also specify as "volumetric_soil_water_layer_1" +#' # time-window, default set to range of dataset-type +#' DateStart = "1995-01-01 00:00", +#' DateStop = "1995-01-03 23:00", +#' TZone = "CET", +#' # temporal aggregation +#' TResolution = "day", +#' # spatial +#' Extent = Jotunheimen_poly, +#' # file storing +#' FileName = "KrigTest2_Raw", +#' # API credentials +#' API_User = API_User, +#' API_Key = API_Key #' ) #' -#' ## PIPELINE (From Scratch) -#' #' # Downloading ERA5-Land air temperature reanalysis data in 12-hour intervals for 02/01/1995 - 04/01/1995 (DD/MM/YYYY), downloading and preparing GMTED 2010 covariate data, and kriging. API User and Key in this example are non-functional. Substitute with your user number and key to run this example. This example produces the same output as the example above. -#' Extent <- extent(c(11.8,15.1,50.1,51.7)) # roughly the extent of Saxony -#' API_User <- "..." -#' API_Key <- "..." -#' Pipe_Krig <- krigR( -#' Variable = "2m_temperature", -#' Type = "reanalysis", -#' DataSet = "era5-land", -#' DateStart = "1995-01-02", -#' DateStop = "1995-01-04", -#' TResolution = "hour",# -#' TStep = 12, -#' Extent = Extent, -#' API_User = API_User, -#' API_Key = API_Key, -#' Target_res = .02, +#' ### Covariate preparations +#' Covariates_ls <- CovariateSetup(Training = Qsoil_rast, +#' #' Target = 0.03, +#' Covariates = "GMTED2010", # this shiuld really be HWSD +#' Extent = Jotunheimen_poly, +#' Keep_Global = TRUE) +#' terra::varnames(Covariates_ls[[1]]) <- terra::varnames(Covariates_ls[[2]]) <- "GMTED2010" # we must ensure that the varnames in the Covariate file match +#' +#' ### kriging itself +#' ShapeKrig <- Kriging( +#' Data = Qsoil_rast, +#' Covariates_training = Covariates_ls[[1]], +#' Covariates_target = Covariates_ls[[2]], +#' Equation = "GMTED2010", +#' Cores = 1, +#' FileName = "KrigTest2", +#' FileExtension = ".nc", +#' Keep_Temporary = FALSE, +#' nmax = 40, +#' verbose = TRUE #' ) #' } -#' #' @export -krigR <- function(Data = NULL, Covariates_coarse = NULL, Covariates_fine = NULL, KrigingEquation = "ERA ~ DEM", Cores = detectCores(), Dir = getwd(), FileName, Keep_Temporary = TRUE, SingularTry = 10, Variable, PrecipFix = FALSE, Type = "reanalysis", DataSet = "era5-land", DateStart, DateStop, TResolution = "month", TStep = 1, FUN = 'mean', Extent, Buffer = 0.5, ID = "ID", API_Key, API_User, Target_res, Source = "USGS", nmax = Inf, TryDown = 10, verbose = TRUE, TimeOut = 36000, SingularDL = FALSE, ...){ - ## CALL LIST (for storing how the function as called in the output) ---- - if(is.null(Data)){ - Data_Retrieval <- list(Variable = Variable, - Type = Type, - PrecipFix = PrecipFix, - DataSet = DataSet, - DateStart = DateStart, - DateStop = DateStop, - TResolution = TResolution, - TStep = TStep, - Extent = Extent) - }else{ - Data_Retrieval <- "None needed. Data was not queried via krigR function, but supplied by user." - } - ## CLIMATE DATA (call to download_ERA function if no Data set is specified) ---- - if(is.null(Data)){ # data check: if no data has been specified - Data <- download_ERA(Variable = Variable, PrecipFix = PrecipFix, Type = Type, DataSet = DataSet, DateStart = DateStart, DateStop = DateStop, TResolution = TResolution, TStep = TStep, FUN = FUN, Extent = Extent, API_User = API_User, API_Key = API_Key, Dir = Dir, TryDown = TryDown, verbose = verbose, ID = ID, Cores = Cores, TimeOut = TimeOut, SingularDL = SingularDL) - } # end of data check - - ## COVARIATE DATA (call to download_DEM function when no covariates are specified) ---- - if(is.null(Covariates_coarse) & is.null(Covariates_fine)){ # covariate check: if no covariates have been specified - if(class(Extent) == "SpatialPolygonsDataFrame" | class(Extent) == "data.frame"){ # Extent check: if Extent input is a shapefile - Shape <- Extent # save shapefile for use as Shape in masking covariate data - }else{ # if Extent is not a shape, then extent specification is already baked into Data - Shape <- NULL # set Shape to NULL so it is ignored in download_DEM function when masking is applied - } # end of Extent check - Covs_ls <- download_DEM(Train_ras = Data, Target_res = Target_res, Shape = Shape, Buffer = Buffer, ID = ID, Keep_Temporary = Keep_Temporary, Dir = Dir, Source = Source) - Covariates_coarse <- Covs_ls[[1]] # extract coarse covariates from download_DEM output - Covariates_fine <- Covs_ls[[2]] # extract fine covariates from download_DEM output - } # end of covariate check - - ## KRIGING FORMULA (assure that KrigingEquation is a formula object) ---- - KrigingEquation <- as.formula(KrigingEquation) +Kriging <- function( + Data, + Covariates_training, + Covariates_target, + Equation = NULL, + Cores = detectCores(), + nmax = Inf, + Dir = getwd(), + FileName, + FileExtension, + Keep_Temporary = FALSE, + verbose = TRUE + ){ + ## Run Preparations =============== + ### Number of layers in data & Progress bar + KrigIterations <- nlyr(Data) # used for krig looping + pb <- progress_bar$new( + format = "Kriging (:current/:total) | [:bar] Elapsed: :elapsed | Remaining: :eta", + total = KrigIterations, # 100 + width = getOption("width")) + progress_layer <- 1:KrigIterations # token reported in progress bar + ### CRS for assignment in loop + CRS_dat <- crs(Data) + ### if no equation is specified, assign additive combination of variables in training covariates + if(is.null(Equation)){Equation <- paste(terra::varnames(Covariates_training), collapse = " + ")} + ### assure that KrigingEquation is a formula object + KrigingEquation <- as.formula(paste("Data ~", Equation)) + ### Metadata + KrigRCall <- match.call() + Meta_vec <- as.character(KrigRCall) + names(Meta_vec) <- names(KrigRCall) + Meta_vec <- c( + "Citation" = paste0("Data kriged using KrigR (DOI:10.1088/1748-9326/ac48b3) on ", Sys.time()), + "KrigRCall" = Meta_vec + ) + ### Temporary Directory + Dir.Temp <- file.path(Dir, paste("TEMP-Kriging", FileName, sep="_")) + if(!dir.exists(Dir.Temp)){dir.create(Dir.Temp)} + ### Remove extension from file name + FileName <- file_path_sans_ext(FileName) - ## CALL LIST (for storing how the function as called in the output) ---- - Call_ls <- list(Data = SummarizeRaster(Data), - Covariates_coarse = SummarizeRaster(Covariates_coarse), - Covariates_fine = SummarizeRaster(Covariates_fine), - KrigingEquation = KrigingEquation, - Cores = Cores, - FileName = FileName, - Keep_Temporary = Keep_Temporary, - nmax = nmax, - Data_Retrieval = Data_Retrieval) + ## Check if already executed once =============== + FCheck1 <- Check.File(FName = paste0(FileName, "_Kriged", FileExtension), Dir = Dir, loadFun = terra::rast, load = TRUE, verbose = TRUE) + FCheck2 <- Check.File(FName = paste0(FileName, "_StDev", FileExtension), Dir = Dir, loadFun = terra::rast, load = TRUE, verbose = TRUE) + if(!is.null(FCheck1)){ + if(FileExtension == ".nc"){ + FCheck1 <- Meta.NC(NC = FCheck1, FName = file.path(Dir, paste0(FileName, "_Kriged.nc")), Attrs = Meta_vec, Read = TRUE) + FCheck2 <- Meta.NC(NC = FCheck2, FName = file.path(Dir, paste0(FileName, "_StDev.nc")), Attrs = Meta_vec, Read = TRUE) + } + terra::time(FCheck1) <- terra::time(FCheck2) <- terra::time(Data) + terra::varnames(FCheck1) <- terra::varnames(FCheck2) <- terra::varnames(Data) + terra::units(FCheck1) <- terra::units(FCheck2) <- terra::units(Data) + terra::metags(FCheck1) <- terra::metags(FCheck2) <- Meta_vec + Krig_ls <- list(FCheck1, FCheck2) + names(Krig_ls) <- c("Prediction", "StDev") + return(Krig_ls) + } - ## SANITY CHECKS (step into check_Krig function to catch most common error messages) ---- - Check_Product <- check_Krig(Data = Data, CovariatesCoarse = Covariates_coarse, CovariatesFine = Covariates_fine, KrigingEquation = KrigingEquation) + ## Catching Most Frequent Issues =============== + Check_Product <- Check.Krig(Data = Data, CovariatesCoarse = Covariates_training, CovariatesFine = Covariates_target, KrigingEquation = KrigingEquation) KrigingEquation <- Check_Product[[1]] # extract KrigingEquation (this may have changed in check_Krig) - DataSkips <- Check_Product[[2]] # extract which layers to skip due to missing data (this is unlikely to ever come into action) + # DataSkips <- Check_Product[[2]] # extract which layers to skip due to missing data (this is unlikely to ever come into action) Terms <- unique(unlist(strsplit(labels(terms(KrigingEquation)), split = ":"))) # identify which layers of data are needed - ## DATA REFORMATTING (Kriging requires spatially referenced data frames, reformatting from rasters happens here) --- - Origin <- raster::as.data.frame(Covariates_coarse, xy = TRUE) # extract covariate layers + ## Data Reformatting =============== + # (Kriging requires spatially referenced data frames, reformatting from rasters happens here) + ### Make Training sf object + Origin <- as.data.frame(Covariates_training, xy = TRUE, na.rm = FALSE) + colnames(Origin)[-1:-2] <- terra::varnames(Covariates_training) Origin <- Origin[, c(1:2, which(colnames(Origin) %in% Terms))] # retain only columns containing terms - - Target <- raster::as.data.frame(Covariates_fine, xy = TRUE) # extract covariate layers + Origin <- st_as_sf(Origin, coords = c("x", "y")) + ### Make Target sf object + Target <- as.data.frame(Covariates_target, xy = TRUE) + colnames(Target)[-1:-2] <- terra::varnames(Covariates_target) Target <- Target[, c(1:2, which(colnames(Target) %in% Terms))] # retain only columns containing terms - Target <- na.omit(Target) - suppressWarnings(gridded(Target) <- ~x+y) # establish a gridded data product ready for use in kriging - Target@grid@cellsize[1] <- Target@grid@cellsize[2] # ensure that grid cells are square + Target <- st_as_sf(Target, coords = c("x", "y")) + ### Make data into data frame for handling in parallel (SpatRasters cannot be used in foreach) + Data_df <- as.data.frame(Data, xy = TRUE, na.rm = FALSE) - ## SET-UP TEMPORARY DIRECTORY (this is where kriged products of each layer will be saved) ---- - Dir.Temp <- file.path(Dir, paste("Kriging", FileName, sep="_")) - if(!dir.exists(Dir.Temp)){dir.create(Dir.Temp)} - - ## KRIGING SPECIFICATION (this will be parsed and evaluated in parallel and non-parallel evaluations further down) ---- + ## Kriging Specification =============== + # (this will be parsed and evaluated in parallel and non-parallel evaluations further down) looptext <- " - OriginK <- cbind(Origin, raster::extract(x = Data[[Iter_Krige]], y = Origin[,1:2], df=TRUE)[, 2]) # combine data of current data layer with training covariate data - OriginK <- na.omit(OriginK) # get rid of NA cells - colnames(OriginK)[length(Terms)+3] <- c(terms(KrigingEquation)[[2]]) # assign column names - suppressWarnings(gridded(OriginK) <- ~x+y) # generate gridded product - OriginK@grid@cellsize[1] <- OriginK@grid@cellsize[2] # ensure that grid cells are square - - Iter_Try = 0 # number of tries set to 0 - kriging_result <- NULL - while(class(kriging_result)[1] != 'autoKrige' & Iter_Try < SingularTry){ # try kriging SingularTry times, this is because of a random process of variogram identification within the automap package that can fail on smaller datasets randomly when it isn't supposed to - try(invisible(capture.output(kriging_result <- autoKrige(formula = KrigingEquation, input_data = OriginK, new_data = Target, nmax = nmax))), silent = TRUE) - Iter_Try <- Iter_Try +1 - } - if(class(kriging_result)[1] != 'autoKrige'){ # give error if kriging fails - message(paste0('Kriging failed for layer ', Iter_Krige, '. Error message produced by autoKrige function: ', geterrmessage())) - } + ## check if already produced this krigr + if(!paste0(str_pad(Iter_Krige,7,'left','0'), '_data.nc') %in% list.files(Dir.Temp)){ + ### Iteration-specific data + DataSF <- Data_df[, c(1:2, Iter_Krige+2)] + colnames(DataSF)[-1:-2] <- 'Data' + DataSF <- st_as_sf(DataSF, coords = c('x', 'y')) + KrigData <- cbind(Origin, DataSF$Data) + KrigData <- na.omit(KrigData) + colnames(KrigData)[ncol(Origin)] <- 'Data' - ## retransform to raster - try( # try fastest way - this fails with certain edge artefacts in meractor projection and is fixed by using rasterize - Krig_ras <- raster(x = kriging_result$krige_output, layer = 1), # extract raster from kriging product - silent = TRUE - ) - try( - Var_ras <- raster(x = kriging_result$krige_output, layer = 3), # extract raster from kriging product - silent = TRUE - ) - if(!exists('Krig_ras') & !exists('Var_ras')){ - Krig_ras <- rasterize(x = kriging_result$krige_output, y = Covariates_fine[[1]])[[2]] # extract raster from kriging product - Var_ras <- rasterize(x = kriging_result$krige_output, y = Covariates_fine)[[4]] # extract raster from kriging product - } - crs(Krig_ras) <- crs(Data) # setting the crs according to the data - crs(Var_ras) <- crs(Data) # setting the crs according to the data - - if(Cores == 1){ - Ras_Krig[[Iter_Krige]] <- Krig_ras - Ras_Var[[Iter_Krige]] <- Var_ras - } # stack kriged raster into raster list if non-parallel computing + ### Try kriging + Iter_Try <- 0 # number of tries set to 0 + kriging_result <- NULL + while(class(kriging_result)[1] != 'autoKrige' & Iter_Try < 10){ # try kriging 10 times, this is because of a random process of variogram identification within the automap package that can fail on smaller datasets randomly when it isn't supposed to + try(invisible(capture.output(kriging_result <- autoKrige(formula = KrigingEquation, input_data = na.omit(KrigData), new_data = Target, nmax = nmax))), silent = TRUE) + Iter_Try <- Iter_Try +1 + } + if(class(kriging_result)[1] != 'autoKrige'){ # give error if kriging fails + message(paste0('Kriging failed for layer ', Iter_Krige, '. Error message produced by autoKrige function: ', geterrmessage())) + } - terra::writeCDF(x = as(brick(Krig_ras), 'SpatRaster'), filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_data.nc')), overwrite = TRUE) - # writeRaster(x = Krig_ras, filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_data.nc')), overwrite = TRUE, format='CDF') # save kriged raster to temporary directory - terra::writeCDF(x = as(brick(Var_ras), 'SpatRaster'), filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_SE.nc')), overwrite = TRUE) - # writeRaster(x = Var_ras, filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_SE.nc')), overwrite = TRUE, format='CDF') # save kriged raster to temporary directory + ### Make SpatRaster from Kriging result + try( + Pred_rast <- rast(x = cbind(st_coordinates(kriging_result$krige_output), st_drop_geometry(kriging_result$krige_output)$var1.pred), type = 'xyz'), + silent = TRUE + ) + try( + StDe_rast <- rast(x = cbind(st_coordinates(kriging_result$krige_output), st_drop_geometry(kriging_result$krige_output)$var1.stdev), type = 'xyz'), + silent = TRUE + ) + if(!exists('Pred_rast') & !exists('StDe_rast')){ + stop('Rasterising of kriging result failed.') + } + terra::crs(StDe_rast) <- terra::crs(Pred_rast) <- CRS_dat # setting the crs according to the data - if(Cores == 1){ # core check: if processing non-parallel - if(Count_Krige == 1){ # count check: if this was the first actual computation - T_End <- Sys.time() # record time at which kriging was done for current layer - Duration <- as.numeric(T_End)-as.numeric(T_Begin) # calculate how long it took to krig on layer - message(paste('Kriging of remaining ', nlayers(Data)-Iter_Krige, ' data layers should finish around: ', as.POSIXlt(T_Begin + Duration*nlayers(Data), tz = Sys.timezone(location=TRUE)), sep='')) # console output with estimate of when the kriging should be done - ProgBar <- txtProgressBar(min = 0, max = nlayers(Data), style = 3) # create progress bar when non-parallel processing - Count_Krige <- Count_Krige + 1 # raise count by one so the stimator isn't called again - } # end of count check - setTxtProgressBar(ProgBar, Iter_Krige) # update progress bar with number of current layer - } # end of core check + ### Data writing to disk + if(FileExtension == '.tif'){ + writeRaster(x = Pred_rast, filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,7,'left','0'), '_data', FileExtension)), overwrite = TRUE) + writeRaster(x = StDe_rast, filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,7,'left','0'), '_StDev', FileExtension)), overwrite = TRUE) + } + if(FileExtension == '.nc'){ + writeCDF(x = Pred_rast, filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,7,'left','0'), '_data', FileExtension)), overwrite = TRUE) + writeCDF(x = StDe_rast, filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,7,'left','0'), '_StDev', FileExtension)), overwrite = TRUE) + } + } + ### Return + NULL # otherwise trying to return SpatRaster " - ## KRIGING PREPARATION (establishing objects which the kriging refers to) ---- - Ras_Krig <- as.list(rep(NA, nlayers(Data))) # establish an empty list which will be filled with kriged layers - Ras_Var <- as.list(rep(NA, nlayers(Data))) # establish an empty list which will be filled with kriged layers - + ## Kriging Execution =============== + ## carry out kriging according to user specifications either in parallel or on a single core if(verbose){message("Commencing Kriging")} - ## DATA SKIPS (if certain layers in the data are empty and need to be skipped, this is handled here) --- - if(!is.null(DataSkips)){ # Skip check: if layers need to be skipped - for(Iter_Skip in DataSkips){ # Skip loop: loop over all layers that need to be skipped - Ras_Krig[[Iter_Skip]] <- Data[[Iter_Skip]] # add raw data (which should be empty) to list - terra::writeCDF(x = as(brick(Ras_Krig[[Iter_Skip]]), 'SpatRaster'), filename = file.path(Dir.Temp, str_pad(Iter_Skip,4,'left','0')), overwrite = TRUE) - # writeRaster(x = Ras_Krig[[Iter_Skip]], filename = file.path(Dir.Temp, str_pad(Iter_Skip,4,'left','0')), overwrite = TRUE, format = 'CDF') # save raw layer to temporary directory, needed for loading back in when parallel processing - } # end of Skip loop - Layers_vec <- 1:nlayers(Data) # identify vector of all layers in data - Compute_Layers <- Layers_vec[which(!Layers_vec %in% DataSkips)] # identify which layers can actually be computed on - }else{ # if we don't need to skip any layers - Compute_Layers <- 1:nlayers(Data) # set computing layers to all layers in data - } # end of Skip check - - - ## ACTUAL KRIGING (carry out kriging according to user specifications either in parallel or on a single core) ---- - if(Cores > 1){ # Cores check: if parallel processing has been specified - ### PARALLEL KRIGING --- - ForeachObjects <- c("Dir.Temp", "Cores", "Data", "KrigingEquation", "Origin", "Target", "Covariates_coarse", "Covariates_fine", "Terms", "SingularTry", "nmax") # objects which are needed for each kriging run and are thus handed to each cluster unit - pb <- txtProgressBar(max = length(Compute_Layers), style = 3) - progress <- function(n){setTxtProgressBar(pb, n)} - opts <- list(progress = progress) - cl <- makeCluster(Cores) # Assuming Cores node cluster - registerDoSNOW(cl) # registering cores - foreach(Iter_Krige = Compute_Layers, # kriging loop over all layers in Data, with condition (%:% when(...)) to only run if current layer is not present in Dir.Temp yet - .packages = c("raster", "stringr", "automap", "ncdf4", "rgdal", "terra"), # import packages necessary to each itteration + ### multi-core kriging ---- + if(Cores > 1){ + ## registering cluster and progress bar for foreach + cl <- makeCluster(Cores) + registerDoSNOW(cl) + progress <- function(n){ + pb$tick(tokens = list(layer = progress_layer[n])) + } + on.exit(stopCluster(cl)) + ## executing foreach kriging + ForeachObjects <- c("Dir.Temp", "Cores", "CRS_dat", "Data_df", "KrigingEquation", "Origin", "Target", "nmax", "FileExtension") # objects which are needed in Kriging + foreach(Iter_Krige = 1:KrigIterations, # kriging loop over all layers in Data, with condition (%:% when(...)) to only run if current layer is not present in Dir.Temp yet + .packages = c("terra", "sf", "stringr", "automap", "ncdf4"), # import packages necessary to each iteration .export = ForeachObjects, - .options.snow = opts) %:% when(!paste0(str_pad(Iter_Krige,4,"left","0"), '_data.nc') %in% list.files(Dir.Temp)) %dopar% { # parallel kriging loop - Ras_Krig <- eval(parse(text=looptext)) # evaluate the kriging specification per cluster unit per layer + .options.snow = list(progress = progress)) %dopar% { # parallel kriging loop # %:% when(!paste0(str_pad(Iter_Krige,7,"left","0"), '_data.nc') %in% list.files(Dir.Temp)) + eval(parse(text=looptext)) # evaluate the kriging specification per cluster unit per layer + Sys.sleep(0.5) + NULL } # end of parallel kriging loop - close(pb) - stopCluster(cl) # close down cluster - Files_krig <- list.files(Dir.Temp)[grep(pattern = "_data.nc", x = list.files(Dir.Temp))] - Files_var <- list.files(Dir.Temp)[grep(pattern = "_SE.nc", x = list.files(Dir.Temp))] - for(Iter_Load in 1:length(Files_krig)){ # load loop: load data from temporary files in Dir.Temp - Ras_Krig[[Iter_Load]] <- raster(file.path(Dir.Temp, Files_krig[Iter_Load])) # load current temporary file and write contents to list of rasters - Ras_Var[[Iter_Load]] <- raster(file.path(Dir.Temp, Files_var[Iter_Load])) # load current temporary file and write contents to list of rasters - } # end of load loop - }else{ # if non-parallel processing has been specified - ### NON-PARALLEL KRIGING --- - Count_Krige <- 1 # Establish count variable which is targeted in kriging specification text for producing an estimator - for(Iter_Krige in Compute_Layers){ # non-parallel kriging loop over all layers in Data - if(paste0(str_pad(Iter_Krige,4,'left','0'), '_data.nc') %in% list.files(Dir.Temp)){ # file check: if this file has already been produced - Ras_Krig[[Iter_Krige]] <- raster(file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_data.nc'))) # load already produced kriged file and save it to list of rasters - Ras_Var[[Iter_Krige]] <- raster(file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_SE.nc'))) - if(!exists("ProgBar")){ProgBar <- txtProgressBar(min = 0, max = nlayers(Data), style = 3)} # create progress bar when non-parallel processing} - setTxtProgressBar(ProgBar, Iter_Krige) # update progress bar - next() # jump to next layer - } # end of file check - T_Begin <- Sys.time() # record system time when layer kriging starts - eval(parse(text=looptext)) # evaluate the kriging specification per layer - } # end of non-parallel kriging loop - } # end of Cores check + } - ## SAVING FINAL PRODUCT ---- - if(is.null(DataSkips)){ # Skip check: if no layers needed to be skipped - # convert list of kriged layers in actual rasterbrick of kriged layers - names(Ras_Krig) <- names(Data) - if(class(Ras_Krig) != "RasterBrick"){Ras_Krig <- brick(Ras_Krig)} - Krig_terra <- as(Ras_Krig, "SpatRaster") - names(Krig_terra) <- names(Data) - terra::writeCDF(x = Krig_terra, filename = file.path(Dir, paste0(FileName, ".nc")), overwrite = TRUE) - # writeRaster(x = Ras_Krig, filename = file.path(Dir, FileName), overwrite = TRUE, format="CDF") # save final product as raster - # convert list of kriged layers in actual rasterbrick of kriged layers - names(Ras_Var) <- names(Data) - if(class(Ras_Var) != "RasterBrick"){Ras_Var <- brick(Ras_Var)} - Var_terra <- as(Ras_Var, "SpatRaster") - names(Var_terra) <- names(Data) + ### single-core kriging ---- + if(Cores == 1){ + for(Iter_Krige in 1:KrigIterations){ + # FileExis <- paste0(str_pad(Iter_Krige,7,'left','0'), '_data', FileExtension) %in% list.files(Dir.Temp) + # if(!FileExis){ + eval(parse(text=looptext)) # evaluate the kriging specification per layer + # } + Sys.sleep(0.5) + pb$tick(tokens = list(layer = progress_layer[Iter_Krige])) + } + } - terra::writeCDF(x = Var_terra, filename = file.path(Dir, paste0("SE_", paste0(FileName, ".nc"))), overwrite = TRUE) - # writeRaster(x = Ras_Var, filename = file.path(Dir, paste0("SE_",FileName)), overwrite = TRUE, format="CDF") # save final product as raster - }else{ # if some layers needed to be skipped - warning(paste0("Some of the layers in your raster could not be kriged. You will find all the individual layers (kriged and not kriged) in ", Dir, ".")) - Keep_Temporary <- TRUE # keep temporary files so kriged products are not deleted - } # end of Skip check + ## Data Loading and Saving =============== + ### loading kriged data back in + Krig_rast <- rast(list.files(Dir.Temp, full.names = TRUE, pattern = "_data")) + SE_rast <- rast(list.files(Dir.Temp, full.names = TRUE, pattern = "_StDev")) + ### assigning time to products + terra::time(Krig_rast) <- terra::time(SE_rast) <- terra::time(Data) + terra::varnames(Krig_rast) <- terra::varnames(SE_rast) <- terra::varnames(Data) + terra::units(Krig_rast) <- terra::units(SE_rast) <- terra::units(Data) + terra::metags(Krig_rast) <- terra::metags(SE_rast) <- Meta_vec + ### Data Saving + if(FileExtension == ".tif"){ + writeRaster(Krig_rast, filename = file.path(Dir, paste0(FileName, "_Kriged", FileExtension))) + writeRaster(SE_rast, filename = file.path(Dir, paste0(FileName, "_StDev", FileExtension))) + } + if(FileExtension == ".nc"){ + Krig_rast <- Meta.NC(NC = Krig_rast, FName = file.path(Dir, paste0(FileName, "_Kriged", FileExtension)), + Attrs = terra::metags(Krig_rast), Write = TRUE) + SE_rast <- Meta.NC(NC = SE_rast, FName = file.path(Dir, paste0(FileName, "_STDev", FileExtension)), + Attrs = terra::metags(SE_rast), Write = TRUE) + } - ### REMOVE FILES FROM HARD DRIVE --- + ## Removing Temporary Files =============== if(Keep_Temporary == FALSE){ # cleanup check unlink(Dir.Temp, recursive = TRUE) } # end of cleanup check - Krig_ls <- list(Ras_Krig, Ras_Var, Call_ls) - names(Krig_ls) <- c("Kriging_Output", "Kriging_SE", "Call") - return(Krig_ls) # return raster or list of layers + ## Data Return =============== + Krig_ls <- list(Krig_rast, SE_rast) + names(Krig_ls) <- c("Prediction", "StDev") + return(Krig_ls) } diff --git a/R/Meta.R b/R/Meta.R new file mode 100644 index 0000000..0857499 --- /dev/null +++ b/R/Meta.R @@ -0,0 +1,335 @@ +### REGISTER METADATA LIST ===================================================== +#' Create a .txt tile holding the names of all supported data sets and their types +#' +#' To be run only by the developer when adding support for new data sets and types. +#' +#' @param Dir directory in which metadata files (.RData objects) are stored locally +#' +#' @return Nothing. But does write a .txt file into the specified directory. +#' +#' @seealso \code{\link{Meta.List}}, \code{\link{Meta.Read}}, \code{\link{Meta.Variables}}, \code{\link{Meta.DOI}}, \code{\link{Meta.QuickFacts}}. +#' +Meta.Register <- function(Dir = file.path(getwd(), "metadata")){ + sink(file = file.path(Dir, "metadata.txt")) + cat(list.files(Dir, ".rds"), sep = "\n") + sink() +} + +### READ METADATA LIST ========================================================= +#' List out all supported data sets +#' +#' Provide an overview of all data sets for which metadata files are present. +#' +#' @param URL Path to where metadata files reside. Should not be changed from default. +#' +#' @importFrom tools file_path_sans_ext +#' +#' @return A vector of supported datasets. +#' +#' @seealso \code{\link{Meta.Read}}, \code{\link{Meta.Variables}}, \code{\link{Meta.DOI}}, \code{\link{Meta.QuickFacts}}. +#' +#' @examples +#' Meta.List() +#' +#' @export +Meta.List <- function(URL = "https://raw.githubusercontent.com/ErikKusch/KrigR/Development/metadata" + ){ + file_path_sans_ext(read.table(file.path(URL, "metadata.txt"))[,1]) +} + +### READ METADATA FACTS ======================================================== +#' Data set overview +#' +#' Read and return metadata for specific data set. +#' +#' @param URL Path to where metadata files reside. Should not be changed from default. +#' @param dataset Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}. +#' +#' @return List. Contains information of data set, type, variables, resolution, citation, etc. +#' +#' @seealso \code{\link{Meta.List}}, \code{\link{Meta.Variables}}, \code{\link{Meta.DOI}}, \code{\link{Meta.QuickFacts}}. +#' +#' @examples +#' Meta.Read() +#' +#' @export +Meta.Read <- function(URL = "https://raw.githubusercontent.com/ErikKusch/KrigR/Development/metadata", ## change this to github repo for these data once ready + dataset = "reanalysis-era5-land"){ + load(url( + paste0( + "https://github.com/ErikKusch/KrigR/blob/Development/metadata/", + dataset, + ".RData?raw=true" + ) + )) + get(ls()[ls() == gsub(dataset, pattern = "-", replacement = "_")]) +} + +### DATASET VARIABLES ========================================================== +#' Variables available within data set +#' +#' Read and return overview of variables available for specific data set. +#' +#' @param dataset Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}. +#' +#' @return Data frame. Contains five columns: +#' \itemize{ +#' \item{Variable}{clear name} +#' \item{CDSname}{name required for CDS query} +#' \item{Description}{plain text description of variable, scraped from CDS webpage} +#' \item{Unit}{unit of measurement} +#' \item{Cumulative}{logical, indexing whether a variable is recorded cumulatively or not} +#' } +#' +#' @seealso \code{\link{Meta.List}}, \code{\link{Meta.Read}}, \code{\link{Meta.DOI}}, \code{\link{Meta.QuickFacts}}. +#' +#' @examples +#' Meta.Variables() +#' +#' @export +Meta.Variables <- function(dataset = "reanalysis-era5-land"){ + Meta.Read(dataset = dataset)$Variables +} + +### DATASET CITATION =========================================================== +#' DOI of data set +#' +#' Read and return DOI of data set for easy citation. +#' +#' @param dataset Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}. +#' +#' @return Character. DOI string for data set. +#' +#' @seealso \code{\link{Meta.List}}, \code{\link{Meta.Read}}, \code{\link{Meta.Variables}}, \code{\link{Meta.QuickFacts}}. +#' +#' @examples +#' Meta.DOI() +#' +#' @export +Meta.DOI <- function(dataset = "reanalysis-era5-land"){ + Meta.Read(dataset = dataset)$Citation +} + +### DATASET QUICK FACTS ======================================================== +#' Fact sheet overview of data set +#' +#' Read and return short overview of data set characteristics, supported types, extent, time frames and required arguments. +#' +#' @param dataset Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}. +#' +#' @return A list object reporting information on queried dataset in standardised way: +#' \itemize{ +#' \item{DataSet}{data set string}. +#' \item{Type}{character, supported types of the data set}. +#' \item{URL}{character, url of CDS webpage corresponding to data set}. +#' \item{Description}{character, plain text description of data set scraped from CDS}. +#' \item{TResolution}{character, base temporal resolution of each layer in data set}. +#' \item{TStep}{numeric, vector of time step between layers in data set corresponding to Type}. +#' \item{TStart}{POSIXct, date and time at which first layer is available}. +#' \item{TEnd}{POSIXct or character, date and time at which first layer is available}. +#' \item{Projection}{crs of data set}. +#' \item{SpatialResolution}{numeric, resolution of data set in space in degrees}. +#' \item{CDSArguments}{list, required arguments for CDS call beyond standard arguments and also reporting default/options for common CDS query arguments}. +#' } +#' +#' @seealso \code{\link{Meta.List}}, \code{\link{Meta.Read}}, \code{\link{Meta.Variables}}, \code{\link{Meta.DOI}}. +#' +#' @examples +#' Meta.QuickFacts() +#' +#' @export +Meta.QuickFacts <- function(dataset = "reanalysis-era5-land"){ + Meta.Read(dataset = dataset)[c("DataSet", "Type", "URL", "Description", + "TResolution", "TStep", "TStart", "TEnd", + "Projection", "SpatialResolution", + "CDSArguments")] +} + +### CDS QUERY VALIDATION AGAINST DATA SET METADATA ============================= +#' Fact sheet overview of data set +#' +#' Read and return short overview of data set characteristics, supported types, extent, time frames and required arguments. +#' +#' @param dataset Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}. +#' @param Type NA or Character. Indicating which sub-type of the specified dataset is queried. +#' @param VariableCheck Character. CDS-compliant variable name. +#' @param CumulativeCheck Logical. Whether queried data will be attempted to be back-calculated from cumulative records. +#' @param ExtentCheck Numeric. Vector defining bounding box of queried data. +#' @param DateCheck data.frame. Containing user-specified dates and their UTC counterparts. +#' @param AggrCheck list. List of length two (1 - TStep, 2 - TResolution). +#' @param QueryTimes Character. Vector of time(s)-of-day for which layers are to be obtained. +#' +#' @importFrom terra ext +#' @importFrom lubridate days_in_month +#' +#' @return List. Contains: +#' \itemize{ +#' \item{QueryDataSet}{queried dataset}. +#' \item{QueryType}{queried sub-type of dataset}. +#' \item{QueryVariable}{queried variable}. +#' \item{QueryFormat}{file format supported by queried dataset}. +#' \item{QueryUnit}{unit of measurement of queried variable from queried dataset}. +#' } +#' +#' @seealso \code{\link{Meta.List}}, \code{\link{Meta.Read}}, \code{\link{Meta.Variables}}, \code{\link{Meta.DOI}}, \code{\link{Meta.QuickFacts}}. +#' +#' @examples +#' Meta.Check(DataSet = "reanalysis-era5-land", Type = NA, VariableCheck = "2m_temperature", CumulativeCheck = FALSE, ExtentCheck = c(53.06, 9.87, 49.89, 15.03), DateCheck = data.frame(IN = c(as.POSIXct("1995-01-01 CET"), as.POSIXct("2005-01-01 23:00:00 CET")), UTC = c(as.POSIXct("1994-12-31 23:00:00 UTC"), as.POSIXct("2005-01-01 22:00:00 UTC"))), AggrCheck = list(1, "hour"), QueryTimes = c('00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00')) +#' +Meta.Check <- function(DataSet = "reanalysis-era5-land", Type = NA, VariableCheck, CumulativeCheck, ExtentCheck, DateCheck, AggrCheck, QueryTimes){ + #--- Variable + ### if a variable not in the data set has been specified + if(length(VariableCheck) == 0){stop("Please specify a variable provided by the data set. Your can be retrieved with the function call: ", "\n", "Meta.Variables(dataset = '", DataSet, "')")} + #--- Cumulative + ### if the cumulative back-calculation is attempting to be applied to a non-cumulative variable + CumVar <- Meta.Variables(dataset = DataSet)$Cumulative[which(Meta.Variables(dataset = DataSet)$CDSname == VariableCheck)] + if(CumulativeCheck & !CumVar){ + stop("You have specified to back-calculation of cumulative data for a non-cumulatively recorded variable. This would produce nonsense data. Please specify CumulVar = FALSE instead. For an overview of which variables are recorded cumulatively for the data set you are querying, please consider the function call:", "\n", "Meta.Variables(dataset = '", DataSet, "')") + } + #--- Extent + ### if an extent outside the data product has been specified + DataExt <- ext(Meta.QuickFacts(dataset = DataSet)$CDSArguments$area)[c(4,1,3,2)] #N,W,S,E + if( + ( + # ymax + (ExtentCheck[1] > DataExt[1]) + + # xmin + (ExtentCheck[2] < DataExt[2]) + + # ymin + (ExtentCheck[3] < DataExt[3]) + + # ymax + (ExtentCheck[4] > DataExt[4]) + ) != 0 + ){ + stop("Please specify an area using the Extent argument that is contained within the data set. The data set covers the area defined by the following extent:", + "\n", ext(Meta.QuickFacts(dataset = DataSet)$CDSArguments$area), " in ", Meta.QuickFacts(dataset = DataSet)$Projection) + } + #--- Time Window + ### check if time window is exceeded + CheckStart <- DateCheck$UTC[1] < Meta.QuickFacts(dataset = DataSet)$TStart + if(class(Meta.QuickFacts(dataset = DataSet)$TEnd)[1] == "POSIXct"){ + CheckEnd <- (DateCheck$UTC[2] > Meta.QuickFacts(dataset = DataSet)$TEnd) + }else{ + CheckEnd <- FALSE + warning("Cannot validate user-specified end date (DateStop) because specified data set is being updated regularly (", + strsplit(Meta.QuickFacts(dataset = DataSet)$TEnd, split = "; ")[[1]][2], "). User-specification may lead to an error.") + } + if(CheckStart + CheckEnd != 0){ + stop("The time window you have specified is not supported by the data set. The data set makes data available from ", + Meta.QuickFacts(dataset = DataSet)$TStart, " until ", Meta.QuickFacts(dataset = DataSet)$TEnd) + } + #--- Aggregation Match + ### check if desired aggregation is supported + SuppRes <- c("hour", "day", "month", "year") + BaseStep <- BaseStep <- Meta.QuickFacts(dataset = DataSet)$TStep[ + na.omit(match(Type, Meta.QuickFacts(dataset = DataSet)$Type))] + if(Meta.QuickFacts(dataset = DataSet)$TResolution != AggrCheck[[2]] | + BaseStep != AggrCheck[[1]]){ # if this is TRUE, we need to check if aggregation works + + ## specification of a temporal resolution finer than the data? + if(which(SuppRes == AggrCheck[[2]]) < which(SuppRes == Meta.QuickFacts(dataset = DataSet)$TResolution)){ + stop("You have specified a temporal aggregation at a scale finer than what the data set reports natively (", + Meta.QuickFacts(dataset = DataSet)$TResolution, "). Please specify the same or a coarser temporal resolution for the TResolution argument. Supported options are '", paste(SuppRes, collapse = "', '"), "'.") + } + + ## specification of tsteps that cannot be achieved with the data? + if(Meta.QuickFacts(dataset = DataSet)$TResolution == AggrCheck[[2]] & + ((AggrCheck[[1]] /BaseStep) %%1!=0)){ + stop("You have specified a temporal aggregation that cannot be achieved with the data. When specifying the same temporal resolution as the data (you have specified TResolution = ", AggrCheck[[2]], "), the TStep must be a multiple of the base temporal resolution of the data (", BaseStep, " for DataSet = ", DataSet, " and Type = ", Type, ").") + } + + ## specification of daily, monthly or annual aggregates but not setting tstart or tend to beginning or end of day/month/year? + if(AggrCheck[[2]] == "day" & + (as.numeric(substr(QueryTimes[1], 0, 2)) != 0 | + as.numeric(substr(QueryTimes[length(QueryTimes)], 0, 2)) != 23)){ + stop("You have specified (multi-)daily temporal aggregation but are querying a time window which does not start at 00:00 and/or does not terminate at 23:00. Please ensure that you set the argument DateStart and DateStop accordingly.") + } + + ## these may fail when querying monthly raw data + MustStartMonth <- as.POSIXct(paste( + paste(format(DateCheck$IN[1], "%Y"), format(DateCheck$IN[1], "%m"), "01", sep = "-"), + "00:00:00"), tz = format(DateCheck$IN[2], "%Z")) + MustEndMonth <- as.POSIXct(paste( + paste(format(DateCheck$IN[2], "%Y"), format(DateCheck$IN[2], "%m"), + days_in_month(DateCheck$IN[2]), sep = "-"), + "24:00:00"), tz = format(DateCheck$IN[2], "%Z")) + if(AggrCheck[[2]] == "month" & + (DateCheck$IN[1] != MustStartMonth | + DateCheck$IN[2] != MustEndMonth)){ + stop("You have specified (multi-)monthly temporal aggregation but are querying a time window which does not start at the first day of a month at 00:00 and/or does not terminate on the last day of a month at 24:00. Please ensure that you set the argument DateStart and DateStop accordingly.") + } + + MustStartYear <- as.POSIXct(paste( + paste(format(DateCheck$IN[1], "%Y"), "01-01", sep = "-"), + "00:00:00"), tz = format(DateCheck$IN[2], "%Z") + ) + MustEndYear <- as.POSIXct(paste( + paste(format(DateCheck$IN[2], "%Y"), "12-31", sep = "-"), + "23:00:00"), tz = format(DateCheck$IN[2], "%Z") + ) + if(AggrCheck[[2]] == "year" & + (DateCheck$IN[1] != MustStartYear | + DateCheck$IN[2] != MustEndYear)){ + stop("You have specified (multi-)yearly temporal aggregation but are querying a time window which does not start at the first of day of a year at 00:00 and/or does not terminate on the last day of a year at 23:00. Please ensure that you set the argument DateStart and DateStop accordingly.") + } + } + + #--- Format, assign default file type for download + QueryFormat <- Meta.QuickFacts(dataset = DataSet)$CDSArguments$format[1] + + #--- Report back + list( + QueryDataSet = DataSet, + QueryType = Type, + QueryVariable = VariableCheck, + QueryFormat = QueryFormat, + QueryUnit = Meta.Variables(dataset = DataSet)$Unit[which(Meta.Variables(dataset = DataSet)$CDSname == VariableCheck)]) +} + +### NETCDF METADATA WRITING AND READING ======================================== +#' Read or write metadata into NetCDF files +#' +#' Read or write metadata attributes from/to netcdf file. +#' +#' @param NC SpatRaster +#' @param FName Filename including directory +#' @param Attrs Named vector of metadata attributes +#' @param Write Logical. Whether to write metadata +#' @param Read Logical Whether to read metadata +#' +#' @importFrom terra writeCDF +#' @importFrom ncdf4 nc_open +#' @importFrom ncdf4 ncatt_put +#' @importFrom ncdf4 nc_close +#' @importFrom ncdf4 ncatt_get +#' @importFrom terra metags +#' @importFrom lubridate days_in_month +#' +#' @return A SpatRaster with metadata +#' +Meta.NC <- function(NC, FName, Attrs, Write = FALSE, Read = FALSE){ + ## Writing metadata + if(Write){ + writeCDF(x = NC, filename = FName) + nc <- nc_open(FName, write = TRUE) + for(name in names(Attrs)) { + ncatt_put(nc, 0, name, Attrs[[name]]) + } + nc_close(nc) + } + ## Reading metadata + if(Read){ + nc <- nc_open(FName) + # Retrieve custom metadata + Meta <- lapply(names(Attrs), FUN = function(name){ + ncatt_get(nc, 0, name)$value + }) + # Close the NetCDF file + nc_close(nc) + Meta_vec <- unlist(Meta) + names(Meta_vec) <- names(Attrs) + terra::metags(NC) <- Meta_vec + } + ## return object + return(NC) +} diff --git a/R/Spatial.R b/R/Spatial.R new file mode 100644 index 0000000..4bdd917 --- /dev/null +++ b/R/Spatial.R @@ -0,0 +1,155 @@ +### POINT LOCATIONS ============================================================ +#' Transform data frame-type inputs into sf +#' +#' Transform data frame with ID for querying functionality around point-loactions to SpatialPoints +#' +#' @param USER_df A data.frame containing geo-referenced points with Lat and Lon columns +#' +#' @importFrom sf st_as_sf +#' +#' @return An sf POINT object. +#' +#' @examples +#' data("Mountains_df") +#' Make.SpatialPoints(Mountains_df) +#' +#' @export +Make.SpatialPoints <- function(USER_df){ + USER_df <- data.frame(USER_df) ## attempt to catch tibbles or data.tables + if(sum(c("Lat", "Lon") %in% colnames(USER_df)) != 2){stop("Please provide your geo-locations with a Lat and a Lon column (named exactly like such).")} + st_as_sf(USER_df, coords = c("Lon", "Lat"), remove = FALSE) +} +### EXTENT CHECKING ============================================================ +#' Check extent specification +#' +#' Try to convert user input into (1) a terra or sf object and also read out the corresponding (2) SpatExtent object. Supports inputs of classes belonging to the packages raster, terra, sf, and sp +#' +#' @param USER_ext User-supplied Extent argument in download_ERA function call +#' +#' @importFrom methods getClass +#' @importFrom terra rast +#' @importFrom terra ext +#' @importFrom sf st_as_sf +#' @importFrom sf st_bbox +#' +#' @return A list containg (1) a terra/sf object and (2) the corresponding SpatExtent object. +#' +#' @examples +#' ## raster +#' Check.Ext(raster::extent(c(9.87, 15.03, 49.89, 53.06))) +#' ## terra +#' Check.Ext(terra::ext(c(9.87, 15.03, 49.89, 53.06))) +#' ## sf +#' set.seed(42) +#' nb_pt <- 10 +#' dd <- data.frame(x = runif(nb_pt, 9.87, 15.03), y = runif(nb_pt, 49.89, 53.06), val = rnorm(nb_pt)) +#' sf <- sf::st_as_sf(dd, coords = c("x","y")) +#' Check.Ext(sf) +#' ## sp +#' Check.Ext(as(sf, "Spatial")) +#' +#' @export +Ext.Check <- function(USER_ext){ + ## find package where USER_ext class originates + class_name <- class(USER_ext) + class_def <- getClass(class_name) + package_name <- class_def@package + + ## sanity check if USER_ext is supported + SupportedPackages <- c("raster", "terra", "sf", "sp") + if(!(package_name %in% SupportedPackages)){ + stop("Please specify the Extent argument as an object defined either with classes found in the raster, terra, or sf packages") + } + + ## Transform into SpatExtent class + if(package_name == "raster"){ + OUT_spatialobj <- rast(USER_ext) + OUT_ext <- ext(USER_ext) + } + if(package_name == "terra" | package_name == "sf"){ + OUT_spatialobj <- USER_ext + if(class_name[1] == "sfc_MULTIPOLYGON"){ + OUT_ext <- ext(st_bbox(USER_ext)) + }else{ + OUT_ext <- ext(USER_ext) + } + } + if(package_name == "sp"){ + OUT_spatialobj <- st_as_sf(USER_ext) + OUT_ext <- ext(OUT_spatialobj) + } + + ## Round digits and return + OUT_list = list(SpatialObj = OUT_spatialobj, + Ext = round(OUT_ext, 3)) + return(OUT_list) +} + +### POINT BUFFERING ============================================================ +#' Square Buffers Around Point Data +#' +#' Allow for drawing of buffer zones around point-location data for downloading and kriging of spatial data around point-locations. Overlapping individual buffers are merged. +#' +#' @param USER_pts An sf POINT object +#' @param USER_buffer Size of buffer in degrees +#' +#' @importFrom sf st_buffer +#' @importFrom sf st_union +#' @importFrom sf st_as_sf +#' +#' @return An sf polygon made up of individual square buffers around point-location input. +#' +#' @examples +#' data("Mountains_df") +#' User_pts <- Make.SpatialPoints(Mountains_df) +#' Buffer.pts(User_pts, USER_buffer = 0.5) +#' +#' @export +Buffer.pts <- function(USER_pts, USER_buffer = .5){ + st_as_sf(st_union(st_buffer(USER_pts, USER_buffer, endCapStyle = "SQUARE"))) +} + +### CROPPING & MASKING ========================================================= +#' Cropping & Range Masking with Edge Support +#' +#' Cropped and masking the original SpatRaster (`BASE`) using supplied SpatExtent or shapefile (`Shape`) and retaining all pixels which are even just partially covered. +#' +#' @param BASE A SpatRaster within which coverage should be identified +#' @param Shape Either a SPatExtent or an sf polygon(-collection) whose coverage of the raster object is to be found. +#' +#' @importFrom terra crop +#' @importFrom terra mask +#' @importFrom terra nlyr +#' @importFrom pbapply pblapply +#' +#' @return A SpatRaster. +#' +#' @examples +#' data("Jotunheimen_ras") +#' data("Jotunheimen_poly") +#' Mask.Shape(Jotunheimen_ras, Jotunheimen_poly) +#' +#' @export +Handle.Spatial <- function(BASE, Shape){ + + ## splitting by rasterlayers if necessary to avoid error reported in https://github.com/rspatial/terra/issues/1556 + if(terra::nlyr(BASE) > 65535){ + Indices <- ceiling((1:terra::nlyr(BASE))/2e4) + r_ls <- terra::split(x = BASE, f = Indices) + ret_ls <- pblapply(r_ls, FUN = function(BASE_iter){ + ret_rast <- crop(BASE_iter, ext(Shape)) + if(class(Shape)[1] == "sf"){ + ret_rast <- mask(ret_rast, Shape, touches = TRUE) + } + }) + ret_rast <- do.call(c, ret_ls) + return(ret_rast) + } + + ## regular cropping and masking for SPatRasters not exceeding layer limit + ret_rast <- crop(BASE, ext(Shape)) + if(class(Shape)[1] == "sf"){ + ret_rast <- mask(ret_rast, Shape, touches = TRUE) + } + return(ret_rast) +} diff --git a/R/Temporal.R b/R/Temporal.R new file mode 100644 index 0000000..fc07162 --- /dev/null +++ b/R/Temporal.R @@ -0,0 +1,307 @@ +### DATE REFORMATTING ========================================================== +#' Resolve time zones as requested by user and UTC format with which to query from CDS +#' +#' Create UTC counterparts of user-input dates for CDS queries +#' +#' @param DatesVec A vector of POSIXct objects +#' +#' @return A data frame on input dates respective to user-queried timezone and their UTC counterparts. +#' +#' @examples +#' IN_DateStart <- as.POSIXct("1995-01-01 00:00", tz = "CET") +#' IN_DateStop <- as.POSIXct("2005-01-01 23:00", tz = "CET") +#' Dates_df <- Make.UTC(DatesVec = c(IN_DateStart, IN_DateStop)) +#' Dates_df +#' +#' @export +Make.UTC <- function(DatesVec = NULL){ + data.frame(IN = DatesVec, + UTC = do.call(c ,lapply(DatesVec, FUN = function(x){as.POSIXct(x, tz = "UTC")})) + ) +} +### QUERY SEPARATING INTO TIME WINDOWS ========================================= +#' Creating time windows for CDS queries +#' +#' Make a list holding date ranges for which to make individual CDS queries +#' +#' @param Dates_df A two-column data frame (column names: "IN" and "UTC") holding POSIXct elements. Created with \code{\link{Make.UTC}}. +#' @param BaseTResolution Character. Base temporal resolution of queried data on CDS +#' @param BaseTStep Numeric. Base time steps of queried data on CDS +#' @param BaseTStart POSIXct. Base starting date and time of queried data on CDS +#' @param TChunkSize Numeric. Maximum amount of layers to include in each query +#' @param DataSet Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}. +#' +#' @importFrom stringr str_pad +#' @importFrom stringr str_c +#' +#' @return List. Contains: +#' \itemize{ +#' \item{QueryTimeWindows}{List of dates for individual CDS queries as used by \code{\link{Make.Request}}.}. +#' \item{QueryTimes}{Character. Layers of data in the raw data set}. +#' } +#' +#' @examples +#' IN_DateStart <- as.POSIXct("1995-01-01 00:00", tz = "CET") +#' IN_DateStop <- as.POSIXct("2005-01-01 23:00", tz = "CET") +#' Dates_df <- Make.UTC(DatesVec = c(IN_DateStart, IN_DateStop)) +#' Make.RequestWindows(Dates_df = Dates_df, +#' BaseTResolution = "hour", +#' BaseTStep = 24 +#' BaseTStart = as.POSIXct("1950-01-01 00:01", tz = "UTC") +#' TChunkSize = 12000) +#' +Make.RequestWindows <- function(Dates_df, BaseTResolution, BaseTStep, BaseTStart, TChunkSize, DataSet){ + ## reformat input + DateStart <- Dates_df$UTC[1] + DateStop <- Dates_df$UTC[2] + if(BaseTResolution == "month"){ + DateStart <- as.POSIXct(paste0(format(DateStart, "%Y-"), "01-01 00:00"), tz = "UTC") # ensure that first of first month in first queried year is used for sequence creation to avoid month skips + DateStop <- as.POSIXct(paste0(format(DateStop, "%Y-"), "12-31 23:00"), tz = "UTC") # ensure that last of last month in last queried year is used for sequence creation to avoid month skips + } + + ## checking chunksize specification + if((TChunkSize/BaseTStep)%%1!=0){stop("Please specify a TChunkSize (currently = ", TChunkSize, + ") that is a multiple of the base temporal resolution of the data you queried from CDS (curently = ", BaseTStep, ").")} + + ## checking alignment of queried data with raw data + if(BaseTResolution == "hour" & BaseTStep != 24){ + # when we are pulling from non-1-hourly records, check whether specified start-date aligns with date layers in raw data + StartCheck <- difftime(DateStart, Meta.QuickFacts(dataset = DataSet)$TStart, units = "hour")/BaseTStep + EndCheck <- difftime(DateStop, Meta.QuickFacts(dataset = DataSet)$TStart, units = "hour")/BaseTStep + AlignCheck <- (as.numeric(StartCheck)%%1==0 | as.numeric(EndCheck)%%1==0) + } + + ## making query time call + if(!(BaseTResolution %in% c("hour", "month"))){stop("Non-hour or -month base resolutions not supported yet")} + if(BaseTResolution == "hour"){ + if(BaseTStep == 24){ + QueryTimes <- str_pad(str_c(0:23,"00",sep=":"), 5,"left","0") ## this is used for telling CDS which layers we want per day + }else{ + QueryTimes <- str_pad(str_c( + seq(from = as.numeric(format(Meta.QuickFacts(dataset = DataSet)$TStart, "%H")), + to = 23, + by = 24/BaseTStep) + ,"00",sep=":"), 5,"left","0") ## this is used for telling CDS which layers we want per day, relevant for ensemble_mean and ensemble_spread for example, which are recorded at 3-hour intervals starting at 00:00 per day + } + } + if(BaseTResolution == "month"){ + QueryTimes <- "00:00" ## this is used for telling CDS which layers we want per day + } + + + ## check alignment with non-1-BaseTStep data products + if(exists("AlignCheck")){ + if(!AlignCheck){ + stop("You have specified download of a data set whose raw layers are provided at a temporal resolution = ", BaseTResolution, " at intervalstime steps = ", BaseTStep, ".", + "\n Either one or both of the the time-window defining dates (DateStart and DateStop arguments) you have specified, once converted to UTC (", DateStart, " and ", DateStop, ") do not align with the structure of the raw data which requires querying of data to start and terminate at any of the following UTC hours of the day: ", paste(QueryTimes, collapse = "; "), ". Please adjust your date specification accordingly.") + } + } + + ## making request ranges + if(BaseTResolution == "month"){ + BaseTStep <- 1 # do not repeat each month, hence set this to 1 + } + T_RequestRange <- seq(from = DateStart, to = DateStop, by = BaseTResolution) + # T_RequestRange <- as.POSIXct(paste(rep(unique(T_RequestDates), each = length(QueryTimes)), QueryTimes), tz = "UTC") + T_RequestDates <- as.Date(rep(unique(format(T_RequestRange, "%Y-%m-%d")), each = BaseTStep)) + list(QueryTimeWindows = split(T_RequestDates, ceiling(seq_along(T_RequestDates)/TChunkSize)), + QueryTimes = QueryTimes + ) +} + +### BACK-CALCULATION OF CUMULATIVE VARIABLES =================================== +#' Make cumulatively stored records into sequential ones +#' +#' Takes a SpatRaster of cumulatively stored records and returns a SpatRaster of sequential counterparts +#' +#' @param CDS_rast SpatRaster +#' @param CumulVar Logical. Whether to apply cumulative back-calculation +#' @param BaseResolution Character. Base temporal resolution of data set +#' @param BaseStep Numeric. Base time step of data set +#' @param TZone Character. Time zone for queried data. +#' +#' @importFrom terra rast +#' @importFrom terra nlyr +#' @importFrom terra subset +#' @importFrom terra time +#' @importFrom lubridate days_in_month +#' +#' @return A SpatRaster +#' +Temporal.Cumul <- function(CDS_rast, CumulVar, BaseResolution, BaseStep, TZone){ + Era5_ras <- CDS_rast + if(CumulVar & BaseResolution == "hour"){ + if(BaseStep != 1){stop("Back-calculation of hourly cumulative variables only supported for 1-hour interval data. The data you have specified reports hourly data in intervals of ", BaseStep, ".")} + ## removing non-needed layers + RemovalLyr <- c(1, (nlyr(Era5_ras)-22):nlyr(Era5_ras)) # need to remove first layer and last 23 for backcalculation + Era5_ras <- subset(Era5_ras, RemovalLyr, negate=TRUE) + ## back-calculation + counter <- 1 + Era5_ls <- as.list(rep(NA, nlyr(Era5_ras))) + names(Era5_ls) <- terra::time(Era5_ras) + for(i in 1:nlyr(Era5_ras)){ + if(counter > 24){counter <- 1} + if(counter == 1){ + Era5_ls[[i]] <- Era5_ras[[i]] + StartI <- i + } + if(counter == 24){ + Era5_ls[[i]] <- Era5_ras[[i]]-sum(rast(Era5_ls[StartI:(StartI+counter-2)])) + } + if(counter != 24 & counter != 1){ + Era5_ls[[i]] <- Era5_ras[[i+1]] - Era5_ras[[i]] + } + counter <- counter + 1 + } + ## finishing off object + Ret_ras <- rast(Era5_ls) + terra::time(Ret_ras) <- as.POSIXct(terra::time(Era5_ras), tz = TZone) - 60*60 # back-dating to be in-line with regular specifications + Era5_ras <- Ret_ras + warning("You toggled on the CumulVar option in the function call. Hourly records have been converted from cumulative aggregates to individual hourly records.") + } + ## multiply by number of days per month + if(CumulVar & BaseResolution == "month"){ + Days_in_Month_vec <- days_in_month(terra::time(CDS_rast)) + if(grepl("ensemble_members", Type)){ + Days_in_Month_vec <- rep(Days_in_Month_vec, each = 10) + } + Era5_ras <- Era5_ras * Days_in_Month_vec + warning("You toggled on the CumulVar option in the function call. Monthly records have been multiplied by the amount of days per respective month.") + } + return(Era5_ras) +} + +### TEMPORAL AGGREGATION ======================================================= +#' Carry out temporal aggregation +#' +#' Takes a SpatRaster and user-specifications of temporal aggregation and carries it out +#' +#' @param CDS_rast SpatRaster +#' @param BaseResolution Character. Base temporal resolution of data set +#' @param BaseStep Numeric. Base time step of data set +#' @param TResolution Character. User-specified temporal resolution +#' @param TStep Numeric. User-specified time step +#' @param FUN User-defined aggregation function +#' @param Cores Numeric. Number of cores for parallel processing +#' @param QueryTargetSteps Character. Target resolution steps +#' @param TZone Character. Time zone for queried data. +#' +#' @importFrom terra time +#' @importFrom terra tapp +#' @importFrom terra app +#' +#' @return A SpatRaster +#' +Temporal.Aggr <- function(CDS_rast, BaseResolution, BaseStep, + TResolution, TStep, FUN, Cores, QueryTargetSteps, TZone){ + if(BaseResolution == TResolution & BaseStep == TStep){ + Final_rast <- CDS_rast # no temporal aggregation needed + }else{ + + + TimeDiff <- sapply(terra::time(CDS_rast), FUN = function(xDate){ + length(seq(from = terra::time(CDS_rast)[1], + to = xDate, + by = TResolution))-1 + }) + AggrIndex <- floor(TimeDiff/TStep)+1 + + Form <- substr(TResolution, 1, 1) + Form <- ifelse(Form %in% c("h", "y"), toupper(Form), Form) + LayerFormat <- format(terra::time(CDS_rast), paste0("%", Form)) + # LayerMatches <- match(LayerFormat, QueryTargetSteps) + # + # if(grepl("Factor =", QueryTargetSteps)){ # happens for hourly ensemble data + # Factor <- as.numeric(sub("Ensembling at base resolution, Factor = ", "", QueryTargetSteps)) + # AggrIndex <- rep(seq(from = 1, to = length(LayerFormat)/(Factor)), each = Factor) + # }else{ + # AggrIndex <- ceiling(LayerMatches/TStep) + # } + + if(length(unique(AggrIndex)) == 1){ ## this is to avoid a warning message thrown by terra + Final_rast <- app(x = CDS_rast, + cores = Cores, + fun = FUN) + }else{ + Final_rast <- tapp(x = CDS_rast, + index = AggrIndex, + cores = Cores, + fun = FUN) + } + + + + if(TResolution == "year"){ + terra::time(Final_rast) <- as.POSIXct( + paste0(LayerFormat[!duplicated(AggrIndex)], "-01-01"), + tz = TZone) + } + if(TResolution == "month"){ + terra::time(Final_rast) <- as.POSIXct( + paste0(format(terra::time(CDS_rast)[!duplicated(AggrIndex)], "%Y-%m"), "-01"), + tz = TZone) + } + if(TResolution == "day"){ + terra::time(Final_rast) <- as.POSIXct( + format(terra::time(CDS_rast)[!duplicated(AggrIndex)], "%Y-%m-%d"), + tz = TZone) + } + if(TResolution == "hour"){ + terra::time(Final_rast) <- as.POSIXct( + terra::time(CDS_rast)[!duplicated(AggrIndex)], + tz = TZone) + } + } + return(Final_rast) +} + +### TEMPORAL AGGREGATION CHECK ================================================= +#' Checking temporal aggregation can use all queried data +#' +#' Error message if specified aggregation and time window clash. +#' +#' @param QuerySeries Character. Vector of dates/times queried for download. Created by \code{\link{Make.RequestWindows}}. +#' @param DateStart UTC start date. +#' @param DateStop UTC stop date. +#' @param TResolution User-specified temporal resolution for aggregation. +#' @param BaseTResolution Dataset-specific native temporal resolution. +#' @param TStep User-specified time step for aggregation. +#' @param BaseTStep Dataset-specific native time step. + +#' @return Character - target resolution formatted steps in data. +#' +TemporalAggregation.Check <- function( + QuerySeries, + DateStart, + DateStop, + TResolution, + BaseTResolution, + TStep, + BaseTStep +){ + + ## check clean division + if(BaseTResolution == TResolution){ ## this comes into play for hourly aggregates of ensemble data + if((TStep/BaseTStep) %%1!=0){ + stop("Your specified time range does not allow for a clean integration of your selected time steps. You specified a time series of raw data with a length of ", length(QueryTargetFormat), " (", BaseTResolution, " intervals of length ", BaseTStep, "). Applying your desired temporal aggregation of ", TResolution, " intervals of length ", TStep, " works out to ", round(TStep/BaseTStep, 3), " intervals. Please fix this so the specified time range can be cleanly divided into aggregation intervals.") + } + QueryTargetSteps <- paste("Ensembling at base resolution, Factor =", TStep/BaseTStep) + # print("ensemble detected") + return(QueryTargetSteps) + } + + # limit query series to what will be retained + QuerySeries <- QuerySeries[as.POSIXct(QuerySeries, tz = "UTC") >= DateStart & as.POSIXct(QuerySeries, tz = "UTC") <= DateStop] + ## extract format of interest + Form <- substr(TResolution, 1, 1) + Form <- ifelse(Form %in% c("h", "y"), toupper(Form), Form) + + ## extract desired format + QueryTargetFormat <- format(as.POSIXct(QuerySeries, tz = "UTC"), paste0("%", Form)) + QueryTargetSteps <- unique(QueryTargetFormat) + + if((length(QueryTargetSteps) / TStep) %%1!=0){ + stop("Your specified time range does not allow for a clean integration of your selected time steps. You specified a time series of raw data with a length of ", length(QueryTargetFormat), " (", BaseTResolution, " intervals of length ", BaseTStep, "). Applying your desired temporal aggregation of ", TResolution, " intervals of length ", TStep, " works out to ", round(length(QueryTargetSteps) / TStep, 3), " intervals. Please fix this so the specified time range can be cleanly divided into aggregation intervals.") + } + return(QueryTargetSteps) +} diff --git a/R/data.R b/R/data.R new file mode 100644 index 0000000..159df78 --- /dev/null +++ b/R/data.R @@ -0,0 +1,23 @@ +#' Coordinates of select summits in Jotunheimen national park +#' +#' A data frame with four rows and three columns (Summit, Lon, Lat). +#' +#' @format a data.frame +#' +"Mountains_df" + +#' Shapefile of boundaries of Jotunheimen national park +#' +#' An sf object containing a polygon describing the boundaries of Jotunheimen national park +#' +#' @format a sf POLYGON +#' +"Jotunheimen_poly" + +#' #' Daily Air-Temperature Raster across Southern and Central Norway +#' #' +#' #' A SpatRaster object containing five layers of daily mean air-temperature data for the time-period 1995-01-01 to 1995-01-5 sourced from ERA5-Land. +#' # +#' #' @format a SpatRaster +#' #' @references Muñoz Sabater, J. (2019): ERA5-Land hourly data from 1950 to present. Copernicus Climate Change Service (C3S) Climate Data Store (CDS). DOI: 10.24381/cds.e2161bac (Accessed on 2024-06-24) +#' "CDS_rast" diff --git a/R/download.R b/R/download.R index 8bc9fd0..2004da9 100644 --- a/R/download.R +++ b/R/download.R @@ -57,6 +57,8 @@ download_ERA <- function(Variable = NULL, PrecipFix = FALSE, Type = "reanalysis" Cores = 1, TimeOut = 36000, SingularDL = FALSE, ...) { + stop("Function currently deprecated as KrigR undergoes major re-development. Please use the stable release to gain access to this functionality.") + if(verbose){message("download_ERA() is starting. Depending on your specifications, this can take a significant time.")} if(verbose){ @@ -556,6 +558,8 @@ download_DEM <- function(Train_ras = NULL, Shape = NULL, Buffer = 0.5, ID = "ID", Dir = getwd(), Keep_Temporary = FALSE, Source = "USGS"){ + stop("Function currently deprecated as KrigR undergoes major re-development. Please use the stable release to gain access to this functionality.") + ### PREPARATION ----- Extent <- extent(Train_ras) # extract extent for later cropping if(Source == "USGS"){ diff --git a/R/krigr.R b/R/krigr.R new file mode 100644 index 0000000..45f5e74 --- /dev/null +++ b/R/krigr.R @@ -0,0 +1,308 @@ +#' (multi-core) Kriging +#' +#' This function statistically downscales input data using covariate data and the kriging methodology. The function can be run in two ways: +#' \enumerate{ +#' \item \strong{By Itself}: Use the arguments Data, Covariates_coarse, Covariates_fine when you already have raster files for your data which is to be downscaled as well as covariate raster data. +#' \item \strong{From Scratch}: Use the arguments Variable, Type, DataSet, DateStart, DateStop, TResolution, TStep, Extent, Dir, FileName, API_Key, API_User, and arget_res. By doing so, krigR will call the functions download_ERA() and download_DEM() for one coherent kriging workflow. Note that this process does not work when targetting UERRA data. +#' } +#' Use optional arguments such as Dir, FileName, Keep_Temporary, SingularTry, KrigingEquation and Cores for ease of use, substitution of non-GMTED2010 covariates, and parallel processing. +#' +#' @param Data Raster file which is to be downscaled. +#' @param Covariates_coarse Raster file containing covariates at training resolution. +#' @param Covariates_fine Raster file containing covariates at target resolution. +#' @param KrigingEquation Formula or character string specifying which covariates to use and how. Layer names in Covariates_coarse and Covariates_fine need to match Parameters in this formula. Needs to start with "X ~ ". X can read anything you like. +#' @param Dir Optional. Directory specifying where to place final kriged product. Default is current working directory. +#' @param FileName Optional. A file name for the netcdf produced. Default is a combination parameters in the function call. +#' @param Keep_Temporary Logical, whether to delete individual kriging products of layers in Data after processing. Default is TRUE. +#' @param Cores Numeric. How many cores to use. If you want output to your console during the process, use Cores == 1. Parallel processing is carried out when Cores is bigger than 1. Default is detecting all cores of your machine. +#' @param SingularTry Numeric. How often to try kriging of each layer of the input. This usually gets around issues of singular covariance matrices in the kriging process, but takes some time. Default is 10 +#' @param Variable Optional, calls download_ERA(). ERA5(Land)-contained climate variable. +#' @param PrecipFix Optional. Era5(-land) total precipitation is recorded in cumulative steps per hour from the 00:00 time mark per day. Setting PrecipFix to TRUE converts these into records which represent the total precipitation per hour. Monthly records in Era5(-land) express the average daily total precipitation. Setting this argument to TRUE multiplies monthly records by the number of days per the respective month(s) to get to total precipitation records instead of average. Default is FALSE. +#' @param Type Optional. Whether to download reanalysis ('reanalysis') or ensemble ('ensemble_members', 'ensemble_mean', or 'ensemble_spread') data. Passed on to download_ERA. +#' @param DataSet Optional. Which ERA5 data set to download data from. 'era5' or 'era5-land'. Passed on to download_ERA. +#' @param DateStart Optional. Date ('YYYY-MM-DD') at which to start time series of downloaded data. Passed on to download_ERA. +#' @param DateStop Optional. Date ('YYYY-MM-DD') at which to stop time series of downloaded data. Passed on to download_ERA. +#' @param TResolution Optional. Temporal resolution of final product. hour', 'day', 'month'. Passed on to download_ERA. +#' @param TStep Optional. Which time steps (numeric) to consider for temporal resolution. Passed on to download_ERA. +#' @param FUN Optional. A raster calculation argument as passed to `raster::stackApply()`. This controls what kind of data to obtain for temporal aggregates of reanalysis data. Specify 'mean' (default) for mean values, 'min' for minimum values, and 'max' for maximum values, among others. +#' @param Extent Optional, download data according to rectangular bounding box. specify as extent() object or as a raster, a SpatialPolygonsDataFrame object, or a data.frame object. If Extent is a SpatialPolygonsDataFrame, this will be treated as a shapefile and the output will be cropped and masked to this shapefile. If Extent is a data.frame of geo-referenced point records, it needs to contain Lat and Lon columns as well as a non-repeating ID-column. Passed on to download_ERA and download_DEM. +#' @param Buffer Optional. Identifies how big a rectangular buffer to draw around points if Extent is a data frame of points. Buffer is expressed as centessimal degrees. Passed on to download_ERA and download_DEM. +#' @param ID Optional. Identifies which column in Extent to use for creation of individual buffers if Extent is a data.frame. Passed on to download_ERA and download_DEM. +#' @param Target_res Optional. The target resolution for the kriging step (i.e. which resolution to downscale to). An object as specified/produced by raster::res(). Passed on to download_DEM. +#' @param Source Optional, character. Whether to attempt download from the official USGS data viewer (Source = "USGS") or a static copy of the data set on a private drive (Source = "Drive"). Default is "USGS". Use this if the USGS viewer is unavailable. Passed on to download_DEM. +#' @param API_Key Optional. ECMWF cds API key. Passed on to download_ERA. +#' @param API_User Optional. ECMWF cds user number. Passed on to download_ERA. +#' @param nmax Optional. Controls local kriging. Number of nearest observations to be used kriging of each observation. Default is to use all available (Inf). You can specify as a number (numeric). +#' @param TryDown Optional, numeric. How often to attempt the download of each individual file (if querying data download) that the function queries from the server. This is to circumvent having to restart the entire function when encountering connectivity issues. +#' @param verbose Optional, logical. Whether to report progress of data download (if queried) in the console or not. +#' @param TimeOut Numeric. The timeout for each download in seconds. Default 36000 seconds (10 hours). +#' @param SingularDL Logical. Whether to force download of data in one call to CDS or automatically break download requests into individual monthly downloads. Default is FALSE. +#' @return A list object containing the downscaled data as well as the standard error for downscaling as well as the call to the krigR function, and two NETCDF (.nc) file in the specified directory which are the two data contents of the aforementioned list. A temporary directory is populated with individual NETCDF (.nc) files throughout the runtime of krigR which is deleted upon completion if Keep_Temporary = TRUE and all layers in the Data raster object were kriged successfully. +#' @examples +#' \dontrun{ +#' ## THREE-STEP PROCESS (By Itself) +#' # Downloading ERA5-Land air temperature reanalysis data in 12-hour intervals for 02/01/1995 - 04/01/1995 (DD/MM/YYYY). API User and Key in this example are non-functional. Substitute with your user number and key to run this example. +#' Extent <- extent(c(11.8,15.1,50.1,51.7)) # roughly the extent of Saxony +#' API_User <- "..." +#' API_Key <- "..." +#' State_Raw <- download_ERA( +#' Variable = "2m_temperature", +#' DataSet = "era5-land", +#' DateStart = "1995-01-02", +#' DateStop = "1995-01-04", +#' TResolution = "hour", +#' TStep = 12, +#' Extent = Extent, +#' API_User = API_User, +#' API_Key = API_Key +#' ) +#' State_Raw # a raster brick with 6 layers at resolution of ~0.1° +#' # Downloading GMTED2010-data at resolution and extent obtained by a call to download_ERA and a target resolution of .02. +#' Covs_ls <- download_DEM( +#' Train_ras = State_Raw, +#' Target_res = .02, +#' Keep_Temporary = TRUE +#' ) +#' Covs_ls # a list with two elements: (1) GMTED 2010 data at training resolution, and (2) GMTED 2010 data aggregated as close as possible to a resolution of 0.02 +#' # Kriging the data sets prepared with the previous functions. +#' State_Krig <- krigR( +#' Data = State_Raw, # data we want to krig as a raster object +#' Covariates_coarse = Covs_ls[[1]], # training covariate as a raster object +#' Covariates_fine = Covs_ls[[2]], # target covariate as a raster object +#' ) +#' +#' ## PIPELINE (From Scratch) +#' #' # Downloading ERA5-Land air temperature reanalysis data in 12-hour intervals for 02/01/1995 - 04/01/1995 (DD/MM/YYYY), downloading and preparing GMTED 2010 covariate data, and kriging. API User and Key in this example are non-functional. Substitute with your user number and key to run this example. This example produces the same output as the example above. +#' Extent <- extent(c(11.8,15.1,50.1,51.7)) # roughly the extent of Saxony +#' API_User <- "..." +#' API_Key <- "..." +#' Pipe_Krig <- krigR( +#' Variable = "2m_temperature", +#' Type = "reanalysis", +#' DataSet = "era5-land", +#' DateStart = "1995-01-02", +#' DateStop = "1995-01-04", +#' TResolution = "hour",# +#' TStep = 12, +#' Extent = Extent, +#' API_User = API_User, +#' API_Key = API_Key, +#' Target_res = .02, +#' ) +#' } +#' +#' @export +krigR <- function(Data = NULL, Covariates_coarse = NULL, Covariates_fine = NULL, KrigingEquation = "ERA ~ DEM", Cores = detectCores(), Dir = getwd(), FileName, Keep_Temporary = TRUE, SingularTry = 10, Variable, PrecipFix = FALSE, Type = "reanalysis", DataSet = "era5-land", DateStart, DateStop, TResolution = "month", TStep = 1, FUN = 'mean', Extent, Buffer = 0.5, ID = "ID", API_Key, API_User, Target_res, Source = "USGS", nmax = Inf, TryDown = 10, verbose = TRUE, TimeOut = 36000, SingularDL = FALSE, ...){ + + stop("Function currently deprecated as KrigR undergoes major re-development. Please use the stable release to gain access to this functionality.") + + ## CALL LIST (for storing how the function as called in the output) ---- + if(is.null(Data)){ + Data_Retrieval <- list(Variable = Variable, + Type = Type, + PrecipFix = PrecipFix, + DataSet = DataSet, + DateStart = DateStart, + DateStop = DateStop, + TResolution = TResolution, + TStep = TStep, + Extent = Extent) + }else{ + Data_Retrieval <- "None needed. Data was not queried via krigR function, but supplied by user." + } + ## CLIMATE DATA (call to download_ERA function if no Data set is specified) ---- + if(is.null(Data)){ # data check: if no data has been specified + Data <- download_ERA(Variable = Variable, PrecipFix = PrecipFix, Type = Type, DataSet = DataSet, DateStart = DateStart, DateStop = DateStop, TResolution = TResolution, TStep = TStep, FUN = FUN, Extent = Extent, API_User = API_User, API_Key = API_Key, Dir = Dir, TryDown = TryDown, verbose = verbose, ID = ID, Cores = Cores, TimeOut = TimeOut, SingularDL = SingularDL) + } # end of data check + + ## COVARIATE DATA (call to download_DEM function when no covariates are specified) ---- + if(is.null(Covariates_coarse) & is.null(Covariates_fine)){ # covariate check: if no covariates have been specified + if(class(Extent) == "SpatialPolygonsDataFrame" | class(Extent) == "data.frame"){ # Extent check: if Extent input is a shapefile + Shape <- Extent # save shapefile for use as Shape in masking covariate data + }else{ # if Extent is not a shape, then extent specification is already baked into Data + Shape <- NULL # set Shape to NULL so it is ignored in download_DEM function when masking is applied + } # end of Extent check + Covs_ls <- download_DEM(Train_ras = Data, Target_res = Target_res, Shape = Shape, Buffer = Buffer, ID = ID, Keep_Temporary = Keep_Temporary, Dir = Dir, Source = Source) + Covariates_coarse <- Covs_ls[[1]] # extract coarse covariates from download_DEM output + Covariates_fine <- Covs_ls[[2]] # extract fine covariates from download_DEM output + } # end of covariate check + + ## KRIGING FORMULA (assure that KrigingEquation is a formula object) ---- + KrigingEquation <- as.formula(KrigingEquation) + + ## CALL LIST (for storing how the function as called in the output) ---- + Call_ls <- list(Data = SummarizeRaster(Data), + Covariates_coarse = SummarizeRaster(Covariates_coarse), + Covariates_fine = SummarizeRaster(Covariates_fine), + KrigingEquation = KrigingEquation, + Cores = Cores, + FileName = FileName, + Keep_Temporary = Keep_Temporary, + nmax = nmax, + Data_Retrieval = Data_Retrieval) + + ## SANITY CHECKS (step into check_Krig function to catch most common error messages) ---- + Check_Product <- check_Krig(Data = Data, CovariatesCoarse = Covariates_coarse, CovariatesFine = Covariates_fine, KrigingEquation = KrigingEquation) + KrigingEquation <- Check_Product[[1]] # extract KrigingEquation (this may have changed in check_Krig) + DataSkips <- Check_Product[[2]] # extract which layers to skip due to missing data (this is unlikely to ever come into action) + Terms <- unique(unlist(strsplit(labels(terms(KrigingEquation)), split = ":"))) # identify which layers of data are needed + + ## DATA REFORMATTING (Kriging requires spatially referenced data frames, reformatting from rasters happens here) --- + Origin <- raster::as.data.frame(Covariates_coarse, xy = TRUE) # extract covariate layers + Origin <- Origin[, c(1:2, which(colnames(Origin) %in% Terms))] # retain only columns containing terms + + Target <- raster::as.data.frame(Covariates_fine, xy = TRUE) # extract covariate layers + Target <- Target[, c(1:2, which(colnames(Target) %in% Terms))] # retain only columns containing terms + Target <- na.omit(Target) + suppressWarnings(gridded(Target) <- ~x+y) # establish a gridded data product ready for use in kriging + Target@grid@cellsize[1] <- Target@grid@cellsize[2] # ensure that grid cells are square + + ## SET-UP TEMPORARY DIRECTORY (this is where kriged products of each layer will be saved) ---- + Dir.Temp <- file.path(Dir, paste("Kriging", FileName, sep="_")) + if(!dir.exists(Dir.Temp)){dir.create(Dir.Temp)} + + ## KRIGING SPECIFICATION (this will be parsed and evaluated in parallel and non-parallel evaluations further down) ---- + looptext <- " + OriginK <- cbind(Origin, raster::extract(x = Data[[Iter_Krige]], y = Origin[,1:2], df=TRUE)[, 2]) # combine data of current data layer with training covariate data + OriginK <- na.omit(OriginK) # get rid of NA cells + colnames(OriginK)[length(Terms)+3] <- c(terms(KrigingEquation)[[2]]) # assign column names + suppressWarnings(gridded(OriginK) <- ~x+y) # generate gridded product + OriginK@grid@cellsize[1] <- OriginK@grid@cellsize[2] # ensure that grid cells are square + + Iter_Try = 0 # number of tries set to 0 + kriging_result <- NULL + while(class(kriging_result)[1] != 'autoKrige' & Iter_Try < SingularTry){ # try kriging SingularTry times, this is because of a random process of variogram identification within the automap package that can fail on smaller datasets randomly when it isn't supposed to + try(invisible(capture.output(kriging_result <- autoKrige(formula = KrigingEquation, input_data = OriginK, new_data = Target, nmax = nmax))), silent = TRUE) + Iter_Try <- Iter_Try +1 + } + if(class(kriging_result)[1] != 'autoKrige'){ # give error if kriging fails + message(paste0('Kriging failed for layer ', Iter_Krige, '. Error message produced by autoKrige function: ', geterrmessage())) + } + + ## retransform to raster + try( # try fastest way - this fails with certain edge artefacts in meractor projection and is fixed by using rasterize + Krig_ras <- raster(x = kriging_result$krige_output, layer = 1), # extract raster from kriging product + silent = TRUE + ) + try( + Var_ras <- raster(x = kriging_result$krige_output, layer = 3), # extract raster from kriging product + silent = TRUE + ) + if(!exists('Krig_ras') & !exists('Var_ras')){ + Krig_ras <- rasterize(x = kriging_result$krige_output, y = Covariates_fine[[1]])[[2]] # extract raster from kriging product + Var_ras <- rasterize(x = kriging_result$krige_output, y = Covariates_fine)[[4]] # extract raster from kriging product + } + crs(Krig_ras) <- crs(Data) # setting the crs according to the data + crs(Var_ras) <- crs(Data) # setting the crs according to the data + + if(Cores == 1){ + Ras_Krig[[Iter_Krige]] <- Krig_ras + Ras_Var[[Iter_Krige]] <- Var_ras + } # stack kriged raster into raster list if non-parallel computing + + terra::writeCDF(x = as(brick(Krig_ras), 'SpatRaster'), filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_data.nc')), overwrite = TRUE) + # writeRaster(x = Krig_ras, filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_data.nc')), overwrite = TRUE, format='CDF') # save kriged raster to temporary directory + terra::writeCDF(x = as(brick(Var_ras), 'SpatRaster'), filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_SE.nc')), overwrite = TRUE) + # writeRaster(x = Var_ras, filename = file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_SE.nc')), overwrite = TRUE, format='CDF') # save kriged raster to temporary directory + + if(Cores == 1){ # core check: if processing non-parallel + if(Count_Krige == 1){ # count check: if this was the first actual computation + T_End <- Sys.time() # record time at which kriging was done for current layer + Duration <- as.numeric(T_End)-as.numeric(T_Begin) # calculate how long it took to krig on layer + message(paste('Kriging of remaining ', nlayers(Data)-Iter_Krige, ' data layers should finish around: ', as.POSIXlt(T_Begin + Duration*nlayers(Data), tz = Sys.timezone(location=TRUE)), sep='')) # console output with estimate of when the kriging should be done + ProgBar <- txtProgressBar(min = 0, max = nlayers(Data), style = 3) # create progress bar when non-parallel processing + Count_Krige <- Count_Krige + 1 # raise count by one so the stimator isn't called again + } # end of count check + setTxtProgressBar(ProgBar, Iter_Krige) # update progress bar with number of current layer + } # end of core check + " + + ## KRIGING PREPARATION (establishing objects which the kriging refers to) ---- + Ras_Krig <- as.list(rep(NA, nlayers(Data))) # establish an empty list which will be filled with kriged layers + Ras_Var <- as.list(rep(NA, nlayers(Data))) # establish an empty list which will be filled with kriged layers + + if(verbose){message("Commencing Kriging")} + ## DATA SKIPS (if certain layers in the data are empty and need to be skipped, this is handled here) --- + if(!is.null(DataSkips)){ # Skip check: if layers need to be skipped + for(Iter_Skip in DataSkips){ # Skip loop: loop over all layers that need to be skipped + Ras_Krig[[Iter_Skip]] <- Data[[Iter_Skip]] # add raw data (which should be empty) to list + terra::writeCDF(x = as(brick(Ras_Krig[[Iter_Skip]]), 'SpatRaster'), filename = file.path(Dir.Temp, str_pad(Iter_Skip,4,'left','0')), overwrite = TRUE) + # writeRaster(x = Ras_Krig[[Iter_Skip]], filename = file.path(Dir.Temp, str_pad(Iter_Skip,4,'left','0')), overwrite = TRUE, format = 'CDF') # save raw layer to temporary directory, needed for loading back in when parallel processing + } # end of Skip loop + Layers_vec <- 1:nlayers(Data) # identify vector of all layers in data + Compute_Layers <- Layers_vec[which(!Layers_vec %in% DataSkips)] # identify which layers can actually be computed on + }else{ # if we don't need to skip any layers + Compute_Layers <- 1:nlayers(Data) # set computing layers to all layers in data + } # end of Skip check + + + ## ACTUAL KRIGING (carry out kriging according to user specifications either in parallel or on a single core) ---- + if(Cores > 1){ # Cores check: if parallel processing has been specified + ### PARALLEL KRIGING --- + ForeachObjects <- c("Dir.Temp", "Cores", "Data", "KrigingEquation", "Origin", "Target", "Covariates_coarse", "Covariates_fine", "Terms", "SingularTry", "nmax") # objects which are needed for each kriging run and are thus handed to each cluster unit + pb <- txtProgressBar(max = length(Compute_Layers), style = 3) + progress <- function(n){setTxtProgressBar(pb, n)} + opts <- list(progress = progress) + cl <- makeCluster(Cores) # Assuming Cores node cluster + registerDoSNOW(cl) # registering cores + foreach(Iter_Krige = Compute_Layers, # kriging loop over all layers in Data, with condition (%:% when(...)) to only run if current layer is not present in Dir.Temp yet + .packages = c("raster", "stringr", "automap", "ncdf4", "rgdal", "terra"), # import packages necessary to each itteration + .export = ForeachObjects, + .options.snow = opts) %:% when(!paste0(str_pad(Iter_Krige,4,"left","0"), '_data.nc') %in% list.files(Dir.Temp)) %dopar% { # parallel kriging loop + Ras_Krig <- eval(parse(text=looptext)) # evaluate the kriging specification per cluster unit per layer + } # end of parallel kriging loop + close(pb) + stopCluster(cl) # close down cluster + Files_krig <- list.files(Dir.Temp)[grep(pattern = "_data.nc", x = list.files(Dir.Temp))] + Files_var <- list.files(Dir.Temp)[grep(pattern = "_SE.nc", x = list.files(Dir.Temp))] + for(Iter_Load in 1:length(Files_krig)){ # load loop: load data from temporary files in Dir.Temp + Ras_Krig[[Iter_Load]] <- raster(file.path(Dir.Temp, Files_krig[Iter_Load])) # load current temporary file and write contents to list of rasters + Ras_Var[[Iter_Load]] <- raster(file.path(Dir.Temp, Files_var[Iter_Load])) # load current temporary file and write contents to list of rasters + } # end of load loop + }else{ # if non-parallel processing has been specified + ### NON-PARALLEL KRIGING --- + Count_Krige <- 1 # Establish count variable which is targeted in kriging specification text for producing an estimator + for(Iter_Krige in Compute_Layers){ # non-parallel kriging loop over all layers in Data + if(paste0(str_pad(Iter_Krige,4,'left','0'), '_data.nc') %in% list.files(Dir.Temp)){ # file check: if this file has already been produced + Ras_Krig[[Iter_Krige]] <- raster(file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_data.nc'))) # load already produced kriged file and save it to list of rasters + Ras_Var[[Iter_Krige]] <- raster(file.path(Dir.Temp, paste0(str_pad(Iter_Krige,4,'left','0'), '_SE.nc'))) + if(!exists("ProgBar")){ProgBar <- txtProgressBar(min = 0, max = nlayers(Data), style = 3)} # create progress bar when non-parallel processing} + setTxtProgressBar(ProgBar, Iter_Krige) # update progress bar + next() # jump to next layer + } # end of file check + T_Begin <- Sys.time() # record system time when layer kriging starts + eval(parse(text=looptext)) # evaluate the kriging specification per layer + } # end of non-parallel kriging loop + } # end of Cores check + + ## SAVING FINAL PRODUCT ---- + if(is.null(DataSkips)){ # Skip check: if no layers needed to be skipped + # convert list of kriged layers in actual rasterbrick of kriged layers + names(Ras_Krig) <- names(Data) + if(class(Ras_Krig) != "RasterBrick"){Ras_Krig <- brick(Ras_Krig)} + Krig_terra <- as(Ras_Krig, "SpatRaster") + names(Krig_terra) <- names(Data) + terra::writeCDF(x = Krig_terra, filename = file.path(Dir, paste0(FileName, ".nc")), overwrite = TRUE) + # writeRaster(x = Ras_Krig, filename = file.path(Dir, FileName), overwrite = TRUE, format="CDF") # save final product as raster + # convert list of kriged layers in actual rasterbrick of kriged layers + names(Ras_Var) <- names(Data) + if(class(Ras_Var) != "RasterBrick"){Ras_Var <- brick(Ras_Var)} + Var_terra <- as(Ras_Var, "SpatRaster") + names(Var_terra) <- names(Data) + + terra::writeCDF(x = Var_terra, filename = file.path(Dir, paste0("SE_", paste0(FileName, ".nc"))), overwrite = TRUE) + # writeRaster(x = Ras_Var, filename = file.path(Dir, paste0("SE_",FileName)), overwrite = TRUE, format="CDF") # save final product as raster + }else{ # if some layers needed to be skipped + warning(paste0("Some of the layers in your raster could not be kriged. You will find all the individual layers (kriged and not kriged) in ", Dir, ".")) + Keep_Temporary <- TRUE # keep temporary files so kriged products are not deleted + } # end of Skip check + + ### REMOVE FILES FROM HARD DRIVE --- + if(Keep_Temporary == FALSE){ # cleanup check + unlink(Dir.Temp, recursive = TRUE) + } # end of cleanup check + + Krig_ls <- list(Ras_Krig, Ras_Var, Call_ls) + names(Krig_ls) <- c("Kriging_Output", "Kriging_SE", "Call") + return(Krig_ls) # return raster or list of layers +} diff --git a/R/misc.R b/R/misc.R index d1b0082..9d31452 100644 --- a/R/misc.R +++ b/R/misc.R @@ -1,263 +1,3 @@ -#' Sanity checks before Kriging commences -#' -#' This function is called upon in the krigR function and performs sanity checks for some of the most common error sources in krigin thereby attempting to return more sensible error messages to the user than what is returned by default. -#' -#' @param Data A raster object containing the data to be kriged. -#' @param CovariatesCoarse A raster object containing covariates for kriging at training resolution. -#' @param CovariatesFine A raster object containing covariates for kriging at target resolution. -#' @param KrigingEquation A formula object obtained from a character vector via as.formula() specifying the covariates to be used in kriging. The covariates used have to be present and named as layers in CovariatesCoarse and CovariatesFine. -#' -#' @return A list containing a potentially altered KrigingEquation if needed as well as an identifier for data layers which need to be skipped when kriging due to a variety of reasons. -#' -check_Krig <- function(Data, CovariatesCoarse, CovariatesFine, KrigingEquation){ - ### RESOLUTIONS ---- - if(res(CovariatesFine)[1] < res(Data)[1]/10){ - warning("It is not recommended to use kriging for statistical downscaling of more than one order of magnitude. You are currently attempting this. Kriging will proceed.") - } - if(all.equal(res(CovariatesCoarse)[1], res(Data)[1]) != TRUE){ - stop(paste0("The resolution of your data (", res(Data)[1], ") does not match the resolution of your covariate data (", res(CovariatesCoarse)[1], ") used for training the kriging model. Kriging can't be performed!" )) - } - ### EXTENTS ---- - # if(extent(Data) == extent(-180, 180, -90, 90)){ - # stop("You are attempting to use kriging at a global extent. For reasons of computational expense and identity of relationships between covariates and variables not being homogenous across the globe, this is not recommended. Instead, try kriging of latitude bands if global kriging is really your goal.") - # } - if(!all.equal(extent(CovariatesCoarse), extent(Data))){ - stop("The extents of your data and training covariates don't match. Kriging can't be performed!") - } - - ### DATA AVAILABILITY ---- - DataSkips <- NULL # data layers without enough data to be skipped in kriging - Data_vals <- base::colSums(matrix(!is.na(values(Data)), ncol = nlayers(Data))) # a value of 0 indicates a layer only made of NAs - if(length(which(Data_vals < 2)) > 0){ - if(length(which(Data_vals < 2)) != nlayers(Data)){ - warning(paste0("Layer(s) ", paste(which(Data_vals == 0), collapse=", "), " of your data do(es) not contain enough data. Kriging will result in a raster identical do the input for this layer.")) - DataSkips <- which(Data_vals < 2) - }else{ - stop("Your Data does not contain enough values. Kriging can't be performed!") - } - } - CovCo_vals <- base::colSums(matrix(!is.na(values(CovariatesCoarse)), ncol = nlayers(CovariatesCoarse))) # a value of 0 indicates a layer only made of NAs - if(length(which(CovCo_vals < 2)) > 0){ - if(length(which(CovCo_vals < 2)) != nlayers(CovariatesCoarse)){ - warning(paste0("Layer(s) ", paste(which(CovCo_vals < 2), collapse=", "), " of your covariates at training resolution do(es) not contain enough data. This/these layer(s) is/are dropped. The Kriging equation might get altered.")) - CovariatesCoarse <- CovariatesCoarse[[-which(CovCo_vals < 2)]] - }else{ - stop("Your covariate data at training resolution does not contain enough values. Kriging can't be performed!") - } - } - CovFin_vals <- base::colSums(matrix(!is.na(values(CovariatesFine)), ncol = nlayers(CovariatesFine))) # a value of 0 indicates a layer only made of NAs - if(length(which(CovFin_vals < 2)) > 0){ - if(length(which(CovFin_vals < 2)) != nlayers(CovariatesFine)){ - warning(paste0("Layer(s) ", paste(which(CovFin_vals == 0), collapse=", "), " of your covariates at target resolution do(es) not contain enough data. This/these layer(s) is/are dropped.")) - CovariatesFine <- CovariatesFine[[-which(CovFin_vals < 2)]] - }else{ - stop("Your covariate data at target resolution does not contain enough values. Kriging can't be performed!") - } - } - ### EQUATION ---- - Terms <- unlist(strsplit(labels(terms(KrigingEquation)), split = ":")) # identify parameters called to in formula - Terms_Required <- unique(Terms) # isolate double-references (e.g. due to ":" indexing for interactions) - Terms_Present <- Reduce(intersect, list(Terms_Required, names(CovariatesCoarse), names(CovariatesFine))) # identify the terms that are available and required - if(sum(Terms_Required %in% Terms_Present) != length(Terms_Required)){ - if(length(Terms_Present) == 0){ # if none of the specified terms were found - KrigingEquation <- paste0("Data ~ ", paste(names(CovariatesCoarse), collapse = "+")) - warn <- paste("None of the terms specified in your KrigingEquation are present in the covariate data sets. The KrigingEquation has been altered to include all available terms in a linear model:", KrigingEquation) - }else{ # at least some of the specified terms were found - KrigingEquation <- paste0("Data ~ ", paste(Terms_Present, collapse = "+")) - warn <- paste("Not all of the terms specified in your KrigingEquation are present in the covariate data sets. The KrigingEquation has been altered to include all available and specified terms in a linear model:", KrigingEquation) - } - Cotinue <- menu(c("Yes", "No"), title=paste(warn, "Do you wish to continue using the new formula?")) - if(Cotinue == 2){ # break operation if user doesn't want this - stop("Kriging terminated by user due to formula issues.") - } - } - ### NA DATA IN LAYERS ---- - # CovariatesFine <- CovariatesFine[[which(names(CovariatesFine) %in% Terms_Present)]] # only look at layers that the krigignequation targets - # if(nlayers(CovariatesFine) > 1){ - # MaskedPix <- length(which(values(sum(CovariatesFine, na.rm = TRUE)) != 0)) # number of non-masked pixels in which data is present in at least one layer - # MissingPix <- length(which(!is.na(values(sum(CovariatesFine, na.rm = FALSE))))) # number of pixels in which all layers have data - # if(MissingPix < MaskedPix){ # when there are any pixels for which data is absent for at least one layer - # stop("One or more more of your target covariate layers is missing data in locations where data is present for other layers. Please either fill these pixels with data or omit terms targeting these layers from your Kriging equation.") - # } - # } - return(list(as.formula(KrigingEquation), DataSkips)) -} - -#' Summary of Raster file characteristics -#' -#' This function is called upon in the krigR function and summarizes Raster characteristics without carrying along the raster file itself. This is used to create lists tracking calls to the function krigR without bloating them too much. -#' -#' @param Object_ras A raster object. -#' -#' @return A list containing information about the input raster. -#' -SummarizeRaster <- function(Object_ras = NULL){ - Summary_ls <- list(Class = class(Object_ras), - Dimensions = list(nrow = nrow(Object_ras), - ncol = ncol(Object_ras), - ncell = ncell(Object_ras)), - Extent = Object_ras@extent, - CRS = crs(Object_ras), - layers = names(Object_ras)) - return(Summary_ls) -} - -#' Square Buffers Around Point Data -#' -#' Allow for drawing of buffer zones around point-location data for downloading and kriging of spatial data around point-locations. Overlapping individual buffers are merged. -#' -#' @param Points A data.frame containing geo-referenced points with Lat and Lon columns -#' @param Buffer Identifies how big a rectangular buffer to draw around points. Expressed as centessimal degrees. -#' @param ID Identifies which column in to use for creation of individual buffers. -#' -#' @return A shape made up of individual square buffers around point-location input. -#' -buffer_Points <- function(Points = NULL, Buffer = .5, ID = "ID"){ - # set the radius for the plots - radius <- Buffer # radius in meters - # define the plot edges based upon the plot radius. - yPlus <- Points$Lat+radius - xPlus <- Points$Lon+radius - yMinus <- Points$Lat-radius - xMinus <- Points$Lon-radius - # calculate polygon coordinates for each plot centroid. - square=cbind(xMinus,yPlus, # NW corner - xPlus, yPlus, # NE corner - xPlus,yMinus, # SE corner - xMinus,yMinus, # SW corner - xMinus,yPlus) # NW corner again - close ploygon - # Extract the plot ID information - ID = Points[,ID] - # create spatial polygons from coordinates - polys <- SpatialPolygons(mapply(function(poly, id) - { - xy <- matrix(poly, ncol=2, byrow=TRUE) - Polygons(list(Polygon(xy)), ID=id) - }, - split(square, row(square)), ID), - proj4string = CRS(as.character("+proj=utm +zone=11 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0")) - ) -} - - - -#' Range Masking with Edge Support -#' -#' Creating a raster mask identifying all cells in the original raster (`base.map`) which are at least partially covered by the supplied shapefile (`Shape`). -#' -#' @param base.map A raster within which coverage should be identified -#' @param Shape A polygon(-collection) whose coverage of the raster object is to be found. -#' -#' @return A raster layer. -#' -mask_Shape <- function(base.map = NULL, Shape = NULL){ - base.map[] <- NA - stars.base.map <- stars::st_as_stars(base.map) - # Subset shape file - select.ranges <- sf::st_as_sf(Shape) - # Cast polygon as lines instead - select.ranges.lines <- sf::st_cast(select.ranges, "MULTILINESTRING") - select.ranges.lines$STARS <- 1 - # Get centroids (FAST!) - range <- fasterize(select.ranges, base.map, fun = "first", background = 0) - # Get edges (slower than fasterize but faster than rasterize) - range.edges <- stars::st_rasterize(select.ranges.lines, stars.base.map, options = "ALL_TOUCHED=TRUE") - if(class(as.vector(range.edges[[1]])) == "stars"| class(as.vector(range.edges[[1]])) == "numeric"){ - range.edges <- as.vector(range.edges[[1]]) - range.edges <- ifelse(is.na(range.edges), 0, 1) - # Merge - range[] <- ifelse(range[] + range.edges, 1, 0) - } - range[range==0] <- NA # set all cells which the shape doesn't touch to NA - return(range) -} - -#' Sanity checks before Kriging commences -#' -#' This function is called upon in the krigR function and performs sanity checks for some of the most common error sources in krigin thereby attempting to return more sensible error messages to the user than what is returned by default. -#' -#' @param Data A raster object containing the data to be kriged. -#' @param CovariatesCoarse A raster object containing covariates for kriging at training resolution. -#' @param CovariatesFine A raster object containing covariates for kriging at target resolution. -#' @param KrigingEquation A formula object obtained from a character vector via as.formula() specifying the covariates to be used in kriging. The covariates used have to be present and named as layers in CovariatesCoarse and CovariatesFine. -#' -#' @return A list containing a potentially altered KrigingEquation if needed as well as an identifier for data layers which need to be skipped when kriging due to a variety of reasons. -#' -#'@export -check_Krig <- function(Data, CovariatesCoarse, CovariatesFine, KrigingEquation){ - ### RESOLUTIONS ---- - if(res(CovariatesFine)[1] < res(Data)[1]/10){ - warning("It is not recommended to use kriging for statistical downscaling of more than one order of magnitude. You are currently attempting this. Kriging will proceed.") - } - if(all.equal(res(CovariatesCoarse)[1], res(Data)[1]) != TRUE){ - stop(paste0("The resolution of your data (", res(Data)[1], ") does not match the resolution of your covariate data (", res(CovariatesCoarse)[1], ") used for training the kriging model. Kriging can't be performed!" )) - } - ### EXTENTS ---- - # if(extent(Data) == extent(-180, 180, -90, 90)){ - # stop("You are attempting to use kriging at a global extent. For reasons of computational expense and identity of relationships between covariates and variables not being homogenous across the globe, this is not recommended. Instead, try kriging of latitude bands if global kriging is really your goal.") - # } - if(!all.equal(extent(CovariatesCoarse), extent(Data))){ - stop("The extents of your data and training covariates don't match. Kriging can't be performed!") - } - - ### DATA AVAILABILITY ---- - DataSkips <- NULL # data layers without enough data to be skipped in kriging - Data_vals <- base::colSums(matrix(!is.na(values(Data)), ncol = nlayers(Data))) # a value of 0 indicates a layer only made of NAs - if(length(which(Data_vals < 2)) > 0){ - if(length(which(Data_vals < 2)) != nlayers(Data)){ - warning(paste0("Layer(s) ", paste(which(Data_vals == 0), collapse=", "), " of your data do(es) not contain enough data. Kriging will result in a raster identical do the input for this layer.")) - DataSkips <- which(Data_vals < 2) - }else{ - stop("Your Data does not contain enough values. Kriging can't be performed!") - } - } - CovCo_vals <- base::colSums(matrix(!is.na(values(CovariatesCoarse)), ncol = nlayers(CovariatesCoarse))) # a value of 0 indicates a layer only made of NAs - if(length(which(CovCo_vals < 2)) > 0){ - if(length(which(CovCo_vals < 2)) != nlayers(CovariatesCoarse)){ - warning(paste0("Layer(s) ", paste(which(CovCo_vals < 2), collapse=", "), " of your covariates at training resolution do(es) not contain enough data. This/these layer(s) is/are dropped. The Kriging equation might get altered.")) - CovariatesCoarse <- CovariatesCoarse[[-which(CovCo_vals < 2)]] - }else{ - stop("Your covariate data at training resolution does not contain enough values. Kriging can't be performed!") - } - } - CovFin_vals <- base::colSums(matrix(!is.na(values(CovariatesFine)), ncol = nlayers(CovariatesFine))) # a value of 0 indicates a layer only made of NAs - if(length(which(CovFin_vals < 2)) > 0){ - if(length(which(CovFin_vals < 2)) != nlayers(CovariatesFine)){ - warning(paste0("Layer(s) ", paste(which(CovFin_vals == 0), collapse=", "), " of your covariates at target resolution do(es) not contain enough data. This/these layer(s) is/are dropped.")) - CovariatesFine <- CovariatesFine[[-which(CovFin_vals < 2)]] - }else{ - stop("Your covariate data at target resolution does not contain enough values. Kriging can't be performed!") - } - } - ### EQUATION ---- - Terms <- unlist(strsplit(labels(terms(KrigingEquation)), split = ":")) # identify parameters called to in formula - Terms_Required <- unique(Terms) # isolate double-references (e.g. due to ":" indexing for interactions) - Terms_Present <- Reduce(intersect, list(Terms_Required, names(CovariatesCoarse), names(CovariatesFine))) # identify the terms that are available and required - if(sum(Terms_Required %in% Terms_Present) != length(Terms_Required)){ - if(length(Terms_Present) == 0){ # if none of the specified terms were found - KrigingEquation <- paste0("Data ~ ", paste(names(CovariatesCoarse), collapse = "+")) - warn <- paste("None of the terms specified in your KrigingEquation are present in the covariate data sets. The KrigingEquation has been altered to include all available terms in a linear model:", KrigingEquation) - }else{ # at least some of the specified terms were found - KrigingEquation <- paste0("Data ~ ", paste(Terms_Present, collapse = "+")) - warn <- paste("Not all of the terms specified in your KrigingEquation are present in the covariate data sets. The KrigingEquation has been altered to include all available and specified terms in a linear model:", KrigingEquation) - } - Cotinue <- menu(c("Yes", "No"), title=paste(warn, "Do you wish to continue using the new formula?")) - if(Cotinue == 2){ # break operation if user doesn't want this - stop("Kriging terminated by user due to formula issues.") - } - } - ### NA DATA IN LAYERS ---- - # CovariatesFine <- CovariatesFine[[which(names(CovariatesFine) %in% Terms_Present)]] # only look at layers that the krigignequation targets - # if(nlayers(CovariatesFine) > 1){ - # MaskedPix <- length(which(values(sum(CovariatesFine, na.rm = TRUE)) != 0)) # number of non-masked pixels in which data is present in at least one layer - # MissingPix <- length(which(!is.na(values(sum(CovariatesFine, na.rm = FALSE))))) # number of pixels in which all layers have data - # if(MissingPix < MaskedPix){ # when there are any pixels for which data is absent for at least one layer - # stop("One or more more of your target covariate layers is missing data in locations where data is present for other layers. Please either fill these pixels with data or omit terms targeting these layers from your Kriging equation.") - # } - # } - return(list(as.formula(KrigingEquation), DataSkips)) -} - #' Summary of Raster file characteristics #' #' This function is called upon in the krigR function and summarizes Raster characteristics without carrying along the raster file itself. This is used to create lists tracking calls to the function krigR without bloating them too much. diff --git a/data-raw/DATASET.R b/data-raw/DATASET.R new file mode 100644 index 0000000..dc8d7be --- /dev/null +++ b/data-raw/DATASET.R @@ -0,0 +1,33 @@ +## code to prepare `DATASET` dataset goes here + +## Mountains_df +Mountains_df <- data.frame( + Summit = c("Fannaråki", "Store Skagastølstind", "Galdhøppigen", "Knutshøe"), + Lon = c(7.6833, 7.7999, 8.2522, 9.2639), + Lat = c(61.5831, 61.4573, 61.6333, 61.5125) +) +usethis::use_data(Mountains_df) + +## CDS_ras +API_Key <- "Nope" +API_User <- "Nope" +numberOfCores <- 1 +Extent_ext <- terra::ext(c(4, 13, 58, 63.5)) + +CDS_rast <- CDownloadS( + Variable = "2m_temperature", + DateStart = "1995-01-01 00:00", + DateStop = "1995-01-05 23:00", + TZone = "CET", + TResolution = "day", + Extent = Extent_ext, # ext(Jotunheimen_poly) + Dir = file.path(getwd(), "inst", "extdata"), + FileName = "CentralNorway", + API_User = API_User, + API_Key = API_Key) +usethis::use_data(CDS_rast) + +## Jotunheimen_poly +Jotunheimen_poly <- sf::st_read("data-raw/Shape/Shape-polygon.shp") +sf::st_transform(Jotunheimen_poly, crs =sf::st_crs(CDS_rast)) +usethis::use_data(Jotunheimen_poly) diff --git a/data-raw/Shape/Jotunheimen.nc b/data-raw/Shape/Jotunheimen.nc new file mode 100644 index 0000000..c8d761c Binary files /dev/null and b/data-raw/Shape/Jotunheimen.nc differ diff --git a/data-raw/Shape/Shape-polygon.cpg b/data-raw/Shape/Shape-polygon.cpg new file mode 100644 index 0000000..3ad133c --- /dev/null +++ b/data-raw/Shape/Shape-polygon.cpg @@ -0,0 +1 @@ +UTF-8 \ No newline at end of file diff --git a/data-raw/Shape/Shape-polygon.dbf b/data-raw/Shape/Shape-polygon.dbf new file mode 100644 index 0000000..5243b65 Binary files /dev/null and b/data-raw/Shape/Shape-polygon.dbf differ diff --git a/data-raw/Shape/Shape-polygon.prj b/data-raw/Shape/Shape-polygon.prj new file mode 100644 index 0000000..a30c00a --- /dev/null +++ b/data-raw/Shape/Shape-polygon.prj @@ -0,0 +1 @@ +GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] \ No newline at end of file diff --git a/data-raw/Shape/Shape-polygon.shp b/data-raw/Shape/Shape-polygon.shp new file mode 100644 index 0000000..1a8b15c Binary files /dev/null and b/data-raw/Shape/Shape-polygon.shp differ diff --git a/data-raw/Shape/Shape-polygon.shx b/data-raw/Shape/Shape-polygon.shx new file mode 100644 index 0000000..791e80e Binary files /dev/null and b/data-raw/Shape/Shape-polygon.shx differ diff --git a/data-raw/Shape/tile_1.tif.aux.json b/data-raw/Shape/tile_1.tif.aux.json new file mode 100644 index 0000000..006b6ef --- /dev/null +++ b/data-raw/Shape/tile_1.tif.aux.json @@ -0,0 +1,4 @@ +{ +"time":["1995-1-1 0:0:0"], +"timestep":"seconds" +} diff --git a/data-raw/Shape/tile_2.tif.aux.json b/data-raw/Shape/tile_2.tif.aux.json new file mode 100644 index 0000000..006b6ef --- /dev/null +++ b/data-raw/Shape/tile_2.tif.aux.json @@ -0,0 +1,4 @@ +{ +"time":["1995-1-1 0:0:0"], +"timestep":"seconds" +} diff --git a/data-raw/Shape/tile_3.tif.aux.json b/data-raw/Shape/tile_3.tif.aux.json new file mode 100644 index 0000000..006b6ef --- /dev/null +++ b/data-raw/Shape/tile_3.tif.aux.json @@ -0,0 +1,4 @@ +{ +"time":["1995-1-1 0:0:0"], +"timestep":"seconds" +} diff --git a/data-raw/Shape/tile_4.tif.aux.json b/data-raw/Shape/tile_4.tif.aux.json new file mode 100644 index 0000000..006b6ef --- /dev/null +++ b/data-raw/Shape/tile_4.tif.aux.json @@ -0,0 +1,4 @@ +{ +"time":["1995-1-1 0:0:0"], +"timestep":"seconds" +} diff --git a/data/Jotunheimen_poly.rda b/data/Jotunheimen_poly.rda new file mode 100644 index 0000000..5762124 Binary files /dev/null and b/data/Jotunheimen_poly.rda differ diff --git a/data/Mountains_df.rda b/data/Mountains_df.rda new file mode 100644 index 0000000..04f299e Binary files /dev/null and b/data/Mountains_df.rda differ diff --git a/inst/extdata/CentralNorway.nc b/inst/extdata/CentralNorway.nc new file mode 100644 index 0000000..7abd6d1 Binary files /dev/null and b/inst/extdata/CentralNorway.nc differ diff --git a/inst/extdata/Covariates_Target.nc b/inst/extdata/Covariates_Target.nc new file mode 100644 index 0000000..78cd198 Binary files /dev/null and b/inst/extdata/Covariates_Target.nc differ diff --git a/inst/extdata/Covariates_Train.nc b/inst/extdata/Covariates_Train.nc new file mode 100644 index 0000000..4e1bc33 Binary files /dev/null and b/inst/extdata/Covariates_Train.nc differ diff --git a/man/Buffer.pts.Rd b/man/Buffer.pts.Rd new file mode 100644 index 0000000..eb40d76 --- /dev/null +++ b/man/Buffer.pts.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Spatial.R +\name{Buffer.pts} +\alias{Buffer.pts} +\title{Square Buffers Around Point Data} +\usage{ +Buffer.pts(USER_pts, USER_buffer = 0.5) +} +\arguments{ +\item{USER_pts}{An sf POINT object} + +\item{USER_buffer}{Size of buffer in degrees} +} +\value{ +An sf polygon made up of individual square buffers around point-location input. +} +\description{ +Allow for drawing of buffer zones around point-location data for downloading and kriging of spatial data around point-locations. Overlapping individual buffers are merged. +} +\examples{ +data("Mountains_df") +User_pts <- Make.SpatialPoints(Mountains_df) +Buffer.pts(User_pts, USER_buffer = 0.5) + +} diff --git a/man/CDownloadS.Rd b/man/CDownloadS.Rd new file mode 100644 index 0000000..4398173 --- /dev/null +++ b/man/CDownloadS.Rd @@ -0,0 +1,194 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/CDownloadS.R +\name{CDownloadS} +\alias{CDownloadS} +\title{Downloading Data from ECMWF Climate Data Store} +\usage{ +CDownloadS( + Variable = NULL, + CumulVar = FALSE, + DataSet = "reanalysis-era5-land", + Type = NA, + DateStart, + DateStop, + TZone = "UTC", + TResolution = "month", + TStep = 1, + FUN = "mean", + Extent, + Buffer = 0.5, + Dir = getwd(), + FileName, + FileExtension = ".nc", + API_User, + API_Key, + TryDown = 10, + TimeOut = 36000, + TChunkSize = 6000, + Cores = 1, + verbose = TRUE, + Keep_Raw = FALSE, + Save_Final = TRUE +) +} +\arguments{ +\item{Variable}{Character. Desired variable from queried dataset. See \code{\link{Meta.Variables}} for options per dataset.} + +\item{CumulVar}{Logical. Some ECMWF CDS data is recorded in cumulative steps per hour/month from the 00:00 time mark per day. Setting CumulVar to TRUE converts these into records which represent the total records per hour using the \code{\link{Temporal.Cumul}} function. Monthly cumulative records express the average daily total value. Setting this argument to TRUE multiplies monthly records by the number of days per the respective month(s) to get to total records instead of average. Default is FALSE. This argument can only be set to TRUE for cumulatively recorded variables. See \code{\link{Meta.Variables}} for an overview of which variables at recorded cumulatively per dataset.} + +\item{DataSet}{Character. Which dataset to query data from. See currently supported datasets by calling \code{\link{Meta.List}}.} + +\item{Type}{Either NA or Character. Which kind of sub-type to query per data set. See \code{\link{Meta.QucikFacts}} for options per dataset.} + +\item{DateStart}{Character. Date ('YYYY-MM-DD HH:SS') at which to start time series of downloaded data.} + +\item{DateStop}{Character. Date ('YYYY-MM-DD HH:SS') at which to stop time series of downloaded data.} + +\item{TZone}{Character. Time zone in which to represent and evaluate time dimension of data. See the output of OlsonNames() for a full overview of supported specifications. Default is UTC.} + +\item{TResolution}{Character. Temporal resolution of final product. 'hour', 'day', 'month', or 'year'.} + +\item{TStep}{Numeric. Which time steps to consider for temporal resolution. For example, specify bi-monthly data records by setting TResolution to 'month' and TStep to 2.} + +\item{FUN}{A raster calculation argument as passed to `terra::tapp()`. This controls what kind of data to obtain for temporal aggregates of reanalysis data. Specify 'mean' (default) for mean values, 'min' for minimum values, and 'max' for maximum values, among others.} + +\item{Extent}{Optional, download data according to desired spatial specification. If missing/unspecified, total area of queried data set is used. Can be specified either as a raster object, an sf object, a terra object, or a data.frame. If Extent is a raster or terra object, data will be queried according to rectangular extent thereof. If Extent is an sf (MULTI-)POLYGON object, this will be treated as a shapefile and the output will be cropped and masked to this shapefile. If Extent is a data.frame of geo-referenced point records, it needs to contain Lat and Lon columns around which a buffered shapefile will be created using the Buffer argument.} + +\item{Buffer}{Optional, Numeric. Identifies how big a circular buffer to draw around points if Extent is a data.frame of points. Buffer is expressed as centessimal degrees.} + +\item{Dir}{Character/Directory Pointer. Directory specifying where to download data to.} + +\item{FileName}{Character. A file name for the produced file.} + +\item{FileExtension}{Character. A file extension for the produced file. Supported values are ".nc" (default) and ".tif" (better support for metadata).} + +\item{API_User}{Character; ECMWF cds user number.} + +\item{API_Key}{Character; ECMWF cds API key.} + +\item{TryDown}{Optional, numeric. How often to attempt the download of each individual file that the function queries from the CDS. This is to circumvent having to restart the entire function when encountering connectivity issues.} + +\item{TimeOut}{Numeric. The timeout for each download in seconds. Default 36000 seconds (10 hours).} + +\item{TChunkSize}{Numeric. Number of layers to bundle in each individual download. Default is 6000 to adhere to most restrictive CDS limits: https://cds.climate.copernicus.eu/live/limits.} + +\item{Cores}{Numeric. How many cores to use when carrying out temporal aggregation. Default is 1.} + +\item{verbose}{Logical. Whether to print/message function progress in console or not.} + +\item{Keep_Raw}{Logical. Whether to retain raw downloaded data or not. Default is FALSE.} + +\item{Save_Final}{Logical. Whether to write the final SpatRaster to the hard drive. Default is TRUE.} +} +\value{ +A SpatRaster object containing the downloaded, cropped/masked, and subsequently temporally aggregated data, and a file (either .nc or .tif) in the specified directory. + +The SpatRaster contains metadata/attributes as a named vector that can be retrieved with terra::metags(...): +\itemize{ +\item{Citation}{ - A string which to use for in-line citation of the data product obtained with CDownloadS}. +\item{KrigRCall.X}{ - Arguments passed to the CDownloadS function that produced the file (API credentials are omitted from these metadata)}. +} + +\strong{ATTENTION:} If data is loaded again from disk at a later point with a different function, take note that the time zone will have to be set anew and existing time parameters in the .nc contents will need to be converted to the desired time zone. Likewise, citation and KrigR-call metadata will not be loaded properly from a .nc when loading data through a different function. CDownloads() handles these .nc specific issues when loading .nc files created previously with CDownloadS from disk. +} +\description{ +This function is used to obtain data from the \href{https://cds.climate.copernicus.eu/#!/home}{Climate Data Store (CDS)} hosted by the \href{https://cds.climate.copernicus.eu/about-c3s}{Copernicus Climate Change Service (C3S)}. By default, this function breaks down download calls into intervals so as to avoid submitting queries which fail, downloads queried data from \href{https://www.ecmwf.int/}{ECMWF} servers according to user-specification, and fuses the downloaded files together according to user-demands. The actual time to download is dependent on ECMWF download queues. Users need an \href{https://cds.climate.copernicus.eu/api-how-to}{API key} for download staging and accept terms and conditions for the specific queried dataset(s). +} +\examples{ +\dontrun{ +## Raw data for one month of full globe +RawGlobe_rast <- CDownloadS( + Variable = "2m_temperature", + DataSet = "reanalysis-era5-land-monthly-means", + Type = "monthly_averaged_reanalysis", + # time-window, default set to range of dataset-type + DateStart = "1995-01-01 00:00", + DateStop = "1995-01-01 23:00", + TZone = "CET", + # temporal aggregation + TResolution = "month", + TStep = 1, + # file storing + FileName = "RawGlobe", + # API credentials + API_User = API_User, + API_Key = API_Key +) +terra::plot(RawGlobe_rast) + +## Monthly air temperature aggregated to bi-annual maximum by SpatRaster +CDS_rast <- terra::rast(system.file("extdata", "CentralNorway.nc", package="KrigR")) +BiAnnAirTemp_rast <- CDownloadS( + Variable = "2m_temperature", + DataSet = "reanalysis-era5-land-monthly-means", + Type = "monthly_averaged_reanalysis", + # time-window, default set to range of dataset-type + DateStart = "1995-01-01 00:00", + DateStop = "1996-12-31 23:00", + TZone = "EET", + # temporal aggregation + TResolution = "year", + TStep = 2, + # spatial + Extent = CDS_rast, + # file storing + FileName = "BiAnnAirTemp", + # API credentials + API_User = API_User, + API_Key = API_Key +) +terra::plot(BiAnnAirTemp_rast) + +## Hourly back-calculated precipitation aggregated to daily averages by shapefiles +data("Jotunheimen_poly") +Jotunheimen_poly +DailyBackCPrecip_rast <- CDownloadS( + Variable = "total_precipitation", + CumulVar = TRUE, + # time-window, default set to range of dataset-type + DateStart = "1995-01-01 00:00", + DateStop = "1995-01-03 23:00", + TZone = "CET", + # temporal aggregation + TResolution = "day", + # spatial + Extent = Jotunheimen_poly, + # file storing + FileName = "DailyBackCPrecip", + # API credentials + API_User = API_User, + API_Key = API_Key +) +terra::plot(DailyBackCPrecip_rast) + +## 6-hourly ensemble member spread sum for air temperature by buffered points +data("Mountains_df") +EnsembleSpreadSum6hour_rast <- CDownloadS( + Variable = "2m_temperature", + DataSet = "reanalysis-era5-single-levels", + Type = "ensemble_spread", + # time-window, default set to range of dataset-type + DateStart = "1995-01-01 00:00:00", + DateStop = "1995-01-01 21:00:00", + TZone = "UTC", + # temporal aggregation + TResolution = "hour", + TStep = 6, + FUN = sum, + # spatial + Extent = Mountains_df, + Buffer = 0.2, + # file storing + FileName = "EnsembleSpreadSum6hour", + FileExtension = ".tif", + # API credentials + API_User = API_User, + API_Key = API_Key, + Keep_Raw = TRUE +) +terra::plot(EnsembleSpreadSum6hour_rast) +} +} +\seealso{ +\code{\link{Meta.List}}, \code{\link{Meta.Variables}}, \code{\link{Meta.QuickFacts}}. +} diff --git a/man/Check.File.Rd b/man/Check.File.Rd new file mode 100644 index 0000000..131d277 --- /dev/null +++ b/man/Check.File.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Checks.R +\name{Check.File} +\alias{Check.File} +\title{Checking if a file already exists} +\usage{ +Check.File(FName, Dir = getwd(), loadFun, load = TRUE, verbose = TRUE) +} +\arguments{ +\item{FName}{File name} + +\item{Dir}{Directory where to look for file} + +\item{loadFun}{function with which to load filetype of FName} + +\item{load}{Logical. Whether to load the data or not} + +\item{verbose}{Logical. Whether to print/message function progress in console or not.} +} +\value{ +Either a data object or NULL +} +\description{ +If a file already exists in a given place, load that file +} +\examples{ +KrigR::Check.File( + FName = basename(system.file("extdata", "CentralNorway.nc", package="KrigR")), + Dir = dirname(system.file("extdata", "CentralNorway.nc", package="KrigR")), + loadFun = terra::rast + ) +} diff --git a/man/Check.Krig.Rd b/man/Check.Krig.Rd new file mode 100644 index 0000000..de56bc8 --- /dev/null +++ b/man/Check.Krig.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Checks.R +\name{Check.Krig} +\alias{Check.Krig} +\title{Sanity checks before Kriging commences} +\usage{ +Check.Krig(Data, CovariatesCoarse, CovariatesFine, KrigingEquation) +} +\arguments{ +\item{Data}{A SpatRaster object containing the data to be kriged.} + +\item{CovariatesCoarse}{A SpatRaster object containing covariates for kriging at training resolution.} + +\item{CovariatesFine}{A SPatRaster object containing covariates for kriging at target resolution.} + +\item{KrigingEquation}{A formula object obtained from a character vector via as.formula() specifying the covariates to be used in kriging. The covariates used have to be present and named as layers in CovariatesCoarse and CovariatesFine.} +} +\value{ +A list containing a potentially altered KrigingEquation if needed as well as an identifier for data layers which need to be skipped when kriging due to a variety of reasons. +} +\description{ +This function is called upon in the Kriging function and performs sanity checks for some of the most common error sources in kriging thereby attempting to return more sensible error messages to the user than what is returned by default. +} +\seealso{ +\code{\link{Kriging}}, \code{\link{KrigingCovariateSetup}}. +} diff --git a/man/CovariateSetup.Rd b/man/CovariateSetup.Rd new file mode 100644 index 0000000..d35710b --- /dev/null +++ b/man/CovariateSetup.Rd @@ -0,0 +1,89 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/CovariateSetup.R +\name{CovariateSetup} +\alias{CovariateSetup} +\title{Preparing Covariate Data for Use in Kriging} +\usage{ +CovariateSetup( + Training, + Target, + Covariates = "GMTED2010", + Source = "Origin", + Extent, + Buffer = 0.5, + Dir = getwd(), + Keep_Global = FALSE, + FileExtension = ".nc" +) +} +\arguments{ +\item{Training}{A SpatRaster file containing the data which is to be downscaled. Covariate data will be resampled to match this.} + +\item{Target}{Either numeric or a SpatRaster. If numeric, a single number representing the target resolution for the kriging step (i.e. wich resolution to downscale to). If a SpatRaster, data that the covariates and kriged products should align with. In case of a numeric input, covariate data is aggregated as closely as possible to desired resolution. If a SpatRaster, covariate data is resampled to match desired output directly.} + +\item{Covariates}{Either character or a SpatRaster. If character, obtain frequently used and provably useful covariate data (i.e., GMTED2010 and HWSD) and prepare for use in Kriging. Supported character values are "GMTED2010" and "HWSD". Note that currently, HWSD data download is not functional. If a SpatRaster, a user-supplied set of covariate data to be prepared for use in Kriging.} + +\item{Source}{Character. Only comes into effect when Covariates argument is specified as a character. Whether to attempt download of covariate data from the official sources (Source = "Origin") or a static copy of the data set on a private drive (Source = "Drive"). Default is "Origin".} + +\item{Extent}{Optional, prepare covariate data according to desired spatial specification. If missing/unspecified, maximal area of supplied data and covariat sets is used. Can be specified either as a raster object, an sf object, a terra object, or a data.frame. If Extent is a raster or terra object, covariates will be prepared according to rectangular extent thereof. If Extent is an sf (MULTI-)POLYGON object, this will be treated as a shapefile and the output will be cropped and masked to this shapefile. If Extent is a data.frame of geo-referenced point records, it needs to contain Lat and Lon columns around which a buffered shapefile will be created using the Buffer argument.} + +\item{Buffer}{Optional, Numeric. Identifies how big a circular buffer to draw around points if Extent is a data.frame of points. Buffer is expressed as centessimal degrees.} + +\item{Dir}{Character/Directory Pointer. Directory specifying where to download data to.} + +\item{Keep_Global}{Logical. Only comes into effect when Covariates argument is specified as a character. Whether to retain raw downloaded covariate data or not. Default is FALSE.} + +\item{FileExtension}{Character. A file extension for the produced files. Supported values are ".nc" (default) and ".tif" (better support for metadata).} +} +\value{ +A list containing two SpatRaster objects (Training and Target) ready to be used as covariates for kriging, and two files called Covariates_Target and Covariates_Train in the specified directory. + +The SpatRasters produced and stored when specifying the Covariates argument as a character string and setting the Keep_Global argument to TRUE contain metadata/attributes as a named vector that can be retrieved with terra::metags(...): +\itemize{ +\item{Citation}{ - A string which to use for in-line citation of the data product.} +} +} +\description{ +This function is used to setup products of covariate data ready for use in Kriging. This functiuonality can either be applied to user-supplied covariate data or ready-made data products such as the Harmised World Soil Data Base and the median statistic of the Global Multi-resolution Terrain Elevation Data (GMTED2010; available at \url{https://topotools.cr.usgs.gov/gmted_viewer/gmted2010_global_grids.php}). In case of the latter, the data is downloaded at 30 arc-sec latitude/longitude grid cells and subsequently resampled to match training and target resolutions specified by the user. +} +\examples{ +\dontrun{ +## Rectangular Covariate data according to input data +CDS_rast <- terra::rast(system.file("extdata", "CentralNorway.nc", package="KrigR")) +Covariates_ls <- CovariateSetup(Training = CDS_rast, + Target = 0.01, + Covariates = "GMTED2010", + Keep_Global = TRUE, + FileExtension = ".nc") +terra::plot(Covariates_ls[[1]]) +terra::plot(Covariates_ls[[2]]) + +## Shapefile-limited covariate data +data("Jotunheimen_poly") +CDS_rast <- terra::rast(system.file("extdata", "CentralNorway.nc", package="KrigR")) +Covariates_ls <- CovariateSetup(Training = CDS_rast, + Target = 0.01, + Covariates = "GMTED2010", + Extent = Jotunheimen_poly, + Keep_Global = TRUE, + FileExtension = ".nc") +terra::plot(Covariates_ls[[1]]) +terra::plot(Covariates_ls[[2]]) + +## buffered-point-limited covariate data +data("Mountains_df") +CDS_rast <- terra::rast(system.file("extdata", "CentralNorway.nc", package="KrigR")) +Covariates_ls <- CovariateSetup(Training = CDS_rast, + Target = 0.01, + Covariates = "GMTED2010", + Extent = Mountains_df, + Buffer = 0.2, + Keep_Global = TRUE, + FileExtension = ".nc") +terra::plot(Covariates_ls[[1]]) +terra::plot(Covariates_ls[[2]]) +} +} +\seealso{ +\code{\link{Kriging}}. +} diff --git a/man/Execute.Requests.Rd b/man/Execute.Requests.Rd new file mode 100644 index 0000000..13a3bd9 --- /dev/null +++ b/man/Execute.Requests.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/CDSAPI.R +\name{Execute.Requests} +\alias{Execute.Requests} +\title{Execute CDS Requests} +\usage{ +Execute.Requests(Requests_ls, Dir, API_User, API_Key, TryDown, verbose = TRUE) +} +\arguments{ +\item{Requests_ls}{List. ecmwfr-ready CDS requests formed with \code{\link{Make.Request}}.} + +\item{Dir}{Character. Directory where to save raw data.} + +\item{API_User}{Character. CDS API User} + +\item{API_Key}{Character. CDS API Key} + +\item{TryDown}{Numeric. How often to retry a failing request/download} + +\item{verbose}{Logical. Whether to print/message function progress in console or not.} +} +\value{ +No R object. Resulting files of CDS query/queries in signated directory. +} +\description{ +Loops over list of fully formed ecmwfr requests and executes these on CDS. +} +\seealso{ +\code{\link{Register.Credentials}}, \code{\link{Make.Request}}. +} diff --git a/man/Ext.Check.Rd b/man/Ext.Check.Rd new file mode 100644 index 0000000..a4b9e9a --- /dev/null +++ b/man/Ext.Check.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Spatial.R +\name{Ext.Check} +\alias{Ext.Check} +\title{Check extent specification} +\usage{ +Ext.Check(USER_ext) +} +\arguments{ +\item{USER_ext}{User-supplied Extent argument in download_ERA function call} +} +\value{ +A list containg (1) a terra/sf object and (2) the corresponding SpatExtent object. +} +\description{ +Try to convert user input into (1) a terra or sf object and also read out the corresponding (2) SpatExtent object. Supports inputs of classes belonging to the packages raster, terra, sf, and sp +} +\examples{ + ## raster +Check.Ext(raster::extent(c(9.87, 15.03, 49.89, 53.06))) +## terra +Check.Ext(terra::ext(c(9.87, 15.03, 49.89, 53.06))) +## sf +set.seed(42) +nb_pt <- 10 +dd <- data.frame(x = runif(nb_pt, 9.87, 15.03), y = runif(nb_pt, 49.89, 53.06), val = rnorm(nb_pt)) +sf <- sf::st_as_sf(dd, coords = c("x","y")) +Check.Ext(sf) +## sp +Check.Ext(as(sf, "Spatial")) + +} diff --git a/man/Handle.Spatial.Rd b/man/Handle.Spatial.Rd new file mode 100644 index 0000000..5b364d1 --- /dev/null +++ b/man/Handle.Spatial.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Spatial.R +\name{Handle.Spatial} +\alias{Handle.Spatial} +\title{Cropping & Range Masking with Edge Support} +\usage{ +Handle.Spatial(BASE, Shape) +} +\arguments{ +\item{BASE}{A SpatRaster within which coverage should be identified} + +\item{Shape}{Either a SPatExtent or an sf polygon(-collection) whose coverage of the raster object is to be found.} +} +\value{ +A SpatRaster. +} +\description{ +Cropped and masking the original SpatRaster (`BASE`) using supplied SpatExtent or shapefile (`Shape`) and retaining all pixels which are even just partially covered. +} +\examples{ +data("Jotunheimen_ras") +data("Jotunheimen_poly") +Mask.Shape(Jotunheimen_ras, Jotunheimen_poly) + +} diff --git a/man/Jotunheimen_poly.Rd b/man/Jotunheimen_poly.Rd new file mode 100644 index 0000000..c763243 --- /dev/null +++ b/man/Jotunheimen_poly.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{Jotunheimen_poly} +\alias{Jotunheimen_poly} +\title{Shapefile of boundaries of Jotunheimen national park} +\format{ +a sf POLYGON +} +\usage{ +Jotunheimen_poly +} +\description{ +An sf object containing a polygon describing the boundaries of Jotunheimen national park +} +\keyword{datasets} diff --git a/man/Kriging.Rd b/man/Kriging.Rd new file mode 100644 index 0000000..ae2076d --- /dev/null +++ b/man/Kriging.Rd @@ -0,0 +1,127 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Kriging.R +\name{Kriging} +\alias{Kriging} +\title{(multi-core) Kriging} +\usage{ +Kriging( + Data, + Covariates_training, + Covariates_target, + Equation = NULL, + Cores = detectCores(), + nmax = Inf, + Dir = getwd(), + FileName, + FileExtension, + Keep_Temporary = FALSE, + verbose = TRUE +) +} +\arguments{ +\item{Data}{SpatRaster which is to be downscaled.} + +\item{Covariates_training}{SpatRaster containing covariates at training resolution.} + +\item{Covariates_target}{SpatRaster containing covariates at target resolution.} + +\item{Equation}{Formula or character string specifying which covariates to use and how. Layer names in Covariates_training and Covariates_target need to match parameters in this formula. Do not include ". ~", just supply the righthand side of this formula like so: "Covariate1+Covariate2" or "Covariate1*Covariate2", etc.} + +\item{Cores}{Numeric. How many cores to use. Parallel processing is carried out when Cores is bigger than 1. Default is detecting all cores of your machine.} + +\item{nmax}{NUmeric. Controls local kriging. Number of nearest observations to be used kriging of each observation. Default is to use all available (Inf). You can specify as a number (numeric).} + +\item{Dir}{Character/Directory Pointer. Directory specifying where to place final kriged product. Default is current working directory.} + +\item{FileName}{Character. A file name for the produced files.} + +\item{FileExtension}{Character. A file extension for the produced file. Supported values are ".nc" (default) and ".tif" (better support for metadata).} + +\item{Keep_Temporary}{Logical, whether to delete individual kriging products of layers in Data after processing. Default is TRUE. These temporary files are stored in a newly created directory in Dir which is pre-pended with "TEMP-" and is deleted if Keep_Temporary = FALSE upon completion.} + +\item{verbose}{Optional, logical. Whether to report progress of data download (if queried) in the console or not.} +} +\value{ +A list object containing SpatRasters reporting (1) the downscaled data as well as (2) the standard deviation for downscaling. Also produces two files of specified extension in the specified directory which are the two data contents of the aforementioned list. A temporary directory is populated with individual files during the execution of this function which is deleted upon completion if Keep_Temporary = FALSE and all layers in the Data raster object were kriged successfully. + +The produced SpatRasters contains metadata/attributes as a named vector that can be retrieved with terra::metags(...): +\itemize{ +\item{Citation}{ - A string which to use for in-line citation of the data product obtained with Kriging}. +\item{KrigRCall.X}{ - Arguments passed to the Kriging function that produced the file}. +} + +\strong{ATTENTION:} If data is loaded again from disk at a later point with a different function, take note that citation and KrigR-call metadata will not be loaded properly from a .nc when loading data through a different function. Kriging() handles these .nc specific issues when loading .nc files created previously with Kriging() from disk. +} +\description{ +This function statistically downscales input data using covariate data and the kriging methodology. +Use optional arguments such as Dir, Keep_Temporary, KrigingEquation, nmax and Cores for ease of use, substitution of non-default covariates, localisation of kriging, and parallel processing. +} +\examples{ +\dontrun{ +## Kriging using pre-fab data with a rectangular extent and a fives layers of data with parallel processing +### Loading data +CDS_rast <- terra::rast(system.file("extdata", "CentralNorway.nc", package="KrigR")) +Cov_train <- terra::rast(system.file("extdata", "Covariates_Train.nc", package="KrigR")) +Cov_target <- terra::rast(system.file("extdata", "Covariates_Target.nc", package="KrigR")) +terra::varnames(Cov_train) <- terra::varnames(Cov_target) <- "GMTED2010" # we must ensure that the varnames in the Covariate file match +### kriging itself +ExtentKrig <- Kriging( + Data = CDS_rast, + Covariates_training = Cov_train, + Covariates_target = Cov_target, + Equation = "GMTED2010", + Cores = 2, + FileName = "KrigTest1", + FileExtension = ".nc", + Keep_Temporary = TRUE, + nmax = 40, + verbose = TRUE +) + +## Kriging using full KrigR pipeline with shapefile data +### Shapefile loading +data("Jotunheimen_poly") +### CDS data download +Qsoil_rast <- CDownloadS( + Variable = "Volumetric soil water layer 1", # can also specify as "volumetric_soil_water_layer_1" + # time-window, default set to range of dataset-type + DateStart = "1995-01-01 00:00", + DateStop = "1995-01-03 23:00", + TZone = "CET", + # temporal aggregation + TResolution = "day", + # spatial + Extent = Jotunheimen_poly, + # file storing + FileName = "KrigTest2_Raw", + # API credentials + API_User = API_User, + API_Key = API_Key +) + +### Covariate preparations +Covariates_ls <- CovariateSetup(Training = Qsoil_rast, + #' Target = 0.03, + Covariates = "GMTED2010", # this shiuld really be HWSD + Extent = Jotunheimen_poly, + Keep_Global = TRUE) +terra::varnames(Covariates_ls[[1]]) <- terra::varnames(Covariates_ls[[2]]) <- "GMTED2010" # we must ensure that the varnames in the Covariate file match + +### kriging itself +ShapeKrig <- Kriging( + Data = Qsoil_rast, + Covariates_training = Covariates_ls[[1]], + Covariates_target = Covariates_ls[[2]], + Equation = "GMTED2010", + Cores = 1, + FileName = "KrigTest2", + FileExtension = ".nc", + Keep_Temporary = FALSE, + nmax = 40, + verbose = TRUE +) +} +} +\seealso{ +\code{\link{CovariateSetup}}. +} diff --git a/man/Make.Request.Rd b/man/Make.Request.Rd new file mode 100644 index 0000000..630fcd5 --- /dev/null +++ b/man/Make.Request.Rd @@ -0,0 +1,54 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/CDSAPI.R +\name{Make.Request} +\alias{Make.Request} +\title{Form CDS Requests} +\usage{ +Make.Request( + QueryTimeWindows, + QueryDataSet, + QueryType, + QueryVariable, + QueryTimes, + QueryExtent, + QueryFormat, + Dir = getwd(), + verbose = TRUE, + API_User, + API_Key +) +} +\arguments{ +\item{QueryTimeWindows}{List. List of date ranges created by \code{\link{Make.RequestWindows}}.} + +\item{QueryDataSet}{Character. Dataset specified by user.} + +\item{QueryType}{Character. Dataset type specified by user.} + +\item{QueryVariable}{Character. CDS internal variable name.} + +\item{QueryTimes}{Character. Layers of data in the raw data set} + +\item{QueryExtent}{Character. Extent object created by Check.Ext(Extent)[c(4,1,3,2)]} + +\item{QueryFormat}{Character. File format queried by user} + +\item{Dir}{Directory pointer. Where to store CDS request outcomes.} + +\item{verbose}{Logical. Whether to print/message function progress in console or not.} + +\item{API_User}{Character. CDS API User} + +\item{API_Key}{Character. CDS API Key} +} +\value{ +List. Each element holding either (1) a list object representing a CDS request or (2) the value NA indicating that a file of this name is already present. +} +\description{ +Loops over time windows of defined size and creates a list of CDS requests. +} +\seealso{ +\code{\link{Make.RequestWindows}}, \code{\link{Register.Credentials}}, \code{\link{Execute.Requests}}. + +Make list of CDS Requests +} diff --git a/man/Make.RequestWindows.Rd b/man/Make.RequestWindows.Rd new file mode 100644 index 0000000..8476f46 --- /dev/null +++ b/man/Make.RequestWindows.Rd @@ -0,0 +1,49 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Temporal.R +\name{Make.RequestWindows} +\alias{Make.RequestWindows} +\title{Creating time windows for CDS queries} +\usage{ +Make.RequestWindows( + Dates_df, + BaseTResolution, + BaseTStep, + BaseTStart, + TChunkSize, + DataSet +) +} +\arguments{ +\item{Dates_df}{A two-column data frame (column names: "IN" and "UTC") holding POSIXct elements. Created with \code{\link{Make.UTC}}.} + +\item{BaseTResolution}{Character. Base temporal resolution of queried data on CDS} + +\item{BaseTStep}{Numeric. Base time steps of queried data on CDS} + +\item{BaseTStart}{POSIXct. Base starting date and time of queried data on CDS} + +\item{TChunkSize}{Numeric. Maximum amount of layers to include in each query} + +\item{DataSet}{Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}.} +} +\value{ +List. Contains: +\itemize{ +\item{QueryTimeWindows}{List of dates for individual CDS queries as used by \code{\link{Make.Request}}.}. +\item{QueryTimes}{Character. Layers of data in the raw data set}. +} +} +\description{ +Make a list holding date ranges for which to make individual CDS queries +} +\examples{ +IN_DateStart <- as.POSIXct("1995-01-01 00:00", tz = "CET") +IN_DateStop <- as.POSIXct("2005-01-01 23:00", tz = "CET") +Dates_df <- Make.UTC(DatesVec = c(IN_DateStart, IN_DateStop)) +Make.RequestWindows(Dates_df = Dates_df, + BaseTResolution = "hour", + BaseTStep = 24 + BaseTStart = as.POSIXct("1950-01-01 00:01", tz = "UTC") + TChunkSize = 12000) + +} diff --git a/man/Make.SpatialPoints.Rd b/man/Make.SpatialPoints.Rd new file mode 100644 index 0000000..26fa6a8 --- /dev/null +++ b/man/Make.SpatialPoints.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Spatial.R +\name{Make.SpatialPoints} +\alias{Make.SpatialPoints} +\title{Transform data frame-type inputs into sf} +\usage{ +Make.SpatialPoints(USER_df) +} +\arguments{ +\item{USER_df}{A data.frame containing geo-referenced points with Lat and Lon columns} +} +\value{ +An sf POINT object. +} +\description{ +Transform data frame with ID for querying functionality around point-loactions to SpatialPoints +} +\examples{ +data("Mountains_df") +Make.SpatialPoints(Mountains_df) + +} diff --git a/man/Make.UTC.Rd b/man/Make.UTC.Rd new file mode 100644 index 0000000..5fee861 --- /dev/null +++ b/man/Make.UTC.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Temporal.R +\name{Make.UTC} +\alias{Make.UTC} +\title{Resolve time zones as requested by user and UTC format with which to query from CDS} +\usage{ +Make.UTC(DatesVec = NULL) +} +\arguments{ +\item{DatesVec}{A vector of POSIXct objects} +} +\value{ +A data frame on input dates respective to user-queried timezone and their UTC counterparts. +} +\description{ +Create UTC counterparts of user-input dates for CDS queries +} +\examples{ +IN_DateStart <- as.POSIXct("1995-01-01 00:00", tz = "CET") +IN_DateStop <- as.POSIXct("2005-01-01 23:00", tz = "CET") +Dates_df <- Make.UTC(DatesVec = c(IN_DateStart, IN_DateStop)) +Dates_df + +} diff --git a/man/Meta.Check.Rd b/man/Meta.Check.Rd new file mode 100644 index 0000000..f015229 --- /dev/null +++ b/man/Meta.Check.Rd @@ -0,0 +1,54 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Meta.R +\name{Meta.Check} +\alias{Meta.Check} +\title{Fact sheet overview of data set} +\usage{ +Meta.Check( + DataSet = "reanalysis-era5-land", + Type = NA, + VariableCheck, + CumulativeCheck, + ExtentCheck, + DateCheck, + AggrCheck, + QueryTimes +) +} +\arguments{ +\item{Type}{NA or Character. Indicating which sub-type of the specified dataset is queried.} + +\item{VariableCheck}{Character. CDS-compliant variable name.} + +\item{CumulativeCheck}{Logical. Whether queried data will be attempted to be back-calculated from cumulative records.} + +\item{ExtentCheck}{Numeric. Vector defining bounding box of queried data.} + +\item{DateCheck}{data.frame. Containing user-specified dates and their UTC counterparts.} + +\item{AggrCheck}{list. List of length two (1 - TStep, 2 - TResolution).} + +\item{QueryTimes}{Character. Vector of time(s)-of-day for which layers are to be obtained.} + +\item{dataset}{Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}.} +} +\value{ +List. Contains: +\itemize{ +\item{QueryDataSet}{queried dataset}. +\item{QueryType}{queried sub-type of dataset}. +\item{QueryVariable}{queried variable}. +\item{QueryFormat}{file format supported by queried dataset}. +\item{QueryUnit}{unit of measurement of queried variable from queried dataset}. +} +} +\description{ +Read and return short overview of data set characteristics, supported types, extent, time frames and required arguments. +} +\examples{ +Meta.Check(DataSet = "reanalysis-era5-land", Type = NA, VariableCheck = "2m_temperature", CumulativeCheck = FALSE, ExtentCheck = c(53.06, 9.87, 49.89, 15.03), DateCheck = data.frame(IN = c(as.POSIXct("1995-01-01 CET"), as.POSIXct("2005-01-01 23:00:00 CET")), UTC = c(as.POSIXct("1994-12-31 23:00:00 UTC"), as.POSIXct("2005-01-01 22:00:00 UTC"))), AggrCheck = list(1, "hour"), QueryTimes = c('00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00')) + +} +\seealso{ +\code{\link{Meta.List}}, \code{\link{Meta.Read}}, \code{\link{Meta.Variables}}, \code{\link{Meta.DOI}}, \code{\link{Meta.QuickFacts}}. +} diff --git a/man/Meta.DOI.Rd b/man/Meta.DOI.Rd new file mode 100644 index 0000000..a3eb9d5 --- /dev/null +++ b/man/Meta.DOI.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Meta.R +\name{Meta.DOI} +\alias{Meta.DOI} +\title{DOI of data set} +\usage{ +Meta.DOI(dataset = "reanalysis-era5-land") +} +\arguments{ +\item{dataset}{Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}.} +} +\value{ +Character. DOI string for data set. +} +\description{ +Read and return DOI of data set for easy citation. +} +\examples{ +Meta.DOI() + +} +\seealso{ +\code{\link{Meta.List}}, \code{\link{Meta.Read}}, \code{\link{Meta.Variables}}, \code{\link{Meta.QuickFacts}}. +} diff --git a/man/Meta.List.Rd b/man/Meta.List.Rd new file mode 100644 index 0000000..f065e42 --- /dev/null +++ b/man/Meta.List.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Meta.R +\name{Meta.List} +\alias{Meta.List} +\title{List out all supported data sets} +\usage{ +Meta.List( + URL = "https://raw.githubusercontent.com/ErikKusch/KrigR/Development/metadata" +) +} +\arguments{ +\item{URL}{Path to where metadata files reside. Should not be changed from default.} +} +\value{ +A vector of supported datasets. +} +\description{ +Provide an overview of all data sets for which metadata files are present. +} +\examples{ +Meta.List() + +} +\seealso{ +\code{\link{Meta.Read}}, \code{\link{Meta.Variables}}, \code{\link{Meta.DOI}}, \code{\link{Meta.QuickFacts}}. +} diff --git a/man/Meta.NC.Rd b/man/Meta.NC.Rd new file mode 100644 index 0000000..b07ea3a --- /dev/null +++ b/man/Meta.NC.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Meta.R +\name{Meta.NC} +\alias{Meta.NC} +\title{Read or write metadata into NetCDF files} +\usage{ +Meta.NC(NC, FName, Attrs, Write = FALSE, Read = FALSE) +} +\arguments{ +\item{NC}{SpatRaster} + +\item{FName}{Filename including directory} + +\item{Attrs}{Named vector of metadata attributes} + +\item{Write}{Logical. Whether to write metadata} + +\item{Read}{Logical Whether to read metadata} +} +\value{ +A SpatRaster with metadata +} +\description{ +Read or write metadata attributes from/to netcdf file. +} diff --git a/man/Meta.QuickFacts.Rd b/man/Meta.QuickFacts.Rd new file mode 100644 index 0000000..bf6aa78 --- /dev/null +++ b/man/Meta.QuickFacts.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Meta.R +\name{Meta.QuickFacts} +\alias{Meta.QuickFacts} +\title{Fact sheet overview of data set} +\usage{ +Meta.QuickFacts(dataset = "reanalysis-era5-land") +} +\arguments{ +\item{dataset}{Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}.} +} +\value{ +A list object reporting information on queried dataset in standardised way: +\itemize{ +\item{DataSet}{data set string}. +\item{Type}{character, supported types of the data set}. +\item{URL}{character, url of CDS webpage corresponding to data set}. +\item{Description}{character, plain text description of data set scraped from CDS}. +\item{TResolution}{character, base temporal resolution of each layer in data set}. +\item{TStep}{numeric, vector of time step between layers in data set corresponding to Type}. +\item{TStart}{POSIXct, date and time at which first layer is available}. +\item{TEnd}{POSIXct or character, date and time at which first layer is available}. +\item{Projection}{crs of data set}. +\item{SpatialResolution}{numeric, resolution of data set in space in degrees}. +\item{CDSArguments}{list, required arguments for CDS call beyond standard arguments and also reporting default/options for common CDS query arguments}. +} +} +\description{ +Read and return short overview of data set characteristics, supported types, extent, time frames and required arguments. +} +\examples{ +Meta.QuickFacts() + +} +\seealso{ +\code{\link{Meta.List}}, \code{\link{Meta.Read}}, \code{\link{Meta.Variables}}, \code{\link{Meta.DOI}}. +} diff --git a/man/Meta.Read.Rd b/man/Meta.Read.Rd new file mode 100644 index 0000000..efed8d9 --- /dev/null +++ b/man/Meta.Read.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Meta.R +\name{Meta.Read} +\alias{Meta.Read} +\title{Data set overview} +\usage{ +Meta.Read( + URL = "https://raw.githubusercontent.com/ErikKusch/KrigR/Development/metadata", + dataset = "reanalysis-era5-land" +) +} +\arguments{ +\item{URL}{Path to where metadata files reside. Should not be changed from default.} + +\item{dataset}{Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}.} +} +\value{ +List. Contains information of data set, type, variables, resolution, citation, etc. +} +\description{ +Read and return metadata for specific data set. +} +\examples{ +Meta.Read() + +} +\seealso{ +\code{\link{Meta.List}}, \code{\link{Meta.Variables}}, \code{\link{Meta.DOI}}, \code{\link{Meta.QuickFacts}}. +} diff --git a/man/Meta.Register.Rd b/man/Meta.Register.Rd new file mode 100644 index 0000000..44e5acf --- /dev/null +++ b/man/Meta.Register.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Meta.R +\name{Meta.Register} +\alias{Meta.Register} +\title{Create a .txt tile holding the names of all supported data sets and their types} +\usage{ +Meta.Register(Dir = file.path(getwd(), "metadata")) +} +\arguments{ +\item{Dir}{directory in which metadata files (.RData objects) are stored locally} +} +\value{ +Nothing. But does write a .txt file into the specified directory. +} +\description{ +To be run only by the developer when adding support for new data sets and types. +} +\seealso{ +\code{\link{Meta.List}}, \code{\link{Meta.Read}}, \code{\link{Meta.Variables}}, \code{\link{Meta.DOI}}, \code{\link{Meta.QuickFacts}}. +} diff --git a/man/Meta.Variables.Rd b/man/Meta.Variables.Rd new file mode 100644 index 0000000..0a2da95 --- /dev/null +++ b/man/Meta.Variables.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Meta.R +\name{Meta.Variables} +\alias{Meta.Variables} +\title{Variables available within data set} +\usage{ +Meta.Variables(dataset = "reanalysis-era5-land") +} +\arguments{ +\item{dataset}{Character. Name of data set. Usually a set of words separated by dashes. See possible datasets by calling \code{\link{Meta.List}}.} +} +\value{ +Data frame. Contains five columns: +\itemize{ +\item{Variable}{clear name} +\item{CDSname}{name required for CDS query} +\item{Description}{plain text description of variable, scraped from CDS webpage} +\item{Unit}{unit of measurement} +\item{Cumulative}{logical, indexing whether a variable is recorded cumulatively or not} +} +} +\description{ +Read and return overview of variables available for specific data set. +} +\examples{ +Meta.Variables() + +} +\seealso{ +\code{\link{Meta.List}}, \code{\link{Meta.Read}}, \code{\link{Meta.DOI}}, \code{\link{Meta.QuickFacts}}. +} diff --git a/man/Mountains_df.Rd b/man/Mountains_df.Rd new file mode 100644 index 0000000..0089f78 --- /dev/null +++ b/man/Mountains_df.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{Mountains_df} +\alias{Mountains_df} +\title{Coordinates of select summits in Jotunheimen national park} +\format{ +a data.frame +} +\usage{ +Mountains_df +} +\description{ +A data frame with four rows and three columns (Summit, Lon, Lat). +} +\keyword{datasets} diff --git a/man/Register.Credentials.Rd b/man/Register.Credentials.Rd new file mode 100644 index 0000000..26b8053 --- /dev/null +++ b/man/Register.Credentials.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/CDSAPI.R +\name{Register.Credentials} +\alias{Register.Credentials} +\title{Register CDS API Credentials} +\usage{ +Register.Credentials(API_User, API_Key) +} +\arguments{ +\item{API_User}{Character. CDS API User} + +\item{API_Key}{Character. CDS API Key} +} +\value{ +No R object. An addition to the keychain if necessary. +} +\description{ +Just checks if provided API user and Key have already been added to keychain and adds them if necessary. +} +\seealso{ +\code{\link{Make.Request}}, \code{\link{Execute.Requests}}. +} diff --git a/man/SummarizeRaster.Rd b/man/SummarizeRaster.Rd index 7c34520..f9072bb 100644 --- a/man/SummarizeRaster.Rd +++ b/man/SummarizeRaster.Rd @@ -4,20 +4,14 @@ \alias{SummarizeRaster} \title{Summary of Raster file characteristics} \usage{ -SummarizeRaster(Object_ras = NULL) - SummarizeRaster(Object_ras = NULL) } \arguments{ \item{Object_ras}{A raster object.} } \value{ -A list containing information about the input raster. - A list containing information about the input raster. } \description{ -This function is called upon in the krigR function and summarizes Raster characteristics without carrying along the raster file itself. This is used to create lists tracking calls to the function krigR without bloating them too much. - This function is called upon in the krigR function and summarizes Raster characteristics without carrying along the raster file itself. This is used to create lists tracking calls to the function krigR without bloating them too much. } diff --git a/man/Temporal.Aggr.Rd b/man/Temporal.Aggr.Rd new file mode 100644 index 0000000..8a0d4c9 --- /dev/null +++ b/man/Temporal.Aggr.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Temporal.R +\name{Temporal.Aggr} +\alias{Temporal.Aggr} +\title{Carry out temporal aggregation} +\usage{ +Temporal.Aggr( + CDS_rast, + BaseResolution, + BaseStep, + TResolution, + TStep, + FUN, + Cores, + QueryTargetSteps, + TZone +) +} +\arguments{ +\item{CDS_rast}{SpatRaster} + +\item{BaseResolution}{Character. Base temporal resolution of data set} + +\item{BaseStep}{Numeric. Base time step of data set} + +\item{TResolution}{Character. User-specified temporal resolution} + +\item{TStep}{Numeric. User-specified time step} + +\item{FUN}{User-defined aggregation function} + +\item{Cores}{Numeric. Number of cores for parallel processing} + +\item{QueryTargetSteps}{Character. Target resolution steps} + +\item{TZone}{Character. Time zone for queried data.} +} +\value{ +A SpatRaster +} +\description{ +Takes a SpatRaster and user-specifications of temporal aggregation and carries it out +} diff --git a/man/Temporal.Cumul.Rd b/man/Temporal.Cumul.Rd new file mode 100644 index 0000000..d1de4c7 --- /dev/null +++ b/man/Temporal.Cumul.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Temporal.R +\name{Temporal.Cumul} +\alias{Temporal.Cumul} +\title{Make cumulatively stored records into sequential ones} +\usage{ +Temporal.Cumul(CDS_rast, CumulVar, BaseResolution, BaseStep, TZone) +} +\arguments{ +\item{CDS_rast}{SpatRaster} + +\item{CumulVar}{Logical. Whether to apply cumulative back-calculation} + +\item{BaseResolution}{Character. Base temporal resolution of data set} + +\item{BaseStep}{Numeric. Base time step of data set} + +\item{TZone}{Character. Time zone for queried data.} +} +\value{ +A SpatRaster +} +\description{ +Takes a SpatRaster of cumulatively stored records and returns a SpatRaster of sequential counterparts +} diff --git a/man/TemporalAggregation.Check.Rd b/man/TemporalAggregation.Check.Rd new file mode 100644 index 0000000..51a1e93 --- /dev/null +++ b/man/TemporalAggregation.Check.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Temporal.R +\name{TemporalAggregation.Check} +\alias{TemporalAggregation.Check} +\title{Checking temporal aggregation can use all queried data} +\usage{ +TemporalAggregation.Check( + QuerySeries, + DateStart, + DateStop, + TResolution, + BaseTResolution, + TStep, + BaseTStep +) +} +\arguments{ +\item{QuerySeries}{Character. Vector of dates/times queried for download. Created by \code{\link{Make.RequestWindows}}.} + +\item{DateStart}{UTC start date.} + +\item{DateStop}{UTC stop date.} + +\item{TResolution}{User-specified temporal resolution for aggregation.} + +\item{BaseTResolution}{Dataset-specific native temporal resolution.} + +\item{TStep}{User-specified time step for aggregation.} + +\item{BaseTStep}{Dataset-specific native time step.} +} +\value{ +Character - target resolution formatted steps in data. +} +\description{ +Error message if specified aggregation and time window clash. +} diff --git a/man/buffer_Points.Rd b/man/buffer_Points.Rd index da08740..2684b70 100644 --- a/man/buffer_Points.Rd +++ b/man/buffer_Points.Rd @@ -4,8 +4,6 @@ \alias{buffer_Points} \title{Square Buffers Around Point Data} \usage{ -buffer_Points(Points = NULL, Buffer = 0.5, ID = "ID") - buffer_Points(Points = NULL, Buffer = 0.5, ID = "ID") } \arguments{ @@ -16,12 +14,8 @@ buffer_Points(Points = NULL, Buffer = 0.5, ID = "ID") \item{ID}{Identifies which column in to use for creation of individual buffers.} } \value{ -A shape made up of individual square buffers around point-location input. - A shape made up of individual square buffers around point-location input. } \description{ -Allow for drawing of buffer zones around point-location data for downloading and kriging of spatial data around point-locations. Overlapping individual buffers are merged. - Allow for drawing of buffer zones around point-location data for downloading and kriging of spatial data around point-locations. Overlapping individual buffers are merged. } diff --git a/man/check_Krig.Rd b/man/check_Krig.Rd deleted file mode 100644 index 23a4dcc..0000000 --- a/man/check_Krig.Rd +++ /dev/null @@ -1,29 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/misc.R -\name{check_Krig} -\alias{check_Krig} -\title{Sanity checks before Kriging commences} -\usage{ -check_Krig(Data, CovariatesCoarse, CovariatesFine, KrigingEquation) - -check_Krig(Data, CovariatesCoarse, CovariatesFine, KrigingEquation) -} -\arguments{ -\item{Data}{A raster object containing the data to be kriged.} - -\item{CovariatesCoarse}{A raster object containing covariates for kriging at training resolution.} - -\item{CovariatesFine}{A raster object containing covariates for kriging at target resolution.} - -\item{KrigingEquation}{A formula object obtained from a character vector via as.formula() specifying the covariates to be used in kriging. The covariates used have to be present and named as layers in CovariatesCoarse and CovariatesFine.} -} -\value{ -A list containing a potentially altered KrigingEquation if needed as well as an identifier for data layers which need to be skipped when kriging due to a variety of reasons. - -A list containing a potentially altered KrigingEquation if needed as well as an identifier for data layers which need to be skipped when kriging due to a variety of reasons. -} -\description{ -This function is called upon in the krigR function and performs sanity checks for some of the most common error sources in krigin thereby attempting to return more sensible error messages to the user than what is returned by default. - -This function is called upon in the krigR function and performs sanity checks for some of the most common error sources in krigin thereby attempting to return more sensible error messages to the user than what is returned by default. -} diff --git a/man/krigR.Rd b/man/krigR.Rd index 1d0dfb9..b3ba54a 100644 --- a/man/krigR.Rd +++ b/man/krigR.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Kriging.R +% Please edit documentation in R/krigr.R \name{krigR} \alias{krigR} \title{(multi-core) Kriging} diff --git a/man/mask_Shape.Rd b/man/mask_Shape.Rd index 76552d4..ffd18b4 100644 --- a/man/mask_Shape.Rd +++ b/man/mask_Shape.Rd @@ -4,8 +4,6 @@ \alias{mask_Shape} \title{Range Masking with Edge Support} \usage{ -mask_Shape(base.map = NULL, Shape = NULL) - mask_Shape(base.map = NULL, Shape = NULL) } \arguments{ @@ -14,12 +12,8 @@ mask_Shape(base.map = NULL, Shape = NULL) \item{Shape}{A polygon(-collection) whose coverage of the raster object is to be found.} } \value{ -A raster layer. - A raster layer. } \description{ -Creating a raster mask identifying all cells in the original raster (`base.map`) which are at least partially covered by the supplied shapefile (`Shape`). - Creating a raster mask identifying all cells in the original raster (`base.map`) which are at least partially covered by the supplied shapefile (`Shape`). } diff --git a/metadata/.Rapp.history b/metadata/.Rapp.history new file mode 100644 index 0000000..5ccd9a4 --- /dev/null +++ b/metadata/.Rapp.history @@ -0,0 +1,2 @@ +load("/Users/erikkus/Documents/[Research] Active Projects/[R Package] KrigR/KrigR_GitHub/data/metadata/reanalysis-era5-land-monthly-means.RData") +load("/Users/erikkus/Documents/[Research] Active Projects/[R Package] KrigR/KrigR_GitHub/data/metadata/reanalysis-era5-land-monthly-means.RData") diff --git a/metadata/TrialMetadata_reanalysis-era5-land.R b/metadata/TrialMetadata_reanalysis-era5-land.R new file mode 100644 index 0000000..12f43ac --- /dev/null +++ b/metadata/TrialMetadata_reanalysis-era5-land.R @@ -0,0 +1,280 @@ +reanalysis_era5_land <- list( + DataSet = "reanalysis-era5-land", + Type = NA, + URL = "https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-land?tab=overview", + Description = "ERA5-Land is a reanalysis dataset providing a consistent view of the evolution of land variables over several decades at an enhanced resolution compared to ERA5. ERA5-Land has been produced by replaying the land component of the ECMWF ERA5 climate reanalysis. Reanalysis combines model data with observations from across the world into a globally complete and consistent dataset using the laws of physics. Reanalysis produces data that goes several decades back in time, providing an accurate description of the climate of the past. + +ERA5-Land uses as input to control the simulated land fields ERA5 atmospheric variables, such as air temperature and air humidity. This is called the atmospheric forcing. Without the constraint of the atmospheric forcing, the model-based estimates can rapidly deviate from reality. Therefore, while observations are not directly used in the production of ERA5-Land, they have an indirect influence through the atmospheric forcing used to run the simulation. In addition, the input air temperature, air humidity and pressure used to run ERA5-Land are corrected to account for the altitude difference between the grid of the forcing and the higher resolution grid of ERA5-Land. This correction is called 'lapse rate correction'. + +The ERA5-Land dataset, as any other simulation, provides estimates which have some degree of uncertainty. Numerical models can only provide a more or less accurate representation of the real physical processes governing different components of the Earth System. In general, the uncertainty of model estimates grows as we go back in time, because the number of observations available to create a good quality atmospheric forcing is lower. ERA5-land parameter fields can currently be used in combination with the uncertainty of the equivalent ERA5 fields. + +The temporal and spatial resolutions of ERA5-Land makes this dataset very useful for all kind of land surface applications such as flood or drought forecasting. The temporal and spatial resolution of this dataset, the period covered in time, as well as the fixed grid used for the data distribution at any period enables decisions makers, businesses and individuals to access and use more accurate information on land states.", + TResolution = "hour", + TStep = 1, + TStart = as.POSIXct("1950-01-01 01:00", tz = "UTC"), + TEnd = "Present; Lag = 3 month", + Projection = "WGS84 (EPSG: 4326)", + SpatialResolution = 0.1, + CDSArguments = list( + 'area' = c(-180, 180, -90, 90), + 'format' = c("grib", "netcdf.zip", "netcdf") + ), + Variables = rbind( + data.frame(Variable = "2m temperature", + CDSname = "2m_temperature", + Description = "Temperature of air at 2m above the surface of land, sea or in-land waters. 2m temperature is calculated by interpolating between the lowest model level and the Earth's surface, taking account of the atmospheric conditions. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Total precipitation", + CDSname = "total_precipitation", + Description = "Accumulated liquid and frozen water, including rain and snow, that falls to the Earth's surface. It is the sum of large-scale precipitation (that precipitation which is generated by large-scale weather patterns, such as troughs and cold fronts) and convective precipitation (generated by convection which occurs when air at lower levels in the atmosphere is warmer and less dense than the air above, so it rises). Precipitation variables do not include fog, dew or the precipitation that evaporates in the atmosphere before it lands at the surface of the Earth. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units of precipitation are depth in metres. It is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box and model time step.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "10m u-component of wind", + CDSname = "10m_u_component_of_wind", + Description = "Eastward component of the 10m wind. It is the horizontal speed of air moving towards the east, at a height of ten metres above the surface of the Earth, in metres per second. Care should be taken when comparing this variable with observations, because wind observations vary on small space and time scales and are affected by the local terrain, vegetation and buildings that are represented only on average in the ECMWF Integrated Forecasting System. This variable can be combined with the V component of 10m wind to give the speed and direction of the horizontal 10m wind.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "10m v-component of wind", + CDSname = "10m_v_component_of_wind", + Description = "Northward component of the 10m wind. It is the horizontal speed of air moving towards the north, at a height of ten metres above the surface of the Earth, in metres per second. Care should be taken when comparing this variable with observations, because wind observations vary on small space and time scales and are affected by the local terrain, vegetation and buildings that are represented only on average in the ECMWF Integrated Forecasting System. This variable can be combined with the U component of 10m wind to give the speed and direction of the horizontal 10m wind.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "2m dewpoint temperature", + CDSname = "2m_dewpoint_temperature", + Description = "Temperature to which the air, at 2 metres above the surface of the Earth, would have to be cooled for saturation to occur.It (external to C3S) is a measure of the humidity of the air. Combined with temperature and pressure, it can be used to calculate the relative humidity. 2m dew point temperature is calculated by interpolating between the lowest model level and the Earth's surface, taking account of the atmospheric conditions. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Evaporation from bare soil", + CDSname = "evaporation_from_bare_soil", + Description = "The amount of evaporation from bare soil at the top of the land surface. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Evaporation from open water surfaces excluding oceans", + CDSname = "evaporation_from_open_water_surfaces_excluding_oceans", + Description = "Amount of evaporation from surface water storage like lakes and inundated areas but excluding oceans. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Evaporation from the top of canopy", + CDSname = "evaporation_from_the_top_of_canopy", + Description = "The amount of evaporation from the canopy interception reservoir at the top of the canopy. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Evaporation from vegetation transpiration", + CDSname = "evaporation_from_vegetation_transpiration", + Description = "Amount of evaporation from vegetation transpiration. This has the same meaning as root extraction i.e. the amount of water extracted from the different soil layers. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Forecast albedo", + CDSname = "forecast_albedo", + Description = "Is a measure of the reflectivity of the Earth's surface. It is the fraction of solar (shortwave) radiation reflected by Earth's surface, across the solar spectrum, for both direct and diffuse radiation. Values are between 0 and 1. Typically, snow and ice have high reflectivity with albedo values of 0.8 and above, land has intermediate values between about 0.1 and 0.4 and the ocean has low values of 0.1 or less. Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The rest is incident on the Earth's surface, where some of it is reflected. The portion that is reflected by the Earth's surface depends on the albedo. In the ECMWF Integrated Forecasting System (IFS), a climatological background albedo (observed values averaged over a period of several years) is used, modified by the model over water, ice and snow. Albedo is often shown as a percentage (%).", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Lake bottom temperature", + CDSname = "lake_bottom_temperature", + Description = "Temperature of water at the bottom of inland water bodies (lakes, reservoirs, rivers) and coastal waters. ECMWF implemented a lake model in May 2015 to represent the water temperature and lake ice of all the world’s major inland water bodies in the Integrated Forecasting System. The model keeps lake depth and surface area (or fractional cover) constant in time.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Lake ice depth", + CDSname = "lake_ice_depth", + Description = "The thickness of ice on inland water bodies (lakes, reservoirs and rivers) and coastal waters. The ECMWF Integrated Forecasting System (IFS) represents the formation and melting of ice on inland water bodies (lakes, reservoirs and rivers) and coastal water. A single ice layer is represented. This parameter is the thickness of that ice layer.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Lake ice temperature", + CDSname = "lake_ice_temperature", + Description = "The temperature of the uppermost surface of ice on inland water bodies (lakes, reservoirs, rivers) and coastal waters. The ECMWF Integrated Forecasting System represents the formation and melting of ice on lakes. A single ice layer is represented. The temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Lake mix-layer depth", + CDSname = "lake_mix_layer_depth", + Description = "The thickness of the upper most layer of an inland water body (lake, reservoirs, and rivers) or coastal waters that is well mixed and has a near constant temperature with depth (uniform distribution of temperature). The ECMWF Integrated Forecasting System represents inland water bodies with two layers in the vertical, the mixed layer above and the thermocline below. Thermoclines upper boundary is located at the mixed layer bottom, and the lower boundary at the lake bottom. Mixing within the mixed layer can occur when the density of the surface (and near-surface) water is greater than that of the water below. Mixing can also occur through the action of wind on the surface of the lake.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Lake mix-layer temperature", + CDSname = "lake_mix_layer_temperature", + Description = "The temperature of the upper most layer of inland water bodies (lakes, reservoirs and rivers) or coastal waters) that is well mixed. The ECMWF Integrated Forecasting System represents inland water bodies with two layers in the vertical, the mixed layer above and the thermocline below. Thermoclines upper boundary is located at the mixed layer bottom, and the lower boundary at the lake bottom. Mixing within the mixed layer can occur when the density of the surface (and near-surface) water is greater than that of the water below. Mixing can also occur through the action of wind on the surface of the lake. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Lake shape factor", + CDSname = "lake_shape_factor", + Description = "This parameter describes the way that temperature changes with depth in the thermocline layer of inland water bodies (lakes, reservoirs and rivers) and coastal waters. It is used to calculate the lake bottom temperature and other lake-related parameters. The ECMWF Integrated Forecasting System represents inland and coastal water bodies with two layers in the vertical, the mixed layer above and the thermocline below where temperature changes with depth.", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Lake total layer temperature", + CDSname = "lake_total_layer_temperature", + Description = "The mean temperature of total water column in inland water bodies (lakes, reservoirs and rivers) and coastal waters. The ECMWF Integrated Forecasting System represents inland water bodies with two layers in the vertical, the mixed layer above and the thermocline below where temperature changes with depth. This parameter is the mean over the two layers. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Leaf area index, high vegetation", + CDSname = "leaf_area_index_high_vegetation", + Description = "One-half of the total green leaf area per unit horizontal ground surface area for high vegetation type.", + Unit = "m2 m-2", + Cumulative = FALSE), + data.frame(Variable = "Leaf area index, low vegetation", + CDSname = "leaf_area_index_low_vegetation", + Description = "One-half of the total green leaf area per unit horizontal ground surface area for low vegetation type.", + Unit = "m2 m-2", + Cumulative = FALSE), + data.frame(Variable = "Potential evaporation", + CDSname = "potential_evaporation", + Description = "Potential evaporation (pev) in the current ECMWF model is computed, by making a second call to the surface energy balance routine with the vegetation variables set to 'crops/mixed farming' and assuming no stress from soil moisture. In other words, evaporation is computed for agricultural land as if it is well watered and assuming that the atmosphere is not affected by this artificial surface condition. The latter may not always be realistic. Although pev is meant to provide an estimate of irrigation requirements, the method can give unrealistic results in arid conditions due to too strong evaporation forced by dry air. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Runoff", + CDSname = "runoff", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is simply called 'runoff'. This variable is the total amount of water accumulated from the beginning of the forecast time to the end of the forecast step. The units of runoff are depth in metres. This is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point rather than averaged over a grid square area. Observations are also often taken in different units, such as mm/day, rather than the accumulated metres produced here. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood. More information about how runoff is calculated is given in the IFS Physical Processes documentation.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Skin reservoir content", + CDSname = "skin_reservoir_content", + Description = "Amount of water in the vegetation canopy and/or in a thin layer on the soil. It represents the amount of rain intercepted by foliage, and water from dew. The maximum amount of 'skin reservoir content' a grid box can hold depends on the type of vegetation, and may be zero. Water leaves the 'skin reservoir' by evaporation.", + Unit = "m of water equivalent", + Cumulative = FALSE), + data.frame(Variable = "Skin temperature", + CDSname = "skin_temperature", + Description = "Temperature of the surface of the Earth. The skin temperature is the theoretical temperature that is required to satisfy the surface energy balance. It represents the temperature of the uppermost surface layer, which has no heat capacity and so can respond instantaneously to changes in surface fluxes. Skin temperature is calculated differently over land and sea. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Snow albedo", + CDSname = "snow_albedo", + Description = "It is defined as the fraction of solar (shortwave) radiation reflected by the snow, across the solar spectrum, for both direct and diffuse radiation. It is a measure of the reflectivity of the snow covered grid cells. Values vary between 0 and 1. Typically, snow and ice have high reflectivity with albedo values of 0.8 and above.", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Snow cover", + CDSname = "snow_cover", + Description = "It represents the fraction (0-1) of the cell / grid-box occupied by snow (similar to the cloud cover fields of ERA5).", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Snow density", + CDSname = "snow_density", + Description = "Mass of snow per cubic metre in the snow layer. The ECMWF Integrated Forecast System (IFS) model represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box.", + Unit = "kg m-3", + Cumulative = FALSE), + data.frame(Variable = "Snow depth", + CDSname = "snow_depth", + Description = "Instantaneous grib-box average of the snow thickness on the ground (excluding snow on canopy).", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Snow depth water equivalent", + CDSname = "snow_depth_water_equivalent", + Description = "Depth of snow from the snow-covered area of a grid box. Its units are metres of water equivalent, so it is the depth the water would have if the snow melted and was spread evenly over the whole grid box. The ECMWF Integrated Forecast System represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box.", + Unit = "m of water equivalent", + Cumulative = FALSE), + data.frame(Variable = "Snow evaporation", + CDSname = "snow_evaporation", + Description = "Evaporation from snow averaged over the grid box (to find flux over snow, divide by snow fraction). This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Snowfall", + CDSname = "snowfall", + Description = "Accumulated total snow that has fallen to the Earth's surface. It consists of snow due to the large-scale atmospheric flow (horizontal scales greater than around a few hundred metres) and convection where smaller scale areas (around 5km to a few hundred kilometres) of warm air rise. If snow has melted during the period over which this variable was accumulated, then it will be higher than the snow depth. This variable is the total amount of water accumulated from the beginning of the forecast time to the end of the forecast step. The units given measure the depth the water would have if the snow melted and was spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box and model time step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Snowmelt", + CDSname = "snowmelt", + Description = "Melting of snow averaged over the grid box (to find melt over snow, divide by snow fraction). This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 1", + CDSname = "soil_temperature_level_1", + Description = "Temperature of the soil in layer 1 (0 - 7 cm) of the ECMWF Integrated Forecasting System. The surface is at 0 cm. Soil temperature is set at the middle of each layer, and heat transfer is calculated at the interfaces between them. It is assumed that there is no heat transfer out of the bottom of the lowest layer. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 2", + CDSname = "soil_temperature_level_2", + Description = "Temperature of the soil in layer 2 (7 -28cm) of the ECMWF Integrated Forecasting System.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 3", + CDSname = "soil_temperature_level_3", + Description = "Temperature of the soil in layer 3 (28-100cm) of the ECMWF Integrated Forecasting System.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 4", + CDSname = "soil_temperature_level_4", + Description = "Temperature of the soil in layer 4 (100-289 cm) of the ECMWF Integrated Forecasting System.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Sub-surface runoff", + CDSname = "sub_surface_runoff", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is simply called 'runoff'. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units of runoff are depth in metres. This is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point rather than averaged over a grid square area. Observations are also often taken in different units, such as mm/day, rather than the accumulated metres produced here. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood. More information about how runoff is calculated is given in the IFS Physical Processes documentation.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Surface latent heat flux", + CDSname = "surface_latent_heat_flux", + Description = "Exchange of latent heat with the surface through turbulent diffusion. This variables is accumulated from the beginning of the forecast time to the end of the forecast step. By model convention, downward fluxes are positive.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface net solar radiation", + CDSname = "surface_net_solar_radiation", + Description = "Amount of solar radiation (also known as shortwave radiation) reaching the surface of the Earth (both direct and diffuse) minus the amount reflected by the Earth's surface (which is governed by the albedo).Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The rest is incident on the Earth's surface, where some of it is reflected. The difference between downward and reflected solar radiation is the surface net solar radiation. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface net thermal radiation", + CDSname = "surface_net_thermal_radiation", + Description = "Net thermal radiation at the surface. Accumulated field from the beginning of the forecast time to the end of the forecast step. By model convention downward fluxes are positive.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface pressure", + CDSname = "surface_pressure", + Description = "Pressure (force per unit area) of the atmosphere on the surface of land, sea and in-land water. It is a measure of the weight of all the air in a column vertically above the area of the Earth's surface represented at a fixed point. Surface pressure is often used in combination with temperature to calculate air density. The strong variation of pressure with altitude makes it difficult to see the low and high pressure systems over mountainous areas, so mean sea level pressure, rather than surface pressure, is normally used for this purpose. The units of this variable are Pascals (Pa). Surface pressure is often measured in hPa and sometimes is presented in the old units of millibars, mb (1 hPa = 1 mb = 100 Pa).", + Unit = "Pa", + Cumulative = FALSE), + data.frame(Variable = "Surface runoff", + CDSname = "surface_runoff", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is simply called 'runoff'. This variable is the total amount of water accumulated from the beginning of the forecast time to the end of the forecast step. The units of runoff are depth in metres. This is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point rather than averaged over a grid square area. Observations are also often taken in different units, such as mm/day, rather than the accumulated metres produced here. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood. More information about how runoff is calculated is given in the IFS Physical Processes documentation.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Surface sensible heat flux", + CDSname = "surface_sensible_heat_flux", + Description = "Transfer of heat between the Earth's surface and the atmosphere through the effects of turbulent air motion (but excluding any heat transfer resulting from condensation or evaporation). The magnitude of the sensible heat flux is governed by the difference in temperature between the surface and the overlying atmosphere, wind speed and the surface roughness. For example, cold air overlying a warm surface would produce a sensible heat flux from the land (or ocean) into the atmosphere. This is a single level variable and it is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface solar radiation downwards", + CDSname = "surface_solar_radiation_downwards", + Description = "Amount of solar radiation (also known as shortwave radiation) reaching the surface of the Earth. This variable comprises both direct and diffuse solar radiation. Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The rest is incident on the Earth's surface (represented by this variable). To a reasonably good approximation, this variable is the model equivalent of what would be measured by a pyranometer (an instrument used for measuring solar radiation) at the surface. However, care should be taken when comparing model variables with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box and model time step. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface thermal radiation downwards", + CDSname = "surface_thermal_radiation_downwards", + Description = "Amount of thermal (also known as longwave or terrestrial) radiation emitted by the atmosphere and clouds that reaches the Earth's surface. The surface of the Earth emits thermal radiation, some of which is absorbed by the atmosphere and clouds. The atmosphere and clouds likewise emit thermal radiation in all directions, some of which reaches the surface (represented by this variable). This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Temperature of snow layer", + CDSname = "temperature_of_snow_layer", + Description = "This variable gives the temperature of the snow layer from the ground to the snow-air interface. The ECMWF Integrated Forecast System (IFS) model represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Total evaporation", + CDSname = "total_evaporation", + Description = "Accumulated amount of water that has evaporated from the Earth's surface, including a simplified representation of transpiration (from vegetation), into vapour in the air above. This variable is accumulated from the beginning of the forecast to the end of the forecast step. The ECMWF Integrated Forecasting System convention is that downward fluxes are positive. Therefore, negative values indicate evaporation and positive values indicate condensation.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Volumetric soil water layer 1", + CDSname = "volumetric_soil_water_layer_1", + Description = "Volume of water in soil layer 1 (0 - 7 cm) of the ECMWF Integrated Forecasting System. The surface is at 0 cm. The volumetric soil water is associated with the soil texture (or classification), soil depth, and the underlying groundwater level.", + Unit = "m3 m-3", + Cumulative = FALSE), + data.frame(Variable = "Volumetric soil water layer 2", + CDSname = "volumetric_soil_water_layer_2", + Description = "Volume of water in soil layer 2 (7 -28 cm) of the ECMWF Integrated Forecasting System.", + Unit = "m3 m-3", + Cumulative = FALSE), + data.frame(Variable = "Volumetric soil water layer 3", + CDSname = "volumetric_soil_water_layer_3", + Description = "Volume of water in soil layer 3 (28-100 cm) of the ECMWF Integrated Forecasting System.", + Unit = "m3 m-3", + Cumulative = FALSE), + data.frame(Variable = "Volumetric soil water layer 4", + CDSname = "volumetric_soil_water_layer_4", + Description = "Volume of water in soil layer 4 (100-289 cm) of the ECMWF Integrated Forecasting System.", + Unit = "m3 m-3", + Cumulative = FALSE) + + ), +Citation = "10.24381/cds.e2161bac" +) + +save(reanalysis_era5_land, + file = file.path(getwd(), "data/metadata", "reanalysis-era5-land.RData")) + diff --git a/metadata/TrialMetadata_reanalysis-era5-single-levels.R b/metadata/TrialMetadata_reanalysis-era5-single-levels.R new file mode 100644 index 0000000..50daaaf --- /dev/null +++ b/metadata/TrialMetadata_reanalysis-era5-single-levels.R @@ -0,0 +1,1283 @@ +reanalysis_era5_single_levels <- list( + DataSet = "reanalysis-era5-single-levels", + Type = c("reanalysis","ensemble_members","ensemble_mean","ensemble_spread"), # Note this one has two types and you need to specify + URL = "https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-single-levels?tab=overview", + Description = "ERA5 is the fifth generation ECMWF reanalysis for the global climate and weather for the past 8 decades. Data is available from 1940 onwards. ERA5 replaces the ERA-Interim reanalysis. + +Reanalysis combines model data with observations from across the world into a globally complete and consistent dataset using the laws of physics. This principle, called data assimilation, is based on the method used by numerical weather prediction centres, where every so many hours (12 hours at ECMWF) a previous forecast is combined with newly available observations in an optimal way to produce a new best estimate of the state of the atmosphere, called analysis, from which an updated, improved forecast is issued. Reanalysis works in the same way, but at reduced resolution to allow for the provision of a dataset spanning back several decades. Reanalysis does not have the constraint of issuing timely forecasts, so there is more time to collect observations, and when going further back in time, to allow for the ingestion of improved versions of the original observations, which all benefit the quality of the reanalysis product. + +ERA5 provides hourly estimates for a large number of atmospheric, ocean-wave and land-surface quantities. An uncertainty estimate is sampled by an underlying 10-member ensemble at three-hourly intervals. Ensemble mean and spread have been pre-computed for convenience. Such uncertainty estimates are closely related to the information content of the available observing system which has evolved considerably over time. They also indicate flow-dependent sensitive areas. To facilitate many climate applications, monthly-mean averages have been pre-calculated too, though monthly means are not available for the ensemble mean and spread. + +ERA5 is updated daily with a latency of about 5 days. In case that serious flaws are detected in this early release (called ERA5T), this data could be different from the final release 2 to 3 months later. In case that this occurs users are notified. + +The data set presented here is a regridded subset of the full ERA5 data set on native resolution. It is online on spinning disk, which should ensure fast and easy access. It should satisfy the requirements for most common applications. + +An overview of all ERA5 datasets can be found in this article. Information on access to ERA5 data on native resolution is provided in these guidelines. + +Data has been regridded to a regular lat-lon grid of 0.25 degrees for the reanalysis and 0.5 degrees for the uncertainty estimate (0.5 and 1 degree respectively for ocean waves). There are four main sub sets: hourly and monthly products, both on pressure levels (upper air fields) and single levels (atmospheric, ocean-wave and land surface quantities). + +The present entry is ERA5 hourly data on single levels from 1940 to present.", + TResolution = "hour", + TStep = c(1, 1, 3, 3), # corresponds to Types + TStart = as.POSIXct("1940-01-01 00:00", tz = "UTC"), + TEnd = "Present; Lag = 3 month", + Projection = "WGS84 (EPSG: 4326)", + SpatialResolution = c(0.25,0.5,0.5,0.5), # So 0.25 is for the atmospheric data in the reanalysis, it is 0.5 in the ensemble mean, spread and members + CDSArguments = list( + 'area' = c(-180, 180, -90, 90), + 'format' = c("grib", "netcdf.zip", "netcdf") + ), + Variables = rbind( + data.frame(Variable = "100m u-component of wind", + CDSname = "100m_u_component_of_wind", + Description = "This parameter is the eastward component of the 100 m wind. It is the horizontal speed of air moving towards the east, at a height of 100 metres above the surface of the Earth, in metres per second. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "100m v-component of wind", + CDSname = "100m_v_component_of_wind", + Description = "This parameter is the northward component of the 100 m wind. It is the horizontal speed of air moving towards the east, at a height of 100 metres above the surface of the Earth, in metres per second. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "10m u-component of neutral wind", + CDSname = "10m_u_component_of_neutral_wind", + Description = "This parameter is the eastward component of the 'neutral wind', at a height of 10 metres above the surface of the Earth. The neutral wind is calculated from the surface stress and the corresponding roughness length by assuming that the air is neutrally stratified. The neutral wind is slower than the actual wind in stable conditions, and faster in unstable conditions. The neutral wind is, by definition, in the direction of the surface stress. The size of the roughness length depends on land surface properties or the sea state.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "10m u-component of wind", + CDSname = "10m_u_component_of_wind", + Description = "Eastward component of the 10m wind. It is the horizontal speed of air moving towards the east, at a height of ten metres above the surface of the Earth, in metres per second. Care should be taken when comparing this variable with observations, because wind observations vary on small space and time scales and are affected by the local terrain, vegetation and buildings that are represented only on average in the ECMWF Integrated Forecasting System. This variable can be combined with the V component of 10m wind to give the speed and direction of the horizontal 10m wind.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "10m v-component of neutral wind", + CDSname = "10m_v_component_of_neutral_wind", + Description = "This parameter is the northward component of the 'neutral wind', at a height of 10 metres above the surface of the Earth. The neutral wind is calculated from the surface stress and the corresponding roughness length by assuming that the air is neutrally stratified. The neutral wind is slower than the actual wind in stable conditions, and faster in unstable conditions. The neutral wind is, by definition, in the direction of the surface stress. The size of the roughness length depends on land surface properties or the sea state.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "10m v-component of wind", + CDSname = "10m_v_component_of_wind", + Description = "Northward component of the 10m wind. It is the horizontal speed of air moving towards the north, at a height of ten metres above the surface of the Earth, in metres per second. Care should be taken when comparing this variable with observations, because wind observations vary on small space and time scales and are affected by the local terrain, vegetation and buildings that are represented only on average in the ECMWF Integrated Forecasting System. This variable can be combined with the U component of 10m wind to give the speed and direction of the horizontal 10m wind.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "10m wind gust since previous post-processing", + CDSname = "10m_wind_gust_since_previous_post_processing", + Description = "MISSING METADATA", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "2m dewpoint temperature", + CDSname = "2m_dewpoint_temperature", + Description = "Temperature to which the air, at 2 metres above the surface of the Earth, would have to be cooled for saturation to occur. It (external to C3S) is a measure of the humidity of the air. Combined with temperature and pressure, it can be used to calculate the relative humidity. 2m dew point temperature is calculated by interpolating between the lowest model level and the Earth's surface, taking account of the atmospheric conditions. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "2m temperature", + CDSname = "2m_temperature", + Description = "Temperature of air at 2m above the surface of land, sea or in-land waters. 2m temperature is calculated by interpolating between the lowest model level and the Earth's surface, taking account of the atmospheric conditions. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Air density over the oceans", + CDSname = "air_density_over_the_oceans", + Description = "This parameter is the mass of air per cubic metre over the oceans, derived from the temperature, specific humidity and pressure at the lowest model level in the atmospheric model. This parameter is one of the parameters used to force the wave model, therefore it is only calculated over water bodies represented in the ocean wave model. It is interpolated from the atmospheric model horizontal grid onto the horizontal grid used by the ocean wave model.", + Unit = "kg m-3", + Cumulative = FALSE), + data.frame(Variable = "Angle of sub-gridscale orography", + CDSname = "angle_of_sub_gridscale_orography", + Description = "This parameter is one of four parameters (the others being standard deviation, slope and anisotropy) that describe the features of the orography that are too small to be resolved by the model grid. These four parameters are calculated for orographic features with horizontal scales comprised between 5 km and the model grid resolution, being derived from the height of valleys, hills and mountains at about 1 km resolution. They are used as input for the sub-grid orography scheme which represents low-level blocking and orographic gravity wave effects. The angle of the sub-grid scale orography characterises the geographical orientation of the terrain in the horizontal plane (from a bird's-eye view) relative to an eastwards axis. This parameter does not vary in time.", + Unit = "radians", + Cumulative = FALSE), + data.frame(Variable = "Anisotropy of sub-gridscale orography", + CDSname = "anisotropy_of_sub_gridscale_orography", + Description = "This parameter is one of four parameters (the others being standard deviation, slope and angle of sub-gridscale orography) that describe the features of the orography that are too small to be resolved by the model grid. These four parameters are calculated for orographic features with horizontal scales comprised between 5 km and the model grid resolution, being derived from the height of valleys, hills and mountains at about 1 km resolution. They are used as input for the sub-grid orography scheme which represents low-level blocking and orographic gravity wave effects. This parameter is a measure of how much the shape of the terrain in the horizontal plane (from a bird's-eye view) is distorted from a circle. A value of one is a circle, less than one an ellipse, and 0 is a ridge. In the case of a ridge, wind blowing parallel to it does not exert any drag on the flow, but wind blowing perpendicular to it exerts the maximum drag. This parameter does not vary in time.", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Benjamin-feir index", + CDSname = "benjamin_feir_index", + Description = "This parameter is used to calculate the likelihood of freak ocean waves, which are waves that are higher than twice the mean height of the highest third of waves. Large values of this parameter (in practice of the order 1) indicate increased probability of the occurrence of freak waves. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). This parameter is derived from the statistics of the two-dimensional wave spectrum. More precisely, it is the square of the ratio of the integral ocean wave steepness and the relative width of the frequency spectrum of the waves. Further information on the calculation of this parameter is given in Section 10.6 of the ECMWF Wave Model documentation.", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Boundary layer dissipation", + CDSname = "boundary_layer_dissipation", + Description = " This parameter is the amount of energy per unit area that is converted from kinetic energy, into heat, due to small-scale motion in the lower levels of the atmosphere. These small-scale motions are called eddies or turbulence. A higher value of this parameter means that more energy is being converted to heat, and so the mean flow is slowing more and the air temperature is rising by a greater amount. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time.", + Unit = "J m-2", + Cumulative = TRUE), ## ERIK check this one! Complicated accumulation rules. + data.frame(Variable = "Boundary layer height", + CDSname = "boundary_layer_height", + Description = "This parameter is the depth of air next to the Earth's surface which is most affected by the resistance to the transfer of momentum, heat or moisture across the surface. The boundary layer height can be as low as a few tens of metres, such as in cooling air at night, or as high as several kilometres over the desert in the middle of a hot sunny day. When the boundary layer height is low, higher concentrations of pollutants (emitted from the Earth's surface) can develop. The boundary layer height calculation is based on the bulk Richardson number (a measure of the atmospheric conditions) following the conclusions of a 2012 review.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Charnock", + CDSname = "charnock", + Description = "This parameter accounts for increased aerodynamic roughness as wave heights grow due to increasing surface stress. It depends on the wind speed, wave age and other aspects of the sea state and is used to calculate how much the waves slow down the wind. When the atmospheric model is run without the ocean model, this parameter has a constant value of 0.018. When the atmospheric model is coupled to the ocean model, this parameter is calculated by the ECMWF Wave Model.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Clear-sky direct solar radiation at surface", + CDSname = "clear_sky_direct_solar_radiation_at_surface", + Description = "This parameter is the amount of direct radiation from the Sun (also known as solar or shortwave radiation) reaching the surface of the Earth, assuming clear-sky (cloudless) conditions. It is the amount of radiation passing through a horizontal plane. Solar radiation at the surface can be direct or diffuse. Solar radiation can be scattered in all directions by particles in the atmosphere, some of which reaches the surface (diffuse solar radiation). Some solar radiation reaches the surface without being scattered (direct solar radiation). Clear-sky radiation quantities are computed for exactly the same atmospheric conditions of temperature, humidity, ozone, trace gases and aerosol as the corresponding total-sky quantities (clouds included), but assuming that the clouds are not there. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The units are joules per square metre (J m-2 ). To convert to watts per square metre (W m-2 ), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Cloud base height", + CDSname = "cloud_base_height", + Description = "The height above the Earth's surface of the base of the lowest cloud layer, at the specified time. This parameter is calculated by searching from the second lowest model level upwards, to the height of the level where cloud fraction becomes greater than 1% and condensate content greater than 1.E-6 kg kg-1. Fog (i.e., cloud in the lowest model layer) is not considered when defining cloud base height.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Coefficient of drag with waves", + CDSname = "coefficient_of_drag_with_waves", + Description = "This parameter is the resistance that ocean waves exert on the atmosphere. It is sometimes also called a 'friction coefficient'. It is calculated by the wave model as the ratio of the square of the friction velocity, to the square of the neutral wind speed at a height of 10 metres above the surface of the Earth. The neutral wind is calculated from the surface stress and the corresponding roughness length by assuming that the air is neutrally stratified. The neutral wind is, by definition, in the direction of the surface stress. The size of the roughness length depends on the sea state.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Convective available potential energy", + CDSname = "convective_available_potential_energy", + Description = "This is an indication of the instability (or stability) of the atmosphere and can be used to assess the potential for the development of convection, which can lead to heavy rainfall, thunderstorms and other severe weather. In the ECMWF Integrated Forecasting System (IFS), CAPE is calculated by considering parcels of air departing at different model levels below the 350 hPa level. If a parcel of air is more buoyant (warmer and/or with more moisture) than its surrounding environment, it will continue to rise (cooling as it rises) until it reaches a point where it no longer has positive buoyancy. CAPE is the potential energy represented by the total excess buoyancy. The maximum CAPE produced by the different parcels is the value retained. Large positive values of CAPE indicate that an air parcel would be much warmer than its surrounding environment and therefore, very buoyant. CAPE is related to the maximum potential vertical velocity of air within an updraft; thus, higher values indicate greater potential for severe weather. Observed values in thunderstorm environments often may exceed 1000 joules per kilogram (J kg-1), and in extreme cases may exceed 5000 J kg-1. The calculation of this parameter assumes: (i) the parcel of air does not mix with surrounding air; (ii) ascent is pseudo-adiabatic (all condensed water falls out) and (iii) other simplifications related to the mixed-phase condensational heating.", + Unit = "J kg-1", + Cumulative = FALSE), + data.frame(Variable = "Convective inhibition", + CDSname = "convective_inhibition", + Description = "This parameter is a measure of the amount of energy required for convection to commence. If the value of this parameter is too high, then deep, moist convection is unlikely to occur even if the convective available potential energy or convective available potential energy shear are large. CIN values greater than 200 J kg-1 would be considered high. An atmospheric layer where temperature increases with height (known as a temperature inversion) would inhibit convective uplift and is a situation in which convective inhibition would be large.", + Unit = "J kg-1", + Cumulative = FALSE), + data.frame(Variable = "Convective precipitation", + CDSname = "convective_precipitation", + Description = "This parameter is the accumulated precipitation that falls to the Earth's surface, which is generated by the convection scheme in the ECMWF Integrated Forecasting System (IFS). The convection scheme represents convection at spatial scales smaller than the grid box. Precipitation can also be generated by the cloud scheme in the IFS, which represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly at spatial scales of the grid box or larger. In the IFS, precipitation is comprised of rain and snow. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The units of this parameter are depth in metres of water equivalent. It is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Convective rain rate", + CDSname = "convective_rain_rate", + Description = "This parameter is the rate of rainfall (rainfall intensity), at the Earth's surface and at the specified time, which is generated by the convection scheme in the ECMWF Integrated Forecasting System (IFS). The convection scheme represents convection at spatial scales smaller than the grid box. Rainfall can also be generated by the cloud scheme in the IFS, which represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly at spatial scales of the grid box or larger. In the IFS, precipitation is comprised of rain and snow. This parameter is the rate the rainfall would have if it were spread evenly over the grid box. 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), therefore the units are equivalent to mm per second. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Convective snowfall", + CDSname = "convective_snowfall", + Description = "This parameter is the accumulated snow that falls to the Earth's surface, which is generated by the convection scheme in the ECMWF Integrated Forecasting System (IFS). The convection scheme represents convection at spatial scales smaller than the grid box. Snowfall can also be generated by the cloud scheme in the IFS, which represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly at spatial scales of the grid box or larger. In the IFS, precipitation is comprised of rain and snow. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The units of this parameter are depth in metres of water equivalent. It is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Convective snowfall rate water equivalent", + CDSname = "convective_snowfall_rate_water_equivalent", + Description = "This parameter is the rate of snowfall (snowfall intensity), at the Earth's surface and at the specified time, which is generated by the convection scheme in the ECMWF Integrated Forecasting System (IFS). The convection scheme represents convection at spatial scales smaller than the grid box. Snowfall can also be generated by the cloud scheme in the IFS, which represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly at spatial scales of the grid box or larger. In the IFS, precipitation is comprised of rain and snow. This parameter is the rate the snowfall would have if it were spread evenly over the grid box. Since 1 kg of water spread over 1 square metre of surface is 1 mm thick (neglecting the effects of temperature on the density of water), the units are equivalent to mm (of liquid water) per second. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Downward UV radiation at the surface", + CDSname = "downward_uv_radiation_at_the_surface", + Description = "This parameter is the amount of ultraviolet (UV) radiation reaching the surface. It is the amount of radiation passing through a horizontal plane. UV radiation is part of the electromagnetic spectrum emitted by the Sun that has wavelengths shorter than visible light. In the ECMWF Integrated Forecasting system (IFS) it is defined as radiation with a wavelength of 0.20-0.44 µm (microns, 1 millionth of a metre). Small amounts of UV are essential for living organisms, but overexposure may result in cell damage; in humans this includes acute and chronic health effects on the skin, eyes and immune system. UV radiation is absorbed by the ozone layer, but some reaches the surface. The depletion of the ozone layer is causing concern over an increase in the damaging effects of UV. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The units are joules per square metre (J m-2 ). To convert to watts per square metre (W m-2 ), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Duct base height", + CDSname = "duct_base_height", + Description = "Duct base height as diagnosed from vertical gradient of atmospheric refractivity.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Eastward gravity wave surface stress", + CDSname = "eastward_gravity_wave_surface_stress", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is the component of the surface stress, in an eastward direction, associated with low-level blocking and orographic gravity waves. It is calculated by the ECMWF Integrated Forecasting System (IFS) sub-grid orography scheme. It represents surface stress due to unresolved valleys, hills and mountains with horizontal scales between 5 km and the model grid. (The surface stress associated with orographic features with horizontal scales smaller than 5 km is accounted for by the turbulent orographic form drag scheme). Orographic gravity waves are oscillations in the flow maintained by the buoyancy of displaced air parcels, produced when the air is deflected upwards by hills and mountains. Hills and mountains can also block the flow of air at low levels. Together these processes can create a drag or stress on the atmosphere at the Earth's surface (and at other levels in the atmosphere). This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time.", + Unit = "N m-2 s", + Cumulative = TRUE), + data.frame(Variable = "Eastward turbulent surface stress", + CDSname = "eastward_turbulent_surface_stress", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is the accumulated stress on the Earth's surface in the eastward direction due to both the turbulent interactions between the atmosphere and the surface, and to turbulent orographic form drag. The turbulent interactions between the atmosphere and the surface are due to the roughness of the surface. The turbulent orographic form drag is the stress due to the valleys, hills and mountains on horizontal scales below 5km being derived from land surface data at about 1 km resolution. Positive (negative) values denote stress in the eastward (westward) direction. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time.", + Unit = "N m-2 s", + Cumulative = TRUE), + data.frame(Variable = "Evaporation", + CDSname = "evaporation", + Description = "This parameter is the accumulated amount of water that has evaporated from the Earth's surface, including a simplified representation of transpiration (from vegetation), into vapour in the air above. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The ECMWF Integrated Forecasting System (IFS) convention is that downward fluxes are positive. Therefore, negative values indicate evaporation and positive values indicate condensation.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Forecast albedo", + CDSname = "forecast_albedo", + Description = "Is a measure of the reflectivity of the Earth's surface. It is the fraction of solar (shortwave) radiation reflected by Earth's surface, across the solar spectrum, for both direct and diffuse radiation. Values are between 0 and 1. Typically, snow and ice have high reflectivity with albedo values of 0.8 and above, land has intermediate values between about 0.1 and 0.4 and the ocean has low values of 0.1 or less. Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The rest is incident on the Earth's surface, where some of it is reflected. The portion that is reflected by the Earth's surface depends on the albedo. In the ECMWF Integrated Forecasting System (IFS), a climatological background albedo (observed values averaged over a period of several years) is used, modified by the model over water, ice and snow. Albedo is often shown as a percentage (%).", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Forecast logarithm of surface roughness for heat", + CDSname = "forecast_logarithm_of_surface_roughness_for_heat", + Description = "This parameter is the natural logarithm of the roughness length for heat. The surface roughness for heat is a measure of the surface resistance to heat transfer. This parameter is used to determine the air to surface transfer of heat. For given atmospheric conditions, a higher surface roughness for heat means that it is more difficult for the air to exchange heat with the surface. A lower surface roughness for heat means that it is easier for the air to exchange heat with the surface. Over the ocean, surface roughness for heat depends on the waves. Over sea-ice, it has a constant value of 0.001 m. Over land, it is derived from the vegetation type and snow cover.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Forecast surface roughness", + CDSname = "forecast_surface_roughness", + Description = "This parameter is the aerodynamic roughness length in metres. It is a measure of the surface resistance. This parameter is used to determine the air to surface transfer of momentum. For given atmospheric conditions, a higher surface roughness causes a slower near-surface wind speed. Over ocean, surface roughness depends on the waves. Over land, surface roughness is derived from the vegetation type and snow cover.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Free convective velocity over the oceans", + CDSname = "free_convective_velocity_over_the_oceans", + Description = "This parameter is an estimate of the vertical velocity of updraughts generated by free convection. Free convection is fluid motion induced by buoyancy forces, which are driven by density gradients. The free convective velocity is used to estimate the impact of wind gusts on ocean wave growth. It is calculated at the height of the lowest temperature inversion (the height above the surface of the Earth where the temperature increases with height). This parameter is one of the parameters used to force the wave model, therefore it is only calculated over water bodies represented in the ocean wave model. It is interpolated from the atmospheric model horizontal grid onto the horizontal grid used by the ocean wave model.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "Friction velocity", + CDSname = "friction_velocity", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is a theoretical wind speed at the Earth's surface that expresses the magnitude of stress. It is calculated by dividing the surface stress by air density and taking its square root. For turbulent flow, the friction velocity is approximately constant in the lowest few metres of the atmosphere. This parameter increases with the roughness of the surface. It is used to calculate the way wind changes with height in the lowest levels of the atmosphere.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "Geopotential", + CDSname = "geopotential", + Description = "This parameter is the gravitational potential energy of a unit mass, at a particular location at the surface of the Earth, relative to mean sea level. It is also the amount of work that would have to be done, against the force of gravity, to lift a unit mass to that location from mean sea level. The (surface) geopotential height (orography) can be calculated by dividing the (surface) geopotential by the Earth's gravitational acceleration, g (=9.80665 m s-2 ). This parameter does not vary in time.", + Unit = "m2 s-2", + Cumulative = FALSE), + data.frame(Variable = "Gravity wave dissipation", + CDSname = "gravity_wave_dissipation", + Description = "This parameter is the amount of energy per unit area that is converted from kinetic energy in the mean flow, into heat, due to the effects of orographic gravity waves. A higher value of this parameter means that more energy is being converted to heat, and so the mean flow is slowing more and the air temperature is rising by a greater amount. Orographic gravity waves are oscillations in the flow maintained by the buoyancy of displaced air parcels, produced when the air is deflected upwards by hills and mountains. Hills and mountains can also block the flow of air at low levels. Together these processes can create a drag or stress on the atmosphere at the Earth's surface (and at other levels in the atmosphere). This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "High cloud cover", + CDSname = "high_cloud_cover", + Description = "The proportion of a grid box covered by cloud occurring in the high levels of the troposphere. High cloud is a single level field calculated from cloud occurring on model levels with a pressure less than 0.45 times the surface pressure. So, if the surface pressure is 1000 hPa (hectopascal), high cloud would be calculated using levels with a pressure of less than 450 hPa (approximately 6km and above (assuming a 'standard atmosphere')). The high cloud cover parameter is calculated from cloud for the appropriate model levels as described above. Assumptions are made about the degree of overlap/randomness between clouds in different model levels. Cloud fractions vary from 0 to 1.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "High vegetation cover", + CDSname = "high_vegetation_cover", + Description = "This parameter is the fraction of the grid box that is covered with vegetation that is classified as 'high'. The values vary between 0 and 1 but do not vary in time. This is one of the parameters in the model that describes land surface vegetation. 'High vegetation' consists of evergreen trees, deciduous trees, mixed forest/woodland, and interrupted forest.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Ice temperature layer 1", + CDSname = "ice_temperature_layer_1", + Description = "This parameter is the sea-ice temperature in layer 1 (0 to 7cm). The ECMWF Integrated Forecasting System (IFS) has a four-layer sea-ice slab: Layer 1: 0-7cm Layer 2: 7-28cm Layer 3: 28-100cm Layer 4: 100-150cm. The temperature of the sea-ice in each layer changes as heat is transferred between the sea-ice layers and the atmosphere above and ocean below. This parameter is defined over the whole globe, even where there is no ocean or sea ice. Regions without sea ice can be masked out by only considering grid points where the sea-ice cover does not have a missing value and is greater than 0.0. Grid points with relatively low values of monthly mean sea-ice cover might include periods during the month when the sea-ice cover is 0.0, in which case the corresponding monthly mean grid point value would be contaminated with fictitious zero ice values.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Ice temperature layer 2", + CDSname = "ice_temperature_layer_2", + Description = "This parameter is the sea-ice temperature in layer 2 (7 to 28cm). The ECMWF Integrated Forecasting System (IFS) has a four-layer sea-ice slab: Layer 1: 0-7cm Layer 2: 7-28cm Layer 3: 28-100cm Layer 4: 100-150cm. The temperature of the sea-ice in each layer changes as heat is transferred between the sea-ice layers and the atmosphere above and ocean below. This parameter is defined over the whole globe, even where there is no ocean or sea ice. Regions without sea ice can be masked out by only considering grid points where the sea-ice cover does not have a missing value and is greater than 0.0. Grid points with relatively low values of monthly mean sea-ice cover might include periods during the month when the sea-ice cover is 0.0, in which case the corresponding monthly mean grid point value would be contaminated with fictitious zero ice values.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Ice temperature layer 3", + CDSname = "ice_temperature_layer_3", + Description = "This parameter is the sea-ice temperature in layer 2 (7 to 28cm). The ECMWF Integrated Forecasting System (IFS) has a four-layer sea-ice slab: Layer 1: 0-7cm Layer 2: 7-28cm Layer 3: 28-100cm Layer 4: 100-150cm. The temperature of the sea-ice in each layer changes as heat is transferred between the sea-ice layers and the atmosphere above and ocean below. This parameter is defined over the whole globe, even where there is no ocean or sea ice. Regions without sea ice can be masked out by only considering grid points where the sea-ice cover does not have a missing value and is greater than 0.0. Grid points with relatively low values of monthly mean sea-ice cover might include periods during the month when the sea-ice cover is 0.0, in which case the corresponding monthly mean grid point value would be contaminated with fictitious zero ice values.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Ice temperature layer 4", + CDSname = "ice_temperature_layer_4", + Description = "", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Instantaneous 10m wind gust", + CDSname = "instantaneous_10m_wind_gust", + Description = "This parameter is the maximum wind gust at the specified time, at a height of ten metres above the surface of the Earth. The WMO defines a wind gust as the maximum of the wind averaged over 3 second intervals. This duration is shorter than a model time step, and so the ECMWF Integrated Forecasting System (IFS) deduces the magnitude of a gust within each time step from the time-step-averaged surface stress, surface friction, wind shear and stability. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "Instantaneous eastward turbulent surface stress", + CDSname = "instantaneous_eastward_turbulent_surface_stress", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is the stress on the Earth's surface at the specified time in the eastward direction due to both the turbulent interactions between the atmosphere and the surface, and to turbulent orographic form drag. The turbulent interactions between the atmosphere and the surface are due to the roughness of the surface. The turbulent orographic form drag is the stress due to the valleys, hills and mountains on horizontal scales below 5km being derived from land surface data at about 1 km resolution. Positive (negative) values denote stress in the eastward (westward) direction.", + Unit = "N m-2", + Cumulative = FALSE), + data.frame(Variable = "Instantaneous large-scale surface precipitation fraction", + CDSname = "instantaneous_large_scale_surface_precipitation_fraction", + Description = "This parameter is the fraction of the grid box (0-1) covered by large-scale precipitation at the specified time. Large-scale precipitation is rain and snow that falls to the Earth's surface, and is generated by the cloud scheme in the ECMWF Integrated Forecasting System (IFS). The cloud scheme represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly by the IFS at spatial scales of a grid box or larger. Precipitation can also be due to convection generated by the convection scheme in the IFS. The convection scheme represents convection at spatial scales smaller than the grid box.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Instantaneous moisture flux", + CDSname = "instantaneous_moisture_flux", + Description = "This parameter is the net rate of moisture exchange between the land/ocean surface and the atmosphere, due to the processes of evaporation (including evapotranspiration) and condensation, at the specified time. By convention, downward fluxes are positive, which means that evaporation is represented by negative values and condensation by positive values.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Instantaneous northward turbulent surface stress", + CDSname = "instantaneous_northward_turbulent_surface_stress", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is the stress on the Earth's surface at the specified time in the northward direction due to both the turbulent interactions between the atmosphere and the surface, and to turbulent orographic form drag. The turbulent interactions between the atmosphere and the surface are due to the roughness of the surface. The turbulent orographic form drag is the stress due to the valleys, hills and mountains on horizontal scales below 5km being derived from land surface data at about 1 km resolution. Positive (negative) values denote stress in the northward (southward) direction.", + Unit = "N m-2", + Cumulative = FALSE), + data.frame(Variable = "Instantaneous surface sensible heat flux", + CDSname = "instantaneous_surface_sensible_heat_flux", + Description = " This parameter is the transfer of heat between the Earth's surface and the atmosphere, at the specified time, through the effects of turbulent air motion (but excluding any heat transfer resulting from condensation or evaporation). The magnitude of the sensible heat flux is governed by the difference in temperature between the surface and the overlying atmosphere, wind speed and the surface roughness. For example, cold air overlying a warm surface would produce a sensible heat flux from the land (or ocean) into the atmosphere. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "K index", + CDSname = "k_index", + Description = "This parameter is a measure of the potential for a thunderstorm to develop, calculated from the temperature and dew point temperature in the lower part of the atmosphere. The calculation uses the temperature at 850, 700 and 500 hPa and dewpoint temperature at 850 and 700 hPa. Higher values of K indicate a higher potential for the development of thunderstorms. This parameter is related to the probability of occurrence of a thunderstorm: <20 K No thunderstorm, 20-25 K Isolated thunderstorms, 26-30 K Widely scattered thunderstorms, 31-35 K Scattered thunderstorms, >35 K Numerous thunderstorms.", + Unit = "K", + Cumulative = NA), + data.frame(Variable = "Lake bottom temperature", + CDSname = "lake_bottom_temperature", + Description = "Temperature of water at the bottom of inland water bodies (lakes, reservoirs, rivers) and coastal waters. ECMWF implemented a lake model in May 2015 to represent the water temperature and lake ice of all the world’s major inland water bodies in the Integrated Forecasting System. The model keeps lake depth and surface area (or fractional cover) constant in time.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Lake cover", + CDSname = "lake_cover", + Description = "This parameter is the proportion of a grid box covered by inland water bodies (lakes, reservoirs, rivers and coastal waters). Values vary between 0: no inland water, and 1: grid box is fully covered with inland water. This parameter is specified from observations and does not vary in time. In May 2015, a lake model was implemented in the ECMWF Integrated Forecasting System (IFS) to represent the water temperature and lake ice of all the world's major inland water bodies.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Lake depth", + CDSname = "lake_depth", + Description = "This parameter is the mean depth of inland water bodies (lakes, reservoirs, rivers and coastal waters). This parameter is specified from in-situ measurements and indirect estimates and does not vary in time. This parameter is defined over the whole globe, even where there is no inland water. Regions without inland water can be masked out by only considering grid points where the lake cover is greater than 0.0. In May 2015, a lake model was implemented in the ECMWF Integrated Forecasting System (IFS) to represent the water temperature and lake ice of all the world's major inland water bodies.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Lake ice depth", + CDSname = "lake_ice_depth", + Description = "The thickness of ice on inland water bodies (lakes, reservoirs and rivers) and coastal waters. The ECMWF Integrated Forecasting System (IFS) represents the formation and melting of ice on inland water bodies (lakes, reservoirs and rivers) and coastal water. A single ice layer is represented. This parameter is the thickness of that ice layer.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Lake ice temperature", + CDSname = "lake_ice_temperature", + Description = "The temperature of the uppermost surface of ice on inland water bodies (lakes, reservoirs, rivers) and coastal waters. The ECMWF Integrated Forecasting System represents the formation and melting of ice on lakes. A single ice layer is represented. The temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Lake mix-layer depth", + CDSname = "lake_mix_layer_depth", + Description = "The thickness of the upper most layer of an inland water body (lake, reservoirs, and rivers) or coastal waters that is well mixed and has a near constant temperature with depth (uniform distribution of temperature). The ECMWF Integrated Forecasting System represents inland water bodies with two layers in the vertical, the mixed layer above and the thermocline below. Thermoclines upper boundary is located at the mixed layer bottom, and the lower boundary at the lake bottom. Mixing within the mixed layer can occur when the density of the surface (and near-surface) water is greater than that of the water below. Mixing can also occur through the action of wind on the surface of the lake.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Lake mix-layer temperature", + CDSname = "lake_mix_layer_temperature", + Description = "The temperature of the upper most layer of inland water bodies (lakes, reservoirs and rivers) or coastal waters) that is well mixed. The ECMWF Integrated Forecasting System represents inland water bodies with two layers in the vertical, the mixed layer above and the thermocline below. Thermoclines upper boundary is located at the mixed layer bottom, and the lower boundary at the lake bottom. Mixing within the mixed layer can occur when the density of the surface (and near-surface) water is greater than that of the water below. Mixing can also occur through the action of wind on the surface of the lake. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Lake shape factor", + CDSname = "lake_shape_factor", + Description = "This parameter describes the way that temperature changes with depth in the thermocline layer of inland water bodies (lakes, reservoirs and rivers) and coastal waters. It is used to calculate the lake bottom temperature and other lake-related parameters. The ECMWF Integrated Forecasting System represents inland and coastal water bodies with two layers in the vertical, the mixed layer above and the thermocline below where temperature changes with depth.", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Lake total layer temperature", + CDSname = "lake_total_layer_temperature", + Description = "The mean temperature of total water column in inland water bodies (lakes, reservoirs and rivers) and coastal waters. The ECMWF Integrated Forecasting System represents inland water bodies with two layers in the vertical, the mixed layer above and the thermocline below where temperature changes with depth. This parameter is the mean over the two layers. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Leaf area index, high vegetation", + CDSname = "leaf_area_index_high_vegetation", + Description = "One-half of the total green leaf area per unit horizontal ground surface area for high vegetation type.", + Unit = "m2 m-2", + Cumulative = FALSE), + data.frame(Variable = "Leaf area index, low vegetation", + CDSname = "leaf_area_index_low_vegetation", + Description = "One-half of the total green leaf area per unit horizontal ground surface area for low vegetation type.", + Unit = "m2 m-2", + Cumulative = FALSE), + data.frame(Variable = "Low cloud cover", + CDSname = "low_cloud_cover", + Description = "This parameter is the proportion of a grid box covered by cloud occurring in the lower levels of the troposphere. Low cloud is a single level field calculated from cloud occurring on model levels with a pressure greater than 0.8 times the surface pressure. So, if the surface pressure is 1000 hPa (hectopascal), low cloud would be calculated using levels with a pressure greater than 800 hPa (below approximately 2km (assuming a 'standard atmosphere')). Assumptions are made about the degree of overlap/randomness between clouds in different model levels. This parameter has values from 0 to 1.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Low vegetation cover", + CDSname = "low_vegetation_cover", + Description = "This parameter is the fraction of the grid box that is covered with vegetation that is classified as 'low'. The values vary between 0 and 1 but do not vary in time. This is one of the parameters in the model that describes land surface vegetation. 'Low vegetation' consists of crops and mixed farming, irrigated crops, short grass, tall grass, tundra, semidesert, bogs and marshes, evergreen shrubs, deciduous shrubs, and water and land mixtures.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Maximum 2m temperature since previous post processing", + CDSname = "maximum_2m_temperature_since_previous_post_processing", + Description = "MISSING METADATA", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Maximum individual wave height", + CDSname = "maximum_individual_wave_height", + Description = "This parameter is an estimate of the height of the expected highest individual wave within a 20 minute time window. It can be used as a guide to the likelihood of extreme or freak waves. The interactions between waves are non-linear and occasionally concentrate wave energy giving a wave height considerably larger than the significant wave height. If the maximum individual wave height is more than twice the significant wave height, then the wave is considered as a freak wave. The significant wave height represents the average height of the highest third of surface ocean/sea waves, generated by local winds and associated with swell. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). This parameter is derived statistically from the two-dimensional wave spectrum. The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of both.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Maximum total precipitation rate since previous post processing", + CDSname = "maximum_total_precipitation_rate_since_previous_post_processing", + Description = "MISSING METADATA", + Unit = " kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean boundary layer dissipation", + CDSname = "mean_boundary_layer_dissipation", + Description = "This parameter is the amount of energy per unit area that is converted from kinetic energy, into heat, due to small-scale motion in the lower levels of the atmosphere. These small-scale motions are called eddies or turbulence. A higher value of this parameter means that more energy is being converted to heat, and so the mean flow is slowing more and the air temperature is rising by a greater amount. This parameter is the mean over a particular time period which depends on the data extracted.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean convective precipitation rate", + CDSname = "mean_convective_precipitation_rate", + Description = "This parameter is the rate of precipitation at the Earth's surface, which is generated by the convection scheme in the ECMWF Integrated Forecasting System (IFS). The convection scheme represents convection at spatial scales smaller than the grid box. Precipitation can also be generated by the cloud scheme in the IFS, which represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly at spatial scales of the grid box or larger. In the IFS, precipitation is comprised of rain and snow. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the precipitation would have if it were spread evenly over the grid box. 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), therefore the units are equivalent to mm (of liquid water) per second. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean convective snowfall rate", + CDSname = "mean_convective_snowfall_rate", + Description = "This parameter is the rate of snowfall (snowfall intensity) at the Earth's surface, which is generated by the convection scheme in the ECMWF Integrated Forecasting System (IFS). The convection scheme represents convection at spatial scales smaller than the grid box. Snowfall can also be generated by the cloud scheme in the IFS, which represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly at spatial scales of the grid box or larger. In the IFS, precipitation is comprised of rain and snow. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the snowfall would have if it were spread evenly over the grid box. Since 1 kg of water spread over 1 square metre of surface is 1 mm thick (neglecting the effects of temperature on the density of water), the units are equivalent to mm (of liquid water) per second. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean direction of total swell", + CDSname = "mean_direction_of_total_swell", + Description = "This parameter is the mean direction of waves associated with swell. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of all swell only. It is the mean over all frequencies and directions of the total swell spectrum. The units are degrees true, which means the direction relative to the geographic location of the north pole. It is the direction that waves are coming from, so 0 degrees means 'coming from the north' and 90 degrees means 'coming from the east'.", + Unit = "degrees", + Cumulative = FALSE), + data.frame(Variable = "Mean direction of wind waves", + CDSname = "mean_direction_of_wind_waves", + Description = "The mean direction of waves generated by local winds. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of wind-sea waves only. It is the mean over all frequencies and directions of the total wind-sea wave spectrum. The units are degrees true, which means the direction relative to the geographic location of the north pole. It is the direction that waves are coming from, so 0 degrees means 'coming from the north' and 90 degrees means 'coming from the east'.", + Unit = "degrees", + Cumulative = FALSE), + data.frame(Variable = " Mean eastward gravity wave surface stress", + CDSname = "mean_eastward_gravity_wave_surface_stress", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is the component of the surface stress, in an eastward direction, associated with low-level blocking and orographic gravity waves. It is calculated by the ECMWF Integrated Forecasting System (IFS) sub-grid orography scheme. It represents surface stress due to unresolved valleys, hills and mountains with horizontal scales between 5 km and the model grid. (The surface stress associated with orographic features with horizontal scales smaller than 5 km is accounted for by the turbulent orographic form drag scheme). Orographic gravity waves are oscillations in the flow maintained by the buoyancy of displaced air parcels, produced when the air is deflected upwards by hills and mountains. Hills and mountains can also block the flow of air at low levels. Together these processes can create a drag or stress on the atmosphere at the Earth's surface (and at other levels in the atmosphere). This parameter is the mean over a particular time period which depends on the data extracted.", + Unit = "N m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean eastward turbulent surface stress", + CDSname = "mean_eastward_turbulent_surface_stress", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is the stress on the Earth's surface in the eastward direction due to both the turbulent interactions between the atmosphere and the surface, and to turbulent orographic form drag. The turbulent interactions between the atmosphere and the surface are due to the roughness of the surface. The turbulent orographic form drag is the stress due to the valleys, hills and mountains on horizontal scales below 5km being derived from land surface data at about 1 km resolution. Positive (negative) values denote stress in the eastward (westward) direction. This parameter is the mean over a particular time period which depends on the data extracted.", + Unit = "N m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean evaporation rate", + CDSname = "mean_evaporation_rate", + Description = "This parameter is the amount of water that has evaporated from the Earth's surface, including a simplified representation of transpiration (from vegetation), into vapour in the air above. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF Integrated Forecasting System (IFS) convention is that downward fluxes are positive. Therefore, negative values indicate evaporation and positive values indicate condensation.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean gravity wave dissipation", + CDSname = "mean_gravity_wave_dissipation", + Description = "This parameter is the amount of energy per unit area that is converted from kinetic energy in the mean flow, into heat, due to the effects of orographic gravity waves. A higher value of this parameter means that more energy is being converted to heat, and so the mean flow is slowing more and the air temperature is rising by a greater amount. Orographic gravity waves are oscillations in the flow maintained by the buoyancy of displaced air parcels, produced when the air is deflected upwards by hills and mountains. Hills and mountains can also block the flow of air at low levels. Together these processes can create a drag or stress on the atmosphere at the Earth's surface (and at other levels in the atmosphere). This parameter is the mean over a particular time period which depends on the data extracted.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean large-scale precipitation fraction", + CDSname = "mean_large_scale_precipitation_fraction", + Description = "This parameter is the mean of the fraction of the grid box (0-1) that is covered by large-scale precipitation. This parameter is the mean over a particular time period which depends on the data extracted.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Mean large-scale precipitation rate", + CDSname = "mean_large_scale_precipitation_rate", + Description = "This parameter is the rate of precipitation at the Earth's surface, which is generated by the cloud scheme in the ECMWF Integrated Forecasting System (IFS). The cloud scheme represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly at spatial scales of the grid box or larger. Precipitation can also be generated by the convection scheme in the IFS, which represents convection at spatial scales smaller than the grid box. In the IFS, precipitation is comprised of rain and snow. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the precipitation would have if it were spread evenly over the grid box. Since 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), the units are equivalent to mm (of liquid water) per second. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean large-scale snowfall rate", + CDSname = "mean_large_scale_snowfall_rate", + Description = "This parameter is the rate of snowfall (snowfall intensity) at the Earth's surface, which is generated by the cloud scheme in the ECMWF Integrated Forecasting System (IFS). The cloud scheme represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly at spatial scales of the grid box or larger. Snowfall can also be generated by the convection scheme in the IFS, which represents convection at spatial scales smaller than the grid box. In the IFS, precipitation is comprised of rain and snow. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the snowfall would have if it were spread evenly over the grid box. Since 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), the units are equivalent to mm (of liquid water) per second. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean northward gravity wave surface stress", + CDSname = "mean_northward_gravity_wave_surface_stress", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is the component of the surface stress, in a northward direction, associated with low-level blocking and orographic gravity waves. It is calculated by the ECMWF Integrated Forecasting System's sub-grid orography scheme. It represents surface stress due to unresolved valleys, hills and mountains with horizontal scales between 5 km and the model grid. (The surface stress associated with orographic features with horizontal scales smaller than 5 km is accounted for by the turbulent orographic form drag scheme). Orographic gravity waves are oscillations in the flow maintained by the buoyancy of displaced air parcels, produced when the air is deflected upwards by hills and mountains. Hills and mountains can also block the flow of air at low levels. Together these processes can create a drag or stress on the atmosphere at the Earth's surface (and at other levels in the atmosphere). This parameter is the mean over a particular time period which depends on the data extracted.", + Unit = "N m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean northward turbulent surface stress", + CDSname = "mean_northward_turbulent_surface_stress", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is the stress on the Earth's surface in the northward direction due to both the turbulent interactions between the atmosphere and the surface, and to turbulent orographic form drag. The turbulent interactions between the atmosphere and the surface are due to the roughness of the surface. The turbulent orographic form drag is the stress due to the valleys, hills and mountains on horizontal scales below 5km being derived from land surface data at about 1 km resolution. Positive (negative) values denote stress in the northward (southward) direction. This parameter is the mean over a particular time period which depends on the data extracted.", + Unit = "N m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean period of total swell", + CDSname = "mean_period_of_total_swell", + Description = "This parameter is the average time it takes for two consecutive wave crests, on the surface of the ocean/sea associated with swell, to pass through a fixed point. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of all swell only. It is the mean over all frequencies and directions of the total swell spectrum.", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean period of wind waves", + CDSname = "mean_period_of_wind_waves", + Description = "This parameter is the average time it takes for two consecutive wave crests, on the surface of the ocean/sea generated by local winds, to pass through a fixed point. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of wind-sea waves only. It is the mean over all frequencies and directions of the total wind-sea spectrum.", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean potential evaporation rate", + CDSname = "mean_potential_evaporation_rate", + Description = "This parameter is a measure of the extent to which near-surface atmospheric conditions are conducive to the process of evaporation. It is usually considered to be the amount of evaporation, under existing atmospheric conditions, from a surface of pure water which has the temperature of the lowest layer of the atmosphere and gives an indication of the maximum possible evaporation. Potential evaporation in the current ECMWF Integrated Forecasting System (IFS) is based on surface energy balance calculations with the vegetation parameters set to 'crops/mixed farming' and assuming 'no stress from soil moisture'. In other words, evaporation is computed for agricultural land as if it is well watered and assuming that the atmosphere is not affected by this artificial surface condition. The latter may not always be realistic. Although potential evaporation is meant to provide an estimate of irrigation requirements, the method can give unrealistic results in arid conditions due to too strong evaporation forced by dry air. This parameter is the mean over a particular time period which depends on the data extracted.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean runoff rate", + CDSname = "mean_runoff_rate", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is called runoff. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the runoff would have if it were spread evenly over the grid box. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point rather than averaged over a grid box. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean sea level pressure", + CDSname = "mean_sea_level_pressure", + Description = "This parameter is the pressure (force per unit area) of the atmosphere at the surface of the Earth, adjusted to the height of mean sea level. It is a measure of the weight that all the air in a column vertically above a point on the Earth's surface would have, if the point were located at mean sea level. It is calculated over all surfaces - land, sea and inland water. Maps of mean sea level pressure are used to identify the locations of low and high pressure weather systems, often referred to as cyclones and anticyclones. Contours of mean sea level pressure also indicate the strength of the wind. Tightly packed contours show stronger winds. The units of this parameter are pascals (Pa). Mean sea level pressure is often measured in hPa and sometimes is presented in the old units of millibars, mb (1 hPa = 1 mb = 100 Pa).", + Unit = "Pa", + Cumulative = FALSE), + data.frame(Variable = "Mean snow evaporation rate", + CDSname = "mean_snow_evaporation_rate", + Description = "This parameter is the average rate of snow evaporation from the snow-covered area of a grid box into vapour in the air above. The ECMWF Integrated Forecasting System (IFS) represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the snow evaporation would have if it were spread evenly over the grid box. 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), therefore the units are equivalent to mm (of liquid water) per second. The IFS convention is that downward fluxes are positive. Therefore, negative values indicate evaporation and positive values indicate deposition.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean snowfall rate", + CDSname = "mean_snowfall_rate", + Description = "This parameter is the rate of snowfall at the Earth's surface. It is the sum of large-scale and convective snowfall. Large-scale snowfall is generated by the cloud scheme in the ECMWF Integrated Forecasting System (IFS). The cloud scheme represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly at spatial scales of the grid box or larger. Convective snowfall is generated by the convection scheme in the IFS, which represents convection at spatial scales smaller than the grid box. In the IFS, precipitation is comprised of rain and snow. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the snowfall would have if it were spread evenly over the grid box. 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), therefore the units are equivalent to mm (of liquid water) per second. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "kg m-2 s-1", + Cumulative = NA), + data.frame(Variable = "Mean snowmelt rate", + CDSname = "mean_snowmelt_rate", + Description = "This parameter is the rate of snow melt in the snow-covered area of a grid box. The ECMWF Integrated Forecasting System (IFS) represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the melting would have if it were spread evenly over the grid box. 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), therefore the units are equivalent to mm (of liquid water) per second.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean square slope of waves", + CDSname = "mean_square_slope_of_waves", + Description = "This parameter can be related analytically to the average slope of combined wind-sea and swell waves. It can also be expressed as a function of wind speed under some statistical assumptions. The higher the slope, the steeper the waves. This parameter indicates the roughness of the sea/ocean surface which affects the interaction between ocean and atmosphere. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). This parameter is derived statistically from the two-dimensional wave spectrum.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Mean sub-surface runoff rate", + CDSname = "mean_sub_surface_runoff_rate", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is called runoff. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the runoff would have if it were spread evenly over the grid box. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point rather than averaged over a grid box. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean surface direct short-wave radiation flux", + CDSname = "mean_surface_direct_short_wave_radiation_flux", + Description = "This parameter is the amount of direct solar radiation (also known as shortwave radiation) reaching the surface of the Earth. It is the amount of radiation passing through a horizontal plane. Solar radiation at the surface can be direct or diffuse. Solar radiation can be scattered in all directions by particles in the atmosphere, some of which reaches the surface (diffuse solar radiation). Some solar radiation reaches the surface without being scattered (direct solar radiation). This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface direct short-wave radiation flux, clear sky", + CDSname = "mean_surface_direct_short_wave_radiation_flux_clear_sky", + Description = "This parameter is the amount of direct radiation from the Sun (also known as solar or shortwave radiation) reaching the surface of the Earth, assuming clear-sky (cloudless) conditions. It is the amount of radiation passing through a horizontal plane. Solar radiation at the surface can be direct or diffuse. Solar radiation can be scattered in all directions by particles in the atmosphere, some of which reaches the surface (diffuse solar radiation). Some solar radiation reaches the surface without being scattered (direct solar radiation). Clear-sky radiation quantities are computed for exactly the same atmospheric conditions of temperature, humidity, ozone, trace gases and aerosol as the corresponding total-sky quantities (clouds included), but assuming that the clouds are not there. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface downward long-wave radiation flux", + CDSname = "mean_surface_downward_long_wave_radiation_flux", + Description = "This parameter is the amount of thermal (also known as longwave or terrestrial) radiation emitted by the atmosphere and clouds that reaches a horizontal plane at the surface of the Earth. The surface of the Earth emits thermal radiation, some of which is absorbed by the atmosphere and clouds. The atmosphere and clouds likewise emit thermal radiation in all directions, some of which reaches the surface (represented by this parameter). This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface downward long-wave radiation flux, clear sky", + CDSname = "mean_surface_downward_long_wave_radiation_flux_clear_sky", + Description = "Clear-sky downward longwave radiation flux at the surface, computed from the model radiation scheme.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface downward short-wave radiation flux", + CDSname = "mean_surface_downward_short_wave_radiation_flux", + Description = "This parameter is the amount of solar radiation (also known as shortwave radiation) that reaches a horizontal plane at the surface of the Earth. This parameter comprises both direct and diffuse solar radiation. Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The rest is incident on the Earth's surface (represented by this parameter). To a reasonably good approximation, this parameter is the model equivalent of what would be measured by a pyranometer (an instrument used for measuring solar radiation) at the surface. However, care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface downward short-wave radiation flux, clear sky", + CDSname = "mean_surface_downward_short_wave_radiation_flux_clear_sky", + Description = "Clear-sky downward shortwave radiation flux at the surface, computed from the model radiation scheme.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface downward UV radiation flux", + CDSname = "mean_surface_downward_uv_radiation_flux", + Description = "This parameter is the amount of ultraviolet (UV) radiation reaching the surface. It is the amount of radiation passing through a horizontal plane. UV radiation is part of the electromagnetic spectrum emitted by the Sun that has wavelengths shorter than visible light. In the ECMWF Integrated Forecasting system (IFS) it is defined as radiation with a wavelength of 0.20-0.44 µm (microns, 1 millionth of a metre). Small amounts of UV are essential for living organisms, but overexposure may result in cell damage; in humans this includes acute and chronic health effects on the skin, eyes and immune system. UV radiation is absorbed by the ozone layer, but some reaches the surface. The depletion of the ozone layer is causing concern over an increase in the damaging effects of UV. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface latent heat flux", + CDSname = "mean_surface_latent_heat_flux", + Description = "This parameter is the transfer of latent heat (resulting from water phase changes, such as evaporation or condensation) between the Earth's surface and the atmosphere through the effects of turbulent air motion. Evaporation from the Earth's surface represents a transfer of energy from the surface to the atmosphere. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface net long-wave radiation flux", + CDSname = "mean_surface_net_long_wave_radiation_flux", + Description = "Thermal radiation (also known as longwave or terrestrial radiation) refers to radiation emitted by the atmosphere, clouds and the surface of the Earth. This parameter is the difference between downward and upward thermal radiation at the surface of the Earth. It is the amount of radiation passing through a horizontal plane. The atmosphere and clouds emit thermal radiation in all directions, some of which reaches the surface as downward thermal radiation. The upward thermal radiation at the surface consists of thermal radiation emitted by the surface plus the fraction of downwards thermal radiation reflected upward by the surface. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface net long-wave radiation flux, clear sky", + CDSname = "mean_surface_net_long_wave_radiation_flux_clear_sky", + Description = "Thermal radiation (also known as longwave or terrestrial radiation) refers to radiation emitted by the atmosphere, clouds and the surface of the Earth. This parameter is the difference between downward and upward thermal radiation at the surface of the Earth, assuming clear-sky (cloudless) conditions. It is the amount of radiation passing through a horizontal plane. Clear-sky radiation quantities are computed for exactly the same atmospheric conditions of temperature, humidity, ozone, trace gases and aerosol as the corresponding total-sky quantities (clouds included), but assuming that the clouds are not there. The atmosphere and clouds emit thermal radiation in all directions, some of which reaches the surface as downward thermal radiation. The upward thermal radiation at the surface consists of thermal radiation emitted by the surface plus the fraction of downwards thermal radiation reflected upward by the surface. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface net short-wave radiation flux", + CDSname = "mean_surface_net_short_wave_radiation_flux", + Description = "This parameter is the amount of solar radiation (also known as shortwave radiation) that reaches a horizontal plane at the surface of the Earth (both direct and diffuse) minus the amount reflected by the Earth's surface (which is governed by the albedo). Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The remainder is incident on the Earth's surface, where some of it is reflected. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface net short-wave radiation flux, clear sky", + CDSname = "mean_surface_net_short_wave_radiation_flux_clear_sky", + Description = "This parameter is the amount of solar (shortwave) radiation reaching the surface of the Earth (both direct and diffuse) minus the amount reflected by the Earth's surface (which is governed by the albedo), assuming clear-sky (cloudless) conditions. It is the amount of radiation passing through a horizontal plane. Clear-sky radiation quantities are computed for exactly the same atmospheric conditions of temperature, humidity, ozone, trace gases and aerosol as the corresponding total-sky quantities (clouds included), but assuming that the clouds are not there. Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The rest is incident on the Earth's surface, where some of it is reflected. The difference between downward and reflected solar radiation is the surface net solar radiation. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean surface runoff rate", + CDSname = "mean_surface_runoff_rate", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is called runoff. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the runoff would have if it were spread evenly over the grid box. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point rather than averaged over a grid box. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean surface sensible heat flux", + CDSname = "mean_surface_sensible_heat_flux", + Description = "This parameter is the transfer of heat between the Earth's surface and the atmosphere through the effects of turbulent air motion (but excluding any heat transfer resulting from condensation or evaporation). The magnitude of the sensible heat flux is governed by the difference in temperature between the surface and the overlying atmosphere, wind speed and the surface roughness. For example, cold air overlying a warm surface would produce a sensible heat flux from the land (or ocean) into the atmosphere. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean top downward short-wave radiation flux", + CDSname = "mean_top_downward_short_wave_radiation_flux", + Description = "This parameter is the incoming solar radiation (also known as shortwave radiation), received from the Sun, at the top of the atmosphere. It is the amount of radiation passing through a horizontal plane. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean top net long-wave radiation flux", + CDSname = "mean_top_net_long_wave_radiation_flux", + Description = "The thermal (also known as terrestrial or longwave) radiation emitted to space at the top of the atmosphere is commonly known as the Outgoing Longwave Radiation (OLR). The top net thermal radiation (this parameter) is equal to the negative of OLR. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean top net long-wave radiation flux, clear sky", + CDSname = "mean_top_net_long_wave_radiation_flux_clear_sky", + Description = "This parameter is the thermal (also known as terrestrial or longwave) radiation emitted to space at the top of the atmosphere, assuming clear-sky (cloudless) conditions. It is the amount passing through a horizontal plane. Note that the ECMWF convention for vertical fluxes is positive downwards, so a flux from the atmosphere to space will be negative. Clear-sky radiation quantities are computed for exactly the same atmospheric conditions of temperature, humidity, ozone, trace gases and aerosol as total-sky quantities (clouds included), but assuming that the clouds are not there. The thermal radiation emitted to space at the top of the atmosphere is commonly known as the Outgoing Longwave Radiation (OLR) (i.e., taking a flux from the atmosphere to space as positive). This parameter is the mean over a particular time period which depends on the data extracted.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean top net short-wave radiation flux", + CDSname = "mean_top_net_short_wave_radiation_flux", + Description = "This parameter is the incoming solar radiation (also known as shortwave radiation) minus the outgoing solar radiation at the top of the atmosphere. It is the amount of radiation passing through a horizontal plane. The incoming solar radiation is the amount received from the Sun. The outgoing solar radiation is the amount reflected and scattered by the Earth's atmosphere and surface. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean top net short-wave radiation flux, clear sky", + CDSname = "mean_top_net_short_wave_radiation_flux_clear_sky", + Description = "This parameter is the incoming solar radiation (also known as shortwave radiation) minus the outgoing solar radiation at the top of the atmosphere, assuming clear-sky (cloudless) conditions. It is the amount of radiation passing through a horizontal plane. The incoming solar radiation is the amount received from the Sun. The outgoing solar radiation is the amount reflected and scattered by the Earth's atmosphere and surface, assuming clear-sky (cloudless) conditions. Clear-sky radiation quantities are computed for exactly the same atmospheric conditions of temperature, humidity, ozone, trace gases and aerosol as the total-sky (clouds included) quantities, but assuming that the clouds are not there. This parameter is the mean over a particular time period which depends on the data extracted. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Mean total precipitation rate", + CDSname = "mean_total_precipitation_rate", + Description = "This parameter is the rate of precipitation at the Earth's surface. It is the sum of the rates due to large-scale precipitation and convective precipitation. Large-scale precipitation is generated by the cloud scheme in the ECMWF Integrated Forecasting System (IFS). The cloud scheme represents the formation and dissipation of clouds and large-scale precipitation due to changes in atmospheric quantities (such as pressure, temperature and moisture) predicted directly at spatial scales of the grid box or larger. Convective precipitation is generated by the convection scheme in the IFS, which represents convection at spatial scales smaller than the grid box. In the IFS, precipitation is comprised of rain and snow. This parameter is the mean over a particular time period which depends on the data extracted. It is the rate the precipitation would have if it were spread evenly over the grid box. 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), therefore the units are equivalent to mm (of liquid water) per second. Care should be taken when comparing model parameters with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean vertical gradient of refractivity inside trapping layer", + CDSname = "mean_vertical_gradient_of_refractivity_inside_trapping_layer", + Description = "Mean vertical gradient of atmospheric refractivity inside trapping layer.", + Unit = "m-1", + Cumulative = FALSE), + data.frame(Variable = "Mean vertically integrated moisture divergence", + CDSname = "mean_vertically_integrated_moisture_divergence", + Description = "The vertical integral of the moisture flux is the horizontal rate of flow of moisture (water vapour, cloud liquid and cloud ice), per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of moisture spreading outward from a point, per square metre. This parameter is the mean over a particular time period which depends on the data extracted. This parameter is positive for moisture that is spreading out, or diverging, and negative for the opposite, for moisture that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of moisture, over the time period. High negative values of this parameter (i.e. large moisture convergence) can be related to precipitation intensification and floods. 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), therefore the units are equivalent to mm (of liquid water) per second.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Mean wave direction", + CDSname = "mean_wave_direction", + Description = "This parameter is the mean direction of ocean/sea surface waves. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). This parameter is a mean over all frequencies and directions of the two-dimensional wave spectrum. The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of both. This parameter can be used to assess sea state and swell. For example, engineers use this type of wave information when designing structures in the open ocean, such as oil platforms, or in coastal applications. The units are degrees true, which means the direction relative to the geographic location of the north pole. It is the direction that waves are coming from, so 0 degrees means 'coming from the north' and 90 degrees means 'coming from the east'.", + Unit = "degree true", + Cumulative = FALSE), + data.frame(Variable = "Mean wave direction of first swell partition", + CDSname = "mean_wave_direction_of_first_swell_partition", + Description = "This parameter is the mean direction of waves in the first swell partition. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. In many situations, swell can be made up of different swell systems, for example, from two distant and separate storms. To account for this, the swell spectrum is partitioned into up to three parts. The swell partitions are labelled first, second and third based on their respective wave height. Therefore, there is no guarantee of spatial coherence (the first swell partition might be from one system at one location and a different system at the neighbouring location). The units are degrees true, which means the direction relative to the geographic location of the north pole. It is the direction that waves are coming from, so 0 degrees means 'coming from the north' and 90 degrees means 'coming from the east'.", + Unit = "degrees", + Cumulative = FALSE), + data.frame(Variable = "Mean wave direction of second swell partition", + CDSname = "mean_wave_direction_of_second_swell_partition", + Description = "This parameter is the mean direction of waves in the second swell partition. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. In many situations, swell can be made up of different swell systems, for example, from two distant and separate storms. To account for this, the swell spectrum is partitioned into up to three parts. The swell partitions are labelled first, second and third based on their respective wave height. Therefore, there is no guarantee of spatial coherence (the first swell partition might be from one system at one location and a different system at the neighbouring location). The units are degrees true, which means the direction relative to the geographic location of the north pole. It is the direction that waves are coming from, so 0 degrees means 'coming from the north' and 90 degrees means 'coming from the east'.", + Unit = "degrees", + Cumulative = FALSE), + data.frame(Variable = "Mean wave direction of third swell partition", + CDSname = "mean_wave_direction_of_third_swell_partition", + Description = "This parameter is the mean direction of waves in the third swell partition. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. In many situations, swell can be made up of different swell systems, for example, from two distant and separate storms. To account for this, the swell spectrum is partitioned into up to three parts. The swell partitions are labelled first, second and third based on their respective wave height. Therefore, there is no guarantee of spatial coherence (the first swell partition might be from one system at one location and a different system at the neighbouring location). The units are degrees true, which means the direction relative to the geographic location of the north pole. It is the direction that waves are coming from, so 0 degrees means 'coming from the north' and 90 degrees means 'coming from the east'.", + Unit = "degrees", + Cumulative = FALSE), + data.frame(Variable = "Mean wave period", + CDSname = "mean_wave_period", + Description = "This parameter is the average time it takes for two consecutive wave crests, on the surface of the ocean/sea, to pass through a fixed point. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). This parameter is a mean over all frequencies and directions of the two-dimensional wave spectrum. The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of both. This parameter can be used to assess sea state and swell. For example, engineers use such wave information when designing structures in the open ocean, such as oil platforms, or in coastal applications.", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean wave period based on first moment", + CDSname = "mean_wave_period_based_on_first_moment", + Description = "This parameter is the reciprocal of the mean frequency of the wave components that represent the sea state. All wave components have been averaged proportionally to their respective amplitude. This parameter can be used to estimate the magnitude of Stokes drift transport in deep water. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). Moments are statistical quantities derived from the two-dimensional wave spectrum.", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean wave period based on first moment for swell", + CDSname = "mean_wave_period_based_on_first_moment_for_swell", + Description = "This parameter is the reciprocal of the mean frequency of the wave components associated with swell. All wave components have been averaged proportionally to their respective amplitude. This parameter can be used to estimate the magnitude of Stokes drift transport in deep water associated with swell. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of all swell only. Moments are statistical quantities derived from the two-dimensional wave spectrum.", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean wave period based on first moment for wind waves", + CDSname = "mean_wave_period_based_on_first_moment_for_wind_waves", + Description = "This parameter is the reciprocal of the mean frequency of the wave components generated by local winds. All wave components have been averaged proportionally to their respective amplitude. This parameter can be used to estimate the magnitude of Stokes drift transport in deep water associated with wind waves. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of wind-sea waves only. Moments are statistical quantities derived from the two-dimensional wave spectrum", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean wave period based on second moment for swell", + CDSname = "mean_wave_period_based_on_second_moment_for_swell", + Description = "This parameter is the reciprocal of the mean frequency of the wave components associated with swell. All wave components have been averaged proportionally to their respective amplitude. This parameter can be used to estimate the magnitude of Stokes drift transport in deep water associated with swell. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of all swell only. Moments are statistical quantities derived from the two-dimensional wave spectrum.", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean wave period based on second moment for wind waves", + CDSname = "mean_wave_period_based_on_second_moment_for_wind_waves", + Description = "This parameter is the reciprocal of the mean frequency of the wave components generated by local winds. All wave components have been averaged proportionally to their respective amplitude. This parameter can be used to estimate the magnitude of Stokes drift transport in deep water associated with wind waves. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of wind-sea waves only. Moments are statistical quantities derived from the two-dimensional wave spectrum", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean wave period of first swell partition", + CDSname = "mean_wave_period_of_first_swell_partition", + Description = "This parameter is the mean period of waves in the first swell partition. The wave period is the average time it takes for two consecutive wave crests, on the surface of the ocean/sea, to pass through a fixed point. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. In many situations, swell can be made up of different swell systems, for example, from two distant and separate storms. To account for this, the swell spectrum is partitioned into up to three parts. The swell partitions are labelled first, second and third based on their respective wave height. Therefore, there is no guarantee of spatial coherence (the first swell partition might be from one system at one location and a different system at the neighbouring location).", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean wave period of second swell partition", + CDSname = "mean_wave_period_of_second_swell_partition", + Description = "This parameter is the mean period of waves in the second swell partition. The wave period is the average time it takes for two consecutive wave crests, on the surface of the ocean/sea, to pass through a fixed point. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. In many situations, swell can be made up of different swell systems, for example, from two distant and separate storms. To account for this, the swell spectrum is partitioned into up to three parts. The swell partitions are labelled first, second and third based on their respective wave height. Therefore, there is no guarantee of spatial coherence (the first swell partition might be from one system at one location and a different system at the neighbouring location).", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean wave period of third swell partition", + CDSname = "mean_wave_period_of_third_swell_partition", + Description = "This parameter is the mean period of waves in the third swell partition. The wave period is the average time it takes for two consecutive wave crests, on the surface of the ocean/sea, to pass through a fixed point. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. In many situations, swell can be made up of different swell systems, for example, from two distant and separate storms. To account for this, the swell spectrum is partitioned into up to three parts. The swell partitions are labelled first, second and third based on their respective wave height. Therefore, there is no guarantee of spatial coherence (the first swell partition might be from one system at one location and a different system at the neighbouring location).", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Mean zero-crossing wave period", + CDSname = "mean_zero_crossing_wave_period", + Description = " This parameter represents the mean length of time between occasions where the sea/ocean surface crosses mean sea level. In combination with wave height information, it could be used to assess the length of time that a coastal structure might be under water, for example. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). In the ECMWF Integrated Forecasting System (IFS) this parameter is calculated from the characteristics of the two-dimensional wave spectrum.", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Medium cloud cover", + CDSname = "medium_cloud_cover", + Description = "This parameter is the proportion of a grid box covered by cloud occurring in the middle levels of the troposphere. Medium cloud is a single level field calculated from cloud occurring on model levels with a pressure between 0.45 and 0.8 times the surface pressure. So, if the surface pressure is 1000 hPa (hectopascal), medium cloud would be calculated using levels with a pressure of less than or equal to 800 hPa and greater than or equal to 450 hPa (between approximately 2km and 6km (assuming a 'standard atmosphere')). The medium cloud parameter is calculated from cloud cover for the appropriate model levels as described above. Assumptions are made about the degree of overlap/randomness between clouds in different model levels. Cloud fractions vary from 0 to 1.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Minimum 2m temperature since previous post processing", + CDSname = "minimum_2m_temperature_since_previous_post_processing", + Description = "MISSING METADATA", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Minimum total precipitation rate since previous post processing", + CDSname = "minimum_total_precipitation_rate_since_previous_post_processing", + Description = "MISSING METADATA", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Minimum vertical gradient of refractivity inside trapping layer", + CDSname = "minimum_vertical_gradient_of_refractivity_inside_trapping_layer", + Description = "Minimum vertical gradient of atmospheric refractivity inside trapping layer.", + Unit = "m-1", + Cumulative = FALSE), + data.frame(Variable = "Model bathymetry", + CDSname = "model_bathymetry", + Description = "This parameter is the depth of water from the surface to the bottom of the ocean. It is used by the ocean wave model to specify the propagation properties of the different waves that could be present. Note that the ocean wave model grid is too coarse to resolve some small islands and mountains on the bottom of the ocean, but they can have an impact on surface ocean waves. The ocean wave model has been modified to reduce the wave energy flowing around or over features at spatial scales smaller than the grid box.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Near IR albedo for diffuse radiation", + CDSname = "near_ir_albedo_for_diffuse_radiation", + Description = "Albedo is a measure of the reflectivity of the Earth's surface. This parameter is the fraction of diffuse solar (shortwave) radiation with wavelengths between 0.7 and 4 µm (microns, 1 millionth of a metre) reflected by the Earth's surface (for snow-free land surfaces only). Values of this parameter vary between 0 and 1. In the ECMWF Integrated Forecasting System (IFS) albedo is dealt with separately for solar radiation with wavelengths greater/less than 0.7µm and for direct and diffuse solar radiation (giving 4 components to albedo). Solar radiation at the surface can be direct or diffuse. Solar radiation can be scattered in all directions by particles in the atmosphere, some of which reaches the surface (diffuse solar radiation). Some solar radiation reaches the surface without being scattered (direct solar radiation). In the IFS, a climatological (observed values averaged over a period of several years) background albedo is used which varies from month to month through the year, modified by the model over water, ice and snow.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Near IR albedo for direct radiation", + CDSname = "near_ir_albedo_for_direct_radiation", + Description = "Albedo is a measure of the reflectivity of the Earth's surface. This parameter is the fraction of direct solar (shortwave) radiation with wavelengths between 0.7 and 4 µm (microns, 1 millionth of a metre) reflected by the Earth's surface (for snow-free land surfaces only). Values of this parameter vary between 0 and 1. In the ECMWF Integrated Forecasting System (IFS) albedo is dealt with separately for solar radiation with wavelengths greater/less than 0.7µm and for direct and diffuse solar radiation (giving 4 components to albedo). Solar radiation at the surface can be direct or diffuse. Solar radiation can be scattered in all directions by particles in the atmosphere, some of which reaches the surface (diffuse solar radiation). Some solar radiation reaches the surface without being scattered (direct solar radiation). In the IFS, a climatological (observed values averaged over a period of several years) background albedo is used which varies from month to month through the year, modified by the model over water, ice and snow.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Normalized energy flux into ocean", + CDSname = "normalized_energy_flux_into_ocean", + Description = "This parameter is the normalised vertical flux of turbulent kinetic energy from ocean waves into the ocean. The energy flux is calculated from an estimation of the loss of wave energy due to white capping waves. A white capping wave is one that appears white at its crest as it breaks, due to air being mixed into the water. When waves break in this way, there is a transfer of energy from the waves to the ocean. Such a flux is defined to be negative. The energy flux has units of Watts per metre squared, and this is normalised by being divided by the product of air density and the cube of the friction velocity.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Normalized energy flux into waves", + CDSname = "normalized_energy_flux_into_waves", + Description = "This parameter is the normalised vertical flux of energy from wind into the ocean waves. A positive flux implies a flux into the waves. The energy flux has units of Watts per metre squared, and this is normalised by being divided by the product of air density and the cube of the friction velocity.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Normalized stress into ocean", + CDSname = "normalized_stress_into_ocean", + Description = "This parameter is the normalised surface stress, or momentum flux, from the air into the ocean due to turbulence at the air-sea interface and breaking waves. It does not include the flux used to generate waves. The ECMWF convention for vertical fluxes is positive downwards. The stress has units of Newtons per metre squared, and this is normalised by being divided by the product of air density and the square of the friction velocity.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Northward gravity wave surface stress", + CDSname = "northward_gravity_wave_surface_stress", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is the component of the surface stress, in a northward direction, associated with low-level blocking and orographic gravity waves. It is calculated by the ECMWF Integrated Forecasting System's sub-grid orography scheme. It represents surface stress due to unresolved valleys, hills and mountains with horizontal scales between 5 km and the model grid. (The surface stress associated with orographic features with horizontal scales smaller than 5 km is accounted for by the turbulent orographic form drag scheme). Orographic gravity waves are oscillations in the flow maintained by the buoyancy of displaced air parcels, produced when the air is deflected upwards by hills and mountains. Hills and mountains can also block the flow of air at low levels. Together these processes can create a drag or stress on the atmosphere at the Earth's surface (and at other levels in the atmosphere). This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. ", + Unit = "N m-2 s", + Cumulative = TRUE), + data.frame(Variable = "Northward turbulent surface stress", + CDSname = "northward_turbulent_surface_stress", + Description = "Air flowing over a surface exerts a stress that transfers momentum to the surface and slows the wind. This parameter is the accumulated stress on the Earth's surface in the northward direction due to both the turbulent interactions between the atmosphere and the surface, and to turbulent orographic form drag. The turbulent interactions between the atmosphere and the surface are due to the roughness of the surface. The turbulent orographic form drag is the stress due to the valleys, hills and mountains on horizontal scales below 5km being derived from land surface data at about 1 km resolution. Positive (negative) values denote stress in the northward (southward) direction. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. ", + Unit = "N m-2 s", + Cumulative = TRUE), + data.frame(Variable = "Ocean surface stress equivalent 10m neutral wind direction", + CDSname = "ocean_surface_stress_equivalent_10m_neutral_wind_direction", + Description = "This parameter is the direction from which the 'neutral wind' blows, in degrees clockwise from true north, at a height of ten metres above the surface of the Earth. The neutral wind is calculated from the surface stress and roughness length by assuming that the air is neutrally stratified. The neutral wind is, by definition, in the direction of the surface stress. The size of the roughness length depends on the sea state. This parameter is the wind direction used to force the wave model, therefore it is only calculated over water bodies represented in the ocean wave model. It is interpolated from the atmospheric model's horizontal grid onto the horizontal grid used by the ocean wave model.", + Unit = "degrees", + Cumulative = FALSE), + data.frame(Variable = "Ocean surface stress equivalent 10m neutral wind speed", + CDSname = "ocean_surface_stress_equivalent_10m_neutral_wind_speed", + Description = "This parameter is the horizontal speed of the 'neutral wind', at a height of ten metres above the surface of the Earth. The units of this parameter are metres per second. The neutral wind is calculated from the surface stress and roughness length by assuming that the air is neutrally stratified. The neutral wind is, by definition, in the direction of the surface stress. The size of the roughness length depends on the sea state. This parameter is the wind speed used to force the wave model, therefore it is only calculated over water bodies represented in the ocean wave model. It is interpolated from the atmospheric model's horizontal grid onto the horizontal grid used by the ocean wave model.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "Peak wave period", + CDSname = "peak_wave_period", + Description = "This parameter represents the period of the most energetic ocean waves generated by local winds and associated with swell. The wave period is the average time it takes for two consecutive wave crests, on the surface of the ocean/sea, to pass through a fixed point. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). This parameter is calculated from the reciprocal of the frequency corresponding to the largest value (peak) of the frequency wave spectrum. The frequency wave spectrum is obtained by integrating the two-dimensional wave spectrum over all directions. The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of both.", + Unit = "s", + Cumulative = FALSE), + data.frame(Variable = "Period corresponding to maximum individual wave height", + CDSname = "period_corresponding_to_maximum_individual_wave_height", + Description = "This parameter is the period of the expected highest individual wave within a 20-minute time window. It can be used as a guide to the characteristics of extreme or freak waves. Wave period is the average time it takes for two consecutive wave crests, on the surface of the ocean/sea, to pass through a fixed point. Occasionally waves of different periods reinforce and interact non-linearly giving a wave height considerably larger than the significant wave height. If the maximum individual wave height is more than twice the significant wave height, then the wave is considered to be a freak wave. The significant wave height represents the average height of the highest third of surface ocean/sea waves, generated by local winds and associated with swell. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). This parameter is derived statistically from the two-dimensional wave spectrum. The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of both.", + Unit = "s", Cumulative = FALSE), + data.frame(Variable = "Potential evaporation", + CDSname = "potential_evaporation", + Description = "Potential evaporation (pev) in the current ECMWF model is computed, by making a second call to the surface energy balance routine with the vegetation variables set to 'crops/mixed farming' and assuming no stress from soil moisture. In other words, evaporation is computed for agricultural land as if it is well watered and assuming that the atmosphere is not affected by this artificial surface condition. The latter may not always be realistic. Although pev is meant to provide an estimate of irrigation requirements, the method can give unrealistic results in arid conditions due to too strong evaporation forced by dry air. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Precipitation type", + CDSname = "precipitation_type", + Description = "This parameter describes the type of precipitation at the surface, at the specified time. A precipitation type is assigned wherever there is a non-zero value of precipitation. In the ECMWF Integrated Forecasting System (IFS) there are only two predicted precipitation variables: rain and snow. Precipitation type is derived from these two predicted variables in combination with atmospheric conditions, such as temperature. Values of precipitation type defined in the IFS: 0 = No precipitation 1 = Rain 3 = Freezing rain (i.e. supercooled raindrops which freeze on contact with the ground and other surfaces) 5 = Snow 6 = Wet snow (i.e. snow particles which are starting to melt) 7 = Mixture of rain and snow 8 = Ice pellets These precipitation types are consistent with WMO Code Table 4.201. 2 (thunderstorm), 4 (mixed ice), 9 (graupel), 10 (hail), 11 (drizzle) and 12 (freezing drizzle) are not diagnosed in the IFS. The monthly mean procedure applied to such integers, will yield non-integer values.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Runoff", + CDSname = "runoff", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is simply called 'runoff'. This variable is the total amount of water accumulated from the beginning of the forecast time to the end of the forecast step. The units of runoff are depth in metres. This is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point rather than averaged over a grid square area. Observations are also often taken in different units, such as mm/day, rather than the accumulated metres produced here. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood. More information about how runoff is calculated is given in the IFS Physical Processes documentation.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Sea-ice cover", + CDSname = "sea_ice_cover", + Description = "This parameter is the fraction of a grid box which is covered by sea ice. Sea ice can only occur in a grid box which includes ocean or inland water according to the land sea mask and lake cover, at the resolution being used. This parameter can be known as sea-ice (area) fraction, sea-ice concentration and more generally as sea-ice cover. In ERA5, sea-ice cover is given by two external providers. Before 1979 the HadISST2 dataset is used. From 1979 to August 2007 the OSI SAF (409a) dataset is used and from September 2007 the OSI SAF oper dataset is used. Sea ice is frozen sea water which floats on the surface of the ocean. Sea ice does not include ice which forms on land such as glaciers, icebergs and ice-sheets. It also excludes ice shelves which are anchored on land, but protrude out over the surface of the ocean. These phenomena are not modelled by the IFS. Long-term monitoring of sea ice is important for understanding climate change. Sea ice also affects shipping routes through the polar regions.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Sea surface temperature", + CDSname = "sea_surface_temperature", + Description = "This parameter (SST) is the temperature of sea water near the surface. In ERA5, this parameter is a foundation SST, which means there are no variations due to the daily cycle of the sun (diurnal variations). SST, in ERA5, is given by two external providers. Before September 2007, SST from the HadISST2 dataset is used and from September 2007 onwards, the OSTIA dataset is used. This parameter has units of kelvin (K). Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Significant height of combined wind waves and swell", + CDSname = "significant_height_of_combined_wind_waves_and_swell", + Description = "This parameter represents the average height of the highest third of surface ocean/sea waves generated by wind and swell. It represents the vertical distance between the wave crest and the wave trough. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of both. More strictly, this parameter is four times the square root of the integral over all directions and all frequencies of the two-dimensional wave spectrum. This parameter can be used to assess sea state and swell. For example, engineers use significant wave height to calculate the load on structures in the open ocean, such as oil platforms, or in coastal applications.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Significant height of total swell", + CDSname = "significant_height_of_total_swell", + Description = "This parameter represents the average height of the highest third of surface ocean/sea waves associated with swell. It represents the vertical distance between the wave crest and the wave trough. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of total swell only. More strictly, this parameter is four times the square root of the integral over all directions and all frequencies of the two-dimensional total swell spectrum. The total swell spectrum is obtained by only considering the components of the two-dimensional wave spectrum that are not under the influence of the local wind. This parameter can be used to assess swell. For example, engineers use significant wave height to calculate the load on structures in the open ocean, such as oil platforms, or in coastal applications.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Significant height of wind waves", + CDSname = "significant_height_of_wind_waves", + Description = "This parameter represents the average height of the highest third of surface ocean/sea waves generated by the local wind. It represents the vertical distance between the wave crest and the wave trough. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of wind-sea waves only. More strictly, this parameter is four times the square root of the integral over all directions and all frequencies of the two-dimensional wind-sea wave spectrum. The wind-sea wave spectrum is obtained by only considering the components of the two-dimensional wave spectrum that are still under the influence of the local wind. This parameter can be used to assess wind-sea waves. For example, engineers use significant wave height to calculate the load on structures in the open ocean, such as oil platforms, or in coastal applications.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Significant wave height of first swell partition", + CDSname = "significant_wave_height_of_first_swell_partition", + Description = "This parameter represents the average height of the highest third of surface ocean/sea waves associated with the first swell partition. Wave height represents the vertical distance between the wave crest and the wave trough. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. In many situations, swell can be made up of different swell systems, for example, from two distant and separate storms. To account for this, the swell spectrum is partitioned into up to three parts. The swell partitions are labelled first, second and third based on their respective wave height. Therefore, there is no guarantee of spatial coherence (the first might be from one system at one location and another system at the neighbouring location). More strictly, this parameter is four times the square root of the integral over all directions and all frequencies of the first swell partition of the two-dimensional swell spectrum. The swell spectrum is obtained by only considering the components of the two-dimensional wave spectrum that are not under the influence of the local wind. This parameter can be used to assess swell. For example, engineers use significant wave height to calculate the load on structures in the open ocean, such as oil platforms, or in coastal applications.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Significant wave height of second swell partition", + CDSname = "significant_wave_height_of_second_swell_partition", + Description = "This parameter represents the average height of the highest third of surface ocean/sea waves associated with the second swell partition. Wave height represents the vertical distance between the wave crest and the wave trough. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. In many situations, swell can be made up of different swell systems, for example, from two distant and separate storms. To account for this, the swell spectrum is partitioned into up to three parts. The swell partitions are labelled first, second and third based on their respective wave height. Therefore, there is no guarantee of spatial coherence (the first might be from one system at one location and another system at the neighbouring location). More strictly, this parameter is four times the square root of the integral over all directions and all frequencies of the first swell partition of the two-dimensional swell spectrum. The swell spectrum is obtained by only considering the components of the two-dimensional wave spectrum that are not under the influence of the local wind. This parameter can be used to assess swell. For example, engineers use significant wave height to calculate the load on structures in the open ocean, such as oil platforms, or in coastal applications.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Significant wave height of third swell partition", + CDSname = "significant_wave_height_of_third_swell_partition", + Description = "This parameter represents the average height of the highest third of surface ocean/sea waves associated with the third swell partition. Wave height represents the vertical distance between the wave crest and the wave trough. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. In many situations, swell can be made up of different swell systems, for example, from two distant and separate storms. To account for this, the swell spectrum is partitioned into up to three parts. The swell partitions are labelled first, second and third based on their respective wave height. Therefore, there is no guarantee of spatial coherence (the first might be from one system at one location and another system at the neighbouring location). More strictly, this parameter is four times the square root of the integral over all directions and all frequencies of the first swell partition of the two-dimensional swell spectrum. The swell spectrum is obtained by only considering the components of the two-dimensional wave spectrum that are not under the influence of the local wind. This parameter can be used to assess swell. For example, engineers use significant wave height to calculate the load on structures in the open ocean, such as oil platforms, or in coastal applications.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Skin reservoir content", + CDSname = "skin_reservoir_content", + Description = "Amount of water in the vegetation canopy and/or in a thin layer on the soil. It represents the amount of rain intercepted by foliage, and water from dew. The maximum amount of 'skin reservoir content' a grid box can hold depends on the type of vegetation, and may be zero. Water leaves the 'skin reservoir' by evaporation.", + Unit = "m of water equivalent", + Cumulative = FALSE), + data.frame(Variable = "Skin temperature", + CDSname = "skin_temperature", + Description = "Temperature of the surface of the Earth. The skin temperature is the theoretical temperature that is required to satisfy the surface energy balance. It represents the temperature of the uppermost surface layer, which has no heat capacity and so can respond instantaneously to changes in surface fluxes. Skin temperature is calculated differently over land and sea. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Slope of sub-gridscale orography", + CDSname = "slope_of_sub_gridscale_orography", + Description = "This parameter is one of four parameters (the others being standard deviation, angle and anisotropy) that describe the features of the orography that are too small to be resolved by the model grid. These four parameters are calculated for orographic features with horizontal scales comprised between 5 km and the model grid resolution, being derived from the height of valleys, hills and mountains at about 1 km resolution. They are used as input for the sub-grid orography scheme which represents low-level blocking and orographic gravity wave effects. This parameter represents the slope of the sub-grid valleys, hills and mountains. A flat surface has a value of 0, and a 45 degree slope has a value of 0.5. This parameter does not vary in time.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Snow albedo", + CDSname = "snow_albedo", + Description = "It is defined as the fraction of solar (shortwave) radiation reflected by the snow, across the solar spectrum, for both direct and diffuse radiation. It is a measure of the reflectivity of the snow covered grid cells. Values vary between 0 and 1. Typically, snow and ice have high reflectivity with albedo values of 0.8 and above.", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Snow density", + CDSname = "snow_density", + Description = "Mass of snow per cubic metre in the snow layer. The ECMWF Integrated Forecast System (IFS) model represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box.", + Unit = "kg m-3", + Cumulative = FALSE), + data.frame(Variable = "Snow depth", + CDSname = "snow_depth", + Description = "Instantaneous grib-box average of the snow thickness on the ground (excluding snow on canopy).", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Snow depth water equivalent", + CDSname = "snow_depth_water_equivalent", + Description = "Depth of snow from the snow-covered area of a grid box. Its units are metres of water equivalent, so it is the depth the water would have if the snow melted and was spread evenly over the whole grid box. The ECMWF Integrated Forecast System represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box.", + Unit = "m of water equivalent", + Cumulative = FALSE), + data.frame(Variable = "Snow evaporation", + CDSname = "snow_evaporation", + Description = "Evaporation from snow averaged over the grid box (to find flux over snow, divide by snow fraction). This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Snowfall", + CDSname = "snowfall", + Description = "Accumulated total snow that has fallen to the Earth's surface. It consists of snow due to the large-scale atmospheric flow (horizontal scales greater than around a few hundred metres) and convection where smaller scale areas (around 5km to a few hundred kilometres) of warm air rise. If snow has melted during the period over which this variable was accumulated, then it will be higher than the snow depth. This variable is the total amount of water accumulated from the beginning of the forecast time to the end of the forecast step. The units given measure the depth the water would have if the snow melted and was spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box and model time step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Snowmelt", + CDSname = "snowmelt", + Description = "Melting of snow averaged over the grid box (to find melt over snow, divide by snow fraction). This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 1", + CDSname = "soil_temperature_level_1", + Description = "Temperature of the soil in layer 1 (0 - 7 cm) of the ECMWF Integrated Forecasting System. The surface is at 0 cm. Soil temperature is set at the middle of each layer, and heat transfer is calculated at the interfaces between them. It is assumed that there is no heat transfer out of the bottom of the lowest layer. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 2", + CDSname = "soil_temperature_level_2", + Description = "Temperature of the soil in layer 2 (7 -28cm) of the ECMWF Integrated Forecasting System.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 3", + CDSname = "soil_temperature_level_3", + Description = "Temperature of the soil in layer 3 (28-100cm) of the ECMWF Integrated Forecasting System.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 4", + CDSname = "soil_temperature_level_4", + Description = "Temperature of the soil in layer 4 (100-289 cm) of the ECMWF Integrated Forecasting System.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Sub-surface runoff", + CDSname = "sub_surface_runoff", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and downward and reflected solar radiation is the surface net solar radiation. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface net thermal radiation", + CDSname = "surface_net_thermal_radiation", + Description = "Net thermal radiation at the surface. Accumulated field from the beginning of the forecast time to the end of the forecast step. By model convention downward fluxes are positive.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface pressure", + CDSname = "surface_pressure", + Description = "Pressure (force per unit area) of the atmosphere on the surface of land, sea and in-land water. It is a measure of the weight of all the air in a column vertically above the area of the Earth's surface represented at a fixed point. Surface pressure is often used in combination with temperature to calculate air density. The strong variation of pressure with altitude makes it difficult to see the low and high pressure systems over mountainous areas, so mean sea level pressure, rather than surface pressure, is normally used for this purpose. The units of this variable are Pascals (Pa). Surface pressure is often measured in hPa and sometimes is presented in the old units of millibars, mb (1 hPa = 1 mb = 100 Pa).", + Unit = "Pa", + Cumulative = FALSE), + data.frame(Variable = "Surface runoff", + CDSname = "surface_runoff", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is simply called 'runoff'. This variable is the total amount of water accumulated from the beginning of the forecast time to the end of the forecast step. The units of runoff are depth in metres. This is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point rather than averaged over a grid square area. Observations are also often taken in different units, such as mm/day, rather than the accumulated metres produced here. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood. More information about how runoff is calculated is given in the IFS Physical Processes documentation.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Surface sensible heat flux", + CDSname = "surface_sensible_heat_flux", + Description = "Transfer of heat between the Earth's surface and the atmosphere through the effects of turbulent air motion (but excluding any heat transfer resulting from condensation or evaporation). The magnitude of the sensible heat flux is governed by the difference in temperature between the surface and the overlying atmosphere, wind speed and the surface roughness. For example, cold air overlying a warm surface would produce a sensible heat flux from the land (or ocean) into the atmosphere. This is a single level variable and it is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface solar radiation downward, clear sky", + CDSname = "surface_solar_radiation_downward_clear_sky", + Description = "Clear-sky downward shortwave radiation flux at the surface, computed from the model radiation scheme. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface solar radiation downwards", + CDSname = "surface_solar_radiation_downwards", + Description = "Amount of solar radiation (also known as shortwave radiation) reaching the surface of the Earth. This variable comprises both direct and diffuse solar radiation. Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The rest is incident on the Earth's surface (represented by this variable). To a reasonably good approximation, this variable is the model equivalent of what would be measured by a pyranometer (an instrument used for measuring solar radiation) at the surface. However, care should be taken when comparing model variables with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box and model time step. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface thermal radiation downwards", + CDSname = "surface_thermal_radiation_downwards", + Description = "Amount of thermal (also known as longwave or terrestrial) radiation emitted by the atmosphere and clouds that reaches the Earth's surface. The surface of the Earth emits thermal radiation, some of which is absorbed by the atmosphere and clouds. The atmosphere and clouds likewise emit thermal radiation in all directions, some of which reaches the surface (represented by this variable). This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Temperature of snow layer", + CDSname = "temperature_of_snow_layer", + Description = "This variable gives the temperature of the snow layer from the ground to the snow-air interface. The ECMWF Integrated Forecast System (IFS) model represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "TOA incident solar radiation", + CDSname = "toa_incident_solar_radiation", + Description = "This parameter is the incoming solar radiation (also known as shortwave radiation), received from the Sun, at the top of the atmosphere. It is the amount of radiation passing through a horizontal plane. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The units are joules per square metre (J m-2 ). To convert to watts per square metre (W m-2 ), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Top net solar radiation", + CDSname = "top_net_solar_radiation", + Description = "This parameter is the incoming solar radiation (also known as shortwave radiation) minus the outgoing solar radiation at the top of the atmosphere. It is the amount of radiation passing through a horizontal plane. The incoming solar radiation is the amount received from the Sun. The outgoing solar radiation is the amount reflected and scattered by the Earth's atmosphere and surface. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The units are joules per square metre (J m-2 ). To convert to watts per square metre (W m-2 ), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Top net solar radiation, clear sky", + CDSname = "top_net_solar_radiation_clear_sky", + Description = "This parameter is the incoming solar radiation (also known as shortwave radiation) minus the outgoing solar radiation at the top of the atmosphere, assuming clear-sky (cloudless) conditions. It is the amount of radiation passing through a horizontal plane. The incoming solar radiation is the amount received from the Sun. The outgoing solar radiation is the amount reflected and scattered by the Earth's atmosphere and surface, assuming clear-sky (cloudless) conditions. Clear-sky radiation quantities are computed for exactly the same atmospheric conditions of temperature, humidity, ozone, trace gases and aerosol as the total-sky (clouds included) quantities, but assuming that the clouds are not there. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The units are joules per square metre (J m-2 ). To convert to watts per square metre (W m-2 ), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Top net thermal radiation", + CDSname = "top_net_thermal_radiation", + Description = "The thermal (also known as terrestrial or longwave) radiation emitted to space at the top of the atmosphere is commonly known as the Outgoing Longwave Radiation (OLR). The top net thermal radiation (this parameter) is equal to the negative of OLR. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The units are joules per square metre (J m-2 ). To convert to watts per square metre (W m-2 ), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Top net thermal radiation, clear sky", + CDSname = "top_net_thermal_radiation_clear_sky", + Description = "This parameter is the thermal (also known as terrestrial or longwave) radiation emitted to space at the top of the atmosphere, assuming clear-sky (cloudless) conditions. It is the amount passing through a horizontal plane. Note that the ECMWF convention for vertical fluxes is positive downwards, so a flux from the atmosphere to space will be negative. Clear-sky radiation quantities are computed for exactly the same atmospheric conditions of temperature, humidity, ozone, trace gases and aerosol as total-sky quantities (clouds included), but assuming that the clouds are not there. The thermal radiation emitted to space at the top of the atmosphere is commonly known as the Outgoing Longwave Radiation (OLR) (i.e., taking a flux from the atmosphere to space as positive). Note that OLR is typically shown in units of watts per square metre (W m-2 ). This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The units are joules per square metre (J m-2 ). To convert to watts per square metre (W m-2 ), the accumulated values should be divided by the accumulation period expressed in seconds.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Total cloud cover", + CDSname = "total_cloud_cover", + Description = "This parameter is the proportion of a grid box covered by cloud. Total cloud cover is a single level field calculated from the cloud occurring at different model levels through the atmosphere. Assumptions are made about the degree of overlap/randomness between clouds at different heights. Cloud fractions vary from 0 to 1.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Total column cloud ice water", + CDSname = "total_column_cloud_ice_water", + Description = "This parameter is the amount of ice contained within clouds in a column extending from the surface of the Earth to the top of the atmosphere. Snow (aggregated ice crystals) is not included in this parameter. This parameter represents the area averaged value for a model grid box. Clouds contain a continuum of different sized water droplets and ice particles. The ECMWF Integrated Forecasting System (IFS) cloud scheme simplifies this to represent a number of discrete cloud droplets/particles including: cloud water droplets, raindrops, ice crystals and snow (aggregated ice crystals). The processes of droplet formation, phase transition and aggregation are also highly simplified in the IFS.", + Unit = "kg m-2", + Cumulative = FALSE), + data.frame(Variable = "Total column cloud liquid water", + CDSname = "total_column_cloud_liquid_water", + Description = "This parameter is the amount of liquid water contained within cloud droplets in a column extending from the surface of the Earth to the top of the atmosphere. Rain water droplets, which are much larger in size (and mass), are not included in this parameter. This parameter represents the area averaged value for a model grid box. Clouds contain a continuum of different sized water droplets and ice particles. The ECMWF Integrated Forecasting System (IFS) cloud scheme simplifies this to represent a number of discrete cloud droplets/particles including: cloud water droplets, raindrops, ice crystals and snow (aggregated ice crystals). The processes of droplet formation, phase transition and aggregation are also highly simplified in the IFS.", + Unit = "kg m-2", + Cumulative = FALSE), + data.frame(Variable = "Total column ozone", + CDSname = "total_column_ozone", + Description = " This parameter is the total amount of ozone in a column of air extending from the surface of the Earth to the top of the atmosphere. This parameter can also be referred to as total ozone, or vertically integrated ozone. The values are dominated by ozone within the stratosphere. In the ECMWF Integrated Forecasting System (IFS), there is a simplified representation of ozone chemistry (including representation of the chemistry which has caused the ozone hole). Ozone is also transported around in the atmosphere through the motion of air. Naturally occurring ozone in the stratosphere helps protect organisms at the surface of the Earth from the harmful effects of ultraviolet (UV) radiation from the Sun. Ozone near the surface, often produced because of pollution, is harmful to organisms. In the IFS, the units for total ozone are kilograms per square metre, but before 12/06/2001 dobson units were used. Dobson units (DU) are still used extensively for total column ozone. 1 DU = 2.1415E-5 kg m-2", + Unit = "kg m-2", + Cumulative = FALSE), + data.frame(Variable = "Total column rain water", + CDSname = "total_column_rain_water", + Description = "This parameter is the total amount of water in droplets of raindrop size (which can fall to the surface as precipitation) in a column extending from the surface of the Earth to the top of the atmosphere. This parameter represents the area averaged value for a grid box. Clouds contain a continuum of different sized water droplets and ice particles. The ECMWF Integrated Forecasting System (IFS) cloud scheme simplifies this to represent a number of discrete cloud droplets/particles including: cloud water droplets, raindrops, ice crystals and snow (aggregated ice crystals). The processes of droplet formation, conversion and aggregation are also highly simplified in the IFS.", + Unit = "kg m-2", + Cumulative = FALSE), + data.frame(Variable = "Total column snow water", + CDSname = "total_column_snow_water", + Description = "This parameter is the total amount of water in the form of snow (aggregated ice crystals which can fall to the surface as precipitation) in a column extending from the surface of the Earth to the top of the atmosphere. This parameter represents the area averaged value for a grid box. Clouds contain a continuum of different sized water droplets and ice particles. The ECMWF Integrated Forecasting System (IFS) cloud scheme simplifies this to represent a number of discrete cloud droplets/particles including: cloud water droplets, raindrops, ice crystals and snow (aggregated ice crystals). The processes of droplet formation, conversion and aggregation are also highly simplified in the IFS.", + Unit = "kg m-2", + Cumulative = FALSE), + data.frame(Variable = "Total column supercooled liquid water", + CDSname = "total_column_supercooled_liquid_water", + Description = "This parameter is the total amount of supercooled water in a column extending from the surface of the Earth to the top of the atmosphere. Supercooled water is water that exists in liquid form below 0oC. It is common in cold clouds and is important in the formation of precipitation. Also, supercooled water in clouds extending to the surface (i.e., fog) can cause icing/riming of various structures. This parameter represents the area averaged value for a grid box. Clouds contain a continuum of different sized water droplets and ice particles. The ECMWF Integrated Forecasting System (IFS) cloud scheme simplifies this to represent a number of discrete cloud droplets/particles including: cloud water droplets, raindrops, ice crystals and snow (aggregated ice crystals). The processes of droplet formation, conversion and aggregation are also highly simplified in the IFS.", + Unit = "kg m-2", + Cumulative = FALSE), + data.frame(Variable = "Total column water", + CDSname = "total_column_water", + Description = "This parameter is the sum of water vapour, liquid water, cloud ice, rain and snow in a column extending from the surface of the Earth to the top of the atmosphere. In old versions of the ECMWF model (IFS), rain and snow were not accounted for.", + Unit = "kg m-2", + Cumulative = FALSE), + data.frame(Variable = "Total column water vapour", + CDSname = "total_column_water_vapour", + Description = "This parameter is the total amount of water vapour in a column extending from the surface of the Earth to the top of the atmosphere. This parameter represents the area averaged value for a grid box.", + Unit = "kg m-2", + Cumulative = FALSE), + data.frame(Variable = "Total precipitation", + CDSname = "total_precipitation", + Description = "Accumulated liquid and frozen water, including rain and snow, that falls to the Earth's surface. It is the sum of large-scale precipitation (that precipitation which is generated by large-scale weather patterns, such as troughs and cold fronts) and convective precipitation (generated by convection which occurs when air at lower levels in the atmosphere is warmer and less dense than the air above, so it rises). Precipitation variables do not include fog, dew or the precipitation that evaporates in the atmosphere before it lands at the surface of the Earth. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units of precipitation are depth in metres. It is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box and model time step.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Total sky direct solar radiation at surface", + CDSname = "total_sky_direct_solar_radiation_at_surface", + Description = "This parameter is the amount of direct solar radiation (also known as shortwave radiation) reaching the surface of the Earth. It is the amount of radiation passing through a horizontal plane. Solar radiation at the surface can be direct or diffuse. Solar radiation can be scattered in all directions by particles in the atmosphere, some of which reaches the surface (diffuse solar radiation). Some solar radiation reaches the surface without being scattered (direct solar radiation). This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. The units are joules per square metre (J m-2 ). To convert to watts per square metre (W m-2 ), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Total totals index", + CDSname = "total_totals_index", + Description = "This parameter gives an indication of the probability of occurrence of a thunderstorm and its severity by using the vertical gradient of temperature and humidity. TT index Thunderstorm Probability <44 Thunderstorms not likely. 44-50 Thunderstorms likely. 51-52 Isolated severe thunderstorms. 53-56 Widely scattered severe thunderstorms. 56-60 Scattered severe thunderstorms more likely. The total totals index is the temperature difference between 850 hPa (near surface) and 500 hPa (mid-troposphere) (lapse rate) plus a measure of the moisture content between 850 hPa and 500 hPa. The probability of deep convection tends to increase with increasing lapse rate and atmospheric moisture content. There are a number of limitations to this index. Also, the interpretation of the index value varies with season and location.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Trapping layer base height", + CDSname = "trapping_layer_base_height", + Description = "Trapping layer base height as diagnosed from vertical gradient of atmospheric refractivity.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Trapping layer top height", + CDSname = "trapping_layer_top_height", + Description = "Trapping layer top height as diagnosed from vertical gradient of atmospheric refractivity.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Type of high vegetation", + CDSname = "type_of_high_vegetation", + Description = "This parameter indicates the 6 types of high vegetation recognised by the ECMWF Integrated Forecasting System: 3 = Evergreen needleleaf trees, 4 = Deciduous needleleaf trees, 5 = Deciduous broadleaf trees, 6 = Evergreen broadleaf trees, 18 = Mixed forest/woodland, 19 = Interrupted forest. A value of 0 indicates a point without high vegetation, including an oceanic or inland water location. Vegetation types are used to calculate the surface energy balance and snow albedo. This parameter does not vary in time.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Type of low vegetation", + CDSname = "type_of_low_vegetation", + Description = "This parameter indicates the 10 types of low vegetation recognised by the ECMWF Integrated Forecasting System: 1 = Crops, Mixed farming, 2 = Grass, 7 = Tall grass, 9 = Tundra, 10 = Irrigated crops, 11 = Semidesert, 13 = Bogs and marshes, 16 = Evergreen shrubs, 17 = Deciduous shrubs, 20 = Water and land mixtures. A value of 0 indicates a point without low vegetation, including an oceanic or inland water location. Vegetation types are used to calculate the surface energy balance and snow albedo. This parameter does not vary in time.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "U-component stokes drift", + CDSname = "u_component_stokes_drift", + Description = "This parameter is the eastward component of the surface Stokes drift. The Stokes drift is the net drift velocity due to surface wind waves. It is confined to the upper few metres of the ocean water column, with the largest value at the surface. For example, a fluid particle near the surface will slowly move in the direction of wave propagation.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "UV visible albedo for diffuse radiation", + CDSname = "uv_visible_albedo_for_diffuse_radiation", + Description = "Albedo is a measure of the reflectivity of the Earth's surface. This parameter is the fraction of diffuse solar (shortwave) radiation with wavelengths between 0.3 and 0.7 µm (microns, 1 millionth of a metre) reflected by the Earth's surface (for snow-free land surfaces only). In the ECMWF Integrated Forecasting System (IFS) albedo is dealt with separately for solar radiation with wavelengths greater/less than 0.7µm and for direct and diffuse solar radiation (giving 4 components to albedo). Solar radiation at the surface can be direct or diffuse. Solar radiation can be scattered in all directions by particles in the atmosphere, some of which reaches the surface (diffuse solar radiation). Some solar radiation reaches the surface without being scattered (direct solar radiation). In the IFS, a climatological (observed values averaged over a period of several years) background albedo is used which varies from month to month through the year, modified by the model over water, ice and snow. This parameter varies between 0 and 1.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "UV visible albedo for direct radiation", + CDSname = "uv_visible_albedo_for_direct_radiation", + Description = "Albedo is a measure of the reflectivity of the Earth's surface. This parameter is the fraction of direct solar (shortwave) radiation with wavelengths between 0.3 and 0.7 µm (microns, 1 millionth of a metre) reflected by the Earth's surface (for snow-free land surfaces only). In the ECMWF Integrated Forecasting System (IFS) albedo is dealt with separately for solar radiation with wavelengths greater/less than 0.7µm and for direct and diffuse solar radiation (giving 4 components to albedo). Solar radiation at the surface can be direct or diffuse. Solar radiation can be scattered in all directions by particles in the atmosphere, some of which reaches the surface (diffuse solar radiation). Some solar radiation reaches the surface without being scattered (direct solar radiation). In the IFS, a climatological (observed values averaged over a period of several years) background albedo is used which varies from month to month through the year, modified by the model over water, ice and snow.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "V-component stokes drift", + CDSname = "v_component_stokes_drift", + Description = "This parameter is the northward component of the surface Stokes drift. The Stokes drift is the net drift velocity due to surface wind waves. It is confined to the upper few metres of the ocean water column, with the largest value at the surface. For example, a fluid particle near the surface will slowly move in the direction of wave propagation.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of divergence of cloud frozen water flux", + CDSname = "vertical_integral_of_divergence_of_cloud_frozen_water_flux", + Description = "The vertical integral of the cloud frozen water flux is the horizontal rate of flow of cloud frozen water, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of cloud frozen water spreading outward from a point, per square metre. This parameter is positive for cloud frozen water that is spreading out, or diverging, and negative for the opposite, for cloud frozen water that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of cloud frozen water. Note that 'cloud frozen water' is the same as 'cloud ice water'.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of divergence of cloud liquid water flux", + CDSname = "vertical_integral_of_divergence_of_cloud_liquid_water_flux", + Description = "The vertical integral of the cloud liquid water flux is the horizontal rate of flow of cloud liquid water, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of cloud liquid water spreading outward from a point, per square metre. This parameter is positive for cloud liquid water that is spreading out, or diverging, and negative for the opposite, for cloud liquid water that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of cloud liquid water.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of divergence of geopotential flux", + CDSname = "vertical_integral_of_divergence_of_geopotential_flux", + Description = "The vertical integral of the geopotential flux is the horizontal rate of flow of geopotential, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of geopotential spreading outward from a point, per square metre. This parameter is positive for geopotential that is spreading out, or diverging, and negative for the opposite, for geopotential that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of geopotential. Geopotential is the gravitational potential energy of a unit mass, at a particular location, relative to mean sea level. It is also the amount of work that would have to be done, against the force of gravity, to lift a unit mass to that location from mean sea level. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of divergence of kinetic energy flux", + CDSname = "vertical_integral_of_divergence_of_kinetic_energy_flux", + Description = "The vertical integral of the kinetic energy flux is the horizontal rate of flow of kinetic energy, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of kinetic energy spreading outward from a point, per square metre. This parameter is positive for kinetic energy that is spreading out, or diverging, and negative for the opposite, for kinetic energy that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of kinetic energy. Atmospheric kinetic energy is the energy of the atmosphere due to its motion. Only horizontal motion is considered in the calculation of this parameter. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of divergence of mass flux", + CDSname = "vertical_integral_of_divergence_of_mass_flux", + Description = "The vertical integral of the mass flux is the horizontal rate of flow of mass, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of mass spreading outward from a point, per square metre. This parameter is positive for mass that is spreading out, or diverging, and negative for the opposite, for mass that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of mass. This parameter can be used to study the atmospheric mass and energy budgets.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of divergence of moisture flux", + CDSname = "vertical_integral_of_divergence_of_moisture_flux", + Description = "The vertical integral of the moisture flux is the horizontal rate of flow of moisture, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of moisture spreading outward from a point, per square metre. This parameter is positive for moisture that is spreading out, or diverging, and negative for the opposite, for moisture that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of moisture. 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), therefore the units are equivalent to mm (of liquid water) per second.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of divergence of ozone flux", + CDSname = "vertical_integral_of_divergence_of_ozone_flux", + Description = " The vertical integral of the ozone flux is the horizontal rate of flow of ozone, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of ozone spreading outward from a point, per square metre. This parameter is positive for ozone that is spreading out, or diverging, and negative for the opposite, for ozone that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of ozone. In the ECMWF Integrated Forecasting System (IFS), there is a simplified representation of ozone chemistry (including a representation of the chemistry which has caused the ozone hole). Ozone is also transported around in the atmosphere through the motion of air.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of divergence of thermal energy flux", + CDSname = "vertical_integral_of_divergence_of_thermal_energy_flux", + Description = "The vertical integral of the thermal energy flux is the horizontal rate of flow of thermal energy, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of thermal energy spreading outward from a point, per square metre. This parameter is positive for thermal energy that is spreading out, or diverging, and negative for the opposite, for thermal energy that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of thermal energy. The thermal energy is equal to enthalpy, which is the sum of the internal energy and the energy associated with the pressure of the air on its surroundings. Internal energy is the energy contained within a system i.e., the microscopic energy of the air molecules, rather than the macroscopic energy associated with, for example, wind, or gravitational potential energy. The energy associated with the pressure of the air on its surroundings is the energy required to make room for the system by displacing its surroundings and is calculated from the product of pressure and volume. This parameter can be used to study the flow of thermal energy through the climate system and to investigate the atmospheric energy budget.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of divergence of total energy flux", + CDSname = "vertical_integral_of_divergence_of_total_energy_flux", + Description = "The vertical integral of the total energy flux is the horizontal rate of flow of total energy, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of total energy spreading outward from a point, per square metre. This parameter is positive for total energy that is spreading out, or diverging, and negative for the opposite, for total energy that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of total energy. Total atmospheric energy is made up of internal, potential, kinetic and latent energy. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of eastward cloud frozen water flux", + CDSname = "vertical_integral_of_eastward_cloud_frozen_water_flux", + Description = "This parameter is the horizontal rate of flow of cloud frozen water, in the eastward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from west to east. Note that 'cloud frozen water' is the same as 'cloud ice water'.", + Unit = "kg m-1 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of eastward cloud liquid water flux", + CDSname = "vertical_integral_of_eastward_cloud_liquid_water_flux", + Description = "This parameter is the horizontal rate of flow of cloud liquid water, in the eastward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from west to east.", + Unit = "kg m-1 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of eastward geopotential flux", + CDSname = "vertical_integral_of_eastward_geopotential_flux", + Description = "This parameter is the horizontal rate of flow of geopotential, in the eastward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from west to east. Geopotential is the gravitational potential energy of a unit mass, at a particular location, relative to mean sea level. It is also the amount of work that would have to be done, against the force of gravity, to lift a unit mass to that location from mean sea level. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of eastward heat flux", + CDSname = "vertical_integral_of_eastward_heat_flux", + Description = "This parameter is the horizontal rate of flow of heat in the eastward direction, per meter across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from west to east. Heat (or thermal energy) is equal to enthalpy, which is the sum of the internal energy and the energy associated with the pressure of the air on its surroundings. Internal energy is the energy contained within a system i.e., the microscopic energy of the air molecules, rather than the macroscopic energy associated with, for example, wind, or gravitational potential energy. The energy associated with the pressure of the air on its surroundings is the energy required to make room for the system by displacing its surroundings and is calculated from the product of pressure and volume. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of eastward kinetic energy flux", + CDSname = "vertical_integral_of_eastward_kinetic_energy_flux", + Description = "This parameter is the horizontal rate of flow of kinetic energy, in the eastward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from west to east. Atmospheric kinetic energy is the energy of the atmosphere due to its motion. Only horizontal motion is considered in the calculation of this parameter. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of eastward mass flux", + CDSname = "vertical_integral_of_eastward_mass_flux", + Description = "This parameter is the horizontal rate of flow of mass, in the eastward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from west to east. This parameter can be used to study the atmospheric mass and energy budgets.", + Unit = "kg m-1 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of eastward ozone flux", + CDSname = "vertical_integral_of_eastward_ozone_flux", + Description = "This parameter is the horizontal rate of flow of ozone in the eastward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values denote a flux from west to east. In the ECMWF Integrated Forecasting System (IFS), there is a simplified representation of ozone chemistry (including a representation of the chemistry which has caused the ozone hole). Ozone is also transported around in the atmosphere through the motion of air.", + Unit = "kg m-1 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of eastward total energy flux", + CDSname = "vertical_integral_of_eastward_total_energy_flux", + Description = "This parameter is the horizontal rate of flow of total energy in the eastward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from west to east. Total atmospheric energy is made up of internal, potential, kinetic and latent energy. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of eastward water vapour flux", + CDSname = "vertical_integral_of_eastward_water_vapour_flux", + Description = "This parameter is the horizontal rate of flow of water vapour, in the eastward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from west to east.", + Unit = "kg m-1 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of energy conversion", + CDSname = "vertical_integral_of_energy_conversion", + Description = "This parameter is one contribution to the amount of energy being converted between kinetic energy, and internal plus potential energy, for a column of air extending from the surface of the Earth to the top of the atmosphere. Negative values indicate a conversion to kinetic energy from potential plus internal energy. This parameter can be used to study the atmospheric energy budget. The circulation of the atmosphere can also be considered in terms of energy conversions.", + Unit = "W m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of kinetic energy", + CDSname = "vertical_integral_of_kinetic_energy", + Description = "This parameter is the vertical integral of kinetic energy for a column of air extending from the surface of the Earth to the top of the atmosphere. Atmospheric kinetic energy is the energy of the atmosphere due to its motion. Only horizontal motion is considered in the calculation of this parameter. This parameter can be used to study the atmospheric energy budget.", + Unit = "J m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of mass of atmosphere", + CDSname = "vertical_integral_of_mass_of_atmosphere", + Description = "This parameter is the total mass of air for a column extending from the surface of the Earth to the top of the atmosphere, per square metre. This parameter is calculated by dividing surface pressure by the Earth's gravitational acceleration, g (=9.80665 m s-2 ), and has units of kilograms per square metre. This parameter can be used to study the atmospheric mass budget.", + Unit = "kg m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of mass tendency", + CDSname = "vertical_integral_of_mass_tendency", + Description = "This parameter is the rate of change of the mass of a column of air extending from the Earth's surface to the top of the atmosphere. An increasing mass of the column indicates rising surface pressure. In contrast, a decrease indicates a falling surface pressure. The mass of the column is calculated by dividing pressure at the Earth's surface by the gravitational acceleration, g (=9.80665 m s-2 ). This parameter can be used to study the atmospheric mass and energy budgets.", + Unit = "kg m-2 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of northward cloud frozen water flux", + CDSname = "vertical_integral_of_northward_cloud_frozen_water_flux", + Description = "This parameter is the horizontal rate of flow of cloud frozen water, in the northward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from south to north. Note that 'cloud frozen water' is the same as 'cloud ice water'.", + Unit = "kg m-1 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of northward cloud liquid water flux", + CDSname = "vertical_integral_of_northward_cloud_liquid_water_flux", + Description = "This parameter is the horizontal rate of flow of cloud liquid water, in the northward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from south to north.", + Unit = "kg m-1 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of northward geopotential flux", + CDSname = "vertical_integral_of_northward_geopotential_flux", + Description = "This parameter is the horizontal rate of flow of geopotential in the northward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from south to north. Geopotential is the gravitational potential energy of a unit mass, at a particular location, relative to mean sea level. It is also the amount of work that would have to be done, against the force of gravity, to lift a unit mass to that location from mean sea level. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of northward heat flux", + CDSname = "vertical_integral_of_northward_heat_flux", + Description = "This parameter is the horizontal rate of flow of heat in the northward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from south to north. Heat (or thermal energy) is equal to enthalpy, which is the sum of the internal energy and the energy associated with the pressure of the air on its surroundings. Internal energy is the energy contained within a system i.e., the microscopic energy of the air molecules, rather than the macroscopic energy associated with, for example, wind, or gravitational potential energy. The energy associated with the pressure of the air on its surroundings is the energy required to make room for the system by displacing its surroundings and is calculated from the product of pressure and volume. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of northward kinetic energy flux", + CDSname = "vertical_integral_of_northward_kinetic_energy_flux", + Description = "This parameter is the horizontal rate of flow of kinetic energy, in the northward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from south to north. Atmospheric kinetic energy is the energy of the atmosphere due to its motion. Only horizontal motion is considered in the calculation of this parameter. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of northward mass flux", + CDSname = "vertical_integral_of_northward_mass_flux", + Description = "This parameter is the horizontal rate of flow of mass, in the northward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from south to north. This parameter can be used to study the atmospheric mass and energy budgets.", + Unit = "kg m-1 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of northward ozone flux", + CDSname = "vertical_integral_of_northward_ozone_flux", + Description = "This parameter is the horizontal rate of flow of ozone in the northward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values denote a flux from south to north. In the ECMWF Integrated Forecasting System (IFS), there is a simplified representation of ozone chemistry (including a representation of the chemistry which has caused the ozone hole). Ozone is also transported around in the atmosphere through the motion of air.", + Unit = "kg m-1 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of northward total energy flux", + CDSname = "vertical_integral_of_northward_total_energy_flux", + Description = "This parameter is the horizontal rate of flow of total energy in the northward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from south to north. Total atmospheric energy is made up of internal, potential, kinetic and latent energy. This parameter can be used to study the atmospheric energy budget.", + Unit = "W m-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of northward water vapour flux", + CDSname = "vertical_integral_of_northward_water_vapour_flux", + Description = "This parameter is the horizontal rate of flow of water vapour, in the northward direction, per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Positive values indicate a flux from south to north.", + Unit = "kg m-1 s-1", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of potential and internal energy", + CDSname = "vertical_integral_of_potential_and_internal_energy", + Description = "This parameter is the mass weighted vertical integral of potential and internal energy for a column of air extending from the surface of the Earth to the top of the atmosphere. The potential energy of an air parcel is the amount of work that would have to be done, against the force of gravity, to lift the air to that location from mean sea level. Internal energy is the energy contained within a system i.e., the microscopic energy of the air molecules, rather than the macroscopic energy associated with, for example, wind, or gravitational potential energy. This parameter can be used to study the atmospheric energy budget. Total atmospheric energy is made up of internal, potential, kinetic and latent energy.", + Unit = "J m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of potential, internal and latent energy", + CDSname = "vertical_integral_of_potential_internal_and_latent_energy", + Description = "This parameter is the mass weighted vertical integral of potential, internal and latent energy for a column of air extending from the surface of the Earth to the top of the atmosphere. The potential energy of an air parcel is the amount of work that would have to be done, against the force of gravity, to lift the air to that location from mean sea level. Internal energy is the energy contained within a system i.e., the microscopic energy of the air molecules, rather than the macroscopic energy associated with, for example, wind, or gravitational potential energy. The latent energy refers to the energy associated with the water vapour in the atmosphere and is equal to the energy required to convert liquid water into water vapour. This parameter can be used to study the atmospheric energy budget. Total atmospheric energy is made up of internal, potential, kinetic and latent energy.", + Unit = "J m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of temperature", + CDSname = "vertical_integral_of_temperature", + Description = "This parameter is the mass-weighted vertical integral of temperature for a column of air extending from the surface of the Earth to the top of the atmosphere. This parameter can be used to study the atmospheric energy budget.", + Unit = "K kg m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of thermal energy", + CDSname = "vertical_integral_of_thermal_energy", + Description = "This parameter is the mass-weighted vertical integral of thermal energy for a column of air extending from the surface of the Earth to the top of the atmosphere. Thermal energy is calculated from the product of temperature and the specific heat capacity of air at constant pressure. The thermal energy is equal to enthalpy, which is the sum of the internal energy and the energy associated with the pressure of the air on its surroundings. Internal energy is the energy contained within a system i.e., the microscopic energy of the air molecules, rather than the macroscopic energy associated with, for example, wind, or gravitational potential energy. The energy associated with the pressure of the air on its surroundings is the energy required to make room for the system by displacing its surroundings and is calculated from the product of pressure and volume. This parameter can be used to study the atmospheric energy budget. Total atmospheric energy is made up of internal, potential, kinetic and latent energy.", + Unit = "J m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertical integral of total energy", + CDSname = "vertical_integral_of_total_energy", + Description = "This parameter is the vertical integral of total energy for a column of air extending from the surface of the Earth to the top of the atmosphere. Total atmospheric energy is made up of internal, potential, kinetic and latent energy. This parameter can be used to study the atmospheric energy budget.", + Unit = "J m-2", + Cumulative = FALSE), + data.frame(Variable = "Vertically integrated moisture divergence", + CDSname = "vertically_integrated_moisture_divergence", + Description = "The vertical integral of the moisture flux is the horizontal rate of flow of moisture (water vapour, cloud liquid and cloud ice), per metre across the flow, for a column of air extending from the surface of the Earth to the top of the atmosphere. Its horizontal divergence is the rate of moisture spreading outward from a point, per square metre. This parameter is accumulated over a particular time period which depends on the data extracted. For the monthly averaged reanalysis and ensemble members, the accumulation period is 1 day. For the monthly averaged reanalysis by hour of day, the accumulation period is 1 hour (3 hours for the ensemble members). For the hourly reanalysis, the accumulation period is over the 1 hour (3 hours for the ensemble members, mean and spread) up to the validity date and time. This parameter is positive for moisture that is spreading out, or diverging, and negative for the opposite, for moisture that is concentrating, or converging (convergence). This parameter thus indicates whether atmospheric motions act to decrease (for divergence) or increase (for convergence) the vertical integral of moisture, over the time period. High negative values of this parameter (i.e. large moisture convergence) can be related to precipitation intensification and floods. 1 kg of water spread over 1 square metre of surface is 1 mm deep (neglecting the effects of temperature on the density of water), therefore the units are equivalent to mm.", + Unit = "kg m-2", + Cumulative = TRUE), + data.frame(Variable = "Volumetric soil water layer 1", + CDSname = "volumetric_soil_water_layer_1", + Description = "Volume of water in soil layer 1 (0 - 7 cm) of the ECMWF Integrated Forecasting System. The surface is at 0 cm. The volumetric soil water is associated with the soil texture (or classification), soil depth, and the underlying groundwater level.", + Unit = "m3 m-3", + Cumulative = FALSE), + data.frame(Variable = "Volumetric soil water layer 2", + CDSname = "volumetric_soil_water_layer_2", + Description = "Volume of water in soil layer 2 (7 -28 cm) of the ECMWF Integrated Forecasting System.", + Unit = "m3 m-3", + Cumulative = FALSE), + data.frame(Variable = "Volumetric soil water layer 3", + CDSname = "volumetric_soil_water_layer_3", + Description = "Volume of water in soil layer 3 (28-100 cm) of the ECMWF Integrated Forecasting System.", + Unit = "m3 m-3", + Cumulative = FALSE), + data.frame(Variable = "Volumetric soil water layer 4", + CDSname = "volumetric_soil_water_layer_4", + Description = "Volume of water in soil layer 4 (100-289 cm) of the ECMWF Integrated Forecasting System.", + Unit = "m3 m-3", + Cumulative = FALSE), + data.frame(Variable = "Wave spectral directional width", + CDSname = "wave_spectral_directional_width", + Description = "This parameter indicates whether waves (generated by local winds and associated with swell) are coming from similar directions or from a wide range of directions. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). Many ECMWF wave parameters (such as the mean wave period) give information averaged over all wave frequencies and directions, so do not give any information about the distribution of wave energy across frequencies and directions. This parameter gives more information about the nature of the two-dimensional wave spectrum. This parameter is a measure of the range of wave directions for each frequency integrated across the two-dimensional spectrum. This parameter takes values between 0 and the square root of 2. Where 0 corresponds to a uni-directional spectrum (i.e., all wave frequencies from the same direction) and the square root of 2 indicates a uniform spectrum (i.e., all wave frequencies from a different direction).", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Wave spectral directional width for swell", + CDSname = "wave_spectral_directional_width_for_swell", + Description = "This parameter indicates whether waves associated with swell are coming from similar directions or from a wide range of directions. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of all swell only. Many ECMWF wave parameters (such as the mean wave period) give information averaged over all wave frequencies and directions, so do not give any information about the distribution of wave energy across frequencies and directions. This parameter gives more information about the nature of the two-dimensional wave spectrum. This parameter is a measure of the range of wave directions for each frequency integrated across the two-dimensional spectrum. This parameter takes values between 0 and the square root of 2. Where 0 corresponds to a uni-directional spectrum (i.e., all wave frequencies from the same direction) and the square root of 2 indicates a uniform spectrum (i.e., all wave frequencies from a different direction).", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Wave spectral directional width for wind waves", + CDSname = "wave_spectral_directional_width_for_wind_waves", + Description = "This parameter indicates whether waves generated by the local wind are coming from similar directions or from a wide range of directions. The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). The wave spectrum can be decomposed into wind-sea waves, which are directly affected by local winds, and swell, the waves that were generated by the wind at a different location and time. This parameter takes account of wind-sea waves only. Many ECMWF wave parameters (such as the mean wave period) give information averaged over all wave frequencies and directions, so do not give any information about the distribution of wave energy across frequencies and directions. This parameter gives more information about the nature of the two-dimensional wave spectrum. This parameter is a measure of the range of wave directions for each frequency integrated across the two-dimensional spectrum. This parameter takes values between 0 and the square root of 2. Where 0 corresponds to a uni-directional spectrum (i.e., all wave frequencies from the same direction) and the square root of 2 indicates a uniform spectrum (i.e., all wave frequencies from a different direction).", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Wave spectral kurtosis", + CDSname = "wave_spectral_kurtosis", + Description = "This parameter is a statistical measure used to forecast extreme or freak ocean/sea waves. It describes the nature of the sea surface elevation and how it is affected by waves generated by local winds and associated with swell. Under typical conditions, the sea surface elevation, as described by its probability density function, has a near normal distribution in the statistical sense. However, under certain wave conditions the probability density function of the sea surface elevation can deviate considerably from normality, signalling increased probability of freak waves. This parameter gives one measure of the deviation from normality. It shows how much of the probability density function of the sea surface elevation exists in the tails of the distribution. So, a positive kurtosis (typical range 0.0 to 0.06) means more frequent occurrences of very extreme values (either above or below the mean), relative to a normal distribution.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Wave spectral peakedness", + CDSname = "wave_spectral_peakedness", + Description = "This parameter is a statistical measure used to forecast extreme or freak waves. It is a measure of the relative width of the ocean/sea wave frequency spectrum (i.e., whether the ocean/sea wave field is made up of a narrow or broad range of frequencies). The ocean/sea surface wave field consists of a combination of waves with different heights, lengths and directions (known as the two-dimensional wave spectrum). When the wave field is more focussed around a narrow range of frequencies, the probability of freak/extreme waves increases. This parameter is Goda's peakedness factor and is used to calculate the Benjamin-Feir Index (BFI). The BFI is in turn used to estimate the probability and nature of extreme/freak waves.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Wave spectral skewness", + CDSname = "wave_spectral_skewness", + Description = "This parameter is a statistical measure used to forecast extreme or freak ocean/sea waves. It describes the nature of the sea surface elevation and how it is affected by waves generated by local winds and associated with swell. Under typical conditions, the sea surface elevation, as described by its probability density function, has a near normal distribution in the statistical sense. However, under certain wave conditions the probability density function of the sea surface elevation can deviate considerably from normality, signalling increased probability of freak waves. This parameter gives one measure of the deviation from normality. It is a measure of the asymmetry of the probability density function of the sea surface elevation. So, a positive/negative skewness (typical range -0.2 to 0.12) means more frequent occurrences of extreme values above/below the mean, relative to a normal distribution.", + Unit = "Dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Zero degree level", + CDSname = "zero_degree_level", + Description = "The height above the Earth's surface where the temperature passes from positive to negative values, corresponding to the top of a warm layer, at the specified time. This parameter can be used to help forecast snow. If more than one warm layer is encountered, then the zero degree level corresponds to the top of the second atmospheric layer. This parameter is set to zero when the temperature in the whole atmosphere is below 0℃.", + Unit = "m", + Cumulative = FALSE) + + + ), +Citation = "10.24381/cds.f17050d7" +) + +save(reanalysis_era5_single_levels, + file = file.path(getwd(), "data/metadata", "reanalysis-era5-single-levels.RData")) + diff --git a/metadata/TrialMetadata_reanalysis-era5_land_monthly-means.R b/metadata/TrialMetadata_reanalysis-era5_land_monthly-means.R new file mode 100644 index 0000000..6479c4b --- /dev/null +++ b/metadata/TrialMetadata_reanalysis-era5_land_monthly-means.R @@ -0,0 +1,279 @@ +reanalysis_era5_land_monthly_means <- list( + DataSet = "reanalysis-era5-land-monthly-means", + Type = c("monthly_averaged_reanalysis","monthly_averaged_reanalysis_by_hour_of_day"), # Note this one has two types and you need to specify + URL = "https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-land-monthly-means?tab=overview", + Description = "ERA5-Land is a reanalysis dataset providing a consistent view of the evolution of land variables over several decades at an enhanced resolution compared to ERA5. ERA5-Land has been produced by replaying the land component of the ECMWF ERA5 climate reanalysis. Reanalysis combines model data with observations from across the world into a globally complete and consistent dataset using the laws of physics. Reanalysis produces data that goes several decades back in time, providing an accurate description of the climate of the past. + +ERA5-Land provides a consistent view of the water and energy cycles at surface level during several decades. It contains a detailed record from 1950 onwards, with a temporal resolution of 1 hour. The native spatial resolution of the ERA5-Land reanalysis dataset is 9km on a reduced Gaussian grid (TCo1279). The data in the CDS has been regridded to a regular lat-lon grid of 0.1x0.1 degrees. + +The data presented here is a post-processed subset of the full ERA5-Land dataset. Monthly-mean averages have been pre-calculated to facilitate many applications requiring easy and fast access to the data, when sub-monthly fields are not required.", + TResolution = "month", + TStep = 1, + TStart = as.POSIXct("1950-01-01 01:00", tz = "UTC"), + TEnd = "Present; Lag = 3 month", + Projection = "WGS84 (EPSG: 4326)", + SpatialResolution = 0.1, + CDSArguments = list( + 'area' = c(-180, 180, -90, 90), + 'format' = c("grib", "netcdf.zip", "netcdf") + ), + Variables = rbind( + data.frame(Variable = "2m temperature", + CDSname = "2m_temperature", + Description = "Temperature of air at 2m above the surface of land, sea or in-land waters. 2m temperature is calculated by interpolating between the lowest model level and the Earth's surface, taking account of the atmospheric conditions. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Total precipitation", + CDSname = "total_precipitation", + Description = "Accumulated liquid and frozen water, including rain and snow, that falls to the Earth's surface. It is the sum of large-scale precipitation (that precipitation which is generated by large-scale weather patterns, such as troughs and cold fronts) and convective precipitation (generated by convection which occurs when air at lower levels in the atmosphere is warmer and less dense than the air above, so it rises). Precipitation variables do not include fog, dew or the precipitation that evaporates in the atmosphere before it lands at the surface of the Earth. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units of precipitation are depth in metres. It is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box and model time step.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "10m u-component of wind", + CDSname = "10m_u_component_of_wind", + Description = "Eastward component of the 10m wind. It is the horizontal speed of air moving towards the east, at a height of ten metres above the surface of the Earth, in metres per second. Care should be taken when comparing this variable with observations, because wind observations vary on small space and time scales and are affected by the local terrain, vegetation and buildings that are represented only on average in the ECMWF Integrated Forecasting System. This variable can be combined with the V component of 10m wind to give the speed and direction of the horizontal 10m wind.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "10m v-component of wind", + CDSname = "10m_v_component_of_wind", + Description = "Northward component of the 10m wind. It is the horizontal speed of air moving towards the north, at a height of ten metres above the surface of the Earth, in metres per second. Care should be taken when comparing this variable with observations, because wind observations vary on small space and time scales and are affected by the local terrain, vegetation and buildings that are represented only on average in the ECMWF Integrated Forecasting System. This variable can be combined with the U component of 10m wind to give the speed and direction of the horizontal 10m wind.", + Unit = "m s-1", + Cumulative = FALSE), + data.frame(Variable = "2m dewpoint temperature", + CDSname = "2m_dewpoint_temperature", + Description = "Temperature to which the air, at 2 metres above the surface of the Earth, would have to be cooled for saturation to occur.It (external to C3S) is a measure of the humidity of the air. Combined with temperature and pressure, it can be used to calculate the relative humidity. 2m dew point temperature is calculated by interpolating between the lowest model level and the Earth's surface, taking account of the atmospheric conditions. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Evaporation from bare soil", + CDSname = "evaporation_from_bare_soil", + Description = "The amount of evaporation from bare soil at the top of the land surface. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Evaporation from open water surfaces excluding oceans", + CDSname = "evaporation_from_open_water_surfaces_excluding_oceans", + Description = "Amount of evaporation from surface water storage like lakes and inundated areas but excluding oceans. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Evaporation from the top of canopy", + CDSname = "evaporation_from_the_top_of_canopy", + Description = "The amount of evaporation from the canopy interception reservoir at the top of the canopy. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Evaporation from vegetation transpiration", + CDSname = "evaporation_from_vegetation_transpiration", + Description = "Amount of evaporation from vegetation transpiration. This has the same meaning as root extraction i.e. the amount of water extracted from the different soil layers. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Forecast albedo", + CDSname = "forecast_albedo", + Description = "Is a measure of the reflectivity of the Earth's surface. It is the fraction of solar (shortwave) radiation reflected by Earth's surface, across the solar spectrum, for both direct and diffuse radiation. Values are between 0 and 1. Typically, snow and ice have high reflectivity with albedo values of 0.8 and above, land has intermediate values between about 0.1 and 0.4 and the ocean has low values of 0.1 or less. Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The rest is incident on the Earth's surface, where some of it is reflected. The portion that is reflected by the Earth's surface depends on the albedo. In the ECMWF Integrated Forecasting System (IFS), a climatological background albedo (observed values averaged over a period of several years) is used, modified by the model over water, ice and snow. Albedo is often shown as a percentage (%).", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Lake bottom temperature", + CDSname = "lake_bottom_temperature", + Description = "Temperature of water at the bottom of inland water bodies (lakes, reservoirs, rivers) and coastal waters. ECMWF implemented a lake model in May 2015 to represent the water temperature and lake ice of all the world’s major inland water bodies in the Integrated Forecasting System. The model keeps lake depth and surface area (or fractional cover) constant in time.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Lake ice depth", + CDSname = "lake_ice_depth", + Description = "The thickness of ice on inland water bodies (lakes, reservoirs and rivers) and coastal waters. The ECMWF Integrated Forecasting System (IFS) represents the formation and melting of ice on inland water bodies (lakes, reservoirs and rivers) and coastal water. A single ice layer is represented. This parameter is the thickness of that ice layer.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Lake ice temperature", + CDSname = "lake_ice_temperature", + Description = "The temperature of the uppermost surface of ice on inland water bodies (lakes, reservoirs, rivers) and coastal waters. The ECMWF Integrated Forecasting System represents the formation and melting of ice on lakes. A single ice layer is represented. The temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Lake mix-layer depth", + CDSname = "lake_mix_layer_depth", + Description = "The thickness of the upper most layer of an inland water body (lake, reservoirs, and rivers) or coastal waters that is well mixed and has a near constant temperature with depth (uniform distribution of temperature). The ECMWF Integrated Forecasting System represents inland water bodies with two layers in the vertical, the mixed layer above and the thermocline below. Thermoclines upper boundary is located at the mixed layer bottom, and the lower boundary at the lake bottom. Mixing within the mixed layer can occur when the density of the surface (and near-surface) water is greater than that of the water below. Mixing can also occur through the action of wind on the surface of the lake.", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Lake mix-layer temperature", + CDSname = "lake_mix_layer_temperature", + Description = "The temperature of the upper most layer of inland water bodies (lakes, reservoirs and rivers) or coastal waters) that is well mixed. The ECMWF Integrated Forecasting System represents inland water bodies with two layers in the vertical, the mixed layer above and the thermocline below. Thermoclines upper boundary is located at the mixed layer bottom, and the lower boundary at the lake bottom. Mixing within the mixed layer can occur when the density of the surface (and near-surface) water is greater than that of the water below. Mixing can also occur through the action of wind on the surface of the lake. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Lake shape factor", + CDSname = "lake_shape_factor", + Description = "This parameter describes the way that temperature changes with depth in the thermocline layer of inland water bodies (lakes, reservoirs and rivers) and coastal waters. It is used to calculate the lake bottom temperature and other lake-related parameters. The ECMWF Integrated Forecasting System represents inland and coastal water bodies with two layers in the vertical, the mixed layer above and the thermocline below where temperature changes with depth.", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Lake total layer temperature", + CDSname = "lake_total_layer_temperature", + Description = "The mean temperature of total water column in inland water bodies (lakes, reservoirs and rivers) and coastal waters. The ECMWF Integrated Forecasting System represents inland water bodies with two layers in the vertical, the mixed layer above and the thermocline below where temperature changes with depth. This parameter is the mean over the two layers. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Leaf area index, high vegetation", + CDSname = "leaf_area_index_high_vegetation", + Description = "One-half of the total green leaf area per unit horizontal ground surface area for high vegetation type.", + Unit = "m2 m-2", + Cumulative = FALSE), + data.frame(Variable = "Leaf area index, low vegetation", + CDSname = "leaf_area_index_low_vegetation", + Description = "One-half of the total green leaf area per unit horizontal ground surface area for low vegetation type.", + Unit = "m2 m-2", + Cumulative = FALSE), + data.frame(Variable = "Potential evaporation", + CDSname = "potential_evaporation", + Description = "Potential evaporation (pev) in the current ECMWF model is computed, by making a second call to the surface energy balance routine with the vegetation variables set to 'crops/mixed farming' and assuming no stress from soil moisture. In other words, evaporation is computed for agricultural land as if it is well watered and assuming that the atmosphere is not affected by this artificial surface condition. The latter may not always be realistic. Although pev is meant to provide an estimate of irrigation requirements, the method can give unrealistic results in arid conditions due to too strong evaporation forced by dry air. This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Runoff", + CDSname = "runoff", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is simply called 'runoff'. This variable is the total amount of water accumulated from the beginning of the forecast time to the end of the forecast step. The units of runoff are depth in metres. This is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point rather than averaged over a grid square area. Observations are also often taken in different units, such as mm/day, rather than the accumulated metres produced here. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood. More information about how runoff is calculated is given in the IFS Physical Processes documentation.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Skin reservoir content", + CDSname = "skin_reservoir_content", + Description = "Amount of water in the vegetation canopy and/or in a thin layer on the soil. It represents the amount of rain intercepted by foliage, and water from dew. The maximum amount of 'skin reservoir content' a grid box can hold depends on the type of vegetation, and may be zero. Water leaves the 'skin reservoir' by evaporation.", + Unit = "m of water equivalent", + Cumulative = FALSE), + data.frame(Variable = "Skin temperature", + CDSname = "skin_temperature", + Description = "Temperature of the surface of the Earth. The skin temperature is the theoretical temperature that is required to satisfy the surface energy balance. It represents the temperature of the uppermost surface layer, which has no heat capacity and so can respond instantaneously to changes in surface fluxes. Skin temperature is calculated differently over land and sea. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Snow albedo", + CDSname = "snow_albedo", + Description = "It is defined as the fraction of solar (shortwave) radiation reflected by the snow, across the solar spectrum, for both direct and diffuse radiation. It is a measure of the reflectivity of the snow covered grid cells. Values vary between 0 and 1. Typically, snow and ice have high reflectivity with albedo values of 0.8 and above.", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Snow cover", + CDSname = "snow_cover", + Description = "It represents the fraction (0-1) of the cell / grid-box occupied by snow (similar to the cloud cover fields of ERA5).", + Unit = "dimensionless", + Cumulative = FALSE), + data.frame(Variable = "Snow density", + CDSname = "snow_density", + Description = "Mass of snow per cubic metre in the snow layer. The ECMWF Integrated Forecast System (IFS) model represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box.", + Unit = "kg m-3", + Cumulative = FALSE), + data.frame(Variable = "Snow depth", + CDSname = "snow_depth", + Description = "Instantaneous grib-box average of the snow thickness on the ground (excluding snow on canopy).", + Unit = "m", + Cumulative = FALSE), + data.frame(Variable = "Snow depth water equivalent", + CDSname = "snow_depth_water_equivalent", + Description = "Depth of snow from the snow-covered area of a grid box. Its units are metres of water equivalent, so it is the depth the water would have if the snow melted and was spread evenly over the whole grid box. The ECMWF Integrated Forecast System represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box.", + Unit = "m of water equivalent", + Cumulative = FALSE), + data.frame(Variable = "Snow evaporation", + CDSname = "snow_evaporation", + Description = "Evaporation from snow averaged over the grid box (to find flux over snow, divide by snow fraction). This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Snowfall", + CDSname = "snowfall", + Description = "Accumulated total snow that has fallen to the Earth's surface. It consists of snow due to the large-scale atmospheric flow (horizontal scales greater than around a few hundred metres) and convection where smaller scale areas (around 5km to a few hundred kilometres) of warm air rise. If snow has melted during the period over which this variable was accumulated, then it will be higher than the snow depth. This variable is the total amount of water accumulated from the beginning of the forecast time to the end of the forecast step. The units given measure the depth the water would have if the snow melted and was spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box and model time step.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Snowmelt", + CDSname = "snowmelt", + Description = "Melting of snow averaged over the grid box (to find melt over snow, divide by snow fraction). This variable is accumulated from the beginning of the forecast time to the end of the forecast step.", + Unit = "m of water equivalent", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 1", + CDSname = "soil_temperature_level_1", + Description = "Temperature of the soil in layer 1 (0 - 7 cm) of the ECMWF Integrated Forecasting System. The surface is at 0 cm. Soil temperature is set at the middle of each layer, and heat transfer is calculated at the interfaces between them. It is assumed that there is no heat transfer out of the bottom of the lowest layer. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 2", + CDSname = "soil_temperature_level_2", + Description = "Temperature of the soil in layer 2 (7 -28cm) of the ECMWF Integrated Forecasting System.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 3", + CDSname = "soil_temperature_level_3", + Description = "Temperature of the soil in layer 3 (28-100cm) of the ECMWF Integrated Forecasting System.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Soil temperature level 4", + CDSname = "soil_temperature_level_4", + Description = "Temperature of the soil in layer 4 (100-289 cm) of the ECMWF Integrated Forecasting System.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Sub-surface runoff", + CDSname = "sub_surface_runoff", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is simply called 'runoff'. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units of runoff are depth in metres. This is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point rather than averaged over a grid square area. Observations are also often taken in different units, such as mm/day, rather than the accumulated metres produced here. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood. More information about how runoff is calculated is given in the IFS Physical Processes documentation.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Surface latent heat flux", + CDSname = "surface_latent_heat_flux", + Description = "Exchange of latent heat with the surface through turbulent diffusion. This variables is accumulated from the beginning of the forecast time to the end of the forecast step. By model convention, downward fluxes are positive.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface net solar radiation", + CDSname = "surface_net_solar_radiation", + Description = "Amount of solar radiation (also known as shortwave radiation) reaching the surface of the Earth (both direct and diffuse) minus the amount reflected by the Earth's surface (which is governed by the albedo).Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The rest is incident on the Earth's surface, where some of it is reflected. The difference between downward and reflected solar radiation is the surface net solar radiation. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface net thermal radiation", + CDSname = "surface_net_thermal_radiation", + Description = "Net thermal radiation at the surface. Accumulated field from the beginning of the forecast time to the end of the forecast step. By model convention downward fluxes are positive.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface pressure", + CDSname = "surface_pressure", + Description = "Pressure (force per unit area) of the atmosphere on the surface of land, sea and in-land water. It is a measure of the weight of all the air in a column vertically above the area of the Earth's surface represented at a fixed point. Surface pressure is often used in combination with temperature to calculate air density. The strong variation of pressure with altitude makes it difficult to see the low and high pressure systems over mountainous areas, so mean sea level pressure, rather than surface pressure, is normally used for this purpose. The units of this variable are Pascals (Pa). Surface pressure is often measured in hPa and sometimes is presented in the old units of millibars, mb (1 hPa = 1 mb = 100 Pa).", + Unit = "Pa", + Cumulative = FALSE), + data.frame(Variable = "Surface runoff", + CDSname = "surface_runoff", + Description = "Some water from rainfall, melting snow, or deep in the soil, stays stored in the soil. Otherwise, the water drains away, either over the surface (surface runoff), or under the ground (sub-surface runoff) and the sum of these two is simply called 'runoff'. This variable is the total amount of water accumulated from the beginning of the forecast time to the end of the forecast step. The units of runoff are depth in metres. This is the depth the water would have if it were spread evenly over the grid box. Care should be taken when comparing model variables with observations, because observations are often local to a particular point rather than averaged over a grid square area. Observations are also often taken in different units, such as mm/day, rather than the accumulated metres produced here. Runoff is a measure of the availability of water in the soil, and can, for example, be used as an indicator of drought or flood. More information about how runoff is calculated is given in the IFS Physical Processes documentation.", + Unit = "m", + Cumulative = TRUE), + data.frame(Variable = "Surface sensible heat flux", + CDSname = "surface_sensible_heat_flux", + Description = "Transfer of heat between the Earth's surface and the atmosphere through the effects of turbulent air motion (but excluding any heat transfer resulting from condensation or evaporation). The magnitude of the sensible heat flux is governed by the difference in temperature between the surface and the overlying atmosphere, wind speed and the surface roughness. For example, cold air overlying a warm surface would produce a sensible heat flux from the land (or ocean) into the atmosphere. This is a single level variable and it is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface solar radiation downwards", + CDSname = "surface_solar_radiation_downwards", + Description = "Amount of solar radiation (also known as shortwave radiation) reaching the surface of the Earth. This variable comprises both direct and diffuse solar radiation. Radiation from the Sun (solar, or shortwave, radiation) is partly reflected back to space by clouds and particles in the atmosphere (aerosols) and some of it is absorbed. The rest is incident on the Earth's surface (represented by this variable). To a reasonably good approximation, this variable is the model equivalent of what would be measured by a pyranometer (an instrument used for measuring solar radiation) at the surface. However, care should be taken when comparing model variables with observations, because observations are often local to a particular point in space and time, rather than representing averages over a model grid box and model time step. This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Surface thermal radiation downwards", + CDSname = "surface_thermal_radiation_downwards", + Description = "Amount of thermal (also known as longwave or terrestrial) radiation emitted by the atmosphere and clouds that reaches the Earth's surface. The surface of the Earth emits thermal radiation, some of which is absorbed by the atmosphere and clouds. The atmosphere and clouds likewise emit thermal radiation in all directions, some of which reaches the surface (represented by this variable). This variable is accumulated from the beginning of the forecast time to the end of the forecast step. The units are joules per square metre (J m-2). To convert to watts per square metre (W m-2), the accumulated values should be divided by the accumulation period expressed in seconds. The ECMWF convention for vertical fluxes is positive downwards.", + Unit = "J m-2", + Cumulative = TRUE), + data.frame(Variable = "Temperature of snow layer", + CDSname = "temperature_of_snow_layer", + Description = "This variable gives the temperature of the snow layer from the ground to the snow-air interface. The ECMWF Integrated Forecast System (IFS) model represents snow as a single additional layer over the uppermost soil level. The snow may cover all or part of the grid box. Temperature measured in kelvin can be converted to degrees Celsius (°C) by subtracting 273.15.", + Unit = "K", + Cumulative = FALSE), + data.frame(Variable = "Total evaporation", + CDSname = "total_evaporation", + Description = "Accumulated amount of water that has evaporated from the Earth's surface, including a simplified representation of transpiration (from vegetation), into vapour in the air above. This variable is accumulated from the beginning of the forecast to the end of the forecast step. The ECMWF Integrated Forecasting System convention is that downward fluxes are positive. Therefore, negative values indicate evaporation and positive values indicate condensation.", + Unit = "m of water equivalent", + Cumulative = TRUE), + data.frame(Variable = "Volumetric soil water layer 1", + CDSname = "volumetric_soil_water_layer_1", + Description = "Volume of water in soil layer 1 (0 - 7 cm) of the ECMWF Integrated Forecasting System. The surface is at 0 cm. The volumetric soil water is associated with the soil texture (or classification), soil depth, and the underlying groundwater level.", + Unit = "m3 m-3", + Cumulative = FALSE), + data.frame(Variable = "Volumetric soil water layer 2", + CDSname = "volumetric_soil_water_layer_2", + Description = "Volume of water in soil layer 2 (7 -28 cm) of the ECMWF Integrated Forecasting System.", + Unit = "m3 m-3", + Cumulative = FALSE), + data.frame(Variable = "Volumetric soil water layer 3", + CDSname = "volumetric_soil_water_layer_3", + Description = "Volume of water in soil layer 3 (28-100 cm) of the ECMWF Integrated Forecasting System.", + Unit = "m3 m-3", + Cumulative = FALSE), + data.frame(Variable = "Volumetric soil water layer 4", + CDSname = "volumetric_soil_water_layer_4", + Description = "Volume of water in soil layer 4 (100-289 cm) of the ECMWF Integrated Forecasting System.", + Unit = "m3 m-3", + Cumulative = FALSE) + + ), +Citation = "10.24381/cds.e2161bac" +) + +save(reanalysis_era5_land_monthly_means, + file = file.path(getwd(), "data/metadata", "reanalysis-era5-land-monthly-means.RData")) + + diff --git a/metadata/metadata.txt b/metadata/metadata.txt new file mode 100644 index 0000000..b7ccbcb --- /dev/null +++ b/metadata/metadata.txt @@ -0,0 +1,3 @@ +reanalysis-era5-land-monthly-means.RData +reanalysis-era5-land.RData +reanalysis-era5-single-levels.RData diff --git a/metadata/reanalysis-era5-land-monthly-means.RData b/metadata/reanalysis-era5-land-monthly-means.RData new file mode 100644 index 0000000..573429c Binary files /dev/null and b/metadata/reanalysis-era5-land-monthly-means.RData differ diff --git a/metadata/reanalysis-era5-land.RData b/metadata/reanalysis-era5-land.RData new file mode 100644 index 0000000..36ded64 Binary files /dev/null and b/metadata/reanalysis-era5-land.RData differ diff --git a/metadata/reanalysis-era5-single-levels.RData b/metadata/reanalysis-era5-single-levels.RData new file mode 100644 index 0000000..78f87e5 Binary files /dev/null and b/metadata/reanalysis-era5-single-levels.RData differ