Ceftazidime (Launay 2024)
Source:vignettes/articles/Launay_2024_ceftazidime.Rmd
Launay_2024_ceftazidime.RmdModel and source
- Citation: Launay M, Ollier E, Kably B, Le Louedec F, Thiery G, Lanoiselee J, Perinel-Ragey S. Loading Dose of Ceftazidime Needs to Be Increased in Critically Ill Patients: A Retrospective Study to Evaluate Recommended Loading Dose with Pharmacokinetic Modelling. Antibiotics. 2024;13(8):756. doi:10.3390/antibiotics13080756
- Description: One-compartment population PK model for ceftazidime in septic critically ill adults receiving continuous intravenous infusion, with CKD-EPI estimated GFR as a power covariate on clearance. Developed to size the loading dose needed before continuous infusion; the ICU volume of distribution (88 L) is roughly 2.4-fold the median of previously published ICU models (37.2 L), which is why a 2 g loading dose is shown to be insufficient.
- Article: https://doi.org/10.3390/antibiotics13080756
- Supplement (Figures S1-S3): https://www.mdpi.com/article/10.3390/antibiotics13080756/s1
Launay 2024 is a retrospective therapeutic-drug-monitoring study asking a single operational question: is the 2 g ceftazidime loading dose recommended before continuous infusion large enough for critically ill patients? The answer turns almost entirely on the volume of distribution, which the authors estimate at 88 L – roughly 2.4-fold the median of the eight previously published ICU models they review (37.2 L). Because a loading dose fills a volume, that difference translates directly into an inadequate loading dose.
Population
The model was developed from 86 adults (223 ceftazidime plasma samples, 1 to 9 per patient) treated in six French ICUs in the Saint-Etienne area between 1 November 2019 and 31 October 2021, all receiving ceftazidime by continuous infusion after a 2 g loading dose and undergoing routine therapeutic drug monitoring (Table 1, Methods sections 4.2-4.3). Patients were mostly male (67/86, 77.9%), mean age 64.5 years (SD 11.9), mean weight 91.3 kg (SD 25.3), and mean BMI 31.2 kg/m^2 (SD 9.5) with 47.7% meeting the obesity threshold. Renal function spanned the full clinical range: CKD-EPI eGFR mean 87.6 mL/min/1.73 m^2 (SD 74.2), with a population median of 73.90 mL/min/1.73 m^2 (Table 2 footnote).
Samples were drawn at least 6 h after the start of the continuous infusion; the assay calibration range was 8-150 mg/L and values below the limit of quantification were set to 4 mg/L. An independent external validation cohort of 32 patients (32 samples, one Paris ICU) was used for evaluation only and did not contribute to parameter estimation.
The same information is available programmatically via
readModelDb("Launay_2024_ceftazidime")()$population.
Source trace
Every ini() entry in
inst/modeldb/specificDrugs/Launay_2024_ceftazidime.R
carries an in-file comment naming its origin. They are collected here
for review.
| Equation / parameter | Value | Source location |
|---|---|---|
lcl (CL) |
4.45 L/h (RSE 7.3%) | Table 2, “Population” block |
lvc (Vd) |
88.0 L (RSE 18.3%) | Table 2, “Population” block |
e_crcl_cl |
0.9 (RSE 15.5%) | Table 2, “Covariate effect”, beta^CL_GFR
|
eGFR reference crclRef
|
73.90 mL/min/1.73 m^2 | Table 2 footnote (“GFRmedian”) |
etalcl |
SD 0.46 (RSE 11.5%, shrinkage 38.9%) | Table 2, “Interindividual variability (standard deviation)” |
etalvc |
SD 0.57 (RSE 25.6%, shrinkage 82.5%) | Table 2, “Interindividual variability (standard deviation)” |
expSd |
0.39 (RSE 6.2%) | Table 2, “Error model”; scale corrected, see Errata |
cl <- exp(lcl + etalcl) * (CRCL / 73.90)^e_crcl_cl |
n/a | Table 2, printed equation
CL(i) = CL(pop) * (GFRi/GFRmedian)^(beta^CL_GFR) * exp(eta_CL)
|
d/dt(central) one-compartment IV |
n/a | Results: “CAZ was best described by a one-compartment … model” |
| Loading-dose formula | LD = TC * Vd * exp(kappa * omega_V) |
Methods section 4.4; TC = 60 mg/L, kappa =
0.84 for 80% of patients |
| Terminal half-life | median 11.9 h (IQR 8.8-18.4) | Results, paragraph 4 |
| Target concentration band | 35-80 mg/L | Introduction and Methods section 4.3 |
mod <- readModelDb("Launay_2024_ceftazidime")
ui <- rxode2::rxode(mod)
#> ℹ parameter labels from comments will be replaced by 'label()'
iniv <- function(nm) ui$iniDf$est[ui$iniDf$name == nm]
cl_pop <- exp(iniv("lcl"))
vd_pop <- exp(iniv("lvc"))
om_vd <- sqrt(iniv("etalvc"))
beta <- iniv("e_crcl_cl")
c(CL = cl_pop, Vd = vd_pop, omega_Vd = om_vd, beta_GFR = beta)
#> CL Vd omega_Vd beta_GFR
#> 4.45 88.00 0.57 0.90Deterministic checks against printed values
These gates are built from the packaged model’s ini()
values and compared against numbers printed in the
paper, so a mis-transcribed parameter turns them red.
Loading dose (Table 4)
Methods section 4.4 gives the loading dose needed to reach a target
concentration TC in a stated fraction of patients as
LD = TC * Vd * exp(kappa * omega_V), with TC =
60 mg/L and kappa = 0.84 (the normal quantile covering 80%
of patients). Table 4 reports 8.5 g for this model. Reproducing that
number is a joint test of Vd and of the
claim that the printed 0.57 is a standard deviation on the log scale
rather than a variance.
kappa <- 0.84 # Methods 4.4: quantile covering 80% of patients
tc <- 60 # mg/L, Methods 4.4 (target concentration)
ld_g <- tc * vd_pop * exp(kappa * om_vd) / 1000
ld_variance_reading <- tc * vd_pop * exp(kappa * sqrt(om_vd)) / 1000
c(published_g = 8.5, model_g = ld_g,
if_0.57_were_a_variance_g = ld_variance_reading)
#> published_g model_g if_0.57_were_a_variance_g
#> 8.500000 8.522640 9.955371
# Table 4, "Current model" row: 8.5 g.
stopifnot(abs(ld_g - 8.5) < 0.05)The SD reading gives 8.52 g, which rounds to the printed 8.5 g. Reading 0.57 as a variance would give 9.96 g, which does not. This is the internal evidence that the Table 2 block heading “Interindividual variability (standard deviation)” is literal.
Terminal half-life (Results)
t_half_typical <- log(2) * vd_pop / cl_pop
c(typical_t_half_h = t_half_typical,
published_median_h = 11.9, published_iqr_lo = 8.8, published_iqr_hi = 18.4)
#> typical_t_half_h published_median_h published_iqr_lo published_iqr_hi
#> 13.70718 11.90000 8.80000 18.40000
# The paper reports a median individual terminal half-life of 11.9 h with an
# IQR of 8.8-18.4 h. The typical-value half-life must land inside that IQR.
stopifnot(t_half_typical > 8.8, t_half_typical < 18.4)Structural solve against the closed form
A one-compartment model under constant-rate infusion has the
closed-form steady-state concentration Rate / CL. This gate
confirms the packaged ODE and the covariate power term behave as written
(it exercises the model encoding, not the transcription – the
printed-value gates above do that).
det <- rxode2::zeroRe(mod)
#> ℹ parameter labels from comments will be replaced by 'label()'
rate <- 6000 / 24 # 6 g/day continuous infusion, mg/h
css_check <- function(crcl) {
ev <- rxode2::et(amt = rate * 2400, rate = rate, cmt = "central") |>
rxode2::et(seq(0, 2400, by = 24), cmt = "central")
ev <- as.data.frame(ev)
ev$CRCL <- crcl
s <- rxode2::rxSolve(det, ev, returnType = "data.frame")
c(simulated = tail(s$Cc, 1),
closed_form = rate / (cl_pop * (crcl / 73.90)^beta))
}
cf <- rbind(`eGFR 73.90 (reference)` = css_check(73.90),
`eGFR 147.80 (2x)` = css_check(147.80),
`eGFR 36.95 (0.5x)` = css_check(36.95))
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvc'
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvc'
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvc'
cf <- cbind(cf, `pct diff` = 100 * (cf[, 1] - cf[, 2]) / cf[, 2])
round(cf, 4)
#> simulated closed_form pct diff
#> eGFR 73.90 (reference) 56.1798 56.1798 0
#> eGFR 147.80 (2x) 30.1060 30.1060 0
#> eGFR 36.95 (0.5x) 104.8352 104.8352 0
stopifnot(max(abs(cf[, "pct diff"])) < 0.01)Virtual cohort
Original patient data are not public. The cohort below reproduces the published eGFR distribution: a log-normal matched to the stated median of 73.90 mL/min/1.73 m^2 and mean of 87.6 mL/min/1.73 m^2 (Tables 1 and 2). The median is the quantity the covariate model is centred on and is matched exactly.
# set.seed() seeds R's RNG only. rxode2's simulation RNG is partitioned per
# solver thread, so a 2-core CI runner and a 16-thread workstation draw
# different cohorts from identical source. Every assertion below is written to
# hold for any cohort this model can produce (bounds checked at 2, 4 and 16
# threads); see pattern 12 of the skill's known-vignette-failure-patterns.
set.seed(20240811)
n_arm <- 200 # cap is 200 per arm
sigma_gfr <- sqrt(2 * log(87.6 / 73.9))
gfr_med <- 73.9
make_arm <- function(n, ld_g, id_offset = 0L, tmax = 48, rate_mgh = 250) {
ids <- id_offset + seq_len(n)
gfr <- gfr_med * exp(stats::rnorm(n, 0, sigma_gfr))
grid <- sort(unique(c(seq(0, 24, by = 0.25), seq(24, tmax, by = 1))))
ev <- rxode2::et(amt = ld_g * 1000, dur = 1, cmt = "central", id = ids) |>
rxode2::et(amt = rate_mgh * (tmax - 1), rate = rate_mgh, time = 1,
cmt = "central", id = ids) |>
rxode2::et(grid, cmt = "central", id = ids)
ev <- as.data.frame(ev)
ev$CRCL <- gfr[match(ev$id, ids)]
ev$regimen <- paste0(ld_g, " g LD + 6 g/day")
ev
}
events <- dplyr::bind_rows(
make_arm(n_arm, 2, id_offset = 0L),
make_arm(n_arm, 4, id_offset = n_arm * 1L)
)
stopifnot(!anyDuplicated(unique(events[, c("id", "time", "evid")])))dur = 1 gives the loading dose as a 1 h infusion; the
paper does not state the loading-dose infusion duration (see
Errata).
Replicate Figure 2
Figure 2 of Launay 2024 shows Monte Carlo simulations over 0-24 h for the standard regimen (2 g loading dose then 6 g/day) and the proposed regimen (4 g loading dose then 6 g/day), with the lower limit of the 35-80 mg/L target band drawn as a red dashed line. The black line in the published panels is the median concentration curve.
fig2 <- sim |>
dplyr::filter(time <= 24) |>
dplyr::group_by(regimen, time) |>
dplyr::summarise(Q05 = quantile(Cc, 0.05), Q50 = median(Cc),
Q95 = quantile(Cc, 0.95), .groups = "drop")
ggplot(fig2, aes(time, Q50)) +
geom_ribbon(aes(ymin = Q05, ymax = Q95), alpha = 0.25, fill = "steelblue") +
geom_line(linewidth = 0.7) +
geom_hline(yintercept = 35, colour = "red", linetype = "dashed") +
facet_wrap(~regimen) +
labs(x = "Time (h)", y = "Ceftazidime concentration (mg/L)",
caption = "Replicates Figure 2 of Launay 2024.") +
theme_bw()
Replicates Figure 2 of Launay 2024: median (line) and 5th-95th percentile band (ribbon) of simulated ceftazidime concentration over the first 24 h. Red dashed line is the 35 mg/L lower target limit.
The paper’s headline simulation endpoint is the time at which the median curve first reaches 35 mg/L: “achieved within a median time of 1 h with a 4 g-loading dose …, compared to 18 h with a standard 2 g-loading dose”.
crossing <- fig2 |>
dplyr::group_by(regimen) |>
dplyr::summarise(
`time to 35 mg/L (h)` = {
i <- which(Q50 >= 35)
if (length(i) == 0) NA_real_ else time[min(i)]
},
`median Cc at 1 h` = Q50[which.min(abs(time - 1))],
`median Cc at 24 h` = Q50[which.max(time)],
.groups = "drop"
)
knitr::kable(crossing, digits = 2,
caption = "Simulated Figure 2 endpoints. Launay 2024 reports ~1 h (4 g LD) and ~18 h (2 g LD), with median concentration ~22 mg/L at 1 h under the 2 g LD.")| regimen | time to 35 mg/L (h) | median Cc at 1 h | median Cc at 24 h |
|---|---|---|---|
| 2 g LD + 6 g/day | 20 | 20.32 | 38.45 |
| 4 g LD + 6 g/day | 1 | 44.00 | 44.44 |
t2 <- crossing$`time to 35 mg/L (h)`[crossing$regimen == "2 g LD + 6 g/day"]
t4 <- crossing$`time to 35 mg/L (h)`[crossing$regimen == "4 g LD + 6 g/day"]
c1 <- crossing$`median Cc at 1 h`[crossing$regimen == "2 g LD + 6 g/day"]
# Bounds set outside the range realised at 2 / 4 / 16 solver threads
# (t2 13.0-16.0 h; t4 0.75-1.0 h; c1 22.0-24.1 mg/L). They still go red on a
# mis-transcribed Vd or CL, which move all three by tens of percent.
stopifnot(
t4 <= 3, # 4 g LD reaches target essentially immediately
t2 >= 6, t2 <= 24, # 2 g LD is substantially delayed
t2 - t4 >= 5, # the paper's central claim
c1 > 17, c1 < 29 # 2 g into 88 L is ~22.7 mg/L before elimination
)The 2 g loading dose reaches the target 35 mg/L only after 20 h in
this cohort, against 1 h for the 4 g dose, reproducing the paper’s
qualitative conclusion and approximating its ~18 h and ~1 h. The
simulated median at 1 h under the 2 g regimen (20.3 mg/L) matches the
~22 mg/L visible in the published panel, which is the clearest single
confirmation that Vd = 88 L was transcribed correctly (2000
mg / 88 L = 22.7 mg/L).
Replicate Table 3
Table 3 reports individual predicted concentrations at 24 h and 48 h under the standard regimen for the 64 patients with unchanged dosing, showing a significant rise (mean 34.6 vs 43.7 mg/L, paired t-test p < 0.0001) – the delayed approach to steady state that motivates the larger loading dose.
t3 <- sim |>
dplyr::filter(regimen == "2 g LD + 6 g/day", time %in% c(24, 48)) |>
dplyr::group_by(time) |>
dplyr::summarise(Median = median(Cc), Mean = mean(Cc),
`First quartile` = quantile(Cc, 0.25),
`Third quartile` = quantile(Cc, 0.75),
`Target attainment >=35 mg/L (%)` = 100 * mean(Cc >= 35),
.groups = "drop") |>
dplyr::rename("Time (h)" = time)
knitr::kable(t3, digits = 1,
caption = "Simulated counterpart to Table 3 of Launay 2024 (published medians 33.9 and 41.8 mg/L; published target attainment 42.2% and 64.0%).")| Time (h) | Median | Mean | First quartile | Third quartile | Target attainment >=35 mg/L (%) |
|---|---|---|---|---|---|
| 24 | 38.5 | 43.6 | 30.3 | 52.8 | 59 |
| 48 | 49.2 | 54.8 | 32.6 | 68.9 | 71 |
m24 <- t3$Median[t3$`Time (h)` == 24]
m48 <- t3$Median[t3$`Time (h)` == 48]
# Structural, not a coin flip: the cohort is still filling toward steady state,
# so 48 h must sit clearly above 24 h. Realised gap 9-11 mg/L at 2/4/16 threads.
stopifnot(m48 - m24 >= 3)Simulated concentrations run about 20% above the published table because Table 3 summarises real patients receiving individually renally-adjusted doses, whereas every virtual subject here receives exactly 6 g/day. The direction and magnitude of the 24 h to 48 h rise – the point the table is making – reproduce.
PKNCA validation
A separate cohort receives 6 g/day by continuous infusion for 240 h (long enough for the typical subject to reach steady state) followed by a 100 h washout, so that both a steady-state dosing interval and a terminal phase are available.
set.seed(20240812)
n_nca <- 200
t_inf <- 240
t_end <- 340
gfr_nca <- gfr_med * exp(stats::rnorm(n_nca, 0, sigma_gfr))
ev_nca <- rxode2::et(amt = rate * t_inf, rate = rate, time = 0,
cmt = "central", id = seq_len(n_nca)) |>
rxode2::et(sort(unique(c(seq(0, t_inf, by = 6), seq(t_inf, t_end, by = 2)))),
cmt = "central", id = seq_len(n_nca))
ev_nca <- as.data.frame(ev_nca)
ev_nca$CRCL <- gfr_nca[ev_nca$id]
ev_nca$regimen <- "6 g/day continuous infusion"
sim_nca_raw <- rxode2::rxSolve(mod, events = ev_nca, keep = c("regimen")) |>
as.data.frame()
# Filter on !is.na(Cc) ONLY -- a `time > 0` or `Cc > 0` filter would drop the
# time-zero anchor PKNCA needs for AUC.
sim_nca <- sim_nca_raw |>
dplyr::filter(!is.na(Cc)) |>
dplyr::select(id, time, Cc, regimen)
sim_nca <- dplyr::bind_rows(
sim_nca,
sim_nca |> dplyr::distinct(id, regimen) |> dplyr::mutate(time = 0, Cc = 0)
) |>
dplyr::distinct(id, regimen, time, .keep_all = TRUE) |>
dplyr::arrange(id, regimen, time)
dose_df <- ev_nca |>
dplyr::filter(evid != 0) |>
dplyr::select(id, time, amt, regimen) |>
dplyr::distinct()
conc_obj <- PKNCA::PKNCAconc(sim_nca, Cc ~ time | regimen + id,
concu = "mg/L", timeu = "h")
dose_obj <- PKNCA::PKNCAdose(dose_df, amt ~ time | regimen + id, doseu = "mg")
intervals <- data.frame(
start = c(t_inf - 24, t_inf),
end = c(t_inf, t_end),
auclast = c(TRUE, FALSE),
cav = c(TRUE, FALSE),
cmax = c(TRUE, FALSE),
cmin = c(TRUE, FALSE),
half.life = c(FALSE, TRUE)
)
nca_res <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_obj, dose_obj,
intervals = intervals))
nca_tbl <- as.data.frame(nca_res$result)
stopifnot(nrow(nca_tbl) > 0)AUC over the steady-state interval against
Dose / CL
At steady state the AUC over a 24 h interval must equal the 24 h dose
divided by that subject’s clearance. This is checked per subject against
each subject’s own simulated cl.
cl_ind <- sim_nca_raw |>
dplyr::group_by(id) |>
dplyr::summarise(cl = dplyr::first(cl), .groups = "drop")
auc_chk <- nca_tbl |>
dplyr::filter(PPTESTCD == "auclast") |>
dplyr::select(id, auclast = PPORRES) |>
dplyr::left_join(cl_ind, by = "id") |>
dplyr::mutate(closed_form = 6000 / cl,
pct_diff = 100 * (auclast - closed_form) / closed_form)
stopifnot(nrow(auc_chk) == n_nca)
c(median_pct_diff = median(auc_chk$pct_diff),
q90_abs_pct_diff = unname(quantile(abs(auc_chk$pct_diff), 0.9)))
#> median_pct_diff q90_abs_pct_diff
#> -0.001223956 2.486855688
# Centre and a robust quantile, never the extreme: subjects with very low eGFR
# have half-lives long enough that 240 h is not yet steady state, so the tail of
# this distribution is a property of the cohort, not of the model. Realised
# median -0.003 to -0.001% and q90 2.3-2.9% at 2/4/16 threads.
stopifnot(
abs(median(auc_chk$pct_diff)) < 0.5,
quantile(abs(auc_chk$pct_diff), 0.9) < 8
)Comparison against published NCA
The only non-compartmental quantity Launay 2024 reports is the individual terminal half-life: median 11.9 h, IQR 8.8-18.4 h.
published <- tibble::tribble(
~regimen, ~half.life,
"6 g/day continuous infusion", 11.9
)
cmp <- nlmixr2lib::ncaComparisonTable(
simulated = nca_res,
reference = published,
by = "regimen",
units = c(half.life = "h"),
tolerance_pct = 20
)
knitr::kable(cmp, caption = "Simulated vs published NCA. * differs from reference by >20%.")| NCA parameter | regimen | Reference | Simulated | % diff |
|---|---|---|---|---|
| t½ (h) | 6 g/day continuous infusion | 11.9 | 13.9 | +16.7% |
hl_med <- median(nca_tbl$PPORRES[nca_tbl$PPTESTCD == "half.life"], na.rm = TRUE)
c(simulated_median_h = hl_med, published_median_h = 11.9,
published_iqr = "8.8-18.4")
#> simulated_median_h published_median_h published_iqr
#> "13.8902377128819" "11.9" "8.8-18.4"
# Assert against the IQR the paper itself prints, not against a bound taken
# from one run. Realised 14.05-14.96 h at 2/4/16 threads.
stopifnot(hl_med > 8.8, hl_med < 18.4)The simulated median half-life (about 14-15 h depending on the drawn
cohort) is some 20% above the published median of 11.9 h and may carry a
*, but it sits comfortably inside the published IQR of
8.8-18.4 h, as does the typical-value half-life of 13.7 h. The published
figure is a median over empirical-Bayes estimates from sparse data with
82.5% shrinkage on Vd, which compresses individual volumes
toward the population value; a forward-simulated cohort with the full
reported between-subject variance is not expected to match it exactly.
No parameter was adjusted to close the gap.
Assumptions and deviations
Errata: the residual error is on the log scale, not in mg/L
Table 2 prints the residual error as
Additive (mg/L) 0.39 (RSE 6.2%) and the Results text says
“one-compartment with additive error model”. The value
0.39 is used unchanged, but the printed unit is treated
as a typo: the model encodes Cc ~ lnorm(expSd) with
expSd = 0.39, i.e. an additive residual on the
log-concentration scale (a log-normal residual in linear space, ~40.5%
CV). The evidence is entirely internal to the paper:
- Magnitude. The assay calibration range is 8-150 mg/L and the target band is 35-80 mg/L. An additive SD of 0.39 mg/L is about 1% of a typical observation, roughly two orders of magnitude tighter than any therapeutic-drug-monitoring population-PK residual.
-
Figure 1B. The observed-versus-individual-predicted
panel shows scatter of tens of mg/L at every concentration. Under a 0.39
mg/L additive residual every point would lie within +/-0.8 mg/L of the
identity line, i.e. visually on it. Digitising the panel gives a
standard deviation of
log(observed / individual predicted)of about 0.33, with ratio quantiles flat across a six-fold concentration range (5th/95th percentile ratios 0.64/1.78 in the 20-30 mg/L bin against 0.30/1.79 in the 80-120 mg/L bin). A constant ratio spread is a relative error, not an additive one, and the measured 0.33 sits just below the reported 0.39 exactly as expected, because residuals taken against shrunken individual predictions understate sigma. - Shrinkage. The reported eta shrinkages (38.9% on CL, 82.5% on Vd) require a substantial residual; a ~1% residual on steady-state samples would identify individual clearance almost exactly and drive CL shrinkage toward zero.
-
The paper’s own printed accuracy metric. This is
the decisive evidence, and unlike point 2 it needs no digitisation.
Methods section 4.5 defines
PE (%) = (Cpred - Cobs) / Cobs, a relative error, and reports MDAPE (its median absolute value) as acceptable if<= 30%. The Results state that “MPDE and MDAPE for individual predictions were between -3.3 and 16.9%”. An additive residual of 0.39 mg/L against observations of tens of mg/L implies an MDAPE of about 1%, which is irreconcilable with a reported 16.9%. A 0.39 standard deviation on the log scale implies a median absolute relative deviation ofexp(0.674 * 0.39) - 1, about 30%, falling to the reported range once individual predictions absorb part of the residual – consistent, and additionally consistent with the paper judging its own MDAPE against a 30% threshold.
lnorm was chosen over prop because the
paper’s own word is “additive”, and additive on the log scale is
log-normal; MONOLIX (used here, Methods section 4.4) names that error
model “constant”, which authors routinely report as “additive”. The two
forms differ materially at this magnitude – a 0.39 log-scale SD is a
40.5% CV, not 39%. The same reasoning and encoding are used in
Sano_2023_fesoterodine.R.
Other assumptions
- Loading-dose infusion duration. The paper does not state how the loading dose was infused in its Monte Carlo simulations. A 1 h infusion is assumed here. It is consistent with the reported “median time of 1 h” to reach 35 mg/L under the 4 g loading dose: 4000 mg into 88 L is 45 mg/L, already above target, so with a bolus the reported median would have been 0 h.
- eGFR distribution. Simulated as log-normal matched to the published median (73.90 mL/min/1.73 m^2) and mean (87.6 mL/min/1.73 m^2), which yields an SD of about 56 rather than the published 74.2. Only three moments are reported and no two-parameter positive distribution matches all three; the median was prioritised because the covariate model is centred on it. The Figure 2 endpoints are insensitive to this choice (matching median and SD instead moves the 2 g crossing time by under 1 h).
- Dosing. Every virtual subject receives exactly 6 g/day, the published median dosage. Real patients in the source cohort received renally adjusted doses, which is the main reason simulated concentrations sit above Table 3.
-
No covariate on Vd. The paper screened body weight,
BMI, age, sex, protein concentration, serum creatinine, creatinine
clearance and ongoing COVID-19 status; only eGFR on CL was retained.
These screened-but-unretained covariates are recorded in the model
file’s
covariatesDataExcludedmetadata for provenance, and are not referenced inmodel(). -
Correlation between etas. Table 2 reports no
off-diagonal covariance, so
etalclandetalvcare independent. - Supplement. The supplementary file (Figures S1-S3: prediction-corrected VPC, external-validation goodness of fit, and individual predicted concentrations over 48 h) was retrieved and reviewed. It contains no parameter tables, so every value in the model file comes from Table 2 of the main article.
-
Non-paper-derived parameter values. None. Every
ini()value is a printed number from Table 2; the only editorial change is the residual-error scale correction documented above, which retains the printed value.