Skip to content

Commit

Permalink
rename fn, add tests, fix trajectories
Browse files Browse the repository at this point in the history
  • Loading branch information
hillalex committed Oct 17, 2024
1 parent e7b129e commit 3fe300a
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 32 deletions.
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
export(add_exposure_data)
export(biokinetics)
export(biokinetics_priors)
export(convert_log_scale_inverse)
export(convert_log2_scale_inverse)
importFrom(R6,R6Class)
importFrom(data.table,":=")
importFrom(data.table,.BY)
Expand Down
17 changes: 10 additions & 7 deletions R/biokinetics.R
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ biokinetics <- R6::R6Class(
#' @param priors Object of type \link[epikinetics]{biokinetics_priors}. Default biokinetics_priors().
#' @param covariate_formula Formula specifying linear regression model. Note all variables in the formula
#' will be treated as categorical variables. Default ~0.
#' @param preds_sd Standard deviation of predictor coefficients. Default 0.25.
#' @param scale One of "log" or "natural". Default "natural". Is provided data on a log or a natural scale? If on a natural scale it
#' will be converted to a log scale for model fitting.
initialize = function(priors = biokinetics_priors(),
Expand Down Expand Up @@ -246,7 +247,7 @@ biokinetics <- R6::R6Class(
validate_formula_vars(private$all_formula_vars, private$data)
logger::log_info("Preparing data for stan")
if (scale == "natural") {
private$data <- convert_log_scale(private$data, "value")
private$data <- convert_log2_scale(private$data, "value")
}
private$data[, `:=`(obs_id = seq_len(.N),
t_since_last_exp = as.integer(day - last_exp_day, units = "days"))]
Expand All @@ -269,6 +270,8 @@ biokinetics <- R6::R6Class(
get_stan_data = function() {
private$stan_input_data
},
#' @description View the mapping of human readable covariate names to the model variable p.
#' @return A data.table mapping the model variable p to human readable covariates.
get_covariate_lookup_table = function() {
private$covariate_lookup_table

Check warning on line 276 in R/biokinetics.R

View check run for this annotation

Codecov / codecov/patch

R/biokinetics.R#L276

Added line #L276 was not covered by tests
},
Expand Down Expand Up @@ -390,10 +393,10 @@ biokinetics <- R6::R6Class(
}

if (summarise) {
dt_out <- convert_log_scale_inverse(
dt_out <- convert_log2_scale_inverse(
dt_out, vars_to_transform = c("me", "lo", "hi"))
} else {
dt_out <- convert_log_scale_inverse(
dt_out <- convert_log2_scale_inverse(
dt_out, vars_to_transform = "mu")
}
dt_out
Expand Down Expand Up @@ -430,7 +433,7 @@ biokinetics <- R6::R6Class(
dt_peak_switch <- private$recover_covariate_names(dt_peak_switch)

if (private$scale == "natural") {
dt_peak_switch <- convert_log_scale_inverse(
dt_peak_switch <- convert_log2_scale_inverse(
dt_peak_switch, vars_to_transform = c("mu_0", "mu_p", "mu_s"))
}

Expand Down Expand Up @@ -491,11 +494,11 @@ biokinetics <- R6::R6Class(
# Running the C++ code to simulate trajectories for each parameter sample
# for each individual
logger::log_info("Simulating individual trajectories")
dt_params_ind_traj <- data.table::setDT(biokinetics_simulate_trajectories(dt_params_ind))
dt_params_ind_traj <- biokinetics_simulate_trajectories(dt_params_ind)

if (private$scale == "natural") {
dt_params_ind_traj <- convert_log_scale_inverse_cpp(
dt_params_ind_traj, vars_to_transform = "mu")
dt_params_ind_traj <- data.table::setDT(convert_log2_scale_inverse_cpp(
dt_params_ind_traj, vars_to_transform = "mu"))
}

# convert numeric pid to original pid
Expand Down
4 changes: 2 additions & 2 deletions R/cpp11.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Generated by cpp11: do not edit by hand

convert_log_scale_inverse_cpp <- function(dt, vars_to_transform) {
.Call(`_epikinetics_convert_log_scale_inverse_cpp`, dt, vars_to_transform)
convert_log2_scale_inverse_cpp <- function(dt, vars_to_transform) {
.Call(`_epikinetics_convert_log2_scale_inverse_cpp`, dt, vars_to_transform)
}

simulate_trajectories_cpp <- function(person_params) {
Expand Down
10 changes: 5 additions & 5 deletions R/utils.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
convert_log_scale <- function(
convert_log2_scale <- function(
dt_in, vars_to_transform = "titre",
simplify_limits = TRUE) {

Expand All @@ -14,14 +14,14 @@ convert_log_scale <- function(

#' @title Invert base 2 log scale conversion
#'
#' @description User provided data is converted to a base 2 log scale before model fitting. This
#' function reverses that transformation. This function does not modify the provided data.table in-place,
#' but returns a transformed copy.
#' @description Natural scale data is converted to a base 2 log scale before model fitting. This
#' function reverses that transformation and may be useful if working directly with fitted parameters.
#' This function does not modify the provided data.table in-place, but returns a transformed copy.
#' @return A data.table, identical to the input data but with specified columns transformed.
#' @param dt_in data.table containing data to be transformed from base 2 log to natural scale.
#' @param vars_to_transform Names of columns to apply the transformation to.
#' @export
convert_log_scale_inverse <- function(dt_in, vars_to_transform) {
convert_log2_scale_inverse <- function(dt_in, vars_to_transform) {
dt_out <- data.table::copy(dt_in)
for (var in vars_to_transform) {
# Reverse the log2 transformation and multiplication by 5.
Expand Down
6 changes: 6 additions & 0 deletions man/biokinetics.Rd

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

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

2 changes: 1 addition & 1 deletion src/convert_log_scale_inverse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using namespace cpp11;

[[cpp11::register]]
cpp11::data_frame convert_log_scale_inverse_cpp(cpp11::writable::list dt,
cpp11::data_frame convert_log2_scale_inverse_cpp(cpp11::writable::list dt,
cpp11::strings vars_to_transform) {

for (int i = 0; i < vars_to_transform.size(); i++) {
Expand Down
10 changes: 5 additions & 5 deletions src/cpp11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
#include <R_ext/Visibility.h>

// convert_log_scale_inverse.cpp
cpp11::data_frame convert_log_scale_inverse_cpp(cpp11::writable::list dt, cpp11::strings vars_to_transform);
extern "C" SEXP _epikinetics_convert_log_scale_inverse_cpp(SEXP dt, SEXP vars_to_transform) {
cpp11::data_frame convert_log2_scale_inverse_cpp(cpp11::writable::list dt, cpp11::strings vars_to_transform);
extern "C" SEXP _epikinetics_convert_log2_scale_inverse_cpp(SEXP dt, SEXP vars_to_transform) {
BEGIN_CPP11
return cpp11::as_sexp(convert_log_scale_inverse_cpp(cpp11::as_cpp<cpp11::decay_t<cpp11::writable::list>>(dt), cpp11::as_cpp<cpp11::decay_t<cpp11::strings>>(vars_to_transform)));
return cpp11::as_sexp(convert_log2_scale_inverse_cpp(cpp11::as_cpp<cpp11::decay_t<cpp11::writable::list>>(dt), cpp11::as_cpp<cpp11::decay_t<cpp11::strings>>(vars_to_transform)));
END_CPP11
}
// simulate_trajectories.cpp
Expand All @@ -22,8 +22,8 @@ extern "C" SEXP _epikinetics_simulate_trajectories_cpp(SEXP person_params) {

extern "C" {
static const R_CallMethodDef CallEntries[] = {
{"_epikinetics_convert_log_scale_inverse_cpp", (DL_FUNC) &_epikinetics_convert_log_scale_inverse_cpp, 2},
{"_epikinetics_simulate_trajectories_cpp", (DL_FUNC) &_epikinetics_simulate_trajectories_cpp, 1},
{"_epikinetics_convert_log2_scale_inverse_cpp", (DL_FUNC) &_epikinetics_convert_log2_scale_inverse_cpp, 2},
{"_epikinetics_simulate_trajectories_cpp", (DL_FUNC) &_epikinetics_simulate_trajectories_cpp, 1},
{NULL, NULL, 0}
};
}
Expand Down
8 changes: 4 additions & 4 deletions tests/testthat/test-convert-log-scale.R
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
test_that("Can convert to and from log scale in R", {
inputs <- data.table::fread(test_path("testdata", "testdata.csv"))
log_inputs <- convert_log_scale(inputs, "me", simplify_limits = FALSE)
unlog_inputs <- convert_log_scale_inverse(log_inputs, "me")
log_inputs <- convert_log2_scale(inputs, "me", simplify_limits = FALSE)
unlog_inputs <- convert_log2_scale_inverse(log_inputs, "me")

expect_equal(inputs, unlog_inputs)
})

test_that("Can convert from log scale in R", {
inputs <- data.table::fread(test_path("testdata", "testdata.csv"))
res <- convert_log_scale_inverse(
res <- convert_log2_scale_inverse(
inputs, vars_to_transform = c("me", "lo"))

expect_equal(res$me, 5 * 2^inputs$me)
Expand All @@ -19,7 +19,7 @@ test_that("Can convert from log scale in R", {

test_that("Can convert from log scale in Cpp", {
inputs <- data.table::fread(test_path("testdata", "testdata.csv"))
rescpp <- convert_log_scale_inverse_cpp(
rescpp <- convert_log2_scale_inverse_cpp(
inputs, vars_to_transform = c("me", "lo"))

expect_equal(rescpp$me, 5 * 2^(inputs$me))
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-data.R
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ test_that("Natural scale data is converted to log scale for stan", {
dat <- data.table::fread(system.file("delta_full.rds", package = "epikinetics"))
mod <- biokinetics$new(data = dat)
stan_data <- mod$get_stan_data()
expect_equivalent(stan_data$value, convert_log_scale(dat, "value")$value)
expect_equivalent(stan_data$value, convert_log2_scale(dat, "value")$value)
})

test_that("Log scale data is passed directly to stan", {
Expand Down
16 changes: 16 additions & 0 deletions tests/testthat/test-simulate-individual-trajectories.R
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,19 @@ test_that("Exposure dates are brought forward by time_shift days", {
expect_equal(trajectories$mu, trajectories_shifted$mu)
expect_true(all(as.numeric(difftime(trajectories$exposure_date, trajectories_shifted$exposure_date, units = "days")) == 75))
})

test_that("Natural scale data is returned on natural scale", {
mod <- biokinetics$new(file_path = system.file("delta_full.rds", package = "epikinetics"),
covariate_formula = ~0 + infection_history, scale = "natural")
mod$fit()
trajectories <- mod$simulate_individual_trajectories(summarise = TRUE, n_draws = 10)
expect_false(all(trajectories$me < 10))
})

test_that("Log scale data is returned on log scale", {
mod <- biokinetics$new(file_path = system.file("delta_full.rds", package = "epikinetics"),
covariate_formula = ~0 + infection_history, scale = "log")
mod$fit()
trajectories <- mod$simulate_individual_trajectories(summarise = TRUE, n_draws = 10)
expect_true(all(trajectories$me < 10))
})
16 changes: 16 additions & 0 deletions tests/testthat/test-simulate-population-trajectories.R
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,19 @@ test_that("Only times up to t_max are returned", {
trajectories <- mod$simulate_population_trajectories(summarise = TRUE, t_max = 10)
expect_true(all(trajectories$t <= 10))
})

test_that("Natural scale data is returned on natural scale", {
mod <- biokinetics$new(file_path = system.file("delta_full.rds", package = "epikinetics"),
covariate_formula = ~0 + infection_history, scale = "natural")
mod$fit()
trajectories <- mod$simulate_population_trajectories(summarise = TRUE, t_max = 10)
expect_false(all(trajectories$me < 10))
})

test_that("Log scale data is returned on log scale", {
mod <- biokinetics$new(file_path = system.file("delta_full.rds", package = "epikinetics"),
covariate_formula = ~0 + infection_history, scale = "log")
mod$fit()
trajectories <- mod$simulate_population_trajectories(summarise = TRUE, t_max = 10)
expect_true(all(trajectories$me < 10))
})

0 comments on commit 3fe300a

Please sign in to comment.