I did a CP/PZ simulation based on an unfavorable case, where the initial assumptions of hazard rates were 0.9 and 0.3 for two groups respectively, while the actual rates were 0.3 for both groups. In that case, I would expect almost all the simulations to turn out to be in the unfavorable zone. However, from Liu and Lim (2017) method, all 100 simulations turn out to be in either promising zone or favorable zone.

I think the major reason is because this paper used z1 (log-rank test statistic at interim) or all the calculations. When the interim is unblinded, it’s fine, z1 is based on observed real data. However, when the method is applied to blinded interim, with only pooled hazard rate observed, and applying the initial assumptions of either difference of hazard rate or hazard ratio, we assume there is still difference between groups. The logrank test is just testing the difference of the two survival curves. Therefore, the method of using log-rank test statistics at interim is not good for blinded interim.

# Load required libraries
library(survival)
## Warning: package 'survival' was built under R version 4.2.3
library(gsDesign)
## Warning: package 'gsDesign' was built under R version 4.2.3
set.seed(12345)

# Set parameters
k <- 2  # Number of analyses (including final)
alpha <- 0.025  # One-sided Type I error rate
beta <- 0.1  # Type II error rate (1 - power)
shape <- 0.15  # Parameter for Wang & Tsiatis boundaries (rho = 0.5 is equivalent to Pocock's boundary)
test.type <- 1  # Two-sided symmetric
rate1 <- 0.9  # Assumed Hazard rate for group 1 
rate2 <- 0.3  # Assumed Hazard rate for group 2 
t1 <- 0.5  # Information fraction at interim
real_rate1 <- 0.3  # Actual Hazard rate for group 1 
real_rate2 <- 0.3  # Actual Hazard rate for group 2 
num_simulations <- 100

# Calculate Wang & Tsiatis upper boundaries
calc_WT_boundary <- function(k, alpha, beta, shape, test.type) {
  gs_result <- gsDesign(k = k, alpha = alpha, beta = beta, sfupar = shape, test.type = test.type, sfu = "WT")
  return(gs_result$upper$bound)     
}

# Calculate the WT upper boundaries
upper_boundaries <- calc_WT_boundary(k, alpha, beta, shape, test.type)

# Extract the specific upper boundary value (for the final analysis)
b <- upper_boundaries[2]

# Calculate initial d (number of events needed)
calc_d <- function(alpha, beta, rate1, rate2) {
  z_alpha <- qnorm(1 - alpha)
  z_beta <- qnorm(1 - beta)
  log_hazard_ratio <- log(rate1 / rate2)
  d <- 2 * ((z_alpha + z_beta)^2) / (log_hazard_ratio^2)
  d1 <- t1 * d
  d2 <- d - d1
  return(list(d = d, d1 = d1, d2 = d2))    
}

# Calculate initial d and d1
initial_d <- calc_d(alpha, beta, rate1, rate2)

# Extract initial d and d1, and dmax for increase
d <- ceiling(initial_d$d)
d1 <- ceiling(initial_d$d1)
d2 <- ceiling(initial_d$d2)
dmax <- 2 * ceiling(initial_d$d)

# Get number of subjects needed at initial planning (up round to next even integer)
n <- ceiling(d / ((rate1 + rate2) / 2) / 2) * 2

# Simulate z1 for num_simulations times at blinded interim
z1_values <- numeric(num_simulations)

for (i in 1:num_simulations) {
  # Generate survival times
  event_time1 <- rexp(n / 2, rate = real_rate1)
  event_time2 <- rexp(n / 2, rate = real_rate2)
  event_time <- c(event_time1, event_time2)

  # Generate full survival data for calculation of interim time
  cens_full <- rep(1, n)
  fit_full <- survfit(Surv(event_time, cens_full) ~ 1)

  # Use full survival data to calculate interim time
  cum_events <- cumsum(fit_full$n.event)
  # Find the interim time at which half of the events is reached
  interim_time <- fit_full$time[cum_events >= (d / 2)][1]

  # Compare with interim time 
  time <- ifelse(event_time <= interim_time, event_time, interim_time)
  # Event indicator: 1 = event, 0 = censored
  cens <- ifelse(event_time <= interim_time, 1, 0)

  # Pooled arms for blinded interim
  a.pooled <- survfit(Surv(time, cens) ~ 1)

  # Get the event rate at the last event time point at interim 
  est.p <- 1 - min(a.pooled$surv)

  # Calculate event rate in each treatment at interim, using assumed hazard ratio
  p1 <- est.p * rate1 / (rate1 + rate2)
  p2 <- est.p * rate2 / (rate1 + rate2)

  # Perform simulation with calculated p1 and p2
  simu_event_time1 <- rexp(n / 2, rate = p1)
  simu_event_time2 <- rexp(n / 2, rate = p2)
  simu_event_time <- c(simu_event_time1, simu_event_time2)
  simu_time <- ifelse(simu_event_time <= interim_time, simu_event_time, interim_time)
  simu_cens <- ifelse(simu_event_time <= interim_time, 1, 0)
  simu_group <- c(rep(1, n / 2), rep(2, n / 2))
  simu_fit <- survfit(Surv(simu_time, simu_cens) ~ simu_group)
  simu_logrank <- survdiff(Surv(simu_time, simu_cens) ~ simu_group)
  z1_values[i] <- sqrt(simu_logrank$chisq)
}
## Warning in pchisq(chi, df, lower.tail = FALSE): NaNs produced
## Warning in pchisq(chi, df, lower.tail = FALSE): NaNs produced
# Calculate new number of events needed in stage two d2*
calc_d2_star <- function(beta, d1, z1, b, d, dmax) {
  z_beta <- qnorm(1 - beta)
  d2_pound <- d1 / (z1^2) * ((b * sqrt(d) - z1 * sqrt(d1)) / sqrt(d - d1) + z_beta)^2
  d2_star <- ifelse(d2_pound <= dmax - d1, d2_pound, dmax - d1)
  return(d2_star)    
}

# Calculate the adjusted critical value b_star
calc_b_star <- function(d1, d2_star, d, b, z1) {
  b_star <- 1 / sqrt(d1 + d2_star) * ((sqrt(d2_star / (d - d1)) * (b * sqrt(d) - z1 * sqrt(d1)) + z1 * sqrt(d1)))
  return(b_star)    
}

# Calculate the adjusted CP and original CP
calc_cp <- function(d1, d2_star, d, b_star, b, z1) {
  val_new <- (b_star * sqrt((d1 + d2_star) / 4) - z1 * sqrt(d1 / 4) - sqrt(d2_star / 4) * z1 / sqrt(d1 / 4)) / sqrt(d2_star / 4)
  cp_star <- 1 - pnorm(val_new)
  val_org <- (b * sqrt((d1 + d2) / 4) - z1 * sqrt(d1 / 4) - sqrt(d2 / 4) * z1 / sqrt(d1 / 4)) / sqrt(d2 / 4)
  cp_org <- 1 - pnorm(val_org)
  return(list(cp_star = cp_star, cp_org = cp_org))  
}

# Store results
results <- data.frame()

for (i in 1:num_simulations) {
  z1 <- z1_values[i]
  d2_star_value <- ceiling(calc_d2_star(beta, d1, z1, b, d, dmax))
  d_star_value <- d2_star_value + d1
  b_star_value <- calc_b_star(d1, d2_star_value, d, b, z1)
  cp_values <- calc_cp(d1, d2_star_value, d, b_star_value, b, z1)
  results <- rbind(results, data.frame(z1 = z1, d = d, d_star = d_star_value, b_star = b_star_value, cp_star = cp_values$cp_star, cp_org = cp_values$cp_org))
}

# Define Promising zone 
pz <- results[results$b_star <= b, ]
cp_star_min_i <- ifelse(nrow(pz) > 0, min(pz$cp_org, na.rm = TRUE), 0)
cp_star_min <- min(cp_star_min_i, 0)
cp_star_max <- 1 - beta

# Define three zones
unfavorable_zone <- results[results$cp_org < cp_star_min, ]
if(nrow(unfavorable_zone) > 0) {
  unfavorable_zone$zone <- 1
  unfavorable_zone$d_star <- d
  unfavorable_zone$cp_star <- unfavorable_zone$cp_org
}

promising_zone <- results[results$cp_org >= cp_star_min & results$cp_org <= cp_star_max, ]
if(nrow(promising_zone) > 0) {
  promising_zone$zone <- 2
}

favorable_zone <- results[results$cp_org > cp_star_max, ]
if(nrow(favorable_zone) > 0) {
  favorable_zone$zone <- 3
  favorable_zone$d_star <- d
  favorable_zone$cp_star <- favorable_zone$cp_org
}

results_final <- rbind(unfavorable_zone, promising_zone, favorable_zone)
results_final$sample_ratio <- results_final$d_star / results_final$d

results_final
##             z1  d d_star   b_star     cp_star      cp_org zone sample_ratio
## 1   0.83207229 18     36 2.152383 0.073494980 0.073494980    2    2.0000000
## 2   0.55755214 18     36 2.252864 0.028209862 0.028209862    2    2.0000000
## 3   0.95748366 18     36 2.106479 0.107260960 0.107260960    2    2.0000000
## 4   0.80390747 18     36 2.162692 0.067172268 0.067172268    2    2.0000000
## 5   2.18584005 18     17 2.037147 0.789888290 0.789888290    2    0.9444444
## 6   1.47672763 18     36 1.916423 0.353525235 0.353525235    2    2.0000000
## 7   1.84211492 18     23 1.928547 0.592180826 0.592180826    2    1.2777778
## 8   1.50567948 18     36 1.905826 0.371619446 0.371619446    2    2.0000000
## 9   1.79508190 18     25 1.910610 0.561498727 0.561498727    2    1.3888889
## 10  0.74784183 18     36 2.183214 0.055846434 0.055846434    2    2.0000000
## 11  1.07250198 18     36 2.064380 0.146967184 0.146967184    2    2.0000000
## 12  1.03609160 18     36 2.077707 0.133453473 0.133453473    2    2.0000000
## 13  1.43902439 18     36 1.930223 0.330454296 0.330454296    2    2.0000000
## 14  1.00000000 18     36 2.090917 0.120926779 0.120926779    2    2.0000000
## 15  1.29467446 18     36 1.983059 0.248492179 0.248492179    2    2.0000000
## 16  1.07250198 18     36 2.064380 0.146967184 0.146967184    2    2.0000000
## 17  0.58009615 18     36 2.244613 0.030727599 0.030727599    2    2.0000000
## 18  0.58009615 18     36 2.244613 0.030727599 0.030727599    2    2.0000000
## 19  1.43902439 18     36 1.930223 0.330454296 0.330454296    2    2.0000000
## 20  0.89417934 18     36 2.129650 0.089032934 0.089032934    2    2.0000000
## 21  0.63916874 18     36 2.222991 0.038217881 0.038217881    2    2.0000000
## 22  0.83207229 18     36 2.152383 0.073494980 0.073494980    2    2.0000000
## 23  1.20849998 18     36 2.014601 0.205291981 0.205291981    2    2.0000000
## 24  1.77589072 18     25 1.914448 0.548861252 0.548861252    2    1.3888889
## 25  0.42342758 18     36 2.301957 0.016531377 0.016531377    2    2.0000000
## 26  1.00000000 18     36 2.090917 0.120926779 0.120926779    2    2.0000000
## 27  0.55755214 18     36 2.252864 0.028209862 0.028209862    2    2.0000000
## 28  1.00159780 18     36 2.090332 0.121463217 0.121463217    2    2.0000000
## 29  2.11344043 18     18 2.006085 0.753444031 0.753444031    2    1.0000000
## 30  0.58009615 18     36 2.244613 0.030727599 0.030727599    2    2.0000000
## 31  0.86232340 18     36 2.141310 0.080782507 0.080782507    2    2.0000000
## 32  1.43902439 18     36 1.930223 0.330454296 0.330454296    2    2.0000000
## 33  1.79508190 18     25 1.910610 0.561498727 0.561498727    2    1.3888889
## 34  0.86232340 18     36 2.141310 0.080782507 0.080782507    2    2.0000000
## 35  1.20370916 18     36 2.016355 0.203028869 0.203028869    2    2.0000000
## 36  0.00000000 18     36 2.456943 0.002276745 0.002276745    2    2.0000000
## 37  0.82356203 18     36 2.155498 0.071538294 0.071538294    2    2.0000000
## 38  0.48316675 18     36 2.280091 0.021089226 0.021089226    2    2.0000000
## 39  1.79508190 18     25 1.910610 0.561498727 0.561498727    2    1.3888889
## 40  1.24343737 18     36 2.001813 0.222243738 0.222243738    2    2.0000000
## 41  2.11344043 18     18 2.006085 0.753444031 0.753444031    2    1.0000000
## 43  1.79508190 18     25 1.910610 0.561498727 0.561498727    2    1.3888889
## 44  0.48316675 18     36 2.280091 0.021089226 0.021089226    2    2.0000000
## 45  0.02439024 18     36 2.448015 0.002583909 0.002583909    2    2.0000000
## 46  1.37835320 18     36 1.952430 0.294675167 0.294675167    2    2.0000000
## 47  0.04881744 18     36 2.439074 0.002928597 0.002928597    2    2.0000000
## 48  0.03577135 18     36 2.443849 0.002739666 0.002739666    2    2.0000000
## 49  1.03609160 18     36 2.077707 0.133453473 0.133453473    2    2.0000000
## 50  1.03609160 18     36 2.077707 0.133453473 0.133453473    2    2.0000000
## 51  2.41215184 18     14 2.187939 0.881639020 0.881639020    2    0.7777778
## 52  0.00000000 18     36 2.456943 0.002276745 0.002276745    2    2.0000000
## 53  1.43902439 18     36 1.930223 0.330454296 0.330454296    2    2.0000000
## 54  1.43902439 18     36 1.930223 0.330454296 0.330454296    2    2.0000000
## 55  0.04881744 18     36 2.439074 0.002928597 0.002928597    2    2.0000000
## 57  0.02439024 18     36 2.448015 0.002583909 0.002583909    2    2.0000000
## 58  1.43902439 18     36 1.930223 0.330454296 0.330454296    2    2.0000000
## 59  2.41215184 18     14 2.187939 0.881639020 0.881639020    2    0.7777778
## 60  1.07250198 18     36 2.064380 0.146967184 0.146967184    2    2.0000000
## 61  0.93066773 18     36 2.116295 0.099235462 0.099235462    2    2.0000000
## 62  1.26435129 18     36 1.994158 0.232762062 0.232762062    2    2.0000000
## 63  1.40922170 18     36 1.941132 0.312657979 0.312657979    2    2.0000000
## 64  0.55755214 18     36 2.252864 0.028209862 0.028209862    2    2.0000000
## 65  1.79508190 18     25 1.910610 0.561498727 0.561498727    2    1.3888889
## 66  0.02439024 18     36 2.448015 0.002583909 0.002583909    2    2.0000000
## 67  1.39083689 18     36 1.947861 0.301890285 0.301890285    2    2.0000000
## 68  1.44192976 18     36 1.929160 0.332210745 0.332210745    2    2.0000000
## 69  0.58009615 18     36 2.244613 0.030727599 0.030727599    2    2.0000000
## 70  1.67178985 18     29 1.899013 0.479775659 0.479775659    2    1.6111111
## 71  1.29708956 18     36 1.982175 0.249768916 0.249768916    2    2.0000000
## 72  1.00159780 18     36 2.090332 0.121463217 0.121463217    2    2.0000000
## 73  1.11110266 18     36 2.050251 0.162264080 0.162264080    2    2.0000000
## 74  1.51391656 18     36 1.902811 0.376821741 0.376821741    2    2.0000000
## 75  2.15136921 18     17 2.035713 0.772945499 0.772945499    2    0.9444444
## 76  1.43902439 18     36 1.930223 0.330454296 0.330454296    2    2.0000000
## 77  0.48316675 18     36 2.280091 0.021089226 0.021089226    2    2.0000000
## 78  2.11344043 18     18 2.006085 0.753444031 0.753444031    2    1.0000000
## 79  1.87898132 18     22 1.938261 0.615851218 0.615851218    2    1.2222222
## 80  0.59737730 18     36 2.238287 0.032781172 0.032781172    2    2.0000000
## 81  2.18584005 18     17 2.037147 0.789888290 0.789888290    2    0.9444444
## 82  2.41215184 18     14 2.187939 0.881639020 0.881639020    2    0.7777778
## 83  1.02173245 18     36 2.082963 0.128366734 0.128366734    2    2.0000000
## 84  1.07250198 18     36 2.064380 0.146967184 0.146967184    2    2.0000000
## 85  0.04206097 18     36 2.441547 0.002829333 0.002829333    2    2.0000000
## 86  1.47672763 18     36 1.916423 0.353525235 0.353525235    2    2.0000000
## 87  1.03609160 18     36 2.077707 0.133453473 0.133453473    2    2.0000000
## 88  1.37835320 18     36 1.952430 0.294675167 0.294675167    2    2.0000000
## 89  1.40922170 18     36 1.941132 0.312657979 0.312657979    2    2.0000000
## 90  1.55973808 18     34 1.897750 0.406146253 0.406146253    2    1.8888889
## 92  0.03577135 18     36 2.443849 0.002739666 0.002739666    2    2.0000000
## 93  2.11344043 18     18 2.006085 0.753444031 0.753444031    2    1.0000000
## 94  0.63916874 18     36 2.222991 0.038217881 0.038217881    2    2.0000000
## 95  2.11344043 18     18 2.006085 0.753444031 0.753444031    2    1.0000000
## 96  1.91873006 18     21 1.950275 0.640894350 0.640894350    2    1.1666667
## 97  0.63916874 18     36 2.222991 0.038217881 0.038217881    2    2.0000000
## 98  1.44192976 18     36 1.929160 0.332210745 0.332210745    2    2.0000000
## 99  1.43902439 18     36 1.930223 0.330454296 0.330454296    2    2.0000000
## 100 1.07250198 18     36 2.064380 0.146967184 0.146967184    2    2.0000000
## 42  3.27522012 18     18 2.968580 0.995624958 0.995624958    3    1.0000000
## 56  2.84910453 18     18 2.571965 0.972028185 0.972028185    3    1.0000000
## 91  3.14451287 18     18 2.885913 0.991887658 0.991887658    3    1.0000000