Itraconazole (Hennig 2007)
Source:vignettes/articles/Hennig_2007_itraconazole.Rmd
Hennig_2007_itraconazole.RmdModel and source
- Citation: Hennig S, Waterhouse TH, Bell SC, France M, Wainwright CE, Miller H, Charles BG, Duffull SB (2007). A D-optimal designed population pharmacokinetic study of oral itraconazole in adult cystic fibrosis patients. Br J Clin Pharmacol 63(4):438-450. doi:10.1111/j.1365-2125.2006.02778.x.
- Article: https://doi.org/10.1111/j.1365-2125.2006.02778.x
- Source files on disk: the published PDF
(
HENNIG_S_BJCP_2007_OD.pdf) and an example BQL-method NONMEM control stream (HENNIG_S_BJCP_2007_OD EXAMPLE_BQL_METHOD4_(BEAL_JPKPD2001)_CTL.ctl) shipped alongside the paper. The .ctl file is an example of the Beal 2001 M4 likelihood implementation rather than the final-model control stream, so all final parameter values come from the paper (Table 3); the .ctl is used only to confirm the structural ODE topology and the cross-over design’s per-recordPREP/FORM_CAPSULEcovariate handling.
mod_fn <- readModelDb("Hennig_2007_itraconazole")
mod <- rxode2::rxode2(mod_fn())Population
Hennig 2007 enrolled 30 adult cystic-fibrosis (CF) inpatients (18 male, 12 female) at The Prince Charles Hospital, Brisbane, Queensland, over an 18-month period. Median (range) age was 25 (16-61) years, weight 57 (46-86) kg, height 169 (149-186) cm, lean body weight 46 (36-64) kg (Cheymol formula), and patients were taking a median 13 (7-21) co-medications. None were on itraconazole for clinical indications at recruitment, none had impaired hepatic function, and protein-pump inhibitors / H2-blockers were administered at least 2 hours after the itraconazole dose to ensure capsule absorption (Hennig 2007 Methods; Table 2).
The study was a within-subject cross-over: each patient received a single 200 mg oral dose of itraconazole on two occasions 72 hours apart, once as two 100 mg Sporanox capsules and once as 20 mL of 10 mg/mL Sporanox oral solution. Eight blood samples per patient were drawn at D-optimal sampling times within tolerance windows (Hennig 2007 Table 1, Figure 2), 241 plasma samples in total. 46.0% of itraconazole concentrations and 27.8% of hydroxy-itraconazole concentrations fell below the limit of detection (LOD = 0.04 mg/L; LOQ = 0.075 mg/L).
local({
fbody <- body(mod_fn)
meta_env <- new.env()
for (stmt in as.list(fbody)[-1]) {
if (is.call(stmt) && length(stmt) >= 1 &&
identical(stmt[[1]], as.name("<-"))) {
eval(stmt, envir = meta_env)
} else {
break
}
}
cat("Population:\n")
str(meta_env$population, max.level = 1)
cat("\nCovariates:\n")
str(meta_env$covariateData, max.level = 1)
})
#> Population:
#> List of 16
#> $ n_subjects : int 30
#> $ n_studies : int 1
#> $ age_range : chr "16-61 years"
#> $ age_median : chr "25 years"
#> $ weight_range : chr "46-86 kg"
#> $ weight_median : chr "57 kg"
#> $ height_range : chr "149-186 cm"
#> $ height_median : chr "169 cm"
#> $ lbw_range : chr "36-64 kg (Cheymol formula)"
#> $ lbw_median : chr "46 kg"
#> $ sex_female_pct: num 40
#> $ race_ethnicity: NULL
#> $ disease_state : chr "Adult cystic fibrosis patients in hospital for management of a chest exacerbation, recruited from the Departmen"| __truncated__
#> $ dose_range : chr "Single 200 mg oral itraconazole on each of two occasions 72 h apart (cross-over): two 100 mg Sporanox capsules "| __truncated__
#> $ regions : chr "Brisbane, Queensland, Australia (single-site)."
#> $ notes : chr "Hennig 2007 Table 2 baseline demographics. Median (range) age 25 (16-61) years, weight 57 (46-86) kg, height 16"| __truncated__
#>
#> Covariates:
#> List of 1
#> $ FORM_CAPSULE:List of 6Source trace
Every parameter and equation traces back to a specific location in
the Hennig 2007 paper. The structural ODE topology is also confirmed
against the bundled example BQL-method NONMEM control stream
(...EXAMPLE_BQL_METHOD4_(BEAL_JPKPD2001)_CTL.ctl), but the
parameter values come from Table 3 of the paper (the .ctl is an
example BQL implementation, not the final-model fit, and reports initial
values rather than the final estimates).
| Equation / parameter | Value | Source location |
|---|---|---|
lka_cap = log(0.032) (1/h) |
0.032 | Hennig 2007 Table 3, k_a cap (RSE 46.7%) |
lka_sol = log(0.125) (1/h) |
0.125 | Hennig 2007 Table 3, k_a sol (RSE 44.2%) |
lcl = log(31.5) (L/h, CL_p / F) |
31.5 | Hennig 2007 Table 3, Cl_p (RSE 14.0%) |
lvc = log(56.7) (L, V_c / F) |
56.7 | Hennig 2007 Table 3, V_c (RSE 33.9%) |
lq = log(71.3) (L/h, Q / F) |
71.3 | Hennig 2007 Table 3, Q (RSE 35.3%) |
lvp = log(2090) (L, V_per / F) |
2090 | Hennig 2007 Table 3, V_per (RSE 35.0%) |
lcl_ohi = log(18.3) (L/h, CL_m / (F * f_m)) |
18.3 | Hennig 2007 Table 3, CL_m (RSE 12.9%) |
lvc_ohi = log(2.67) (L, V_m / (F * f_m)) |
2.67 | Hennig 2007 Table 3, V_m (RSE 49.8%) |
lfdepot = log(0.817) (relative bioavailability of
capsule) |
0.817 | Hennig 2007 Table 3, F_rel (RSE 23.5%) |
llag = log(19.3 / 60) (h, lag time) |
19.3 min -> 0.3217 h | Hennig 2007 Table 3, t_lag (RSE 1.68%) |
etalcl ~ log(1 + 0.221^2) = 0.0477 |
22.1 % CV | Hennig 2007 Table 3, BSV Cl_p (RSE 75.2%) |
etalvc ~ log(1 + 0.773^2) = 0.4684 |
77.3 % CV | Hennig 2007 Table 3, BSV V_c (RSE 48.5%) |
etalka_cap ~ log(1 + 0.919^2) = 0.6122 |
91.9 % CV | Hennig 2007 Table 3, BSV k_a cap (RSE 33.5%) |
etalka_sol ~ log(1 + 1.063^2) = 0.7561 |
106.3 % CV | Hennig 2007 Table 3, BSV k_a sol (RSE 31.4%) |
etalfdepot ~ log(1 + 0.623^2) = 0.3279 |
62.3 % CV | Hennig 2007 Table 3, BSV F_rel (RSE 24.7%) |
propSd = 0.408 (proportional residual error,
itraconazole) |
40.8 % CV | Hennig 2007 Table 3, residual itraconazole (RSE 16.6%) |
propSd_ohi = 0.479 (proportional residual error,
OH-itraconazole) |
47.9 % CV | Hennig 2007 Table 3, residual hydroxy-itraconazole (RSE 12.7%) |
| 2-cmt parent + 1-cmt metabolite topology | – | Hennig 2007 Figure 1 (“Final Model”); page 443 |
f_m = 1 fixed (fraction metabolised to
OH-itraconazole) |
– | Hennig 2007 Methods (page 441): “The fraction (f_m) … was therefore fixed to 1” |
| Pure proportional residual error (no additive component) | – | Hennig 2007 Results (page 443): “A proportional error model was shown to be sufficient … for both the parent drug and the metabolite” |
| Formulation-specific KA via per-record FORM_CAPSULE covariate | – | .ctl $PK block:
IF (PREP.EQ.1) KA = THETA(3)*EXP(ETA(4)) ; capsule else
THETA(4)*EXP(ETA(5)) |
F = 1 for solution arm; F = F_rel for
capsule arm |
– | Hennig 2007 Methods (page 441): “F_rel was determined by fixing F_rel to 1 for administration of the oral solution and then estimating F_rel for the capsule” |
| Single shared lag time across both formulations | – | Hennig 2007 Table 3, single t_lag row; .ctl
ALAG1 = TVLAG/60 (no PREP branch) |
Virtual cohort
We build a virtual cohort that mirrors the Hennig 2007 study design:
30 cross-over subjects each receiving a single 200 mg oral dose of
itraconazole, with half the simulation IDs marking the capsule arm
(FORM_CAPSULE = 1) and the other half marking the oral-solution arm
(FORM_CAPSULE = 0). The per-record FORM_CAPSULE covariate
is the source NONMEM PREP column verbatim (PREP = 1 =
capsule, PREP = 0 = solution; same orientation as the package
canonical). Observations are taken over 72 h post-dose to match the
published sampling window.
set.seed(20260508L)
n_per_arm <- 30L
obs_times <- c(0, 0.25, 0.5, 0.75, 1, 1.5, 2, 3, 4, 6, 8, 12,
16, 20, 24, 30, 36, 48, 60, 72)
build_events <- function(n, capsule_value, treatment_label, id_offset) {
ids <- id_offset + seq_len(n)
dose_rows <- data.frame(
id = ids,
time = 0,
evid = 1L,
amt = 200, # mg
cmt = 1L, # depot
treatment = treatment_label,
FORM_CAPSULE = capsule_value
)
obs_rows <- expand.grid(
id = ids,
time = obs_times,
KEEP.OUT.ATTRS = FALSE
)
obs_rows$evid <- 0L
obs_rows$amt <- 0
obs_rows$cmt <- 5L # Cc (parent itraconazole); Cc_ohi is read from the
# sim's wide-format columns alongside Cc.
obs_rows$treatment <- treatment_label
obs_rows$FORM_CAPSULE <- capsule_value
out <- rbind(dose_rows, obs_rows)
out[order(out$id, out$time, -out$evid), ]
}
events <- dplyr::bind_rows(
build_events(n_per_arm, capsule_value = 1L,
treatment_label = "Capsule", id_offset = 0L),
build_events(n_per_arm, capsule_value = 0L,
treatment_label = "Oral solution", id_offset = n_per_arm)
)Simulation
A typical-value (no-IIV, no-residual-error) replication is the cleanest way to compare against the paper’s deterministic Figure 4 median curves; a stochastic VPC then layers IIV + residual error on top of the same cohort skeleton.
mod_typical <- rxode2::zeroRe(mod)
sim_typical <- rxode2::rxSolve(
mod_typical,
events = events,
keep = c("treatment", "FORM_CAPSULE")
) |>
as.data.frame()
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvc', 'etalka_cap', 'etalka_sol', 'etalfdepot'
#> Warning: multi-subject simulation without without 'omega'
sim <- rxode2::rxSolve(
mod,
events = events,
keep = c("treatment", "FORM_CAPSULE")
) |>
as.data.frame()Replicate published figures
Figure 4 of Hennig 2007 shows observed itraconazole and hydroxy-itraconazole plasma concentrations together with the median and 5%-95% prediction intervals from the final model, in four panels (itraconazole oral solution, itraconazole capsule, hydroxy- itraconazole oral solution, hydroxy-itraconazole capsule), over a 72-hour window after a single 200 mg oral dose.
sim_typical |>
tidyr::pivot_longer(c(Cc, Cc_ohi), names_to = "analyte",
values_to = "conc_mgL") |>
dplyr::mutate(
analyte = dplyr::recode(analyte,
Cc = "Itraconazole",
Cc_ohi = "Hydroxy-itraconazole")
) |>
dplyr::filter(time > 0, conc_mgL > 0) |>
ggplot(aes(time, conc_mgL, colour = treatment)) +
geom_line(linewidth = 0.8) +
facet_wrap(~ analyte, scales = "free_y") +
scale_y_log10() +
labs(
x = "Time post-dose (h)",
y = "Plasma concentration (mg/L)",
colour = NULL,
title = "Typical-value plasma trajectory after a single 200 mg oral dose",
caption = paste(
"Replicates Hennig 2007 Figure 4 (single-dose 200 mg).",
"Capsule traces are lower than oral-solution traces because of",
"F_rel = 0.817 and the slower capsule absorption rate",
"(k_a cap = 0.032 vs k_a sol = 0.125 1/h)."
)
)
sim_vpc <- sim |>
tidyr::pivot_longer(c(Cc, Cc_ohi), names_to = "analyte",
values_to = "conc_mgL") |>
dplyr::mutate(
analyte = dplyr::recode(analyte,
Cc = "Itraconazole",
Cc_ohi = "Hydroxy-itraconazole")
) |>
dplyr::filter(time > 0, conc_mgL > 0) |>
dplyr::group_by(time, treatment, analyte) |>
dplyr::summarise(
p05 = quantile(conc_mgL, 0.05, na.rm = TRUE),
p50 = quantile(conc_mgL, 0.50, na.rm = TRUE),
p95 = quantile(conc_mgL, 0.95, na.rm = TRUE),
.groups = "drop"
)
ggplot(sim_vpc, aes(time, p50, colour = treatment, fill = treatment)) +
geom_ribbon(aes(ymin = p05, ymax = p95), alpha = 0.2, colour = NA) +
geom_line(linewidth = 0.6) +
facet_wrap(~ analyte, scales = "free_y") +
scale_y_log10() +
labs(
x = "Time post-dose (h)",
y = "Plasma concentration (mg/L)",
colour = NULL, fill = NULL,
title = "Stochastic VPC after a single 200 mg oral dose (5%-50%-95%)",
caption = paste(
"Compare against Hennig 2007 Figure 4 (4-panel observed-vs-predicted",
"VPC). The cross-over study's BQL handling (LOD = 0.04 mg/L) is not",
"reproduced here; the simulated trajectory is a forward",
"no-BQL-handling simulation of the same structural model."
)
)
PKNCA validation
Single-dose, 72-hour NCA per the recipe in
references/pknca-recipes.md, with the formulation arm
carried as the treatment grouping variable so the per-arm Cmax / Tmax /
AUC can be summarised side-by-side. NCA is run separately for
itraconazole (Cc) and hydroxy-itraconazole
(Cc_ohi). The PKNCA dose object only carries the parent
dose; the metabolite NCA therefore does not report a dose-normalised
AUC.
sim_nca_itz <- sim |>
dplyr::filter(!is.na(Cc), time > 0) |>
dplyr::select(id, time, Cc, treatment)
dose_df <- events |>
dplyr::filter(evid == 1) |>
dplyr::select(id, time, amt, treatment)
conc_obj_itz <- PKNCA::PKNCAconc(sim_nca_itz, Cc ~ time | treatment + id,
concu = "mg/L", timeu = "h")
dose_obj <- PKNCA::PKNCAdose(dose_df, amt ~ time | treatment + id,
doseu = "mg")
intervals <- data.frame(
start = 0,
end = 72,
cmax = TRUE,
tmax = TRUE,
auclast = TRUE,
aucinf.obs = TRUE,
half.life = TRUE
)
nca_itz <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_obj_itz, dose_obj,
intervals = intervals))
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Warning: Too few points for half-life calculation (min.hl.points=3 with only 2
#> points)
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Warning: Too few points for half-life calculation (min.hl.points=3 with only 2
#> points)
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Warning: Too few points for half-life calculation (min.hl.points=3 with only 0
#> points)
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Warning: Too few points for half-life calculation (min.hl.points=3 with only 1
#> points)
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
sim_nca_ohi <- sim |>
dplyr::filter(!is.na(Cc_ohi), time > 0) |>
dplyr::select(id, time, Cc_ohi, treatment)
conc_obj_ohi <- PKNCA::PKNCAconc(sim_nca_ohi, Cc_ohi ~ time | treatment + id,
concu = "mg/L", timeu = "h")
nca_ohi <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_obj_ohi, dose_obj,
intervals = intervals))
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Warning: Too few points for half-life calculation (min.hl.points=3 with only 2
#> points)
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Warning: Too few points for half-life calculation (min.hl.points=3 with only 2
#> points)
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Warning: Too few points for half-life calculation (min.hl.points=3 with only 0
#> points)
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Warning: Too few points for half-life calculation (min.hl.points=3 with only 1
#> points)
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.25) is not allowed
nca_itz_df <- as.data.frame(nca_itz$result)
itz_summary <- nca_itz_df |>
dplyr::filter(PPTESTCD %in% c("cmax", "tmax", "auclast",
"aucinf.obs", "half.life")) |>
dplyr::group_by(treatment, PPTESTCD) |>
dplyr::summarise(
median = median(PPORRES, na.rm = TRUE),
p05 = quantile(PPORRES, 0.05, na.rm = TRUE),
p95 = quantile(PPORRES, 0.95, na.rm = TRUE),
.groups = "drop"
) |>
tidyr::pivot_wider(names_from = treatment,
values_from = c(median, p05, p95))
knitr::kable(
itz_summary,
caption = paste("Simulated NCA -- itraconazole (Cc), single oral 200 mg",
"dose, by formulation arm (median [5%-95%])."),
digits = 3
)| PPTESTCD | median_Capsule | median_Oral solution | p05_Capsule | p05_Oral solution | p95_Capsule | p95_Oral solution |
|---|---|---|---|---|---|---|
| aucinf.obs | NA | NA | NA | NA | NA | NA |
| auclast | NA | NA | NA | NA | NA | NA |
| cmax | 0.051 | 0.192 | 0.012 | 0.043 | 0.227 | 0.721 |
| half.life | 66.477 | 61.220 | 46.109 | 49.583 | 198.406 | 81.684 |
| tmax | 3.500 | 2.000 | 1.450 | 0.863 | 48.000 | 10.600 |
nca_ohi_df <- as.data.frame(nca_ohi$result)
ohi_summary <- nca_ohi_df |>
dplyr::filter(PPTESTCD %in% c("cmax", "tmax", "auclast",
"aucinf.obs", "half.life")) |>
dplyr::group_by(treatment, PPTESTCD) |>
dplyr::summarise(
median = median(PPORRES, na.rm = TRUE),
p05 = quantile(PPORRES, 0.05, na.rm = TRUE),
p95 = quantile(PPORRES, 0.95, na.rm = TRUE),
.groups = "drop"
) |>
tidyr::pivot_wider(names_from = treatment,
values_from = c(median, p05, p95))
knitr::kable(
ohi_summary,
caption = paste("Simulated NCA -- hydroxy-itraconazole (Cc_ohi), single",
"oral 200 mg parent dose, by formulation arm",
"(median [5%-95%])."),
digits = 3
)| PPTESTCD | median_Capsule | median_Oral solution | p05_Capsule | p05_Oral solution | p95_Capsule | p95_Oral solution |
|---|---|---|---|---|---|---|
| aucinf.obs | NA | NA | NA | NA | NA | NA |
| auclast | NA | NA | NA | NA | NA | NA |
| cmax | 0.089 | 0.292 | 0.021 | 0.097 | 0.377 | 1.152 |
| half.life | 66.368 | 61.193 | 46.079 | 49.496 | 199.128 | 81.635 |
| tmax | 4.000 | 2.000 | 1.725 | 1.000 | 48.000 | 10.600 |
Comparison against published NCA (Hennig 2007 Table 5)
Hennig 2007 Table 5 reports posterior-Bayes-derived NCA estimates for itraconazole only (parent drug). The simulated medians from the forward-simulation cohort are compared below; ranges are reported as median (5th-95th percentile) for the simulation and as median (range) for the published table.
| Endpoint | Capsule (sim, median [5%-95%]) | Capsule (Table 5, median [range]) | Solution (sim, median [5%-95%]) | Solution (Table 5, median [range]) |
|---|---|---|---|---|
| Cmax (mg/L) | 0.051 [0.012-0.227] | 0.064 [0.018-0.23] | 0.192 [0.043-0.721] | 0.230 [0.038-1.094] |
| tmax (h) | 3.50 [1.45-48.00] | 4.15 [1.78-105.31] | 2.00 [0.86-10.60] | 1.94 [0.85-20.86] |
| AUC0-inf (mg*h/L) | NA [NA-NA] | 4.42 [2.15-23.81] | NA [NA-NA] | 6.32 [3.76-8.47] |
The simulated medians and ranges are in qualitative agreement with Table 5: oral solution Cmax exceeds capsule Cmax by roughly 3-4x, solution tmax is much shorter than capsule tmax (the capsule has a markedly slower absorption rate, k_a cap = 0.032 vs k_a sol = 0.125 1/h), and the capsule-to-solution AUC ratio is consistent with the relative bioavailability F_rel = 0.817. Forward-simulation tails for tmax and AUC differ from the published Bayes-posterior tails because the simulated cohort uses log-normal IIV with the published BSV CV% (Cl_p 22.1%, V_c 77.3%, k_a cap 91.9%, k_a sol 106.3%, F_rel 62.3%), whereas the published Table 5 ranges are observed posterior summaries from the 30-subject CF cohort and reflect the joint posterior of all etas + the data via the FOCEI fit (and thus include observed realizations of the long upper tails on tmax / AUC, including the 105.31 h tmax tail for one capsule subject).
Steady-state target-attainment cross-check
Hennig 2007 Section Simulation reports a single quantitative secondary outcome: at 200 mg twice daily, only 35% of patients on the solution and 31% on the capsules achieve a steady-state target trough concentration in the recommended range (C_min,ss = 0.5-2 mg/L for itraconazole alone); this rises to 87% (solution) and 63% (capsules) at 500 mg twice daily (Hennig 2007 page 446). We reproduce this as an order-of-magnitude check: simulate steady-state trough concentrations for both formulations at 200 mg BID and 500 mg BID over 7 days and compute the percentage of subjects within 0.5-2 mg/L on day 7. Numerical agreement is not expected to be exact because the published target-attainment uses N = 2000 Monte Carlo subjects (vs the 30-per-arm cohort here) and a slightly different sampling-window structure; the simulation is therefore a qualitative cross-check, not a tuning target.
ss_n_per_arm <- 30L
ss_dose_times <- seq(0, by = 12, length.out = 14) # 7 days, BID
ss_obs_times <- seq(0, 7 * 24, by = 1)
ss_obs_grid <- ss_obs_times[ss_obs_times <= 7 * 24]
build_ss_events <- function(n, capsule_value, treatment_label,
id_offset, dose_mg) {
ids <- id_offset + seq_len(n)
dose_rows <- expand.grid(
id = ids,
time = ss_dose_times,
KEEP.OUT.ATTRS = FALSE
)
dose_rows$evid <- 1L
dose_rows$amt <- dose_mg
dose_rows$cmt <- 1L # depot
dose_rows$treatment <- treatment_label
dose_rows$FORM_CAPSULE <- capsule_value
obs_rows <- expand.grid(
id = ids,
time = ss_obs_grid,
KEEP.OUT.ATTRS = FALSE
)
obs_rows$evid <- 0L
obs_rows$amt <- 0
obs_rows$cmt <- 5L # Cc (parent itraconazole)
obs_rows$treatment <- treatment_label
obs_rows$FORM_CAPSULE <- capsule_value
out <- rbind(dose_rows, obs_rows)
out[order(out$id, out$time, -out$evid), ]
}
ss_arms <- list(
list(dose = 200, label_cap = "Capsule 200 mg BID",
label_sol = "Solution 200 mg BID"),
list(dose = 500, label_cap = "Capsule 500 mg BID",
label_sol = "Solution 500 mg BID")
)
ss_events <- dplyr::bind_rows(lapply(seq_along(ss_arms), function(i) {
arm <- ss_arms[[i]]
id_base <- (i - 1L) * 2L * ss_n_per_arm
rbind(
build_ss_events(ss_n_per_arm, capsule_value = 1L,
treatment_label = arm$label_cap,
id_offset = id_base,
dose_mg = arm$dose),
build_ss_events(ss_n_per_arm, capsule_value = 0L,
treatment_label = arm$label_sol,
id_offset = id_base + ss_n_per_arm,
dose_mg = arm$dose)
)
}))
ss_sim <- rxode2::rxSolve(
mod,
events = ss_events,
keep = c("treatment", "FORM_CAPSULE")
) |>
as.data.frame()
trough_target_low <- 0.5
trough_target_high <- 2.0
ss_trough <- ss_sim |>
dplyr::filter(time == max(ss_dose_times)) |>
dplyr::group_by(treatment) |>
dplyr::summarise(
n = dplyr::n(),
in_range = mean(Cc >= trough_target_low & Cc <= trough_target_high,
na.rm = TRUE),
median = median(Cc, na.rm = TRUE),
p05 = quantile(Cc, 0.05, na.rm = TRUE),
p95 = quantile(Cc, 0.95, na.rm = TRUE),
.groups = "drop"
)
knitr::kable(
ss_trough,
caption = paste(
"Simulated steady-state itraconazole trough concentration",
"(Cc at 7 d after first dose, just before the day-7 morning",
"dose); fraction of subjects in the 0.5-2.0 mg/L target range.",
"Compare directionally with Hennig 2007 page 446: 35% / 31%",
"at 200 mg BID (sol / cap) and 87% / 63% at 500 mg BID."
),
digits = 3
)| treatment | n | in_range | median | p05 | p95 |
|---|---|---|---|---|---|
| Capsule 200 mg BID | 30 | 0.267 | 0.320 | 0.105 | 0.869 |
| Capsule 500 mg BID | 30 | 0.500 | 0.521 | 0.212 | 1.207 |
| Solution 200 mg BID | 30 | 0.000 | 0.353 | 0.249 | 0.476 |
| Solution 500 mg BID | 30 | 0.933 | 0.816 | 0.550 | 1.109 |
Assumptions and deviations
Cross-over IIV between formulations is approximated as independent. The Hennig 2007 study is a within-subject cross-over in which each of 30 patients receives both formulations 72 h apart. In this validation cohort we simulate 30 subjects per arm as independent draws (60 total) rather than 30 paired draws, so the per-arm Cl_p / V_c BSV are reproduced but the within-subject correlation between the capsule and oral-solution arms is not. Because the paper does not report between-occasion variability (BOV was not considered, per Methods page 441) and because the forward-simulation NCA is reported per arm rather than as a paired cap-vs-sol contrast, this approximation does not affect the per-arm summary statistics.
Block-correlation between etalcl and etalvc is omitted. The bundled example BQL .ctl declares
$OMEGA BLOCK(2)on (etalcl, etalvc) with initial-value off-diagonal 0.064 (variances 0.0816 and 1.83), but Table 3 of the paper does not report the final-fit off-diagonal estimate, and the .ctl is an example BQL- method run rather than the final-model fit. The two etas are therefore modelled as independent here. The diagonal BSV CV% (22.1% on Cl_p and 77.3% on V_c) match Table 3 exactly.Molecular-weight correction factor on V_m and CL_m is omitted. The bundled .ctl applies a correction factor
722.64 / 705.64(~1.024) to V_m and CL_m for the molecular-weight difference between hydroxy-itraconazole (722.64 g/mol) and itraconazole (705.64 g/mol). Because the factor is applied to both V_m and CL_m and the metabolite elimination rate constant isk_el,m = CL_m / V_m, the metabolite half-life is unchanged whether the correction is included or omitted. The only effect is on the absolute scaling of the metabolite concentration (~2.4% lower with the correction applied). The package model uses the Table 3 values directly (CL_m = 18.3 L/h, V_m = 2.67 L) without the additional multiplication, on the grounds that those are the values a reader would expect to plug in based on the paper’s table.BQL handling is not reproduced in the forward simulation. The M5 method (BLOD = 0.5 * LOD) was used for fitting, and the M4 method (BEAL 2001 censored likelihood) is shown in the bundled .ctl as an alternative. For forward simulation no BQL handling is applied; the simulated trajectory descends below the LOD = 0.04 mg/L late in the 72 h window and those values are retained rather than censored. The final-model parameters from Table 3 (M5-fitted) are unaffected because the package model is for forward use, not refitting.
Race / ethnicity composition of the cohort is not reported. The source paper does not record race or ethnicity for the 30 CF inpatients (Hennig 2007 Table 2 reports only sex / age / weight / height / lean body weight / number of co-medications). The package’s
populationmetadata leavesrace_ethnicityas NULL.No covariate effects are modelled. Hennig 2007 explicitly reports that none of the screened covariates (total body weight, lean body weight, age, proton-pump inhibitor / H2-blocker co-administration) showed a statistically supported relationship with any pharmacokinetic parameter, so the final model contains no covariate effects (Hennig 2007 page 444). The package model matches that final-model structure.
FORM_CAPSULE covariate registration. A new specific-scope
FORM_CAPSULEcanonical was added toinst/references/covariate-columns.mdfor this model; the source NONMEM columnPREP(PREP = 1 = capsule, PREP = 0 = oral solution) maps toFORM_CAPSULEwith the same orientation. A separateFORM_TABLETcanonical (Kyhl 2016 nalmefene) already exists for tablet-vs-solution; the two are deliberately distinct because the formulation contrasts come from different studies and select different parameter splits.