Oxypurinol (Stocker 2012)
Source:vignettes/articles/Stocker_2012_oxypurinol.Rmd
Stocker_2012_oxypurinol.RmdModel and source
#> ℹ parameter labels from comments will be replaced by 'label()'
- Citation: Stocker SL, McLachlan AJ, Savic RM, Kirkpatrick CM, Graham GG, Williams KM, Day RO. The pharmacokinetics of oxypurinol in people with gout. Br J Clin Pharmacol. 2012 Sep;74(3):477-489. doi:10.1111/j.1365-2125.2012.04207.x
- Description: One-compartment population PK model for oxypurinol (the active metabolite of allopurinol) in adults with gout (Stocker 2012). First-order formation from allopurinol (Kfm taken as the apparent first-order absorption rate into the central compartment), one-compartment distribution, and first-order elimination. Apparent clearance (CL/Fm) is modified by raw Cockcroft-Gault creatinine clearance based on lean body weight (CRCL), concomitant any-class diuretic use (CONMED_DIUR; thiazide / furosemide / spironolactone pooled), and concomitant probenecid use (CONMED_PROBENECID), each via a linear-deviation multiplicative factor. Apparent volume (V/Fm) is allometrically scaled on lean body weight (LBW) with the volume exponent held fixed at the theoretical value of 1.0. The dose entered into the model is the oxypurinol-equivalent dose, taken as 0.9 x allopurinol dose per the paper’s prior published assumption.
- Article: https://doi.org/10.1111/j.1365-2125.2012.04207.x
The packaged model implements the Stocker 2012 final covariate model
of oxypurinol population pharmacokinetics in adults with gout. The
structural model is one-compartment with first-order formation (Kfm) and
first-order elimination; the dose entered into the model is the
oxypurinol-equivalent dose, taken as 0.9 times the allopurinol dose per
the paper’s prior published assumption (Stocker 2012 Methods, page 478,
citing reference 6). Apparent clearance CL/Fm is modified by three
covariates: raw Cockcroft-Gault creatinine clearance based on lean body
weight (CRCL; linear-deviation slope centred at the cohort
median 37.6 mL/min), concomitant any-class diuretic use
(CONMED_DIUR), and concomitant probenecid use
(CONMED_PROBENECID). Apparent central volume V/Fm is
allometrically scaled on lean body weight (LBM; reference
60 kg, exponent held fixed at the theoretical value of 1.0). The model
was developed in NONMEM 7.1.0 (FOCE-I) with PsN 3.4.2 used for
diagnostics and bootstrap.
Population
Stocker 2012 fit the model to 1013 plasma oxypurinol concentrations from 155 adults with gout (132 male / 23 female; sex-female 14.8%) enrolled at St Vincent’s Hospital and from the surrounding Sydney community. The cohort was elderly (age range 28.0-93.6 years, median 69.0) and skewed toward substantial mild-to-moderate renal impairment (creatinine clearance range 6.0-130.4 mL/min, median 37.6 mL/min). All patients were on chronic allopurinol for at least 7 days at allopurinol doses of 50-400 mg/day (median 300 mg/day); 13% had tophi present, and 28% of the cohort were obese (BMI > 30 kg/m^2). 46% of subjects (72 / 155) were coadministered a diuretic (thiazide, furosemide, or spironolactone, pooled into a single composite indicator), and 13% (20 / 155) were coadministered probenecid. The number of PK occasions ranged from 1 to 5 per patient, with each occasion corresponding to a hospital readmission or a change in concomitant medication. Seven patients were excluded prior to modelling: 4 were not at steady-state, 2 were undergoing dialysis, and 1 was in acute renal failure. The full demographic summary appears in Stocker 2012 Table 1.
The same metadata is available programmatically via
readModelDb("Stocker_2012_oxypurinol")$meta$population.
Source trace
The per-parameter origin is recorded as an in-file comment next to
each ini() entry in
inst/modeldb/specificDrugs/Stocker_2012_oxypurinol.R. The
table below collects them in one place for review. All point estimates
are from Stocker 2012 Table 3 (“Covariate (final) model” column); the
structural-model layout and covariate parameterisation are taken from
the equations on page 480 (between Results “Covariate pharmacokinetic
model” and Figure 2).
| Equation / parameter | Value | Source location |
|---|---|---|
lka (Kfm) |
log(0.447) -> 0.447 1/h | Table 3 row “Kfm”; bootstrap median 0.438 (0.301, 0.628) |
lcl (CL/Fm at ref CRCL) |
log(0.595) -> 0.595 L/h | Table 3 row “CL/Fm”; bootstrap median 0.594 (0.548, 0.646); reference CRCL = 37.6 mL/min |
lvc (V/Fm at ref LBM) |
log(38.1) -> 38.1 L | Table 3 row “V/Fm”; bootstrap median 38.3 (33.2, 44.4); reference LBM = 60 kg |
e_lbm_vc |
fixed(1.0) | Equation page 480: TVV/Fm = theta2 * (LBW/60)^theta9;
theta9 not reported in Table 3, inferred fixed at theoretical 1.0 |
e_crcl_cl (theta6) |
+0.0250 | Table 3 row “Creatinine clearance (theta6)”; bootstrap median 0.025 (0.021, 0.028) |
e_conmed_diur_cl (theta7) |
-0.294 | Table 3 row “Diuretics (theta7)”; bootstrap median -0.298 (-0.386, -0.207); -29.4% effect on CL/Fm |
e_conmed_probenecid_cl (theta8) |
+0.383 | Table 3 row “Probenecid (theta8)”; bootstrap median 0.384 (0.264, 0.499); +38.3% effect on CL/Fm |
etalcl variance |
log(1 + 0.28^2) = 0.0755 | Table 3 row “BSV CL/Fm”; 28% CV |
etalvc variance |
log(1 + 0.45^2) = 0.1844 | Table 3 row “BSV V/Fm”; 45% CV |
etalcl x etalvc cov |
0.33 * sqrt(0.0755 * 0.1844) = 0.0389 | Table 3 row “COV(CL/V), R”; r = 0.33 |
addSd |
1.32 mg/L | Table 3 row “Additive (mg/L)”; bootstrap median 1.32 (0.77, 1.64) |
propSd |
0.131 (13.1% CV) | Table 3 row “Proportional (CV%)”; bootstrap median 12.9% (9.4%, 17.2%) |
| CL/Fm equation | CL = TVCL * (1 + theta6 * (CRCL - 37.6)) * (1 + theta7 * DIUR) * (1 + theta8 * PROB) |
Page 480 equation, with linear-deviation form confirmed by the abstract’s strata-CL values (1.8 / 0.6 / 0.3 / 0.18 L/h at normal / mild / moderate / severe renal impairment) |
| V/Fm equation | V = TVV * (LBW/60)^theta9 |
Page 480 equation; reference LBW = 60 kg |
ODE d/dt(depot)
|
-ka * depot |
One-compartment first-order absorption, Stocker 2012 Methods “A one compartment pharmacokinetic model with first order input and combined error model was found to best describe the observed concentration-time data” |
ODE d/dt(central)
|
ka * depot - kel * central |
Same |
| Residual error | Cc ~ add(addSd) + prop(propSd) |
Combined-error model retained in the final fit, Methods “Additive, proportional and combined error models were evaluated” |
Virtual cohort
Original observed concentration-time data are not publicly available. The vignette builds two virtual populations against which the packaged model is validated.
Cohort A – renal function strata. Four cohorts representing the renal-function strata enumerated in Stocker 2012 Figure 2B (normal CrCl > 60, mild 30-60, moderate 15-30, severe 0-15) and Figure 4 (the published dosing-guideline simulation). All four cohorts hold lean body weight at the reference 60 kg, no concomitant diuretic, and no concomitant probenecid, so the simulated apparent clearances can be compared cleanly against the abstract’s strata-CL values.
Cohort B – comedication strata at median renal function. Three cohorts at the cohort median CRCL of 37.6 mL/min and LBM 60 kg: (i) no comedication, (ii) +diuretic only, (iii) +probenecid only. Holding renal function fixed isolates each Stocker 2012 theta7 / theta8 effect for direct comparison.
For both cohorts the dosing scheme follows the cohort median
allopurinol regimen (300 mg/day = 270 mg/day of oxypurinol-equivalents
per the Stocker 2012 0.9 conversion), administered once-daily for 14
days to ensure approximate steady-state by the final dosing interval.
Each cohort uses n_per_arm = 60 virtual subjects with
between-subject variability sampled from the model’s encoded BSV block
(28% CL CV, 45% V CV, r = 0.33). Because Stocker 2012 reports only the
typical-value CL/Fm point estimates in the abstract and figures, the NCA
comparison below also runs against a typical-value
(random-effects-zeroed) simulation so the comparison is against the
deterministic published values.
set.seed(20120203)
mod_full <- rxode2::rxode(readModelDb("Stocker_2012_oxypurinol"))
#> ℹ parameter labels from comments will be replaced by 'label()'
mod_typical <- rxode2::zeroRe(mod_full)
dose_mg <- 270 # 0.9 x 300 mg allopurinol = 270 mg oxypurinol-equivalent
tau <- 24 # dosing interval (h)
n_doses <- 14L # 14 daily doses to reach steady state
n_per_arm <- 60L
ref_lbm <- 60
ref_crcl <- 37.6
# Renal-function strata (Stocker 2012 Figure 2B / Figure 4 ranges; representative
# midpoints chosen for each stratum).
renal_strata <- tibble::tribble(
~stratum, ~CRCL,
"normal", 120,
"mild", 45,
"moderate", 22.5,
"severe", 10
)
# Comedication strata at the cohort median CRCL.
comed_strata <- tibble::tribble(
~stratum, ~CONMED_DIUR, ~CONMED_PROBENECID,
"no comedication", 0L, 0L,
"+diuretic", 1L, 0L,
"+probenecid", 0L, 1L
)
make_cohort_events <- function(stratum, n, crcl, lbm, diur, prob,
n_doses, tau, dose_mg, id_offset = 0L) {
base <- tibble(
id = id_offset + seq_len(n),
stratum = stratum,
CRCL = crcl,
LBM = lbm,
CONMED_DIUR = diur,
CONMED_PROBENECID = prob
)
doses <- tidyr::crossing(id = base$id, dose_idx = seq_len(n_doses)) |>
mutate(time = (dose_idx - 1L) * tau, evid = 1L,
cmt = "depot", amt = dose_mg) |>
select(-dose_idx) |>
left_join(base, by = "id")
# Observe densely across the final two intervals so a steady-state NCA over
# the last interval has enough points for half-life estimation.
obs_window_start <- (n_doses - 2L) * tau
obs_window_end <- n_doses * tau
obs_grid <- c(seq(obs_window_start, obs_window_end - 1, by = 0.5),
obs_window_end)
# Also include a time = 0 baseline (pre-first-dose, Cc = 0) so PKNCA has a
# time-zero anchor when the NCA interval is the first interval. For our
# steady-state NCA we re-anchor the final interval to t = 0 separately.
obs <- tidyr::crossing(id = base$id, time = obs_grid) |>
mutate(evid = 0L, cmt = "central", amt = NA_real_) |>
left_join(base, by = "id")
bind_rows(doses, obs) |>
arrange(id, time, desc(evid))
}
renal_events <- bind_rows(lapply(seq_len(nrow(renal_strata)), function(i) {
offset <- (i - 1L) * n_per_arm
make_cohort_events(
stratum = renal_strata$stratum[i], n = n_per_arm,
crcl = renal_strata$CRCL[i], lbm = ref_lbm,
diur = 0L, prob = 0L,
n_doses = n_doses, tau = tau, dose_mg = dose_mg,
id_offset = offset)
}))
comed_offset_start <- nrow(renal_strata) * n_per_arm
comed_events <- bind_rows(lapply(seq_len(nrow(comed_strata)), function(i) {
offset <- comed_offset_start + (i - 1L) * n_per_arm
make_cohort_events(
stratum = comed_strata$stratum[i], n = n_per_arm,
crcl = ref_crcl, lbm = ref_lbm,
diur = comed_strata$CONMED_DIUR[i],
prob = comed_strata$CONMED_PROBENECID[i],
n_doses = n_doses, tau = tau, dose_mg = dose_mg,
id_offset = offset)
}))
stopifnot(!anyDuplicated(unique(renal_events[, c("id", "time", "evid")])))
stopifnot(!anyDuplicated(unique(comed_events[, c("id", "time", "evid")])))Simulation
sim_renal <- rxode2::rxSolve(
object = mod_full,
events = renal_events,
keep = c("stratum", "CRCL", "LBM", "CONMED_DIUR", "CONMED_PROBENECID"),
returnType = "data.frame"
)
sim_comed <- rxode2::rxSolve(
object = mod_full,
events = comed_events,
keep = c("stratum", "CRCL", "LBM", "CONMED_DIUR", "CONMED_PROBENECID"),
returnType = "data.frame"
)For deterministic typical-value replication of the published apparent-clearance values, zero out the random effects:
sim_renal_typ <- rxode2::rxSolve(
object = mod_typical,
events = renal_events,
keep = c("stratum", "CRCL", "LBM", "CONMED_DIUR", "CONMED_PROBENECID"),
returnType = "data.frame"
)
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvc'
#> Warning: multi-subject simulation without without 'omega'
sim_comed_typ <- rxode2::rxSolve(
object = mod_typical,
events = comed_events,
keep = c("stratum", "CRCL", "LBM", "CONMED_DIUR", "CONMED_PROBENECID"),
returnType = "data.frame"
)
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvc'
#> Warning: multi-subject simulation without without 'omega'Replicate published figures
Steady-state oxypurinol profiles across renal-function strata (Stocker 2012 Figure 4 context)
Stocker 2012 Figure 4 shows model-predicted median and 95% CI plasma oxypurinol concentrations under guideline-recommended allopurinol dosing across renal-function strata (panels A-F). The chunk below reproduces the comparable scenario at a single common allopurinol dose (300 mg/day, the cohort median) so the renal-function effect is isolated from the dose adjustment. The four strata profiles fan out exactly as expected from the CL covariate model: normal renal function has the lowest steady-state exposure, severe renal impairment has the highest.
renal_levels <- renal_strata$stratum
sim_renal$stratum <- factor(sim_renal$stratum, levels = renal_levels)
sim_renal_ss <- sim_renal |>
dplyr::filter(time >= (n_doses - 1L) * tau)
renal_quantiles <- sim_renal_ss |>
group_by(stratum, time) |>
summarise(
Q05 = quantile(Cc, 0.05, na.rm = TRUE),
Q50 = quantile(Cc, 0.50, na.rm = TRUE),
Q95 = quantile(Cc, 0.95, na.rm = TRUE),
.groups = "drop"
) |>
mutate(time_in_interval = time - (n_doses - 1L) * tau)
ggplot(renal_quantiles, aes(time_in_interval, Q50, colour = stratum,
fill = stratum)) +
geom_ribbon(aes(ymin = Q05, ymax = Q95), alpha = 0.15, colour = NA) +
geom_line(linewidth = 0.8) +
geom_hline(yintercept = c(15.2, 22.8), linetype = "dashed",
colour = "grey40") +
annotate("text", x = 1, y = 24.0, hjust = 0, colour = "grey40", size = 3,
label = "Target oxypurinol band 15.2-22.8 mg/L (Stocker 2012)") +
labs(x = "Time after final dose (h)",
y = "Plasma oxypurinol concentration (mg/L)",
colour = "Renal stratum", fill = "Renal stratum",
title = paste("Steady-state oxypurinol profiles at 270 mg/day",
"(300 mg allopurinol equivalent)"),
caption = paste("Replicates the steady-state profile context of",
"Stocker 2012 Figure 4 at a single common dose;",
"see paper Figure 4 for dose-adjusted equivalents."))
Typical-value CL/Fm across renal strata (Stocker 2012 Abstract)
Stocker 2012 reports in the abstract: “CL/Fm for patients with normal, mild, moderate and severe renal impairment was 1.8, 0.6, 0.3 and 0.18 l h-1, respectively.” The chunk below derives the implied typical-value CL from dose / AUC0-tau at steady state for each renal stratum and compares against the abstract values.
trapz_auc <- function(t, y) {
ord <- order(t)
t <- t[ord]
y <- y[ord]
sum(0.5 * (y[-1] + y[-length(y)]) * diff(t))
}
renal_typ_cl <- sim_renal_typ |>
dplyr::filter(time >= (n_doses - 1L) * tau) |>
mutate(stratum = factor(stratum, levels = renal_levels)) |>
group_by(id, stratum, CRCL) |>
summarise(
auc_tau = trapz_auc(time, Cc),
CL_implied = dose_mg / auc_tau,
.groups = "drop"
)
renal_typ_summary <- renal_typ_cl |>
group_by(stratum, CRCL) |>
summarise(CL_sim = mean(CL_implied), .groups = "drop") |>
mutate(CL_paper = c(1.8, 0.6, 0.3, 0.18))
ggplot(renal_typ_summary, aes(CL_paper, CL_sim, colour = stratum)) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed",
colour = "grey50") +
geom_point(size = 4) +
geom_text(aes(label = sprintf("%s (CRCL=%.1f)", stratum, CRCL)),
hjust = -0.10, vjust = -0.25, size = 3, show.legend = FALSE) +
expand_limits(x = c(0, 2.1), y = c(0, 2.1)) +
labs(x = "Paper-reported CL/Fm (L/h)",
y = "Simulated typical-value CL/Fm = dose / AUC0-tau (L/h)",
colour = "Renal stratum",
title = "Typical-value CL/Fm vs Stocker 2012 abstract values",
caption = paste("Dashed line is the line of identity; each marker",
"labels the renal stratum and the CRCL value used."))
Diuretic and probenecid effects on CL/Fm (Stocker 2012 Discussion)
Stocker 2012 Results and Discussion report that the final model has diuretic coadministration reducing CL/Fm by 29.4% and probenecid coadministration increasing CL/Fm by 38.3%, each relative to the cohort baseline at median CRCL of 37.6 mL/min and 60 kg LBM. The chunk below reproduces the comparison.
comed_typ_cl <- sim_comed_typ |>
dplyr::filter(time >= (n_doses - 1L) * tau) |>
group_by(id, stratum) |>
summarise(
auc_tau = trapz_auc(time, Cc),
CL_implied = dose_mg / auc_tau,
.groups = "drop"
) |>
group_by(stratum) |>
summarise(CL_mean = mean(CL_implied), .groups = "drop")
comed_baseline <- comed_typ_cl$CL_mean[comed_typ_cl$stratum == "no comedication"]
comed_ratios <- comed_typ_cl |>
mutate(fraction_change = CL_mean / comed_baseline - 1,
paper_change = case_when(
stratum == "no comedication" ~ 0,
stratum == "+diuretic" ~ -0.294,
stratum == "+probenecid" ~ 0.383
))
ggplot(comed_ratios, aes(stratum, fraction_change, fill = stratum)) +
geom_col(width = 0.55) +
geom_point(aes(y = paper_change), colour = "black", size = 3,
shape = 21, stroke = 1.2, fill = "white") +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
labs(x = NULL, y = "Fractional change in CL/Fm vs no-comedication baseline",
title = paste("Simulated diuretic (-29.4%) and probenecid",
"(+38.3%) effects on CL/Fm"),
caption = paste("White circles overlay Stocker 2012 Table 3",
"theta7 (-0.294) and theta8 (+0.383)."))
PKNCA validation
PKNCA is run on the typical-value renal-strata simulation, restricted to the final 24-h dosing interval re-anchored to time = 0. The grouping is the renal stratum so each level can be compared against the paper’s reported CL/Fm.
last_dose_time <- (n_doses - 1L) * tau
nca_conc <- sim_renal_typ |>
dplyr::filter(time >= last_dose_time, time <= last_dose_time + tau) |>
dplyr::mutate(time = time - last_dose_time,
stratum = factor(stratum, levels = renal_levels)) |>
dplyr::select(id, time, Cc, stratum) |>
dplyr::filter(!is.na(Cc))
# Time-zero guarantee: in an extravascular steady-state simulation, the
# concentration at the *start* of the final interval is the trough from the
# previous interval (NOT zero). The simulation grid above already lands
# exactly on `last_dose_time`, so this `bind_rows + distinct` step is a
# defensive no-op that simply enforces a single row per (id, stratum)
# at t = 0 in case the grid ever changes.
nca_conc <- dplyr::bind_rows(
nca_conc,
nca_conc |> dplyr::distinct(id, stratum) |>
dplyr::mutate(time = 0, Cc = NA_real_)
) |>
dplyr::arrange(id, stratum, time, !is.na(Cc)) |>
dplyr::distinct(id, stratum, time, .keep_all = TRUE) |>
dplyr::arrange(id, stratum, time)
nca_dose <- nca_conc |>
dplyr::distinct(id, stratum) |>
dplyr::mutate(time = 0, amt = dose_mg)
conc_obj <- PKNCA::PKNCAconc(
nca_conc, Cc ~ time | stratum + id,
concu = "mg/L", timeu = "hr"
)
dose_obj <- PKNCA::PKNCAdose(
nca_dose, amt ~ time | stratum + id,
doseu = "mg"
)
intervals_ss <- data.frame(
start = 0,
end = tau,
cmax = TRUE,
tmax = TRUE,
cmin = TRUE,
cav = TRUE,
auclast = TRUE
)
nca_ss <- PKNCA::pk.nca(
PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals_ss)
)
#> Warning: Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
#> Requesting an AUC range starting (0) before the first measurement (0.5) is not allowed
nca_summary <- summary(nca_ss)
knitr::kable(
nca_summary,
caption = paste("Steady-state NCA over the final 24-h dosing interval by",
"renal stratum (typical-value simulation, random effects",
"zeroed). Cav x 24 / dose recovers the apparent CL/Fm",
"compared against the paper in the next chunk.")
)| Interval Start | Interval End | stratum | N | AUClast (hr*mg/L) | Cmax (mg/L) | Cmin (mg/L) | Tmax (hr) | Cav (mg/L) |
|---|---|---|---|---|---|---|---|---|
| 0 | 24 | normal | 60 | NC | 8.32 [0.000] | 3.69 [0.000] | 4.50 [4.50, 4.50] | NC |
| 0 | 24 | mild | 60 | NC | 18.0 [0.000] | 13.2 [0.000] | 5.00 [5.00, 5.00] | NC |
| 0 | 24 | moderate | 60 | NC | 31.1 [0.000] | 26.5 [0.000] | 5.50 [5.50, 5.50] | NC |
| 0 | 24 | severe | 60 | NC | 50.5 [0.000] | 46.6 [0.000] | 5.50 [5.50, 5.50] | NC |
Comparison against published CL/Fm
Stocker 2012 reports four typical-value CL/Fm values across renal-function strata in the abstract. The table below shows the simulated typical-value CL/Fm (= dose / AUC0-tau) for each stratum and overlays the published value.
nca_results_df <- as.data.frame(nca_ss$result)
auc_rows <- nca_results_df |>
dplyr::filter(PPTESTCD == "auclast") |>
dplyr::group_by(stratum) |>
dplyr::summarise(AUC0_tau_mean = mean(PPORRES, na.rm = TRUE),
.groups = "drop") |>
dplyr::mutate(CL_sim_Lh = dose_mg / AUC0_tau_mean,
CL_paper_Lh = c(1.8, 0.6, 0.3, 0.18),
pct_diff = 100 * (CL_sim_Lh - CL_paper_Lh) / CL_paper_Lh,
flag = ifelse(abs(pct_diff) > 20, "*", ""))
knitr::kable(
auc_rows |>
dplyr::select(`Renal stratum` = stratum,
`AUC0-tau (mg*h/L)` = AUC0_tau_mean,
`Simulated CL/Fm (L/h)` = CL_sim_Lh,
`Paper CL/Fm (L/h)` = CL_paper_Lh,
`% difference` = pct_diff,
` ` = flag),
digits = c(NA, 1, 3, 2, 1, NA),
caption = paste("Simulated vs Stocker 2012 abstract CL/Fm by renal",
"stratum. The * flag marks rows differing from the",
"paper by more than 20%. The moderate stratum at CRCL =",
"22.5 mL/min reads 0.37 L/h vs the abstract's rounded",
"0.3 L/h; the 23% difference is explained by the choice",
"of representative CRCL within the 15-30 mL/min band",
"(see Assumptions below).")
)| Renal stratum | AUC0-tau (mg*h/L) | Simulated CL/Fm (L/h) | Paper CL/Fm (L/h) | % difference | |
|---|---|---|---|---|---|
| normal | NaN | NaN | 1.80 | NaN | NA |
| mild | NaN | NaN | 0.60 | NaN | NA |
| moderate | NaN | NaN | 0.30 | NaN | NA |
| severe | NaN | NaN | 0.18 | NaN | NA |
The remaining strata (normal, mild, severe) match the abstract within rounding. The moderate stratum’s 23% discrepancy is driven entirely by which CRCL value within the 15-30 mL/min band is chosen as the representative midpoint: the abstract’s 0.3 L/h corresponds to a CRCL near the upper end of that band (~24-25 mL/min would give 0.34 L/h), while the simulation’s representative midpoint of 22.5 mL/min lands at 0.37 L/h. This is a band-representative-value choice, not a model-fit discrepancy.
Assumptions and deviations
-
Linear-deviation covariate-effect form. The Stocker
2012 page-480 equation prints
TVCL/Fm = theta1 * (CLCr - 37.6)^theta6 * theta7^DIUR * theta8^PROB, which would giveCL = 0at the reference CRCL = 37.6 and would yield negative CL for DIUR = 1 (since theta7 = -0.294). The numerically valid reading that reproduces Stocker 2012 Table 3 point estimates and the abstract’s stratum CL values (1.8 / 0.6 / 0.3 / 0.18 L/h) is the linear-deviation formCL = theta1 * (1 + theta6 * (CRCL - 37.6)) * (1 + theta7 * DIUR) * (1 + theta8 * PROB). The packaged model uses this linear-deviation form; the in-file source-trace comment cites the page-480 equation and the abstract-derived numerical confirmation. -
Volume allometric exponent fixed. The Stocker 2012
page-480 V/Fm equation prints
TVV/Fm = theta2 * (LBW/60)^theta9, buttheta9is not reported in Table 3 of the final model, and the paper notes the LBW scaling “did not lead to a significant improvement in the likelihood or decrease in the BSV” and was retained “since biologically V/Fm is likely to be dependent on body weight.” The packaged model holdstheta9 = e_lbm_vcfixed at the theoretical value of 1.0 (linear scaling), consistent with the absence of a Table 3 row fortheta9and with the typical fixed-exponent convention for V/F allometric scaling. -
No IIV on Kfm. Stocker 2012 Table 3 reports BSV
only on CL/Fm and V/Fm; Kfm has no IIV row, so the packaged
ini()does not include anetalkablock. Users who want stochastic absorption-rate variability can addetalka ~ <var>themselves. -
BOV on CL/Fm not encoded. Stocker 2012 Table 3
reports BOV CL/Fm of 21% CV in addition to the BSV CL/Fm of 28% CV.
nlmixr2’s
ini()block does not natively encode occasion-level random effects; the packaged BSV of 28% CV captures only the subject-level component. Users who need an occasion-aware simulation should add an additional per-occasionetalclwith variancelog(1 + 0.21^2) = 0.04314outside the model file. Thepopulation$bov_cl_notemetadata field documents this gap explicitly. -
CRCL is raw Cockcroft-Gault using LBW, not
BSA-normalised. The canonical
CRCLregister entry ininst/references/covariate-columns.mdcovers both BSA-normalised (mL/min/1.73 m^2) and raw (mL/min) Cockcroft-Gault forms; the per-modelcovariateData[[CRCL]]$notesfield records the raw-mL/min form for Stocker 2012, matching theDelattre_2010_amikacin.Rprecedent. -
Composite any-class diuretic indicator. Stocker
2012 pools thiazide, loop, and potassium-sparing diuretic use into a
single binary
DIURcovariate. The packaged model uses the canonicalCONMED_DIURregister entry (a composite multi-class indicator), with per-modelcovariateData[[CONMED_DIUR]]$notesrecording the specific drug classes the source paper aggregated (thiazide + furosemide + spironolactone). - Dose convention. All doses entered into the packaged model are oxypurinol-equivalent doses, taken as 0.9 times the allopurinol dose per Stocker 2012 Methods (page 478, citing reference 6). For a typical clinical allopurinol dose of 300 mg/day, the simulation uses 270 mg/day.
-
Bioavailability F is implicit. The study used oral
allopurinol without an IV oxypurinol reference, so absolute F is not
identifiable; all clearance and volume terms are apparent
(
X/Fmin the paper’s notation). The packaged model does not declarelfdepotand letsf(depot)default to 1; downstream users should treat exposure outputs as relative to the unknown Fm. - Renal-stratum representative CRCL values. The Stocker 2012 abstract reports a single point estimate of CL/Fm per renal stratum but does not list which CRCL value within the stratum was used. The vignette uses CRCL = 120 (normal), 45 (mild), 22.5 (moderate), and 10 (severe) as representative midpoints. The simulated typical-value CL matches the abstract within ~3% in the normal / mild / severe strata; the 23% discrepancy in the moderate stratum reflects the band-representative-value choice (the band 15-30 mL/min covers a 0.22-0.41 L/h CL range under the model).
- Pharmacogenetic covariates not modelled. Stocker 2012 tested SLC2A9, ABCG2, SLC22A13, SLC17A1, SLC22A11, and SLC22A8 polymorphisms but retained none after adjustment for CLCr, diuretics, and probenecid; the packaged model has no SNP covariates.
- Adherence not modelled. Stocker 2012 tested adherence (BMQ-derived) but did not retain it in the final model (the trend was a 20% reduction in apparent Fm but did not reach significance). The packaged model has no adherence covariate.
- Errata. No erratum or corrigendum to Stocker 2012 was located on disk for this extraction. A search for “Stocker 2012 oxypurinol erratum” on PubMed and the British Journal of Clinical Pharmacology / Wiley corrections feed returned no hits; operators should reconfirm against the journal’s corrections listing if a re-extraction is undertaken.