Skip to content

Commit

Permalink
Merge pull request #79 from iiasa/dev
Browse files Browse the repository at this point in the history
Merging 0.1 dev branch to main
  • Loading branch information
Martin-Jung authored Nov 9, 2023
2 parents 068ad37 + a4bbbcc commit f8d204b
Show file tree
Hide file tree
Showing 46 changed files with 1,522 additions and 391 deletions.
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ message: 'To cite package "ibis.iSDM" in publications use:'
type: software
license: CC-BY-4.0
title: 'ibis.iSDM: Modelling framework for integrated biodiversity distribution scenarios'
version: 0.0.9
version: 0.1.0
abstract: Integrated framework of modelling the distribution of species and ecosystems
in a suitability framing. This package allows the estimation of integrated species
distribution models (iSDM) based on several sources of evidence and provided presence-only
Expand Down
4 changes: 3 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: ibis.iSDM
Type: Package
Title: Modelling framework for integrated biodiversity distribution scenarios
Version: 0.0.9
Version: 0.1.0
Authors@R:
c(person(given = "Martin",
family = "Jung",
Expand Down Expand Up @@ -99,6 +99,7 @@ Collate:
'bdproto-predictors.R'
'add_predictors.R'
'add_predictors_globiom.R'
'add_predictors_model.R'
'identifier.R'
'bdproto-distributionmodel.R'
'bdproto-priorlist.R'
Expand Down Expand Up @@ -141,6 +142,7 @@ Collate:
'pseudoabsence.R'
'scenario.R'
'similarity.R'
'simulate_population_steps.R'
'summary.R'
'threshold.R'
'train.R'
Expand Down
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export(add_predictor_elevationpref)
export(add_predictor_range)
export(add_predictors)
export(add_predictors_globiom)
export(add_predictors_model)
export(add_priors)
export(add_pseudoabsence)
export(alignRasters)
Expand Down Expand Up @@ -138,6 +139,7 @@ export(sanitize_names)
export(scenario)
export(sel_predictors)
export(similarity)
export(simulate_population_steps)
export(spartial)
export(thin_observations)
export(threshold)
Expand Down Expand Up @@ -182,6 +184,7 @@ exportMethods(add_predictor_elevationpref)
exportMethods(add_predictor_range)
exportMethods(add_predictors)
exportMethods(add_predictors_globiom)
exportMethods(add_predictors_model)
exportMethods(add_priors)
exportMethods(check)
exportMethods(distribution)
Expand All @@ -201,6 +204,7 @@ exportMethods(rm_priors)
exportMethods(scenario)
exportMethods(sel_predictors)
exportMethods(similarity)
exportMethods(simulate_population_steps)
exportMethods(threshold)
exportMethods(train)
exportMethods(validate)
Expand Down
26 changes: 25 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
# ibis.iSDM 0.0.9 (current dev branch)
# ibis.iSDM 0.1.0 (current dev branch)

#### New features
* Added a small convenience wrapper to add model outputs to another model `add_predictors_model()`
* Started adding mechanistic SDM vignette #67
* Wrapper for *steps* implemented via `simulate_population_steps()` #68

#### Minor improvements and bug fixes
* Added R-universe installation option as alternative to github #38
* Minor bug fixes in `scenario()` object, and MigClim and Kissmig wrappers.
* Bug fix related to CRS classes of sp and sf
* Bug fix related to blas.num.threads
* Bug fix that crashed `write_summary()` outputs when no prediction was made.
* Bug fix related to CRS in `engine_inla()`
* Bug fix in `engine_stan()` related to background layer
* Class of biodiversity data is identical for PO and PA
* Bug fix in `built_formula_glmnet()` and response
* Bug fix in `built_formula_gdb()` and response
* Each model$biodiversity stores only predictors of current ID
* Bug fix in `built_formula_inla()` for INLABRU

# ibis.iSDM 0.0.9

#### New features
* Added new vignette on available functions for data preparation #67
* Addition of small `mask()` function that emulates the for `terra`.
Expand All @@ -13,6 +35,7 @@
* Improved error messages and handling of formula's.

# ibis.iSDM 0.0.8

#### New features
* Implemented min size constraint (`add_constraint_minsize()`) #56
* Added a function for estimating partial effects of ensembles `ensemble_spartial()`.
Expand All @@ -26,6 +49,7 @@
* Allow to specify location of biodiversity point records in `threshold()`.

# ibis.iSDM 0.0.7

#### New features
* Added method proximity to `add_control_bias()` to place lower weights on points closer to another.
* Added helper functions `get_data()` and the option to apply `threshold()` directly on BiodiversityScenarios.
Expand Down
22 changes: 16 additions & 6 deletions R/add_constraint.R
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,16 @@ NULL
#' can be particular useful to limit the influence of increasing marginal
#' responses and avoid biologically unrealistic projections.
#'
#' **Boundary**:
#' **Boundary and size**:
#' * \code{boundary} - Applies a hard boundary constraint on the projection, thus disallowing an expansion of a range outside
#' the provide layer. Similar as specifying projection limits (see
#' [`distribution`]), but can be used to specifically constrain a projection
#' within a certain area (e.g. a species range or an island).
#'
#' * \code{minsize} - Allows to specify a certain size that must be satisfied
#' in order for a thresholded patch to be occupied. Can be thought of as a minimum
#' size requirement. See `add_constraint_minsize()` for the required parameters.
#'
#' @returns Adds constraints data to a [`BiodiversityScenario`] object.
#' @references
#' * Bateman, B. L., Murphy, H. T., Reside, A. E., Mokany, K., & VanDerWal, J. (2013). Appropriateness of full‐, partial‐and no‐dispersal scenarios in climate change impact modelling. Diversity and Distributions, 19(10), 1224-1234.
Expand Down Expand Up @@ -106,7 +110,8 @@ methods::setMethod(
# Match method
method <- match.arg(arg = method,
choices = c("sdd_fixed", "sdd_nexpkernel", "kissmig", "migclim",
"hardbarrier","resistance", "boundary",
"hardbarrier","resistance",
"boundary", "minsize",
"nichelimit"), several.ok = FALSE)

# Now call the respective functions individually
Expand All @@ -126,8 +131,10 @@ methods::setMethod(
# --- #
"nichelimit" = add_constraint_adaptability(mod, method = "nichelimit", ...),
# --- #
"boundary" = add_constraint_boundary(mod, ...)
)
"boundary" = add_constraint_boundary(mod, ...),
# --- #
"minsize" = add_constraint_minsize(mod, ...)
)
return(o)
}
)
Expand Down Expand Up @@ -352,7 +359,7 @@ methods::setMethod(
is.vector(params) || is.list(params),
is.null(resistance) || is.logical(resistance) || is.Raster(resistance),
# Check that baseline threshold raster is binomial
length(unique(baseline_threshold))==2
length(unique(baseline_threshold)[,1])==2
)

check_package('kissmig')
Expand All @@ -366,12 +373,15 @@ methods::setMethod(
# Simulate kissmig for a given threshold and suitability raster
km <- kissmig::kissmig(O = terra_to_raster( baseline_threshold ),
# Rescale newsuit to 0-1
S = predictor_transform(new_suit, 'norm'),
S = predictor_transform(new_suit, 'norm') |>
terra_to_raster(),
it = as.numeric( params['iteration'] ),
type = params['type'],
pext = as.numeric(params['pext']),
pcor = as.numeric(params['pcor'])
)
# Convert to terra again
km <- terra::rast(km)
if(is.factor(km)) km <- terra::as.int(km)

# Now multiply the net suitability projection with this mask Thus removing any
Expand Down
2 changes: 1 addition & 1 deletion R/add_constraint_MigClim.R
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ NULL
#'
#' @name add_constraint_MigClim
#' @aliases add_constraint_MigClim
#' @family constrain
#' @family constraint
#' @keywords scenario
#' @exportMethod add_constraint_MigClim
#' @export
Expand Down
2 changes: 2 additions & 0 deletions R/add_predictors.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ NULL
#' the [distribution] object. This function furthermore allows to transform or
#' create derivates of provided predictors.
#'
#' @details
#'
#' A transformation takes the provided rasters and for instance rescales them or
#' transforms them through a principal component analysis ([prcomp]). In
#' contrast, derivates leave the original provided predictors alone, but instead
Expand Down
172 changes: 172 additions & 0 deletions R/add_predictors_model.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#' @include utils.R bdproto.R bdproto-biodiversitydistribution.R bdproto-predictors.R
NULL

#' Add predictors from a fitted model to a Biodiversity distribution object
#'
#' @description This function is a convenience wrapper to add the output from a
#' previous fitted [`DistributionModel`] to another [`BiodiversityDistribution-class`]
#' object. Obviously only works if a prediction was fitted in the model. Options
#' to instead add thresholds, or to transform / derivate the model outputs are
#' also supported.
#'
#' @details
#'
#' A transformation takes the provided rasters and for instance rescales them or
#' transforms them through a principal component analysis ([prcomp]). In
#' contrast, derivates leave the original provided predictors alone, but instead
#' create new ones, for instance by transforming their values through a
#' quadratic or hinge transformation. Note that this effectively increases the
#' number of predictors in the object, generally requiring stronger
#' regularization by the used [`Engine`]. Both transformations and derivates can
#' also be combined. Available options for transformation are:
#' * \code{'none'} - Leaves the provided predictors in the original scale.
#' * \code{'pca'} - Converts the predictors to principal components. Note that this
#' results in a renaming of the variables to principal component axes!
#' * \code{'scale'} - Transforms all predictors by applying [scale] on them.
#' * \code{'norm'} - Normalizes all predictors by transforming them to a scale from 0 to 1.
#' * \code{'windsor'} - Applies a windsorization to the target predictors. By default
#' this effectively cuts the predictors to the 0.05 and 0.95, thus helping to
#' remove extreme outliers.
#'
#' Available options for creating derivates are:
#' * \code{'none'} - No additional predictor derivates are created.
#' * \code{'quad'} - Adds quadratic transformed predictors.
#' * \code{'interaction'} - Add interacting predictors. Interactions need to be specified (\code{"int_variables"})!
#' * \code{'thresh'} - Add threshold transformed predictors.
#' * \code{'hinge'} - Add hinge transformed predictors.
#' * \code{'bin'} - Add predictors binned by their percentiles.
#'
#' @param x [distribution()] (i.e. [`BiodiversityDistribution-class`]) object.
#' @param model A [`DistributionModel`] object.
#' @param transform A [`vector`] stating whether predictors should be
#' preprocessed in any way (Options: \code{'none'},\code{'pca'},
#' \code{'scale'}, \code{'norm'})
#' @param derivates A Boolean check whether derivate features should be
#' considered (Options: \code{'none'}, \code{'thresh'}, \code{'hinge'},
#' \code{'quad'}) )
#' @param threshold_only A [`logical`] flag indicating whether to add thresholded
#' layers from the fitted model (if existing) instead (Default: \code{FALSE}).
#' @param priors A [`PriorList-class`] object. Default is set to \code{NULL}
#' which uses default prior assumptions.
#' @param ... Other parameters passed down
#' @aliases add_predictors_model
#' @examples
#' \dontrun{
#' # Fit first model
#' fit <- distribution(background) |>
#' add_predictors(covariates) |>
#' add_biodiversity_poipa(species) |>
#' engine_glmnet() |>
#' train()
#'
#' # New model object
#' obj <- distribution(background) |>
#' add_predictors_model(fit)
#' obj
#' }
#' @name add_predictors_model
NULL

#' @name add_predictors_model
#' @rdname add_predictors_model
#' @exportMethod add_predictors_model
#' @export
methods::setGeneric(
"add_predictors_model",
signature = methods::signature("x", "model"),
function(x, model, transform = 'scale', derivates = 'none',
threshold_only = FALSE, priors = NULL, ...) standardGeneric("add_predictors_model"))

#' @name add_predictors_model
#' @rdname add_predictors_model
#' @usage
#' \S4method{add_predictors_model}{BiodiversityDistribution,ANY,character,character,logical,ANY}(x,model,transform,derivates,threshold_only,priors,...)
methods::setMethod(
"add_predictors_model",
methods::signature(x = "BiodiversityDistribution", model = "ANY"),
function(x, model, transform = 'scale', derivates = 'none',
threshold_only = FALSE, priors = NULL, ...) {
# Try and match transform and derivatives arguments
transform <- match.arg(transform, c('none','pca', 'scale', 'norm', 'windsor') , several.ok = TRUE)
derivates <- match.arg(derivates, c('none','thresh', 'hinge', 'quadratic', 'bin', 'interaction') , several.ok = TRUE)

assertthat::assert_that(inherits(x, "BiodiversityDistribution"),
inherits(model, "DistributionModel"),
is.logical(threshold_only),
all(transform == 'none') || all( transform %in% c('pca', 'scale', 'norm', 'windsor') ),
all(derivates == 'none') || all( derivates %in% c('thresh', 'hinge', 'quadratic', 'bin', 'interaction') ),
is.null(priors) || inherits(priors,'PriorList')
)
# Messenger
if(getOption('ibis.setupmessages')) myLog('[Setup]','green','Adding predictors from fitted model...')

# If priors have been set, save them in the distribution object
if(!is.null(priors)) {
x <- x$set_priors(priors)
}

# Get prediction from model object
assertthat::assert_that(
"prediction" %in% model$show_rasters(),
msg = "No prediction found in model object!"
)
if(threshold_only){
tr <- grep('threshold', model$show_rasters(),ignore.case = TRUE,value = TRUE)
if(length(tr)==1){
prediction <- model$get_data(tr)
} else {
if(getOption('ibis.setupmessages')) myLog('[Setup]','yellow','No threshold found in fitted model. Using prediction...')
prediction <- model$get_data()
}
} else {
prediction <- model$get_data()
}
assertthat::assert_that(is.Raster(prediction))
# Set names
names(prediction) <- paste0(make.names(model$model$runname),"__",names(prediction))

# Standardization and scaling
if('none' %notin% transform){
if(getOption('ibis.setupmessages')) myLog('[Setup]','green','Transforming prediction...')
for(tt in transform) prediction <- predictor_transform(prediction, option = tt)
}
assertthat::assert_that(is.Raster(prediction))

# Calculate derivates if set
if('none' %notin% derivates){
if(getOption('ibis.setupmessages')) myLog('[Setup]','green','Creating prediction derivates...')
# Specific condition for interaction
new_prediction <- terra::rast()
for(dd in derivates){
suppressWarnings(
new_prediction <- c(new_prediction, predictor_derivate(prediction,
option = dd) )
)
}
# Add
prediction <- c(prediction, new_prediction)
rm(new_prediction)
}

# Assign an attribute to this object to keep track of it
attr(prediction,'transform') <- transform

# Sanitize names if specified
if(getOption('ibis.cleannames')) names(prediction) <- sanitize_names(names(prediction))

# Get existing predictors
if(!is.Waiver(x$predictors)){
env <- x$predictors$get_data()
env <- c(env, prediction)
}

# Finally set the data to the BiodiversityDistribution object
x$set_predictors(
bdproto(NULL, PredictorDataset,
id = new_id(),
data = env,
...
)
)
}
)
Loading

0 comments on commit f8d204b

Please sign in to comment.