From 3788b53708942cc63fc6dce25f7d790b316b1aeb Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 13 Sep 2024 12:46:56 +0200 Subject: [PATCH 01/22] sort index alphabetically --- _pkgdown.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_pkgdown.yml b/_pkgdown.yml index a156972..07e7ae6 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -8,9 +8,9 @@ reference: - subtitle: Trait evolution desc: Simulate trait evolution contents: - - stasis - - random_walk - ornstein_uhlenbeck + - random_walk + - stasis - subtitle: Event type data desc: Simulate event type data (e.g., fossil location/ages, first/last occurrences) @@ -22,10 +22,10 @@ reference: - subtitle: Ecology and taphonomy desc: Ecological niche models and taphonomic effects contents: - - apply_niche - - snd_niche - bounded_niche + - apply_niche - apply_taphonomy + - snd_niche - thin - subtitle: Example data From 839e1306373c9cd8657e344928d1d3ee86752989 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 13 Sep 2024 14:54:24 +0200 Subject: [PATCH 02/22] add available distances from shore to docs --- R/scenarioA.R | 2 +- man/scenarioA.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/scenarioA.R b/R/scenarioA.R index 63976d8..b07e20e 100644 --- a/R/scenarioA.R +++ b/R/scenarioA.R @@ -8,7 +8,7 @@ #' #' * `t_myr` : numeric vector. timesteps of the simulation in Myr #' * `sl_m` : numeric vector. eustatic sea level in m -#' * `dist_from_shore` : character vector. Distance from shore in km of locations at which the observations were made +#' * `dist_from_shore` : character vector. Distance from shore in km of locations at which the observations were made. Available distances are "2km", "4km", "6km", "8km", "10km", "12km". #' * `h_m` : matrix of size length(t_myr) x length(dist_from_shore). Accumulated sediment height in m at examined locations #' * `wd_m`: matrix of size length(t_myr) x length(dist_from_shore). Water depth in m at examined locations #' * `strat_col`: list with length(dist_from shore) elements. Represents a stratigraphic column. Each element is a list with two elements: diff --git a/man/scenarioA.Rd b/man/scenarioA.Rd index 41ea1dc..1f5356d 100644 --- a/man/scenarioA.Rd +++ b/man/scenarioA.Rd @@ -9,7 +9,7 @@ A list with 6 elements: \itemize{ \item \code{t_myr} : numeric vector. timesteps of the simulation in Myr \item \code{sl_m} : numeric vector. eustatic sea level in m -\item \code{dist_from_shore} : character vector. Distance from shore in km of locations at which the observations were made +\item \code{dist_from_shore} : character vector. Distance from shore in km of locations at which the observations were made. Available distances are "2km", "4km", "6km", "8km", "10km", "12km". \item \code{h_m} : matrix of size length(t_myr) x length(dist_from_shore). Accumulated sediment height in m at examined locations \item \code{wd_m}: matrix of size length(t_myr) x length(dist_from_shore). Water depth in m at examined locations \item \code{strat_col}: list with length(dist_from shore) elements. Represents a stratigraphic column. Each element is a list with two elements: From 058377a35901aab3329162904654654015e71652 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:30:43 +0200 Subject: [PATCH 03/22] expand documentation --- R/stasis.R | 8 +++++--- man/stasis.Rd | 9 ++++++--- tests/testthat/test_stasis.R | 11 +++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 tests/testthat/test_stasis.R diff --git a/R/stasis.R b/R/stasis.R index 817583c..50fd1d5 100644 --- a/R/stasis.R +++ b/R/stasis.R @@ -4,11 +4,13 @@ stasis = function(t, mean = 0, sd = 1){ #' @title simulate phenotypic stasis #' #' @param t times at which the traits are determined - #' @param mean scalar, mean trait value - #' @param sd strictly positive scalar, standard deviation of traits + #' @param mean number, mean trait value + #' @param sd strictly positive number, standard deviation of traits + #' + #' @seealso [random_walk()] and [ornstein_uhlenbeck()] to simulate other modes of evolution, [stasis_sl()] to simulate stasis on specimen level #' #' @description - #' Simulates stasis as independent, normally distributed random variables with mean `mean` and standard deviation `sd` + #' Simulates stasis of mean trait values as independent, normally distributed random variables with mean `mean` and standard deviation `sd` #' #' @returns A list with two elements: `t` and `y`. `t` is a duplicate of the input `t`, `y` are the corresponding trait values. Output list is of S3 class `timelist` (inherits from `list`) and can thus be plotted directly using `plot`, see `?admtools::plot.timelist` #' @examples diff --git a/man/stasis.Rd b/man/stasis.Rd index 54a8319..fbe760e 100644 --- a/man/stasis.Rd +++ b/man/stasis.Rd @@ -9,15 +9,15 @@ stasis(t, mean = 0, sd = 1) \arguments{ \item{t}{times at which the traits are determined} -\item{mean}{scalar, mean trait value} +\item{mean}{number, mean trait value} -\item{sd}{strictly positive scalar, standard deviation of traits} +\item{sd}{strictly positive number, standard deviation of traits} } \value{ A list with two elements: \code{t} and \code{y}. \code{t} is a duplicate of the input \code{t}, \code{y} are the corresponding trait values. Output list is of S3 class \code{timelist} (inherits from \code{list}) and can thus be plotted directly using \code{plot}, see \code{?admtools::plot.timelist} } \description{ -Simulates stasis as independent, normally distributed random variables with mean \code{mean} and standard deviation \code{sd} +Simulates stasis of mean trait values as independent, normally distributed random variables with mean \code{mean} and standard deviation \code{sd} } \examples{ @@ -30,3 +30,6 @@ Simulates stasis as independent, normally distributed random variables with mean } +\seealso{ +\code{\link[=random_walk]{random_walk()}} and \code{\link[=ornstein_uhlenbeck]{ornstein_uhlenbeck()}} to simulate other modes of evolution, \code{\link[=stasis_sl]{stasis_sl()}} to simulate stasis on specimen level +} diff --git a/tests/testthat/test_stasis.R b/tests/testthat/test_stasis.R new file mode 100644 index 0000000..5befff9 --- /dev/null +++ b/tests/testthat/test_stasis.R @@ -0,0 +1,11 @@ +test_that("throws error for negative sd", { + expect_error(stasis(c(1,2), mean = 1, sd = - 0.1)) +}) + +test_that("returns constant for sd of 0",{ + sd = 0 + t = seq(0, 1, by = 0.1) + mean = 0 + st = stasis(t, mean, sd) + expect_equal(rep(mean, length(t)), st$y) +}) From 65a094d69503e03c41a0c7c42982f38840d3a2d1 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:31:39 +0200 Subject: [PATCH 04/22] add stasis simulation for pre-paleoTS format --- NAMESPACE | 3 +++ man/stasis_sl.Rd | 28 ++++++++++++++++++++++++++++ tests/testthat/test_stasis_sl.R | 8 ++++++++ 3 files changed, 39 insertions(+) create mode 100644 man/stasis_sl.Rd create mode 100644 tests/testthat/test_stasis_sl.R diff --git a/NAMESPACE b/NAMESPACE index 047e790..4ec05b7 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,6 @@ # Generated by roxygen2: do not edit by hand +S3method(reduce_to_paleoTS,pre_paleoTS) export(apply_niche) export(apply_taphonomy) export(bounded_niche) @@ -7,7 +8,9 @@ export(ornstein_uhlenbeck) export(p3) export(p3_var_rate) export(random_walk) +export(reduce_to_paleoTS) export(rej_samp) export(snd_niche) export(stasis) +export(stasis_sl) export(thin) diff --git a/man/stasis_sl.Rd b/man/stasis_sl.Rd new file mode 100644 index 0000000..bd7f92a --- /dev/null +++ b/man/stasis_sl.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/stasis_sl.R +\name{stasis_sl} +\alias{stasis_sl} +\title{simulate phenotypic stasis (pre-paleoTS format)} +\usage{ +stasis_sl(t, mean = 0, sd = 1, interpop_var = 1, n_per_sample = 10) +} +\arguments{ +\item{t}{times at which the traits are determined} + +\item{mean}{mean trait value} + +\item{sd}{stictly positive number, standard deviation of traits around the mean} + +\item{interpop_var}{interpopulation variance, determines how much specimens from the same population vary} + +\item{n_per_sample}{integer, number of specimens sampled per population/sampling locality} +} +\value{ +description +} +\description{ +simulated stasis as independent, normally distributed random variables with mean \code{mean} and standard deviation \code{sd}, draws \code{n_per_sample} samples from each sampling location (population) that have specified variance \code{interpop_var} +} +\seealso{ +\code{\link[=stasis]{stasis()}} for the version that simulated stasis of mean trait values. +} diff --git a/tests/testthat/test_stasis_sl.R b/tests/testthat/test_stasis_sl.R new file mode 100644 index 0000000..dc9c5c7 --- /dev/null +++ b/tests/testthat/test_stasis_sl.R @@ -0,0 +1,8 @@ +test_that("correct S3 class is returned",{ + expect_s3_class(stasis_sl(1:2), "pre_paleoTS") +}) + +test_that("incorrect parameters are caught", { + expect_error(stasis_sl(1:2, interpop_var = 0)) + expect_error(stasis_sl(1:2, n_per_sample = 0)) +}) From 24673f77b110a7e578ef1d4e82b79b1c04c0eca4 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:32:36 +0200 Subject: [PATCH 05/22] stasis simulation for pre-palepTS format" --- R/stasis_sl.R | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 R/stasis_sl.R diff --git a/R/stasis_sl.R b/R/stasis_sl.R new file mode 100644 index 0000000..060119f --- /dev/null +++ b/R/stasis_sl.R @@ -0,0 +1,35 @@ +stasis_sl = function(t, mean = 0, sd = 1, interpop_var = 1, n_per_sample = 10){ + #' @export + #' + #' @title simulate phenotypic stasis (pre-paleoTS format) + #' + #' @param t times at which the traits are determined + #' @param mean mean trait value + #' @param sd stictly positive number, standard deviation of traits around the mean + #' @param interpop_var interpopulation variance, determines how much specimens from the same population vary + #' @param n_per_sample integer, number of specimens sampled per population/sampling locality + #' + #' @description + #' simulated stasis as independent, normally distributed random variables with mean `mean` and standard deviation `sd`, draws `n_per_sample` samples from each sampling location (population) that have specified variance `interpop_var` + #' + #' @seealso [stasis()] for the version that simulates stasis of mean trait values. + #' + #' @returns an object of S3 class "pre-paleoTS". This object can be transformed using `apply_taphonomy`, `apply_niche` or `time_to_strat`, and then reduced to a `paleoTS` object using `reduce_to_paleoTS`. This can then be used to test for different modes of evolution. + #' + + if (interpop_var <= 0){ + stop("parameter \'interpop_var\' must me >0 ") + } + if (n_per_sample <1){ + stop("parameter \'n_per_sample\' must be >=1") + } + x = stasis(t, mean, sd) + r = list(t = x$t) + vals = list() + for (i in seq_along(x$t)){ + vals[[i]] = rnorm(n = n_per_sample, mean = x$y[i], sd = sqrt(interpop_var)) + } + r[["vals"]] = vals + class(r) = c("pre_paleoTS","timelist", "list") + return(r) +} From 69f9a012e7ee9462ea3a03e06d9bd01ba3d25d8f Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:33:11 +0200 Subject: [PATCH 06/22] remove test bc of wrong naming --- tests/testthat/test_stasis..R | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 tests/testthat/test_stasis..R diff --git a/tests/testthat/test_stasis..R b/tests/testthat/test_stasis..R deleted file mode 100644 index 5befff9..0000000 --- a/tests/testthat/test_stasis..R +++ /dev/null @@ -1,11 +0,0 @@ -test_that("throws error for negative sd", { - expect_error(stasis(c(1,2), mean = 1, sd = - 0.1)) -}) - -test_that("returns constant for sd of 0",{ - sd = 0 - t = seq(0, 1, by = 0.1) - mean = 0 - st = stasis(t, mean, sd) - expect_equal(rep(mean, length(t)), st$y) -}) From 34bcc24bcd4b91f1367bf0bbec9c739e5d9c70f5 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:51:52 +0200 Subject: [PATCH 07/22] add reduction of pre-paleoTS to paleoTS --- R/reduce_to_paleoTS.R | 46 ++++++++++++++++++++++++++++++++++++++++ man/reduce_to_paleoTS.Rd | 28 ++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 R/reduce_to_paleoTS.R create mode 100644 man/reduce_to_paleoTS.Rd diff --git a/R/reduce_to_paleoTS.R b/R/reduce_to_paleoTS.R new file mode 100644 index 0000000..5b68be2 --- /dev/null +++ b/R/reduce_to_paleoTS.R @@ -0,0 +1,46 @@ +reduce_to_paleoTS = function(x, ...){ + #' @export + #' + #' @title reduce pre-paleoTS format to paleoTS + #' + #' @description + #' paleoTS is a format for paleontological time series. It is a summary format where interpopulation variance is provided as a parameter. As a result, taphonomic and ecological effects that act on individual specimens can not be modeled for paleoTS objects. To resolve this, the pre_paleoTS format tracks each specimen individually. This function reduces the pre-paleoTS format into standard paleoTS object, which can be used by the paleoTS package. + #' + #' @param x a `pre_paleoTS` object + #' @param ... other options. currently unused + #' + #' @seealso [stasis_sl()] to simulate stasis on specimen level (sl), returning an object of call `pre_paleoTS` + #' + #' @returns a `paleoTS` object + #' + #' @examples + #' x = stasis_sl(t = 0:5) # create pre_paleoTS object representing stasis on specimen level + #' y = reduce_to_paleoTS(x) # reduce to standard paleoTS format + #' # now analyses using the paleoTS package can be applied to y + #' + + UseMethod("reduce_to_paleoTS") +} + +reduce_to_paleoTS.pre_paleoTS = function(x, ...){ + + #' @export + #' + if (inherits(x, "timelist")){ + tt = x$t + } + if (inherits(x, "stratlist")){ + tt = x$h + } + l = length(x$t) + mm = rep(NA, l) + vv = rep(NA, l) + nn = rep(NA, l) + for (i in seq_along(x$t)){ + mm[i] = mean(x$vals[[i]]) + vv[i] = stats::var(x$vals[[i]]) + nn[i] = length(x$vals[[i]]) + } + x = paleoTS::as.paleoTS(mm, vv, nn, tt) + return(x) +} diff --git a/man/reduce_to_paleoTS.Rd b/man/reduce_to_paleoTS.Rd new file mode 100644 index 0000000..f3ed3ec --- /dev/null +++ b/man/reduce_to_paleoTS.Rd @@ -0,0 +1,28 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/reduce_to_paleoTS.R +\name{reduce_to_paleoTS} +\alias{reduce_to_paleoTS} +\title{reduce pre-paleoTS format to paleoTS} +\usage{ +reduce_to_paleoTS(x, ...) +} +\arguments{ +\item{x}{a \code{pre_paleoTS} object} + +\item{...}{other options. currently unused} +} +\value{ +a \code{paleoTS} object +} +\description{ +paleoTS is a format for paleontological time series. It is a summary format where interpopulation variance is provided as a parameter. As a result, taphonomic and ecological effects that act on individual specimens can not be modeled for paleoTS objects. To resolve this, the pre_paleoTS format tracks each specimen individually. This function reduces the pre-paleoTS format into standard paleoTS object, which can be used by the paleoTS package. +} +\examples{ +x = stasis_sl(t = 0:5) # create pre_paleoTS object representing stasis on specimen level +y = reduce_to_paleoTS(x) # reduce to standard paleoTS format +# now analyses using the paleoTS package can be applied to y + +} +\seealso{ +\code{\link[=stasis_sl]{stasis_sl()}} to simulate stasis on specimen level (sl), returning an object of call \code{pre_paleoTS} +} From a4835e9e542794e1e71ff89c55631b5fd42ecb97 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:52:44 +0200 Subject: [PATCH 08/22] add paleoTS dependency --- DESCRIPTION | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 644b101..bb666a3 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -20,7 +20,8 @@ Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 Imports: - admtools (>= 0.3.0) + admtools (>= 0.3.0), + paleoTS Suggests: knitr, rmarkdown, From a85e3a07211c5e2dbecad93326b7d9b683c21eb8 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:53:09 +0200 Subject: [PATCH 09/22] expand docs --- R/stasis_sl.R | 2 +- man/stasis_sl.Rd | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/stasis_sl.R b/R/stasis_sl.R index 060119f..4654bad 100644 --- a/R/stasis_sl.R +++ b/R/stasis_sl.R @@ -27,7 +27,7 @@ stasis_sl = function(t, mean = 0, sd = 1, interpop_var = 1, n_per_sample = 10){ r = list(t = x$t) vals = list() for (i in seq_along(x$t)){ - vals[[i]] = rnorm(n = n_per_sample, mean = x$y[i], sd = sqrt(interpop_var)) + vals[[i]] = stats::rnorm(n = n_per_sample, mean = x$y[i], sd = sqrt(interpop_var)) } r[["vals"]] = vals class(r) = c("pre_paleoTS","timelist", "list") diff --git a/man/stasis_sl.Rd b/man/stasis_sl.Rd index bd7f92a..c06d940 100644 --- a/man/stasis_sl.Rd +++ b/man/stasis_sl.Rd @@ -18,11 +18,11 @@ stasis_sl(t, mean = 0, sd = 1, interpop_var = 1, n_per_sample = 10) \item{n_per_sample}{integer, number of specimens sampled per population/sampling locality} } \value{ -description +an object of S3 class "pre-paleoTS". This object can be transformed using \code{apply_taphonomy}, \code{apply_niche} or \code{time_to_strat}, and then reduced to a \code{paleoTS} object using \code{reduce_to_paleoTS}. This can then be used to test for different modes of evolution. } \description{ simulated stasis as independent, normally distributed random variables with mean \code{mean} and standard deviation \code{sd}, draws \code{n_per_sample} samples from each sampling location (population) that have specified variance \code{interpop_var} } \seealso{ -\code{\link[=stasis]{stasis()}} for the version that simulated stasis of mean trait values. +\code{\link[=stasis]{stasis()}} for the version that simulates stasis of mean trait values. } From c0c86e1c8b72e8b8090fc1b183e9730f8fa688e1 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:02:48 +0200 Subject: [PATCH 10/22] add new functions to index --- _pkgdown.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/_pkgdown.yml b/_pkgdown.yml index 07e7ae6..f3ae0ac 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -11,6 +11,7 @@ reference: - ornstein_uhlenbeck - random_walk - stasis + - stasis_sl - subtitle: Event type data desc: Simulate event type data (e.g., fossil location/ages, first/last occurrences) @@ -32,3 +33,8 @@ reference: desc: Example data from stratigraphic forward models contents: - scenarioA + +- subtitle: paleoTS functionality + desc: Tools for linkage with the paleoTS package + contents: + - reduce_to_paleoTS From be239e39310ef04cafbd18eafd2b23919906cdf9 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:07:00 +0200 Subject: [PATCH 11/22] introduce dispatch --- NAMESPACE | 2 ++ R/apply_niche.R | 8 +++++++- R/apply_taphonomy.R | 5 +++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/NAMESPACE b/NAMESPACE index 4ec05b7..0673378 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,7 @@ # Generated by roxygen2: do not edit by hand +S3method(apply_niche,numeric) +S3method(apply_taphonomy,numeric) S3method(reduce_to_paleoTS,pre_paleoTS) export(apply_niche) export(apply_taphonomy) diff --git a/R/apply_niche.R b/R/apply_niche.R index 03a9c3d..4c9515b 100644 --- a/R/apply_niche.R +++ b/R/apply_niche.R @@ -46,10 +46,16 @@ apply_niche = function(x, niche_def, gc){ #' #' #' @seealso [apply_taphonomy()] to model taphonomic effects based on the same principle, [thin()] for the underlying mathematical procedure. Basic niche models available are [bounded_niche()] and [snd_niche()] + UseMethod("apply_niche") +} + +apply_niche.numeric = function(x, niche_def, gc){ + + #' @export # function that returns collection probability as a function of y (typically time) change_in_niche = function(y) niche_def(gc(y)) # thin events based on collection probability r = thin(x, change_in_niche) return(r) - } +} diff --git a/R/apply_taphonomy.R b/R/apply_taphonomy.R index f8ca9a5..3776aef 100644 --- a/R/apply_taphonomy.R +++ b/R/apply_taphonomy.R @@ -22,7 +22,12 @@ apply_taphonomy = function(x, pres_potential, ctc){ #' # for details on usage #' #' + UseMethod("apply_taphonomy") +} + +apply_taphonomy.numeric = function(x, pres_potential, ctc){ + #' @export # function that returns preservation potential as a function of input (e.g. time or position) change_pres_pot = function(y) pres_potential(ctc(y)) # thin events From 239b1bdb1f7b525b5843a0de1d5a746a8515b0be Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:27:23 +0200 Subject: [PATCH 12/22] start implmentation of niche modeling for pre-paleoTS --- NAMESPACE | 1 + R/apply_niche.R | 13 +++++++++++++ tests/testthat/test_apply_niche.R | 7 ++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/NAMESPACE b/NAMESPACE index 0673378..c6a45f7 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand S3method(apply_niche,numeric) +S3method(apply_niche,pre_paleoTS) S3method(apply_taphonomy,numeric) S3method(reduce_to_paleoTS,pre_paleoTS) export(apply_niche) diff --git a/R/apply_niche.R b/R/apply_niche.R index 4c9515b..44a5559 100644 --- a/R/apply_niche.R +++ b/R/apply_niche.R @@ -59,3 +59,16 @@ apply_niche.numeric = function(x, niche_def, gc){ r = thin(x, change_in_niche) return(r) } + +apply_niche.pre_paleoTS = function(x, niche_def, gc){ + #' @export + #' + change_in_niche = function(y) niche_def(gc(y)) + thin_vals = change_in_niche(x$t) + for (i in seq_along(x$t)){ + r = stats::rbinom(length(x$vals[[i]]), size = 1, prob = thin_vals[i]) + x$vals[[i]] = x$vals[[i]][as.logical(r)] + } + return(x) + +} diff --git a/tests/testthat/test_apply_niche.R b/tests/testthat/test_apply_niche.R index 615e049..2b9652c 100644 --- a/tests/testthat/test_apply_niche.R +++ b/tests/testthat/test_apply_niche.R @@ -1,5 +1,10 @@ -test_that("returns fewer events", { +test_that("returns fewer events for event type data", { n = 10 x = runif(n, 0, 1) expect_lt(length(apply_niche(x, niche_def = function(x) 0.5, gc = function(x) 1)), n) }) + +x = stasis_sl(1:3) +niche_def = function(x) rep(1, length(x)) +gc = function(x) rep(1, length(x)) +apply_niche(x, niche_def, gc) From d37aa97da2c4e53c4b02bca147a6937f33611cab Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 27 Sep 2024 07:35:51 +0200 Subject: [PATCH 13/22] expand documentation --- R/stasis_sl.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/stasis_sl.R b/R/stasis_sl.R index 4654bad..a1a6743 100644 --- a/R/stasis_sl.R +++ b/R/stasis_sl.R @@ -14,8 +14,11 @@ stasis_sl = function(t, mean = 0, sd = 1, interpop_var = 1, n_per_sample = 10){ #' #' @seealso [stasis()] for the version that simulates stasis of mean trait values. #' - #' @returns an object of S3 class "pre-paleoTS". This object can be transformed using `apply_taphonomy`, `apply_niche` or `time_to_strat`, and then reduced to a `paleoTS` object using `reduce_to_paleoTS`. This can then be used to test for different modes of evolution. + #' @returns an object of S3 class `pre_paleoTS`, inherits from `timelist` and `list`. The list has two elements: `t`, containing a vector of times of sampling, and `vals`, a list of trait values of the same length as `t`, with element containing trait values of individual specimens. This object can be transformed using `apply_taphonomy`, `apply_niche` or `time_to_strat`, and then reduced to a `paleoTS` object using `reduce_to_paleoTS`. This can then be used to test for different modes of evolution. #' + #' @examples + #' x = stasis_sl(1:5, mean = 2, sd = 2) + #' if (interpop_var <= 0){ stop("parameter \'interpop_var\' must me >0 ") From 0730611740a205653e02d9b8680556a2e60c339a Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 27 Sep 2024 07:41:47 +0200 Subject: [PATCH 14/22] add docs --- man/stasis_sl.Rd | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/man/stasis_sl.Rd b/man/stasis_sl.Rd index c06d940..a028454 100644 --- a/man/stasis_sl.Rd +++ b/man/stasis_sl.Rd @@ -18,10 +18,14 @@ stasis_sl(t, mean = 0, sd = 1, interpop_var = 1, n_per_sample = 10) \item{n_per_sample}{integer, number of specimens sampled per population/sampling locality} } \value{ -an object of S3 class "pre-paleoTS". This object can be transformed using \code{apply_taphonomy}, \code{apply_niche} or \code{time_to_strat}, and then reduced to a \code{paleoTS} object using \code{reduce_to_paleoTS}. This can then be used to test for different modes of evolution. +an object of S3 class \code{pre_paleoTS}, inherits from \code{timelist} and \code{list}. The list has two elements: \code{t}, containing a vector of times of sampling, and \code{vals}, a list of trait values of the same length as \code{t}, with element containing trait values of individual specimens. This object can be transformed using \code{apply_taphonomy}, \code{apply_niche} or \code{time_to_strat}, and then reduced to a \code{paleoTS} object using \code{reduce_to_paleoTS}. This can then be used to test for different modes of evolution. } \description{ simulated stasis as independent, normally distributed random variables with mean \code{mean} and standard deviation \code{sd}, draws \code{n_per_sample} samples from each sampling location (population) that have specified variance \code{interpop_var} +} +\examples{ +x = stasis_sl(1:5, mean = 2, sd = 2) + } \seealso{ \code{\link[=stasis]{stasis()}} for the version that simulates stasis of mean trait values. From 5fbf3b35fec805fbe848be7bec5fe768b85461e7 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 27 Sep 2024 07:41:58 +0200 Subject: [PATCH 15/22] add tests --- tests/testthat/test_reduce_to_paleoTS.R | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/testthat/test_reduce_to_paleoTS.R diff --git a/tests/testthat/test_reduce_to_paleoTS.R b/tests/testthat/test_reduce_to_paleoTS.R new file mode 100644 index 0000000..672d390 --- /dev/null +++ b/tests/testthat/test_reduce_to_paleoTS.R @@ -0,0 +1,9 @@ +test_that("runs without problems", { + x = stasis_sl(1:2) + expect_no_condition(reduce_to_paleoTS(x)) +}) + +test_that("retruns correct S3 class", { + x = stasis_sl(1:2) + expect_s3_class(reduce_to_paleoTS(x), "paleoTS") +}) From 2587df34d443873818bbde16d8009d9d11493619 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 27 Sep 2024 08:08:43 +0200 Subject: [PATCH 16/22] add helper function for probabilistic removal of elements --- NAMESPACE | 1 + R/prob_remove.R | 22 ++++++++++++++++++++++ _pkgdown.yml | 1 + man/prob_remove.Rd | 26 ++++++++++++++++++++++++++ tests/testthat/test_prob_remove.R | 6 ++++++ 5 files changed, 56 insertions(+) create mode 100644 R/prob_remove.R create mode 100644 man/prob_remove.Rd create mode 100644 tests/testthat/test_prob_remove.R diff --git a/NAMESPACE b/NAMESPACE index c6a45f7..448999b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -10,6 +10,7 @@ export(bounded_niche) export(ornstein_uhlenbeck) export(p3) export(p3_var_rate) +export(prob_remove) export(random_walk) export(reduce_to_paleoTS) export(rej_samp) diff --git a/R/prob_remove.R b/R/prob_remove.R new file mode 100644 index 0000000..4252ea5 --- /dev/null +++ b/R/prob_remove.R @@ -0,0 +1,22 @@ +prob_remove = function(x, prob){ + #' @export + #' + #' @title probabilistic removal of elements + #' + #' @param x vector + #' @param prob number between 0 and 1, probability to preserve elements + #' + #' @description + #' probabilistic removal of elements from x. For each element, the probability to be preserved is independent and specified by prob + #' + #' @returns a vector of the same type as x + #' + #' @examples + #' x = prob_remove(1:10, 0.5) + #' x + #' @seealso [apply_niche()] and [apply_taphonomy()] use this function for transformation of `pre_paleoTS` objects + + r = stats::rbinom(length(x), size = 1, prob = prob) + x = x[as.logical(r)] + return(x) +} diff --git a/_pkgdown.yml b/_pkgdown.yml index f3ae0ac..43adf1f 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -28,6 +28,7 @@ reference: - apply_taphonomy - snd_niche - thin + - prob_remove - subtitle: Example data desc: Example data from stratigraphic forward models diff --git a/man/prob_remove.Rd b/man/prob_remove.Rd new file mode 100644 index 0000000..1597524 --- /dev/null +++ b/man/prob_remove.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/prob_remove.R +\name{prob_remove} +\alias{prob_remove} +\title{probabilistic removal of elements} +\usage{ +prob_remove(x, prob) +} +\arguments{ +\item{x}{vector} + +\item{prob}{number between 0 and 1, probability to preserve elements} +} +\value{ +a vector of the same type as x +} +\description{ +probabilistic removal of elements from x. For each element, the probability to be preserved is independent and specified by prob +} +\examples{ +x = prob_remove(1:10, 0.5) +x +} +\seealso{ +\code{\link[=apply_niche]{apply_niche()}} and \code{\link[=apply_taphonomy]{apply_taphonomy()}} use this function for transformation of \code{pre_paleoTS} objects +} diff --git a/tests/testthat/test_prob_remove.R b/tests/testthat/test_prob_remove.R new file mode 100644 index 0000000..945c8e2 --- /dev/null +++ b/tests/testthat/test_prob_remove.R @@ -0,0 +1,6 @@ +test_that("number of entries behaves as expected", { + x = 1:10 + expect_lt(length(prob_remove(x, 0.5)), length(x)) + expect_equal(length(prob_remove(x, 1)), length(x)) + expect_equal(length(prob_remove(x, 0)), 0) +}) From a64bde0414864df545bb5761e5ac653fba90eff7 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 27 Sep 2024 08:19:06 +0200 Subject: [PATCH 17/22] niche modeling for pre_paleoTS objects --- R/apply_niche.R | 23 +++++++++++------------ man/apply_niche.Rd | 20 ++++++++++---------- tests/testthat/test_apply_niche.R | 22 +++++++++++++++++----- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/R/apply_niche.R b/R/apply_niche.R index 44a5559..39af59d 100644 --- a/R/apply_niche.R +++ b/R/apply_niche.R @@ -1,20 +1,20 @@ apply_niche = function(x, niche_def, gc){ #' @export #' - #' @title apply niche model to events + #' @title apply niche model #' - #' @param x events, e.g. times/ages of fossil occurrences or their stratigraphic position. - #' @param niche_def function, specifying the niche along a gradient. Should return 0 when taxon is outside of niche, and 1 when inside niche. Values between 0 and 1 are interpreted as collection probabilities. - #' @param gc function, stands for "gradient change". Specifies how the gradient changes, e.g. with time + #' @param x events, e.g. times/ages of fossil occurrences or their stratigraphic position, or a `pre_paleoTS` object (e.g. produced by `stasis_sl`). + #' @param niche_def function, specifying the niche along a gradient. Should return 0 when taxon is outside of niche, and 1 when inside niche. Values between 0 and 1 are interpreted as collection probabilities. Must be vectorized, meaning if given a vector, it must return a vector of equal length. + #' @param gc function, stands for "gradient change". Specifies how the gradient changes, e.g. with time. Must be vectorized, meaning if given a vector, it must return a vector of equal length. #' #' @description - #' Models niches by removing events (fossil occurrences) when they are outside of their niche using the function `thin`. - #' Combines the functions `niche_def` and `gc` ("gradient change") to determine how the taxons' collection probability changes with time/position. This is done by composing `niche_def` and `gc`. The result is then used as a thinning on the events `x`. + #' Models niches by removing events (fossil occurrences) or specimens when they are outside of their niche. For event type data, this is done using the function `thin`, for `pre_paleoTS` this is done by applying the function `prob_remove` on the specimens. + #' Combines the functions `niche_def` and `gc` ("gradient change") to determine how the taxons' collection probability changes with time/position. This is done by composing `niche_def` and `gc`. The result is then used to remove events/specimens in `x`. #' - #' @returns numeric vector, timing/location of events (e.g. fossil ages/locations) preserved after the niche model is applied + #' @returns for a numeric vector input, returns a numeric vector, timing/location of events (e.g. fossil ages/locations) preserved after the niche model is applied. For a `pre_paleoTS` object as input, returns a `pre_paleoTS` object with specimens removed according to the niche model. #' #' @examples - #' + #' ### example for event type data #' ## setup #' # using water depth as gradient #' t = scenarioA$t_myr @@ -41,11 +41,11 @@ apply_niche = function(x, niche_def, gc){ #' #' # see also #' #vignette("event_data") - #' # for a detailed example on niche modeling + #' # for a detailed example on niche modeling for event type data #' #' #' - #' @seealso [apply_taphonomy()] to model taphonomic effects based on the same principle, [thin()] for the underlying mathematical procedure. Basic niche models available are [bounded_niche()] and [snd_niche()] + #' @seealso [apply_taphonomy()] to model taphonomic effects based on the same principle, [thin()] and [prob_remove()] for the underlying mathematical procedure. Basic niche models available are [bounded_niche()] and [snd_niche()] UseMethod("apply_niche") } @@ -66,9 +66,8 @@ apply_niche.pre_paleoTS = function(x, niche_def, gc){ change_in_niche = function(y) niche_def(gc(y)) thin_vals = change_in_niche(x$t) for (i in seq_along(x$t)){ - r = stats::rbinom(length(x$vals[[i]]), size = 1, prob = thin_vals[i]) + r = prob_remove(x$vals[[i]], prob = thin_vals) x$vals[[i]] = x$vals[[i]][as.logical(r)] } return(x) - } diff --git a/man/apply_niche.Rd b/man/apply_niche.Rd index cf81b44..4e91c1e 100644 --- a/man/apply_niche.Rd +++ b/man/apply_niche.Rd @@ -2,26 +2,26 @@ % Please edit documentation in R/apply_niche.R \name{apply_niche} \alias{apply_niche} -\title{apply niche model to events} +\title{apply niche model} \usage{ apply_niche(x, niche_def, gc) } \arguments{ -\item{x}{events, e.g. times/ages of fossil occurrences or their stratigraphic position.} +\item{x}{events, e.g. times/ages of fossil occurrences or their stratigraphic position, or a \code{pre_paleoTS} object (e.g. produced by \code{stasis_sl}).} -\item{niche_def}{function, specifying the niche along a gradient. Should return 0 when taxon is outside of niche, and 1 when inside niche. Values between 0 and 1 are interpreted as collection probabilities.} +\item{niche_def}{function, specifying the niche along a gradient. Should return 0 when taxon is outside of niche, and 1 when inside niche. Values between 0 and 1 are interpreted as collection probabilities. Must be vectorized, meaning if given a vector, it must return a vector of equal length.} -\item{gc}{function, stands for "gradient change". Specifies how the gradient changes, e.g. with time} +\item{gc}{function, stands for "gradient change". Specifies how the gradient changes, e.g. with time. Must be vectorized, meaning if given a vector, it must return a vector of equal length.} } \value{ -numeric vector, timing/location of events (e.g. fossil ages/locations) preserved after the niche model is applied +for a numeric vector input, returns a numeric vector, timing/location of events (e.g. fossil ages/locations) preserved after the niche model is applied. For a \code{pre_paleoTS} object as input, returns a \code{pre_paleoTS} object with speciments removed according to the niche model. } \description{ -Models niches by removing events (fossil occurrences) when they are outside of their niche using the function \code{thin}. -Combines the functions \code{niche_def} and \code{gc} ("gradient change") to determine how the taxons' collection probability changes with time/position. This is done by composing \code{niche_def} and \code{gc}. The result is then used as a thinning on the events \code{x}. +Models niches by removing events (fossil occurrences) or specimens when they are outside of their niche. For event type data, this is done using the function \code{thin}, for \code{pre_paleoTS} this is done by applying the function \code{prob_remove} on the specimens. +Combines the functions \code{niche_def} and \code{gc} ("gradient change") to determine how the taxons' collection probability changes with time/position. This is done by composing \code{niche_def} and \code{gc}. The result is then used to remove events/specimens in \code{x}. } \examples{ - +### example for event type data ## setup # using water depth as gradient t = scenarioA$t_myr @@ -48,11 +48,11 @@ Combines the functions \code{niche_def} and \code{gc} ("gradient change") to det # see also #vignette("event_data") - # for a detailed example on niche modeling + # for a detailed example on niche modeling for event type data } \seealso{ -\code{\link[=apply_taphonomy]{apply_taphonomy()}} to model taphonomic effects based on the same principle, \code{\link[=thin]{thin()}} for the underlying mathematical procedure. Basic niche models available are \code{\link[=bounded_niche]{bounded_niche()}} and \code{\link[=snd_niche]{snd_niche()}} +\code{\link[=apply_taphonomy]{apply_taphonomy()}} to model taphonomic effects based on the same principle, \code{\link[=thin]{thin()}} and \code{\link[=prob_remove]{prob_remove()}} for the underlying mathematical procedure. Basic niche models available are \code{\link[=bounded_niche]{bounded_niche()}} and \code{\link[=snd_niche]{snd_niche()}} } diff --git a/tests/testthat/test_apply_niche.R b/tests/testthat/test_apply_niche.R index 2b9652c..47b552a 100644 --- a/tests/testthat/test_apply_niche.R +++ b/tests/testthat/test_apply_niche.R @@ -1,10 +1,22 @@ -test_that("returns fewer events for event type data", { +test_that("for event type data, returns fewer events", { + # reduce number of events n = 10 x = runif(n, 0, 1) expect_lt(length(apply_niche(x, niche_def = function(x) 0.5, gc = function(x) 1)), n) + # returns identical events for trivial niche + niche_def = function(x) rep(1, length(x)) + gc = function(x) rep(1, length(x)) + expect_equal(apply_niche(x, niche_def, gc), x) + # returns vector of length 0 when niche is 0 everywhere + niche_def = function(x) rep(0, length(x)) + gc = function(x) rep(1, length(x)) + expect_equal(length(apply_niche(x, niche_def, gc)), 0) +}) + +test_that("for pre_paleoTS, returns identical result for trivial niche", { + x = stasis_sl(1:3) + niche_def = function(x) rep(1, length(x)) + gc = function(x) rep(1, length(x)) + expect_equal(apply_niche(x, niche_def, gc), x) }) -x = stasis_sl(1:3) -niche_def = function(x) rep(1, length(x)) -gc = function(x) rep(1, length(x)) -apply_niche(x, niche_def, gc) From 83e18823ebd2ad2c5e4de6440bf853f8d94b6b4f Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 27 Sep 2024 08:32:06 +0200 Subject: [PATCH 18/22] add spellchecker --- DESCRIPTION | 2 + R/bounded_niche.R | 2 +- R/p3_var_rate.R | 2 +- R/stasis_sl.R | 2 +- inst/WORDLIST | 80 ++++++++++++++++++++++++++++++ man/apply_niche.Rd | 2 +- man/bounded_niche.Rd | 2 +- man/p3_var_rate.Rd | 2 +- man/stasis_sl.Rd | 2 +- tests/spelling.R | 3 ++ vignettes/StratPal.Rmd | 8 +-- vignettes/event_data.Rmd | 4 +- vignettes/phenotypic_evolution.Rmd | 4 +- 13 files changed, 100 insertions(+), 15 deletions(-) create mode 100644 inst/WORDLIST create mode 100644 tests/spelling.R diff --git a/DESCRIPTION b/DESCRIPTION index bb666a3..ed9ae0e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -25,6 +25,7 @@ Imports: Suggests: knitr, rmarkdown, + spelling, testthat (>= 3.0.0) VignetteBuilder: knitr Depends: @@ -33,3 +34,4 @@ LazyData: true URL: https://mindthegap-erc.github.io/StratPal/ , https://github.com/MindTheGap-ERC/StratPal BugReports: https://github.com/MindTheGap-ERC/StratPal/issues Config/testthat/edition: 3 +Language: en-US diff --git a/R/bounded_niche.R b/R/bounded_niche.R index 00c36c2..b9700ac 100644 --- a/R/bounded_niche.R +++ b/R/bounded_niche.R @@ -11,7 +11,7 @@ bounded_niche = function(g_min, g_max){ #' @returns a function describing the niche for usage with `apply_niche`. The function returns 1 if the taxon is within its niche (the gradient is between `g_min` and `g_max`), and 0 otherwise #' #' @description - #' Defines a simple niche model where the niche defined is given by a lower limit (`g_min`) and an upper limie (`g_max`) of a gradient the taxon can tolerate + #' Defines a simple niche model where the niche defined is given by a lower limit (`g_min`) and an upper limit (`g_max`) of a gradient the taxon can tolerate #' #' @examples #' diff --git a/R/p3_var_rate.R b/R/p3_var_rate.R index 5c09e6b..b4b3070 100644 --- a/R/p3_var_rate.R +++ b/R/p3_var_rate.R @@ -36,7 +36,7 @@ p3_var_rate = function(x, y = NULL, from = 0, to = 1, f_max = 1, n = NULL){ #' #' @seealso [p3()] for the constant rate implementation, [rej_samp()] for the underlying random number generation. #' - #' @returns numeric vector, timing/location of events. Depending on the modeling framework, tyese events can represent location/age of fossils, or first/last occurrences of a group of taxa. + #' @returns numeric vector, timing/location of events. Depending on the modeling framework, these events can represent location/age of fossils, or first/last occurrences of a group of taxa. if (from >= to){ stop("\"from\" must be smaller than \"to\".") diff --git a/R/stasis_sl.R b/R/stasis_sl.R index a1a6743..0c69590 100644 --- a/R/stasis_sl.R +++ b/R/stasis_sl.R @@ -5,7 +5,7 @@ stasis_sl = function(t, mean = 0, sd = 1, interpop_var = 1, n_per_sample = 10){ #' #' @param t times at which the traits are determined #' @param mean mean trait value - #' @param sd stictly positive number, standard deviation of traits around the mean + #' @param sd strictly positive number, standard deviation of traits around the mean #' @param interpop_var interpopulation variance, determines how much specimens from the same population vary #' @param n_per_sample integer, number of specimens sampled per population/sampling locality #' diff --git a/inst/WORDLIST b/inst/WORDLIST new file mode 100644 index 0000000..3329f37 --- /dev/null +++ b/inst/WORDLIST @@ -0,0 +1,80 @@ +BMC +Bookstein +CMD +CarboCAT +CarboCATLite +DOI +ERC +Geosciences +Github +Jarochowska +Jere +Joël +Koelewijn +Lande +Lipps +MFSTFR +Maruyama +MindTheGap +Myr +NHohmann +ORCID +OU +Orcid +Ornstein +PALAIOS +Palaeontology +Paleobiology +Patzkowsky +Phyletic +StG +Stratigraphic +Taphonomic +Taphonomy +Uhlenbeck +Zenodo +al +approxfun +artefactual +automata +cff +chronostratigraphic +cline +ctc +directionality +doi +eScience +erc +et +eu +eustatic +facies +github +heterodistant +hohmann +https +interpopulation +io +ith +kyr +md +mindthegap +myr +nl +ornstein +paleoTS +paleobiology +paleontological +pre +sedimentological +siliciclastic +sl +snd +stratigraphic +stratigraphy +taphonomic +taphonomy +timelist +uhlenbeck +uu +vectorized diff --git a/man/apply_niche.Rd b/man/apply_niche.Rd index 4e91c1e..cff1ed9 100644 --- a/man/apply_niche.Rd +++ b/man/apply_niche.Rd @@ -14,7 +14,7 @@ apply_niche(x, niche_def, gc) \item{gc}{function, stands for "gradient change". Specifies how the gradient changes, e.g. with time. Must be vectorized, meaning if given a vector, it must return a vector of equal length.} } \value{ -for a numeric vector input, returns a numeric vector, timing/location of events (e.g. fossil ages/locations) preserved after the niche model is applied. For a \code{pre_paleoTS} object as input, returns a \code{pre_paleoTS} object with speciments removed according to the niche model. +for a numeric vector input, returns a numeric vector, timing/location of events (e.g. fossil ages/locations) preserved after the niche model is applied. For a \code{pre_paleoTS} object as input, returns a \code{pre_paleoTS} object with specimens removed according to the niche model. } \description{ Models niches by removing events (fossil occurrences) or specimens when they are outside of their niche. For event type data, this is done using the function \code{thin}, for \code{pre_paleoTS} this is done by applying the function \code{prob_remove} on the specimens. diff --git a/man/bounded_niche.Rd b/man/bounded_niche.Rd index 4ea7ac8..15cc157 100644 --- a/man/bounded_niche.Rd +++ b/man/bounded_niche.Rd @@ -15,7 +15,7 @@ bounded_niche(g_min, g_max) a function describing the niche for usage with \code{apply_niche}. The function returns 1 if the taxon is within its niche (the gradient is between \code{g_min} and \code{g_max}), and 0 otherwise } \description{ -Defines a simple niche model where the niche defined is given by a lower limit (\code{g_min}) and an upper limie (\code{g_max}) of a gradient the taxon can tolerate +Defines a simple niche model where the niche defined is given by a lower limit (\code{g_min}) and an upper limit (\code{g_max}) of a gradient the taxon can tolerate } \examples{ diff --git a/man/p3_var_rate.Rd b/man/p3_var_rate.Rd index 3d490ae..fd66668 100644 --- a/man/p3_var_rate.Rd +++ b/man/p3_var_rate.Rd @@ -20,7 +20,7 @@ p3_var_rate(x, y = NULL, from = 0, to = 1, f_max = 1, n = NULL) \item{n}{NULL or an integer. Number of events drawn. If NULL, the number of events is determined by the rate (specified by x and y). If an integer is passed, n events are returned.} } \value{ -numeric vector, timing/location of events. Depending on the modeling framework, tyese events can represent location/age of fossils, or first/last occurrences of a group of taxa. +numeric vector, timing/location of events. Depending on the modeling framework, these events can represent location/age of fossils, or first/last occurrences of a group of taxa. } \description{ simulates events based on a variable rate Poisson point process. Rates can be either specified by a function passed to \code{x}, or by providing two vectors \code{x} and \code{y}. In this case the rate is specified by approxfun(x, y, rule = 2), i.e. by linear interpolation between the values of x (abscissa) and y (ordinate) diff --git a/man/stasis_sl.Rd b/man/stasis_sl.Rd index a028454..d91a5f6 100644 --- a/man/stasis_sl.Rd +++ b/man/stasis_sl.Rd @@ -11,7 +11,7 @@ stasis_sl(t, mean = 0, sd = 1, interpop_var = 1, n_per_sample = 10) \item{mean}{mean trait value} -\item{sd}{stictly positive number, standard deviation of traits around the mean} +\item{sd}{strictly positive number, standard deviation of traits around the mean} \item{interpop_var}{interpopulation variance, determines how much specimens from the same population vary} diff --git a/tests/spelling.R b/tests/spelling.R new file mode 100644 index 0000000..6713838 --- /dev/null +++ b/tests/spelling.R @@ -0,0 +1,3 @@ +if(requireNamespace('spelling', quietly = TRUE)) + spelling::spell_check_test(vignettes = TRUE, error = FALSE, + skip_on_cran = TRUE) diff --git a/vignettes/StratPal.Rmd b/vignettes/StratPal.Rmd index 41ebc6b..4e910c6 100644 --- a/vignettes/StratPal.Rmd +++ b/vignettes/StratPal.Rmd @@ -1,8 +1,8 @@ --- -title: "Intoduction to the StratPal package" +title: "Introduction to the StratPal package" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Intoduction to the StratPal package} + %\VignetteIndexEntry{Introduction to the StratPal package} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -60,7 +60,7 @@ to install the latest stable version of the package and all its dependencies. ## Dependencies {#dependencies} -The `StratPal` heavily relies on the age-depth modelling tools provided by the `admtools` package, which is *automatically* installed when you install `StratPal`. +The `StratPal` heavily relies on the age-depth modeling tools provided by the `admtools` package, which is *automatically* installed when you install `StratPal`. To use its functionality, you need to run @@ -214,7 +214,7 @@ You can see that there are a 8 shorter hiatuses (below 100 kyr) and 2 long hiatu Given a stratigraphic position, an age-depth model can tell us how old that positions is. Conversely, if we know the timing of an event, an age-depth model can tell us at what stratigraphic position that event will occur. This can be used to transform all types of data from the time domain to the stratigraphic domain and vice versa. -In `admtools`, the transformation of data is done by the functions `time_to_strat` (for transforming temporal data into stratigraphic data) and `strat_to_time` (for transforming stratigrahic data into temporal data). Details on how this is done and what types of data can be transformed can be found in the [vignette of the `admtools` package](https://mindthegap-erc.github.io/admtools/articles/admtools.html), for applications to stratigraphic paleobiology see the vignettes linked below under ["Getting started"](#getting-started). +In `admtools`, the transformation of data is done by the functions `time_to_strat` (for transforming temporal data into stratigraphic data) and `strat_to_time` (for transforming stratigraphic data into temporal data). Details on how this is done and what types of data can be transformed can be found in the [vignette of the `admtools` package](https://mindthegap-erc.github.io/admtools/articles/admtools.html), for applications to stratigraphic paleobiology see the vignettes linked below under ["Getting started"](#getting-started). ## Getting started {#getting-started} diff --git a/vignettes/event_data.Rmd b/vignettes/event_data.Rmd index 2d7bfbe..307ee44 100644 --- a/vignettes/event_data.Rmd +++ b/vignettes/event_data.Rmd @@ -224,7 +224,7 @@ In this example, the temporal range offset is `r signif(time_range_offset_myr, d So far, we have only examined the effects of stratigraphic distortions (i.e., gaps and changes in sedimentation rates) on event type data. Here, we increase the complexity of the pipeline by incorporating niche modeling. For this, we need two components: -- a niche definition that describes a taxon's optimum value along an environmental gradient (cline), i.e. where is it the most abundant, and its tolerance along this gradient +- a niche definition that describes a taxons' optimum value along an environmental gradient (cline), i.e. where is it the most abundant, and its tolerance along this gradient - information on how that gradient changes with time @@ -244,7 +244,7 @@ plot(t, gc(t), main = "Water depth 2 km offshore") ``` -Next, we define the niche. This is done using a function that takes water depth (our gradient) as input, and returns numbers between 0 and 1. A 1 corresponds to the taxon's environmental optimum, and a 0 reflects that it is completely outside of its niche. Values between 0 and 1 are are interpreted as observation or collection probabilities. If a specimen is present at a given time, the collection probability is the probability to observe it at the specified gradient. +Next, we define the niche. This is done using a function that takes water depth (our gradient) as input, and returns numbers between 0 and 1. A 1 corresponds to the taxons' environmental optimum, and a 0 reflects that it is completely outside of its niche. Values between 0 and 1 are are interpreted as observation or collection probabilities. If a specimen is present at a given time, the collection probability is the probability to observe it at the specified gradient. For our example, we use the helper function `snd_niche` (*snd* standing for "scaled normal distribution") to define a niche. The collection probability in this model follows the shape of a bell curve with a peak at the environmental optimum, and a width specified by the `tol` parameter. This is identical to the *probability of collection* model by [Holland and Patzkowsky (1999)](#References). See the "advanced functionality" vignette for details how to construct other niche definitions, or `?bounded_niche` for another template niche model. diff --git a/vignettes/phenotypic_evolution.Rmd b/vignettes/phenotypic_evolution.Rmd index 7713189..be7c7e6 100644 --- a/vignettes/phenotypic_evolution.Rmd +++ b/vignettes/phenotypic_evolution.Rmd @@ -148,7 +148,7 @@ sampling_loc_m |> # sampling locations strat_to_time(adm_2km) |> # determine times where lineage is sampled random_walk(sigma = 1, mu = 3) |> # simulate trait values at these times time_to_strat(adm_2km, destructive = FALSE) |> # transform trait values to stratigraphic domain - plot(orientation = "lr", # plot stratigrahic data + plot(orientation = "lr", # plot stratigraphic data type = "l", ylab = "Trait Value", xlab = paste0("Stratigraphic height [", get_L_unit(adm_2km), "]"), @@ -187,7 +187,7 @@ for details on how to expand on the modeling pipelines described here, or explor * Hunt, Gene. 2006. “Fitting and Comparing Models of Phyletic Evolution: Random Walks and Beyond.” Paleobiology. https://doi.org/10.1666/05070.1. -* Lande, Russell. 1976. "Natural selection and random gentic drift in phenotypic evolution." Evolution. https://doi.org/10.1111/j.1558-5646.1976.tb00911.x +* Lande, Russell. 1976. "Natural selection and random genetic drift in phenotypic evolution." Evolution. https://doi.org/10.1111/j.1558-5646.1976.tb00911.x From 37f421dce1c09b453fda3da1016ab2340d8dc1e3 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 27 Sep 2024 08:40:43 +0200 Subject: [PATCH 19/22] more robust implementation --- R/apply_niche.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/apply_niche.R b/R/apply_niche.R index 39af59d..61c0631 100644 --- a/R/apply_niche.R +++ b/R/apply_niche.R @@ -65,8 +65,8 @@ apply_niche.pre_paleoTS = function(x, niche_def, gc){ #' change_in_niche = function(y) niche_def(gc(y)) thin_vals = change_in_niche(x$t) - for (i in seq_along(x$t)){ - r = prob_remove(x$vals[[i]], prob = thin_vals) + for (i in seq_along(thin_vals)){ + r = prob_remove(x$vals[[i]], prob = thin_vals[i]) x$vals[[i]] = x$vals[[i]][as.logical(r)] } return(x) From 09c4dce49616d8615078ff6b39554f35fd139491 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 27 Sep 2024 08:57:27 +0200 Subject: [PATCH 20/22] add taphonomy for S3 class pre_paleoTS --- NAMESPACE | 1 + R/apply_taphonomy.R | 30 +++++++++++++++++++++------ man/apply_taphonomy.Rd | 12 +++++------ tests/testthat/test_apply_taphonomy.R | 18 +++++++++++++++- 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 448999b..4013580 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,6 +3,7 @@ S3method(apply_niche,numeric) S3method(apply_niche,pre_paleoTS) S3method(apply_taphonomy,numeric) +S3method(apply_taphonomy,pre_paleoTS) S3method(reduce_to_paleoTS,pre_paleoTS) export(apply_niche) export(apply_taphonomy) diff --git a/R/apply_taphonomy.R b/R/apply_taphonomy.R index 3776aef..2f431fb 100644 --- a/R/apply_taphonomy.R +++ b/R/apply_taphonomy.R @@ -3,17 +3,17 @@ apply_taphonomy = function(x, pres_potential, ctc){ #' #' @title model taphonomic effects #' - #' @param x events, e.g. times/ages of fossil occurrences or their stratigraphic position. - #' @param pres_potential function. Takes taphonomic conditions as input and returns the preservation potential (a number between 0 and 1) - #' @param ctc function, change in taphonomic conditions (ctc) with time or stratigraphic position. + #' @param x event type data, e.g. times/ages of fossil occurrences or their stratigraphic position, or a `pre_paleoTS` object. + #' @param pres_potential function. Takes taphonomic conditions as input and returns the preservation potential (a number between 0 and 1). Must be vectorized, meaning if given a vector, it must return a vector of equal length. + #' @param ctc function, change in taphonomic conditions (ctc) with time or stratigraphic position. . Must be vectorized, meaning if given a vector, it must return a vector of equal length. #' #' @description - #' Models taphonomy by combining the change in taphonomic conditions with the preservation potential as a function of taphonomic conditions to determine how preservation potential changes. This is then used to systematically remove (thin) the event data using `thin`. + #' Models taphonomy by combining the change in taphonomic conditions with the preservation potential as a function of taphonomic conditions to determine how preservation potential changes. This is then used to systematically remove (thin) the event data using `thin`/ remove specimens from the `pre_paleoTS` object using `prob_remove`. #' #' - #' @seealso [apply_niche()] for modeling niche preferences based on the same principle, [thin()] for the underlying mathematical procedure. + #' @seealso [apply_niche()] for modeling niche preferences based on the same principle, [thin()] and [prob_remove()] for the underlying mathematical procedure. #' - #' @returns numeric vector, location/timing of events (e.g. fossil occurrences) after the taphonomic filter is applied + #' @returns if given event type data, a numeric vector, location/timing of events (e.g. fossil occurrences) after the taphonomic filter is applied. If given a `pre_paleoTS` object, returns another `pre_paleoTS` object with reduced number of specimens. #' #' @examples #' @@ -34,3 +34,21 @@ apply_taphonomy.numeric = function(x, pres_potential, ctc){ r = thin(x, change_pres_pot) return(r) } + +apply_taphonomy.pre_paleoTS = function(x, pres_potential, ctc){ + #' @export + #' + # function that returns preservation potential as a function of input (e.g. time or position) + change_pres_pot = function(y) pres_potential(ctc(y)) + if (inherits(x, "timelist")){ + thin_vals = change_pres_pot(x$t) + } + if (inherits(x, "stratlist")){ + thin_vals = change_pres_pot(x$h) + } + for (i in seq_along(thin_vals)){ + r = prob_remove(x$vals[[i]], prob = thin_vals[i]) + x$vals[[i]] = x$vals[[i]][as.logical(r)] + } + return(x) +} diff --git a/man/apply_taphonomy.Rd b/man/apply_taphonomy.Rd index 641b8a2..28a1c79 100644 --- a/man/apply_taphonomy.Rd +++ b/man/apply_taphonomy.Rd @@ -7,17 +7,17 @@ apply_taphonomy(x, pres_potential, ctc) } \arguments{ -\item{x}{events, e.g. times/ages of fossil occurrences or their stratigraphic position.} +\item{x}{event type data, e.g. times/ages of fossil occurrences or their stratigraphic position, or a \code{pre_paleoTS} object.} -\item{pres_potential}{function. Takes taphonomic conditions as input and returns the preservation potential (a number between 0 and 1)} +\item{pres_potential}{function. Takes taphonomic conditions as input and returns the preservation potential (a number between 0 and 1). Must be vectorized, meaning if given a vector, it must return a vector of equal length.} -\item{ctc}{function, change in taphonomic conditions (ctc) with time or stratigraphic position.} +\item{ctc}{function, change in taphonomic conditions (ctc) with time or stratigraphic position. . Must be vectorized, meaning if given a vector, it must return a vector of equal length.} } \value{ -numeric vector, location/timing of events (e.g. fossil occurrences) after the taphonomic filter is applied +if given event type data, a numeric vector, location/timing of events (e.g. fossil occurrences) after the taphonomic filter is applied. If given a \code{pre_paleoTS} object, returns another \code{pre_paleoTS} object with reduced number of specimens. } \description{ -Models taphonomy by combining the change in taphonomic conditions with the preservation potential as a function of taphonomic conditions to determine how preservation potential changes. This is then used to systematically remove (thin) the event data using \code{thin}. +Models taphonomy by combining the change in taphonomic conditions with the preservation potential as a function of taphonomic conditions to determine how preservation potential changes. This is then used to systematically remove (thin) the event data using \code{thin}/ remove specimens from the \code{pre_paleoTS} object using \code{prob_remove}. } \examples{ @@ -28,5 +28,5 @@ Models taphonomy by combining the change in taphonomic conditions with the prese } \seealso{ -\code{\link[=apply_niche]{apply_niche()}} for modeling niche preferences based on the same principle, \code{\link[=thin]{thin()}} for the underlying mathematical procedure. +\code{\link[=apply_niche]{apply_niche()}} for modeling niche preferences based on the same principle, \code{\link[=thin]{thin()}} and \code{\link[=prob_remove]{prob_remove()}} for the underlying mathematical procedure. } diff --git a/tests/testthat/test_apply_taphonomy.R b/tests/testthat/test_apply_taphonomy.R index 06ce858..9daaadd 100644 --- a/tests/testthat/test_apply_taphonomy.R +++ b/tests/testthat/test_apply_taphonomy.R @@ -1,5 +1,21 @@ -test_that("returns fewer events", { +test_that("returns correct number of events", { n = 10 x = runif(n, 0, 1) + # reduces number of elements for intermediate preservation expect_lt(length(apply_taphonomy(x, pres_potential = function(x) 0.5, ctc = function(x) 1)), n) + # returns identical data for perfect preservation + pres_potential = function(x) rep(1, length(x)) + ctc = function(x) rep(1, length(x)) + expect_equal(length(apply_taphonomy(x, pres_potential, ctc)), n) + # all events are destroyed for pres. potential of 0 + pres_potential = function(x) rep(0, length(x)) + ctc = function(x) rep(0, length(x)) + expect_equal(length(apply_taphonomy(x, pres_potential, ctc)), 0) +}) + +test_that("pre_paleoTS object remains unchanged for perfect preservation", { + x = stasis_sl(1:3) + pres_potential = function(x) rep(1, length(x)) + ctc = function(x) rep(1, length(x)) + expect_identical(apply_taphonomy(x, pres_potential, ctc), x) }) From a915c8fd8f12bca274f9b50d53654f43d6f28983 Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:04:33 +0200 Subject: [PATCH 21/22] Increment version number to 0.1.1.9001 --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index ed9ae0e..2824306 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: StratPal Title: Stratigraphic Paleobiology Modeling Pipelines -Version: 0.1.1.9000 +Version: 0.1.1.9001 Authors@R: person("Niklas", "Hohmann", , "N.H.Hohmann@uu.nl", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-1559-1838")) From e37170903a3a38ff14bb3d07d214a5e5d0c1c00a Mon Sep 17 00:00:00 2001 From: Niklas Hohmann <67792281+NiklasHohmann@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:07:44 +0200 Subject: [PATCH 22/22] update news --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 66c9062..7243098 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # StratPal (development version) +* introduce S3 class `pre_paleoTS` with simulation procedures, functions to reduce to `paleoTS` via `reduce_to_paleoTS`, and implementaions of niche models and taphonomy via `apply_niche` and `apply_taphonomy` + * add more tests * add input checks