Comparing Sample Size and Power Calculation Results for a Group Sequential Trial with a Survival Endpoint: rpact vs. gsDesign

Planning
Survival
This document provides an example that illustrates how to compare sample size and power calculation results of the two different R packages rpact and gsDesign.
Author
Published

March 4, 2026

The design

  • 1:1 randomized
  • Two-sided log-rank test; 80% power at 5% significance level (or one-sided at 2.5%)
  • Target HR for primary endpoint (PFS) is 0.75
  • PFS in the control arm follows a piece-wise exponential distribution, with the hazard rate h(t) estimated using historical controls as follows:
    • h(t) = 0.025 for t between 0 and 6 months;
    • h(t) = 0.04 for t between 6 and 9 months;
    • h(t) = 0.015 for t between 9 and 15 months;
    • h(t) = 0.01 for t between 15 and 21 months;
    • h(t) = 0.007 for t beyond 21 months.
  • An annual dropout probability of 20%
  • Interim analyses at 33% and 70% of total information
  • Alpha-spending version of O’Brien-Fleming boundary for efficacy
  • No futility interim
  • 1405 subjects recruited in total
  • Staggered recruitment:
    • 15 pt/month during first 12 months;
    • subsequently, increase of # of sites and ramp up of recruitment by +6 pt/month each month until a maximum of 45 pt/month

Calculation with gsDesign

# Load the package `gsDesign`
library(gsDesign)
options(warn = -1) # avoid warnings generated by gsDesign
x <- gsSurv(
    k = 3, test.type = 1, alpha = 0.025, beta = 0.2,
    timing = c(0.33, 0.7), sfu = sfLDOF, # boundary
    hr = 0.75,
    lambdaC = c(0.025, 0.04, 0.015, 0.01, 0.007), # piecewise lambdas
    S = c(6, 3, 6, 6), # piecewise survival times
    eta = -log(1 - 0.2) / 12, # dropout
    gamma = c(15, 21, 27, 33, 39, 45), # recruitment, pt no
    R = c(12, 1, 1, 1, 1, (1405 - 300) / 45), # recruitment duration
    minfup = NULL
)
print(x, digits = 5)
Group sequential design (method=LachinFoulkes; k=3 analyses; One-sided (efficacy only))
N=1405.0 subjects | D=385.9 events | T=50.8 study duration | accrual=40.6 Accrual duration | minfup=10.2 minimum follow-up | ratio=1 randomization ratio (experimental/control)

Spending functions:
  Efficacy bounds derived using a Lan-DeMets O'Brien-Fleming approximation spending function (no parameters).

Analysis summary:
Method: LachinFoulkes 
    Analysis               Value Efficacy
   IA 1: 33%                   Z   3.7307
      N: 786         p (1-sided)   0.0001
 Events: 128        ~HR at bound   0.5162
   Month: 27    P(Cross) if HR=1   0.0001
             P(Cross) if HR=0.75   0.0175
   IA 2: 70%                   Z   2.4396
     N: 1320         p (1-sided)   0.0074
 Events: 271        ~HR at bound   0.7431
   Month: 39    P(Cross) if HR=1   0.0074
             P(Cross) if HR=0.75   0.4691
       Final                   Z   2.0001
     N: 1406         p (1-sided)   0.0227
 Events: 386        ~HR at bound   0.8158
   Month: 51    P(Cross) if HR=1   0.0250
             P(Cross) if HR=0.75   0.8000

Key inputs (names preserved):
                               desc    item                              value
                    Accrual rate(s)   gamma             15, 21, 27 ... (len=6)
           Accrual rate duration(s)       R               12, 1, 1 ... (len=6)
             Control hazard rate(s) lambdaC     0.025, 0.04, 0.015 ... (len=5)
            Control dropout rate(s)     eta 0.0186, 0.0186, 0.0186 ... (len=5)
       Experimental dropout rate(s)    etaE 0.0186, 0.0186, 0.0186 ... (len=5)
 Event and dropout rate duration(s)       S                6, 3, 6 ... (len=4)
                          input
         15, 21, 27 ... (len=6)
           12, 1, 1 ... (len=6)
 0.025, 0.04, 0.015 ... (len=5)
                         0.0186
                           etaE
            6, 3, 6 ... (len=4)

Calculation with rpact

Design

# Load the package `rpact`
library(rpact)
packageVersion("rpact")
design <- getDesignGroupSequential(
    sided = 1, 
    alpha = 0.025, 
    beta = 0.2,
    informationRates = c(0.33, 0.7, 1),
    typeOfDesign = "asOF"
)
design |> summary()

Sequential analysis with a maximum of 3 looks (group sequential design)

O’Brien & Fleming type alpha spending design, one-sided overall significance level 2.5%, power 80%, undefined endpoint, inflation factor 1.015, ASN H1 0.8656, ASN H01 0.9826, ASN H0 1.0127.

Stage 1 2 3
Planned information rate 33% 70% 100%
Cumulative alpha spent <0.0001 0.0074 0.0250
Stage levels (one-sided) <0.0001 0.0074 0.0227
Efficacy boundary (z-value scale) 3.731 2.440 2.000
Cumulative power 0.0175 0.4691 0.8000

Sample size / timing of interim analyses

piecewiseSurvivalTime <- list(
    "0 - <6" = 0.025,
    "6 - <9" = 0.04,
    "9 - <15" = 0.015,
    "15 - <21" = 0.01,
    ">= 21" = 0.007
)

accrualTime <- list(
    "0  - <12" = 15,
    "12 - <13" = 21,
    "13 - <14" = 27,
    "14 - <15" = 33,
    "15 - <16" = 39,
    ">= 16" = 45
)

y <- getPowerSurvival(
    design = design, 
    typeOfComputation = "Schoenfeld",
    thetaH0 = 1, 
    directionUpper = FALSE,
    dropoutRate1 = 0.2, 
    dropoutRate2 = 0.2, 
    dropoutTime = 12,
    allocationRatioPlanned = 1,
    accrualTime = accrualTime,
    piecewiseSurvivalTime = piecewiseSurvivalTime,
    hazardRatio = 0.75,
    maxNumberOfEvents = x$n.I[3],
    maxNumberOfSubjects = 1405
)
y |> summary()

Power calculation for a survival endpoint

Sequential analysis with a maximum of 3 looks (group sequential design), one-sided overall significance level 2.5%. The results were calculated for a two-sample logrank test, H0: hazard ratio = 1, power directed towards smaller values, H1: hazard ratio = 0.75, piecewise survival distribution, piecewise survival time = c(0, 6, 9, 15, 21), control lambda(2) = c(0.025, 0.04, 0.015, 0.01, 0.007), maximum number of subjects = 1405, maximum number of events = 386, accrual time = c(12, 13, 14, 15, 16, 40.556), accrual intensity = c(15, 21, 27, 33, 39, 45), dropout rate(1) = 0.2, dropout rate(2) = 0.2, dropout time = 12.

Stage 1 2 3
Planned information rate 33% 70% 100%
Cumulative alpha spent <0.0001 0.0074 0.0250
Stage levels (one-sided) <0.0001 0.0074 0.0227
Efficacy boundary (z-value scale) 3.731 2.440 2.000
Efficacy boundary (t) 0.516 0.743 0.816
Cumulative power 0.0175 0.4702 0.8009
Number of subjects 785.4 1318.1 1405.0
Expected number of subjects under H1 1354.8
Cumulative number of events 127.3 270.1 385.9
Expected number of events under H1 328.9
Analysis time 26.79 38.62 50.80
Expected study duration under H1 44.87
Exit probability for efficacy (under H0) <0.0001 0.0073
Exit probability for efficacy (under H1) 0.0175 0.4526

Legend:

  • (t): treatment effect scale

Comparison: Analysis time of rpact vs. gsDesign

Absolute differences:

timeDiff <- as.data.frame(sprintf("%.5f", (x$T - y$analysisTime)))
rownames(timeDiff) <- c("Stage 1", "Stage 2", "Stage 3")
colnames(timeDiff) <- "Difference analysis time"
kable(timeDiff)
Difference analysis time
Stage 1 -0.00000
Stage 2 0.00004
Stage 3 -0.00011

Remark

Obviously, there is a difference in the calculation of the necessary number of events which are, in rpact, calculated as

(qnorm(0.975) + qnorm(0.8))^2 / log(0.75)^2 * 4 *
    getDesignCharacteristics(getDesignGroupSequential(
        sided = 1, alpha = 0.025,
        kMax = 3, typeOfDesign = "asOF", informationRates = c(0.33, 0.7, 1)
    ))$inflationFactor
[1] 385.0479

which is slightly different to the maximum number of events in gsDesign which is

x$n.I[3]
[1] 385.881

Therefore, running

getSampleSizeSurvival(
    design = design, 
    typeOfComputation = "Schoenfeld",
    thetaH0 = 1,
    dropoutRate1 = 0.2, 
    dropoutRate2 = 0.2, 
    dropoutTime = 12,
    allocationRatioPlanned = 1,
    accrualTime = accrualTime,
    piecewiseSurvivalTime = piecewiseSurvivalTime,
    hazardRatio = 0.75,
    maxNumberOfSubjects = 1405
)$analysisTime
         [,1]
[1,] 26.76183
[2,] 38.57834
[3,] 50.63114

is not exactly equal to getPowerSurvival() from above. This, however, has definitely no consequences in practice but explains the slight differences in rpact and gsDesign.


System: rpact 4.4.0, R version 4.5.2 (2025-10-31), platform: x86_64-pc-linux-gnu

To cite R in publications use:

R Core Team (2025). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing, Vienna, Austria. https://www.R-project.org/.

To cite package ‘rpact’ in publications use:

Wassmer G, Pahlke F (2026). rpact: Confirmatory Adaptive Clinical Trial Design and Analysis. R package version 4.4.0. doi:10.32614/CRAN.package.rpact

Wassmer G, Brannath W (2025). Group Sequential and Confirmatory Adaptive Designs in Clinical Trials, 2nd edition. Springer, Cham, Switzerland. ISBN 978-3-031-89668-2, doi:10.1007/978-3-031-89669-9 https://doi.org/10.1007/978-3-031-89669-9.