diff options
author | Johannes Ranke <jranke@uni-bremen.de> | 2021-02-06 18:30:32 +0100 |
---|---|---|
committer | Johannes Ranke <jranke@uni-bremen.de> | 2021-02-06 18:30:32 +0100 |
commit | 48c463680b51fa767b4cd7bd62865f192d0354ac (patch) | |
tree | 5b66eb08a7fd5e29fb7e6d3a9a8258ccdcaea73e /tests/testthat | |
parent | 2ee20b257e34210e2d1f044431f3bfe059c9c5e7 (diff) |
Reintroduce interface to saemix
Also after the upgrade from buster to bullseye of my local system, some
test results for saemix have changed.
Diffstat (limited to 'tests/testthat')
-rw-r--r-- | tests/testthat/setup_script.R | 18 | ||||
-rw-r--r-- | tests/testthat/summary_saem_biphasic_s.txt | 77 | ||||
-rw-r--r-- | tests/testthat/test_mixed.R | 135 | ||||
-rw-r--r-- | tests/testthat/test_plot.R | 11 |
4 files changed, 240 insertions, 1 deletions
diff --git a/tests/testthat/setup_script.R b/tests/testthat/setup_script.R index 547b2d6c..9229c198 100644 --- a/tests/testthat/setup_script.R +++ b/tests/testthat/setup_script.R @@ -178,6 +178,10 @@ ds_biphasic <- lapply(ds_biphasic_mean, function(ds) { }) # Mixed model fits +saemix_available <- FALSE +if (requireNamespace("saemix", quietly = TRUE)) { + if(packageVersion("saemix") >= "3.1.9000") saemix_available <- TRUE +} mmkin_sfo_1 <- mmkin("SFO", ds_sfo, quiet = TRUE, error_model = "tc", cores = n_cores) mmkin_dfop_1 <- mmkin("DFOP", ds_dfop, quiet = TRUE, cores = n_cores) mmkin_biphasic <- mmkin(list("DFOP-SFO" = DFOP_SFO), ds_biphasic, quiet = TRUE, cores = n_cores) @@ -186,6 +190,16 @@ mmkin_biphasic_mixed <- mixed(mmkin_biphasic) dfop_nlme_1 <- nlme(mmkin_dfop_1) nlme_biphasic <- nlme(mmkin_biphasic) +if (saemix_available) { + sfo_saem_1 <- saem(mmkin_sfo_1, quiet = TRUE, transformations = "saemix") + + dfop_saemix_1 <- saem(mmkin_dfop_1, quiet = TRUE, transformations = "mkin") + dfop_saemix_2 <- saem(mmkin_dfop_1, quiet = TRUE, transformations = "saemix") + + saem_biphasic_m <- saem(mmkin_biphasic, transformations = "mkin", quiet = TRUE) + saem_biphasic_s <- saem(mmkin_biphasic, transformations = "saemix", quiet = TRUE) +} + ds_uba <- lapply(experimental_data_for_UBA_2019[6:10], function(x) subset(x$data[c("name", "time", "value")])) names(ds_uba) <- paste("Dataset", 6:10) @@ -197,3 +211,7 @@ f_uba_mmkin <- mmkin(list("SFO-SFO" = sfo_sfo_uba, "DFOP-SFO" = dfop_sfo_uba), ds_uba, quiet = TRUE, cores = n_cores) f_uba_dfop_sfo_mixed <- mixed(f_uba_mmkin[2, ]) +if (saemix_available) { + f_uba_sfo_sfo_saem <- saem(f_uba_mmkin["SFO-SFO", ], quiet = TRUE, transformations = "saemix") + f_uba_dfop_sfo_saem <- saem(f_uba_mmkin["DFOP-SFO", ], quiet = TRUE, transformations = "saemix") +} diff --git a/tests/testthat/summary_saem_biphasic_s.txt b/tests/testthat/summary_saem_biphasic_s.txt new file mode 100644 index 00000000..1e0f1ccc --- /dev/null +++ b/tests/testthat/summary_saem_biphasic_s.txt @@ -0,0 +1,77 @@ +saemix version used for fitting: Dummy 0.0 for testing +mkin version used for pre-fitting: Dummy 0.0 for testing +R version used for fitting: Dummy R version for testing +Date of fit: Dummy date for testing +Date of summary: Dummy date for testing + +Equations: +d_parent/dt = - ((k1 * g * exp(-k1 * time) + k2 * (1 - g) * exp(-k2 * + time)) / (g * exp(-k1 * time) + (1 - g) * exp(-k2 * time))) + * parent +d_m1/dt = + f_parent_to_m1 * ((k1 * g * exp(-k1 * time) + k2 * (1 - g) + * exp(-k2 * time)) / (g * exp(-k1 * time) + (1 - g) * + exp(-k2 * time))) * parent - k_m1 * m1 + +Data: +509 observations of 2 variable(s) grouped in 15 datasets + +Model predictions using solution type analytical + +Fitted in test time 0 s using 300, 100 iterations + +Variance model: Constant variance + +Mean of starting values for individual parameters: + parent_0 k_m1 f_parent_to_m1 k1 k2 + 1.0e+02 4.8e-03 4.8e-01 6.8e-02 1.3e-02 + g + 4.2e-01 + +Fixed degradation parameter values: +None + +Results: + +Likelihood computed by importance sampling + AIC BIC logLik + 2645 2654 -1310 + +Optimised parameters: + est. lower upper +parent_0 1.0e+02 99.627 1.0e+02 +k_m1 4.8e-03 0.004 5.6e-03 +f_parent_to_m1 4.8e-01 0.437 5.2e-01 +k1 6.5e-02 0.051 8.0e-02 +k2 1.2e-02 0.010 1.4e-02 +g 4.3e-01 0.362 5.0e-01 + +Correlation: + prnt_0 k_m1 f_p__1 k1 k2 +k_m1 -0.156 +f_parent_to_m1 -0.157 0.372 +k1 0.159 0.000 -0.029 +k2 0.074 0.145 0.032 0.332 +g -0.072 -0.142 -0.044 -0.422 -0.570 + +Random effects: + est. lower upper +SD.parent_0 1.14 0.251 2.03 +SD.k_m1 0.14 -0.073 0.35 +SD.f_parent_to_m1 0.29 0.176 0.41 +SD.k1 0.36 0.211 0.52 +SD.k2 0.18 0.089 0.27 +SD.g 0.32 0.098 0.53 + +Variance model: + est. lower upper +a.1 2.7 2.5 2.9 + +Resulting formation fractions: + ff +parent_m1 0.48 +parent_sink 0.52 + +Estimated disappearance times: + DT50 DT90 DT50back DT50_k1 DT50_k2 +parent 25 145 44 11 58 +m1 145 481 NA NA NA diff --git a/tests/testthat/test_mixed.R b/tests/testthat/test_mixed.R index 6f28d0c3..0eb1f0d5 100644 --- a/tests/testthat/test_mixed.R +++ b/tests/testthat/test_mixed.R @@ -1,9 +1,98 @@ context("Nonlinear mixed-effects models") +test_that("Parent fits using saemix are correctly implemented", { + skip_if(!saemix_available) + + expect_error(saem(fits), "Only row objects") + # Some fits were done in the setup script + mmkin_sfo_2 <- update(mmkin_sfo_1, fixed_initials = c(parent = 100)) + expect_error(update(mmkin_sfo_1, models = c("SFOOO")), "Please supply models.*") + + sfo_saem_2 <- saem(mmkin_sfo_1, quiet = TRUE, transformations = "mkin") + sfo_saem_3 <- expect_error(saem(mmkin_sfo_2, quiet = TRUE), "at least two parameters") + s_sfo_s1 <- summary(sfo_saem_1) + s_sfo_s2 <- summary(sfo_saem_2) + + sfo_nlme_1 <- expect_warning(nlme(mmkin_sfo_1), "not converge") + s_sfo_n <- summary(sfo_nlme_1) + + # Compare with input + expect_equal(round(s_sfo_s2$confint_ranef["SD.log_k_parent", "est."], 1), 0.3) + # k_parent is a bit different from input 0.03 here + expect_equal(round(s_sfo_s1$confint_back["k_parent", "est."], 3), 0.035) + expect_equal(round(s_sfo_s2$confint_back["k_parent", "est."], 3), 0.035) + + # But the result is pretty unanimous between methods + expect_equal(round(s_sfo_s1$confint_back["k_parent", "est."], 3), + round(s_sfo_s2$confint_back["k_parent", "est."], 3)) + expect_equal(round(s_sfo_s1$confint_back["k_parent", "est."], 3), + round(s_sfo_n$confint_back["k_parent", "est."], 3)) + + mmkin_fomc_1 <- mmkin("FOMC", ds_fomc, quiet = TRUE, error_model = "tc", cores = n_cores) + fomc_saem_1 <- saem(mmkin_fomc_1, quiet = TRUE) + ci_fomc_s1 <- summary(fomc_saem_1)$confint_back + + fomc_pop <- as.numeric(fomc_pop) + expect_true(all(ci_fomc_s1[, "lower"] < fomc_pop)) + expect_true(all(ci_fomc_s1[, "upper"] > fomc_pop)) + + mmkin_fomc_2 <- update(mmkin_fomc_1, state.ini = 100, fixed_initials = "parent") + fomc_saem_2 <- saem(mmkin_fomc_2, quiet = TRUE, transformations = "mkin") + ci_fomc_s2 <- summary(fomc_saem_2)$confint_back + + expect_true(all(ci_fomc_s2[, "lower"] < fomc_pop[2:3])) + expect_true(all(ci_fomc_s2[, "upper"] > fomc_pop[2:3])) + + s_dfop_s1 <- summary(dfop_saemix_1) + s_dfop_s2 <- summary(dfop_saemix_2) + s_dfop_n <- summary(dfop_nlme_1) + + dfop_pop <- as.numeric(dfop_pop) + expect_true(all(s_dfop_s1$confint_back[, "lower"] < dfop_pop)) + expect_true(all(s_dfop_s1$confint_back[, "upper"] > dfop_pop)) + expect_true(all(s_dfop_s2$confint_back[, "lower"] < dfop_pop)) + expect_true(all(s_dfop_s2$confint_back[, "upper"] > dfop_pop)) + + dfop_mmkin_means_trans <- apply(parms(mmkin_dfop_1, transformed = TRUE), 1, mean) + dfop_mmkin_means <- backtransform_odeparms(dfop_mmkin_means_trans, mmkin_dfop_1$mkinmod) + + # We get < 22% deviations by averaging the transformed parameters + rel_diff_mmkin <- (dfop_mmkin_means - dfop_pop) / dfop_pop + expect_true(all(rel_diff_mmkin < 0.22)) + + # We get < 50% deviations with transformations made in mkin + rel_diff_1 <- (s_dfop_s1$confint_back[, "est."] - dfop_pop) / dfop_pop + expect_true(all(rel_diff_1 < 0.5)) + + # We get < 12% deviations with transformations made in saemix + rel_diff_2 <- (s_dfop_s2$confint_back[, "est."] - dfop_pop) / dfop_pop + expect_true(all(rel_diff_2 < 0.12)) + + mmkin_hs_1 <- mmkin("HS", ds_hs, quiet = TRUE, error_model = "const", cores = n_cores) + hs_saem_1 <- saem(mmkin_hs_1, quiet = TRUE) + ci_hs_s1 <- summary(hs_saem_1)$confint_back + + hs_pop <- as.numeric(hs_pop) + # expect_true(all(ci_hs_s1[, "lower"] < hs_pop)) # k1 is overestimated + expect_true(all(ci_hs_s1[, "upper"] > hs_pop)) + + mmkin_hs_2 <- update(mmkin_hs_1, state.ini = 100, fixed_initials = "parent") + hs_saem_2 <- saem(mmkin_hs_2, quiet = TRUE) + ci_hs_s2 <- summary(hs_saem_2)$confint_back + + #expect_true(all(ci_hs_s2[, "lower"] < hs_pop[2:4])) # k1 again overestimated + expect_true(all(ci_hs_s2[, "upper"] > hs_pop[2:4])) + + # HS would likely benefit from implemenation of transformations = "saemix" +}) + test_that("Print methods work", { expect_known_output(print(fits[, 2:3], digits = 2), "print_mmkin_parent.txt") expect_known_output(print(mmkin_biphasic_mixed, digits = 2), "print_mmkin_biphasic_mixed.txt") expect_known_output(print(nlme_biphasic, digits = 1), "print_nlme_biphasic.txt") + + skip_if(!saemix_available) + expect_known_output(print(sfo_saem_1, digits = 1), "print_sfo_saem_1.txt") }) test_that("nlme results are reproducible to some degree", { @@ -20,6 +109,50 @@ test_that("nlme results are reproducible to some degree", { dfop_sfo_pop <- as.numeric(dfop_sfo_pop) ci_dfop_sfo_n <- summary(nlme_biphasic)$confint_back - # expect_true(all(ci_dfop_sfo_n[, "lower"] < dfop_sfo_pop)) # k2 is overestimated + expect_true(all(ci_dfop_sfo_n[, "lower"] < dfop_sfo_pop)) expect_true(all(ci_dfop_sfo_n[, "upper"] > dfop_sfo_pop)) }) + +test_that("saem results are reproducible for biphasic fits", { + + skip_if(!saemix_available) + test_summary <- summary(saem_biphasic_s) + test_summary$saemixversion <- "Dummy 0.0 for testing" + test_summary$mkinversion <- "Dummy 0.0 for testing" + test_summary$Rversion <- "Dummy R version for testing" + test_summary$date.fit <- "Dummy date for testing" + test_summary$date.summary <- "Dummy date for testing" + test_summary$time <- c(elapsed = "test time 0") + + expect_known_output(print(test_summary, digits = 2), "summary_saem_biphasic_s.txt") + + dfop_sfo_pop <- as.numeric(dfop_sfo_pop) + no_k1 <- c(1, 2, 3, 5, 6) + no_k2 <- c(1, 2, 3, 4, 6) + no_k1_k2 <- c(1, 2, 3, 6) + + ci_dfop_sfo_s_s <- summary(saem_biphasic_s)$confint_back + # k1 and k2 are overestimated + expect_true(all(ci_dfop_sfo_s_s[no_k1_k2, "lower"] < dfop_sfo_pop[no_k1_k2])) + expect_true(all(ci_dfop_sfo_s_s[, "upper"] > dfop_sfo_pop)) + + # k1 and k2 are not fitted well + ci_dfop_sfo_s_m <- summary(saem_biphasic_m)$confint_back + expect_true(all(ci_dfop_sfo_s_m[no_k2, "lower"] < dfop_sfo_pop[no_k2])) + expect_true(all(ci_dfop_sfo_s_m[no_k1, "upper"] > dfop_sfo_pop[no_k1])) + + # I tried to only do few iterations in routine tests as this is so slow + # but then deSolve fails at some point (presumably at the switch between + # the two types of iterations) + #saem_biphasic_2 <- saem(mmkin_biphasic, solution_type = "deSolve", + # control = list(nbiter.saemix = c(10, 5), nbiter.burn = 5), quiet = TRUE) + + skip("Fitting with saemix takes around 10 minutes when using deSolve") + saem_biphasic_2 <- saem(mmkin_biphasic, solution_type = "deSolve", quiet = TRUE) + + # As with the analytical solution, k1 and k2 are not fitted well + ci_dfop_sfo_s_d <- summary(saem_biphasic_2)$confint_back + expect_true(all(ci_dfop_sfo_s_d[no_k2, "lower"] < dfop_sfo_pop[no_k2])) + expect_true(all(ci_dfop_sfo_s_d[no_k1, "upper"] > dfop_sfo_pop[no_k1])) +}) + diff --git a/tests/testthat/test_plot.R b/tests/testthat/test_plot.R index 0bf3ee66..1c95d069 100644 --- a/tests/testthat/test_plot.R +++ b/tests/testthat/test_plot.R @@ -35,6 +35,11 @@ test_that("Plotting mkinfit, mmkin and mixed model objects is reproducible", { plot_biphasic_mmkin <- function() plot(f_uba_dfop_sfo_mixed) vdiffr::expect_doppelganger("mixed model fit for mmkin object", plot_biphasic_mmkin) + if (saemix_available) { + plot_biphasic_saem_s <- function() plot(f_uba_dfop_sfo_saem) + vdiffr::expect_doppelganger("mixed model fit for saem object with saemix transformations", plot_biphasic_saem_s) + } + skip_on_travis() plot_biphasic_nlme <- function() plot(dfop_nlme_1) @@ -43,6 +48,12 @@ test_that("Plotting mkinfit, mmkin and mixed model objects is reproducible", { #plot_biphasic_mmkin <- function() plot(mixed(mmkin_biphasic)) # Biphasic fits with lots of data and fits have lots of potential for differences plot_biphasic_nlme <- function() plot(nlme_biphasic) + if (saemix_available) { + #plot_biphasic_saem_s <- function() plot(saem_biphasic_s) + plot_biphasic_saem_m <- function() plot(saem_biphasic_m) + + vdiffr::expect_doppelganger("mixed model fit for saem object with mkin transformations", plot_biphasic_saem_m) + } # different results when working with eigenvalues plot_errmod_fit_D_obs_eigen <- function() plot_err(fit_D_obs_eigen, sep_obs = FALSE) |