---
title: "Inotuzumab (Wu 2024)"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Inotuzumab (Wu 2024)}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
library(nlmixr2lib)
library(rxode2)
library(dplyr)
library(tidyr)
library(ggplot2)
library(PKNCA)
```

# Inotuzumab ozogamicin population PK in pediatric and adult B-cell precursor ALL / NHL

Simulate inotuzumab ozogamicin (InO) concentration-time profiles using
the final population PK model of Wu et al. (2024). The model was
developed by reanalyzing the Garrett 2019 adult InO population PK model
on a pooled adult + pediatric dataset (8924 serum InO concentrations
from 818 patients across 12 studies — 531 adult B-cell non-Hodgkin
lymphoma (NHL), 234 adult B-cell precursor acute lymphoblastic leukemia
(BCP-ALL), and 53 pediatric BCP-ALL participants from ITCC-059) and
adding pediatric-specific covariate effects. The structural model is a
two-compartment disposition with IV input and a total clearance that
sums a linear (steady-state) component (CL_SS, the paper's CL1) and a
time-decaying target-mediated component
(CL_t = CL_TIME * exp(-kdes * time), the paper's CL2 arm).

\[
  CL_{\text{total}}(t) = CL_{\text{SS}} + CL_{\text{TIME}} \, e^{-k_{\text{des}}\, t}
\]

* Article: <https://doi.org/10.1007/s40262-024-01386-z>
* PubMed (PMID 38907948): <https://pubmed.ncbi.nlm.nih.gov/38907948/>

## Population

The pooled analysis included three cohorts:

* **Adult B-cell NHL** (n = 531; 5609 observations): age 18–92 y
  (median 65 y), LBM 24.4–87.4 kg (median 53.6 kg), albumin
  2.20–5.20 g/dL.
* **Adult BCP-ALL** (n = 234; 2752 observations): age 20–79 y
  (median 46 y), LBM 29.4–95.9 kg (median 54.4 kg), peripheral-blood
  blasts median 4.00% (absolute counts median 0.82 x 10^9).
* **Pediatric BCP-ALL** (n = 53; 563 observations; ITCC-059 phase IA
  + phase II): age 1–17 y (median 9 y), body weight 12.7–147 kg
  (median 34.3 kg), LBM 10.9–69.0 kg (median 29.5 kg), peripheral-blood
  blasts median 3.00%; 67.9% male; 13 patients on dose level 1
  (1.4 mg/m^2/cycle), 40 on dose level 2 / RP2D (1.8 mg/m^2/cycle).

Demographics are summarized in Wu 2024 Table 2 and ESM Table 3. The
same metadata is available programmatically via
`readModelDb("Wu_2024_inotuzumab")$population`.

## Source trace

The per-parameter origin is recorded as an in-file comment next to each
`ini()` entry in `inst/modeldb/specificDrugs/Wu_2024_inotuzumab.R`. The
table below collects the mapping in one place for reviewer audit.

| Element | Source location | Value / form |
| --- | --- | --- |
| Two-compartment IV model | Wu 2024 Methods Section 2.3 + Figure 1 (schematic) | `d/dt(central) = -kel*central - k12*central + k21*peripheral1`; `d/dt(peripheral1) = k12*central - k21*peripheral1` |
| Total clearance | Wu 2024 Methods Section 2.3 | `CL_total = CL_SS + CL_TIME * exp(-cl_exp_kdes * time)` (paper notation: CL1 + CL2*exp(-kdes*time)) |
| CL_SS, Vc, CL_TIME, kdes, Q, Vp typical values | Wu 2024 Table 3 | 0.130 L/h, 6.49 L, 0.569 L/h, 0.0577 1/h, 0.0437 L/h, 4.74 L (for an NHL adult at LBM 52.7 kg, AGE 60 y, BLSTABL 0.352, RITUX 0) |
| LBM on CL_SS | Wu 2024 Table 3 | Power: `(LBM/52.7)^1.05` |
| LBM on Vc | Wu 2024 Table 3 | Power: `(LBM/52.7)^0.977` |
| LBM on CL_TIME | Wu 2024 Table 3 | Power: `(LBM/52.7)^0.687` |
| ALL effect (DIS_BCPALL) on CL_SS | Wu 2024 Table 3 | Dummy: `1 + (-0.767)*DIS_BCPALL` |
| ALL effect on CL_TIME | Wu 2024 Table 3 | Dummy: `1 + (-0.362)*DIS_BCPALL` |
| ALL effect on kdes | Wu 2024 Table 3 | Dummy: `1 + (-0.924)*DIS_BCPALL` |
| BLSTABL on kdes (BCP-ALL only) | Wu 2024 Table 3 | Power, gated: `(BLSTABL/0.352)^(-0.0484*DIS_BCPALL)` |
| AGE on kdes (BCP-ALL only) | Wu 2024 Table 3 | Power, gated: `(AGE/60)^(-0.296*DIS_BCPALL)` |
| Concomitant rituximab (CONMED_RITUX) on CL_SS | Wu 2024 Table 3 | Dummy: `1 + (-0.132)*CONMED_RITUX` |
| Reference subject | Wu 2024 Table 3 / Methods | LBM 52.7 kg (population median), AGE 60 y, BLSTABL 0.352 x 10^9, NHL adult (DIS_BCPALL = 0), no concomitant rituximab |
| IIV (omega^2 = CV^2) | Wu 2024 Table 3 | CV%: CL_SS 40.0, Vc 40.1, CL_TIME 73.7, kdes 59.7. CL_SS+Vc+CL_TIME form a 3x3 correlated block (covariances 0.136 / 0.194 / 0.204; correlations 84.7% / 65.8% / 69.0%); kdes is independent. |
| Residual error (log-scale SD) | Wu 2024 Table 3, footnote d | Adult NHL 0.444; adult BCP-ALL 0.612; pediatric BCP-ALL 0.452 (`Cc ~ lnorm(expSd)`; the packaged `ini()` defaults to the pediatric BCP-ALL value 0.452) |
| Pediatric RP2D regimen | Wu 2024 Methods Section 2.1 / 2.6 | 1.8 mg/m^2/cycle in cycle 1 (fractions 0.8 + 0.5 + 0.5 mg/m^2 on days 1, 8, 15) then 1.5 mg/m^2/cycle for up to five cycles of 28 days (fractions 0.5 + 0.5 + 0.5 mg/m^2). Each dose is a 60-min IV infusion. |
| Adult dosing regimen | Wu 2024 Methods Section 2.1 / Introduction | Same RP2D regimen (1.8 then 1.5 mg/m^2/cycle, IV). |
| Pediatric terminal half-life | Wu 2024 Section 3.5 | 423 h (~17.6 d) for pediatric BCP-ALL; 285 h (~11.9 d) for adult BCP-ALL |

## Covariate column naming

| Source column | Canonical column used here | Notes |
| --- | --- | --- |
| `LBM` | `LBM` (kg) | Time-fixed baseline. Boer's equation for adults; Peters et al. for children. |
| `AGE` | `AGE` (years) | Time-fixed baseline. |
| `ALL` | `DIS_BCPALL` (binary) | 1 = BCP-ALL, 0 = NHL. New canonical entry registered in `inst/references/covariate-columns.md`. Wu 2024 calls this the "ALL effect" because it bundles disease type and the corresponding bioanalytical assay difference. |
| `RITUX` | `CONMED_RITUX` (binary) | 1 = on concomitant rituximab combination therapy, 0 = without rituximab (reference). Wu 2024 Table 3 footnote b explicitly flips the reference category vs. the predecessor Garrett 2019 adult model (which used "with rituximab" as reference). New canonical entry. |
| `BLSTABL` | `BLSTABL` (10^9 counts) | Baseline absolute blast counts in peripheral blood. Not applicable for NHL patients; supply 0.352 (the BCP-ALL median) for NHL subjects so the gated power term evaluates to 1. New canonical entry. |

## Virtual population

Wu 2024 does not publish individual baseline covariates. The cohort
below approximates the ITCC-059 pediatric BCP-ALL population centered
on the medians reported in Wu 2024 Table 2.

```{r virtual-pop}
set.seed(2024)
n_subj <- 200

pop <- data.frame(
  ID           = seq_len(n_subj),
  AGE          = pmin(pmax(round(rnorm(n_subj, 9, 4.5)), 1), 17),
  LBM          = pmin(pmax(rnorm(n_subj, 29.5, 11), 10.9), 69.0),
  DIS_BCPALL   = 1L,
  CONMED_RITUX = 0L,
  # BLSTABL is highly skewed in the pediatric ITCC-059 cohort
  # (median 0 with a long upper tail extending to 32 x 10^9 counts).
  # For a power covariate centered at 0.352 we cannot use 0 directly;
  # draw from a log-normal centered on the BCP-ALL reference 0.352 to
  # avoid singularities in the (BLSTABL/0.352)^exp term while preserving
  # the right-skewed character.
  BLSTABL      = pmin(pmax(rlnorm(n_subj, log(0.352), 1.6), 0.01), 32)
)

# Compute body weight implied by the pediatric Peters et al. LBM relationship is
# circular; instead approximate BSA from a Mosteller-like surrogate using
# (heuristic) BSA ~ LBM-scaled body weight for children. We only need BSA to
# convert mg/m^2 doses to mg, so use the published Wu 2024 cohort relationship
# (median LBM 29.5 -> median BSA 1.18) and scale linearly with LBM.
pop$BSA <- pop$LBM * (1.18 / 29.5)
```

## Dosing dataset — pediatric RP2D (1.8 / 1.5 mg/m^2/cycle, IV)

Cycle 1 (21 days): 0.8 + 0.5 + 0.5 mg/m^2 on days 1, 8, 15. Cycles 2–6
(28-day cycles): 0.5 + 0.5 + 0.5 mg/m^2 on days 1, 8, 15. Each dose is
a 60-minute IV infusion. Below we simulate three full cycles
(1 cycle of 21 days + 2 cycles of 28 days = 77 days = 1848 h).

```{r dosing-rp2d}
infusion_dur_h <- 1   # 60-minute IV infusion (Wu 2024 Methods 2.1)

# Cycle / fraction schedule (mg/m^2 per fractioned dose).
schedule <- tibble::tribble(
  ~cycle, ~day, ~mg_m2,
  1L,      1L,    0.8,
  1L,      8L,    0.5,
  1L,     15L,    0.5,
  2L,     22L,    0.5,
  2L,     29L,    0.5,
  2L,     36L,    0.5,
  3L,     50L,    0.5,
  3L,     57L,    0.5,
  3L,     64L,    0.5
)

doses <- tidyr::crossing(pop, schedule) %>%
  mutate(
    TIME = (day - 1) * 24,         # day 1 -> hour 0
    AMT  = mg_m2 * BSA,            # mg
    RATE = AMT / infusion_dur_h,   # mg/h (60-min infusion)
    EVID = 1L,
    CMT  = "central",
    DV   = NA_real_
  ) %>%
  select(ID, TIME, AMT, RATE, EVID, CMT, DV,
         AGE, LBM, DIS_BCPALL, CONMED_RITUX, BLSTABL)

obs_times <- sort(unique(c(
  seq(0, 24, by = 1),                   # day 1 hourly
  seq(24, 24 * 21, by = 12),            # cycle 1 every 12 h
  seq(24 * 21, 24 * 49, by = 24),       # cycle 2 daily
  seq(24 * 49, 24 * 77, by = 24)        # cycle 3 daily
)))

obs <- tidyr::crossing(pop, TIME = obs_times) %>%
  mutate(
    AMT = NA_real_, RATE = NA_real_,
    EVID = 0L, CMT = "central", DV = NA_real_
  ) %>%
  select(ID, TIME, AMT, RATE, EVID, CMT, DV,
         AGE, LBM, DIS_BCPALL, CONMED_RITUX, BLSTABL)

events <- bind_rows(doses, obs) %>%
  arrange(ID, TIME, desc(EVID)) %>%
  as.data.frame()

# Disjoint-ID guard for the bind_rows (single cohort here, but cheap regression check).
stopifnot(!anyDuplicated(unique(events[, c("ID", "TIME", "EVID")])))
```

## Simulate the pediatric RP2D regimen

```{r simulate-rp2d}
mod <- nlmixr2lib::readModelDb("Wu_2024_inotuzumab")
sim <- rxode2::rxSolve(mod, events, returnType = "data.frame")
```

### Pediatric concentration-time profile (replicates Figure 8 of Wu 2024 — pediatric panel)

```{r figure-8-ped, fig.width = 7, fig.height = 5}
sim_summary <- sim %>%
  filter(time > 0, !is.na(Cc), Cc > 0) %>%
  group_by(time) %>%
  summarise(
    median = median(Cc),
    lo10   = quantile(Cc, 0.10),
    hi90   = quantile(Cc, 0.90),
    .groups = "drop"
  )

ggplot(sim_summary, aes(x = time / 24)) +
  geom_ribbon(aes(ymin = lo10, ymax = hi90), alpha = 0.20, fill = "darkgreen") +
  geom_line(aes(y = median), color = "darkgreen", linewidth = 0.9) +
  scale_y_log10() +
  labs(
    x = "Time (days)",
    y = "Inotuzumab ozogamicin (ng/mL)",
    title = "Simulated pediatric BCP-ALL inotuzumab ozogamicin PK",
    subtitle = sprintf("RP2D (1.8 then 1.5 mg/m^2/cycle, IV; N = %d virtual pediatric patients)", n_subj),
    caption = "Replicates Figure 8 of Wu 2024 (pediatric panel; median + 10th-90th percentile)."
  ) +
  theme_bw()
```

## Adult BCP-ALL comparison (replicates Figure 8 of Wu 2024 — adult panel)

For the adult cohort we re-use the same dosing schedule (which is also
the adult approved regimen) but draw covariates from the adult BCP-ALL
population (Wu 2024 Table 2): median LBM 54.4 kg, median age 46 y.

```{r simulate-adult-rp2d}
set.seed(2024)
pop_adult <- data.frame(
  ID           = seq_len(n_subj) + n_subj,                # disjoint IDs
  AGE          = pmin(pmax(round(rnorm(n_subj, 46, 14)), 20), 79),
  LBM          = pmin(pmax(rnorm(n_subj, 54.4, 12), 29.4), 95.9),
  DIS_BCPALL   = 1L,
  CONMED_RITUX = 0L,
  BLSTABL      = pmin(pmax(rlnorm(n_subj, log(0.82), 1.5), 0.01), 254)
)
pop_adult$BSA <- pop_adult$LBM * (1.86 / 54.4)            # adult BCP-ALL median BSA / LBM

doses_a <- tidyr::crossing(pop_adult, schedule) %>%
  mutate(
    TIME = (day - 1) * 24,
    AMT  = mg_m2 * BSA,
    RATE = AMT / infusion_dur_h,
    EVID = 1L, CMT = "central", DV = NA_real_
  ) %>%
  select(ID, TIME, AMT, RATE, EVID, CMT, DV,
         AGE, LBM, DIS_BCPALL, CONMED_RITUX, BLSTABL)

obs_a <- tidyr::crossing(pop_adult, TIME = obs_times) %>%
  mutate(AMT = NA_real_, RATE = NA_real_,
         EVID = 0L, CMT = "central", DV = NA_real_) %>%
  select(ID, TIME, AMT, RATE, EVID, CMT, DV,
         AGE, LBM, DIS_BCPALL, CONMED_RITUX, BLSTABL)

events_adult <- bind_rows(doses_a, obs_a) %>%
  arrange(ID, TIME, desc(EVID)) %>%
  as.data.frame()

stopifnot(!anyDuplicated(unique(events_adult[, c("ID", "TIME", "EVID")])))

sim_adult <- rxode2::rxSolve(mod, events_adult, returnType = "data.frame")
```

```{r figure-8-overlay, fig.width = 7, fig.height = 5}
both <- bind_rows(
  sim       %>% mutate(cohort = "Pediatric BCP-ALL"),
  sim_adult %>% mutate(cohort = "Adult BCP-ALL")
) %>%
  filter(time > 0, !is.na(Cc), Cc > 0) %>%
  group_by(cohort, time) %>%
  summarise(
    median = median(Cc),
    lo10   = quantile(Cc, 0.10),
    hi90   = quantile(Cc, 0.90),
    .groups = "drop"
  )

ggplot(both, aes(x = time / 24, color = cohort, fill = cohort)) +
  geom_ribbon(aes(ymin = lo10, ymax = hi90), alpha = 0.18, color = NA) +
  geom_line(aes(y = median), linewidth = 0.9) +
  scale_y_log10() +
  scale_color_manual(values = c("Pediatric BCP-ALL" = "darkgreen",
                                "Adult BCP-ALL"     = "firebrick")) +
  scale_fill_manual(values = c("Pediatric BCP-ALL" = "darkgreen",
                               "Adult BCP-ALL"     = "firebrick")) +
  labs(
    x = "Time (days)",
    y = "Inotuzumab ozogamicin (ng/mL)",
    color = NULL, fill = NULL,
    title = "Simulated InO PK at the RP2D — pediatric vs adult BCP-ALL",
    caption = "Replicates Figure 8 of Wu 2024 (adult vs pediatric overlay)."
  ) +
  theme_bw()
```

## PKNCA validation

Compute steady-state cumulative AUC at the end of cycle 1 (per Wu 2024
Section 3.4 / Table 4: median 26.1 x 10^3 ng*h/mL among pediatric
responders). The PKNCA window is the full 21-day cycle 1
(time 0 to 504 h) for both cohorts.

```{r nca}
nca_conc <- bind_rows(
  sim       %>% filter(time <= 504) %>%
    transmute(ID = id, time, Cc, treatment = "Pediatric BCP-ALL"),
  sim_adult %>% filter(time <= 504) %>%
    transmute(ID = id, time, Cc, treatment = "Adult BCP-ALL")
)

nca_dose <- bind_rows(
  doses   %>% transmute(ID, time = TIME, AMT, treatment = "Pediatric BCP-ALL"),
  doses_a %>% transmute(ID, time = TIME, AMT, treatment = "Adult BCP-ALL")
) %>%
  filter(time <= 504)

conc_obj <- PKNCA::PKNCAconc(nca_conc, Cc ~ time | treatment + ID)
dose_obj <- PKNCA::PKNCAdose(nca_dose, AMT ~ time | treatment + ID)

intervals <- data.frame(
  start    = 0,
  end      = 504,    # 21 days = 504 hours
  cmax     = TRUE,
  tmax     = TRUE,
  auclast  = TRUE
)

data_obj <- PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals)
nca_res  <- PKNCA::pk.nca(data_obj)
nca_summary <- summary(nca_res)
knitr::kable(
  nca_summary,
  digits  = 3,
  caption = "Simulated NCA over cycle 1 (0-504 h) for pediatric and adult BCP-ALL cohorts."
)
```

### Comparison against Wu 2024 Table 4 / Table 5

```{r nca-published-comparison}
# Cumulative AUC at end of cycle 1 from Wu 2024 (Tables 4 and 5):
#   - Table 4 (pediatric trial-data-driven, model-based AUC): responders 26.1
#     [18.9-35.0], non-responders 10.1 [9.19-16.1]; combined median 19.7
#     (informally) x 10^3 ng*h/mL.
#   - Table 5 (model-based simulation at RP2D):
#       Adult BCP-ALL:     19.7 [12.1-30.3] x 10^3 ng*h/mL
#       Pediatric BCP-ALL: 26.6 [17.9-37.0] x 10^3 ng*h/mL
sim_auc <- bind_rows(
  sim       %>% mutate(cohort = "Pediatric BCP-ALL"),
  sim_adult %>% mutate(cohort = "Adult BCP-ALL")
) %>%
  filter(time <= 504, !is.na(Cc)) %>%
  arrange(cohort, id, time) %>%
  group_by(cohort, id) %>%
  summarise(
    AUC0_504 = sum(diff(time) * (head(Cc, -1) + tail(Cc, -1)) / 2),
    .groups  = "drop"
  )

q <- function(x) {
  c(median   = median(x),
    p25      = quantile(x, 0.25, names = FALSE),
    p75      = quantile(x, 0.75, names = FALSE))
}

published <- tibble::tribble(
  ~Cohort,                ~Source,         ~`Median AUC0-504 (10^3 ng*h/mL)`, ~`IQR (10^3 ng*h/mL)`,
  "Adult BCP-ALL",        "Wu 2024 Table 5",                          19.7,  "12.1-30.3",
  "Pediatric BCP-ALL",    "Wu 2024 Table 5",                          26.6,  "17.9-37.0"
)

simulated <- sim_auc %>%
  group_by(cohort) %>%
  summarise(
    `Median AUC0-504 (10^3 ng*h/mL)` = round(median(AUC0_504) / 1000, 1),
    `IQR (10^3 ng*h/mL)`             = sprintf("%.1f-%.1f",
                                                quantile(AUC0_504, 0.25) / 1000,
                                                quantile(AUC0_504, 0.75) / 1000),
    Source = "This vignette (simulated)",
    .groups = "drop"
  ) %>%
  rename(Cohort = cohort) %>%
  select(Cohort, Source,
         `Median AUC0-504 (10^3 ng*h/mL)`,
         `IQR (10^3 ng*h/mL)`)

knitr::kable(
  bind_rows(published, simulated) %>% arrange(Cohort, Source),
  caption = paste(
    "Cycle-1 cumulative AUC0-504h: simulated vs. published Wu 2024",
    "Table 5 model-based simulation values."
  )
)
```

The simulated medians are expected to track the published Wu 2024
Table 5 values to within ~10–20%. Residual differences come from the
virtual-population covariate distributions (especially the BLSTABL
right-skew, BSA-from-LBM heuristic, and our finite N = 200 vs the
paper's 1000-subject simulation), not from differences in the model
parameters themselves.

## Adult NHL profile

For completeness, simulate the adult NHL cohort. NHL patients have no
BLSTABL or AGE effect on kdes; supply BLSTABL = 0.352 (the BCP-ALL
reference) so the gated power term evaluates to 1.

```{r simulate-adult-nhl}
set.seed(2024)
pop_nhl <- data.frame(
  ID           = seq_len(n_subj) + 2L * n_subj,
  AGE          = pmin(pmax(round(rnorm(n_subj, 65, 12)), 18), 92),
  LBM          = pmin(pmax(rnorm(n_subj, 53.6, 12), 24.4), 87.4),
  DIS_BCPALL   = 0L,                     # NHL
  CONMED_RITUX = 0L,
  BLSTABL      = 0.352                   # gated off for NHL
)
pop_nhl$BSA <- pop_nhl$LBM * (1.83 / 53.6)

doses_n <- tidyr::crossing(pop_nhl, schedule) %>%
  mutate(
    TIME = (day - 1) * 24,
    AMT  = mg_m2 * BSA,
    RATE = AMT / infusion_dur_h,
    EVID = 1L, CMT = "central", DV = NA_real_
  ) %>%
  select(ID, TIME, AMT, RATE, EVID, CMT, DV,
         AGE, LBM, DIS_BCPALL, CONMED_RITUX, BLSTABL)

obs_n <- tidyr::crossing(pop_nhl, TIME = obs_times) %>%
  mutate(AMT = NA_real_, RATE = NA_real_,
         EVID = 0L, CMT = "central", DV = NA_real_) %>%
  select(ID, TIME, AMT, RATE, EVID, CMT, DV,
         AGE, LBM, DIS_BCPALL, CONMED_RITUX, BLSTABL)

events_nhl <- bind_rows(doses_n, obs_n) %>%
  arrange(ID, TIME, desc(EVID)) %>%
  as.data.frame()

stopifnot(!anyDuplicated(unique(events_nhl[, c("ID", "TIME", "EVID")])))

sim_nhl <- rxode2::rxSolve(mod, events_nhl, returnType = "data.frame")
```

## Assumptions and deviations

Wu 2024 does not publish individual baseline covariates, so the virtual
populations approximate the paper's reported medians and ranges:

- **LBM**: drawn from population-specific normal distributions centered
  on the medians in Wu 2024 Table 2 and clipped to the published min/max.
- **AGE**: pediatric BCP-ALL drawn from N(9, 4.5) clipped to 1–17 y;
  adult BCP-ALL N(46, 14) clipped to 20–79 y; adult NHL N(65, 12)
  clipped to 18–92 y, matching Wu 2024 Table 2.
- **BLSTABL**: drawn from a log-normal centered on the reference
  0.352 x 10^9 to avoid a zero-singularity in the
  `(BLSTABL/0.352)^exponent` power covariate. The pediatric ITCC-059
  cohort had a true median of 0; for simulation we use the population
  reference because Wu 2024 itself notes BLSTABL is not clinically
  relevant for the InO disposition over the treatment duration.
- **BSA**: approximated from LBM via a per-cohort linear scaling
  (ratio of cohort-median BSA / cohort-median LBM from Wu 2024 Table 2).
  The exact BSA is required only to convert mg/m^2 doses to mg; the
  model's PK parameters depend on LBM, not BSA, so BSA distribution
  errors propagate only through dose magnitude, not through clearance.
- **Race / sex distributions**: not retained as covariates by Wu 2024,
  so not simulated.
- **Residual error**: the packaged `ini()` defaults to the pediatric
  BCP-ALL log-scale SD 0.452. To simulate adult NHL or adult BCP-ALL
  with their published residuals, override via
  `mod <- ini(mod, expSd = 0.444)` (adult NHL) or
  `mod <- ini(mod, expSd = 0.612)` (adult BCP-ALL).
- **`expSd` parameter naming**: deviates from the canonical
  `propSd`/`addSd` names (flagged by `checkModelConventions()`). Wu 2024
  models the residual as additive on log-transformed concentrations
  (NONMEM `Y = LOG(IPRED) + EPS(1)` with `EPS(1) ~ N(0, sigma^2)`),
  which maps to `Cc ~ lnorm(SD)` in nlmixr2 — not a proportional or
  additive linear-scale form. The `expSd` name follows the
  `Cirincione_2017_exenatide` precedent in this repo for log-scale
  residual SDs and is documented as a justified deviation.
- **Concentration units**: dosing in mg, concentration in ng/mL
  (`Cc = (central / vc) * 1000`). The paper reports the bioanalytical
  LLOQ as 1.0 ng/mL, so ng/mL is the natural reporting unit;
  `checkModelConventions()` flags the mg/ng magnitude difference as an
  informational note, with the conversion explicitly applied in the
  model code.
- **Time**: hours (matches Wu 2024 Table 3 unit for kdes 1/h and CL in
  L/h). Half-life and AUC values reported in the paper are quoted in h
  / h*ng/mL or in days; convert as needed.
- **Time-dependent CL `time` semantics**: `time` in `cl_exp_component * exp(-cl_exp_kdes * time)`
  is the integration time from the start of the simulation (= time
  from the first dose for event datasets that begin at t = 0). For
  patients whose first observation is partway through a treatment
  course (e.g., cycle-2 only), build the event table relative to the
  first dose so the time-decay term is on the correct clock.

## Model summary

- **Structure**: 2-compartment IV PK with linear / steady-state (CL_SS,
  paper's CL1) plus time-decaying target-mediated
  (CL_t = CL_TIME * exp(-kdes * time), paper's CL2 arm) clearance
  components. No depot.
- **Population**: pooled adult B-cell NHL + adult BCP-ALL +
  pediatric BCP-ALL (n = 818 across 12 studies; 8924 InO
  concentrations).
- **Reference subject** (NHL adult, LBM 52.7 kg, AGE 60 y,
  BLSTABL 0.352, no rituximab): CL_SS 0.130 L/h, Vc 6.49 L,
  CL_TIME 0.569 L/h, kdes 0.0577 1/h, Q 0.0437 L/h, Vp 4.74 L.
  Terminal half-life ≈ 285 h (~11.9 d) for adult BCP-ALL,
  ≈ 423 h (~17.6 d) for pediatric BCP-ALL (Wu 2024 Section 3.5).
- **Strongest covariates**: LBM on CL_SS (1.05), Vc (0.977), CL_TIME (0.687);
  ALL effect (DIS_BCPALL) on CL_SS (-0.767), CL_TIME (-0.362), kdes (-0.924);
  AGE on kdes (-0.296, BCP-ALL only).

## Reference

* `r rxode2::rxode(readModelDb("Wu_2024_inotuzumab"))$reference`
