diff --git a/DESCRIPTION b/DESCRIPTION index d0c5d69..48ec313 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,18 +9,17 @@ Authors@R: c(person("Jorge", "Garcia Molinos", email = "jorgegmolinos@arc.hokuda Description: Functions to calculate the velocity of climate change (VoCC) and related metrics including both gradient-based (Burrows et al. 2011, Burrows et al. 2014), and distance-based (Hamann et a. 2013, Garcia Molinos et al. 2017) approaches. -Depends: R (>= 3.5) +Depends: R (>= 4.1) Imports: assertthat, CircStats, cowplot, data.table, - doParallel, dplyr, - foreach, + furrr, geosphere, magrittr, - parallelly, + purrr, RColorBrewer, rlang, sf, @@ -28,15 +27,15 @@ Imports: terra, tibble, tidyr, - tidyselect, xts Suggests: + future, ggplot2, knitr, mapplots, ncdf4, + parallelly, patchwork, - purrr, rmarkdown, scales, tidyterra, @@ -46,6 +45,6 @@ BugReports: https://github.com/MathMarEcol/VoCC/issues License: AGPL (>= 3) Encoding: UTF-8 LazyData: true -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 VignetteBuilder: knitr, rmarkdown diff --git a/NAMESPACE b/NAMESPACE index 2517e72..09d1214 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -14,7 +14,6 @@ export(trajClas) export(trajLine) export(voccTraj) importFrom(data.table,":=") -importFrom(foreach,"%dopar%") importFrom(magrittr,"%>%") importFrom(rlang,.data) importFrom(stats,na.omit) diff --git a/R/angulo.R b/R/angulo.R index 39744e2..b88010e 100644 --- a/R/angulo.R +++ b/R/angulo.R @@ -1,16 +1,16 @@ #' Internal. Angle associated to the spatial gradient #' @param dx \code{numeric} giving the longitudinal gradient component #' @param dy \code{numeric} giving the latitudinal gradient component -#' @author Jorge Garcia Molinos and David S. Schoeman #' angulo() angulo <- function(dx, dy) { - d <- cbind(dx, dy) - angline <- function(rw) { - angle <- ifelse(rw[2] < 0, 180 + CircStats::deg(atan(rw[1] / rw[2])), - ifelse(rw[1] < 0, 360 + CircStats::deg(atan(rw[1] / rw[2])), CircStats::deg(atan(rw[1] / rw[2]))) - ) - return(angle) - } - return(apply(d, 1, angline)) + # OPTIMIZATION: Fully vectorized angle calculation - eliminates apply() loop + # Convert atan to degrees once for all values + atan_deg <- CircStats::deg(atan(dx / dy)) + + # Vectorized conditional logic - much faster than apply() + angle <- ifelse(dy < 0, 180 + atan_deg, + ifelse(dx < 0, 360 + atan_deg, atan_deg)) + + return(angle) } diff --git a/R/climPCA.R b/R/climPCA.R index 7356993..bd45331 100644 --- a/R/climPCA.R +++ b/R/climPCA.R @@ -20,10 +20,10 @@ #' @importFrom data.table ":=" #' #' @export -#' @author Jorge Garcia Molinos +#' #' @examples -#' \dontrun{ -#' JapTC <- VoCC_get_data("JapTC.tif") +#' +#' JapTC <- terra::rast(system.file("extdata", "JapTC.tif", package = "VoCC")) #' #' comp <- climPCA(JapTC[[c(1, 3, 5)]], JapTC[[c(2, 4, 6)]], #' trans = NA, cen = TRUE, sc = TRUE, th = 0.85) @@ -31,24 +31,38 @@ #' # Create a data frame with the necessary variables in the required order (see climAna? for details) #' clim <- comp[[2]][, c(2, 4, 3, 5, 1)] #' clim[, c("x", "y")] <- terra::xyFromCell(JapTC[[1]], clim$cid) -#' } #' climPCA <- function(climp, climf, trans = function(x) log(x), cen = TRUE, sc = TRUE, th = 0.8) { + + .SD <- NULL + + # OPTIMIZATION: Pre-calculate cell count to avoid repeated calls + n_cells <- terra::ncell(climp[[1]]) + # get a data table with the pooled values (current/future) of the clim variables clim <- data.table::data.table(rbind(terra::values(climp), terra::values(climf))) - clim <- stats::na.omit(clim[, c("cid", "p") := list(rep(1:terra::ncell(climp[[1]]), times = 2), rep(c("present", "future"), each = terra::ncell(climp[[1]])))]) + clim <- stats::na.omit(clim[, c("cid", "p") := list(rep(1:n_cells, times = 2), rep(c("present", "future"), each = n_cells))]) + + # OPTIMIZATION: Store column indices to avoid repeated column selection + data_cols <- !names(clim) %in% c("cid", "p") # apply transformation if required if (!is.na(trans)) { - clim <- trans(clim[, -c("cid", "p")]) + clim_data <- clim[, .SD, .SDcols = data_cols] + clim_data <- trans(clim_data) + # Rebuild clim with transformed data + clim <- cbind(clim_data, clim[, c("cid", "p")]) } # apply PCA - clim.pca <- stats::prcomp(clim[, -c("cid", "p")], center = cen, scale. = sc) + clim.pca <- stats::prcomp(clim[, .SD, .SDcols = data_cols], center = cen, scale. = sc) + + # OPTIMIZATION: Vectorized variance calculation + sdev_squared <- clim.pca$sdev^2 + cumvar_prop <- cumsum(sdev_squared) / sum(sdev_squared) + a <- which(cumvar_prop >= th)[1] - # extract numper of components explaining more than th accumulated variance - a <- which((cumsum((clim.pca$sdev)^2) / sum(clim.pca$sdev^2)) >= th)[1] - val.pca <- clim.pca$x[, 1:a] + val.pca <- clim.pca$x[, 1:a, drop = FALSE] val <- data.frame(val.pca, cid = clim$cid, p = clim$p) # put it back in wide form diff --git a/R/climPlot.R b/R/climPlot.R index 73f979f..10d1acf 100644 --- a/R/climPlot.R +++ b/R/climPlot.R @@ -15,10 +15,9 @@ #' @seealso{\code{\link{dVoCC}}, \code{\link{climPCA}}} #' #' @export -#' @author Jorge Garcia Molinos and Naoki H. Kumagai #' @examples -#' \dontrun{ -#' JapTC <- VoCC_get_data("JapTC.tif") +#' +#' JapTC <- terra::rast(system.file("extdata", "JapTC.tif", package = "VoCC")) #' #' # Plot climate space for the two first variables(annual precipitation and maximum temperature) #' xy <- stats::na.omit(data.frame( @@ -37,18 +36,24 @@ #' plot = out, filename = file.path(getwd(), "example_plot.pdf"), #' width = 17, height = 17, unit = "cm" #' ) -#' } +#' climPlot <- function(xy, x.binSize, y.binSize, x.name = "V1", y.name = "V2") { xp <- xy[, 1] yp <- xy[, 3] xf <- xy[, 2] yf <- xy[, 4] + # OPTIMIZATION: Pre-calculate ranges to avoid repeated min/max calls + x_combined <- c(xp, xf) + y_combined <- c(yp, yf) + x_range <- range(x_combined) + y_range <- range(y_combined) + # bins per axis - x.nbins <- floor((abs(range(xp, xf)[2] - range(xp, xf)[1])) / x.binSize) - y.nbins <- floor((abs(range(yp, yf)[2] - range(yp, yf)[1])) / y.binSize) - x.bin <- seq(floor(min(cbind(xp, xf))), ceiling(max(cbind(xp, xf))), length = x.nbins) - y.bin <- seq(floor(min(cbind(yp, yf))), ceiling(max(cbind(yp, yf))), length = y.nbins) + x.nbins <- floor(abs(x_range[2] - x_range[1]) / x.binSize) + y.nbins <- floor(abs(y_range[2] - y_range[1]) / y.binSize) + x.bin <- seq(floor(x_range[1]), ceiling(x_range[2]), length = x.nbins) + y.bin <- seq(floor(y_range[1]), ceiling(y_range[2]), length = y.nbins) # define palette rf <- grDevices::colorRampPalette(rev(RColorBrewer::brewer.pal(11, "Spectral"))) @@ -75,18 +80,20 @@ climPlot <- function(xy, x.binSize, y.binSize, x.name = "V1", y.name = "V2") { freq2Dp[freq2Dp > UL] <- UL freq2Df[freq2Df > UL] <- UL - # novel (in future but not present, 2), remnant (in both, 1), and dissapearing (in present but not future, 3) climates - freq2D <- diag(nrow = x.nbins, ncol = y.nbins) - freq2D[] <- NA - for (i in 1:x.nbins) { - for (j in 1:y.nbins) { - freq2D[i, j] <- ifelse(is.na(freq2Dp[i, j]) & !is.na(freq2Df[i, j]), 1, - ifelse(!is.na(freq2Dp[i, j]) & is.na(freq2Df[i, j]), 2, - ifelse(is.na(freq2Dp[i, j]) & is.na(freq2Df[i, j]), NA, 0) - ) - ) - } - } + # OPTIMIZATION: Vectorized climate classification - eliminates nested loops + freq2D <- matrix(NA, nrow = x.nbins, ncol = y.nbins) + + # Vectorized logical operations - much faster than nested loops + present_na <- is.na(freq2Dp) + future_na <- is.na(freq2Df) + + # Novel climates: in future but not present + freq2D[present_na & !future_na] <- 1 + # Disappearing climates: in present but not future + freq2D[!present_na & future_na] <- 2 + # Remnant climates: in both present and future + freq2D[!present_na & !future_na] <- 0 + # NA remains NA (neither present nor future) # plot climate space Freq2Dpf <- rbind( diff --git a/R/dVoCC.R b/R/dVoCC.R index d9e7c69..f4916b2 100644 --- a/R/dVoCC.R +++ b/R/dVoCC.R @@ -5,7 +5,6 @@ #' other (target) cells in the future by reference to a specified climatic threshold. The function allows for the #' specification of search distances and incorporates both least-cost path and Great Circle (as-the-crow-flies) distances. #' -#' @importFrom foreach %dopar% #' #' @param clim \code{data.frame} with the value for the climatic parameters (columns) by cell (rows), arranged as follows (see examples below): #' The first 2n columns must contain the present and future values for each of the n climatic variables (V1p, V1f, V2p, V2f,...). @@ -39,10 +38,9 @@ #' @seealso{\code{\link{climPCA}}, \code{\link{climPlot}}} #' #' @export -#' @author Jorge Garcia Molinos #' @examples -#' \dontrun{ -#' JapTC <- VoCC_get_data("JapTC.tif") +#' +#' JapTC <- terra::rast(system.file("extdata", "JapTC.tif", package = "VoCC")) #' #' # Create a data frame with the necessary variables in the required order #' clim <- stats::na.omit(data.frame(terra::values(JapTC), cid = 1:terra::ncell(JapTC))) @@ -58,6 +56,7 @@ #' r1[avocc1$focal] <- avocc1$vel #' terra::plot(r1) #' +#' \dontrun{ #' # Cell-specific, distance-unrestricted climate analogue velocity based on least-cost path distances #' # First, create the conductance matrix (all land cells considered to have conductance of 1) #' r <- JapTC[[1]] @@ -81,8 +80,6 @@ dVoCC <- function(clim, n, tdiff, method = "Single", climTol, geoTol, distfun = "GreatCircle", trans = NA, lonlat = TRUE) { - geoDis <- climDis <- ang <- vel <- target <- cid <- a <- NULL # Fix devtools check warnings - if (distfun == "Euclidean" && lonlat == TRUE) { print("Error: Euclidean distances specified for unprojected coordinates") stop() @@ -99,144 +96,118 @@ dVoCC <- function(clim, n, tdiff, method = "Single", climTol, geoTol, dat <- stats::na.omit(data.table::data.table(clim)) - # matrix with the future climatic values for all cells - fut <- dat[, seq(2, (2 * n), by = 2), with = FALSE] - - # Determine optimal number of cores, ensuring we don't exceed data rows - ncores <- parallelly::availableCores(constraints = "connections", omit = 2) - ncores <- min(ncores, nrow(dat)) # Don't use more cores than data rows - ncores <- max(ncores, 1) # Ensure at least 1 core - - # Only use parallel processing if we have multiple cores and sufficient data - if (ncores > 1 && nrow(dat) > ncores) { - cuts <- cut(seq_len(nrow(dat)), ncores, labels = FALSE) - cl <- parallelly::makeClusterPSOCK(ncores, autoStop = TRUE) - - doParallel::registerDoParallel(cl) - - result <- foreach::foreach(a = seq_len(ncores), - .combine = rbind, - .packages = c("terra", "gdistance", "geosphere", "data.table"), - .multicombine = TRUE) %dopar% { - - Dat <- dat[cuts == a, ] - - resu <- data.table::data.table( - focal = Dat$cid, - target = as.integer(NA), - climDis = as.double(NA), - geoDis = as.double(NA), - ang = as.double(NA), - vel = as.double(NA) - ) - - i <- 0 - while (i <= nrow(Dat)) { - i <- i + 1 - - # for each focal cell subset target cell analogues (within ClimTol) - pres <- as.numeric(Dat[i, seq(1, (2 * n), by = 2), with = FALSE]) - dif <- data.table::data.table(sweep(fut, 2, pres, "-")) - - # Identify future analogue cells - if (method == "Single") { # Ohlemuller et al 2006 / Hamann et al 2015 - upper <- colnames(dif) - l <- lapply(upper, function(x) call("<", call("abs", as.name(x)), climTol[grep(x, colnames(dif))])) - ii <- Reduce(function(c1, c2) substitute(.c1 & .c2, list(.c1 = c1, .c2 = c2)), l) - anacid <- dat$cid[dif[eval(ii), which = TRUE]] # cids analogue cells - } - - if (method == "Variable") { # Garcia Molinos et al. 2017 - climTol <- as.numeric(Dat[i, ((2 * n) + 1):(3 * n), with = FALSE]) # focal cell tolerance - upper <- colnames(dif) - l <- lapply(upper, function(x) call("<", call("abs", as.name(x)), climTol[grep(x, colnames(dif))])) - ii <- Reduce(function(c1, c2) substitute(.c1 & .c2, list(.c1 = c1, .c2 = c2)), l) - anacid <- dat$cid[dif[eval(ii), which = TRUE]] # cids analogue cells - } - - # LOCATE CLOSEST ANALOGUE - if (length(anacid) > 0) { - # check which of those are within distance and get the analogue at minimum distance - if (distfun == "Euclidean") { - d <- stats::dist(cbind(Dat$x[i], Dat$y[i]), cbind(dat$x[dat$cid %in% anacid], dat$y[dat$cid %in% anacid])) - } # in x/y units - if (distfun == "GreatCircle") { - d <- (geosphere::distHaversine(cbind(Dat$x[i], Dat$y[i]), cbind(dat$x[dat$cid %in% anacid], dat$y[dat$cid %in% anacid]))) / 1000 - } # in km - - # LeastCost distances not supported - error is thrown at function start - - an <- anacid[d < geoTol] # cids analogue cells within search radius - dis <- d[d < geoTol] # distance to candidate analogues - if (length(an) > 0) { - resu[i, target := an[which.min(dis)]] # cid of geographically closest climate analogue - if (method == "Single") { - resu[i, climDis := mean(as.numeric(dif[which(anacid == resu[i, target]), ]))] - } # mean clim difference for the closest analogue - resu[i, geoDis := min(dis)] - resu[i, ang := geosphere::bearing(Dat[i, c("x", "y")], dat[cid == resu[i, target], c("x", "y")])] - resu[i, vel := resu$geoDis[i] / tdiff] - } - } - } - return(resu) - } - } else { - # Sequential processing for small datasets or limited cores - result <- data.table::data.table( - focal = dat$cid, - target = as.integer(NA), - climDis = as.double(NA), - geoDis = as.double(NA), - ang = as.double(NA), - vel = as.double(NA) - ) - - for (i in seq_len(nrow(dat))) { - # for each focal cell subset target cell analogues (within ClimTol) - pres <- as.numeric(dat[i, seq(1, (2 * n), by = 2), with = FALSE]) - dif <- data.table::data.table(sweep(fut, 2, pres, "-")) - - # Identify future analogue cells - if (method == "Single") { # Ohlemuller et al 2006 / Hamann et al 2015 - upper <- colnames(dif) - l <- lapply(upper, function(x) call("<", call("abs", as.name(x)), climTol[grep(x, colnames(dif))])) - ii <- Reduce(function(c1, c2) substitute(.c1 & .c2, list(.c1 = c1, .c2 = c2)), l) - anacid <- dat$cid[dif[eval(ii), which = TRUE]] # cids analogue cells - } - if (method == "Variable") { # Garcia Molinos et al. 2017 - climTol <- as.numeric(dat[i, ((2 * n) + 1):(3 * n), with = FALSE]) # focal cell tolerance - upper <- colnames(dif) - l <- lapply(upper, function(x) call("<", call("abs", as.name(x)), climTol[grep(x, colnames(dif))])) - ii <- Reduce(function(c1, c2) substitute(.c1 & .c2, list(.c1 = c1, .c2 = c2)), l) - anacid <- dat$cid[dif[eval(ii), which = TRUE]] # cids analogue cells - } + # Check if column cid (cell ID exists) + if (!"cid" %in% names(dat)) { + dat <- dat %>% + dplyr::mutate(cid = dplyr::row_number()) + } + + # OPTIMIZATION: Improved chunking strategy for better load balancing + n_cores <- future::availableCores() + + # Calculate optimal chunk size based on data size and cores + # Aim for 2-4 chunks per core for good load balancing + target_chunks <- n_cores * 3 + optimal_chunk_size <- max(100, ceiling(nrow(dat) / target_chunks)) + + # Ensure we don't create too many tiny chunks + actual_chunks <- min(target_chunks, ceiling(nrow(dat) / optimal_chunk_size)) + final_chunk_size <- ceiling(nrow(dat) / actual_chunks) + + # Create balanced chunks + dat_chunks <- split(dat, ceiling(seq_len(nrow(dat)) / final_chunk_size)) + + result <- dat_chunks %>% + furrr::future_map(pdVoCC, + dat_full = dat, # Pass full dataset for analogue search + n = n, + tdiff = tdiff, + method = method, + climTol = climTol, + geoTol = geoTol, + distfun = distfun, + trans = trans, + lonlat = lonlat, + .options = furrr::furrr_options(seed = TRUE), + .progress = TRUE) %>% + purrr::list_rbind() + + return(result) + +} + + - # LOCATE CLOSEST ANALOGUE - if (length(anacid) > 0) { - # check which of those are within distance and get the analogue at minimum distance - if (distfun == "Euclidean") { - d <- stats::dist(cbind(dat$x[i], dat$y[i]), cbind(dat$x[dat$cid %in% anacid], dat$y[dat$cid %in% anacid])) - } # in x/y units - if (distfun == "GreatCircle") { - d <- (geosphere::distHaversine(cbind(dat$x[i], dat$y[i]), cbind(dat$x[dat$cid %in% anacid], dat$y[dat$cid %in% anacid]))) / 1000 - } # in km - - an <- anacid[d < geoTol] # cids analogue cells within search radius - dis <- d[d < geoTol] # distance to candidate analogues - if (length(an) > 0) { - result[i, target := an[which.min(dis)]] # cid of geographically closest climate analogue - if (method == "Single") { - result[i, climDis := mean(as.numeric(dif[which(anacid == result[i, target]), ]))] - } # mean clim difference for the closest analogue - result[i, geoDis := min(dis)] - result[i, ang := geosphere::bearing(dat[i, c("x", "y")], dat[cid == result[i, target], c("x", "y")])] - result[i, vel := result$geoDis[i] / tdiff] - } +#' Run parallel dVoCC +#' +#' @noRd +pdVoCC <- function(dat, dat_full, n, tdiff, method = "Single", climTol, geoTol, + distfun = "GreatCircle", trans = NA, lonlat = TRUE) { + + geoDis <- climDis <- ang <- vel <- target <- cid <- a <- NULL # Fix devtools check warnings + + # Ensure both datasets are data.tables + dat <- data.table::as.data.table(dat) # Focal cells (chunk) + dat_full <- data.table::as.data.table(dat_full) # All cells (for analogue search) + + result <- data.table::data.table( + focal = dat$cid, + target = as.integer(NA), + climDis = as.double(NA), + geoDis = as.double(NA), + ang = as.double(NA), + vel = as.double(NA) + ) + + # FIXED: Use full dataset for analogue search, not just the chunk + fut <- dat_full[, seq(2, (2 * n), by = 2), with = FALSE] + + for (i in seq_len(nrow(dat))) { + + # for each focal cell subset target cell analogues (within ClimTol) + pres <- as.numeric(dat[i, seq(1, (2 * n), by = 2), with = FALSE]) + dif <- data.table::data.table(sweep(fut, 2, pres, "-")) + + # Identify future analogue cells + if (method == "Single") { # Ohlemuller et al 2006 / Hamann et al 2015 + upper <- colnames(dif) + l <- lapply(upper, function(x) call("<", call("abs", as.name(x)), climTol[grep(x, colnames(dif))])) + ii <- Reduce(function(c1, c2) substitute(.c1 & .c2, list(.c1 = c1, .c2 = c2)), l) + anacid <- dat_full$cid[dif[eval(ii), which = TRUE]] # FIXED: Use full dataset for analogue search + } + + if (method == "Variable") { # Garcia Molinos et al. 2017 + climTol <- as.numeric(dat[i, ((2 * n) + 1):(3 * n), with = FALSE]) # focal cell tolerance + upper <- colnames(dif) + l <- lapply(upper, function(x) call("<", call("abs", as.name(x)), climTol[grep(x, colnames(dif))])) + ii <- Reduce(function(c1, c2) substitute(.c1 & .c2, list(.c1 = c1, .c2 = c2)), l) + anacid <- dat_full$cid[dif[eval(ii), which = TRUE]] # FIXED: Use full dataset for analogue search + } + + # LOCATE CLOSEST ANALOGUE + if (length(anacid) > 0) { + # check which of those are within distance and get the analogue at minimum distance + if (distfun == "Euclidean") { + d <- stats::dist(cbind(dat$x[i], dat$y[i]), cbind(dat_full$x[dat_full$cid %in% anacid], dat_full$y[dat_full$cid %in% anacid])) + } # in x/y units + if (distfun == "GreatCircle") { + d <- (geosphere::distHaversine(cbind(dat$x[i], dat$y[i]), cbind(dat_full$x[dat_full$cid %in% anacid], dat_full$y[dat_full$cid %in% anacid]))) / 1000 + } # in km + + an <- anacid[d < geoTol] # cids analogue cells within search radius + dis <- d[d < geoTol] # distance to candidate analogues + if (length(an) > 0) { + result[i, target := an[which.min(dis)]] # cid of geographically closest climate analogue + if (method == "Single") { + result[i, climDis := mean(as.numeric(dif[which(anacid == result[i, target]), ]))] + } # mean clim difference for the closest analogue + result[i, geoDis := min(dis)] + result[i, ang := geosphere::bearing(dat[i, c("x", "y")], dat_full[cid == result[i, target], c("x", "y")])] + result[i, vel := result$geoDis[i] / tdiff] } } - } + } # End of the loop return(result) } diff --git a/R/gVoCC.R b/R/gVoCC.R index 8a9e21d..c9c2737 100644 --- a/R/gVoCC.R +++ b/R/gVoCC.R @@ -16,11 +16,11 @@ #' @seealso{\code{\link{tempTrend}}, \code{\link{spatGrad}}} #' #' @export -#' @author Jorge Garcia Molinos #' #' @examples -#' \dontrun{ -#' HSST <- VoCC_get_data("HSST.tif") +#' +#' HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) +#' #' yrSST <- sumSeries(HSST, #' p = "1960-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), #' fun = function(x) colMeans(x, na.rm = TRUE), freqin = "months", freqout = "years" @@ -37,11 +37,23 @@ gVoCC <- function(tempTrend, spatGrad) { VoCC <- tempTrend[[1]] / spatGrad[[1]] - # velocity angles have opposite direction to the spatial climatic gradient if warming and same direction (cold to warm) if cooling - ind <- which(terra::values(VoCC) > 0) + # OPTIMIZATION: Extract values once and use vectorized operations + VoCC_values <- terra::values(VoCC) + spatGrad_ang_values <- terra::values(spatGrad[[2]]) + + # Vectorized angle calculation with proper NA handling + warming_cells <- VoCC_values > 0 & !is.na(VoCC_values) + VoCCang_values <- spatGrad_ang_values + VoCCang_values[warming_cells] <- spatGrad_ang_values[warming_cells] + 180 + + # Handle angle wrapping with NA protection + needs_wrapping <- !is.na(VoCCang_values) & VoCCang_values >= 360 + VoCCang_values[needs_wrapping] <- VoCCang_values[needs_wrapping] - 360 + + # Create output raster efficiently VoCCang <- spatGrad[[2]] - VoCCang[ind] <- spatGrad[[2]][ind] + 180 - VoCCang[] <- ifelse(VoCCang[] >= 360, VoCCang[] - 360, VoCCang[]) + terra::values(VoCCang) <- VoCCang_values + output <- c(VoCC, VoCCang) names(output) <- c("voccMag", "voccAng") return(output) diff --git a/R/resTime.R b/R/resTime.R index a8e327a..8c6385d 100644 --- a/R/resTime.R +++ b/R/resTime.R @@ -15,19 +15,21 @@ #' @seealso{\code{\link{gVoCC}}} #' #' @export -#' @author Jorge Garcia Molinos #' @examples #' #' # Load example Exclusive Economic Zone polygon -#' \dontrun{ -#' EEZ <- VoCC_get_data("EEZ.gpkg") -#' HSST <- VoCC_get_data("HSST.tif") +#' +#' EEZ <- terra::vect(system.file("extdata", "EEZ.gpkg", package = "VoCC")) +#' +#' HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) %>% +#' terra::crop(terra::ext(EEZ)) #' #' yrSST <- sumSeries(HSST, #' p = "1969-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), #' fun = function(x) colMeans(x, na.rm = TRUE), #' freqin = "months", freqout = "years" #' ) +#' #' tr <- tempTrend(yrSST, th = 10) #' sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) #' v <- gVoCC(tr, sg) @@ -42,16 +44,16 @@ #' a2 #' #' # Using a user defined polygon -#' x_coord <- c(-28, -20, -20.3, -25.5) -#' y_coord <- c(60, 61, 63, 62) +#' x_coord <- c(-28, -20, -20.3, -25.5, -28) +#' y_coord <- c(60, 61, 63, 62, 60) #' coords <- matrix(c(x_coord, y_coord), ncol = 2) #' poly_sf <- sf::st_sf(geometry = sf::st_sfc(sf::st_polygon(list(coords)))) #' a3 <- resTime(poly_sf, vel, areapg = NA) #' #' terra::plot(vel) -#' plot(sf::st_geometry(EEZ), add = TRUE) +#' terra::plot(EEZ, add = TRUE) #' plot(sf::st_geometry(poly_sf), add = TRUE) -#' } +#' resTime <- function(pg, vel, areapg = NA) { resTim <- v <- d <- NULL # Fix devtools check warnings @@ -72,12 +74,12 @@ resTime <- function(pg, vel, areapg = NA) { # Extract velocity values using terra::vect for efficiency extracted_values <- terra::extract(vel, pg_vect, fun = mean, na.rm = TRUE) - + # Handle case where extraction returns NULL or empty results if (is.null(extracted_values) || nrow(extracted_values) == 0) { stop("No values could be extracted from the raster. Check that polygons overlap with the raster and have the same coordinate system.") } - + # Extract the mean values, handling potential column name variations if ("mean" %in% names(extracted_values)) { RT[, v := extracted_values$mean] diff --git a/R/shiftTime.R b/R/shiftTime.R index 5148bc5..e25d98a 100644 --- a/R/shiftTime.R +++ b/R/shiftTime.R @@ -19,40 +19,48 @@ #' shifting climate in marine and terrestrial ecosystems. Science, 334, 652-655. #' #' @export -#' @author Jorge Garcia Molinos and Michael T. Burrows #' @examples -#' \dontrun{ -#' HSST <- VoCC_get_data("HSST.tif") +#' +#' HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) #' Apr <- shiftTime(HSST, yr1 = 1960, yr2 = 2009, yr0 = 1955, th = 10, m = 4) #' #' terra::plot(Apr) -#' } +#' shiftTime <- function(r, yr1, yr2, yr0, th, m) { + # OPTIMIZATION: Pre-calculate constants and month indices + yr_offset <- (yr1 - yr0) * 12 + # 1. Long term trends in monthly values (e.g. deg/year if temperature) - m1 <- ((yr1 - yr0) * 12) + m + m1 <- yr_offset + m m2 <- ((yr2 - yr0) * 12) + m r1 <- r[[seq(m1, m2, by = 12)]] trend <- tempTrend(r1, th)[[1]] - # 2. seasonal rate of shift in temperature centered on each month (deg/month) = difference in - # temperature between preceding and following months divided by 2 months (slope) preceding month - b <- ifelse((m - 1) == 0, 12, (m - 1)) - m1 <- ((yr1 - yr0) * 12) + b - m2 <- ((yr2 - yr0) * 12) + b - x2 <- r[[seq(m1, m2, by = 12)]] + # OPTIMIZATION: Pre-calculate preceding and following months with bounds checking + prev_month <- if (m == 1) 12 else (m - 1) + next_month <- if (m == 12) 1 else (m + 1) + + # 2. seasonal rate of shift in temperature centered on each month (deg/month) + # preceding month + m1_prev <- yr_offset + prev_month + m2_prev <- ((yr2 - yr0) * 12) + prev_month + x2 <- r[[seq(m1_prev, m2_prev, by = 12)]] # following month - b <- ifelse((m + 1) == 13, 1, (m + 1)) - m1 <- ((yr1 - yr0) * 12) + b - m2 <- ((yr2 - yr0) * 12) + b - x3 <- r[[seq(m1, m2, by = 12)]] + m1_next <- yr_offset + next_month + m2_next <- ((yr2 - yr0) * 12) + next_month + x3 <- r[[seq(m1_next, m2_next, by = 12)]] + + # OPTIMIZATION: Pre-calculate conversion factor + days_per_decade_factor <- 3652.5 / 12 # 304.375 # slope x4 <- terra::mean((x3 - x2) / 2, na.rm = TRUE) - # 3. seasonal shifts (month/year) converted to days per decade by multiplying by 10 years, 365.25 days per year and dividing by 12 months - sShift <- (trend / x4) * (3652.5 / 12) + # 3. seasonal shifts (month/year) converted to days per decade + sShift <- (trend / x4) * days_per_decade_factor sShift[sShift == Inf | sShift == -Inf] <- NA + r2 <- c(trend, x4, sShift) names(r2) <- c("mTrend", "seaRate", "seaShift") return(r2) diff --git a/R/spatGrad.R b/R/spatGrad.R index 60b7e87..c88bcf4 100644 --- a/R/spatGrad.R +++ b/R/spatGrad.R @@ -16,7 +16,8 @@ #' (Grad in C per km for unprojected rasters and C per spatial unit for projected rasters), #' and the associated angle (Ang in degrees). #' -#' @references \href{http://science.sciencemag.org/content/334/6056/652}{Burrows et al. 2011}. The pace of shifting climate in marine and terrestrial ecosystems. Science, 334, 652-655. +#' @references \href{http://science.sciencemag.org/content/334/6056/652}{Burrows et al. 2011}. +#' The pace of shifting climate in marine and terrestrial ecosystems. Science, 334, 652-655. #' #' @seealso{\code{\link{tempTrend}}, \code{\link{gVoCC}}} #' @@ -24,10 +25,9 @@ #' @importFrom stats na.omit #' #' @export -#' @author Jorge Garcia Molinos, David S. Schoeman, and Michael T. Burrows #' @examples -#' \dontrun{ -#' HSST <- VoCC_get_data("HSST.tif") +#' +#' HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) #' #' yrSST <- sumSeries(HSST, #' p = "1969-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), @@ -39,15 +39,16 @@ #' sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) #' #' terra::plot(sg) -#' } #' spatGrad <- function(r, th = -Inf, projected = FALSE) { # Fix devtools check warnings "." <- NULL - gradNS1 <- gradNS2 <- gradNS3 <- gradNS4 <- gradNS5 <- gradNS6 <- gradWE1 <- gradWE2 <- gradWE3 <- gradWE4 <- gradWE5 <- gradWE6 <- NULL + gradNS1 <- gradNS2 <- gradNS3 <- gradNS4 <- gradNS5 <- gradNS6 <- NULL + gradWE1 <- gradWE2 <- gradWE3 <- gradWE4 <- gradWE5 <- gradWE6 <- NULL sy <- sx <- NSgrad <- WEgrad <- NULL - clim <- climE <- climN <- climNE <- climNW <- climS <- climSE <- climSW <- climW <- climFocal <- NULL + clim <- climE <- climN <- climNE <- climNW <- NULL + climS <- climSE <- climSW <- climW <- climFocal <- NULL to <- code <- i.to <- LAT <- angle <- Grad <- .SD <- NULL if (terra::nlyr(r) > 1) { @@ -57,12 +58,20 @@ spatGrad <- function(r, th = -Inf, projected = FALSE) { # get resolution of the raster re <- terra::res(r) + # OPTIMIZATION: Pre-extract raster values once to avoid repeated calls + spatRaster_values <- terra::values(r) + n_cells <- terra::ncell(r) + + # OPTIMIZATION: Pre-calculate row and column indices to avoid repeated terra calls + row_indices <- terra::rowFromCell(r, 1:n_cells) + col_indices <- terra::colFromCell(r, 1:n_cells) + # Create a columns for focal and each of its 8 adjacent cells y <- data.table::data.table(terra::adjacent(r, 1:terra::ncell(r), directions = 8, pairs = TRUE)) - y <- na.omit(y[, climFocal := terra::values(r)[from]][order(from, to)]) # Get value for focal cell, order the table by raster sequence and omit NAs (land cells) - y[, clim := terra::values(r)[to]] # Insert values for adjacent cells - y[, sy := terra::rowFromCell(r, from) - terra::rowFromCell(r, to)] # Column to identify rows in the raster (N = 1, mid = 0, S = -1) - y[, sx := terra::colFromCell(r, to) - terra::colFromCell(r, from)] # Same for columns (E = 1, mid = 0, W = -1) + y <- na.omit(y[, climFocal := spatRaster_values[from]][order(from, to)]) # OPTIMIZED: Use pre-extracted values + y[, clim := spatRaster_values[to]] # OPTIMIZED: Use pre-extracted values + y[, sy := row_indices[from] - row_indices[to]] # Column to identify rows in the raster (N = 1, mid = 0, S = -1) + y[, sx := col_indices[to] - col_indices[from]] # Same for columns (E = 1, mid = 0, W = -1) y[sx > 1, sx := -1] # Sort out the W-E wrap at the dateline, part I y[sx < -1, sx := 1] # Sort out the W-E wrap at the dateline, part II y[, code := paste0(sx, sy)] # Make a unique code for each of the eight neighbouring cells @@ -72,8 +81,11 @@ spatGrad <- function(r, th = -Inf, projected = FALSE) { to = c("climE", "climW", "climNW", "climSW", "climNE", "climSE", "climN", "climS")), on = "code", code := i.to] y <- data.table::dcast(y[, c("from", "code", "clim")], from ~ code, value.var = "clim") - y[, climFocal := terra::values(r)[from]] # Put climFocal back in - y[, LAT := terra::yFromCell(r, from)] # Add focal cell latitude + y[, climFocal := spatRaster_values[from]] # OPTIMIZED: Use pre-extracted values + + # OPTIMIZATION: Pre-calculate latitude values to avoid repeated terra calls + lat_values <- terra::yFromCell(r, 1:n_cells) + y[, LAT := lat_values[from]] # Add focal cell latitude using pre-calculated values # Calculate individual spatial temperature gradients: grads (degC per km) # WE gradients difference in temperatures for each western and eastern pairs divided by the distance between the cells in each pair (corrected for latitudinal distortion if unprojected) @@ -99,19 +111,49 @@ spatGrad <- function(r, th = -Inf, projected = FALSE) { y[, gradNS5 := (climFocal - climS) / (d * re[2])] y[, gradNS6 := (climE - climSE) / (d * re[2])] - # Calulate NS and WE gradients. + # OPTIMIZATION: Vectorized weighted mean calculations instead of apply() + # Calculate NS and WE gradients using vectorized operations # NOTE: for angles to work (at least using simple positive and negative values on Cartesian axes), # S-N & W-E gradients need to be positive) - y[, WEgrad := apply(.SD, 1, function(x) stats::weighted.mean(x, c(1, 2, 1, 1, 2, 1), na.rm = TRUE)), .SDcols = 12:17] - y[, NSgrad := apply(.SD, 1, function(x) stats::weighted.mean(x, c(1, 2, 1, 1, 2, 1), na.rm = TRUE)), .SDcols = 18:23] + + # Extract gradient matrices for vectorized operations + WE_gradients <- as.matrix(y[, .(gradWE1, gradWE2, gradWE3, gradWE4, gradWE5, gradWE6)]) + NS_gradients <- as.matrix(y[, .(gradNS1, gradNS2, gradNS3, gradNS4, gradNS5, gradNS6)]) + + # Vectorized weighted mean calculation + weights <- c(1, 2, 1, 1, 2, 1) + + # Calculate weighted means with proper NA handling (equivalent to na.rm = TRUE) + # Replace NA values with 0 for matrix multiplication, but track valid values + WE_valid <- !is.na(WE_gradients) + NS_valid <- !is.na(NS_gradients) + + # Create matrices with NAs replaced by 0 for calculation + WE_clean <- WE_gradients + NS_clean <- NS_gradients + WE_clean[!WE_valid] <- 0 + NS_clean[!NS_valid] <- 0 + + # Calculate weighted sums only for valid (non-NA) values + WE_weighted_sums <- rowSums(WE_clean * rep(weights, each = nrow(WE_clean))) + NS_weighted_sums <- rowSums(NS_clean * rep(weights, each = nrow(NS_clean))) + + # Calculate sum of weights for valid values only + WE_weight_sums <- rowSums(WE_valid * rep(weights, each = nrow(WE_valid))) + NS_weight_sums <- rowSums(NS_valid * rep(weights, each = nrow(NS_valid))) + + # Calculate weighted means (equivalent to stats::weighted.mean with na.rm = TRUE) + y[, WEgrad := ifelse(WE_weight_sums > 0, WE_weighted_sums / WE_weight_sums, NA_real_)] + y[, NSgrad := ifelse(NS_weight_sums > 0, NS_weighted_sums / NS_weight_sums, NA_real_)] + y[is.na(WEgrad) & !is.na(NSgrad), WEgrad := 0L] # Where NSgrad does not exist, but WEgrad does, make NSgrad 0 y[!is.na(WEgrad) & is.na(NSgrad), NSgrad := 0L] # same the other way around # Calculate angles of gradients (degrees) - adjusted for quadrant (0 deg is North) y[, angle := angulo(.SD$WEgrad, .SD$NSgrad), .SDcols = c("WEgrad", "NSgrad")] - # Calculate the vector sum of gradients (C/km) - y[, Grad := sqrt(apply(cbind((y$WEgrad^2), (y$NSgrad^2)), 1, sum, na.rm = TRUE))] + # OPTIMIZATION: Vectorized magnitude calculation instead of apply() + y[, Grad := sqrt(WEgrad^2 + NSgrad^2)] # Merge the reduced file back into the main file to undo the initial na.omit from <- data.table::data.table(1:terra::ncell(r)) # Make ordered from cells @@ -121,6 +163,13 @@ spatGrad <- function(r, th = -Inf, projected = FALSE) { rAng[y$from] <- y$angle rGrad[y$from] <- y$Grad rGrad[rGrad[] < th] <- th + + # MEMORY LEAK FIX: Clean up large intermediate objects + rm(spatRaster_values, lat_values, row_indices, col_indices, + WE_gradients, NS_gradients, WE_clean, NS_clean, + WE_valid, NS_valid, WE_weighted_sums, NS_weighted_sums, + WE_weight_sums, NS_weight_sums, y, from) + output <- c(rGrad, rAng) names(output) <- c("Grad", "Ang") diff --git a/R/splitLine.R b/R/splitLine.R index bd61aea..5671502 100644 --- a/R/splitLine.R +++ b/R/splitLine.R @@ -2,8 +2,7 @@ #' @param A \code{numeric} giving coordinates of first point #' @param B \code{numeric} giving coordinates of second point #' @param n \code{numeric} number of segments to divide the distance between points with -#' @author Jorge Garcia Molinos - +#' splitLine <- function(A, B, n) { # Remove sign change for dateline, if needed B[, 1] <- with(B, ifelse(abs(B[, 1] - A[, 1]) > 180 & B[, 1] < 0, B[, 1] + 360, B[, 1])) diff --git a/R/sumSeries.R b/R/sumSeries.R index 3de447a..2bbfa92 100644 --- a/R/sumSeries.R +++ b/R/sumSeries.R @@ -26,12 +26,11 @@ #' of Matrices (and to Vectors). R package version 0.53.1. #' #' @export -#' @author Jorge Garcia Molinos #' @examples -#' \dontrun{ +#' #' # Monthly mean SST (HadISST) data for Europe Jan-1950 to Dec-2010 #' -#' HSST <- VoCC_get_data("HSST.tif") +#' HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) #' #' # Calculate mean annual monthly SST #' @@ -66,7 +65,6 @@ #' p = "1969-01/2009-12", yr0 = "1950-01-01", l = terra::nlyr(HSST), #' fun = myf, freqin = "months", freqout = "other" #' ) -#' } #' sumSeries <- function(r, p, yr0, l = terra::nlyr(r), fun = function(x) colMeans(x, na.rm = TRUE), freqin = "months", freqout = "years") { # construct xts object @@ -93,18 +91,27 @@ sumSeries <- function(r, p, yr0, l = terra::nlyr(r), fun = function(x) colMeans( s <- fun(x) } - # create raster stack - for (i in 1:nrow(s)) { - r2 <- terra::rast(r[[1]]) - r2[] <- as.numeric(s[i, ]) - if (i == 1) { - r1 <- r2 - } else { - r1 <- c(r1, r2) - } + # MEMORY LEAK FIX: More efficient raster creation using terra::setValues + raster_list <- vector("list", nrow(s)) + template_raster <- terra::rast(r[[1]]) + + # OPTIMIZED: Vectorized raster creation + for (i in seq_len(nrow(s))) { + r2 <- terra::rast(template_raster) # Use template to avoid repeated rast() calls + terra::values(r2) <- as.numeric(s[i, ]) # More efficient than r2[] <- + raster_list[[i]] <- r2 } + + # MEMORY LEAK FIX: Create stack once from list instead of incremental growth + r1 <- terra::rast(raster_list) + + # Set names before cleaning up variables (x is needed for stats::start) if (freqout != "other") { names(r1) <- seq(stats::start(x), length = terra::nlyr(r1), by = freqout) } + + # Clean up temporary objects after using them + rm(raster_list, template_raster, m, ts1, x, s) + return(r1) } diff --git a/R/tempTrend.R b/R/tempTrend.R index 638fb53..4613522 100644 --- a/R/tempTrend.R +++ b/R/tempTrend.R @@ -17,10 +17,9 @@ #' @seealso{\code{\link{spatGrad}}, \code{\link{gVoCC}}} #' #' @export -#' @author Jorge Garcia Molinos and Christopher J. Brown #' @examples -#' \dontrun{ -#' HSST <- VoCC_get_data("HSST.tif") +#' +#' HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) #' #' yrSST <- sumSeries(HSST, #' p = "1969-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), @@ -32,42 +31,60 @@ #' tr <- tempTrend(yrSST, th = 10) #' #' terra::plot(tr) -#' } +#' tempTrend <- function(r, th) { y <- terra::values(r) ocean <- which(rowSums(is.na(y)) != ncol(y)) # remove land cells y <- t(y[ocean, ]) - N <- apply(y, 2, function(x) sum(!is.na(x))) + + # OPTIMIZED: Vectorized NA counting using colSums instead of apply + N <- colSums(!is.na(y)) ind <- which(N >= th) - y <- y[, ind] # drop cells with less than th observations - N <- apply(y, 2, function(x) sum(!is.na(x))) - x <- matrix(nrow = terra::nlyr(r), ncol = ncol(y)) - x[] <- 1:terra::nlyr(r) + y <- y[, ind, drop = FALSE] # drop cells with less than th observations + N <- N[ind] # Use pre-calculated N values + + # OPTIMIZED: More efficient x matrix creation using outer product + n_layers <- terra::nlyr(r) + n_cells <- ncol(y) + + # Create time vector once and replicate efficiently + time_vec <- seq_len(n_layers) + x <- matrix(rep(time_vec, n_cells), nrow = n_layers, ncol = n_cells) # put NA values into the x values so they correspond with y - x1 <- y - x1[!is.na(x1)] <- 1 - x <- x * x1 + x[is.na(y)] <- NA - # calculate the sum terms - sx <- apply(x, 2, sum, na.rm = T) - sy <- apply(y, 2, sum, na.rm = T) - sxx <- apply(x, 2, function(x) sum(x^2, na.rm = T)) - syy <- apply(y, 2, function(x) sum(x^2, na.rm = T)) - xy <- x * y - sxy <- apply(xy, 2, sum, na.rm = T) + # OPTIMIZED: Vectorized sum calculations using colSums instead of apply + sx <- colSums(x, na.rm = TRUE) + sy <- colSums(y, na.rm = TRUE) + sxx <- colSums(x^2, na.rm = TRUE) + syy <- colSums(y^2, na.rm = TRUE) + sxy <- colSums(x * y, na.rm = TRUE) - # Estimate slope coefficients and associated standard errors and p-values - slope <- (N * sxy - (sx * sy)) / (N * sxx - sx^2) - sres <- (N * syy - sy^2 - slope^2 * (N * sxx - sx^2)) / (N * (N - 2)) - SE <- suppressWarnings(sqrt((N * sres) / (N * sxx - sx^2))) + # OPTIMIZED: Vectorized slope calculations with better numerical stability + denominator <- N * sxx - sx^2 + # Add small epsilon to prevent division by zero + denominator[denominator == 0] <- .Machine$double.eps + + slope <- (N * sxy - (sx * sy)) / denominator + sres <- (N * syy - sy^2 - slope^2 * denominator) / (N * (N - 2)) + SE <- suppressWarnings(sqrt((N * sres) / denominator)) Test <- slope / SE - p <- mapply(function(x, y) (2 * stats::pt(abs(x), df = y - 2, lower.tail = FALSE)), x = Test, y = N) - slpTrends <- sigTrends <- seTrends <- terra::rast(r[[1]]) - slpTrends[ocean[ind]] <- slope - seTrends[ocean[ind]] <- SE - sigTrends[ocean[ind]] <- p + # OPTIMIZED: Vectorized p-value calculation with bounds checking + df_vals <- pmax(N - 2, 1) # Ensure df >= 1 + p <- 2 * stats::pt(abs(Test), df = df_vals, lower.tail = FALSE) + + # OPTIMIZED: Direct raster creation and assignment + template_raster <- terra::rast(r[[1]]) + slpTrends <- seTrends <- sigTrends <- template_raster + + # Use vectorized assignment + ocean_ind <- ocean[ind] + slpTrends[ocean_ind] <- slope + seTrends[ocean_ind] <- SE + sigTrends[ocean_ind] <- p + output <- c(slpTrends, seTrends, sigTrends) names(output) <- c("slpTrends", "seTrends", "sigTrends") diff --git a/R/trajClas.R b/R/trajClas.R index f029d29..2a34229 100644 --- a/R/trajClas.R +++ b/R/trajClas.R @@ -42,10 +42,13 @@ #' @seealso{\code{\link{voccTraj}}} #' #' @export -#' @author Jorge Garcia Molinos #' @examples +#' #' \dontrun{ -#' HSST <- VoCC_get_data("HSST.tif") +#' EEZ <- terra::vect(system.file("extdata", "EEZ.gpkg", package = "VoCC")) +#' +#' HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) %>% +#' terra::crop(terra::ext(EEZ) + 10) #' #' # input raster layers #' yrSST <- sumSeries(HSST, @@ -61,16 +64,13 @@ #' ang <- v[[2]] #' #' # Get the set of starting cells for the trajectories and calculate trajectories -#' # at 1/4-deg resolution (16 trajectories per 1-deg cell) -#' mnd <- terra::disagg(mn, 4) -#' veld <- terra::disagg(vel, 4) -#' angd <- terra::disagg(ang, 4) #' lonlat <- stats::na.omit(data.frame( -#' terra::xyFromCell(veld, 1:terra::ncell(veld)), -#' terra::values(veld), terra::values(angd), terra::values(mnd) +#' terra::xyFromCell(vel, 1:terra::ncell(vel)), +#' terra::values(vel), terra::values(ang), terra::values(mn) #' ))[, 1:2] #' -#' traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) +#' traj <- voccTraj(lonlat, vel, ang, mn, tstep = 1/4, tyr = 20, seed = 23) +#' #' #' # Generate the trajectory-based classification #' clas <- trajClas(traj, vel, ang, mn, @@ -78,35 +78,38 @@ #' Nend = 45, Nst = 15, NFT = 70, DateLine = FALSE #' ) #' -#' # Define first the colour palette for the full set of categories -#' my_col <- c( -#' "gainsboro", "darkseagreen1", "coral4", "firebrick2", "mediumblue", "darkorange1", -#' "magenta1", "cadetblue1", "yellow1" -#' ) -#' # Keep only the categories present in our raster -#' my_col <- my_col[sort(unique(terra::values(clas[[7]])))] -#' #' # Classify raster / build attribute table #' clasr <- terra::as.factor(clas[[7]]) #' rat_r <- data.frame(ID = sort(unique(terra::values(clas[[7]]))), #' trajcat = c("N-M", "S-M", "IS", "BS", "Srce", #' "RS", "Cor", "Div", "Con")[sort(unique(terra::values(clas[[7]])))]) -#' terra::cats(clasr) <- rat_r -#' # Produce the plot using the rasterVis levelplot function -#' rasterVis::levelplot(clasr, -#' col.regions = my_col, -#' xlab = NULL, ylab = NULL, scales = list(draw = FALSE) -#' ) +#' levels(clasr) <- rat_r +#' terra::plot(clasr) #' } +#' trajClas <- function(traj, vel, ang, mn, trajSt, tyr, nmL, smL, Nend, Nst, NFT, DateLine = FALSE) { ang1 <- ang2 <- ang3 <- ang4 <- d1 <- d2 <- d3 <- d4 <- NULL # Fix devtools check warnings - isink <- .SD <- .N <- cid <- coastal <- val <- trajIDs <- NULL # Fix devtools check warnings + isink <- .SD <- .N <- cid <- coastal <- val <- ID <- NULL # Fix devtools check warnings + + # MEMORY LEAK FIX: Create template raster once and reuse + template_raster <- terra::rast(ang) # Force loading of ang values to avoid lazy loading warnings invisible(terra::values(ang)) - TrajEnd <- TrajFT <- TrajSt <- IntS <- BounS <- TrajClas <- terra::rast(ang) + TrajEnd <- terra::rast(template_raster) + terra::values(TrajEnd) <- 0 + TrajFT <- terra::rast(template_raster) + terra::values(TrajFT) <- 0 + TrajSt <- terra::rast(template_raster) + terra::values(TrajSt) <- 0 + IntS <- terra::rast(template_raster) + terra::values(IntS) <- 0 + BounS <- terra::rast(template_raster) + terra::values(BounS) <- 0 + TrajClas <- terra::rast(template_raster) + terra::values(TrajClas) <- 0 # add cell ID to the data frame traj <- data.table::data.table(traj) @@ -117,16 +120,14 @@ trajClas <- function(traj, vel, ang, mn, trajSt, tyr, nmL, smL, Nend, Nst, NFT, terra::values(TrajSt)[!is.na(terra::values(ang))] <- trajSt # B. Number of traj ending in each cell - tr <- traj[, data.table::.SD[.N], by = trajIDs] # subset last point of each trajectory + tr <- traj[, data.table::.SD[.N], by = ID] # subset last point of each trajectory enTraj <- tr[, .N, by = cid] - terra::values(TrajEnd) <- 0 TrajEnd <- terra::mask(TrajEnd, vel) terra::values(TrajEnd)[enTraj$cid] <- enTraj$N # C. Number of traj flowing through each cell - cxtrj <- unique(traj, by = c("trajIDs", "cid")) + cxtrj <- unique(traj, by = c("ID", "cid")) TotTraj <- cxtrj[, .N, by = cid] # total number of trajectories per cell - terra::values(TrajFT) <- 0 TrajFT <- terra::mask(TrajFT, vel) terra::values(TrajFT)[TotTraj$cid] <- TotTraj$N TrajFT <- TrajFT - TrajEnd - TrajSt # subtract traj starting and ending to get those actually transversing the cell @@ -152,27 +153,39 @@ trajClas <- function(traj, vel, ang, mn, trajSt, tyr, nmL, smL, Nend, Nst, NFT, res_x/2, res_y/2), # top-right ncol = 2, byrow = TRUE) + # OPTIMIZED: Vectorized corner coordinate calculation # Get the four cells for each coordinate point - # Initialize as numeric matrix explicitly - a <- matrix(as.numeric(NA), nrow = nrow(coords), ncol = 4) - - for(i in 1:nrow(coords)) { - if(!is.na(coords[i,1]) && !is.na(coords[i,2])) { - # Calculate corner coordinates - corner_coords <- sweep(offsets, 2, coords[i,], "+") - # Get cell numbers for each corner - handle one at a time - for(k in 1:4) { - cell_num <- terra::cellFromXY(ang, corner_coords[k, , drop = FALSE]) - a[i, k] <- as.numeric(cell_num[1]) - } + n_coords <- nrow(coords) + a <- matrix(as.numeric(NA), nrow = n_coords, ncol = 4) + + # Only process valid coordinates + valid_idx <- !is.na(coords[,1]) & !is.na(coords[,2]) + valid_coords <- coords[valid_idx, , drop = FALSE] + + if (nrow(valid_coords) > 0) { + # Vectorized corner calculation for all valid coordinates at once + n_valid <- nrow(valid_coords) + + # Create all corner coordinates in one operation + all_corners <- array(NA, dim = c(n_valid, 4, 2)) + for(k in 1:4) { + # Fix dimension mismatch by ensuring proper matrix dimensions + offset_matrix <- matrix(rep(offsets[k,], each = n_valid), nrow = n_valid, ncol = 2) + all_corners[, k, ] <- offset_matrix + valid_coords } - } - # Sort each row as in original code - for(i in 1:nrow(a)) { - a[i,] <- sort(a[i,]) + # Get cell numbers for all corners at once + for(k in 1:4) { + corner_matrix <- all_corners[, k, , drop = FALSE] + dim(corner_matrix) <- c(n_valid, 2) + cell_nums <- terra::cellFromXY(ang, corner_matrix) + a[valid_idx, k] <- as.numeric(cell_nums) + } } + # OPTIMIZED: Vectorized row sorting using apply + a <- t(apply(a, 1, sort, na.last = TRUE)) + # If date line crossing, correct sequences on date line if (DateLine == TRUE) { a[seq(terra::ncol(ang), by = terra::ncol(ang), length = terra::nrow(ang)), ] <- t(apply(a[seq(terra::ncol(ang), by = terra::ncol(ang), length = terra::nrow(ang)), ], 1, function(x) { @@ -180,21 +193,17 @@ trajClas <- function(traj, vel, ang, mn, trajSt, tyr, nmL, smL, Nend, Nst, NFT, })) } + # OPTIMIZED: Vectorized angle extraction # Extract the angles for each group of 4 cells - # Use direct indexing approach that works better with terra b <- matrix(NA, nrow = nrow(a), ncol = 4) # Get all angle values once to avoid repeated calls ang_values <- terra::values(ang) + max_cell <- length(ang_values) - for(i in 1:nrow(a)) { - for(j in 1:4) { - cell_val <- a[i,j] # Should now be numeric - if(!is.na(cell_val) && cell_val > 0 && cell_val <= length(ang_values)) { - b[i,j] <- ang_values[cell_val] - } - } - } + # Vectorized angle extraction + valid_cells <- !is.na(a) & a > 0 & a <= max_cell + b[valid_cells] <- ang_values[a[valid_cells]] # Ensure a and b have the same number of rows before combining if(nrow(a) != nrow(b)) { # Pad b to match a if needed @@ -213,7 +222,6 @@ trajClas <- function(traj, vel, ang, mn, trajSt, tyr, nmL, smL, Nend, Nst, NFT, # get the cids for the cells contained in the sinks celdas <- ll[isink == 1, 3:6] - terra::values(IntS) <- 0 IntS <- terra::mask(IntS, vel) # Convert data.table columns to vectors and combine @@ -231,17 +239,22 @@ trajClas <- function(traj, vel, ang, mn, trajSt, tyr, nmL, smL, Nend, Nst, NFT, # detect coastal cells coast <- suppressWarnings(terra::boundaries(vel, inner = TRUE)) # terra uses 'inner' parameter instead of 'type' + # OPTIMIZED: Pre-extract raster values once to avoid repeated terra::values() calls + vel_values <- terra::values(vel) + mn_values <- terra::values(mn) + coast_values <- terra::values(coast) + # make a list of vel values and SST values for each coastal cells and their marine neighbours - cc <- stats::na.omit(data.table::data.table(cid = 1:terra::ncell(vel), coast = terra::values(coast))) + cc <- stats::na.omit(data.table::data.table(cid = 1:terra::ncell(vel), coast = coast_values)) ad <- terra::adjacent(vel, cc$cid, directions = 8, include = TRUE) # matrix with adjacent cells # Sort the adjacency matrix to ensure consistent ordering (replaces sorted=TRUE from raster package) ad <- ad[order(ad[, 1], ad[, 2]), ] ad <- data.table::data.table( coastal = ad[, 1], adjacent = ad[, 2], - cvel = terra::values(vel)[ad[, 1]], - ctemp = terra::values(mn)[ad[, 1]], - atemp = terra::values(mn)[ad[, 2]] + cvel = vel_values[ad[, 1]], + ctemp = mn_values[ad[, 1]], + atemp = mn_values[ad[, 2]] ) # locate the sinks @@ -249,51 +262,85 @@ trajClas <- function(traj, vel, ang, mn, trajSt, tyr, nmL, smL, Nend, Nst, NFT, j <- ad[, ifelse(.SD$cvel > 0, all(.SD$ctemp <= .SD$atemp), all(.SD$ctemp >= .SD$atemp)), by = coastal] data.table::setkey(j) j <- unique(j) - terra::values(BounS) <- 0 BounS <- terra::mask(BounS, vel) boundary_cells <- unique(subset(j$coastal, j$V == TRUE)) if(length(boundary_cells) > 0) { terra::values(BounS)[as.numeric(boundary_cells)] <- 1 } + # OPTIMIZED: Pre-extract ang values and minimize raster operations + ang_values <- terra::values(ang) + # Total number of trajectories per cell and proportions per cell TrajTotal <- TrajSt + TrajFT + TrajEnd - terra::values(TrajTotal)[is.na(terra::values(ang))] <- NA + terra::values(TrajTotal)[is.na(ang_values)] <- NA PropTrajEnd <- (TrajEnd / TrajTotal) * 100 PropTrajFT <- (TrajFT / TrajTotal) * 100 PropTrajSt <- (TrajSt / TrajTotal) * 100 - # reclassify by traj length - rclM <- matrix(c(0, (nmL / tyr), 1, (nmL / tyr), (smL / tyr), 2, (smL / tyr), Inf, 3), ncol = 3, byrow = TRUE) - v <- terra::rast(vel) - terra::values(v) <- abs(terra::values(vel)) - ClassMov <- terra::classify(v, rclM) + # OPTIMIZED: Direct classification using pre-extracted values - avoid creating intermediate rasters + abs_vel_values <- abs(vel_values) - # Classify the cells - terra::values(TrajClas) <- 0 - TrajClas <- terra::mask(TrajClas, vel) + # Vectorized classification instead of terra::classify + ClassMov_values <- ifelse(abs_vel_values <= (nmL / tyr), 1, + ifelse(abs_vel_values <= (smL / tyr), 2, 3)) + ClassMov_values[is.na(vel_values)] <- NA + + # OPTIMIZED: Pre-extract all raster values for classification + IntS_values <- terra::values(IntS) + BounS_values <- terra::values(BounS) + PropTrajEnd_values <- terra::values(PropTrajEnd) + PropTrajSt_values <- terra::values(PropTrajSt) + PropTrajFT_values <- terra::values(PropTrajFT) + + # Classify the cells using vectorized operations + TrajClas_values <- rep(0, terra::ncell(TrajClas)) + TrajClas_values[is.na(vel_values)] <- NA # capture non-moving (1) - terra::values(TrajClas)[terra::values(ClassMov) == 1] <- 1 + TrajClas_values[ClassMov_values == 1] <- 1 # capture slow-moving (2) - terra::values(TrajClas)[terra::values(ClassMov) == 2] <- 2 + TrajClas_values[ClassMov_values == 2] <- 2 # capture internal (3) and (4) boundary sinks - terra::values(TrajClas)[terra::values(IntS) == 1] <- 3 - terra::values(TrajClas)[terra::values(BounS) == 1] <- 4 - - # Classify remaining cells into sources(5), rel sinks(6), corridors(7), divergence(8) and convergence(9) - d <- stats::na.omit(data.table::data.table(cid = 1:terra::ncell(TrajClas), val = terra::values(TrajClas))) - d <- d[val == 0, 1] - d[, Nend := terra::values(PropTrajEnd)[d$cid]] - d[, Nst := terra::values(PropTrajSt)[d$cid]] - d[, NFT := terra::values(PropTrajFT)[d$cid]] - d$clas <- ifelse(d$Nend == 0, 5, ifelse(d$Nend > Nend & d$Nst < Nst, 6, ifelse(d$NFT > NFT, 7, ifelse(d$Nend < d$Nst, 8, 9)))) - terra::values(TrajClas)[d$cid] <- d$clas + TrajClas_values[IntS_values == 1] <- 3 + TrajClas_values[BounS_values == 1] <- 4 + + # OPTIMIZED: Vectorized classification for remaining cells + remaining_cells <- which(TrajClas_values == 0) + if (length(remaining_cells) > 0) { + Nend_vals <- PropTrajEnd_values[remaining_cells] + Nst_vals <- PropTrajSt_values[remaining_cells] + NFT_vals <- PropTrajFT_values[remaining_cells] + + # Vectorized classification logic + clas_vals <- ifelse(Nend_vals == 0, 5, + ifelse(Nend_vals > Nend & Nst_vals < Nst, 6, + ifelse(NFT_vals > NFT, 7, + ifelse(Nend_vals < Nst_vals, 8, 9)))) + TrajClas_values[remaining_cells] <- clas_vals + } + + # Set final values + terra::values(TrajClas) <- TrajClas_values + + # Create ClassMov raster from the values before cleanup + ClassMov <- terra::rast(template_raster) + terra::values(ClassMov) <- ClassMov_values + + # MEMORY LEAK FIX: Clean up large intermediate objects before final assembly + rm(TrajClas_values, ClassMov_values, IntS_values, BounS_values, + PropTrajEnd_values, PropTrajSt_values, PropTrajFT_values, + vel_values, mn_values, coast_values, ang_values, template_raster, + abs_vel_values) # return raster s <- c(PropTrajEnd, PropTrajFT, PropTrajSt, ClassMov, IntS, BounS, TrajClas) names(s) <- c("PropEnd", "PropFT", "PropSt", "ClassL", "IntS", "BounS", "TrajClas") + + # Force garbage collection + gc() + return(s) } diff --git a/R/trajLine.R b/R/trajLine.R index 21007b2..a36931f 100644 --- a/R/trajLine.R +++ b/R/trajLine.R @@ -7,7 +7,7 @@ #' @param projx \code{CRS} detailing the coordinate reference system of the input data #' (default geographic CRS). #' -#' @return A \code{SpatialLinesDataFrame} with one line per trajectory as specified in x. +#' @return A \code{sf} object with one line per trajectory as specified in x. #' To avoid artifacts, trajectories crossing the date line need to be split into two segments. #' Where the trajectory on one side of the date line is only composed of a single point, #' the trajectory won't be displayed (no line object created). The function assumes @@ -16,10 +16,11 @@ #' @seealso{\code{\link{voccTraj}}} #' #' @export -#' @author Jorge Garcia Molinos #' @examples -#' \dontrun{ -#' HSST <- VoCC_get_data("HSST.tif") +#' +#' EEZ <- terra::vect(system.file("extdata", "EEZ.gpkg", package = "VoCC")) +#' HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) %>% +#' terra::crop(terra::ext(EEZ) + 10) #' #' yrSST <- sumSeries(HSST, #' p = "1969-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), @@ -41,41 +42,54 @@ #' ))[, 1:2] #' #' # Calculate trajectories. -#' traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) +#' traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, tstep = 1/12) #' #' # create a spatial line data frame from traj #' lns <- trajLine(x = traj) #' terra::plot(mn) -#' terra::plot(lns, add = TRUE) +#' plot(lns %>% sf::st_geometry(), add = TRUE) +#' #' -#' # Export as ESRI shape file -#' terra::writeVector(lns, filename = "velTraj", filetype = "ESRI Shapefile") -#' } trajLine <- function(x, projx = "EPSG:4326") { + x %>% + dplyr::group_split(.data$ID) %>% + furrr::future_map(get_trajLine, proj_x = projx, + .options = furrr::furrr_options(seed = TRUE), + .progress = TRUE) %>% + purrr::list_rbind() %>% + sf::st_sf() + +} + + +#' @noRd +get_trajLine <- function(x, proj_x){ + # Get distance between first and last points - d <- dplyr::bind_rows(dplyr::slice(x, 1), dplyr::slice(x, dplyr::n())) %>% - sf::st_as_sf(coords = c("llon", "llat")) %>% - sf::st_set_crs(projx) %>% - sf::st_distance(.) %>% + d <- dplyr::bind_rows(dplyr::slice(x, 1), dplyr::slice(x, dplyr::n())) |> + sf::st_as_sf(coords = c("lon", "lat")) |> + sf::st_set_crs(proj_x) |> + sf::st_distance() |> max() # Get number of steps; anything <240 means that the tracer died on land steps <- max(x$Steps) # Get distance along the tracer - line_string <- x %>% - sf::st_as_sf(coords = c("llon", "llat")) %>% - sf::st_set_crs(projx) %>% - dplyr::summarise(do_union = FALSE) %>% - sf::st_cast(to = "LINESTRING") %>% + line_string <- x |> + sf::st_as_sf(coords = c("lon", "lat")) |> + sf::st_set_crs(proj_x) |> + dplyr::summarise(do_union = FALSE) |> + sf::st_cast(to = "LINESTRING") + +# Seperate this out to allow use of sf::st_length(line_string) + line_string |> dplyr::mutate(steps = steps, line_distance = d, - line_length = sf::st_length(.), - cellID = dplyr::first(x$cellIDs), - lon = dplyr::first(x$llon), - lat = dplyr::first(x$llat)) - - return(line_string) + line_length = sf::st_length(line_string), + ID = dplyr::first(x$ID), + lon = dplyr::first(x$lon), + lat = dplyr::first(x$lat)) } diff --git a/R/utils_voccTraj.R b/R/utils_voccTraj.R new file mode 100644 index 0000000..793b6f2 --- /dev/null +++ b/R/utils_voccTraj.R @@ -0,0 +1,369 @@ +# Internal helper functions ---------------------------------------------------- + +# Function for finding minimum distance +mfind <- function(rw) { + X <- which.min(rw) + return(X) +} + +# Function to extract corner coordinates per row +mplace <- function(rw) { + X <- rw[(rw[1] + 1)] + Y <- rw[rw[1]] + return(c(X, Y)) +} + +# Simple circular functions +deg2rad <- function(deg) { + return(deg * pi / 180) +} +rad2deg <- function(rad) { + return(180 * rad / pi) +} + + +#' Find distances from departure point to corners of ttcell +#' OPTIMIZED: Use direct Haversine formula instead of expensive sf operations +#' +#' @noRd +get_dist <- function(y1, x1, y2, x2) { + # Convert degrees to radians + lat1_rad <- y1 * pi / 180 + lon1_rad <- x1 * pi / 180 + lat2_rad <- y2 * pi / 180 + lon2_rad <- x2 * pi / 180 + + # Haversine formula - much faster than sf::st_distance + dlat <- lat2_rad - lat1_rad + dlon <- lon2_rad - lon1_rad + + a <- sin(dlat/2)^2 + cos(lat1_rad) * cos(lat2_rad) * sin(dlon/2)^2 + c <- 2 * atan2(sqrt(a), sqrt(1-a)) + + # Earth radius in meters (same units as sf::st_distance) + R <- 6371000 + distance <- R * c + + return(distance) +} + + +#' Function for to find closest cooler/warmer cell within the union of two levels of 8-cell adjacency from the "departed" and "destination" cells +#' Use when working with the coarse grid! +#' JDE - Add bfr as an argument to voccTraj? +#' A from-to cell pair and coordinates of departure point; bfr is a search radius in km for nearest cooler cell, if you end on land +#' +#' @noRd +get_dest_cell_coarse <- function(rw, x_res, y_res, bfr, vel_values, mn_values, vel_raster, mn_raster) { + + # Add error handling for invalid inputs + if (any(is.na(rw[1:4]))) { + return(NA) + } + + # Find clumps of ocean; the rule is that you can't jump from one clump to another, + # because this would mean passing over unbroken land + pos_depart <- tryCatch({ + data.frame(x = purrr::pluck(rw, 3), + y = purrr::pluck(rw, 4)) %>% # Departure coordinates + sf::st_as_sf(coords = c("x", "y"), crs = "EPSG:4326") + }, error = function(e) { + return(NULL) + }) + + if (is.null(pos_depart)) { + return(NA) + } + + clumped <- tryCatch({ + get_clumps(pos_depart, mn_raster, bfr, x_res, y_res) + }, error = function(e) { + return(NULL) + }) + + if (is.null(clumped)) { + return(NA) + } + + # Which clump did I start in? + r1 <- purrr::pluck(rw, 1) # We use this cell a lot, so let's just make it an object + from_clump <- terra::extract(clumped, terra::xyFromCell(mn_raster, r1)) %>% + unlist() + + # What are the coordinates of cells within the search area that fall in the clump I came from? + search_xy <- terra::xyFromCell(clumped, which(clumped[] == from_clump)) %>% + as.data.frame() + + # Get the ssts in the cells to search + or <- terra::extract(mn_raster, search_xy, cells = TRUE, xy = TRUE) %>% + dplyr::rename(sst = 2, x = 4, y = 5) + + # MEMORY LEAK FIX: Use pre-extracted values instead of raster indexing + if (vel_values[r1] > 0) { + o <- or %>% + dplyr::filter(.data$sst < mn_values[r1]) %>% + stats::na.omit() + if (nrow(o) == 0) { + dest_cell <- NA + } else { + # OPTIMIZED: Use vectorized Haversine instead of sf::st_distance + depart_coords <- sf::st_coordinates(pos_depart) + distances <- get_dist(depart_coords[1,2], depart_coords[1,1], o$y, o$x) + dest_cell <- o$cell[which.min(distances)] + } + } else { # Otherwise, find nearest warmer cell, if there is one + o <- or %>% + dplyr::filter(.data$sst > mn_values[r1]) %>% + stats::na.omit() + if (nrow(o) == 0) { + dest_cell <- NA + } else { + # OPTIMIZED: Use vectorized Haversine instead of sf::st_distance + depart_coords <- sf::st_coordinates(pos_depart) + distances <- get_dist(depart_coords[1,2], depart_coords[1,1], o$y, o$x) + dest_cell <- o$cell[which.min(distances)] + } + } + return(dest_cell) +} + + + + + +#' Function to find closest cooler/warmer cell within the union of two levels of 8-cell adjacency from the "departed" and "destination" cells +#' +#' @noRd +get_dest_cell_fine <- function(rw, x_res, y_res, bfr, vel_values, mn_values, vel_raster, mn_raster) { + + # Add error handling for invalid inputs + if (any(is.na(rw[1:4]))) { + return(NA) + } + + # Find clumps of ocean; the rule is that you can't jump from one clump to another, because this would mean passing over unbroken land + pos_depart <- tryCatch({ + data.frame( + x = purrr::pluck(rw, 3), + y = purrr::pluck(rw, 4) + ) + }, error = function(e) { + return(NULL) + }) + + if (is.null(pos_depart)) { + return(NA) + } + + xy <- tryCatch({ + terra::xyFromCell(mn_raster, as.vector(as.matrix(rw[1:2]))) %>% # Coordinates of cell centres for start cell and end cell + as.data.frame() %>% + sf::st_as_sf(coords = c("x", "y"), crs = "EPSG:4326") + }, error = function(e) { + return(NULL) + }) + + if (is.null(xy)) { + return(NA) + } + + clumped <- tryCatch({ + get_clumps(xy, mn_raster, bfr, x_res, y_res) + }, error = function(e) { + return(NULL) + }) + + if (is.null(clumped)) { + return(NA) + } + + # Which clump did I start in? + r1 <- purrr::pluck(rw, 1) # We use this cell a lot, so let's just make it an object + from_clump <- purrr::pluck(terra::extract(clumped, terra::xyFromCell(mn_raster, r1)), 1) + + # What are the coordinates of cells within the search area that fall in the clump I came from? + search_xy <- terra::xyFromCell(clumped, which(clumped[] == from_clump)) %>% + as.data.frame() + search_cells <- terra::cellFromXY(mn_raster, search_xy) # Which cells are these + + # Get the ssts in the cells to search + or <- terra::extract(mn_raster, search_xy, cells = TRUE, xy = TRUE) %>% + dplyr::rename(sst = 2, x = 4, y = 5) + + # MEMORY LEAK FIX: Use pre-extracted values instead of raster indexing + if (vel_values[r1] > 0) { + # Find all cells in the search area that meet the sst criterion + o <- or %>% + dplyr::filter(.data$sst < mn_values[r1]) %>% + stats::na.omit() + if (nrow(o) == 0) { + dest_cell <- NA # Set condition with which to ID stuck cells (i.e., if there are no suitable cells in the search area) + } else { + # OPTIMIZED: Use vectorized Haversine instead of sf::st_distance + distances <- get_dist(pos_depart$y, pos_depart$x, o$y, o$x) + potential_dest_cells <- o %>% + dplyr::mutate(distances = distances) %>% + dplyr::arrange(.data$distances) + n_cells <- 25 # Number of "close" cells to pick among *** Can change this, or set as an argument (just remove the hard-code here) + if (nrow(potential_dest_cells) >= n_cells) { + dest_cell <- potential_dest_cells %>% + dplyr::slice_head(n = n_cells) %>% # Get the closest cells + dplyr::slice_sample(n = 1) %>% # Remove .preserve = TRUE which may cause seed issues + dplyr::pull(.data$cell) + } else { # If fewer than n_cells, sample 10% of what you have + n_sample <- max(1, ceiling(nrow(potential_dest_cells) / 10)) + dest_cell <- potential_dest_cells %>% + dplyr::slice_head(n = n_sample) %>% + dplyr::slice_sample(n = 1) %>% # Remove .preserve = TRUE which may cause seed issues + dplyr::pull(.data$cell) + } + } + } else { # Otherwise, find nearest cells that is warmer, if there are any + # Find all cells in the search area that meet the sst criterion + o <- or %>% + dplyr::filter(.data$sst > mn_values[r1]) %>% + stats::na.omit() + if (nrow(o) == 0) { + dest_cell <- NA # Set condition with which to ID stuck cells (i.e., if there are no suitable cells in the search area) + } else { + # OPTIMIZED: Use vectorized Haversine instead of sf::st_distance + distances <- get_dist(pos_depart$y, pos_depart$x, o$y, o$x) + potential_dest_cells <- o %>% + dplyr::mutate(distances = distances) %>% + dplyr::arrange(.data$distances) + + n_cells <- 25 # Number of "close" cells to pick among *** Can change this, or set as an argument (just remove the hard-code here) + if (nrow(potential_dest_cells) >= n_cells) { + dest_cell <- potential_dest_cells %>% + dplyr::slice_head(n = n_cells) %>% # Get the closest cells + dplyr::slice_sample(n = 1) %>% # Remove .preserve = TRUE which may cause seed issues + dplyr::pull(.data$cell) + } else { # If fewer than n_cells, sample 10% of what you have + n_sample <- max(1, ceiling(nrow(potential_dest_cells) / 10)) + dest_cell <- potential_dest_cells %>% + dplyr::slice_head(n = n_sample) %>% + dplyr::slice_sample(n = 1) %>% # Remove .preserve = TRUE which may cause seed issues + dplyr::pull(.data$cell) + } + } + } + return(dest_cell) +} + + +# JDE - I think we should rearrange arguments to x, y to be consistent + +# Find new destination, given velocity (km/yr), angle (º), time step (yr) and initial coordinates (ºlon, ºlat); max allowed jump is 1 deg +# vell = vel[fcells] %>% pull(1); angg = ang[fcells] %>% pull(1); timestep = tstep; ll = llold +#' +#' @noRd +destcoords <- function(vell, angg, timestep, ll, y_res, x_res) { + # OPTIMIZED: Pre-compute trigonometric values to avoid repeated calculations + angg_rad <- deg2rad(angg) + cos_angg <- cos(angg_rad) + sin_angg <- sin(angg_rad) + + # OPTIMIZED: Vectorized calculations with better numerical stability + abs_vell <- abs(vell) + latshift <- (abs_vell * timestep * cos_angg) / 111.325 # Calculate shift in lat + latnew <- ll[, 2] + latshift # Find new lat...first approximation + + # OPTIMIZED: Pre-compute cos(deg2rad(latnew)) for longitude calculation + cos_latnew <- cos(deg2rad(latnew)) + # Add small epsilon to prevent division by zero + cos_latnew[cos_latnew == 0] <- .Machine$double.eps + + lonshift <- (abs_vell * timestep * sin_angg) / (111.325 * cos_latnew) # Shift in lon + + # OPTIMIZED: Vectorized clamping instead of conditional assignment + lonshift <- pmax(pmin(lonshift, x_res), -x_res) + + # OPTIMIZED: Vectorized adjustment for extreme longitude shifts + needs_adjustment <- (abs(lonshift) == x_res) + if (any(needs_adjustment)) { + cos_ll_adj <- cos(deg2rad(ll[needs_adjustment, 2])) + tan_angg_adj <- tan(angg_rad[needs_adjustment]) + # Prevent division by zero + tan_angg_adj[tan_angg_adj == 0] <- .Machine$double.eps + latshift[needs_adjustment] <- (x_res * 111.325 * cos_ll_adj / tan_angg_adj) / 111.325 + } + + latnew <- ll[, 2] + latshift # Find new lat by adding the adjusted lats + + # OPTIMIZED: Vectorized pole clamping + latnew <- pmax(pmin(latnew, 90), -90) + + # Adjust lon + lonnew <- ll[, 1] + lonshift # Find new lon...first approximation + + # OPTIMIZED: More efficient dateline adjustment + lonnew <- lonnew - (360 * floor((lonnew + 180) / 360)) + + # OPTIMIZED: Direct data.frame creation instead of pipe + result <- data.frame(dlon = lonnew, dlat = latnew) + return(result) +} + + +#' +#' @noRd +get_clumps <- function(xy, mn, bfr, x_res, y_res){ + + # MEMORY LEAK FIX: Add error handling and explicit memory management + tryCatch({ + # MEMORY LEAK FIX: Limit buffer size to prevent excessive memory usage + max_bfr <- min(bfr, 200) # Cap buffer at 200km to prevent memory issues + sp_buffer <- sf::st_buffer(xy, max_bfr * 1000) # Buffer around departure point, remembering that buffer is in metres + + buffer_zone <- terra::extract(mn, sp_buffer, cells = TRUE, xy = TRUE) %>% + dplyr::select(-"ID") %>% + dplyr::distinct() %>% + dplyr::rename(sst = 1) %>% #*** rename "climatology", if needed + dplyr::select("x", "y", "sst", "cell") %>% + tidyr::drop_na("sst") + + # Check if buffer_zone is empty + if (nrow(buffer_zone) == 0) { + return(NULL) + } + + # MEMORY LEAK FIX: Adaptive sampling based on buffer size and resolution + max_cells <- min(10000, ceiling(pi * max_bfr^2 / (x_res * y_res * 111.325^2))) + if (nrow(buffer_zone) > max_cells) { + # Stratified sampling to maintain spatial distribution + buffer_zone <- buffer_zone[sample(nrow(buffer_zone), max_cells), ] + } + + # OPTIMIZATION: Pre-calculate raster bounds to avoid repeated min/max calls + x_range <- range(buffer_zone$x) + y_range <- range(buffer_zone$y) + + clumped_rast <- terra::rast( + xmin = x_range[1] - x_res/2, + xmax = x_range[2] + x_res/2, + ymin = y_range[1] - y_res/2, + ymax = y_range[2] + y_res/2, + resolution = c(x_res, y_res), + crs = "EPSG:4326" + ) + + # MEMORY LEAK FIX: Create SpatVector more efficiently and clean up immediately + buffer_vect <- terra::vect(buffer_zone[, c("x", "y", "sst")], geom = c("x", "y"), crs = "EPSG:4326") + + clumped <- terra::rasterize( + x = buffer_vect, + y = clumped_rast, # The template to rasterize onto + field = "sst") %>% # The data + terra::patches(directions = 8, allowGaps = FALSE) + + # MEMORY LEAK FIX: Explicitly clean up temporary objects + rm(buffer_vect, clumped_rast, sp_buffer, buffer_zone, x_range, y_range) + + return(clumped) + + }, error = function(e) { + warning("Error in get_clumps: ", e$message) + return(NULL) + }) +} + diff --git a/R/voccTraj.R b/R/voccTraj.R index 7810e9b..1883529 100644 --- a/R/voccTraj.R +++ b/R/voccTraj.R @@ -11,24 +11,26 @@ #' @param vel \code{raster} with the magnitude of gradient-based climate velocity. #' @param ang \code{raster} with velocity angles in degrees. #' @param mn \code{raster} with the overall mean climatic value over the period of interest. -#' @param vel_c -#' @param ang_c -#' @param mn_c -#' @param fine_coast -#' @param lk_up -#' @param tstep -#' @param tyr \code{integer} temporal length of the period of interest. +#' @param x_res Numeric. Resolution of the grid in longitude direction (degrees or km). +#' @param y_res Numeric. Resolution of the grid in latitude direction (degrees or km). +#' @param tstep Numeric. Timestep for each trajectory iteration (usually decimal year). +#' @param tyr Integer. Temporal length of the period of interest (years). +#' @param bfr Numeric. Distance around a cell to look for a cooler/warmer cell. +#' @param grid_resolution Character. "coarse" (default) or "fine". Controls how land crossings are handled and allows for higher resolution grids. +#' @param seed Integer. Random seed for reproducibility. If NULL (default), no seed is set. #' -#' @return a \code{data.frame} containing the coordinates ("x", "y") of the constituent -#' points and identification number ("trajIDs") for each trajectory. +#' +#' @return a \code{tibble} containing the coordinates ("lon", "lat") of the constituent +#' points, time step ("Steps"), identification number ("ID") for each trajectory, and cell IDs for start and end cells. #' #' @references \href{https://www.nature.com/articles/nature12976}{Burrows et al. 2014}. Geographical limits to species-range shifts are suggested by climate velocity. Nature, 507, 492-495. #' #' @seealso{\code{\link{gVoCC}}, \code{\link{trajClas}}} #' @export -#' @author Jorge Garcia Molinos, David S. Schoeman and Michael T. Burrows #' @examples #' \dontrun{ +#' HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) +#' #' yrSST <- sumSeries(HSST, #' p = "1960-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), #' fun = function(x) colMeans(x, na.rm = TRUE), @@ -56,369 +58,424 @@ #' ))[, 1:2] #' #' # Calculate trajectories -#' # The following throws an error due to the trajectories moving beyond the raster extent -#' traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50) -#' -#' # This accounts for the extent issue -#' traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) +#' traj <- voccTraj(lonlat, vel, ang, mn, tstep = 1/4, tyr = 50) #' } #' -voccTraj <- function(lonlat, - vel, ang, mn, - # vel_c, ang_c, mn_c, - #fine_coast, lk_up, - tstep, tyr = 50) { +voccTraj <- function(lonlat, # Starting points + vel, ang, mn, # Components of velocity: speed, angle and climatology + tstep, # Timestep (usually decimal year) + x_res = NULL, y_res = NULL, # Resolution of the grid at which velocity was computed + tyr = 20, # Number of years to run for + bfr = 75, + grid_resolution = "coarse", # Set to "fine" if you have disaggregated to original velocity field to a finer resolution + seed = NULL) { # Random seed for reproducibility + # Setup ------------------------------------------------------------------- - y_res <- x_res <- terra::res(vel)[1] # Set resolution of operations + # Validation checks using assertthat + assertthat::assert_that( + # lonlat must be a data.frame with at least 2 columns + is.data.frame(lonlat), + msg = "lonlat must be a data.frame" + ) + + assertthat::assert_that( + ncol(lonlat) >= 2, + msg = "lonlat must have at least 2 columns (longitude and latitude)" + ) + + assertthat::assert_that( + nrow(lonlat) > 0, + msg = "lonlat must contain at least one row" + ) + + assertthat::assert_that( + # vel, ang, and mn must be terra rasters + inherits(vel, "SpatRaster"), + msg = "vel must be a terra SpatRaster" + ) + + assertthat::assert_that( + inherits(ang, "SpatRaster"), + msg = "ang must be a terra SpatRaster" + ) + + assertthat::assert_that( + inherits(mn, "SpatRaster"), + msg = "mn must be a terra SpatRaster" + ) + + assertthat::assert_that( + # tstep must be positive numeric + is.numeric(tstep) && length(tstep) == 1 && tstep > 0, + msg = "tstep must be a positive numeric value" + ) + + assertthat::assert_that( + # x_res and y_res must be positive if provided + is.null(x_res) || (is.numeric(x_res) && length(x_res) == 1 && x_res > 0), + msg = "x_res must be a positive numeric value if provided" + ) + + assertthat::assert_that( + is.null(y_res) || (is.numeric(y_res) && length(y_res) == 1 && y_res > 0), + msg = "y_res must be a positive numeric value if provided" + ) + + assertthat::assert_that( + # When either x_res or y_res is given, the other must also be given + (is.null(x_res) && is.null(y_res)) || (!is.null(x_res) && !is.null(y_res)), + msg = "When either x_res or y_res is provided, both must be provided" + ) + + assertthat::assert_that( + # tyr must be positive numeric + is.numeric(tyr) && length(tyr) == 1 && tyr > 0, + msg = "tyr must be a positive numeric value" + ) + + assertthat::assert_that( + # bfr must be positive numeric + is.numeric(bfr) && length(bfr) == 1 && bfr > 0, + msg = "bfr must be a positive numeric value" + ) + + assertthat::assert_that( + # grid_resolution can only be "coarse" or "fine" + is.character(grid_resolution) && length(grid_resolution) == 1 && + grid_resolution %in% c("coarse", "fine"), + msg = "grid_resolution must be either 'coarse' or 'fine'" + ) + + assertthat::assert_that( + # When both x_res and y_res are NULL, grid_resolution must be "coarse" + !(is.null(x_res) && is.null(y_res)) || grid_resolution == "coarse", + msg = "When both x_res and y_res are NULL, grid_resolution must be 'coarse'" + ) + + assertthat::assert_that( + # seed must be numeric if provided + is.null(seed) || (is.numeric(seed) && length(seed) == 1), + msg = "seed must be a numeric value if provided" + ) + + if (is.null(x_res) | is.null(y_res)){ + vel_res <- terra::res(vel) + + x_res <- vel_res[1] + y_res <- vel_res[2] + + } + + + # Set seed for reproducibility if provided + if (!is.null(seed)) { + set.seed(seed) + } + + # A base raster with original resolution and extent + r_base <- terra::rast(res = c(x_res, y_res)) %>% + terra::crop(vel) - # Constrain max velocity to avoid stepping over grid squares - max_vel = 111.325*x_res/tstep - vel[vel > max_vel] <- max_vel - vel[vel < -max_vel] <- -max_vel - # vel_c[vel_c > max_vel] <- max_vel - # vel_c[vel_c < -max_vel] <- -max_vel + # MEMORY LEAK FIX: Don't modify original raster, work with values directly + max_vel <- 111.325 * x_res / tstep + vel_values <- terra::values(vel) + vel_values[vel_values > max_vel] <- max_vel + vel_values[vel_values < -max_vel] <- -max_vel + # Sort out start points lonlat <- lonlat %>% - dplyr::select(tidyselect::all_of(c("x", "y"))) %>% # Collect just lon and lat (in case there's anything else there) + dplyr::select("x", "y") %>% # Collect just lon and lat (in case there's anything else there) as.data.frame() + # Get initial descriptors tcells <- terra::cellFromXY(vel, lonlat) # # Cell IDs of starting cells n <- nrow(lonlat) # Get number of cells in your sequence - sflags <- rep(NA, n) # Set a string of cells that change from NA to 1 where the trajectory sticks - - # Set up variables to catch results, allocating the right amount of memory - llon <- numeric((n * tyr / tstep) + n) # Needs to have a set of starting lons, plus one more set for each time step - llat <- numeric((n * tyr / tstep) + n) # Needs to have a set of starting lats, plus one more set for each time step - # cellIDs <- rep(tcells, ((tyr / tstep) + 1)) # Needs to have a set of starting cells, plus one more set for each time step—just as a reference - cellIDs <- rep(1:n, ((tyr / tstep) + 1)) # Needs to have a set of starting cells, plus one more set for each time step—just as a reference - cellIDend <- numeric((n * tyr / tstep) + n) # Needs to have a set of ending cells, plus one more set for each time step - # coast <- llon != 0 # Needs to have a set of starting coastal flags, plus one more set for each time step...set up as boolean - flags <- numeric((n * tyr / tstep) + n) # Needs to have a set of starting flags, plus one more set for each time step - Steps <- numeric((n * tyr / tstep) + n) # Needs to have a set of starting steps, plus one more set for each time step - - # Populate the first n slots with starting points - llon[1:n] <- lonlat[,1] - llat[1:n] <- lonlat[,2] - cellIDend[1:n] <- tcells - # coast[1:n] <- scoast - flags[1:n] <- NA - Steps[1:n] <- 0 - - # Get coarse cellIDs that exist in fine raster - # fn_lk_up <- lk_up[] %>% - # na.omit() %>% - # unique() - - # Helper functions -------------------------------------------------------- - - # Trajectory helper functions - - # Function for to grep min distance - mfind <- function(rw){ - X <- which.min(rw) - return(X) - } - # Function for to extract corner coordinates per row - mplace <- function(rw){ - X <- rw[(rw[1]+1)] - Y <- rw[rw[1]] - return(c(X, Y)) - } + # OPTIMIZATION: Use the already constrained vel_values and extract ang_values + ang_values <- terra::values(ang) + mn_values <- terra::values(mn) # Pre-extract mn values too - # Simple circular functions - deg2rad <- function(deg) return(deg*pi/180) - rad2deg <- function(rad) return(180*rad/pi) - - # A function to find the nearest coastal cell - get_nearest_coastal_cell <- function(x, y, tccell, lk_up, ...) { # JDE added lk_up to arguments - t_block <- which(lk_up[] == tccell) # The cellIDs of lk_up - cst_pts <- terra::xyFromCell(lk_up, t_block) %>% - as.data.frame() %>% - sf::st_as_sf(coords = c("x", "y"), crs = terra::crs(terra::rast())) - # Here, we can't search for corners and add random "fuzz" to we collect 10 random points (if there are 10), and select the nearest of those, instead. If there are 10 or fewer, just pick the nearest - if(nrow(cst_pts) > 10) { - cst_pts <- cst_pts[sample(1:nrow(cst_pts), 10, replace = FALSE),] - } # The unspoken "else" is that we just retain the cst_pts we have - pt <- sf::st_as_sf(data.frame(x = x, y = y), coords = c("x", "y"), crs = terra::crs(terra::rast())) # The point departed from - nearest <- sf::st_distance(cst_pts, pt) %>% - which.min() - out <- cst_pts[nearest,] %>% - sf::st_coordinates() %>% - as.data.frame() %>% - dplyr::rename(x = 1, y = 2) - return(out) - } + # MEMORY OPTIMIZATION: Pre-allocate list structure (not content) to avoid dynamic growth + # This creates a list of NULL pointers - no contiguous memory required + max_steps <- ceiling(tyr / tstep) + 1 # Maximum possible steps + initial - # Find new destination, given velocity (km/yr), angle (º), time step (yr) and initial coordinates (ºlon, ºlat); max allowed jump is 1 deg - # vell = vel[fcells] %>% pull(1); angg = ang[fcells] %>% pull(1); timestep = tstep; ll = llold - destcoords <- function(vell, angg, timestep, ll, y_res, x_res){ - - latshift <- (abs(vell) * timestep * cos(deg2rad(angg))) / 111.325 # Calculate shift in lat - latnew <- ll[,2] + latshift # Find new lat...first approximation - lonshift <- (abs(vell) * timestep * sin(deg2rad(angg))) / (111.325 * cos(deg2rad(latnew))) # Shift in lon - # Limit large longitudinal jumps at high latitudes - - # Because we constrain velocity to be no more than 12 * y_res, all problems will be with lonshift - # Limit lonshift to at most 1 cell - lonshift[lonshift > x_res] <- x_res - lonshift[lonshift < -x_res] <- -x_res - - # Now on that basis, adjust latshift - x_gt <- which(lonshift == x_res) # Indices for adjusted lon shifts - latshift[x_gt] <- ((x_res*111.325 * cos(deg2rad(ll[x_gt,2])))/tan(deg2rad(angg[x_gt])))/111.325 # Using trig on distances - x_lt <- which(lonshift == -x_res) # Indices for adjusted lon shifts - latshift[x_lt] <- ((x_res*111.325 * cos(deg2rad(ll[x_lt,2])))/tan(deg2rad(angg[x_lt])))/111.325 # Using trig on distances - latnew <- ll[,2] + latshift # Find new lat by adding the adjusted lats - # Stop new lat from jumping the poles - latnew[latnew > 90] <- 90 - latnew[latnew < -90] <- -90 - # Adjust lon - lonnew <- ll[,1] + lonshift # Find new lon...first approximation - # Adjust for dateline jumps - lonnew <- lonnew - (360 * floor((lonnew + 180) / 360)) - return(data.frame(lonnew, latnew) %>% - stats::setNames(c("dlon", "dlat"))) - } + # Pre-allocate list structure only - each element will be allocated independently + llon <- vector("list", max_steps) + llat <- vector("list", max_steps) + cellIDend <- vector("list", max_steps) + Steps <- vector("list", max_steps) + cellIDs <- vector("list", max_steps) + trajIDs <- vector("list", max_steps) - # Function for to find closest cooler/warmer cell within the union of two levels of 8-cell adjacency from the "departed" and "destination" cells - # TODO JDE - The arguments are not correct. Only 1, but it should include. `mn` - get_dest_cell <- function(rw) { # A to-from cell pair and the buffer around a cell on land that can be searched for a suitable cell + # Populate the first slots with starting points + cellIDs[[1]] <- tcells + trajIDs[[1]] <- 1:n + llon[[1]] <- lonlat[, 1] + llat[[1]] <- lonlat[, 2] + cellIDend[[1]] <- tcells + Steps[[1]] <- rep(0, n) + # Set up objects that keep track of things + sflags <- rep(NA, n) + trj_id <- trajIDs[[1]] - x_res <- terra::res(mn)[1] - y_res <- terra::res(mn)[2] - # Find clumps of ocean; the rule is that you can't jump from one clump to another, because this would mean passing over unbroken land - xy <- terra::xyFromCell(mn, as.vector(as.matrix(rw))) %>% - as.data.frame() + # Loop -------------------------------------------------------------------- + # Loop through the trajectories + n_steps <- ceiling(tyr / tstep) - bfr = ((y_res*111.325) + 1) * 1000 # Set buffer to be 1 grid-square width at the equator + 1 km + # Add safety check for reasonable number of steps + if (n_steps > 1000) { + warning("Large number of trajectory steps (", n_steps, "). Consider reducing tyr or increasing tstep.") + } - xy <- xy %>% - sf::st_as_sf(coords = c("x", "y"), crs = "EPSG:4326") + # Track actual steps used for efficient final processing + actual_steps_used <- 1 # Start with 1 (initial step) - sp_buffer <- sf::st_buffer(sf::st_as_sf(xy), bfr) # Remembering that buffer is in metres + for (i in seq_len(n_steps)) { - buffer_zone <- terra::extract(mn, sp_buffer, cells = TRUE, xy = TRUE, touches = TRUE) %>% - dplyr::select(-"ID") %>% - dplyr::distinct() %>% - dplyr::rename(sst = mean) %>% # JDE Changed from climatology to mean - dplyr::select(tidyselect::all_of(c("x", "y", "sst", "cell"))) %>% - tidyr::drop_na(.data$sst) + # Safety check: if no trajectories remain, break early + if (nrow(lonlat) == 0) { + message("All trajectories terminated at step ", i-1) + break + } - # JDE Changes. When all cells are in a straight line (only 1 unique x or y), - # rast() will not work. So here we add a more robust approach to creating - # a rast() regardless of the data + llold <- lonlat # Take a copy of lonlat - # clumped <- buffer_zone %>% - # dplyr::select(-cell) %>% - # rast(crs = "EPSG:4326") %>% - # terra::patches(directions = 8, allowGaps = FALSE) + # OPTIMIZATION: Get cell IDs first, then extract values by indexing (much faster) + fcells <- terra::cellFromXY(vel, llold) # Get the cells that the trajectories start in + # MEMORY LEAK FIX: Add bounds checking to prevent invalid indexing + valid_fcells <- !is.na(fcells) & fcells > 0 & fcells <= length(vel_values) + if (!any(valid_fcells)) { + message("All trajectories moved out of bounds at step ", i) + break + } - clumped_rast <- terra::rast( - xmin = min(buffer_zone$x) - x_res/2, - xmax = max(buffer_zone$x) + x_res/2, - ymin = min(buffer_zone$y) - y_res/2, - ymax = max(buffer_zone$y) + y_res/2, - resolution = c(x_res, y_res), - crs = "EPSG:4326" - ) + # Extract values by direct indexing (much faster than terra::extract) + vell <- vel_values[fcells[valid_fcells]] + angg <- ang_values[fcells[valid_fcells]] - clumped <- terra::rasterize( - x = buffer_zone %>% # Needs to be SpatVector to add the sst - dplyr::select(-"cell") %>% - terra::vect(geom = c("x", "y"), crs = "EPSG:4326"), - y = clumped_rast, # The template to rasterize onto - field = "sst") %>% # The data - terra::patches(directions = 8, allowGaps = FALSE) + # Update tracking variables for valid cells only + if (!all(valid_fcells)) { + llold <- llold[valid_fcells, , drop = FALSE] + fcells <- fcells[valid_fcells] + trj_id <- trj_id[valid_fcells] + sflags <- sflags[valid_fcells] + } - # JDE END CHANGES + # Get new locations + lonlat <- destcoords(vell, angg, tstep, llold, y_res, x_res) # Extract lon and lat of landing point + tcells <- terra::cellFromXY(vel, lonlat) # Get the cells that the trajectories end in + sflags[which(is.na(tcells))] <- 1 # Sets the trajectory to "stuck" if it exits the velocity field (i.e., tcells == NA) + + # Remove out-of-bounds cells + in_bounds <- which(is.na(sflags)) + llold <- llold[in_bounds, ] + fcells <- fcells[in_bounds] + lonlat <- lonlat[in_bounds, ] + tcells <- tcells[in_bounds] + sflags <- sflags[in_bounds] + trj_id <- trj_id[in_bounds] + + # MEMORY LEAK FIX: Use pre-extracted values instead of raster indexing + onland <- which(is.na(vel_values[tcells])) + + if (length(onland) > 0) { # Only bother if there is at least one cell that returns a NA velocity = land + if (grid_resolution == "fine") { #*** Fine switch + + # Collect the stuff we need here for cells that are onland + fpos <- llold[onland, ] + tpos <- lonlat[onland, ] + SFlags <- sflags[onland] + fcell <- fcells[onland] + tcell <- tcells[onland] + + ft <- data.frame(fcell = fcell, + tcell = tcell, + fx = purrr::pluck(fpos, 1), + fy = purrr::pluck(fpos, 2), + code = paste(fcell, tcell, sep = " "), + ref = 1:length(fcell)) + + # MEMORY LEAK FIX: Pass values instead of full raster objects + ttcell <- apply(ft[, 1:4], 1, get_dest_cell_fine, x_res = x_res, y_res = y_res, bfr = bfr, + vel_values = vel_values, mn_values = mn_values, vel_raster = vel, mn_raster = mn) + + # Filter "stuck" flags here + stuck <- which(is.na(ttcell)) # This is set in get_dest_cell(), where no cell in the "catchment" has a suitable sst to facilitate movement + unstuck <- which(!is.na(ttcell)) + SFlags[stuck] <- 1 # Adjust flags + + # Make data frame to catch data needed to find new positions + ttpos <- data.frame(x = rep(NA, length(onland)), y = rep(NA, length(onland))) + ttpos[stuck, ] <- fpos[stuck, ] # If they're stuck, pass on starting points + ttcell[stuck] <- fcell[stuck] # If they're stuck, pass on starting cells + + ttpos[unstuck, ] <- terra::xyFromCell(mn, ttcell[unstuck]) + + # Collect results + lonlat[onland, ] <- ttpos + tcells[onland] <- ttcell + sflags[onland] <- SFlags + } else { + # Old onland loop here + # Collect the stuff we need here + fpos <- llold[onland, ] + tpos <- lonlat[onland, ] + SFlags <- sflags[onland] + fcell <- fcells[onland] + tcell <- tcells[onland] + + # ft <- data.frame(fcell = fcell, tcell = tcell, code = paste(fcell, tcell, sep = " "), ref = 1:length(fcell)) + # ttcell <- apply(ft[,1:2], 1, get_dest_cell) + ft <- data.frame( + fcell = fcell, tcell = tcell, + fx = fpos %>% purrr::pluck(1), + fy = fpos %>% purrr::pluck(2), + code = paste(fcell, tcell, sep = " "), ref = 1:length(fcell) + ) + # MEMORY LEAK FIX: Pass values instead of full raster objects + ttcell <- apply(ft[, 1:4], 1, get_dest_cell_coarse, x_res = x_res, y_res = y_res, bfr = bfr, + vel_values = vel_values, mn_values = mn_values, vel_raster = vel, mn_raster = mn) + + # Filter "stuck" flags here + stuck <- which(is.na(ttcell)) # This is set in get_dest_cell(), where no cell in the "catchment" has a suitable sst to facilitate movement + unstuck <- which(!is.na(ttcell)) + SFlags[stuck] <- 1 # Adjust flags + + # Make data frame to catch data needed to find new positions #***done up to here + ttpos <- data.frame(x = rep(NA, length(onland)), y = rep(NA, length(onland))) + ttpos[stuck, ] <- fpos[stuck, ] # If they're stuck, pass on starting points + ttcell[stuck] <- fcell[stuck] # If they're stuck, pass on starting cells + if (length(unstuck) > 0) { + tt_original_cells <- terra::cellFromXY(mn, fpos[unstuck, ]) # Departure cells in the resolution of the original velocity field + ttdat <- tibble::tibble(ttcell = ttcell[unstuck]) %>% # Destination cells (nearest cell with appropriate sst) + dplyr::mutate( + loncent = terra::xFromCell(mn, ttcell), # Coordinates of destination cell + latcent = terra::yFromCell(mn, ttcell) + ) %>% # Coordinates of destination cell + dplyr::mutate(e = NA, w = NA, n = NA, s = NA, dlon = NA, dlat = NA) # To facilitate finding corners of the cells + corner_block_size <- 0.25 * x_res # The "corner" is set to 0.25 of the grid square at the original resolution + + # Send trajectory to the nearest corner of the appropriate cell, where corner is a quarter of the grid size. Position is "fuzzed" within this corner at random. + # Use reproducible random numbers for package checking + n_points <- nrow(ttdat) #TODO Check that this is still 1. Not sure why we need it. + ttdat$e <- ttdat$loncent + (0.5 * x_res) - (stats::runif(n_points, -1, 1) * corner_block_size) # The centre of the "corner" +- random fuzz... + ttdat$w <- ttdat$loncent - (0.5 * x_res) + (stats::runif(n_points, -1, 1) * corner_block_size) # The centre of the "corner" +- random fuzz... + ttdat$n <- ttdat$latcent + (0.5 * y_res) - (stats::runif(n_points, -1, 1) * corner_block_size) # The centre of the "corner" +- random fuzz... + ttdat$s <- ttdat$latcent - (0.5 * y_res) + (stats::runif(n_points, -1, 1) * corner_block_size) # The centre of the "corner" +- random fuzz... + coords <- with(ttdat, cbind(n, e, n, w, s, w, s, e)) # NE, NW, SW, SE corners' coordinates + + corners <- data.frame(ne = get_dist(fpos[unstuck, 2], fpos[unstuck, 1], coords[, 1], coords[, 2])) %>% + dplyr::mutate( + nw = get_dist(fpos[unstuck, 2], fpos[unstuck, 1], coords[, 3], coords[, 4]), + sw = get_dist(fpos[unstuck, 2], fpos[unstuck, 1], coords[, 5], coords[, 6]), + se = get_dist(fpos[unstuck, 2], fpos[unstuck, 1], coords[, 7], coords[, 8]) + ) + + # Select nearest corner + cornset <- apply(corners, 1, mfind) * 2 # Identify which corners for each onland cell. Have to mul by 2 to shift along correctly. + cornset <- cbind(cornset, coords) # Add in coordinates + ttdat[, 8:9] <- data.frame(t(apply(cornset, 1, mplace))) # Add in coordinates of correct corner point + ttpos[unstuck, ] <- terra::xyFromCell(mn, ttcell[unstuck]) + ttcell[unstuck] <- terra::cellFromXY(mn, ttpos[unstuck, ]) + } - # Which clump did I start in? - r1 <- rw[1] %>% - as.vector() # We use this cell a lot, so let's just make it an object + # Collect results + lonlat[onland, ] <- ttpos + tcells[onland] <- ttcell + sflags[onland] <- SFlags + } + } - from_clump <- terra::extract(clumped, terra::xyFromCell(mn, r1)) %>% - unlist() %>% - as.vector() + # Pass on only those cells that are not stuck + # if(sum(is.na(lonlat[,1])) > 0) {break} + cells_to_keep <- which(is.na(sflags)) + lonlat <- lonlat[cells_to_keep, ] + + # MEMORY OPTIMIZATION: Direct assignment to pre-allocated list slots + # Each element is stored independently - no contiguous memory required + step_index <- i + 1 + llon[[step_index]] <- lonlat[, 1] + llat[[step_index]] <- lonlat[, 2] + cellIDs[[step_index]] <- fcells[cells_to_keep] + cellIDend[[step_index]] <- tcells[cells_to_keep] + Steps[[step_index]] <- rep(i, length(tcells[cells_to_keep])) + trajIDs[[step_index]] <- trj_id[cells_to_keep] + + # Update tracking variables + sflags <- sflags[cells_to_keep] + trj_id <- trj_id[cells_to_keep] + actual_steps_used <- step_index + + # Progress reporting - only in interactive sessions or when explicitly requested + if (interactive() && getOption("VoCC.verbose", FALSE)) { + message("Step ", i, "/", tyr/tstep, " (", round(100 * i / (tyr / tstep), 1), "%) - ", + length(onland), " cells on land - ", Sys.time()) + } - # What are the coordinates of cells within the search area that fall in the clump I came from? - search_xy <- terra::xyFromCell(clumped, which(clumped[] == from_clump)) %>% - as.data.frame() #**** - search_cells <- terra::cellFromXY(mn, search_xy) # Which cells are these + } - # Check if any of these are NOT in in EITHER fine coast or mn, and eliminate, if needed - to_keep <- c(which(!is.na(terra::extract(mn, search_xy, ID = FALSE) %>% - dplyr::pull(1)))) %>% #, # Coords in the coarse grid - # which(search_cells %in% fn_lk_up)) %>% - unique() + # MEMORY LEAK FIX: Clean up large objects before final processing + rm(vel_values, ang_values, mn_values) + + # MEMORY OPTIMIZATION: Only process used slots and clean up progressively + # Trim to actual used length - unused slots remain as NULL (minimal memory) + if (actual_steps_used < max_steps) { + llon <- llon[1:actual_steps_used] + llat <- llat[1:actual_steps_used] + Steps <- Steps[1:actual_steps_used] + trajIDs <- trajIDs[1:actual_steps_used] + cellIDs <- cellIDs[1:actual_steps_used] + cellIDend <- cellIDend[1:actual_steps_used] + } - search_xy1 <- search_xy[to_keep,] %>% - as.data.frame() %>% - dplyr::distinct() + # MEMORY LEAK FIX: Progressive cleanup to minimize peak memory usage + # Each unlist operation works on independent memory chunks + steps_vec <- unlist(Steps, use.names = FALSE) + rm(Steps) - # Get the ssts in the cells to search - or <- terra::extract(mn, search_xy1, cells = TRUE, xy = TRUE) %>% - dplyr::rename(sst = 2, x = 4, y = 5) + lon_vec <- unlist(llon, use.names = FALSE) + rm(llon) + lat_vec <- unlist(llat, use.names = FALSE) + rm(llat) - # If velocity is positive, find nearest cell that is cooler, if there is one - if(unlist(vel[r1]) > 0) { - o <- or %>% - dplyr::filter(.data$sst < unlist(mn[r1])) %>% - na.omit() - if(nrow(o) == 0) { - dest_cell <- NA # Set condition with which to ID stuck cells - } else { - pt <- terra::xyFromCell(mn, r1) %>% - data.frame() + id_vec <- unlist(trajIDs, use.names = FALSE) + rm(trajIDs) - dest_cell <- sf::st_distance(sf::st_as_sf(pt, coords = c("x", "y"), crs = terra::crs(terra::rast())), - sf::st_as_sf(data.frame(o), coords = c("x", "y"), crs = terra::crs(terra::rast()))) %>% - which.min() %>% - o$cell[.] - } - } else { # Otherwise, find nearest cell that is warmer, if there is one - o <- or %>% - dplyr::filter(.data$sst > unlist(mn[r1])) %>% - na.omit() - if(nrow(o) == 0) { - dest_cell <- NA # Set condition with which to ID stuck cells - } else { - pt <- terra::xyFromCell(mn, r1) %>% - data.frame() + start_cell_vec <- unlist(cellIDs, use.names = FALSE) + rm(cellIDs) - dest_cell <- sf::st_distance(sf::st_as_sf(pt, coords = c("x", "y"), crs = terra::crs(terra::rast())), - sf::st_as_sf(o, coords = c("x", "y"), crs = terra::crs(terra::rast()))) %>% - which.min() %>% - o$cell[.] - } - } - return(dest_cell) - } + end_cell_vec <- unlist(cellIDend, use.names = FALSE) + rm(cellIDend) - # Loop -------------------------------------------------------------------- + # Create final result with cleaned vectors + result <- tibble::tibble( + Steps = steps_vec, + lon = lon_vec, + lat = lat_vec, + ID = id_vec, + start_cell = start_cell_vec, + end_cell = end_cell_vec + ) - # Loop through the trajectories - for(i in 1:(tyr/tstep)) { # 1:(tyr/tstep) - llold <- lonlat # Take a copy of lonlat - fcells <- terra::cellFromXY(vel,llold) # Get the cells that the trajectories start in + # Clean up final vectors + rm(steps_vec, lon_vec, lat_vec, id_vec, start_cell_vec, end_cell_vec) - # Pull velocity and angle from the "inland" versions, because we always ensure that we can find destination cells for departures within the coastal "blind spot" - # TIN: changed this from vel_c to vel and ang_c to ang because we don't have coarse/fine versions - vc <- vel[fcells] %>% dplyr::pull(1) - ac <- ang[fcells] %>% dplyr::pull(1) - llc <- llold + # Clean up any remaining large objects from the loop + if (exists("lonlat")) rm(lonlat) + if (exists("llold")) rm(llold) + if (exists("fcells")) rm(fcells) + if (exists("tcells")) rm(tcells) + if (exists("sflags")) rm(sflags) + if (exists("trj_id")) rm(trj_id) - # Get new locations - lonlat <- destcoords(vc, ac, tstep, llc, y_res, x_res) # Extract lon and lat of landing point - tcells <- terra::cellFromXY(vel,lonlat) # Get the cells that the trajectories end in - sflags[which(is.na(tcells))] <- 1 # Sets the trajectory to "stuck" if it exits the velocity field (i.e., tcells == NA) - - # Bounce stuck cells - stuck_cells <- which(!is.na(sflags)) - lonlat[stuck_cells,] <- llold[stuck_cells,] # Bounce the corresponding coordinates across for "stuck" cells - tcells[stuck_cells] <- fcells[stuck_cells] # Bounce the corresponding cells across for "stuck" cells - - # Deal with cells that end on land - onland <- which(is.na(vel[tcells])) %>% # Identify which rows of velend are on land, provided that they are not stuck - dplyr::setdiff(stuck_cells) # Ignoring stuck cells - - # if(length(onland) > 0){ # Only bother if there is at least one cell that returns a NA velocity = land - # Here, you need to check whether it really *IS* on land, or whether it is just in the coastal "blind spot" - # fn <- terra::extract(fine_coast, lonlat[onland,], ID = FALSE) %>% - # pull(1) - # onland <- onland[which(is.na(fn))] - if(length(onland) > 0) { - # Collect the stuff we need here for cells that are really onland - fpos <- llold[onland,] - tpos <- lonlat[onland,] - SFlags <- sflags[onland] - fcell <- fcells[onland] - tcell <- tcells[onland] - ft <- data.frame(fcell = fcell, tcell = tcell, code = paste(fcell, tcell, sep = " "), ref = 1:length(fcell)) - - # Get the destination cells of those that are hitting the coast - ttcell <- apply(ft[,1:2], 1, get_dest_cell) # TODO using apply in places and map in others. Can we consistently move to purrr? - - # Filter "stuck" flags here - stuck <- which(is.na(ttcell)) - unstuck <- which(!is.na(ttcell)) - SFlags[stuck] <- 1 # Adjust flags - - # Make data frame to catch data needed to find new positions - ttpos <- data.frame(x = rep(NA, length(onland)), y = rep(NA, length(onland))) - ttpos[stuck,] <- fpos[stuck,] # If they're stuck, pass on starting points - ttcell[stuck] <- fcell[stuck] # If they're stuck, pass on starting cells - - if(length(unstuck) > 0) { - ttdat <- data.frame(ttcell = ttcell[unstuck], - loncent = terra::xFromCell(vel, ttcell[unstuck]), - latcent = terra::yFromCell(vel, ttcell[unstuck])) %>% # Start building coordinates - dplyr::mutate(e = NA, w = NA, n = NA, s = NA, dlon = NA, dlat = NA) # To facilitate finding corners, if we need them - - # Separate cells in the coastal blind spot from those that are not - # which_coast <- which(ttdat$ttcell %in% fn_lk_up) - # which_not_coast <- which(!(ttdat$ttcell %in% fn_lk_up)) - # For non-coastal cells - - idx <- 1:nrow(ttdat) - - if(nrow(ttdat) > 0) { - corner_block_size <- 0.25*x_res - nc_ttdat <- ttdat # Copying data - nc_ttdat$e <- nc_ttdat$loncent + (0.5 * x_res) - (stats::runif(1, 0, 1) * corner_block_size) - nc_ttdat$w <- nc_ttdat$loncent - (0.5 * x_res) + (stats::runif(1, 0, 1) * corner_block_size) - nc_ttdat$n <- nc_ttdat$latcent + (0.5 * y_res) - (stats::runif(1, 0, 1) * corner_block_size) - nc_ttdat$s <- nc_ttdat$latcent - (0.5 * y_res) + (stats::runif(1, 0, 1) * corner_block_size) - coords <- with(nc_ttdat, cbind(n, e, n, w, s, w, s, e)) # NE, NW, SW, SE corners' coordinates - # Find distances from departure point to corners of ttcell - get_dist <- function(y1, x1, y2, x2) { - pt1 <- sf::st_as_sf(data.frame(x = x1, y = y1), coords = c("x", "y"), crs = terra::crs(terra::rast())) - pt2 <- sf::st_as_sf(data.frame(x = x2, y = y2), coords = c("x", "y"), crs = terra::crs(terra::rast())) - out <- sf::st_distance(pt1, pt2, by_element = TRUE) %>% - as.vector() - return(out) - } - - corners <- data.frame(ne = get_dist(fpos[idx,2], fpos[idx,1], coords[,1], coords[,2])) %>% - dplyr::mutate(nw = get_dist(fpos[idx,2], fpos[idx,1], coords[,3], coords[,4]), - sw = get_dist(fpos[idx,2], fpos[idx,1], coords[,5], coords[,6]), - se = get_dist(fpos[idx,2], fpos[idx,1], coords[,7], coords[,8])) - cornset <- apply(corners, 1, mfind)*2 # Identify which corners for each onland cell. Have to mul by 2 to shift along correctly. - cornset <- cbind(cornset, coords) # Add in coordinates - ttdat[,8:9] <- data.frame(t(apply(cornset, 1, mplace))) # Extract coordinates of correct corner - } - # # For coastal cells - # if(length(which_coast) > 0) { - # coastal_dat <- ttdat[which_coast,2:3] %>% - # mutate(x = fpos[which_coast,1], y = fpos[which_coast,2], - # tccell = ttdat[which_coast,]$ttcell) - # # JDE TODO - Argument to get_nearest_coast_cell are not correct - `get_nearest_coastal_cell <- function(x, y, tccell, lk_up, ...)` - # ttdat[which_coast,8:9] <- pmap_df(coastal_dat, get_nearest_coastal_cell) - # } - ttpos[unstuck,] <- ttdat[,8:9] - ttcell[unstuck] <- terra::cellFromXY(mn, ttpos[unstuck,]) - } - # Collect results - lonlat[onland,] <- ttpos - tcells[onland] <- ttcell - sflags[onland] <- SFlags - } - # } - llon[((i * n) + 1): ((i * n) + n)] <- lonlat[,1] # Add lon to the list - llat[((i * n) + 1): ((i * n) + n)] <- lonlat[,2]# Add lat to the list - cellIDend[((i * n) + 1): ((i * n) + n)] <- tcells # Add cellIDs to the list - flags[((i * n) + 1): ((i * n) + n)] <- sflags # Add flags to the list - Steps[((i * n) + 1): ((i * n) + n)] <- i # Capture the time_step - # print(c(i, length(onland), round(100*i/(tyr/tstep), 3), date())) # Keep a reference of progress + # Force garbage collection to free memory immediately + gc() - } - return(cbind(Steps, llon, llat, cellIDs, cellIDend, flags) %>% - tibble::as_tibble()) + return(result) } - diff --git a/data-raw/DATASET.R b/data-raw/DATASET.R index 2a25e19..e2a0bc0 100644 --- a/data-raw/DATASET.R +++ b/data-raw/DATASET.R @@ -4,8 +4,9 @@ # Use the existing ones for now. I will speak to Jorge. load("data-raw/EEZ.RData") -EEZ <- terra::vect(EEZ) -terra::writeVector(EEZ, filename = "inst/extdata/EEZ.gpkg", overwrite = TRUE) +EEZ <- sf::st_as_sf(EEZ) %>% + sf::st_make_valid() %>% + sf::st_write("inst/extdata/EEZ.gpkg", append = FALSE) load("data-raw/HSST.RData") HSST <- terra::rast(HSST) diff --git a/docs/articles/VoCC.html b/docs/articles/VoCC.html index 7792bf8..f65f866 100644 --- a/docs/articles/VoCC.html +++ b/docs/articles/VoCC.html @@ -287,17 +287,17 @@

# prepare raster layers vel <- gv[[1]] ang <- gv[[2]] -mn <- app(r, mean, na.rm = T) +mn <- terra::app(r, mean, na.rm = T) # generate a velocity layer centered and cropped to study region to extract the initial coordinates for the trajectories from -x1 <- crop(gv[[1]], ext(-180, 0, -90, 90)) -x2 <- crop(gv[[1]], ext(0, 180, -90, 90)) -ext(x1) <- c(180, 360, -90, 90) -velc <- merge(x1, x2) +x1 <- terra::crop(gv[[1]], terra::ext(-180, 0, -90, 90)) +x2 <- terra::crop(gv[[1]], terra::ext(0, 180, -90, 90)) +terra::ext(x1) <- c(180, 360, -90, 90) +velc <- terra::merge(x1, x2) # crop to the desired extent # display restricted to +180 longitude to avoid plotting issues with date line crossing -velc <- crop(velc, c(90, 180, -32, 33)) +velc <- terra::crop(velc, c(90, 180, -32, 33))

We can now populate the data frame with the cell centroid coordinates for the trajectories.

@@ -312,14 +312,15 @@ 

 
-traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, tstep = 1/12)

+traj <- voccTraj(lonlat, vel, ang, mn, x_res = terra::res(vel)[1], y_res = terra::res(vel)[2], tyr = 50, tstep = 1/12)

Plot them over the climate velocities and the EEZ polygons from the EEZs data set (Fig. 3a in Garcia Molinos et al. 2019)

 # create the spatial object with the trajectories and plot them together with the EEZ polygons
-lns <- map(traj %>% group_split(cellIDs), trajLine) %>% 
-  purrr::list_rbind() %>% 
-  sf::st_sf()
+lns <- trajLine(traj)
+
+# mirai::daemons(0) # Set daemons to 0 to close cluster
+
 
 # Load and simplify polygons to speed plotting up
 EEZs <- sf::st_read(system.file("extdata", "EEZs.gpkg", package = "VoCCdata")) %>% 
@@ -348,7 +349,6 @@ 

 # classify trajectories (16 trajectories starting from each 1-deg cell cell)
 clas <- trajClas(traj25, vel, ang, mn, trajSt = 16, tyr = 50, nmL = 20, smL = 100, Nend = 45, Nst = 15, NFT = 70)
-#> Warning: [readValues] raster has no values
 
 # Extract proportions by categories for each EEZ
 v <- data.table(terra::extract(clas[[7]], EEZs, df = TRUE))
diff --git a/docs/articles/VoCC_files/figure-html/unnamed-chunk-10-1.png b/docs/articles/VoCC_files/figure-html/unnamed-chunk-10-1.png
index 42fadce..f897f17 100644
Binary files a/docs/articles/VoCC_files/figure-html/unnamed-chunk-10-1.png and b/docs/articles/VoCC_files/figure-html/unnamed-chunk-10-1.png differ
diff --git a/docs/articles/VoCC_files/figure-html/unnamed-chunk-14-1.png b/docs/articles/VoCC_files/figure-html/unnamed-chunk-14-1.png
index 8522263..9b9abf9 100644
Binary files a/docs/articles/VoCC_files/figure-html/unnamed-chunk-14-1.png and b/docs/articles/VoCC_files/figure-html/unnamed-chunk-14-1.png differ
diff --git a/docs/articles/VoCC_files/figure-html/unnamed-chunk-9-1.png b/docs/articles/VoCC_files/figure-html/unnamed-chunk-9-1.png
index 2ff7b8f..14967c3 100644
Binary files a/docs/articles/VoCC_files/figure-html/unnamed-chunk-9-1.png and b/docs/articles/VoCC_files/figure-html/unnamed-chunk-9-1.png differ
diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml
index ca99e68..3abb57c 100644
--- a/docs/pkgdown.yml
+++ b/docs/pkgdown.yml
@@ -3,4 +3,4 @@ pkgdown: 2.1.3
 pkgdown_sha: ~
 articles:
   VoCC: VoCC.html
-last_built: 2025-09-02T04:58Z
+last_built: 2025-09-15T02:48Z
diff --git a/docs/reference/check_mirai_daemons.html b/docs/reference/check_mirai_daemons.html
new file mode 100644
index 0000000..15db6f1
--- /dev/null
+++ b/docs/reference/check_mirai_daemons.html
@@ -0,0 +1,78 @@
+
+Check for mirai daemons and provide a helpful message. — check_mirai_daemons • VoCC
+    Skip to contents
+
+
+    
+
+
+ +
+

This utility function checks the status of `mirai` daemons. If no +daemons are found, it prints a user-friendly message explaining that +parallel processing will not be active and provides a suggestion to the user +on how to launch them.

+
+ +
+

Usage

+
check_mirai_daemons()
+
+ +
+

Value

+

NULL, invisibly. This function is called for its side effects.

+
+ +
+ + +
+ + + +
+ + + + + + + diff --git a/docs/reference/trajLine.html b/docs/reference/trajLine.html index 23dd357..f430ac4 100644 --- a/docs/reference/trajLine.html +++ b/docs/reference/trajLine.html @@ -58,7 +58,7 @@

Arguments

Value

-

A SpatialLinesDataFrame with one line per trajectory as specified in x. +

A sf object with one line per trajectory as specified in x. To avoid artifacts, trajectories crossing the date line need to be split into two segments. Where the trajectory on one side of the date line is only composed of a single point, the trajectory won't be displayed (no line object created). The function assumes diff --git a/docs/reference/voccTraj.html b/docs/reference/voccTraj.html index 177a874..c1d36e3 100644 --- a/docs/reference/voccTraj.html +++ b/docs/reference/voccTraj.html @@ -51,7 +51,18 @@

Climate velocity trajectories

Usage

-
voccTraj(lonlat, vel, ang, mn, tstep, tyr = 50)
+
voccTraj(
+  lonlat,
+  vel,
+  ang,
+  mn,
+  x_res,
+  y_res,
+  tstep,
+  tyr = 20,
+  bfr = 75,
+  grid_resolution = "coarse"
+)
@@ -75,14 +86,30 @@

Argumentsx_res +

Numeric. Resolution of the grid in longitude direction (degrees or km).

+ + +
y_res
+

Numeric. Resolution of the grid in latitude direction (degrees or km).

+ + +
tstep
+

Numeric. Timestep for each trajectory iteration (usually decimal year).

+ +
tyr
-

integer temporal length of the period of interest.

+

Integer. Temporal length of the period of interest (years).

+ + +
grid_resolution
+

Character. "coarse" (default) or "fine". Controls how land crossings are handled and allows for higher resolution grids.

Value

-

a data.frame containing the coordinates ("x", "y") of the constituent -points and identification number ("trajIDs") for each trajectory.

+

a tibble containing the coordinates ("lon", "lat") of the constituent +points, time step ("Steps"), identification number ("ID") for each trajectory, and cell IDs for start and end cells.

References

diff --git a/docs/search.json b/docs/search.json index 98f4fc1..d6755be 100644 --- a/docs/search.json +++ b/docs/search.json @@ -1 +1 @@ -[{"path":"/LICENSE.html","id":null,"dir":"","previous_headings":"","what":"GNU Affero General Public License","title":"GNU Affero General Public License","text":"Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc.  Everyone permitted copy distribute verbatim copies license document, changing allowed.","code":""},{"path":"/LICENSE.html","id":"preamble","dir":"","previous_headings":"","what":"Preamble","title":"GNU Affero General Public License","text":"GNU Affero General Public License free, copyleft license software kinds works, specifically designed ensure cooperation community case network server software. licenses software practical works designed take away freedom share change works. contrast, General Public Licenses intended guarantee freedom share change versions program–make sure remains free software users. speak free software, referring freedom, price. General Public Licenses designed make sure freedom distribute copies free software (charge wish), receive source code can get want , can change software use pieces new free programs, know can things. Developers use General Public Licenses protect rights two steps: (1) assert copyright software, (2) offer License gives legal permission copy, distribute /modify software. secondary benefit defending users’ freedom improvements made alternate versions program, receive widespread use, become available developers incorporate. Many developers free software heartened encouraged resulting cooperation. However, case software used network servers, result may fail come . GNU General Public License permits making modified version letting public access server without ever releasing source code public. GNU Affero General Public License designed specifically ensure , cases, modified source code becomes available community. requires operator network server provide source code modified version running users server. Therefore, public use modified version, publicly accessible server, gives public access source code modified version. older license, called Affero General Public License published Affero, designed accomplish similar goals. different license, version Affero GPL, Affero released new version Affero GPL permits relicensing license. precise terms conditions copying, distribution modification follow.","code":""},{"path":[]},{"path":"/LICENSE.html","id":"id_0-definitions","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"0. Definitions.","title":"GNU Affero General Public License","text":"“License” refers version 3 GNU Affero General Public License. “Copyright” also means copyright-like laws apply kinds works, semiconductor masks. “Program” refers copyrightable work licensed License. licensee addressed “”. “Licensees” “recipients” may individuals organizations. “modify” work means copy adapt part work fashion requiring copyright permission, making exact copy. resulting work called “modified version” earlier work work “based ” earlier work. “covered work” means either unmodified Program work based Program. “propagate” work means anything , without permission, make directly secondarily liable infringement applicable copyright law, except executing computer modifying private copy. Propagation includes copying, distribution (without modification), making available public, countries activities well. “convey” work means kind propagation enables parties make receive copies. Mere interaction user computer network, transfer copy, conveying. interactive user interface displays “Appropriate Legal Notices” extent includes convenient prominently visible feature (1) displays appropriate copyright notice, (2) tells user warranty work (except extent warranties provided), licensees may convey work License, view copy License. interface presents list user commands options, menu, prominent item list meets criterion.","code":""},{"path":"/LICENSE.html","id":"id_1-source-code","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"1. Source Code.","title":"GNU Affero General Public License","text":"“source code” work means preferred form work making modifications . “Object code” means non-source form work. “Standard Interface” means interface either official standard defined recognized standards body, , case interfaces specified particular programming language, one widely used among developers working language. “System Libraries” executable work include anything, work whole, () included normal form packaging Major Component, part Major Component, (b) serves enable use work Major Component, implement Standard Interface implementation available public source code form. “Major Component”, context, means major essential component (kernel, window system, ) specific operating system () executable work runs, compiler used produce work, object code interpreter used run . “Corresponding Source” work object code form means source code needed generate, install, (executable work) run object code modify work, including scripts control activities. However, include work’s System Libraries, general-purpose tools generally available free programs used unmodified performing activities part work. example, Corresponding Source includes interface definition files associated source files work, source code shared libraries dynamically linked subprograms work specifically designed require, intimate data communication control flow subprograms parts work. Corresponding Source need include anything users can regenerate automatically parts Corresponding Source. Corresponding Source work source code form work.","code":""},{"path":"/LICENSE.html","id":"id_2-basic-permissions","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"2. Basic Permissions.","title":"GNU Affero General Public License","text":"rights granted License granted term copyright Program, irrevocable provided stated conditions met. License explicitly affirms unlimited permission run unmodified Program. output running covered work covered License output, given content, constitutes covered work. License acknowledges rights fair use equivalent, provided copyright law. may make, run propagate covered works convey, without conditions long license otherwise remains force. may convey covered works others sole purpose make modifications exclusively , provide facilities running works, provided comply terms License conveying material control copyright. thus making running covered works must exclusively behalf, direction control, terms prohibit making copies copyrighted material outside relationship . Conveying circumstances permitted solely conditions stated . Sublicensing allowed; section 10 makes unnecessary.","code":""},{"path":"/LICENSE.html","id":"id_3-protecting-users-legal-rights-from-anti-circumvention-law","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"3. Protecting Users’ Legal Rights From Anti-Circumvention Law.","title":"GNU Affero General Public License","text":"covered work shall deemed part effective technological measure applicable law fulfilling obligations article 11 WIPO copyright treaty adopted 20 December 1996, similar laws prohibiting restricting circumvention measures. convey covered work, waive legal power forbid circumvention technological measures extent circumvention effected exercising rights License respect covered work, disclaim intention limit operation modification work means enforcing, work’s users, third parties’ legal rights forbid circumvention technological measures.","code":""},{"path":"/LICENSE.html","id":"id_4-conveying-verbatim-copies","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"4. Conveying Verbatim Copies.","title":"GNU Affero General Public License","text":"may convey verbatim copies Program’s source code receive , medium, provided conspicuously appropriately publish copy appropriate copyright notice; keep intact notices stating License non-permissive terms added accord section 7 apply code; keep intact notices absence warranty; give recipients copy License along Program. may charge price price copy convey, may offer support warranty protection fee.","code":""},{"path":"/LICENSE.html","id":"id_5-conveying-modified-source-versions","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"5. Conveying Modified Source Versions.","title":"GNU Affero General Public License","text":"may convey work based Program, modifications produce Program, form source code terms section 4, provided also meet conditions: work must carry prominent notices stating modified , giving relevant date. work must carry prominent notices stating released License conditions added section 7. requirement modifies requirement section 4 “keep intact notices”. must license entire work, whole, License anyone comes possession copy. License therefore apply, along applicable section 7 additional terms, whole work, parts, regardless packaged. License gives permission license work way, invalidate permission separately received . work interactive user interfaces, must display Appropriate Legal Notices; however, Program interactive interfaces display Appropriate Legal Notices, work need make . compilation covered work separate independent works, nature extensions covered work, combined form larger program, volume storage distribution medium, called “aggregate” compilation resulting copyright used limit access legal rights compilation’s users beyond individual works permit. Inclusion covered work aggregate cause License apply parts aggregate.","code":""},{"path":"/LICENSE.html","id":"id_6-conveying-non-source-forms","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"6. Conveying Non-Source Forms.","title":"GNU Affero General Public License","text":"may convey covered work object code form terms sections 4 5, provided also convey machine-readable Corresponding Source terms License, one ways: Convey object code , embodied , physical product (including physical distribution medium), accompanied Corresponding Source fixed durable physical medium customarily used software interchange. Convey object code , embodied , physical product (including physical distribution medium), accompanied written offer, valid least three years valid long offer spare parts customer support product model, give anyone possesses object code either (1) copy Corresponding Source software product covered License, durable physical medium customarily used software interchange, price reasonable cost physically performing conveying source, (2) access copy Corresponding Source network server charge. Convey individual copies object code copy written offer provide Corresponding Source. alternative allowed occasionally noncommercially, received object code offer, accord subsection 6b. Convey object code offering access designated place (gratis charge), offer equivalent access Corresponding Source way place charge. need require recipients copy Corresponding Source along object code. place copy object code network server, Corresponding Source may different server (operated third party) supports equivalent copying facilities, provided maintain clear directions next object code saying find Corresponding Source. Regardless server hosts Corresponding Source, remain obligated ensure available long needed satisfy requirements. Convey object code using peer--peer transmission, provided inform peers object code Corresponding Source work offered general public charge subsection 6d. separable portion object code, whose source code excluded Corresponding Source System Library, need included conveying object code work. “User Product” either (1) “consumer product”, means tangible personal property normally used personal, family, household purposes, (2) anything designed sold incorporation dwelling. determining whether product consumer product, doubtful cases shall resolved favor coverage. particular product received particular user, “normally used” refers typical common use class product, regardless status particular user way particular user actually uses, expects expected use, product. product consumer product regardless whether product substantial commercial, industrial non-consumer uses, unless uses represent significant mode use product. “Installation Information” User Product means methods, procedures, authorization keys, information required install execute modified versions covered work User Product modified version Corresponding Source. information must suffice ensure continued functioning modified object code case prevented interfered solely modification made. convey object code work section , , specifically use , User Product, conveying occurs part transaction right possession use User Product transferred recipient perpetuity fixed term (regardless transaction characterized), Corresponding Source conveyed section must accompanied Installation Information. requirement apply neither third party retains ability install modified object code User Product (example, work installed ROM). requirement provide Installation Information include requirement continue provide support service, warranty, updates work modified installed recipient, User Product modified installed. Access network may denied modification materially adversely affects operation network violates rules protocols communication across network. Corresponding Source conveyed, Installation Information provided, accord section must format publicly documented (implementation available public source code form), must require special password key unpacking, reading copying.","code":""},{"path":"/LICENSE.html","id":"id_7-additional-terms","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"7. Additional Terms.","title":"GNU Affero General Public License","text":"“Additional permissions” terms supplement terms License making exceptions one conditions. Additional permissions applicable entire Program shall treated though included License, extent valid applicable law. additional permissions apply part Program, part may used separately permissions, entire Program remains governed License without regard additional permissions. convey copy covered work, may option remove additional permissions copy, part . (Additional permissions may written require removal certain cases modify work.) may place additional permissions material, added covered work, can give appropriate copyright permission. Notwithstanding provision License, material add covered work, may (authorized copyright holders material) supplement terms License terms: Disclaiming warranty limiting liability differently terms sections 15 16 License; Requiring preservation specified reasonable legal notices author attributions material Appropriate Legal Notices displayed works containing ; Prohibiting misrepresentation origin material, requiring modified versions material marked reasonable ways different original version; Limiting use publicity purposes names licensors authors material; Declining grant rights trademark law use trade names, trademarks, service marks; Requiring indemnification licensors authors material anyone conveys material (modified versions ) contractual assumptions liability recipient, liability contractual assumptions directly impose licensors authors. non-permissive additional terms considered “restrictions” within meaning section 10. Program received , part , contains notice stating governed License along term restriction, may remove term. license document contains restriction permits relicensing conveying License, may add covered work material governed terms license document, provided restriction survive relicensing conveying. add terms covered work accord section, must place, relevant source files, statement additional terms apply files, notice indicating find applicable terms. Additional terms, permissive non-permissive, may stated form separately written license, stated exceptions; requirements apply either way.","code":""},{"path":"/LICENSE.html","id":"id_8-termination","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"8. Termination.","title":"GNU Affero General Public License","text":"may propagate modify covered work except expressly provided License. attempt otherwise propagate modify void, automatically terminate rights License (including patent licenses granted third paragraph section 11). However, cease violation License, license particular copyright holder reinstated () provisionally, unless copyright holder explicitly finally terminates license, (b) permanently, copyright holder fails notify violation reasonable means prior 60 days cessation. Moreover, license particular copyright holder reinstated permanently copyright holder notifies violation reasonable means, first time received notice violation License (work) copyright holder, cure violation prior 30 days receipt notice. Termination rights section terminate licenses parties received copies rights License. rights terminated permanently reinstated, qualify receive new licenses material section 10.","code":""},{"path":"/LICENSE.html","id":"id_9-acceptance-not-required-for-having-copies","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"9. Acceptance Not Required for Having Copies.","title":"GNU Affero General Public License","text":"required accept License order receive run copy Program. Ancillary propagation covered work occurring solely consequence using peer--peer transmission receive copy likewise require acceptance. However, nothing License grants permission propagate modify covered work. actions infringe copyright accept License. Therefore, modifying propagating covered work, indicate acceptance License .","code":""},{"path":"/LICENSE.html","id":"id_10-automatic-licensing-of-downstream-recipients","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"10. Automatic Licensing of Downstream Recipients.","title":"GNU Affero General Public License","text":"time convey covered work, recipient automatically receives license original licensors, run, modify propagate work, subject License. responsible enforcing compliance third parties License. “entity transaction” transaction transferring control organization, substantially assets one, subdividing organization, merging organizations. propagation covered work results entity transaction, party transaction receives copy work also receives whatever licenses work party’s predecessor interest give previous paragraph, plus right possession Corresponding Source work predecessor interest, predecessor can get reasonable efforts. may impose restrictions exercise rights granted affirmed License. example, may impose license fee, royalty, charge exercise rights granted License, may initiate litigation (including cross-claim counterclaim lawsuit) alleging patent claim infringed making, using, selling, offering sale, importing Program portion .","code":""},{"path":"/LICENSE.html","id":"id_11-patents","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"11. Patents.","title":"GNU Affero General Public License","text":"“contributor” copyright holder authorizes use License Program work Program based. work thus licensed called contributor’s “contributor version”. contributor’s “essential patent claims” patent claims owned controlled contributor, whether already acquired hereafter acquired, infringed manner, permitted License, making, using, selling contributor version, include claims infringed consequence modification contributor version. purposes definition, “control” includes right grant patent sublicenses manner consistent requirements License. contributor grants non-exclusive, worldwide, royalty-free patent license contributor’s essential patent claims, make, use, sell, offer sale, import otherwise run, modify propagate contents contributor version. following three paragraphs, “patent license” express agreement commitment, however denominated, enforce patent (express permission practice patent covenant sue patent infringement). “grant” patent license party means make agreement commitment enforce patent party. convey covered work, knowingly relying patent license, Corresponding Source work available anyone copy, free charge terms License, publicly available network server readily accessible means, must either (1) cause Corresponding Source available, (2) arrange deprive benefit patent license particular work, (3) arrange, manner consistent requirements License, extend patent license downstream recipients. “Knowingly relying” means actual knowledge , patent license, conveying covered work country, recipient’s use covered work country, infringe one identifiable patents country reason believe valid. , pursuant connection single transaction arrangement, convey, propagate procuring conveyance , covered work, grant patent license parties receiving covered work authorizing use, propagate, modify convey specific copy covered work, patent license grant automatically extended recipients covered work works based . patent license “discriminatory” include within scope coverage, prohibits exercise , conditioned non-exercise one rights specifically granted License. may convey covered work party arrangement third party business distributing software, make payment third party based extent activity conveying work, third party grants, parties receive covered work , discriminatory patent license () connection copies covered work conveyed (copies made copies), (b) primarily connection specific products compilations contain covered work, unless entered arrangement, patent license granted, prior 28 March 2007. Nothing License shall construed excluding limiting implied license defenses infringement may otherwise available applicable patent law.","code":""},{"path":"/LICENSE.html","id":"id_12-no-surrender-of-others-freedom","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"12. No Surrender of Others’ Freedom.","title":"GNU Affero General Public License","text":"conditions imposed (whether court order, agreement otherwise) contradict conditions License, excuse conditions License. convey covered work satisfy simultaneously obligations License pertinent obligations, consequence may convey . example, agree terms obligate collect royalty conveying convey Program, way satisfy terms License refrain entirely conveying Program.","code":""},{"path":"/LICENSE.html","id":"id_13-remote-network-interaction-use-with-the-gnu-general-public-license","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"13. Remote Network Interaction; Use with the GNU General Public License.","title":"GNU Affero General Public License","text":"Notwithstanding provision License, modify Program, modified version must prominently offer users interacting remotely computer network (version supports interaction) opportunity receive Corresponding Source version providing access Corresponding Source network server charge, standard customary means facilitating copying software. Corresponding Source shall include Corresponding Source work covered version 3 GNU General Public License incorporated pursuant following paragraph. Notwithstanding provision License, permission link combine covered work work licensed version 3 GNU General Public License single combined work, convey resulting work. terms License continue apply part covered work, work combined remain governed version 3 GNU General Public License.","code":""},{"path":"/LICENSE.html","id":"id_14-revised-versions-of-this-license","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"14. Revised Versions of this License.","title":"GNU Affero General Public License","text":"Free Software Foundation may publish revised /new versions GNU Affero General Public License time time. new versions similar spirit present version, may differ detail address new problems concerns. version given distinguishing version number. Program specifies certain numbered version GNU Affero General Public License “later version” applies , option following terms conditions either numbered version later version published Free Software Foundation. Program specify version number GNU Affero General Public License, may choose version ever published Free Software Foundation. Program specifies proxy can decide future versions GNU Affero General Public License can used, proxy’s public statement acceptance version permanently authorizes choose version Program. Later license versions may give additional different permissions. However, additional obligations imposed author copyright holder result choosing follow later version.","code":""},{"path":"/LICENSE.html","id":"id_15-disclaimer-of-warranty","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"15. Disclaimer of Warranty.","title":"GNU Affero General Public License","text":"WARRANTY PROGRAM, EXTENT PERMITTED APPLICABLE LAW. EXCEPT OTHERWISE STATED WRITING COPYRIGHT HOLDERS /PARTIES PROVIDE PROGRAM “” WITHOUT WARRANTY KIND, EITHER EXPRESSED IMPLIED, INCLUDING, LIMITED , IMPLIED WARRANTIES MERCHANTABILITY FITNESS PARTICULAR PURPOSE. ENTIRE RISK QUALITY PERFORMANCE PROGRAM . PROGRAM PROVE DEFECTIVE, ASSUME COST NECESSARY SERVICING, REPAIR CORRECTION.","code":""},{"path":"/LICENSE.html","id":"id_16-limitation-of-liability","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"16. Limitation of Liability.","title":"GNU Affero General Public License","text":"EVENT UNLESS REQUIRED APPLICABLE LAW AGREED WRITING COPYRIGHT HOLDER, PARTY MODIFIES /CONVEYS PROGRAM PERMITTED , LIABLE DAMAGES, INCLUDING GENERAL, SPECIAL, INCIDENTAL CONSEQUENTIAL DAMAGES ARISING USE INABILITY USE PROGRAM (INCLUDING LIMITED LOSS DATA DATA RENDERED INACCURATE LOSSES SUSTAINED THIRD PARTIES FAILURE PROGRAM OPERATE PROGRAMS), EVEN HOLDER PARTY ADVISED POSSIBILITY DAMAGES.","code":""},{"path":"/LICENSE.html","id":"id_17-interpretation-of-sections-15-and-16","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"17. Interpretation of Sections 15 and 16.","title":"GNU Affero General Public License","text":"disclaimer warranty limitation liability provided given local legal effect according terms, reviewing courts shall apply local law closely approximates absolute waiver civil liability connection Program, unless warranty assumption liability accompanies copy Program return fee. END TERMS CONDITIONS","code":""},{"path":"/LICENSE.html","id":"how-to-apply-these-terms-to-your-new-programs","dir":"","previous_headings":"","what":"How to Apply These Terms to Your New Programs","title":"GNU Affero General Public License","text":"develop new program, want greatest possible use public, best way achieve make free software everyone can redistribute change terms. , attach following notices program. safest attach start source file effectively state exclusion warranty; file least “copyright” line pointer full notice found. Also add information contact electronic paper mail. software can interact users remotely computer network, also make sure provides way users get source. example, program web application, interface display “Source” link leads users archive code. many ways offer source, different solutions better different programs; see section 13 specific requirements. also get employer (work programmer) school, , sign “copyright disclaimer” program, necessary. information , apply follow GNU AGPL, see https://www.gnu.org/licenses/.","code":" Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see ."},{"path":"/articles/VoCC.html","id":"example-1-prediction-of-biogeographical-shifts","dir":"Articles","previous_headings":"","what":"Example 1: Prediction of biogeographical shifts","title":"VoCC","text":"look first “marshift” global data set containing reported range shifts marine species corresponding given periods time. Next, calculate gradient- distance-based velocities (1960-2009), using HadiSST data set, later extract corresponding values observed shift. Next, extract mean velocity estimates reported shift taking average grid cell values within circle radius equal reported range-shift distance. used fit simple linear regression models observed range shifts climate velocity. Distance-based velocities strictly positive definition, compare like like change first sign negative present local climates warmer future analogues. Produce observed vs predicted scatterplots regression lines (Fig. 2 Garcia Molinos et al. 2019).","code":"str(marshift) #> 'data.frame': 343 obs. of 6 variables: #> $ lat : num 49.7 53.8 53.8 40 43 ... #> $ long : num -4.33 5 5 1 -9.3 -1.4 -9.3 -71.7 -71.7 -71.7 ... #> $ timespan : int 30 40 40 55 35 35 84 39 26 54 ... #> $ years_data: int 23 40 40 15 4 2 5 2 2 2 ... #> $ taxa : Factor w/ 12 levels \"Benthic algae\",..: 6 6 6 6 3 3 4 5 5 5 ... #> $ Shift : num 536.1 65.6 95.9 40 10 ... HadiSST <- terra::rast(system.file(\"extdata\", \"HadiSST.tif\", package = \"VoCCdata\")) # monthly to annual averages r <- sumSeries(HadiSST, p = \"1960-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HadiSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\") vt <- tempTrend(r, th = 10) # temporal trend vg <- spatGrad(r, th = 0.0001, projected = FALSE) # spatial gradient gv <- gVoCC(vt, vg) # climate velocity # Now the distance-based velocities # Take 1960-1970 as base period against 2000-2009 r2 <- c(terra::mean(r[[1:10]], na.rm = TRUE), terra::mean(r[[41:50]], na.rm = TRUE)) # prepare the data frame with the necessary variables clim <- na.omit(data.frame(terra::values(r2), cid = 1:terra::ncell(r))) clim[, c(\"x\", \"y\")] <- terra::xyFromCell(r, clim$cid) # 1965-2004 (40 yr), 500 km search radius v <- dVoCC(clim, n = 1, tdiff = 40, method = \"Single\", climTol = 0.1, geoTol = 500, distfun = \"GreatCircle\", trans = NA, lonlat = TRUE) # Change sign as needed and create the distance-based velocity raster # Change sign as needed - terra approach for value comparison focal_vals <- terra::values(r2[[1]])[v$focal] target_vals <- terra::values(r2[[2]])[v$target] ind <- which(focal_vals > target_vals) v$velBis <- v$vel v$velBis[ind] <- v$vel[ind] * -1 # put output in raster format - create single layer empty template like raster(gv) dv <- terra::rast(terra::ext(gv), resolution = terra::res(gv), crs = terra::crs(gv)) dv[v$focal] <- v$velBis # Create point geometries and buffer them coords <- terra::vect(cbind(marshift$long, marshift$lat), crs = \"EPSG:4326\") buffer_size <- marshift$Shift * (marshift$timespan / 10) * 1000 # Get the mean velocity within the buffer for each data point. # Match old raster::extract approach exactly marshift$GV <- terra::extract(abs(gv[[1]]), coords, buffer = buffer_size, fun = mean, na.rm = TRUE, weights = TRUE, exact = FALSE)[,2] marshift$DV <- terra::extract(abs(dv), coords, buffer = buffer_size, fun = mean, na.rm = TRUE, weights = TRUE, exact = FALSE)[,2] # For points that didn't get values (NA), find nearest valid cells missing_points <- coords[is.na(marshift$GV)] # Identify NAs if(!is.empty(missing_points)){ marine_cells <- terra::as.points(gv[[1]]) # vector of all valid marine cell locations. nearest_indices <- terra::nearest(missing_points, marine_cells) # Find the nearest marine cell nearest_values <- terra::extract(gv[[1]], marine_cells[nearest_indices]) # get the values from the nearest marine cells. marshift$GV[is.na(marshift$GV)] <- nearest_values[, 2] # Replace the NA values in `marshift$GV` } missing_points <- coords[is.na(marshift$DV)] # Identify NAs if(!is.empty(missing_points)){ marine_cells <- terra::as.points(dv[[1]]) # vector of all valid marine cell locations. nearest_cells <- terra::nearest(missing_points, marine_cells) # Find the nearest marine cell nearest_values <- terra::extract(dv[[1]], nearest_cells) # get the values from the nearest marine cells. marshift$DV[is.na(marshift$DV)] <- nearest_values[, 2] # Replace the NA values in `marshift$GV` } # fit the regression models Mgv <- lm(Shift^(1 / 4) ~ I((GV * 10)^(1 / 4)), data = marshift, weights = years_data) summary(Mgv) #> #> Call: #> lm(formula = Shift^(1/4) ~ I((GV * 10)^(1/4)), data = marshift, #> weights = years_data) #> #> Weighted Residuals: #> Min 1Q Median 3Q Max #> -8.7627 -2.3540 -0.5463 1.5966 14.8297 #> #> Coefficients: #> Estimate Std. Error t value Pr(>|t|) #> (Intercept) 1.20025 0.23469 5.114 5.28e-07 *** #> I((GV * 10)^(1/4)) 0.50348 0.09599 5.245 2.75e-07 *** #> --- #> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 #> #> Residual standard error: 3.865 on 340 degrees of freedom #> (1 observation deleted due to missingness) #> Multiple R-squared: 0.07486, Adjusted R-squared: 0.07214 #> F-statistic: 27.51 on 1 and 340 DF, p-value: 2.75e-07 Mdv <- lm(Shift^(1 / 4) ~ I((DV * 10)^(1 / 4)), data = marshift, weights = years_data) summary(Mdv) #> #> Call: #> lm(formula = Shift^(1/4) ~ I((DV * 10)^(1/4)), data = marshift, #> weights = years_data) #> #> Weighted Residuals: #> Min 1Q Median 3Q Max #> -9.1097 -2.3602 -0.7524 1.6379 15.2653 #> #> Coefficients: #> Estimate Std. Error t value Pr(>|t|) #> (Intercept) 0.8565 0.3371 2.541 0.0115 * #> I((DV * 10)^(1/4)) 0.6192 0.1335 4.636 5.07e-06 *** #> --- #> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 #> #> Residual standard error: 3.904 on 338 degrees of freedom #> (3 observations deleted due to missingness) #> Multiple R-squared: 0.05979, Adjusted R-squared: 0.05701 #> F-statistic: 21.5 on 1 and 338 DF, p-value: 5.074e-06 # first compare both velocities p1 <- ggplot() + geom_spatraster(data = gv[[1]]) + scale_fill_distiller(palette = \"RdBu\", direction = -1, limits = c(-50, 50)) + ggtitle(\"Gradient-based vocc\") + scale_x_continuous(expand = c(0,0)) + scale_y_continuous(expand = c(0,0)) p2 <- ggplot() + geom_spatraster(data = dv[[1]]) + scale_fill_distiller(palette = \"RdBu\", direction = -1, limits = c(-20, 20)) + ggtitle(\"Distance-based vocc\") + scale_x_continuous(expand = c(0,0)) + scale_y_continuous(expand = c(0,0)) wrap_plots(p1, p2, ncol = 1) # scatter plots with the resulting regression line p1 <- ggplot(na.omit(marshift), aes(x = (GV * 10)^(1 / 4), y = Shift^(1 / 4))) + geom_point(color = \"grey\") + geom_smooth(method = lm, se = FALSE) + theme_classic() + scale_color_brewer(palette = \"Accent\") + labs(x = \"Predicted shift (x^1/4; km/yr)\", y = \"Observed shift (y^1/4; km/yr)\") p2 <- ggplot(na.omit(marshift), aes(x = (DV * 10)^(1 / 4), y = Shift^(1 / 4))) + geom_point(color = \"grey\") + geom_smooth(method = lm, se = FALSE) + theme_classic() + scale_color_brewer(palette = \"Accent\") + labs(x = \"Predicted shift (x^1/4; km/yr)\", y = \"Observed shift (y^1/4; km/yr)\") wrap_plots(p1, p2, nrow = 1) #> `geom_smooth()` using formula = 'y ~ x' #> `geom_smooth()` using formula = 'y ~ x' #> Warning: Removed 2 rows containing non-finite outside the scale range #> (`stat_smooth()`). #> Warning: Removed 2 rows containing missing values or values outside the scale range #> (`geom_point()`)."},{"path":"/articles/VoCC.html","id":"example-2-analysis-of-climate-exposure-and-connectivity-in-the-western-pacific-ocean","dir":"Articles","previous_headings":"","what":"Example 2: Analysis of climate exposure and connectivity in the Western Pacific Ocean","title":"VoCC","text":"example use climate velocity trajectories (based 1960-2009 mean annual SST) analyse climate connectivity Western Pacific region calculate residence time corresponding exclusive economic zones region index climatic exposure. First, arrange raster layers analysis. can now populate data frame cell centroid coordinates trajectories. Let’s calculate trajectories parallel processing demonstrate can used speed things (especially useful dealing fine resolutions large extents). Plot climate velocities EEZ polygons EEZs data set (Fig. 3a Garcia Molinos et al. 2019) now calculate trajectory classes residence times EEZ using traj25 data set. Finally let’s plot category proportions pie charts top EEZ, size chart proportional respective residence time (Fig. 3b Garcia Molinos et al. 2019).","code":"# prepare raster layers vel <- gv[[1]] ang <- gv[[2]] mn <- app(r, mean, na.rm = T) # generate a velocity layer centered and cropped to study region to extract the initial coordinates for the trajectories from x1 <- crop(gv[[1]], ext(-180, 0, -90, 90)) x2 <- crop(gv[[1]], ext(0, 180, -90, 90)) ext(x1) <- c(180, 360, -90, 90) velc <- merge(x1, x2) # crop to the desired extent # display restricted to +180 longitude to avoid plotting issues with date line crossing velc <- crop(velc, c(90, 180, -32, 33)) lonlat <- data.frame(terra::xyFromCell(velc, 1:ncell(velc))) lonlat$vel <- terra::extract(vel, lonlat, ID = FALSE) lonlat$ang <- terra::extract(ang, lonlat[, 1:2], ID = FALSE) lonlat$mn <- terra::extract(mn, lonlat[, 1:2], ID = FALSE) lonlat$lineID <- 1:nrow(lonlat) lonlat <- drop_na(lonlat) traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, tstep = 1/12) # create the spatial object with the trajectories and plot them together with the EEZ polygons lns <- map(traj %>% group_split(cellIDs), trajLine) %>% purrr::list_rbind() %>% sf::st_sf() # Load and simplify polygons to speed plotting up EEZs <- sf::st_read(system.file(\"extdata\", \"EEZs.gpkg\", package = \"VoCCdata\")) %>% sf::st_break_antimeridian() %>% sf::st_simplify(preserveTopology = TRUE, dTolerance = 500) %>% sf::st_crop(xmin = 75, xmax = 180, ymin = -35, ymax = 35) #> Reading layer `EEZs' from data source #> `/Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/library/VoCCdata/extdata/EEZs.gpkg' #> using driver `GPKG' #> Simple feature collection with 35 features and 22 fields #> Geometry type: MULTIPOLYGON #> Dimension: XY #> Bounding box: xmin: -179.9999 ymin: -31.24447 xmax: 179.9999 ymax: 31.79787 #> Geodetic CRS: +proj=longlat +datum=WGS84 +no_defs ggplot() + geom_spatraster(data = velc, aes(fill = voccMag)) + scale_fill_viridis_c(option = \"inferno\", name = \"Velocity\") + geom_sf(data = lns %>% sf::st_shift_longitude(), colour = \"grey70\", linewidth = 0.1) + geom_sf(data = EEZs %>% sf::st_shift_longitude(), colour = \"white\", fill = NA, linewidth = 0.3) + scale_x_continuous(expand = c(0, 0)) + scale_y_continuous(expand = c(0, 0)) # classify trajectories (16 trajectories starting from each 1-deg cell cell) clas <- trajClas(traj25, vel, ang, mn, trajSt = 16, tyr = 50, nmL = 20, smL = 100, Nend = 45, Nst = 15, NFT = 70) #> Warning: [readValues] raster has no values # Extract proportions by categories for each EEZ v <- data.table(terra::extract(clas[[7]], EEZs, df = TRUE)) v[, TrajClas := as.character(TrajClas)] v[, ID := as.ordered(ID)] # proportions by class d <- prop.table(table(v), 1) # residence times by EEZ EEZa <- resTime(EEZs, vel, areapg = NA) D <- data.table(d) # put data in long format D[, name := as.character(EEZs$Territory1)[as.numeric(ID)]] # add EEZ names for reference D[, RT := as.character(EEZa$resTim)[as.numeric(ID)]] # prepare data frame to plot the pie charts with dt <- as.data.frame.matrix(d) dt$country <- as.character(EEZs$Territory1) coords <- sf::st_coordinates(sf::st_centroid(EEZs)) dt[, c(\"x\", \"y\")] <- coords[, c(\"X\", \"Y\")] dt$RT <- EEZa$resTim # # generate the plot plot(velc) plot(eez_simp, add = TRUE) mycol <- c(scales::alpha(rgb(192, 192, 192, maxColorValue = 255), 0.5), scales::alpha(rgb(204, 255, 204, maxColorValue = 255), 0.5), scales::alpha(rgb(255, 153, 51, maxColorValue = 255), 0.5), scales::alpha(rgb(255, 51, 51, maxColorValue = 255), 0.5), scales::alpha(rgb(51, 51, 255, maxColorValue = 255), 0.5), scales::alpha(rgb(204, 102, 0, maxColorValue = 255), 0.5), scales::alpha(rgb(204, 0, 204, maxColorValue = 255), 0.5), scales::alpha(rgb(255, 255, 51, maxColorValue = 255), 0.5), scales::alpha(rgb(153, 204, 255, maxColorValue = 255), 0.5)) # mylab = c(\"Non-moving\", \"Slow-moving\", \"Internal Sink\", \"Boundary sink\", # \"Source\", \"Internal sink\",\"Corridor\", \"Divergence\", \"Convergence\") for (i in 1:35) { add.pie(z = as.numeric(dt[i, 1:5]), x = dt[i, \"x\"], y = dt[i, \"y\"], radius = log(dt[i, \"RT\"]), col = mycol, labels = \"\") }"},{"path":"/articles/VoCC.html","id":"references","dir":"Articles","previous_headings":"","what":"References","title":"VoCC","text":"García Molinos, J., Schoeman, D. S., Brown, C. J. Burrows, M. T. (2019), VoCC: R package calculating velocity climate change related climatic metrics. Methods Ecol Evol. doi:10.1111/2041-210X.13295","code":""},{"path":"/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Jorge Garcia Molinos. Author, maintainer. David S. Schoeman. Author. Christopher J. Brown. Author. Michael T. Burrows. Author. Naoki H. Kumagai. Contributor.","code":""},{"path":"/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Garcia Molinos J, S. Schoeman D, J. Brown C, T. Burrows M (2025). VoCC: Velocity Climate Change related climatic metrics. R package version 0.0.1, https://mathmarecol.github.io/VoCC/.","code":"@Manual{, title = {VoCC: The Velocity of Climate Change and related climatic metrics}, author = {Jorge {Garcia Molinos} and David {S. Schoeman} and Christopher {J. Brown} and Michael {T. Burrows}}, year = {2025}, note = {R package version 0.0.1}, url = {https://mathmarecol.github.io/VoCC/}, }"},{"path":"/index.html","id":"vocc-the-velocity-of-climate-change-and-related-climatic-metrics","dir":"","previous_headings":"","what":"The Velocity of Climate Change and related climatic metrics","title":"The Velocity of Climate Change and related climatic metrics","text":"Jorge Garcia Molinos et al. 18 July 2019 package now release version (v 1.0.0). Please contact questions feed-back.","code":""},{"path":"/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"The Velocity of Climate Change and related climatic metrics","text":"can install development version VoCC GitHub :","code":"# install.packages(\"devtools\") devtools::install_github(\"JorGarMol/VoCC\")"},{"path":[]},{"path":"/index.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"The Velocity of Climate Change and related climatic metrics","text":"cite package please use: García Molinos, J., Schoeman, D. S., Brown, C. J. Burrows, M. T. (2019). VoCC: Velocity Climate Change related climatic metrics. R package version 1.0.0. https://doi.org/10.5281/zenodo.3382092 following paper explains package functionality provides examples covered code package vignette García Molinos, J., Schoeman, D. S., Brown, C. J. Burrows, M. T. (2019), VoCC: R package calculating velocity climate change related climatic metrics. Methods Ecol Evol. doi:10.1111/2041-210X.13295","code":""},{"path":"/reference/EEZ.html","id":null,"dir":"Reference","previous_headings":"","what":"Icelandic Exclusive Economic Zone (EEZ) — EEZ","title":"Icelandic Exclusive Economic Zone (EEZ) — EEZ","text":"Icelandic Exclusive Economic Zone (v10).","code":""},{"path":"/reference/EEZ.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Icelandic Exclusive Economic Zone (EEZ) — EEZ","text":"spatial polygon data frame containing Icenalndic EEZ (200 NM).","code":""},{"path":"/reference/EEZ.html","id":"source","dir":"Reference","previous_headings":"","what":"Source","title":"Icelandic Exclusive Economic Zone (EEZ) — EEZ","text":"Marineregions.org http://www.marineregions.org/downloads.php","code":""},{"path":"/reference/HSST.html","id":null,"dir":"Reference","previous_headings":"","what":"Monthly mean sea surface temperatures (SST) around Iceland for 1955-2010 — HSST","title":"Monthly mean sea surface temperatures (SST) around Iceland for 1955-2010 — HSST","text":"Monthly mean sea surface temperatures (SST) around Iceland 1955-2010","code":""},{"path":"/reference/HSST.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Monthly mean sea surface temperatures (SST) around Iceland for 1955-2010 — HSST","text":"raster stack 672 layers containing mean monthly SSTs (C) 1-deg resolution period Jan 1955 Dec 2010 Atlantic waters surrounding Iceland.","code":""},{"path":"/reference/HSST.html","id":"source","dir":"Reference","previous_headings":"","what":"Source","title":"Monthly mean sea surface temperatures (SST) around Iceland for 1955-2010 — HSST","text":"Hadley Centre data set HadISST 1.1 (data accessed May 2018).","code":""},{"path":"/reference/HSST.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Monthly mean sea surface temperatures (SST) around Iceland for 1955-2010 — HSST","text":"Rayner et al. 2003. Global analyses sea surface temperature, sea ice, night marine air temperature since late nineteenth century. J. Geophys. Res.Vol. 108: 4407.","code":""},{"path":"/reference/JapTC.html","id":null,"dir":"Reference","previous_headings":"","what":"Multivariate Terraclimate data for Japan — JapTC","title":"Multivariate Terraclimate data for Japan — JapTC","text":"Historical (1960-1969) present (2008-2017) multivariate 1/24 Terraclimate data set (Abatzoglou et al. 2018), extracted Japanese archipelago including 3 variables: mean annual monthly precipitation (mm), maximum minimum temperatures (C).","code":""},{"path":"/reference/JapTC.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Multivariate Terraclimate data for Japan — JapTC","text":"raster stack 9 layers historical (1960-1969) current (2008-2017) average (AnMn) standard deviation (AnMnSD) mean annual (AnMn) precipitation (Ppr), maximum (Tmax) minimum (Tmin) temperature.","code":""},{"path":"/reference/JapTC.html","id":"source","dir":"Reference","previous_headings":"","what":"Source","title":"Multivariate Terraclimate data for Japan — JapTC","text":"Terraclimate data set.","code":""},{"path":"/reference/JapTC.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Multivariate Terraclimate data for Japan — JapTC","text":"Abatzoglou et al. 2018. Terraclimate, high-resolution global dataset monthly climate climatic water balance 1958-2015, Scientific Data, 5: 170191","code":""},{"path":"/reference/angulo.html","id":null,"dir":"Reference","previous_headings":"","what":"Internal. Angle associated to the spatial gradient — angulo","title":"Internal. Angle associated to the spatial gradient — angulo","text":"Internal. Angle associated spatial gradient","code":""},{"path":"/reference/angulo.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Internal. Angle associated to the spatial gradient — angulo","text":"","code":"angulo(dx, dy)"},{"path":"/reference/angulo.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Internal. Angle associated to the spatial gradient — angulo","text":"dx numeric giving longitudinal gradient component dy numeric giving latitudinal gradient component","code":""},{"path":"/reference/angulo.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Internal. Angle associated to the spatial gradient — angulo","text":"Jorge Garcia Molinos David S. Schoeman angulo()","code":""},{"path":"/reference/climPCA.html","id":null,"dir":"Reference","previous_headings":"","what":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"Function extract first n principal components explaining predefined total amount variance among climatic variables. components can subsequently used synthetic climatic variables reduce dimensionality climate-analogue methods.","code":""},{"path":"/reference/climPCA.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"","code":"climPCA( climp, climf, trans = function(x) log(x), cen = TRUE, sc = TRUE, th = 0.8 )"},{"path":"/reference/climPCA.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"climp raster.stack one layer climatic variable values present baseline conditions. climf raster.stack one layer climatic variable values future conditions. trans function specifying type transformation applied prior PCA. Specify NA transformation required (default log(x)). cen logical variables centered prior PCA? (default TRUE). sc logical variables scaled prior PCA? (default TRUE). th numeric threshold giving minimum amount total variance explained principal components extracted.","code":""},{"path":"/reference/climPCA.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"list containing () output PCA (call 'prcomp'), (ii) table present/future cell values principal components accounting specified percentage total variance (th).","code":""},{"path":[]},{"path":"/reference/climPCA.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/climPCA.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"","code":"if (FALSE) { # \\dontrun{ JapTC <- VoCC_get_data(\"JapTC.tif\") comp <- climPCA(JapTC[[c(1, 3, 5)]], JapTC[[c(2, 4, 6)]], trans = NA, cen = TRUE, sc = TRUE, th = 0.85) summary(comp[[1]]) # first two components explain >90% of variance # Create a data frame with the necessary variables in the required order (see climAna? for details) clim <- comp[[2]][, c(2, 4, 3, 5, 1)] clim[, c(\"x\", \"y\")] <- terra::xyFromCell(JapTC[[1]], clim$cid) } # }"},{"path":"/reference/climPlot.html","id":null,"dir":"Reference","previous_headings":"","what":"Binned scatter plot for 2-dimensional climate space — climPlot","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"Function create binned scatter plot two climate variables.","code":""},{"path":"/reference/climPlot.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"","code":"climPlot(xy, x.binSize, y.binSize, x.name = \"V1\", y.name = \"V2\")"},{"path":"/reference/climPlot.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"xy data.frame cells rows 4 columns representing present future local values two variables (V1p, V1f, V2p, V2f). x.binSize numeric bin size first variable. y.binSize numeric bin size second variable. x.name character variable name first variable. Used label plot. y.name character variable name second variable. Used label plot.","code":""},{"path":"/reference/climPlot.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"series plot objects displaying () present (ii) future cell frequency combination local climates, (iii) location remnant, novel disappearing climates periods.","code":""},{"path":[]},{"path":"/reference/climPlot.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"Jorge Garcia Molinos Naoki H. Kumagai","code":""},{"path":"/reference/climPlot.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"","code":"if (FALSE) { # \\dontrun{ JapTC <- VoCC_get_data(\"JapTC.tif\") # Plot climate space for the two first variables(annual precipitation and maximum temperature) xy <- stats::na.omit(data.frame( terra::values(JapTC[[1]]), terra::values(JapTC[[2]]), terra::values(JapTC[[3]]), terra::values(JapTC[[4]]) )) out <- climPlot(xy, x.binSize = 5, y.binSize = 0.2, x.name = \"Precipitation (mm)\", y.name = \"Temperature max (°C)\" ) # output plots can be saved as: ggplot2::ggsave( plot = out, filename = file.path(getwd(), \"example_plot.pdf\"), width = 17, height = 17, unit = \"cm\" ) } # }"},{"path":"/reference/dVoCC.html","id":null,"dir":"Reference","previous_headings":"","what":"Distance-based velocity based on geographically closest climate analogue — dVoCC","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"Function calculate geographically closest climate analogues related distance-based velocity. Cell analogues identified comparing baseline climatic conditions focal cell existing (target) cells future reference specified climatic threshold. function allows specification search distances incorporates least-cost path Great Circle (--crow-flies) distances.","code":""},{"path":"/reference/dVoCC.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"","code":"dVoCC( clim, n, tdiff, method = \"Single\", climTol, geoTol, distfun = \"GreatCircle\", trans = NA, lonlat = TRUE )"},{"path":"/reference/dVoCC.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"clim data.frame value climatic parameters (columns) cell (rows), arranged follows (see examples ): first 2n columns must contain present future values n climatic variables (V1p, V1f, V2p, V2f,...). cell-specific analogue thresholds (see \"variable\" \"method\" ) calculated, next (2n+1:3n) columns contain standard deviation (measure climatic variability) variable baseline period. columns required using \"Single\" method. last three columns table contain identifyier centroid coordinates cell. n integer defining number climatic variables. tdiff integer defining number years (temporal unit) periods. method character string specifying analogue method used. 'Single': constant, single analogue threshold climate variable applied cells (Ohlemuller et al. 2006, Hamann et al. 2015); climate analogy corresponds target cells values specified threshold climatic variable. 'Variable': cell-specific climate threshold used climatic variable determine climate analogues associated cell reference baseline climatic variability (Garcia Molinos et al. 2017). climTol numeric vector length n giving tolerance threshold defining climate analogue conditions climatic variable. cell-specific threshold used, function parameter passed NA. geoTol integer impose geographical distance threshold (km lat/lon map units projected). used, pool potential climate analogues limited cells within distance focal cell. distfun character string specifying function used estimating distances focal target cells. Either 'Euclidean', 'GreatCircle' (Great Circle Distances). 'LeastCost' (Least Cost Path Distances) CURRENTLY IMPLEMENTED. LeastCost requires transition matrix supplied function via de 'trans' argument. trans TransitionLayer CURRENTLY IMPLEMENTED gdistance object used analogue search distfun = 'LeastCost'. lonlat logical analysis done unprojected (lon/lat) coordinates?","code":""},{"path":"/reference/dVoCC.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"data.frame containing cell id future analogue focal cell (NA = analogue available), together climatic (\"climDis\") geographical (\"geoDis\") distances input units, bearing (\"ang\", degrees North), resulting climate velocity (\"vel\", km/yr). Mean climatic distances returned multivariate analogues.","code":""},{"path":"/reference/dVoCC.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"Ohlemuller et al. 2006. Towards European climate risk surfaces: extent distribution analogous non-analogous climates 1931-2100. Global Ecology Biogeography, 15, 395-405. Hamann et al. 2015. Velocity climate change algorithms guiding conservation management. Global Change Biology, 21, 997-1004. Garcia Molinos et al. 2017. Improving interpretability climate landscape metrics: ecological risk analysis Japan's Marine Protected Areas. Global Change Biology, 23, 4440-4452.","code":""},{"path":[]},{"path":"/reference/dVoCC.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/dVoCC.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"","code":"if (FALSE) { # \\dontrun{ JapTC <- VoCC_get_data(\"JapTC.tif\") # Create a data frame with the necessary variables in the required order clim <- stats::na.omit(data.frame(terra::values(JapTC), cid = 1:terra::ncell(JapTC))) clim[, c(\"x\", \"y\")] <- terra::xyFromCell(JapTC, clim$cid) # Constant threshold, distance-restricted velocity based on geographical distances avocc1 <- dVoCC(clim, n = 3, tdiff = 40, method = \"Single\", climTol = c(10, 0.1, 0.1), geoTol = 160, distfun = \"GreatCircle\", trans = NA, lonlat = TRUE ) r1 <- JapTC[[1]] r1[avocc1$focal] <- avocc1$vel terra::plot(r1) # Cell-specific, distance-unrestricted climate analogue velocity based on least-cost path distances # First, create the conductance matrix (all land cells considered to have conductance of 1) r <- JapTC[[1]] r[!is.na(JapTC[[1]])] <- 1 h8 <- gdistance::transition(r, transitionFunction = mean, directions = 8) h8 <- gdistance::geoCorrection(h8, type = \"c\") # Now calculate the analogue velocity using the baseline SD for each variable as analogue threshold avocc2 <- dVoCC(clim, n = 3, tdiff = 40, method = \"Variable\", climTol = NA, geoTol = Inf, distfun = \"LeastCost\", trans = h8, lonlat = TRUE ) # Plot results r1 <- r2 <- JapTC[[1]] r1[avocc1$focal] <- avocc1$vel r2[avocc2$focal] <- avocc2$vel terra::plot(c(r1, r2)) } # }"},{"path":"/reference/gVoCC.html","id":null,"dir":"Reference","previous_headings":"","what":"Gradient-based climate velocity — gVoCC","title":"Gradient-based climate velocity — gVoCC","text":"Function calculate velocity climate change Burrows et al. (2011) based local climatic temporal trends spatial gradients.","code":""},{"path":"/reference/gVoCC.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Gradient-based climate velocity — gVoCC","text":"","code":"gVoCC(tempTrend, spatGrad)"},{"path":"/reference/gVoCC.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Gradient-based climate velocity — gVoCC","text":"tempTrend output tempTrend function containing long-term linear climatic trends. spatGrad output spatGrad function containing magnitudes angles spatial climatic gradient.","code":""},{"path":"/reference/gVoCC.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Gradient-based climate velocity — gVoCC","text":"RasterStack containing climate velocity magnitude (\"voccMag\", km/yr unprojected rasters spatial unit/year projected rasters) angle(\"voccAng\" degrees north: 0N, 90E, 180S 270W).","code":""},{"path":"/reference/gVoCC.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Gradient-based climate velocity — gVoCC","text":"Burrows et al. 2011. pace shifting climate marine terrestrial ecosystems. Science, 334, 652-655.","code":""},{"path":[]},{"path":"/reference/gVoCC.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Gradient-based climate velocity — gVoCC","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/gVoCC.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Gradient-based climate velocity — gVoCC","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") yrSST <- sumSeries(HSST, p = \"1960-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) tr <- tempTrend(yrSST, th = 10) sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) # Magnitude and angle of the climate velocity (km/yr) 1960-2009 v <- gVoCC(tr, sg) terra::plot(v) } # }"},{"path":"/reference/pipe.html","id":null,"dir":"Reference","previous_headings":"","what":"Pipe operator — %>%","title":"Pipe operator — %>%","text":"See magrittr::%>% details.","code":""},{"path":"/reference/pipe.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Pipe operator — %>%","text":"","code":"lhs %>% rhs"},{"path":"/reference/pipe.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Pipe operator — %>%","text":"lhs value magrittr placeholder. rhs function call using magrittr semantics.","code":""},{"path":"/reference/pipe.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Pipe operator — %>%","text":"result calling `rhs(lhs)`.","code":""},{"path":"/reference/resTime.html","id":null,"dir":"Reference","previous_headings":"","what":"Climatic residence time of a polygon — resTime","title":"Climatic residence time of a polygon — resTime","text":"Function calculate VoCC-based residence time isotherms within polygon Loaire et al. (2009)","code":""},{"path":"/reference/resTime.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Climatic residence time of a polygon — resTime","text":"","code":"resTime(pg, vel, areapg = NA)"},{"path":"/reference/resTime.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Climatic residence time of a polygon — resTime","text":"pg sf object terra::vect object containing polygons residence time calculated. polygons must coordinate system vel. vel raster climate velocity (km/year) period interest. areapg vector area (km2) polygons. Use NA (default) calculate internally field avilable.","code":""},{"path":"/reference/resTime.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Climatic residence time of a polygon — resTime","text":"data.frame containing polygon ID, mean velocity (km/yr), diameter equivalent circle (km), residence time (years) ratio D/vel.","code":""},{"path":"/reference/resTime.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Climatic residence time of a polygon — resTime","text":"Loarie et al. 2009. velocity climate change. Nature, 462, 1052-1055.","code":""},{"path":[]},{"path":"/reference/resTime.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Climatic residence time of a polygon — resTime","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/resTime.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Climatic residence time of a polygon — resTime","text":"","code":"# Load example Exclusive Economic Zone polygon if (FALSE) { # \\dontrun{ EEZ <- VoCC_get_data(\"EEZ.gpkg\") HSST <- VoCC_get_data(\"HSST.tif\") yrSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) tr <- tempTrend(yrSST, th = 10) sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) v <- gVoCC(tr, sg) vel <- v[[1]] # Calculating area internally a1 <- resTime(EEZ, vel, areapg = NA) a1 # Using the area field from the polygon data table a2 <- resTime(EEZ, vel, areapg = as.numeric(as.numeric(levels(EEZ$Area_km2))[EEZ$Area_km2])) a2 # Using a user defined polygon x_coord <- c(-28, -20, -20.3, -25.5) y_coord <- c(60, 61, 63, 62) coords <- matrix(c(x_coord, y_coord), ncol = 2) poly_sf <- sf::st_sf(geometry = sf::st_sfc(sf::st_polygon(list(coords)))) a3 <- resTime(poly_sf, vel, areapg = NA) terra::plot(vel) plot(sf::st_geometry(EEZ), add = TRUE) plot(sf::st_geometry(poly_sf), add = TRUE) } # }"},{"path":"/reference/shiftTime.html","id":null,"dir":"Reference","previous_headings":"","what":"Shift in timing of seasonal climatology — shiftTime","title":"Shift in timing of seasonal climatology — shiftTime","text":"Function calculate seasonal shift arriving typical seasonal climates given period interest per Burrows et al. (2011).","code":""},{"path":"/reference/shiftTime.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Shift in timing of seasonal climatology — shiftTime","text":"","code":"shiftTime(r, yr1, yr2, yr0, th, m)"},{"path":"/reference/shiftTime.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Shift in timing of seasonal climatology — shiftTime","text":"r stack monthly values climatic variable period interest. yr1 integer specifying initial year period interest. yr2 integer specifying end year period interest. yr0 integer specifying first year series. th integer minimum number non NAs series needed calculate trend (default 3). m integer number (1-12) month shift calculated","code":""},{"path":"/reference/shiftTime.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Shift in timing of seasonal climatology — shiftTime","text":"stack long-term monthly trend (C/year temperature degrees; \"mTrend\"), seasonal rate change (C/month; \"seaRate\"), seasonal shift (day/decade; \"seaShift\").","code":""},{"path":"/reference/shiftTime.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Shift in timing of seasonal climatology — shiftTime","text":"Burrows et al. 2011. pace shifting climate marine terrestrial ecosystems. Science, 334, 652-655.","code":""},{"path":"/reference/shiftTime.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Shift in timing of seasonal climatology — shiftTime","text":"Jorge Garcia Molinos Michael T. Burrows","code":""},{"path":"/reference/shiftTime.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Shift in timing of seasonal climatology — shiftTime","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") Apr <- shiftTime(HSST, yr1 = 1960, yr2 = 2009, yr0 = 1955, th = 10, m = 4) terra::plot(Apr) } # }"},{"path":"/reference/spatGrad.html","id":null,"dir":"Reference","previous_headings":"","what":"Local spatial climatic gradients — spatGrad","title":"Local spatial climatic gradients — spatGrad","text":"Function calculate magnitude direction spatial gradient associated climatic variable Burrows et al. (2011). trend used calculation gradient-based climate velocity using gVoCC.","code":""},{"path":"/reference/spatGrad.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Local spatial climatic gradients — spatGrad","text":"","code":"spatGrad(r, th = -Inf, projected = FALSE)"},{"path":"/reference/spatGrad.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Local spatial climatic gradients — spatGrad","text":"r RasterStack annual climatic values period interest. Alternatively, raster annual climatic values averaged period interest. th Integer indicating lower threshold truncate spatial gradient . Use -Inf (default) threshold required. projected Logical source raster projected coordinate system? FALSE (default) correction made account latitudinal distortion.","code":""},{"path":"/reference/spatGrad.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Local spatial climatic gradients — spatGrad","text":"RasterStack magnitude spatial gradient (Grad C per km unprojected rasters C per spatial unit projected rasters), associated angle (Ang degrees).","code":""},{"path":"/reference/spatGrad.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Local spatial climatic gradients — spatGrad","text":"Burrows et al. 2011. pace shifting climate marine terrestrial ecosystems. Science, 334, 652-655.","code":""},{"path":[]},{"path":"/reference/spatGrad.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Local spatial climatic gradients — spatGrad","text":"Jorge Garcia Molinos, David S. Schoeman, Michael T. Burrows","code":""},{"path":"/reference/spatGrad.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Local spatial climatic gradients — spatGrad","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") yrSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) # Spatial gradient (magnitude and angle) for the average mean annual SST. sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) terra::plot(sg) } # }"},{"path":"/reference/splitLine.html","id":null,"dir":"Reference","previous_headings":"","what":"Internal. Split a line segment defined by points A-B into n parts — splitLine","title":"Internal. Split a line segment defined by points A-B into n parts — splitLine","text":"Internal. Split line segment defined points -B n parts","code":""},{"path":"/reference/splitLine.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Internal. Split a line segment defined by points A-B into n parts — splitLine","text":"","code":"splitLine(A, B, n)"},{"path":"/reference/splitLine.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Internal. Split a line segment defined by points A-B into n parts — splitLine","text":"numeric giving coordinates first point B numeric giving coordinates second point n numeric number segments divide distance points ","code":""},{"path":"/reference/splitLine.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Internal. Split a line segment defined by points A-B into n parts — splitLine","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/sumSeries.html","id":null,"dir":"Reference","previous_headings":"","what":"Summarize climatic series to higher temporal resolution — sumSeries","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"Function convert climatic series (provided RasterStack) coarser time frequency series period interest. function transforms RasterStack xts time series object extract values period interest apply summary function. mainly wrapper apply. function family package xts (Ryan Ulrich 2017).","code":""},{"path":"/reference/sumSeries.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"","code":"sumSeries( r, p, yr0, l = terra::nlyr(r), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" )"},{"path":"/reference/sumSeries.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"r RasterStack containing time series climatic variable. p character string defining period extract calculation series (see examples). yr0 character string specifying first (yr0) year series (see examples). l integer length input time series. fun logical summary function computed. Summary functions need applied cell (columns) structure 'function(x) apply(x, 2, function(y))'. convenience, sumSeries imports colMaxs, colMins package ‘matrixStats’ (Bengtsson 2018) can called directly. freqin character string specifying original time frequency series. freqout character string specifying desired time frequency new series. Must one following: \"weeks\", \"months\", \"quarters\", \"years\", \"\". Argument \"\" allows user-defined functions applied 'xts' time series object period interest (see examples).","code":""},{"path":"/reference/sumSeries.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"RasterStack new series.","code":""},{"path":"/reference/sumSeries.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"Ray Ulrich. 2017. xts: eXtensible Time Series. R package version 0.10-1. Bengtsson 2018. matrixStats: Functions Apply Rows Columns Matrices (Vectors). R package version 0.53.1.","code":""},{"path":"/reference/sumSeries.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/sumSeries.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"","code":"if (FALSE) { # \\dontrun{ # Monthly mean SST (HadISST) data for Europe Jan-1950 to Dec-2010 HSST <- VoCC_get_data(\"HSST.tif\") # Calculate mean annual monthly SST yrSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) # Extract Jul Aug mean SST each year (xts months are indexed from 0 to 11) myf <- function(x, m = c(7, 8)) { x[xts::.indexmon(x) %in% (m - 1)] } JlAugSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1950-01-01\", l = terra::nlyr(HSST), fun = myf, freqin = \"months\", freqout = \"other\" ) # Same but calculating the annual variance of the two months myf <- function(x, m = c(7, 8)) { x1 <- x[xts::.indexmon(x) %in% (m - 1)] xts::apply.yearly(x1, function(y) { apply(y, 2, function(y) { var(y, na.rm = TRUE) }) }) } meanJASST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1950-01-01\", l = terra::nlyr(HSST), fun = myf, freqin = \"months\", freqout = \"other\" ) } # }"},{"path":"/reference/tempTrend.html","id":null,"dir":"Reference","previous_headings":"","what":"Long-term local climatic trends — tempTrend","title":"Long-term local climatic trends — tempTrend","text":"Function calculate temporal trend raster series climatic variable. trend used calculation gradient-based climate velocity using gVoCC.","code":""},{"path":"/reference/tempTrend.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Long-term local climatic trends — tempTrend","text":"","code":"tempTrend(r, th)"},{"path":"/reference/tempTrend.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Long-term local climatic trends — tempTrend","text":"r RasterStack containing time series (annual, seasonal, monthly...) values climatic variable period interest. th Integer minimum number observations series needed calculate trend cell.","code":""},{"path":"/reference/tempTrend.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Long-term local climatic trends — tempTrend","text":"RasterStack containing cell-specific temporal trends extracted simple linear regressions climatic variable time (\"slpTrends\" degree Celsius per year), together standard errors (\"seTrends\") statistical significance (\"sigTrends\").","code":""},{"path":[]},{"path":"/reference/tempTrend.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Long-term local climatic trends — tempTrend","text":"Jorge Garcia Molinos Christopher J. Brown","code":""},{"path":"/reference/tempTrend.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Long-term local climatic trends — tempTrend","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") yrSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) # Mean annual SST trend (minimum threshold of 10 years of data), with SE and p-values. tr <- tempTrend(yrSST, th = 10) terra::plot(tr) } # }"},{"path":"/reference/trajClas.html","id":null,"dir":"Reference","previous_headings":"","what":"Climate velocity trajectory classification — trajClas","title":"Climate velocity trajectory classification — trajClas","text":"Function spatial classification cells based VoCC trajectories Burrows et al. (2014). function performs hierarchical sequential classification based length trajectories, geographical features, relative abundance trajectories ending , starting flowing cell. Essentially, cells first classified non-moving, slow-moving fast-moving relative distance trajectory cover projection period based local climate velocities. Two types climate sinks identified among fast-moving cells: () boundary (e.g., coastal) cells disconnected cooler (warmer) neighbouring cells locally warming (cooling) climate, (ii) locations endorheic spatial gradients velocity angles neighbouring cells converge towards central point intersection. Finally, remaining cells classified reference total number trajectories per cell based proportions number trajectories starting (Nst), ending (Nend), flowing (NFT) cell period. Based proportions, cells classified five classes: (1) climate sources, trajectories end cell (Nend = 0); (2) relative climate sinks, relative number trajectories ending cell high proportion starting trajectories low; (3) corridors cells high proportion trajectories passing ; (4) divergence (5) convergence cells identified remaining cells fewer/trajectories ended started cell, respectively.","code":""},{"path":"/reference/trajClas.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Climate velocity trajectory classification — trajClas","text":"","code":"trajClas( traj, vel, ang, mn, trajSt, tyr, nmL, smL, Nend, Nst, NFT, DateLine = FALSE )"},{"path":"/reference/trajClas.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Climate velocity trajectory classification — trajClas","text":"traj data.frame retuned voccTraj containing coordinates identification number trajectory. vel SpatRaster magnitude gradient-based climate velocity. ang SpatRaster velocity angles. mn SpatRaster mean climatic values study period. trajSt integer number trajectories starting cell spatial unit. tyr integer number years comprising projected period. nmL numeric upper threshold (distance units per vel object) trajectory considered traveled negligible distance study period (non-moving). smL numeric upper threshold trajectory considered traveled small distance study period (slow-moving). Nend numeric percentage trajectories ending used threshold classification. Nst numeric percentage trajectories starting used threshold classification. NFT numeric percentage trajectories flowing used threshold classification. DateLine logical raster extent cross international date line? (default \"FALSE\").","code":""},{"path":"/reference/trajClas.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Climate velocity trajectory classification — trajClas","text":"SpatRaster containing trajectory classification (\"TrajClas\"), well based trajectory length (\"ClassL\"; 1 non-moving, 2 slow-moving, 3 fast-moving cells), boundrary (\"BounS\") internal sinks (\"IntS\"), proportion trajectories ending(\"PropEnd\"), flowing (\"PropFT\") starting (\"PropSt\"). trajectory classes (\"TrajClas\") (1) non-moving, (2) slow-moving, (3) internal sinks, (4) boundary sinks, (5) sources, (6) relative sinks, (7) corridors, (8) divergence (9) convergence.","code":""},{"path":"/reference/trajClas.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Climate velocity trajectory classification — trajClas","text":"Burrows et al. 2014. Geographical limits species-range shifts suggested climate velocity. Nature, 507, 492-495.","code":""},{"path":[]},{"path":"/reference/trajClas.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Climate velocity trajectory classification — trajClas","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/trajClas.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Climate velocity trajectory classification — trajClas","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") # input raster layers yrSST <- sumSeries(HSST, p = \"1960-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) mn <- terra::mean(yrSST, na.rm = TRUE) tr <- tempTrend(yrSST, th = 10) sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) v <- gVoCC(tr, sg) vel <- v[[1]] ang <- v[[2]] # Get the set of starting cells for the trajectories and calculate trajectories # at 1/4-deg resolution (16 trajectories per 1-deg cell) mnd <- terra::disagg(mn, 4) veld <- terra::disagg(vel, 4) angd <- terra::disagg(ang, 4) lonlat <- stats::na.omit(data.frame( terra::xyFromCell(veld, 1:terra::ncell(veld)), terra::values(veld), terra::values(angd), terra::values(mnd) ))[, 1:2] traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) # Generate the trajectory-based classification clas <- trajClas(traj, vel, ang, mn, trajSt = 16, tyr = 50, nmL = 20, smL = 100, Nend = 45, Nst = 15, NFT = 70, DateLine = FALSE ) # Define first the colour palette for the full set of categories my_col <- c( \"gainsboro\", \"darkseagreen1\", \"coral4\", \"firebrick2\", \"mediumblue\", \"darkorange1\", \"magenta1\", \"cadetblue1\", \"yellow1\" ) # Keep only the categories present in our raster my_col <- my_col[sort(unique(terra::values(clas[[7]])))] # Classify raster / build attribute table clasr <- terra::as.factor(clas[[7]]) rat_r <- data.frame(ID = sort(unique(terra::values(clas[[7]]))), trajcat = c(\"N-M\", \"S-M\", \"IS\", \"BS\", \"Srce\", \"RS\", \"Cor\", \"Div\", \"Con\")[sort(unique(terra::values(clas[[7]])))]) terra::cats(clasr) <- rat_r # Produce the plot using the rasterVis levelplot function rasterVis::levelplot(clasr, col.regions = my_col, xlab = NULL, ylab = NULL, scales = list(draw = FALSE) ) } # }"},{"path":"/reference/trajLine.html","id":null,"dir":"Reference","previous_headings":"","what":"Climate velocity trajectory spatial lines — trajLine","title":"Climate velocity trajectory spatial lines — trajLine","text":"Create spatial line data frame object trajectory points.","code":""},{"path":"/reference/trajLine.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Climate velocity trajectory spatial lines — trajLine","text":"","code":"trajLine(x, projx = \"EPSG:4326\")"},{"path":"/reference/trajLine.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Climate velocity trajectory spatial lines — trajLine","text":"x data.frame containing coordinates (x, y) constituent points identification number (trajIDs) trajectory returned VoCCTraj. projx CRS detailing coordinate reference system input data (default geographic CRS).","code":""},{"path":"/reference/trajLine.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Climate velocity trajectory spatial lines — trajLine","text":"SpatialLinesDataFrame one line per trajectory specified x. avoid artifacts, trajectories crossing date line need split two segments. trajectory one side date line composed single point, trajectory displayed (line object created). function assumes -180 180 longitudinal arrangement.","code":""},{"path":[]},{"path":"/reference/trajLine.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Climate velocity trajectory spatial lines — trajLine","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/trajLine.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Climate velocity trajectory spatial lines — trajLine","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") yrSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) tr <- tempTrend(yrSST, th = 10) sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) v <- gVoCC(tr, sg) vel <- v[[1]] ang <- v[[2]] # calculate the annual SST mean over the period mn <- terra::mean(yrSST, na.rm = TRUE) # get the set of starting cells for the trajectories lonlat <- stats::na.omit(data.frame( terra::xyFromCell(vel, 1:terra::ncell(vel)), vel[], ang[], mn[] ))[, 1:2] # Calculate trajectories. traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) # create a spatial line data frame from traj lns <- trajLine(x = traj) terra::plot(mn) terra::plot(lns, add = TRUE) # Export as ESRI shape file terra::writeVector(lns, filename = \"velTraj\", filetype = \"ESRI Shapefile\") } # }"},{"path":"/reference/voccTraj.html","id":null,"dir":"Reference","previous_headings":"","what":"Climate velocity trajectories — voccTraj","title":"Climate velocity trajectories — voccTraj","text":"Function calculate vocc trajectories Burrows et al (2014). Trajectories calculated propagating climatic isopleths using magnitude direction local (cell) velocities. slightly modified version original Burrows et al. (2014) approach iterations trajectory based cumulative time traveled instead using fixed time steps.","code":""},{"path":"/reference/voccTraj.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Climate velocity trajectories — voccTraj","text":"","code":"voccTraj(lonlat, vel, ang, mn, tstep, tyr = 50)"},{"path":"/reference/voccTraj.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Climate velocity trajectories — voccTraj","text":"lonlat data.frame longitude latitude (decimal degrees) points project. vel raster magnitude gradient-based climate velocity. ang raster velocity angles degrees. mn raster overall mean climatic value period interest. tyr integer temporal length period interest.","code":""},{"path":"/reference/voccTraj.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Climate velocity trajectories — voccTraj","text":"data.frame containing coordinates (\"x\", \"y\") constituent points identification number (\"trajIDs\") trajectory.","code":""},{"path":"/reference/voccTraj.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Climate velocity trajectories — voccTraj","text":"Burrows et al. 2014. Geographical limits species-range shifts suggested climate velocity. Nature, 507, 492-495.","code":""},{"path":[]},{"path":"/reference/voccTraj.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Climate velocity trajectories — voccTraj","text":"Jorge Garcia Molinos, David S. Schoeman Michael T. Burrows","code":""},{"path":"/reference/voccTraj.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Climate velocity trajectories — voccTraj","text":"","code":"if (FALSE) { # \\dontrun{ yrSST <- sumSeries(HSST, p = \"1960-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) # Long-term local climatic trends tr <- tempTrend(yrSST, th = 10) # Local spatial climatic gradients sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) # Gradient-based climate velocity v <- gVoCC(tr, sg) vel <- v[[1]] ang <- v[[2]] # Calculate the annual SST mean over the period mn <- terra::mean(yrSST, na.rm = TRUE) # Get the set of starting cells for the trajectories lonlat <- stats::na.omit(data.frame( terra::xyFromCell(vel, 1:terra::ncell(vel)), vel[], ang[], mn[] ))[, 1:2] # Calculate trajectories # The following throws an error due to the trajectories moving beyond the raster extent traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50) # This accounts for the extent issue traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) } # }"}] +[{"path":"/LICENSE.html","id":null,"dir":"","previous_headings":"","what":"GNU Affero General Public License","title":"GNU Affero General Public License","text":"Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc.  Everyone permitted copy distribute verbatim copies license document, changing allowed.","code":""},{"path":"/LICENSE.html","id":"preamble","dir":"","previous_headings":"","what":"Preamble","title":"GNU Affero General Public License","text":"GNU Affero General Public License free, copyleft license software kinds works, specifically designed ensure cooperation community case network server software. licenses software practical works designed take away freedom share change works. contrast, General Public Licenses intended guarantee freedom share change versions program–make sure remains free software users. speak free software, referring freedom, price. General Public Licenses designed make sure freedom distribute copies free software (charge wish), receive source code can get want , can change software use pieces new free programs, know can things. Developers use General Public Licenses protect rights two steps: (1) assert copyright software, (2) offer License gives legal permission copy, distribute /modify software. secondary benefit defending users’ freedom improvements made alternate versions program, receive widespread use, become available developers incorporate. Many developers free software heartened encouraged resulting cooperation. However, case software used network servers, result may fail come . GNU General Public License permits making modified version letting public access server without ever releasing source code public. GNU Affero General Public License designed specifically ensure , cases, modified source code becomes available community. requires operator network server provide source code modified version running users server. Therefore, public use modified version, publicly accessible server, gives public access source code modified version. older license, called Affero General Public License published Affero, designed accomplish similar goals. different license, version Affero GPL, Affero released new version Affero GPL permits relicensing license. precise terms conditions copying, distribution modification follow.","code":""},{"path":[]},{"path":"/LICENSE.html","id":"id_0-definitions","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"0. Definitions.","title":"GNU Affero General Public License","text":"“License” refers version 3 GNU Affero General Public License. “Copyright” also means copyright-like laws apply kinds works, semiconductor masks. “Program” refers copyrightable work licensed License. licensee addressed “”. “Licensees” “recipients” may individuals organizations. “modify” work means copy adapt part work fashion requiring copyright permission, making exact copy. resulting work called “modified version” earlier work work “based ” earlier work. “covered work” means either unmodified Program work based Program. “propagate” work means anything , without permission, make directly secondarily liable infringement applicable copyright law, except executing computer modifying private copy. Propagation includes copying, distribution (without modification), making available public, countries activities well. “convey” work means kind propagation enables parties make receive copies. Mere interaction user computer network, transfer copy, conveying. interactive user interface displays “Appropriate Legal Notices” extent includes convenient prominently visible feature (1) displays appropriate copyright notice, (2) tells user warranty work (except extent warranties provided), licensees may convey work License, view copy License. interface presents list user commands options, menu, prominent item list meets criterion.","code":""},{"path":"/LICENSE.html","id":"id_1-source-code","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"1. Source Code.","title":"GNU Affero General Public License","text":"“source code” work means preferred form work making modifications . “Object code” means non-source form work. “Standard Interface” means interface either official standard defined recognized standards body, , case interfaces specified particular programming language, one widely used among developers working language. “System Libraries” executable work include anything, work whole, () included normal form packaging Major Component, part Major Component, (b) serves enable use work Major Component, implement Standard Interface implementation available public source code form. “Major Component”, context, means major essential component (kernel, window system, ) specific operating system () executable work runs, compiler used produce work, object code interpreter used run . “Corresponding Source” work object code form means source code needed generate, install, (executable work) run object code modify work, including scripts control activities. However, include work’s System Libraries, general-purpose tools generally available free programs used unmodified performing activities part work. example, Corresponding Source includes interface definition files associated source files work, source code shared libraries dynamically linked subprograms work specifically designed require, intimate data communication control flow subprograms parts work. Corresponding Source need include anything users can regenerate automatically parts Corresponding Source. Corresponding Source work source code form work.","code":""},{"path":"/LICENSE.html","id":"id_2-basic-permissions","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"2. Basic Permissions.","title":"GNU Affero General Public License","text":"rights granted License granted term copyright Program, irrevocable provided stated conditions met. License explicitly affirms unlimited permission run unmodified Program. output running covered work covered License output, given content, constitutes covered work. License acknowledges rights fair use equivalent, provided copyright law. may make, run propagate covered works convey, without conditions long license otherwise remains force. may convey covered works others sole purpose make modifications exclusively , provide facilities running works, provided comply terms License conveying material control copyright. thus making running covered works must exclusively behalf, direction control, terms prohibit making copies copyrighted material outside relationship . Conveying circumstances permitted solely conditions stated . Sublicensing allowed; section 10 makes unnecessary.","code":""},{"path":"/LICENSE.html","id":"id_3-protecting-users-legal-rights-from-anti-circumvention-law","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"3. Protecting Users’ Legal Rights From Anti-Circumvention Law.","title":"GNU Affero General Public License","text":"covered work shall deemed part effective technological measure applicable law fulfilling obligations article 11 WIPO copyright treaty adopted 20 December 1996, similar laws prohibiting restricting circumvention measures. convey covered work, waive legal power forbid circumvention technological measures extent circumvention effected exercising rights License respect covered work, disclaim intention limit operation modification work means enforcing, work’s users, third parties’ legal rights forbid circumvention technological measures.","code":""},{"path":"/LICENSE.html","id":"id_4-conveying-verbatim-copies","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"4. Conveying Verbatim Copies.","title":"GNU Affero General Public License","text":"may convey verbatim copies Program’s source code receive , medium, provided conspicuously appropriately publish copy appropriate copyright notice; keep intact notices stating License non-permissive terms added accord section 7 apply code; keep intact notices absence warranty; give recipients copy License along Program. may charge price price copy convey, may offer support warranty protection fee.","code":""},{"path":"/LICENSE.html","id":"id_5-conveying-modified-source-versions","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"5. Conveying Modified Source Versions.","title":"GNU Affero General Public License","text":"may convey work based Program, modifications produce Program, form source code terms section 4, provided also meet conditions: work must carry prominent notices stating modified , giving relevant date. work must carry prominent notices stating released License conditions added section 7. requirement modifies requirement section 4 “keep intact notices”. must license entire work, whole, License anyone comes possession copy. License therefore apply, along applicable section 7 additional terms, whole work, parts, regardless packaged. License gives permission license work way, invalidate permission separately received . work interactive user interfaces, must display Appropriate Legal Notices; however, Program interactive interfaces display Appropriate Legal Notices, work need make . compilation covered work separate independent works, nature extensions covered work, combined form larger program, volume storage distribution medium, called “aggregate” compilation resulting copyright used limit access legal rights compilation’s users beyond individual works permit. Inclusion covered work aggregate cause License apply parts aggregate.","code":""},{"path":"/LICENSE.html","id":"id_6-conveying-non-source-forms","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"6. Conveying Non-Source Forms.","title":"GNU Affero General Public License","text":"may convey covered work object code form terms sections 4 5, provided also convey machine-readable Corresponding Source terms License, one ways: Convey object code , embodied , physical product (including physical distribution medium), accompanied Corresponding Source fixed durable physical medium customarily used software interchange. Convey object code , embodied , physical product (including physical distribution medium), accompanied written offer, valid least three years valid long offer spare parts customer support product model, give anyone possesses object code either (1) copy Corresponding Source software product covered License, durable physical medium customarily used software interchange, price reasonable cost physically performing conveying source, (2) access copy Corresponding Source network server charge. Convey individual copies object code copy written offer provide Corresponding Source. alternative allowed occasionally noncommercially, received object code offer, accord subsection 6b. Convey object code offering access designated place (gratis charge), offer equivalent access Corresponding Source way place charge. need require recipients copy Corresponding Source along object code. place copy object code network server, Corresponding Source may different server (operated third party) supports equivalent copying facilities, provided maintain clear directions next object code saying find Corresponding Source. Regardless server hosts Corresponding Source, remain obligated ensure available long needed satisfy requirements. Convey object code using peer--peer transmission, provided inform peers object code Corresponding Source work offered general public charge subsection 6d. separable portion object code, whose source code excluded Corresponding Source System Library, need included conveying object code work. “User Product” either (1) “consumer product”, means tangible personal property normally used personal, family, household purposes, (2) anything designed sold incorporation dwelling. determining whether product consumer product, doubtful cases shall resolved favor coverage. particular product received particular user, “normally used” refers typical common use class product, regardless status particular user way particular user actually uses, expects expected use, product. product consumer product regardless whether product substantial commercial, industrial non-consumer uses, unless uses represent significant mode use product. “Installation Information” User Product means methods, procedures, authorization keys, information required install execute modified versions covered work User Product modified version Corresponding Source. information must suffice ensure continued functioning modified object code case prevented interfered solely modification made. convey object code work section , , specifically use , User Product, conveying occurs part transaction right possession use User Product transferred recipient perpetuity fixed term (regardless transaction characterized), Corresponding Source conveyed section must accompanied Installation Information. requirement apply neither third party retains ability install modified object code User Product (example, work installed ROM). requirement provide Installation Information include requirement continue provide support service, warranty, updates work modified installed recipient, User Product modified installed. Access network may denied modification materially adversely affects operation network violates rules protocols communication across network. Corresponding Source conveyed, Installation Information provided, accord section must format publicly documented (implementation available public source code form), must require special password key unpacking, reading copying.","code":""},{"path":"/LICENSE.html","id":"id_7-additional-terms","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"7. Additional Terms.","title":"GNU Affero General Public License","text":"“Additional permissions” terms supplement terms License making exceptions one conditions. Additional permissions applicable entire Program shall treated though included License, extent valid applicable law. additional permissions apply part Program, part may used separately permissions, entire Program remains governed License without regard additional permissions. convey copy covered work, may option remove additional permissions copy, part . (Additional permissions may written require removal certain cases modify work.) may place additional permissions material, added covered work, can give appropriate copyright permission. Notwithstanding provision License, material add covered work, may (authorized copyright holders material) supplement terms License terms: Disclaiming warranty limiting liability differently terms sections 15 16 License; Requiring preservation specified reasonable legal notices author attributions material Appropriate Legal Notices displayed works containing ; Prohibiting misrepresentation origin material, requiring modified versions material marked reasonable ways different original version; Limiting use publicity purposes names licensors authors material; Declining grant rights trademark law use trade names, trademarks, service marks; Requiring indemnification licensors authors material anyone conveys material (modified versions ) contractual assumptions liability recipient, liability contractual assumptions directly impose licensors authors. non-permissive additional terms considered “restrictions” within meaning section 10. Program received , part , contains notice stating governed License along term restriction, may remove term. license document contains restriction permits relicensing conveying License, may add covered work material governed terms license document, provided restriction survive relicensing conveying. add terms covered work accord section, must place, relevant source files, statement additional terms apply files, notice indicating find applicable terms. Additional terms, permissive non-permissive, may stated form separately written license, stated exceptions; requirements apply either way.","code":""},{"path":"/LICENSE.html","id":"id_8-termination","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"8. Termination.","title":"GNU Affero General Public License","text":"may propagate modify covered work except expressly provided License. attempt otherwise propagate modify void, automatically terminate rights License (including patent licenses granted third paragraph section 11). However, cease violation License, license particular copyright holder reinstated () provisionally, unless copyright holder explicitly finally terminates license, (b) permanently, copyright holder fails notify violation reasonable means prior 60 days cessation. Moreover, license particular copyright holder reinstated permanently copyright holder notifies violation reasonable means, first time received notice violation License (work) copyright holder, cure violation prior 30 days receipt notice. Termination rights section terminate licenses parties received copies rights License. rights terminated permanently reinstated, qualify receive new licenses material section 10.","code":""},{"path":"/LICENSE.html","id":"id_9-acceptance-not-required-for-having-copies","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"9. Acceptance Not Required for Having Copies.","title":"GNU Affero General Public License","text":"required accept License order receive run copy Program. Ancillary propagation covered work occurring solely consequence using peer--peer transmission receive copy likewise require acceptance. However, nothing License grants permission propagate modify covered work. actions infringe copyright accept License. Therefore, modifying propagating covered work, indicate acceptance License .","code":""},{"path":"/LICENSE.html","id":"id_10-automatic-licensing-of-downstream-recipients","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"10. Automatic Licensing of Downstream Recipients.","title":"GNU Affero General Public License","text":"time convey covered work, recipient automatically receives license original licensors, run, modify propagate work, subject License. responsible enforcing compliance third parties License. “entity transaction” transaction transferring control organization, substantially assets one, subdividing organization, merging organizations. propagation covered work results entity transaction, party transaction receives copy work also receives whatever licenses work party’s predecessor interest give previous paragraph, plus right possession Corresponding Source work predecessor interest, predecessor can get reasonable efforts. may impose restrictions exercise rights granted affirmed License. example, may impose license fee, royalty, charge exercise rights granted License, may initiate litigation (including cross-claim counterclaim lawsuit) alleging patent claim infringed making, using, selling, offering sale, importing Program portion .","code":""},{"path":"/LICENSE.html","id":"id_11-patents","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"11. Patents.","title":"GNU Affero General Public License","text":"“contributor” copyright holder authorizes use License Program work Program based. work thus licensed called contributor’s “contributor version”. contributor’s “essential patent claims” patent claims owned controlled contributor, whether already acquired hereafter acquired, infringed manner, permitted License, making, using, selling contributor version, include claims infringed consequence modification contributor version. purposes definition, “control” includes right grant patent sublicenses manner consistent requirements License. contributor grants non-exclusive, worldwide, royalty-free patent license contributor’s essential patent claims, make, use, sell, offer sale, import otherwise run, modify propagate contents contributor version. following three paragraphs, “patent license” express agreement commitment, however denominated, enforce patent (express permission practice patent covenant sue patent infringement). “grant” patent license party means make agreement commitment enforce patent party. convey covered work, knowingly relying patent license, Corresponding Source work available anyone copy, free charge terms License, publicly available network server readily accessible means, must either (1) cause Corresponding Source available, (2) arrange deprive benefit patent license particular work, (3) arrange, manner consistent requirements License, extend patent license downstream recipients. “Knowingly relying” means actual knowledge , patent license, conveying covered work country, recipient’s use covered work country, infringe one identifiable patents country reason believe valid. , pursuant connection single transaction arrangement, convey, propagate procuring conveyance , covered work, grant patent license parties receiving covered work authorizing use, propagate, modify convey specific copy covered work, patent license grant automatically extended recipients covered work works based . patent license “discriminatory” include within scope coverage, prohibits exercise , conditioned non-exercise one rights specifically granted License. may convey covered work party arrangement third party business distributing software, make payment third party based extent activity conveying work, third party grants, parties receive covered work , discriminatory patent license () connection copies covered work conveyed (copies made copies), (b) primarily connection specific products compilations contain covered work, unless entered arrangement, patent license granted, prior 28 March 2007. Nothing License shall construed excluding limiting implied license defenses infringement may otherwise available applicable patent law.","code":""},{"path":"/LICENSE.html","id":"id_12-no-surrender-of-others-freedom","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"12. No Surrender of Others’ Freedom.","title":"GNU Affero General Public License","text":"conditions imposed (whether court order, agreement otherwise) contradict conditions License, excuse conditions License. convey covered work satisfy simultaneously obligations License pertinent obligations, consequence may convey . example, agree terms obligate collect royalty conveying convey Program, way satisfy terms License refrain entirely conveying Program.","code":""},{"path":"/LICENSE.html","id":"id_13-remote-network-interaction-use-with-the-gnu-general-public-license","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"13. Remote Network Interaction; Use with the GNU General Public License.","title":"GNU Affero General Public License","text":"Notwithstanding provision License, modify Program, modified version must prominently offer users interacting remotely computer network (version supports interaction) opportunity receive Corresponding Source version providing access Corresponding Source network server charge, standard customary means facilitating copying software. Corresponding Source shall include Corresponding Source work covered version 3 GNU General Public License incorporated pursuant following paragraph. Notwithstanding provision License, permission link combine covered work work licensed version 3 GNU General Public License single combined work, convey resulting work. terms License continue apply part covered work, work combined remain governed version 3 GNU General Public License.","code":""},{"path":"/LICENSE.html","id":"id_14-revised-versions-of-this-license","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"14. Revised Versions of this License.","title":"GNU Affero General Public License","text":"Free Software Foundation may publish revised /new versions GNU Affero General Public License time time. new versions similar spirit present version, may differ detail address new problems concerns. version given distinguishing version number. Program specifies certain numbered version GNU Affero General Public License “later version” applies , option following terms conditions either numbered version later version published Free Software Foundation. Program specify version number GNU Affero General Public License, may choose version ever published Free Software Foundation. Program specifies proxy can decide future versions GNU Affero General Public License can used, proxy’s public statement acceptance version permanently authorizes choose version Program. Later license versions may give additional different permissions. However, additional obligations imposed author copyright holder result choosing follow later version.","code":""},{"path":"/LICENSE.html","id":"id_15-disclaimer-of-warranty","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"15. Disclaimer of Warranty.","title":"GNU Affero General Public License","text":"WARRANTY PROGRAM, EXTENT PERMITTED APPLICABLE LAW. EXCEPT OTHERWISE STATED WRITING COPYRIGHT HOLDERS /PARTIES PROVIDE PROGRAM “” WITHOUT WARRANTY KIND, EITHER EXPRESSED IMPLIED, INCLUDING, LIMITED , IMPLIED WARRANTIES MERCHANTABILITY FITNESS PARTICULAR PURPOSE. ENTIRE RISK QUALITY PERFORMANCE PROGRAM . PROGRAM PROVE DEFECTIVE, ASSUME COST NECESSARY SERVICING, REPAIR CORRECTION.","code":""},{"path":"/LICENSE.html","id":"id_16-limitation-of-liability","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"16. Limitation of Liability.","title":"GNU Affero General Public License","text":"EVENT UNLESS REQUIRED APPLICABLE LAW AGREED WRITING COPYRIGHT HOLDER, PARTY MODIFIES /CONVEYS PROGRAM PERMITTED , LIABLE DAMAGES, INCLUDING GENERAL, SPECIAL, INCIDENTAL CONSEQUENTIAL DAMAGES ARISING USE INABILITY USE PROGRAM (INCLUDING LIMITED LOSS DATA DATA RENDERED INACCURATE LOSSES SUSTAINED THIRD PARTIES FAILURE PROGRAM OPERATE PROGRAMS), EVEN HOLDER PARTY ADVISED POSSIBILITY DAMAGES.","code":""},{"path":"/LICENSE.html","id":"id_17-interpretation-of-sections-15-and-16","dir":"","previous_headings":"TERMS AND CONDITIONS","what":"17. Interpretation of Sections 15 and 16.","title":"GNU Affero General Public License","text":"disclaimer warranty limitation liability provided given local legal effect according terms, reviewing courts shall apply local law closely approximates absolute waiver civil liability connection Program, unless warranty assumption liability accompanies copy Program return fee. END TERMS CONDITIONS","code":""},{"path":"/LICENSE.html","id":"how-to-apply-these-terms-to-your-new-programs","dir":"","previous_headings":"","what":"How to Apply These Terms to Your New Programs","title":"GNU Affero General Public License","text":"develop new program, want greatest possible use public, best way achieve make free software everyone can redistribute change terms. , attach following notices program. safest attach start source file effectively state exclusion warranty; file least “copyright” line pointer full notice found. Also add information contact electronic paper mail. software can interact users remotely computer network, also make sure provides way users get source. example, program web application, interface display “Source” link leads users archive code. many ways offer source, different solutions better different programs; see section 13 specific requirements. also get employer (work programmer) school, , sign “copyright disclaimer” program, necessary. information , apply follow GNU AGPL, see https://www.gnu.org/licenses/.","code":" Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see ."},{"path":"/articles/VoCC.html","id":"example-1-prediction-of-biogeographical-shifts","dir":"Articles","previous_headings":"","what":"Example 1: Prediction of biogeographical shifts","title":"VoCC","text":"look first “marshift” global data set containing reported range shifts marine species corresponding given periods time. Next, calculate gradient- distance-based velocities (1960-2009), using HadiSST data set, later extract corresponding values observed shift. Next, extract mean velocity estimates reported shift taking average grid cell values within circle radius equal reported range-shift distance. used fit simple linear regression models observed range shifts climate velocity. Distance-based velocities strictly positive definition, compare like like change first sign negative present local climates warmer future analogues. Produce observed vs predicted scatterplots regression lines (Fig. 2 Garcia Molinos et al. 2019).","code":"str(marshift) #> 'data.frame': 343 obs. of 6 variables: #> $ lat : num 49.7 53.8 53.8 40 43 ... #> $ long : num -4.33 5 5 1 -9.3 -1.4 -9.3 -71.7 -71.7 -71.7 ... #> $ timespan : int 30 40 40 55 35 35 84 39 26 54 ... #> $ years_data: int 23 40 40 15 4 2 5 2 2 2 ... #> $ taxa : Factor w/ 12 levels \"Benthic algae\",..: 6 6 6 6 3 3 4 5 5 5 ... #> $ Shift : num 536.1 65.6 95.9 40 10 ... HadiSST <- terra::rast(system.file(\"extdata\", \"HadiSST.tif\", package = \"VoCCdata\")) # monthly to annual averages r <- sumSeries(HadiSST, p = \"1960-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HadiSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\") vt <- tempTrend(r, th = 10) # temporal trend vg <- spatGrad(r, th = 0.0001, projected = FALSE) # spatial gradient gv <- gVoCC(vt, vg) # climate velocity # Now the distance-based velocities # Take 1960-1970 as base period against 2000-2009 r2 <- c(terra::mean(r[[1:10]], na.rm = TRUE), terra::mean(r[[41:50]], na.rm = TRUE)) # prepare the data frame with the necessary variables clim <- na.omit(data.frame(terra::values(r2), cid = 1:terra::ncell(r))) clim[, c(\"x\", \"y\")] <- terra::xyFromCell(r, clim$cid) # 1965-2004 (40 yr), 500 km search radius v <- dVoCC(clim, n = 1, tdiff = 40, method = \"Single\", climTol = 0.1, geoTol = 500, distfun = \"GreatCircle\", trans = NA, lonlat = TRUE) # Change sign as needed and create the distance-based velocity raster # Change sign as needed - terra approach for value comparison focal_vals <- terra::values(r2[[1]])[v$focal] target_vals <- terra::values(r2[[2]])[v$target] ind <- which(focal_vals > target_vals) v$velBis <- v$vel v$velBis[ind] <- v$vel[ind] * -1 # put output in raster format - create single layer empty template like raster(gv) dv <- terra::rast(terra::ext(gv), resolution = terra::res(gv), crs = terra::crs(gv)) dv[v$focal] <- v$velBis # Create point geometries and buffer them coords <- terra::vect(cbind(marshift$long, marshift$lat), crs = \"EPSG:4326\") buffer_size <- marshift$Shift * (marshift$timespan / 10) * 1000 # Get the mean velocity within the buffer for each data point. # Match old raster::extract approach exactly marshift$GV <- terra::extract(abs(gv[[1]]), coords, buffer = buffer_size, fun = mean, na.rm = TRUE, weights = TRUE, exact = FALSE)[,2] marshift$DV <- terra::extract(abs(dv), coords, buffer = buffer_size, fun = mean, na.rm = TRUE, weights = TRUE, exact = FALSE)[,2] # For points that didn't get values (NA), find nearest valid cells missing_points <- coords[is.na(marshift$GV)] # Identify NAs if(!is.empty(missing_points)){ marine_cells <- terra::as.points(gv[[1]]) # vector of all valid marine cell locations. nearest_indices <- terra::nearest(missing_points, marine_cells) # Find the nearest marine cell nearest_values <- terra::extract(gv[[1]], marine_cells[nearest_indices]) # get the values from the nearest marine cells. marshift$GV[is.na(marshift$GV)] <- nearest_values[, 2] # Replace the NA values in `marshift$GV` } missing_points <- coords[is.na(marshift$DV)] # Identify NAs if(!is.empty(missing_points)){ marine_cells <- terra::as.points(dv[[1]]) # vector of all valid marine cell locations. nearest_cells <- terra::nearest(missing_points, marine_cells) # Find the nearest marine cell nearest_values <- terra::extract(dv[[1]], nearest_cells) # get the values from the nearest marine cells. marshift$DV[is.na(marshift$DV)] <- nearest_values[, 2] # Replace the NA values in `marshift$GV` } # fit the regression models Mgv <- lm(Shift^(1 / 4) ~ I((GV * 10)^(1 / 4)), data = marshift, weights = years_data) summary(Mgv) #> #> Call: #> lm(formula = Shift^(1/4) ~ I((GV * 10)^(1/4)), data = marshift, #> weights = years_data) #> #> Weighted Residuals: #> Min 1Q Median 3Q Max #> -8.7627 -2.3540 -0.5463 1.5966 14.8297 #> #> Coefficients: #> Estimate Std. Error t value Pr(>|t|) #> (Intercept) 1.20025 0.23469 5.114 5.28e-07 *** #> I((GV * 10)^(1/4)) 0.50348 0.09599 5.245 2.75e-07 *** #> --- #> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 #> #> Residual standard error: 3.865 on 340 degrees of freedom #> (1 observation deleted due to missingness) #> Multiple R-squared: 0.07486, Adjusted R-squared: 0.07214 #> F-statistic: 27.51 on 1 and 340 DF, p-value: 2.75e-07 Mdv <- lm(Shift^(1 / 4) ~ I((DV * 10)^(1 / 4)), data = marshift, weights = years_data) summary(Mdv) #> #> Call: #> lm(formula = Shift^(1/4) ~ I((DV * 10)^(1/4)), data = marshift, #> weights = years_data) #> #> Weighted Residuals: #> Min 1Q Median 3Q Max #> -9.1097 -2.3602 -0.7524 1.6379 15.2653 #> #> Coefficients: #> Estimate Std. Error t value Pr(>|t|) #> (Intercept) 0.8565 0.3371 2.541 0.0115 * #> I((DV * 10)^(1/4)) 0.6192 0.1335 4.636 5.07e-06 *** #> --- #> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 #> #> Residual standard error: 3.904 on 338 degrees of freedom #> (3 observations deleted due to missingness) #> Multiple R-squared: 0.05979, Adjusted R-squared: 0.05701 #> F-statistic: 21.5 on 1 and 338 DF, p-value: 5.074e-06 # first compare both velocities p1 <- ggplot() + geom_spatraster(data = gv[[1]]) + scale_fill_distiller(palette = \"RdBu\", direction = -1, limits = c(-50, 50)) + ggtitle(\"Gradient-based vocc\") + scale_x_continuous(expand = c(0,0)) + scale_y_continuous(expand = c(0,0)) p2 <- ggplot() + geom_spatraster(data = dv[[1]]) + scale_fill_distiller(palette = \"RdBu\", direction = -1, limits = c(-20, 20)) + ggtitle(\"Distance-based vocc\") + scale_x_continuous(expand = c(0,0)) + scale_y_continuous(expand = c(0,0)) wrap_plots(p1, p2, ncol = 1) # scatter plots with the resulting regression line p1 <- ggplot(na.omit(marshift), aes(x = (GV * 10)^(1 / 4), y = Shift^(1 / 4))) + geom_point(color = \"grey\") + geom_smooth(method = lm, se = FALSE) + theme_classic() + scale_color_brewer(palette = \"Accent\") + labs(x = \"Predicted shift (x^1/4; km/yr)\", y = \"Observed shift (y^1/4; km/yr)\") p2 <- ggplot(na.omit(marshift), aes(x = (DV * 10)^(1 / 4), y = Shift^(1 / 4))) + geom_point(color = \"grey\") + geom_smooth(method = lm, se = FALSE) + theme_classic() + scale_color_brewer(palette = \"Accent\") + labs(x = \"Predicted shift (x^1/4; km/yr)\", y = \"Observed shift (y^1/4; km/yr)\") wrap_plots(p1, p2, nrow = 1) #> `geom_smooth()` using formula = 'y ~ x' #> `geom_smooth()` using formula = 'y ~ x' #> Warning: Removed 2 rows containing non-finite outside the scale range #> (`stat_smooth()`). #> Warning: Removed 2 rows containing missing values or values outside the scale range #> (`geom_point()`)."},{"path":"/articles/VoCC.html","id":"example-2-analysis-of-climate-exposure-and-connectivity-in-the-western-pacific-ocean","dir":"Articles","previous_headings":"","what":"Example 2: Analysis of climate exposure and connectivity in the Western Pacific Ocean","title":"VoCC","text":"example use climate velocity trajectories (based 1960-2009 mean annual SST) analyse climate connectivity Western Pacific region calculate residence time corresponding exclusive economic zones region index climatic exposure. First, arrange raster layers analysis. can now populate data frame cell centroid coordinates trajectories. Let’s calculate trajectories parallel processing demonstrate can used speed things (especially useful dealing fine resolutions large extents). Plot climate velocities EEZ polygons EEZs data set (Fig. 3a Garcia Molinos et al. 2019) now calculate trajectory classes residence times EEZ using traj25 data set. Finally let’s plot category proportions pie charts top EEZ, size chart proportional respective residence time (Fig. 3b Garcia Molinos et al. 2019).","code":"# prepare raster layers vel <- gv[[1]] ang <- gv[[2]] mn <- terra::app(r, mean, na.rm = T) # generate a velocity layer centered and cropped to study region to extract the initial coordinates for the trajectories from x1 <- terra::crop(gv[[1]], terra::ext(-180, 0, -90, 90)) x2 <- terra::crop(gv[[1]], terra::ext(0, 180, -90, 90)) terra::ext(x1) <- c(180, 360, -90, 90) velc <- terra::merge(x1, x2) # crop to the desired extent # display restricted to +180 longitude to avoid plotting issues with date line crossing velc <- terra::crop(velc, c(90, 180, -32, 33)) lonlat <- data.frame(terra::xyFromCell(velc, 1:ncell(velc))) lonlat$vel <- terra::extract(vel, lonlat, ID = FALSE) lonlat$ang <- terra::extract(ang, lonlat[, 1:2], ID = FALSE) lonlat$mn <- terra::extract(mn, lonlat[, 1:2], ID = FALSE) lonlat$lineID <- 1:nrow(lonlat) lonlat <- drop_na(lonlat) traj <- voccTraj(lonlat, vel, ang, mn, x_res = terra::res(vel)[1], y_res = terra::res(vel)[2], tyr = 50, tstep = 1/12) # create the spatial object with the trajectories and plot them together with the EEZ polygons lns <- trajLine(traj) # mirai::daemons(0) # Set daemons to 0 to close cluster # Load and simplify polygons to speed plotting up EEZs <- sf::st_read(system.file(\"extdata\", \"EEZs.gpkg\", package = \"VoCCdata\")) %>% sf::st_break_antimeridian() %>% sf::st_simplify(preserveTopology = TRUE, dTolerance = 500) %>% sf::st_crop(xmin = 75, xmax = 180, ymin = -35, ymax = 35) #> Reading layer `EEZs' from data source #> `/Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/library/VoCCdata/extdata/EEZs.gpkg' #> using driver `GPKG' #> Simple feature collection with 35 features and 22 fields #> Geometry type: MULTIPOLYGON #> Dimension: XY #> Bounding box: xmin: -179.9999 ymin: -31.24447 xmax: 179.9999 ymax: 31.79787 #> Geodetic CRS: +proj=longlat +datum=WGS84 +no_defs ggplot() + geom_spatraster(data = velc, aes(fill = voccMag)) + scale_fill_viridis_c(option = \"inferno\", name = \"Velocity\") + geom_sf(data = lns %>% sf::st_shift_longitude(), colour = \"grey70\", linewidth = 0.1) + geom_sf(data = EEZs %>% sf::st_shift_longitude(), colour = \"white\", fill = NA, linewidth = 0.3) + scale_x_continuous(expand = c(0, 0)) + scale_y_continuous(expand = c(0, 0)) # classify trajectories (16 trajectories starting from each 1-deg cell cell) clas <- trajClas(traj25, vel, ang, mn, trajSt = 16, tyr = 50, nmL = 20, smL = 100, Nend = 45, Nst = 15, NFT = 70) # Extract proportions by categories for each EEZ v <- data.table(terra::extract(clas[[7]], EEZs, df = TRUE)) v[, TrajClas := as.character(TrajClas)] v[, ID := as.ordered(ID)] # proportions by class d <- prop.table(table(v), 1) # residence times by EEZ EEZa <- resTime(EEZs, vel, areapg = NA) D <- data.table(d) # put data in long format D[, name := as.character(EEZs$Territory1)[as.numeric(ID)]] # add EEZ names for reference D[, RT := as.character(EEZa$resTim)[as.numeric(ID)]] # prepare data frame to plot the pie charts with dt <- as.data.frame.matrix(d) dt$country <- as.character(EEZs$Territory1) coords <- sf::st_coordinates(sf::st_centroid(EEZs)) dt[, c(\"x\", \"y\")] <- coords[, c(\"X\", \"Y\")] dt$RT <- EEZa$resTim # # generate the plot plot(velc) plot(eez_simp, add = TRUE) mycol <- c(scales::alpha(rgb(192, 192, 192, maxColorValue = 255), 0.5), scales::alpha(rgb(204, 255, 204, maxColorValue = 255), 0.5), scales::alpha(rgb(255, 153, 51, maxColorValue = 255), 0.5), scales::alpha(rgb(255, 51, 51, maxColorValue = 255), 0.5), scales::alpha(rgb(51, 51, 255, maxColorValue = 255), 0.5), scales::alpha(rgb(204, 102, 0, maxColorValue = 255), 0.5), scales::alpha(rgb(204, 0, 204, maxColorValue = 255), 0.5), scales::alpha(rgb(255, 255, 51, maxColorValue = 255), 0.5), scales::alpha(rgb(153, 204, 255, maxColorValue = 255), 0.5)) # mylab = c(\"Non-moving\", \"Slow-moving\", \"Internal Sink\", \"Boundary sink\", # \"Source\", \"Internal sink\",\"Corridor\", \"Divergence\", \"Convergence\") for (i in 1:35) { add.pie(z = as.numeric(dt[i, 1:5]), x = dt[i, \"x\"], y = dt[i, \"y\"], radius = log(dt[i, \"RT\"]), col = mycol, labels = \"\") }"},{"path":"/articles/VoCC.html","id":"references","dir":"Articles","previous_headings":"","what":"References","title":"VoCC","text":"García Molinos, J., Schoeman, D. S., Brown, C. J. Burrows, M. T. (2019), VoCC: R package calculating velocity climate change related climatic metrics. Methods Ecol Evol. doi:10.1111/2041-210X.13295","code":""},{"path":"/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Jorge Garcia Molinos. Author, maintainer. David S. Schoeman. Author. Christopher J. Brown. Author. Michael T. Burrows. Author. Naoki H. Kumagai. Contributor.","code":""},{"path":"/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Garcia Molinos J, S. Schoeman D, J. Brown C, T. Burrows M (2025). VoCC: Velocity Climate Change related climatic metrics. R package version 0.0.1, https://mathmarecol.github.io/VoCC/.","code":"@Manual{, title = {VoCC: The Velocity of Climate Change and related climatic metrics}, author = {Jorge {Garcia Molinos} and David {S. Schoeman} and Christopher {J. Brown} and Michael {T. Burrows}}, year = {2025}, note = {R package version 0.0.1}, url = {https://mathmarecol.github.io/VoCC/}, }"},{"path":"/index.html","id":"vocc-the-velocity-of-climate-change-and-related-climatic-metrics","dir":"","previous_headings":"","what":"The Velocity of Climate Change and related climatic metrics","title":"The Velocity of Climate Change and related climatic metrics","text":"Jorge Garcia Molinos et al. 18 July 2019 package now release version (v 1.0.0). Please contact questions feed-back.","code":""},{"path":"/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"The Velocity of Climate Change and related climatic metrics","text":"can install development version VoCC GitHub :","code":"# install.packages(\"devtools\") devtools::install_github(\"JorGarMol/VoCC\")"},{"path":[]},{"path":"/index.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"The Velocity of Climate Change and related climatic metrics","text":"cite package please use: García Molinos, J., Schoeman, D. S., Brown, C. J. Burrows, M. T. (2019). VoCC: Velocity Climate Change related climatic metrics. R package version 1.0.0. https://doi.org/10.5281/zenodo.3382092 following paper explains package functionality provides examples covered code package vignette García Molinos, J., Schoeman, D. S., Brown, C. J. Burrows, M. T. (2019), VoCC: R package calculating velocity climate change related climatic metrics. Methods Ecol Evol. doi:10.1111/2041-210X.13295","code":""},{"path":"/reference/EEZ.html","id":null,"dir":"Reference","previous_headings":"","what":"Icelandic Exclusive Economic Zone (EEZ) — EEZ","title":"Icelandic Exclusive Economic Zone (EEZ) — EEZ","text":"Icelandic Exclusive Economic Zone (v10).","code":""},{"path":"/reference/EEZ.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Icelandic Exclusive Economic Zone (EEZ) — EEZ","text":"spatial polygon data frame containing Icenalndic EEZ (200 NM).","code":""},{"path":"/reference/EEZ.html","id":"source","dir":"Reference","previous_headings":"","what":"Source","title":"Icelandic Exclusive Economic Zone (EEZ) — EEZ","text":"Marineregions.org http://www.marineregions.org/downloads.php","code":""},{"path":"/reference/HSST.html","id":null,"dir":"Reference","previous_headings":"","what":"Monthly mean sea surface temperatures (SST) around Iceland for 1955-2010 — HSST","title":"Monthly mean sea surface temperatures (SST) around Iceland for 1955-2010 — HSST","text":"Monthly mean sea surface temperatures (SST) around Iceland 1955-2010","code":""},{"path":"/reference/HSST.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Monthly mean sea surface temperatures (SST) around Iceland for 1955-2010 — HSST","text":"raster stack 672 layers containing mean monthly SSTs (C) 1-deg resolution period Jan 1955 Dec 2010 Atlantic waters surrounding Iceland.","code":""},{"path":"/reference/HSST.html","id":"source","dir":"Reference","previous_headings":"","what":"Source","title":"Monthly mean sea surface temperatures (SST) around Iceland for 1955-2010 — HSST","text":"Hadley Centre data set HadISST 1.1 (data accessed May 2018).","code":""},{"path":"/reference/HSST.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Monthly mean sea surface temperatures (SST) around Iceland for 1955-2010 — HSST","text":"Rayner et al. 2003. Global analyses sea surface temperature, sea ice, night marine air temperature since late nineteenth century. J. Geophys. Res.Vol. 108: 4407.","code":""},{"path":"/reference/JapTC.html","id":null,"dir":"Reference","previous_headings":"","what":"Multivariate Terraclimate data for Japan — JapTC","title":"Multivariate Terraclimate data for Japan — JapTC","text":"Historical (1960-1969) present (2008-2017) multivariate 1/24 Terraclimate data set (Abatzoglou et al. 2018), extracted Japanese archipelago including 3 variables: mean annual monthly precipitation (mm), maximum minimum temperatures (C).","code":""},{"path":"/reference/JapTC.html","id":"format","dir":"Reference","previous_headings":"","what":"Format","title":"Multivariate Terraclimate data for Japan — JapTC","text":"raster stack 9 layers historical (1960-1969) current (2008-2017) average (AnMn) standard deviation (AnMnSD) mean annual (AnMn) precipitation (Ppr), maximum (Tmax) minimum (Tmin) temperature.","code":""},{"path":"/reference/JapTC.html","id":"source","dir":"Reference","previous_headings":"","what":"Source","title":"Multivariate Terraclimate data for Japan — JapTC","text":"Terraclimate data set.","code":""},{"path":"/reference/JapTC.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Multivariate Terraclimate data for Japan — JapTC","text":"Abatzoglou et al. 2018. Terraclimate, high-resolution global dataset monthly climate climatic water balance 1958-2015, Scientific Data, 5: 170191","code":""},{"path":"/reference/angulo.html","id":null,"dir":"Reference","previous_headings":"","what":"Internal. Angle associated to the spatial gradient — angulo","title":"Internal. Angle associated to the spatial gradient — angulo","text":"Internal. Angle associated spatial gradient","code":""},{"path":"/reference/angulo.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Internal. Angle associated to the spatial gradient — angulo","text":"","code":"angulo(dx, dy)"},{"path":"/reference/angulo.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Internal. Angle associated to the spatial gradient — angulo","text":"dx numeric giving longitudinal gradient component dy numeric giving latitudinal gradient component","code":""},{"path":"/reference/angulo.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Internal. Angle associated to the spatial gradient — angulo","text":"Jorge Garcia Molinos David S. Schoeman angulo()","code":""},{"path":"/reference/check_mirai_daemons.html","id":null,"dir":"Reference","previous_headings":"","what":"Check for mirai daemons and provide a helpful message. — check_mirai_daemons","title":"Check for mirai daemons and provide a helpful message. — check_mirai_daemons","text":"utility function checks status `mirai` daemons. daemons found, prints user-friendly message explaining parallel processing active provides suggestion user launch .","code":""},{"path":"/reference/check_mirai_daemons.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check for mirai daemons and provide a helpful message. — check_mirai_daemons","text":"","code":"check_mirai_daemons()"},{"path":"/reference/check_mirai_daemons.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check for mirai daemons and provide a helpful message. — check_mirai_daemons","text":"NULL, invisibly. function called side effects.","code":""},{"path":"/reference/climPCA.html","id":null,"dir":"Reference","previous_headings":"","what":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"Function extract first n principal components explaining predefined total amount variance among climatic variables. components can subsequently used synthetic climatic variables reduce dimensionality climate-analogue methods.","code":""},{"path":"/reference/climPCA.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"","code":"climPCA( climp, climf, trans = function(x) log(x), cen = TRUE, sc = TRUE, th = 0.8 )"},{"path":"/reference/climPCA.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"climp raster.stack one layer climatic variable values present baseline conditions. climf raster.stack one layer climatic variable values future conditions. trans function specifying type transformation applied prior PCA. Specify NA transformation required (default log(x)). cen logical variables centered prior PCA? (default TRUE). sc logical variables scaled prior PCA? (default TRUE). th numeric threshold giving minimum amount total variance explained principal components extracted.","code":""},{"path":"/reference/climPCA.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"list containing () output PCA (call 'prcomp'), (ii) table present/future cell values principal components accounting specified percentage total variance (th).","code":""},{"path":[]},{"path":"/reference/climPCA.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/climPCA.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Reduce dimensionality of climate predictors via Principal Component Analysis — climPCA","text":"","code":"if (FALSE) { # \\dontrun{ JapTC <- VoCC_get_data(\"JapTC.tif\") comp <- climPCA(JapTC[[c(1, 3, 5)]], JapTC[[c(2, 4, 6)]], trans = NA, cen = TRUE, sc = TRUE, th = 0.85) summary(comp[[1]]) # first two components explain >90% of variance # Create a data frame with the necessary variables in the required order (see climAna? for details) clim <- comp[[2]][, c(2, 4, 3, 5, 1)] clim[, c(\"x\", \"y\")] <- terra::xyFromCell(JapTC[[1]], clim$cid) } # }"},{"path":"/reference/climPlot.html","id":null,"dir":"Reference","previous_headings":"","what":"Binned scatter plot for 2-dimensional climate space — climPlot","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"Function create binned scatter plot two climate variables.","code":""},{"path":"/reference/climPlot.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"","code":"climPlot(xy, x.binSize, y.binSize, x.name = \"V1\", y.name = \"V2\")"},{"path":"/reference/climPlot.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"xy data.frame cells rows 4 columns representing present future local values two variables (V1p, V1f, V2p, V2f). x.binSize numeric bin size first variable. y.binSize numeric bin size second variable. x.name character variable name first variable. Used label plot. y.name character variable name second variable. Used label plot.","code":""},{"path":"/reference/climPlot.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"series plot objects displaying () present (ii) future cell frequency combination local climates, (iii) location remnant, novel disappearing climates periods.","code":""},{"path":[]},{"path":"/reference/climPlot.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"Jorge Garcia Molinos Naoki H. Kumagai","code":""},{"path":"/reference/climPlot.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Binned scatter plot for 2-dimensional climate space — climPlot","text":"","code":"if (FALSE) { # \\dontrun{ JapTC <- VoCC_get_data(\"JapTC.tif\") # Plot climate space for the two first variables(annual precipitation and maximum temperature) xy <- stats::na.omit(data.frame( terra::values(JapTC[[1]]), terra::values(JapTC[[2]]), terra::values(JapTC[[3]]), terra::values(JapTC[[4]]) )) out <- climPlot(xy, x.binSize = 5, y.binSize = 0.2, x.name = \"Precipitation (mm)\", y.name = \"Temperature max (°C)\" ) # output plots can be saved as: ggplot2::ggsave( plot = out, filename = file.path(getwd(), \"example_plot.pdf\"), width = 17, height = 17, unit = \"cm\" ) } # }"},{"path":"/reference/dVoCC.html","id":null,"dir":"Reference","previous_headings":"","what":"Distance-based velocity based on geographically closest climate analogue — dVoCC","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"Function calculate geographically closest climate analogues related distance-based velocity. Cell analogues identified comparing baseline climatic conditions focal cell existing (target) cells future reference specified climatic threshold. function allows specification search distances incorporates least-cost path Great Circle (--crow-flies) distances.","code":""},{"path":"/reference/dVoCC.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"","code":"dVoCC( clim, n, tdiff, method = \"Single\", climTol, geoTol, distfun = \"GreatCircle\", trans = NA, lonlat = TRUE )"},{"path":"/reference/dVoCC.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"clim data.frame value climatic parameters (columns) cell (rows), arranged follows (see examples ): first 2n columns must contain present future values n climatic variables (V1p, V1f, V2p, V2f,...). cell-specific analogue thresholds (see \"variable\" \"method\" ) calculated, next (2n+1:3n) columns contain standard deviation (measure climatic variability) variable baseline period. columns required using \"Single\" method. last three columns table contain identifyier centroid coordinates cell. n integer defining number climatic variables. tdiff integer defining number years (temporal unit) periods. method character string specifying analogue method used. 'Single': constant, single analogue threshold climate variable applied cells (Ohlemuller et al. 2006, Hamann et al. 2015); climate analogy corresponds target cells values specified threshold climatic variable. 'Variable': cell-specific climate threshold used climatic variable determine climate analogues associated cell reference baseline climatic variability (Garcia Molinos et al. 2017). climTol numeric vector length n giving tolerance threshold defining climate analogue conditions climatic variable. cell-specific threshold used, function parameter passed NA. geoTol integer impose geographical distance threshold (km lat/lon map units projected). used, pool potential climate analogues limited cells within distance focal cell. distfun character string specifying function used estimating distances focal target cells. Either 'Euclidean', 'GreatCircle' (Great Circle Distances). 'LeastCost' (Least Cost Path Distances) CURRENTLY IMPLEMENTED. LeastCost requires transition matrix supplied function via de 'trans' argument. trans TransitionLayer CURRENTLY IMPLEMENTED gdistance object used analogue search distfun = 'LeastCost'. lonlat logical analysis done unprojected (lon/lat) coordinates?","code":""},{"path":"/reference/dVoCC.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"data.frame containing cell id future analogue focal cell (NA = analogue available), together climatic (\"climDis\") geographical (\"geoDis\") distances input units, bearing (\"ang\", degrees North), resulting climate velocity (\"vel\", km/yr). Mean climatic distances returned multivariate analogues.","code":""},{"path":"/reference/dVoCC.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"Ohlemuller et al. 2006. Towards European climate risk surfaces: extent distribution analogous non-analogous climates 1931-2100. Global Ecology Biogeography, 15, 395-405. Hamann et al. 2015. Velocity climate change algorithms guiding conservation management. Global Change Biology, 21, 997-1004. Garcia Molinos et al. 2017. Improving interpretability climate landscape metrics: ecological risk analysis Japan's Marine Protected Areas. Global Change Biology, 23, 4440-4452.","code":""},{"path":[]},{"path":"/reference/dVoCC.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/dVoCC.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Distance-based velocity based on geographically closest climate analogue — dVoCC","text":"","code":"if (FALSE) { # \\dontrun{ JapTC <- VoCC_get_data(\"JapTC.tif\") # Create a data frame with the necessary variables in the required order clim <- stats::na.omit(data.frame(terra::values(JapTC), cid = 1:terra::ncell(JapTC))) clim[, c(\"x\", \"y\")] <- terra::xyFromCell(JapTC, clim$cid) # Constant threshold, distance-restricted velocity based on geographical distances avocc1 <- dVoCC(clim, n = 3, tdiff = 40, method = \"Single\", climTol = c(10, 0.1, 0.1), geoTol = 160, distfun = \"GreatCircle\", trans = NA, lonlat = TRUE ) r1 <- JapTC[[1]] r1[avocc1$focal] <- avocc1$vel terra::plot(r1) # Cell-specific, distance-unrestricted climate analogue velocity based on least-cost path distances # First, create the conductance matrix (all land cells considered to have conductance of 1) r <- JapTC[[1]] r[!is.na(JapTC[[1]])] <- 1 h8 <- gdistance::transition(r, transitionFunction = mean, directions = 8) h8 <- gdistance::geoCorrection(h8, type = \"c\") # Now calculate the analogue velocity using the baseline SD for each variable as analogue threshold avocc2 <- dVoCC(clim, n = 3, tdiff = 40, method = \"Variable\", climTol = NA, geoTol = Inf, distfun = \"LeastCost\", trans = h8, lonlat = TRUE ) # Plot results r1 <- r2 <- JapTC[[1]] r1[avocc1$focal] <- avocc1$vel r2[avocc2$focal] <- avocc2$vel terra::plot(c(r1, r2)) } # }"},{"path":"/reference/gVoCC.html","id":null,"dir":"Reference","previous_headings":"","what":"Gradient-based climate velocity — gVoCC","title":"Gradient-based climate velocity — gVoCC","text":"Function calculate velocity climate change Burrows et al. (2011) based local climatic temporal trends spatial gradients.","code":""},{"path":"/reference/gVoCC.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Gradient-based climate velocity — gVoCC","text":"","code":"gVoCC(tempTrend, spatGrad)"},{"path":"/reference/gVoCC.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Gradient-based climate velocity — gVoCC","text":"tempTrend output tempTrend function containing long-term linear climatic trends. spatGrad output spatGrad function containing magnitudes angles spatial climatic gradient.","code":""},{"path":"/reference/gVoCC.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Gradient-based climate velocity — gVoCC","text":"RasterStack containing climate velocity magnitude (\"voccMag\", km/yr unprojected rasters spatial unit/year projected rasters) angle(\"voccAng\" degrees north: 0N, 90E, 180S 270W).","code":""},{"path":"/reference/gVoCC.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Gradient-based climate velocity — gVoCC","text":"Burrows et al. 2011. pace shifting climate marine terrestrial ecosystems. Science, 334, 652-655.","code":""},{"path":[]},{"path":"/reference/gVoCC.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Gradient-based climate velocity — gVoCC","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/gVoCC.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Gradient-based climate velocity — gVoCC","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") yrSST <- sumSeries(HSST, p = \"1960-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) tr <- tempTrend(yrSST, th = 10) sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) # Magnitude and angle of the climate velocity (km/yr) 1960-2009 v <- gVoCC(tr, sg) terra::plot(v) } # }"},{"path":"/reference/pipe.html","id":null,"dir":"Reference","previous_headings":"","what":"Pipe operator — %>%","title":"Pipe operator — %>%","text":"See magrittr::%>% details.","code":""},{"path":"/reference/pipe.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Pipe operator — %>%","text":"","code":"lhs %>% rhs"},{"path":"/reference/pipe.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Pipe operator — %>%","text":"lhs value magrittr placeholder. rhs function call using magrittr semantics.","code":""},{"path":"/reference/pipe.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Pipe operator — %>%","text":"result calling `rhs(lhs)`.","code":""},{"path":"/reference/resTime.html","id":null,"dir":"Reference","previous_headings":"","what":"Climatic residence time of a polygon — resTime","title":"Climatic residence time of a polygon — resTime","text":"Function calculate VoCC-based residence time isotherms within polygon Loaire et al. (2009)","code":""},{"path":"/reference/resTime.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Climatic residence time of a polygon — resTime","text":"","code":"resTime(pg, vel, areapg = NA)"},{"path":"/reference/resTime.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Climatic residence time of a polygon — resTime","text":"pg sf object terra::vect object containing polygons residence time calculated. polygons must coordinate system vel. vel raster climate velocity (km/year) period interest. areapg vector area (km2) polygons. Use NA (default) calculate internally field avilable.","code":""},{"path":"/reference/resTime.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Climatic residence time of a polygon — resTime","text":"data.frame containing polygon ID, mean velocity (km/yr), diameter equivalent circle (km), residence time (years) ratio D/vel.","code":""},{"path":"/reference/resTime.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Climatic residence time of a polygon — resTime","text":"Loarie et al. 2009. velocity climate change. Nature, 462, 1052-1055.","code":""},{"path":[]},{"path":"/reference/resTime.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Climatic residence time of a polygon — resTime","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/resTime.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Climatic residence time of a polygon — resTime","text":"","code":"# Load example Exclusive Economic Zone polygon if (FALSE) { # \\dontrun{ EEZ <- VoCC_get_data(\"EEZ.gpkg\") HSST <- VoCC_get_data(\"HSST.tif\") yrSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) tr <- tempTrend(yrSST, th = 10) sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) v <- gVoCC(tr, sg) vel <- v[[1]] # Calculating area internally a1 <- resTime(EEZ, vel, areapg = NA) a1 # Using the area field from the polygon data table a2 <- resTime(EEZ, vel, areapg = as.numeric(as.numeric(levels(EEZ$Area_km2))[EEZ$Area_km2])) a2 # Using a user defined polygon x_coord <- c(-28, -20, -20.3, -25.5) y_coord <- c(60, 61, 63, 62) coords <- matrix(c(x_coord, y_coord), ncol = 2) poly_sf <- sf::st_sf(geometry = sf::st_sfc(sf::st_polygon(list(coords)))) a3 <- resTime(poly_sf, vel, areapg = NA) terra::plot(vel) plot(sf::st_geometry(EEZ), add = TRUE) plot(sf::st_geometry(poly_sf), add = TRUE) } # }"},{"path":"/reference/shiftTime.html","id":null,"dir":"Reference","previous_headings":"","what":"Shift in timing of seasonal climatology — shiftTime","title":"Shift in timing of seasonal climatology — shiftTime","text":"Function calculate seasonal shift arriving typical seasonal climates given period interest per Burrows et al. (2011).","code":""},{"path":"/reference/shiftTime.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Shift in timing of seasonal climatology — shiftTime","text":"","code":"shiftTime(r, yr1, yr2, yr0, th, m)"},{"path":"/reference/shiftTime.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Shift in timing of seasonal climatology — shiftTime","text":"r stack monthly values climatic variable period interest. yr1 integer specifying initial year period interest. yr2 integer specifying end year period interest. yr0 integer specifying first year series. th integer minimum number non NAs series needed calculate trend (default 3). m integer number (1-12) month shift calculated","code":""},{"path":"/reference/shiftTime.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Shift in timing of seasonal climatology — shiftTime","text":"stack long-term monthly trend (C/year temperature degrees; \"mTrend\"), seasonal rate change (C/month; \"seaRate\"), seasonal shift (day/decade; \"seaShift\").","code":""},{"path":"/reference/shiftTime.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Shift in timing of seasonal climatology — shiftTime","text":"Burrows et al. 2011. pace shifting climate marine terrestrial ecosystems. Science, 334, 652-655.","code":""},{"path":"/reference/shiftTime.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Shift in timing of seasonal climatology — shiftTime","text":"Jorge Garcia Molinos Michael T. Burrows","code":""},{"path":"/reference/shiftTime.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Shift in timing of seasonal climatology — shiftTime","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") Apr <- shiftTime(HSST, yr1 = 1960, yr2 = 2009, yr0 = 1955, th = 10, m = 4) terra::plot(Apr) } # }"},{"path":"/reference/spatGrad.html","id":null,"dir":"Reference","previous_headings":"","what":"Local spatial climatic gradients — spatGrad","title":"Local spatial climatic gradients — spatGrad","text":"Function calculate magnitude direction spatial gradient associated climatic variable Burrows et al. (2011). trend used calculation gradient-based climate velocity using gVoCC.","code":""},{"path":"/reference/spatGrad.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Local spatial climatic gradients — spatGrad","text":"","code":"spatGrad(r, th = -Inf, projected = FALSE)"},{"path":"/reference/spatGrad.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Local spatial climatic gradients — spatGrad","text":"r RasterStack annual climatic values period interest. Alternatively, raster annual climatic values averaged period interest. th Integer indicating lower threshold truncate spatial gradient . Use -Inf (default) threshold required. projected Logical source raster projected coordinate system? FALSE (default) correction made account latitudinal distortion.","code":""},{"path":"/reference/spatGrad.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Local spatial climatic gradients — spatGrad","text":"RasterStack magnitude spatial gradient (Grad C per km unprojected rasters C per spatial unit projected rasters), associated angle (Ang degrees).","code":""},{"path":"/reference/spatGrad.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Local spatial climatic gradients — spatGrad","text":"Burrows et al. 2011. pace shifting climate marine terrestrial ecosystems. Science, 334, 652-655.","code":""},{"path":[]},{"path":"/reference/spatGrad.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Local spatial climatic gradients — spatGrad","text":"Jorge Garcia Molinos, David S. Schoeman, Michael T. Burrows","code":""},{"path":"/reference/spatGrad.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Local spatial climatic gradients — spatGrad","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") yrSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) # Spatial gradient (magnitude and angle) for the average mean annual SST. sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) terra::plot(sg) } # }"},{"path":"/reference/splitLine.html","id":null,"dir":"Reference","previous_headings":"","what":"Internal. Split a line segment defined by points A-B into n parts — splitLine","title":"Internal. Split a line segment defined by points A-B into n parts — splitLine","text":"Internal. Split line segment defined points -B n parts","code":""},{"path":"/reference/splitLine.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Internal. Split a line segment defined by points A-B into n parts — splitLine","text":"","code":"splitLine(A, B, n)"},{"path":"/reference/splitLine.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Internal. Split a line segment defined by points A-B into n parts — splitLine","text":"numeric giving coordinates first point B numeric giving coordinates second point n numeric number segments divide distance points ","code":""},{"path":"/reference/splitLine.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Internal. Split a line segment defined by points A-B into n parts — splitLine","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/sumSeries.html","id":null,"dir":"Reference","previous_headings":"","what":"Summarize climatic series to higher temporal resolution — sumSeries","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"Function convert climatic series (provided RasterStack) coarser time frequency series period interest. function transforms RasterStack xts time series object extract values period interest apply summary function. mainly wrapper apply. function family package xts (Ryan Ulrich 2017).","code":""},{"path":"/reference/sumSeries.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"","code":"sumSeries( r, p, yr0, l = terra::nlyr(r), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" )"},{"path":"/reference/sumSeries.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"r RasterStack containing time series climatic variable. p character string defining period extract calculation series (see examples). yr0 character string specifying first (yr0) year series (see examples). l integer length input time series. fun logical summary function computed. Summary functions need applied cell (columns) structure 'function(x) apply(x, 2, function(y))'. convenience, sumSeries imports colMaxs, colMins package ‘matrixStats’ (Bengtsson 2018) can called directly. freqin character string specifying original time frequency series. freqout character string specifying desired time frequency new series. Must one following: \"weeks\", \"months\", \"quarters\", \"years\", \"\". Argument \"\" allows user-defined functions applied 'xts' time series object period interest (see examples).","code":""},{"path":"/reference/sumSeries.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"RasterStack new series.","code":""},{"path":"/reference/sumSeries.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"Ray Ulrich. 2017. xts: eXtensible Time Series. R package version 0.10-1. Bengtsson 2018. matrixStats: Functions Apply Rows Columns Matrices (Vectors). R package version 0.53.1.","code":""},{"path":"/reference/sumSeries.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/sumSeries.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Summarize climatic series to higher temporal resolution — sumSeries","text":"","code":"if (FALSE) { # \\dontrun{ # Monthly mean SST (HadISST) data for Europe Jan-1950 to Dec-2010 HSST <- VoCC_get_data(\"HSST.tif\") # Calculate mean annual monthly SST yrSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) # Extract Jul Aug mean SST each year (xts months are indexed from 0 to 11) myf <- function(x, m = c(7, 8)) { x[xts::.indexmon(x) %in% (m - 1)] } JlAugSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1950-01-01\", l = terra::nlyr(HSST), fun = myf, freqin = \"months\", freqout = \"other\" ) # Same but calculating the annual variance of the two months myf <- function(x, m = c(7, 8)) { x1 <- x[xts::.indexmon(x) %in% (m - 1)] xts::apply.yearly(x1, function(y) { apply(y, 2, function(y) { var(y, na.rm = TRUE) }) }) } meanJASST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1950-01-01\", l = terra::nlyr(HSST), fun = myf, freqin = \"months\", freqout = \"other\" ) } # }"},{"path":"/reference/tempTrend.html","id":null,"dir":"Reference","previous_headings":"","what":"Long-term local climatic trends — tempTrend","title":"Long-term local climatic trends — tempTrend","text":"Function calculate temporal trend raster series climatic variable. trend used calculation gradient-based climate velocity using gVoCC.","code":""},{"path":"/reference/tempTrend.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Long-term local climatic trends — tempTrend","text":"","code":"tempTrend(r, th)"},{"path":"/reference/tempTrend.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Long-term local climatic trends — tempTrend","text":"r RasterStack containing time series (annual, seasonal, monthly...) values climatic variable period interest. th Integer minimum number observations series needed calculate trend cell.","code":""},{"path":"/reference/tempTrend.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Long-term local climatic trends — tempTrend","text":"RasterStack containing cell-specific temporal trends extracted simple linear regressions climatic variable time (\"slpTrends\" degree Celsius per year), together standard errors (\"seTrends\") statistical significance (\"sigTrends\").","code":""},{"path":[]},{"path":"/reference/tempTrend.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Long-term local climatic trends — tempTrend","text":"Jorge Garcia Molinos Christopher J. Brown","code":""},{"path":"/reference/tempTrend.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Long-term local climatic trends — tempTrend","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") yrSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) # Mean annual SST trend (minimum threshold of 10 years of data), with SE and p-values. tr <- tempTrend(yrSST, th = 10) terra::plot(tr) } # }"},{"path":"/reference/trajClas.html","id":null,"dir":"Reference","previous_headings":"","what":"Climate velocity trajectory classification — trajClas","title":"Climate velocity trajectory classification — trajClas","text":"Function spatial classification cells based VoCC trajectories Burrows et al. (2014). function performs hierarchical sequential classification based length trajectories, geographical features, relative abundance trajectories ending , starting flowing cell. Essentially, cells first classified non-moving, slow-moving fast-moving relative distance trajectory cover projection period based local climate velocities. Two types climate sinks identified among fast-moving cells: () boundary (e.g., coastal) cells disconnected cooler (warmer) neighbouring cells locally warming (cooling) climate, (ii) locations endorheic spatial gradients velocity angles neighbouring cells converge towards central point intersection. Finally, remaining cells classified reference total number trajectories per cell based proportions number trajectories starting (Nst), ending (Nend), flowing (NFT) cell period. Based proportions, cells classified five classes: (1) climate sources, trajectories end cell (Nend = 0); (2) relative climate sinks, relative number trajectories ending cell high proportion starting trajectories low; (3) corridors cells high proportion trajectories passing ; (4) divergence (5) convergence cells identified remaining cells fewer/trajectories ended started cell, respectively.","code":""},{"path":"/reference/trajClas.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Climate velocity trajectory classification — trajClas","text":"","code":"trajClas( traj, vel, ang, mn, trajSt, tyr, nmL, smL, Nend, Nst, NFT, DateLine = FALSE )"},{"path":"/reference/trajClas.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Climate velocity trajectory classification — trajClas","text":"traj data.frame retuned voccTraj containing coordinates identification number trajectory. vel SpatRaster magnitude gradient-based climate velocity. ang SpatRaster velocity angles. mn SpatRaster mean climatic values study period. trajSt integer number trajectories starting cell spatial unit. tyr integer number years comprising projected period. nmL numeric upper threshold (distance units per vel object) trajectory considered traveled negligible distance study period (non-moving). smL numeric upper threshold trajectory considered traveled small distance study period (slow-moving). Nend numeric percentage trajectories ending used threshold classification. Nst numeric percentage trajectories starting used threshold classification. NFT numeric percentage trajectories flowing used threshold classification. DateLine logical raster extent cross international date line? (default \"FALSE\").","code":""},{"path":"/reference/trajClas.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Climate velocity trajectory classification — trajClas","text":"SpatRaster containing trajectory classification (\"TrajClas\"), well based trajectory length (\"ClassL\"; 1 non-moving, 2 slow-moving, 3 fast-moving cells), boundrary (\"BounS\") internal sinks (\"IntS\"), proportion trajectories ending(\"PropEnd\"), flowing (\"PropFT\") starting (\"PropSt\"). trajectory classes (\"TrajClas\") (1) non-moving, (2) slow-moving, (3) internal sinks, (4) boundary sinks, (5) sources, (6) relative sinks, (7) corridors, (8) divergence (9) convergence.","code":""},{"path":"/reference/trajClas.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Climate velocity trajectory classification — trajClas","text":"Burrows et al. 2014. Geographical limits species-range shifts suggested climate velocity. Nature, 507, 492-495.","code":""},{"path":[]},{"path":"/reference/trajClas.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Climate velocity trajectory classification — trajClas","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/trajClas.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Climate velocity trajectory classification — trajClas","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") # input raster layers yrSST <- sumSeries(HSST, p = \"1960-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) mn <- terra::mean(yrSST, na.rm = TRUE) tr <- tempTrend(yrSST, th = 10) sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) v <- gVoCC(tr, sg) vel <- v[[1]] ang <- v[[2]] # Get the set of starting cells for the trajectories and calculate trajectories # at 1/4-deg resolution (16 trajectories per 1-deg cell) mnd <- terra::disagg(mn, 4) veld <- terra::disagg(vel, 4) angd <- terra::disagg(ang, 4) lonlat <- stats::na.omit(data.frame( terra::xyFromCell(veld, 1:terra::ncell(veld)), terra::values(veld), terra::values(angd), terra::values(mnd) ))[, 1:2] traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) # Generate the trajectory-based classification clas <- trajClas(traj, vel, ang, mn, trajSt = 16, tyr = 50, nmL = 20, smL = 100, Nend = 45, Nst = 15, NFT = 70, DateLine = FALSE ) # Define first the colour palette for the full set of categories my_col <- c( \"gainsboro\", \"darkseagreen1\", \"coral4\", \"firebrick2\", \"mediumblue\", \"darkorange1\", \"magenta1\", \"cadetblue1\", \"yellow1\" ) # Keep only the categories present in our raster my_col <- my_col[sort(unique(terra::values(clas[[7]])))] # Classify raster / build attribute table clasr <- terra::as.factor(clas[[7]]) rat_r <- data.frame(ID = sort(unique(terra::values(clas[[7]]))), trajcat = c(\"N-M\", \"S-M\", \"IS\", \"BS\", \"Srce\", \"RS\", \"Cor\", \"Div\", \"Con\")[sort(unique(terra::values(clas[[7]])))]) terra::cats(clasr) <- rat_r # Produce the plot using the rasterVis levelplot function rasterVis::levelplot(clasr, col.regions = my_col, xlab = NULL, ylab = NULL, scales = list(draw = FALSE) ) } # }"},{"path":"/reference/trajLine.html","id":null,"dir":"Reference","previous_headings":"","what":"Climate velocity trajectory spatial lines — trajLine","title":"Climate velocity trajectory spatial lines — trajLine","text":"Create spatial line data frame object trajectory points.","code":""},{"path":"/reference/trajLine.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Climate velocity trajectory spatial lines — trajLine","text":"","code":"trajLine(x, projx = \"EPSG:4326\")"},{"path":"/reference/trajLine.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Climate velocity trajectory spatial lines — trajLine","text":"x data.frame containing coordinates (x, y) constituent points identification number (trajIDs) trajectory returned VoCCTraj. projx CRS detailing coordinate reference system input data (default geographic CRS).","code":""},{"path":"/reference/trajLine.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Climate velocity trajectory spatial lines — trajLine","text":"sf object one line per trajectory specified x. avoid artifacts, trajectories crossing date line need split two segments. trajectory one side date line composed single point, trajectory displayed (line object created). function assumes -180 180 longitudinal arrangement.","code":""},{"path":[]},{"path":"/reference/trajLine.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Climate velocity trajectory spatial lines — trajLine","text":"Jorge Garcia Molinos","code":""},{"path":"/reference/trajLine.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Climate velocity trajectory spatial lines — trajLine","text":"","code":"if (FALSE) { # \\dontrun{ HSST <- VoCC_get_data(\"HSST.tif\") yrSST <- sumSeries(HSST, p = \"1969-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) tr <- tempTrend(yrSST, th = 10) sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) v <- gVoCC(tr, sg) vel <- v[[1]] ang <- v[[2]] # calculate the annual SST mean over the period mn <- terra::mean(yrSST, na.rm = TRUE) # get the set of starting cells for the trajectories lonlat <- stats::na.omit(data.frame( terra::xyFromCell(vel, 1:terra::ncell(vel)), vel[], ang[], mn[] ))[, 1:2] # Calculate trajectories. traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) # create a spatial line data frame from traj lns <- trajLine(x = traj) terra::plot(mn) terra::plot(lns, add = TRUE) # Export as ESRI shape file terra::writeVector(lns, filename = \"velTraj\", filetype = \"ESRI Shapefile\") } # }"},{"path":"/reference/voccTraj.html","id":null,"dir":"Reference","previous_headings":"","what":"Climate velocity trajectories — voccTraj","title":"Climate velocity trajectories — voccTraj","text":"Function calculate vocc trajectories Burrows et al (2014). Trajectories calculated propagating climatic isopleths using magnitude direction local (cell) velocities. slightly modified version original Burrows et al. (2014) approach iterations trajectory based cumulative time traveled instead using fixed time steps.","code":""},{"path":"/reference/voccTraj.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Climate velocity trajectories — voccTraj","text":"","code":"voccTraj( lonlat, vel, ang, mn, x_res, y_res, tstep, tyr = 20, bfr = 75, grid_resolution = \"coarse\" )"},{"path":"/reference/voccTraj.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Climate velocity trajectories — voccTraj","text":"lonlat data.frame longitude latitude (decimal degrees) points project. vel raster magnitude gradient-based climate velocity. ang raster velocity angles degrees. mn raster overall mean climatic value period interest. x_res Numeric. Resolution grid longitude direction (degrees km). y_res Numeric. Resolution grid latitude direction (degrees km). tstep Numeric. Timestep trajectory iteration (usually decimal year). tyr Integer. Temporal length period interest (years). grid_resolution Character. \"coarse\" (default) \"fine\". Controls land crossings handled allows higher resolution grids.","code":""},{"path":"/reference/voccTraj.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Climate velocity trajectories — voccTraj","text":"tibble containing coordinates (\"lon\", \"lat\") constituent points, time step (\"Steps\"), identification number (\"ID\") trajectory, cell IDs start end cells.","code":""},{"path":"/reference/voccTraj.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"Climate velocity trajectories — voccTraj","text":"Burrows et al. 2014. Geographical limits species-range shifts suggested climate velocity. Nature, 507, 492-495.","code":""},{"path":[]},{"path":"/reference/voccTraj.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"Climate velocity trajectories — voccTraj","text":"Jorge Garcia Molinos, David S. Schoeman Michael T. Burrows","code":""},{"path":"/reference/voccTraj.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Climate velocity trajectories — voccTraj","text":"","code":"if (FALSE) { # \\dontrun{ yrSST <- sumSeries(HSST, p = \"1960-01/2009-12\", yr0 = \"1955-01-01\", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = \"months\", freqout = \"years\" ) # Long-term local climatic trends tr <- tempTrend(yrSST, th = 10) # Local spatial climatic gradients sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) # Gradient-based climate velocity v <- gVoCC(tr, sg) vel <- v[[1]] ang <- v[[2]] # Calculate the annual SST mean over the period mn <- terra::mean(yrSST, na.rm = TRUE) # Get the set of starting cells for the trajectories lonlat <- stats::na.omit(data.frame( terra::xyFromCell(vel, 1:terra::ncell(vel)), vel[], ang[], mn[] ))[, 1:2] # Calculate trajectories # The following throws an error due to the trajectories moving beyond the raster extent traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50) # This accounts for the extent issue traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) } # }"}] diff --git a/docs/sitemap.xml b/docs/sitemap.xml index c8dc9b2..5761b13 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -9,6 +9,7 @@ /reference/HSST.html /reference/JapTC.html /reference/angulo.html +/reference/check_mirai_daemons.html /reference/climPCA.html /reference/climPlot.html /reference/dVoCC.html diff --git a/inst/extdata/EEZ.gpkg b/inst/extdata/EEZ.gpkg index 79454ee..973e7a9 100644 Binary files a/inst/extdata/EEZ.gpkg and b/inst/extdata/EEZ.gpkg differ diff --git a/man/angulo.Rd b/man/angulo.Rd index 22a8f98..246dddf 100644 --- a/man/angulo.Rd +++ b/man/angulo.Rd @@ -9,12 +9,9 @@ angulo(dx, dy) \arguments{ \item{dx}{\code{numeric} giving the longitudinal gradient component} -\item{dy}{\code{numeric} giving the latitudinal gradient component} +\item{dy}{\code{numeric} giving the latitudinal gradient component +angulo()} } \description{ Internal. Angle associated to the spatial gradient } -\author{ -Jorge Garcia Molinos and David S. Schoeman -angulo() -} diff --git a/man/climPCA.Rd b/man/climPCA.Rd index a90d99e..6d1e022 100644 --- a/man/climPCA.Rd +++ b/man/climPCA.Rd @@ -37,8 +37,8 @@ Function to extract the first n principal components explaining a predefined tot These components can subsequently be used as synthetic climatic variables to reduce dimensionality in climate-analogue methods. } \examples{ -\dontrun{ -JapTC <- VoCC_get_data("JapTC.tif") + +JapTC <- terra::rast(system.file("extdata", "JapTC.tif", package = "VoCC")) comp <- climPCA(JapTC[[c(1, 3, 5)]], JapTC[[c(2, 4, 6)]], trans = NA, cen = TRUE, sc = TRUE, th = 0.85) @@ -46,12 +46,8 @@ summary(comp[[1]]) # first two components explain >90\% of variance # Create a data frame with the necessary variables in the required order (see climAna? for details) clim <- comp[[2]][, c(2, 4, 3, 5, 1)] clim[, c("x", "y")] <- terra::xyFromCell(JapTC[[1]], clim$cid) -} } \seealso{ {\code{\link{dVoCC}}, \code{\link{climPlot}}} } -\author{ -Jorge Garcia Molinos -} diff --git a/man/climPlot.Rd b/man/climPlot.Rd index e0d6e40..8c4e019 100644 --- a/man/climPlot.Rd +++ b/man/climPlot.Rd @@ -26,8 +26,8 @@ and (iii) the location of remnant, novel and disappearing climates between both Function to create a binned scatter plot of two climate variables. } \examples{ -\dontrun{ -JapTC <- VoCC_get_data("JapTC.tif") + +JapTC <- terra::rast(system.file("extdata", "JapTC.tif", package = "VoCC")) # Plot climate space for the two first variables(annual precipitation and maximum temperature) xy <- stats::na.omit(data.frame( @@ -46,11 +46,8 @@ ggplot2::ggsave( plot = out, filename = file.path(getwd(), "example_plot.pdf"), width = 17, height = 17, unit = "cm" ) -} + } \seealso{ {\code{\link{dVoCC}}, \code{\link{climPCA}}} } -\author{ -Jorge Garcia Molinos and Naoki H. Kumagai -} diff --git a/man/dVoCC.Rd b/man/dVoCC.Rd index 4e805fe..791f828 100644 --- a/man/dVoCC.Rd +++ b/man/dVoCC.Rd @@ -58,8 +58,8 @@ other (target) cells in the future by reference to a specified climatic threshol specification of search distances and incorporates both least-cost path and Great Circle (as-the-crow-flies) distances. } \examples{ -\dontrun{ -JapTC <- VoCC_get_data("JapTC.tif") + +JapTC <- terra::rast(system.file("extdata", "JapTC.tif", package = "VoCC")) # Create a data frame with the necessary variables in the required order clim <- stats::na.omit(data.frame(terra::values(JapTC), cid = 1:terra::ncell(JapTC))) @@ -75,6 +75,7 @@ r1 <- JapTC[[1]] r1[avocc1$focal] <- avocc1$vel terra::plot(r1) +\dontrun{ # Cell-specific, distance-unrestricted climate analogue velocity based on least-cost path distances # First, create the conductance matrix (all land cells considered to have conductance of 1) r <- JapTC[[1]] @@ -104,6 +105,3 @@ terra::plot(c(r1, r2)) \seealso{ {\code{\link{climPCA}}, \code{\link{climPlot}}} } -\author{ -Jorge Garcia Molinos -} diff --git a/man/gVoCC.Rd b/man/gVoCC.Rd index ce2d787..df9c34d 100644 --- a/man/gVoCC.Rd +++ b/man/gVoCC.Rd @@ -19,23 +19,6 @@ degrees north: 0N, 90E, 180S and 270W). \description{ Function to calculate the velocity of climate change after Burrows et al. (2011) based on local climatic temporal trends and spatial gradients. -} -\examples{ -\dontrun{ -HSST <- VoCC_get_data("HSST.tif") -yrSST <- sumSeries(HSST, - p = "1960-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), - fun = function(x) colMeans(x, na.rm = TRUE), freqin = "months", freqout = "years" -) -tr <- tempTrend(yrSST, th = 10) -sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) - -# Magnitude and angle of the climate velocity (km/yr) 1960-2009 - -v <- gVoCC(tr, sg) -terra::plot(v) -} - } \references{ \href{http://science.sciencemag.org/content/334/6056/652}{Burrows et al. 2011}. The pace of shifting climate @@ -44,6 +27,3 @@ in marine and terrestrial ecosystems. Science, 334, 652-655. \seealso{ {\code{\link{tempTrend}}, \code{\link{spatGrad}}} } -\author{ -Jorge Garcia Molinos -} diff --git a/man/resTime.Rd b/man/resTime.Rd index 595cbe5..96a1e9e 100644 --- a/man/resTime.Rd +++ b/man/resTime.Rd @@ -24,15 +24,18 @@ Function to calculate VoCC-based residence time of isotherms within a polygon af \examples{ # Load example Exclusive Economic Zone polygon -\dontrun{ -EEZ <- VoCC_get_data("EEZ.gpkg") -HSST <- VoCC_get_data("HSST.tif") + +EEZ <- terra::vect(system.file("extdata", "EEZ.gpkg", package = "VoCC")) + +HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) \%>\% + terra::crop(terra::ext(EEZ)) yrSST <- sumSeries(HSST, p = "1969-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), freqin = "months", freqout = "years" ) + tr <- tempTrend(yrSST, th = 10) sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) v <- gVoCC(tr, sg) @@ -47,16 +50,16 @@ a2 <- resTime(EEZ, vel, areapg = as.numeric(as.numeric(levels(EEZ$Area_km2))[EEZ a2 # Using a user defined polygon -x_coord <- c(-28, -20, -20.3, -25.5) -y_coord <- c(60, 61, 63, 62) +x_coord <- c(-28, -20, -20.3, -25.5, -28) +y_coord <- c(60, 61, 63, 62, 60) coords <- matrix(c(x_coord, y_coord), ncol = 2) poly_sf <- sf::st_sf(geometry = sf::st_sfc(sf::st_polygon(list(coords)))) a3 <- resTime(poly_sf, vel, areapg = NA) terra::plot(vel) -plot(sf::st_geometry(EEZ), add = TRUE) +terra::plot(EEZ, add = TRUE) plot(sf::st_geometry(poly_sf), add = TRUE) -} + } \references{ \href{https://www.nature.com/articles/nature08649}{Loarie et al. 2009}. The velocity of climate change. Nature, 462, 1052-1055. @@ -64,6 +67,3 @@ plot(sf::st_geometry(poly_sf), add = TRUE) \seealso{ {\code{\link{gVoCC}}} } -\author{ -Jorge Garcia Molinos -} diff --git a/man/shiftTime.Rd b/man/shiftTime.Rd index af67b85..ff0a6b9 100644 --- a/man/shiftTime.Rd +++ b/man/shiftTime.Rd @@ -30,17 +30,14 @@ Function to calculate the seasonal shift in the arriving of typical seasonal cli for a given period of interest as per Burrows et al. (2011). } \examples{ -\dontrun{ -HSST <- VoCC_get_data("HSST.tif") + +HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) Apr <- shiftTime(HSST, yr1 = 1960, yr2 = 2009, yr0 = 1955, th = 10, m = 4) terra::plot(Apr) -} + } \references{ \href{http://science.sciencemag.org/content/334/6056/652}{Burrows et al. 2011}. The pace of shifting climate in marine and terrestrial ecosystems. Science, 334, 652-655. } -\author{ -Jorge Garcia Molinos and Michael T. Burrows -} diff --git a/man/spatGrad.Rd b/man/spatGrad.Rd index 95c155a..6fa8097 100644 --- a/man/spatGrad.Rd +++ b/man/spatGrad.Rd @@ -28,8 +28,8 @@ associated to a climatic variable after Burrows et al. (2011). This trend is to be used for the calculation of the gradient-based climate velocity using gVoCC. } \examples{ -\dontrun{ -HSST <- VoCC_get_data("HSST.tif") + +HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) yrSST <- sumSeries(HSST, p = "1969-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), @@ -41,15 +41,12 @@ yrSST <- sumSeries(HSST, sg <- spatGrad(yrSST, th = 0.0001, projected = FALSE) terra::plot(sg) -} } \references{ -\href{http://science.sciencemag.org/content/334/6056/652}{Burrows et al. 2011}. The pace of shifting climate in marine and terrestrial ecosystems. Science, 334, 652-655. +\href{http://science.sciencemag.org/content/334/6056/652}{Burrows et al. 2011}. +The pace of shifting climate in marine and terrestrial ecosystems. Science, 334, 652-655. } \seealso{ {\code{\link{tempTrend}}, \code{\link{gVoCC}}} } -\author{ -Jorge Garcia Molinos, David S. Schoeman, and Michael T. Burrows -} diff --git a/man/splitLine.Rd b/man/splitLine.Rd index a5ae948..ea19d2d 100644 --- a/man/splitLine.Rd +++ b/man/splitLine.Rd @@ -16,6 +16,3 @@ splitLine(A, B, n) \description{ Internal. Split a line segment defined by points A-B into n parts } -\author{ -Jorge Garcia Molinos -} diff --git a/man/sumSeries.Rd b/man/sumSeries.Rd index 5d4faa8..b668129 100644 --- a/man/sumSeries.Rd +++ b/man/sumSeries.Rd @@ -45,10 +45,10 @@ apply some summary function. It is mainly a wrapper from the \code{apply.} funct in the package xts (Ryan and Ulrich 2017). } \examples{ -\dontrun{ + # Monthly mean SST (HadISST) data for Europe Jan-1950 to Dec-2010 -HSST <- VoCC_get_data("HSST.tif") +HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) # Calculate mean annual monthly SST @@ -83,7 +83,6 @@ meanJASST <- sumSeries(HSST, p = "1969-01/2009-12", yr0 = "1950-01-01", l = terra::nlyr(HSST), fun = myf, freqin = "months", freqout = "other" ) -} } \references{ @@ -91,6 +90,3 @@ meanJASST <- sumSeries(HSST, \href{https://CRAN.R-project.org/package=matrixStats}{Bengtsson 2018}. matrixStats: Functions that Apply to Rows and Columns of Matrices (and to Vectors). R package version 0.53.1. } -\author{ -Jorge Garcia Molinos -} diff --git a/man/tempTrend.Rd b/man/tempTrend.Rd index efe33ab..9b84dd6 100644 --- a/man/tempTrend.Rd +++ b/man/tempTrend.Rd @@ -25,8 +25,8 @@ of a climatic variable. This trend is to be used for the calculation of the gradient-based climate velocity using gVoCC. } \examples{ -\dontrun{ -HSST <- VoCC_get_data("HSST.tif") + +HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) yrSST <- sumSeries(HSST, p = "1969-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), @@ -38,11 +38,8 @@ yrSST <- sumSeries(HSST, tr <- tempTrend(yrSST, th = 10) terra::plot(tr) -} + } \seealso{ {\code{\link{spatGrad}}, \code{\link{gVoCC}}} } -\author{ -Jorge Garcia Molinos and Christopher J. Brown -} diff --git a/man/trajClas.Rd b/man/trajClas.Rd index fadae12..5e117fd 100644 --- a/man/trajClas.Rd +++ b/man/trajClas.Rd @@ -71,8 +71,12 @@ and (5) convergence cells identified from the remaining cells as those where few cell, respectively. } \examples{ + \dontrun{ -HSST <- VoCC_get_data("HSST.tif") +EEZ <- terra::vect(system.file("extdata", "EEZ.gpkg", package = "VoCC")) + +HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) \%>\% + terra::crop(terra::ext(EEZ) + 10) # input raster layers yrSST <- sumSeries(HSST, @@ -88,16 +92,13 @@ vel <- v[[1]] ang <- v[[2]] # Get the set of starting cells for the trajectories and calculate trajectories -# at 1/4-deg resolution (16 trajectories per 1-deg cell) -mnd <- terra::disagg(mn, 4) -veld <- terra::disagg(vel, 4) -angd <- terra::disagg(ang, 4) lonlat <- stats::na.omit(data.frame( - terra::xyFromCell(veld, 1:terra::ncell(veld)), - terra::values(veld), terra::values(angd), terra::values(mnd) + terra::xyFromCell(vel, 1:terra::ncell(vel)), + terra::values(vel), terra::values(ang), terra::values(mn) ))[, 1:2] -traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) +traj <- voccTraj(lonlat, vel, ang, mn, tstep = 1/4, tyr = 20, seed = 23) + # Generate the trajectory-based classification clas <- trajClas(traj, vel, ang, mn, @@ -105,26 +106,15 @@ clas <- trajClas(traj, vel, ang, mn, Nend = 45, Nst = 15, NFT = 70, DateLine = FALSE ) -# Define first the colour palette for the full set of categories -my_col <- c( - "gainsboro", "darkseagreen1", "coral4", "firebrick2", "mediumblue", "darkorange1", - "magenta1", "cadetblue1", "yellow1" -) -# Keep only the categories present in our raster -my_col <- my_col[sort(unique(terra::values(clas[[7]])))] - # Classify raster / build attribute table clasr <- terra::as.factor(clas[[7]]) rat_r <- data.frame(ID = sort(unique(terra::values(clas[[7]]))), trajcat = c("N-M", "S-M", "IS", "BS", "Srce", "RS", "Cor", "Div", "Con")[sort(unique(terra::values(clas[[7]])))]) -terra::cats(clasr) <- rat_r -# Produce the plot using the rasterVis levelplot function -rasterVis::levelplot(clasr, - col.regions = my_col, - xlab = NULL, ylab = NULL, scales = list(draw = FALSE) -) +levels(clasr) <- rat_r +terra::plot(clasr) } + } \references{ \href{https://www.nature.com/articles/nature12976}{Burrows et al. 2014}. Geographical limits to species-range shifts are suggested by climate velocity. Nature, 507, 492-495. @@ -132,6 +122,3 @@ rasterVis::levelplot(clasr, \seealso{ {\code{\link{voccTraj}}} } -\author{ -Jorge Garcia Molinos -} diff --git a/man/trajLine.Rd b/man/trajLine.Rd index 1530c48..b20ea49 100644 --- a/man/trajLine.Rd +++ b/man/trajLine.Rd @@ -14,7 +14,7 @@ points and identification number (trajIDs) for each trajectory as returned by Vo (default geographic CRS).} } \value{ -A \code{SpatialLinesDataFrame} with one line per trajectory as specified in x. +A \code{sf} object with one line per trajectory as specified in x. To avoid artifacts, trajectories crossing the date line need to be split into two segments. Where the trajectory on one side of the date line is only composed of a single point, the trajectory won't be displayed (no line object created). The function assumes @@ -24,8 +24,10 @@ a -180 to 180 longitudinal arrangement. Create a spatial line data frame object from trajectory points. } \examples{ -\dontrun{ -HSST <- VoCC_get_data("HSST.tif") + +EEZ <- terra::vect(system.file("extdata", "EEZ.gpkg", package = "VoCC")) +HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) \%>\% + terra::crop(terra::ext(EEZ) + 10) yrSST <- sumSeries(HSST, p = "1969-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), @@ -47,20 +49,15 @@ lonlat <- stats::na.omit(data.frame( ))[, 1:2] # Calculate trajectories. -traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) +traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, tstep = 1/12) # create a spatial line data frame from traj lns <- trajLine(x = traj) terra::plot(mn) -terra::plot(lns, add = TRUE) +plot(lns \%>\% sf::st_geometry(), add = TRUE) + -# Export as ESRI shape file -terra::writeVector(lns, filename = "velTraj", filetype = "ESRI Shapefile") -} } \seealso{ {\code{\link{voccTraj}}} } -\author{ -Jorge Garcia Molinos -} diff --git a/man/voccTraj.Rd b/man/voccTraj.Rd index 3a17010..db833a2 100644 --- a/man/voccTraj.Rd +++ b/man/voccTraj.Rd @@ -4,7 +4,19 @@ \alias{voccTraj} \title{Climate velocity trajectories} \usage{ -voccTraj(lonlat, vel, ang, mn, tstep, tyr = 50) +voccTraj( + lonlat, + vel, + ang, + mn, + tstep, + x_res = NULL, + y_res = NULL, + tyr = 20, + bfr = 75, + grid_resolution = "coarse", + seed = NULL +) } \arguments{ \item{lonlat}{\code{data.frame} with the longitude and latitude (in decimal degrees) @@ -16,11 +28,23 @@ of the points to project.} \item{mn}{\code{raster} with the overall mean climatic value over the period of interest.} -\item{tyr}{\code{integer} temporal length of the period of interest.} +\item{tstep}{Numeric. Timestep for each trajectory iteration (usually decimal year).} + +\item{x_res}{Numeric. Resolution of the grid in longitude direction (degrees or km).} + +\item{y_res}{Numeric. Resolution of the grid in latitude direction (degrees or km).} + +\item{tyr}{Integer. Temporal length of the period of interest (years).} + +\item{bfr}{Numeric. Distance around a cell to look for a cooler/warmer cell.} + +\item{grid_resolution}{Character. "coarse" (default) or "fine". Controls how land crossings are handled and allows for higher resolution grids.} + +\item{seed}{Integer. Random seed for reproducibility. If NULL (default), no seed is set.} } \value{ -a \code{data.frame} containing the coordinates ("x", "y") of the constituent -points and identification number ("trajIDs") for each trajectory. +a \code{tibble} containing the coordinates ("lon", "lat") of the constituent +points, time step ("Steps"), identification number ("ID") for each trajectory, and cell IDs for start and end cells. } \description{ Function to calculate vocc trajectories after Burrows et al (2014). Trajectories @@ -31,6 +55,8 @@ cumulative time traveled instead of using fixed time steps. } \examples{ \dontrun{ +HSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) + yrSST <- sumSeries(HSST, p = "1960-01/2009-12", yr0 = "1955-01-01", l = terra::nlyr(HSST), fun = function(x) colMeans(x, na.rm = TRUE), @@ -58,11 +84,7 @@ lonlat <- stats::na.omit(data.frame( ))[, 1:2] # Calculate trajectories -# The following throws an error due to the trajectories moving beyond the raster extent -traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50) - -# This accounts for the extent issue -traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) +traj <- voccTraj(lonlat, vel, ang, mn, tstep = 1/4, tyr = 50) } } @@ -72,6 +94,3 @@ traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, correct = TRUE) \seealso{ {\code{\link{gVoCC}}, \code{\link{trajClas}}} } -\author{ -Jorge Garcia Molinos, David S. Schoeman and Michael T. Burrows -} diff --git a/vignettes/.build.timestamp b/vignettes/.build.timestamp new file mode 100644 index 0000000..e69de29 diff --git a/vignettes/VoCC.R b/vignettes/VoCC.R new file mode 100644 index 0000000..0444765 --- /dev/null +++ b/vignettes/VoCC.R @@ -0,0 +1,184 @@ +## ----setup, include = FALSE--------------------------------------------------- +knitr::opts_chunk$set( +collapse = TRUE, +comment = "#>" +) + +# Reduce memory usage and optimize temp file handling +terra::terraOptions(memfrac = 0.5, tempdir = tempdir()) + +# Force sequential processing to avoid parallel processing issues during package checking +Sys.setenv("R_PARALLELLY_AVAILABLECORES_FALLBACK" = "1") + +## ----message=FALSE------------------------------------------------------------ +library(VoCC) +library(dplyr) +library(tidyr) +library(data.table) +library(terra) +library(purrr) +library(future) + +# For Plotting +library(ggplot2) +library(tidyterra) +library(patchwork) +library(mapplots) + +## ----message=FALSE------------------------------------------------------------ +library(VoCCdata) + +## ----------------------------------------------------------------------------- +str(marshift) + +## ----------------------------------------------------------------------------- +HadiSST <- terra::rast(system.file("extdata", "HadiSST.tif", package = "VoCCdata")) + +# monthly to annual averages +r <- sumSeries(HadiSST, p = "1960-01/2009-12", yr0 = "1955-01-01", + l = terra::nlyr(HadiSST), + fun = function(x) colMeans(x, na.rm = TRUE), + freqin = "months", freqout = "years") + +vt <- tempTrend(r, th = 10) # temporal trend +vg <- spatGrad(r, th = 0.0001, projected = FALSE) # spatial gradient +gv <- gVoCC(vt, vg) # climate velocity + +# Now the distance-based velocities +# Take 1960-1970 as base period against 2000-2009 +r2 <- c(terra::mean(r[[1:10]], na.rm = TRUE), terra::mean(r[[41:50]], na.rm = TRUE)) + +# prepare the data frame with the necessary variables +clim <- na.omit(data.frame(terra::values(r2), cid = 1:terra::ncell(r))) + +clim[, c("x", "y")] <- terra::xyFromCell(r, clim$cid) + + +future::plan(future::multisession, workers = parallelly::availableCores(omit = 2)) + +# 1965-2004 (40 yr), 500 km search radius +v <- dVoCC(clim, n = 1, tdiff = 40, method = "Single", climTol = 0.1, geoTol = 500, distfun = "GreatCircle", trans = NA, lonlat = TRUE) + +future::plan(future::sequential) + + +## ----------------------------------------------------------------------------- +# Change sign as needed and create the distance-based velocity raster +# Change sign as needed - terra approach for value comparison +focal_vals <- terra::values(r2[[1]])[v$focal] +target_vals <- terra::values(r2[[2]])[v$target] +ind <- which(focal_vals > target_vals) +v$velBis <- v$vel +v$velBis[ind] <- v$vel[ind] * -1 + +# put output in raster format - create single layer empty template like raster(gv) +dv <- terra::rast(terra::ext(gv), resolution = terra::res(gv), crs = terra::crs(gv)) +dv[v$focal] <- v$velBis + +# Create point geometries and buffer them +coords <- terra::vect(cbind(marshift$long, marshift$lat), crs = "EPSG:4326") +buffer_size <- marshift$Shift * (marshift$timespan / 10) * 1000 + +# Get the mean velocity within the buffer for each data point. +# Match old raster::extract approach exactly +marshift$GV <- terra::extract(abs(gv[[1]]), coords, + buffer = buffer_size, + fun = mean, na.rm = TRUE, + weights = TRUE, exact = FALSE)[,2] + +marshift$DV <- terra::extract(abs(dv), coords, + buffer = buffer_size, + fun = mean, na.rm = TRUE, + weights = TRUE, exact = FALSE)[,2] + +## ----------------------------------------------------------------------------- +# For points that didn't get values (NA), find nearest valid cells + +missing_points <- coords[is.na(marshift$GV)] # Identify NAs +if(!is.empty(missing_points)){ + marine_cells <- terra::as.points(gv[[1]]) # vector of all valid marine cell locations. + nearest_indices <- terra::nearest(missing_points, marine_cells) # Find the nearest marine cell + nearest_values <- terra::extract(gv[[1]], marine_cells[nearest_indices]) # get the values from the nearest marine cells. + marshift$GV[is.na(marshift$GV)] <- nearest_values[, 2] # Replace the NA values in `marshift$GV` +} + +missing_points <- coords[is.na(marshift$DV)] # Identify NAs +if(!is.empty(missing_points)){ + marine_cells <- terra::as.points(dv[[1]]) # vector of all valid marine cell locations. + nearest_cells <- terra::nearest(missing_points, marine_cells) # Find the nearest marine cell + nearest_values <- terra::extract(dv[[1]], nearest_cells) # get the values from the nearest marine cells. + marshift$DV[is.na(marshift$DV)] <- nearest_values[, 2] # Replace the NA values in `marshift$GV` +} + + +## ----------------------------------------------------------------------------- +# fit the regression models +Mgv <- lm(Shift^(1 / 4) ~ I((GV * 10)^(1 / 4)), data = marshift, weights = years_data) +summary(Mgv) + +## ----------------------------------------------------------------------------- +Mdv <- lm(Shift^(1 / 4) ~ I((DV * 10)^(1 / 4)), data = marshift, weights = years_data) +summary(Mdv) + +## ----------------------------------------------------------------------------- +# first compare both velocities + +p1 <- ggplot() + + geom_spatraster(data = gv[[1]]) + + scale_fill_distiller(palette = "RdBu", direction = -1, limits = c(-50, 50)) + + ggtitle("Gradient-based vocc") + + scale_x_continuous(expand = c(0,0)) + + scale_y_continuous(expand = c(0,0)) + +p2 <- ggplot() + + geom_spatraster(data = dv[[1]]) + + scale_fill_distiller(palette = "RdBu", direction = -1, limits = c(-20, 20)) + + ggtitle("Distance-based vocc") + + scale_x_continuous(expand = c(0,0)) + + scale_y_continuous(expand = c(0,0)) + +wrap_plots(p1, p2, ncol = 1) + + +## ----------------------------------------------------------------------------- +# scatter plots with the resulting regression line +p1 <- ggplot(na.omit(marshift), aes(x = (GV * 10)^(1 / 4), y = Shift^(1 / 4))) + + geom_point(color = "grey") + + geom_smooth(method = lm, se = FALSE) + + theme_classic() + + scale_color_brewer(palette = "Accent") + + labs(x = "Predicted shift (x^1/4; km/yr)", y = "Observed shift (y^1/4; km/yr)") + +p2 <- ggplot(na.omit(marshift), aes(x = (DV * 10)^(1 / 4), y = Shift^(1 / 4))) + + geom_point(color = "grey") + + geom_smooth(method = lm, se = FALSE) + + theme_classic() + + scale_color_brewer(palette = "Accent") + + labs(x = "Predicted shift (x^1/4; km/yr)", y = "Observed shift (y^1/4; km/yr)") + +wrap_plots(p1, p2, nrow = 1) + +## ----------------------------------------------------------------------------- +# prepare raster layers +vel <- gv[[1]] +ang <- gv[[2]] +mn <- terra::app(r, mean, na.rm = T) + +# generate a velocity layer centered and cropped to study region to extract the initial coordinates for the trajectories from +x1 <- terra::crop(gv[[1]], terra::ext(-180, 0, -90, 90)) +x2 <- terra::crop(gv[[1]], terra::ext(0, 180, -90, 90)) +terra::ext(x1) <- c(180, 360, -90, 90) +velc <- terra::merge(x1, x2) + +# crop to the desired extent +# display restricted to +180 longitude to avoid plotting issues with date line crossing +velc <- terra::crop(velc, c(90, 180, -32, 33)) + +## ----------------------------------------------------------------------------- +lonlat <- data.frame(terra::xyFromCell(velc, 1:ncell(velc))) +lonlat$vel <- terra::extract(vel, lonlat, ID = FALSE) +lonlat$ang <- terra::extract(ang, lonlat[, 1:2], ID = FALSE) +lonlat$mn <- terra::extract(mn, lonlat[, 1:2], ID = FALSE) +lonlat$lineID <- 1:nrow(lonlat) +lonlat <- drop_na(lonlat) + diff --git a/vignettes/VoCC.Rmd b/vignettes/VoCC.Rmd index b4f7cfa..47b3d5e 100644 --- a/vignettes/VoCC.Rmd +++ b/vignettes/VoCC.Rmd @@ -7,14 +7,17 @@ vignette: > %\VignetteIndexEntry{VoCC} \usepackage[utf8]{inputenc} --- - - + + ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) +# Reduce memory usage and optimize temp file handling +terra::terraOptions(memfrac = 0.5, tempdir = tempdir()) + # Force sequential processing to avoid parallel processing issues during package checking Sys.setenv("R_PARALLELLY_AVAILABLECORES_FALLBACK" = "1") ``` @@ -32,6 +35,7 @@ library(tidyr) library(data.table) library(terra) library(purrr) +library(future) # For Plotting library(ggplot2) @@ -79,8 +83,14 @@ clim <- na.omit(data.frame(terra::values(r2), cid = 1:terra::ncell(r))) clim[, c("x", "y")] <- terra::xyFromCell(r, clim$cid) + +future::plan(future::multisession, workers = parallelly::availableCores(omit = 2)) + # 1965-2004 (40 yr), 500 km search radius v <- dVoCC(clim, n = 1, tdiff = 40, method = "Single", climTol = 0.1, geoTol = 500, distfun = "GreatCircle", trans = NA, lonlat = TRUE) + +future::plan(future::sequential) + ``` Next, we extract the mean velocity estimates for each reported shift by taking the average of all grid cell values within a circle of radius equal to the reported range-shift distance. These are then used to fit the simple linear regression models of observed range shifts against climate velocity. Distance-based velocities are strictly positive by definition, so to compare like with like we change first their sign to negative where present local climates are warmer than their future analogues. @@ -153,18 +163,18 @@ Produce the observed vs predicted scatterplots with regression lines (Fig. 2 in ```{r} # first compare both velocities -p1 <- ggplot() + - geom_spatraster(data = gv[[1]]) + +p1 <- ggplot() + + geom_spatraster(data = gv[[1]]) + scale_fill_distiller(palette = "RdBu", direction = -1, limits = c(-50, 50)) + ggtitle("Gradient-based vocc") + - scale_x_continuous(expand = c(0,0)) + + scale_x_continuous(expand = c(0,0)) + scale_y_continuous(expand = c(0,0)) -p2 <- ggplot() + - geom_spatraster(data = dv[[1]]) + +p2 <- ggplot() + + geom_spatraster(data = dv[[1]]) + scale_fill_distiller(palette = "RdBu", direction = -1, limits = c(-20, 20)) + ggtitle("Distance-based vocc") + - scale_x_continuous(expand = c(0,0)) + + scale_x_continuous(expand = c(0,0)) + scale_y_continuous(expand = c(0,0)) wrap_plots(p1, p2, ncol = 1) @@ -198,17 +208,17 @@ In this example we use climate velocity trajectories (based on 1960-2009 mean an # prepare raster layers vel <- gv[[1]] ang <- gv[[2]] -mn <- app(r, mean, na.rm = T) +mn <- terra::app(r, mean, na.rm = T) # generate a velocity layer centered and cropped to study region to extract the initial coordinates for the trajectories from -x1 <- crop(gv[[1]], ext(-180, 0, -90, 90)) -x2 <- crop(gv[[1]], ext(0, 180, -90, 90)) -ext(x1) <- c(180, 360, -90, 90) -velc <- merge(x1, x2) +x1 <- terra::crop(gv[[1]], terra::ext(-180, 0, -90, 90)) +x2 <- terra::crop(gv[[1]], terra::ext(0, 180, -90, 90)) +terra::ext(x1) <- c(180, 360, -90, 90) +velc <- terra::merge(x1, x2) # crop to the desired extent # display restricted to +180 longitude to avoid plotting issues with date line crossing -velc <- crop(velc, c(90, 180, -32, 33)) +velc <- terra::crop(velc, c(90, 180, -32, 33)) ``` We can now populate the data frame with the cell centroid coordinates for the trajectories. @@ -224,19 +234,23 @@ lonlat <- drop_na(lonlat) Let's calculate the trajectories with parallel processing to demonstrate how this can be used to speed things up (especially useful when dealing with fine resolutions or large extents). -```{r} - -traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, tstep = 1/12) - +```{r voccTraj, eval=TRUE} +# traj <- voccTraj(lonlat, vel, ang, mn, tyr = 50, tstep = 1/12, seed = 23) +traj <- voccTraj(lonlat, vel, ang, mn, tyr = 10, tstep = 1/4, seed = 23) ``` + Plot them over the climate velocities and the EEZ polygons from the EEZs data set (Fig. 3a in Garcia Molinos et al. 2019) -```{r message=FALSE, warning=FALSE} +```{r trajLine, eval=TRUE, message=FALSE, warning=FALSE} # create the spatial object with the trajectories and plot them together with the EEZ polygons -lns <- map(traj %>% group_split(cellIDs), trajLine) %>% - purrr::list_rbind() %>% - sf::st_sf() + +future::plan(multisession, workers = parallelly::availableCores(omit = 2)) + +lns <- trajLine(traj) + +future::plan(sequential) + # Load and simplify polygons to speed plotting up EEZs <- sf::st_read(system.file("extdata", "EEZs.gpkg", package = "VoCCdata")) %>% diff --git a/vignettes/VoCC_files/figure-html/unnamed-chunk-10-1.png b/vignettes/VoCC_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 0000000..f897f17 Binary files /dev/null and b/vignettes/VoCC_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/vignettes/VoCC_files/figure-html/unnamed-chunk-9-1.png b/vignettes/VoCC_files/figure-html/unnamed-chunk-9-1.png new file mode 100644 index 0000000..14967c3 Binary files /dev/null and b/vignettes/VoCC_files/figure-html/unnamed-chunk-9-1.png differ