---
title: "Intravascular (IV) Examples"
---
```{r setup, include=FALSE}
library(PKNCA)
library(dplyr)
library(ggplot2)
conflicted::conflicts_prefer(dplyr::filter, dplyr::select, .quiet = TRUE)
```
## The IV dataset: Indomethacin
We use `datasets::Indometh` — IV bolus indomethacin in 6 subjects, sampled over 8 hours.
```{r}
head(Indometh)
str(Indometh)
```
Columns: `Subject` (factor, 6 levels), `time` (h), `conc` (mcg/mL).
We add dose information. The standard IV bolus dose for this study was 25 mg.
```{r}
d_conc <- as.data.frame(Indometh)
d_dose <- data.frame(
Subject = unique(d_conc$Subject),
dose = 25, # mg
time = 0
)
# Quick look at concentration profiles
ggplot(d_conc, aes(x = time, y = conc, group = Subject, colour = Subject)) +
geom_line() + geom_point() +
scale_y_log10() +
labs(title = "Indomethacin IV — log-linear concentration profiles",
x = "Time (h)", y = "Concentration (mcg/mL)") +
theme_minimal()
```
The log-scale profiles show a biexponential decline — a rapid distribution phase followed by a log-linear terminal phase — typical of IV bolus data; NCA's λz applies to the terminal portion.
---
## Basic IV analysis
```{r}
o_conc <- PKNCAconc(d_conc, conc ~ time | Subject)
o_dose <- PKNCAdose(d_dose, dose ~ time | Subject, route = "intravascular")
# Indometh: no sample at t = 0 (first sample is at 0.25 h).
# auclast/aucinf.obs need a concentration at the interval start, so
# impute = "start_conc0" adds conc = 0 at t = 0. For an IV bolus this
# underestimates the AUC; the auciv* family below uses the back-extrapolated C0.
# Request the core IV parameters
iv_intervals <- data.frame(
start = 0,
end = Inf,
auclast = TRUE,
aucinf.obs = TRUE,
half.life = TRUE,
cmax = TRUE,
tmax = TRUE,
lambda.z = TRUE,
cl.obs = TRUE,
vz.obs = TRUE,
mrt.iv.last = TRUE,
mrt.iv.obs = TRUE
)
o_data <- PKNCAdata(o_conc, o_dose, intervals = iv_intervals, impute = "start_conc0")
o_nca <- pk.nca(o_data)
as.data.frame(o_nca) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject, PPTESTCD)
```
Imputation methods, including `start_conc0`, are described in the [Data Imputation vignette](https://humanpred.github.io/pknca/articles/v08-data-imputation.html). The zero imputed at the dose time keeps this chapter's examples short, but it is not the concentration after an IV bolus: the [`auciv*` family](#iv-route-auc-auciv) and the clearance and volume built on it (`cl.iv.*`, `vz.iv.*`) replace the first segment using the back-extrapolated C0. When `intervals` is omitted, the automatically generated intervals (≥ 0.13.0) treat an IV bolus the same way: they impute with `start_predose_conc0` (a predose concentration if there is one, else 0, keeping any concentration measured at the dose time) and add a separate request for `c0`.
---
## Parameter reference
### Concentration and time landmarks
For IV bolus, Cmax is the first measured concentration (no absorption phase). Tmax is the time of that first sample.
| Parameter | Meaning |
|---|---|
| `cmax` | Maximum observed concentration |
| `tmax` | Time of Cmax |
| `cmin` | Minimum observed concentration in the interval |
| `tmin` | Time of the minimum observed concentration (≥ 0.13.0) |
| `tfirst` | First time with a non-zero (non-BLQ) concentration |
| `tlast` | Last time with a measurable concentration |
| `clast.obs` | Observed concentration at `tlast` |
| `clast.pred` | Predicted concentration at `tlast` (from λz fit) |
| `count_conc` | Total observations (including BLQ) |
| `count_conc_measured` | Observations above LOQ (non-BLQ) |
| `lambda.z.time.last` | Last timepoint used in the λz regression |
```{r}
landmark_params <- data.frame(
start = 0,
end = Inf,
cmax = TRUE,
tmax = TRUE,
cmin = TRUE,
tmin = TRUE,
tfirst = TRUE,
tlast = TRUE,
clast.obs = TRUE,
clast.pred = TRUE,
count_conc = TRUE,
count_conc_measured = TRUE
)
o_nca_lm <- pk.nca(PKNCAdata(o_conc, o_dose, intervals = landmark_params, impute = "start_conc0"))
as.data.frame(o_nca_lm) |>
filter(PPTESTCD %in% c("cmax","tmax","cmin","tmin","tfirst","tlast",
"clast.obs","clast.pred","count_conc","count_conc_measured")) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject, PPTESTCD)
```
### C0 — extrapolated initial concentration
For IV bolus, the true concentration at time 0 is not directly measured (the first sample is taken minutes later). When `c0` is requested, PKNCA tries a chain of methods and uses the first that succeeds: a measured, nonzero concentration at the dose time (`c0`); otherwise back-extrapolation of the semilog line through the first two measured post-dose concentrations (`logslope`); otherwise the first post-dose concentration (`c1`), then the minimum concentration (`cmin`), then zero (`set0`). Here the value at t = 0 is an imputed 0 rather than a measured concentration, so `logslope` supplies C0.
```{r}
iv_with_c0 <- data.frame(
start = 0,
end = Inf,
c0 = TRUE,
cmax = TRUE,
auclast = TRUE,
aucinf.obs = TRUE
)
o_data_c0 <- PKNCAdata(o_conc, o_dose, intervals = iv_with_c0, impute = "start_conc0")
o_nca_c0 <- pk.nca(o_data_c0)
as.data.frame(o_nca_c0) |>
filter(PPTESTCD %in% c("c0", "cmax", "auclast", "aucinf.obs")) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject, PPTESTCD)
```
> **Note:** C0 > Cmax is expected for IV bolus — Cmax is the first measured point, C0 is extrapolated back to time 0.
### AUC variants
| Parameter | Meaning |
|---|---|
| `auclast` | AUC from 0 to last measurable concentration (trapezoidal) |
| `aucinf.obs` | AUC extrapolated to ∞, using observed Clast |
| `aucinf.pred` | AUC extrapolated to ∞, using predicted Clast from λz fit |
| `aucpext.obs` | % of AUCinf that is extrapolated (quality check) |
All of these are computed with the current integration method (default **lin up/log down**) — see the [AUC chapter](auc-methods.qmd) for the available methods and how to choose one. AUC families are covered in [AUC Calculation with PKNCA](https://humanpred.github.io/pknca/articles/v05-auc-calculation-with-PKNCA.html).
```{r}
auc_params <- data.frame(
start = 0,
end = Inf,
auclast = TRUE,
aucinf.obs = TRUE,
aucinf.pred = TRUE,
aucpext.obs = TRUE
)
o_data_auc <- PKNCAdata(o_conc, o_dose, intervals = auc_params, impute = "start_conc0")
o_nca_auc <- pk.nca(o_data_auc)
as.data.frame(o_nca_auc) |>
filter(PPTESTCD %in% c("auclast", "aucinf.obs", "aucinf.pred", "aucpext.obs")) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject, PPTESTCD)
```
> **Quality check:** `aucpext.obs` > 20% (the default `max.aucinf.pext` threshold) means too much of the AUC is extrapolated — the study may not have sampled long enough.
### Half-life and λz
λz (lambda.z) is the terminal elimination rate constant estimated from log-linear regression of the terminal phase. Half-life = ln(2) / λz.
```{r}
hl_params <- data.frame(
start = 0,
end = Inf,
lambda.z = TRUE,
half.life = TRUE,
r.squared = TRUE,
lambda.z.n.points = TRUE
)
o_data_hl <- PKNCAdata(o_conc, o_dose, intervals = hl_params, impute = "start_conc0")
o_nca_hl <- pk.nca(o_data_hl)
as.data.frame(o_nca_hl) |>
filter(PPTESTCD %in% c("lambda.z", "half.life", "r.squared", "lambda.z.n.points")) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject, PPTESTCD)
```
**Controlling half-life quality:**
```{r}
# Stricter: require at least 4 points in the fit; then exclude fits with
# R² < 0.95 (min.hl.r.squared is applied by the exclusion rule, not by the fit)
o_data_strict <- PKNCAdata(
o_conc, o_dose,
intervals = hl_params,
impute = "start_conc0",
options = list(min.hl.points = 4)
)
o_nca_strict <- pk.nca(o_data_strict) |>
exclude(FUN = exclude_nca_min.hl.r.squared(0.95))
as.data.frame(o_nca_strict) |>
filter(PPTESTCD %in% c("half.life", "r.squared", "lambda.z.n.points")) |>
select(Subject, PPTESTCD, PPORRES, exclude) |>
arrange(Subject, PPTESTCD)
```
The λz point-selection algorithm and its quality criteria are detailed in the [Half-life chapter](halflife.qmd) and the [Half-Life Calculation vignette](https://humanpred.github.io/pknca/articles/v06-half-life-calculation.html).
**Excluding specific points from λz:**
Use the `exclude_half.life` argument of `PKNCAconc()` to name a logical column (here `excl_hl`) marking points that should not be included in the terminal regression. Below, subject 1's 8 h sample is dropped from the λz fit, and the regression is re-selected without it. The half-life parameters need no concentration at the dose time, so this interval is calculated without imputation:
```{r}
d_conc_excl <- d_conc |>
mutate(excl_hl = ifelse(Subject == "1" & time == 8, TRUE, NA))
o_conc_excl <- PKNCAconc(
d_conc_excl,
conc ~ time | Subject,
exclude_half.life = "excl_hl"
)
hl_params_times <- hl_params |>
mutate(lambda.z.time.first = TRUE, lambda.z.time.last = TRUE)
o_nca_hl_all <- pk.nca(PKNCAdata(o_conc, o_dose, intervals = hl_params_times))
o_nca_excl_hl <- pk.nca(PKNCAdata(o_conc_excl, o_dose, intervals = hl_params_times))
# Subject 1's terminal fit changes when the 8 h point is excluded
bind_rows(
as.data.frame(o_nca_hl_all) |> mutate(version = "all points"),
as.data.frame(o_nca_excl_hl) |> mutate(version = "8 h excluded")
) |>
filter(Subject == "1",
PPTESTCD %in% c("lambda.z.time.first", "lambda.z.time.last",
"lambda.z.n.points", "half.life")) |>
select(version, PPTESTCD, PPORRES) |>
tidyr::pivot_wider(names_from = PPTESTCD, values_from = PPORRES)
```
With all points, the best fit uses the last three samples (5 to 8 h). Without the 8 h sample, the selected fit runs from 2 to 6 h with five points, and the half-life is shorter.
::: {.callout-warning}
In the PKNCA development version this book documents, combining `exclude_half.life` (or `include_half.life`) with an imputation that adds a concentration, such as `start_conc0`, misaligns the per-point flags with the concentrations: the flags stay attached to the original row positions while the imputed point shifts the concentrations by one. Calculate half-life with point selection in an interval without imputation, as here.
:::
### Clearance and volume
For IV dosing, clearance and volume are obtained directly (no bioavailability factor involved), unlike the apparent CL/F and Vz/F of extravascular routes.
| Parameter | Formula | Meaning |
|---|---|---|
| `cl.obs` | Dose / AUCinf.obs | Total body clearance (L/h) |
| `cl.pred` | Dose / AUCinf.pred | CL using predicted Clast |
| `cl.last` | Dose / AUClast | CL using AUClast only (no extrapolation) |
| `cl.all` | Dose / AUCall | CL using AUCall (BLQs as zero) |
| `vz.obs` | CL.obs / λz | Volume of distribution — terminal phase |
| `vz.pred` | CL.pred / λz | Vz using predicted Clast |
| `vss.obs` | CL.obs × MRT | Volume at steady state (observed) |
| `vss.pred` | CL.pred × MRT | Volume at steady state (predicted) |
| `vss.iv.obs` | CL.obs × MRT.iv.obs | Vss with the IV MRT (infusion-duration correction) |
| `cl.iv.obs` | Dose / AUCiv,inf,obs | CL from the AUC with C0 back-extrapolation (≥ 0.13.0) |
| `cl.iv.last` | Dose / AUCiv,last | As above, from `aucivlast` (≥ 0.13.0) |
| `vz.iv.obs` | CL.iv.obs / λz | Vz from the back-extrapolated AUC (≥ 0.13.0) |
PKNCA 0.13.0 completed these families across AUC bases: each of `cl.*`, `vz.*`, and `vss.*` has `.obs`, `.pred`, `.last`, `.all`, and interval-AUC (`.int.last`, `.int.all`, `.int.inf.obs`, `.int.inf.pred`) forms, and the IV bolus variants `cl.iv.*`, `vz.iv.*` (built on `auciv*`) and `vss.iv.*` (built on `mrt.iv.*`) come in the matching forms (`cl.iv.all`, `cl.ivint.last`, `vz.iv.last`, `vss.ivint.all`, …). The full list is printed at the end of this chapter.
```{r}
cl_params <- data.frame(
start = 0,
end = Inf,
cl.obs = TRUE,
cl.pred = TRUE,
cl.last = TRUE,
vz.obs = TRUE,
vz.pred = TRUE,
vss.obs = TRUE,
vss.iv.obs = TRUE,
cl.iv.obs = TRUE,
vz.iv.obs = TRUE
)
o_data_cl <- PKNCAdata(o_conc, o_dose, intervals = cl_params, impute = "start_conc0")
o_nca_cl <- pk.nca(o_data_cl)
as.data.frame(o_nca_cl) |>
filter(PPTESTCD %in% c("cl.obs", "cl.pred", "cl.last", "vz.obs", "vss.obs", "vss.iv.obs",
"cl.iv.obs", "vz.iv.obs")) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject, PPTESTCD)
```
`cl.iv.obs` is lower than `cl.obs` for every subject because its AUC includes the back-extrapolated area between the dose and the first sample, which the imputed zero leaves out of `aucinf.obs`.
### Mean residence time (MRT)
MRT quantifies the average time a drug molecule spends in the body.
For IV, the AUMC (area under the first moment curve) method gives MRT = AUMC / AUC.
All MRT variants for IV:
| Parameter | Meaning |
|---|---|
| `mrt.iv.last` | MRT using AUMClast and AUClast (IV correction) |
| `mrt.iv.obs` | MRT extrapolated to ∞, observed Clast (IV correction) |
| `mrt.iv.pred` | MRT extrapolated to ∞, predicted Clast (IV correction) |
| `mrt.last` | MRT using AUMClast (no IV correction) |
| `mrt.obs` | MRT extrapolated to ∞, observed Clast (no IV correction) |
| `mrt.pred` | MRT extrapolated to ∞, predicted Clast (no IV correction) |
The other AUC bases follow the same naming: `mrt.all` / `mrt.iv.all` (AUCall), `mrt.int.*` / `mrt.ivint.*` (interval AUCs; ≥ 0.13.0), and the steady-state `mrt.md.*` and `mrt.ivmd.*` (see the [infusion section](#mrt-correction-for-infusions)).
The IV-corrected variants (`mrt.iv.*`) subtract half the infusion duration from the raw AUMC/AUC ratio, while the non-IV variants (`mrt.*`) use the raw ratio — see [MRT correction for infusions](#mrt-correction-for-infusions) below for the formula and a worked example.
```{r}
mrt_params <- data.frame(
start = 0,
end = Inf,
mrt.iv.last = TRUE,
mrt.iv.obs = TRUE,
mrt.iv.pred = TRUE,
mrt.last = TRUE,
mrt.obs = TRUE,
mrt.pred = TRUE
)
o_data_mrt <- PKNCAdata(o_conc, o_dose, intervals = mrt_params, impute = "start_conc0")
o_nca_mrt <- pk.nca(o_data_mrt)
as.data.frame(o_nca_mrt) |>
filter(grepl("^mrt", PPTESTCD)) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject, PPTESTCD)
```
### Effective half-life and elimination rate constant
**Effective half-life** (`thalf.eff`) is derived from MRT rather than from the terminal regression: `thalf.eff = ln(2) × MRT`. It reflects the half-life that would produce the same accumulation as the observed MRT, useful for multiple-dose design.
**kel** in PKNCA is computed as `1 / MRT`, **not** as λz (the terminal slope from the half-life regression). `kel` and `lambda.z` answer different questions: `lambda.z` is the terminal log-linear slope; `kel` is the MRT-derived rate constant used for multiple-dose accumulation calculations.
All variants:
| Parameter | Formula | Based on |
|---|---|---|
| `thalf.eff.iv.last` | ln(2) × MRT | `mrt.iv.last` |
| `thalf.eff.iv.obs` | ln(2) × MRT | `mrt.iv.obs` |
| `thalf.eff.iv.pred` | ln(2) × MRT | `mrt.iv.pred` |
| `thalf.eff.pred` | ln(2) × MRT | `mrt.pred` |
| `thalf.eff.last` | ln(2) × MRT | `mrt.last` |
| `thalf.eff.obs` | ln(2) × MRT | `mrt.obs` |
| `kel.obs` | 1 / MRT | `mrt.obs` |
| `kel.pred` | 1 / MRT | `mrt.pred` |
| `kel.last` | 1 / MRT | `mrt.last` |
| `kel.iv.obs` | 1 / MRT | `mrt.iv.obs` |
| `kel.iv.pred` | 1 / MRT | `mrt.iv.pred` |
| `kel.iv.last` | 1 / MRT | `mrt.iv.last` |
```{r}
eff_params <- data.frame(
start = 0,
end = Inf,
thalf.eff.iv.last = TRUE,
thalf.eff.iv.obs = TRUE,
thalf.eff.iv.pred = TRUE,
thalf.eff.pred = TRUE,
thalf.eff.last = TRUE,
thalf.eff.obs = TRUE,
kel.obs = TRUE,
kel.pred = TRUE,
kel.last = TRUE,
kel.iv.obs = TRUE,
kel.iv.pred = TRUE,
kel.iv.last = TRUE
)
o_nca_eff <- pk.nca(PKNCAdata(o_conc, o_dose, intervals = eff_params, impute = "start_conc0"))
as.data.frame(o_nca_eff) |>
filter(grepl("^(thalf|kel)", PPTESTCD)) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject, PPTESTCD)
```
### IV-route AUC (`auciv*`)
`auciv*` parameters compute the AUC of an IV bolus with C0: the first segment, from the dose to the first sample, is integrated from the back-extrapolated `c0` (see [C0](#c0-extrapolated-initial-concentration) above) rather than from whatever concentration the data hold at time 0. Since PKNCA 0.13.0 they do not need a concentration at time 0 at all: when the profile starts after the dose, `c0` supplies it. The `aumciv*` parameters (≥ 0.13.0) do the same for the AUMC.
Complete `auciv*` family:
| Parameter | Meaning |
|---|---|
| `aucivlast` | AUC(0–last), IV method (C0 back-extrapolated) |
| `aucivall` | AUC(0–last), IV method, BLQ treated as 0 |
| `aucivinf.obs` | AUC(0–∞) IV method, observed Clast |
| `aucivinf.pred` | AUC(0–∞) IV method, predicted Clast |
| `aucivint.last` | AUC over interval [start,end], IV method, AUClast extrapolation |
| `aucivint.all` | AUC over interval [start,end], IV method, AUCall extrapolation |
| `aumcivlast`, `aumcivall`, `aumcivinf.obs`, `aumcivinf.pred`, `aumcivint.last`, `aumcivint.all` | The matching AUMCs, IV method |
| `aucivpbextlast` | % of `aucivlast` contributed by back-extrapolation — the C0 segment before the first measured sample |
| `aucivpbextall` | % of `aucivall` contributed by the back-extrapolated C0 segment |
| `aucivpbextinf.obs` | % of `aucivinf.obs` contributed by the back-extrapolated C0 segment |
| `aucivpbextinf.pred` | % of `aucivinf.pred` contributed by the back-extrapolated C0 segment |
| `aucivpbextint.last` | % of `aucivint.last` contributed by the back-extrapolated C0 segment |
| `aucivpbextint.all` | % of `aucivint.all` contributed by the back-extrapolated C0 segment |
The percent back-extrapolated, `100 × (1 − AUC / AUCiv)`, compares the IV AUC with the ordinary AUC calculated from the data, so it needs a concentration at time 0 in the data: one that was measured, or one imputed as here. Without any concentration at time 0, `aucivpbext*` is `NA` (≥ 0.13.0) with the reason "Percent back-extrapolated requires a measured concentration at time 0", because the ordinary AUC then either cannot be calculated or already extrapolates back to time 0 and does not describe the observed part.
This example uses `start_predose_conc0`, the imputation that the automatic intervals use for an IV bolus (Indometh has no predose samples, so it imputes 0 at the dose time, as `start_conc0` would):
```{r}
auciv_params <- data.frame(
start = 0,
end = Inf,
aucivlast = TRUE,
aucivall = TRUE,
aucivinf.obs = TRUE,
aucivinf.pred = TRUE,
aumcivinf.obs = TRUE,
aucivpbextlast = TRUE,
aucivpbextall = TRUE,
aucivpbextinf.obs = TRUE,
aucivpbextinf.pred = TRUE
)
o_nca_auciv <- pk.nca(PKNCAdata(o_conc, o_dose, intervals = auciv_params,
impute = "start_predose_conc0"))
as.data.frame(o_nca_auciv) |>
filter(grepl("^(auciv|aumciv)", PPTESTCD)) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject, PPTESTCD)
```
```{r}
#| include: false
pbext <- as.data.frame(o_nca_auciv) |>
filter(grepl("^aucivpbext", PPTESTCD)) |>
pull(PPORRES)
```
> **When to use `auciv*` vs `auclast`/`aucinf.obs`:** For an IV bolus sampled after the dose, `aucivlast` and `aucivinf.obs` give the more theoretically correct AUC, and `cl.iv.*` / `vz.iv.*` carry it into clearance and volume. `aucivpbext*` shows how much of that AUC came from back-extrapolation; for Indometh it is `r round(min(pbext))`–`r round(max(pbext))`% depending on the subject and AUC, so the choice matters here.
---
## IV infusion (non-bolus)
For IV infusions, tell PKNCA the infusion duration via a `duration` column in the dose data frame and the `duration` argument to `PKNCAdose()`. PKNCA then:
- Interpolates the concentration **at end of infusion** (`ceoi`) from the surrounding measured timepoints
- Applies the IV correction to MRT: `MRT_infusion = AUMC/AUC − duration/2`
The Indomethacin dataset is IV bolus, but we can re-label the dose as a 30-minute (0.5 h) infusion to illustrate the workflow. The concentration data are unchanged; only the dose metadata differs.
```{r}
# Re-label the bolus dose as a 30-minute infusion
d_dose_inf <- d_dose |>
mutate(duration = 0.5) # 0.5 hours = 30 min
o_dose_inf <- PKNCAdose(
d_dose_inf,
dose ~ time | Subject,
route = "intravascular",
duration = "duration" # column name in d_dose_inf
)
```
### Infusion-specific parameter: `ceoi`
`ceoi` is the concentration at the **end of infusion** — for an infusion, `ceoi` plays the role that Cmax plays for extravascular dosing. PKNCA interpolates it from the surrounding observed timepoints using the current AUC method. Interpolation rules are documented in the [dose-aware interpolation vignette](https://humanpred.github.io/pknca/articles/v21-methods-for-dose-aware-interpolation-and-extrapolation.html).
```{r}
inf_intervals <- data.frame(
start = 0,
end = Inf,
ceoi = TRUE, # concentration at end of infusion (interpolated)
auclast = TRUE,
aucinf.obs = TRUE,
half.life = TRUE,
cl.obs = TRUE,
mrt.iv.obs = TRUE # MRT with infusion duration correction
)
o_data_inf <- PKNCAdata(o_conc, o_dose_inf, intervals = inf_intervals,
impute = "start_conc0")
o_nca_inf <- pk.nca(o_data_inf)
as.data.frame(o_nca_inf) |>
filter(PPTESTCD %in% c("ceoi", "auclast", "aucinf.obs",
"half.life", "cl.obs", "mrt.iv.obs")) |>
select(Subject, PPTESTCD, PPORRES) |>
tidyr::pivot_wider(names_from = PPTESTCD, values_from = PPORRES) |>
arrange(Subject)
```
### MRT correction for infusions
The `mrt.iv.*` parameters subtract `duration/2` from the raw `AUMC/AUC` ratio:
$$\text{MRT}_{IV} = \frac{\text{AUMC}}{\text{AUC}} - \frac{\text{duration}}{2}$$
For an IV bolus (`duration = 0`) the correction is zero. For a 0.5 h infusion, the correction is 0.25 h. Any deviation from theory comes from the trapezoidal AUMC/AUC estimate itself, not from the correction term.
Use `mrt.iv.obs` (extrapolated to ∞) when the terminal phase is well characterized and `mrt.iv.last` (to last measurable) otherwise.
At steady state after repeated infusions, use `mrt.ivmd.obs` / `mrt.ivmd.pred` and `vss.ivmd.obs` / `vss.ivmd.pred` (≥ 0.13.0). They subtract half the infusion duration, which `mrt.md.*` and `vss.md.*` do not, so for an infusion those are high by `duration/2` (MRT) and by `cl.last × duration/2` (Vss). All of them need the dosing interval `tau`, which is detected from the dose times or given as a `tau` column of the intervals; see the [Multiple-Dose chapter](multiple-dose.qmd).
---
## AUC over a specific interval
For steady-state or partial AUC windows:
```{r}
# AUC from 0 to 4 hours
partial_auc <- data.frame(
start = 0,
end = 4,
auclast = TRUE,
cmax = TRUE
)
o_data_partial <- PKNCAdata(o_conc, o_dose, intervals = partial_auc, impute = "start_conc0")
o_nca_partial <- pk.nca(o_data_partial)
as.data.frame(o_nca_partial) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject)
```
`auclast` integrates only the measured points inside the window. For an AUC over exactly 0–4 h whether or not a sample falls at 4 h, request `aucint.last` (or `aucint.all`, `aucint.inf.obs`, `aucint.inf.pred`), which interpolate or extrapolate to the window ends; `aucivint.last` and `aucivint.all` do the same with the IV C0. Every `aucint` parameter is dose-aware since PKNCA 0.13.0, so the former `aucint.*.dose` variants are retired (requesting one is an error naming its replacement); see the [AUC chapter](auc-methods.qmd) and [Dose-Aware Interpolation chapter](dose-aware-interpolation.qmd).
Interval semantics are explained in [Selection of Calculation Intervals](https://humanpred.github.io/pknca/articles/v03-selection-of-calculation-intervals.html).
---
## Units
Assign units to get automatic unit propagation through derived parameters. See the [Units chapter](units.qmd) and [Unit Assignment and Conversion with PKNCA](https://humanpred.github.io/pknca/articles/v07-unit-conversion.html) for the full units workflow.
```{r}
units_table <- pknca_units_table(
concu = "mcg/mL",
timeu = "h",
doseu = "mg",
amountu = "mg"
)
o_conc_u <- PKNCAconc(d_conc, conc ~ time | Subject, concu = "mcg/mL", timeu = "h")
o_dose_u <- PKNCAdose(d_dose, dose ~ time | Subject, route = "intravascular",
doseu = "mg")
o_data_u <- PKNCAdata(o_conc_u, o_dose_u, intervals = iv_intervals, units = units_table,
impute = "start_conc0")
o_nca_u <- pk.nca(o_data_u)
as.data.frame(o_nca_u) |>
filter(PPTESTCD %in% c("auclast", "cl.obs", "vz.obs")) |>
select(Subject, PPTESTCD, PPORRES) |>
arrange(Subject, PPTESTCD)
```
---
## Excluding observations
Mark individual observations to exclude from calculations (e.g. suspected sampling errors):
```{r}
d_conc_with_excl <- d_conc |>
mutate(excl = ifelse(Subject == "2" & time == 2, "suspected contamination", NA_character_))
o_conc_excl_gen <- PKNCAconc(d_conc_with_excl, conc ~ time | Subject, exclude = "excl")
# The flagged row stays in the data with its exclusion reason
as.data.frame(o_conc_excl_gen) |> filter(!is.na(excl))
```
The exclusion reason travels with the data (shown above), and the excluded point is dropped from every parameter calculation. This is broader than the `exclude_half.life` example in the half-life section, which removed a point from only the λz regression.
Below-limit-of-quantification (BLQ) values are handled separately from exclusions, via the `conc.blq` option — see the [BLQ section of the Extravascular chapter](extravascular.qmd#blq-below-limit-of-quantification-handling).
---
## Summary with custom statistics
```{r}
# Default summary uses geometric mean ± CV% for most parameters
summary(o_nca)
```
Customize the summary function — for example, report arithmetic mean (SD) for Tmax instead of its default median [range]:
```{r}
PKNCA.set.summary(
"tmax",
description = "arithmetic mean (SD)",
point = business.mean,
spread = business.sd
)
summary(o_nca)
```
Summary customization and results exclusion are covered in the [Post-processing chapter](postprocessing.qmd) and the [Post-Processing vignette](https://humanpred.github.io/pknca/articles/v07-post-processing.html).
---
## Full parameter list for IV
All IV-relevant parameters you can request in an interval:
```{r}
interval_cols <- get.interval.cols()
iv_relevant <- c(
# Concentration / time landmarks
"c0", "cmax", "cmin", "tmax", "tmin", "tfirst", "tlast",
"clast.obs", "clast.pred", "count_conc", "count_conc_measured",
# AUC family
"auclast", "aucall", "aucinf.obs", "aucinf.pred",
"aucpext.obs", "aucpext.pred",
"aucint.last", "aucint.all", "aucint.inf.obs", "aucint.inf.pred",
# IV-specific AUC and AUMC
"aucivlast", "aucivall", "aucivinf.obs", "aucivinf.pred",
"aucivint.last", "aucivint.all",
"aucivpbextlast", "aucivpbextall", "aucivpbextinf.obs", "aucivpbextinf.pred",
"aucivpbextint.last", "aucivpbextint.all",
"aumcivlast", "aumcivall", "aumcivinf.obs", "aumcivinf.pred",
"aumcivint.last", "aumcivint.all",
# AUMC
"aumclast", "aumcall", "aumcinf.obs", "aumcinf.pred",
"aumcint.last", "aumcint.all", "aumcint.inf.obs", "aumcint.inf.pred",
# Half-life / λz
"half.life", "lambda.z", "lambda.z.n.points", "lambda.z.time.first", "lambda.z.time.last",
"r.squared", "adj.r.squared", "span.ratio",
# Clearance
"cl.obs", "cl.pred", "cl.last", "cl.all",
"cl.int.last", "cl.int.all", "cl.int.inf.obs", "cl.int.inf.pred",
"cl.iv.obs", "cl.iv.pred", "cl.iv.last", "cl.iv.all", "cl.ivint.last", "cl.ivint.all",
# Volume
"vz.obs", "vz.pred", "vz.last", "vz.all",
"vz.int.last", "vz.int.all", "vz.int.inf.obs", "vz.int.inf.pred",
"vz.iv.obs", "vz.iv.pred", "vz.iv.last", "vz.iv.all", "vz.ivint.last", "vz.ivint.all",
"vss.obs", "vss.pred", "vss.last", "vss.all",
"vss.int.last", "vss.int.all", "vss.int.inf.obs", "vss.int.inf.pred",
"vss.iv.obs", "vss.iv.pred", "vss.iv.last", "vss.iv.all", "vss.ivint.last", "vss.ivint.all",
"vss.md.obs", "vss.md.pred", "vss.ivmd.obs", "vss.ivmd.pred",
# MRT
"mrt.last", "mrt.obs", "mrt.pred", "mrt.all",
"mrt.int.last", "mrt.int.all", "mrt.int.inf.obs", "mrt.int.inf.pred",
"mrt.iv.last", "mrt.iv.obs", "mrt.iv.pred", "mrt.iv.all", "mrt.ivint.last", "mrt.ivint.all",
"mrt.md.obs", "mrt.md.pred", "mrt.ivmd.obs", "mrt.ivmd.pred",
# Effective half-life / kel
"thalf.eff.iv.last", "thalf.eff.iv.obs", "thalf.eff.iv.pred", "thalf.eff.pred",
"thalf.eff.last", "thalf.eff.obs",
"kel.obs", "kel.pred", "kel.last", "kel.all",
"kel.int.last", "kel.int.all", "kel.int.inf.obs", "kel.int.inf.pred",
"kel.iv.obs", "kel.iv.pred", "kel.iv.last", "kel.iv.all", "kel.ivint.last", "kel.ivint.all",
# Dose-normalized
"auclast.dn", "aucinf.obs.dn", "cmax.dn", "clast.obs.dn"
)
sort(names(interval_cols)[names(interval_cols) %in% iv_relevant])
# Every name above is registered
setdiff(iv_relevant, names(interval_cols))
```
This list is curated. `pknca_parameter_table()` (≥ 0.13.0) records the routes each registered parameter applies to, so the parameters for an IV bolus can be listed directly; for example, those that apply to an IV bolus but not to extravascular dosing:
```{r}
d_param_table <- pknca_parameter_table()
d_param_table$parameter[grepl("iv_bolus", d_param_table$route) &
!grepl("extravascular", d_param_table$route)]
```
---
::: {.callout-note icon=false appearance="minimal"}
**pkgdown reference:** [PKNCAconc()](https://humanpred.github.io/pknca/reference/PKNCAconc.html) · [PKNCAdose()](https://humanpred.github.io/pknca/reference/PKNCAdose.html) · [PKNCAdata()](https://humanpred.github.io/pknca/reference/PKNCAdata.html) · [pk.nca()](https://humanpred.github.io/pknca/reference/pk.nca.html) · [pk.calc.c0()](https://humanpred.github.io/pknca/reference/pk.calc.c0.html) · [pk.calc.auciv()](https://humanpred.github.io/pknca/reference/pk.calc.auxciv.html) · [pk.calc.mrt.iv()](https://humanpred.github.io/pknca/reference/pk.calc.mrt.html) · [pknca_parameter_table()](https://humanpred.github.io/pknca/reference/pknca_parameter_table.html) · [pknca_units_table()](https://humanpred.github.io/pknca/reference/pknca_units_table.html) · [PKNCA.set.summary()](https://humanpred.github.io/pknca/reference/PKNCA.set.summary.html) · [get.interval.cols()](https://humanpred.github.io/pknca/reference/get.interval.cols.html) · [summary()](https://humanpred.github.io/pknca/reference/summary.PKNCAresults.html) · [business.*()](https://humanpred.github.io/pknca/reference/business.mean.html) · [PKNCA_impute_method_start_*()](https://humanpred.github.io/pknca/reference/PKNCA_impute_method.html)
:::