Endotoxin, TNF-alpha and IL-6 in piglets (Thorsted 2019)
Source:vignettes/articles/Thorsted_2019_endotoxin.Rmd
Thorsted_2019_endotoxin.RmdModel and source
mod <- readModelDb("Thorsted_2019_endotoxin")
ui <- rxode2::rxode(mod)
#> ℹ parameter labels from comments will be replaced by 'label()'- Citation: Thorsted A, Bouchene S, Tano E, Castegren M, Lipcsey M, Sjolin J, Karlsson MO, Friberg LE, Nielsen EI. (2019). A non-linear mixed effect model for innate immune response: In vivo kinetics of endotoxin and its induction of the cytokines tumor necrosis factor alpha and interleukin-6. PLoS ONE 14(2):e0211981. doi:10.1371/journal.pone.0211981.
- Description: Preclinical (piglet). Semi-mechanistic model of intravenously infused E. coli O111:B4 endotoxin (ETX) and the innate cytokine response it induces in anaesthetised piglets (Thorsted 2019). ETX follows one-compartment disposition with Michaelis-Menten elimination plus a constant assay baseline. ETX stimulates TNF-alpha production through a sigmoidal Emax whose EC50 is itself raised by ETX through a three-stage moderator chain (endotoxin tolerance). IL-6 production is stimulated linearly by the relative increase in TNF-alpha and by ETX, with appearance in plasma delayed by four transit compartments. A mixture sub-population (MIX_ETX_CONTAM) carries pre-study contaminating ETX that is measured but does not drive the cytokines, so the model keeps a second, identically eliminated ETX pool (central_contam) for the assay read-out. Every infusion must be given to both central and central_contam.
- Article: https://doi.org/10.1371/journal.pone.0211981 (PMC6383944, open access)
- Supplements: S1 Text (the final NONMEM control stream, with every ODE) and S1 Table (the 116-piglet modelling dataset), both deposited with the PLOS ONE record.
Thorsted 2019 is a semi-mechanistic model of the innate immune response to intravenously infused endotoxin (ETX, E. coli O111:B4) in anaesthetised piglets. It links three measured time-courses:
- ETX follows one-compartment disposition with Michaelis-Menten elimination and a constant assay baseline.
- TNF-alpha follows a turnover model whose production rate is stimulated by a sigmoidal Emax in the ETX concentration.
- IL-6 follows a turnover model whose production rate is stimulated linearly by the relative increase in TNF-alpha and by ETX, with plasma appearance delayed through four transit compartments.
Endotoxin tolerance is built in: the ETX concentration raises
EC50 of the ETX-TNF-alpha relationship through a
three-stage moderator chain, so continued exposure progressively blunts
the TNF-alpha response.
Why two endotoxin compartments
The source $MODEL block declares two ETX compartments
with identical kinetics (same Vmax, KM,
Vc) that receive the same infusion and differ only in their
initial condition:
-
centralstarts at zero. Only this pool drives TNF-alpha and IL-6, because (Results, “Host response”) control groups showed no cytokine response to the constant baseline or to the pre-study contamination. -
central_contamstarts at a pre-study contaminating amount in the contamination mixture sub-population (MIX_ETX_CONTAM = 1, Eq 1). The measured endotoxin concentration isCc = rbase_etx + central_contam / vc.
Because elimination is Michaelis-Menten, the two pools are not
additively separable, so a single state cannot give both the measured
concentration and the pharmacologically active one. Every dosing record
must therefore be given to both compartments; the
source dataset does this with two EVID = 1 rows (CMT 1 and
CMT 2) of the same amount and rate.
This is an endogenous / mechanistic model: there is no classical absorption-distribution-elimination profile of an administered drug to integrate (the “drug” is an immune stimulus), so NCA is not the right validation. Instead the sections below check the biological steady state, recovery after a perturbation, mass balance at steady state, dimensional consistency, and reproduction of the paper’s Figure 6.
Population
The model was fit to 116 anaesthetised piglets (approximately 12 weeks old, mean weight approximately 27 kg) pooled across six studies (A-F; Thorsted 2019 Table 1), contributing 278 ETX, 1068 TNF-alpha and 1045 IL-6 observations. ETX was infused intravenously for 1-30 h at 0 (saline) to 16.0 ug/kg/h; the batch potency was 1000 EU/ug (studies A, B, E) or 3000 EU/ug (studies C, D, F). ETX was measured in studies C, E and F only. A seventh study (G, n = 6) was held out for external evaluation and is not part of the fit.
mod()$population
#> $species
#> [1] "pig (anaesthetised piglets)"
#>
#> $n_subjects
#> [1] 116
#>
#> $n_studies
#> [1] 6
#>
#> $age_range
#> [1] "approximately 12 weeks"
#>
#> $weight_median
#> [1] "mean approximately 27 kg"
#>
#> $disease_state
#> [1] "experimental endotoxaemia (porcine endotoxin model); saline-infused controls included"
#>
#> $dose_range
#> [1] "Continuous IV infusion of E. coli O111:B4 endotoxin for 1-30 h at 0 (saline) to 16.0 ug/kg/h; batch potency 1000 EU/ug (studies A, B, E) or 3000 EU/ug (studies C, D, F)"
#>
#> $regions
#> [1] "Sweden (Uppsala University Hospital)"
#>
#> $notes
#> [1] "Six studies (A-F, Thorsted 2019 Table 1) pooled: 278 ETX, 1068 TNF-alpha and 1045 IL-6 observations. ETX was measured in studies C, E and F only. A seventh study (G, n = 6) was held out for external evaluation and is not part of the fit. Sex not reported."Source trace
Every ini() value is traced to its source in an in-file
comment next to the parameter in
inst/modeldb/pharmacodynamics/Thorsted_2019_endotoxin.R.
The table collects them. Structure is from S1 Text; final values are
from Table 2 (the stream’s $THETA/$OMEGA
blocks are the run045 initial estimates, e.g. KM
12325.3 vs Table 2’s 12600, so Table 2 governs per the standard
initial-vs-final rule).
| Parameter | Value | Source |
|---|---|---|
lvmax |
442000 EU/h | Table 2 Vmax
|
lkm |
12600 EU/L | Table 2 KM
|
lvc |
36.1 L | Table 2 Vc
|
lrbase_etx / lrbase_etx_f
|
155 / 1810 EU/L | Table 2 BASE ETX (Endochrome C+E / Coatest F) |
lprop_cont |
132 | Table 2 Propcont; Eq 1 |
lmtt_tnf |
1.04 h | Table 2 MTT TNF-alpha
|
lrbase_tnf / _e / _cf /
_d
|
281 / 25.4 / 3.06 / 68.2 ng/L | Table 2 S0,TNF-alpha (DuoSet A+B / DuoSet E / BioSource
C+F / BioSource D) |
lemax_tnf |
2540 | Table 2 Emax
|
lec50_tnf |
286 EU/L | Table 2 EC0
|
lhill_tnf |
2.10 | Table 2 gamma
|
lmtt_tol |
6.33 h | Table 2 MTT EC50
|
lemax_tol |
45100 | Table 2 Tmax
|
lec50_tol |
29300 EU/L | Table 2 TC50
|
lmtt_il6 |
1.45 h | Table 2 MTT IL-6
|
lrbase_il6 / _cdf
|
49.2 / 8.19 ng/L | Table 2 S0,IL-6 (DuoSet A+B+E / BioSource C+D+F) |
lslope_tnf |
0.961 | Table 2 ESLP,TNF-alpha; Eq 2 |
lslope_etx |
0.00937 | Table 2 ESLP,ETX
|
expSd / expSd_tnf /
expSd_il6
|
0.321 / 0.485 / 0.505 | Table 2 residual error |
| IIV (6 terms + KM-Vc correlation) | see below | Table 2 CV%; r(KM,Vc) = -0.42 |
d/dt(central), d/dt(central_contam)
|
n/a | S1 Text $DES (Michaelis-Menten ETX) |
d/dt(tnf) |
n/a | S1 Text $DES; Eq 3 |
d/dt(moderator1..3) |
n/a | S1 Text $DES (tolerance chain) |
d/dt(transit1..4), d/dt(il6)
|
n/a | S1 Text $DES; Eq 2 |
IIV reading. Table 2 footnote c reports variability
“on the approximate standard deviation scale”, and
100 * sqrt(omega^2) reproduces the printed CV% column
against the stream’s $OMEGA variances
(e.g. KM: 100*sqrt(1.44) = 120, matching the
printed 120; the exact log-normal CV would be 180). So the variances are
omega^2 = (CV/100)^2, and the KM-Vc covariance is
-0.42 * 1.20 * 0.753 = -0.3795 (Results reports the
correlation as -0.42; the stream’s block gives -0.4251).
Units table (dimensional check)
| ODE term | Units multiply to | Equals d/dt(state)
|
|---|---|---|
vmax * (A/vc) / (km + A/vc) |
(EU/h)(EU/L)/(EU/L) = EU/h | EU/h |
kin_tnf * (1 + eff_tnf) |
(ng/L / h)(unitless) = ng/L/h | ng/L/h |
kout_tnf * tnf |
(1/h)(ng/L) = ng/L/h | ng/L/h |
kin_tol * (1 + tol) |
(EU/L / h)(unitless) = EU/L/h | EU/L/h |
kout_il6 * transit |
(1/h)(ng/L) = ng/L/h | ng/L/h |
slope_etx * cp_etx |
(L/EU)(EU/L) = unitless | n/a (adds to stimulation) |
eff_il6 = slope_tnf * (tnf/rbase_tnf - 1) + slope_etx * cp_etx
is unitless, as required of a multiplier on the IL-6 production rate:
the TNF-alpha term is a ratio and slope_etx carries L/EU to
cancel the EU/L of cp_etx.
Steady-state check
With no infusion the system must sit at its biological baseline
indefinitely: measured ETX at rbase_etx, TNF-alpha at
rbase_tnf, IL-6 at rbase_il6, and
EC50 at EC0. Solve the typical-value model
(study A/B, no contamination) for 60 h with no dose.
typ <- mod |> rxode2::zeroRe()
#> ℹ parameter labels from comments will be replaced by 'label()'
cov0 <- list(
MIX_ETX_CONTAM = 0, STUDY_ETX_C = 0, STUDY_ETX_D = 0,
STUDY_ETX_E = 0, STUDY_ETX_F = 0
)
# The model has three endpoints (Cc, tnf, il6), so rxode2 only accepts an
# observation row whose `cmt` is one of them. `tnf` is both an endpoint and an
# ODE state, so it is used throughout; rxode2 still returns every state and Cc
# on each row.
obs_rows <- function(times, covs) {
out <- data.frame(id = 1L, time = times, evid = 0L, amt = 0, cmt = "tnf")
for (nm in names(covs)) out[[nm]] <- covs[[nm]]
out
}
ev_ss <- obs_rows(seq(0, 60, by = 1), cov0)
s_ss <- rxode2::rxSolve(typ, ev_ss, returnType = "data.frame")
#> ℹ omega/sigma items treated as zero: 'etalkm', 'etalvc', 'etalrbase_etx', 'etalmtt_tnf', 'etalrbase_tnf', 'etalmtt_il6', 'etalrbase_il6'
# ETX, TNF-alpha, IL-6 and EC50 should hold at the reported baselines.
stopifnot(
max(abs(s_ss$Cc - 155)) < 1e-6,
max(abs(s_ss$tnf - 281)) < 1e-4,
max(abs(s_ss$il6 - 49.2)) < 1e-4,
max(abs(s_ss$moderator3 - 286)) < 1e-4
)
range(s_ss$tnf)
#> [1] 281 281
range(s_ss$il6)
#> [1] 49.2 49.2In the contamination sub-population the measured ETX must start at the assay baseline plus the contaminating amount of Eq 1:
cov_c <- cov0
cov_c$MIX_ETX_CONTAM <- 1
ev_c <- obs_rows(seq(0, 6, by = 0.5), cov_c)
s_c <- rxode2::rxSolve(typ, ev_c, returnType = "data.frame")
#> ℹ omega/sigma items treated as zero: 'etalkm', 'etalvc', 'etalrbase_etx', 'etalmtt_tnf', 'etalrbase_tnf', 'etalmtt_il6', 'etalrbase_il6'
# central_contam(0) = rbase_etx * prop_cont = 155 * 132 = 20460 EU;
# Cc(0) = rbase_etx + 20460/vc = 155 + 20460/36.1.
stopifnot(abs(s_c$Cc[s_c$time == 0] - (155 + 155 * 132 / 36.1)) < 1e-6)
s_c$Cc[s_c$time == 0]
#> [1] 721.759Perturbation recovery
rxSolve(inits = ) cannot be used to displace the
cytokines, because the model sets tnf(0) and
il6(0) from their baselines and that assignment takes
precedence. Two perturbations are applied with events instead, and each
is first asserted to have moved the system before its recovery is
checked:
- a bolus that doubles TNF-alpha and IL-6 at
t = 0with no ETX present; - a 1 h ETX infusion at 4000 EU/kg/h (27 kg piglet) into both ETX pools, which stimulates both cytokines and raises EC50 through the tolerance chain.
After the ETX has been eliminated, every state must return to its baseline.
obs_grid <- seq(0, 72, by = 0.5)
ev_bolus <- dplyr::bind_rows(
data.frame(id = 1L, time = 0, evid = 1L, amt = c(281, 49.2),
cmt = c("tnf", "il6")),
obs_rows(obs_grid, list())
)
for (nm in names(cov0)) ev_bolus[[nm]] <- cov0[[nm]]
pulse_rate <- 4000 * 27 # EU/h
ev_pulse <- dplyr::bind_rows(
data.frame(id = 1L, time = 0, evid = 1L, amt = pulse_rate, rate = pulse_rate,
cmt = c("central", "central_contam")),
obs_rows(obs_grid, list())
)
for (nm in names(cov0)) ev_pulse[[nm]] <- cov0[[nm]]
s_bolus <- rxode2::rxSolve(typ, ev_bolus, returnType = "data.frame")
#> ℹ omega/sigma items treated as zero: 'etalkm', 'etalvc', 'etalrbase_etx', 'etalmtt_tnf', 'etalrbase_tnf', 'etalmtt_il6', 'etalrbase_il6'
s_pulse <- rxode2::rxSolve(typ, ev_pulse, returnType = "data.frame")
#> ℹ omega/sigma items treated as zero: 'etalkm', 'etalvc', 'etalrbase_etx', 'etalmtt_tnf', 'etalrbase_tnf', 'etalmtt_il6', 'etalrbase_il6'
end_of <- function(s) s[s$time == max(s$time), ]
rel_dev <- function(x, ref) abs(x / ref - 1)
stopifnot(
# The perturbations happened.
max(s_bolus$tnf) > 1.5 * 281,
max(s_bolus$il6) > 1.5 * 49.2,
max(s_pulse$tnf) > 10 * 281,
max(s_pulse$il6) > 10 * 49.2,
max(s_pulse$moderator3) > 10 * 286,
# ...and every state relaxed back to its baseline by 72 h.
rel_dev(end_of(s_bolus)$tnf, 281) < 0.01,
rel_dev(end_of(s_bolus)$il6, 49.2) < 0.01,
rel_dev(end_of(s_pulse)$tnf, 281) < 0.01,
rel_dev(end_of(s_pulse)$il6, 49.2) < 0.01,
rel_dev(end_of(s_pulse)$moderator3, 286) < 0.01,
rel_dev(end_of(s_pulse)$Cc, 155) < 0.01
)
dplyr::bind_rows(
transform(s_bolus, perturbation = "Cytokine bolus (2x baseline)"),
transform(s_pulse, perturbation = "1 h ETX pulse, 4000 EU/kg/h")
) |>
dplyr::select(time, perturbation, tnf, il6, moderator3) |>
tidyr::pivot_longer(c(tnf, il6, moderator3), names_to = "state",
values_to = "value") |>
ggplot(aes(time, value, colour = perturbation)) +
geom_line() +
facet_wrap(~state, scales = "free_y") +
scale_y_log10() +
labs(x = "Time (h)", y = "Value (ng/L; EC50 in EU/L)",
title = "Perturbation recovery to baseline", colour = NULL) +
theme(legend.position = "bottom")
Mass-balance / flux check
At the undisturbed baseline every turnover state has production equal
to elimination, so d/dt = 0. Verify symbolically for
TNF-alpha and IL-6 using the typical values.
rbase_tnf <- 281; mtt_tnf <- 1.04
kout_tnf <- 1 / mtt_tnf
kin_tnf <- rbase_tnf * kout_tnf
# With no ETX: eff_tnf = 0, so d/dt(tnf) = kin_tnf - kout_tnf * rbase_tnf.
stopifnot(abs(kin_tnf - kout_tnf * rbase_tnf) < 1e-9)
rbase_il6 <- 49.2; mtt_il6 <- 1.45
kout_il6 <- 5 / mtt_il6
kin_il6 <- rbase_il6 * kout_il6
# Each IL-6 chain stage flows at kout_il6 * rbase_il6 in and out at baseline.
stopifnot(abs(kin_il6 - kout_il6 * rbase_il6) < 1e-9)
# EC50 chain: kin_tol = EC0 * kout_tol, so the chain holds at EC0 with no ETX.
ec0 <- 286; mtt_tol <- 6.33
kout_tol <- 3 / mtt_tol
kin_tol <- ec0 * kout_tol
stopifnot(abs(kin_tol - kout_tol * ec0) < 1e-9)
c(kin_tnf = kin_tnf, kin_il6 = kin_il6, kin_tol = kin_tol)
#> kin_tnf kin_il6 kin_tol
#> 270.1923 169.6552 135.5450Replicate Figure 6
Figure 6 shows typical-value 30 h predictions of ETX (A), TNF-alpha (B), IL-6 (C) and the potency parameter EC50 (D) across initial infusion rates of 63, 250, 500, 1000, 4000, 8000 and 16000 EU/kg/h, with the four lowest rates switched to 4000 EU/kg/h after 15 h to demonstrate tolerance (an infusion dataset uses EU, so the per-kg rate times the 27 kg mean weight gives the EU/h infusion). The model has no weight covariate; the per-kg scaling is applied when the event table is built. Each infusion goes to both ETX compartments.
wt <- 27 # mean piglet weight (kg), Thorsted 2019 Methods
rates <- c(63, 250, 500, 1000, 4000, 8000, 16000)
make_subject <- function(i, r) {
switched <- r < 4000
seg <- if (switched) {
data.frame(time = c(0, 15), rate = c(r, 4000) * wt, dur = c(15, 15))
} else {
data.frame(time = 0, rate = r * wt, dur = 30)
}
seg$amt <- seg$rate * seg$dur
dose <- dplyr::bind_rows(
transform(seg, cmt = "central"),
transform(seg, cmt = "central_contam")
)
dose <- dose[, c("time", "amt", "rate", "cmt")]
dose$evid <- 1L
obs <- data.frame(time = seq(0, 30, by = 0.25), amt = 0, rate = 0,
cmt = "tnf", evid = 0L)
out <- dplyr::bind_rows(dose, obs)
out$id <- i
out$rate_lab <- r
out[order(out$time, -out$evid), ]
}
ev6 <- dplyr::bind_rows(Map(make_subject, seq_along(rates), rates))
for (nm in names(cov0)) ev6[[nm]] <- cov0[[nm]]
stopifnot(!anyDuplicated(unique(ev6[, c("id", "time", "evid")])))
sim6 <- rxode2::rxSolve(typ, ev6, keep = "rate_lab",
returnType = "data.frame") |>
dplyr::mutate(rate_lab = factor(rate_lab, levels = rates))
#> ℹ omega/sigma items treated as zero: 'etalkm', 'etalvc', 'etalrbase_etx', 'etalmtt_tnf', 'etalrbase_tnf', 'etalmtt_il6', 'etalrbase_il6'
#> Warning: multi-subject simulation without without 'omega'
sim6 |>
dplyr::transmute(time, rate_lab,
`A: ETX (EU/L)` = Cc,
`B: TNF-alpha (ng/L)` = tnf,
`C: IL-6 (ng/L)` = il6,
`D: EC50 (EU/L)` = moderator3) |>
tidyr::pivot_longer(-c(time, rate_lab), names_to = "panel",
values_to = "value") |>
dplyr::filter(value > 0) |>
ggplot(aes(time, value, colour = rate_lab)) +
geom_line() +
facet_wrap(~panel, scales = "free_y") +
scale_y_log10() +
labs(x = "Time (h)", y = NULL, colour = "Initial rate\n(EU/kg/h)",
title = "Figure 6 - typical-value 30 h predictions",
caption = "Replicates Figure 6 of Thorsted 2019.")
The simulation reproduces the paper’s Figure 6 behaviour:
summ <- sim6 |>
dplyr::group_by(rate_lab) |>
dplyr::summarise(
etx_plateau = Cc[time == 6],
tnf_peak = max(tnf),
tnf_tpeak = time[which.max(tnf)],
tnf_second = max(tnf[time > 15]),
il6_peak = max(il6),
ec50_end = moderator3[time == 30],
.groups = "drop"
)
summ
#> # A tibble: 7 × 7
#> rate_lab etx_plateau tnf_peak tnf_tpeak tnf_second il6_peak ec50_end
#> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 63 204. 2676. 1.5 2508. 1927. 1487817.
#> 2 250 350. 20302. 1.25 539. 2535. 1490979.
#> 3 500 550. 52373. 1 366. 6210. 1495319.
#> 4 1000 970. 114978. 1 309. 13341. 1504417.
#> 5 4000 4114. 259039. 0.75 284. 30735. 1574569.
#> 6 8000 10472. 300317. 0.75 287. 36793. 3749216.
#> 7 16000 31219. 323425. 1 314. 42569. 9039660.
stopifnot(
# ETX plateau rises monotonically with infusion rate (Panel A).
all(diff(summ$etx_plateau) > 0),
# TNF-alpha peaks within the first few hours (Panel B).
all(summ$tnf_tpeak <= 3),
# TNF-alpha response increases with dose (Panel B).
all(diff(summ$tnf_peak) > 0),
# Tolerance (Discussion, on Fig 3A): a 4000 EU/kg/h challenge after
# pre-exposure gives a response "much lower than without any pre-exposure",
# and lower after the higher pre-exposure. Typical values, so deterministic.
summ$tnf_second[summ$rate_lab == "63"] < 0.05 * summ$tnf_peak[summ$rate_lab == "4000"],
summ$tnf_second[summ$rate_lab == "250"] < summ$tnf_second[summ$rate_lab == "63"],
# EC50 climbs far above its EC0 = 286 baseline (tolerance; Panel D).
all(summ$ec50_end > 1e4)
)At a constant infusion rate R (EU/h) below
Vmax, Michaelis-Menten elimination has the closed-form
steady state C = KM * R / (Vmax - R), and the tolerance
chain then settles at
EC50 = EC0 * (1 + Tmax * C / (TC50 + C)). The 4000 EU/kg/h
arm (108000 EU/h) is effectively at steady state by 30 h, so its
simulated ETX and EC50 must match these values. A mis-transcribed
Vmax, KM, Vc, EC0,
Tmax or TC50 moves them by far more than the
bound.
r_4000 <- 4000 * 27
c_ss <- 12600 * r_4000 / (442000 - r_4000)
ec50_ss <- 286 * (1 + 45100 * c_ss / (29300 + c_ss))
at30 <- sim6[sim6$rate_lab == "4000" & sim6$time == 30, ]
cf <- data.frame(
quantity = c("ETX incl. baseline (EU/L)", "EC50 (EU/L)"),
closed_form = c(155 + c_ss, ec50_ss),
simulated = c(at30$Cc, at30$moderator3)
)
cf$rel_diff <- cf$simulated / cf$closed_form - 1
knitr::kable(cf, digits = c(0, 1, 1, 5),
caption = "4000 EU/kg/h arm at 30 h vs. analytic steady state.")| quantity | closed_form | simulated | rel_diff |
|---|---|---|---|
| ETX incl. baseline (EU/L) | 4229.3 | 4229.3 | 0.00000 |
| EC50 (EU/L) | 1574917.3 | 1574568.8 | -0.00022 |
# Measured residuals ~2e-4 (the chains are still converging); bound 10x above.
stopifnot(all(abs(cf$rel_diff) < 2e-3))Reading Figure 6 by eye gives the same magnitudes: ETX plateaus near
4 x 10^3 EU/L at 4000 EU/kg/h and near 8 x 10^4 EU/L at 30 h for 16000
EU/kg/h (panel A); TNF-alpha peaks near 2 x 10^3 ng/L at 63 EU/kg/h and
2.4 x 10^5 ng/L at 16000 EU/kg/h (panel B); IL-6 settles near 2 x 10^3
ng/L under 4000 EU/kg/h (panel C); and EC50 reaches about 1.5 x 10^6
EU/L at 4000 EU/kg/h and 9 x 10^6 EU/L at 16000 EU/kg/h (panel D). The
figure’s control baselines sit at about 205 ng/L (TNF-alpha) and 49 ng/L
(IL-6), the EBE-median DuoSet baselines the paper used for study G,
rather than the study A/B typical values used here (281 and 49.2 ng/L).
TNF-alpha production scales with its baseline, so the TNF-alpha curves
here sit about 1.4-fold (281/205) above the figure’s; solving with
lrbase_tnf = log(205) and
lrbase_il6 = log(49.3) reproduces the figure’s levels.
Assumptions and deviations
-
Structure from the control stream, values from Table
2. The S1 Text
$THETA/$OMEGAblocks hold the run045 initial estimates seeding the final importance-sampling run; the maintainers took every final value from Table 2, following the standard rule that a results table supersedes control-stream initials. -
IIV variances read on the SD scale. Table 2 reports
variability as a CV% that equals
100 * sqrt(omega^2)(footnote c, “approximate standard deviation scale”), so the variances encoded are(CV/100)^2and the KM-Vc covariance is-0.42 * 1.20 * 0.753 = -0.3795. The six fixed$OMEGAvariances (0.000625) in the stream are structural parameters the paper did not vary and carry no IIV in the model. -
Residual error is additive on log-transformed data,
which the maintainers encoded as
lnorm()(Methods, “an additive relation was used for RUV (approximately proportional with log-transformed data)”); the BLOQ M3 likelihood handling in the stream is an estimation detail with no bearing on simulation. -
The mixture probability (0.399, fixed) is not an
ini()parameter. Following theMIX_LARGE_BASEprecedent, it is documented in theMIX_ETX_CONTAMcovariate entry; set the covariate to 0 for a typical uncontaminated animal or drawBernoulli(0.399)per subject for a population. - No weight covariate. The model reads no body weight; infusion rates are supplied in EU/h, so the per-kg rates of Figure 6 are multiplied by the 27 kg mean weight when the event table is built. Study G (external evaluation) is not part of the fit.
- External-evaluation baselines. For reproducing the held-out study G (Figure 5) the paper uses EBE-median baselines of 205 ng/L (TNF-alpha) and 49.3 ng/L (IL-6); those are evaluation inputs, not model parameters, and are not encoded here.
- No correction notice was found for doi:10.1371/journal.pone.0211981 as of 2026-10-16.