--- title: "Climatic niche geometry and workflow" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Climatic niche geometry and workflow} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.align = "center") ``` `climniche` compares current and projected climate at each location with one current climatic niche reference. This vignette defines that reference, the four reported quantities and the fitting and projection workflow. ## Current climatic niche reference Let $c_i$ and $f_i$ denote current and projected climate at location $i$. A non-negative weight $w_i$ determines how much that location contributes to the current climatic niche reference. Its centre is $$ \mu=\frac{\sum_i w_i c_i}{\sum_i w_i}. $$ Distance is measured under a positive semidefinite climatic metric $A$: $$ d_A(x,y)=\sqrt{(x-y)^\mathsf{T}A(x-y)}. $$ If $r_{0i}=d_A(c_i,\mu)$, the weighted quantile $$ B_q=Q_q^w(r_0) $$ defines the empirical radial boundary. The transformation, metric, centre and boundary are fitted from current climate and remain fixed when projected conditions are evaluated. ## Reported quantities At each location, `climniche` calculates $$ \begin{aligned} D_i &= d_A(f_i,c_i),\\ R_i &= d_A(f_i,\mu)-d_A(c_i,\mu),\\ C_i &= \sqrt{\max(0,D_i^2-R_i^2)},\\ E_i &= \max(0,d_A(f_i,\mu)-B_q). \end{aligned} $$ Climatic Displacement ($D_i$) is the magnitude of local climatic change. Niche Distance Shift ($R_i$) is negative when projected climate moves towards the reference centre and positive when it moves away. Climatic Reconfiguration ($C_i$) describes displacement that is not expressed as a change in distance from the centre. The three quantities satisfy $D_i^2=R_i^2+C_i^2$. If $r_{1i}=d_A(f_i,\mu)$ and $\theta_i$ is the angle between the centred current and projected vectors, then $$ C_i^2=2r_{0i}r_{1i}\{1-\cos(\theta_i)\}. $$ Climatic Reconfiguration is derived from Climatic Displacement and Niche Distance Shift. It is not a strict orthogonal projection or an independently estimated ecological process. Niche Boundary Exceedance ($E_i$) is separate from this decomposition and measures projected distance beyond $B_q$. ## Workflow Every input interface follows four steps. 1. Match current and projected climatic variables and locations, then convert occurrence, range or SDM data to non-negative reference weights. 2. Fit preprocessing and standardisation to current climate, construct the climatic metric and estimate the weighted niche centre and boundary. 3. Hold the fitted reference fixed while calculating the four quantities and climatic-variable contributions for projected conditions. 4. Return location-level values, weighted summaries, maps and reports from the same fitted reference. `fit_climniche()` accepts matrices and data frames. `fit_climniche_raster()` accepts `RasterLayer`, `RasterStack` and `RasterBrick` objects, whereas `fit_climniche_terra()` accepts `SpatRaster` objects. The current reference can also be fitted with `fit_climniche_reference()` and reused with `project_climniche()`. `fit_climniche_series()` applies one fitted reference to an ordered set of projections. ```{r} library(climniche) sim <- simulate_climniche(n = 200, p = 6, seed = 7) fit <- fit_climniche( current = sim[["current"]], future = sim[["future_away"]], occupied = sim[["occupied"]], sensitivity = sim[["sensitivity"]] ) head(climniche_table(fit)) ``` ## Interpreting equal climatic displacement Four two-variable examples start one unit from a fixed centre. The towards and away examples have the same Climatic Displacement but opposite Niche Distance Shift. The fourth example changes climatic configuration while retaining the same niche distance. ```{r} current <- matrix( rep(c(1, 0), 4), ncol = 2, byrow = TRUE, dimnames = list( c("unchanged", "towards centre", "away from centre", "same niche distance"), c("climate 1", "climate 2") ) ) future <- rbind( unchanged = c(1, 0), `towards centre` = c(0, 0), `away from centre` = c(2, 0), `same niche distance` = c(0, 1) ) colnames(future) <- colnames(current) geometry_fit <- fit_climniche( current = current, future = future, occupied = rep(1, nrow(current)), center = c(0, 0), A = diag(2), scale = FALSE, preprocess = FALSE, boundary = 0.95, tolerance = 0 ) geometry_table <- data.frame( path = rownames(current), `Climatic Displacement` = geometry_fit[["climate_change_amount"]], `Niche Distance Shift` = geometry_fit[["niche_distance_change"]], `Climatic Reconfiguration` = geometry_fit[["climate_reconfiguration"]], `Niche Boundary Exceedance` = geometry_fit[["niche_boundary_exceedance"]], check.names = FALSE ) knitr::kable(geometry_table, digits = 3) ``` The towards and away examples both have $D_i=1$, with $R_i=-1$ and $R_i=1$, respectively. Moving to $(0,1)$ leaves niche distance unchanged, so $R_i=0$ and all displacement is represented by Climatic Reconfiguration. Only the away example lies beyond the fitted boundary. ```{r} identity_error <- with( geometry_fit, climate_change_amount^2 - niche_distance_change^2 - climate_reconfiguration^2 ) max(abs(identity_error)) ``` ## Using SDM outputs Binary SDM output can define zero-one reference weights. Continuous suitability values can remain continuous; `occupied_threshold` sets values at or below a cutoff to zero without converting larger values to one. These weights define how current locations contribute to the climatic niche reference. They are not a projected suitability response, and the four `climniche` quantities remain distances and positions in climatic space.