Nothing
#' Is the dataset a memory summary?'
#'
#' @param dat data set
#' @return TRUE if the dataset is an \code{rxMemSummary}, FALSE otherwise
#' @noRd
#' @author Matthew L. Fidler
.isRxMemSummary <- function(dat) {
inherits(dat, "rxMemSummary") ||
(is.data.frame(dat) &&
all(c("nobs", "ndoses") %in% names(dat)) &&
!("evid" %in% names(dat)))
}
#' Create a per-ID event summary for memory estimation
#'
#' @param id Integer or character vector of subject IDs (optional).
#' @param nobs Integer vector of observation counts per ID.
#' @param ndoses Integer vector of dose event counts per ID.
#' @return A data.frame with class \code{"rxMemSummary"}.
#' @examples
#'
#' # Three subjects with known observation and dose counts
#' rxMemSummary(nobs = c(48L, 96L, 48L), ndoses = c(7L, 14L, 7L))
#'
#' # Explicit subject IDs
#' rxMemSummary(nobs = c(10L, 20L), ndoses = c(5L, 5L), id = c(101L, 102L))
#' @export
rxMemSummary <- function(nobs, ndoses, id = seq_along(nobs)) {
.ret <- data.frame(id = id, nobs = as.integer(nobs), ndoses = as.integer(ndoses))
class(.ret) <- c("rxMemSummary", "data.frame")
.ret
}
#' Summarize data for memory estimation from an event-table dataset
#'
#' It will be sent rxMemSummarizeDat()
#'
#' @param dat data to summarize
#' @return An \code{rxMemSummary} data.frame with columns \code{id}, \code{nobs}, and
#' \code{ndoses}.
#' @noRd
#' @author Matthew L. Fidler
.rxMemSummarizeDat <- function(dat) {
evid <- . <- NULL # nolint
.groups <- attr(dat, "rxHomGroups", exact = TRUE)
if (is.data.frame(dat) && !is.null(.groups) && "evid" %in% names(dat)) {
.idCol <- grep("^id$", names(dat), ignore.case = TRUE, value = TRUE)[1]
if (!is.na(.idCol)) {
.repIds <- suppressWarnings(as.integer(dat[[.idCol]]))
if (!anyNA(.repIds)) {
.ids <- vector("list", 0L)
.nobs <- vector("list", 0L)
.ndoses <- vector("list", 0L)
for (.i in seq_along(.groups)) {
.groupIds <- .groups[[.i]]
if (length(.groupIds) == 0L) next
.rows <- .repIds == .i
.nobsGroup <- sum(dat$evid[.rows] == 0L, na.rm = TRUE)
.ndosesGroup <- sum(dat$evid[.rows] != 0L, na.rm = TRUE)
.ids[[length(.ids) + 1L]] <- .groupIds
.nobs[[length(.nobs) + 1L]] <- rep.int(.nobsGroup, length(.groupIds))
.ndoses[[length(.ndoses) + 1L]] <- rep.int(.ndosesGroup, length(.groupIds))
}
if (length(.ids) > 0L) {
return(rxMemSummary(
id = unlist(.ids, use.names = FALSE),
nobs = unlist(.nobs, use.names = FALSE),
ndoses = unlist(.ndoses, use.names = FALSE)
))
}
}
}
}
if (is.rxEt(dat)) {
.groups <- .etGetGroups(.rxEtEnv(dat))
if (length(.groups) == 0L) {
return(rxMemSummary(nobs = integer(0), ndoses = integer(0), id = integer(0)))
}
.ids <- vector("list", length(.groups))
.nobs <- vector("list", length(.groups))
.ndoses <- vector("list", length(.groups))
for (.i in seq_along(.groups)) {
.g <- .groups[[.i]]
.ids[[.i]] <- as.integer(.g$ids)
.nobs[[.i]] <- rep.int(sum(.g$data$evid == 0L, na.rm = TRUE), length(.g$ids))
.ndoses[[.i]] <- rep.int(sum(.g$data$evid != 0L, na.rm = TRUE), length(.g$ids))
}
return(rxMemSummary(
id = unlist(.ids, use.names = FALSE),
nobs = unlist(.nobs, use.names = FALSE),
ndoses = unlist(.ndoses, use.names = FALSE)
))
}
.dt <- data.table::as.data.table(dat)
.idCol <- grep("^id$", names(.dt), ignore.case = TRUE, value = TRUE)[1]
if (is.na(.idCol)) {
.ret <- rxMemSummary(
nobs = sum(.dt[["evid"]] == 0L, na.rm = TRUE),
ndoses = sum(.dt[["evid"]] != 0L, na.rm = TRUE)
)
} else {
.agg <- .dt[, list(nobs = sum(evid == 0L, na.rm = TRUE),
ndoses = sum(evid != 0L, na.rm = TRUE)),
by = .idCol]
.ret <- rxMemSummary(id = .agg[[.idCol]], nobs = .agg$nobs, ndoses = .agg$ndoses)
}
.ret
}
.rxMemSolveLayoutStats <- function(dat, control = NULL, model = NULL) {
.solveDat <- NULL
.modelParams <- character(0)
if (!is.null(model)) {
.modelParams <- rxModelVars(model)$params
}
if (is.rxEt(dat)) {
.solveInput <- dat
if (!is.null(control) && !is.null(control$iCov) &&
length(.etGroups(.rxEtEnv(dat))) > 0L) {
.groupedSolve <- .etGroupedSolveDataICov(dat, control$iCov,
keep = control$keep,
modelParams = .modelParams)
if (!is.null(.groupedSolve)) {
.solveInput <- .groupedSolve$events
}
}
.solveDat <- .etPrepareSolveEvents(.solveInput, control)
} else if (is.data.frame(dat) && !is.null(attr(dat, "rxHomGroups", exact = TRUE))) {
if (!is.null(control) && !is.null(control$iCov)) {
.groupedSolve <- .etGroupedSolveDataFrameICov(dat, control$iCov,
keep = control$keep,
modelParams = .modelParams)
if (!is.null(.groupedSolve)) {
dat <- .groupedSolve$events
}
}
.solveDat <- .etPrepareGroupedSolveData(dat, control)
} else if (is.data.frame(dat) && "evid" %in% names(dat)) {
.solveDat <- .etFixCmtForSolve(dat)
if (nrow(.solveDat) > 0L &&
all(.solveDat$evid != 0L, na.rm = TRUE) &&
!is.null(control) &&
any(vapply(control[c("from", "to", "by", "length.out")], Negate(is.null), logical(1)))) {
.solveDat <- .etAddSolveObsRows(.solveDat, .etSolveObsTimes(.solveDat, control))
}
}
if (is.null(.solveDat)) {
return(NULL)
}
.solveNallTotal <- nrow(.solveDat)
if (.solveNallTotal == 0L) {
return(list(nallTotal = 0L, maxAllTimes = 0L))
}
.solveMaxAllTimes <- if ("id" %in% names(.solveDat)) {
max(tabulate(match(.solveDat$id, unique(.solveDat$id))))
} else {
.solveNallTotal
}
list(
nallTotal = as.integer(.solveNallTotal),
maxAllTimes = as.integer(.solveMaxAllTimes)
)
}
.rxMemResolveInput <- function(dat, control = NULL) {
if (inherits(dat, "rxSolve")) {
.env <- attr(class(dat), ".rxode2.env", exact = TRUE)
if (is.environment(.env) && exists(".args.events", envir = .env, inherits = FALSE)) {
.events <- get(".args.events", envir = .env, inherits = FALSE)
if (is.null(control) && exists(".args", envir = .env, inherits = FALSE)) {
control <- get(".args", envir = .env, inherits = FALSE)
}
return(list(dat = .events, control = control))
}
}
if (is.character(dat) && length(dat) == 1L && .rxIsSerializedSolvePath(dat)) {
.bundle <- .rxReadStateBundle(dat)
if (is.null(.bundle$events)) {
stop(sprintf("Serialized solve '%s' does not contain event data for memory estimation", dat),
call. = FALSE)
}
return(list(dat = .bundle$events, control = control))
}
if (is.list(dat) && !is.data.frame(dat) && !is.null(dat$events)) {
return(list(dat = dat$events, control = control))
}
list(dat = dat, control = control)
}
#' Extract model dimensions from model variables
#'
#'
#' @param model model variables to extract dimensions from
#'
#' @return A list with elements \code{neq}, \code{stateSize},
#' \code{nlhs}, \code{npars}, \code{extraCmt}, \code{linB},
#' \code{nMtime}, \code{nLlik}, and \code{nIndSim}. All are used to
#' calculate memory useage.
#' @noRd
#' @author Matthew L. Fidler
.rxMemExtractModel <- function(model) {
.mv <- rxModelVars(model)
.flags <- .mv[["flags"]]
list(
neq = length(.mv[["state"]]),
stateSize = length(.mv[["state"]]),
nlhs = length(.mv[["lhs"]]),
npars = length(.mv[["params"]]),
extraCmt = as.integer(.mv[["extraCmt"]]),
linB = as.integer(.flags["linB"]),
nMtime = as.integer(.mv[["nMtime"]]),
nLlik = as.integer(.flags["nLlik"]),
nIndSim = as.integer(.flags["nIndSim"])
)
}
#' Extract memory-relevant options from an rxControl object
#'
#' @param ctrl An \code{rxControl} object.
#' @return A list with \code{cores}, \code{nsim}, \code{neta}, \code{neps},
#' \code{nLlikAlloc}, and \code{nSubEff} (effective subject count;
#' 0 means use the data-derived count).
#' @noRd
#' @author Matthew L. Fidler
.rxMemExtractControl <- function(ctrl) {
.cores <- as.integer(ctrl$cores)
if (.cores <= 0L) .cores <- getRxThreads()
.nsim <- if (is.null(ctrl$nsim)) 1L else as.integer(ctrl$nsim)
.neta <- if (is.matrix(ctrl$omega)) nrow(ctrl$omega) else 0L
.neps <- if (is.matrix(ctrl$sigma)) nrow(ctrl$sigma) else 0L
.nSub <- if (is.null(ctrl$nSub)) 1L else as.integer(ctrl$nSub)
.nStud <- if (is.null(ctrl$nStud)) 1L else as.integer(ctrl$nStud)
list(
cores = .cores,
nsim = .nsim,
neta = as.integer(.neta),
neps = as.integer(.neps),
nLlikAlloc = ctrl$nLlikAlloc,
nSub = .nSub,
nStud = .nStud
)
}
#' Detect total physical RAM in bytes
#'
#' @return Numeric bytes of total RAM, or \code{NA_real_} if unavailable.
#' @noRd
#' @author Matthew L. Fidler
.getRamBytes <- function() {
.ram <- tryCatch(.Call(`_rxode2_rxRamBytes_`)[["total"]],
error = function(e) NA_real_)
if (!is.na(.ram) && .ram > 0) return(.ram)
NA_real_
}
.rxMemEstimateOutputData <- function(dat, summary, control, neq, nlhs, ncov,
nsim, nsub, nobsTotal, nallTotal) {
.addCov <- TRUE
.addDosing <- FALSE
.subsetNonmem <- TRUE
.returnType <- "rxSolve"
.nkeep <- 0L
.ncov0 <- 0L
.hasEvid2 <- FALSE
.ptrBytes <- .Machine$sizeof.pointer
if (!is.null(control)) {
if (!is.null(control$addCov)) {
.addCov <- isTRUE(control$addCov)
}
if ("addDosing" %in% names(control)) {
.addDosing <- control$addDosing
}
if (!is.null(control$subsetNonmem)) {
.subsetNonmem <- isTRUE(control$subsetNonmem)
}
if (!is.null(control$returnType) && length(control$returnType) > 0L) {
.returnType <- control$returnType[[1L]]
}
if (!is.null(control$keep)) {
.nkeep <- length(control$keep)
}
if (!is.null(control$iCov)) {
.ncov0 <- ncol(control$iCov)
}
}
if (is.data.frame(dat) && "evid" %in% names(dat)) {
.hasEvid2 <- any(dat$evid == 2L, na.rm = TRUE)
}
.doDose0 <- 0L
if (is.null(.addDosing)) {
.doDose0 <- -1L
} else if (length(.addDosing) > 0L && isTRUE(is.na(.addDosing[[1L]]))) {
.doDose0 <- 1L
} else if (length(.addDosing) > 0L && isTRUE(.addDosing[[1L]])) {
.doDose0 <- if (.subsetNonmem) 3L else 2L
}
.doDose <- as.integer(.doDose0 > 0L)
.nmevid <- as.integer(.doDose0 %in% c(2L, 3L))
.doTBS <- as.integer(identical(.returnType, "data.frame.TBS"))
.nidCols <- as.integer(nsub > 1L) + as.integer(nsim > 1L)
.nevid2col <- as.integer(.doDose0 == 0L && .hasEvid2)
.nr <- if (.doDose0 > 0L) {
nallTotal * nsim
} else {
nobsTotal * nsim
}
.nIntCols <- .nidCols + .nevid2col + .doDose + 2L * .nmevid
.nDblCols <- 1L + as.integer(neq) + as.integer(nlhs) +
.doDose + 3L * .nmevid + .doTBS * 4L +
as.integer(.addCov) * (as.integer(ncov) + .ncov0)
.keepBytes <- 0
if (.nkeep > 0L) {
.keepNames <- control$keep
.keepBytes <- sum(vapply(.keepNames, function(.nm) {
if (!is.data.frame(dat) || !(.nm %in% names(dat))) {
return(.nr * 8)
}
.col <- dat[[.nm]]
if (is.character(.col)) {
.nr * .ptrBytes
} else if (is.logical(.col) || is.factor(.col) || is.integer(.col)) {
.nr * 4
} else {
.nr * 8
}
}, numeric(1)))
}
.dataBytes <- .nr * (.nIntCols * 4 + .nDblCols * 8) + .keepBytes
.listBytes <- (.nIntCols + .nDblCols + .nkeep) * .ptrBytes * 2
.dataBytes + .listBytes
}
#' Detect currently available memory for allocation in bytes
#'
#' Uses the allocator preflight estimate (\code{rxAvailableMemoryBytes()}),
#' which may exceed physical RAM (page file on Windows, swap on Linux).
#'
#' @return Numeric bytes of available memory, or \code{NA_real_} if
#' unavailable.
#' @noRd
#' @author Matthew L. Fidler
.getFreeRamBytes <- function() {
.free <- tryCatch(.Call(`_rxode2_rxRamBytes_`)[["free"]],
error = function(e) NA_real_)
if (!is.na(.free) && .free > 0) return(.free)
NA_real_
}
#' Estimate memory required by rxSolve() for a given dataset and model
#'
#' Accepts either a pre-summarized per-ID table (an \code{\link{rxMemSummary}}
#' or any data.frame with \code{nobs} and \code{ndoses} columns) or a full
#' event-table data.frame with an \code{evid} column. Model dimensions can
#' be supplied via a compiled rxode2 model object or overridden individually.
#'
#' The byte counts are computed by \code{rxMemoryComponents_()} which calls
#' the same \code{rxFillMemLayout()} used by the real allocator, so any
#' change to the allocation formulas propagates here automatically.
#'
#' @param dat A \code{\link{rxMemSummary}}, a data.frame with
#' \code{nobs}/\code{ndoses} columns, or a full event-table
#' data.frame with an \code{evid} column. This can also be a
#' serialized solve state file path, a solve state bundle list
#' containing an \code{events} element, or an \code{rxSolve}
#' object (using its stored solve events).
#' @param model Optional rxode2 model object. When supplied,
#' \code{neq}, \code{nlhs}, \code{npars}, \code{extraCmt},
#' \code{linB}, \code{nMtime}, \code{nLlik}, and \code{nIndSim} are
#' extracted automatically.
#' @param control Optional \code{\link{rxControl}} object. When
#' supplied, \code{cores}, \code{nsim}, \code{neta} (from
#' \code{omega}), \code{neps} (from \code{sigma}), and \code{nLlik}
#' (adjusted by \code{nLlikAlloc}) are overridden automatically.
#' @param neq Number of ODE states.
#' @param stateSize Effective \code{state.size()} seen by the solver.
#' Equals \code{neq} for pure ODE models; may differ for linCmt-only
#' models. Defaults to \code{neq}.
#' @param nlhs Number of LHS (calculated) output variables.
#' @param npars Number of model parameters (drives \code{gpars} size).
#' @param neta Number of random effects (etas).
#' @param neps Number of residual-error levels (epsilons).
#' @param ncov Number of time-varying covariates.
#' @param nsim Number of simulations.
#' @param cores Number of parallel OMP threads.
#' @param nMtime Number of model measurement times.
#' @param extraCmt Extra compartments (0, 1 = depot, 2 =
#' depot+central).
#' @param linB \code{TRUE}/\code{1} if using a linear-compartment
#' model.
#' @param nLlik Number of log-likelihood terms (FOCEi use).
#' @param nIndSim Per-individual simulation count. Defaults to
#' \code{neta + neps} when not supplied explicitly.
#' @param numLinSens Number of linear sensitivity parameters (FOCEi +
#' linCmt).
#' @param numLin Number of linear compartment terms (FOCEi + linCmt).
#' @return A named list of class \code{"rxMemoryEstimate"} whose
#' elements are raw byte counts plus \code{outputData},
#' \code{ramBytes}, \code{freeRamBytes}, \code{total},
#' \code{sizeofInd}, and \code{rxLlikSaveSize}.
#' @export
#'
#' @examples
#'
#' \donttest{
#'
#' mod <- rxode2::rxode2({
#' d/dt(depot) <- -ka * depot
#' d/dt(center) <- ka * depot - cl / v * center
#' cp <- center / v
#' })
#'
#' ev <- rxode2::et(amt = 100, ii = 24, until = 168) |>
#' rxode2::et(seq(0, 168, by = 1))
#'
#' # Basic estimate from event table and model
#' rxMemoryEstimate(as.data.frame(ev), model = mod)
#'
#' # With rxControl: population simulation with omega and 4 cores
#' ctrl <- rxode2::rxControl(
#' cores = 4L,
#' omega = lotri::lotri(eta.ka ~ 0.09, eta.cl ~ 0.04)
#' )
#' rxMemoryEstimate(as.data.frame(ev), model = mod, control = ctrl)
#'
#' }
rxMemoryEstimate <- function(
dat,
model = NULL,
control = NULL,
neq = 1L,
stateSize = neq,
nlhs = 0L,
npars = neq,
neta = 0L,
neps = 0L,
ncov = 0L,
nsim = 1L,
cores = 1L,
nMtime = 0L,
extraCmt = 0L,
linB = FALSE,
nLlik = 0L,
nIndSim = NULL,
numLinSens = 0L,
numLin = 0L) {
.resolved <- .rxMemResolveInput(dat, control)
dat <- .resolved$dat
control <- .resolved$control
if (.isRxMemSummary(dat)) {
.summary <- dat
if (!inherits(.summary, "rxMemSummary")) {
class(.summary) <- c("rxMemSummary", "data.frame")
}
} else if (is.data.frame(dat) && "evid" %in% names(dat)) {
.summary <- .rxMemSummarizeDat(dat)
} else {
stop("'dat' must be an rxMemSummary, a data.frame with 'nobs'/'ndoses' ",
"columns, or a data.frame with an 'evid' column")
}
if (!is.null(model)) {
.mi <- .rxMemExtractModel(model)
neq <- .mi$neq
stateSize <- .mi$stateSize
nlhs <- .mi$nlhs
npars <- .mi$npars
extraCmt <- .mi$extraCmt
linB <- .mi$linB
nMtime <- .mi$nMtime
nLlik <- .mi$nLlik
if (is.null(nIndSim)) nIndSim <- .mi$nIndSim
}
.ci <- NULL
if (!is.null(control)) {
.ci <- .rxMemExtractControl(control)
cores <- .ci$cores
nsim <- .ci$nsim
if (.ci$neta > 0L) neta <- .ci$neta
if (.ci$neps > 0L) neps <- .ci$neps
if (!is.null(.ci$nLlikAlloc)) nLlik <- max(nLlik, as.integer(.ci$nLlikAlloc))
}
if (cores <= 0L) {
cores <- 1L
}
if (is.null(nIndSim)) nIndSim <- neta + neps
.nallVec <- .summary$nobs + .summary$ndoses
.nsub <- nrow(.summary)
.nobsTotal <- sum(.summary$nobs)
.nallTotal <- sum(.nallVec)
.maxAllTimes <- max(.nallVec)
.solveStats <- .rxMemSolveLayoutStats(dat, control, model)
.solveNallTotal <- .nallTotal
.solveMaxAllTimes <- .maxAllTimes
if (!is.null(.ci) && (.ci$nSub > 1L || .ci$nStud > 1L)) {
.subPerStudy <- if (.ci$nSub > 1L) .ci$nSub else .nsub
.meanObsTimes <- .nobsTotal / .nsub
.meanAllTimes <- .nallTotal / .nsub
.nsub <- .subPerStudy * .ci$nStud
.nobsTotal <- .meanObsTimes * .nsub
.nallTotal <- .meanAllTimes * .nsub
} else if (!is.null(.solveStats)) {
.solveNallTotal <- .solveStats$nallTotal
.solveMaxAllTimes <- .solveStats$maxAllTimes
}
.raw <- rxMemoryComponents_(
neq = as.integer(neq),
stateSize = as.integer(stateSize),
nlhs = as.integer(nlhs),
npars = as.integer(npars),
neta = as.integer(neta),
neps = as.integer(neps),
ncov = as.integer(ncov),
nsim = as.integer(nsim),
cores = as.integer(cores),
nMtime = as.integer(nMtime),
extraCmt = as.integer(extraCmt),
linB = as.integer(linB),
nLlik = as.integer(nLlik),
nIndSim = as.integer(nIndSim),
numLinSens = as.integer(numLinSens),
numLin = as.integer(numLin),
nsub = as.integer(.nsub),
nallTotal = as.double(.solveNallTotal),
maxAllTimes = as.double(.solveMaxAllTimes)
)
.meta <- c("sizeofInd", "rxLlikSaveSize")
.sizes <- .raw[!names(.raw) %in% .meta]
.outputData <- .rxMemEstimateOutputData(
dat = dat,
summary = .summary,
control = control,
neq = neq,
nlhs = nlhs,
ncov = ncov,
nsim = nsim,
nsub = .nsub,
nobsTotal = .nobsTotal,
nallTotal = .nallTotal
)
.sizes <- c(.sizes, outputData = .outputData)
.wrapped <- lapply(.sizes, function(bytes) {
structure(bytes, class = "rxRawBytes")
})
.total <- Reduce(`+`, .wrapped)
.ret <- c(list(total = .total), .wrapped,
list(sizeofInd = .raw[["sizeofInd"]],
rxLlikSaveSize = .raw[["rxLlikSaveSize"]],
ramBytes = .getRamBytes(),
freeRamBytes = .getFreeRamBytes(),
effectiveSubs = .nsub))
class(.ret) <- "rxMemoryEstimate"
attr(.ret, "summary") <- .summary
.ret
}
.rxOomChunkSize <- function(model, summary, control, safetyFactor = 0.80) {
.est <- rxMemoryEstimate(summary, model = model, control = control)
if (is.na(.est$freeRamBytes) || .est$freeRamBytes <= 0 || .est$effectiveSubs <= 0) {
return(1L)
}
.memPerSub <- as.numeric(.est$total) / max(1L, .est$effectiveSubs)
.avail <- .est$freeRamBytes * safetyFactor
max(1L, as.integer(floor(.avail / .memPerSub)))
}
#' @export
print.rxMemoryEstimate <- function(x, ...) {
.meta <- c("total", "sizeofInd", "rxLlikSaveSize", "ramBytes", "freeRamBytes", "effectiveSubs")
.comps <- x[!names(x) %in% .meta]
.fmtSize <- function(v) {
.b <- if (is.numeric(v)) v else unclass(v)
if (.b >= 1e9) sprintf("%.2f GB", .b / 1e9)
else if (.b >= 1e6) sprintf("%.2f MB", .b / 1e6)
else if (.b >= 1e3) sprintf("%.2f KB", .b / 1e3)
else sprintf("%.0f B", .b)
}
cat("rxSolve() memory estimate\n")
cat(sprintf(" Total: %s\n\n", .fmtSize(x$total)))
.bytes <- vapply(.comps, as.numeric, numeric(1))
.ord <- order(.bytes, decreasing = TRUE)
.nm <- names(.comps)[.ord]
.sz <- .bytes[.ord]
.tot <- sum(.sz)
.labels <- c(
gsolve = "gsolve (double buffer total)",
gsolve_n0 = " |_ n0: ODE state output matrix",
gon = "gon (int buffer)",
gall_times = "gall_times (event time/dv/amt/ii/limit)",
gevid = "gevid (event IDs)",
gcov = "gcov (covariates)",
gpars = "gpars (parameters)",
gomega = "gomega (omega matrix)",
gsigma = "gsigma (sigma matrix)",
gall_timesS = "gall_timesS (extra sim times)",
ordId = "ordId (subject ordering)",
gInfusionRate = "gInfusionRate (per-thread infusion)",
inds_global = "inds_global (per-subject structs)",
outputData = "outputData (estimated returned data)"
)
for (.i in seq_along(.nm)) {
.n <- .nm[.i]
.lab <- if (!is.na(.labels[.n])) .labels[.n] else .n
.pct <- if (.tot > 0) sprintf(" (%4.1f%%)", 100 * .sz[.i] / .tot) else ""
cat(sprintf(" %-42s %s%s\n", .lab, .fmtSize(.comps[[.n]]), .pct))
}
.nsub <- if (!is.null(x$effectiveSubs)) as.integer(x$effectiveSubs) else nrow(attr(x, "summary"))
cat(sprintf("\n Subjects: %d | sizeof(rx_solving_options_ind): %d B",
.nsub, as.integer(x$sizeofInd)))
.ramBytes <- x$ramBytes
.freeRamBytes <- x$freeRamBytes
if (!is.null(.ramBytes) && !is.na(.ramBytes) && .ramBytes > 0) {
.totalBytes <- as.numeric(x$total)
cat(sprintf(" | %.1f%% of RAM (%s)",
100 * .totalBytes / .ramBytes, .fmtSize(.ramBytes)))
if (!is.null(.freeRamBytes) && !is.na(.freeRamBytes) && .freeRamBytes > 0) {
cat(sprintf(" | %.1f%% of available memory (%s available)",
100 * .totalBytes / .freeRamBytes, .fmtSize(.freeRamBytes)))
}
cat("\n")
} else {
cat("\n")
}
invisible(x)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.