Skip to content

Commit

Permalink
add custom rounding function
Browse files Browse the repository at this point in the history
  • Loading branch information
silvtal committed Jul 6, 2023
1 parent 516ce3b commit e363762
Show file tree
Hide file tree
Showing 21 changed files with 206 additions and 145 deletions.
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export(growth)
export(growth_log)
export(growth_one_group)
export(pick_new_bugs)
export(roundVectorPreservingSum)
export(simulate_timeseries)
importFrom(Rcpp,sourceCpp)
importFrom(data.table,transpose)
Expand Down
34 changes: 17 additions & 17 deletions R/RcppExports.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ pick_new_bugs <- function(arr, size, replace, prob) {
#' function calculates the probability of growth for each organism based on
#' their current abundance and any specified interactions between organisms. The
#' function then randomly selects organisms to grow based on these probabilities
#' and increases their abundance by grow_step (1 by default).
#' and increases their abundance by growth_step (1 by default).
#' The function takes four arguments:
#' @param this_timestep A numeric vector representing the current abundance of
#' each organism in the population.
#' @param grow_step An integer representing the growth step for organisms in
#' @param growth_step An integer representing the growth step for organisms in
#' the community, 1 by default.
#' @param interactions An optional numeric matrix representing the interaction
#' between organisms in the population. This argument is set to R_NilValue by
#' default.
#' @export
growth_one_group <- function(this_timestep, grow_step, interactions = NULL) {
.Call(`_dilgrowth_growth_one_group`, this_timestep, grow_step, interactions)
growth_one_group <- function(this_timestep, growth_step, interactions = NULL) {
.Call(`_dilgrowth_growth_one_group`, this_timestep, growth_step, interactions)
}

#' growth
Expand All @@ -47,17 +47,17 @@ growth_one_group <- function(this_timestep, grow_step, interactions = NULL) {
#'
#' As opposed to growth_one_group(), the growth rate (probability of being
#' picked for growth) is determined for each individual by the carrying
#' capacity of its group(\[grow_step * group's % of total carrying capacity]).
#' capacity of its group(\[growth_step * group's % of total carrying capacity]).
#' An optionally passed interactions matrix has an effect as well. Every group
#' will have grow_step (by default 1) of its present individuals grow in each
#' will have growth_step (by default 1) of its present individuals grow in each
#' run, and they can be from the same ASV/OTU/species or not. Also, growth step
#' is proportional to the carrying capacity of its group. This is to avoid group
#' extinction and also to ensure growth has a similar, proportional rate for
#' each group so all groups reach their CC at the same time.
#'`
#' @export
growth <- function(x, carrying_capacities, grow_step, interactions = NULL) {
.Call(`_dilgrowth_growth`, x, carrying_capacities, grow_step, interactions)
growth <- function(x, carrying_capacities, growth_step, interactions = NULL) {
.Call(`_dilgrowth_growth`, x, carrying_capacities, growth_step, interactions)
}

#' growth_log
Expand All @@ -72,13 +72,13 @@ growth <- function(x, carrying_capacities, grow_step, interactions = NULL) {
#' only on their abundances but also on their carrying capacity.
#'
#' As opposed to growth_one_group(), the growth rate is given by a logistic
#' function and not grow_step. Another difference is that growing species are
#' function and not growth_step. Another difference is that growing species are
#' not chosen one by one by sampling, but with a binomial function. That means
#' that the number of different species and the number of individuals that can
#' grow in each iteration of this function is not limited.
#'
#' The difference with growth() is that growth is logistic in this function and
#' there is not grow_step here.
#' there is not growth_step here.
#'
#' If the carrying capacity for a group was surpassed before starting the
#' growth cycle, the species of that group will die at a proportionate rate,
Expand All @@ -91,25 +91,25 @@ growth_log <- function(x, carrying_capacities, interactions = NULL) {

#' check_step
#'
#' Checks if a given grow_step is ok for running a growth() function and adjusts
#' Checks if a given growth_step is ok for running a growth() function and adjusts
#' it accordingly if it's not (for example not allowing for it to cause too big
#' of a growth, surpassing total wanted final community abundance).
#' @param is_grow_step_a_perc Boolean: if false, grow_step is taken as a fixed
#' @param is_growth_step_a_perc Boolean: if false, growth_step is taken as a fixed
#' value, so the step will always be the same. If true, it is taken to indicate
#' a percentage - the step will be changed proportionally to the community size.
#' If grow_step is 0.02, 2% of the members in the community will grow the next
#' If growth_step is 0.02, 2% of the members in the community will grow the next
#' iteration
#' @export
check_step <- function(this_timestep, abun_total, grow_step, is_grow_step_a_perc = FALSE) {
.Call(`_dilgrowth_check_step`, this_timestep, abun_total, grow_step, is_grow_step_a_perc)
check_step <- function(this_timestep, abun_total, growth_step, is_growth_step_a_perc = FALSE) {
.Call(`_dilgrowth_check_step`, this_timestep, abun_total, growth_step, is_growth_step_a_perc)
}

#' full_growth
#'
#' This function consists in a loop that runs growth(...)() functions as many
#' times as needed to reach a given population size.
#' @export
full_growth <- function(this_timestep, abun_total, grow_step, is_grow_step_a_perc = FALSE, func = "growth", interactions = NULL, carrying_capacities = NULL) {
.Call(`_dilgrowth_full_growth`, this_timestep, abun_total, grow_step, is_grow_step_a_perc, func, interactions, carrying_capacities)
full_growth <- function(this_timestep, abun_total, growth_step, is_growth_step_a_perc = FALSE, func = "growth", interactions = NULL, carrying_capacities = NULL) {
.Call(`_dilgrowth_full_growth`, this_timestep, abun_total, growth_step, is_growth_step_a_perc, func, interactions, carrying_capacities)
}

31 changes: 31 additions & 0 deletions R/roundVectorPreservingSum.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#' roundVectorPreservingSum
#'
#' This function rounds the input vector and then calculates the difference in
#' the sum of the original vector and the rounded vector. To fix this difference,
#' it randomly selects elements from the rounded vector and adjusts their values
#' to preserve the sum of the original vector.
#'
#' This is needed to avoid decimals in the final simulated communities when
#' simulating multiple functional groups.
#'
#' @param vector
#'
#' @return
#' @export
#'
#' @examples
roundVectorPreservingSum <- function(vector) {
rounded_vector <- round(vector) # Round the vector
diff_sum <- sum(vector) - sum(rounded_vector) # Calculate the difference in sum

# Adjust the rounded vector to preserve the sum
if (diff_sum > 0) {
indices <- sample(length(vector), diff_sum)
rounded_vector[indices] <- rounded_vector[indices] + 1
} else if (diff_sum < 0) {
indices <- sample(length(vector), -diff_sum)
rounded_vector[indices] <- rounded_vector[indices] - 1
}

return(rounded_vector)
}
16 changes: 8 additions & 8 deletions R/simulate_timeseries.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#' @param dilution
#' @param no_of_dil
#' @param fixation_at
#' @param grow_step Number of individuals that grow each timestep (Default: 1)
#' @param growth_step Number of individuals that grow each timestep (Default: 1)
#' @param keep_all_timesteps
#' @param allow_group_extinctions If TRUE, simulations will continue even if one
#' or more groups go extinct, and the function will try to reach fixation in all
Expand All @@ -35,8 +35,8 @@ simulate_timeseries <- function (counts_data,
no_of_dil=12,
fixation_at=1,
abun_total=NULL,
grow_step=1,
is_grow_step_a_perc=FALSE,
growth_step=1,
is_growth_step_a_perc=FALSE,
keep_all_timesteps=FALSE,
allow_group_extinctions=TRUE,
force_continue=FALSE) {
Expand Down Expand Up @@ -130,7 +130,7 @@ simulate_timeseries <- function (counts_data,
# Growth without groups (growth_one_group())
# ==========================================
while (sum(this_timestep) < abun_total) {
step <- check_step(this_timestep, abun_total, grow_step, is_grow_step_a_perc)
step <- check_step(this_timestep, abun_total, growth_step, is_growth_step_a_perc)
this_timestep <- growth_one_group(this_timestep,
step,
interactions)
Expand Down Expand Up @@ -181,11 +181,11 @@ simulate_timeseries <- function (counts_data,
}
} else {
while (round(sum(this_timestep)) < abun_total) {
step <- check_step(this_timestep, abun_total, grow_step, is_grow_step_a_perc)
step <- check_step(this_timestep, abun_total, growth_step, is_growth_step_a_perc)
this_timestep <- growth(
x = this_timestep,
carrying_capacities = carrying_capacities,
grow_step = step,
growth_step = step,
interactions = interactions
)
}
Expand All @@ -199,7 +199,7 @@ simulate_timeseries <- function (counts_data,
if (keep_all_timesteps){
# once the growth's finished, the next dilution can happen. But if
# keep_all_timesteps, we have to save the abundances first
trajectory[as.character(dil),] <- this_timestep
trajectory[as.character(dil),] <- roundVectorPreservingSum(this_timestep)
}

# Check again for fixation before next iteration
Expand All @@ -215,5 +215,5 @@ simulate_timeseries <- function (counts_data,
if (keep_all_timesteps){
return(trajectory)
} else {
return(this_timestep)
return(roundVectorPreservingSum(this_timestep))
}}
13 changes: 9 additions & 4 deletions man/check_step.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions man/full_growth.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions man/growth.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions man/growth_log.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions man/growth_one_group.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions man/roundVectorPreservingSum.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions man/simulate_timeseries.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 10 additions & 10 deletions scripts/dilgrowth.R
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ option_list <- list(
make_option(c("--save_all"), type = "logical",
default = FALSE,
help = "save all intermediate states of the simulations? default FALSE"),
make_option(c("--grow_step"), type = "double",
make_option(c("--growth_step"), type = "double",
default = 1,
help = "How many bugs are born on each iteration. 1 by default"),
make_option(c("--is_grow_step_a_perc"), type = "logical",
make_option(c("--is_growth_step_a_perc"), type = "logical",
default = FALSE,
help = "If FALSE, grow_step is taken as a fixed value, so the step will always be the same. If TRUE, it's read as a percentage - the step will be changed proportionally to the community size. If grow_step is 0.02, 2% of the members in the community will grow the next iteration. FALSE by default"),
help = "If FALSE, growth_step is taken as a fixed value, so the step will always be the same. If TRUE, it's read as a percentage - the step will be changed proportionally to the community size. If growth_step is 0.02, 2% of the members in the community will grow the next iteration. FALSE by default"),
make_option(c("--logistic"), type = "logical",
default = FALSE,
help = "¿Should growth be logistic? If TRUE, the grow_step/growth rate of each species will change over the course of the simulation, in a logistic growth manner (see growth_log)."),
help = "¿Should growth be logistic? If TRUE, the growth_step/growth rate of each species will change over the course of the simulation, in a logistic growth manner (see growth_log)."),
make_option(c("--no_of_simulations"), type = "integer",
default = 1,
help = "Number of simulations"),
Expand Down Expand Up @@ -150,12 +150,12 @@ outputname <- opt$outputname # e.g. "X2_rep4"
cores <- opt$cores # e.g. 16

save_all <- opt$save_all
grow_step <- opt$grow_step
is_grow_step_a_perc <- opt$is_grow_step_a_perc
growth_step <- opt$growth_step
is_growth_step_a_perc <- opt$is_growth_step_a_perc
allow_group_extinctions <- opt$allow_group_extinctions

if (is_grow_step_a_perc && (grow_step == 1)) {
message("WARNING: grow_step has been defined as a percentage of value 1. All organisms will duplicate every iteration. If you meant for grow_step to be a fixed value, set is_grow_step_a_perc to FALSE instead.")
if (is_growth_step_a_perc && (growth_step == 1)) {
message("WARNING: growth_step has been defined as a percentage of value 1. All organisms will duplicate every iteration. If you meant for growth_step to be a fixed value, set is_growth_step_a_perc to FALSE instead.")
}

logistic <- opt$logistic
Expand Down Expand Up @@ -249,8 +249,8 @@ if (abun_total == 0) {
no_of_dil = no_of_dil,
fixation_at = fixation_at,
abun_total = abun_total,
grow_step = grow_step,
is_grow_step_a_perc = is_grow_step_a_perc,
growth_step = growth_step,
is_growth_step_a_perc = is_growth_step_a_perc,
keep_all_timesteps = save_all,
allow_group_extinctions = allow_group_extinctions,
force_continue = FALSE)
Expand Down
Loading

0 comments on commit e363762

Please sign in to comment.