gsSurvPower() computes power for a group sequential survival design
with specified enrollment, dropout, treatment effect, and analysis timing.
Unlike gsSurv() and gsSurvCalendar() which solve for sample
size to achieve target power, gsSurvPower() takes fixed design
assumptions and computes the resulting power. Its two primary uses are
computing achieved power when sample size is not being derived and
evaluating alternative enrollment, failure, treatment-effect, and analysis
timing scenarios. It computes one set of assumptions at a time; scenario
grids are evaluated with separate calls.
For k = 1, power is computed through the fixed-design
nSurv(beta = NULL) path. The returned object is normalized as a
single-analysis gsSurv object so it can be passed to
toInteger and gsBoundSummary.
gsSurvPower(
x = NULL,
k = NULL,
test.type = NULL,
alpha = NULL,
sided = NULL,
astar = NULL,
sfu = NULL,
sfupar = NULL,
sfl = NULL,
sflpar = NULL,
sfharm = NULL,
sfharmparam = NULL,
r = NULL,
usTime = NULL,
lsTime = NULL,
testUpper = NULL,
testLower = NULL,
testHarm = NULL,
lambdaC = NULL,
hr = NULL,
hr0 = NULL,
hr1 = NULL,
eta = NULL,
etaE = NULL,
gamma = NULL,
R = NULL,
targetN = NULL,
S = NULL,
ratio = NULL,
minfup = NULL,
method = NULL,
spending = c("information", "calendar", "min_planned_actual"),
plannedCalendarTime = NULL,
targetEvents = NULL,
maxExtension = NULL,
minTimeFromPreviousAnalysis = NULL,
minN = NULL,
minFollowUp = NULL,
informationRates = NULL,
fullSpendingAtFinal = FALSE,
tol = .Machine$double.eps^0.25,
targetEventsPerStratum = NULL,
maxCalendarTime = NULL,
minNPerStratum = NULL
)An object of class
c("gsSurvPower", "gsSurv", "gsDesign") containing:
Number of analyses.
Total expected events at each analysis.
Information fractions at each analysis.
Calendar times of analyses.
Expected events by stratum (control, experimental).
Expected sample sizes by stratum (control, experimental).
Cumulative total expected enrollment at each analysis.
Bounds and crossing probabilities.
Harm-bound information when test.type is 7 or 8.
Expected sample size summary and drift values returned by
gsDesign::gsProbability().
Assumed, null, and design hazard ratios.
Overall power (sum of upper-bound crossing probabilities under the assumed HR).
Type II error (1 - power).
Always "Power".
Design settings and the original call used for the power calculation.
Evaluated arguments supplied to gsSurvPower(). The
calculation can be reproduced under the same package version with
do.call(gsSurvPower, inputs). When x is supplied, the
evaluated reference design is retained so that inherited design settings
and planned-versus-actual spending can be reproduced.
Planned information-fraction caps and final effective-spending-time setting used for bound spending.
Logical indicators of which analyses include each bound type, when relevant.
Rate and timing inputs used in the calculation.
Optional gsSurv or gsSurvCalendar object providing
defaults for all parameters. When provided, any user-specified parameter
overrides the corresponding value from x.
Number of analyses planned, including interim and final.
1 = one-sided, 2 = two-sided symmetric,
3 = two-sided, asymmetric, beta-spending with binding lower bound,
4 = two-sided, asymmetric, beta-spending with non-binding lower bound,
5 = two-sided, asymmetric, lower bound spending under the null
hypothesis with binding lower bound,
6 = two-sided, asymmetric, lower bound spending under the null
hypothesis with non-binding lower bound,
7 = two-sided, asymmetric, with binding futility and binding harm
bounds,
8 = two-sided, asymmetric, with non-binding futility and
non-binding harm bounds.
Type I error rate. Default is 0.025 since 1-sided testing
is default. Internally divided by sided before passing to
gsDesign(), matching the convention used by gsSurv() and
gsSurvCalendar().
1 for 1-sided, 2 for 2-sided testing. Used to convert
alpha to one-sided via alpha / sided for internal
calculations, matching the convention of gsSurv() and
nSurv(). When x is provided and sided is omitted,
gsSurvPower() reuses the stored sided value from the design call
when available.
Lower bound total crossing probability for test.type
5 or 6. Default 0.
Upper bound spending function (default sfHSD).
Parameter for sfu (default -4).
Lower bound spending function (default sfHSD).
Parameter for sfl (default -2).
Spending function for the harm bound, used with
test.type = 7 or test.type = 8. Default sfHSD.
Real value, default \(-2\). Parameter for the harm
bound spending function sfharm.
Integer grid parameter for numerical integration (default 18).
Upper spending time override; vector of length k
without missing values, or NULL (default) to use information
fractions. Ignored when
spending = "calendar", because realized analysis times determine
the spending fractions.
Lower spending time override; vector of length k
without missing values, or NULL (default) to use information
fractions. Ignored when spending = "calendar".
Indicator of which analyses include an efficacy test.
TRUE (default) for all analyses. A logical vector of length
k may be specified. Missing values are not allowed; use
FALSE to omit the test at an analysis.
Indicator of which analyses include a futility test.
TRUE (default) for all analyses. A logical vector of length
k may be specified. Missing values are not allowed; use
FALSE to omit the test at an analysis.
Indicator of which analyses include a harm bound.
TRUE (default) for all analyses. A logical vector of length
k may be specified. Missing values are not allowed; use
FALSE to omit the test at an analysis. Only used for
test.type 7 or 8.
Scalar, vector, or matrix of control event hazard rates. Rows = time periods, columns = strata.
Assumed hazard ratio (experimental/control) for power computation. This is the "what-if" treatment effect.
Null hazard ratio. Set hr0 > 1 for non-inferiority.
Design alternative hazard ratio used to calibrate futility bounds
(test.type 3, 4, 7, 8 only; not used for 5, 6 or harm bounds).
Defaults to x$hr when x is provided, otherwise hr.
Scalar, vector, or matrix of control dropout hazard rates.
Experimental dropout hazard rates; if NULL, set to
eta.
Scalar, vector, or matrix of enrollment rates by period (rows) and strata (columns).
Scalar or vector of enrollment period durations.
Target total sample size. When specified, R is
uniformly rescaled so that sum(gamma * R) == targetN, preserving
the relative duration of each enrollment period. This changes enrollment
duration rather than the enrollment rates. Cannot be used together with
an explicit non-NULL R; to keep a fixed enrollment duration,
specify R and scale gamma directly.
Scalar or vector of piecewise failure period durations; NULL
for exponential failure.
Randomization ratio (experimental/control). Default 1.
Minimum follow-up time. When explicitly supplied,
event-driven analyses cannot place the final analysis before the end of
enrollment plus minfup.
Sample-size variance formulation. One of
"LachinFoulkes" (default), "Schoenfeld",
"Freedman", or "BernsteinLagakos". Affects n.fix
computation when x is not provided.
One of "information" (default), "calendar",
or "min_planned_actual". Information spending tracks expected
event fractions within the scenario. Calendar spending uses
T / max(T). With a reference design x,
"min_planned_actual" uses
pmin(x$n.I, actual events) / x$n.I[k], matching the planned-versus-
actual spending convention in simtrial. The latter two modes derive
usTime and lsTime and ignore user-supplied overrides.
Calendar times for analyses (time 0 = start of
randomization). Scalar (recycled) or vector of length k. Use
NA for analyses not determined by calendar time.
Overall target number of events at each analysis.
Scalar (recycled) or vector of length k. Use NA for
analyses without an overall event requirement. A matrix is accepted as a
deprecated alias for targetEventsPerStratum.
Maximum time extension beyond the floor time to wait
for targetEvents. Scalar or vector of length k. Requires a
floor timing criterion for the affected analysis, most commonly
plannedCalendarTime. Use NA for analyses without a relative
extension cap.
Minimum elapsed time since the previous
analysis. Scalar or vector of length k. Ignored for the first
analysis. Use NA for later analyses without a spacing requirement.
Minimum total sample size enrolled before analysis can proceed.
Scalar or vector of length k. Can be used with
minFollowUp as the primary timing criterion; the resulting
analysis times and expected event totals must be strictly increasing. Use
NA for analyses without an overall enrollment requirement.
Minimum follow-up time after all active minN and
minNPerStratum requirements are reached. Scalar or vector of
length k. Must be >= 0. Use NA for no additional follow-up
at an analysis. Each non-missing value requires an active minN or
minNPerStratum requirement at the same analysis.
Numeric vector of length k specifying
planned information-fraction caps, with no missing values. At each
analysis, the effective upper and lower spending time is
pmin(informationRates, actual_timing), where
actual_timing is expected events divided by maximum expected
events. This prevents spending ahead of either the planned information
schedule or the information actually accumulated. When supplied,
informationRates takes precedence over spending,
usTime, and lsTime; upper and lower spending use the same
effective spending-time vector. Default NULL uses actual
information fractions (or calendar fractions when
spending = "calendar").
Logical. When TRUE, the final element of
the effective upper and lower spending-time vectors is forced to 1 after
applying
informationRates, calendar or planned-versus-actual spending, or
user-supplied usTime/lsTime. This ensures full upper- and
lower-bound
spending whenever a selected spending-time vector would otherwise end
below 1.
Default FALSE.
Tolerance for uniroot when solving for
analysis times.
Per-stratum event requirements. Numeric matrix
with k rows and one column per stratum; NA omits a stratum
requirement at an analysis. The analysis waits until every active stratum
requirement and any overall targetEvents requirement are met.
Absolute calendar-time cap for each analysis. Scalar
or vector of length k. When supplied with maxExtension, the
earlier cap applies. This corresponds to
max_extension_for_target_event in simtrial. Use NA
for analyses without an absolute calendar-time cap.
Per-stratum minimum enrollment requirements. Numeric
matrix with k rows and one column per stratum; NA omits a
stratum requirement at an analysis.
Accepting a gsSurv object:
An optional gsSurv-class object x provides defaults for all
parameters. This includes output from gsSurv() and
gsSurvCalendar(). User-specified parameters override these defaults,
enabling "what-if" analyses: e.g., gsSurvPower(x = design, hr = 0.8)
evaluates power under HR = 0.8 using all other parameters from the design.
When x is not provided, all design parameters must be specified
directly.
Interpretation and limitations: Enrollment, dropout, event accumulation, and analysis timing are represented by their expected values under the supplied assumptions. Consequently, event- and enrollment-triggered analysis times are expected analysis times, not simulated realizations. The calculation does not represent trial-to-trial variation in enrollment, failure, dropout, or operational timing. Use simulation when that variation may materially affect operating characteristics or the probability that combined timing rules are met; see, for example, the simtrial package.
Hazard ratio roles:
Two distinct hazard ratios serve different purposes. hr is the
assumed treatment effect under which power is evaluated.
hr1 is the design alternative used to calibrate futility bounds
(for test.type 3, 4, 7, 8). It is not used for test.type
5 or 6 (which use H0 spending for the lower bound) or for harm bounds.
When x is provided, hr1 defaults
to x$hr, so futility bounds remain calibrated to the original design
even when power is evaluated under a different hr.
Beta spending in scenario analyses:
For beta-spending test types 3, 4, 7, and 8, x$beta is the design
beta used with hr1, sfl, and sflpar to calibrate
futility bounds. The beta returned by gsSurvPower() instead
equals 1 - power under the scenario assumptions and can differ
substantially from the design beta.
When information fractions and spending inputs are unchanged,
futility bounds are reused from x.
When information fractions or spending times change, futility
bounds are recomputed on the new schedule using the design beta and
hr1; achieved beta is then evaluated under hr.
When only alpha or upper-bound spending changes with timing fixed,
futility bounds from x are preserved, apart from clipping a
lower bound that exceeds the new efficacy bound.
Test types 5 and 6 spend lower-bound probability under the null rather than beta under the alternative. Harm spending for test types 7 and 8 is also a separate null-based calculation.
Analysis timing:
Analysis times are determined by per-analysis criteria. Except for the
final-analysis-only scalar minfup, each timing-rule parameter can be
a scalar (recycled to all k analyses), a vector of length k,
or NA at position i to indicate that the rule does not apply
to analysis i. For the per-stratum matrix arguments, NA
deactivates only that analysis-by-stratum requirement.
The choice between plannedCalendarTime and overall
targetEvents has an important consequence for sensitivity analyses:
Used alone, plannedCalendarTime fixes calendar times;
when combined with other criteria, it supplies a timing floor. Expected
events are recomputed under the assumed HR. A worse HR produces more
events at the same calendar time (the experimental arm fails faster).
This gives an "unconditional" power.
targetEvents fixes overall event counts; calendar times
adjust. Since events are held constant, information fractions do not
change with HR, and results match the gsDesign power plot
(plot(x, plottype = 2)) to numerical precision.
How criteria combine within a single analysis:
For analysis i, the analysis time T[i] is determined as:
Compute floor times from applicable criteria:
plannedCalendarTime[i],
T[i-1] + minTimeFromPreviousAnalysis[i], and
time when minN[i] enrolled + minFollowUp[i], and the
corresponding time for every active column of
minNPerStratum[i, ]. When minfup is explicitly supplied,
the final analysis also has a floor at the end of enrollment plus
minfup.
floor_time = max(all applicable floor times).
Find the expected time for the overall targetEvents[i] and
for every active column of targetEventsPerStratum[i, ]. Their
maximum is t_events, so all active requirements use AND logic.
If t_events <= floor_time, analysis at floor_time. If
t_events > floor_time and
maxExtension[i] is set, analysis at
min(t_events, floor_time + maxExtension[i]). Otherwise, analysis
at t_events.
If no event requirement is active: analysis at floor_time.
maxExtension defines a hard deadline: the analysis time
is never pushed
beyond plannedCalendarTime[i] + maxExtension[i] (or
T[i-1] + maxExtension[i] when no calendar time is specified),
even if other criteria such as minTimeFromPreviousAnalysis
or minN + minFollowUp would require a later time. Each analysis
using maxExtension must have a floor timing criterion such as
plannedCalendarTime, minTimeFromPreviousAnalysis,
minN, minNPerStratum, or explicit final-analysis
minfup.
Finally, maxCalendarTime[i] applies an absolute calendar-time
cap. If both cap types are supplied, the earlier cap applies. This
mirrors the realized-cut grammar in simtrial, where the argument
named max_extension_for_target_event is applied as an absolute
analysis date.
Normalization and consistency:
When x is provided, x$n.fix is used for the
gsDesign::gsDesign() call to ensure the internal drift parameter
\(\theta\) and bounds match the original design exactly.
The assumed HR's drift is obtained by scaling:
\(\theta_{\mathrm{assumed}} = \theta_{\mathrm{design}} \times
|\log(\mathrm{hr}/\mathrm{hr}_0)| / |\log(\mathrm{hr}_1/\mathrm{hr}_0)|\).
Power is computed via gsDesign::gsProbability() with actual expected
events as n.I. At the design HR, this reproduces the design power
exactly.
Stratified timing requirements:
targetEvents accepts a scalar (recycled) or a vector of length
k for overall event targets. Use targetEventsPerStratum for a
k-by-nstrata matrix of per-stratum event requirements and
minNPerStratum for per-stratum enrollment requirements. Overall and
per-stratum requirements may be combined and all active requirements must
be met unless a cap intervenes. NA omits a requirement. A matrix
passed through targetEvents is a deprecated alias for
targetEventsPerStratum; unlike the earlier row-sum interpretation,
its entries are enforced by stratum.
Bound recalculation when parameters change:
When x is provided, the handling of bounds depends on which
parameters change relative to the original design:
No bound parameters changed (same alpha, sfu,
sfupar) and timing matches: both bounds are reused from x
exactly.
Upper-bound parameters changed (alpha, sfu,
or sfupar) but timing matches: new efficacy bounds are computed
using the non-binding efficacy convention at the new alpha while
preserving the original testUpper schedule and futility bounds
from x. Any futility bound that exceeds the new efficacy bound
is clipped. This follows the same convention as
gsBoundSummary(). Lower-bound spending settings from x
are intentionally kept in this branch, which avoids complications with
astar validation for binding types.
For non-binding test types 1, 4, 6, and 8, this calculation can be used
to evaluate alpha propagated by a graphical multiple-testing procedure.
For binding test types 2, 3, 5, and 7, it is a planning sensitivity
calculation only; it is not a Maurer--Bretz sequential-p-value or
graphical alpha-recycling procedure.
Timing changed (different target events or calendar
times): both bounds are recomputed from scratch using the full
test.type and all spending parameters.
vignette("gsSurvPower", package = "gsDesign") for
worked examples including calendar spending, stratified event targets,
and biomarker subgroup analyses.
vignette("gsSurvBasicExamples", package = "gsDesign") for deriving
survival sample size designs and vignette("SeqDesignSurvival",
package = "gsDesign") for reproducing SAS PROC SEQDESIGN survival output.
gsSurv, gsSurvCalendar,
gsDesign, gsProbability
# Create a design, then evaluate power at the design HR
design <- gsSurv(
k = 3, test.type = 4, alpha = 0.025, sided = 1, beta = 0.1,
lambdaC = log(2) / 12, hr = 0.7, eta = 0.01,
gamma = 10, R = 16, minfup = 12, T = 28
)
pwr <- gsSurvPower(x = design, plannedCalendarTime = design$T)
pwr$power # should be 0.9
# Power under a worse HR
gsSurvPower(x = design, hr = 0.8, plannedCalendarTime = design$T)$power
# Event-driven timing (matches gsDesign power plot)
design_events <- design$n.I
gsSurvPower(x = design, hr = 0.8, targetEvents = design_events)$power
# Without a reference design
gsSurvPower(
k = 2, test.type = 4, alpha = 0.025, sided = 1,
lambdaC = log(2) / 6, hr = 0.65, eta = 0.01,
gamma = 8, R = 18, ratio = 1,
plannedCalendarTime = c(24, 36)
)$power
# Use targetN without R to solve enrollment duration from relative rates
pwr_target_n <- gsSurvPower(
k = 2, test.type = 1, alpha = 0.025, sided = 1,
lambdaC = log(2) / 15, hr = 0.7, eta = 0.001,
gamma = c(10, 20, 30, 40), targetN = 500,
ratio = 1.5, plannedCalendarTime = c(24, 36),
testLower = FALSE
)
sum(rowSums(pwr_target_n$gamma) * pwr_target_n$R)
# Require event counts within each stratum
pwr_stratified <- gsSurvPower(
k = 2, test.type = 1, alpha = 0.025, sided = 1,
lambdaC = matrix(log(2) / c(6, 12), ncol = 2),
hr = 0.7, eta = 0.01,
gamma = matrix(c(5, 5), ncol = 2), R = 12, ratio = 1,
targetEventsPerStratum = matrix(
c(20, 10, 40, 20), nrow = 2, byrow = TRUE
)
)
pwr_stratified$eDC + pwr_stratified$eDE
Run the code above in your browser using DataLab