diff --git a/DESCRIPTION b/DESCRIPTION index c73555093bb5d336c3e7539c41c718137cdbebfc..362b4f8c2ee238a93eae8e292f5ad086fced9dc3 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -22,6 +22,8 @@ Imports: s2dverification, abind, stats +Suggests: + testthat License: LGPL-3 URL: https://earth.bsc.es/gitlab/external/cstools BugReports: https://earth.bsc.es/gitlab/external/cstools/issues diff --git a/R/AnoMultiMetric.R b/R/AnoMultiMetric.R index 1e52cd580d3143593acafc58f282330208932000..764a8d702949e4401d84012aaaf0b4fdceece8bb 100644 --- a/R/AnoMultiMetric.R +++ b/R/AnoMultiMetric.R @@ -1,6 +1,7 @@ #'Multiple Metrics applied in Multiple Model Anomalies #' #'@author Mishra Niti, \email{niti.mishra@bsc.es} +#'@author Perez-Zanon Nuria, \email{nuria.perez@bsc.es} #'@description This function calculates correlation (Anomaly Correlation Coefficient; ACC), root mean square error (RMS) and the root mean square error skill score (RMSSS) of individual anomaly models and multi-models mean (if desired) with the observations. #' #'@param data an s2dverification object (list) giving as output of \code{Load} function from S2dverification package. @@ -14,9 +15,9 @@ #' \itemize{ #' \item\code{$ano_exp} {an array with the same dimensions as the \code{mod} label in the input \code{data}.} #' \item\code{$ano_exp} {an array with the same dimensions as the \code{obs} label in the input \code{data}.}}} -#'\item\code{$metric} {An array with the same dimensions as the \code{mod} label in the input \code{data} without the 'ftime' dimension containing the correlations coefficients. if \code{multimodel} is TRUE, the greatest first dimension correspons. The third dimension contains the statistics selected: for \code{correlation} and \code{rms} metrics, the third dimension of length four corresponds to the lower limit of the \code{siglev}\% confidence interval, the statistics itselfs, the upper limit of the \code{siglev}\% confidence interval and the \code{siglev}\% significance level, while for the \code{rmsss}, the third dimension of length two corresponds to the statistics itselfs and the p-value of the one-sided Fisher test with Ho: RMSSS = 0.} +#'\item\code{$metric} {An array with two datset dimensions from the \code{mod} and \code{obs} label in the input \code{data}. If \code{multimodel} is TRUE, the greatest first dimension correspons to the Multi-Model Mean. The third dimension contains the statistics selected. For metric \code{correlation}, the third dimension is of length four and they corresponds to the lower limit of the 95\% confidence interval, the statistics itselfs, the upper limit of the 95\% confidence interval and the 95\% significance level. For metric \code{rms}, the third dimension is length three and they corresponds to the lower limit of the 95\% confidence interval, the RMSE and the upper limit of the 95\% confidence interval. For metric \code{rmsss}, the third dimension is length two and they corresponds to the statistics itselfs and the p-value of the one-sided Fisher test with Ho: RMSSS = 0.} #'\item\code{$names} {A vector containing the names of the models.}} -#'@seealso \code{\link[s2dverification]{Corr}} and \code{link[s2dverification]{Load}} +#'@seealso \code{\link[s2dverification]{Corr}}, \code{\link[s2dverification]{RMS}}, \code{\link[s2dverification]{RMSSS}} and \code{\link[s2dverification]{Load}} #'@references #' \url{http://link.springer.com/10.1007/s00382-018-4404-z} #' @@ -61,7 +62,12 @@ from s2dverification package.") names <- paste0('mod', 1 : dim(data$mod)[1]) } } - + if (!is.null(names)) { + if (length(names) != dim(data$mod)[1]) { + stop("Parameter 'names' must be the same length as the number of + models in the element 'mod' of parameter 'data'.") + } + } if (!is.logical(multimodel)) { stop("Parameter 'multimodel' must be a logical value.") } @@ -78,6 +84,7 @@ from s2dverification package.") # seasonal average of anomalies per model AvgExp <- MeanListDim(ano$ano_exp, narm = T, c(2, 4)) AvgObs <- MeanListDim(ano$ano_obs, narm = T, c(2, 4)) + # indv model correlation if (metric == 'correlation') { corr <- Corr(AvgExp, AvgObs, posloop = 1, poscor = 2) @@ -91,8 +98,8 @@ from s2dverification package.") } if (multimodel == TRUE) { # seasonal avg of anomalies for multi-model - AvgExp_MMM <- MeanListDim(AvgExp, narm = T, 1) - AvgObs_MMM <- MeanListDim(AvgObs, narm = T, 1) + AvgExp_MMM <- MeanListDim(AvgExp, narm = TRUE, 1) + AvgObs_MMM <- MeanListDim(AvgObs, narm = TRUE, 1) # multi model correlation if (metric == 'correlation') { corr_MMM <- Corr(var_exp = InsertDim(AvgExp_MMM, 1, 1), @@ -110,6 +117,8 @@ from s2dverification package.") corr <- abind::abind(corr, corr_MMM, along = 1) names <- c(names, 'MMM') } - names(dim(corr))[3] <- 'statistics' + + names(dim(corr)) <- c(dimnames[1], dimnames[1], 'statistics', dimnames[5 : 6]) + return(list(ano = ano, metric = corr, names = names)) } diff --git a/man/AnoMultiMetric.Rd b/man/AnoMultiMetric.Rd index 77a1f6ac3bc03f0cc577adb9d61ea99cfff16d6a..4e8e0715efd2bd4c58c5f70725f87daa02d9eabc 100644 --- a/man/AnoMultiMetric.Rd +++ b/man/AnoMultiMetric.Rd @@ -23,7 +23,7 @@ A list of 3: \itemize{ \item\code{$ano_exp} {an array with the same dimensions as the \code{mod} label in the input \code{data}.} \item\code{$ano_exp} {an array with the same dimensions as the \code{obs} label in the input \code{data}.}}} -\item\code{$metric} {An array with the same dimensions as the \code{mod} label in the input \code{data} without the 'ftime' dimension containing the correlations coefficients. if \code{multimodel} is TRUE, the greatest first dimension correspons. The third dimension contains the statistics selected: for \code{correlation} and \code{rms} metrics, the third dimension of length four corresponds to the lower limit of the \code{siglev}\% confidence interval, the statistics itselfs, the upper limit of the \code{siglev}\% confidence interval and the \code{siglev}\% significance level, while for the \code{rmsss}, the third dimension of length two corresponds to the statistics itselfs and the p-value of the one-sided Fisher test with Ho: RMSSS = 0.} +\item\code{$metric} {An array with two datset dimensions from the \code{mod} and \code{obs} label in the input \code{data}. If \code{multimodel} is TRUE, the greatest first dimension correspons to the Multi-Model Mean. The third dimension contains the statistics selected. For metric \code{correlation}, the third dimension is of length four and they corresponds to the lower limit of the 95\% confidence interval, the statistics itselfs, the upper limit of the 95\% confidence interval and the 95\% significance level. For metric \code{rms}, the third dimension is length three and they corresponds to the lower limit of the 95\% confidence interval, the RMSE and the upper limit of the 95\% confidence interval. For metric \code{rmsss}, the third dimension is length two and they corresponds to the statistics itselfs and the p-value of the one-sided Fisher test with Ho: RMSSS = 0.} \item\code{$names} {A vector containing the names of the models.}} } \description{ @@ -44,8 +44,10 @@ str(a) \url{http://link.springer.com/10.1007/s00382-018-4404-z} } \seealso{ -\code{\link[s2dverification]{Corr}} and \code{link[s2dverification]{Load}} +\code{\link[s2dverification]{Corr}}, \code{\link[s2dverification]{RMS}}, \code{\link[s2dverification]{RMSSS}} and \code{\link[s2dverification]{Load}} } \author{ Mishra Niti, \email{niti.mishra@bsc.es} + +Perez-Zanon Nuria, \email{nuria.perez@bsc.es} } diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000000000000000000000000000000000000..009a2fc85ed678aba94520c6cffaf441ff659071 --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,4 @@ +library(testthat) +library(CSTools) + +test_check("CSTools") diff --git a/tests/testthat/test-AnoMultiMetric.R b/tests/testthat/test-AnoMultiMetric.R new file mode 100644 index 0000000000000000000000000000000000000000..56de35dd7ee6e07ea5ae4e6e4dac7b705645d607 --- /dev/null +++ b/tests/testthat/test-AnoMultiMetric.R @@ -0,0 +1,77 @@ +context("Generic tests") +test_that("basic use case", { + mod <- 1 : (2 * 3 * 4 * 5 * 6 * 8) + dim(mod) <- c(dataset = 2, member = 3, sdate = 4, ftime = 5, lat = 6, lon = 8) + obs <- 1 : (1 * 1 * 4 * 5 * 6 * 8) + dim(obs) <- c(dataset = 1, member = 1, sdate = 4, ftime = 5, lat = 6, lon = 8) + lon <- seq(0, 30, 5) + lat <- seq(0, 30, 5) + dat <- list(mod = mod, obs = obs, lat = lat, lon = lon) + + expect_equal( + AnoMultiMetric(dat), + list(ano = list(ano_exp = array(rep( + c(rep(-12, 6), rep(-4, 6), rep(4, 6), rep(12, 6)), 360), + dim = c(dataset = 2, member = 3, sdate = 4, ftime = 5, + lat = 6, lon = 8)), + ano_obs = array(rep(c(-2, -2/3, 2/3, 2), 360), + dim = c(dataset = 1, member = 1, sdate = 4, ftime = 5, + lat = 6, lon = 8))), + metric = array(rep(c(rep(1, 9), rep(0.9, 3)), 48), + dim = c(dataset = 3, dataset = 1, statistics = 4, lat = 6, lon = 8)), + names = c("mod1", "mod2", "MMM"))) + + res <- AnoMultiMetric(dat, metric = 'rms') + expect_equal(length(res), 3) + expect_equal(length(res$ano), 2) + expect_equal(dim(res$ano$ano_exp), + c(dataset = 2, member = 3, sdate = 4, ftime = 5, lat = 6, lon = 8)) + expect_equal(dim(res$ano$ano_obs), + c(dataset = 1, member = 1, sdate = 4, ftime = 5, lat = 6, lon = 8)) + expect_equal(dim(res$metric), + c(dataset = 3, dataset = 1, statistics = 3, lat = 6, lon = 8)) + res <- AnoMultiMetric(dat, metric = 'rms', multimodel = FALSE) + expect_equal(dim(res$metric), + c(dataset = 2, dataset = 1, statistics = 3, lat = 6, lon = 8)) + res <- AnoMultiMetric(dat, metric = 'rmsss') + expect_equal(dim(res$metric), + c(dataset = 3, dataset = 1, statistics = 2, lat = 6, lon = 8)) + res <- AnoMultiMetric(dat, metric = 'rmsss', multimodel = FALSE) + expect_equal(dim(res$metric), + c(dataset = 2, dataset = 1, statistics = 2, lat = 6, lon =8)) + res <- AnoMultiMetric(dat, names = c('A', 'B')) + expect_equal(res$names, c('A', 'B', 'MMM')) +}) + + +test_that("Sanity checks", { + expect_error( + AnoMultiMetric(data = 1), + "Parameter 'data' must be a list as output of Load function +from s2dverification package") + mod <- 1 : (2 * 3 * 4 * 5 * 6 * 8) + dim(mod) <- c(dataset = 2, member = 3, sdate = 4, ftime = 5, lat = 6, lon = 8) + obs <- 1 : (1 * 1 * 4 * 5 * 6 * 8) + dim(obs) <- c(dataset = 1, member = 1, sdate = 4, ftime = 5, lat = 6, lon = 8) + lon <- seq(0, 30, 5) + lat <- seq(0, 30, 5) + dat <- list(mod = mod, obs = obs, lat = lat, lon = lon) + + expect_error( + AnoMultiMetric(data = dat, metric = 1), + "Parameter 'metric' must be a character string indicating one of the + options: 'correlation', 'rms' or 'rmse'") + expect_error( + AnoMultiMetric(data = dat, metric = NA), + "missing value where TRUE/FALSE needed") + expect_error( + AnoMultiMetric(data = dat, metric = NULL), + "argument is of length zero") + expect_error( + AnoMultiMetric(data = dat, metric = "correlation", multimodel = NULL), + "Parameter 'multimodel' must be a logical value.") + expect_error( + AnoMultiMetric(data = dat, metric = "correlation", multimodel = FALSE, names = 1), + "Parameter 'names' must be the same length as the number of + models in the element 'mod' of parameter 'data'.") +})