Skip to content

Commit a3ce5d8

Browse files
authored
Merge pull request #8 from MathMarEcol/devel_JDE
Devel jde
2 parents 21a069c + 1323925 commit a3ce5d8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1720
-889
lines changed

DESCRIPTION

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,33 @@ Authors@R: c(person("Jorge", "Garcia Molinos", email = "[email protected]
99
Description: Functions to calculate the velocity of climate change (VoCC) and related metrics including
1010
both gradient-based (Burrows et al. 2011, Burrows et al. 2014), and distance-based (Hamann et a. 2013,
1111
Garcia Molinos et al. 2017) approaches.
12-
Depends: R (>= 3.5)
12+
Depends: R (>= 4.1)
1313
Imports:
1414
assertthat,
1515
CircStats,
1616
cowplot,
1717
data.table,
18-
doParallel,
1918
dplyr,
20-
foreach,
19+
furrr,
2120
geosphere,
2221
magrittr,
23-
parallelly,
22+
purrr,
2423
RColorBrewer,
2524
rlang,
2625
sf,
2726
stats,
2827
terra,
2928
tibble,
3029
tidyr,
31-
tidyselect,
3230
xts
3331
Suggests:
32+
future,
3433
ggplot2,
3534
knitr,
3635
mapplots,
3736
ncdf4,
37+
parallelly,
3838
patchwork,
39-
purrr,
4039
rmarkdown,
4140
scales,
4241
tidyterra,
@@ -46,6 +45,6 @@ BugReports: https://github.com/MathMarEcol/VoCC/issues
4645
License: AGPL (>= 3)
4746
Encoding: UTF-8
4847
LazyData: true
49-
RoxygenNote: 7.3.2
48+
RoxygenNote: 7.3.3
5049
VignetteBuilder: knitr,
5150
rmarkdown

NAMESPACE

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export(trajClas)
1414
export(trajLine)
1515
export(voccTraj)
1616
importFrom(data.table,":=")
17-
importFrom(foreach,"%dopar%")
1817
importFrom(magrittr,"%>%")
1918
importFrom(rlang,.data)
2019
importFrom(stats,na.omit)

R/angulo.R

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
#' Internal. Angle associated to the spatial gradient
22
#' @param dx \code{numeric} giving the longitudinal gradient component
33
#' @param dy \code{numeric} giving the latitudinal gradient component
4-
#' @author Jorge Garcia Molinos and David S. Schoeman
54
#' angulo()
65

76
angulo <- function(dx, dy) {
8-
d <- cbind(dx, dy)
9-
angline <- function(rw) {
10-
angle <- ifelse(rw[2] < 0, 180 + CircStats::deg(atan(rw[1] / rw[2])),
11-
ifelse(rw[1] < 0, 360 + CircStats::deg(atan(rw[1] / rw[2])), CircStats::deg(atan(rw[1] / rw[2])))
12-
)
13-
return(angle)
14-
}
15-
return(apply(d, 1, angline))
7+
# OPTIMIZATION: Fully vectorized angle calculation - eliminates apply() loop
8+
# Convert atan to degrees once for all values
9+
atan_deg <- CircStats::deg(atan(dx / dy))
10+
11+
# Vectorized conditional logic - much faster than apply()
12+
angle <- ifelse(dy < 0, 180 + atan_deg,
13+
ifelse(dx < 0, 360 + atan_deg, atan_deg))
14+
15+
return(angle)
1616
}

R/climPCA.R

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,49 @@
2020
#' @importFrom data.table ":="
2121
#'
2222
#' @export
23-
#' @author Jorge Garcia Molinos
23+
#'
2424
#' @examples
25-
#' \dontrun{
26-
#' JapTC <- VoCC_get_data("JapTC.tif")
25+
#'
26+
#' JapTC <- terra::rast(system.file("extdata", "JapTC.tif", package = "VoCC"))
2727
#'
2828
#' comp <- climPCA(JapTC[[c(1, 3, 5)]], JapTC[[c(2, 4, 6)]],
2929
#' trans = NA, cen = TRUE, sc = TRUE, th = 0.85)
3030
#' summary(comp[[1]]) # first two components explain >90% of variance
3131
#' # Create a data frame with the necessary variables in the required order (see climAna? for details)
3232
#' clim <- comp[[2]][, c(2, 4, 3, 5, 1)]
3333
#' clim[, c("x", "y")] <- terra::xyFromCell(JapTC[[1]], clim$cid)
34-
#' }
3534
#'
3635
climPCA <- function(climp, climf, trans = function(x) log(x), cen = TRUE, sc = TRUE, th = 0.8) {
36+
37+
.SD <- NULL
38+
39+
# OPTIMIZATION: Pre-calculate cell count to avoid repeated calls
40+
n_cells <- terra::ncell(climp[[1]])
41+
3742
# get a data table with the pooled values (current/future) of the clim variables
3843
clim <- data.table::data.table(rbind(terra::values(climp), terra::values(climf)))
39-
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]])))])
44+
clim <- stats::na.omit(clim[, c("cid", "p") := list(rep(1:n_cells, times = 2), rep(c("present", "future"), each = n_cells))])
45+
46+
# OPTIMIZATION: Store column indices to avoid repeated column selection
47+
data_cols <- !names(clim) %in% c("cid", "p")
4048

4149
# apply transformation if required
4250
if (!is.na(trans)) {
43-
clim <- trans(clim[, -c("cid", "p")])
51+
clim_data <- clim[, .SD, .SDcols = data_cols]
52+
clim_data <- trans(clim_data)
53+
# Rebuild clim with transformed data
54+
clim <- cbind(clim_data, clim[, c("cid", "p")])
4455
}
4556

4657
# apply PCA
47-
clim.pca <- stats::prcomp(clim[, -c("cid", "p")], center = cen, scale. = sc)
58+
clim.pca <- stats::prcomp(clim[, .SD, .SDcols = data_cols], center = cen, scale. = sc)
59+
60+
# OPTIMIZATION: Vectorized variance calculation
61+
sdev_squared <- clim.pca$sdev^2
62+
cumvar_prop <- cumsum(sdev_squared) / sum(sdev_squared)
63+
a <- which(cumvar_prop >= th)[1]
4864

49-
# extract numper of components explaining more than th accumulated variance
50-
a <- which((cumsum((clim.pca$sdev)^2) / sum(clim.pca$sdev^2)) >= th)[1]
51-
val.pca <- clim.pca$x[, 1:a]
65+
val.pca <- clim.pca$x[, 1:a, drop = FALSE]
5266
val <- data.frame(val.pca, cid = clim$cid, p = clim$p)
5367

5468
# put it back in wide form

R/climPlot.R

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@
1515
#' @seealso{\code{\link{dVoCC}}, \code{\link{climPCA}}}
1616
#'
1717
#' @export
18-
#' @author Jorge Garcia Molinos and Naoki H. Kumagai
1918
#' @examples
20-
#' \dontrun{
21-
#' JapTC <- VoCC_get_data("JapTC.tif")
19+
#'
20+
#' JapTC <- terra::rast(system.file("extdata", "JapTC.tif", package = "VoCC"))
2221
#'
2322
#' # Plot climate space for the two first variables(annual precipitation and maximum temperature)
2423
#' xy <- stats::na.omit(data.frame(
@@ -37,18 +36,24 @@
3736
#' plot = out, filename = file.path(getwd(), "example_plot.pdf"),
3837
#' width = 17, height = 17, unit = "cm"
3938
#' )
40-
#' }
39+
#'
4140
climPlot <- function(xy, x.binSize, y.binSize, x.name = "V1", y.name = "V2") {
4241
xp <- xy[, 1]
4342
yp <- xy[, 3]
4443
xf <- xy[, 2]
4544
yf <- xy[, 4]
4645

46+
# OPTIMIZATION: Pre-calculate ranges to avoid repeated min/max calls
47+
x_combined <- c(xp, xf)
48+
y_combined <- c(yp, yf)
49+
x_range <- range(x_combined)
50+
y_range <- range(y_combined)
51+
4752
# bins per axis
48-
x.nbins <- floor((abs(range(xp, xf)[2] - range(xp, xf)[1])) / x.binSize)
49-
y.nbins <- floor((abs(range(yp, yf)[2] - range(yp, yf)[1])) / y.binSize)
50-
x.bin <- seq(floor(min(cbind(xp, xf))), ceiling(max(cbind(xp, xf))), length = x.nbins)
51-
y.bin <- seq(floor(min(cbind(yp, yf))), ceiling(max(cbind(yp, yf))), length = y.nbins)
53+
x.nbins <- floor(abs(x_range[2] - x_range[1]) / x.binSize)
54+
y.nbins <- floor(abs(y_range[2] - y_range[1]) / y.binSize)
55+
x.bin <- seq(floor(x_range[1]), ceiling(x_range[2]), length = x.nbins)
56+
y.bin <- seq(floor(y_range[1]), ceiling(y_range[2]), length = y.nbins)
5257

5358
# define palette
5459
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") {
7580
freq2Dp[freq2Dp > UL] <- UL
7681
freq2Df[freq2Df > UL] <- UL
7782

78-
# novel (in future but not present, 2), remnant (in both, 1), and dissapearing (in present but not future, 3) climates
79-
freq2D <- diag(nrow = x.nbins, ncol = y.nbins)
80-
freq2D[] <- NA
81-
for (i in 1:x.nbins) {
82-
for (j in 1:y.nbins) {
83-
freq2D[i, j] <- ifelse(is.na(freq2Dp[i, j]) & !is.na(freq2Df[i, j]), 1,
84-
ifelse(!is.na(freq2Dp[i, j]) & is.na(freq2Df[i, j]), 2,
85-
ifelse(is.na(freq2Dp[i, j]) & is.na(freq2Df[i, j]), NA, 0)
86-
)
87-
)
88-
}
89-
}
83+
# OPTIMIZATION: Vectorized climate classification - eliminates nested loops
84+
freq2D <- matrix(NA, nrow = x.nbins, ncol = y.nbins)
85+
86+
# Vectorized logical operations - much faster than nested loops
87+
present_na <- is.na(freq2Dp)
88+
future_na <- is.na(freq2Df)
89+
90+
# Novel climates: in future but not present
91+
freq2D[present_na & !future_na] <- 1
92+
# Disappearing climates: in present but not future
93+
freq2D[!present_na & future_na] <- 2
94+
# Remnant climates: in both present and future
95+
freq2D[!present_na & !future_na] <- 0
96+
# NA remains NA (neither present nor future)
9097

9198
# plot climate space
9299
Freq2Dpf <- rbind(

0 commit comments

Comments
 (0)