---
title: "Nelfinavir (Hirt 2007)"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Nelfinavir (Hirt 2007)}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 4.5)
library(nlmixr2lib)
library(PKNCA)
library(rxode2)
library(dplyr)
library(tidyr)
library(ggplot2)
```

# Model and source

* Citation: `r rxode2::rxode2(readModelDb("Hirt_2007_nelfinavir"))$reference`
* Description: `r rxode2::rxode2(readModelDb("Hirt_2007_nelfinavir"))$description`
* Article: <https://doi.org/10.1111/j.1365-2125.2007.02885.x>

# Population

The Hirt 2007 dataset pools 196 women (4 cohorts) at one French perinatology
centre (Port Royal Hospital, Paris) and one obstetrics centre (Louis Mourier
Hospital, Colombes). Cohort breakdown per Table 1: 75 women sampled on the day
of delivery (77 samples; gestational age 31-41 weeks, median 38 weeks); 53
pregnant women sampled before delivery (75 samples, mean gestation 32 weeks,
range 10-39); 61 non-pregnant women (120 samples) sampled as part of routine
therapeutic-drug monitoring; and 7 additional women who contributed both
pregnant and non-pregnant samples (20 samples; counted once in the subject
total). Four women on concurrent ritonavir were excluded. Mean weight was
73 +/- 14 kg in the delivery cohort and 65 +/- 15 kg in the non-delivery
cohorts; mean age was 32.7 +/- 4.4 and 33.4 +/- 4.5 years, respectively. All
women received nelfinavir as part of antiretroviral therapy: 92 percent of the
delivery cohort and 82 percent of non-delivery women on the 1250 mg twice
daily regimen, the remainder on 750 mg thrice daily. Concomitant NNRTI use
was reported in 8 of 75 delivery women and 13 of 121 non-delivery women.

The same information is available programmatically via the model's
`population` metadata
(`rxode2::rxode2(readModelDb("Hirt_2007_nelfinavir"))$population`).

# Source trace

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

| Equation / parameter | Value | Source location |
|----------------------|-------|-----------------|
| `lka` (= log 0.67)           | ka = 0.67 1/h         | Table 5 row `ka` |
| `ltlag` (= log 0.87)         | tlag = 0.87 h         | Table 5 row `tlag` |
| `lvc` (= log 557)            | V/F = 557 L           | Table 5 row `V` |
| `lcl` (= log 39.5)           | CL_Nm_No/F = 39.5 L/h | Table 5 row `CL_Nm_No/F` |
| `lcl_m8m` (= log 0.77)       | CL_Nm_M8m/F = 0.77 L/h| Table 5 row `CL_Nm_M8m/F` |
| `lk_m8m_out` (= log 3.41)    | k_M8m_M8o = 3.41 1/h  | Table 5 row `k_M8m_M8o` |
| `lcl_nc` (= log 0.058)       | CL_Nm_Nc/F = 0.058 L/h| Table 5 row `CL_Nm_Nc/F` |
| `lk_nc_naf` (= log 0.23)     | k_Nc_Naf = 0.23 1/h   | Table 5 row `k_Nc_Naf` |
| `lk_naf_out` (= log 0.36)    | k_Naf_No = 0.36 1/h   | Table 5 row `k_Naf_No` |
| `lk_m8m_m8c` (= log 0.35)    | k_M8m_M8c = 0.35 1/h  | Table 5 row `k_M8m_M8c` |
| `lk_m8c_m8af` (= log 0.59)   | k_M8c_M8af = 0.59 1/h | Table 5 row `k_M8c_M8af` |
| `lk_m8af_out` (= log 0.49)   | k_M8af_M8o = 0.49 1/h | Table 5 row `k_M8af_M8o` |
| `e_day_delivery_cl_vc`       | theta_DEL = 1.92      | Table 5 row `CL_Nm_No/F and V, theta_DEL` |
| `e_wt_cl`                    | theta_BW(DEL) = 2.81  | Table 5 row `CL_Nm_No/F, theta_BW (on DEL)` |
| `e_preg_k_m8m_out`           | theta_PREG = 0.67     | Table 5 row `k_M8m_M8o, theta_PREG` |
| `e_wt_k_m8m_out`             | theta_BW = 1.41       | Table 5 row `k_M8m_M8o, theta_BW` |
| `e_conmed_nnrti_k_m8m_out`   | theta_NNRTI = 1.48    | Table 5 row `k_M8m_M8o, theta_NNRTI` |
| `etalvc` variance            | CV 132%, omega^2 = log(1+1.32^2) = 1.0089 | Table 5 row w(V) |
| `etalcl` variance            | CV 53%, omega^2 = 0.2476  | Table 5 row w(CL_Nm_No/F) |
| `etalk_m8m_out` variance     | CV 74%, omega^2 = 0.4368  | Table 5 row w(k_M8m_M8o/F) |
| `etalcl_nc` variance         | CV 34%, omega^2 = 0.1094  | Table 5 row w(CL_Nm_Nc) |
| `etalk_m8m_m8c` variance     | CV 76%, omega^2 = 0.4560  | Table 5 row w(k_M8m_M8c) |
| `addSd` (mother nelfinavir)  | 1.07 mg/L             | Table 5 row s_NELFI_MOTHER |
| `addSd_Cm8` (mother M8)      | 0.24 mg/L             | Table 5 row s_M8_MOTHER |
| `addSd_Ccord_n` (cord nelf.) | 0.09 mg/L (shared w/ AF) | Table 5 row s_NELFI_FETUS/CORD |
| `addSd_Caf_n` (AF nelf.)     | 0.09 mg/L (shared w/ cord) | Table 5 row s_NELFI_FETUS/CORD |
| `addSd_Ccord_m8` (cord M8)   | 0.12 mg/L             | Table 5 row s_M8_CORD |
| `addSd_Caf_m8` (AF M8)       | 0.03 mg/L             | Table 5 row s_M8_FETUS |
| 6-compartment ODE system     | n/a                   | Figure 1 schematic + Methods 'Population pharmacokinetic modelling' |
| Day-of-delivery cohort coding (PREG=0, DAY_DELIVERY=1) | n/a | Methods 'On the day of delivery, the coding was zero for pregnancy and one for delivery.' |
| Body-weight covariate references (73 kg delivery; 63 kg M8) | n/a | Results 'A 10 kg increase from mean bodyweight increased CL_Nm_No 1.44 fold' and 'for every 10 kg increase above the mean weight of 63 kg, k_M8m_M8o was increased by 1.23' |

# Virtual cohort

Original observed data are not publicly available. The figures below use
three typical-value cohorts whose covariate distributions match Hirt 2007's
Table 1: a non-pregnant, non-NNRTI-coadministered 65 kg woman; a pregnant
non-delivery, non-NNRTI 65 kg woman (gestation prior to labour); and a
day-of-delivery, non-NNRTI 73 kg woman. All cohorts receive 1250 mg
nelfinavir twice daily orally, the most common regimen (92 percent of the
delivery cohort).

```{r cohort}
set.seed(20070927L)

# One subject per cohort, simulated at typical values across one steady-state
# dosing day (the 8th day of treatment per the source paper's >= 6-day
# steady-state assumption). The Hirt 2007 model treats the day of delivery as
# a discrete cohort; the simulation horizon includes 14 doses (7 days of BID
# dosing) covering observations through the morning following the final dose.
make_subject <- function(id, weight, preg, day_delivery, nnrti) {
  # Dosing events: 1250 mg BID for 7 days (14 doses; q12h).
  dose <- tibble(
    id           = id,
    time         = seq(0, by = 12, length.out = 14L),
    amt          = 1250,
    evid         = 1L,
    cmt          = "depot",
    WT           = weight,
    PREG         = preg,
    DAY_DELIVERY = day_delivery,
    CONMED_NNRTI = nnrti
  )
  # Observation grid: dense early to capture absorption, then through 192 h
  # to cover a full steady-state trough at the end of the regimen.
  obs <- tibble(
    id           = id,
    time         = unique(c(seq(0, 12, by = 0.25), seq(12, 192, by = 0.5))),
    amt          = 0,
    evid         = 0L,
    cmt          = "Cc",
    WT           = weight,
    PREG         = preg,
    DAY_DELIVERY = day_delivery,
    CONMED_NNRTI = nnrti
  )
  dplyr::bind_rows(dose, obs) |>
    dplyr::arrange(time, dplyr::desc(evid))
}

events <- dplyr::bind_rows(
  make_subject(1L, weight = 65, preg = 0L, day_delivery = 0L, nnrti = 0L) |>
    dplyr::mutate(cohort = "Non-pregnant, 65 kg"),
  make_subject(2L, weight = 65, preg = 1L, day_delivery = 0L, nnrti = 0L) |>
    dplyr::mutate(cohort = "Pregnant non-delivery, 65 kg"),
  make_subject(3L, weight = 73, preg = 0L, day_delivery = 1L, nnrti = 0L) |>
    dplyr::mutate(cohort = "Day of delivery, 73 kg")
)

stopifnot(!anyDuplicated(unique(events[, c("id", "time", "evid")])))
```

# Simulation

```{r simulate-typical}
mod         <- rxode2::rxode2(readModelDb("Hirt_2007_nelfinavir"))
mod_typical <- rxode2::zeroRe(mod)
sim_typical <- rxode2::rxSolve(
  mod_typical,
  events = events,
  keep   = c("WT", "PREG", "DAY_DELIVERY", "CONMED_NNRTI", "cohort")
) |>
  as.data.frame()
```

# Replicate published Figure 4 (nelfinavir, mother and cord)

Figure 4 of Hirt 2007 plots typical individual predicted nelfinavir
concentrations in maternal plasma (left) and umbilical plasma (right) over a
single dosing day on the day-of-delivery cohort. The chunk below renders the
analogous typical-value trajectories for the three virtual cohorts during the
final steady-state day of the BID regimen (t = 156-168 h, i.e. dosing day 7
relative to the start of the simulation horizon).

```{r figure-4-nelfinavir}
plot_steady <- sim_typical |>
  dplyr::filter(time >= 156, time <= 168) |>
  dplyr::mutate(time_in_day = time - 156)

p_nelf <- ggplot(plot_steady, aes(time_in_day, Cc, colour = cohort)) +
  geom_line(size = 0.8) +
  labs(
    x = "Time within steady-state dosing day (h)",
    y = "Maternal nelfinavir Cc (mg/L)",
    title = "Maternal nelfinavir concentration over one steady-state dosing day",
    caption = "Analogous to Hirt 2007 Figure 4 (maternal plasma panel)."
  ) +
  theme_minimal(base_size = 11)

p_cord <- ggplot(plot_steady, aes(time_in_day, Ccord_n, colour = cohort)) +
  geom_line(size = 0.8) +
  labs(
    x = "Time within steady-state dosing day (h)",
    y = "Cord nelfinavir (mg/L)",
    title = "Cord (umbilical) nelfinavir concentration over one steady-state dosing day",
    caption = "Analogous to Hirt 2007 Figure 4 (cord plasma panel)."
  ) +
  theme_minimal(base_size = 11)

p_nelf
p_cord
```

# Replicate published Figure 5 (M8 metabolite, mother and cord)

Figure 5 of Hirt 2007 plots the analogous M8 metabolite concentrations in
maternal plasma and umbilical plasma.

```{r figure-5-m8}
p_m8m <- ggplot(plot_steady, aes(time_in_day, Cm8, colour = cohort)) +
  geom_line(size = 0.8) +
  labs(
    x = "Time within steady-state dosing day (h)",
    y = "Maternal M8 (mg/L)",
    title = "Maternal M8 metabolite concentration",
    caption = "Analogous to Hirt 2007 Figure 5 (maternal plasma panel)."
  ) +
  theme_minimal(base_size = 11)

p_m8c <- ggplot(plot_steady, aes(time_in_day, Ccord_m8, colour = cohort)) +
  geom_line(size = 0.8) +
  labs(
    x = "Time within steady-state dosing day (h)",
    y = "Cord M8 (mg/L)",
    title = "Cord (umbilical) M8 concentration",
    caption = "Analogous to Hirt 2007 Figure 5 (cord plasma panel)."
  ) +
  theme_minimal(base_size = 11)

p_m8m
p_m8c
```

# Cord-to-mother and amniotic-fluid-to-cord concentration ratios

Hirt 2007 Table 3 reports median concentration ratios across the cohort for
nelfinavir and M8. Below, the typical-value ratios at the midpoint of the
final steady-state dose (t = 162 h) are computed for the day-of-delivery
73 kg woman, the cohort represented in Table 3.

```{r ratios-table}
ratio_row <- sim_typical |>
  dplyr::filter(cohort == "Day of delivery, 73 kg",
                abs(time - 162) < 1e-6) |>
  dplyr::slice(1) |>
  dplyr::transmute(
    `Nelfinavir cord:mother (Ccord_n / Cc)`      = Ccord_n / Cc,
    `M8 cord:mother (Ccord_m8 / Cm8)`            = Ccord_m8 / Cm8,
    `Nelfinavir AF:cord (Caf_n / Ccord_n)`       = Caf_n / Ccord_n,
    `M8 AF:cord (Caf_m8 / Ccord_m8)`             = Caf_m8 / Ccord_m8
  ) |>
  tidyr::pivot_longer(everything(), names_to = "Ratio", values_to = "Simulated (typical, t=162 h)")

published_ratios <- tibble::tribble(
  ~Ratio,                                          ~`Hirt 2007 Table 3 median`,
  "Nelfinavir cord:mother (Ccord_n / Cc)",         0.25,
  "M8 cord:mother (Ccord_m8 / Cm8)",               0.55,
  "Nelfinavir AF:cord (Caf_n / Ccord_n)",          0.59,
  "M8 AF:cord (Caf_m8 / Ccord_m8)",                1.00
)

ratio_compare <- dplyr::left_join(ratio_row, published_ratios, by = "Ratio")

knitr::kable(
  ratio_compare,
  caption = "Simulated typical-value placental-transfer ratios vs Hirt 2007 Table 3 medians.",
  digits  = 3,
  align   = c("l", "r", "r")
)
```

The simulated steady-state nelfinavir cord:mother ratio is in close agreement
with the paper's median (0.25). The simulated AF:cord ratios diverge from the
medians because the steady-state simulation samples a single instant in the
dosing interval; the published medians pool across irregularly timed delivery
samples drawn from a heterogeneous gestational-age cohort, so an exact
numeric match is not expected here.

# PKNCA validation -- maternal nelfinavir steady state

The Hirt 2007 paper does not report a tabulated steady-state NCA (the focus
of the publication is the placental transfer ratios). We use PKNCA to derive
the steady-state maternal nelfinavir AUC0-tau, Cmax_ss, Tmax_ss, and Cmin_ss
for each cohort over the final dosing interval (t = 156-168 h), so that
downstream users have a reproducible programmatic NCA output that anchors the
typical-value pharmacokinetics encoded in the model.

```{r pknca-mother}
sim_nca <- sim_typical |>
  dplyr::filter(!is.na(Cc)) |>
  dplyr::select(id, time, Cc, cohort) |>
  dplyr::rename(treatment = cohort)

dose_df <- events |>
  dplyr::filter(evid == 1) |>
  dplyr::select(id, time, amt, cohort) |>
  dplyr::rename(treatment = cohort)

conc_obj <- PKNCA::PKNCAconc(sim_nca, Cc ~ time | treatment + id,
                             concu = "mg/L", timeu = "h")
dose_obj <- PKNCA::PKNCAdose(dose_df, amt ~ time | treatment + id,
                             doseu = "mg")

# Steady-state interval: the final dosing interval (t = 156 to 168 h).
intervals <- data.frame(
  start = 156,
  end   = 168,
  cmax  = TRUE,
  tmax  = TRUE,
  cmin  = TRUE,
  auclast = TRUE
)

nca_res <- PKNCA::pk.nca(PKNCA::PKNCAdata(conc_obj, dose_obj, intervals = intervals))

nca_summary <- as.data.frame(nca_res$result) |>
  dplyr::select(treatment, PPTESTCD, PPORRES) |>
  tidyr::pivot_wider(names_from = PPTESTCD, values_from = PPORRES) |>
  dplyr::transmute(
    Cohort                  = treatment,
    `Cmax_ss (mg/L)`        = round(cmax, 3),
    `Tmax_ss (h, relative)` = round(tmax - 156, 2),
    `Cmin_ss (mg/L)`        = round(cmin, 3),
    `AUC0-tau (mg*h/L)`     = round(auclast, 2)
  )

knitr::kable(
  nca_summary,
  caption = paste("Simulated steady-state nelfinavir NCA per cohort",
                  "(typical-value, no IIV). Tau = 12 h dosing interval.",
                  "Tmax is reported relative to the start of the dosing",
                  "interval at t = 156 h.")
)
```

The non-pregnant 65 kg cohort yields a steady-state Cmin around 1 mg/L
(matching the paper's stated minimum effective concentration in adults for
nelfinavir) and Cmax in the 3-4 mg/L range. The day-of-delivery 73 kg cohort
yields markedly lower steady-state exposure consistent with the paper's
reported maternal bioavailability drop on the day of delivery (nelfinavir CL
and V each increase ~92 percent, decreasing apparent steady-state exposure).

# Assumptions and deviations

* **Residual-error interpretation.** Hirt 2007 Table 5 lists five additive
  residual SDs for the six-output model: `s NELFI MOTHER` (1.07), `s M8
  MOTHER` (0.24), `s NELFI FETUS/CORD` (0.09), `s M8 FETUS` (0.03), `s M8
  CORD` (0.12). The label `FETUS/CORD` was interpreted as a single SD shared
  between the nelfinavir cord and amniotic-fluid observations (the slash
  notation indicates pooling); the labels `M8 FETUS` and `M8 CORD` were
  interpreted as `M8 in amniotic fluid` (= 0.03) and `M8 in cord plasma`
  (= 0.12) respectively, consistent with the magnitude pattern (lower SD in
  the matrix further downstream from the source). The paper narrative uses
  `fetus` and `cord` interchangeably in several places, so a small chance
  remains that the M8 mapping could be swapped (`M8 FETUS` = cord plasma and
  `M8 CORD` = amniotic fluid). This convention was approved via sidecar
  before the model was drafted (request-001, response-001).
* **Within-individual residual correlation.** Hirt 2007 reports a
  within-individual correlation of `0.50 +/- 31 %` between the nelfinavir
  and M8 residual errors. nlmixr2's standard residual-error structure does
  not natively support a cross-output correlation on the residual errors,
  so the correlation is omitted from the encoded model. The omission only
  affects the propagation of within-individual error variance in
  simulations that draw from the residual model; typical-value (no-RE)
  predictions, RTV / VPC summaries, and PKNCA-derived NCA metrics are not
  affected.
* **Fixed downstream-compartment volumes.** Per the paper, the volume of
  the maternal M8 compartment, the cord nelfinavir compartment, the cord
  M8 compartment, the amniotic-fluid nelfinavir compartment, and the
  amniotic-fluid M8 compartment were not estimable and were each fixed at
  1 L. Concentrations in these compartments are therefore numerically
  equal to the amount of drug in each compartment (in mg). This is a
  source-paper structural choice carried forward verbatim and is the
  reason the cord-side transfer parameters mix clearances (CL_Nm_Nc) and
  rate constants (k_M8m_M8c, k_Nc_Naf, k_M8c_M8af, k_Naf_No, k_M8af_M8o).
* **Pregnancy effect on CL_Nm_No deleted in backward elimination.** The
  paper retained pregnancy (`PREG`) as a covariate on M8 maternal
  elimination (theta = 0.67) but deleted the effect on maternal nelfinavir
  clearance during backward elimination (OFV penalty of 5 < 7 retention
  threshold). The final model encoded here therefore carries `PREG` only
  on `k_M8m_M8o`.
* **AGE screened but not retained.** Subject age was screened as a
  continuous covariate during model building but did not produce a
  significant effect on any final-model parameter, so it is not part of
  `covariateData`.
* **Two reference body weights.** The body-weight power scaling uses two
  separate reference weights: 73 kg for the day-of-delivery cohort effect
  on `CL_Nm_No` (the delivery-cohort mean per Table 1) and 63 kg for the
  M8 elimination effect (the full-database mean stated in the Results
  text). Both references are propagated verbatim from the source paper.
* **PKNCA validation scope.** Hirt 2007 does not report a tabulated NCA
  table for nelfinavir or M8 PK. The PKNCA block above computes
  steady-state Cmax / Tmax / Cmin / AUC0-tau for each cohort so that
  downstream users have a reproducible programmatic NCA output anchoring
  the typical-value pharmacokinetics, but there are no per-cohort
  published NCA reference values to compare against. The placental-transfer
  ratio table earlier in the vignette is the load-bearing source-paper
  comparison.
