Nothing
## |
## | *Time classes*
## |
## | This file is part of the R package rpact:
## | Confirmatory Adaptive Clinical Trial Design and Analysis
## |
## | Author: Gernot Wassmer, PhD, and Friedrich Pahlke, PhD
## | Licensed under "GNU Lesser General Public License" version 3
## | License text can be found here: https://www.r-project.org/Licenses/LGPL-3
## |
## | RPACT company website: https://www.rpact.com
## | rpact package website: https://www.rpact.org
## |
## | Contact us for information about our services: info@rpact.com
## |
## | File version: $Revision: 8624 $
## | Last changed: $Date: 2025-03-21 13:24:59 +0100 (Fr, 21 Mrz 2025) $
## | Last changed by: $Author: pahlke $
## |
#' @include f_design_general_utilities.R
NULL
C_REGEXP_GREATER_OR_EQUAL <- ">= ?"
C_REGEXP_SMALLER <- "< ?"
C_REGEXP_SMALLER_OR_EQUAL <- "<= ?"
C_REGEXP_DECIMAL_NUMBER <- "\\d*(\\.{1}\\d*)?"
TimeDefinition <- R6::R6Class("TimeDefinition",
inherit = ParameterSet,
public = list(
initialize = function(...) {
super$initialize()
},
.getRegexpFromTo = function(..., from, to, fromPrefix = "", toPrefix = "") {
return(paste0("(^ *", fromPrefix, from, " *- *", toPrefix, to, " *$)"))
},
.getRegexpSmallerThan = function() {
return(paste0("(^ *", C_REGEXP_SMALLER, C_REGEXP_DECIMAL_NUMBER, " *$)"))
},
.getRegexpDecimalNumber = function() {
return(paste0("(^ *", C_REGEXP_DECIMAL_NUMBER, " *$)"))
},
.getRegexpGreaterOrEqualThan = function() {
return(paste0("(^ *", C_REGEXP_GREATER_OR_EQUAL, C_REGEXP_DECIMAL_NUMBER, " *$)"))
},
.getRegexpDecimalRangeStart = function() {
return(self$.getRegexpFromTo(
from = "0",
to = C_REGEXP_DECIMAL_NUMBER,
toPrefix = C_REGEXP_SMALLER
))
},
.getRegexpDecimalRange = function() {
return(self$.getRegexpFromTo(
from = C_REGEXP_DECIMAL_NUMBER, to = C_REGEXP_DECIMAL_NUMBER,
toPrefix = C_REGEXP_SMALLER
))
},
.getRegexpDecimalRangeEnd = function() {
return(self$.getRegexpFromTo(
from = C_REGEXP_DECIMAL_NUMBER, to = "(Inf|x|\\?)",
toPrefix = paste0("(", C_REGEXP_SMALLER, " *)?")
))
},
.getRegexpDecimalRangeFiniteEnd = function() {
return(self$.getRegexpFromTo(
from = C_REGEXP_DECIMAL_NUMBER, to = C_REGEXP_DECIMAL_NUMBER,
toPrefix = "<=? ?"
))
},
.getRegexpOr = function(...) {
args <- list(...)
if (length(args) == 0) {
return("")
}
if (length(args) == 1) {
return(args[[1]])
}
return(paste(unlist(args, recursive = FALSE, use.names = FALSE), collapse = "|"))
},
.validateTimePeriod = function(timePeriod, i, n, accrualTimeMode = FALSE) {
endOfAccrualIsUndefined <- FALSE
if (i == 1 && (n > 1 || !accrualTimeMode)) {
if (!grepl(self$.getRegexpOr(self$.getRegexpSmallerThan(), self$.getRegexpDecimalRangeStart()),
timePeriod,
perl = TRUE
)) {
if (!accrualTimeMode && n == 1 && !grepl("(0 *- ?)?<?\\?|x|\\.", timePeriod)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"the name of the first region must have the format ",
"\"<time\" or \"0 - <time\", e.g., \"<5\" or \"0 - <5\""
)
}
}
if (grepl(self$.getRegexpSmallerThan(), timePeriod, perl = TRUE)) {
timePeriod <- sub("^ *< *", "0 - <", timePeriod)
}
if (!accrualTimeMode && n == 1 && !grepl("(0 *- ?)?<?\\?|x|\\.", timePeriod)) {
warning("Defined time period \"", timePeriod, "\" will be ignored ",
"because 'piecewiseSurvivalTime' list has only 1 entry",
call. = FALSE
)
}
} else if (i == n) {
if (accrualTimeMode) {
if (!grepl(
self$.getRegexpOr(
self$.getRegexpDecimalNumber(),
self$.getRegexpGreaterOrEqualThan(), self$.getRegexpDecimalRangeEnd(),
self$.getRegexpDecimalRangeFiniteEnd()
),
timePeriod,
perl = TRUE
)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"the name of the last region must have the format \"time\", ",
"\">=time\", \"time - Inf\" or \"time1 - <=time2\", ",
"e.g., \"20\", \">=20\" or \"20 - Inf\" or \"20 - <=30\""
)
}
if (grepl(
self$.getRegexpOr(
self$.getRegexpGreaterOrEqualThan(),
self$.getRegexpDecimalRangeEnd()
),
timePeriod,
perl = TRUE
)) {
endOfAccrualIsUndefined <- TRUE
}
timePeriod <- gsub("([Inf >=\\?x]*)|-", "", timePeriod)
} else {
if (!grepl(
self$.getRegexpOr(
self$.getRegexpGreaterOrEqualThan(),
self$.getRegexpDecimalRangeEnd()
),
timePeriod,
perl = TRUE
)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"the name of the last region must have the format ",
"\">=time\" or \"time - Inf\", e.g., \">=20\" or \"20 - Inf\""
)
}
}
} else {
if (!grepl(self$.getRegexpDecimalRange(), timePeriod, perl = TRUE)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"the name of the inner regions must have ",
"the format \"time_1 - <time_2\", e.g., \"5 - <20\""
)
}
}
if (accrualTimeMode) {
return(list(timePeriod = timePeriod, endOfAccrualIsUndefined = endOfAccrualIsUndefined))
}
return(timePeriod)
}
)
)
#' @title
#' Get Piecewise Survival Time
#'
#' @description
#' Returns a \code{PiecewiseSurvivalTime} object that contains the all relevant parameters
#' of an exponential survival time cumulative distribution function.
#' Use \code{\link[base]{names}} to obtain the field names.
#'
#' @param piecewiseSurvivalTime A vector that specifies the time intervals for the piecewise
#' definition of the exponential survival time cumulative distribution function (see details).
#' @inheritParams param_lambda1
#' @inheritParams param_lambda2
#' @inheritParams param_median1
#' @inheritParams param_median2
#' @inheritParams param_pi1_survival
#' @inheritParams param_pi2_survival
#' @inheritParams param_hazardRatio
#' @inheritParams param_eventTime
#' @inheritParams param_kappa
#' @param delayedResponseAllowed If \code{TRUE}, delayed response is allowed;
#' otherwise it will be validated that the response is not delayed, default is \code{FALSE}.
#' @inheritParams param_three_dots
#'
#' @template details_piecewise_survival
#'
#' @return Returns a \code{\link{PiecewiseSurvivalTime}} object.
#' The following generics (R generic functions) are available for this result object:
#' \itemize{
#' \item \code{\link[=names.FieldSet]{names()}} to obtain the field names,
#' \item \code{\link[=print.FieldSet]{print()}} to print the object,
#' \item \code{\link[=summary.ParameterSet]{summary()}} to display a summary of the object,
#' \item \code{\link[=plot.ParameterSet]{plot()}} to plot the object,
#' \item \code{\link[=as.data.frame.ParameterSet]{as.data.frame()}} to coerce the object to a \code{\link[base]{data.frame}},
#' \item \code{\link[=as.matrix.FieldSet]{as.matrix()}} to coerce the object to a \code{\link[base]{matrix}}.
#' }
#' @template how_to_get_help_for_generics
#'
#' @template examples_get_piecewise_survival_time
#'
#' @export
#'
getPiecewiseSurvivalTime <- function(piecewiseSurvivalTime = NA_real_,
...,
lambda1 = NA_real_,
lambda2 = NA_real_,
hazardRatio = NA_real_,
pi1 = NA_real_,
pi2 = NA_real_,
median1 = NA_real_,
median2 = NA_real_,
eventTime = 12, # C_EVENT_TIME_DEFAULT
kappa = 1,
delayedResponseAllowed = FALSE) {
.warnInCaseOfUnknownArguments(
functionName = "getPiecewiseSurvivalTime", ...,
ignore = c(".pi1Default", ".lambdaBased", ".silent"), exceptionEnabled = TRUE
)
if (inherits(piecewiseSurvivalTime, "TrialDesignPlanSurvival")) {
piecewiseSurvivalTime <- piecewiseSurvivalTime$.piecewiseSurvivalTime
}
if (inherits(piecewiseSurvivalTime, "PiecewiseSurvivalTime")) {
lambdaBased <- .getOptionalArgument(".lambdaBased", ...)
if (!is.null(lambdaBased) && isTRUE(lambdaBased) &&
!piecewiseSurvivalTime$.isLambdaBased()) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'piecewiseSurvivalTime' must be lambda or median based; ",
"pi based defintion is not allowed"
)
}
.warnInCaseOfUnusedArgument(lambda1, "lambda1", NA_real_, "getPiecewiseSurvivalTime")
.warnInCaseOfUnusedArgument(lambda2, "lambda2", NA_real_, "getPiecewiseSurvivalTime")
.warnInCaseOfUnusedArgument(hazardRatio, "hazardRatio", NA_real_, "getPiecewiseSurvivalTime")
.warnInCaseOfUnusedArgument(pi1, "pi1", NA_real_, "getPiecewiseSurvivalTime")
.warnInCaseOfUnusedArgument(pi2, "pi2", NA_real_, "getPiecewiseSurvivalTime")
.warnInCaseOfUnusedArgument(eventTime, "eventTime", C_EVENT_TIME_DEFAULT, "getPiecewiseSurvivalTime")
.warnInCaseOfUnusedArgument(kappa, "kappa", 1, "getPiecewiseSurvivalTime")
return(piecewiseSurvivalTime)
}
.assertIsValidLambda(lambda1, 1)
.assertIsValidLambda(lambda2, 2)
.assertIsNumericVector(hazardRatio, "hazardRatio", naAllowed = TRUE)
.assertIsNumericVector(pi1, "pi1", naAllowed = TRUE)
.assertIsSingleNumber(pi2, "pi2", naAllowed = TRUE)
.assertIsNumericVector(median1, "median1", naAllowed = TRUE)
.assertIsSingleNumber(median2, "median2", naAllowed = TRUE)
.assertIsSingleNumber(eventTime, "eventTime", naAllowed = TRUE)
.assertIsValidKappa(kappa)
.assertIsSingleLogical(delayedResponseAllowed, "delayedResponseAllowed")
return(PiecewiseSurvivalTime$new(
piecewiseSurvivalTime = piecewiseSurvivalTime,
lambda1 = lambda1,
lambda2 = lambda2,
hazardRatio = hazardRatio,
pi1 = pi1,
pi2 = pi2,
median1 = median1,
median2 = median2,
eventTime = eventTime,
kappa = kappa,
delayedResponseAllowed = delayedResponseAllowed,
...
))
}
#' @title
#' Get Accrual Time
#'
#' @description
#' Returns an \code{AccrualTime} object that contains the accrual time and the accrual intensity.
#'
#' @inheritParams param_accrualTime
#' @inheritParams param_accrualIntensity
#' @inheritParams param_accrualIntensityType
#' @param maxNumberOfSubjects The maximum number of subjects.
#' @inheritParams param_three_dots
#'
#' @template details_piecewise_accrual
#'
#' @seealso \code{\link[=getNumberOfSubjects]{getNumberOfSubjects()}} for calculating the number of subjects at given time points.
#'
#' @return Returns an \code{\link{AccrualTime}} object.
#' The following generics (R generic functions) are available for this result object:
#' \itemize{
#' \item \code{\link[=names.FieldSet]{names()}} to obtain the field names,
#' \item \code{\link[=print.FieldSet]{print()}} to print the object,
#' \item \code{\link[=summary.ParameterSet]{summary()}} to display a summary of the object,
#' \item \code{\link[=plot.ParameterSet]{plot()}} to plot the object,
#' \item \code{\link[=as.data.frame.ParameterSet]{as.data.frame()}} to coerce the object to a \code{\link[base]{data.frame}},
#' \item \code{\link[=as.matrix.FieldSet]{as.matrix()}} to coerce the object to a \code{\link[base]{matrix}}.
#' }
#' @template how_to_get_help_for_generics
#'
#' @template examples_get_accrual_time
#'
#' @export
#'
getAccrualTime <- function(
accrualTime = NA_real_,
...,
accrualIntensity = NA_real_,
accrualIntensityType = c("auto", "absolute", "relative"),
maxNumberOfSubjects = NA_real_) {
.warnInCaseOfUnknownArguments(
functionName = "getAccrualTime", ...,
ignore = c("showWarnings")
)
if (inherits(accrualTime, "AccrualTime") ||
inherits(accrualTime, "TrialDesignPlanSurvival")) {
if (!identical(accrualIntensity, C_ACCRUAL_INTENSITY_DEFAULT)) {
.warnInCaseOfUnusedArgument(
accrualIntensity,
"accrualIntensity", NA_real_, "getAccrualTime"
)
}
.warnInCaseOfUnusedArgument(
maxNumberOfSubjects,
"maxNumberOfSubjects", NA_real_, "getAccrualTime"
)
}
if (inherits(accrualTime, "AccrualTime")) {
return(accrualTime)
}
if (inherits(accrualTime, "TrialDesignPlanSurvival")) {
return(accrualTime$.accrualTime)
}
accrualIntensityType <- match.arg(accrualIntensityType)
.assertIsNumericVector(accrualIntensity, "accrualIntensity", naAllowed = TRUE)
.assertIsValidMaxNumberOfSubjects(maxNumberOfSubjects, naAllowed = TRUE)
.assertIsSingleCharacter(accrualIntensityType, "accrualIntensityType")
if (!is.null(accrualTime) && is.numeric(accrualTime) && !all(is.na(accrualTime)) &&
!all(is.na(accrualIntensity))) {
accrualTimeLength <- length(accrualTime)
accrualIntensityLength <- length(accrualIntensity)
if (!accrualIntensityLength %in% c(accrualTimeLength, accrualTimeLength - 1)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"length of 'accrualIntensity' (", accrualIntensityLength, ") must be ",
"equal to the length of 'accrualTime' (", accrualTimeLength, ") or ",
"one element shorter"
)
}
}
absoluteAccrualIntensityEnabled <- NA
if (accrualIntensityType == "absolute") {
absoluteAccrualIntensityEnabled <- TRUE
if (!all(is.na(accrualIntensity)) && any(na.omit(accrualIntensity) < 1)) {
stop(
C_EXCEPTION_TYPE_CONFLICTING_ARGUMENTS,
"'accrualIntensityType' is 'absolute' and the 'accrualIntensity' (",
.arrayToString(accrualIntensity), ") therefore must be >= 1"
)
}
} else if (accrualIntensityType == "relative") {
absoluteAccrualIntensityEnabled <- FALSE
}
args <- list(...)
showWarnings <- args[["showWarnings"]]
if (is.null(showWarnings) || !is.logical(showWarnings)) {
showWarnings <- TRUE
}
return(AccrualTime$new(
accrualTime = accrualTime,
accrualIntensity = accrualIntensity,
maxNumberOfSubjects = maxNumberOfSubjects,
showWarnings = showWarnings,
absoluteAccrualIntensityEnabled = absoluteAccrualIntensityEnabled
))
}
#'
#' @name PiecewiseSurvivalTime
#'
#' @title
#' Piecewise Exponential Survival Time
#'
#' @description
#' Class for the definition of piecewise survival times.
#'
#' @template field_piecewiseSurvivalTime
#' @template field_lambda1
#' @template field_lambda2
#' @template field_hazardRatio
#' @template field_pi1_survival
#' @template field_pi2_survival
#' @template field_median1
#' @template field_median2
#' @template field_eventTime
#' @template field_kappa
#' @template field_piecewiseSurvivalEnabled
#' @template field_delayedResponseAllowed
#' @template field_delayedResponseEnabled
#'
#' @details
#' \code{PiecewiseSurvivalTime} is a class for the definition of piecewise survival times.
#'
#' @include f_core_constants.R
#' @include class_core_parameter_set.R
#' @include f_core_utilities.R
#' @include f_logger.R
#'
#' @keywords internal
#'
#' @importFrom methods new
#'
PiecewiseSurvivalTime <- R6::R6Class("PiecewiseSurvivalTime",
inherit = TimeDefinition,
public = list(
.pi1Default = NULL,
.lambdaBased = NULL,
.silent = NULL,
piecewiseSurvivalTime = NULL,
lambda1 = NULL,
lambda2 = NULL,
hazardRatio = NULL,
pi1 = NULL,
pi2 = NULL,
median1 = NULL,
median2 = NULL,
eventTime = NULL,
kappa = NULL,
piecewiseSurvivalEnabled = NULL,
delayedResponseAllowed = NULL,
delayedResponseEnabled = NULL,
initialize = function(piecewiseSurvivalTime = NA_real_,
...,
lambda1 = NA_real_,
lambda2 = NA_real_,
hazardRatio = NA_real_,
pi1 = NA_real_,
pi2 = NA_real_,
median1 = NA_real_,
median2 = NA_real_,
eventTime = C_EVENT_TIME_DEFAULT,
kappa = 1,
delayedResponseAllowed = FALSE) {
super$initialize()
self$piecewiseSurvivalTime <- piecewiseSurvivalTime
self$lambda1 <- lambda1
self$lambda2 <- lambda2
self$hazardRatio <- hazardRatio
self$pi1 <- pi1
self$pi2 <- pi2
self$median1 <- median1
self$median2 <- median2
self$eventTime <- eventTime
self$kappa <- kappa
self$delayedResponseAllowed <- delayedResponseAllowed
if (length(self$piecewiseSurvivalTime) == 0) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'piecewiseSurvivalTime' must be defined ",
"(set to NA_real_ if not applicable)"
)
}
self$.stopInCaseOfConflictingArguments(self$lambda1, "lambda1", self$median1, "median1")
self$.stopInCaseOfConflictingArguments(self$lambda2, "lambda2", self$median2, "median2")
self$.stopInCaseOfConflictingArguments(self$pi1, "pi1", self$median1, "median1")
self$.stopInCaseOfConflictingArguments(self$pi1, "pi1", self$median2, "median2")
self$.stopInCaseOfConflictingArguments(self$pi1, "pi1", self$lambda1, "lambda1")
self$.stopInCaseOfConflictingArguments(self$pi1, "pi1", self$lambda2, "lambda2")
self$.stopInCaseOfConflictingArguments(self$pi2, "pi2", self$median1, "median1")
self$.stopInCaseOfConflictingArguments(self$pi2, "pi2", self$median2, "median2")
self$.stopInCaseOfConflictingArguments(self$pi2, "pi2", self$lambda1, "lambda1")
self$.stopInCaseOfConflictingArguments(self$pi2, "pi2", self$lambda2, "lambda2")
if (length(self$median1) > 0 && !all(is.na(self$median1))) {
self$lambda1 <- getLambdaByMedian(self$median1, kappa = self$kappa)
self$.setParameterType("median1", C_PARAM_USER_DEFINED)
self$.setParameterType("lambda1", C_PARAM_GENERATED)
} else {
self$.setParameterType("median1", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("lambda1", ifelse(length(self$lambda1) == 1 && is.na(self$lambda1),
C_PARAM_NOT_APPLICABLE, C_PARAM_USER_DEFINED
))
}
if (length(self$median2) > 0 && !all(is.na(self$median2))) {
self$lambda2 <- getLambdaByMedian(self$median2, kappa = self$kappa)
self$.setParameterType("median2", C_PARAM_USER_DEFINED)
self$.setParameterType("lambda2", C_PARAM_GENERATED)
} else {
self$.setParameterType("median2", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("lambda2", C_PARAM_NOT_APPLICABLE)
}
args <- list(...)
if (!is.null(args[[".pi1Default"]])) {
self$.pi1Default <- args[[".pi1Default"]]
}
if (!is.null(args[[".lambdaBased"]])) {
self$.lambdaBased <- args[[".lambdaBased"]]
}
if (!is.null(args[[".silent"]])) {
self$.silent <- args[[".silent"]]
} else {
self$.silent <- FALSE
}
self$piecewiseSurvivalEnabled <- FALSE
self$delayedResponseEnabled <- FALSE
self$.setParameterType("piecewiseSurvivalTime", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("piecewiseSurvivalEnabled", C_PARAM_GENERATED)
self$.setParameterType("delayedResponseEnabled", ifelse(isTRUE(self$delayedResponseAllowed),
C_PARAM_GENERATED, C_PARAM_NOT_APPLICABLE
))
self$.setParameterType("delayedResponseAllowed", ifelse(isTRUE(self$delayedResponseAllowed),
C_PARAM_USER_DEFINED, C_PARAM_DEFAULT_VALUE
))
self$.setParameterType("pi1", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("pi2", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("eventTime", ifelse(length(self$eventTime) == 1 && is.na(self$eventTime),
C_PARAM_NOT_APPLICABLE,
ifelse(self$eventTime == C_EVENT_TIME_DEFAULT, C_PARAM_DEFAULT_VALUE, C_PARAM_USER_DEFINED)
))
self$.setParameterType("kappa", ifelse(length(self$kappa) == 1 && !is.na(self$kappa) && self$kappa == 1,
C_PARAM_DEFAULT_VALUE, C_PARAM_USER_DEFINED
))
self$.init(self$piecewiseSurvivalTime)
if (self$.getParameterType("median1") == C_PARAM_USER_DEFINED &&
self$.getParameterType("lambda1") == C_PARAM_USER_DEFINED) {
self$.setParameterType("lambda1", C_PARAM_GENERATED)
}
if (self$.getParameterType("median2") == C_PARAM_USER_DEFINED &&
self$.getParameterType("lambda2") == C_PARAM_USER_DEFINED) {
self$.setParameterType("lambda2", C_PARAM_GENERATED)
}
if (!is.na(self$eventTime) &&
self$.getParameterType("pi1") != C_PARAM_USER_DEFINED &&
self$.getParameterType("pi1") != C_PARAM_DEFAULT_VALUE &&
self$.getParameterType("pi2") != C_PARAM_USER_DEFINED &&
self$.getParameterType("pi2") != C_PARAM_DEFAULT_VALUE) {
if (self$.getParameterType("eventTime") == C_PARAM_USER_DEFINED) {
warning("'eventTime' (", round(self$eventTime, 3), ") has no influence on simulated results", call. = FALSE)
}
self$.setParameterType("eventTime", C_PARAM_NOT_APPLICABLE)
self$eventTime <- NA_real_
}
self$.validateCalculatedArguments()
},
.validateCalculatedArguments = function() {
if (self$.getParameterType("median1") == C_PARAM_USER_DEFINED) {
if (!isTRUE(all.equal(getLambdaByMedian(
self$median1,
kappa = self$kappa
), self$lambda1, tolerance = 1e-05))) {
stop(
C_EXCEPTION_TYPE_RUNTIME_ISSUE, "'lambda1' must be ",
round(getLambdaByMedian(self$median1, kappa = self$kappa), 5), ", ",
"but is ", round(self$lambda1, 5)
)
}
if (!any(is.na(self$pi1)) &&
!isTRUE(all.equal(
getPiByMedian(self$median1,
eventTime = self$eventTime, kappa = self$kappa
),
self$pi1,
tolerance = 1e-05
))) {
stop(
C_EXCEPTION_TYPE_RUNTIME_ISSUE, "'pi1' must be ",
round(getPiByMedian(self$median1,
eventTime = self$eventTime,
kappa = self$kappa
), 5), ", but is ", round(self$pi1, 5)
)
}
}
if (self$.getParameterType("median2") == C_PARAM_USER_DEFINED) {
if (!isTRUE(all.equal(getLambdaByMedian(self$median2,
kappa = self$kappa
), self$lambda2, tolerance = 1e-05))) {
stop(
C_EXCEPTION_TYPE_RUNTIME_ISSUE, "'lambda2' must be ",
round(getLambdaByMedian(self$median2, kappa = self$kappa), 5), ", ",
"but is ", round(self$lambda2, 5)
)
}
if (!is.na(self$pi2) &&
!isTRUE(all.equal(getPiByMedian(self$median2, eventTime = self$eventTime, kappa = self$kappa),
self$pi2,
tolerance = 1e-05
))) {
stop(
C_EXCEPTION_TYPE_RUNTIME_ISSUE, "'pi2' must be ",
round(getPiByMedian(self$median2,
eventTime = self$eventTime,
kappa = self$kappa
), 5), ", but is ", round(self$pi2, 5)
)
}
}
if (self$.getParameterType("lambda1") == C_PARAM_USER_DEFINED ||
self$.getParameterType("median1") == C_PARAM_USER_DEFINED ||
self$.getParameterType("lambda2") == C_PARAM_USER_DEFINED ||
self$.getParameterType("median2") == C_PARAM_USER_DEFINED) {
if (!any(is.na(self$pi1))) {
stop(C_EXCEPTION_TYPE_RUNTIME_ISSUE, "'pi1' (", self$pi1, ") must be NA_real_")
}
if (self$.getParameterType("pi1") != C_PARAM_NOT_APPLICABLE) {
stop(
C_EXCEPTION_TYPE_RUNTIME_ISSUE, "parameter type of 'pi1' (",
self$.getParameterType("pi1"), ") must be C_PARAM_NOT_APPLICABLE"
)
}
if (!any(is.na(self$pi1))) {
stop(C_EXCEPTION_TYPE_RUNTIME_ISSUE, "'pi2' (", self$pi2, ") must be NA_real_")
}
if (self$.getParameterType("pi2") != C_PARAM_NOT_APPLICABLE) {
stop(
C_EXCEPTION_TYPE_RUNTIME_ISSUE, "parameter type of 'pi2' (",
self$.getParameterType("pi2"), ") must be C_PARAM_NOT_APPLICABLE"
)
}
if (!any(is.na(self$eventTime))) {
stop(C_EXCEPTION_TYPE_RUNTIME_ISSUE, "'eventTime' (", self$eventTime, ") must be NA_real_")
}
if (self$.getParameterType("eventTime") != C_PARAM_NOT_APPLICABLE) {
stop(
C_EXCEPTION_TYPE_RUNTIME_ISSUE, "parameter type of 'eventTime' (",
self$.getParameterType("eventTime"), ") must be C_PARAM_NOT_APPLICABLE"
)
}
}
if (self$.getParameterType("hazardRatio") == C_PARAM_TYPE_UNKNOWN) {
stop(
C_EXCEPTION_TYPE_RUNTIME_ISSUE, "parameter type of 'hazardRatio' (",
self$hazardRatio, ") must be != C_PARAM_TYPE_UNKNOWN"
)
}
},
.stopInCaseOfConflictingArguments = function(arg1, argName1, arg2, argName2) {
if (length(arg1) > 0 && !all(is.na(arg1)) && length(arg2) > 0 && !all(is.na(arg2))) {
stop(
C_EXCEPTION_TYPE_CONFLICTING_ARGUMENTS,
"it is not allowed to specify '", argName1, "' (", .arrayToString(arg1), ")",
" and '", argName2, "' (", .arrayToString(arg2), ") concurrently"
)
}
},
.asDataFrame = function() {
data <- data.frame(
piecewiseSurvivalTime = self$piecewiseSurvivalTime,
lambda1 = self$lambda1,
lambda2 = self$lambda2,
hazardRatio = self$hazardRatio
)
colnames(data) <- c(
"Start time",
.getParameterCaption("lambda1", tableOutputEnabled = TRUE),
.getParameterCaption("lambda2", tableOutputEnabled = TRUE),
.getParameterCaption("hazardRatio", tableOutputEnabled = TRUE)
)
rownames(data) <- as.character(1:nrow(data))
return(data)
},
.isPiBased = function() {
return(!self$.isLambdaBased())
},
.isLambdaBased = function(minNumberOfLambdas = 2) {
if (self$.getParameterType("lambda2") == C_PARAM_USER_DEFINED ||
self$.getParameterType("median2") == C_PARAM_USER_DEFINED) {
if (length(self$lambda2) >= minNumberOfLambdas && !any(is.na(self$lambda2))) {
return(TRUE)
}
}
return((length(self$pi1) == 0 || any(is.na(self$pi1))) && (length(self$pi2) == 0 || any(is.na(self$pi2))))
},
show = function(showType = 1, digits = NA_integer_) {
self$.show(showType = showType, digits = digits, consoleOutputEnabled = TRUE)
},
.show = function(showType = 1, digits = NA_integer_, consoleOutputEnabled = TRUE) {
"Method for automatically printing piecewise survival time objects"
self$.resetCat()
if (showType == 2) {
super$.show(
showType = showType, digits = digits,
consoleOutputEnabled = consoleOutputEnabled
)
} else {
self$.cat("Piecewise exponential survival times:\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
if (!self$piecewiseSurvivalEnabled) {
self$.cat(" Piecewise exponential survival is disabled.\n\n",
consoleOutputEnabled = consoleOutputEnabled
)
} else if (length(self$piecewiseSurvivalTime) == 1) {
self$.cat(" At all times:", self$lambda2[1], "\n\n",
consoleOutputEnabled = consoleOutputEnabled
)
} else {
piecewiseSurvivalTimeStr <- format(self$piecewiseSurvivalTime)
lambda2Str <- format(self$lambda2)
for (i in seq_len(length(self$piecewiseSurvivalTime))) {
if (i < length(self$piecewiseSurvivalTime)) {
self$.cat(" ", piecewiseSurvivalTimeStr[i], " - <",
piecewiseSurvivalTimeStr[i + 1], ": ",
lambda2Str[i], "\n",
sep = "",
consoleOutputEnabled = consoleOutputEnabled
)
} else {
self$.cat(" ", rep(" ", 2 + max(nchar(piecewiseSurvivalTimeStr))),
">=", piecewiseSurvivalTimeStr[i], ": ",
lambda2Str[i], "\n",
sep = "",
consoleOutputEnabled = consoleOutputEnabled
)
}
}
if (self$delayedResponseEnabled) {
self$.cat("Delayed response is enabled.\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
self$.cat("\n", consoleOutputEnabled = consoleOutputEnabled)
}
self$.cat("Details:\n\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
self$.showParametersOfOneGroup(self$.getUserDefinedParameters(),
"User defined parameters",
orderByParameterName = FALSE,
consoleOutputEnabled = consoleOutputEnabled
)
self$.showParametersOfOneGroup(self$.getDefaultParameters(),
"Default parameters",
orderByParameterName = FALSE,
consoleOutputEnabled = consoleOutputEnabled
)
self$.showParametersOfOneGroup(self$.getGeneratedParameters(),
"Generated parameters",
orderByParameterName = FALSE,
consoleOutputEnabled = consoleOutputEnabled
)
self$.showUnknownParameters(consoleOutputEnabled = consoleOutputEnabled)
}
},
.toString = function(startWithUpperCase = FALSE) {
s <- "piecewise survival time"
return(ifelse(startWithUpperCase, .firstCharacterToUpperCase(s), s))
},
isDelayedResponseEnabled = function() {
return(self$delayedResponseEnabled)
},
isPiecewiseSurvivalEnabled = function() {
if (length(self$piecewiseSurvivalTime) == 0) {
return(FALSE)
}
if (length(self$piecewiseSurvivalTime) == 1 && is.na(self$piecewiseSurvivalTime)) {
return(FALSE)
}
return(TRUE)
},
.initFromList = function(pwSurvTimeList) {
if (!is.list(pwSurvTimeList)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'piecewiseSurvivalTime' must be a list"
)
}
if (length(pwSurvTimeList) == 0) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'piecewiseSurvivalTime' must contain at least one entry"
)
}
if (is.null(names(pwSurvTimeList))) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'piecewiseSurvivalTime' must be a named list"
)
}
if (!all(is.na(self$lambda2))) {
warning("'lambda2' (", .arrayToString(self$lambda2),
") will be ignored because 'piecewiseSurvivalTime' is a list",
call. = FALSE
)
}
pwSurvStartTimes <- c(0)
pwSurvLambda2 <- c()
pwSurvTimeNames <- names(pwSurvTimeList)
for (i in seq_len(length(pwSurvTimeNames))) {
timePeriod <- pwSurvTimeNames[i]
lambdaValue <- pwSurvTimeList[[timePeriod]]
.assertIsSingleNumber(lambdaValue, paste0("pwSurvLambda[", i, "]"))
timePeriod <- self$.validateTimePeriod(
timePeriod,
i = i, n = length(pwSurvTimeNames)
)
if (i < length(pwSurvTimeNames)) {
parts <- strsplit(timePeriod, "- *(< *)?", perl = TRUE)[[1]]
if (length(parts) != 2) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"all regions (", timePeriod, ") must have the format ",
"\"time_1 - <time_2\", e.g., \"3 - <6\""
)
}
intervalBoundary <- as.numeric(trimws(parts[2]))
pwSurvStartTimes <- c(pwSurvStartTimes, intervalBoundary)
}
pwSurvLambda2 <- c(pwSurvLambda2, lambdaValue)
}
self$piecewiseSurvivalTime <- pwSurvStartTimes
self$.setParameterType("piecewiseSurvivalTime", C_PARAM_USER_DEFINED)
if (length(self$hazardRatio) == 1 && !is.na(self$hazardRatio)) {
self$lambda1 <- pwSurvLambda2 * self$hazardRatio^(1 / self$kappa)
self$.setParameterType("lambda1", C_PARAM_GENERATED)
} else if (length(self$hazardRatio) > 1 && self$delayedResponseAllowed) {
if (length(self$hazardRatio) != length(pwSurvLambda2)) {
warning("Only the first 'hazardRatio' (", round(self$hazardRatio[1], 4),
") was used for piecewise survival time definition ",
"(use a loop over the function to simulate different hazard ratios)",
call. = FALSE
)
self$hazardRatio <- self$hazardRatio[1]
} else {
self$delayedResponseEnabled <- TRUE
}
self$lambda1 <- pwSurvLambda2 * self$hazardRatio^(1 / self$kappa)
self$.setParameterType("lambda1", C_PARAM_GENERATED)
} else {
self$lambda1 <- NA_real_
self$.setParameterType("lambda1", C_PARAM_NOT_APPLICABLE)
}
self$lambda2 <- pwSurvLambda2
self$.setParameterType("lambda2", C_PARAM_USER_DEFINED)
self$piecewiseSurvivalEnabled <- !identical(self$piecewiseSurvivalTime, 0)
},
.init = function(pwSurvTime) {
.logDebug("pwSurvTime %s, %s", ifelse(is.numeric(pwSurvTime),
.arrayToString(pwSurvTime), pwSurvTime
), .getClassName(pwSurvTime[1]))
.logDebug("lambda1 %s, %s", .arrayToString(self$lambda1, vectorLookAndFeelEnabled = TRUE),
self$.getParameterType("lambda1"))
if (length(self$hazardRatio) > 0 && !any(is.na(self$hazardRatio)) &&
(length(self$lambda2) == 0 || all(is.na(self$lambda2))) &&
length(self$lambda1) > 0 && !any(is.na(self$lambda1)) &&
!self$isGeneratedParameter("lambda1")) {
self$lambda2 <- self$lambda1 / self$hazardRatio^(1 / self$kappa)
self$.setParameterType("lambda2", C_PARAM_GENERATED)
}
.logDebug("lambda2 %s, %s", .arrayToString(self$lambda2, vectorLookAndFeelEnabled = TRUE),
self$.getParameterType("lambda2"))
# case 1: lambda1 and lambda2 = NA or generated
if (length(pwSurvTime) == 1 && (is.na(pwSurvTime) || is.numeric(pwSurvTime)) &&
(all(is.na(self$lambda1)) || self$isGeneratedParameter("lambda1")) &&
length(self$lambda2) == 1 && (is.na(self$lambda2) ||
self$isGeneratedParameter("lambda2"))
) {
.logDebug(".init, case 1: lambda1 and lambda2 = NA")
if (!is.null(self$.lambdaBased) && isTRUE(self$.lambdaBased)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'lambda1' and 'lambda2' must be specified"
)
}
if (!any(is.na(self$pi1))) {
self$.setParameterType("pi1", C_PARAM_USER_DEFINED)
}
if (!any(is.na(self$hazardRatio))) {
self$.setParameterType("hazardRatio", C_PARAM_USER_DEFINED)
}
if (!is.na(pwSurvTime)) {
warning("'piecewiseSurvivalTime' (", pwSurvTime, ") will be ignored")
}
if (is.na(self$pi2)) {
if (!is.na(self$median2) || !any(is.na(self$median1))) {
.logDebug(".init: set pi2 to 'not applicable'")
self$.setParameterType("pi2", C_PARAM_NOT_APPLICABLE)
} else {
if (length(self$pi1) > 0 && !any(is.na(self$pi1)) &&
length(self$hazardRatio) > 0 && !any(is.na(self$hazardRatio))) {
.logDebug(".init: calculate pi2 via pi1 and hazard ratio")
self$lambda1 <- getLambdaByPi(pi = self$pi1, eventTime = self$eventTime, kappa = self$kappa)
self$.setParameterType("lambda1", C_PARAM_GENERATED)
self$lambda2 <- self$lambda1 / self$hazardRatio^(1 / self$kappa)
self$.setParameterType("lambda2", C_PARAM_GENERATED)
self$pi2 <- getPiByLambda(self$lambda2, eventTime = self$eventTime, kappa = self$kappa)
self$.setParameterType("pi2", C_PARAM_GENERATED)
self$median2 <- getMedianByLambda(self$lambda2, self$kappa)
self$.setParameterType("median2", C_PARAM_GENERATED)
} else {
.logDebug(".init: set pi2 to default")
self$median2 <- getMedianByPi(pi = self$pi2, eventTime = self$eventTime, kappa = self$kappa)
self$pi2 <- C_PI_2_DEFAULT
self$.setParameterType("pi2", C_PARAM_DEFAULT_VALUE)
}
}
} else {
.assertIsSingleNumber(self$pi2, "pi2")
self$.setParameterType("pi2", ifelse(self$pi2 == C_PI_2_DEFAULT,
C_PARAM_DEFAULT_VALUE, C_PARAM_USER_DEFINED
))
if (!any(is.na(self$median2))) {
warning("'median2' (", .arrayToString(self$median2), ") will be ignored")
self$median2 <- NA_real_
}
}
hazardRatioCalculationEnabled <- !self$isUserDefinedParameter("hazardRatio")
if (self$isUserDefinedParameter("pi1") && self$isUserDefinedParameter("pi2")) {
hazardRatioCalculationEnabled <- TRUE
}
if (all(is.na(self$pi1))) {
if ((all(is.na(self$median1)) || all(is.na(self$median2))) &&
length(self$hazardRatio) > 0 && !all(is.na(self$hazardRatio))) {
self$.setParameterType("hazardRatio", C_PARAM_USER_DEFINED)
hazardRatioCalculationEnabled <- FALSE
}
if (!any(is.na(self$median1))) {
.logDebug(".init: set pi1 to 'not applicable'")
self$.setParameterType("pi1", C_PARAM_NOT_APPLICABLE)
if (is.na(self$median2)) {
if (any(is.na(self$hazardRatio))) {
stop(
C_EXCEPTION_TYPE_MISSING_ARGUMENT,
"'hazardRatio', 'lambda2', or 'median2' must be specified"
)
}
if (length(self$hazardRatio) != length(self$median1)) {
stop(
C_EXCEPTION_TYPE_CONFLICTING_ARGUMENTS,
"length of 'hazardRatio' (", .arrayToString(self$hazardRatio), ") must be ",
"equal to length of 'median1' (", .arrayToString(self$median1), ")"
)
}
.logDebug(".init: calculate lambda2 and median2 by median1")
self$lambda2 <- getLambdaByMedian(self$median1, self$kappa) / self$hazardRatio^(1 / self$kappa)
if (!self$delayedResponseAllowed && length(unique(round(self$lambda2, 8))) > 1) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'lambda2' can only be calculated if ",
"'unique(lambda1 / hazardRatio^(1 / kappa))' ",
"result in a single value; current result = ",
.arrayToString(round(self$lambda2, 4), vectorLookAndFeelEnabled = TRUE),
" (e.g., delayed response is not allowed)"
)
}
self$median2 <- getMedianByLambda(self$lambda2, self$kappa)
self$.setParameterType("lambda2", C_PARAM_GENERATED)
self$.setParameterType("median2", C_PARAM_GENERATED)
}
} else if (length(self$hazardRatio) > 0 && !all(is.na(self$hazardRatio))) {
self$.setParameterType("pi1", C_PARAM_NOT_APPLICABLE)
if (!any(is.na(self$lambda1))) {
.logDebug(".init: calculate median1 by lambda1")
self$median1 <- getMedianByLambda(self$lambda1, self$kappa)
self$.setParameterType("median1", C_PARAM_GENERATED)
} else if (!is.na(self$median2)) {
.logDebug(".init: calculate lambda1 and median1 by median2")
self$lambda1 <- getLambdaByMedian(self$median2, self$kappa) *
self$hazardRatio^(1 / self$kappa)
self$median1 <- getMedianByLambda(self$lambda1, self$kappa)
self$.setParameterType("lambda1", C_PARAM_GENERATED)
self$.setParameterType("median1", C_PARAM_GENERATED)
}
} else {
.logDebug(".init: set pi1 to default")
if (!is.null(self$.pi1Default) && is.numeric(self$.pi1Default) &&
length(self$.pi1Default) > 0) {
self$pi1 <- self$.pi1Default
} else {
self$pi1 <- C_PI_1_SAMPLE_SIZE_DEFAULT
}
self$.setParameterType("pi1", C_PARAM_DEFAULT_VALUE)
}
} else {
.assertIsNumericVector(self$pi1, "pi1")
if (!any(is.na(self$median1))) {
.logDebug(".init: set median1 to NA")
warning("'median1' (", .arrayToString(self$median1), ") will be ignored")
self$median1 <- NA_real_
}
}
if (hazardRatioCalculationEnabled) {
if (length(self$hazardRatio) > 0 && !all(is.na(self$hazardRatio))) {
warning("'hazardRatio' (", .arrayToString(self$hazardRatio),
") will be ignored because it will be calculated",
call. = FALSE
)
}
if (!any(is.na(self$lambda1)) && !any(is.na(self$lambda2))) {
.logDebug(".init: calculate hazardRatio by lambda1 and lambda2")
self$hazardRatio <- (self$lambda1 / self$lambda2)^self$kappa
self$.setParameterType("hazardRatio", C_PARAM_GENERATED)
} else if (!any(is.na(self$pi1)) && !is.na(self$pi2)) {
.logDebug(".init: calculate hazardRatio by pi1 and pi2")
self$hazardRatio <- getHazardRatioByPi(
self$pi1, self$pi2, self$eventTime,
kappa = self$kappa
)
self$.setParameterType("hazardRatio", C_PARAM_GENERATED)
}
}
if (length(self$pi1) > 0 && !any(is.na(self$pi1))) {
pi1Default <- C_PI_1_SAMPLE_SIZE_DEFAULT
if (!is.null(self$.pi1Default) && is.numeric(self$.pi1Default) &&
length(self$.pi1Default) > 0) {
pi1Default <- self$.pi1Default
}
if (identical(self$pi1, pi1Default)) {
self$.setParameterType("pi1", C_PARAM_DEFAULT_VALUE)
} else if (hazardRatioCalculationEnabled &&
!self$isGeneratedParameter("pi1")) {
self$.setParameterType("pi1", C_PARAM_USER_DEFINED)
}
}
if (length(self$pi2) == 1 && !is.na(self$pi2)) {
if (length(self$eventTime) == 1 && !is.na(self$eventTime)) {
self$lambda2 <- getLambdaByPi(self$pi2, self$eventTime, kappa = self$kappa)
self$.setParameterType("lambda2", C_PARAM_GENERATED)
}
if (length(self$pi1) == 1 && is.na(self$pi1) && !any(is.na(self$hazardRatio))) {
self$pi1 <- getPiByLambda(
getLambdaByPi(
self$pi2, self$eventTime,
kappa = self$kappa
) * self$hazardRatio^(1 / self$kappa),
self$eventTime,
kappa = self$kappa
)
self$.setParameterType("pi1", C_PARAM_GENERATED)
}
if (length(self$pi1) > 0 && !any(is.na(self$pi1)) &&
length(self$eventTime) == 1 && !is.na(self$eventTime)) {
self$lambda1 <- getLambdaByPi(self$pi1, self$eventTime, kappa = self$kappa)
self$.setParameterType("lambda1", C_PARAM_GENERATED)
}
}
self$.initMedian()
return(invisible())
}
if (length(pwSurvTime) == 1 && is.na(pwSurvTime)) {
pwSurvTime <- NA_real_
}
if (is.list(pwSurvTime)) {
.assertIsValidHazardRatioVector(self$hazardRatio)
self$.initFromList(pwSurvTime)
self$.initHazardRatio(1)
if (!self$piecewiseSurvivalEnabled) {
self$.initPi()
self$.initMedian()
}
} else if (self$delayedResponseAllowed &&
(length(self$lambda2) == 1 && !is.na(self$lambda2) ||
(length(self$lambda1) > 0 && !any(is.na(self$lambda1)))) &&
length(self$hazardRatio) > 0 &&
(all(is.na(pwSurvTime)) || identical(pwSurvTime, 0))) {
.logDebug(".init, case 2: delayedResponseAllowed")
self$piecewiseSurvivalEnabled <- FALSE
if (!all(is.na(pwSurvTime)) && !identical(pwSurvTime, 0)) {
warning("'piecewiseSurvivalTime' (", .arrayToString(pwSurvTime), ") will be ignored")
}
self$piecewiseSurvivalTime <- 0
hazardRatioCalculationEnabled <- TRUE
if ((length(self$lambda2) == 0 || all(is.na(self$lambda2))) &&
length(self$lambda1) > 0 && !any(is.na(self$lambda1))) {
self$lambda2 <- self$lambda1 / self$hazardRatio^(1 / self$kappa)
self$.setParameterType("lambda2", C_PARAM_GENERATED)
hazardRatioCalculationEnabled <- FALSE
}
self$.initPi()
if (hazardRatioCalculationEnabled) {
self$.initHazardRatio(2)
}
self$.initMedian()
} else if (!is.numeric(pwSurvTime)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'piecewiseSurvivalTime' must be a list, a numeric value, or vector"
)
} else {
self$piecewiseSurvivalTime <- pwSurvTime
if ((all(is.na(self$piecewiseSurvivalTime)) || identical(self$piecewiseSurvivalTime, 0)) &&
(length(self$lambda2) == 1 && !is.na(self$lambda2))) {
.logDebug(".init, case 3: piecewise survival is disabled")
if (!all(is.na(self$piecewiseSurvivalTime)) &&
!identical(self$piecewiseSurvivalTime, 0)) {
warning(
"'piecewiseSurvivalTime' (",
.arrayToString(self$piecewiseSurvivalTime), ") will be ignored"
)
}
self$piecewiseSurvivalTime <- 0
self$.setParameterType("piecewiseSurvivalTime", C_PARAM_DEFAULT_VALUE)
self$piecewiseSurvivalEnabled <- FALSE
self$.initHazardRatio(3)
self$.initPi()
self$.initMedian()
} else {
.logDebug(".init, case 3: piecewise survival is enabled (%s)",
.arrayToString(self$piecewiseSurvivalTime))
if (all(is.na(self$piecewiseSurvivalTime))) {
if (self$.getParameterType("median1") == C_PARAM_USER_DEFINED) {
stop(
C_EXCEPTION_TYPE_CONFLICTING_ARGUMENTS,
"'median1' (", .arrayToString(self$median1), ") with length > 1 can only ",
"defined together with a single 'median2', 'lambda2' or 'pi2'"
)
}
if (self$delayedResponseAllowed && length(self$lambda1 > 0) &&
!all(is.na(self$lambda1)) &&
length(self$lambda1) != length(self$lambda2) &&
self$delayedResponseAllowed) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"length of 'lambda1' (", length(self$lambda1), "), ",
"'lambda2' (", length(self$lambda2), "), and ",
"'piecewiseSurvivalTime' (", length(self$piecewiseSurvivalTime), ") must be equal"
)
}
stop(
C_EXCEPTION_TYPE_MISSING_ARGUMENT,
"'piecewiseSurvivalTime' must be specified"
)
}
self$.setParameterType("piecewiseSurvivalTime", C_PARAM_USER_DEFINED)
self$piecewiseSurvivalEnabled <- TRUE
self$.initHazardRatio(4)
self$.initPi()
}
}
if (self$piecewiseSurvivalEnabled) {
for (param in c("pi", "median")) {
for (group in 1:2) {
paramName <- paste0(param, group)
if (self$.getParameterType(paramName) == C_PARAM_USER_DEFINED) {
warning(
"'", paramName, "' (", .arrayToString(self[[paramName]]), ") ",
"was converted to 'lambda", group, "' ",
"and is not available in output because piecewise ",
"exponential survival time is enabled"
)
}
}
}
self$pi1 <- NA_real_
self$pi2 <- NA_real_
self$median1 <- NA_real_
self$median2 <- NA_real_
self$.setParameterType("pi1", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("pi2", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("median1", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("median2", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("eventTime", C_PARAM_NOT_APPLICABLE)
if (!is.na(self$eventTime) && self$eventTime != C_EVENT_TIME_DEFAULT) {
warning("Event time (", self$eventTime, ") will be ignored because it is not ",
"applicable for piecewise exponential survival time",
call. = FALSE
)
self$eventTime <- C_EVENT_TIME_DEFAULT
}
}
self$.validateInitialization()
},
.initMedian = function() {
if (length(self$eventTime) == 1 && !is.na(self$eventTime)) {
if (length(self$pi1) > 0 && !all(is.na(self$pi1)) &&
self$.getParameterType("median1") != C_PARAM_USER_DEFINED) {
self$median1 <- getMedianByPi(self$pi1, self$eventTime, kappa = self$kappa)
self$.setParameterType("median1", C_PARAM_GENERATED)
}
if (length(self$pi2) == 1 && !is.na(self$pi2) &&
self$.getParameterType("median2") != C_PARAM_USER_DEFINED) {
self$median2 <- getMedianByPi(self$pi2, self$eventTime, kappa = self$kappa)
self$.setParameterType("median2", C_PARAM_GENERATED)
}
} else {
if (length(self$lambda1) > 0 && !all(is.na(self$lambda1)) &&
self$.getParameterType("median1") != C_PARAM_USER_DEFINED) {
self$median1 <- getMedianByLambda(self$lambda1, kappa = self$kappa)
self$.setParameterType("median1", C_PARAM_GENERATED)
}
if (length(self$lambda2) == 1 && !is.na(self$lambda2) &&
self$.getParameterType("median2") != C_PARAM_USER_DEFINED) {
self$median2 <- getMedianByLambda(self$lambda2, kappa = self$kappa)
self$.setParameterType("median2", C_PARAM_GENERATED)
}
}
},
.initPi = function() {
.logDebug(".initPi: set pi1, pi2, and eventTime to NA")
if (!is.na(self$eventTime) && self$.getParameterType("eventTime") == C_PARAM_USER_DEFINED) {
warning("'eventTime' (", round(self$eventTime, 3), ") will be ignored", call. = FALSE)
}
if (!is.na(self$pi1) && !identical(self$pi2, C_PI_1_DEFAULT) &&
!identical(self$pi2, C_PI_1_SAMPLE_SIZE_DEFAULT)) {
warning("'pi1' (", .arrayToString(self$pi1), ") will be ignored", call. = FALSE)
}
if (!is.na(self$pi2) && self$pi2 != C_PI_2_DEFAULT) {
warning("'pi2' (", self$pi2, ") will be ignored", call. = FALSE)
}
self$.setParameterType("eventTime", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("pi1", C_PARAM_NOT_APPLICABLE)
self$.setParameterType("pi2", C_PARAM_NOT_APPLICABLE)
self$eventTime <- NA_real_
self$pi1 <- NA_real_
self$pi2 <- NA_real_
if (length(self$lambda2) == 0 || any(is.na(self$lambda2))) {
stop(
C_EXCEPTION_TYPE_RUNTIME_ISSUE,
"'lambda2' must be defined before .initPi() can be called"
)
}
if (self$isUndefinedParameter("lambda2") || self$isNotApplicableParameter("lambda2")) {
self$.setParameterType("lambda2", C_PARAM_USER_DEFINED)
}
if (self$piecewiseSurvivalEnabled && length(self$hazardRatio) > 1) {
return(invisible())
}
if (length(self$lambda1) == 0 || any(is.na(self$lambda1))) {
if (length(self$hazardRatio) > 0 && !any(is.na(self$hazardRatio))) {
.logDebug(".initPi: calculate lambda1 by hazardRatio")
self$lambda1 <- self$lambda2 * self$hazardRatio^(1 / self$kappa)
self$.setParameterType("lambda1", C_PARAM_GENERATED)
} else if (length(self$lambda1) == 0) {
self$lambda1 <- NA_real_
} else if (self$delayedResponseAllowed) {
self$.setParameterType("lambda1", C_PARAM_USER_DEFINED)
}
}
},
.initHazardRatio = function(number = -1) {
.logDebug(".initHazardRatio(#%s)", number)
if (!is.null(self$hazardRatio) && length(self$hazardRatio) > 0 && !all(is.na(self$hazardRatio))) {
if ((length(self$lambda1) == 1 && is.na(self$lambda1)) ||
(self$isGeneratedParameter("lambda1") &&
(
self$.getParameterType("median1") != C_PARAM_USER_DEFINED ||
self$.getParameterType("median2") != C_PARAM_USER_DEFINED
)
) ||
(self$isGeneratedParameter("lambda2") &&
(
self$.getParameterType("median1") != C_PARAM_USER_DEFINED ||
self$.getParameterType("median2") != C_PARAM_USER_DEFINED
)
)
) {
self$.setParameterType("hazardRatio", C_PARAM_USER_DEFINED)
return(invisible())
}
if (!self$.silent) {
warning("'hazardRatio' (", .arrayToString(self$hazardRatio),
") will be ignored because it will be calculated",
call. = FALSE
)
}
}
if (any(is.na(self$lambda2))) {
stop(C_EXCEPTION_TYPE_MISSING_ARGUMENT, "'lambda2' must be specified")
}
if (any(is.na(self$lambda1))) {
if (self$delayedResponseAllowed && any(is.na(self$hazardRatio) &&
!any(is.na(self$piecewiseSurvivalTime)) &&
length(self$lambda2) == length(self$piecewiseSurvivalTime))) {
stop(C_EXCEPTION_TYPE_MISSING_ARGUMENT, "'hazardRatio' must be specified")
}
if (any(is.na(self$hazardRatio))) {
stop(
C_EXCEPTION_TYPE_MISSING_ARGUMENT,
"'hazardRatio', 'lambda1' or 'median1' must be specified"
)
}
stop(C_EXCEPTION_TYPE_MISSING_ARGUMENT, "'lambda1' must be specified")
}
self$.setParameterType("lambda1", C_PARAM_USER_DEFINED)
hr <- unique(round(self$lambda1 / self$lambda2, 8)^self$kappa)
if (length(hr) == 1) {
.logDebug(".init: calculate hazardRatio by lambda1 and lambda2 (one hazard ratio)")
self$hazardRatio <- ((self$lambda1 / self$lambda2)^self$kappa)[1]
self$.setParameterType("hazardRatio", C_PARAM_GENERATED)
return(invisible())
}
if (length(self$lambda2) == 1 && length(self$lambda1) > 1) {
.logDebug(".init: calculate hazardRatio by lambda1 and lambda2 (multiple lambda2 values)")
self$hazardRatio <- (self$lambda1 / self$lambda2)^self$kappa
self$.setParameterType("hazardRatio", C_PARAM_GENERATED)
return(invisible())
}
if (self$delayedResponseAllowed) {
.logDebug(".init: calculate hazardRatio by lambda1 and lambda2 (delayed response allowed)")
self$hazardRatio <- (self$lambda1 / self$lambda2)^self$kappa
self$.setParameterType("hazardRatio", C_PARAM_GENERATED)
self$delayedResponseEnabled <- TRUE
return(invisible())
}
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'hazardRatio' can only be calculated if 'unique(lambda1 / lambda2)' ",
"result in a single value; current result = ",
.arrayToString(round(hr, 4), vectorLookAndFeelEnabled = TRUE),
" (e.g., delayed response is not allowed)"
)
},
.validateInitialization = function() {
if (length(self$piecewiseSurvivalTime) == 0) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'piecewiseSurvivalTime' must contain at least one survival start time"
)
}
if (any(is.na(self$piecewiseSurvivalTime))) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'piecewiseSurvivalTime' must contain valid survival start times"
)
}
if (self$piecewiseSurvivalTime[1] != 0) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"the first value of 'piecewiseSurvivalTime' must be 0"
)
}
if (length(self$piecewiseSurvivalTime) != length(self$lambda2)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"length of 'piecewiseSurvivalTime' (", length(self$piecewiseSurvivalTime),
") and length of 'lambda2' (", length(self$lambda2), ") must be equal"
)
}
.assertValuesAreStrictlyIncreasing(self$piecewiseSurvivalTime, "piecewiseSurvivalTime")
if ((length(self$lambda1) != 1 || is.na(self$lambda1)) &&
!(self$.getParameterType("lambda1") %in% c(C_PARAM_GENERATED, C_PARAM_USER_DEFINED))) {
if (length(self$hazardRatio) == 1 && !is.na(self$hazardRatio)) {
self$lambda1 <- self$lambda2 * self$hazardRatio^(1 / self$kappa)
self$.setParameterType("lambda1", C_PARAM_GENERATED)
} else if (length(self$hazardRatio) > 1 && self$delayedResponseAllowed &&
!is.na(self$hazardRatio[1])) {
if (!self$delayedResponseEnabled && self$.isLambdaBased()) {
if (self$delayedResponseAllowed) {
if (length(self$hazardRatio) != length(self$lambda2)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"length of 'hazardRatio' (", length(self$hazardRatio),
") and length of 'lambda2' (", length(self$lambda2), ") must be equal"
)
}
self$delayedResponseEnabled <- TRUE
} else {
warning("Only the first 'hazardRatio' (", round(self$hazardRatio[1], 4),
") was used for piecewise survival time definition",
call. = FALSE
)
self$hazardRatio <- self$hazardRatio[1]
}
self$lambda1 <- self$lambda2 * self$hazardRatio^(1 / self$kappa)
self$.setParameterType("lambda1", C_PARAM_GENERATED)
}
} else if (!self$delayedResponseEnabled && !(length(self$lambda2) == 1 && length(self$lambda1) > 1)) {
if (length(self$lambda1) > 1) {
warning("'lambda1' (", .arrayToString(self$lambda1),
") will be ignored",
call. = FALSE
)
}
self$lambda1 <- NA_real_
self$.setParameterType("lambda1", C_PARAM_NOT_APPLICABLE)
}
} else if (length(self$hazardRatio) == 1 && !is.na(self$hazardRatio) &&
length(self$lambda1) > 0 && !any(is.na(self$lambda1)) &&
length(self$lambda2) > 0 && !any(is.na(self$lambda2))) {
target <- self$lambda2 * self$hazardRatio^(1 / self$kappa)
if (length(self$lambda1) > 0 && !all(is.na(self$lambda1)) &&
!isTRUE(all.equal(target, self$lambda1))) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'lambda1' (", .arrayToString(self$lambda1), ") ",
"is not as expected (", .arrayToString(target), ") ",
"for given hazard ratio ", self$hazardRatio
)
}
}
if (self$piecewiseSurvivalEnabled && !(length(self$lambda1) == 1 && is.na(self$lambda1)) &&
length(self$piecewiseSurvivalTime) != length(self$lambda1)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"length of 'piecewiseSurvivalTime' (", length(self$piecewiseSurvivalTime),
") and length of 'lambda1' (", length(self$lambda1), ") must be equal"
)
}
}
)
)
#'
#' @name AccrualTime
#'
#' @title
#' Accrual Time
#'
#' @description
#' Class for the definition of accrual time and accrual intensity.
#'
#' @template field_endOfAccrualIsUserDefined
#' @template field_followUpTimeMustBeUserDefined
#' @template field_maxNumberOfSubjectsIsUserDefined
#' @template field_maxNumberOfSubjectsCanBeCalculatedDirectly
#' @template field_absoluteAccrualIntensityEnabled
#' @template field_accrualTime
#' @template field_accrualIntensity
#' @template field_accrualIntensityRelative
#' @template field_maxNumberOfSubjects
#' @template field_remainingTime
#' @template field_piecewiseAccrualEnabled
#'
#' @details
#' \code{AccrualTime} is a class for the definition of accrual time and accrual intensity.
#'
#' @include f_core_constants.R
#' @include f_core_utilities.R
#' @include class_core_parameter_set.R
#'
#' @keywords internal
#'
#' @importFrom methods new
#'
AccrualTime <- R6::R6Class("AccrualTime",
inherit = TimeDefinition,
public = list(
.showWarnings = NULL,
endOfAccrualIsUserDefined = NULL,
followUpTimeMustBeUserDefined = NULL,
maxNumberOfSubjectsIsUserDefined = NULL,
maxNumberOfSubjectsCanBeCalculatedDirectly = NULL,
absoluteAccrualIntensityEnabled = NULL,
accrualTime = NULL,
accrualTimeOriginal = NULL,
accrualIntensity = NULL,
accrualIntensityRelative = NULL,
maxNumberOfSubjects = NULL,
remainingTime = NULL,
piecewiseAccrualEnabled = NULL,
initialize = function(accrualTime = NA_real_,
...,
accrualIntensity = NA_real_,
maxNumberOfSubjects = NA_real_,
showWarnings = TRUE,
absoluteAccrualIntensityEnabled = NA) {
super$initialize()
self$accrualTime <- accrualTime
self$accrualIntensity <- accrualIntensity
self$maxNumberOfSubjects <- maxNumberOfSubjects
self$.showWarnings <- showWarnings
self$absoluteAccrualIntensityEnabled <- absoluteAccrualIntensityEnabled
self$endOfAccrualIsUserDefined <- NA
self$followUpTimeMustBeUserDefined <- NA
self$maxNumberOfSubjectsIsUserDefined <- NA
self$maxNumberOfSubjectsCanBeCalculatedDirectly <- TRUE
self$.setParameterType("endOfAccrualIsUserDefined", C_PARAM_GENERATED)
self$.setParameterType("followUpTimeMustBeUserDefined", C_PARAM_GENERATED)
self$.setParameterType("maxNumberOfSubjectsIsUserDefined", C_PARAM_GENERATED)
self$.setParameterType("maxNumberOfSubjectsCanBeCalculatedDirectly", C_PARAM_GENERATED)
self$.setParameterType(
"absoluteAccrualIntensityEnabled",
ifelse(is.na(self$absoluteAccrualIntensityEnabled),
C_PARAM_GENERATED, C_PARAM_USER_DEFINED
)
)
self$accrualTimeOriginal <- NA_real_
self$.setParameterType("accrualTimeOriginal", C_PARAM_NOT_APPLICABLE)
self$accrualIntensityRelative <- NA_real_
self$.setParameterType("accrualIntensityRelative", C_PARAM_NOT_APPLICABLE)
self$remainingTime <- NA_real_
self$.init(self$accrualTime)
# case 6 correction
if (!self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
!self$absoluteAccrualIntensityEnabled) {
self$remainingTime <- NA_real_
self$.setParameterType("remainingTime", C_PARAM_NOT_APPLICABLE)
self$accrualTime <- self$accrualTime[seq_len(length(self$accrualIntensity))]
}
self$.initAccrualIntensityAbsolute()
self$.validateFormula()
self$.showWarningIfCaseIsNotAllowed()
},
.asDataFrame = function() {
accrualIntensityTemp <- self$accrualIntensity
if (!all(is.na(self$accrualIntensityRelative))) {
accrualIntensityTemp <- self$accrualIntensityRelative
}
if (length(accrualIntensityTemp) + 1 == length(self$accrualTime)) {
accrualIntensityTemp <- c(accrualIntensityTemp, NA_real_)
}
data <- data.frame(
accrualTime = self$accrualTime,
accrualIntensity = accrualIntensityTemp
)
rownames(data) <- as.character(1:nrow(data))
colnames(data) <- c(
"Start time",
.getParameterCaption("accrualIntensity", self)
)
return(data)
},
show = function(showType = 1, digits = NA_integer_) {
self$.show(showType = showType, digits = digits, consoleOutputEnabled = TRUE)
},
.isAbsoluteAccrualIntensity = function(x) {
return(!self$.isRelativeAccrualIntensity(x))
},
.isRelativeAccrualIntensity = function(x) {
return(all(x < 1))
},
.show = function(showType = 1, digits = NA_integer_, consoleOutputEnabled = TRUE) {
"Method for automatically printing accrual time objects"
self$.resetCat()
if (showType == 2) {
super$.show(
showType = showType, digits = digits,
consoleOutputEnabled = consoleOutputEnabled
)
} else {
self$.cat("Accrual time and intensity:\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
if (!self$isAccrualTimeEnabled()) {
self$.cat(" Accrual time is disabled.\n",
consoleOutputEnabled = consoleOutputEnabled
)
} else if (length(self$accrualTime) == 1) {
self$.cat(" At all times:", self$accrualIntensity[1], "\n",
consoleOutputEnabled = consoleOutputEnabled
)
} else {
accrualTimeStr <- format(self$accrualTime)
accrualIntensityStr <- format(self$accrualIntensity)
for (i in seq_len(length(self$accrualTime))) {
prefix <- ifelse(i == length(self$accrualTime) - 1, "<=", " <")
suffix <- ""
if (!self$maxNumberOfSubjectsIsUserDefined) {
suffix <- " "
}
if (i < length(self$accrualTime)) {
self$.cat(" ", accrualTimeStr[i], " - ", prefix, accrualTimeStr[i + 1], suffix, ": ",
accrualIntensityStr[i], "\n",
consoleOutputEnabled = consoleOutputEnabled
)
} else if (!self$maxNumberOfSubjectsIsUserDefined && !is.na(accrualIntensityStr[i]) &&
accrualIntensityStr[i] != "NA") {
self$.cat(" ", accrualTimeStr[i], " - <=[?]: ",
accrualIntensityStr[i], "\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
}
self$.cat("", consoleOutputEnabled = consoleOutputEnabled)
}
self$.cat("\n", consoleOutputEnabled = consoleOutputEnabled)
if (self$isAccrualTimeEnabled()) {
self$.showFormula(consoleOutputEnabled = consoleOutputEnabled)
self$.cat("\n", consoleOutputEnabled = consoleOutputEnabled)
self$.showCase(consoleOutputEnabled = consoleOutputEnabled)
self$.cat("\n", consoleOutputEnabled = consoleOutputEnabled)
}
self$.cat("Details:\n\n", sep = "", heading = 1, consoleOutputEnabled = consoleOutputEnabled)
self$.showParametersOfOneGroup(self$.getUserDefinedParameters(), "User defined parameters",
orderByParameterName = FALSE, consoleOutputEnabled = consoleOutputEnabled
)
self$.showParametersOfOneGroup(self$.getDefaultParameters(), "Default parameters",
orderByParameterName = FALSE, consoleOutputEnabled = consoleOutputEnabled
)
self$.showParametersOfOneGroup(self$.getGeneratedParameters(), "Generated parameters",
orderByParameterName = FALSE, consoleOutputEnabled = consoleOutputEnabled
)
self$.showUnknownParameters(consoleOutputEnabled = consoleOutputEnabled)
}
},
.getFormula = function() {
s <- ""
for (i in seq_len(length(self$accrualTime))) {
if (i < length(self$accrualTime)) {
s <- paste0(
s, (round(self$accrualTime[i + 1], 4) - round(self$accrualTime[i], 4)),
" * ", round(self$accrualIntensity[i], 4)
)
if (!self$absoluteAccrualIntensityEnabled &&
(!self$maxNumberOfSubjectsIsUserDefined || !self$endOfAccrualIsUserDefined)) {
s <- paste0(s, " * c ")
}
if (i < length(self$accrualIntensity)) {
s <- paste0(s, " + ")
}
}
}
return(s)
},
.validateFormula = function() {
if (is.na(self$maxNumberOfSubjects) || length(self$accrualTime) != length(self$accrualIntensity) + 1) {
return(invisible())
}
numberOfSubjects <- 0
for (i in seq_len(length(self$accrualTime))) {
if (i < length(self$accrualTime)) {
numberOfSubjects <- numberOfSubjects +
(self$accrualTime[i + 1] - self$accrualTime[i]) * self$accrualIntensity[i]
}
}
if (!isTRUE(all.equal(numberOfSubjects, self$maxNumberOfSubjects, tolerance = 1e-03)) &&
self$absoluteAccrualIntensityEnabled) {
stop(
C_EXCEPTION_TYPE_CONFLICTING_ARGUMENTS,
"'maxNumberOfSubjects' (", self$maxNumberOfSubjects, ") disagrees with ",
"the defined accrual time and intensity: ",
self$.getFormula(), " = ", numberOfSubjects
)
}
},
.showWarningIfCaseIsNotAllowed = function() {
caseIsAllowed <- TRUE
if (!self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
!self$absoluteAccrualIntensityEnabled) {
caseIsAllowed <- FALSE
} else if (!self$endOfAccrualIsUserDefined && !self$maxNumberOfSubjectsIsUserDefined &&
self$followUpTimeMustBeUserDefined && !self$absoluteAccrualIntensityEnabled) {
caseIsAllowed <- FALSE
}
if (!caseIsAllowed) {
warning("The specified accrual time and intensity cannot be ",
"supplemented automatically with the missing information; ",
"therefore further calculations are not possible",
call. = FALSE
)
}
},
.showFormula = function(consoleOutputEnabled) {
self$.cat("Formula:\n", sep = "", heading = 1, consoleOutputEnabled = consoleOutputEnabled)
self$.cat(" ", consoleOutputEnabled = consoleOutputEnabled)
self$.cat("maxNumberOfSubjects = ", consoleOutputEnabled = consoleOutputEnabled)
if (!is.na(self$maxNumberOfSubjects)) {
self$.cat(self$maxNumberOfSubjects, " = ", consoleOutputEnabled = consoleOutputEnabled)
}
self$.cat(self$.getFormula(), consoleOutputEnabled = consoleOutputEnabled)
if (length(self$accrualTime) == length(self$accrualIntensity)) {
self$.cat("(x - ", self$accrualTime[length(self$accrualTime)], ") * ",
self$accrualIntensity[length(self$accrualIntensity)],
consoleOutputEnabled = consoleOutputEnabled
)
if (!self$absoluteAccrualIntensityEnabled &&
(!self$maxNumberOfSubjectsIsUserDefined || !self$endOfAccrualIsUserDefined)) {
self$.cat(" * c ", consoleOutputEnabled = consoleOutputEnabled)
}
self$.cat(", where 'x' is the unknown last accrual time",
consoleOutputEnabled = consoleOutputEnabled
)
if (!self$absoluteAccrualIntensityEnabled &&
(!self$maxNumberOfSubjectsIsUserDefined || !self$endOfAccrualIsUserDefined)) {
self$.cat(" and 'c' a constant factor", consoleOutputEnabled = consoleOutputEnabled)
}
} else if (!self$absoluteAccrualIntensityEnabled &&
(!self$maxNumberOfSubjectsIsUserDefined || !self$endOfAccrualIsUserDefined)) {
self$.cat(", where 'c' is a constant factor", consoleOutputEnabled = consoleOutputEnabled)
}
self$.cat("\n", consoleOutputEnabled = consoleOutputEnabled)
},
.showCase = function(consoleOutputEnabled = TRUE) {
caseIsAllowed <- TRUE
prefix <- " "
# Case 1
# example: getAccrualTime(accrualTime = c(0, 6, 30), accrualIntensity = c(22, 33),
# maxNumberOfSubjects = 1000)
if (self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
self$absoluteAccrualIntensityEnabled) {
self$.cat("Case (#1):\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "End of accrual, absolute accrual intensity ",
"and 'maxNumberOfSubjects' are given, ",
" 'followUpTime'** shall be calculated.\n",
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "Example: getAccrualTime(accrualTime = c(0, 6, 30), ",
"accrualIntensity = c(22, 33), maxNumberOfSubjects = 924)\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
# Case 2
# example: getAccrualTime(accrualTime = c(0, 6, 30), accrualIntensity = c(0.22, 0.33),
# maxNumberOfSubjects = 1000)
else if (self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
!self$absoluteAccrualIntensityEnabled) {
self$.cat("Case (#2):\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "End of accrual, relative accrual intensity ",
"and 'maxNumberOfSubjects' are given, ",
"absolute accrual intensity* and 'followUpTime'** shall be calculated.\n",
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "Example: getAccrualTime(accrualTime = c(0, 6, 30), ",
"accrualIntensity = c(0.22, 0.33), maxNumberOfSubjects = 1000)\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
# Case 3
# example: getAccrualTime(accrualTime = c(0, 6, 30), accrualIntensity = c(22, 33))
else if (self$endOfAccrualIsUserDefined && !self$maxNumberOfSubjectsIsUserDefined &&
self$absoluteAccrualIntensityEnabled) {
self$.cat("Case (#3):\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "End of accrual and absolute accrual intensity are given, ",
"'maxNumberOfSubjects'* and 'followUpTime'** shall be calculated.\n",
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "Example: getAccrualTime(accrualTime = c(0, 6, 30), accrualIntensity = c(22, 33))\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
# Case 4
# example: getAccrualTime(accrualTime = c(0, 6, 30), accrualIntensity = c(0.22, 0.33))
else if (self$endOfAccrualIsUserDefined && !self$maxNumberOfSubjectsIsUserDefined &&
!self$absoluteAccrualIntensityEnabled) {
self$.cat("Case (#4):\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "End of accrual, relative accrual ",
"intensity and 'followUpTime' are given, ",
"absolute accrual intensity** and 'maxNumberOfSubjects'** shall be calculated.\n",
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "Example: getAccrualTime(accrualTime = c(0, 6, 30), accrualIntensity = c(0.22, 0.33))\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
# Case 5
# example: getAccrualTime(accrualTime = c(0, 6), accrualIntensity = c(22, 33),
# maxNumberOfSubjects = 1000)
else if (!self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
self$absoluteAccrualIntensityEnabled) {
self$.cat("Case (#5):\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "'maxNumberOfSubjects' and absolute accrual intensity are given, ",
"end of accrual* and 'followUpTime'** shall be calculated\n",
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "Example: getAccrualTime(accrualTime = c(0, 6), ",
"accrualIntensity = c(22, 33), maxNumberOfSubjects = 1000)\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
# Case 6
# example: getAccrualTime(accrualTime = c(0, 6), accrualIntensity = c(0.22, 0.33),
# maxNumberOfSubjects = 1000)
else if (!self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
!self$absoluteAccrualIntensityEnabled) {
caseIsAllowed <- FALSE
self$.cat("Case (#6):\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "'maxNumberOfSubjects' and relative accrual intensity are given, ",
"absolute accrual intensity@, end of accrual* and 'followUpTime'** shall be calculated\n",
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "Example: getAccrualTime(accrualTime = c(0, 6), ",
"accrualIntensity = c(0.22, 0.33), maxNumberOfSubjects = 1000)\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
# Case 7
# example: getAccrualTime(accrualTime = c(0, 6), accrualIntensity = c(22, 33))
else if (!self$endOfAccrualIsUserDefined && !self$maxNumberOfSubjectsIsUserDefined &&
self$followUpTimeMustBeUserDefined && self$absoluteAccrualIntensityEnabled) {
self$.cat("Case (#7):\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "'followUpTime' and absolute accrual intensity are given, ",
"end of accrual** and 'maxNumberOfSubjects'** shall be calculated\n",
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "Example: getAccrualTime(accrualTime = c(0, 6), accrualIntensity = c(22, 33))\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
# Case 8
# example: getAccrualTime(accrualTime = c(0, 6), accrualIntensity = c(0.22, 0.33))
else if (!self$endOfAccrualIsUserDefined && !self$maxNumberOfSubjectsIsUserDefined &&
self$followUpTimeMustBeUserDefined && !self$absoluteAccrualIntensityEnabled) {
caseIsAllowed <- FALSE
self$.cat("Case (#8):\n",
sep = "", heading = 1,
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "'followUpTime' and relative accrual intensity are given, ",
"absolute accrual intensity@, end of accrual and 'maxNumberOfSubjects' shall be calculated\n",
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "Example: getAccrualTime(accrualTime = c(0, 6), accrualIntensity = c(0.22, 0.33))\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
if (!caseIsAllowed) {
self$.cat(prefix, "(@) Cannot be calculated.\n",
consoleOutputEnabled = consoleOutputEnabled
)
}
self$.cat(prefix, "(*) Can be calculated directly.\n",
consoleOutputEnabled = consoleOutputEnabled
)
self$.cat(prefix, "(**) Cannot be calculated directly but with ",
"'getSampleSizeSurvival()' or 'getPowerSurvival()'.\n",
consoleOutputEnabled = consoleOutputEnabled
)
},
.followUpTimeShallBeCalculated = function() {
# Case 1: 'followUpTime'** shall be calculated
if (self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
self$absoluteAccrualIntensityEnabled) {
return(TRUE)
}
# Case 2: 'followUpTime'** shall be calculated
else if (self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
!self$absoluteAccrualIntensityEnabled) {
return(TRUE)
}
# Case 3: 'followUpTime'** shall be calculated
else if (self$endOfAccrualIsUserDefined && !self$maxNumberOfSubjectsIsUserDefined &&
self$absoluteAccrualIntensityEnabled) {
return(TRUE)
}
# Case 5: 'followUpTime'** shall be calculated
else if (!self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
self$absoluteAccrualIntensityEnabled) {
return(TRUE)
}
# Case 6: 'followUpTime'** shall be calculated
else if (!self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
!self$absoluteAccrualIntensityEnabled) {
return(TRUE)
}
# (**) Cannot be calculated directly but with 'getSampleSizeSurvival()' or 'getPowerSurvival()'
return(FALSE)
},
.validate = function() {
# Case 6
if (!self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
!self$absoluteAccrualIntensityEnabled) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"the calculation of 'followUpTime' for given 'maxNumberOfSubjects' ",
"and relative accrual intensities (< 1) ",
"can only be done if end of accrual is defined"
)
}
# Case 8
else if (!self$endOfAccrualIsUserDefined && !self$maxNumberOfSubjectsIsUserDefined &&
self$followUpTimeMustBeUserDefined && !self$absoluteAccrualIntensityEnabled) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"the calculation of 'maxNumberOfSubjects' for given 'followUpTime' ",
"and relative accrual intensities (< 1) ",
"can only be done if end of accrual is defined"
)
}
},
.toString = function(startWithUpperCase = FALSE) {
s <- "accrual time"
return(ifelse(startWithUpperCase, .firstCharacterToUpperCase(s), s))
},
.getAccrualTimeWithoutLeadingZero = function() {
if (length(self$accrualTime) <= 1) {
return(NA_real_)
}
return(self$accrualTime[2:length(self$accrualTime)])
},
isAccrualTimeEnabled = function() {
if (length(self$accrualTime) == 0) {
return(FALSE)
}
if (length(self$accrualTime) == 1 && is.na(self$accrualTime)) {
return(FALSE)
}
return(TRUE)
},
.initFromList = function(accrualTimeList) {
if (!is.list(accrualTimeList)) {
stop(C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT, "'accrualTime' must be a list")
}
if (length(accrualTimeList) == 0) {
stop(C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT, "'accrualTime' must contain at least one entry")
}
if (is.null(names(accrualTimeList))) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'accrualTime' must be a named list where the names specify ",
"the time regions and the values the accrual time"
)
}
if (self$.showWarnings && !all(is.na(self$accrualIntensity)) &&
(length(self$accrualIntensity) != 1 ||
self$accrualIntensity != C_ACCRUAL_INTENSITY_DEFAULT)) {
warning("'accrualIntensity' (", .arrayToString(self$accrualIntensity),
") will be ignored because 'accrualTime' is a list",
call. = FALSE
)
}
self$accrualTime <- numeric(0)
self$accrualIntensity <- numeric(0)
timeRegions <- names(accrualTimeList)
endOfAccrualIsUndefined <- FALSE
self$accrualTime <- c(self$accrualTime, 0)
for (i in seq_len(length(timeRegions))) {
timePeriod <- timeRegions[i]
accrualTimeValue <- accrualTimeList[[timePeriod]]
.assertIsSingleNumber(accrualTimeValue, paste0("accrualTime[", i, "]"))
settings <- self$.validateTimePeriod(timePeriod,
i = i,
n = length(timeRegions), accrualTimeMode = TRUE
)
timePeriod <- settings$timePeriod
endOfAccrualIsUndefined <- settings$endOfAccrualIsUndefined
if (i < length(timeRegions)) {
parts <- strsplit(timePeriod, "- *(< *)?", perl = TRUE)[[1]]
if (length(parts) != 2) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"all regions (", timePeriod, ") must have the format ",
"\"time_1 - <time_2\", e.g., \"3 - <6\""
)
}
self$accrualTime <- c(self$accrualTime, as.numeric(trimws(parts[2])))
} else {
parts <- strsplit(timePeriod, " *< *", perl = TRUE)[[1]]
if (length(parts) == 2) {
self$accrualTime <- c(self$accrualTime, as.numeric(trimws(parts[2])))
}
}
self$accrualIntensity <- c(self$accrualIntensity, accrualTimeValue)
}
self$.setParameterType("accrualTime", C_PARAM_USER_DEFINED)
self$.setParameterType("accrualIntensity", C_PARAM_USER_DEFINED)
return(endOfAccrualIsUndefined = endOfAccrualIsUndefined)
},
.initAccrualIntensityAbsolute = function() {
if (is.null(self$maxNumberOfSubjects) || length(self$maxNumberOfSubjects) != 1 ||
is.na(self$maxNumberOfSubjects) || self$maxNumberOfSubjects == 0) {
if (!self$absoluteAccrualIntensityEnabled) {
self$accrualIntensityRelative <- self$accrualIntensity
}
return(invisible())
}
if (!self$endOfAccrualIsUserDefined && self$maxNumberOfSubjectsIsUserDefined &&
!self$absoluteAccrualIntensityEnabled) {
return(invisible()) # case 6
}
if (length(self$accrualTime) >= 2 && length(self$accrualTime) == length(self$accrualIntensity) + 1 &&
!any(is.na(self$accrualTime)) && !any(is.na(self$accrualIntensity))) {
len <- length(self$accrualIntensity)
accrualIntensityAbsolute <- self$maxNumberOfSubjects / sum((self$accrualTime[2:(len + 1)] -
self$accrualTime[1:len]) * self$accrualIntensity) * self$accrualIntensity
if (!isTRUE(all.equal(accrualIntensityAbsolute, self$accrualIntensity, tolerance = 1e-06)) &&
!isTRUE(all.equal(accrualIntensityAbsolute, 0, tolerance = 1e-06))) {
self$.validateAccrualTimeAndIntensity()
if (self$absoluteAccrualIntensityEnabled &&
self$.getParameterType("maxNumberOfSubjects") == C_PARAM_USER_DEFINED) {
if (self$.getParameterType("accrualTime") == C_PARAM_DEFAULT_VALUE) {
self$accrualTime <- self$maxNumberOfSubjects / self$accrualIntensity
self$.setParameterType("accrualTime", C_PARAM_GENERATED)
self$remainingTime <- self$accrualTime
self$accrualTime <- c(0, self$accrualTime)
} else {
stop(
C_EXCEPTION_TYPE_CONFLICTING_ARGUMENTS,
"'maxNumberOfSubjects' (", self$maxNumberOfSubjects, ") disagrees with ",
"the defined accrual time (", .arrayToString(self$accrualTime), ") and intensity: ",
self$.getFormula(), " = ", self$.getSampleSize()
)
}
} else {
if (!self$absoluteAccrualIntensityEnabled &&
self$.getParameterType("accrualIntensity") == C_PARAM_USER_DEFINED &&
self$.getParameterType("accrualTime") == C_PARAM_DEFAULT_VALUE &&
self$.getParameterType("maxNumberOfSubjects") == C_PARAM_USER_DEFINED) {
if (self$.showWarnings) {
warning("'accrualIntensity' (", self$accrualIntensity, ") will be ignored", call. = FALSE)
}
self$accrualIntensityRelative <- C_ACCRUAL_INTENSITY_DEFAULT
self$accrualIntensity <- accrualIntensityAbsolute
self$.setParameterType("accrualIntensity", C_PARAM_GENERATED)
self$.setParameterType("remainingTime", C_PARAM_NOT_APPLICABLE)
} else {
self$accrualIntensityRelative <- self$accrualIntensity
self$accrualIntensity <- accrualIntensityAbsolute
self$.setParameterType("accrualIntensity", C_PARAM_GENERATED)
self$.setParameterType("accrualIntensityRelative", C_PARAM_USER_DEFINED)
}
}
}
}
},
.isNoPiecewiseAccrualTime = function(accrualTimeArg) {
if (length(accrualTimeArg) == 0 || any(is.na(accrualTimeArg)) ||
!all(is.numeric(accrualTimeArg))) {
stop(C_EXCEPTION_TYPE_RUNTIME_ISSUE, "'accrualTimeArg' must a be valid numeric vector")
}
if (length(accrualTimeArg) == 1) {
return(TRUE)
}
if (length(accrualTimeArg) == 2 && accrualTimeArg[1] == 0) {
return(TRUE)
}
return(FALSE)
},
.init = function(accrualTimeArg) {
if (length(accrualTimeArg) == 0) {
stop(C_EXCEPTION_TYPE_MISSING_ARGUMENT, "'accrualTime' must be defined")
}
if (length(accrualTimeArg) == 1 && is.numeric(accrualTimeArg) && is.na(accrualTimeArg)) {
accrualTimeArg <- C_ACCRUAL_TIME_DEFAULT
}
calculateLastAccrualTimeEnabled <- FALSE
if (is.list(accrualTimeArg)) {
endOfAccrualIsUndefined <- self$.initFromList(accrualTimeArg)
calculateLastAccrualTimeEnabled <- endOfAccrualIsUndefined &&
!is.null(self$maxNumberOfSubjects) && length(self$maxNumberOfSubjects) == 1 &&
!is.na(self$maxNumberOfSubjects)
} else if (is.numeric(accrualTimeArg)) {
.assertIsNumericVector(accrualTimeArg, "accrualTime")
if (length(self$accrualIntensity) > 1) {
.assertIsNumericVector(self$accrualIntensity, "accrualIntensity")
}
if (self$.isNoPiecewiseAccrualTime(accrualTimeArg) &&
(length(self$accrualIntensity) == 0 || is.null(self$accrualIntensity) ||
all(is.na(self$accrualIntensity)) ||
all(self$accrualIntensity == C_ACCRUAL_INTENSITY_DEFAULT))) {
accrualTimeArg <- accrualTimeArg[length(accrualTimeArg)]
self$accrualTime <- c(0L, accrualTimeArg)
self$.setParameterType("accrualTime", ifelse(
isTRUE(all.equal(as.integer(self$accrualTime), C_ACCRUAL_TIME_DEFAULT)),
C_PARAM_DEFAULT_VALUE, C_PARAM_USER_DEFINED
))
self$accrualIntensity <- C_ACCRUAL_INTENSITY_DEFAULT
self$.setParameterType("accrualIntensity", C_PARAM_DEFAULT_VALUE)
self$.setParameterType(
"maxNumberOfSubjects",
ifelse(length(self$maxNumberOfSubjects) == 1 && is.na(self$maxNumberOfSubjects),
C_PARAM_DEFAULT_VALUE, C_PARAM_USER_DEFINED
)
)
self$endOfAccrualIsUserDefined <- length(self$accrualTime) == length(self$accrualIntensity) + 1
self$maxNumberOfSubjectsIsUserDefined <-
self$.getParameterType("maxNumberOfSubjects") == C_PARAM_USER_DEFINED
self$followUpTimeMustBeUserDefined <- !self$endOfAccrualIsUserDefined &&
!self$maxNumberOfSubjectsIsUserDefined
self$absoluteAccrualIntensityEnabled <- FALSE
if (self$maxNumberOfSubjectsIsUserDefined) {
self$accrualIntensity <- self$maxNumberOfSubjects / self$accrualTime[length(self$accrualTime)]
self$.setParameterType("accrualIntensity", C_PARAM_GENERATED)
}
return(invisible())
}
self$accrualTime <- accrualTimeArg
if (length(self$accrualTime) == 0) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'accrualTime' must contain at least one time value"
)
}
if (self$accrualTime[1] != 0) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"the first value of 'accrualTime' (", .arrayToString(self$accrualTime), ") must be 0"
)
}
self$.setParameterType("accrualTime", ifelse(
isTRUE(all.equal(self$accrualTime, C_ACCRUAL_TIME_DEFAULT)),
C_PARAM_DEFAULT_VALUE, C_PARAM_USER_DEFINED
))
self$.setParameterType("accrualIntensity", C_PARAM_USER_DEFINED)
} else {
stop(C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT, "'accrualTime' must be a list or a numeric vector")
}
if (is.na(self$absoluteAccrualIntensityEnabled)) {
self$absoluteAccrualIntensityEnabled <- self$.isAbsoluteAccrualIntensity(self$accrualIntensity)
}
if (is.null(self$maxNumberOfSubjects) || length(self$maxNumberOfSubjects) == 0 ||
any(is.na(self$maxNumberOfSubjects))) {
if (length(self$accrualTime) != length(self$accrualIntensity) + 1 ||
!self$absoluteAccrualIntensityEnabled) {
self$maxNumberOfSubjectsCanBeCalculatedDirectly <- FALSE
}
self$.setParameterType("maxNumberOfSubjects", C_PARAM_NOT_APPLICABLE)
} else {
if (!(length(self$accrualTime) %in% c(
length(self$accrualIntensity),
length(self$accrualIntensity) + 1
))) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"length of 'accrualTime' (", length(self$accrualTime),
") must be equal to length of 'accrualIntensity' if the last 'accrualTime' ",
"shall be calculated ",
"based on 'maxNumberOfSubjects' or length of 'accrualIntensity' (",
length(self$accrualIntensity), ") + 1 otherwise"
)
}
if (length(self$accrualTime) == length(self$accrualIntensity)) {
calculateLastAccrualTimeEnabled <- TRUE
}
self$.setParameterType("maxNumberOfSubjects", C_PARAM_USER_DEFINED)
}
self$endOfAccrualIsUserDefined <- length(self$accrualTime) == length(self$accrualIntensity) + 1
if (calculateLastAccrualTimeEnabled) {
self$.calculateRemainingTime()
} else if (self$maxNumberOfSubjectsCanBeCalculatedDirectly) {
if (length(self$accrualTime) == 1) {
if (length(self$maxNumberOfSubjects) > 0 && !is.na(self$maxNumberOfSubjects) &&
self$maxNumberOfSubjects > 0 && self$maxNumberOfSubjects < self$accrualIntensity[1]) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'maxNumberOfSubjects' (", self$maxNumberOfSubjects, ") ",
"must be >= ", self$accrualIntensity[1], " ('accrualIntensity')"
)
}
self$remainingTime <- self$accrualTime
self$.setParameterType("remainingTime", C_PARAM_USER_DEFINED)
} else if (length(self$accrualTime) > 1) {
sampleSize <- self$.getSampleSize()
if (!isTRUE(all.equal(sampleSize, self$maxNumberOfSubjects, tolerance = 1e-04))) {
if (length(self$maxNumberOfSubjects) == 1 && !is.na(self$maxNumberOfSubjects) &&
self$maxNumberOfSubjects > 0 && self$maxNumberOfSubjects < sampleSize) {
if (length(self$accrualIntensity) == 1 && length(self$accrualTime) == 1) {
self$.setParameterType("maxNumberOfSubjects", C_PARAM_USER_DEFINED)
self$accrualTime <- 0
self$.calculateRemainingTime()
} else {
if (length(self$accrualTime) == length(self$accrualIntensity) + 1 &&
self$absoluteAccrualIntensityEnabled) {
stop(
C_EXCEPTION_TYPE_CONFLICTING_ARGUMENTS,
"'maxNumberOfSubjects' (", self$maxNumberOfSubjects, ") disagrees with ",
"the defined accrual time and intensity: ",
self$.getFormula(), " = ", sampleSize
)
} else {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT, "'maxNumberOfSubjects' (",
self$maxNumberOfSubjects, ") ", "must be >= ", sampleSize
)
}
}
} else {
if ((length(self$maxNumberOfSubjects) != 1 || is.na(self$maxNumberOfSubjects)) &&
self$absoluteAccrualIntensityEnabled) {
self$maxNumberOfSubjects <- sampleSize
self$.setParameterType("maxNumberOfSubjects", C_PARAM_GENERATED)
}
self$remainingTime <- self$accrualTime[length(self$accrualTime)] -
self$accrualTime[length(self$accrualTime) - 1]
self$.setParameterType(
"remainingTime",
ifelse(!isTRUE(all.equal(0, self$remainingTime, tolerance = 1e-06)),
C_PARAM_GENERATED, C_PARAM_NOT_APPLICABLE
)
)
}
}
}
}
self$.validateInitialization()
self$maxNumberOfSubjectsIsUserDefined <- self$.getParameterType("maxNumberOfSubjects") == C_PARAM_USER_DEFINED
self$followUpTimeMustBeUserDefined <- !self$endOfAccrualIsUserDefined &&
!self$maxNumberOfSubjectsIsUserDefined
},
.getSampleSize = function() {
if (length(self$accrualTime) < 2) {
return(0)
}
sampleSize <- 0
for (i in 2:length(self$accrualTime)) {
time <- self$accrualTime[i] - self$accrualTime[i - 1]
sampleSize <- sampleSize + time * self$accrualIntensity[i - 1]
}
return(sampleSize)
},
.getValuesAfterDecimalPoint = function(x) {
values <- c()
for (value in x) {
baseLevel <- value - floor(value)
if (baseLevel == 0) {
baseLevel <- 1
}
values <- c(values, baseLevel)
}
return(values)
},
.getBaseLevel = function(x) {
return(min(self$.getValuesAfterDecimalPoint(x[x > 0])))
},
.calcSampleSize = function() {
if (length(self$accrualTime) <= 1) {
return(0)
}
accrualTimeTemp <- self$accrualTime
accrualIntensityTemp <- self$accrualIntensity
sampleSize <- 0
for (i in 2:length(self$accrualTime)) {
time <- self$accrualTime[i] - self$accrualTime[i - 1]
sampleSize <- sampleSize + time * self$accrualIntensity[i - 1]
if (sampleSize >= self$maxNumberOfSubjects &&
length(self$accrualTime) == length(self$accrualIntensity)) {
if (sampleSize > self$maxNumberOfSubjects) {
self$accrualTime <- self$accrualTime[1:(i - 1)]
}
i2 <- i
if (length(self$accrualTime) == length(self$accrualIntensity) + 1) {
i2 <- i - 1
}
self$accrualIntensity <- self$accrualIntensity[1:(i2 - 1)]
while (length(self$accrualTime) > length(self$accrualIntensity) + 1) {
self$accrualTime <- self$accrualTime[1:(length(self$accrualTime) - 1)]
}
sampleSize <- 0
if (length(self$accrualTime) > 1) {
sampleSize <- self$.getSampleSize()
}
if (self$.showWarnings) {
n1 <- length(accrualTimeTemp) - length(self$accrualTime)
n2 <- length(accrualIntensityTemp) - length(self$accrualIntensity)
if (n1 == 1) {
warning("Last accrual time value (",
accrualTimeTemp[length(accrualTimeTemp)], ") ignored",
call. = FALSE
)
} else if (n1 > 1) {
warning("Last ", n1, " accrual time values (",
.arrayToString(accrualTimeTemp[(length(accrualTimeTemp) - n1 + 1):length(accrualTimeTemp)]),
") ignored",
call. = FALSE
)
}
if (n2 == 1) {
warning("Last accrual intensity value (",
accrualIntensityTemp[length(accrualIntensityTemp)], ") ignored",
call. = FALSE
)
} else if (n2 > 1) {
warning("Last ", n2, " accrual intensity values (",
.arrayToString(accrualIntensityTemp[i2:length(accrualIntensityTemp)]),
") ignored",
call. = FALSE
)
}
}
return(sampleSize)
}
}
return(sampleSize)
},
.calculateRemainingTime = function(stopInCaseOfError = TRUE) {
.assertIsValidMaxNumberOfSubjects(self$maxNumberOfSubjects)
sampleSize <- self$.calcSampleSize()
remainingSubjects <- self$maxNumberOfSubjects - sampleSize
if (remainingSubjects < 0) {
if (!stopInCaseOfError) {
return(invisible())
}
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'maxNumberOfSubjects' (", self$maxNumberOfSubjects, ") ",
"is too small for the defined accrual time (minimum = ", sampleSize, ")"
)
}
lastAccrualIntensity <- self$accrualIntensity[length(self$accrualIntensity)]
self$remainingTime <- remainingSubjects / lastAccrualIntensity
self$.setParameterType(
"remainingTime",
ifelse(!isTRUE(all.equal(0, self$remainingTime, tolerance = 1e-06)),
C_PARAM_GENERATED, C_PARAM_NOT_APPLICABLE
)
)
if (length(self$accrualTime) == length(self$accrualIntensity)) {
if (self$.getParameterType("remainingTime") == C_PARAM_GENERATED) {
self$accrualTimeOriginal <- self$accrualTime
if (identical(self$accrualTime, c(0, 12)) || identical(self$accrualTime, C_ACCRUAL_TIME_DEFAULT)) {
self$.setParameterType("accrualTimeOriginal", C_PARAM_DEFAULT_VALUE)
} else {
self$.setParameterType("accrualTimeOriginal", C_PARAM_USER_DEFINED)
}
self$.setParameterType("accrualTime", C_PARAM_GENERATED)
}
self$accrualTime <- c(self$accrualTime, self$accrualTime[length(self$accrualTime)] + self$remainingTime)
}
if (any(self$accrualTime < 0)) {
if (!stopInCaseOfError) {
return(invisible())
}
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT, "'maxNumberOfSubjects' (", self$maxNumberOfSubjects, ") ",
"is too small for the defined accrual time"
)
}
},
.validateAccrualTimeAndIntensity = function() {
if ((length(self$accrualTime) >= 2 && any(self$accrualTime[2:length(self$accrualTime)] < 0))) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'accrualTime' (", .arrayToString(self$accrualTime), ") must be > 0"
)
}
.assertValuesAreStrictlyIncreasing(self$accrualTime, "accrualTime")
if ((length(self$accrualTime) > 1) && any(self$accrualIntensity < 0)) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"'accrualIntensity' (", .arrayToString(self$accrualIntensity), ") must be >= 0"
)
}
if (length(self$accrualIntensity) == 1 && !is.na(self$accrualIntensity) &&
self$accrualIntensity == 0) {
stop(
C_EXCEPTION_TYPE_ILLEGAL_ARGUMENT,
"at least one 'accrualIntensity' value must be > 0"
)
}
if (length(self$accrualIntensity) > 0 && self$accrualIntensity[1] == 0) {
warning(
"It makes no sense to start 'accrualIntensity' (",
.arrayToString(self$accrualIntensity), ") with 0"
)
}
},
.validateInitialization = function() {
self$.validateAccrualTimeAndIntensity()
self$piecewiseAccrualEnabled <- !self$.isNoPiecewiseAccrualTime(self$accrualTime)
}
)
)
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.