diff --git a/DESCRIPTION b/DESCRIPTION index a40a74ed2..e6c7995b1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Type: Package Package: mrgsolve Title: Simulate from ODE-Based Models -Version: 0.11.1 +Version: 0.11.2 Authors@R: c(person(given = "Kyle T", family = "Baron", role = c("aut", "cre"), diff --git a/NEWS.md b/NEWS.md index 2546d1dfd..61820f83b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,23 @@ +# mrgsolve 0.11.2 + +- In `pk2iv`, change scaling volume for `CENT` from `V2` (incorrect) to + `V1` (#831, #832, #833) + +- Fix bug collating multiple `$OMEGA` or `$SIGMA` matrices when parsing a + model (#863) + +- Refactor how debugging information is processed when using the `recover` + argument to `mread()` (#853) + +- Fix typo in documentation for `as_cmat()`; the off-diagonals are assumed + to contain correlations (#856) + +- Wrote a `as.data.frame.matrix()` function in Rcpp; all simulation results + return from the C++ simulation code as a data frame (#857) + +- Fix bug where dynamic capture (via `mread()`) was not allowed for variables + declared in `$GLOBAL` (#868) + # mrgsolve 0.11.1 - `mrgsim()` will now periodically check for user interrupt signal so that diff --git a/R/class_build.R b/R/class_build.R index 0c13dd9ce..fcf5aeb39 100644 --- a/R/class_build.R +++ b/R/class_build.R @@ -209,20 +209,26 @@ build_output_cleanup <- function(x,build) { patt <- "^ *In function .*void _model.*:$" errr <- msub(pattern = patt, replacement = "", x = errr) x[["stderr"]] <- errr - x <- structure(x, class = "mrgsolve-build-error") + x <- structure(x, class = c("mrgsolve-build-error", "list")) x } - -build_failed <- function(out,build,mod,ignore.stdout) { - outt <- list(out) - names(outt) <- paste0("mrgsolve.build.", build[["model"]]) - options(outt) +build_failed <- function(out,build,mod,spec,ignore.stdout) { out <- build_output_cleanup(out,build) - if(build[["recover"]]) { + if(isTRUE(build[["recover"]])) { warning("returning object for debugging purposes only.") - ans <- list(build = build, mod = as.list(mod), shlib=list(compiled=FALSE), out=out) - return(structure(ans,class = "mrgsolve-build-recover")) + build <- as.list(build) + mod <- as.list(mod) + mod[["envir"]] <- as.list(mod[["envir"]]) + mod[["shlib"]][["version"]] <- unlist(mod[["shlib"]][["version"]]) + mod[["shlib"]][["compiled"]] <- FALSE + ans <- list( + out = out, + build = build, + mod = mod, + spec = spec + ) + return(structure(ans, class = c("mrgsolve-build-recover", "list"))) } if(!ignore.stdout) { msg <- divider_msg("stdout") @@ -241,22 +247,16 @@ build_failed <- function(out,build,mod,ignore.stdout) { stop("the model build step failed.",call.=FALSE) } - -build_save_output <- function(out) { - out[["date"]] <- date() - path <- file.path(tempdir(), "mrgsolve-build-result.RDS") - saveRDS(out, file=path) - return(invisible(path)) -} - -build_get_output <- function() { - file <- file.path(tempdir(),"mrgsolve-build-result.RDS") - file <- normalizePath(file,mustWork=FALSE) - if(!file.exists(file)) { - message("No build output was found.") - return(invisible(list())) +build_format_recover <- function(data, path = NULL) { + if(!requireNamespace("yaml")) { + stop("please install the yaml package to format recovery data", call.=FALSE) + } + ans <- yaml::as.yaml(data) + if(is.character(path)) { + writeLines(text = ans, con = path) + return(invisible(ans)) } - return(readRDS(file)) + ans } build_handle_127 <- function(out) { diff --git a/R/class_matlist.R b/R/class_matlist.R index 470d55991..ab8e52015 100644 --- a/R/class_matlist.R +++ b/R/class_matlist.R @@ -47,7 +47,7 @@ valid.matlist <- function(object) { } if(!x4) { - y <- which(sapply(object@data, det) < 0) + y <- which(!sapply(object@data, det) > 0) message("Problem with this matrix:") print(object@data[y]) out <- c(out, "Invalid matrix: determinant is less than 0.") diff --git a/R/funset.R b/R/funset.R index ac5d979b0..d7bcddd1c 100644 --- a/R/funset.R +++ b/R/funset.R @@ -19,10 +19,10 @@ FUNSET_ERROR__ <- ' There was a problem accessing the model shared object. - Either the model object is corrupted or the model was + Either the model object was corrupted or the model was not properly compiled and/or loaded. If the model is - not loaded, use loadso(mod) to do so. This is usually - required for parallel simuilation on a worker node that + not loaded, use `loadso(mod)` to do so. This is usually + required for parallel simulation on a worker node that was not forked (e.g. when using future::multisession). Also check mrgsolve:::funset(mod) for more information. ' diff --git a/R/matlist.R b/R/matlist.R index 52ea03b67..fff1d7cd6 100644 --- a/R/matlist.R +++ b/R/matlist.R @@ -200,7 +200,6 @@ setMethod("smat", "mrgsims", function(.x,make=FALSE,...) { as.matrix(mod(.x)@sigma) }) - #' Zero out random effects in a model object #' #' Sets all elements of the OMEGA or SIGMA matrix to zero @@ -260,7 +259,9 @@ setMethod("as.list", "matlist", function(x, ...) x@data) #' @rdname matlist #' @export setMethod("as.matrix", "matlist", function(x, ...) { - if(length(x@data)==0) return(matrix(nrow=0,ncol=0)) + if(length(x@data)==0) { + return(matrix(nrow = 0, ncol = 0)) + } SUPERMATRIX(x@data, ...) }) @@ -335,13 +336,14 @@ cumoffset <- function(x) { ##' @rdname matlist_ops ##' @export setMethod("c", "matlist", function(x,...,recursive=FALSE) { - what <- c(list(x),list(...)) - stopifnot(all(sapply(what,is.matlist))) + what <- c(list(x), list(...)) + stopifnot(all(sapply(what, is.matlist))) + what <- what[sapply(what, slot, name = "n") > 0] if(length(what)==1) return(x) - d <- lapply(what,as.matrix) - d <- setNames(d,sapply(what,names)) + d <- lapply(what, as.matrix) + d <- setNames(d, sapply(what, names)) l <- sapply(unname(what), labels) - create_matlist(d,labels=l, class=class(x)[1]) + create_matlist(d, labels = l, class = class(x)[1]) }) collapse_matrix <- function(x,class) { diff --git a/R/matrix.R b/R/matrix.R index 876188167..a8feb18de 100644 --- a/R/matrix.R +++ b/R/matrix.R @@ -1,5 +1,4 @@ -# Copyright (C) 2013 - 2019 Metrum Research Group, LLC -# +# Copyright (C) 2013 - 2021 Metrum Research Group # This file is part of mrgsolve. # # mrgsolve is free software: you can redistribute it and/or modify it @@ -15,9 +14,10 @@ # You should have received a copy of the GNU General Public License # along with mrgsolve. If not, see . - -SUPERMATRIX <- function(x,keep_names=FALSE) { - x <- .Call(`_mrgsolve_SUPERMATRIX`,x,keep_names,PACKAGE="mrgsolve") +SUPERMATRIX <- function(x, keep_names = FALSE) { + stopifnot(is.list(x)) + stopifnot(all(sapply(x, is.matrix))) + x <- .Call(`_mrgsolve_SUPERMATRIX`, x, keep_names, PACKAGE = "mrgsolve") if(nrow(x) > 0 & !keep_names) { dimnames(x) <- list(paste0(seq_len(nrow(x)), ": "), NULL) } @@ -132,7 +132,7 @@ Diag <- function(x) { ##' Create matrices from vector input ##' ##' @param ... matrix data -##' @param correlation logical; if TRUE, off diagonal elements are assumed +##' @param correlation logical; if TRUE, off-diagonal elements are assumed ##' to be correlations and converted to covariances ##' @param digits if greater than zero, matrix is passed to signif (along ##' with digits) prior to returning @@ -192,7 +192,7 @@ dmat <- function(...) { ##' @details ##' Use \code{as_dmat} to create a diagonal matrix, \code{as_bmat} ##' to create a block matrix, and \code{as_cmat} to create a block -##' matrix where diagonal elements are understood to be correlations +##' matrix where off-diagonal elements are understood to be correlations ##' rather than covariances. \code{as_cmat} uses \code{as_bmat} to ##' form the matrix and then converts off-diagonal elements to ##' covariances before returning. diff --git a/R/modspec.R b/R/modspec.R index fde6b4720..fd9e774a5 100644 --- a/R/modspec.R +++ b/R/modspec.R @@ -328,7 +328,7 @@ get_c_vars2 <- function(y,context) { if(length(regm)==0) return(data.frame()) vars <- gsub(pattern="\\s*=$", replacement = "", x = regm, perl=TRUE) vars <- token_space(vars) - ans <- as.data.frame(do.call(rbind,vars),stringsAsFactors = FALSE) + ans <- as.data.frame(do.call(rbind,vars), stringsAsFactors = FALSE) names(ans) <- c("type", "var") if(nrow(ans) > 0) ans$context <- context ans @@ -354,7 +354,12 @@ pp_defs <- function(x,context) { code <- s_pick(x, 3) list( vars = vars, code = code, n = length(x), - tab = data.frame(type = "define", var = vars, context = "global") + tab = data.frame( + type = "define", + var = vars, + context = "global", + stringsAsFactors = FALSE + ) ) } diff --git a/R/mread.R b/R/mread.R index ce6fab32c..4ec0d0b3a 100644 --- a/R/mread.R +++ b/R/mread.R @@ -48,8 +48,9 @@ NULL #' @param quiet don't print messages when compiling #' @param preclean logical; if \code{TRUE}, compilation artifacts are #' cleaned up first -#' @param recover if \code{TRUE}, an object will be returned in case -#' the model shared object fails to build +#' @param recover if \code{TRUE}, a list of build will be returned in case +#' the model shared object fails to compile; use this option to and +#' the returned object to collect information assist in debugging #' @param capture a character vector or comma-separated string of additional #' model variables to capture; these variables will be added to the capture #' list for the current call to \code{\link{mread}} only @@ -282,8 +283,7 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()), unlist(labels(sigma)), .eta, .eps, - mread.env[["move_global"]], - mread.env[["defines"]] + build[["cpp_variables"]][["var"]] ) unique(ans) } @@ -539,7 +539,7 @@ mread <- function(model, project = getOption("mrgsolve.project", getwd()), if(!comp_success) { if(ignore.stdout) message("error.\n", appendLF=FALSE) - return(build_failed(out,build,x,ignore.stdout)) + return(build_failed(out,build,x,spec,ignore.stdout)) } if(ignore.stdout) { diff --git a/R/mrgsim_q.R b/R/mrgsim_q.R index 92e0995ad..4ef16b3a9 100644 --- a/R/mrgsim_q.R +++ b/R/mrgsim_q.R @@ -157,20 +157,21 @@ mrgsim_q <- function(x, PACKAGE = "mrgsolve" )[["data"]] - dimnames(out) <- list(NULL, c("ID", tcol,x@cmtL,x@capL)) + names(out) <- c("ID", tcol, x@cmtL, x@capL) if(output=="df") { - return(as.data.frame(out)) + return(out) } + if(output=="matrix") { - return(out) + return(as.matrix(out)) } new( "mrgsims", - request=x@cmtL, - data=as.data.frame(out), - outnames=x@capL, - mod=x + request = x@cmtL, + data = out, + outnames = x@capL, + mod = x ) } diff --git a/R/mrgsolve.R b/R/mrgsolve.R index 813286766..33d4695d0 100644 --- a/R/mrgsolve.R +++ b/R/mrgsolve.R @@ -637,7 +637,7 @@ do_mrgsim <- function(x, capture.output(file=capture, append=TRUE, print(data)) capture.output(file=capture, append=TRUE, print(carry_out)) } - + out <- .Call( `_mrgsolve_DEVTRAN`, parin, @@ -654,11 +654,10 @@ do_mrgsim <- function(x, PACKAGE = "mrgsolve" ) - # out$trannames always comes back lower case in a specific order # need to rename to get back to requested case # Then, rename again for user-supplied renaming - carry.tran <- .ren.rename(rename.carry.tran,out[["trannames"]]) + carry.tran <- .ren.rename(rename.carry.tran, out[["trannames"]]) if(tad) tcol <- c(tcol,"tad") @@ -686,51 +685,50 @@ do_mrgsim <- function(x, } cnames <- new_names } - - dimnames(out[["data"]]) <- list(NULL, cnames) - - ans <- as.data.frame.matrix( - out[["data"]], - stringsAsFactors = FALSE - ) + + names(out[["data"]]) <- cnames if(do_recover_data || do_recover_idata) { if(do_recover_data) { if(!rename.recov$identical) { names(join_data) <- .ren.rename(rename.recov,names(join_data)) } - ans <- left_join(ans,join_data,by=".data_row.",suffix=c("", ".recov")) - ans$.data_row. <- NULL + out[["data"]] <- left_join(out[["data"]],join_data,by=".data_row.",suffix=c("", ".recov")) + out[["data"]][[".data_row."]] <- NULL } if(do_recover_idata) { if(!rename.recov$identical) { names(join_idata) <- .ren.rename(rename.recov,names(join_idata)) } - ans <- left_join(ans,join_idata,by="ID",suffix=c("", ".recov")) + out[["data"]] <- left_join(out[["data"]],join_idata,by="ID",suffix=c("", ".recov")) } } if(!is.null(output)) { if(output=="df") { - return(ans) + return(out[["data"]]) } if(output=="matrix") { - return(out[["data"]]) + if(!all(sapply(out[["data"]], is.numeric))) { + stop("can't return matrix because non-numeric data was found.", call.=FALSE) + } + return(data.matrix(out[["data"]])) } } new( "mrgsims", request = x@cmtL, - data=ans, - outnames=x@capL, - mod=x + data = out[["data"]], + outnames = x@capL, + mod = x ) } #' Basic, simple simulation from model object #' -#' This is just a lighter version of [mrgsim], with fewer options. See `Details`. +#' This is just a lighter version of [mrgsim()], with fewer options. +#' See `Details`. #' #' @inheritParams mrgsim #' @@ -758,7 +756,7 @@ do_mrgsim <- function(x, #' #' out <- qsim(mod,dose) #' -#' @seealso [mrgsim_q], [mrgsim], [mrgsim_variants] +#' @seealso [mrgsim_q()], [mrgsim()], [mrgsim_variants] #' #' @md #' @@ -846,19 +844,19 @@ qsim <- function(x, ) if(tad) tcol <- c(tcol,"tad") - - dimnames(out[["data"]]) <- list(NULL, c("ID", tcol, x@cmtL, x@capL)) + + names(out[["data"]]) <- c("ID", tcol, x@cmtL, x@capL) if(output=="df") { - return(as.data.frame.matrix(out[["data"]])) + return(out[["data"]]) } new( "mrgsims", - request=x@cmtL, - data=as.data.frame.matrix(out[["data"]]), - outnames=x@capL, - mod=x + request = x@cmtL, + data = out[["data"]], + outnames = x@capL, + mod = x ) } diff --git a/R/utils.R b/R/utils.R index 80bdacb82..aff79b965 100644 --- a/R/utils.R +++ b/R/utils.R @@ -570,7 +570,13 @@ system4 <- function(cmd, args=character(0), pattern, path) { files <- file.path(path, paste0("system4__",c("stdout","stderr"),"__", pattern)) x <- list(status=system2(cmd, args, stdout = files[1], stderr = files[2])) x[["stdout"]] <- readLines(files[1]) + if(length(x[["stdout"]])==0) { + x[["stdout"]] <- "stdout could not be recovered after system4 call" + } x[["stderr"]] <- readLines(files[2]) + if(length(x[["stderr"]])==0) { + x[["stderr"]] <- "stderr could not be recovered after system4 call" + } x } diff --git a/inst/include/mrgsolve.h b/inst/include/mrgsolve.h index 857d04f51..ddf91c5da 100644 --- a/inst/include/mrgsolve.h +++ b/inst/include/mrgsolve.h @@ -61,6 +61,8 @@ Rcpp::NumericMatrix EXPAND_EVENTS(const Rcpp::IntegerVector& idcol_, const Rcpp::NumericMatrix& events, const Rcpp::NumericVector& id); +Rcpp::List mat2df(Rcpp::NumericMatrix const& x); + // Rcpp::NumericMatrix recdata(Rcpp::NumericMatrix& dose, // Rcpp::NumericMatrix& obs, // Rcpp::IntegerVector& cols, diff --git a/inst/maintenance/unit/test-capture.R b/inst/maintenance/unit/test-capture.R index 618fca698..914896191 100644 --- a/inst/maintenance/unit/test-capture.R +++ b/inst/maintenance/unit/test-capture.R @@ -52,6 +52,8 @@ test_that("error if cmt in capture issue-555", { code <- ' $PARAM CL=1, V2=20,Q=30,V3=200,KA=1 +$GLOBAL +double z = 5; $MAIN double b = 2; $OMEGA 1 $OMEGA @labels OGA2 @@ -60,15 +62,15 @@ $CAPTURE CL VP = V2 ' test_that("capture via mread", { - mod <- mcode("capture-mread", code, capture = "Q,a=b,OGA2") + mod <- mcode("capture-mread", code, capture = "Q,a=b,OGA2,z") out <- outvars(mod) - expect_equal(out$capture, c("CL", "VP", "Q", "a", "OGA2")) + expect_equal(out$capture, c("CL", "VP", "Q", "a", "OGA2", "z")) expect_error( - mread("pk1",modlib(),capture = "mrgsolve"), + mread("pk1", modlib(), capture = "mrgsolve"), msg = "all requested `capture` variables must exist in the model" ) - mod <- mcode("capture-mread", code, capture="(everything)", compile=FALSE) - res <- c("CL","VP", "Q", "V3", "KA", "OGA2", "ETA_1", "ETA_2", "b") + mod <- mcode("capture-mread", code, capture="(everything)", compile = FALSE) + res <- c("CL","VP", "Q", "V3", "KA", "OGA2", "ETA_1", "ETA_2", "z", "b") expect_equal(outvars(mod)$capture, res) }) @@ -76,4 +78,3 @@ test_that("capture pp directive via mread", { mod <- modlib("irm3", capture = "STIM", compile = FALSE) expect_equal(outvars(mod)$capture, c("CP", "STIM")) }) - diff --git a/inst/maintenance/unit/test-modlib.R b/inst/maintenance/unit/test-modlib.R index 4cfea92d7..2369a3493 100644 --- a/inst/maintenance/unit/test-modlib.R +++ b/inst/maintenance/unit/test-modlib.R @@ -100,3 +100,8 @@ test_that("all modlib models", { expect_is(x[[1]],"mrgmod") expect_is(x[[2]],"mrgsims") }) + +test_that("pk2iv uses V1 to scale CENT", { + x <- readLines(file.path(modlib(), "pk2iv.cpp")) + expect_match(x, "#define CP (CENT/V1)", fixed = TRUE, all = FALSE) +}) diff --git a/inst/maintenance/unit/test-mread.R b/inst/maintenance/unit/test-mread.R index 15415547c..414c1de57 100644 --- a/inst/maintenance/unit/test-mread.R +++ b/inst/maintenance/unit/test-mread.R @@ -1,4 +1,4 @@ -# Copyright (C) 2013 - 2019 Metrum Research Group, LLC +# Copyright (C) 2013 - 2021 Metrum Research Group # # This file is part of mrgsolve. # @@ -70,7 +70,7 @@ $SIGMA @block ' -mod <- suppressWarnings(mcode("test2",code, warn=TRUE, soloc = '.')) +mod <- suppressWarnings(mcode("test2",code, warn=TRUE)) test_that("Parameters are parsed properly with mread", { expect_equal(param(mod)$CL,1) @@ -116,20 +116,18 @@ test_that("Sigma matrices are properly parsed", { expect_equivalent(mat[3,2],0.002) }) - test_that("EPS values have proper variance", { set.seed(8282) out <- mrgsim(mod,end=100000, delta=1, init = list(GUT = 0, CENT = 0)) expect_equal(round(var(out$EPS1),2),0.55) }) - test_that("Error when code is passed as project", { expect_error(suppressWarnings(mread("hey",code))) }) test_that("Model name with spaces is error", { - expect_error(mcode("ab cd", "")) + expect_error(mcode("ab cd", "")) }) test_that("Error with duplicate blocks", { @@ -137,3 +135,20 @@ test_that("Error with duplicate blocks", { expect_error(mcode("a", "$SET \n $SET",compile = FALSE)) }) +test_that("Recover data when compile fails", { + code <- '[main] double a = 2\n[param] b = 5\n' + expect_warning( + mod <- mcode("fail", code, recover = TRUE), + regexp = "returning object for debugging purposes only" + ) + expect_is(mod, "list") + expect_named(mod) + expect_true("mod" %in% names(mod)) + expect_true("build" %in% names(mod)) + expect_true("out" %in% names(mod)) + expect_true("spec" %in% names(mod)) + recov <- mrgsolve:::build_format_recover(mod) + expect_is(recov, "character") + recov_list <- yaml::yaml.load(recov) + expect_is(recov_list, "list") +}) diff --git a/inst/models/pk2iv.cpp b/inst/models/pk2iv.cpp index c5291b3dc..e8d0a20bd 100644 --- a/inst/models/pk2iv.cpp +++ b/inst/models/pk2iv.cpp @@ -9,10 +9,9 @@ CENT : Central compartment (mass) PERIPH : Peripheral compartment (mass) $GLOBAL -#define CP (CENT/V2) +#define CP (CENT/V1) $PKMODEL ncmt = 2, depot = FALSE $CAPTURE @annotated CP : Plasma concentration (mass/time) - diff --git a/man/matrix_converters.Rd b/man/matrix_converters.Rd index 94b818ae4..22939bb8e 100644 --- a/man/matrix_converters.Rd +++ b/man/matrix_converters.Rd @@ -58,7 +58,7 @@ matrix (\code{c}). \details{ Use \code{as_dmat} to create a diagonal matrix, \code{as_bmat} to create a block matrix, and \code{as_cmat} to create a block -matrix where diagonal elements are understood to be correlations +matrix where off-diagonal elements are understood to be correlations rather than covariances. \code{as_cmat} uses \code{as_bmat} to form the matrix and then converts off-diagonal elements to covariances before returning. diff --git a/man/matrix_helpers.Rd b/man/matrix_helpers.Rd index 2fbc08103..9759c037c 100644 --- a/man/matrix_helpers.Rd +++ b/man/matrix_helpers.Rd @@ -16,7 +16,7 @@ dmat(...) \arguments{ \item{...}{matrix data} -\item{correlation}{logical; if TRUE, off diagonal elements are assumed +\item{correlation}{logical; if TRUE, off-diagonal elements are assumed to be correlations and converted to covariances} \item{digits}{if greater than zero, matrix is passed to signif (along diff --git a/man/mread.Rd b/man/mread.Rd index aab5223d4..4f8a2503b 100644 --- a/man/mread.Rd +++ b/man/mread.Rd @@ -81,8 +81,9 @@ list for the current call to \code{\link{mread}} only} \item{preclean}{logical; if \code{TRUE}, compilation artifacts are cleaned up first} -\item{recover}{if \code{TRUE}, an object will be returned in case -the model shared object fails to build} +\item{recover}{if \code{TRUE}, a list of build will be returned in case +the model shared object fails to compile; use this option to and +the returned object to collect information assist in debugging} \item{...}{passed to \code{\link[mrgsolve]{update}}; also arguments passed to mread from \code{\link{mread_cache}}.} diff --git a/man/qsim.Rd b/man/qsim.Rd index c0382c218..2ece85726 100644 --- a/man/qsim.Rd +++ b/man/qsim.Rd @@ -64,7 +64,8 @@ default output object; other options include \code{df} (for data.frame) or \code{matrix}} } \description{ -This is just a lighter version of \link{mrgsim}, with fewer options. See \code{Details}. +This is just a lighter version of \code{\link[=mrgsim]{mrgsim()}}, with fewer options. +See \code{Details}. } \details{ There is no pipeline interface for this function; all configuration options @@ -84,5 +85,5 @@ out <- qsim(mod,dose) } \seealso{ -\link{mrgsim_q}, \link{mrgsim}, \link{mrgsim_variants} +\code{\link[=mrgsim_q]{mrgsim_q()}}, \code{\link[=mrgsim]{mrgsim()}}, \link{mrgsim_variants} } diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 7b6b645d7..e64d5bdec 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -7,6 +7,11 @@ using namespace Rcpp; +#ifdef RCPP_USE_GLOBAL_ROSTREAM +Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); +Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); +#endif + // DEVTRAN Rcpp::List DEVTRAN(const Rcpp::List parin, const Rcpp::NumericVector& inpar, const Rcpp::CharacterVector& parnames, const Rcpp::NumericVector& init, Rcpp::CharacterVector& cmtnames, const Rcpp::IntegerVector& capture, const Rcpp::List& funs, const Rcpp::NumericMatrix& data, const Rcpp::NumericMatrix& idata, Rcpp::NumericMatrix& OMEGA, Rcpp::NumericMatrix& SIGMA, Rcpp::Environment envir); RcppExport SEXP _mrgsolve_DEVTRAN(SEXP parinSEXP, SEXP inparSEXP, SEXP parnamesSEXP, SEXP initSEXP, SEXP cmtnamesSEXP, SEXP captureSEXP, SEXP funsSEXP, SEXP dataSEXP, SEXP idataSEXP, SEXP OMEGASEXP, SEXP SIGMASEXP, SEXP envirSEXP) { diff --git a/src/devtran.cpp b/src/devtran.cpp index 8c8dfb58c..1458f67e7 100644 --- a/src/devtran.cpp +++ b/src/devtran.cpp @@ -640,6 +640,6 @@ Rcpp::List DEVTRAN(const Rcpp::List parin, if((tscale != 1) && (tscale >= 0)) { ans(Rcpp::_,1) = ans(Rcpp::_,1) * tscale; } - return Rcpp::List::create(Rcpp::Named("data") = ans, + return Rcpp::List::create(Rcpp::Named("data") = mat2df(ans), Rcpp::Named("trannames") = tran_names); } diff --git a/src/mrgsolve.cpp b/src/mrgsolve.cpp index 42cd032da..3e92f1260 100644 --- a/src/mrgsolve.cpp +++ b/src/mrgsolve.cpp @@ -150,6 +150,10 @@ void dcorr(Rcpp::NumericMatrix& x) { //[[Rcpp::export]] Rcpp::NumericMatrix SUPERMATRIX(const Rcpp::List& a, bool keep_names) { + if(a.size()==1) { + return a[0]; + } + int j,k; Rcpp::NumericMatrix mat; @@ -388,6 +392,19 @@ Rcpp::List EXPAND_OBSERVATIONS( Rcpp::Named("index") = index); } +Rcpp::List mat2df(Rcpp::NumericMatrix const& x) { + Rcpp::List ret(x.ncol()); + for(int i = 0; i < x.ncol(); ++i) { + ret[i] = x(Rcpp::_,i); + } + Rcpp::IntegerVector rn(2); + rn[0] = NA_INTEGER; + rn[1] = x.nrow()*-1; + ret.attr("class") = "data.frame"; + ret.attr("row.names") = rn; + return ret; +} + #endif diff --git a/tests/testthat/test-carry_out.R b/tests/testthat/test-carry_out.R index d18de26af..3fd3b68ba 100644 --- a/tests/testthat/test-carry_out.R +++ b/tests/testthat/test-carry_out.R @@ -106,3 +106,12 @@ test_that("recover input idata-set items", { expect_is(out$b,"character") expect_error(mrgsim_e(mod,idata,recover="b",carry_out="b")) }) + +test_that("error to request matrix and recover character data", { + data <- expand.ev(amt = 100, group = "A") + expect_is(mrgsim(mod, data, recover = "group"), "mrgsims") + expect_error( + mrgsim(mod, data, recover = "group", output = "matrix"), + msg = "can't return matrix because non-numeric data was found" + ) +}) diff --git a/tests/testthat/test-matlist.R b/tests/testthat/test-matlist.R index dde2031d8..273792b5b 100644 --- a/tests/testthat/test-matlist.R +++ b/tests/testthat/test-matlist.R @@ -49,10 +49,10 @@ test_that("Indexing SIGMA matrix elements", { expect_equivalent(as.matrix(smat(mod))[3,3],0.3) }) -o1 <- - omat(diag(c(1.1, 2.2, 3.3)), - diag(c(4.4, 5.5, 6.6)), - matrix(seq(91,99),nrow=3, byrow=TRUE)) +a <- diag(c(1.1, 2.2, 3.3)) +b <- diag(c(4.4, 5.5, 6.6)) +c <- matrix(seq(91,99),nrow = 3, byrow = TRUE) +o1 <- omat(a,b,c) mat <- as.matrix(o1) diff --git a/tests/testthat/test-matrix.R b/tests/testthat/test-matrix.R index c810e5f6e..81b1642db 100644 --- a/tests/testthat/test-matrix.R +++ b/tests/testthat/test-matrix.R @@ -31,7 +31,22 @@ test_that("Testing modMATRIX", { expect_equal(modMATRIX("0 0 0", use=FALSE), matrix(0,nrow=3,ncol=3)) }) - - - - +test_that("SUPERMATRIX", { + ml <- list(matrix(1, 2, 2), matrix(3, 4, 4)) + dimnames(ml[[1]]) <- list(c("a", "b"), c("A", "B")) + ans <- mrgsolve:::SUPERMATRIX(ml) + expect_is(ans, "matrix") + expect_equal(dim(ans), c(6, 6)) + ml$a <- "a" + expect_error(mrgsolve:::SUPERMATRIX(ml), msg = "is not TRUE") + expect_error(mrgsolve:::SUPERMATRIX(ml[[1]]), msg = "is not TRUE") + ml$a <- NULL + ans <- mrgsolve:::SUPERMATRIX(ml[2]) + expect_identical(unname(ml[[2]]),unname(ans)) + ans <- mrgsolve:::SUPERMATRIX(ml[1], keep_names = TRUE) + expect_identical(ans, ml[[1]]) + ans1 <- mrgsolve:::SUPERMATRIX(list()) + expect_identical(ans1, matrix(0, nrow = 0, ncol = 0)) + ans2 <- mrgsolve:::SUPERMATRIX(omat()@data) + expect_identical(ans1, ans2) +})