Model and source
- Citation: Smit C, Goulooze SC, Bruggemann RJM, Sherwin CM, Knibbe CAJ. Dosing Recommendations for Vancomycin in Children and Adolescents with Varying Levels of Obesity and Renal Dysfunction: a Population Pharmacokinetic Study in 1892 Children Aged 1-18 Years. AAPS J. 2021;23(3):53. doi:10.1208/s12248-021-00577-x
- Description: Two-compartment IV population PK model for vancomycin in normal-weight, overweight and obese children and adolescents aged 1-18 years with a wide range of renal function (Smit 2021). Clearance scales as a power function of total body weight (estimated exponent 0.745, reference 22.1 kg) and linearly with bedside-Schwartz creatinine clearance capped at 120 mL/min/1.73 m^2 (reference 100 mL/min/1.73 m^2); central and peripheral volumes scale linearly with total body weight and intercompartmental clearance as a power function of total body weight (exponent 0.599). Residual variability is additive on log-transformed concentrations.
- Article: https://doi.org/10.1208/s12248-021-00577-x
- Supplement (methods, results, NONMEM control stream of the final model): Online Resource 1 at the article landing page.
Smit 2021 is a retrospective multicenter population PK analysis of intravenous vancomycin in 1892 children and adolescents aged 1-18 years, 548 of whom were overweight or obese, with renal function spanning a bedside Schwartz creatinine clearance of 8.6 to over 900 mL/min/1.73 m^2. The final two-compartment model (Table II) drives clearance by total body weight (power function, estimated exponent 0.745) and by bedside Schwartz CLcr (linear, capped at 120 mL/min/1.73 m^2). The paper then uses the typical-value model to derive a weight- and renal-function-based dosing guideline (Table III) and demonstrates it on six typical individuals (Figure 4). This vignette reproduces Figure 4 numerically from the packaged model.
Population
The analysis used routine therapeutic-drug-monitoring data from 21 Intermountain Healthcare hospitals in Utah, USA, collected between 2006 and 2012 (Smit 2021 Methods; Table I). Of 1924 eligible patients, 26 on renal replacement therapy or ECMO and 6 without a recorded body weight were excluded, leaving 1892 patients and 5524 serum concentrations: 1344 normal weight, 247 overweight and 301 obese (BMI-for-age above the 85th and 95th percentile of the WHO (1-2 years) or CDC (2-18 years) charts). Median age was about 7 years in each weight group (range 1-18); median total body weight was 20.6, 25.0 and 30.0 kg in the three groups (overall range 5.8-188 kg). About 56% were male and 88% Caucasian; 35% were admitted to intensive care and about 17% were neutropenic. Median bedside Schwartz CLcr was 111.7-121.2 mL/min/1.73 m^2 across weight groups; only 12 patients were below 30 mL/min/1.73 m^2. Vancomycin was generally dosed at 15-20 mg/kg two to four times daily as 60-min infusions.
The same information is available programmatically via the model’s
population metadata
(readModelDb("Smit_2021_vancomycin")()$population).
Source trace
Per-parameter origin is recorded as an in-file comment next to each
ini() entry in
inst/modeldb/specificDrugs/Smit_2021_vancomycin.R. The
table below collects them in one place.
| Equation / parameter | Value | Source location |
|---|---|---|
lcl (CL at 22.1 kg, CLcr 100) |
2.12 L/h (RSE 1%) | Table II, TVCL |
lvc (V1 at 22.1 kg) |
8.90 L (RSE 3%) | Table II, TVV1 |
lq (Q at 22.1 kg) |
1.55 L/h (RSE 5%) | Table II, TVQ (the table prints the unit as “L”; Q is a clearance, L/h) |
lvp (V2 at 22.1 kg) |
12.3 L (RSE 6%) | Table II, TVV2 |
e_wt_cl |
0.745 (RSE 2%) | Table II, theta1 |
e_wt_q |
0.599 (RSE 9%) | Table II, theta2 |
e_wt_vc_vp |
1, fixed | Table II equations TVV1 x (TBW/22.1),
TVV2 x (TBW/22.1); supplement control stream
THETA(7) = (1) FIX
|
e_crcl_cl |
1, fixed | Table II equation
TVCL x (TBW/22.1)^theta1 x (SCHW/100); supplement control
stream THETA(5) = (1) FIX
|
| CLcr cap | 120 mL/min/1.73 m^2 | Table II footnote a; control stream
IF(SCHW.GT.120) SCHW_MAX=120
|
etalcl |
log(1 + 0.287^2) = 0.0792 | Table II, IIV CL 28.7%; footnote c defines CV = sqrt(exp(omega^2) - 1) |
etalvp |
log(1 + 1.10^2) = 0.793 | Table II, IIV V2 110% |
cov(etalcl, etalvp) |
-0.085 | Table II, covariance IIV CL-V2 |
expSd |
sqrt(0.0789) = 0.281 | Table II, proportional error 0.0789 (read as the log-domain variance; see Assumptions) |
| Two-compartment ODE | n/a | Supplement control stream
$SUBROUTINE ADVAN3 TRANS4
|
| Residual model | n/a | Supplement control stream $ERROR:
Y = LOG(F) + ERR(1) on log-transformed DV |
Replicate Figure 4: the proposed dosing guideline in six typical individuals
Figure 4 of Smit 2021 simulates the Table III dosing guideline in six typical individuals from the dataset (1 year / 11 kg, 9 years / 46 kg, 12 years / 25 kg, 13 years / 78 kg, 16 years / 63 kg and 17 years / 118 kg), each at four bedside Schwartz CLcr values (10, 40, 70 and 120 mL/min/1.73 m^2), without between-subject or residual variability. Each panel prints AUCday3 (AUC from 48 to 72 h), Cmin at day 3 and AUCday1 (AUC from 0 to 24 h). Age does not enter the model; only weight and CLcr do.
Table III maps weight and CLcr to a regimen:
| CLcr (mL/min/1.73 m^2) | TBW < 30 kg | TBW 30-70 kg | TBW > 70 kg |
|---|---|---|---|
| > 90 | 15 mg/kg q6h | 15 mg/kg q8h | 18 mg/kg q12h |
| 50-90 | 11 mg/kg q6h (a) | 11 mg/kg q8h (a) | 12 mg/kg q12h (a) |
| 30-50 | 5 mg/kg q6h (a) | 5 mg/kg q8h (a) | 6 mg/kg q12h (a) |
| 10-30 | 5 mg/kg q12h (a) | 3 mg/kg q12h (a) | 3 mg/kg q12h (a) |
- First dose is 15 mg/kg.
fig4_individuals <- tibble::tribble(
~individual, ~WT,
"1 year - 11 kg - normal weight", 11,
"9 year - 46 kg - morbidly obese", 46,
"12 year - 25 kg - normal weight", 25,
"13 year - 78 kg - morbidly obese", 78,
"16 year - 63 kg - normal weight", 63,
"17 year - 118 kg - morbidly obese", 118
)
# Table III: maintenance dose (mg/kg) and interval (h) by CLcr row and weight column.
table3 <- tibble::tribble(
~CRCL, ~wt_band, ~dose_mgkg, ~tau, ~footnote_a,
120, "<30", 15, 6, FALSE,
120, "30-70", 15, 8, FALSE,
120, ">70", 18, 12, FALSE,
70, "<30", 11, 6, TRUE,
70, "30-70", 11, 8, TRUE,
70, ">70", 12, 12, TRUE,
40, "<30", 5, 6, TRUE,
40, "30-70", 5, 8, TRUE,
40, ">70", 6, 12, TRUE,
10, "<30", 5, 12, TRUE,
10, "30-70", 3, 12, TRUE,
10, ">70", 3, 12, TRUE
)
fig4_scenarios <- tidyr::crossing(fig4_individuals, CRCL = c(10, 40, 70, 120)) |>
dplyr::mutate(wt_band = dplyr::case_when(WT < 30 ~ "<30", WT <= 70 ~ "30-70", TRUE ~ ">70")) |>
dplyr::left_join(table3, by = c("CRCL", "wt_band")) |>
dplyr::mutate(
id = dplyr::row_number(),
scenario = paste0(individual, " | CLcr ", CRCL),
# Footnote (a) rows start with 15 mg/kg; the > 90 row has no footnote, so
# its first dose is the maintenance dose.
first_mgkg = ifelse(footnote_a, 15, dose_mgkg)
)
knitr::kable(
fig4_scenarios |>
dplyr::select(individual, WT, CRCL, first_mgkg, dose_mgkg, tau) |>
dplyr::rename(
"Individual" = individual, "TBW (kg)" = WT, "CLcr" = CRCL,
"First dose (mg/kg)" = first_mgkg, "Maintenance (mg/kg)" = dose_mgkg,
"Interval (h)" = tau
),
caption = "The 24 Figure 4 scenarios and their Table III regimens."
)| Individual | TBW (kg) | CLcr | First dose (mg/kg) | Maintenance (mg/kg) | Interval (h) |
|---|---|---|---|---|---|
| 1 year - 11 kg - normal weight | 11 | 10 | 15 | 5 | 12 |
| 1 year - 11 kg - normal weight | 11 | 40 | 15 | 5 | 6 |
| 1 year - 11 kg - normal weight | 11 | 70 | 15 | 11 | 6 |
| 1 year - 11 kg - normal weight | 11 | 120 | 15 | 15 | 6 |
| 12 year - 25 kg - normal weight | 25 | 10 | 15 | 5 | 12 |
| 12 year - 25 kg - normal weight | 25 | 40 | 15 | 5 | 6 |
| 12 year - 25 kg - normal weight | 25 | 70 | 15 | 11 | 6 |
| 12 year - 25 kg - normal weight | 25 | 120 | 15 | 15 | 6 |
| 13 year - 78 kg - morbidly obese | 78 | 10 | 15 | 3 | 12 |
| 13 year - 78 kg - morbidly obese | 78 | 40 | 15 | 6 | 12 |
| 13 year - 78 kg - morbidly obese | 78 | 70 | 15 | 12 | 12 |
| 13 year - 78 kg - morbidly obese | 78 | 120 | 18 | 18 | 12 |
| 16 year - 63 kg - normal weight | 63 | 10 | 15 | 3 | 12 |
| 16 year - 63 kg - normal weight | 63 | 40 | 15 | 5 | 8 |
| 16 year - 63 kg - normal weight | 63 | 70 | 15 | 11 | 8 |
| 16 year - 63 kg - normal weight | 63 | 120 | 15 | 15 | 8 |
| 17 year - 118 kg - morbidly obese | 118 | 10 | 15 | 3 | 12 |
| 17 year - 118 kg - morbidly obese | 118 | 40 | 15 | 6 | 12 |
| 17 year - 118 kg - morbidly obese | 118 | 70 | 15 | 12 | 12 |
| 17 year - 118 kg - morbidly obese | 118 | 120 | 18 | 18 | 12 |
| 9 year - 46 kg - morbidly obese | 46 | 10 | 15 | 3 | 12 |
| 9 year - 46 kg - morbidly obese | 46 | 40 | 15 | 5 | 8 |
| 9 year - 46 kg - morbidly obese | 46 | 70 | 15 | 11 | 8 |
| 9 year - 46 kg - morbidly obese | 46 | 120 | 15 | 15 | 8 |
Doses are infused at 10 mg/min (600 mg/h) with a minimum duration of
1 h: a dose up to 600 mg runs over 60 min, a larger dose over
amt / 600 hours (see Assumptions for why).
obs_times <- round(seq(0, 96, by = 0.05), 2)
build_fig4_events <- function(sc) {
dose_times <- seq(0, 95.99, by = sc$tau)
amts <- c(sc$first_mgkg, rep(sc$dose_mgkg, length(dose_times) - 1)) * sc$WT
doses <- tibble::tibble(
id = sc$id, time = dose_times, amt = amts, rate = pmin(amts, 600),
evid = 1L, cmt = "central"
)
obs <- tibble::tibble(
id = sc$id, time = obs_times, amt = 0, rate = 0, evid = 0L, cmt = "central"
)
dplyr::bind_rows(doses, obs) |>
dplyr::mutate(WT = sc$WT, CRCL = sc$CRCL, scenario = sc$scenario)
}
fig4_events <- lapply(split(fig4_scenarios, fig4_scenarios$id), build_fig4_events) |>
dplyr::bind_rows() |>
dplyr::arrange(id, time, dplyr::desc(evid))
stopifnot(!anyDuplicated(fig4_events[, c("id", "time", "evid")]))
mod <- readModelDb("Smit_2021_vancomycin")
mod_typical <- mod |> rxode2::zeroRe()
#> ℹ parameter labels from comments will be replaced by 'label()'
sim_fig4 <- rxode2::rxSolve(
mod_typical,
events = fig4_events,
keep = c("scenario", "WT", "CRCL")
) |>
as.data.frame() |>
dplyr::left_join(
fig4_scenarios |> dplyr::select(id, individual, tau),
by = "id"
)
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvp'
#> Warning: multi-subject simulation without without 'omega'(The left_join above attaches one row of per-scenario
metadata per id; the id values are unique per
scenario, so it cannot fan out rows.)
ggplot(sim_fig4, aes(time, Cc, colour = factor(CRCL))) +
geom_line() +
geom_hline(yintercept = c(10, 15), linetype = "dashed") +
facet_wrap(~individual, ncol = 3) +
scale_x_continuous(breaks = seq(0, 96, 24)) +
scale_colour_manual(
values = c(`10` = "#D7191C", `40` = "#FDAE61", `70` = "#A6D96A", `120` = "#2C7BB6")
) +
labs(
x = "Time (h)", y = "Vancomycin concentration (mg/L)",
colour = "CLcr (Schwartz)\n(mL/min/1.73 m^2)",
title = "Figure 4 - Table III dosing guideline in six typical individuals",
caption = "Replicates Figure 4 of Smit 2021 (typical values, no variability)."
) +
theme_bw()
PKNCA validation against the Figure 4 labels
PKNCA computes AUCday1 (0-24 h) and AUCday3 (48-72 h) on each
typical-value profile. The Figure 4 Cmin at day 3 matches the first
trough after the 48 h dose (the minimum over the day-3 window once the
trough at 48 h itself is excluded), so it is computed as the PKNCA
cmin over 49-72 h: every dose infuses for at least 1 h and
troughs rise through day 3, so that minimum is the trough at 48 h +
tau.
nca_conc <- sim_fig4 |>
dplyr::filter(!is.na(Cc)) |>
dplyr::select(id, scenario, time, Cc)
nca_dose <- fig4_events |>
dplyr::filter(evid == 1) |>
dplyr::select(id, scenario, time, amt)
conc_obj <- PKNCA::PKNCAconc(nca_conc, Cc ~ time | scenario + id)
dose_obj <- PKNCA::PKNCAdose(nca_dose, amt ~ time | scenario + id)
intervals <- data.frame(
start = c(0, 48, 49),
end = c(24, 72, 72),
auclast = c(TRUE, TRUE, FALSE),
cmin = c(FALSE, FALSE, TRUE)
)
nca_res <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals))
nca_wide <- as.data.frame(nca_res) |>
dplyr::mutate(param = dplyr::case_when(
PPTESTCD == "auclast" & start == 0 ~ "auc_day1",
PPTESTCD == "auclast" & start == 48 ~ "auc_day3",
PPTESTCD == "cmin" ~ "cmin_day3"
)) |>
dplyr::select(scenario, param, PPORRES) |>
tidyr::pivot_wider(names_from = param, values_from = PPORRES)The published values below were transcribed by the maintainers from the text labels printed inside each Figure 4 panel (red = CLcr 10, orange = 40, green = 70, blue = 120 mL/min/1.73 m^2).
published_fig4 <- tibble::tribble(
~individual, ~CRCL, ~auc_day3, ~cmin_day3, ~auc_day1,
"1 year - 11 kg - normal weight", 10, 593.45, 21.2, 420.88,
"1 year - 11 kg - normal weight", 40, 422.52, 13.7, 373.65,
"1 year - 11 kg - normal weight", 70, 541.09, 14.7, 415.70,
"1 year - 11 kg - normal weight", 120, 435.02, 8.9, 355.16,
"9 year - 46 kg - morbidly obese", 10, 496.28, 18.1, 448.20,
"9 year - 46 kg - morbidly obese", 40, 435.67, 13.8, 398.87,
"9 year - 46 kg - morbidly obese", 70, 565.90, 14.9, 425.38,
"9 year - 46 kg - morbidly obese", 120, 463.76, 9.2, 363.41,
"12 year - 25 kg - normal weight", 10, 646.89, 23.0, 453.24,
"12 year - 25 kg - normal weight", 40, 503.07, 16.6, 420.30,
"12 year - 25 kg - normal weight", 70, 655.77, 18.6, 478.97,
"12 year - 25 kg - normal weight", 120, 533.20, 11.8, 418.58,
"13 year - 78 kg - morbidly obese", 10, 521.67, 19.1, 469.74,
"13 year - 78 kg - morbidly obese", 40, 393.37, 11.6, 377.29,
"13 year - 78 kg - morbidly obese", 70, 463.61, 10.9, 356.34,
"13 year - 78 kg - morbidly obese", 120, 420.97, 7.2, 334.17,
"16 year - 63 kg - normal weight", 10, 511.40, 18.7, 460.97,
"16 year - 63 kg - normal weight", 40, 463.01, 14.8, 417.03,
"16 year - 63 kg - normal weight", 70, 605.87, 16.4, 448.31,
"16 year - 63 kg - normal weight", 120, 499.53, 10.5, 385.51,
"17 year - 118 kg - morbidly obese", 10, 541.76, 19.8, 486.35,
"17 year - 118 kg - morbidly obese", 40, 424.72, 12.7, 399.07,
"17 year - 118 kg - morbidly obese", 70, 505.23, 12.5, 380.20,
"17 year - 118 kg - morbidly obese", 120, 462.88, 8.8, 360.13
) |>
dplyr::mutate(scenario = paste0(individual, " | CLcr ", CRCL)) |>
dplyr::select(scenario, auc_day3, cmin_day3, auc_day1)
stopifnot(nrow(published_fig4) == 24, setequal(published_fig4$scenario, nca_wide$scenario))
cmp <- nlmixr2lib::ncaComparisonTable(
simulated = nca_wide,
reference = published_fig4,
by = "scenario",
params = c("auc_day3", "cmin_day3", "auc_day1"),
units = c(auc_day3 = "mg*h/L", cmin_day3 = "mg/L", auc_day1 = "mg*h/L"),
tolerance_pct = 20
)
#> Warning: ncaParamLabel(): unknown PKNCA code(s) returned as-is: 'auc_day3',
#> 'cmin_day3', 'auc_day1'
knitr::kable(
cmp,
caption = "Simulated (PKNCA) vs. published Figure 4 values. * differs from the reference by >20%."
)| NCA parameter | scenario | Reference | Simulated | % diff |
|---|---|---|---|---|
| auc_day1 (mg*h/L) | 1 year - 11 kg - normal weight | CLcr 10 | 421 | 421 | +0.0% |
| auc_day1 (mg*h/L) | 1 year - 11 kg - normal weight | CLcr 40 | 374 | 374 | +0.0% |
| auc_day1 (mg*h/L) | 1 year - 11 kg - normal weight | CLcr 70 | 416 | 416 | +0.0% |
| auc_day1 (mg*h/L) | 1 year - 11 kg - normal weight | CLcr 120 | 355 | 355 | +0.0% |
| auc_day1 (mg*h/L) | 9 year - 46 kg - morbidly obese | CLcr 10 | 448 | 448 | +0.0% |
| auc_day1 (mg*h/L) | 9 year - 46 kg - morbidly obese | CLcr 40 | 399 | 399 | +0.0% |
| auc_day1 (mg*h/L) | 9 year - 46 kg - morbidly obese | CLcr 70 | 425 | 425 | +0.0% |
| auc_day1 (mg*h/L) | 9 year - 46 kg - morbidly obese | CLcr 120 | 363 | 363 | +0.0% |
| auc_day1 (mg*h/L) | 12 year - 25 kg - normal weight | CLcr 10 | 453 | 453 | +0.0% |
| auc_day1 (mg*h/L) | 12 year - 25 kg - normal weight | CLcr 40 | 420 | 420 | +0.0% |
| auc_day1 (mg*h/L) | 12 year - 25 kg - normal weight | CLcr 70 | 479 | 479 | +0.0% |
| auc_day1 (mg*h/L) | 12 year - 25 kg - normal weight | CLcr 120 | 419 | 419 | +0.0% |
| auc_day1 (mg*h/L) | 13 year - 78 kg - morbidly obese | CLcr 10 | 470 | 470 | +0.0% |
| auc_day1 (mg*h/L) | 13 year - 78 kg - morbidly obese | CLcr 40 | 377 | 377 | +0.0% |
| auc_day1 (mg*h/L) | 13 year - 78 kg - morbidly obese | CLcr 70 | 356 | 356 | +0.0% |
| auc_day1 (mg*h/L) | 13 year - 78 kg - morbidly obese | CLcr 120 | 334 | 334 | +0.0% |
| auc_day1 (mg*h/L) | 16 year - 63 kg - normal weight | CLcr 10 | 461 | 461 | +0.0% |
| auc_day1 (mg*h/L) | 16 year - 63 kg - normal weight | CLcr 40 | 417 | 417 | +0.0% |
| auc_day1 (mg*h/L) | 16 year - 63 kg - normal weight | CLcr 70 | 448 | 448 | +0.0% |
| auc_day1 (mg*h/L) | 16 year - 63 kg - normal weight | CLcr 120 | 386 | 386 | +0.0% |
| auc_day1 (mg*h/L) | 17 year - 118 kg - morbidly obese | CLcr 10 | 486 | 486 | +0.0% |
| auc_day1 (mg*h/L) | 17 year - 118 kg - morbidly obese | CLcr 40 | 399 | 399 | +0.0% |
| auc_day1 (mg*h/L) | 17 year - 118 kg - morbidly obese | CLcr 70 | 380 | 380 | +0.0% |
| auc_day1 (mg*h/L) | 17 year - 118 kg - morbidly obese | CLcr 120 | 360 | 360 | +0.0% |
| auc_day3 (mg*h/L) | 1 year - 11 kg - normal weight | CLcr 10 | 593 | 594 | +0.0% |
| auc_day3 (mg*h/L) | 1 year - 11 kg - normal weight | CLcr 40 | 423 | 423 | +0.0% |
| auc_day3 (mg*h/L) | 1 year - 11 kg - normal weight | CLcr 70 | 541 | 541 | +0.0% |
| auc_day3 (mg*h/L) | 1 year - 11 kg - normal weight | CLcr 120 | 435 | 435 | +0.0% |
| auc_day3 (mg*h/L) | 9 year - 46 kg - morbidly obese | CLcr 10 | 496 | 496 | +0.0% |
| auc_day3 (mg*h/L) | 9 year - 46 kg - morbidly obese | CLcr 40 | 436 | 436 | +0.0% |
| auc_day3 (mg*h/L) | 9 year - 46 kg - morbidly obese | CLcr 70 | 566 | 566 | +0.0% |
| auc_day3 (mg*h/L) | 9 year - 46 kg - morbidly obese | CLcr 120 | 464 | 464 | +0.0% |
| auc_day3 (mg*h/L) | 12 year - 25 kg - normal weight | CLcr 10 | 647 | 647 | +0.0% |
| auc_day3 (mg*h/L) | 12 year - 25 kg - normal weight | CLcr 40 | 503 | 503 | +0.0% |
| auc_day3 (mg*h/L) | 12 year - 25 kg - normal weight | CLcr 70 | 656 | 656 | +0.0% |
| auc_day3 (mg*h/L) | 12 year - 25 kg - normal weight | CLcr 120 | 533 | 533 | +0.0% |
| auc_day3 (mg*h/L) | 13 year - 78 kg - morbidly obese | CLcr 10 | 522 | 522 | +0.0% |
| auc_day3 (mg*h/L) | 13 year - 78 kg - morbidly obese | CLcr 40 | 393 | 393 | +0.0% |
| auc_day3 (mg*h/L) | 13 year - 78 kg - morbidly obese | CLcr 70 | 464 | 464 | +0.0% |
| auc_day3 (mg*h/L) | 13 year - 78 kg - morbidly obese | CLcr 120 | 421 | 421 | +0.0% |
| auc_day3 (mg*h/L) | 16 year - 63 kg - normal weight | CLcr 10 | 511 | 512 | +0.0% |
| auc_day3 (mg*h/L) | 16 year - 63 kg - normal weight | CLcr 40 | 463 | 463 | +0.0% |
| auc_day3 (mg*h/L) | 16 year - 63 kg - normal weight | CLcr 70 | 606 | 606 | +0.0% |
| auc_day3 (mg*h/L) | 16 year - 63 kg - normal weight | CLcr 120 | 500 | 500 | +0.0% |
| auc_day3 (mg*h/L) | 17 year - 118 kg - morbidly obese | CLcr 10 | 542 | 542 | +0.0% |
| auc_day3 (mg*h/L) | 17 year - 118 kg - morbidly obese | CLcr 40 | 425 | 425 | +0.0% |
| auc_day3 (mg*h/L) | 17 year - 118 kg - morbidly obese | CLcr 70 | 505 | 505 | +0.0% |
| auc_day3 (mg*h/L) | 17 year - 118 kg - morbidly obese | CLcr 120 | 463 | 463 | +0.0% |
| cmin_day3 (mg/L) | 1 year - 11 kg - normal weight | CLcr 10 | 21.2 | 21.1 | -0.2% |
| cmin_day3 (mg/L) | 1 year - 11 kg - normal weight | CLcr 40 | 13.7 | 13.6 | -0.7% |
| cmin_day3 (mg/L) | 1 year - 11 kg - normal weight | CLcr 70 | 14.7 | 14.6 | -0.7% |
| cmin_day3 (mg/L) | 1 year - 11 kg - normal weight | CLcr 120 | 8.9 | 8.79 | -1.2% |
| cmin_day3 (mg/L) | 9 year - 46 kg - morbidly obese | CLcr 10 | 18.1 | 18.1 | +0.1% |
| cmin_day3 (mg/L) | 9 year - 46 kg - morbidly obese | CLcr 40 | 13.8 | 13.8 | -0.2% |
| cmin_day3 (mg/L) | 9 year - 46 kg - morbidly obese | CLcr 70 | 14.9 | 14.8 | -0.5% |
| cmin_day3 (mg/L) | 9 year - 46 kg - morbidly obese | CLcr 120 | 9.2 | 9.11 | -1.0% |
| cmin_day3 (mg/L) | 12 year - 25 kg - normal weight | CLcr 10 | 23 | 23 | -0.1% |
| cmin_day3 (mg/L) | 12 year - 25 kg - normal weight | CLcr 40 | 16.6 | 16.5 | -0.5% |
| cmin_day3 (mg/L) | 12 year - 25 kg - normal weight | CLcr 70 | 18.6 | 18.5 | -0.8% |
| cmin_day3 (mg/L) | 12 year - 25 kg - normal weight | CLcr 120 | 11.8 | 11.6 | -1.5% |
| cmin_day3 (mg/L) | 13 year - 78 kg - morbidly obese | CLcr 10 | 19.1 | 19 | -0.3% |
| cmin_day3 (mg/L) | 13 year - 78 kg - morbidly obese | CLcr 40 | 11.6 | 11.5 | -0.6% |
| cmin_day3 (mg/L) | 13 year - 78 kg - morbidly obese | CLcr 70 | 10.9 | 10.8 | -0.8% |
| cmin_day3 (mg/L) | 13 year - 78 kg - morbidly obese | CLcr 120 | 7.2 | 7.1 | -1.4% |
| cmin_day3 (mg/L) | 16 year - 63 kg - normal weight | CLcr 10 | 18.7 | 18.7 | -0.2% |
| cmin_day3 (mg/L) | 16 year - 63 kg - normal weight | CLcr 40 | 14.8 | 14.8 | -0.2% |
| cmin_day3 (mg/L) | 16 year - 63 kg - normal weight | CLcr 70 | 16.4 | 16.3 | -0.9% |
| cmin_day3 (mg/L) | 16 year - 63 kg - normal weight | CLcr 120 | 10.5 | 10.4 | -0.8% |
| cmin_day3 (mg/L) | 17 year - 118 kg - morbidly obese | CLcr 10 | 19.8 | 19.8 | -0.1% |
| cmin_day3 (mg/L) | 17 year - 118 kg - morbidly obese | CLcr 40 | 12.7 | 12.7 | -0.3% |
| cmin_day3 (mg/L) | 17 year - 118 kg - morbidly obese | CLcr 70 | 12.5 | 12.4 | -0.6% |
| cmin_day3 (mg/L) | 17 year - 118 kg - morbidly obese | CLcr 120 | 8.8 | 8.66 | -1.5% |
chk <- dplyr::inner_join(nca_wide, published_fig4, by = "scenario", suffix = c("_sim", "_pub")) |>
dplyr::mutate(
d_auc_day3 = 100 * (auc_day3_sim / auc_day3_pub - 1),
d_auc_day1 = 100 * (auc_day1_sim / auc_day1_pub - 1),
d_cmin_day3 = 100 * (cmin_day3_sim / cmin_day3_pub - 1)
)
summary(chk[, c("d_auc_day3", "d_auc_day1", "d_cmin_day3")])
#> d_auc_day3 d_auc_day1 d_cmin_day3
#> Min. :0.009066 Min. :0.008505 Min. :-1.54676
#> 1st Qu.:0.015452 1st Qu.:0.014761 1st Qu.:-0.83777
#> Median :0.019324 Median :0.019198 Median :-0.61125
#> Mean :0.019514 Mean :0.018163 Mean :-0.63213
#> 3rd Qu.:0.024072 3rd Qu.:0.022356 3rd Qu.:-0.24545
#> Max. :0.027814 Max. :0.024565 Max. : 0.08824
# A deterministic typical-value solve compared against the paper's own
# deterministic typical-value simulation, so tight all() bounds are correct.
# Measured on the final files: every AUC within 0.1%, every Cmin within about
# -1.5% to +0.1% (the published Cmin sits consistently a little above the exact
# trough, as expected if it was read off a discrete output grid).
stopifnot(
nrow(chk) == 24,
all(abs(chk$d_auc_day3) < 1),
all(abs(chk$d_auc_day1) < 1),
all(abs(chk$d_cmin_day3) < 3),
# The paper's summary: all AUCday3 within the 400-700 mg*h/L target, and
# day-3 troughs spanning 7.2-23 mg/L.
all(chk$auc_day3_sim > 390 & chk$auc_day3_sim < 700),
abs(min(chk$cmin_day3_sim) - 7.2) < 0.3,
abs(max(chk$cmin_day3_sim) - 23) < 0.5
)All 72 Figure 4 labels are reproduced: both AUC columns to within 0.1% and Cmin to within about 2%. One published AUCday3 (13 years / 78 kg / CLcr 40: 393.37 mgh/L) is just below the 400 mgh/L lower target despite the paper’s statement that every individual is within target; the simulation agrees with the printed 393.
Why the regimen details matter
The Figure 4 AUCday1 values discriminate two details of the regimen that the paper states only in the table footnotes and not in the Methods. A 60-min infusion for every dose and a 15 mg/kg first dose for every row gives the AUCday3 values unchanged but misses AUCday1 by up to 8% in the heavier individuals:
naive_events <- fig4_events |>
dplyr::left_join(fig4_scenarios |> dplyr::select(id, dose_mgkg, tau), by = "id") |>
dplyr::mutate(
amt = dplyr::case_when(
evid == 1 & time == 0 ~ 15 * WT,
TRUE ~ amt
),
rate = ifelse(evid == 1, amt, 0)
) |>
dplyr::select(-dose_mgkg, -tau)
sim_naive <- rxode2::rxSolve(mod_typical, events = naive_events, keep = "scenario") |>
as.data.frame()
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvp'
#> Warning: multi-subject simulation without without 'omega'
auc_window <- function(d, lo, hi) {
d <- d[d$time >= lo & d$time <= hi, ]
sum(diff(d$time) * (utils::head(d$Cc, -1) + utils::tail(d$Cc, -1)) / 2)
}
naive_auc1 <- sim_naive |>
dplyr::group_by(scenario) |>
dplyr::summarise(auc_day1_naive = auc_window(dplyr::pick(time, Cc), 0, 24), .groups = "drop") |>
dplyr::inner_join(published_fig4 |> dplyr::select(scenario, auc_day1), by = "scenario") |>
dplyr::mutate(d_naive = 100 * (auc_day1_naive / auc_day1 - 1))
knitr::kable(
naive_auc1 |>
dplyr::filter(abs(d_naive) > 1) |>
dplyr::rename(
"Scenario" = scenario, "AUCday1, 60-min infusions and 15 mg/kg first dose" = auc_day1_naive,
"Published AUCday1" = auc_day1, "Difference (%)" = d_naive
),
digits = 1,
caption = "Scenarios whose AUCday1 misses the published value by more than 1% under the simplified regimen."
)| Scenario | AUCday1, 60-min infusions and 15 mg/kg first dose | Published AUCday1 | Difference (%) |
|---|---|---|---|
| 13 year - 78 kg - morbidly obese | CLcr 10 | 475.6 | 469.7 | 1.3 |
| 13 year - 78 kg - morbidly obese | CLcr 120 | 307.4 | 334.2 | -8.0 |
| 17 year - 118 kg - morbidly obese | CLcr 10 | 498.8 | 486.4 | 2.6 |
| 17 year - 118 kg - morbidly obese | CLcr 120 | 335.0 | 360.1 | -7.0 |
| 17 year - 118 kg - morbidly obese | CLcr 40 | 405.6 | 399.1 | 1.6 |
| 17 year - 118 kg - morbidly obese | CLcr 70 | 387.4 | 380.2 | 1.9 |
Replicate Figure 2: clearance versus body weight
fig2 <- tidyr::crossing(WT = seq(6, 188, by = 1), CRCL = c(15, 50, 110, 150)) |>
dplyr::mutate(CL = 2.12 * (WT / 22.1)^0.745 * pmin(CRCL, 120) / 100)
ggplot(fig2, aes(WT, CL, colour = factor(CRCL))) +
geom_line() +
labs(
x = "Total body weight (kg)", y = "Vancomycin clearance (L/h)",
colour = "CLcr\n(mL/min/1.73 m^2)",
title = "Figure 2 - typical clearance versus total body weight",
caption = "Replicates the model lines of Figure 2 of Smit 2021. The 150 line is capped at 120."
) +
theme_bw()
The paper plots the 150 mL/min/1.73 m^2 line even though the model caps CLcr at 120, so that line is the CLcr = 120 line: 1.2 times the typical clearance at CLcr 100.
Between-subject variability around the guideline
The paper’s Figure 4 deliberately omits between-subject variability. The stochastic simulation below shows how much it matters, for 200 virtual normal-weight 25 kg children with CLcr 120 mL/min/1.73 m^2 dosed 15 mg/kg every 6 hours.
rxode2::rxSetSeed(20210411)
n_sub <- 200
stoch_events <- lapply(seq_len(n_sub), function(i) {
sc <- tibble::tibble(id = i, WT = 25, CRCL = 120, tau = 6, first_mgkg = 15, dose_mgkg = 15, scenario = "25 kg, CLcr 120")
build_fig4_events(sc)
}) |>
dplyr::bind_rows() |>
dplyr::arrange(id, time, dplyr::desc(evid))
sim_stoch <- rxode2::rxSolve(mod, events = stoch_events, keep = "WT") |>
as.data.frame()
#> ℹ parameter labels from comments will be replaced by 'label()'
auc3_stoch <- sim_stoch |>
dplyr::group_by(id) |>
dplyr::summarise(auc_day3 = auc_window(dplyr::pick(time, Cc), 48, 72), .groups = "drop")
typical_auc3 <- chk$auc_day3_sim[chk$scenario == "12 year - 25 kg - normal weight | CLcr 120"]
knitr::kable(
tibble::tibble(
Statistic = c("Typical-value AUCday3", "Median AUCday3", "5th percentile", "95th percentile", "Fraction within 400-700"),
Value = c(
typical_auc3, stats::median(auc3_stoch$auc_day3),
stats::quantile(auc3_stoch$auc_day3, c(0.05, 0.95)),
mean(auc3_stoch$auc_day3 >= 400 & auc3_stoch$auc_day3 <= 700)
)
),
digits = 2,
caption = "AUCday3 (mg*h/L) with between-subject variability, 200 virtual subjects."
)| Statistic | Value |
|---|---|
| Typical-value AUCday3 | 533.28 |
| Median AUCday3 | 523.44 |
| 5th percentile | 330.27 |
| 95th percentile | 770.58 |
| Fraction within 400-700 | 0.74 |
# Centre, not extremes: with log-normal IIV on CL, the median AUC tracks the
# typical-value AUC.
stopifnot(abs(stats::median(auc3_stoch$auc_day3) / typical_auc3 - 1) < 0.1)With a 28.7% CV on clearance, a substantial fraction of individuals falls outside the 400-700 mg*h/L window even when the typical individual sits in the middle of it, which is why the paper recommends Bayesian forecasting on therapeutic drug monitoring samples to individualise exposure.
Assumptions and deviations
-
Residual error scale. Table II prints the final
proportional error as 0.0789 with the footnote “Proportional error is
shown as sigma”. The maintainers read it as the NONMEM
$SIGMAvariance of the additive error on log-transformed concentrations, giving a log-scale SD of sqrt(0.0789) = 0.281. Three lines of evidence support this: the supplement control stream’s$SIGMA 0.0788 ; PROP ERR IN LOGDOMAINis a variance by NONMEM definition and is essentially the published value; the reported 24% eta shrinkage on CL with a median of 4 samples per patient implies a residual variance near 0.08, whereas an SD of 0.0789 (variance 0.0062) would imply almost no CL shrinkage; and the reported 16% epsilon shrinkage is consistent with the same variance. The residual error does not affect the typical-value Figure 4 reproduction. - Covariance of the CL and V2 random effects. Table II prints the covariance directly (-0.085, correlation about -0.34 with the variances above); it is used as printed.
- V2 variability. Table II gives 110% CV; the supplement Results give 109.5%. The table value is used (variance 0.793 vs 0.788).
- Random effects on V1 and Q are fixed to zero in the supplement control stream and are omitted from the model.
- Bedside Schwartz constant. Main-text Eq. 1 prints 0.41 while the supplement Results give 0.413. The model takes CLcr as an input, so the choice only matters when a user derives CRCL from height and creatinine.
- CLcr cap. The model applies the 120 mL/min/1.73 m^2 cap internally, so users supply the uncapped bedside Schwartz value.
- Figure 4 regimen details. Two details are not stated in the Methods but are needed to reproduce the Figure 4 AUCday1 labels; both are consistent with the paper and together make every one of the 72 labels reproduce. First, in Table III only the rows marked with footnote (a) (CLcr at or below 90) start with a 15 mg/kg first dose; the CLcr above 90 row has no footnote, so its first dose is the maintenance dose (18 mg/kg for patients over 70 kg). Second, doses are infused at 10 mg/min with a 60-min minimum, the usual vancomycin infusion-rate limit, so large doses run longer than 60 min. The regimen-sensitivity section above shows the simplified alternative misses the published AUCday1 by up to 8%.
- Cmin at day 3 is taken as the first trough after the 48 h dose. The published Cmin values run up to about 1.5% above the exact trough.
- No correction notice for the article was found as of 2026-09-28.