Bernstein, D and Lagakos, SW. *Sample size and power determination for stratified clinical trials*. Journal of Statistical Computation Simulation, 8:65-73, 1978.

The Two Arm Survival calculator computes an estimate of total sample size and either accrual rate or power for a comparison of survival between two arms.

The calculations are based on the assumptions of uniform accrual over time, no loss to follow-up, exponentially distributed event times, large sample approximation, and use of the exponential MLE test.

The user is prompted for the type of calculation to be performed, either a calculation of sample size required or a calculation of power. The user can also perform the calculation over a specified number of strata (maximum 6). The default setting is to estimate the power for a single stratum. The user is then prompted for the inputs listed below.

All inputs must be in terms of the same time units (e.g. years, months, etc).

For survival calculations involving more than one stratum, all calculations will be performed such that the hazard ratio will remain equal between all strata. For input type of hazard ratio, the hazard ratio input will be used for all strata; for input types of survival proportion and median survival, only the first strata will have prompts for estimates on the experimental arm, and the hazard ratio calculated from these estimates will be automatically applied to the additional strata.

Some input items have initial default values, as indicated in parentheses below.

The user is prompted for values to the following items. For items that have initial default values set, the values are given in parentheses.

- Type of calculation- sample size or power
- Input type: hazard ratio, survival proportions, or median survival
- One-sided or two-sided test
- Number of strata (1)
- Proportion of patients in the standard/control group (0.5)
**\(\alpha\)**, the significance level (.05)- Accrual period length
- Follow-up time length
- Accrual rate, if performing a calculation for power
- Power, or
**\(1-\beta\)**, if performing a calculation of sample size - Proportion of patients in each strata (1 if one stratum declared; 0.5 in each stratum if two strata declared, etc.)

If input type is hazard ratio:

**\(S(t)_{0}\)**, the proportion of patients in the standard arm surviving at time*t*- Survival time
*t*corresponding to the above proportion estimate in the standard arm - Hazard ratio for comparison between study arms

If input type is survival proportions:

**\(S(t)_{0}\)**, the proportion of patients in the standard arm surviving at time*t*- Survival time
*t*corresponding to the above proportion estimate in the standard arm **\(S(t)_{a}\)**, the proportion of patients in the experimental arm surviving at time*t*- Survival time
*t*corresponding to the above proportion estimate in the experimental arm

If input type is median survival:

**\(M_{0}\)**, the median survival time estimate in the standard arm**\(M_{a}\)**, the median survival time estimate in the experimental arm

- Power (if power calculation was requested)
- Accrual rate (if sample size calculation was requested)
- Total accrual

Within each stratum, the following will also be output:

- Hazard rate in the standard arm
- Hazard rate in the experimental arm

If input type is hazard ratio:

- Proportion surviving in the experimental arm
- Survival time in the experimental arm (will automatically be set equal to survival time in the standard arm)
- Median survival, standard arm
- Median survival, experimental arm

If input type is survival proportions:

- Hazard ratio (calculation will be fixed such that hazard ratio is the same across all strata)
- Proportion surviving in the experimental arm for all strata after the first
- Survival time in the experimental arm for all strata after the first (will automatically be set equal to survival time in the standard arm)
- Median survival, standard arm
- Median survival, experimental arm

If input type is median survival:

- Hazard ratio (calculation will be fixed such that hazard ratio is the same across all strata)
- Survival time in the experimental arm for all strata after the first (will automatically be determined based on hazard ratio for the survival calculation in the first stratum)

- Accrual rate: Note that accrual rate will be based on the same unit of time as the input used for time parameter inputs (e.g. if all time estimates input into the calculation are in years, accrual rate will be number of subjects per year).

The program is written in *R*.

```
function(calc_type = "Sample Size", input_type = "Hazard Ratio", p_s, sides, accrual, followup, pstrat = 1, p0, t0, hr, p1, t1, accrualRate, alpha, power) {
if (input_type == "Survival Proportions") {
hr = (-log(p0) / t0) / (-log(p1) / t1)
}
if (input_type == "Median Survival") {
hr = (-log(p0) / t0) / (-log(p1) / t1)
}
alpha = alpha / sides
zalpha = qnorm(alpha)
nstrata = length(p0)
hre_s = array(nstrata)
hre_e = array(nstrata)
ps_e = array(nstrata)
ms_s = array(nstrata)
ms_e = array(nstrata)
st_e = array(nstrata)
cpie = array(nstrata)
epie = array(nstrata)
stratvalues = matrix(, nrow = nstrata, ncol = 6)
for (i in 1:nstrata) {
hre_s[i] = -log(p0[i]) / t0[i]
hre_e[i] = (-log(p0[i]) / t0[i]) / hr
ps_e[i] = exp(-hre_e[i] * t0[i])
ms_s[i] = -log(0.5) / hre_s[i]
ms_e[i] = -log(0.5) / hre_e[i]
if(input_type == "Hazard Ratio") {st_e[i] = t0[i]}
else if(input_type == "Survival Proportions" | input_type == "Median Survival") {st_e[i] = t1[i]}
stratvalues[i, 1] = round(hre_s[i], 4)
stratvalues[i, 2] = round(hre_e[i], 4)
stratvalues[i, 3] = round(ps_e[i], 3)
stratvalues[i, 4] = round(ms_s[i], 3)
stratvalues[i, 5] = round(ms_e[i], 3)
stratvalues[i, 6] = round(st_e[i], 3)
cpie[i] = 1 - (exp(-hre_s[i] * followup) - exp(-hre_s[i] * accrual - hre_s[i] * followup)) / (accrual * hre_s[i])
epie[i] = 1 - (exp(-hre_e[i] * followup) - exp(-hre_e[i] * accrual - hre_e[i] * followup)) / (accrual * hre_e[i])
}
wn = 0
wa = 0
if (calc_type == "Sample Size") {
#sample size calculation given input of power
for (i in 1:nstrata) {
f = pstrat[i] * accrual
fc = f * p_s
fe = f - fc
#set varN, varA to same calculation (alt-alt variance term)
#this matches the formula in the Bernstein, Lagakos manuscript
#the code in this manuscript uses null-null instead of alt-alt and is erroneous
varN = 1 / (fc * cpie[i]) + 1 / (fe * epie[i])
varA = 1 / (fc * cpie[i]) + 1 / (fe * epie[i])
wn = wn + 1 / varN
wa = wa + 1 / varA
}
vn = 1 / wn
va = 1 / wa
zalpha = -zalpha
crit = zalpha * sqrt(vn)
zbeta = qnorm(1 - power)
accrualRate = (crit - zbeta * sqrt(va)) / log(hr)
accrualRate = round(accrualRate * accrualRate, 2)
totalAccrual = floor(accrualRate * accrual)
} else if (calc_type == "Power") {
#power calculation given inputs of sample size, accrual rate
for (i in 1:nstrata) {
f = accrualRate * pstrat[i] * accrual
fc = f * p_s
fe = f - fc
#set varN, varA to same calculation (alt-alt variance term)
#this matches the formula in the Bernstein, Lagakos manuscript
#the code in this manuscript uses null-null instead of alt-alt and is erroneous
varN = 1 / (fc * cpie[i]) + 1 / (fe * epie[i])
varA = 1 / (fc * cpie[i]) + 1. / (fe * epie[i])
wn = wn + 1 / varN
wa = wa + 1 / varA
}
vn = 1 / wn
va = 1 / wa
zalpha = -zalpha
crit = zalpha * sqrt(vn)
power = round(1 - pnorm((crit - log(hr)) / sqrt(va)), 4)
totalAccrual = floor(accrualRate * accrual)
}
calcvalues = data.frame(Power = power,
Sample_Size = totalAccrual,
Accrual_Rate = accrualRate,
Hazard_Ratio = hr)
stratvalues = as.data.frame(stratvalues)
names(stratvalues) = c("Hazard_Rate_Std", "Hazard_Rate_Exp", "Prop_Surviving_Exp",
"Median_Survival_Std", "Median_Survival_Exp", "Survival_Time_Exp")
output = list(calcvalues = calcvalues,
stratvalues = stratvalues)
return(jsonlite::toJSON(output, pretty = TRUE))
}
```