#' Perform a hierarchical model fit with multiple starting values #' #' The purpose of this method is to check if a certain algorithm for fitting #' nonlinear hierarchical models (also known as nonlinear mixed-effects models) #' will reliably yield results that are sufficiently similar to each other, if #' started with a certain range of reasonable starting parameters. It is #' inspired by the article on practical identifiabiliy in the frame of nonlinear #' mixed-effects models by Duchesne et al (2021). #' #' Currently, parallel execution of the fits is only supported using #' [parallel::mclapply], i.e. not available on Windows. #' #' In case the online version of this help page contains error messages #' in the example code and no plots, this is due to the multistart method #' not working when called by pkgdown. Please refer to the #' [online vignette](https://pkgdown.jrwb.de/mkin/dev/articles/web_only/multistart.html) #' in this case. #' #' @param object The fit object to work with #' @param n How many different combinations of starting parameters should be #' used? #' @param cores How many fits should be run in parallel? #' @param \dots Passed to the update function. #' @param x The multistart object to print #' @return A list of [saem.mmkin] objects, with class attributes #' 'multistart.saem.mmkin' and 'multistart'. #' @seealso [parhist], [llhist] #' #' @references Duchesne R, Guillemin A, Gandrillon O, Crauste F. Practical #' identifiability in the frame of nonlinear mixed effects models: the example #' of the in vitro erythropoiesis. BMC Bioinformatics. 2021 Oct 4;22(1):478. #' doi: 10.1186/s12859-021-04373-4. #' @export #' @examples #' \dontrun{ #' library(mkin) #' dmta_ds <- lapply(1:7, function(i) { #' ds_i <- dimethenamid_2018$ds[[i]]$data #' ds_i[ds_i$name == "DMTAP", "name"] <- "DMTA" #' ds_i$time <- ds_i$time * dimethenamid_2018$f_time_norm[i] #' ds_i #' }) #' names(dmta_ds) <- sapply(dimethenamid_2018$ds, function(ds) ds$title) #' dmta_ds[["Elliot"]] <- rbind(dmta_ds[["Elliot 1"]], dmta_ds[["Elliot 2"]]) #' dmta_ds[["Elliot 1"]] <- dmta_ds[["Elliot 2"]] <- NULL #' #' f_mmkin <- mmkin("DFOP", dmta_ds, error_model = "tc", cores = 7, quiet = TRUE) #' f_saem_full <- saem(f_mmkin) #' f_saem_full_multi <- multistart(f_saem_full, n = 16, cores = 16) #' parhist(f_saem_full_multi, lpos = "bottomright") #' #' f_saem_reduced <- update(f_saem_full, covariance.model = diag(c(1, 1, 0, 1))) #' f_saem_reduced_multi <- multistart(f_saem_reduced, n = 16, cores = 16) #' parhist(f_saem_reduced_multi, lpos = "bottomright") #' } multistart <- function(object, n = 50, cores = 1, ...) { UseMethod("multistart", object) } #' @rdname multistart #' @export multistart.saem.mmkin <- function(object, n = 50, cores = 1, ...) { mmkin_parms <- parms(object$mmkin, errparms = FALSE, transformed = object$transformations == "mkin") start_parms <- apply( mmkin_parms, 1, function(x) stats::runif(n, min(x), max(x))) if (n == 1) dim(start_parms) <- c(1, length(start_parms)) res <- parallel::mclapply(1:n, function(x) { update(object, degparms_start = start_parms[x, ], ...) }, mc.cores = cores) attr(res, "orig") <- object attr(res, "start_parms") <- start_parms class(res) <- c("multistart.saem.mmkin", "multistart") return(res) } #' @rdname multistart #' @export print.multistart <- function(x, ...) { cat("Multistart object with", length(x), "fits of the following type:\n\n") print(x[[1]]) } #' @rdname multistart #' @export parms.multistart <- function(object, ...) { t(sapply(object, parms)) }