Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace references to serial interval with generation interval #116

Merged
merged 21 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
58e8a92
Rename function to refer to gen_interval
jamesmbaazam Nov 29, 2023
feddba9
Replace all occurrences of serial interval with generation interval
jamesmbaazam Nov 29, 2023
8bc664b
Rename gen_interval to generation_time
jamesmbaazam Nov 30, 2023
a011a3e
Change serial interval to generation time in README
jamesmbaazam Nov 30, 2023
51ec1e2
Change generation interval to generation time in vignette for consist…
jamesmbaazam Nov 30, 2023
30ead89
Reword serial interval section to use generation time
jamesmbaazam Nov 30, 2023
3f0e665
Automatic readme update
actions-user Nov 30, 2023
3f0ebe9
Rename generation time function
jamesmbaazam Nov 30, 2023
7c96042
Define generation time function appropriately
jamesmbaazam Nov 30, 2023
887942a
Rename serial_dist function to generation_time
jamesmbaazam Nov 30, 2023
bf3075e
Use renamed generation_time check function
jamesmbaazam Nov 30, 2023
0edb0e3
Delete old serial_dist check function
jamesmbaazam Nov 30, 2023
4957f6b
Revise stop() message to use generation_time
jamesmbaazam Nov 30, 2023
48fdc59
Update snapshots
jamesmbaazam Nov 30, 2023
d3e92e8
Fix a test
jamesmbaazam Dec 1, 2023
bf4a751
Update snapshots
jamesmbaazam Dec 1, 2023
f63056e
Fix test
jamesmbaazam Dec 1, 2023
7c52315
Apply suggested revisions from code review
jamesmbaazam Dec 1, 2023
5ccd0f3
Rename generation interval to generation time for consistency
jamesmbaazam Dec 1, 2023
d2dd43e
Inherit the param
jamesmbaazam Dec 1, 2023
8bfb2a3
Break up long lines
jamesmbaazam Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions R/checks.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,26 @@ check_offspring_func_valid <- function(roffspring_name) {
}


#' Check if the serials_dist argument is valid.
#' Check if the generation_time argument is specified as a function
#'
#' Check if the serials_dist argument is a function with one argument `n`
#' and returns a numerical vector of length `n`.
#'
#' @param serials_dist The serial interval distribution function; the name of a
#' @param generation_time The generation interval function; the name of a
#' user-defined named or anonymous function with only one argument `n`,
#' representing the number of serial intervals to generate.
#' representing the number of generation intervals to sample.
#'
#' @keywords internal
check_serial_valid <- function(serials_dist) {
if (!checkmate::test_function(serials_dist, nargs = 1)) {
check_generation_time_valid <- function(generation_time) {
if (!checkmate::test_function(generation_time, nargs = 1)) {
stop(sprintf(
"%s %s",
"The `serials_dist` argument must be a function",
"(see details in ?sim_chain_tree)."
"The `generation_time` argument must be a function",
"(see details in ?simulate_tree)."
))
}
x <- serials_dist(10)
x <- generation_time(10)
if (!checkmate::test_numeric(x, len = 10)) {
stop(
"The return values of `serials_dist` must be a numeric vector of length ",
"`n`."
"The return values of `generation_time`",
"must be a numeric vector of length `n`."
)
}
}
Expand Down
2 changes: 1 addition & 1 deletion R/epichains.R
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ tail.epichains <- function(x, ...) {
#' statistic = "size",
#' offspring_dist = "pois",
#' stat_max = 10,
#' serials_dist = function(n) rep(3, n),
#' generation_time = function(n) rep(3, n),
#' lambda = 2
#' )
#' chains
Expand Down
95 changes: 39 additions & 56 deletions R/simulate.r
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@
#' @param stat_max A cut off for the chain statistic (size/length) being
#' computed. Results above the specified value, are set to this value.
#' Defaults to `Inf`.
#' @param serials_dist The serial interval distribution function; the name of a
#' user-defined named or anonymous function with only one argument, usually
#' called `n`, that returns a numeric vector of `n` randomly sampled serial
#' intervals. See details.
#' @param t0 Start time (if serial interval is given); either a single value
#' or a vector of same length as `ntrees` (number of simulations) with
#' @param generation_time The generation interval function; the name
#' of a user-defined named or anonymous function with only one argument `n`,
#' representing the number of generation intervals to generate. See details.
#' @param t0 Start time (if generation interval is given); either a single value
#' or a vector of same length as `nchains` (number of simulations) with
#' initial times. Defaults to 0.
#' @param tf End time (if serial interval is given).
#' @param tf End time (if generation interval is given).
#' @param ... Parameters of the offspring distribution as required by R.
#' @return An `<epichains>` object, which is basically a `<data.frame>` with
#' columns `infectee_id`, `sim_id` (a unique ID within each simulation
Expand All @@ -44,41 +43,27 @@
#' The distribution of secondary cases, \eqn{X_{t, i}} is modelled by the
#' offspring distribution (`offspring_dist`).
#'
#' # The serial interval (`serials_dist`)
#' ## Assumptions/disambiguation
#' ## Specifying `generation_time`
#'
#' In epidemiology, the generation interval is the duration between successive
#' infectious events in a chain of transmission. Similarly, the serial
#' interval is the duration between observed symptom onset times between
#' successive cases in a transmission chain. The generation interval is
#' often hard to observe because exact times of infection are hard to
#' measure hence, the serial interval is often used instead . Here, we
#' use the serial interval to represent what would normally be called the
#' generation interval, that is, the time between successive cases.
#'
#' See References below for some literature on the subject.
#'
#' ## Specifying `serials_dist`
#'
#' `serials_dist` must be specified as a named or
#' `generation_time` must be specified as a named or
#' [anonymous/inline/unnamed function](https://en.wikipedia.org/wiki/Anonymous_function#R)
#' with one argument.
#'
#' For example, assuming we want to specify the serial interval
#' distribution as a random log-normally distributed variable with
#' For example, assuming we want to specify the generation time
#' as a random log-normally distributed variable with
#' `meanlog = 0.58` and `sdlog = 1.58`, we could define a named function,
#' let's call it "serial_interval", with only one argument representing the
#' number of serial intervals to sample:
#' \code{serial_interval <- function(n){rlnorm(n, 0.58, 1.38)}},
#' and assign the name of the function to `serials_dist` in
#' let's call it "generation_time_fn", with only one argument representing the
#' number of generation intervals to sample:
#' \code{generation_time_fn <- function(n){rlnorm(n, 0.58, 1.38)}},
#' and assign the name of the function to `generation_time` in
#' the simulation function, i.e.
#' \code{`simulate_*`(..., serials_dist = serial_interval)},
#' \code{`simulate_*`(..., generation_time = generation_time_fn)},
#' where `...` are the other arguments to `simulate_*()` and * is a placeholder
#' for the rest of simulation function's name.
#'
#' Alternatively, we could assign an anonymous function to `serials_dist`
#' Alternatively, we could assign an anonymous function to `generation_time`
#' in the `simulate_*()` call, i.e.
#' \code{simulate_*(..., serials_dist = function(n){rlnorm(n, 0.58, 1.38)})},
#' \code{simulate_*(..., generation_time = function(n){rlnorm(n, 0.58, 1.38)})},
#' where `...` are the other arguments to `simulate_*()`.
#nolint end
#' @seealso
Expand All @@ -93,7 +78,7 @@
#' statistic = "size",
#' offspring_dist = "pois",
#' stat_max = 10,
#' serials_dist = function(n) rep(3, n),
#' generation_time = function(n) rep(3, n),
#' lambda = 2
#' )
#' @references
Expand All @@ -112,7 +97,7 @@
#' 1186–1204. \doi{https://doi.org/10.3390/ijerph7031204}
simulate_tree <- function(ntrees, statistic = c("size", "length"),
offspring_dist, stat_max = Inf,
serials_dist, t0 = 0,
generation_time, t0 = 0,
tf = Inf, ...) {
statistic <- match.arg(statistic)

Expand All @@ -131,8 +116,8 @@ simulate_tree <- function(ntrees, statistic = c("size", "length"),
stat_max, lower = 0
)

if (!missing(serials_dist)) {
check_serial_valid(serials_dist)
if (!missing(generation_time)) {
check_generation_time_valid(generation_time)
}
checkmate::assert_numeric(
t0, lower = 0, finite = TRUE
Expand All @@ -144,10 +129,10 @@ simulate_tree <- function(ntrees, statistic = c("size", "length"),
# Gather offspring distribution parameters
pars <- list(...)

if (!missing(serials_dist)) {
check_serial_valid(serials_dist)
if (!missing(generation_time)) {
check_generation_time_valid(generation_time)
} else if (!missing(tf)) {
stop("If `tf` is specified, `serials_dist` must be specified too.")
stop("If `tf` is specified, `generation_time` must be specified too.")
}

# Initialisations
Expand All @@ -165,7 +150,7 @@ simulate_tree <- function(ntrees, statistic = c("size", "length"),
generation = generation
)

if (!missing(serials_dist)) {
if (!missing(generation_time)) {
tree_df$time <- t0
times <- tree_df$time
}
Expand Down Expand Up @@ -221,10 +206,10 @@ simulate_tree <- function(ntrees, statistic = c("size", "length"),
generation = generation
)

# if a serial interval model/function was specified, use it
# to generate serial intervals for the cases
if (!missing(serials_dist)) {
times <- rep(times, next_gen) + serials_dist(sum(n_offspring))
# if a generation interval model/function was specified, use it
# to generate generation intervals for the cases
if (!missing(generation_time)) {
times <- rep(times, next_gen) + generation_time(sum(n_offspring))
current_min_time <- unname(tapply(times, indices, min))
new_df$time <- times
}
Expand All @@ -235,11 +220,11 @@ simulate_tree <- function(ntrees, statistic = c("size", "length"),
## the specified maximum size/length
sim <- which(n_offspring > 0 & stat_track < stat_max)
if (length(sim) > 0) {
if (!missing(serials_dist)) {
if (!missing(generation_time)) {
## only continue to simulate chains that don't go beyond tf
sim <- intersect(sim, unique(indices)[current_min_time < tf])
}
if (!missing(serials_dist)) {
if (!missing(generation_time)) {
times <- times[indices %in% sim]
}
infector_ids <- ids[indices %in% sim]
Expand Down Expand Up @@ -271,7 +256,6 @@ simulate_tree <- function(ntrees, statistic = c("size", "length"),
#' @param stat_max A cut off for the chain statistic (size/length) being
#' computed. Results above the specified value, are set to `Inf`.
#' @inheritSection simulate_tree Calculating chain sizes and lengths
#' @inheritSection simulate_tree The serial interval (`serials_dist`)
#' @author James M. Azam, Sebastian Funk
#' @seealso
#' * [simulate_tree()] for simulating transmission trees from an
Expand Down Expand Up @@ -400,7 +384,6 @@ simulate_summary <- function(ntrees, statistic = c("size", "length"),
#' * the maximal chain statistic is limited by `pop` instead of
#' `stat_max` (in `simulate_tree()`),
#' * `offspring_dist` can only handle "pois" and "nbinom".
#' @inheritSection simulate_tree The serial interval (`serials_dist`)
#' @author Flavio Finger, James M. Azam, Sebastian Funk
#' @seealso
#' * [simulate_tree()] for simulating transmission trees from an
Expand All @@ -413,20 +396,20 @@ simulate_summary <- function(ntrees, statistic = c("size", "length"),
#' pop = 100,
#' offspring_dist = "pois",
#' lambda = 0.5,
#' serials_dist = function(n) rep(3, n)
#' generation_time = function(n) rep(3, n)
#' )
#'
#' # Simulate with negative binomial offspring
#' simulate_tree_from_pop(
#' pop = 100, offspring_dist = "nbinom",
#' mu = 0.5,
#' size = 1.1,
#' serials_dist = function(n) rep(3, n)
#' generation_time = function(n) rep(3, n)
#' )
#' @export
simulate_tree_from_pop <- function(pop,
offspring_dist = c("pois", "nbinom"),
serials_dist,
generation_time,
initial_immune = 0,
t0 = 0,
tf = Inf,
Expand All @@ -438,8 +421,8 @@ simulate_tree_from_pop <- function(pop,
pop, lower = 1, finite = TRUE
)
checkmate::assert_string(offspring_dist)
if (!missing(serials_dist)) {
check_serial_valid(serials_dist)
if (!missing(generation_time)) {
check_generation_time_valid(generation_time)
}
checkmate::assert_number(
initial_immune, lower = 0, upper = pop - 1
Expand Down Expand Up @@ -532,11 +515,11 @@ simulate_tree_from_pop <- function(pop,

## add to df
if (n_offspring > 0) {
## draw serial times
new_times <- serials_dist(n_offspring)
## draw generation times
new_times <- generation_time(n_offspring)

if (any(new_times < 0)) {
stop("Serial interval must be >= 0.")
stop("Generation interval must be >= 0.")
}

new_df <- data.frame(
Expand Down
6 changes: 4 additions & 2 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ _{{ packagename }}_ provides four main functions:
* `simulate_tree()`: simulates transmission chains using an initial number of
cases and information on the offspring distribution. This function returns
an object with columns that track information on who infected whom, the
generation of infection and, if a serial interval is given, the time of infection.
generation of infection and, if a generation time function is specified, the
time of infection.

* `simulate_summary()`: simulates a vector of transmission chain sizes or
lengths using an initial number of cases and information on the offspring
Expand All @@ -81,7 +82,8 @@ length.
population size and information on the offspring distribution. You can also
specify a given level of pre-existing immunity. This function returns
an object with columns that track information on who infected whom, the
generation of infection and, if a serial interval is given, the time of infection.
generation of infection and, if a generation time function is given, the
time of infection.

* `likelihood()`: calculates the loglikelihood (or likelihood, depending
on the value of `log`) of observing a vector of transmission chain sizes or
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ library("epichains")
- `simulate_tree()`: simulates transmission chains using an initial
number of cases and information on the offspring distribution. This
function returns an object with columns that track information on who
infected whom, the generation of infection and, if a serial interval
is given, the time of infection.
infected whom, the generation of infection and, if a generation time
function is specified, the time of infection.

- `simulate_summary()`: simulates a vector of transmission chain sizes
or lengths using an initial number of cases and information on the
Expand All @@ -81,8 +81,8 @@ library("epichains")
initial population size and information on the offspring distribution.
You can also specify a given level of pre-existing immunity. This
function returns an object with columns that track information on who
infected whom, the generation of infection and, if a serial interval
is given, the time of infection.
infected whom, the generation of infection and, if a generation time
function is given, the time of infection.

- `likelihood()`: calculates the loglikelihood (or likelihood, depending
on the value of `log`) of observing a vector of transmission chain
Expand Down
2 changes: 1 addition & 1 deletion man/aggregate.epichains.Rd

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

17 changes: 17 additions & 0 deletions man/check_generation_time_valid.Rd

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

18 changes: 0 additions & 18 deletions man/check_serial_valid.Rd

This file was deleted.

Loading