Author: Gautier Paux and Alex Dmitrieniko
Date: 2019-05-08

# Mediana: an R package for clinical trial simulations

#### Gautier Paux and Alex Dmitrieniko

#### 2019-05-08

# Introduction

## About

Mediana is an R package which provides a general framework for clinical trial simulations based on the Clinical Scenario Evaluation approach. The package supports a broad class of data models (including clinical trials with continuous, binary, survival-type and count-type endpoints as well as multivariate outcomes that are based on combinations of different endpoints), analysis strategies and commonly used evaluation criteria.

## Expert and development teams

Package design: Alex Dmitrienko (Mediana Inc.).

Core development team: Gautier Paux (Servier), Alex Dmitrienko (Mediana Inc.).

Extended development team: Thomas Brechenmacher (Novartis), Fei Chen (Johnson and Johnson), Ilya Lipkovich (Quintiles), Ming-Dauh Wang (Lilly), Jay Zhang (MedImmune), Haiyan Zheng (Osaka University).

Expert team: Keaven Anderson (Merck), Frank Harrell (Vanderbilt University), Mani Lakshminarayanan (Pfizer), Brian Millen (Lilly), Jose Pinheiro (Johnson and Johnson), Thomas Schmelter (Bayer).

## Installation

### Latest release

Install the latest version of the Mediana package from CRAN using the `install.packages` command in R:

    install.packages("Mediana")

Alternatively, you can download the package from the CRAN website.

### Development version

The up-to-date development version can be found and installed directly from the GitHub web site. You need to install the `devtools` package and then call the `install_github` function in R:

    # install.packages("devtools")
    devtools::install_github("gpaux/Mediana")

## Clinical Scenario Evaluation Framework

The Mediana R package was developed to provide a general software implementation of the Clinical Scenario Evaluation (CSE) framework. This framework introduced by Benda et al. (2010) and Friede et al. (2010) recognizes that sample size calculation and power evaluation in clinical trials are high-dimensional statistical problems. This approach helps decompose this complex problem by identifying key elements of the evaluation process. These components are termed models:

- Data models define the process of generating trial data (e.g., sample sizes, outcome distributions and parameters).
- Analysis models define the statistical methods applied to the trial data (e.g., statistical tests, multiplicity adjustments).
- Evaluation models specify the measures for evaluating the performance of the analysis strategies (e.g., traditional success criteria such as marginal power or composite criteria such as disjunctive power).

Find out more about the role of each model and how to specify the three models to perform Clinical Scenario Evaluation by reviewing the dedicated pages (click on the links above).

## Case studies

Multiple case studies are provided on the web site’s package to facilitate the implementation of Clinical Scenario Evaluation in different clinical trial settings using the Mediana package. These case studies will be updated on a regular basis. Another vignette accessible with the following command is also available presenting these case studies.

    vignette("case-studies", package = "Mediana")

The Mediana package has been successfully used in multiple clinical trials to perform power calculations as well as optimally select trial designs and analysis strategies (clinical trial optimization). For more information on applications of the Mediana package, download the following papers:

- Dmitrienko, A., Paux, G., Brechenmacher, T. (2016). Power calculations in clinical trials with complex clinical objectives. Journal of the Japanese Society of Computational Statistics. 28, 15-50.
- Dmitrienko, A., Paux, G., Pulkstenis, E., Zhang, J. (2016). Tradeoff-based optimization criteria in clinical trials with multiple objectives and adaptive designs. Journal of Biopharmaceutical Statistics. 26, 120-140.

# Data model

Data models define the process of generating patient data in clinical trials.

## Initialization

A data model can be initialized using the following command

    # DataModel initialization
    data.model = DataModel()

It is highly recommended to use this command as it will simplify the process of specifying components of the data model, e.g., `OutcomeDist`, `Sample`, `SampleSize`, `Event` and `Design` objects.

## Components of a data model

Once the `DataModel` object has been initialized, components of the data model can be specified by adding objects to the model using the ‘+’ operator as shown below.

    # Outcome parameter set 1
    outcome1.placebo = parameters(mean = 0, sd = 70)
    outcome1.treatment = parameters(mean = 40, sd = 70)

    # Outcome parameter set 2
    outcome2.placebo = parameters(mean = 0, sd = 70)
    outcome2.treatment = parameters(mean = 50, sd = 70)

    # Data model
    case.study1.data.model =  DataModel() +
      OutcomeDist(outcome.dist = "NormalDist") +
      SampleSize(c(50, 55, 60, 65, 70)) +
      Sample(id = "Placebo",
             outcome.par = parameters(outcome1.placebo, outcome2.placebo)) +
      Sample(id = "Treatment",
             outcome.par = parameters(outcome1.treatment, outcome2.treatment))

### `OutcomeDist` object

#### Description

This object specifies the distribution of patient outcomes in a data model. An `OutcomeDist` object is defined by two arguments:

- `outcome.dist` defines the outcome distribution.

- `outcome.type` defines the outcome type (optional). There are two acceptable values of this argument: `standard` (fixed-design setting) and `event` (event-driven design setting).

Several distributions that can be specified using the `outcome.dist` argument are already implemented in the Mediana package. These distributions are listed below along with the required parameters to be included in the `outcome.par` argument of the `Sample` object:

- `UniformDist`: generate data following a univariate distribution. Required parameter: `max`.

- `NormalDist`: generate data following a normal distribution. Required parameters: `mean` and `sd`.

- `BinomDist`: generate data following a binomial distribution. Required parameter: `prop`.

- `BetaDist`: generate data following a beta distribution. Required parameter: `a` and `b`.

- `ExpoDist`: generate data following an exponential distribution. Required parameter: `rate`.

- `WeibullDist`: generate data following a weibull distribution. Required parameter: `shape` and `scale`.

- `TruncatedExpoDist`: generate data following a truncated exponential distribution. Required parameter: `rate` an `trunc`.

- `PoissonDist`: generate data following a Poisson distribution. Required parameter: `lambda`.

- `NegBinomDist`: generate data following a negative binomial distribution. Required parameters: `dispersion` and `mean`.

- `MultinomialDist`: generate data following a multinomial distribution. Required parameters: `prob`.

- `MVNormalDist`: generate data following a multivariate normal distribution. Required parameters: `par` and `corr`. For each generated endpoint, the `par` parameter must contain the required parameters `mean` and `sd`. The `corr` parameter specifies the correlation matrix for the endpoints.

- `MVBinomDist`: generate data following a multivariate binomial distribution. Required parameters: `par` and `corr`. For each generated endpoint, the `par` parameter must contain the required parameter `prop`. The `corr` parameter specifies the correlation matrix for the endpoints.

- `MVExpoDist`: generate data following a multivariate exponential distribution. Required parameters: `par` and `corr`. For each generated endpoint, the `par` parameter must contain the required parameter `rate`. The `corr`parameter specifies the correlation matrix for the endpoints.

- `MVExpoPFSOSDist`: generate data following a multivariate exponential distribution to generate PFS and OS endpoints. The PFS value is imputed to the OS value if the latter occurs earlier. Required parameters: `par` and `corr`. For each generated endpoint, the `par` parameter must contain the required parameter `rate`. The`corr` parameter specifies the correlation matrix for the endpoints.

- `MVMixedDist`: generate data following a multivariate mixed distribution. Required parameters: `type`, `par` and `corr`. The `type` parameter assumes the following values: `NormalDist`, `BinomDist` and `ExpoDist`. For each generated endpoint, the `par` parameter must contain the required parameters according to the distribution type. The `corr` parameter specifies the correlation matrix for the endpoints.

The `outcome.type` argument defines the outcome’s type. This argument accepts only two values:

- `standard`: for fixed design setting.

- `event`: for event-driven design setting.

The outcome’s type must be defined for each endpoint in case of multivariate disribution, e.g. `c("event","event")` in case of multivariate exponential distribution. The `outcome.type` argument is essential to get censored events for time-to-event endpoints if the `SampleSize` object is used to specify the number of patients to generate.

A single `OutcomeDist` object can be added to a `DataModel` object.

For more information about the `OutcomeDist` object, see the documentation for OutcomeDist on the CRAN web site.

If a certain outcome distribution is not implemented in the Mediana package, the user can create a custom function and use it within the package (see the dedicated vignette `vignette("custom-functions", package = "Mediana")`).

#### Example

Examples of `OutcomeDist` objects:

Specify popular univariate distributions:

    # Normal distribution
    OutcomeDist(outcome.dist = "NormalDist")

    # Binomial distribution
    OutcomeDist(outcome.dist = "BinomDist")

    # Exponential distribution
    OutcomeDist(outcome.dist = "ExpoDist")

Specify a mixed multivariate distribution:

    # Multivariate Mixed distribution
    OutcomeDist(outcome.dist = "MVMixedDist")

### `Sample` object

#### Description

This object specifies parameters of a sample (e.g., treatment arm in a trial) in a data model. Samples are defined as mutually exclusive groups of patients, for example, treatment arms. A `Sample` object is defined by three arguments:

- `id` defines the sample’s unique ID (label).

- `outcome.par` defines the parameters of the outcome distribution for the sample.

- `sample.size` defines the sample’s size (optional).

The `sample.size` argument is optional but must be used to define the sample size only if an unbalanced design is considered (i.e., the sample size varies across the samples). The sample size must be either defined in the `Sample` object or in the `SampleSize` object, but not in both.

Several `Sample` objects can be added to a `DataModel` object.

For more information about the `Sample` object, see the documentation Sample on the CRAN web site.

#### Example

Examples of `Sample` objects:

Specify two samples with a continuous endpoint following a normal distribution:

    # Outcome parameters set 1
    outcome1.placebo = parameters(mean = 0, sd = 70)
    outcome1.treatment = parameters(mean = 40, sd = 70)

    # Outcome parameters set 2
    outcome2.placebo = parameters(mean = 0, sd = 70)
    outcome2.treatment = parameters(mean = 50, sd = 70)

    # Placebo sample object
    Sample(id = "Placebo",
           outcome.par = parameters(outcome1.placebo,
                                    outcome2.placebo))

    # Treatment sample object
    Sample(id = "Treatment",
           outcome.par = parameters(outcome1.treatment,
                                    outcome2.treatment))

Specify two samples with a binary endpoint following a binomial distribution:

    # Outcome parameters set
    outcome.placebo = parameters(prop = 0.30)
    outcome.treatment = parameters(prop = 0.50)

    # Placebo sample object
    Sample(id = "Placebo",
           outcome.par = parameters(outcome1.placebo))

    # Treatment sample object
    Sample(id = "Treatment",
           outcome.par = parameters(outcome1.treatment))

Specify two samples with a time-to-event (survival) endpoint following an exponential distribution:

    # Outcome parameters
    median.time.placebo = 6
    rate.placebo = log(2)/median.time.placebo
    outcome.placebo = parameters(rate = rate.placebo)

    median.time.treatment = 9
    rate.treatment = log(2)/median.time.treatment
    outcome.treatment = parameters(rate = rate.treatment)

    # Placebo sample object
    Sample(id = "Placebo",
           outcome.par = parameters(outcome.placebo))

    # Treatment sample object
    Sample(id = "Treatment",
           outcome.par = parameters(outcome.treatment))

Specify three samples with two primary endpoints that follow a binomial and a normal distribution, respectively:

    # Variable types
    var.type = list("BinomDist", "NormalDist")

    # Outcome distribution parameters
    placebo.par = parameters(parameters(prop = 0.3),
                             parameters(mean = -0.10, sd = 0.5))

    dosel.par = parameters(parameters(prop = 0.40),
                           parameters(mean = -0.20, sd = 0.5))

    doseh.par = parameters(parameters(prop = 0.50),
                           parameters(mean = -0.30, sd = 0.5))

    # Correlation between two endpoints
    corr.matrix = matrix(c(1.0, 0.5,
                           0.5, 1.0), 2, 2)

    # Outcome parameters set
    outcome.placebo = parameters(type = var.type,
                                 par = plac.par,
                                 corr = corr.matrix)

    outcome.dosel = parameters(type = var.type,
                               par = dosel.par,
                               corr = corr.matrix)

    outcome.doseh = parameters(type = var.type,
                               par = doseh.par,
                               corr = corr.matrix)

    # Placebo sample object
    Sample(id = list("Plac ACR20", "Plac HAQ-DI"),
           outcome.par = parameters(outcome.placebo))

    # Low Dose sample object
    Sample(id = list("DoseL ACR20", "DoseL HAQ-DI"),
           outcome.par = parameters(outcome.dosel))

    # High Dose sample object
    Sample(id = list("DoseH ACR20", "DoseH HAQ-DI"),
           outcome.par = parameters(outcome.doseh))

### `SampleSize` object

#### Description

This object specifies the sample size in a balanced trial design (all samples will have the same sample size). A `SampleSize` object is defined by one argument:

- `sample.size` specifies a list or vector of sample size(s).

A single `SampleSize` object can be added to a `DataModel` object.

For more information about the `SampleSize` object, see the package’s documentation SampleSize.

#### Example

Examples of `SampleSize` objects:

Several equivalent specifications of the `SampleSize` object:

    SampleSize(c(50, 55, 60, 65, 70))
    SampleSize(list(50, 55, 60, 65, 70))
    SampleSize(seq(50, 70, 5))

### `Event` object

#### Description

This object specifies the total number of events (total event count) among all samples in an event-driven clinical trial. An `Event` object is defined by two arguments:

- `n.events` defines a vector of the required event counts.

- `rando.ratio` defines a vector of randomization ratios for each `Sample` object defined in the `DataModel` object.

A single `Event` object can be added to a `DataModel` object.

For more information about the `Event` object, see the package’s documentation Event.

#### Example

Examples of `Event` objects:

Specify the required number of events in a trial with a 2:1 randomization ratio (Treatment:Placebo):

    # Event parameters
    event.count.total = c(390, 420)
    randomization.ratio = c(1,2)

    # Event object
    Event(n.events = event.count.total,
          rando.ratio = randomization.ratio)

### `Design` object

#### Description

This object specifies the design parameters used in event-driven designs if the user is interested in modeling the enrollment (or accrual) and dropout (or loss to follow up) processes. A `Design` object is defined by seven arguments:

- `enroll.period` defines the length of the enrollment period.

- `enroll.dist` defines the enrollment distribution.

- `enroll.dist.par` defines the parameters of the enrollment distribution (optional).

- `followup.period` defines the length of the follow-up period for each patient in study designs with a fixed follow-up period, i.e., the length of time from the enrollment to planned discontinuation is constant across patients. The user must specify either `followup.period` or `study.duration`.

- `study.duration` defines the total study duration in study designs with a variable follow-up period. The total study duration is defined as the length of time from the enrollment of the first patient to the discontinuation of the last patient.

- `dropout.dist` defines the dropout distribution.

- `dropout.dist.par` defines the parameters of the dropout distribution.

Several `Design` objects can be added to a `DataModel` object.

For more information about the `Design` object, see the package’s documentation Design.

A convienient way to model non-uniform enrollment is to use a beta distribution (`BetaDist`). If `enroll.dist = "BetaDist"`, the `enroll.dist.par` should contain the parameter of the beta distribution (`a` and `b`). These parameters must be derived according to the expected enrollment at a specific timepoint. For example, if half the patients are expected to be enrolled at 75% of the enrollment period, the beta distribution is a `Beta(log(0.5)/log(0.75), 1)`. Generally, let `q` be the proportion of enrolled patients at `100p`% of the enrollment period, the Beta distribution can be derived as follows:

- If `q < p`, the Beta distribution is `Beta(a,1)` with `a = log(q) / log(p)`

- If `q > p`, the Beta distribution is `Beta (1,b)` with `b = log(1-q) / log(1-p)`

- Otherwise the Beta distribution is `Beta(1,1)`

#### Example

Examples of `Design` objects:

Specify parameters of the enrollment and dropout processes with a uniform enrollment distribution and exponential dropout distribution:

    # Design parameters (in months)
    Design(enroll.period = 9,
           study.duration = 21,
           enroll.dist = "UniformDist",
           dropout.dist = "ExpoDist",
           dropout.dist.par = parameters(rate = 0.0115))

# Analysis model

Analysis models define statistical methods (e.g., significance tests or descriptive statistics) that are applied to the study data in a clinical trial.

## Initialization

An analysis model can be initialized using the following command:

    # AnalysisModel initialization
    analysis.model = AnalysisModel()

It is highly recommended to use this command to initialize an analysis model as it will simplify the process of specifying components of the data model, including the `MultAdj`, `MultAdjProc`, `MultAdjStrategy`, `Test`, `Statistic` objects.

## Components of an analysis model

After an `AnalysisModel` object has been initialized, components of the analysis model can be specified by adding objects to the model using the ‘+’ operator as shown below.

    # Analysis model
    case.study1.analysis.model = AnalysisModel() +
      Test(id = "Placebo vs treatment",
           samples = samples("Placebo", "Treatment"),
           method = "TTest") +
      Statistic(id = "Mean Treatment",
                method = "MeanStat",
                samples = samples("Treatment"))

### `Test` object

#### Description

This object specifies a significance test that will be applied to one or more samples defined in a data model. A `Test` object is defined by the following four arguments:

- `id` defines the test’s unique ID (label).

- `method` defines the significance test.

- `samples` defines the IDs of the samples (defined in the data model) that the significance test is applied to.

- `par` defines the parameter(s) of the statistical test.

Several commonly used significance tests are already implemented in the Mediana package. In addition, the user can easily define custom significance tests (see the dedicated vignette `vignette("custom-functions", package = "Mediana")`). The built-in tests are listed below along with the required parameters that need to be included in the `par` argument:

- `TTest`: perform the two-sample t-test between the two samples defined in the `samples` argument. Optional parameter: `larger` (Larger value is expected in the second sample (`TRUE` or `FALSE`)).

- `TTestNI`: perform the non-inferiority two-sample t-test between the two samples defined in the `samples` argument. Required parameter: `margin` (positive non-inferiority margin). Optional parameter: `larger` (Larger value is expected in the second sample (`TRUE` or `FALSE`)).

- `WilcoxTest`: perform the Wilcoxon-Mann-Whitney test between the two samples defined in the `samples` argument. Optional parameter: `larger` (Larger value is expected in the second sample (`TRUE` or `FALSE`)).

- `PropTest`: perform the two-sample test for proportions between the two samples defined in the `samples` argument. Optional parameter: `yates` (Yates’ continuity correction flag that is set to `TRUE` or `FALSE`) and `larger` (Larger value is expected in the second sample (`TRUE` or `FALSE`)).

- `PropTestNI`: perform the non-inferiority two-sample test for proportions between the two samples defined in the `samples` argument. Required parameter: `margin` (positive non-inferiority margin). Optional parameter: `yates` (Yates’ continuity correction flag that is set to `TRUE` or `FALSE`) and `larger` (Larger value is expected in the second sample (`TRUE` or `FALSE`)).

- `FisherTest`: perform the Fisher exact test between the two samples defined in the `samples` argument. Optional parameter: `larger` (Larger value is expected in the second sample (`TRUE` or `FALSE`)).

- `GLMPoissonTest`: perform the Poisson regression test between the two samples defined in the `samples` argument. Optional parameter: `larger` (Larger value is expected in the second sample (`TRUE` or `FALSE`)).

- `GLMNegBinomTest`: perform the Negative-binomial regression test between the two `samples` defined in the `samples` argument. Optional parameter: `larger` (Larger value is expected in the second sample (`TRUE` or `FALSE`)).

- `LogrankTest`: perform the Log-rank test between the two samples defined in the `samples` argument. Optional parameter: `larger` (Larger value is expected in the second sample (`TRUE` or `FALSE`)).

- `OrdinalLogisticRegTest`: perform an ordinal logistic regression test between the two samples defined in the `samples` argument. Optional parameter: `larger` (Larger value is expected in the second sample (`TRUE` or `FALSE`)).

It needs to be noted that the significance tests listed above are implemented as one-sided tests and thus the sample order in the `samples` argument is important. In particular, the Mediana package assumes by default that a numerically larger value of the endpoint is expected in Sample 2 compared to Sample 1. Suppose, for example, that a higher treatment response indicates a beneficial effect (e.g., higher improvement rate). In this case Sample 1 should include control patients whereas Sample 2 should include patients allocated to the experimental treatment arm. The sample order needs to be reversed if a beneficial treatment effect is associated with a lower value of the endpoint (e.g., lower blood pressure), or alternatively (from version 1.0.6), the optional parameters `larger` must be set to FALSE to indicate that a larger value is expected on the first Sample.

Several `Test` objects can be added to an `AnalysisModel`object.

For more information about the `Test` object, see the package’s documentation Test on the CRAN web site.

#### Example

Examples of `Test` objects:

Carry out the two-sample t-test:

    # Placebo and Treatment samples were defined in the data model
    Test(id = "Placebo vs treatment",
         samples = samples("Placebo", "Treatment"),
         method = "TTest")

Carry out the two-sample t-test with larger values expected in the first sample (from v1.0.6):

    # Placebo and Treatment samples were defined in the data model
    Test(id = "Placebo vs treatment",
         samples = samples("Treatment", "Placebo"),
         method = "TTest",
         par = parameters(larger = FALSE))

Carry out the two-sample t-test for non-inferiority:

    # Placebo and Treatment samples were defined in the data model
    Test(id = "Placebo vs treatment",
         samples = samples("Placebo", "Treatment"),
         method = "TTestNI",
         par = parameters(margin = 0.2))

Carry out the two-sample t-test with pooled samples:

    # Placebo M-, Placebo M+, Treatment M- and Treatment M+ samples were defined in the data model
    Test(id = "OP test",
         samples = samples(c("Placebo M-", "Placebo M+"),
                           c("Treatment M-", "Treatment M+")),
         method = "TTest")

### `Statistic` object

#### Description

This object specifies a descriptive statistic that will be computed based on one or more samples defined in a data model. A `Statistic` object is defined by four arguments:

- `id` defines the descriptive statistic’s unique ID (label).

- `method` defines the type of statistic/method for computing the statistic.

- `samples` defines the samples (pre-defined in the data model) to be used for computing the statistic.

- `par` defines the parameter(s) of the statistic.

Several methods for computing descriptive statistics are already implemented in the Mediana package and the user can also define custom functions for computing descriptive statistics (see the dedicated vignette `vignette("custom-functions", package = "Mediana")`). These methods are shown below along with the required parameters that need to be defined in the `par` argument:

- `MedianStat`: compute the median of the sample defined in the `samples` argument.

- `MeanStat`: compute the mean of the sample defined in the `samples` argument.

- `SdStat`: compute the standard deviation of the sample defined in the `samples` argument.

- `MinStat`: compute the minimum value in the sample defined in the `samples` argument.

- `MaxStat`: compute the maximum value in the sample defined in the `samples` argument.

- `DiffMeanStat`: compute the difference of means between the two samples defined in the `samples` argument. Two samples must be defined.

- `EffectSizeContStat`: compute the effect size for a continuous endpoint. Two samples must be defined.

- `RatioEffectSizeContStat`: compute the ratio of two effect sizes for a continuous endpoint. Four samples must be defined.

- `PropStat`: generate the proportion of the sample defined in the `samples` argument.

- `DiffPropStat`: compute the difference of the proportions between the two samples defined in the `samples` argument. Two samples must be defined.

- `EffectSizePropStat`: compute the effect size for a binary endpoint. Two samples must be defined.

- `RatioEffectSizePropStat`: compute the ratio of two effect sizes for a binary endpoint. Four samples must be defined.

- `HazardRatioStat`: compute the hazard ratio of the two samples defined in the samples argument. Two samples must be defined. By default the Log-Rank method is used. Optional argument: `method` taking as value `Log-Rank` or `Cox`.

- `EffectSizeEventStat`: compute the effect size for a survival endpoint (log of the HR. Two samples must be defined. Two samples must be defined. By default the Log-Rank method is used. Optional argument: `method` taking as value `Log-Rank` or `Cox`.

- `RatioEffectSizeEventStat`: compute the ratio of two effect sizes for a survival endpoint based on the Log-Rank method. Four samples must be defined. By default the Log-Rank method is used. Optional argument: `method` taking as value `Log-Rank` or `Cox`.

- `EventCountStat`: compute the number of events observed in the sample(s) defined in the `samples` argument.

- `PatientCountStat`: compute the number of patients observed in the sample(s) defined in the `samples` argument

Several `Statistic` objects can be added to an `AnalysisModel` object.

For more information about the `Statistic` object, see the R documentation Statistic.

#### Example

Examples of `Statistic` objects:

Compute the mean of a single sample:

    # Treatment sample was defined in the data model
    Statistic(id = "Mean Treatment",
              method = "MeanStat",
              samples = samples("Treatment"))

### `MultAdjProc` object

#### Description

This object specifies a multiplicity adjustment procedure that will be applied to the significance tests in order to protect the overall Type I error rate. A `MultAdjProc` object is defined by three arguments:

- `proc` defines a multiplicity adjustment procedure.

- `par` defines the parameter(s) of the multiplicity adjustment procedure (optional).

- `tests` defines the specific tests (defined in the analysis model) to which the multiplicity adjustment procedure will be applied.

If no `tests` are defined, the multiplicity adjustment procedure will be applied to all tests defined in the `AnalysisModel` object.

Several commonly used multiplicity adjustment procedures are included in the Mediana package. In addition, the user can easily define custom multiplicity adjustments. The built-in multiplicity adjustments are defined below along with the required parameters that need to be included in the `par` argument:

- `BonferroniAdj`: Bonferroni procedure. Optional parameter: `weight` (vector of hypothesis weights).

- `HolmAdj`: Holm procedure. Optional parameter: `weight` (vector of hypothesis weights).

- `HochbergAdj`: Hochberg procedure. Optional parameter: `weight` (vector of hypothesis weights).

- `HommelAdj`: Hommel procedure. Optional parameter: `weight` (vector of hypothesis weights).

- `FixedSeqAdj`: Fixed-sequence procedure.

- `ChainAdj`: Family of chain procedures. Required parameters: `weight` (vector of hypothesis weights) and `transition` (matrix of transition parameters).

- `FallbackAdj`: Fallback procedure. Required parameters: `weight` (vector of hypothesis weights).

- `NormalParamAdj`: Parametric multiple testing procedure derived from a multivariate normal distribution. Required parameter: `corr` (correlation matrix of the multivariate normal distribution). Optional parameter: `weight` (vector of hypothesis weights).

- `ParallelGatekeepingAdj`: Family of parallel gatekeeping procedures. Required parameters: `family` (vectors of hypotheses included in each family), `proc` (vector of procedure names applied to each family), `gamma` (vector of truncation parameters).

- `MultipleSequenceGatekeepingAdj`: Family of multiple-sequence gatekeeping procedures. Required parameters: `family` (vectors of hypotheses included in each family), `proc` (vector of procedure names applied to each family), `gamma` (vector of truncation parameters).

- `MixtureGatekeepingAdj`: Family of mixture-based gatekeeping procedures. Required parameters: `family` (vectors of hypotheses included in each family), `proc` (vector of procedure names applied to each family), `gamma` (vector of truncation parameters), `serial` (matrix of indicators), `parallel` (matrix of indicators).

Several `MultAdjProc` objects can be added to an `AnalysisModel`object using the ‘+’ operator or by grouping them into a MultAdj object.

For more information about the `MultAdjProc` object, see the package’s documentation MultAdjProc.

#### Example

Examples of `MultAdjProc` objects:

Apply a multiplicity adjustment based on the chain procedure:

    # Parameters of the chain procedure (equivalent to a fixed-sequence procedure)
    # Vector of hypothesis weights
    chain.weight = c(1, 0)
    # Matrix of transition parameters
    chain.transition = matrix(c(0, 1,
                                0, 0), 2, 2, byrow = TRUE)

    # MultAdjProc
    MultAdjProc(proc = "ChainAdj",
                par = parameters(weight = chain.weight,
                                 transition = chain.transition))

This procedure implementation is facilicated by the use of the `FixedSeqAdj` method intoduced in version 1.0.4.

    # MultAdjProc
    MultAdjProc(proc = "FixedSeqAdj")

Apply a multiple-sequence gatekeeping procedure:

    # Parameters of the multiple-sequence gatekeeping procedure
    # Tests to which the multiplicity adjustment will be applied (defined in the AnalysisModel)
    test.list = tests("Pl vs DoseH - ACR20",
                      "Pl vs DoseL - ACR20",
                      "Pl vs DoseH - HAQ-DI",
                      "Pl vs DoseL - HAQ-DI")

    # Hypothesis included in each family (the number corresponds to the position of the test in the test.list vector)
    family = families(family1 = c(1, 2),
                      family2 = c(3, 4))

    # Component procedure of each family
    component.procedure = families(family1 ="HolmAdj",
                                   family2 = "HolmAdj")

    # Truncation parameter of each family
    gamma = families(family1 = 0.8,
                     family2 = 1)

    # MultAdjProc
    MultAdjProc(proc = "MultipleSequenceGatekeepingAdj",
                par = parameters(family = family,
                                 proc = component.procedure,
                                 gamma = gamma),
                tests = test.list)

### `MultAdjStrategy` object

#### Description

This object specifies a multiplicity adjustment strategy that can include several multiplicity adjustment procedures. A multiplicity adjustment strategy may be defined when the same Clinical Scenario Evaluation approach is applied to several clinical trials.

A `MultAdjStrategy` object serves as a wrapper for several `MultAdjProc` objects.

For more information about the `MultAdjStrategy` object, see the package’s documentation MultAdjStrategy.

#### Example

Example of a `MultAdjStrategy` object:

Perform complex multiplicity adjustments based on gatekeeping procedures in two clinical trials with three endpoints:

    # Parallel gatekeeping procedure parameters
    family = families(family1 = c(1),
                      family2 = c(2, 3))

    component.procedure = families(family1 ="HolmAdj",
                                   family2 = "HolmAdj")

    gamma = families(family1 = 0.8,
                     family2 = 1)

    # Multiple sequence gatekeeping procedure parameters for Trial A
    mult.adj.trialA = MultAdjProc(proc = "ParallelGatekeepingAdj",
                                  par = parameters(family = family,
                                                   proc = component.procedure,
                                                   gamma = gamma),
                                  tests = tests("Trial A Pla vs Trt End1",
                                                "Trial A Pla vs Trt End2",
                                                "Trial A Pla vs Trt End3"))

    mult.adj.trialB = MultAdjProc(proc = "ParallelGatekeepingAdj",
                                  par = parameters(family = family,
                                                   proc = component.procedure,
                                                   gamma = gamma),
                                  tests = tests("Trial B Pla vs Trt End1",
                                                "Trial B Pla vs Trt End2",
                                                "Trial B Pla vs Trt End3"))

    # Analysis model
    analysis.model = AnalysisModel() +
      MultAdjStrategy(mult.adj.trialA, mult.adj.trialB) +
      # Tests for study A
      Test(id = "Trial A Pla vs Trt End1",
           method = "PropTest",
           samples = samples("Trial A Plac End1", "Trial A Trt End1")) +
      Test(id = "Trial A Pla vs Trt End2",
           method = "TTest",
           samples = samples("Trial A Plac End2", "Trial A Trt End2")) +
      Test(id = "Trial A Pla vs Trt End3",
           method = "TTest",
           samples = samples("Trial A Plac End3", "Trial A Trt End3")) +
      # Tests for study B
      Test(id = "Trial B Pla vs Trt End1",
           method = "PropTest",
           samples = samples("Trial B Plac End1", "Trial B Trt End1")) +
      Test(id = "Trial B Pla vs Trt End2",
           method = "TTest",
           samples = samples("Trial B Plac End2", "Trial B Trt End2")) +
      Test(id = "Trial B Pla vs Trt End3",
           method = "TTest",
           samples = samples("Trial B Plac End3", "Trial B Trt End3"))

### `MultAdj` object

#### Description

This object can be used to combine several `MultAdjProc` or `MultAdjStrategy` objects and add them as a single object to an `AnalysisModel` object . This object is provided mainly for convenience and its use is optional. Alternatively, `MultAdjProc` or `MultAdjStrategy` objects can be added to an `AnalysisModel` object incrementally using the ‘+’ operator.

For more information about the `MultAdj` object, see the package’s documentation MultAdj.

#### Example

Example of a `MultAdj` object:

Perform Clinical Scenario Evaluation to compare three candidate multiplicity adjustment procedures:

    # Multiplicity adjustments to compare
    mult.adj1 = MultAdjProc(proc = "BonferroniAdj")
    mult.adj2 = MultAdjProc(proc = "HolmAdj")
    mult.adj3 = MultAdjProc(proc = "HochbergAdj")

    # Analysis model
    analysis.model = AnalysisModel() +
                     MultAdj(mult.adj1, mult.adj2, mult.adj3) +
                     Test(id = "Pl vs Dose L",
                          samples = samples("Placebo", "Dose L"),
                          method = "TTest") +
                     Test(id = "Pl vs Dose M",
                          samples = samples ("Placebo", "Dose M"),
                          method = "TTest") +
                     Test(id = "Pl vs Dose H",
                          samples = samples("Placebo", "Dose H"),
                          method = "TTest")

    # Note that the code presented above is equivalent to:
    analysis.model = AnalysisModel() +
                     mult.adj1 +
                     mult.adj2 +
                     mult.adj3 +
                     Test(id = "Pl vs Dose L",
                          samples = samples("Placebo", "Dose L"),
                          method = "TTest") +
                     Test(id = "Pl vs Dose M",
                          samples = samples ("Placebo", "Dose M"),
                          method = "TTest") +
                     Test(id = "Pl vs Dose H",
                          samples = samples("Placebo", "Dose H"),
                          method = "TTest")

# Evaluation model

Evaluation models are used within the Mediana package to specify the success criteria or metrics for evaluating the performance of the selected clinical scenario (combination of data and analysis models).

## Initialization

An evaluation model can be initialized using the following command:

    # EvaluationModel initialization
    evaluation.model = EvaluationModel()

It is highly recommended to use this command to initialize an evaluation model because it simplifies the process of specifying components of the evaluation model such as `Criterion` objects.

## Components of an evaluation model

After an `EvaluationModel` object has been initialized, components of the evaluation model can be specified by adding objects to the model using the ‘+’ operator as shown below.

    # Evaluation model
    case.study1.evaluation.model = EvaluationModel() +
      Criterion(id = "Marginal power",
                method = "MarginalPower",
                tests = tests("Placebo vs treatment"),
                labels = c("Placebo vs treatment"),
                par = parameters(alpha = 0.025))  +
      Criterion(id = "Average Mean",
                method = "MeanSumm",
                statistics = statistics("Mean Treatment"),
                labels = c("Average Mean Treatment"))

### `Criterion` object

#### Description

This object specifies the success criteria that will be applied to a clinical scenario to evaluate the performance of selected analysis methods. A `Criterion` object is defined by six arguments:

- `id` defines the criterion’s unique ID (label).

- `method` defines the criterion.

- `tests` defines the IDs of the significance tests (defined in the analysis model) that the criterion is applied to.

- `statistics` defines the IDs the descriptive statistics (defined in the analysis model) that the criterion is applied to.

- `par` defines the parameter(s) of the criterion.

- `label` defines the label(s) of the criterion values (the label(s) will be used in the simulation report).

Several commonly used success criteria are implemented in the Mediana package. The user can also define custom significance criteria. The built-in success criteria are listed below along with the required parameters that need to be included in the `par` argument:

- `MarginalPower`: compute the marginal power of all tests included in the `test` argument. Required parameter: `alpha` (significance level used in each test).

- `WeightedPower`: compute the weighted power of all tests included in the `test` argument. Required parameters: `alpha` (significance level used in each test) and `weight` (vector of weights assigned to the significance tests).

- `DisjunctivePower`: compute the disjunctive power (probability of achieving statistical significance in at least one test included in the `test` argument). Required parameter: `alpha` (significance level used in each test).

- `ConjunctivePower`: compute the conjunctive power (probability of achieving statistical significance in all tests included in the `test` argument). Required parameter: `alpha` (significance level used in each test).

- `ExpectedRejPower`: compute the expected number of statistical significant tests. Required parameter: `alpha`(significance level used in each test).

Several `Criterion` objects can be added to an `EvaluationModel` object.

For more information about the `Criterion` object, see the package’s documentation Criterion.

If a certain success criterion is not implemented in the Mediana package, the user can create a custom function and use it within the package (see the dedicated vignette `vignette("custom-functions", package = "Mediana")`).

#### Examples

Examples of `Criterion` objects:

Compute marginal power with alpha = 0.025:

    Criterion(id = "Marginal power",
              method = "MarginalPower",
              tests = tests("Placebo vs treatment"),
              labels = c("Placebo vs treatment"),
              par = parameters(alpha = 0.025))

Compute weighted power with alpha = 0.025 and unequal test-specific weights:

    Criterion(id = "Weighted power",
              method = "WeightedPower",
              tests = tests("Placebo vs treatment - Endpoint 1",
                            "Placebo vs treatment - Endpoint 2"),
              labels = c("Weighted power"),
              par = parameters(alpha = 0.025,
                               weight = c(2/3, 1/3)))

Compute disjunctive power with alpha = 0.025:

    Criterion(id = "Disjunctive power",
              method = "DisjunctivePower",
              tests = tests("Placebo vs Dose H",
                            "Placebo vs Dose M",
                            "Placebo vs Dose L"),
              labels = c("Disjunctive power"),
              par = parameters(alpha = 0.025))

# Clinical Scenario Evaluation

Clinical Scenario Evaluation (CSE) is performed based on the data, analysis and evaluation models as well as simulation parameters specified by the user. The simulation parameters are defined using the `SimParameters` object.

## Clinical Scenario Evaluation objects

### `SimParameters` object

#### Description

The `SimParameters` object is a required argument of the `CSE` function and has the following arguments:

- `n.sims` defines the number of simulations.
- `seed` defines the seed to be used in the simulations.
- `proc.load` defines the processor load in parallel computations.

The `proc.load` argument is used to define the number of processor cores dedicated to the simulations. A numeric value can be defined as well as character value which automatically detects the number of cores:

- `low`: 1 processor core.

- `med`: Number of available processor cores / 2.

- `high`: Number of available processor cores 1.

- `full`: All available processor cores.

#### Examples

Examples of `SimParameters` object specification:

Perform 10000 simulations using all available processor cores:

    SimParameters(n.sims = 10000,
                  proc.load = "full",
                  seed = 42938001)

Perform 10000 simulations using 2 processor cores:

    SimParameters(n.sims = 10000,
                  proc.load = 2,
                  seed = 42938001)

### `CSE` function

#### Description

The `CSE` function is invoked to runs simulations under the Clinical Scenario Evaluation approach. This function uses four arguments:

- `data` defines a `DataModel` object.

- `analysis` defines an `AnalysisModel` object.

- `evaluation` defines an `EvaluationModel` object.

- `simulation` defines a `SimParameters` object.

#### Examples

The following example illustrates the use of the `CSE` function:

    # Outcome parameter set 1
    outcome1.placebo = parameters(mean = 0, sd = 70)
    outcome1.treatment = parameters(mean = 40, sd = 70)

    # Outcome parameter set 2
    outcome2.placebo = parameters(mean = 0, sd = 70)
    outcome2.treatment = parameters(mean = 50, sd = 70)

    # Data model
    case.study1.data.model = DataModel() +
      OutcomeDist(outcome.dist = "NormalDist") +
      SampleSize(c(50, 55, 60, 65, 70)) +
      Sample(id = "Placebo",
             outcome.par = parameters(outcome1.placebo, outcome2.placebo)) +
      Sample(id = "Treatment",
             outcome.par = parameters(outcome1.treatment, outcome2.treatment))

    # Analysis model
    case.study1.analysis.model = AnalysisModel() +
      Test(id = "Placebo vs treatment",
           samples = samples("Placebo", "Treatment"),
           method = "TTest")

    # Evaluation model
    case.study1.evaluation.model = EvaluationModel() +
      Criterion(id = "Marginal power",
                method = "MarginalPower",
                tests = tests("Placebo vs treatment"),
                labels = c("Placebo vs treatment"),
                par = parameters(alpha = 0.025))

    # Simulation Parameters
    case.study1.sim.parameters = SimParameters(n.sims = 1000, proc.load = 2, seed = 42938001)

    # Perform clinical scenario evaluation
    case.study1.results = CSE(case.study1.data.model,
                              case.study1.analysis.model,
                              case.study1.evaluation.model,
                              case.study1.sim.parameters)

### Summary of results

Once Clinical Scenario Evaluation-based simulations have been run, the `CSE` object returned by the `CSE` function contains a list with the following components:

- `simulation.results`: a data frame containing the results of the simulations for each scenario.

- `analysis.scenario.grid`: a data frame containing the grid of the combination of data and analysis scenarios.

- `data.structure`: a list containing the data structure according to the `DataModel` object.

- `analysis.structure`: a list containing the analysis structure according to the `AnalysisModel` object.

- `evaluation.structure`: a list containing the evaluation structure according to the `EvaluationModel` object.

- `sim.parameters`: a list containing the simulation parameters according to `SimParameters` object.

- `timestamp`: a list containing information about the start time, end time and duration of the simulation runs.

The simulation results can be summarized in the R console using the `summary` function:

    summary(case.study1.results)

A Microsoft Word-based simulation report can be generated from the simulation results produced by the `CSE` function using the `GenerateReport` function, see Simulation report.

# Simulation report

The Mediana R package uses the officer R package package to generate a Microsoft Word-based report that summarizes the results of Clinical Scenario Evaluation-based simulations.

The user can easily customize this simulation report by adding a description of the project as well as labels to each scenario, including data scenarios (sample size, outcome distribution parameters, design parameters) and analysis scenarios (multiplicity adjustment). The user can also customize the report’s structure, e.g., create sections and subsections within the report and specify how the rows will be sorted within each table.

In order to customize the report, the user has to use a `PresentationModel` object described below.

Once a `PresentationModel` object has been defined, the `GenerateReport` function can be called to generate a Clinical Scenario Evaluation report.

## Initialization

A presentation model can be initialized using the following command

    # PresentationModel initialization
    presentation.model = PresentationModel()

Initialization with this command is highly recommended as it will simplify the process of adding related objects, e.g., the `Project`, `Section`, `Subsection`, `Table`, `CustomLabel` objects.

## Specific objects

Once the `PresentationModel` object has been initialized, specific objects can be added by simply using the ‘+’ operator as in data, analysis and evaluation models.

### `Project` object

#### Description

This object specifies a description of the project. The `Project` object is defined by three optional arguments:

- `username` defines the username to be included in the report (by default, the username is “[Unknown User]”).

- `title` defines the project’s in the report (the default value is “[Unknown title]”).

- `description` defines the project’s description (the default value is “[No description]”).

This information will be added in the report generated using the `GenerateReport` function.

A single object of the `Project` class can be added to an object of the `PresentationModel` class.

#### Examples

A simple `Project` object can be created as follows:

    Project(username = "Gautier Paux",
            title = "Case study 1",
            description = "Clinical trial in patients with pulmonary arterial hypertension")

### `Section` object

#### Description

This object specifies the sections that will be created within the simulation report. A `Section` object is defined by a single argument:

- `by` defines the rules for setting up sections.

The `by` argument can contain several parameters from the following list:

- `sample.size`: a separate section will be created for each sample size.

- `event`: a separate section will be created for each event count.

- `outcome.parameter`: a separate section will be created for each outcome parameter scenario.

- `design.parameter`: a separate section will be created for each design parameter scenario.

- `multiplicity.adjustment`: a separate section will be created for each multiplicity adjustment scenario.

Note that, if a parameter is defined in the `by` argument, it must be defined only in this object (i.e., neither in the `Subection` object nor in the `Table` object).

A single object of the `Section` class can be added to an object of the `PresentationModel` class.

#### Examples

A `Section` object can be defined as follows:

Create a separate section within the report for each outcome parameter scenario:

    Section(by = "outcome.parameter")

Create a separate section for each unique combination of the sample size and outcome parameter scenarios:

    Section(by = c("sample.size", "outcome.parameter"))

### `Subsection` object

#### Description

This object specifies the rules for creating subsections within the simulation report. A `Subsection` object is defined by a single argument:

- `by` defines the rules for creating subsections.

The `by` argument can contain several parameters from the following list:

- `sample.size`: a separate subsection will be created for each sample size.

- `event`: a separate subsection will be created for each number of events.

- `outcome.parameter`: a separate subsection will be created for each outcome parameter scenario.

- `design.parameter`: a separate subsection will be created for each design parameter scenario.

- `multiplicity.adjustment`: a separate subsection will be created for each multiplicity adjustment scenario.

As before, if a parameter is defined in the `by` argument, it must be defined only in this object (i.e., neither in the `Section` object nor in the `Table` object).

A single object of the `Subsection` class can be added to an object of the `PresentationModel` class. #### Examples

`Subsection` objects can be set up as follows:

Create a separate subsection for each sample size scenario:

    Subsection(by = "sample.size")

Create a separate subsection for each unique combination of the sample size and outcome parameter scenarios:

    Subsection(by = c("sample.size", "outcome.parameter"))

### `Table` object

#### Description

This object specifies how the summary tables will be sorted within the report. A `Table` object is defined by a single argument:

- `by` defines how the tables of the report will be sorted.

The `by` argument can contain several parameters, the value must be contain in the following list:

- `sample.size`: the tables will be sorted by the sample size.

- `event`: the tables will be sorted by the number of events.

- `outcome.parameter`: the tables will be sorted by the outcome parameter scenario.

- `design.parameter`: the tables will be sorted by the design parameter scenario.

- `multiplicity.adjustment`: the tables will be sorted by the multiplicity adjustment scenario.

If a parameter is defined in the `by` argument it must be defined only in this object (i.e., neither in the `Section` object nor in the `Subsection` object).

A single object of class `Table` can be added to an object of class `PresentationModel`.

#### Examples

Examples of `Table` objects:

Create a summary table sorted by sample size scenarios:

    Table(by = "sample.size")

Create a summary table sorted by sample size and outcome parameter scenarios:

    Table(by = c("sample.size", "outcome.parameter"))

### `CustomLabel` object

#### Description

This object specifies the labels that will be assigned to sets of parameter values or simulation scenarios. These labels will be used in the section and subsection titles of the Clinical Scenario Evaluation Report as well as in the summary tables. A `CustomLabel` object is defined by two arguments:

- `param` defines a parameter (scenario) to which the current set of labels will be assigned.

- `label` defines the label(s) to assign to each value of the parameter.

The `param` argument can contain several parameters from the following list:

- `sample.size`: labels will be applied to sample size values.

- `event`: labels will be applied to number of events values.

- `outcome.parameter`: labels will be applied to outcome parameter scenarios.

- `design.parameter`: labels will be applied to design parameter scenarios.

- `multiplicity.adjustment`: labels will be applied to multiplicity adjustment scenarios.

Several objects of the `CustomLabel` class can be added to an object of the `PresentationModel` class.

#### Examples

Examples of `CustomLabel` objects:

Assign a custom label to the sample size values:

    CustomLabel(param = "sample.size",
                label= paste0("N = ",c(50, 55, 60, 65, 70)))

Assign a custom label to the outcome parameter scenarios:

    CustomLabel(param = "outcome.parameter",
                label=c("Pessimistic", "Expected", "Optimistic"))

## `GenerateReport` function

### Description

The Clinical Scenario Evaluation Report is generated using the `GenerateReport` function. This function has four arguments:

- `presentation.model` defines a `PresentationModel` object.

- `cse.result` defines a `CSE` object returned by the CSE function.

- `report.filename` defines the filename of the Word-based report generated by this function.

- `report.template` defines a Word-based template (it is an optional argument).

The `GenerateReport` function requires the officer R package package to generate a Word-based simulation report. Optionally, a custom template can be selected by defining `report.template`, this argument specifies the name of a Word document located in the working directory.

The Word-based simulation report is structured as follows:

1. GENERAL INFORMATION
   1. PROJECT INFORMATION
   2. SIMULATION PARAMETERS
2. DATA MODEL
   1. DESIGN (if a `Design` object has been defined)
   2. SAMPLE SIZE (or EVENT if an `Event` object has been defined)
   3. OUTCOME DISTRIBUTION
   4. DESIGN
3. ANALYSIS MODEL
   1. TESTS
   2. MULTIPLICITY ADJUSTMENT
4. EVALUATION MODEL
   1. CRITERIA
5. RESULTS
   1. SECTION (if a `Section` object has been defined)
      1. SUBSECTION (if a `Subsection` object has been defined)
      2. …
   2. …

### Examples

This example illustrates the use of the `GenerateReport` function:

    # Define a presentation model
    case.study1.presentation.model = PresentationModel() +
      Section(by = "outcome.parameter") +
      Table(by = "sample.size") +
      CustomLabel(param = "sample.size",
                  label= paste0("N = ",c(50, 55, 60, 65, 70))) +
      CustomLabel(param = "outcome.parameter",
                  label=c("Standard 1", "Standard 2"))

    # Report Generation
    GenerateReport(presentation.model = case.study1.presentation.model,
                   cse.results = case.study1.results,
                   report.filename = "Case study 1 (normally distributed endpoint).docx")