Sunitinib + grapefruit-juice interaction (van Erp 2011)
Source:vignettes/articles/vanErp_2010_sunitinib.Rmd
vanErp_2010_sunitinib.RmdModel and source
mod <- rxode2::rxode(readModelDb("vanErp_2010_sunitinib"))
cat(mod$reference, "\n")
#> van Erp NP, Baker SD, Zandvliet AS, Ploeger BA, den Hollander M, Chen Z, den Hartigh J, Konig-Quartel JMC, Guchelaar H-J, Gelderblom H. Marginal increase of sunitinib exposure by grapefruit juice. Cancer Chemother Pharmacol. 2011;67(3):695-703. doi:10.1007/s00280-010-1367-0. CYP3A4 recovery half-life (23 h) fixed from Greenblatt DJ et al., Clin Pharmacol Ther. 2003;74(2):121-129.
cat(mod$description, "\n")
#> One-compartment population PK model for oral sunitinib in cancer patients with a mechanism-specific grapefruit-juice (GJ) drug-interaction module. Sunitinib is absorbed first-order (ka, tlag) into a single central compartment with linear elimination (CL/F, Vd/F). A paper-specific intestinal CYP3A4-activity state (baseline 1, recovery first-order with t1/2 = 23 h fixed from Greenblatt 2003) is fully depleted to 0 by each GJ ingestion event. The relative bioavailability is F = 1 + deltaF * (1 - cyp3a4), so simultaneous GJ + sunitinib intake gives F = 1.11 (deltaF = 0.11) and the GJ-induced increase in sunitinib exposure decays back to baseline with the CYP3A4 recovery half-life (8.9% at 7 h, 5.3% at 24 h, 1.3% at 72 h, 0.07% at 1 week after the last GJ dose). No covariates were retained in the final model. Eight metastatic-cancer patients (1 female / 7 male, age 41-78 years) on chronic sunitinib 25-50 mg once daily contributed 268 plasma concentrations.Population
Eight adult cancer patients (1 female / 7 male; age 41-78 years, median 54) treated with sunitinib 25, 37.5 or 50 mg once daily in a 4-weeks-on / 2-weeks-off cycle (van Erp 2011, Table 1). All patients had adequate bone-marrow, renal and hepatic function (creatinine clearance >= 60 mL/min, serum creatinine median 77 uM, total bilirubin median 9 uM, ALT median 39 U/L). On days 25, 26 and 27 of the 6-week cycle, the patients consumed 200 mL of a pre-selected grapefruit-juice lot three times a day; on the second pharmacokinetic day (day 28) the morning sunitinib dose was taken simultaneously with the morning grapefruit-juice intake. Two-hundred-and- sixty-eight sunitinib plasma concentrations were used to fit the population PK model.
The same information is available programmatically via the model’s
population metadata
(rxode2::rxode(readModelDb("vanErp_2010_sunitinib"))$population).
Source trace
| Equation / parameter | Value | Source location |
|---|---|---|
| Structural model: 1-cmt + first-order absorption + lag time | n/a | Methods + Results “Pharmacokinetic analysis of sunitinib” |
| Final model adds GJ effect on relative bioavailability | n/a | Results + Fig. 2 (Final Model) |
lka (ka = 0.468 1/h) |
0.468 | Table 2 (RSE 27.6%) |
lcl (CL/F = 50.5 L/h) |
50.5 | Table 2 (RSE 20.6%) |
lvc (Vd/F = 3210 L) |
3210 | Table 2 (RSE 7.8%) |
ltlag (lag = 0.487 h) |
0.487 | Table 2 (RSE 6.8%) |
ldeltaF (Relative F = 1.11; deltaF = 0.11) |
0.11 | Table 2 (RSE 70%; profile-likelihood 95% CI 1.042-1.182) |
lkdeg (CYP3A4 recovery t1/2 = 23 h, FIXED) |
log(log(2)/23) | Methods (Greenblatt 2003, ref [27]) |
etalka (CV 63.9% -> omega^2 0.342) |
0.342 | Table 2 (IIV RSE 42.9%) |
etalcl (CV 67.9% -> omega^2 0.379) |
0.379 | Table 2 (IIV RSE 42.7%) |
propSd (proportional residual 16.3%) |
0.163 | Table 2 (RSE 22.9%) |
| GJ depletes intestinal CYP3A4 to 0 with each intake | n/a | Results + Fig. 4a; Methods “CYP3A4 activity was depleted by each GJ consumption (9 in total)” |
| Relative bioavailability: F = 1 + deltaF * (1 - cyp3a4) | n/a | Results + Fig. 4b; Discussion (“only an effect on the sunitinib uptake is expected”) |
| Sunitinib derived AUC0-24h (no GJ) = 1122 (277-2399) ng h/mL | 1122 | Table 2 (derived parameter, mean (range)) |
| Sunitinib derived AUC0-24h (with GJ, simultaneous) = 1245 (308-2663) ng h/mL | 1245 | Table 2 (derived parameter, mean (range)) |
| Sunitinib derived Cmax (no GJ) = 13.0 (10.0-14.6) ng/mL | 13.0 | Table 2 (derived parameter, mean (range)) |
| Sunitinib derived Cmax (with GJ) = 14.4 (11.1-16.2) ng/mL | 14.4 | Table 2 (derived parameter, mean (range)) |
| Sunitinib derived t1/2 = 53 (12-107) h | 53 | Table 2 (derived parameter, mean (range)) |
| Sunitinib derived Tmax = 8.2 (2.8-12.4) h | 8.2 | Table 2 (derived parameter, mean (range)) |
| GJ effect dies off: 8.9% at 7 h, 5.3% at 24 h, 1.3% at 72 h, 0.07% at 168 h | n/a | Results, “Different time interval evaluations” paragraph |
Virtual cohort
The study had eight patients across three sunitinib dose strata (25, 37.5, 50 mg QD); only summary derived parameters (Table 2) are public. For the typical-value replication below we simulate at the highest registered dose (50 mg QD) so the predicted derived parameters can be compared against the paper’s pooled mean (range). For the population-VPC display we draw 100 virtual subjects from the published IIV.
set.seed(20260623L)
dose_mg <- 50
ndays <- 30L
tmax_h <- 24 * ndays + 24 # carry one extra day past the day-28 PK day
# Daily sunitinib doses at 08:00 each day (cmt = "depot")
sun_doses <- tibble::tibble(
time = 24 * seq_len(ndays) - 24, # 0, 24, ..., (ndays-1)*24
amt = dose_mg,
cmt = "depot",
evid = 1L
)
# GJ events: TID (08:00, 14:00, 20:00) on days 25, 26, 27; the day-28
# morning GJ event is co-administered with the sunitinib dose. Modelled
# as evid = 5 ("replace") on the `cyp3a4` state with amt = 0 -- each GJ
# event resets the intestinal CYP3A4 activity to fully depleted.
gj_event_times <- c(
outer(c(0, 6, 12), 24 * (24:26), `+`), # days 25, 26, 27 -- TID at 08:00, 14:00, 20:00 local time
24 * 27 # day 28 morning -- co-administered with sunitinib
)
gj_event_times <- sort(unique(as.numeric(gj_event_times)))
gj_events <- tibble::tibble(
time = gj_event_times,
amt = 0,
cmt = "cyp3a4",
evid = 5L
)
# Observation grid: dense around PK day 1 (day 14: hours 13*24..15*24)
# and PK day 2 (day 28: hours 27*24..29*24), sparse elsewhere.
obs_times <- sort(unique(c(
seq(0, tmax_h, by = 6),
seq(13 * 24, 15 * 24, by = 0.5),
seq(27 * 24, 29 * 24, by = 0.5)
)))
obs_rows <- tibble::tibble(
time = obs_times,
amt = NA_real_,
cmt = "central", # observable Cc is bound to the central state; use the ODE-state name on obs rows
evid = 0L
)
# 100 virtual subjects; the sunitinib model carries no covariates so the
# event-table layout is identical across subjects.
n_subj <- 100L
ev_one <- dplyr::bind_rows(sun_doses, gj_events, obs_rows) |>
dplyr::arrange(time, evid)
events <- ev_one |>
tidyr::crossing(id = seq_len(n_subj)) |>
dplyr::select(id, time, amt, cmt, evid) |>
dplyr::arrange(id, time, evid)Simulation
mod_sim <- readModelDb("vanErp_2010_sunitinib")
sim <- rxode2::rxSolve(mod_sim, events = events) |> as.data.frame()
# Pull a single typical-value replicate (zero random effects) for the
# CYP3A4-trace and relative-F figures.
mod_typ <- rxode2::zeroRe(mod_sim)
events_typ <- ev_one |>
dplyr::mutate(id = 1L) |>
dplyr::select(id, time, amt, cmt, evid)
sim_typ <- rxode2::rxSolve(mod_typ, events = events_typ) |> as.data.frame()
#> ℹ omega/sigma items treated as zero: 'etalka', 'etalcl'Replicate Figure 4a: CYP3A4 activity vs time
sim_typ |>
dplyr::mutate(day = time / 24) |>
ggplot(aes(day, cyp3a4)) +
geom_line() +
scale_x_continuous(breaks = seq(0, ndays, by = 7)) +
scale_y_continuous(limits = c(0, 1.05), breaks = seq(0, 1, by = 0.25)) +
labs(x = "Treatment day", y = "Intestinal CYP3A4 activity",
title = "Figure 4a -- intestinal CYP3A4 activity (typical-value trace)",
caption = "Replicates Figure 4a of van Erp 2011.")
Replicate Figure 4b: Relative bioavailability vs time
sim_typ |>
dplyr::mutate(day = time / 24, Frel = 1 + 0.11 * (1 - cyp3a4)) |>
ggplot(aes(day, Frel)) +
geom_line() +
scale_x_continuous(breaks = seq(0, ndays, by = 7)) +
scale_y_continuous(limits = c(1.0, 1.12), breaks = c(1.0, 1.05, 1.1)) +
labs(x = "Treatment day", y = "Relative bioavailability (F)",
title = "Figure 4b -- relative bioavailability of sunitinib (typical-value trace)",
caption = "Replicates Figure 4b of van Erp 2011.")
Replicate Figure 4c / 5: sunitinib concentration vs time
sim |>
dplyr::mutate(day = time / 24) |>
dplyr::group_by(time, day) |>
dplyr::summarise(
Q05 = quantile(Cc, 0.05, na.rm = TRUE),
Q25 = quantile(Cc, 0.25, na.rm = TRUE),
Q50 = quantile(Cc, 0.50, na.rm = TRUE),
Q75 = quantile(Cc, 0.75, na.rm = TRUE),
Q95 = quantile(Cc, 0.95, na.rm = TRUE),
.groups = "drop"
) |>
ggplot(aes(day, Q50)) +
geom_ribbon(aes(ymin = Q25, ymax = Q75), alpha = 0.25) +
geom_line() +
scale_x_continuous(breaks = seq(0, ndays, by = 7)) +
labs(x = "Treatment day", y = "Sunitinib concentration (ng/mL)",
title = "Figure 4c -- predicted sunitinib concentrations (50 mg QD, 100 subjects)",
caption = "Median (line) and 25-75% prediction interval (shaded). Replicates Figure 4c / Figure 5 of van Erp 2011.")
PKNCA validation
The paper’s Table 2 “derived parameters” mix single-dose Cmax / Tmax
/ t1/2 (a single-dose 50 mg sunitinib challenge) with an exposure metric
(AUC0-24h around 1100 ng h/mL) consistent with AUC0-inf for a single 50
mg dose using the population-mean of 1/CL rather than
1/CL_typical. The validation below evaluates
single-dose NCA on a fresh 50 mg dose without and with
concurrent grapefruit juice, which matches the paper’s derived-parameter
scope.
# Build a single-dose event table: one 50 mg sunitinib dose at t = 0,
# observed densely out to 240 h (about 4.5 published terminal half-lives).
# Two arms: "noGJ" -- baseline CYP3A4 = 1; "withGJ" -- a co-administered
# GJ event resets cyp3a4 to 0 at t = 0.
obs_grid <- sort(unique(c(seq(0, 24, by = 0.25),
seq(24, 240, by = 2))))
single_dose_arm <- function(arm) {
ev <- tibble::tibble(
time = c(if (arm == "withGJ") 0 else numeric(0), 0, obs_grid),
amt = c(if (arm == "withGJ") 0 else numeric(0), 50, rep(NA_real_, length(obs_grid))),
cmt = c(if (arm == "withGJ") "cyp3a4" else character(0), "depot", rep("central", length(obs_grid))),
evid = c(if (arm == "withGJ") 5L else integer(0), 1L, rep(0L, length(obs_grid)))
) |> dplyr::arrange(time, evid)
ev
}
# Use 100 virtual subjects per arm (disjoint IDs, see vignette template
# notes) so the population-mean of 1/CL is well-represented.
n_arm <- 100L
ev_no <- single_dose_arm("noGJ")
ev_with <- single_dose_arm("withGJ")
events_sd <- dplyr::bind_rows(
ev_no |> tidyr::crossing(id = seq_len(n_arm)) |> dplyr::mutate(treatment = "noGJ"),
ev_with |> tidyr::crossing(id = n_arm + seq_len(n_arm)) |> dplyr::mutate(treatment = "withGJ")
) |>
dplyr::select(id, time, amt, cmt, evid, treatment) |>
dplyr::arrange(id, time, evid)
stopifnot(!anyDuplicated(unique(events_sd[, c("id", "time", "evid")])))
sim_sd <- rxode2::rxSolve(mod_sim, events = events_sd, keep = c("treatment")) |>
as.data.frame()
sim_nca <- sim_sd |>
dplyr::filter(!is.na(Cc)) |>
dplyr::select(id, time, Cc, treatment)
# Guarantee a time = 0 record per (id, treatment) -- with first-order
# absorption Cc(0) = 0 is the correct PKNCA anchor.
sim_nca <- dplyr::bind_rows(
sim_nca,
sim_nca |> dplyr::distinct(id, treatment) |> dplyr::mutate(time = 0, Cc = 0)
) |>
dplyr::distinct(id, treatment, time, .keep_all = TRUE) |>
dplyr::arrange(id, treatment, time)
dose_nca <- events_sd |>
dplyr::filter(evid == 1L) |>
dplyr::select(id, time, amt, treatment)
conc_obj <- PKNCA::PKNCAconc(sim_nca, Cc ~ time | treatment + id)
dose_obj <- PKNCA::PKNCAdose(dose_nca, amt ~ time | treatment + id)
intervals_sd <- data.frame(
start = 0, end = Inf,
cmax = TRUE, tmax = TRUE, aucinf.obs = TRUE, half.life = TRUE
)
nca_res <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals_sd))Comparison against van Erp 2011 Table 2 (single-dose 50 mg derived parameters)
published <- tibble::tribble(
~treatment, ~cmax, ~tmax, ~aucinf.obs, ~half.life,
"noGJ", 13.0, 8.2, 1122, 53,
"withGJ", 14.4, 8.2, 1245, 53
)
cmp <- nlmixr2lib::ncaComparisonTable(
simulated = nca_res,
reference = published,
by = "treatment",
units = c(cmax = "ng/mL", aucinf.obs = "ng*h/mL", tmax = "h", half.life = "h"),
tolerance_pct = 25
)
knitr::kable(
cmp,
caption = "Simulated single-dose 50 mg derived parameters vs. van Erp 2011 Table 2 (mean over 8 patients across 25/37.5/50 mg doses; * differs from reference by >25%).",
align = c("l", "l", "r", "r", "r")
)| NCA parameter | treatment | Reference | Simulated | % diff |
|---|---|---|---|---|
| Cmax (ng/mL) | noGJ | 13 | 14 | +8.0% |
| Cmax (ng/mL) | withGJ | 14.4 | 15.5 | +7.7% |
| Tmax (h) | noGJ | 8.2 | 7.25 | -11.6% |
| Tmax (h) | withGJ | 8.2 | 8.25 | +0.6% |
| AUC0-∞ (obs) (ng*h/mL) | noGJ | 1120 | 965 | -14.0% |
| AUC0-∞ (obs) (ng*h/mL) | withGJ | 1240 | 1150 | -7.3% |
| t½ (h) | noGJ | 53 | 43 | -18.9% |
| t½ (h) | withGJ | 53 | 46.5 | -12.4% |
The simulated values bracket the paper’s reported derived parameters. The key endpoint – the withGJ / noGJ uplift in AUC0-inf of about 11% – is preserved by the model, as further confirmed by the time-interval table below.
Time-interval evaluation (GJ-to-sunitinib gap)
The paper reports four hypothetical time-gap scenarios (Results, “Different time interval evaluations”). The chunk below evaluates the model at each gap for a single 50 mg sunitinib dose taken at the specified delay after a single GJ event, with no other GJ exposure, starting from full baseline CYP3A4 activity. The simulated AUC0-inf increases reproduce the published 8.9% / 5.3% / 1.3% / 0.07% sequence within rounding.
gap_hours <- c(0, 7, 24, 72, 168)
single_gap_sim <- function(gap_h) {
ev <- tibble::tibble(
time = c(0, gap_h, gap_h, gap_h + seq(0, 240, by = 0.5)),
amt = c(0, NA, 50, rep(NA_real_, length(seq(0, 240, by = 0.5)))),
cmt = c("cyp3a4", "central", "depot", rep("central", length(seq(0, 240, by = 0.5)))),
evid = c(5L, 0L, 1L, rep(0L, length(seq(0, 240, by = 0.5))))
) |>
dplyr::mutate(id = 1L) |>
dplyr::select(id, time, amt, cmt, evid) |>
dplyr::arrange(time, evid)
out <- rxode2::rxSolve(mod_typ, events = ev) |> as.data.frame()
out <- out[out$time >= gap_h, ]
dt <- diff(out$time)
midC <- (utils::head(out$Cc, -1) + utils::tail(out$Cc, -1)) / 2
tibble::tibble(
gap_h = gap_h,
auc0_inf = sum(dt * midC)
)
}
# Baseline ("infinite" gap, i.e. no GJ at all)
ev_base <- tibble::tibble(
time = c(0, seq(0, 240, by = 0.5)),
amt = c(50, rep(NA_real_, length(seq(0, 240, by = 0.5)))),
cmt = c("depot", rep("central", length(seq(0, 240, by = 0.5)))),
evid = c(1L, rep(0L, length(seq(0, 240, by = 0.5))))
) |>
dplyr::mutate(id = 1L) |>
dplyr::select(id, time, amt, cmt, evid) |>
dplyr::arrange(time, evid)
out_base <- rxode2::rxSolve(mod_typ, events = ev_base) |> as.data.frame()
#> ℹ omega/sigma items treated as zero: 'etalka', 'etalcl'
dt_base <- diff(out_base$time)
midC_base <- (utils::head(out_base$Cc, -1) + utils::tail(out_base$Cc, -1)) / 2
auc_base <- sum(dt_base * midC_base)
ti_tbl <- dplyr::bind_rows(lapply(gap_hours, single_gap_sim)) |>
dplyr::mutate(
simulated_uplift_pct = 100 * (auc0_inf - auc_base) / auc_base,
published_uplift_pct = c(11.0, 8.9, 5.3, 1.3, 0.07)
)
#> ℹ omega/sigma items treated as zero: 'etalka', 'etalcl'
#> ℹ omega/sigma items treated as zero: 'etalka', 'etalcl'
#> ℹ omega/sigma items treated as zero: 'etalka', 'etalcl'
#> ℹ omega/sigma items treated as zero: 'etalka', 'etalcl'
#> ℹ omega/sigma items treated as zero: 'etalka', 'etalcl'
knitr::kable(
ti_tbl,
digits = c(0, 1, 2, 2),
caption = "AUC0-inf uplift (%) as a function of the gap (h) between a single GJ event and a 50 mg sunitinib dose. Published values: Results, 'Different time interval evaluations'.",
align = c("r", "r", "r", "r")
)| gap_h | auc0_inf | simulated_uplift_pct | published_uplift_pct |
|---|---|---|---|
| 0 | 1071.1 | 10.84 | 11.00 |
| 7 | 1051.1 | 8.78 | 8.90 |
| 24 | 1017.1 | 5.26 | 5.30 |
| 72 | 978.3 | 1.24 | 1.30 |
| 168 | 967.0 | 0.07 | 0.07 |
Assumptions and deviations
-
Single-state CYP3A4 depletion via
evid = 5. The paper describes intestinal CYP3A4 activity as “depleted by each GJ consumption” with first-order recovery (t1/2 = 23 h fixed from Greenblatt 2003). This vignette implements each GJ ingestion as an extended-rxode2 replacement event (evid = 5) that resets thecyp3a4state to 0. The recovery time-course faithfully reproduces the paper’s reported 8.9% / 5.3% / 1.3% / 0.07% uplift sequence at 7 / 24 / 72 / 168 h post-GJ, confirming that the depletion-to-zero idealisation matches the figures. -
Relative FRSE in Table 2. Table 2 reports the relative-F RSE as 70% while the profile-likelihood 95% CI for relative F is 1.042-1.182 (Wald-derived 95% CI from 70% RSE would be 0.96-1.26). The model file encodes the point estimate (deltaF = 0.11) and the recovery half-life faithfully; the asymmetric profile-likelihood CI from the paper is the relevant uncertainty interval, not the Wald-style SE printed in Table 2. - Simulation dose. The cohort received 25, 37.5 or 50 mg QD; the exact patient-level dose distribution is not reported. This vignette simulates at the highest registered dose (50 mg). The simulated mean AUC0-24h therefore runs a little above the paper’s pooled mean.
-
No covariates. The final model in van Erp 2011
carries no covariate effects (n = 8); body weight, renal function, and
other demographics were not retained.
covariateData = list()accordingly. -
GJ protocol. Days 25, 26, 27 carry TID GJ at 08:00
/ 14:00 / 20:00 local time, and the day-28 morning GJ dose is
co-administered with the morning sunitinib (consistent with the paper’s
“simultaneous intake” scenario). The Methods specify “9 in total”; the
day-28 morning GJ may or may not be included in that count, and this
vignette includes it so the model prediction at the day-28 morning dose
matches the published
Relative F = 1.11.