diff --git a/DESCRIPTION b/DESCRIPTION index d7691f7166a63a8c3f07280ad393e0da61963ffe..2956cceafa992df51fd607935987cf296076c344 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,11 +1,11 @@ Package: ClimProjDiags Title: Set of Tools to Compute Various Climate Indices -Version: 0.0.4 +Version: 0.1.1 Authors@R: c( person("BSC-CNS", role = c("aut", "cph")), - person("Alasdair", "Hunter", , "alasdair.hunter@bsc.es", role = "aut"), - person("Nuria", "Perez-Zanon", , "nuria.perez@bsc.es", role = c("aut", "cre")), + person("Nuria", "Perez-Zanon", , "nuria.perez@bsc.es", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-8568-3071")), person("Nicolau", "Manubens", , "nicolau.manubens@bsc.es", role = "ctb"), + person("Alasdair", "Hunter", , "alasdair.hunter@bsc.es", role = "aut"), person("Louis-Philippe", "Caron", , "louis-philippe.caron@bsc.es", role = "ctb")) Description: Set of tools to compute metrics and indices for climate analysis. The package provides functions to compute extreme indices, evaluate the @@ -18,17 +18,19 @@ Depends: R (>= 3.2.0) Imports: multiApply (>= 2.0.0), - climdex.pcic, PCICt, plyr, + climdex.pcic, stats -License: LGPL-3 +License: Apache License 2.0 URL: https://earth.bsc.es/gitlab/es/ClimProjDiags -BugReports: https://earth.bsc.es/gitlab/es/ClimProjDiags/issues +BugReports: https://earth.bsc.es/gitlab/es/ClimProjDiags/-/issues Encoding: UTF-8 LazyData: true RoxygenNote: 5.0.0 Suggests: knitr, + testthat, + markdown, rmarkdown VignetteBuilder: knitr diff --git a/NAMESPACE b/NAMESPACE index 8c0c72b49711d1083ace038843337edfa80dfba2..8364b61887761eac1e0b44e525030c7a28468b07 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -7,6 +7,7 @@ export(DTRIndicator) export(DTRRef) export(DailyAno) export(Extremes) +export(Lon2Index) export(SeasonSelect) export(SelBox) export(Subset) diff --git a/R/Climdex.R b/R/Climdex.R index e182979054ea086f42ef6e0e8ebf41166fe09b86..a13b15ba283bb6455729bd2ea0bd6ce69bb6fc46 100644 --- a/R/Climdex.R +++ b/R/Climdex.R @@ -16,8 +16,8 @@ #' \item\code{$result} {An array with the same dimensions as the input array, except for the temporal dimension which is renamed to 'year', moved to the first dimension position and reduce to annual resolution.} #' \item\code{$years} {A vector of the corresponding years.}} #' -#'@import climdex.pcic #'@import multiApply +#'@import climdex.pcic #'@import PCICt #'@examples #'##Example synthetic data: @@ -48,6 +48,9 @@ #' #'clim <- Climdex(data, metric = "t90p", threshold = thres) #'str(clim) +#'@references David Bronaugh for the Pacific Climate Impacts Consortium (2015). +#' climdex.pcic: PCIC Implementation of Climdex Routines. R package +#' version 1.1-6. http://CRAN.R-project.org/package=climdex.pcic #'@export Climdex <- function(data, metric, threshold = NULL, base.range = NULL, dates = NULL, timedim = NULL, calendar = NULL, ncores = NULL) { @@ -243,3 +246,5 @@ Climdex <- function(data, metric, threshold = NULL, base.range = NULL, dates = N } return(result) } + + diff --git a/R/DTRRef.R b/R/DTRRef.R index 008a993f825d1e1aabb0e486d27e38f2ba06471f..f275ddca810a4446ba059370797159588df39547 100644 --- a/R/DTRRef.R +++ b/R/DTRRef.R @@ -99,12 +99,12 @@ DTRRef <- function(tmax, tmin, by.seasons = TRUE, dates = NULL, timedim = NULL, dim_names <- names(dim(tmax)) } if (is.null(dates)) { - dates.max <- attr(tmax, 'Variables')$common$time - if (is.null(dates.max)) { + dates.tmax <- attr(tmax, 'Variables')$common$time + if (is.null(dates.tmax)) { dates.tmax <- attr(tmax, 'Variables')$dat1$time } - dates.min <- attr(tmin, 'Variables')$common$time - if (is.null(dates.min)) { + dates.tmin <- attr(tmin, 'Variables')$common$time + if (is.null(dates.tmin)) { dates.tmin <- attr(tmin, 'Variables')$dat1$time } if (length(dates.tmax) != length(dates.tmin)) { diff --git a/R/Extremes.R b/R/Extremes.R index 46ecbaf80d1621060a64bf6659f9bd4fb4af93f2..f3e7b16b7e187e6cb20c705bd37b1901bf25c57e 100644 --- a/R/Extremes.R +++ b/R/Extremes.R @@ -21,8 +21,8 @@ #'@details This routine compares data to the thresholds using the given operator, generating a series of TRUE or FALSE values; these values are then filtered to remove any sequences of less than \code{min.length} days of TRUE values. It then computes the lengths of the remaining sequences of TRUE values (spells) and sums their lengths. The \code{spells.can.spa .years} option controls whether spells must always terminate at the end of a period, or whether they may continue until the criteria ceases to be met or the end of the data is reached. The default for fclimdex is FALSE. #' #'@import multiApply -#'@import climdex.pcic #'@import PCICt +#'@import climdex.pcic #'@examples #'##Example synthetic data: #'data <- 1:(2 * 3 * 372 * 1) @@ -216,3 +216,4 @@ Extremes <- function(data, threshold, op = ">", min.length = 6, spells.can.span. threshold,op, min.length, spells.can.span.years, max.missing.days) } + diff --git a/R/Lon2Index.R b/R/Lon2Index.R new file mode 100644 index 0000000000000000000000000000000000000000..1ab719714f75954d954e2a58cb9cea48ab9eb826 --- /dev/null +++ b/R/Lon2Index.R @@ -0,0 +1,87 @@ +#'Obtain the index of positions for a region in longitudes +#' +#'@description This auxiliary function returns the index of position of a region of longitudes in a given vector of longitudes. +#' +#'@param lon vector of longitudes values. +#'@param lonmin a numeric value indicating the minimum longitude of the region (understand as the left marging of the region). +#'@param lonmax a numeric value indicating the maximum longitude of the region (understand as the right mariging of the region). +#' +#'@return the index of positions of all values inside the region in the vector lon. +#' +#'@examples +#' +#'lon <- 1 : 360 +#'pos <- Lon2Index(lon, lonmin = -20, lonmax = 20) +#'lon[pos] +#'pos <- Lon2Index(lon, lonmin = 340, lonmax = 20) +#'lon[pos] +#'lon <- -180 : 180 +#'pos <- Lon2Index(lon, lonmin = -20, lonmax = 20) +#'lon[pos] +#'pos <- Lon2Index(lon, lonmin = 340, lonmax = 20) +#'lon[pos] +#' +#'@export +Lon2Index <- function(lon, lonmin, lonmax) { + if (is.null(lon)) { + stop("Parameter 'lon' cannot be NULL.") + } + if (!is.numeric(lon)) { + stop("Parameter 'lon' must be numeric.") + } + if (!is.vector(lon)) { + stop("Parameter 'lon' must be a vector.") + } + if (!is.numeric(lonmin) | !is.numeric(lonmax)) { + stop("Parameter 'lonmin' and 'lonmax' must be numeric.") + } + if (!is.vector(lonmin) | !is.vector(lonmax)) { + stop("Parameter 'lonmin'and 'lonmax' must be a vector.") + } + + vlonmax <- max(lon) + vlonmin <- min(lon) + if (vlonmin < 0 & !(vlonmax > 180)) { # -180 to 180 + if (lonmin < -180) { + stop("Change parameter 'lonmin' to match longitudes ", + "in the range -180 to 180.") + } else if (lonmin > 180) { + lonmin <- lonmin - 360 + } + if (lonmax < -180) { + stop("Change parameter 'lonmax' to match longitudes ", + "in the range -180 to 180.") + } else if (lonmax > 180) { + lonmax <- lonmax - 360 + } + if (lonmin > lonmax) { + index <- c(which(lon >= lonmin), which(lon <= lonmax)) + } else { + index <- which(lon >= lonmin & lon <= lonmax) + } + } else if (vlonmin < 0 & vlonmax > 180) { # -360 to 360 + if (lonmin > lonmax) { + index <- c(which(lon >= lonmin), which(lon <= lonmax)) + } else { + index <- which(lon >= lonmin & lon <= lonmax) + } + } else { # 0 : 360 + if (lonmin < 0) { + lonmin <- lonmin + 360 + } else if (lonmin > 360) { + lonmin <- lonmin - 360 + } + if (lonmax < 0) { + lonmax <- lonmax + 360 + } else if (lonmax > 360) { + lonmax <- lonmax - 360 + } + if (lonmin > lonmax) { + index <- c(which(lon >= lonmin), which(lon <= lonmax)) + } else { + index <- which(lon >= lonmin & lon <= lonmax) + } + } + +return(index) +} diff --git a/R/SelBox.R b/R/SelBox.R index 608e19e0d65121960a1488765ed3f6b1f1d4ef98..5b7cd5982583f278142a8321c250539115676027 100644 --- a/R/SelBox.R +++ b/R/SelBox.R @@ -83,11 +83,13 @@ SelBox <- function(data, lon, lat, region, londim = NULL, latdim = NULL, mask = } else { LatIdx <- which(lat <= region[3] | lat >= region[4]) } - if (region[1] <= region[2]) { - LonIdx <- which(lon >= region[1] & lon <= region[2]) - } else { - LonIdx <- which(lon >= region[1] | lon <= region[2]) - } + #if (region[1] <= region[2]) { + # LonIdx <- which(lon >= region[1] & lon <= region[2]) + #} else { + # LonIdx <- which(lon >= region[1] | lon <= region[2]) + #} + LonIdx <- Lon2Index(lon, lonmin = region[1], lonmax = region[2]) + data <- Subset(data, along = londim, indices = LonIdx, drop = "none") data <- Subset(data, along = latdim, indices = LatIdx, drop = "none") if (!is.null(mask)) { diff --git a/R/Threshold.R b/R/Threshold.R index 311163a07747f93b9b97ab677b70583831372ffa..181a5f04fd0a9c2385f8d3069de0e0a16babf6d8 100644 --- a/R/Threshold.R +++ b/R/Threshold.R @@ -13,7 +13,6 @@ #'@return An array with similar dimensions as the \code{data} input, but without 'time' dimension, and a new 'jdays' dimension. #' #'@import multiApply -#'@import climdex.pcic #'@import PCICt #'@importFrom stats quantile #'@examples diff --git a/R/WaveDuration.R b/R/WaveDuration.R index b46ef52d855c98514c4e4c5bcb60bf2b7256cd71..23c2d97e68d0753aee49fe13660c651070f6544b 100644 --- a/R/WaveDuration.R +++ b/R/WaveDuration.R @@ -16,9 +16,9 @@ #' \item\code{$result}{An array with the same dimensions as the input \code{data}, but with the time dimension reduce from daily to monthly or seasonal resolution depending on the selected resolution in \code{by.season}.} #' \item\code{$years}{A vector of the years and season/months corresponding to the resolution selected in \code{by.season} and temporal length of the input \code{data}}} #' -#'@import climdex.pcic #'@import multiApply #'@import PCICt +#'@import climdex.pcic #'@examples #'##Example synthetic data: #'data <- 1:(2 * 3 * 31 * 5) @@ -231,3 +231,4 @@ WaveDuration <- function(data, threshold, op = ">", spell.length = 6, by.seasons spells.can.span.years = TRUE, 1) return(result) } + diff --git a/R/WeightedMean.R b/R/WeightedMean.R index 70c33b465e7567538774c4f6e08a2404965e38c7..2ab1a1a94a252ced4d88a684003807a9c6c9fe77 100644 --- a/R/WeightedMean.R +++ b/R/WeightedMean.R @@ -120,7 +120,8 @@ WeightedMean <- function(data, lon, lat, region = NULL, mask = NULL, londim = NU cosphi <- t(array(cos(lat * pi / 180), dim = c(length(lat), length(lon)))) nblat <- length(lat) nblon <- length(lon) - dlon <- abs(c(lon[2 : nblon] - lon[1 : nblon - 1])) * pi / 180 + lon[lon > 180] = lon[lon > 180] - 360 + dlon <- abs(c(abs(lon[2 : nblon]) - abs(lon[1 : nblon - 1]))) * pi / 180 dlon <- c(dlon, dlon[1]) dlon <- array(dlon, dim = c(nblon, nblat)) dlat <- abs(c(lat[2 : nblat] - lat[1 : nblat - 1])) * pi / 180 diff --git a/man/Climdex.Rd b/man/Climdex.Rd index 3ff6bb76494faed3037cdf06037f308802799bf5..669570ab98f8060630d9df2ec90911deec345a1b 100644 --- a/man/Climdex.Rd +++ b/man/Climdex.Rd @@ -63,4 +63,9 @@ str(thres) clim <- Climdex(data, metric = "t90p", threshold = thres) str(clim) } +\references{ +David Bronaugh for the Pacific Climate Impacts Consortium (2015). + climdex.pcic: PCIC Implementation of Climdex Routines. R package + version 1.1-6. http://CRAN.R-project.org/package=climdex.pcic +} diff --git a/man/Lon2Index.Rd b/man/Lon2Index.Rd new file mode 100644 index 0000000000000000000000000000000000000000..b2012a61f97126ee886ba942f3e5020961d29994 --- /dev/null +++ b/man/Lon2Index.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Lon2Index.R +\name{Lon2Index} +\alias{Lon2Index} +\title{Obtain the index of positions for a region in longitudes} +\usage{ +Lon2Index(lon, lonmin, lonmax) +} +\arguments{ +\item{lon}{vector of longitudes values.} + +\item{lonmin}{a numeric value indicating the minimum longitude of the region (understand as the left marging of the region).} + +\item{lonmax}{a numeric value indicating the maximum longitude of the region (understand as the right mariging of the region).} +} +\value{ +the index of positions of all values inside the region in the vector lon. +} +\description{ +This auxiliary function returns the index of position of a region of longitudes in a given vector of longitudes. +} +\examples{ + +lon <- 1 : 360 +pos <- Lon2Index(lon, lonmin = -20, lonmax = 20) +lon[pos] +pos <- Lon2Index(lon, lonmin = 340, lonmax = 20) +lon[pos] +lon <- -180 : 180 +pos <- Lon2Index(lon, lonmin = -20, lonmax = 20) +lon[pos] +pos <- Lon2Index(lon, lonmin = 340, lonmax = 20) +lon[pos] + +} + diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000000000000000000000000000000000000..6b1f95fe7d2e17b7d026368643c5dd5ffb760f3e --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,5 @@ +library(testthat) +library(ClimProjDiags) + +test_check("ClimProjDiags") + diff --git a/tests/testthat/test-Lon2index.R b/tests/testthat/test-Lon2index.R new file mode 100644 index 0000000000000000000000000000000000000000..8f530796f4911d759b3972a588fbcc265e59b763 --- /dev/null +++ b/tests/testthat/test-Lon2index.R @@ -0,0 +1,98 @@ +context("Generic tests") +test_that("Sanity checks", { + expect_error(Lon2Index(lon = NULL), "Parameter 'lon' cannot be NULL.") + expect_error(Lon2Index(lon = 'a'), "Parameter 'lon' must be numeric.") + expect_error(Lon2Index(lon = 1), + 'argument "lonmin" is missing, with no default') + expect_error(Lon2Index(lon = 1, lonmin = 'a'), + 'argument "lonmax" is missing, with no default') + expect_error(Lon2Index(lon = 1, lonmin = 'a', lonmax = 1), + "Parameter 'lonmin' and 'lonmax' must be numeric.") + expect_error(Lon2Index(lon = 1, lonmin = 1, lonmax = 'b'), + "Parameter 'lonmin' and 'lonmax' must be numeric.") + expect_equal(Lon2Index(lon = 1, lonmin = 1, lonmax = 1), 1) +}) + +test_that("Case 1 to 360", { +lon <- 1 : 360 + expect_equal(Lon2Index(lon, lonmin = -20, lonmax = 20), + c(340 : 360, 1 : 20)) + expect_equal(Lon2Index(lon, lonmin = 340, lonmax = 20), + c(340 : 360, 1 : 20)) + expect_equal(Lon2Index(lon, lonmin = 20, lonmax = 340), + 20 : 340) + expect_equal(Lon2Index(lon, lonmin = -40, lonmax = -20), + 320 : 340) + expect_equal(Lon2Index(lon, lonmin = 320, lonmax = 340), + 320 : 340) + expect_equal(Lon2Index(lon, lonmin = -220, lonmax = -170), + 140 : 190) + expect_equal(Lon2Index(lon, lonmin = -350, lonmax = -300), + 10 : 60) + expect_equal(Lon2Index(lon, lonmin = -400, lonmax = -370), integer(0)) + expect_equal(Lon2Index(lon, lonmin = 340, lonmax = 380), + c(340 : 360, 1 : 20)) +}) + +test_that("Case -180 to 180", { +lon <- -180 : 180 + expect_equal(Lon2Index(lon, lonmin = -20, lonmax = 20), + 161 : 201) + expect_equal(Lon2Index(lon, lonmin = 340, lonmax = 20), + 161 : 201) + expect_equal(Lon2Index(lon, lonmin = 20, lonmax = 340), + c(201 : 361, 1 : 161)) + expect_equal(Lon2Index(lon, lonmin = -40, lonmax = -20), + 141 : 161) + expect_equal(Lon2Index(lon, lonmin = 320, lonmax = 340), + 141 : 161) + expect_error(Lon2Index(lon, lonmin = -220, lonmax = -170), + "Change parameter 'lonmin' to match longitudes in the range -180 to 180.") + expect_error(Lon2Index(lon, lonmin = -350, lonmax = -300), + "Change parameter 'lonmin' to match longitudes in the range -180 to 180.") + expect_error(Lon2Index(lon, lonmin = -400, lonmax = -370), + "Change parameter 'lonmin' to match longitudes in the range -180 to 180.") + expect_equal(Lon2Index(lon, lonmin = 340, lonmax = 380), + 161 : 201) +}) + +test_that("Case -360 to 360", { +lon <- -360 : 360 + expect_equal(Lon2Index(lon, lonmin = -20, lonmax = 20), + 341 : 381) + expect_equal(Lon2Index(lon, lonmin = 340, lonmax = 20), + c(701 : 721, 1 : 381)) + expect_equal(Lon2Index(lon, lonmin = 20, lonmax = 340), + 381 : 701) + expect_equal(Lon2Index(lon, lonmin = -40, lonmax = -20), + 321 : 341) + expect_equal(Lon2Index(lon, lonmin = 320, lonmax = 340), + 681 : 701) + expect_equal(Lon2Index(lon, lonmin = -220, lonmax = -170), + 141 : 191) + expect_equal(Lon2Index(lon, lonmin = -350, lonmax = -300), + 11 : 61) + expect_equal(Lon2Index(lon, lonmin = -400, lonmax = -370), integer(0)) + expect_equal(Lon2Index(lon, lonmin = 340, lonmax = 380), + 701 : 721) +}) + + + + + + + + + + + + + + + + + + + +