diff options
author | Johannes Ranke <jranke@uni-bremen.de> | 2020-11-30 14:50:33 +0100 |
---|---|---|
committer | Johannes Ranke <jranke@uni-bremen.de> | 2020-11-30 14:50:33 +0100 |
commit | 78884beed74c18c99521b9ceeaa643e13cf94c06 (patch) | |
tree | af1ebfd975cac837a6bf15c86638299a67a0e017 | |
parent | b3bebc06061cc77b6d549f7b2760afe0b9489bf7 (diff) |
Log-Cholesky parameterisation as default in nlme.mmkin
-rw-r--r-- | R/nlme.R | 1 | ||||
-rw-r--r-- | R/nlme.mmkin.R | 47 | ||||
-rw-r--r-- | R/summary.nlme.mmkin.R | 1 | ||||
-rw-r--r-- | man/mkinmod.Rd | 6 | ||||
-rw-r--r-- | man/nlme.Rd | 1 | ||||
-rw-r--r-- | man/nlme.mmkin.Rd | 45 | ||||
-rw-r--r-- | man/summary.nlme.mmkin.Rd | 1 | ||||
-rw-r--r-- | test.log | 22 | ||||
-rw-r--r-- | tests/testthat/test_nlme.R | 20 |
9 files changed, 86 insertions, 58 deletions
@@ -54,7 +54,6 @@ #' # The procedure is greatly simplified by the nlme.mmkin function #' f_nlme <- nlme(f) #' plot(f_nlme) -#' #' @return A function that can be used with nlme #' @export nlme_function <- function(object) { diff --git a/R/nlme.mmkin.R b/R/nlme.mmkin.R index a9e1694f..b434bbf4 100644 --- a/R/nlme.mmkin.R +++ b/R/nlme.mmkin.R @@ -56,15 +56,15 @@ get_deg_func <- function() { #' f <- mmkin(c("SFO", "DFOP"), ds, quiet = TRUE, cores = 1) #' library(nlme) #' f_nlme_sfo <- nlme(f["SFO", ]) -#' f_nlme_dfop <- nlme(f["DFOP", ]) -#' AIC(f_nlme_sfo, f_nlme_dfop) -#' print(f_nlme_dfop) -#' plot(f_nlme_dfop) -#' endpoints(f_nlme_dfop) #' #' \dontrun{ -#' f_nlme_2 <- nlme(f["SFO", ], start = c(parent_0 = 100, log_k_parent = 0.1)) -#' update(f_nlme_2, random = parent_0 ~ 1) +#' +#' f_nlme_dfop <- nlme(f["DFOP", ]) +#' anova(f_nlme_sfo, f_nlme_dfop) +#' print(f_nlme_dfop) +#' plot(f_nlme_dfop) +#' endpoints(f_nlme_dfop) +#' #' ds_2 <- lapply(experimental_data_for_UBA_2019[6:10], #' function(x) x$data[c("name", "time", "value")]) #' m_sfo_sfo <- mkinmod(parent = mkinsub("SFO", "A1"), @@ -82,14 +82,15 @@ get_deg_func <- function() { #' f_nlme_sfo_sfo <- nlme(f_2["SFO-SFO", ]) #' plot(f_nlme_sfo_sfo) #' -#' # With formation fractions -#' f_nlme_sfo_sfo_ff <- nlme(f_2["SFO-SFO-ff", ]) -#' plot(f_nlme_sfo_sfo_ff) +#' # With formation fractions this does not coverge with defaults +#' # f_nlme_sfo_sfo_ff <- nlme(f_2["SFO-SFO-ff", ]) +#' #plot(f_nlme_sfo_sfo_ff) #' -#' # For the following fit we need to increase pnlsMaxIter and the tolerance -#' # to get convergence -#' f_nlme_dfop_sfo <- nlme(f_2["DFOP-SFO", ], -#' control = list(pnlsMaxIter = 120, tolerance = 5e-4), verbose = TRUE) +#' # With the log-Cholesky parameterization, this converges in 11 +#' # iterations and around 100 seconds, but without tweaking control +#' # parameters (with pdDiag, increasing the tolerance and pnlsMaxIter was +#' # necessary) +#' f_nlme_dfop_sfo <- nlme(f_2["DFOP-SFO", ]) #' #' plot(f_nlme_dfop_sfo) #' @@ -114,10 +115,18 @@ get_deg_func <- function() { #' ds_2, quiet = TRUE, error_model = "obs") #' f_nlme_sfo_sfo_obs <- nlme(f_2_obs["SFO-SFO", ]) #' print(f_nlme_sfo_sfo_obs) -#' # The same with DFOP-SFO does not converge, apparently the variances of -#' # parent and A1 are too similar in this case, so that the model is -#' # overparameterised -#' #f_nlme_dfop_sfo_obs <- nlme(f_2_obs["DFOP-SFO", ], control = list(maxIter = 100)) +#' f_nlme_dfop_sfo_obs <- nlme(f_2_obs["DFOP-SFO", ]) +#' +#' f_2_tc <- mmkin(list("SFO-SFO" = m_sfo_sfo, +#' "DFOP-SFO" = m_dfop_sfo), +#' ds_2, quiet = TRUE, error_model = "tc") +#' # f_nlme_sfo_sfo_tc <- nlme(f_2_tc["SFO-SFO", ]) # stops with error message +#' f_nlme_dfop_sfo_tc <- nlme(f_2_tc["DFOP-SFO", ]) +#' # We get warnings about false convergence in the LME step in several iterations +#' # but as the last such warning occurs in iteration 25 and we have 28 iterations +#' # we can ignore these +#' anova(f_nlme_dfop_sfo, f_nlme_dfop_sfo_obs, f_nlme_dfop_sfo_tc) +#' #' } nlme.mmkin <- function(model, data = sys.frame(sys.parent()), fixed, random = fixed, @@ -160,7 +169,7 @@ nlme.mmkin <- function(model, data = sys.frame(sys.parent()), eval(parse(text = paste(el, 1, sep = "~")))) if (missing(random)) { - thisCall[["random"]] <- pdDiag(thisCall[["fixed"]]) + thisCall[["random"]] <- pdLogChol(thisCall[["fixed"]]) } error_model <- model[[1]]$err_mod diff --git a/R/summary.nlme.mmkin.R b/R/summary.nlme.mmkin.R index 42326b39..29f1207b 100644 --- a/R/summary.nlme.mmkin.R +++ b/R/summary.nlme.mmkin.R @@ -55,6 +55,7 @@ #' ds_sfo_mean <- lapply(k_in, pred_sfo) #' names(ds_sfo_mean) <- paste("ds", 1:5) #' +#' set.seed(12345) #' ds_sfo_syn <- lapply(ds_sfo_mean, function(ds) { #' add_err(ds, #' sdfunc = function(value) sqrt(1^2 + value^2 * 0.07^2), diff --git a/man/mkinmod.Rd b/man/mkinmod.Rd index 77319aac..95cec09a 100644 --- a/man/mkinmod.Rd +++ b/man/mkinmod.Rd @@ -155,13 +155,17 @@ print(SFO_SFO) fit_sfo_sfo <- mkinfit(SFO_SFO, FOCUS_2006_D, quiet = TRUE, solution_type = "deSolve") # Now supplying compound names used for plotting, and write to user defined location + # We need to choose a path outside the session tempdir because this gets removed + DLL_dir <- "~/.local/share/mkin" + if (!dir.exists(DLL_dir)) dir.create(DLL_dir) SFO_SFO.2 <- mkinmod( parent = mkinsub("SFO", "m1", full_name = "Test compound"), m1 = mkinsub("SFO", full_name = "Metabolite M1"), - name = "SFO_SFO", dll_dir = "~/dll", unload = TRUE, overwrite = TRUE) + name = "SFO_SFO", dll_dir = DLL_dir, unload = TRUE, overwrite = TRUE) # Now we can save the model and restore it in a new session saveRDS(SFO_SFO.2, file = "~/SFO_SFO.rds") # Terminate the R session here if you would like to check, and then do +library(mkin) SFO_SFO.3 <- readRDS("~/SFO_SFO.rds") fit_sfo_sfo <- mkinfit(SFO_SFO.3, FOCUS_2006_D, quiet = TRUE, solution_type = "deSolve") diff --git a/man/nlme.Rd b/man/nlme.Rd index df721a0f..307cca82 100644 --- a/man/nlme.Rd +++ b/man/nlme.Rd @@ -78,7 +78,6 @@ plot(augPred(m_nlme, level = 0:1), layout = c(3, 1)) # The procedure is greatly simplified by the nlme.mmkin function f_nlme <- nlme(f) plot(f_nlme) - } \seealso{ \code{\link{nlme.mmkin}} diff --git a/man/nlme.mmkin.Rd b/man/nlme.mmkin.Rd index abcd0e81..0a9f6913 100644 --- a/man/nlme.mmkin.Rd +++ b/man/nlme.mmkin.Rd @@ -87,15 +87,15 @@ ds <- lapply(experimental_data_for_UBA_2019[6:10], f <- mmkin(c("SFO", "DFOP"), ds, quiet = TRUE, cores = 1) library(nlme) f_nlme_sfo <- nlme(f["SFO", ]) -f_nlme_dfop <- nlme(f["DFOP", ]) -AIC(f_nlme_sfo, f_nlme_dfop) -print(f_nlme_dfop) -plot(f_nlme_dfop) -endpoints(f_nlme_dfop) \dontrun{ - f_nlme_2 <- nlme(f["SFO", ], start = c(parent_0 = 100, log_k_parent = 0.1)) - update(f_nlme_2, random = parent_0 ~ 1) + + f_nlme_dfop <- nlme(f["DFOP", ]) + anova(f_nlme_sfo, f_nlme_dfop) + print(f_nlme_dfop) + plot(f_nlme_dfop) + endpoints(f_nlme_dfop) + ds_2 <- lapply(experimental_data_for_UBA_2019[6:10], function(x) x$data[c("name", "time", "value")]) m_sfo_sfo <- mkinmod(parent = mkinsub("SFO", "A1"), @@ -113,14 +113,15 @@ endpoints(f_nlme_dfop) f_nlme_sfo_sfo <- nlme(f_2["SFO-SFO", ]) plot(f_nlme_sfo_sfo) - # With formation fractions - f_nlme_sfo_sfo_ff <- nlme(f_2["SFO-SFO-ff", ]) - plot(f_nlme_sfo_sfo_ff) + # With formation fractions this does not coverge with defaults + # f_nlme_sfo_sfo_ff <- nlme(f_2["SFO-SFO-ff", ]) + #plot(f_nlme_sfo_sfo_ff) - # For the following fit we need to increase pnlsMaxIter and the tolerance - # to get convergence - f_nlme_dfop_sfo <- nlme(f_2["DFOP-SFO", ], - control = list(pnlsMaxIter = 120, tolerance = 5e-4), verbose = TRUE) + # With the log-Cholesky parameterization, this converges in 11 + # iterations and around 100 seconds, but without tweaking control + # parameters (with pdDiag, increasing the tolerance and pnlsMaxIter was + # necessary) + f_nlme_dfop_sfo <- nlme(f_2["DFOP-SFO", ]) plot(f_nlme_dfop_sfo) @@ -145,10 +146,18 @@ endpoints(f_nlme_dfop) ds_2, quiet = TRUE, error_model = "obs") f_nlme_sfo_sfo_obs <- nlme(f_2_obs["SFO-SFO", ]) print(f_nlme_sfo_sfo_obs) - # The same with DFOP-SFO does not converge, apparently the variances of - # parent and A1 are too similar in this case, so that the model is - # overparameterised - #f_nlme_dfop_sfo_obs <- nlme(f_2_obs["DFOP-SFO", ], control = list(maxIter = 100)) + f_nlme_dfop_sfo_obs <- nlme(f_2_obs["DFOP-SFO", ]) + + f_2_tc <- mmkin(list("SFO-SFO" = m_sfo_sfo, + "DFOP-SFO" = m_dfop_sfo), + ds_2, quiet = TRUE, error_model = "tc") + # f_nlme_sfo_sfo_tc <- nlme(f_2_tc["SFO-SFO", ]) # stops with error message + f_nlme_dfop_sfo_tc <- nlme(f_2_tc["DFOP-SFO", ]) + # We get warnings about false convergence in the LME step in several iterations + # but as the last such warning occurs in iteration 25 and we have 28 iterations + # we can ignore these + anova(f_nlme_dfop_sfo, f_nlme_dfop_sfo_obs, f_nlme_dfop_sfo_tc) + } } \seealso{ diff --git a/man/summary.nlme.mmkin.Rd b/man/summary.nlme.mmkin.Rd index ea625dd7..d7e61074 100644 --- a/man/summary.nlme.mmkin.Rd +++ b/man/summary.nlme.mmkin.Rd @@ -80,6 +80,7 @@ pred_sfo <- function(k) { ds_sfo_mean <- lapply(k_in, pred_sfo) names(ds_sfo_mean) <- paste("ds", 1:5) +set.seed(12345) ds_sfo_syn <- lapply(ds_sfo_mean, function(ds) { add_err(ds, sdfunc = function(value) sqrt(1^2 + value^2 * 0.07^2), @@ -6,11 +6,11 @@ Testing mkin ✔ | 2 | Export dataset for reading into CAKE ✔ | 14 | Results for FOCUS D established in expertise for UBA (Ranke 2014) [0.9 s] ✔ | 4 | Calculation of FOCUS chi2 error levels [0.4 s] -✔ | 7 | Fitting the SFORB model [3.2 s] -✔ | 5 | Analytical solutions for coupled models [2.9 s] +✔ | 7 | Fitting the SFORB model [3.4 s] +✔ | 5 | Analytical solutions for coupled models [3.1 s] ✔ | 5 | Calculation of Akaike weights ✔ | 10 | Confidence intervals and p-values [1.0 s] -✔ | 14 | Error model fitting [4.3 s] +✔ | 14 | Error model fitting [4.4 s] ✔ | 4 | Test fitting the decline of metabolites from their maximum [0.3 s] ✔ | 1 | Fitting the logistic model [0.2 s] ✔ | 1 | Test dataset class mkinds used in gmkin @@ -26,24 +26,28 @@ Reason: getRversion() < "4.1.0" is TRUE Skip (test_nafta.R:55:5): Test data from Appendix D are correctly evaluated Reason: getRversion() < "4.1.0" is TRUE ──────────────────────────────────────────────────────────────────────────────── -✔ | 9 | Nonlinear mixed-effects models [7.8 s] +✖ | 7 1 | Nonlinear mixed-effects models [8.0 s] +──────────────────────────────────────────────────────────────────────────────── +FAILURE (test_nlme.R:90:3): nlme_function works correctly +`tmp <- update(m_nlme_mmkin)` did not produce any warnings. +──────────────────────────────────────────────────────────────────────────────── ✔ | 0 1 | Plotting [0.7 s] ──────────────────────────────────────────────────────────────────────────────── Skip (test_plot.R:25:3): Plotting mkinfit and mmkin objects is reproducible Reason: getRversion() < "4.1.0" is TRUE ──────────────────────────────────────────────────────────────────────────────── ✔ | 4 | Residuals extracted from mkinfit models -✔ | 2 | Complex test case from Schaefer et al. (2007) Piacenza paper [1.4 s] +✔ | 2 | Complex test case from Schaefer et al. (2007) Piacenza paper [1.5 s] ✔ | 4 | Summary [0.1 s] ✔ | 1 | Summaries of old mkinfit objects -✔ | 4 | Results for synthetic data established in expertise for UBA (Ranke 2014) [2.0 s] -✔ | 9 | Hypothesis tests [6.4 s] +✔ | 4 | Results for synthetic data established in expertise for UBA (Ranke 2014) [2.2 s] +✔ | 9 | Hypothesis tests [7.2 s] ✔ | 4 | Calculation of maximum time weighted average concentrations (TWAs) [2.4 s] ══ Results ═════════════════════════════════════════════════════════════════════ -Duration: 36.9 s +Duration: 38.9 s ── Skipped tests ────────────────────────────────────────────────────────────── ● getRversion() < "4.1.0" is TRUE (3) -[ FAIL 0 | WARN 0 | SKIP 3 | PASS 146 ] +[ FAIL 1 | WARN 0 | SKIP 3 | PASS 144 ] diff --git a/tests/testthat/test_nlme.R b/tests/testthat/test_nlme.R index 4fd8e53f..da994f49 100644 --- a/tests/testthat/test_nlme.R +++ b/tests/testthat/test_nlme.R @@ -38,24 +38,27 @@ test_that("nlme_function works correctly", { m_nlme_raw <- nlme(value ~ SSasymp(time, 0, parent_0, log_k_parent_sink), data = grouped_data, fixed = parent_0 + log_k_parent_sink ~ 1, - random = pdDiag(parent_0 + log_k_parent_sink ~ 1), - start = mean_dp) + random = pdLogChol(parent_0 + log_k_parent_sink ~ 1), + start = mean_dp, + control = list("msWarnNoConv" = FALSE)) m_nlme_mkin <- nlme(value ~ nlme_f(name, time, parent_0, log_k_parent_sink), data = grouped_data, fixed = parent_0 + log_k_parent_sink ~ 1, - random = pdDiag(parent_0 + log_k_parent_sink ~ 1), - start = mean_dp) + random = pdLogChol(parent_0 + log_k_parent_sink ~ 1), + start = mean_dp, + control = list("msWarnNoConv" = FALSE)) expect_equal(m_nlme_raw$coefficients, m_nlme_mkin$coefficients) - m_nlme_mmkin <- nlme(f) + m_nlme_mmkin <- nlme(f, control = list("msWarnNoConv" = FALSE)) m_nlme_raw_2 <- nlme(value ~ SSasymp(time, 0, parent_0, log_k_parent), data = grouped_data, fixed = parent_0 + log_k_parent ~ 1, - random = pdDiag(parent_0 + log_k_parent ~ 1), - start = mean_degparms(f, random = TRUE)) + random = pdLogChol(parent_0 + log_k_parent ~ 1), + start = mean_degparms(f, random = TRUE), + control = list("msWarnNoConv" = FALSE)) expect_equal(m_nlme_raw_2$coefficients, m_nlme_mmkin$coefficients) @@ -84,8 +87,7 @@ test_that("nlme_function works correctly", { m_nlme_mkin_up_2 <- update(m_nlme_mkin, random = parent_0 ~ 1) expect_equal(m_nlme_raw_up_2$coefficients, m_nlme_mkin_up_2$coefficients) - expect_silent(tmp <- update(m_nlme_mkin)) - expect_silent(tmp <- update(m_nlme_mmkin)) + expect_warning(tmp <- update(m_nlme_mmkin), "Iteration 1, LME step") geomean_dt50_mmkin <- exp(mean(log((sapply(f, function(x) endpoints(x)$distimes["parent", "DT50"]))))) expect_equal(round(endpoints(m_nlme_mmkin)$distimes["parent", "DT50"]), round(geomean_dt50_mmkin)) |