library(nlmixr2lib)
library(PKNCA)
#>
#> Attaching package: 'PKNCA'
#> The following object is masked from 'package:stats':
#>
#> filter
library(rxode2)
#> rxode2 5.1.8 using 2 threads (see ?getRxThreads)
#> no cache: create with `rxCreateCache()`
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
library(tidyr)
library(ggplot2)Model and source
- Citation: Wang X, Mallikaarjun S, Gibiansky E. Population Pharmacokinetic Analysis of Delamanid in Patients with Pulmonary Multidrug-Resistant Tuberculosis. Antimicrob Agents Chemother. 2020;65(1):e01202-20. doi:10.1128/AAC.01202-20
- Description: Two-compartment population PK model for oral delamanid in adults with pulmonary multidrug-resistant tuberculosis (Wang 2020): first-order absorption with lag time, morning doses (dosed into depot) and evening doses (dosed into depot2) with separate absorption rate constants, lag times and relative bioavailability, and relative bioavailability that also falls with dose and depends on inpatient versus outpatient setting and enrollment region.
- Article: https://doi.org/10.1128/AAC.01202-20 (open access)
Wang et al. pooled 20,483 plasma delamanid concentrations from 744
patients with pulmonary multidrug-resistant tuberculosis (MDR-TB)
enrolled in three phase II trials (242-07-204, 242-07-208, 242-08-210)
and the phase III trial 242-09-213. Delamanid was described by a
two-compartment model with first-order absorption and elimination and an
absorption lag time. Every dose condition the authors examined acts on
absorption: the morning and evening doses of a twice-daily regimen have
their own absorption rate constant, lag time and relative
bioavailability (in the packaged model, morning doses go into
depot and evening doses into depot2), and
relative bioavailability also falls with dose and differs between
inpatient and outpatient settings and between enrollment regions. Weight
and sex act on the volumes; hypoalbuminemia and efavirenz raise apparent
clearance.
mod <- readModelDb("Wang_2020_delamanid")
ui <- rxode2::rxode(mod)
#> ℹ parameter labels from comments will be replaced by 'label()'Population
The analysis population (Table 2) was 744 adults aged 18 to 64 years (median 33), weighing 27 to 99.6 kg (median 55 kg), 69.5% male. 40.5% were Asian (26.9% enrolled in Southeast Asia, i.e. the Philippines; 13.3% in Northeast Asia, i.e. China, Japan or Korea), 23.8% White, 6.9% Black and 28.9% other. 70.4% had MDR-TB, 16.8% pre-XDR-TB and 12.8% XDR-TB; 4.2% were HIV-positive and 3.0% received efavirenz. Baseline serum albumin was below 3.4 g/dL in 27.2% and below 2.8 g/dL in 8.7%. Doses were 100, 200, 250 and 300 mg twice daily and 200 mg once daily in the morning, always with food (Table 1).
str(ui$population)
#> List of 17
#> $ species : chr "human"
#> $ n_subjects : num 744
#> $ n_studies : num 4
#> $ n_observations : num 20483
#> $ age_range : chr "18-64 years"
#> $ age_median : chr "33 years"
#> $ weight_range : chr "27-99.6 kg"
#> $ weight_median : chr "55 kg"
#> $ sex_female_pct : num 30.5
#> $ race_ethnicity : Named num [1:4] 40.5 23.8 6.9 28.9
#> ..- attr(*, "names")= chr [1:4] "Asian" "White" "Black" "Other"
#> $ disease_state : chr "Pulmonary multidrug-resistant tuberculosis (70.4% MDR-TB, 16.8% pre-XDR-TB, 12.8% XDR-TB); 4.2% HIV-coinfected"
#> $ dose_range : chr "100 mg BID, 200 mg BID, 250 mg BID, 300 mg BID and 200 mg QD (morning) orally with food, for 8 to 28 weeks"
#> $ regions : chr "Asia (Philippines, China, Japan, Korea), Peru and other global sites"
#> $ renal_function : chr "15.3% CKD stage II and 1.6% CKD stage III by MDRD"
#> $ hypoalbuminemia: chr "27.2% baseline albumin < 3.4 g/dL; 8.7% < 2.8 g/dL"
#> $ co_medication : chr "Optimized background regimen in all but 10 patients (Table 3); efavirenz 3.0%, lamivudine 3.1%, tenofovir 2.2%"
#> $ notes : chr "Pooled phase II trials 242-07-204, 242-07-208 and 242-08-210 and phase III trial 242-09-213 (Table 1). Baseline"| __truncated__Source trace
Every ini() value carries an in-file comment pointing at
its source in
inst/modeldb/specificDrugs/Wang_2020_delamanid.R. All
values come from Table 4 (final model) unless stated.
| Equation / parameter | Value | Source location |
|---|---|---|
lcl (CL/F) |
log(37.1 L/h) | Table 4, theta1 |
lvc (V2/F at 55 kg) |
log(655 L) | Table 4, theta2 |
lq (Q/F) |
log(104 L/h) | Table 4, theta3 |
lvp (V3/F, 55-kg male) |
log(870 L) | Table 4, theta4 |
lka_am / lka_pm
|
log(0.397) / log(0.248) 1/h | Table 4, theta5 / theta9 |
ltlag_am / ltlag_pm
|
log(0.825) / log(1.38) h | Table 4, theta6 / theta10 |
lfdepot |
fixed log(1) | Results: F1 reference is a 100-mg morning inpatient dose in a non-Asian patient; Figure 1B |
e_dose200_f |
0.760 | Table 4, theta7 |
e_dosegt200_f |
0.580 | Table 4, theta8 |
e_dosetime_evening_f |
1.26 | Table 4, theta11 |
e_outpatient_f |
1.09 | Table 4, theta12 |
e_wt_vc_vp |
0.316 | Table 4, theta13 (one exponent shared by V2/F and V3/F) |
e_sexf_vp |
1.65 | Table 4, theta14 |
e_region_eastasia_f |
1.53 | Table 4, theta15 |
e_region_southeastasia_f |
1.40 | Table 4, theta16 |
e_alb_cl |
-0.892 | Table 4, theta17; functional form in footnote b |
e_conmed_efv_cl |
1.35 | Table 4, theta18 |
etalcl, etalvp, etalka_am,
etalfdepot, etalq, etalka_pm
|
0.056, 0.152, 0.517, 0.0344, 0.456, 0.343 | Table 4, OMEGA(1,1) to OMEGA(6,6); diagonal |
propSd / propSd_t208
|
sqrt(0.0715) / sqrt(0.174) | Table 4, SIGMA(1,1) / SIGMA(2,2) |
addSd / addSd_t213
|
sqrt(2.39) / sqrt(1950) ng/mL | Table 4, SIGMA(4,4) / SIGMA(3,3) |
Log-normal IIV, P = P_typ * exp(eta)
|
– | Methods, Stage 1 |
C = Chat * (1 + w_pr * eps1) + w_add * eps2 |
– | Methods, Stage 1 |
Power covariate model (COV / COV_REF)^theta, WT
reference 55 kg |
– | Methods; Figure 1 legend (typical 55-kg patient) |
IALB = min(ALB / 3.4, 1) with ALB in g/dL |
– | Table 4 footnote b |
| Covariate reference: 100-mg morning inpatient dose, non-Asian, male, 55 kg, ALB >= 3.4 g/dL, no efavirenz | – | Results; Figure 1 legend |
Covariate effects (Figure 1)
Figure 1 displays each covariate effect as a ratio to the reference patient. The typical-value model is solved once per scenario below and the parameter ratios are read from the solved model rather than recomputed from the estimates, so this exercises the albumin unit conversion and cap, the weight scaling and the bioavailability multipliers as coded.
mod_typ <- rxode2::zeroRe(mod)
#> ℹ parameter labels from comments will be replaced by 'label()'
#> Warning: No sigma parameters in the model
ref_cov <- data.frame(
WT = 55, SEXF = 0, ALB = 40, CONMED_EFV = 0,
DOSE_DELAMANID_MG = 100, OUTPATIENT = 0,
REGION_EASTASIA = 0, REGION_SOUTHEASTASIA = 0,
STUDY_242_07_208 = 0, STUDY_242_09_213 = 0
)
fig1_scen <- bind_rows(
mutate(ref_cov, scenario = "Reference"),
mutate(ref_cov, scenario = "ALB = 2.8 g/dL", ALB = 28),
mutate(ref_cov, scenario = "ALB = 2.0 g/dL", ALB = 20),
mutate(ref_cov, scenario = "ALB = 4.5 g/dL", ALB = 45),
mutate(ref_cov, scenario = "Efavirenz", CONMED_EFV = 1),
mutate(ref_cov, scenario = "200 mg dose", DOSE_DELAMANID_MG = 200),
mutate(ref_cov, scenario = ">200 mg dose", DOSE_DELAMANID_MG = 300),
mutate(ref_cov, scenario = "Outpatient", OUTPATIENT = 1),
mutate(ref_cov, scenario = "NE Asian", REGION_EASTASIA = 1),
mutate(ref_cov, scenario = "SE Asian", REGION_SOUTHEASTASIA = 1),
mutate(ref_cov, scenario = "WT = 40 kg", WT = 40),
mutate(ref_cov, scenario = "WT = 75 kg", WT = 75),
mutate(ref_cov, scenario = "WT = 90 kg", WT = 90),
mutate(ref_cov, scenario = "Female", SEXF = 1)
) |>
mutate(id = row_number(), time = 0, evid = 0, amt = 0, cmt = "central") |>
relocate(id, time, evid, amt, cmt)
fig1_sol <- as.data.frame(rxode2::rxSolve(mod_typ, fig1_scen, returnType = "data.frame"))
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvp', 'etalka_am', 'etalfdepot', 'etalq', 'etalka_pm'
#> Warning: multi-subject simulation without without 'omega'
if (is.null(fig1_sol$id)) fig1_sol$id <- 1L
fig1_sol$scenario <- fig1_scen$scenario[fig1_sol$id]
ref_row <- fig1_sol[fig1_sol$scenario == "Reference", ]
fig1_tab <- fig1_sol |>
transmute(
scenario,
`CL/F ratio` = cl / ref_row$cl,
`F1 ratio` = fdepot / ref_row$fdepot,
`Evening F1 ratio` = fdepot2 / ref_row$fdepot,
`V2/F ratio` = vc / ref_row$vc,
`V3/F ratio` = vp / ref_row$vp
)
knitr::kable(fig1_tab, digits = 3, caption = "Typical-value parameter ratios to the Figure 1 reference patient.")| scenario | CL/F ratio | F1 ratio | Evening F1 ratio | V2/F ratio | V3/F ratio |
|---|---|---|---|---|---|
| Reference | 1.000 | 1.00 | 1.260 | 1.000 | 1.000 |
| ALB = 2.8 g/dL | 1.189 | 1.00 | 1.260 | 1.000 | 1.000 |
| ALB = 2.0 g/dL | 1.605 | 1.00 | 1.260 | 1.000 | 1.000 |
| ALB = 4.5 g/dL | 1.000 | 1.00 | 1.260 | 1.000 | 1.000 |
| Efavirenz | 1.350 | 1.00 | 1.260 | 1.000 | 1.000 |
| 200 mg dose | 1.000 | 0.76 | 0.958 | 1.000 | 1.000 |
| >200 mg dose | 1.000 | 0.58 | 0.731 | 1.000 | 1.000 |
| Outpatient | 1.000 | 1.09 | 1.373 | 1.000 | 1.000 |
| NE Asian | 1.000 | 1.53 | 1.928 | 1.000 | 1.000 |
| SE Asian | 1.000 | 1.40 | 1.764 | 1.000 | 1.000 |
| WT = 40 kg | 1.000 | 1.00 | 1.260 | 0.904 | 0.904 |
| WT = 75 kg | 1.000 | 1.00 | 1.260 | 1.103 | 1.103 |
| WT = 90 kg | 1.000 | 1.00 | 1.260 | 1.168 | 1.168 |
| Female | 1.000 | 1.00 | 1.260 | 1.000 | 1.650 |
# Deterministic: typical values on both sides and no RNG, so a tight bound is
# correct. Each expected value is written from Table 4 directly.
r <- setNames(fig1_tab$`CL/F ratio`, fig1_tab$scenario)
f <- setNames(fig1_tab$`F1 ratio`, fig1_tab$scenario)
f_pm <- setNames(fig1_tab$`Evening F1 ratio`, fig1_tab$scenario)
v2 <- setNames(fig1_tab$`V2/F ratio`, fig1_tab$scenario)
v3 <- setNames(fig1_tab$`V3/F ratio`, fig1_tab$scenario)
stopifnot(
abs(r[["ALB = 2.8 g/dL"]] - (2.8 / 3.4)^-0.892) < 1e-6,
abs(r[["ALB = 2.0 g/dL"]] - (2.0 / 3.4)^-0.892) < 1e-6,
abs(r[["ALB = 4.5 g/dL"]] - 1) < 1e-6, # no effect above 3.4 g/dL
abs(r[["Efavirenz"]] - 1.35) < 1e-6,
abs(f[["200 mg dose"]] - 0.76) < 1e-6,
abs(f[[">200 mg dose"]] - 0.58) < 1e-6,
abs(f_pm[["Reference"]] - 1.26) < 1e-6,
abs(f_pm[["Outpatient"]] - 1.26 * 1.09) < 1e-6,
abs(f[["Outpatient"]] - 1.09) < 1e-6,
abs(f[["NE Asian"]] - 1.53) < 1e-6,
abs(f[["SE Asian"]] - 1.40) < 1e-6,
abs(v2[["WT = 90 kg"]] - (90 / 55)^0.316) < 1e-6,
abs(v3[["WT = 40 kg"]] - (40 / 55)^0.316) < 1e-6,
abs(v3[["Female"]] - 1.65) < 1e-6,
abs(v2[["Female"]] - 1) < 1e-6
)The Figure 1 panel A marker for albumin 2.0 g/dL sits near 1.6 and the weight markers at 40, 75 and 90 kg near 0.90, 1.10 and 1.17, matching the table above. The Results text states that CL/F “was higher by about 22%” at albumin 2.8 g/dL; the Table 4 exponent gives 18.9% and the Figure 1 marker sits at about 1.19, so the text figure appears to be rounded from a different calculation. The model uses the Table 4 estimate.
Closed-form check: Table 5 mean steady-state AUC
Table 5 lists the mean steady-state AUC0-24 for 55-kg outpatients
without hypoalbuminemia or efavirenz, simulated with interindividual but
not residual variability. For a linear model at steady state, AUC0-24 =
(daily bioavailable dose) / CL for each patient, and with log-normal IIV
the mean over patients is the typical value multiplied by
exp(omega_F1^2 / 2 + omega_CL^2 / 2). Sex does not enter
AUC in this model (it acts only on V3/F), so each male/female pair in
Table 5 is two independent 2,000-patient estimates of the same
quantity.
table5 <- tribble(
~regimen, ~region, ~sex, ~cmax, ~auclast,
"100 mg BID", "Non-Asian", "Male", 333, 6863,
"100 mg BID", "Non-Asian", "Female", 334, 6879,
"100 mg BID", "Northeast Asian", "Male", 516, 10673,
"100 mg BID", "Northeast Asian", "Female", 511, 10488,
"100 mg BID", "Southeast Asian", "Male", 474, 9812,
"100 mg BID", "Southeast Asian", "Female", 464, 9551,
"200 mg QD", "Non-Asian", "Male", 258, 4625,
"200 mg QD", "Non-Asian", "Female", 263, 4665,
"200 mg QD", "Northeast Asian", "Male", 400, 7194,
"200 mg QD", "Northeast Asian", "Female", 400, 7116,
"200 mg QD", "Southeast Asian", "Male", 366, 6611,
"200 mg QD", "Southeast Asian", "Female", 364, 6479
)
th <- ui$theta
om <- diag(ui$omega)
region_f <- c(
"Non-Asian" = 1,
"Northeast Asian" = th[["e_region_eastasia_f"]],
"Southeast Asian" = th[["e_region_southeastasia_f"]]
)
iiv_mean <- exp(om[["etalfdepot"]] / 2 + om[["etalcl"]] / 2)
closed <- table5 |>
mutate(
daily_bioavail_mg = ifelse(
regimen == "100 mg BID",
100 * (1 + th[["e_dosetime_evening_f"]]),
200 * th[["e_dose200_f"]]
) * th[["e_outpatient_f"]] * region_f[region],
auc_model = 1000 * daily_bioavail_mg / exp(th[["lcl"]]) * iiv_mean,
pct_diff = 100 * (auc_model / auclast - 1)
)
closed |>
select(regimen, region, sex, auclast, auc_model, pct_diff) |>
dplyr::rename(
Regimen = regimen, Region = region, Sex = sex,
"Table 5 mean AUC0-24 (ng*h/mL)" = auclast,
"Closed-form mean AUC0-24 (ng*h/mL)" = auc_model,
"% difference" = pct_diff
) |>
knitr::kable(digits = 1, caption = "Closed-form mean steady-state AUC0-24 versus Table 5.")| Regimen | Region | Sex | Table 5 mean AUC0-24 (ng*h/mL) | Closed-form mean AUC0-24 (ng*h/mL) | % difference |
|---|---|---|---|---|---|
| 100 mg BID | Non-Asian | Male | 6863 | 6946.9 | 1.2 |
| 100 mg BID | Non-Asian | Female | 6879 | 6946.9 | 1.0 |
| 100 mg BID | Northeast Asian | Male | 10673 | 10628.8 | -0.4 |
| 100 mg BID | Northeast Asian | Female | 10488 | 10628.8 | 1.3 |
| 100 mg BID | Southeast Asian | Male | 9812 | 9725.7 | -0.9 |
| 100 mg BID | Southeast Asian | Female | 9551 | 9725.7 | 1.8 |
| 200 mg QD | Non-Asian | Male | 4625 | 4672.3 | 1.0 |
| 200 mg QD | Non-Asian | Female | 4665 | 4672.3 | 0.2 |
| 200 mg QD | Northeast Asian | Male | 7194 | 7148.5 | -0.6 |
| 200 mg QD | Northeast Asian | Female | 7116 | 7148.5 | 0.5 |
| 200 mg QD | Southeast Asian | Male | 6611 | 6541.2 | -1.1 |
| 200 mg QD | Southeast Asian | Female | 6479 | 6541.2 | 1.0 |
# Deterministic model side; the Table 5 side carries Monte Carlo error from
# 2,000 simulated patients (about 0.7% standard error on a mean with a 31%
# CV). A transcription error in CL/F, a relative-bioavailability factor or the
# evening-dose multiplier moves these by 9% or more.
stopifnot(all(abs(closed$pct_diff) < 5))All twelve rows agree within 1.8%, which confirms the relative-bioavailability reference (100-mg morning inpatient dose), the outpatient and region multipliers, the 1.26-fold evening-dose factor and the 0.76 factor for the 200-mg dose.
Simulated steady state (Table 5 and Figure 4)
A virtual cohort of 200 patients per Table 5 row is simulated with interindividual variability and without residual error, as in the paper: 55 kg, albumin 4.0 g/dL (not hypoalbuminemic), no efavirenz, outpatient setting. Twice-daily doses are 12 hours apart, the first of each day being the morning dose; once-daily doses are morning doses. Concentrations are recorded every hour on day 1 and on day 20, matching the paper’s hourly simulation grid.
n_per_group <- 200
tau_day <- 24
n_days <- 20
groups <- table5 |>
select(regimen, region, sex) |>
mutate(group = row_number())
subjects <- groups[rep(seq_len(nrow(groups)), each = n_per_group), ] |>
mutate(
id = row_number(),
WT = 55,
SEXF = as.integer(sex == "Female"),
ALB = 40,
CONMED_EFV = 0,
OUTPATIENT = 1,
REGION_EASTASIA = as.integer(region == "Northeast Asian"),
REGION_SOUTHEASTASIA = as.integer(region == "Southeast Asian"),
STUDY_242_07_208 = 0,
STUDY_242_09_213 = 0
)
dose_rows <- bind_rows(
subjects |>
filter(regimen == "100 mg BID") |>
tidyr::crossing(day = seq_len(n_days) - 1, evening = c(0L, 1L)) |>
mutate(time = day * tau_day + 12 * evening, amt = 100, cmt = ifelse(evening == 1L, "depot2", "depot")),
subjects |>
filter(regimen == "200 mg QD") |>
tidyr::crossing(day = seq_len(n_days) - 1) |>
mutate(time = day * tau_day, evening = 0L, amt = 200, cmt = "depot")
) |>
mutate(evid = 1L, DOSE_DELAMANID_MG = amt) |>
select(-day, -evening)
obs_times <- c(0:24, (n_days - 1) * tau_day + 0:24)
obs_rows <- subjects |>
tidyr::crossing(time = obs_times) |>
mutate(evid = 0L, cmt = "central", amt = 0)
# DOSE_DELAMANID_MG is a property of the dose record (it sets that dose's
# relative bioavailability); observation rows carry the value of the most
# recent dose so the column has no gaps.
events <- bind_rows(obs_rows, dose_rows) |>
arrange(id, time, desc(evid == 0L)) |>
group_by(id) |>
tidyr::fill(DOSE_DELAMANID_MG, .direction = "downup") |>
ungroup() |>
select(
id, time, evid, amt, cmt, WT, SEXF, ALB, CONMED_EFV, OUTPATIENT,
REGION_EASTASIA, REGION_SOUTHEASTASIA, STUDY_242_07_208,
STUDY_242_09_213, DOSE_DELAMANID_MG
)
rxode2::rxSetSeed(20201216)
mod_nores <- rxode2::zeroRe(mod, which = "sigma")
#> ℹ parameter labels from comments will be replaced by 'label()'
#> Warning: No sigma parameters in the model
sim <- as.data.frame(rxode2::rxSolve(
mod_nores, events,
returnType = "data.frame", covsInterpolation = "locf"
))
sim <- sim |>
left_join(subjects |> select(id, group, regimen, region, sex), by = "id") |>
mutate(treatment = paste(regimen, region, sex, sep = " / "))PKNCA
ss_start <- (n_days - 1) * tau_day
conc_df <- sim |>
dplyr::filter(!is.na(Cc)) |>
select(id, time, Cc, treatment, regimen, region, sex)
dose_df <- events |>
dplyr::filter(evid == 1) |>
left_join(subjects |> select(id, regimen, region, sex), by = "id") |>
mutate(treatment = paste(regimen, region, sex, sep = " / ")) |>
select(id, time, amt, treatment)
conc_obj <- PKNCA::PKNCAconc(
conc_df, Cc ~ time | treatment + id,
concu = "ng/mL", timeu = "h"
)
dose_obj <- PKNCA::PKNCAdose(
dose_df, amt ~ time | treatment + id,
doseu = "mg"
)
intervals <- data.frame(
start = c(0, ss_start),
end = c(tau_day, ss_start + tau_day),
cmax = c(TRUE, TRUE),
auclast = c(TRUE, TRUE)
)
nca_res <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals))
nca_df <- as.data.frame(nca_res)
ss_means <- nca_df |>
dplyr::filter(start == ss_start, PPTESTCD %in% c("cmax", "auclast")) |>
group_by(treatment, PPTESTCD) |>
summarise(PPORRES = mean(PPORRES), .groups = "drop")
reference <- table5 |>
mutate(treatment = paste(regimen, region, sex, sep = " / ")) |>
select(treatment, cmax, auclast)
cmp <- nlmixr2lib::ncaComparisonTable(
simulated = ss_means,
reference = reference,
by = "treatment",
units = c(cmax = "ng/mL", auclast = "ng*h/mL"),
tolerance_pct = 10
)
knitr::kable(
cmp,
caption = paste(
"Mean steady-state (day 20) Cmax and AUC0-24 by Table 5 group: 200",
"simulated patients per group versus the paper's 2,000."
)
)| NCA parameter | treatment | Reference | Simulated | % diff |
|---|---|---|---|---|
| Cmax (ng/mL) | 100 mg BID / Non-Asian / Male | 333 | 325 | -2.3% |
| Cmax (ng/mL) | 100 mg BID / Non-Asian / Female | 334 | 342 | +2.5% |
| Cmax (ng/mL) | 100 mg BID / Northeast Asian / Male | 516 | 522 | +1.1% |
| Cmax (ng/mL) | 100 mg BID / Northeast Asian / Female | 511 | 506 | -1.1% |
| Cmax (ng/mL) | 100 mg BID / Southeast Asian / Male | 474 | 464 | -2.2% |
| Cmax (ng/mL) | 100 mg BID / Southeast Asian / Female | 464 | 475 | +2.4% |
| Cmax (ng/mL) | 200 mg QD / Non-Asian / Male | 258 | 263 | +2.1% |
| Cmax (ng/mL) | 200 mg QD / Non-Asian / Female | 263 | 258 | -1.9% |
| Cmax (ng/mL) | 200 mg QD / Northeast Asian / Male | 400 | 405 | +1.3% |
| Cmax (ng/mL) | 200 mg QD / Northeast Asian / Female | 400 | 389 | -2.9% |
| Cmax (ng/mL) | 200 mg QD / Southeast Asian / Male | 366 | 374 | +2.2% |
| Cmax (ng/mL) | 200 mg QD / Southeast Asian / Female | 364 | 358 | -1.6% |
| AUClast (ng*h/mL) | 100 mg BID / Non-Asian / Male | 6860 | 6790 | -1.1% |
| AUClast (ng*h/mL) | 100 mg BID / Non-Asian / Female | 6880 | 7160 | +4.0% |
| AUClast (ng*h/mL) | 100 mg BID / Northeast Asian / Male | 10700 | 10900 | +2.0% |
| AUClast (ng*h/mL) | 100 mg BID / Northeast Asian / Female | 10500 | 10500 | +0.1% |
| AUClast (ng*h/mL) | 100 mg BID / Southeast Asian / Male | 9810 | 9640 | -1.8% |
| AUClast (ng*h/mL) | 100 mg BID / Southeast Asian / Female | 9550 | 9880 | +3.4% |
| AUClast (ng*h/mL) | 200 mg QD / Non-Asian / Male | 4620 | 4730 | +2.2% |
| AUClast (ng*h/mL) | 200 mg QD / Non-Asian / Female | 4660 | 4600 | -1.4% |
| AUClast (ng*h/mL) | 200 mg QD / Northeast Asian / Male | 7190 | 7260 | +1.0% |
| AUClast (ng*h/mL) | 200 mg QD / Northeast Asian / Female | 7120 | 6990 | -1.8% |
| AUClast (ng*h/mL) | 200 mg QD / Southeast Asian / Male | 6610 | 6820 | +3.1% |
| AUClast (ng*h/mL) | 200 mg QD / Southeast Asian / Female | 6480 | 6420 | -1.0% |
auclast here is the AUC over the day-20 24-hour
interval, the quantity Table 5 labels AUC0-24.
pct <- ss_means |>
inner_join(
reference |> tidyr::pivot_longer(-treatment, names_to = "PPTESTCD", values_to = "ref"),
by = c("treatment", "PPTESTCD")
) |>
mutate(pct_diff = 100 * (PPORRES / ref - 1))
# Each simulated mean carries about 2% Monte Carlo error (200 patients, ~30%
# CV); the paper's about 0.7%. Assert on the centre and on the envelope.
stopifnot(
nrow(pct) == 24,
abs(median(pct$pct_diff)) < 5,
max(abs(pct$pct_diff)) < 12
)Accumulation ratio
The paper reports that the ratio of steady-state AUC0-24 to day-1 AUC0-24 for 100 mg twice daily was 3.1 to 3.4 across subpopulations. In the cohort below the ratio of mean AUCs is somewhat higher, because patients in the slow tails of the absorption and distribution IIV accumulate more than the typical patient; the typical-value ratio is checked against the paper’s range in the typical-profile section further down.
acc <- nca_df |>
dplyr::filter(PPTESTCD == "auclast") |>
mutate(day = ifelse(start == 0, "day1", "ss")) |>
select(id, treatment, day, PPORRES) |>
tidyr::pivot_wider(names_from = day, values_from = PPORRES) |>
left_join(subjects |> select(id, regimen, region), by = "id") |>
dplyr::filter(regimen == "100 mg BID") |>
group_by(region) |>
summarise(
`Ratio of mean AUC0-24` = mean(ss) / mean(day1),
`Median individual ratio` = stats::median(ss / day1),
.groups = "drop"
)
knitr::kable(acc, digits = 2, caption = "Accumulation ratio (AUC0-24 on day 20 / AUC0-24 on day 1), 100 mg BID, simulated cohort.")| region | Ratio of mean AUC0-24 | Median individual ratio |
|---|---|---|
| Non-Asian | 3.49 | 3.43 |
| Northeast Asian | 3.50 | 3.41 |
| Southeast Asian | 3.51 | 3.42 |
Implementation identity
For each simulated patient on 100 mg twice daily, the steady-state
AUC over the day must equal the bioavailable daily dose divided by that
patient’s clearance. The check uses the patient’s own cl,
fdepot (morning) and fdepot2 (evening) read
from the solve, so it exercises the two depots with their own lag times,
absorption rate constants and bioavailability.
indiv <- sim |>
dplyr::filter(regimen == "100 mg BID", time >= ss_start) |>
group_by(id) |>
summarise(
cl = first(cl),
f_am = first(fdepot),
f_pm = first(fdepot2),
.groups = "drop"
) |>
inner_join(
nca_df |> dplyr::filter(start == ss_start, PPTESTCD == "auclast") |> select(id, auc = PPORRES),
by = "id"
) |>
mutate(ratio = auc * cl / (1000 * 100 * (f_am + f_pm)))
summary(indiv$ratio)
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 0.8631 0.9985 0.9999 0.9972 1.0001 1.0035
# The trapezoidal AUC on an hourly grid slightly overstates or understates
# a sharp absorption peak for patients with a fast ka, so assert on the centre
# and a robust envelope rather than on every patient.
stopifnot(
nrow(indiv) == 6 * n_per_group,
abs(stats::median(indiv$ratio) - 1) < 0.01,
stats::quantile(abs(indiv$ratio - 1), 0.9) < 0.03
)Figure 4
Figure 4 of the paper shows boxplots of steady-state AUC0-24 for 100 mg twice daily versus 200 mg once daily. In the published figure all nine panels look identical even though Table 5 and the region effects imply 40-53% higher exposure in the Asian panels, so the figure is not used as a numerical target; the plot below shows the simulated distributions by region.
nca_df |>
dplyr::filter(start == ss_start, PPTESTCD == "auclast") |>
left_join(subjects |> select(id, regimen, region), by = "id") |>
ggplot(aes(regimen, PPORRES)) +
geom_boxplot(fill = "lightblue") +
facet_wrap(~region) +
labs(
x = "Regimen", y = "Steady-state AUC0-24 (ng*h/mL)",
title = "Simulated steady-state AUC0-24, 55-kg outpatients",
caption = "Compare with Figure 4 of Wang 2020."
) +
theme_bw()
Typical concentration-time profile
The model application in the paper switched from 100 mg twice daily for 20 days to 200 mg once daily in the morning. The typical-value profile for a 55-kg male outpatient in each region is shown below.
typ_subj <- tibble(
region = c("Non-Asian", "Northeast Asian", "Southeast Asian"),
id = 1:3
)
typ_dose <- bind_rows(
tidyr::crossing(typ_subj, day = 0:19, evening = c(0L, 1L)) |>
mutate(time = day * 24 + 12 * evening, amt = 100, cmt = ifelse(evening == 1L, "depot2", "depot")),
tidyr::crossing(typ_subj, day = 20:29) |>
mutate(time = day * 24, evening = 0L, amt = 200, cmt = "depot")
) |>
mutate(evid = 1L, DOSE_DELAMANID_MG = amt) |>
select(-day, -evening)
typ_obs <- tidyr::crossing(typ_subj, time = seq(0, 30 * 24, by = 1)) |>
mutate(evid = 0L, cmt = "central", amt = 0)
typ_events <- bind_rows(typ_obs, typ_dose) |>
arrange(id, time, desc(evid == 0L)) |>
group_by(id) |>
tidyr::fill(DOSE_DELAMANID_MG, .direction = "downup") |>
ungroup() |>
mutate(
WT = 55, SEXF = 0, ALB = 40, CONMED_EFV = 0, OUTPATIENT = 1,
REGION_EASTASIA = as.integer(region == "Northeast Asian"),
REGION_SOUTHEASTASIA = as.integer(region == "Southeast Asian"),
STUDY_242_07_208 = 0, STUDY_242_09_213 = 0
) |>
select(
id, time, evid, amt, cmt, WT, SEXF, ALB, CONMED_EFV, OUTPATIENT,
REGION_EASTASIA, REGION_SOUTHEASTASIA, STUDY_242_07_208,
STUDY_242_09_213, DOSE_DELAMANID_MG
)
typ_sim <- as.data.frame(rxode2::rxSolve(
mod_typ, typ_events,
returnType = "data.frame", covsInterpolation = "locf"
)) |>
left_join(typ_subj, by = "id")
#> ℹ omega/sigma items treated as zero: 'etalcl', 'etalvp', 'etalka_am', 'etalfdepot', 'etalq', 'etalka_pm'
#> Warning: multi-subject simulation without without 'omega'
ggplot(typ_sim, aes(time / 24, Cc, colour = region)) +
geom_line() +
labs(
x = "Time (days)", y = "Delamanid (ng/mL)", colour = "Region",
title = "Typical profile: 100 mg BID for 20 days, then 200 mg QD (morning)"
) +
theme_bw()
auc_window <- function(d, lo, hi) {
d <- d[d$time >= lo & d$time <= hi, ]
sum(diff(d$time) * (head(d$Cc, -1) + tail(d$Cc, -1)) / 2)
}
typ_na <- typ_sim[typ_sim$region == "Non-Asian", ]
acc_typ <- auc_window(typ_na, 456, 480) / auc_window(typ_na, 0, 24)
acc_typ
#> [1] 3.198938
# Deterministic typical-value solve; the paper's reported range is 3.1 to 3.4.
stopifnot(acc_typ > 3.1, acc_typ < 3.4)The typical patient’s accumulation ratio for 100 mg twice daily is 3.20, inside the 3.1 to 3.4 range the paper reports.
Assumptions and deviations
-
Morning and evening doses. The paper estimates
separate absorption rate constants (each with its own IIV), lag times
and relative bioavailability for morning and evening doses but does not
print its control stream. The model gives each its own depot: morning
doses go into
depot, evening doses intodepot2, so every dose is absorbed with the rate constant, lag time and bioavailability of its own dosing time. If the original analysis instead switched the rate constant of a single depot with a morning/evening flag, the two forms differ only while one dose is still being absorbed when the next is given, and not at all in AUC. The maintainers chose separate depots because a flag that drives a lag time must be read at the dose record, and rxode2 does not reliably read a time-varying covariate that setsalag()from the dose record itself. - Dose-level bioavailability. Table 4 gives relative bioavailability for the 200-mg dose and for doses above 200 mg against the 100-mg reference. The model applies the 200-mg value to any dose above 100 mg up to 200 mg. Only 100, 200, 250 and 300 mg were studied, so intermediate doses are an extrapolation.
-
Weight reference. The Methods describe a normalised
power model without printing the reference weight. 55 kg, the population
median (Table 2) and the weight of the Figure 1 typical patient, is
used; the Figure 1 weight markers reproduce
(WT / 55)^0.316. -
Albumin units. The canonical
ALBcolumn is in g/L; the model divides by 10 to reach the g/dL scale of the published effect. Albumin is the baseline value in the source analysis. -
Enrollment region. “Northeast Asian” (China, Japan,
Korea) and “Southeast Asian” (the Philippines) are regions of enrollment
among Asian patients (Table 2). They are carried as
REGION_EASTASIAandREGION_SOUTHEASTASIA; Asian patients enrolled in Peru belong to the non-Asian reference. - Residual error. The combined error model has independent proportional and additive terms (Methods equation), with a larger proportional SD in trial 242-07-208 and a larger additive SD in trial 242-09-213 (Table 4). Table 4 reports variances; their square roots are used.
- Results text versus Table 4. The Results state that CL/F is about 22% higher at albumin 2.8 g/dL; Table 4 gives 18.9% and Figure 1 agrees with Table 4. The model uses Table 4.
- Figure 4. The nine published panels appear identical and do not show the region effects that Table 5 reports; Table 5 is used as the numerical target.