--- title: "Extending mixpower with custom backends" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Extending mixpower with custom backends} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") ``` This vignette describes the **backend contract** used by `mp_power()` so you can plug in custom simulators, fitters, and tests without modifying the core loop. ## The three-function contract An `mp_scenario` stores an `engine` with: 1. **`simulate_fun(scenario, seed = NULL)`** — returns a `data.frame` of simulated data. `mp_power()` passes `seed` when the function accepts it (see `?mp_power`). 2. **`fit_fun(data, scenario)`** — returns a fitted model object. 3. **`test_fun(fit, scenario)`** — returns `list(p_value = )`. Use `NA_real_` for `p_value` when the test cannot be computed. `mp_power()` records `fit_ok`, optional `singular` from `attr(fit, "singular")`, and aggregates power using `alpha` and `failure_policy`. ## Building a validated backend with `mp_backend()` Use `mp_backend()` to wrap the three functions with a name and optional metadata. `validate_mp_backend()` checks formal argument names before you run simulations: ```{r backend-toy} library(mixpower) sim_fun <- function(scenario, seed = NULL) { n <- scenario$design$clusters$subject x <- stats::rbinom(n, 1, 0.5) y <- scenario$assumptions$fixed_effects$condition * x + stats::rnorm(n, sd = scenario$assumptions$residual_sd) data.frame(y = y, condition = x) } fit_fun <- function(data, scenario) stats::lm(scenario$formula, data = data) test_fun <- function(fit, scenario) { sm <- summary(fit) p <- sm$coefficients["condition", "Pr(>|t|)"] list(p_value = as.numeric(p)) } eng <- mp_backend(sim_fun, fit_fun, test_fun, name = "toy_lm") eng ``` ## Using `mp_scenario()` and `mp_power()` ```{r run} d <- mp_design(list(subject = 25), trials_per_cell = 1) a <- mp_assumptions(list(`(Intercept)` = 0, condition = 0.2), residual_sd = 1) scn <- mp_scenario( y ~ condition, d, a, test = "custom", simulate_fun = eng$simulate_fun, fit_fun = eng$fit_fun, test_fun = eng$test_fun ) mp_power(scn, nsim = 12, seed = 1) ``` ## Built-in backends - **lme4**: `mp_backend_lme4()`, `mp_backend_lme4_binomial()`, etc., return `mp_backend` objects. Scenario helpers (`mp_scenario_lme4()`, …) copy the three functions into the scenario. - **glmmTMB** (optional): `mp_backend_glmmtmb()` when package `glmmTMB` is installed — see `?mp_backend_glmmtmb`. ## Parallel grids Sensitivity and power-curve grids can be evaluated in parallel **outside** `mp_power()` (e.g. `mp_sensitivity_parallel()`, `mp_power_curve_parallel()`) using per-cell seeds `seed + cell_index - 1L` for reproducibility. ## Further reading - `?mp_backend`, `?validate_mp_backend`, `?mp_scenario`, `?mp_power` - Vignette `mixpower-intro` for Wald vs LRT and design-first workflows.