Simulation
Maturity: stable — see Feature Maturity for what this means.
The optional [simulation] block defines a virtual clinical trial design for generating simulated data. This is useful for model validation and testing.
Syntax
[simulation]
n_subjects = N
dose_amt = AMOUNT
dose_cmt = COMPARTMENT
seed = SEED
times = [t1, t2, t3, ...]
horizon = T # TTE only — administrative censoring time
| Key | Aliases | Description |
|---|---|---|
n_subjects |
subjects |
Number of virtual subjects to simulate |
dose_amt |
dose |
Dose amount administered to each subject |
dose_cmt |
cmt |
Dosing compartment (1-indexed) |
seed |
Random seed for reproducible simulations | |
times |
Continuous observation time points (Gaussian endpoints) | |
horizon |
Administrative censoring time for TTE endpoints (finite, > 0) |
A block must define at least one of times or horizon, matched to the model’s endpoints:
- a model with a continuous (residual-error) endpoint requires
times; - a model with a time-to-event endpoint requires
horizon(see TTE simulation below); - a joint PK + TTE model requires both.
Supplying only horizon for a model that has a continuous endpoint is an error (it would otherwise simulate zero continuous observations), as is supplying only times for a TTE model.
An unknown or malformed key in [simulation] is a parse error (not silently ignored), so a typo such as n_subject, or a line missing its = such as n_subjects 6, is reported rather than falling back to the default. A horizon that is not finite and strictly positive is likewise rejected.
Example
[simulation]
n_subjects = 100
dose_amt = 100
dose_cmt = 1
seed = 12345
times = [0.5, 1, 2, 4, 8, 12, 24]
This simulates 100 subjects, each receiving a dose of 100 units into compartment 1, with observations at 0.5, 1, 2, 4, 8, 12, and 24 hours.
Usage
Run a simulation-estimation study from the CLI:
ferx model.ferx --simulateThis will: 1. Parse the model and [simulation] block 2. Generate simulated data using the model’s default parameters and random effects 3. Fit the model to the simulated data 4. Report parameter estimates and diagnostics
Simulation Process
- For each subject, random effects are sampled from \(\eta_i \sim N(0, \Omega)\)
- Individual parameters are computed using the
[individual_parameters]equations - Predictions are generated using the structural model
- Residual error is added: \(DV = IPRED + \epsilon\), where \(\epsilon \sim N(0, V)\)
- Observations below 0.001 are clipped to 0.001
TTE simulation
For a time-to-event model there are no continuous observations to schedule; instead each synthetic subject is followed until an event occurs or until the administrative horizon, at which point an event-free subject is right-censored. --simulate therefore generates, for each subject, one right-censored TTE row per event (cause) compartment, then draws the outcome:
- a single
[event_model]yields one row per subject — an event before the horizon, or right-censoring at the horizon; - competing risks (several
[event_model]blocks on distinct compartments) yield one row per cause: the earliest latent event is observed and the remaining causes are right-censored at that same time, or — if no cause fires before the horizon — every cause is right-censored at the horizon.
[simulation]
n_subjects = 200
horizon = 14 # follow each subject to t = 14, censoring survivors there
seed = 12345
Because a TTE design has no continuous times, the horizon key is required when the model has a TTE endpoint; omitting it is a parse error. See examples/tte_competing_risks.ferx.
Decoupled horizon and VPC
The horizon is an administrative censoring time decoupled from the observed event times. This matters when re-simulating an existing event-bearing dataset for a visual predictive check (VPC): without an explicit horizon a record that already carries an event imposes no censoring window (it would re-draw unbounded), which biases the simulated event-time distribution. Supplying horizon overrides each record’s per-record window so every simulated cause censors at the planned study end. The same control is available on the library API as SimulateOptions { horizon, .. }.
Covariates in Simulation
Covariates can be specified per subject in the [simulation] block. Currently, the simulated population uses default covariate values (covariates are not randomized).