---
title: "Risankizumab (Thakre 2022)"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Risankizumab (Thakre 2022)}
  %\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)
```

# Risankizumab population PK in psoriatic arthritis

Simulate risankizumab concentration-time profiles using the final population
PK model of Thakre et al. (2022) in patients with active psoriatic arthritis
(PsA). The source paper pooled data from five studies (one phase 1 healthy-
participant study, one phase 2 dose-ranging study in PsA with an open-label
extension, and two pivotal phase 3 PsA studies, KEEPsAKE 1 and KEEPsAKE 2)
— 3631 concentrations from 1527 individuals.

The model is a two-compartment model with first-order subcutaneous
absorption and first-order elimination. The final covariate set is
body weight, age, serum albumin, serum creatinine, and baseline
high-sensitivity C-reactive protein (CRP) on clearance, plus body weight on central
volume of distribution. ADA titers on CL and body weight on V2 were
evaluated but did not meet retention criteria and are not in the final
model.

## Source trace

| Element | Source location | Value / form |
| --- | --- | --- |
| CL, Vc, Vp, Q, ka, F | Thakre 2022 Table 1 | 0.248 L/day, 4.71 L, 4.26 L, 0.839 L/day, 0.218 /day, 0.835 |
| WT on CL | Thakre 2022 Eq. 2 / Table 1 | Power: (WTKG/70)^0.869 |
| ALB on CL | Thakre 2022 Eq. 2 / Table 1 | Power: (ALB/45)^-0.703 |
| CREAT on CL | Thakre 2022 Eq. 2 / Table 1 | Power: (CRE/70.73)^-0.201 |
| CRP (hs-CRP) on CL | Thakre 2022 Eq. 2 / Table 1 | Power: (CRPHS/5.21)^0.0471 |
| AGE on CL | Thakre 2022 Eq. 2 / Table 1 | Power: (AGE/52)^-0.138 |
| WT on Vc | Thakre 2022 Eq. 3 / Table 1 | Power: (WTKG/70)^1.46 |
| IIV CL / V1 (correlated) | Thakre 2022 Table 1 | var(CL)=0.0943, var(V1)=0.171, cov=0.0836 (correlation ~66%) |
| IIV ka | Thakre 2022 Table 1 | var=0.164 |
| Residual error | Thakre 2022 Table 1 | Proportional, variance = 0.0382 (~19.5% CV) |
| Dosing regimen (clinical) | Thakre 2022 Abstract / Discussion | 150 mg SC at weeks 0 and 4, then every 12 weeks |

## Covariate column naming

| Source column | Canonical column used here |
| --- | --- |
| `WTKG` | `WT` (per `covariate-columns.md`) |
| `AGE` | `AGE` |
| `ALB` (g/L) | `ALB` (g/L) |
| `CRE` (umol/L) | `CREAT` (umol/L; canonical name) |
| `CRPHS` (mg/L) | `CRP` (mg/L; canonical general-scope name; hs-CRP assay documented in `covariateData[[CRP]]`) |

## Virtual population

PsA phase 2/3 trial-like covariate distributions. The source paper does not
publish per-subject data, so the distributions below approximate typical
PsA populations and are centered so that simulated individual parameters
bracket the paper's reference covariates.

```{r virtual-pop}
set.seed(2022)
n_subj <- 500

pop <- data.frame(
  ID    = seq_len(n_subj),
  WT    = rlnorm(n_subj, log(85), 0.22),  # median ~85 kg
  AGE   = round(pmin(pmax(rnorm(n_subj, 51, 12), 18), 80)),
  ALB   = pmin(pmax(rnorm(n_subj, 43, 3.5), 30), 52),     # units g/L
  CREAT = pmin(pmax(rnorm(n_subj, 72, 16), 40), 140),     # units umol/L
  CRP   = rlnorm(n_subj, log(6), 1.1)                     # mg/L, skewed right (hs-CRP)
)
```

## Dosing dataset

Approved PsA clinical regimen: 150 mg SC at weeks 0 and 4, then every
12 weeks (q12w) thereafter. Simulate the first three full dosing
intervals (weeks 0-28), matching Thakre 2022 Table 2.

```{r dosing}
dose_weeks <- c(0, 4, 16, 28)    # 4 SC doses through week 28
dose_times <- dose_weeks * 7     # convert to days

obs_times <- sort(unique(c(
  seq(0,   28,  by = 0.5),
  seq(28,  196, by = 2)
)))

d_dose <- pop %>%
  crossing(TIME = dose_times) %>%
  mutate(
    AMT  = 150,       # mg SC
    EVID = 1,
    CMT  = 1,         # depot
    DV   = NA_real_
  )

d_obs <- pop %>%
  crossing(TIME = obs_times) %>%
  mutate(AMT = NA_real_, EVID = 0, CMT = 2, DV = NA_real_)

d_sim <- bind_rows(d_dose, d_obs) %>%
  arrange(ID, TIME, desc(EVID)) %>%
  as.data.frame()
```

## Simulate

```{r simulate}
mod <- readModelDb("Thakre_2022_risankizumab")
conc_unit <- rxode2::rxode(mod)$units[["concentration"]]
sim <- rxSolve(mod, d_sim, returnType = "data.frame")
```

## Concentration-time profile

```{r pk-plot, fig.width = 7, fig.height = 5}
sim_summary <- sim %>%
  filter(time > 0) %>%
  group_by(time) %>%
  summarise(
    median = median(Cc, na.rm = TRUE),
    lo     = quantile(Cc, 0.05, na.rm = TRUE),
    hi     = quantile(Cc, 0.95, na.rm = TRUE),
    .groups = "drop"
  )

ggplot(sim_summary, aes(x = time / 7)) +
  geom_ribbon(aes(ymin = lo, ymax = hi), alpha = 0.2, fill = "steelblue") +
  geom_line(aes(y = median), color = "steelblue", linewidth = 1) +
  scale_y_log10() +
  labs(
    x = "Time (weeks)",
    y = paste0("Risankizumab concentration (", conc_unit, ")"),
    title = "Simulated risankizumab PK (150 mg SC, weeks 0, 4, 16, 28)",
    subtitle = "Median and 90% prediction interval (N = 500 virtual PsA patients)",
    caption = "Model: Thakre et al. (2022) Rheumatol Ther"
  ) +
  theme_bw()
```

## Per dosing-interval exposures vs Thakre 2022 Table 2

Compute Cmax, Ctrough, and AUC over the first three full dosing
intervals (weeks 0-4, 4-16, 16-28) and compare against Thakre 2022
Table 2.

```{r interval-exposures}
intervals <- tribble(
  ~label,    ~start_wk, ~end_wk,
  "1 (0-4)",   0,   4,
  "2 (4-16)",  4,  16,
  "3 (16-28)", 16, 28
)

ivl_summary <- intervals %>%
  rowwise() %>%
  do({
    row <- .
    sub <- sim %>%
      filter(time >= row$start_wk * 7, time <= row$end_wk * 7, Cc > 0)
    per_id <- sub %>%
      group_by(id) %>%
      summarise(
        Cmax    = max(Cc, na.rm = TRUE),
        Ctrough = Cc[which.max(time)],
        AUCtau  = sum(diff(time) * (head(Cc, -1) + tail(Cc, -1)) / 2),
        .groups = "drop"
      )
    tibble(
      interval = row$label,
      Cmax_median    = median(per_id$Cmax),
      Cmax_mean      = mean(per_id$Cmax),
      Ctrough_median = median(per_id$Ctrough),
      Ctrough_mean   = mean(per_id$Ctrough),
      AUCtau_median  = median(per_id$AUCtau),
      AUCtau_mean    = mean(per_id$AUCtau)
    )
  }) %>%
  bind_rows()

knitr::kable(
  ivl_summary,
  digits = 2,
  caption = paste(
    "Simulated per-interval exposures (compare with Thakre 2022 Table 2:",
    "interval-1 Cmax median 9.40, interval-2 Cmax median 14.1,",
    "interval-3 Cmax median 11.0 ug/mL;",
    "interval-1 Ctrough median 5.68, interval-2 Ctrough median 1.93,",
    "interval-3 Ctrough median 1.52 ug/mL;",
    "interval AUC medians 207, 565, 439 ug*day/mL)."
  )
)
```

## PKNCA validation

Run PKNCA on the third dosing interval (weeks 16-28, steady-state
maintenance), which is the one reported as `Third dosing interval` in
Thakre 2022 Table 2.

```{r nca}
nca_conc <- sim %>%
  filter(time >= 16 * 7, time <= 28 * 7) %>%
  mutate(
    time_rel  = time - 16 * 7,
    treatment = "risankizumab_150mg_q12w"
  ) %>%
  rename(ID = id) %>%
  select(ID, time_rel, Cc, treatment)

nca_dose <- pop %>%
  mutate(
    time_rel  = 0,
    AMT       = 150,
    treatment = "risankizumab_150mg_q12w"
  ) %>%
  select(ID, time_rel, AMT, treatment)

conc_obj <- PKNCAconc(nca_conc, Cc ~ time_rel | treatment + ID)
dose_obj <- PKNCAdose(nca_dose, AMT ~ time_rel | treatment + ID)
data_obj <- PKNCAdata(
  conc_obj,
  dose_obj,
  intervals = data.frame(
    start     = 0,
    end       = 12 * 7,
    cmax      = TRUE,
    tmax      = TRUE,
    auclast   = TRUE,
    half.life = TRUE
  )
)
nca_results <- pk.nca(data_obj)
nca_summary <- summary(nca_results)
knitr::kable(
  nca_summary,
  digits  = 2,
  caption = paste(
    "PKNCA summary for the third dosing interval (weeks 16-28).",
    "Compare Cmax / AUClast against Thakre 2022 Table 2 interval 3."
  )
)
```

## Assumptions and deviations

Thakre 2022 does not publish individual PK or per-subject covariate
values, so the virtual population above approximates typical PsA
phase 2/3 populations rather than reproducing them:

- **Weight:** sampled log-normal around a 85 kg median, SD 0.22 on
  the log scale. The paper references 70 kg; the median in PsA
  phase-3 trials is typically ~85 kg.
- **Age:** normal around 51 years, SD 12, clipped to 18-80. The
  paper references 52 years.
- **Serum albumin:** normal around 43 g/L, SD 3.5, clipped to
  30-52 g/L (reference 45 g/L).
- **Serum creatinine:** normal around 72 umol/L, SD 16, clipped to
  40-140 umol/L (reference 70.73 umol/L).
- **CRP (hs-CRP assay):** log-normal around a median of 6 mg/L (reference 5.21
  mg/L). hs-CRP is highly skewed in PsA.
- **No correlation** between continuous covariates is imposed; the
  paper does not report joint distributions.
- **Dosing regimen** uses the approved PsA label (150 mg SC at
  weeks 0 and 4, then every 12 weeks). Thakre 2022 included earlier
  dose-ranging phase 1 / 2 data; those regimens are not simulated
  here.
- **ADA titers** are not included because they were evaluated but
  did not meet retention criteria in the final model.

## Notes

- **Model:** two-compartment with first-order SC absorption and
  linear elimination. No TMDD.
- **Typical-subject CL** at reference covariates: 0.248 L/day.
  Typical-subject V1: 4.71 L. Typical-subject Vp: 4.26 L.
  Steady-state Vss = V1 + V2 ~ 9.0 L (reference subject; the paper
  cites approximately 0.31 L/day and 6.8 L for Vc at median-PsA
  covariates).
- **Strongest covariates:** body weight (power 0.869 on CL, 1.46 on
  V1) and serum albumin (power -0.703 on CL).

## Reference

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