diff --git a/NAMESPACE b/NAMESPACE index 40ba7331c261038fcdff6ba9a02051ef15184726..e3226a5a05d98a2802001d21c5e6708f9d79b700 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -15,6 +15,7 @@ export(ShiftLon) export(Subset) export(Threshold) export(WaveDuration) +export(WeightedCells) export(WeightedMean) import(PCICt) import(climdex.pcic) diff --git a/R/WeightedCells.R b/R/WeightedCells.R new file mode 100644 index 0000000000000000000000000000000000000000..884870fa21247d66169666bc3491de63fccc1ff9 --- /dev/null +++ b/R/WeightedCells.R @@ -0,0 +1,103 @@ +#'Compute the square-root of the cosine of the latitude weighting on the given +#'array. +#' +#'This function performs square-root of the cosine of the latitude weighting on +#'the given array. +#' +#'@param data A numeric array with named dimensions, representing the data to be +#' applied the weights. It should have at least the latitude dimension and it +#' can have more other dimensions. +#'@param lat A numeric vector or array with one dimension containing the +#' latitudes (in degrees). +#'@param lat_dim A character string indicating the name of the latitudinal +#' dimension. The default value is 'lat'. +#'@param method A character string indicating the type of weighting applied: +#' 'cos' (cosine of the latitude) or 'sqrtcos' (square-root of the +#' cosine of the latitude). The default value is 'cos'. +#'@param ncores An integer indicating the number of cores to use for parallel +#' computation. The default value is NULL. +#' +#'@return An array containing the latitude weighted data with same dimensions as +#'parameter 'data'. +#' +#'@examples +#'exp <- array(rnorm(1:30), dim = c(lat = 3, lon = 5, sdate = 2)) +#'lat <- c(10, 15, 20) +#'res <- WeightedCells(data = exp, lat = lat) +#'@import multiApply +#'@export +WeightedCells <- function(data, lat, lat_dim = 'lat', method = 'cos', ncores = NULL) { + + # Check inputs + ## data + if (is.null(data)) { + stop("Parameter 'data' cannot be NULL.") + } + if (!is.numeric(data)) { + stop("Parameter 'data' must be a numeric array.") + } + if (is.null(dim(data))) { + stop("Parameter 'data' must be at least latitude dimension.") + } + if(any(is.null(names(dim(data)))) | any(nchar(names(dim(data))) == 0)) { + stop("Parameter 'data' must have dimension names.") + } + + ## lat_dim + if (!is.character(lat_dim) | length(lat_dim) > 1) { + stop("Parameter 'lat_dim' must be a character string.") + } + if (!lat_dim %in% names(dim(data))) { + stop("Parameter 'lat_dim' is not found in 'data'.") + } + + ## lat + if (is.null(lat)) { + stop("Parameter 'lat' cannot be NULL.") + } + if (!is.numeric(lat)) { + stop("Parameter 'lat' must be a numeric vector or array.") + } + if (dim(data)[lat_dim] != length(lat)) { + stop("Length of parameter 'lat' doesn't match the length of ", + "latitudinal dimension in parameter 'data'.") + } + + ## method + if (!method %in% c('cos', 'sqrtcos')) { + stop("Parameter 'method' must be 'cos' or 'sqrtcos'.") + } + + ## ncores + if (!is.null(ncores)) { + if (!is.numeric(ncores) | ncores %% 1 != 0 | ncores <= 0 | + length(ncores) > 1) { + stop("Parameter 'ncores' must be either NULL or a positive integer.") + } + } + + namedims <- names(dim(data)) + lat <- as.vector(lat) + + if (method == 'cos') { + wt <- cos(lat * pi / 180) + } else { + wt <- sqrt(cos(lat * pi / 180)) + } + + res <- Apply(data = data, + target_dims = c(lat_dim), + fun = .WeightedCells, + wt = wt, + ncores = ncores)$output1 + + order <- match(namedims, names(dim(res))) + res <- aperm(res, order) + + return(res) +} + +.WeightedCells <- function(data, wt) { + data <- wt * data + return(data) +} diff --git a/man/WeightedCells.Rd b/man/WeightedCells.Rd new file mode 100644 index 0000000000000000000000000000000000000000..9b5c880378cdcc25467bc60800c2833e9b632f6c --- /dev/null +++ b/man/WeightedCells.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/WeightedCells.R +\name{WeightedCells} +\alias{WeightedCells} +\title{Compute the square-root of the cosine of the latitude weighting on the given +array.} +\usage{ +WeightedCells(data, lat, lat_dim = "lat", method = "cos", ncores = NULL) +} +\arguments{ +\item{data}{A numeric array with named dimensions, representing the data to be +applied the weights. It should have at least the latitude dimension and it +can have more other dimensions.} + +\item{lat}{A numeric vector or array with one dimension containing the +latitudes (in degrees).} + +\item{lat_dim}{A character string indicating the name of the latitudinal +dimension. The default value is 'lat'.} + +\item{method}{A character string indicating the type of weighting applied: +'cos' (cosine of the latitude) or 'sqrtcos' (square-root of the +cosine of the latitude). The default value is 'cos'.} + +\item{ncores}{An integer indicating the number of cores to use for parallel +computation. The default value is NULL.} +} +\value{ +An array containing the latitude weighted data with same dimensions as +parameter 'data'. +} +\description{ +This function performs square-root of the cosine of the latitude weighting on +the given array. +} +\examples{ +exp <- array(rnorm(1:30), dim = c(lat = 3, lon = 5, sdate = 2)) +lat <- c(10, 15, 20) +res <- WeightedCells(data = exp, lat = lat) +} diff --git a/tests/testthat/test-WeightedCells.R b/tests/testthat/test-WeightedCells.R new file mode 100644 index 0000000000000000000000000000000000000000..dcf171d6f29eecfdcb2819aec595d6b279eafc64 --- /dev/null +++ b/tests/testthat/test-WeightedCells.R @@ -0,0 +1,111 @@ +context("s2dv::WeightedCells tests") + +############################################## + +# dat1 +set.seed(1) +data1 <- array(rnorm(5), dim = c(lat = 5)) +set.seed(2) +lat1 <- array(rnorm(5)*5) + +# dat2 +set.seed(1) +data2 <- array(rnorm(60), dim = c(sdate = 10, lat = 2, lon = 3)) +set.seed(2) +lat2 <- array(rnorm(2)*10) + + +############################################## +test_that("1. Input checks", { + # data + expect_error( + WeightedCells(c()), + "Parameter 'data' cannot be NULL." + ) + expect_error( + WeightedCells('lat'), + "Parameter 'data' must be a numeric array." + ) + expect_error( + WeightedCells(rnorm(5)), + "Parameter 'data' must be at least latitude dimension." + ) + expect_error( + WeightedCells(array(rnorm(5), dim = c(5))), + "Parameter 'data' must have dimension names." + ) + #lat_dim + expect_error( + WeightedCells(data1, lat1, 3), + "Parameter 'lat_dim' must be a character string." + ) + expect_error( + WeightedCells(data1, lat1, 'latitude'), + "Parameter 'lat_dim' is not found in 'data'." + ) + #lat + expect_error( + WeightedCells(data1, NULL), + "Parameter 'lat' cannot be NULL." + ) + expect_error( + WeightedCells(data1, list(lat1)), + "Parameter 'lat' must be a numeric vector or array." + ) + expect_error( + WeightedCells(data1, rnorm(10)), + "Length of parameter 'lat' doesn't match the length of latitudinal dimension in parameter 'data'." + ) + # method + expect_error( + WeightedCells(data1, lat1, method = 1.5), + "Parameter 'method' must be 'cos' or 'sqrtcos'." + ) + # ncores + expect_error( + WeightedCells(data1, lat1, ncores = 1.5), + "Parameter 'ncores' must be either NULL or a positive integer." + ) + +}) + +############################################## +test_that("2. Output checks: dat1", { + + expect_equal( + dim(WeightedCells(data1, lat1)), + c(lat = 5) + ) + expect_equal( + as.vector(WeightedCells(data1, lat1)), + c(-0.6245359, 0.1836194, -0.8276192, 1.5875256, 0.3294997), + tolerance = 0.0001 + ) + +}) + +############################################## +test_that("3. Output checks: dat2", { + + expect_equal( + dim(WeightedCells(data2, lat2)), + c(sdate = 10, lat = 2, lon = 3) + ) + expect_equal( + as.vector(WeightedCells(data2, lat2))[1:5], + c(-0.6187938, 0.1813978, -0.8254109, 1.5757744, 0.3254787), + tolerance = 0.0001 + ) + expect_equal( + dim(WeightedCells(data2, lat2)), + dim(data2) + ) + expect_equal( + WeightedCells(data2, lat2), + WeightedCells(data2, lat2, method = 'sqrtcos') * as.vector(sqrt(cos(lat2 * pi/180))), + tolerance = 0.01 + ) + +}) + +##############################################