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

Develop #343

Merged
merged 60 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
feaa6d4
add more flexibility with delays (#305)
sbfnk Nov 18, 2022
4568af6
documentation fixes and deprecation warning (#335)
sbfnk Nov 23, 2022
9d13484
fixes to small issues introduced by PR #305 (#336)
sbfnk Nov 24, 2022
2c5a4ef
upper bound `frac_obs` by 1 (#340)
sbfnk Dec 9, 2022
20b302e
Merge branch 'main' into develop
seabbs Jan 18, 2023
0945d9b
Documentation: Fix report_plots example
seabbs Jan 18, 2023
0dacc19
merge changes from main
seabbs Jan 18, 2023
568e10c
Merge branch 'main' into develop
seabbs Jan 18, 2023
f911647
Catch change in max delay definition in report_cases()
seabbs Jan 18, 2023
44f0ba2
Merge branch 'main' into develop
seabbs Jan 19, 2023
3ff53b3
Hotfix: Fix estimate_infections() example for truncation which did no…
seabbs Jan 19, 2023
ba11198
Merge changes from main
seabbs Jan 20, 2023
fc2854b
update news file to use categories
seabbs Jan 23, 2023
51e441c
update news
seabbs Jan 23, 2023
d5149e2
Tests: Add tests for stan convolution functions
seabbs Jan 23, 2023
f6ddb66
Feature: Add fixed argument to get_dist functions
seabbs Jan 23, 2023
7e31395
Documentation: Make new left truncation clearer
seabbs Jan 23, 2023
d384baf
Package: Surface reversing of PMF to happen once and explicitly vs wi…
seabbs Jan 23, 2023
7f4cadc
Package: Check code compilation and reset testing for CI
seabbs Jan 23, 2023
1b3b0b3
Documnetation: Make sure fixed is documented in all get_dist children
seabbs Jan 23, 2023
3f96cea
Tests: Add generation_time_opts test that should pas
seabbs Jan 23, 2023
f8c4a58
move synthetic validation to its own folder
seabbs Jan 23, 2023
79758e2
Tests: Add a synthetic recovery test for estimate_secondary (prevalen…
seabbs Jan 23, 2023
1173581
Package: Review estimate_secondary code
seabbs Jan 23, 2023
4faefa1
Package: Clean up not currently generated syntethic validation figures
seabbs Jan 23, 2023
749eaa1
Package: Add support for passing generation time distribution to gene…
seabbs Jan 23, 2023
e1ccc55
Package: Use rev_ to indicate reversed PMFs and catch reverse induced…
seabbs Jan 23, 2023
0b0d21b
Package: Add random walk + stationary GP to synthetic recovery
seabbs Jan 23, 2023
c489845
Package: Fix synthetic validation
seabbs Jan 24, 2023
d0cf718
Package: First pass at vector of delay mean lower bounds - depends on…
seabbs Jan 24, 2023
d7fc4a2
Package: Use reals vs ints for lower bounds of course
seabbs Jan 24, 2023
8c1b6ba
Package: Arrggh vectorised lower bounds are not in stan 2.21
seabbs Jan 24, 2023
5d6ff41
Documentation: Refresh docs style
seabbs Jan 24, 2023
ebb8ba4
Package: Update namespace
seabbs Jan 24, 2023
0fd749b
Package: Restyle code and docs
seabbs Jan 24, 2023
f10d18b
Package: Add use of delays_lp for generation time and define truncate…
seabbs Jan 24, 2023
44ce892
Model: Use delays_lp for truncation and generation time to properly s…
seabbs Jan 24, 2023
4140bdf
Model: Catch missinng changes for truncation in estimate_secondary
seabbs Jan 24, 2023
1b9d952
Bug: Fix edge case when using mixed distributions so that seeding tim…
seabbs Jan 24, 2023
c6627e8
Docmentation: Refresh README
seabbs Jan 24, 2023
872b9ea
Bug: Fix edge case where generation_time_opts was ignoring max from g…
seabbs Jan 24, 2023
c63d92f
Model: Drop numeric stabilisation in convolve
seabbs Jan 24, 2023
743deaf
Bug: Update if/else to check for max in generation_time_opts when loo…
seabbs Jan 24, 2023
c6908e5
Documentation: Refresh docs
seabbs Jan 24, 2023
49a5994
Tests: Fix tests failing due to PR changes
seabbs Jan 24, 2023
f5fe5a6
Documentation: Move frac_obs change into breaking changes section of …
seabbs Jan 24, 2023
3bd5f61
Documentation: Check everything is included in pkgdown:
seabbs Jan 24, 2023
d3b4593
update synthetic validation
sbfnk Jan 25, 2023
9305115
Documentation: URL check and spelling
seabbs Jan 25, 2023
f1299a7
Merge branch 'develop' of https://github.com/epiforecasts/EpiNow2 int…
seabbs Jan 25, 2023
f965d85
Update R/create.R
seabbs Jan 27, 2023
b0ec85f
Update README.Rmd
seabbs Jan 27, 2023
25e6608
Update R/create.R
seabbs Jan 27, 2023
18338a0
Update R/estimate_truncation.R
seabbs Jan 27, 2023
62f984a
Update R/create.R
seabbs Jan 27, 2023
1fcfbc5
Update NEWS.md
seabbs Jan 27, 2023
f3b5887
clarify connection between forecast_ and simulate_ secondary
seabbs Jan 30, 2023
dae890a
update news to remove reference to improved run times
seabbs Jan 30, 2023
e30d803
refresh documentation
seabbs Jan 30, 2023
c54b74e
update CRAN comments after window devel check
seabbs Jan 30, 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
2 changes: 1 addition & 1 deletion .github/workflows/synthetic-validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
local::.
- name: Run synthetic validation
run: |
source("inst/dev/recover-synthetic.R")
source("inst/dev/recover-synthetic/rt.R")
shell: Rscript {0}

- name: Upload validation figures
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ src/stanExports*.h
# docs
inst/doc
docs
*.html

# CRAN
CRAN-RELEASE
Expand Down
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export(create_stan_data)
export(delay_opts)
export(dist_fit)
export(dist_skel)
export(dist_spec)
export(epinow)
export(estimate_delay)
export(estimate_infections)
Expand All @@ -44,6 +45,7 @@ export(extract_inits)
export(extract_stan_param)
export(forecast_secondary)
export(gamma_dist_def)
export(generation_time_opts)
export(get_dist)
export(get_generation_time)
export(get_incubation_period)
Expand Down
33 changes: 27 additions & 6 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,47 @@
# EpiNow2 1.3.4

This is mainly a maintenance release focussing on bug fixes and package infrastructure updates along with a few quality of life improvements.
This release focusses on bug fixes and package infrastructure updates along with a few quality of life improvements such as enabling the use of fixed delays and generation times.

Thanks to @seabbs, and @sbfnk and for [SACEMA](https://sacema.org) for hosting @seabbs whilst some of the development work on this release was being done.
Thanks to @seabbs, and @sbfnk and for [SACEMA](https://www.sacema.org/) for hosting @seabbs whilst some of the development work on this release was being done.

## Breaking changes

* To streamline the interface with the definition of delay distributions `trunc_opts()` now takes a single argument (`dist`) which defines the truncation delay rather than a arbitrary list of arguments (which was previously used to define the distribution).
* Updated the handling of generation times in the renewal equation to be left truncation adjusted for the zeroth day. This more better the approach taken to estimate generation times but may slightly impact estimates vs those produced using previous versions.
* The range of the `frac_obs` parameter has restricted with an upper bound of 1 to reflect its name and description. This may impact a small number of edge case uses with the majority being models fit using `estimate_secondary()`. By @sbfnk in #340.

## Features

* Adds a new function `simulate_secondary()` for simulating secondary observations under the generative process model assumed by `estimate_secondary`. Unlike `forecast_secondary()` which uses a `stan` model to simulate secondary cases (which shares code with the `estimate_secondary` model) this new function is implemented entirely in R and is therefore useful to sense check any results from the `stan` implementation.
* Adds support for fixed delays (mean only or fixed lognormal distributed) or truncations (fixed lognormal distributed), and for pre-computing these delays as well as generation times if they are fixed. By @sbfnk and @seabbs.
* Support for gamma distributed delays and log-normal distributed generation times.

## Package

* Update the GitHub Action files to new versions.
* Switched to using `seq_along()` rather than `1:length()`.
* Switched to using `seq_along()` rather than `1:length()` in all package code.
* Fixed a broken example in the documentation for `regional_runtimes()`.
* Add compatibility changes for the latest version of `rstan` and `rstantools`.
* Remove legacy use of `pkgnet` for package dependency visualisation.
* Slight edits to the model outline for `estimate_infections()`.
* Restyled all code using `styler`.
* Dropped dependency on `RcppParallel`.
* Updated `report_cases` to work with the new `delay_opts` helper function.
* Added test coverage for `report_cases` though note this function will likely be deprecated in future releases.
* Adds a new function `simulate_secondary()` for simulating secondary observations under the generative process model assumed by `estimate_secondary`.
* Switched to `linewidth` in `plot_CrIs` rather than `size` to avoid issues with `ggplot2` 3.4.0.
* Set up validation against synthetic data to run as a CI check.
* Added tests for internal stan convolution functions.
* Update all `get_` distribution functions to return the distribution as well as summary
parameters.

## Documentation

* Slight edits to the model outline for `estimate_infections()`.
* Updated examples to make use of fixed distributions.

## Bugs

* Fixed a bug in `simulate_infections()` where passing a custom number of samples would cause the input vector of R values to be replicated in a column-wise fashion meaning that the intended R trajectory was not simulated.
* Fixed a bug in the `estimate_infections()` deconvolution model where the generation time was not correctly being reversed.
* Added a new CI check to perform validation against simulated data.

# EpiNow2 1.3.3

Expand Down
5 changes: 5 additions & 0 deletions R/adjust.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@
#' Maps from cases by date of infection to date of report via date of
#' onset.
#' @param infections `data.table` containing a `date` variable and a numeric `cases` variable.
#'
#' @param delay_defs A list of single row data.tables that each defines a delay distribution (model, parameters and maximum delay for each model).
#' See `lognorm_dist_def` for an example of the structure.
#'
#' @param reporting_effect A numeric vector of length 7 that allows the scaling of reported cases
#' by the day on which they report (1 = Monday, 7 = Sunday). By default no scaling occurs.
#'
#' @param reporting_model A function that takes a single numeric vector as an argument and returns a
#' single numeric vector. Can be used to apply stochastic reporting effects. See the examples for details.
#'
#' @return A `data.table` containing a `date` variable (date of report) and a `cases` variable. If `return_onset = TRUE` there will be
#' a third variable `reference` which indicates what the date variable refers to.
#' @export
#' @inheritParams sample_approx_dist
#' @importFrom data.table setorder data.table data.table
#' @importFrom lubridate wday
#' @author Sam Abbott
#' @examples
#' \donttest{
#' # define example cases
Expand Down
113 changes: 60 additions & 53 deletions R/create.R
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#' @inheritParams estimate_infections
#' @importFrom data.table copy merge.data.table setorder setDT frollsum
#' @return A cleaned data frame of reported cases
#' @author Sam Abbott
seabbs marked this conversation as resolved.
Show resolved Hide resolved
#' @author Lloyd Chapman
#' @export
create_clean_reported_cases <- function(reported_cases, horizon,
filter_leading_zeros = TRUE,
Expand Down Expand Up @@ -75,6 +77,7 @@ create_clean_reported_cases <- function(reported_cases, horizon,
#' @importFrom runner mean_run
#' @return A data frame for shifted reported cases
#' @export
#' @author Sam Abbott
#' @examples
#' create_shifted_cases(example_confirmed, 7, 14, 7)
create_shifted_cases <- function(reported_cases, shift,
Expand Down Expand Up @@ -131,6 +134,7 @@ create_shifted_cases <- function(reported_cases, shift,
#' from this many days into the future (or past if negative) past will be used forwards in time.
#' @param delay Numeric mean delay
#' @return A list containing a logical called fixed and an integer called from
#' @author Sam Abbott
create_future_rt <- function(future = "latest", delay = 0) {
out <- list(fixed = FALSE, from = 0)
if (is.character(future)) {
Expand Down Expand Up @@ -167,6 +171,7 @@ create_future_rt <- function(future = "latest", delay = 0) {
#' @return A list of settings defining the time-varying reproduction number
#' @inheritParams create_future_rt
#' @export
#' @author Sam Abbott
#' @examples
#' # default Rt data
#' create_rt_data()
Expand Down Expand Up @@ -229,6 +234,7 @@ create_rt_data <- function(rt = rt_opts(), breakpoints = NULL,
#' @seealso backcalc_opts
#' @return A list of settings defining the Gaussian process
#' @export
#' @author Sam Abbott
#' @examples
#' # define input data required
#' data <- list(
Expand Down Expand Up @@ -268,6 +274,7 @@ create_backcalc_data <- function(backcalc = backcalc_opts) {
#' @seealso gp_opts
#' @return A list of settings defining the Gaussian process
#' @export
#' @author Sam Abbott
#' @examples
#' # define input data required
#' data <- list(
Expand Down Expand Up @@ -334,6 +341,7 @@ create_gp_data <- function(gp = gp_opts(), data) {
#' @return A list of settings ready to be passed to stan defining
#' the Observation Model
#' @export
#' @author Sam Abbott
#' @examples
#' dates <- seq(as.Date("2020-03-15"), by = "days", length.out = 15)
#' # default observation model data
Expand Down Expand Up @@ -374,13 +382,17 @@ create_obs_model <- function(obs = obs_opts(), dates) {
#' Create Stan Data Required for estimate_infections
#'
#' @description`r lifecycle::badge("stable")`
#' Takes the output of `stan_opts()` and converts it into a list understood by `stan`. Internally
#' calls the other `create_` family of functions to construct a single list for input into stan
#' with all data required present.
#' Takes the output of `stan_opts()` and converts it into a list understood by
#' `stan`. Internally calls the other `create_` family of functions to
#' construct a single list for input into stan with all data required present.
#'
#' @param shifted_cases A dataframe of delay shifted cases
#' @param truncation `r lifecycle::badge("experimental")` A list of options as generated by `trunc_opts()`
#' defining the truncation of observed data. Defaults to `trunc_opts()`. See `estimate_truncation()`
#' for an approach to estimating truncation from data.
#'
#' @param truncation `r lifecycle::badge("experimental")` A list of options as
#' generated by `trunc_opts()` defining the truncation of observed data.
#' Defaults to `trunc_opts()`. See `estimate_truncation()` for an approach to
#' estimating truncation from data.
#'
#' @inheritParams create_gp_data
#' @inheritParams create_obs_model
#' @inheritParams create_rt_data
Expand All @@ -389,42 +401,20 @@ create_obs_model <- function(obs = obs_opts(), dates) {
#' @importFrom stats lm
#' @importFrom purrr safely
#' @return A list of stan data
#' @author Sam Abbott
seabbs marked this conversation as resolved.
Show resolved Hide resolved
#' @author Sebastian Funk
#' @export
create_stan_data <- function(reported_cases, generation_time,
rt, gp, obs, delays, horizon,
backcalc, shifted_cases,
truncation) {
## make sure we have at least max_gt seeding time
## make sure we have at least gt_max seeding time
delays$seeding_time <- max(delays$seeding_time, generation_time$max)

## complete generation time parameters if not all are given
if (is.null(generation_time)) {
generation_time <- list(mean = 1)
}
for (param in c("mean_sd", "sd", "sd_sd")) {
if (!(param %in% names(generation_time))) generation_time[[param]] <- 0
}
## check if generation time is fixed
if (generation_time$sd == 0 && generation_time$sd_sd == 0) {
if ("max_gt" %in% names(generation_time)) {
if (generation_time$max_gt != generation_time$mean) {
stop(
"Error in generation time defintion: if max_gt(",
generation_time$max_gt,
") is given it must be equal to the mean (",
generation_time$mean,
")"
)
}
} else {
generation_time$max_gt <- generation_time$mean
}
if (any(generation_time$mean_sd > 0, generation_time$sd_sd > 0)) {
stop(
"Error in generation time definition: if sd_mean is 0 and ",
"sd_sd is 0 then mean_sd must be 0, too."
)
}
## for backwards compatibility call generation_time_opts internally
if (is.list(generation_time) &&
all(c("mean", "mean_sd", "sd", "sd_sd") %in% names(generation_time))) {
generation_time <- do.call(generation_time_opts, generation_time)
}

cases <- reported_cases[(delays$seeding_time + 1):(.N - horizon)]$confirm
Expand All @@ -434,13 +424,10 @@ create_stan_data <- function(reported_cases, generation_time,
shifted_cases = shifted_cases,
t = length(reported_cases$date),
horizon = horizon,
gt_mean_mean = generation_time$mean,
gt_mean_sd = generation_time$mean_sd,
gt_sd_mean = generation_time$sd,
gt_sd_sd = generation_time$sd_sd,
max_gt = generation_time$max,
burn_in = 0
)
# add gt data
data <- c(data, generation_time)
# add delay data
data <- c(data, delays)
# add truncation data
Expand All @@ -462,6 +449,10 @@ create_stan_data <- function(reported_cases, generation_time,
data$prior_infections <- ifelse(is.na(data$prior_infections) | is.null(data$prior_infections),
0, data$prior_infections
)
if (is.null(data$gt_weight)) {
## default: weigh by number of data points
data$gt_weight <- data$t - data$seeding_time - data$horizon
}
if (data$seeding_time > 1) {
safe_lm <- purrr::safely(stats::lm)
data$prior_growth <- safe_lm(log(confirm) ~ t, data = first_week)[[1]]
Expand Down Expand Up @@ -504,29 +495,41 @@ create_stan_data <- function(reported_cases, generation_time,
#' @importFrom purrr map2_dbl
#' @importFrom truncnorm rtruncnorm
#' @export
# @author Sam Abbott
seabbs marked this conversation as resolved.
Show resolved Hide resolved
# @author Sebastian Funk
create_initial_conditions <- function(data) {
init_fun <- function() {
out <- list()
if (data$delays > 0) {
if (data$n_uncertain_mean_delays > 0) {
out$delay_mean <- array(purrr::map2_dbl(
data$delay_mean_mean, data$delay_mean_sd * 0.1,
data$delay_mean_mean[data$uncertain_mean_delays],
data$delay_mean_sd[data$uncertain_mean_delays] * 0.1,
~ rnorm(1, mean = .x, sd = .y)
))
}
if (data$n_uncertain_sd_delays > 0) {
out$delay_sd <- array(purrr::map2_dbl(
data$delay_sd_mean, data$delay_sd_sd * 0.1,
data$delay_sd_mean[data$uncertain_sd_delays],
data$delay_sd_sd[data$uncertain_sd_delays] * 0.1,
~ rnorm(1, mean = .x, sd = .y)
))
}
if (data$truncation > 0) {
out$truncation_mean <- array(rnorm(1,
mean = data$trunc_mean_mean,
sd = data$trunc_mean_sd * 0.1
))
out$truncation_sd <- array(truncnorm::rtruncnorm(1,
a = 0,
mean = data$trunc_sd_mean,
sd = data$trunc_sd_sd * 0.1
))
if (data$trunc_mean_sd > 0) {
out$truncation_mean <- array(rnorm(1,
mean = data$trunc_mean_mean,
sd = data$trunc_mean_sd * 0.1
))
}
if (data$trunc_sd_sd > 0) {
out$truncation_sd <- array(
truncnorm::rtruncnorm(1,
a = 0,
mean = data$trunc_sd_mean,
sd = data$trunc_sd_sd * 0.1
)
)
}
}
if (data$fixed == 0) {
out$eta <- array(rnorm(data$M, mean = 0, sd = 0.1))
Expand Down Expand Up @@ -578,11 +581,14 @@ create_initial_conditions <- function(data) {
}
if (data$obs_scale == 1) {
out$frac_obs <- array(truncnorm::rtruncnorm(1,
a = 0,
a = 0, b = 1,
mean = data$obs_scale_mean,
sd = data$obs_scale_sd * 0.1
))
}
if (data$week_effect > 0) {
out$day_of_week_simplex <- array(rep(1 / data$week_effect, data$week_effect))
}
return(out)
}
return(init_fun)
Expand All @@ -601,6 +607,7 @@ create_initial_conditions <- function(data) {
#' as supplied by `create_intitial_conditions`).
#' @param verbose Logical, defaults to `FALSE`. Should verbose progress messages be returned.
#' @return A list of stan arguments
#' @author Sam Abbott
#' @export
#' @examples
#' # default settings
Expand Down
Loading