Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .agents/skills/survival-design-routing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,25 @@ description: Choose the appropriate gsDesign survival or exact-binomial workflow
otherwise keep the appropriate survival design function.
- Set `ratio` explicitly when randomization is specified; `ratio = 1` means
equal experimental:control randomization.
- For the common four-period enrollment ramp-up, use `gamma = 1:4` for equal
relative rate increments and `R = rep(1, 4)`. The final period is extended
as needed by the selected duration solve.
- With `T` and `minfup` specified, `gsSurv()` and `gsSurvCalendar()` fix total
study and minimum follow-up duration, scale `gamma` proportionally to power
the trial, and extend the final `R` period to `T - minfup`.
- With `T = NULL` and `minfup` specified, keep `gamma` fixed and solve the
enrollment duration by extending the final `R` period.
- With both `T = NULL` and `minfup = NULL`, keep enrollment rates and duration
fixed and solve follow-up duration. Warn that this can be infeasible when
the fixed enrollment plan is always over- or under-powered.
- Use `gsSurvPower()` when enrollment, follow-up, and analysis timing are fixed
and the objective is achieved power rather than a powered sample-size plan.
- Use `toInteger()` after design derivation when integer event targets and an
allocation-compatible total enrollment are needed.
- For a `gsSurv` object, use `N` for cumulative total expected enrollment at
each analysis. Use `eNC` and `eNE` for control and experimental enrollment by
stratum.
- For an `nSurv` object, scalar `n` and scalar `N` are identical total expected
enrollment values. Accept either name without converting existing code.
- For stratified survival designs, supply matrices whose columns are strata;
align the columns of `lambdaC`, `eta`, `etaE`, and `gamma`.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Package: gsDesign
Version: 3.11.0.9002
Version: 3.11.0.9003
Title: Group Sequential Design
Authors@R: c(
person("Keaven", "Anderson", email = "keaven_anderson@merck.com", role = c("aut", "cre")),
Expand Down
8 changes: 8 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## New features

- All `gsSurv` objects now include `N`, the cumulative total expected
enrollment at each analysis. `nSurv` objects retain scalar `n` and also
return identical scalar `N` as a non-breaking alias (#299).
- Added survival enrollment-planning documentation for four-period ramp-up,
the three combinations of fixed or solved enrollment and follow-up duration,
calendar-time analyses, power sensitivity, integer conversion, and
stratified designs. `gsSurv(T = NULL, minfup = ...)` now consistently keeps
enrollment rates fixed and solves enrollment duration (#300).
- Added `minMedianFollowUp()` and `plotMinMedianFollowUp()` to compute and plot
minimum median follow-up at any calendar time from the piecewise enrollment
assumptions in an `nSurv` or `gsSurv` design. The plot accepts arbitrary
Expand Down
26 changes: 24 additions & 2 deletions R/gsSurv-nSurv.R
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@
#' \item{hr0}{As input.}
#' \item{n}{Total expected sample size corresponding to output accrual rates
#' and durations.}
#' \item{N}{Identical to \code{n}; provided as a non-breaking alias for total
#' expected sample size.}
#' \item{d}{Total expected number of events under the alternate
#' hypothesis.}
#' \item{tol}{As input, except when not used in computations in
Expand Down Expand Up @@ -277,6 +279,8 @@
#' \item{minfup}{As input.}
#' \item{hr}{As input.}
#' \item{hr0}{As input.}
#' \item{N}{A vector containing cumulative total expected enrollment at each
#' analysis.}
#' \item{eNC}{Total expected sample size corresponding to output accrual rates
#' and durations.}
#' \item{eNE}{Total expected sample size corresponding to output accrual rates
Expand Down Expand Up @@ -325,8 +329,10 @@
#'
#' @author Keaven Anderson \email{keaven_anderson@@merck.com}
#'
#' @seealso \code{vignette("gsSurvBasicExamples", package = "gsDesign")} for
#' basic survival sample size examples, \code{vignette("SurvivalOverview",
#' @seealso \code{vignette("SurvivalEnrollmentPlanning", package = "gsDesign")}
#' for enrollment ramp-up and duration planning,
#' \code{vignette("gsSurvBasicExamples", package = "gsDesign")} for basic
#' survival sample size examples, \code{vignette("SurvivalOverview",
#' package = "gsDesign")} for method background, and
#' \code{vignette("SeqDesignSurvival", package = "gsDesign")} for a SAS PROC
#' SEQDESIGN translation example.
Expand Down Expand Up @@ -412,6 +418,21 @@
#' ) |>
#' print()
#'
#' # Common four-period enrollment ramp-up. With T and minfup fixed, the
#' # relative gamma pattern is scaled to power the trial, and the final R
#' # period is extended so enrollment lasts T - minfup.
#' ramp_rate <- gsSurv(
#' T = 26, minfup = 12,
#' gamma = 1:4, R = rep(1, 4)
#' )
#'
#' # With T = NULL and minfup fixed, gamma stays fixed and the final
#' # enrollment period is extended to obtain the required sample size.
#' ramp_duration <- gsSurv(
#' T = NULL, minfup = 12,
#' gamma = 1:4, R = rep(1, 4)
#' )
#'
#' # Vary minimum follow-up duration minfup to obtain power
#' # Accrual duration R rate gamma are fixed and will not change on output.
#' # Trial duration T and minimum follow-up minfup are input as NULL
Expand Down Expand Up @@ -575,6 +596,7 @@ nSurv <- function(
xx$method <- method
xx$call <- match.call()
xx$inputs <- input_vals
xx$N <- xx$n
return(xx)
}

Expand Down
8 changes: 7 additions & 1 deletion R/gsSurv-utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ validate_survival_timing_inputs <- function(R, T, minfup, call = "nSurv") {
invisible(TRUE)
}

# Add cumulative total enrollment at each analysis to a gsSurv object.
gsSurvAddN <- function(x) {
x$N <- rowSums(as.matrix(x$eNC)) + rowSums(as.matrix(x$eNE))
x
}

# Construct the gsDesign portion of a single-analysis survival design without
# calling gsDesign(), whose group-sequential validation requires k >= 2.
gsSurvFixedDesignObject <- function(
Expand Down Expand Up @@ -185,5 +191,5 @@ asGsSurvFixedDesign <- function(
design$inputs <- inputs
class(design) <- c("gsSurv", "gsDesign")

design
gsSurvAddN(design)
}
9 changes: 1 addition & 8 deletions R/gsSurv.R
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,6 @@ gsSurv <- function(
)$root
T <- sum(R) + minfup
}
# Preserve the historical Lachin-Foulkes default: with fixed follow-up and
# T = NULL, keep R fixed and vary the accrual rate.
if (method == "LachinFoulkes" && is.null(T) && !is.null(minfup) &&
!is.null(R) && length(R) > 0 &&
!is.null(gamma) && length(gamma) > 0) {
T <- sum(R) + minfup
}
x <- nSurv(
lambdaC = lambdaC, hr = hr, hr0 = hr0, eta = eta, etaE = etaE,
gamma = gamma, R = R, S = S, T = T, minfup = minfup, ratio = ratio,
Expand Down Expand Up @@ -176,7 +169,7 @@ gsSurv <- function(
colnames(y$etaE) <- stratnames
rownames(y$gamma) <- nameR
colnames(y$gamma) <- stratnames
return(y)
return(gsSurvAddN(y))
}

# gsnSurv function [sinew] ----
Expand Down
14 changes: 11 additions & 3 deletions R/gsSurvCalendar.R
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@
#'
#' @rdname gsSurvCalendar
#'
#' @seealso \code{vignette("SeqDesignSurvival", package = "gsDesign")} for a
#' SAS PROC SEQDESIGN sample size translation example and
#' @seealso \code{vignette("SurvivalEnrollmentPlanning", package = "gsDesign")}
#' for enrollment ramp-up and duration planning,
#' \code{vignette("SeqDesignSurvival", package = "gsDesign")} for a SAS
#' PROC SEQDESIGN sample size translation example and
#' \code{vignette("gsSurvPower", package = "gsDesign")} for power
#' calculations with fixed calendar analysis assumptions.
#'
Expand Down Expand Up @@ -71,6 +73,12 @@
#' y$usTime
#' # Actual calendar fraction from design after toInteger() conversion
#' y$T / max(y$T)
#'
#' # Four-period enrollment ramp-up with fixed study duration and follow-up.
#' ramp_calendar <- gsSurvCalendar(
#' calendarTime = c(12, 18, 26), minfup = 12,
#' gamma = 1:4, R = rep(1, 4)
#' )
gsSurvCalendar <- function(
test.type = 4, alpha = 0.025, sided = 1, beta = 0.1, astar = 0,
sfu = gsDesign::sfHSD, sfupar = -4,
Expand Down Expand Up @@ -184,5 +192,5 @@ gsSurvCalendar <- function(
colnames(y$etaE) <- stratnames
rownames(y$gamma) <- nameR
colnames(y$gamma) <- stratnames
return(y)
return(gsSurvAddN(y))
}
3 changes: 2 additions & 1 deletion R/gsSurvPower.R
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@
#' \item{T}{Calendar times of analyses.}
#' \item{eDC, eDE}{Expected events by stratum (control, experimental).}
#' \item{eNC, eNE}{Expected sample sizes by stratum (control, experimental).}
#' \item{N}{Cumulative total expected enrollment at each analysis.}
#' \item{upper, lower}{Bounds and crossing probabilities.}
#' \item{harm}{Harm-bound information when \code{test.type} is 7 or 8.}
#' \item{en, theta}{Expected sample size summary and drift values returned by
Expand Down Expand Up @@ -1236,5 +1237,5 @@ gsSurvPower <- function(
result$beta <- 1 - result$power

class(result) <- c("gsSurv", "gsDesign")
.gsSurvPower_label_output_matrices(result)
gsSurvAddN(.gsSurvPower_label_output_matrices(result))
}
2 changes: 2 additions & 0 deletions R/toInteger.R
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ toInteger <- function(x, ratio = x$ratio, roundUpFinal = TRUE) {
for (nm in plan_fields) result[[nm]] <- integer_design[[nm]]
result$d <- integer_design$n.I[1]
result$n <- sum(result$eNC + result$eNE)
result$N <- result$n
result$beta <- integer_design$beta
result$power <- 1 - result$beta
class(result) <- class(original)
Expand Down Expand Up @@ -402,6 +403,7 @@ toInteger <- function(x, ratio = x$ratio, roundUpFinal = TRUE) {
rownames(xi$gamma) <- nameR
colnames(xi$gamma) <- stratnames
}
if (inherits(xi, "gsSurv")) xi <- gsSurvAddN(xi)
return(xi)
}

Expand Down
1 change: 1 addition & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ articles:
contents:
- SurvivalOverview
- gsSurvBasicExamples
- SurvivalEnrollmentPlanning
- gsSurvPower
- SeqDesignSurvival
- toInteger
Expand Down
12 changes: 10 additions & 2 deletions man/gsSurvCalendar.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions man/gsSurvPower.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 23 additions & 2 deletions man/nSurv.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading