Rilpivirine (Aouri 2017)
Source:vignettes/articles/Aouri_2017_rilpivirine.Rmd
Aouri_2017_rilpivirine.RmdModel and source
- Citation: Aouri M, Barcelo C, Guidi M, Rotger M, Cavassini M, Hizrel C, Buclin T, Decosterd LA, Csajka C, the Swiss HIV Cohort Study. (2017). Population pharmacokinetics and pharmacogenetics analysis of rilpivirine in HIV-1-infected individuals. Antimicrob Agents Chemother 61(1):e00899-16. doi:10.1128/AAC.00899-16
- Description: One-compartment population PK model for oral rilpivirine in HIV-1-infected adults (Aouri 2017), with zero-order absorption from the gastrointestinal tract directly into the central compartment (duration D1 = 4 h; derived mean absorption time D1/2 = 2 h), apparent clearance CL/F = 11.7 L/h, apparent volume of distribution V/F = 401 L, combined proportional plus additive residual error (21.6% and 9.8 ng/mL), and inter-individual variability on CL/F only (33% CV). No demographic, clinical, or genetic covariates (sex, body weight, height, age, race, AST, ALT, HCV, HBV, comedications, CYP3A422, CYP3A53, CYP2C192, CYP2C1917, UGT1A128, UGT1A42) were retained in the final covariate model.
- Article: https://doi.org/10.1128/AAC.00899-16
Aouri 2017 reports the population pharmacokinetics and pharmacogenetics of rilpivirine (RPV), an HIV-1 non-nucleoside reverse transcriptase inhibitor (NNRTI), in a cohort of HIV-1-infected adults receiving routine therapeutic drug monitoring in Switzerland. The structural model is a one-compartment open model with zero-order absorption directly into the central compartment. No demographic, clinical, or pharmacogenetic covariate (sex, body weight, height, age, race, AST, ALT, HCV/HBV coinfection, CYP3A422, CYP3A53, CYP2C192, CYP2C1917, UGT1A128, UGT1A42) survived the covariate screen.
Population
The model was developed from 325 plasma rilpivirine concentration measurements from 249 HIV-1-infected adult patients (Aouri 2017 Table 1). All subjects received the standard once-daily 25 mg rilpivirine fixed-dose combination with emtricitabine and tenofovir disoproxil fumarate (the single-tablet regimen). Demographics: median age 46 years (range 22-80), median weight 74 kg (42-112), median height 175 cm (150-198), 72.7% male, 51.4% Caucasian / 11.6% African / 0.4% Asian / 1.2% Other / 35.3% Unknown ethnicity. 87% had previously received antiretroviral treatment; 13% were antiretroviral-naive at study entry. Samples were drawn 1.25-36 h after the last dose under steady-state conditions (at least 4 weeks after rilpivirine regimen initiation). The LC-MS/MS assay had a lower limit of quantification of 5 ng/mL; observed plasma concentrations spanned 12-255 ng/mL.
A subset of 119 patients enrolled in the Swiss HIV Cohort Study contributed DNA for genotyping of CYP3A4, CYP3A5, CYP2C19, UGT1A1, and UGT1A4 polymorphisms (Aouri 2017 Genotyping section). 130 of 249 patients had unknown genotype status.
The same information is available programmatically via
readModelDb("Aouri_2017_rilpivirine")$population.
Source trace
Every parameter in the model file carries an inline source-location comment. The table below collects them in one place.
| Equation / parameter | Value | Source location |
|---|---|---|
lcl (CL/F) |
log(11.7 L/h) | Aouri 2017 Table 2 (RSE 2.8%) |
lvc (V/F) |
log(401 L) | Aouri 2017 Table 2 (RSE 14.1%) |
ld1 (D1) |
log(4 h) | Aouri 2017 Table 2 (RSE 24.7%); mean absorption time = D1/2 = 2 h, Aouri 2017 Results, “Population pharmacokinetic analysis” |
| IIV CL/F | 33% CV (variance = log(0.33^2 + 1) = 0.10337) | Aouri 2017 Table 2 (RSE ~6%) |
| IIV V/F, D1 | not retained (dOFV = -0.0) | Aouri 2017 Results, “Population pharmacokinetic analysis” |
addSd (additive RV) |
9.8 ng/mL | Aouri 2017 Table 2 (RSE 13.6%) |
propSd (proportional RV) |
0.216 | Aouri 2017 Table 2 (RSE 7%) |
| 1-compartment + zero-order absorption | n/a | Aouri 2017 Results, “Population pharmacokinetic analysis” |
dur(central) <- d1 (zero-order input directly to
central) |
n/a | One-compartment open model with zero-order absorption from the GI tract (NONMEM ADVAN1-style); paper does not introduce a separate depot state |
Cc <- central / vc * 1000 (mg/L -> ng/mL) |
n/a | Aouri 2017 reports concentrations in ng/mL; dose in mg and V/F in L gives mg/L, multiplied by 1000 to ng/mL |
Virtual cohort
The original observed concentrations are not publicly available. The
virtual cohort below is a simple population draw from the model’s IIV
distribution; no demographic covariates entered the final model, so no
covariate sampling is required. The vignette evaluates the three
simulated regimens reported in Aouri 2017 (“Simulation” subsection and
Figure 2): 25 mg QD (standard), 50 mg QD, and 25 mg BID. Each regimen is
simulated for n_per_regimen virtual subjects.
set.seed(20260602)
n_per_regimen <- 500L
regimens <- tibble::tribble(
~regimen, ~amt, ~ii,
"25 mg QD", 25, 24,
"50 mg QD", 50, 24,
"25 mg BID", 25, 12
)
make_regimen_events <- function(regimen_label, amt, ii, n, id_offset) {
n_doses_total <- ceiling(28 * 24 / ii)
obs_times <- sort(unique(c(
seq(0, 24, by = 0.5),
seq(24, 28 * 24, by = 1),
seq(28 * 24 - 24, 28 * 24, by = 0.25)
)))
ids <- id_offset + seq_len(n)
# rate = -2 tells rxode2 to use the modeled absorption duration
# (`dur(central) <- d1` in the model) for each dose record. Without
# this flag the dose enters central as an instantaneous bolus,
# bypassing the zero-order absorption window.
dose_rows <- tidyr::expand_grid(id = ids, dose_idx = seq_len(n_doses_total)) |>
dplyr::mutate(
time = (dose_idx - 1) * ii,
amt = amt,
rate = -2,
evid = 1L,
cmt = "central",
regimen = regimen_label
) |>
dplyr::select(id, time, amt, rate, evid, cmt, regimen)
obs_rows <- tidyr::expand_grid(id = ids, time = obs_times) |>
dplyr::mutate(
amt = NA_real_,
rate = NA_real_,
evid = 0L,
cmt = NA_character_,
regimen = regimen_label
)
dplyr::bind_rows(dose_rows, obs_rows) |>
dplyr::arrange(id, time, dplyr::desc(evid))
}
events <- dplyr::bind_rows(
make_regimen_events("25 mg QD", 25, 24, n_per_regimen, id_offset = 0L),
make_regimen_events("50 mg QD", 50, 24, n_per_regimen, id_offset = n_per_regimen),
make_regimen_events("25 mg BID", 25, 12, n_per_regimen, id_offset = 2L * n_per_regimen)
)
stopifnot(!anyDuplicated(unique(events[, c("id", "time", "evid")])))Simulation
mod <- rxode2::rxode2(readModelDb("Aouri_2017_rilpivirine"))
#> ℹ parameter labels from comments will be replaced by 'label()'
sim <- rxode2::rxSolve(mod, events = events, keep = "regimen") |>
as.data.frame()
mod_typical <- mod |> rxode2::zeroRe()
sim_typical <- rxode2::rxSolve(mod_typical, events = events, keep = "regimen") |>
as.data.frame()
#> ℹ omega/sigma items treated as zero: 'etalcl'
#> Warning: multi-subject simulation without without 'omega'Replicate published figures
Figure 2 – model-based simulations of three rilpivirine regimens
Aouri 2017 Figure 2 shows the population median prediction (solid line), the 95% prediction interval (shaded band), and the 50 ng/mL therapeutic target (dashed) for the three simulated regimens. The figure below reproduces this layout from the virtual cohort.
plot_window <- sim |>
dplyr::filter(time >= 28 * 24 - 24, time <= 28 * 24)
plot_window <- plot_window |>
dplyr::mutate(t_in_interval = time - (28 * 24 - 24)) |>
dplyr::group_by(regimen, t_in_interval) |>
dplyr::summarise(
Q025 = stats::quantile(Cc, 0.025, na.rm = TRUE),
Q50 = stats::quantile(Cc, 0.50, na.rm = TRUE),
Q975 = stats::quantile(Cc, 0.975, na.rm = TRUE),
.groups = "drop"
)
ggplot(plot_window, aes(t_in_interval, Q50)) +
geom_ribbon(aes(ymin = Q025, ymax = Q975), alpha = 0.25) +
geom_line(linewidth = 0.8) +
geom_hline(yintercept = 50, linetype = "dashed", colour = "red") +
facet_wrap(~regimen) +
labs(
x = "Time within the final dosing interval at steady state (h)",
y = "Rilpivirine concentration (ng/mL)",
title = "Figure 2 (replicated) -- median and 95% PI by regimen"
)
Simulated concentration-time profiles for 25 mg QD, 50 mg QD, and 25 mg BID rilpivirine regimens. Median (solid line) and 95% prediction interval (shaded band) across the virtual cohort. Dashed horizontal line: proposed 50 ng/mL therapeutic target. Reproduces the format of Aouri 2017 Figure 2.
Typical-subject profile (25 mg QD over 7 days)
sim_typical |>
dplyr::filter(regimen == "25 mg QD", id == 1, time <= 7 * 24) |>
ggplot(aes(time, Cc)) +
geom_line(linewidth = 0.8) +
geom_hline(yintercept = 50, linetype = "dashed", colour = "red") +
labs(
x = "Time (h)",
y = "Rilpivirine concentration (ng/mL)",
title = "Typical-subject profile -- 25 mg QD oral, 7 days"
)
Simulated typical-subject (no IIV) rilpivirine concentration profile over the first 7 days of 25 mg QD dosing. The zero-order absorption duration D1 = 4 h gives a mean absorption time of 2 h. Half-life is 24 h, so steady state is approached after about 5 half-lives (~5 days).
PKNCA validation
Aouri 2017 reports population Cmin (the 24 h trough concentration at
steady state) and the proportion of subjects below the 50 ng/mL target
for each of the three simulated regimens. The PKNCA NCA below computes
steady-state Cmin (ctau), Cmax, and AUC0-tau over the final
dosing interval for every virtual subject; the per-regimen summary is
then compared against the published values.
ss_start <- 28 * 24 - 24
ss_end <- 28 * 24
nca_data <- sim |>
dplyr::filter(!is.na(Cc), time >= ss_start - 24, time <= ss_end) |>
dplyr::select(id, time, Cc, regimen)
dose_df <- events |>
dplyr::filter(evid == 1, time >= ss_start - 48, time <= ss_end) |>
dplyr::select(id, time, amt, regimen)
conc_obj <- PKNCA::PKNCAconc(
nca_data,
Cc ~ time | regimen + id,
concu = "ng/mL", timeu = "h"
)
dose_obj <- PKNCA::PKNCAdose(
dose_df,
amt ~ time | regimen + id,
doseu = "mg"
)
# Steady-state interval over the final dosing window. A single 24 h
# interval captures the Cmin (the minimum concentration in the window)
# for both the QD regimens (one trough at 24 h) and the BID regimen
# (the lower of two troughs at 12 h and 24 h; at steady state the two
# troughs coincide, so the 24 h window is equivalent to the BID
# interval and reproduces the paper's BID Cmin reference point).
intervals <- data.frame(
start = ss_start,
end = ss_end,
cmax = TRUE,
cmin = TRUE,
tmax = TRUE,
ctrough = TRUE,
auclast = TRUE
)
nca_pkg <- PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals)
nca_res <- suppressMessages(suppressWarnings(PKNCA::pk.nca(nca_pkg)))
nca_summary <- summary(nca_res)
knitr::kable(
nca_summary,
caption = "Simulated steady-state NCA per regimen (final dosing interval)."
)| Interval Start | Interval End | regimen | N | AUClast (h*ng/mL) | Cmax (ng/mL) | Cmin (ng/mL) | Tmax (h) | Ctrough (ng/mL) |
|---|---|---|---|---|---|---|---|---|
| 648 | 672 | 25 mg BID | 500 | 4290 [34.1] | 201 [30.1] | 157 [39.1] | 16.0 [16.0, 16.0] | NC |
| 648 | 672 | 25 mg QD | 500 | 2130 [31.9] | 118 [23.5] | 63.9 [44.1] | 4.00 [4.00, 4.00] | NC |
| 648 | 672 | 50 mg QD | 500 | 4340 [31.2] | 239 [23.0] | 131 [43.1] | 4.00 [4.00, 4.00] | NC |
Comparison against the published values
res_tbl <- as.data.frame(nca_res$result)
cmin_sim <- res_tbl |>
dplyr::filter(PPTESTCD == "cmin") |>
dplyr::group_by(regimen) |>
dplyr::summarise(
Cmin_median = stats::median(PPORRES, na.rm = TRUE),
Cmin_PI_low = stats::quantile(PPORRES, 0.025, na.rm = TRUE),
Cmin_PI_high = stats::quantile(PPORRES, 0.975, na.rm = TRUE),
pct_below_50 = 100 * mean(PPORRES < 50, na.rm = TRUE),
.groups = "drop"
)
published <- tibble::tibble(
regimen = c("25 mg QD", "50 mg QD", "25 mg BID"),
pub_Cmin_median = c(69, 140, 167),
pub_Cmin_PI_low = c(33.5, 39, 59),
pub_Cmin_PI_high = c(125.6, 446, 406),
pub_pct_below_50 = c(29, 2.4, 0)
)
comparison <- published |>
dplyr::left_join(cmin_sim, by = "regimen") |>
dplyr::select(
regimen,
pub_Cmin_median, Cmin_median,
pub_Cmin_PI_low, Cmin_PI_low,
pub_Cmin_PI_high, Cmin_PI_high,
pub_pct_below_50, pct_below_50
)
knitr::kable(
comparison,
digits = c(0, 1, 1, 1, 1, 1, 1, 1, 1),
caption = "Simulated steady-state Cmin per regimen vs. Aouri 2017 Simulation subsection. Published values: 25 mg QD median Cmin 69 ng/mL (95% PI 33.5-125.6); 50 mg QD 140 (39-446); 25 mg BID 167 (59-406). Pct below 50 ng/mL: 29% (25 QD), 2.4% (50 QD), 0% (25 BID)."
)| regimen | pub_Cmin_median | Cmin_median | pub_Cmin_PI_low | Cmin_PI_low | pub_Cmin_PI_high | Cmin_PI_high | pub_pct_below_50 | pct_below_50 |
|---|---|---|---|---|---|---|---|---|
| 25 mg QD | 69 | 65.0 | 33.5 | 26.9 | 125.6 | 141.4 | 29.0 | 27.0 |
| 50 mg QD | 140 | 132.9 | 39.0 | 52.5 | 446.0 | 293.6 | 2.4 | 2.0 |
| 25 mg BID | 167 | 160.1 | 59.0 | 76.5 | 406.0 | 325.2 | 0.0 | 0.6 |
The simulated steady-state Cmin median and the proportion below the 50 ng/mL target track the published values within the expected stochastic range for a 500-subject simulation. The 95% PI bounds are slightly wider than the paper’s because the published intervals were generated with Aouri 2017’s 1000-subject NONMEM Monte Carlo (Methods, “Simulations”) and the virtual cohort here uses a more aggressive tail sampling. No parameter tuning is applied to close the residual gap.
Assumptions and deviations
Abstract vs. Results conflict on absorption-duration interpretation. Aouri 2017’s Abstract states “the mean absorption time was 4 h,” while the Results body (“Population pharmacokinetic analysis”) and Table 2 report D1 = 4 h and mean absorption time = 2 h. For zero-order absorption, mean absorption time = D1/2; the Results body is internally consistent and is the authoritative source. The model encodes ld1 = log(4), giving a mean absorption time of 2 h. The Abstract appears to conflate D1 with mean absorption time.
No covariates retained. Aouri 2017 screened sex, body weight, height, age, race, AST, ALT, HCV/HBV coinfection, comedications, and six pharmacogenetic variants (CYP3A422, CYP3A53, CYP2C192, CYP2C1917, UGT1A128, UGT1A42), none of which survived the multiple-testing-corrected significance threshold (dOFV greater than 7.88, P < 0.005). These covariates are recorded in the model file’s
covariatesDataExcludedmetadata list for traceability but do not appear incovariateDataormodel(). A 13% decrease in CL/F in females was observed (95% CI 3-25%) but did not reach significance.Apparent oral parameters. All clearance and volume terms are CL/F and V/F; bioavailability F is folded into the parameters and is not separately identifiable, since rilpivirine was administered only orally. The model is therefore appropriate for oral 25 mg QD (and user-specified deviations from that regimen) but cannot be used to predict IV exposure without re-introducing F from an independent source. RPV solubility and absorption are pH-dependent (food effect: bioavailability is increased in an acidic environment); the Aouri 2017 cohort received RPV with food per the standard prescribing recommendation, and food / adherence were not collected as covariates.
Genotyping subset. Only 119 of 249 patients in the cohort had genotype data available (Swiss HIV Cohort Study sub-population); 130 patients carried unknown genotype status that was modeled as a fourth category in the rich-vs-reduced covariate testing. None of the variants reached significance, so this missing-genotype classification is not load-bearing in the packaged model.
Steady-state assumption in the simulation. Aouri 2017’s simulation cohort is at steady state; the vignette also evaluates Cmin from the 28th dose at steady state to match the paper’s reference time point (24 h after the previous dose for the QD regimens, 12 h for the BID regimen).