diff --git a/DESCRIPTION b/DESCRIPTION index b352859dd73355af00868dae2a717f358482dbbe..d3f1bf34739dd1a11e1e3d93feaffc9dba821fc4 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -91,5 +91,5 @@ VignetteBuilder: knitr License: GPL-3 Encoding: UTF-8 LazyData: true -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1 Config/testthat/edition: 3 diff --git a/NAMESPACE b/NAMESPACE index 2a976636158adf2a36afb18e279bb434312e5211..336b1abfa413c0aa61db1c1d9fe730d5bfd54952 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -10,6 +10,7 @@ export(BEI_ProbsWeighting) export(BEI_TercilesWeighting) export(BEI_Weights) export(BiasCorrection) +export(BindDim) export(CST_AdamontAnalog) export(CST_AdamontQQCorr) export(CST_Analogs) @@ -17,6 +18,7 @@ export(CST_AnalogsPredictors) export(CST_Anomaly) export(CST_BEI_Weighting) export(CST_BiasCorrection) +export(CST_BindDim) export(CST_Calibration) export(CST_CategoricalEnsCombination) export(CST_ChangeDimNames) @@ -39,6 +41,7 @@ export(CST_SaveExp) export(CST_SplitDim) export(CST_Start) export(CST_Subset) +export(CST_Summary) export(CST_WeatherRegimes) export(Calibration) export(CategoricalEnsCombination) diff --git a/R/CST_BindDim.R b/R/CST_BindDim.R new file mode 100644 index 0000000000000000000000000000000000000000..c2048ecb012ec64a51c47262d990e1e5f61504e6 --- /dev/null +++ b/R/CST_BindDim.R @@ -0,0 +1,200 @@ +#'Bind two objects of class s2dv_cube +#' +#'This function combines the data inside two or more objects of class +#'\code{s2dv_cube} along the specified \code{along} dimension, and modifies the +#'dimensions, coordinates and attributes accordingly, producing a result that +#'contains the complete metadata for all variables, time steps and spatial +#'coordinates that are bound in the process. It ensures that the information +#'inside the s2dv_cube remains coherent with the data it contains.\cr\cr +#'If the dimension specified in \code{along} is among the time dimensions in +#'\code{attrs$Dates}, the dates arrays are also bound along this dimension. +#'The \code{load_parameters} and \code{when} attributes of the first cube +#'are preserved. The \code{source_files} attribute is bound along the +#'\code{var_dim} and \code{dat_dim} dimensions. +#' +#'@author Agudetse Roures Victoria, \email{victoria.agudetse@bsc.es} +#' +#'@param x Two or more objects of class \code{s2dv_cube} to be bound together. +#'@param along A character string indicating the name of the binding dimension. +#'@param dat_dim A character string indicating the name of dataset dimension. +#' The default value is NULL. Specifying this dimension ensures the dataset +#' metadata is correctly preserved. +#'@param var_dim A character string indicating the name of the variable +#' dimension. The default value is NULL. Specifying this dimension ensures +# the variable metadata is correctly preserved. +#' +#'@return An object of class \code{s2dv_cube} with the combined data, +#' dimensions, coordinates and attributes of the elements in \code{x}. +#' +#'@examples +#'\dontrun{ +#' # Example with sample data: +#' # Check original dimensions and coordinates +#' lonlat_temp$exp$dims +#' lonlat_temp$obs$dims +#' # Bind both datasets along the member dimension +#' res <- CST_BindDim(x = list(lonlat_temp$exp, lonlat_temp$obs), +#' along = "member", +#' var_dim = NULL, +#' dat_dim = "dat") +#' # Check new dimensions and coordinates +#' res$dims +#' names(res$coords) +#'} +#' +#'@seealso \link[abind]{abind} +#' +#'@importFrom abind abind +#'@export + +CST_BindDim <- function(x, along, var_dim = NULL, dat_dim = NULL) { + # Check that at least two objects have been passed + if (length(x) < 2) { + stop("'x' must contain at least two 's2dv_cube' objects.") + } + # Check list + if (!is.list(x)) { + x <- as.list(x) + } + # Check that x elements are of s2dv_cube class + if (!all(vapply(x, function (x) {inherits(x, "s2dv_cube")}, logical(1)))) { + stop("All elements of 'x' must be of the class 's2dv_cube'.") + } + # Check 'along' dimension + inner_dimensions <- lapply(x, + function(x) { + x$dims[names(x$dims) %in% along] + }) + if (any(lengths(inner_dimensions) == 0)) { + stop("The dimension specified in 'along' must be present in all the ", + "s2dv_cubes in 'x'.") + } + # Check that all s2dv_cubes have the same dimensions + outer_dimensions <- lapply(x, + function(x) { + x$dims[!names(x$dims) %in% along] + }) + if (length(unique(outer_dimensions)) > 1) { + stop("All elements of 'x' must have the same dimension names and length, ", + "except for the dimension specified in 'along'.") + } + # Check var_dim + if (!is.null(var_dim)) { + if ((!is.character(var_dim)) || (length(var_dim) > 1)) { + stop("Parameter 'var_dim' must be a character string.") + } + } else { + warning("Parameter 'var_dim' not specified, variable metadata ", + "of the output might be inconsistent with the input.") + } + # Check dat_dim + if (!is.null(dat_dim)) { + if ((!is.character(dat_dim)) || (length(dat_dim) > 1)) { + stop("Parameter 'dat_dim' must be a character string.") + } + } else { + warning("Parameter 'dat_dim' not specified, dataset metadata ", + "of the output might be inconsistent with the input.") + } + + # Bind data + res <- list() + res$data <- BindDim(x = lapply(x, "[[", "data"), + along = along) + # Adjust dimensions + res$dims <- dim(res$data) + # Adjust coordinates and coordinate attributes + ## TODO: Can probably be improved + coords_attrs <- x[[1]]$coords + res$coords <- coords_attrs + # If indices or unsure, simply create new sequence of indices + if (is.null(attr(coords_attrs[[along]], "indices")) || + attr(coords_attrs[[along]], "indices")) { + res$coords[[along]] <- seq(1:res$dims[[along]]) + attr(res$coords[[along]], "indices") <- TRUE + } else { + res$coords[[along]] <- sapply(x, + function(x, along) { + return(x$coords[[along]]) + }, + along = along) + attributes(res$coords[[along]]) <- attributes(coords_attrs[[along]]) + } + # Variable + res$attrs <- x$attrs + attrs <- lapply(x, "[[", "attrs") + if (along %in% names(dim(x[[1]]$attrs$Dates))) { + original_timezone <- attr(x[[1]]$attrs$Dates[1], "tzone") + res$attrs$Dates <- BindDim(x = lapply(attrs, "[[", "Dates"), + along = along) + # Transform dates back to POSIXct + res$attrs$Dates <- as.POSIXct(res$attrs$Dates, + origin = "1970-01-01", + tz = original_timezone) + + } else if (!is.null(var_dim) && along == var_dim) { + var_names <- sapply(x, + function(x) { + return(x$attrs$Variable$varName) + }) + res$attrs$Variable$varName <- var_names + for (i in 1:length(x)) { + var_name <- var_names[i] + res$attrs$Variable$metadata[var_name] <- x[i]$attrs$Variable$metadata[var_name] + } + } else if (!is.null(dat_dim) && along == dat_dim) { + res$attrs$Datasets <- sapply(x, + function(x) { + return(x$attrs$Datasets) + }) + } + # Source files + source_files <- lapply(attrs, "[[", "source_files") + res$attrs$source_files <- as.vector(sapply(list(source_files), c)) + # When + res$attrs$when <- Sys.time() + # Class + class(res) <- "s2dv_cube" + return(res) +} + +#'Bind two arrays by a specified named dimension +#' +#'This function combines the data inside two or more arrays with named +#'dimensions along the specified \code{along} dimension. It is a wrapper of the +#'abind() function from the abind package. +#' +#'@author Agudetse Roures Victoria, \email{victoria.agudetse@bsc.es} +#' +#'@param x A list of two or more arrays with named dimensions to be bound +#' together. +#'@param along A character string indicating the name of the binding dimension. +#' +#'@return A single array combining the arrays in \code{x} along the specified +#' dimension, with dimension names. The order of the dimensions will be the +#' same as in the first array provided in the list. +#' +#'@examples +#'array1 <- array(1:100, dim = c(time = 1, lon = 10, lat = 10)) +#'array2 <- array(101:200, dim = c(lon = 10, lat = 10, time = 1)) +#'# Bind arrays +#'array3 <- BindDim(x = list(array1, array2), +#' along = "time") +#'# Check new dimensions +#'dim(array3) +#' +#'@seealso \link[abind]{abind} +#' +#'@importFrom abind abind +#'@importFrom s2dv Reorder +#'@export + +BindDim <- function(x, along) { + original_dims <- names(dim(x[[1]])) + # All array dimensions must be in the same order + x <- lapply(x, s2dv::Reorder, order = original_dims) + # Bind arrays and restore dimension names + res <- abind(x, along = which(original_dims == along)) + names(dim(res)) <- original_dims + return(res) +} diff --git a/man/BindDim.Rd b/man/BindDim.Rd new file mode 100644 index 0000000000000000000000000000000000000000..d28c1416418d7f4db4e53f523d3daa150ee980e1 --- /dev/null +++ b/man/BindDim.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/CST_BindDim.R +\name{BindDim} +\alias{BindDim} +\title{Bind two arrays by a specified named dimension} +\usage{ +BindDim(x, along) +} +\arguments{ +\item{x}{A list of two or more arrays with named dimensions to be bound +together.} + +\item{along}{A character string indicating the name of the binding dimension.} +} +\value{ +A single array combining the arrays in \code{x} along the specified + dimension, with dimension names. The order of the dimensions will be the + same as in the first array provided in the list. +} +\description{ +This function combines the data inside two or more arrays with named +dimensions along the specified \code{along} dimension. It is a wrapper of the +abind() function from the abind package. +} +\examples{ +array1 <- array(1:100, dim = c(time = 1, lon = 10, lat = 10)) +array2 <- array(101:200, dim = c(lon = 10, lat = 10, time = 1)) +# Bind arrays +array3 <- BindDim(x = list(array1, array2), + along = "time") +# Check new dimensions +dim(array3) + +} +\seealso{ +\link[abind]{abind} +} +\author{ +Agudetse Roures Victoria, \email{victoria.agudetse@bsc.es} +} diff --git a/man/CST_BindDim.Rd b/man/CST_BindDim.Rd new file mode 100644 index 0000000000000000000000000000000000000000..ef4be389816647c0d32903f7432928508f1bd7eb --- /dev/null +++ b/man/CST_BindDim.Rd @@ -0,0 +1,60 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/CST_BindDim.R +\name{CST_BindDim} +\alias{CST_BindDim} +\title{Bind two objects of class s2dv_cube} +\usage{ +CST_BindDim(x, along, var_dim = NULL, dat_dim = NULL) +} +\arguments{ +\item{x}{Two or more objects of class \code{s2dv_cube} to be bound together.} + +\item{along}{A character string indicating the name of the binding dimension.} + +\item{var_dim}{A character string indicating the name of the variable +dimension. The default value is NULL. Specifying this dimension ensures} + +\item{dat_dim}{A character string indicating the name of dataset dimension. +The default value is NULL. Specifying this dimension ensures the dataset +metadata is correctly preserved.} +} +\value{ +An object of class \code{s2dv_cube} with the combined data, + dimensions, coordinates and attributes of the elements in \code{x}. +} +\description{ +This function combines the data inside two or more objects of class +\code{s2dv_cube} along the specified \code{along} dimension, and modifies the +dimensions, coordinates and attributes accordingly, producing a result that +contains the complete metadata for all variables, time steps and spatial +coordinates that are bound in the process. It ensures that the information +inside the s2dv_cube remains coherent with the data it contains.\cr\cr +If the dimension specified in \code{along} is among the time dimensions in +\code{attrs$Dates}, the dates arrays are also bound along this dimension. +The \code{load_parameters} and \code{when} attributes of the first cube +are preserved. The \code{source_files} attribute is bound along the +\code{var_dim} and \code{dat_dim} dimensions. +} +\examples{ +\dontrun{ + # Example with sample data: + # Check original dimensions and coordinates + lonlat_temp$exp$dims + lonlat_temp$obs$dims + # Bind both datasets along the member dimension + res <- CST_BindDim(x = list(lonlat_temp$exp, lonlat_temp$obs), + along = "member", + var_dim = NULL, + dat_dim = "dat") + # Check new dimensions and coordinates + res$dims + names(res$coords) +} + +} +\seealso{ +\link[abind]{abind} +} +\author{ +Agudetse Roures Victoria, \email{victoria.agudetse@bsc.es} +} diff --git a/man/CST_Calibration.Rd b/man/CST_Calibration.Rd index 6843f1c9a244212e8071a317c9fa0b0d994c0bb4..008925156af5acece3b5fb63912bda1b2e2db2d5 100644 --- a/man/CST_Calibration.Rd +++ b/man/CST_Calibration.Rd @@ -19,7 +19,7 @@ CST_Calibration( sdate_dim = "sdate", dat_dim = NULL, ncores = NULL, - k = 1, + k = 1, tail.out = TRUE ) } diff --git a/man/CST_Summary.Rd b/man/CST_Summary.Rd new file mode 100644 index 0000000000000000000000000000000000000000..1c0a7a70ac759cf7540bc3f6975e1dc6cc54d318 --- /dev/null +++ b/man/CST_Summary.Rd @@ -0,0 +1,83 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/CST_Summary.R +\name{CST_Summary} +\alias{CST_Summary} +\title{Generate a Summary of the data and metadata in the s2dv_cube object} +\usage{ +CST_Summary(data, show_loaded_files = FALSE, show_NA = FALSE, var_dim = "var") +} +\arguments{ +\item{data}{An \code{s2dv_cube} object containing: +- \code{data}: N-dimensional array with named dimensions +- \code{dim}: Dimensions, including \code{var} (variables). +- \code{attrs}: Attributes such as \code{VarName} and \code{Metadata}. +- \code{coords}: Named list with coordinates of dimensions.} + +\item{show_loaded_files}{A logical value indicating if the names of the +loaded files will be displayed in the output or not. Default = FALSE.} + +\item{show_NA}{A logical value indicating if details of NA values in the +loaded object will be displayed in the output or not. Default = FALSE.} + +\item{var_dim}{A character string indicating the name of the variable +dimension. Default = "var".} +} +\description{ +This function prints the summary of the data and metadata of an object of +class \code{s2dv_cube}. +} +\details{ +The function uses the data and metadata from the loaded + \code{s2dv_cube} object to generate a summary of the object.The summary + includes : + - months: Months that have been loaded. + - range: Range of the dates that have been loaded. + - dimensions: Object dimensions. + - Statistical summary of the data in data: Basic statistical + summary of the data. + - Variable: Loaded Variables, along with their units (units:) + - NA-Indices per Dimension: Index with NA values per dimension + - Number of NAs in NA-Indices per Dimensions: Number of NAs, + in the Indices with NA values per dimension + - Loaded files: Successfully loaded Files +} +\examples{ +# Example 1: +CST_Summary(data = lonlat_temp_st$exp) + +# Example 2: +\dontrun{ +# s2dv cube paths +repos1 <- "/esarchive/exp/ecmwf/system4_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc" +repos2 <- "/esarchive/exp/ecmwf/system5_m1/monthly_mean/$var$_f6h/$var$_$sdate$.nc" + +# Create data cube +data <- CST_Start(dat = list( + list(name = 'system4_m1', path = repos1), + list(name = 'system5_m1', path = repos2)), + var = c('tas', 'sfcWind'), + sdate = '20170101', + ensemble = indices(1), + time = indices(1:3), + lat = indices(1:5), + lon = indices(1:5), + synonims = list(lat = c('lat', 'latitude'), + lon = c('lon', 'longitude')), + return_vars = list(time = 'sdate', + longitude = 'dat', + latitude = 'dat'), + metadata_dims = c('dat', 'var'), + retrieve = TRUE) + +# Generate summary +CST_Summary(data) +} + +} +\seealso{ +\link[CSTools]{CST_start} or \link[CSTools]{s2dv_cube} for creating + an s2dv cube object. +} +\author{ +Theertha Kariyathan, \email{theertha.kariyathan@bsc.es} +} diff --git a/man/Calibration.Rd b/man/Calibration.Rd index 1c9bb1b55b2714f4a50ca9a303439d7c476e7f47..9a201df870c8ef4f370335b6974afc8c8f705105 100644 --- a/man/Calibration.Rd +++ b/man/Calibration.Rd @@ -18,7 +18,9 @@ Calibration( memb_dim = "member", sdate_dim = "sdate", dat_dim = NULL, - ncores = NULL + ncores = NULL, + k = 1, + tail.out = TRUE ) } \arguments{ diff --git a/man/CategoricalEnsCombination.Rd b/man/CategoricalEnsCombination.Rd index c3599d032e4b76643c844d01b2ebac2a9dd20869..67200289e2abe417eb200292b193903ecb51e2b4 100644 --- a/man/CategoricalEnsCombination.Rd +++ b/man/CategoricalEnsCombination.Rd @@ -5,7 +5,16 @@ \title{Make categorical forecast based on a multi-model forecast with potential for calibrate} \usage{ -CategoricalEnsCombination(fc, obs, cat.method, eval.method, amt.cat, ...) +CategoricalEnsCombination( + fc, + obs, + cat.method, + eval.method, + amt.cat, + k, + tail.out, + ... +) } \arguments{ \item{fc}{A multi-dimensional array with named dimensions containing the diff --git a/man/QuantileMapping.Rd b/man/QuantileMapping.Rd index ffd39f882ca21cd469bdfdd7ea84377d93df6e33..e2b5b33156efdced8eb5f3e43ecd5fbd7b1f47d4 100644 --- a/man/QuantileMapping.Rd +++ b/man/QuantileMapping.Rd @@ -74,8 +74,8 @@ obs <- as.numeric(rnorm(prod(1,10,15), 50)) dim(obs) <- c(member = 1, syear = 10, window = 15) fcst <- 100*(1:prod(8,1,1)) dim(fcst) <- c(member = 8, syear = 1, swindow = 1) -res <- QuantileMapping(exp = exp, obs = obs, exp_cor = fcst, memb_dim = 'member', - sdate_dim = 'syear', window_dim = 'window') +res <- QuantileMapping(exp = exp, obs = obs, exp_cor = fcst, + memb_dim = 'member', sdate_dim = 'syear', window_dim = 'window') } \seealso{ \code{\link[qmap]{fitQmap}} and \code{\link[qmap]{doQmap}} diff --git a/tests/testthat/test-CST_BindDim.R b/tests/testthat/test-CST_BindDim.R new file mode 100644 index 0000000000000000000000000000000000000000..f2483f3933247bf60b8d20a16bc0bbda9cf3e47e --- /dev/null +++ b/tests/testthat/test-CST_BindDim.R @@ -0,0 +1,119 @@ +############################################## + +# dat1 +data1 <- 1 : 20 +dim(data1) <- c(time = 20) +data1 <- list(data = data1, + dims = dim(data1)) +class(data1) <- 's2dv_cube' + +data2 <- 21 : 30 +dim(data2) <- c(time = 10) +data2 <- list(data = data2, + dims = dim(data2)) +class(data2) <- 's2dv_cube' + +data3 <- data2 +dim(data3$data) <- c(time = 10, sdate = 1) +data3$dims <- dim(data3$data) +############################################## + +test_that("1. Input checks", { + expect_error( + CST_BindDim(x = 1), + paste0("'x' must contain at least two 's2dv_cube' objects.") + ) + expect_error( + CST_BindDim(x = list(1, 1)), + paste0("All elements of 'x' must be of the class 's2dv_cube'.") + ) + expect_error( + CST_BindDim(x = list(data1, data2), along = "sdate"), + paste0("The dimension specified in 'along' must be present in ", + "all the s2dv_cubes in 'x'.") + ) + expect_error( + CST_BindDim(x = list(data1, data3), along = "time"), + paste0("All elements of 'x' must have the same dimension names and length,", + " except for the dimension specified in 'along'.") + ) + expect_error( + suppressWarnings( + CST_BindDim(x = list(data1, data2), along = "time", var_dim = 1)), + "Parameter 'var_dim' must be a character string." + ) + expect_error( + suppressWarnings( + CST_BindDim(x = list(data1, data2), along = "time", dat_dim = 1)), + "Parameter 'dat_dim' must be a character string." + ) + expect_warning( + CST_BindDim(x = list(data1, data2), along = "time", var_dim = "var"), + paste0("Parameter 'dat_dim' not specified, dataset metadata of the ", + "output might be inconsistent with the input.") + ) + expect_warning( + CST_BindDim(x = list(data1, data2), along = "time", dat_dim = "dat"), + paste0("Parameter 'var_dim' not specified, variable metadata of the ", + "output might be inconsistent with the input.") + ) +}) + +############################################## + +output1 <- list() +output1$data <- 1:30 +output1$dims <- c(time = 30) +output1$coords <- list(time = 1:30) +attr(output1$coords$time, "indices") <- TRUE +output1$attrs$source_files <- array(list(NULL, NULL), dim = c(2, 1)) +class(output1) <- "s2dv_cube" + +res1 <- suppressWarnings(CST_BindDim(x = list(data1, data2), along = "time")) + +test_that("2. Output checks", { + expect_equal( + class(res1), + "s2dv_cube" + ) + expect_equal( + as.vector(res1$data), + as.vector(output1$data) + ) + expect_equal( + res1$dims, + output1$dims + ) + expect_equal( + res1$coords, + output1$coords + ) + expect_equal( + res1$attrs$source_files, + output1$attrs$source_files + ) +}) + +############################################## + +test_that("3. Output checks: sample data", { + res2 <- suppressWarnings( + exp_obs_combined <- CST_BindDim(x = list(lonlat_temp$exp, lonlat_temp$obs), + along = "member", + var_dim = NULL, + dat_dim = "dataset") + ) + expect_equal( + dim(res2$data), + c(dataset = 1, member = 16, sdate = 6, ftime = 3, lat = 22, lon = 53) + ) + expect_equal( + res2$dims, + c(dataset = 1, member = 16, sdate = 6, ftime = 3, lat = 22, lon = 53) + ) + expect_equal( + as.vector(res2$coords$member), + 1:16 + ) + +})