--- title: "Designing and running a randomized trial with PhysioTrial" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Designing and running a randomized trial with PhysioTrial} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` PhysioTrial provides reproducible trial-design infrastructure: randomization with allocation concealment, CONSORT/SPIRIT operations, explicit analysis populations, power and sample-size helpers, and deterministic CDISC-shaped exports. This vignette walks one small trial end to end on synthetic data. These exports are auditable and structurally checked; they are **not** a claim of formal CDISC, third-party validator, or regulatory acceptance. ```{r setup} library(PhysioTrial) ``` ## 1. Define the trial ```{r trial} trial <- Trial( "rehab-01", arms = c("active", "control"), strata = list(site = c("north", "south")) ) arms(trial) ``` ## 2. Plan the sample size ```{r power} # Two-arm comparison of a continuous endpoint (e.g. change in gait speed). sampleSizeContinuous(delta = 0.12, sd = 0.20, power = 0.8) ``` ## 3. Randomize with allocation concealment Stratified permuted-block randomization is reproducible from a seed. Future treatment assignments stay masked in the sealed sequence. ```{r randomize} participants <- data.frame( id = sprintf("P%03d", 1:8), site = rep(c("north", "south"), each = 4) ) sequence <- randomize( trial, method = "stratified_block", participants = participants, seed = 2026 ) assignments(sequence) ``` Allocations are revealed one at a time, through an auditable request: ```{r allocate} allocation <- nextAllocation(sequence, requester = "site") allocation$arm sequence <- allocation$sequence ``` ## 4. CONSORT flow CONSORT counts and the flow diagram are inspectable without a rendering dependency (`render = FALSE`). ```{r consort} flow <- data.frame( participant_id = c("P001", "P002"), eligible = c(TRUE, FALSE), randomized = c(TRUE, FALSE), arm = c("active", NA), received_allocated = c(TRUE, NA), followup_complete = c(TRUE, NA), analysed = c(TRUE, NA), pre_exclusion_reason = c(NA, "ineligible"), not_received_reason = NA_character_, followup_reason = NA_character_, analysis_exclusion_reason = NA_character_ ) diagram <- consortDiagram(trial, flow, render = FALSE) consortCounts(diagram) ``` ## 5. Analysis populations Intention-to-treat and per-protocol membership consume explicit finalized assignments. ```{r populations} participant_state <- data.frame( id = c("P001", "P002", "screen-01"), arm = c("active", "control", NA), randomized = c(TRUE, TRUE, FALSE), adherent = c(TRUE, FALSE, NA) ) itt <- intentionToTreat(trial, participant_state) pp <- perProtocol(trial, participant_state, adherent_col = "adherent") analysisExclusions(pp) ``` ## 6. CDISC-shaped export Exports keep the source-to-`USUBJID` map explicit and are structurally validated. ```{r cdisc} sdtm <- toSDTM(trial, participant_state) validateCDISC(sdtm) sdtm$metadata$id_map ``` ## Where to go next `?PhysioTrial` lists every entry point: blinding and unblinding audits (`blindingManager()`, `unblind()`), SPIRIT schedules (`spiritSchedule()`), adverse-event summaries (`aeSummary()`), endpoint wrappers (`endpointANCOVA()`, `endpointMMRM()`), and the ADaM export (`toADaM()`).