# A minimal interval: AUClast over the first 24 hours
my_intervals <- data.frame(
start = 0,
end = 24,
auclast = TRUE
)
my_intervals start end auclast
1 0 24 TRUE
intervals argumentpknca_interval_table()
pknca_parameter_table()get.parameter.deps()Intervals tell PKNCA when to calculate and what to calculate. Every calculated parameter value comes from exactly one interval row, and each row is independent of all others. See also the package vignette Selection of Calculation Intervals.
An interval specification is a plain R data.frame with one row per calculation window. Two columns are required:
| Column | Type | Meaning |
|---|---|---|
start |
numeric | Start of the calculation window (same units as time) |
end |
numeric | End of the calculation window; use Inf for open-ended windows |
Every remaining column is normally a parameter flag: its name must match a known PKNCA parameter name and its value must be TRUE (calculate) or FALSE (skip). Columns set to FALSE are simply ignored, so you only need to list the parameters you actually want. The exceptions are:
impute argument of PKNCAdata() names (see Imputation columns below and the Concentration Imputation chapter);interval_id column and <parameter>_ref columns, which link an interval to a reference interval for secondary parameters such as renal clearance, bioavailability, and ratios (≥ 0.13.0; see the Secondary Parameters chapter); andconc_above (the concentration threshold for time_above) and tau (the dosing interval for mrt.md.* and vss.md.*, ≥ 0.13.0; see the Multiple-Dose and Steady-State chapter);interval_time_kind, which pk.nca() adds when it converts date-time intervals; andkeep_interval_cols option.Any other column is an error (pknca_error_invalid_interval_columns) when the intervals are checked by PKNCAdata(intervals = ), set_intervals(), or pk.nca() (≥ 0.13.0; see Validating intervals).
start end auclast
1 0 24 TRUE
You can also request multiple parameters in a single row:
start end cmax tmax half.life aucinf.obs
1 0 Inf TRUE TRUE TRUE TRUE
A parameter cannot be named start, end, or the same as a grouping variable you use in PKNCAconc() — a column whose name matches a grouping variable is treated as a matching key, not a parameter flag.
PKNCA matches interval rows to concentration data by comparing the shared column names between the interval data frame and the grouping columns of the concentration object. Any column that appears in both is used as a matching key.
o_conc <- PKNCAconc(Theoph, conc ~ Time | Subject)
# Intervals with a Subject column — each row applies to exactly one subject
subject_intervals <- data.frame(
Subject = c("1", "2"),
start = c(0, 0),
end = c(24, 24),
auclast = TRUE
)
# Intervals without Subject — this row applies to ALL subjects (default interval)
# Shown for illustration; the run below uses subject_intervals only
default_interval <- data.frame(
start = 0,
end = 24,
auclast = TRUE
)If an interval row has no group columns, it is a default interval and is applied to every group present in the concentration data. This is useful when the same calculation windows apply to all subjects and analytes.
Running the subject-specific intervals shows the matching in action. To keep the output short, restrict the concentration data to subjects 1–3. Subject 3 has no matching interval row, so PKNCA warns about it and returns results only for subjects 1 and 2 (no dose object is needed here because auclast is dose-independent):
Warning: Subject=3: No intervals for data
# A tibble: 2 × 5
Subject start end PPTESTCD PPORRES
<chr> <dbl> <dbl> <chr> <dbl>
1 2 0 24 auclast 67.2
2 1 0 24 auclast 92.4
intervals argumentWhen you call PKNCAdata() without an intervals argument, PKNCA generates intervals from the dose times of each group. It finds the dosing regimen, places the intervals (after a single dose, after the first dose, over the last dosing interval at steady state), and asks pknca_interval_table() (described below) for the parameters and the imputation that suit each interval (≥ 0.13.0). For a single extravascular dose, as in Theoph, every subject gets one interval from the dose to infinity:
o_dose <- PKNCAdose(
Theoph |> group_by(Subject) |>
summarise(Dose = Dose[1] * Wt[1], .groups = "drop") |>
mutate(Time = 0),
Dose ~ Time | Subject
)
# No intervals argument: intervals are generated automatically
o_data_default <- PKNCAdata(
PKNCAconc(Theoph, conc ~ Time | Subject),
o_dose
)
# Show subject 1, keeping only the columns that request a parameter
o_data_default$intervals |>
filter(Subject == "1") |>
select(where(~ !is.logical(.x) || any(.x)))# A tibble: 1 × 13
start end auclast cmax tmax tlag count_conc half.life aucinf.obs
<dbl> <dbl> <lgl> <lgl> <lgl> <lgl> <lgl> <lgl> <lgl>
1 0 Inf TRUE TRUE TRUE TRUE TRUE TRUE TRUE
# ℹ 4 more variables: aucpext.obs <lgl>, cl.obs <lgl>, Subject <ord>,
# impute <chr>
The row requests auclast, cmax, tmax, tlag, count_conc, half.life, aucinf.obs, aucpext.obs, and cl.obs, and its impute column holds start_predose_conc0, which keeps a concentration measured at the dose time, carries a predose concentration forward when there is none, and imputes 0 otherwise. An intravenous bolus gets an extra row that back-extrapolates c0 without imputation, multiple-dose data get rows built on the aucint.* family, and a sparse design imputes only a zero at a single dose. The Automatic Intervals and Dosing Regimens chapter covers how the regimen is detected, the auto.interval.tolerance and tau.choices options, and the intervals each design gets.
Before 0.13.0, a single dose got the two rows of the single.dose.aucs option instead: auclast over 0 to 24 and cmax, tmax, half.life, and aucinf.obs over 0 to infinity, with no imputation. The option still exists and is used when auto.interval.method = "legacy":
# A tibble: 2 × 8
start end auclast cmax tmax half.life aucinf.obs Subject
<dbl> <dbl> <lgl> <lgl> <lgl> <lgl> <lgl> <ord>
1 0 24 TRUE FALSE FALSE FALSE FALSE 1
2 0 Inf FALSE TRUE TRUE TRUE TRUE 1
The 0 to 24 window of single.dose.aucs is written for hours; with a time unit other than hours, the legacy method warns (pknca_warning_single_dose_aucs_unit). See also Options for Controlling PKNCA.
Each row of the interval data frame is applied independently. A single subject (or group) can have any number of interval rows, each with its own time window and parameter set. PKNCA applies every matching row and collects the results.
start end auclast cmax half.life aucinf.obs
1 0 24 TRUE FALSE FALSE FALSE
2 0 Inf FALSE TRUE TRUE TRUE
PKNCA processes each row separately: the first row restricts data to \(t \in [0, 24]\) for the auclast calculation, while the second row uses all available data to derive terminal parameters.
Overlapping intervals are allowed and do not interfere with each other.
Some sampling designs record a duration rather than an instantaneous sample — for example, urine collection periods or IV infusions. PKNCA tracks these via the duration argument in PKNCAconc() and PKNCAdose().
When a concentration object carries duration information, PKNCA still selects samples for an interval by their recorded time, which is the start of the collection period: a collection is included when its start is at or after the interval start and at or before the interval end. The duration is not consulted during selection, so a collection that starts inside the interval but ends after end contributes its full amount to the interval. For results that are simple to interpret, align the collection boundaries with the interval boundaries, as here:
# Urine collected 0-4, 4-8, and 8-24 h after a 100 mg oral dose
d_urine_conc <- data.frame(
Subject = 1,
time = c(0, 4, 8), # collection start times (h)
duration = c(4, 4, 16), # collection lengths (h)
conc = c(20, 15, 5), # urine concentration (mg/L)
volume = c(0.5, 0.6, 1.2) # collected urine volume (L)
)
o_urine_conc <- PKNCAconc(
d_urine_conc, conc ~ time | Subject,
duration = "duration", volume = "volume"
)
o_urine_dose <- PKNCAdose(
data.frame(Subject = 1, dose = 100, time = 0),
dose ~ time | Subject
)
# end = 24 matches the end of the final collection (8 + 16 = 24)
urine_intervals <- data.frame(start = 0, end = 24, ae = TRUE)
o_urine <- pk.nca(PKNCAdata(o_urine_conc, o_urine_dose, intervals = urine_intervals))
as.data.frame(o_urine)# A tibble: 1 × 7
Subject start end PPTESTCD PPORRES PPANMETH exclude
<dbl> <dbl> <dbl> <chr> <dbl> <chr> <chr>
1 1 0 24 ae 25 "" <NA>
ae (amount excreted) is the sum of concentration × volume over the collections in the interval: \(20 \times 0.5 + 15 \times 0.6 + 5 \times 1.2 = 25\) mg of the 100 mg dose.
For IV infusions, setDuration() on the dose object sets the infusion duration, and ceoi (concentration at end of infusion) becomes calculable within an interval when a sample was drawn at the end-of-infusion time within the interval.
pknca_interval_table()pknca_interval_table() (≥ 0.13.0) builds an interval specification from a description of the analysis instead of a list of parameter names. Given a start, an end, how often the drug was given (dosing), and how (route), it chooses the parameters usually reported for that context, the AUC they are built on, and the imputation to calculate them from. It is the function the automatic intervals use, so for a single extravascular dose it returns the same row as the default intervals above:
start end auclast cmax tmax tlag count_conc half.life aucinf.obs aucpext.obs
1 0 Inf TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
cl.obs impute
1 TRUE start_predose_conc0
The arguments describe the context:
| Argument | Values | Meaning |
|---|---|---|
start, end |
numbers (vectors allowed) | The interval bounds; vectors give one set of rows per interval |
dosing |
"single" (default), "multiple", "steady_state" |
Given once, repeatedly, or repeatedly at steady state (pknca_dosing()) |
route |
"extravascular" (default), "iv_bolus", "iv_infusion", "iv_continuous_infusion" |
How the drug was given (pknca_routes()); note these are not the "intravascular" spelling of PKNCAdose() |
sample_type |
"spot" (default), "interval" |
Samples at a point in time (blood, plasma) or collections over an interval (urine, feces) (pknca_sample_types()) |
sparse |
FALSE (default), TRUE |
A sparse design keeps the same parameters but imputes only start_conc0 at a single dose and nothing otherwise |
tier |
"common" (default), "all" |
The parameters usually reported, or every parameter the context can calculate |
include, exclude |
parameter names or concepts | Add to or remove from what the context gives; naming one in both is an error |
impute |
NULL (default), a method string, or NA |
NULL chooses the imputation from the context; NA uses none |
preset |
a name from pknca_presets() |
A named set of the arguments above to start from; explicit arguments override it |
clast_type |
"obs" (default), "pred" |
Extrapolate to infinity from the observed or the predicted last concentration |
... |
named values | Columns added to every row, typically the groups the interval applies to |
A single dose is built on AUClast and its extrapolation to infinity; a repeated dose is built on the aucint.* family, which interpolates at both interval boundaries, with clearance, volume, and MRT chosen to match. At steady state with the fluctuation parameters added (and a group column given through ...):
start end aucint.last cmax tmax ctrough ptr tlag deg.fluc swing count_conc
1 144 168 TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
half.life aucint.inf.obs cl.int.inf.obs impute Subject
1 TRUE TRUE TRUE start_predose 1
include and exclude accept parameter names or the concepts listed by pknca_concepts(), so include = "mrt" adds the MRT parameters the single-dose context calculates (mrt.last and mrt.obs in the output below) and exclude = "clearance" drops cl.obs:
start end auclast aumclast cmax tmax mrt.last tlag count_conc half.life
1 0 Inf TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
aucinf.obs aucpext.obs mrt.obs impute
1 TRUE TRUE TRUE start_predose_conc0
When an imputed value would become the answer, the parameter is kept out of the imputation by splitting the interval into more than one row. After an intravenous bolus, c0 is back-extrapolated in a second row with no imputation, so that an imputed concentration at the dose time cannot become C0:
start end auclast c0 cmax tmax count_conc half.life aucinf.obs
1 0 Inf TRUE FALSE TRUE TRUE TRUE TRUE TRUE
2 0 Inf FALSE TRUE FALSE FALSE FALSE FALSE FALSE
aucpext.obs cl.obs impute
1 TRUE TRUE start_predose_conc0
2 FALSE FALSE <NA>
tier = "all" gives every parameter the context can calculate (55 parameters for a single extravascular dose, rather than 9), which is a convenient starting point that you can then trim with interval_remove_param().
The table is an ordinary interval data frame, so it goes straight into PKNCAdata(). Its impute column is read because impute defaults to NA, which looks for a column named "impute":
# A tibble: 21 × 5
Subject start end PPTESTCD PPORRES
<ord> <dbl> <dbl> <chr> <dbl>
1 1 0 Inf auclast 147.
2 1 0 Inf aumclast 1499.
3 1 0 Inf cmax 10.5
4 1 0 Inf tmax 1.12
5 1 0 Inf tlast 24.4
6 1 0 Inf clast.obs 3.28
7 1 0 Inf tlag 0
8 1 0 Inf count_conc 11
9 1 0 Inf lambda.z 0.0485
10 1 0 Inf r.squared 1.000
# ℹ 11 more rows
pknca_presets() gives named argument sets for common analyses. Each is a list of arguments to pknca_interval_table():
[1] "single_dose" "steady_state" "bioequivalence"
[4] "first_in_human" "mass_balance" "sparse_single_dose"
$dosing
[1] "single"
$route
[1] "extravascular"
$include
[1] "aucall" "clast.obs" "tlast"
| Preset | Arguments it sets |
|---|---|
single_dose |
dosing = "single", route = "extravascular" |
steady_state |
dosing = "steady_state", route = "extravascular" |
bioequivalence |
single extravascular dose, include = c("aucall", "clast.obs", "tlast") |
first_in_human |
single extravascular dose, include = c("clast.obs", "tlast", "span.ratio") |
mass_balance |
single extravascular dose, sample_type = "interval", include = "excretion_rate" |
sparse_single_dose |
single extravascular dose, sparse = TRUE |
Arguments given directly override the preset, here removing the imputation:
start end auclast aucall cmax tmax tlast clast.obs tlag count_conc half.life
1 0 Inf TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
aucinf.obs aucpext.obs cl.obs
1 TRUE TRUE TRUE
The Bioequivalence chapter uses the bioequivalence preset, and the Sparse Sampling chapter covers sparse designs.
pknca_parameter_table()pknca_interval_table() chooses parameters from a classification of every registered parameter (≥ 0.13.0). pknca_parameter_table() shows it: the concept a parameter computes, its reporting tier, its sample_type, whether it is a sparse estimator output, secondary (needs inputs from more than one profile), or dose_normalized, and the comma-separated route and dosing contexts it applies to.
parameter concept tier sample_type secondary
1 auclast auc common spot FALSE
2 aucint.last auc common spot FALSE
3 cmax peak_conc common spot FALSE
4 cl.obs clearance common spot FALSE
5 ae excreted_amount common interval FALSE
6 f.obs bioavailability uncommon spot TRUE
dosing
1 single,multiple,steady_state
2 single,multiple,steady_state
3 single,multiple,steady_state
4 single
5 single,multiple,steady_state
6 single
The vocabularies have their own listing functions: pknca_concepts(), pknca_tiers(), pknca_dosing(), and pknca_sample_types() (with pknca_routes() for routes).
[1] "auc" "aumc" "auc_above_conc"
[4] "auc_extrapolation" "peak_conc" "min_conc"
[7] "last_conc" "average_conc" "trough_conc"
[10] "start_conc" "initial_conc" "eoi_conc"
[13] "peak_time" "min_time" "last_time"
[16] "first_time" "lag_time" "time_above_conc"
[19] "clearance" "renal_clearance" "volume_z"
[22] "volume_ss" "mrt" "half_life"
[25] "effective_half_life" "elimination_rate" "fluctuation"
[28] "excreted_amount" "excreted_fraction" "excretion_rate"
[31] "collected_volume" "bioavailability" "total_dose"
[34] "observation_count" "parameter_ratio"
[1] "common" "uncommon"
A parameter’s concept is declared on its calculation function with pknca_concept(), so a parameter registered by another package (or by you, see the Writing Custom Parameter Functions chapter) can be chosen automatically too. An unclassified parameter is not an error: it is calculated when you request it by name but is never selected automatically, and pknca_check_parameter_classification() lists such parameters (zero rows means every registered parameter is classified).
Secondary parameters (f.obs, clr.obs, ratio.*, and others) are never selected automatically, because one interval cannot say which other profile is the reference; request them by name as described in the Secondary Parameters chapter.
Four functions edit an interval specification (≥ 0.13.0). Each accepts either a data frame of intervals or a PKNCAdata object (whose $intervals it edits), so you can start from the automatic intervals or from pknca_interval_table() and adjust them:
| Function | What it does | Key arguments |
|---|---|---|
interval_add_param() |
Request more parameters | param (names), param_pattern (regular expressions), target_groups |
interval_remove_param() |
Stop requesting parameters | param, param_pattern, target_groups |
interval_add_impute() |
Add an imputation method | target_impute, after (position in an existing chain: 0 first, Inf last), target_params, target_groups |
interval_remove_impute() |
Remove an imputation method | target_impute, target_params, target_groups |
target_groups is a data frame of group values; a row of the intervals is edited when it matches every column of at least one of its rows.
start end cmax tmax auclast half.life
1 0 Inf TRUE TRUE TRUE TRUE
start end cmax tmax aucint.last aucint.all
1 0 Inf TRUE TRUE TRUE TRUE
Removing every parameter from every interval is an error (pknca_error_interval_nothing_remains), since nothing would be left to calculate.
When the parameters of one row no longer share the same imputation, the row is split into as many rows as needed, and rows that come to share every value are merged again. Imputing a start concentration for auclast only splits the row:
start end cmax auclast half.life impute
1 0 Inf TRUE FALSE TRUE <NA>
2 0 Inf FALSE TRUE FALSE start_conc0
Editing a PKNCAdata object changes all of its intervals at once. Starting from the automatic Theoph intervals, drop tlag and count_conc, add aumclast, and calculate the half-life without the imputed start concentration:
o_data_edited <- o_data_default |>
interval_remove_param(param = c("tlag", "count_conc")) |>
interval_add_param(param = "aumclast") |>
interval_remove_impute(target_impute = "start_predose_conc0", target_params = "half.life")
o_data_edited$intervals |>
filter(Subject == "1") |>
select(where(~ !is.logical(.x) || any(.x))) start end auclast aumclast cmax tmax half.life aucinf.obs aucpext.obs
1 0 Inf TRUE TRUE TRUE TRUE FALSE TRUE TRUE
2 0 Inf FALSE FALSE FALSE FALSE TRUE FALSE FALSE
cl.obs Subject impute
1 TRUE 1 start_predose_conc0
2 FALSE 1 <NA>
target_groups restricts an edit to some groups, here subject 2 only:
Subject start end auclast impute
1 1 0 Inf TRUE <NA>
2 2 0 Inf TRUE start_conc0
The imputation column of an interval table may have any name (≥ 0.13.0). PKNCAdata(impute = ) reads it this way:
impute names a column of the intervals, each row’s method comes from that column.impute is NA (the default) and the intervals have a column named "impute", each row’s method comes from that column. This is how the automatic intervals and pknca_interval_table() carry their imputation.impute is itself the method string for every interval (an NA with no "impute" column means no imputation).The column must be character (pknca_error_interval_impute_not_character), except that a column of only NA means no imputation. get_impute_column() and get_impute_method() apply the same rule, which is useful when you write code around PKNCA objects:
d_int_named <- data.frame(
start = c(0, 0), end = c(24, Inf),
auclast = c(TRUE, FALSE), aucinf.obs = c(FALSE, TRUE),
my_impute = c("start_conc0", "start_predose_conc0")
)
o_data_named <- PKNCAdata(o_conc, o_dose, intervals = d_int_named, impute = "my_impute")
get_impute_column(o_data_named$intervals, impute = o_data_named$impute)[1] "my_impute"
[1] "start_conc0" "start_predose_conc0"
NULL
interval_add_impute() and interval_remove_impute() edit whichever column the object’s impute setting names. The methods themselves are described in the Concentration Imputation chapter.
With date-time (POSIXct or Date) concentration and dose times (≥ 0.13.0), start and end may also be date-times. pk.nca() converts each row to numeric time relative to the time reference (the first dose) of the group it applies to. A row that does not name every reference group becomes one row per group, because one clock-time window is a different relative window for each subject. An end of Inf stays infinite.
d_conc_dt <- data.frame(
Subject = rep(c("A", "B"), each = 8),
datetime = as.POSIXct("2024-03-04 08:00", tz = "UTC") +
3600 * c(c(0, 0.5, 1, 2, 4, 8, 12, 24), 25.5 + c(0, 0.5, 1, 2, 4, 8, 12, 24)),
conc = c(0, 4.1, 6.3, 5.9, 4.4, 2.6, 1.5, 0.4,
0, 3.2, 5.5, 5.8, 4.6, 2.9, 1.8, 0.6)
)
d_dose_dt <- data.frame(
Subject = c("A", "B"),
datetime = as.POSIXct(c("2024-03-04 08:00", "2024-03-05 09:30"), tz = "UTC"),
dose = 100
)
# One clock-time window for both subjects: from subject A's dose onward
d_int_dt <- data.frame(
start = as.POSIXct("2024-03-04 08:00", tz = "UTC"),
end = Inf,
cmax = TRUE
)
o_nca_dt <- pk.nca(PKNCAdata(
PKNCAconc(d_conc_dt, conc ~ datetime | Subject),
PKNCAdose(d_dose_dt, dose ~ datetime | Subject),
intervals = d_int_dt
))
as.data.frame(o_nca_dt) |>
select(Subject, start, end, PPTESTCD, PPORRES)# A tibble: 2 × 5
Subject start end PPTESTCD PPORRES
<chr> <dbl> <dbl> <chr> <dbl>
1 A 0 Inf cmax 6.3
2 B -25.5 Inf cmax 5.8
Subject B was dosed 25.5 hours after subject A, so the same window starts at −25.5 h relative to subject B’s dose. The converted intervals, with an interval_time_kind column, are in o_nca_dt$data$intervals. Date-time bounds mixed with finite numeric bounds, an infinite start, date-time intervals for numeric data, and a time zone that differs from the data are errors. The Date-Time Data and Time References chapter covers date-time data in full.
The complete list of calculable parameters is available programmatically via get.interval.cols(). Each entry carries a description, the calculation function, unit type, and dependency information. The table below joins in the concept and tier from pknca_parameter_table():
cols <- get.interval.cols()
param_table <- data.frame(
parameter = names(cols),
description = sapply(cols, function(x) x$desc),
stringsAsFactors = FALSE
)
# Exclude the structural columns start/end from the display
param_table <- param_table[!param_table$parameter %in% c("start", "end"), ]
param_table <- merge(
param_table,
pknca_parameter_table()[, c("parameter", "concept", "tier")],
by = "parameter", sort = FALSE
)
rownames(param_table) <- NULL
knitr::kable(
param_table,
col.names = c("Parameter", "Description", "Concept", "Tier"),
caption = paste0(
"All ", nrow(param_table),
" calculable parameters in PKNCA ", packageVersion("PKNCA")
)
)| Parameter | Description | Concept | Tier |
|---|---|---|---|
| auclast | AUC start to last conc above LOQ | auc | common |
| auclast_se | SE of AUClast (sparse PK only) | auc | uncommon |
| auclast_df | DF for AUClast (sparse PK only) | auc | uncommon |
| aucall | AUClast plus triangle, 0 at BLQ | auc | uncommon |
| aucall_se | SE of AUCall (sparse PK only) | auc | uncommon |
| aucall_df | DF for AUCall (sparse PK only) | auc | uncommon |
| aumclast | AUMC start to last conc above LOQ | aumc | uncommon |
| aumclast_se | SE of AUMClast (sparse PK only) | aumc | uncommon |
| aumclast_df | DF for AUMClast (sparse PK only) | aumc | uncommon |
| aumcall | AUMClast plus triangle moment, 0 at BLQ | aumc | uncommon |
| aumcall_se | SE of AUMCall (sparse PK only) | aumc | uncommon |
| aumcall_df | DF for AUMCall (sparse PK only) | aumc | uncommon |
| aucint.last | AUC from T1 to T2 (zero extrap) | auc | common |
| aucint.all | AUC from T1 to T2 (AUCall extrap) | auc | uncommon |
| aumcint.last | AUMC from T1 to T2 (zero extrap) | aumc | uncommon |
| aumcint.all | AUMC from T1 to T2 (AUMCall extrap) | aumc | uncommon |
| c0 | Initial conc after IV bolus | initial_conc | common |
| cmax | Maximum observed concentration | peak_conc | common |
| cmin | Minimum observed concentration | min_conc | uncommon |
| tmax | Time of maximum observed conc | peak_time | common |
| tmin | Time of minimum observed conc | min_time | uncommon |
| tlast | Time of last conc above LOQ | last_time | uncommon |
| tfirst | Time of first conc above LOQ | first_time | uncommon |
| clast.obs | Last conc observed above LOQ | last_conc | uncommon |
| cl.last | Clearance, AUClast | clearance | uncommon |
| cl.all | Clearance, AUCall | clearance | uncommon |
| cl.int.all | Clearance, AUCint,all | clearance | uncommon |
| cl.int.last | Clearance, AUCint,last | clearance | uncommon |
| mrt.last | MRT, AUClast/AUMClast | mrt | uncommon |
| mrt.all | MRT, AUCall/AUMCall | mrt | uncommon |
| mrt.int.all | MRT, interval AUCall/AUMCall | mrt | uncommon |
| mrt.int.last | MRT, interval AUClast/AUMClast | mrt | uncommon |
| mrt.iv.last | IV MRT, AUClast/AUMClast | mrt | uncommon |
| vss.last | Vss, calc from AUClast | volume_ss | uncommon |
| vss.iv.last | IV Vss, calc from AUClast | volume_ss | uncommon |
| vss.all | Vss, calc from AUCall | volume_ss | uncommon |
| vss.int.all | Vss, calc from interval AUCint,all | volume_ss | uncommon |
| vss.int.last | Vss, calc from interval AUCint,last | volume_ss | uncommon |
| cav | Avg conc in interval (AUClast) | average_conc | uncommon |
| cav.int.last | Avg conc in interval (AUCint,last) | average_conc | uncommon |
| cav.int.all | Avg conc in interval (AUCint,all) | average_conc | uncommon |
| ctrough | Trough (end of interval) conc | trough_conc | common |
| cstart | The predose concentration | start_conc | uncommon |
| ptr | Peak-to-trough ratio | fluctuation | uncommon |
| tlag | Lag time | lag_time | common |
| deg.fluc | Degree of fluctuation | fluctuation | uncommon |
| swing | Swing relative to Cmin | fluctuation | uncommon |
| ceoi | Concentration at the end of infusion | eoi_conc | common |
| aucabove.predose.all | AUC above predose, floor at 0 | auc_above_conc | uncommon |
| aucabove.trough.all | AUC above trough, floor at 0 | auc_above_conc | uncommon |
| count_conc | Count of non-missing conc | observation_count | common |
| count_conc_measured | Count of measured, non-BLQ conc | observation_count | uncommon |
| totdose | Total dose given in interval | total_dose | uncommon |
| volpk | Sum of urine volumes for interval | collected_volume | common |
| ae | Amount excreted (urine/feces) | excreted_amount | common |
| clr.last | Renal clearance, AUClast | renal_clearance | uncommon |
| clr.obs | Renal clearance, AUCinf,obs | renal_clearance | common |
| clr.pred | Renal clearance, AUCinf,pred | renal_clearance | uncommon |
| fe | Fraction of dose excreted | excreted_fraction | common |
| ertlst | Midpoint time of last excr rate | excretion_rate | uncommon |
| ermax | Maximum excretion rate | excretion_rate | uncommon |
| ertmax | Midpoint time of max excr rate | excretion_rate | uncommon |
| erint | Excretion rate from T1 to T2 | excretion_rate | uncommon |
| erlst | Last measurable excretion rate | excretion_rate | uncommon |
| ratio.cmax | Ratio of Cmax to reference | parameter_ratio | uncommon |
| ratio.auclast | Ratio of AUClast to reference | parameter_ratio | uncommon |
| ratio.aucint.last | Ratio of AUCint,last to reference | parameter_ratio | uncommon |
| ratio.aucint.all | Ratio of AUCint,all to reference | parameter_ratio | uncommon |
| sparse_auclast | Sparse AUC to last conc above LOQ | auc | common |
| sparse_auc_se | SE of sparse AUC to last conc above LOQ | auc | common |
| sparse_auc_df | DF for sparse AUC to last conc above LOQ | auc | uncommon |
| sparse_aumclast | Sparse AUMC to last conc above LOQ | aumc | uncommon |
| sparse_aumc_se | SE of sparse AUMC to last conc above LOQ | aumc | uncommon |
| sparse_aumc_df | DF for sparse AUMClast | aumc | uncommon |
| time_above | Time above a given concentration | time_above_conc | uncommon |
| aucivlast | AUClast, IV back-extrap C0 | auc | uncommon |
| aucivlast_se | SE of AUClast IV (sparse PK only) | auc | uncommon |
| aucivlast_df | DF for AUClast IV (sparse PK only) | auc | uncommon |
| aucivall | AUCall, IV back-extrap C0 | auc | uncommon |
| aucivall_se | SE of AUCall IV (sparse PK only) | auc | uncommon |
| aucivall_df | DF for AUCall IV (sparse PK only) | auc | uncommon |
| aucivint.last | AUCint,last, IV back-extrap C0 | auc | uncommon |
| aucivint.all | AUCint,all, IV back-extrap C0 | auc | uncommon |
| aucivpbextlast | Back-extrap %, IV, AUClast | auc_extrapolation | uncommon |
| aucivpbextall | Back-extrap %, IV, AUCall | auc_extrapolation | uncommon |
| aucivpbextint.last | Back-extrap %, IV, AUCint,last | auc_extrapolation | uncommon |
| aucivpbextint.all | Back-extrap %, IV, AUCint,all | auc_extrapolation | uncommon |
| aumcivlast | AUMClast, IV back-extrap C0 | aumc | uncommon |
| aumcivlast_se | SE of AUMClast IV (sparse PK only) | aumc | uncommon |
| aumcivlast_df | DF for AUMClast IV (sparse PK only) | aumc | uncommon |
| aumcivall | AUMCall, IV back-extrap C0 | aumc | uncommon |
| aumcivall_se | SE of AUMCall IV (sparse PK only) | aumc | uncommon |
| aumcivall_df | DF for AUMCall IV (sparse PK only) | aumc | uncommon |
| aumcivint.last | AUMCint,last, IV back-extrap C0 | aumc | uncommon |
| aumcivint.all | AUMCint,all, IV back-extrap C0 | aumc | uncommon |
| half.life | The (terminal) half-life | half_life | common |
| r.squared | R-squared of half-life fit | half_life | uncommon |
| adj.r.squared | Adjusted R-sq of half-life fit | half_life | uncommon |
| lambda.z.corrxy | Corr(time,log-conc) for lambda.z | half_life | uncommon |
| lambda.z | Terminal elim rate (lambda.z) | half_life | uncommon |
| lambda.z.time.first | First time point for lambda.z | half_life | uncommon |
| lambda.z.time.last | Last time point for lambda.z | half_life | uncommon |
| lambda.z.n.points | Number of points used, lambda.z | half_life | uncommon |
| clast.pred | Predicted Clast from half-life | last_conc | uncommon |
| span.ratio | Ratio of lambda.z time span to half-life | half_life | uncommon |
| tobit_residual | Tobit fit residual SD, log-conc | half_life | uncommon |
| adj_tobit_residual | Adjusted Tobit residual SD | half_life | uncommon |
| lambda.z.n.points_blq | BLQ points in Tobit lambda.z | half_life | uncommon |
| thalf.eff.last | Effective half-life, MRTlast | effective_half_life | uncommon |
| thalf.eff.iv.last | Effective half-life, IV MRTlast | effective_half_life | uncommon |
| kel.last | Elim rate, MRT via AUClast | elimination_rate | uncommon |
| kel.iv.last | Elim rate, IV MRTlast | elimination_rate | uncommon |
| kel.all | Elim rate, MRTall | elimination_rate | uncommon |
| kel.int.all | Elim rate, MRTint,all | elimination_rate | uncommon |
| kel.int.last | Elim rate, MRTint,last | elimination_rate | uncommon |
| cl.iv.all | IV clearance, AUCall | clearance | uncommon |
| cl.iv.last | IV clearance, AUClast | clearance | uncommon |
| cl.ivint.all | IV clearance, AUCint,all | clearance | uncommon |
| cl.ivint.last | IV clearance, AUCint,last | clearance | uncommon |
| cl.sparse.last | Clearance, sparse AUClast | clearance | uncommon |
| f.last | Bioavailability from AUClast | bioavailability | uncommon |
| f.int.last | Bioavailability from AUCint,last | bioavailability | uncommon |
| f.int.all | Bioavailability from AUCint,all | bioavailability | uncommon |
| mrt.sparse.last | MRT, sparse AUClast/AUMClast | mrt | uncommon |
| mrt.iv.all | IV MRT, AUCall/AUMCall | mrt | uncommon |
| mrt.ivint.all | IV MRT, interval AUCall/AUMCall | mrt | uncommon |
| mrt.ivint.last | IV MRT, interval AUClast/AUMClast | mrt | uncommon |
| vz.all | Vz, AUCall-based CL | volume_z | uncommon |
| vz.int.all | Vz, interval AUCint,all | volume_z | uncommon |
| vz.int.last | Vz, interval AUCint,last | volume_z | uncommon |
| vz.iv.all | IV Vz, AUCall | volume_z | uncommon |
| vz.iv.last | IV Vz, AUClast | volume_z | uncommon |
| vz.ivint.all | IV Vz, interval AUCint,all | volume_z | uncommon |
| vz.ivint.last | IV Vz, interval AUCint,last | volume_z | uncommon |
| vz.last | Vz, AUClast-based CL | volume_z | uncommon |
| vss.iv.all | IV Vss, calc from AUCall | volume_ss | uncommon |
| vss.ivint.all | IV Vss, calc from interval AUCint,all | volume_ss | uncommon |
| vss.ivint.last | IV Vss, calc from interval AUCint,last | volume_ss | uncommon |
| vss.sparse.last | Vss, calc from sparse AUClast | volume_ss | uncommon |
| aucinf.obs | AUC start to inf, obs Clast extrap | auc | common |
| aucinf.obs_se | SE of AUCinf,obs (sparse PK only) | auc | uncommon |
| aucinf.obs_df | DF for AUCinf,obs (sparse PK only) | auc | uncommon |
| aucinf.pred | AUC start to inf, pred Clast extrap | auc | uncommon |
| aumcinf.obs | AUMC start to inf, obs Clast extrap | aumc | uncommon |
| aumcinf.obs_se | SE of AUMCinf,obs (sparse PK only) | aumc | uncommon |
| aumcinf.obs_df | DF for AUMCinf,obs (sparse PK only) | aumc | uncommon |
| aumcinf.pred | AUMC start to inf, pred Clast extrap | aumc | uncommon |
| aucint.inf.obs | AUC from T1 to T2 (AUCinf,obs extrap) | auc | common |
| aucint.inf.pred | AUC from T1 to T2 (AUCinf,pred extrap) | auc | uncommon |
| aumcint.inf.obs | AUMC from T1 to T2 (AUMCinf,obs extrap) | aumc | uncommon |
| aumcint.inf.pred | AUMC from T1 to T2 (AUMCinf,pred extrap) | aumc | uncommon |
| aucivinf.obs | AUCinf,obs, IV back-extrap C0 | auc | uncommon |
| aucivinf.obs_se | SE of AUCinf,obs IV (sparse PK only) | auc | uncommon |
| aucivinf.obs_df | DF for AUCinf,obs IV (sparse PK only) | auc | uncommon |
| aucivinf.pred | AUCinf,pred, IV back-extrap C0 | auc | uncommon |
| aucivpbextinf.obs | Back-extrap %, IV, AUCinf,obs | auc_extrapolation | uncommon |
| aucivpbextinf.pred | Back-extrap %, IV, AUCinf,pred | auc_extrapolation | uncommon |
| aumcivinf.obs | AUMCinf,obs, IV back-extrap C0 | aumc | uncommon |
| aumcivinf.obs_se | SE of AUMCinf,obs IV (sparse PK only) | aumc | uncommon |
| aumcivinf.obs_df | DF for AUMCinf,obs IV (sparse PK only) | aumc | uncommon |
| aumcivinf.pred | AUMCinf,pred, IV back-extrap C0 | aumc | uncommon |
| aucpext.obs | % AUCinf extrap after Tlast, obs | auc_extrapolation | common |
| aucpext.pred | % AUCinf extrap after Tlast, pred | auc_extrapolation | uncommon |
| kel.iv.all | Elim rate, IV MRTall | elimination_rate | uncommon |
| kel.ivint.all | Elim rate, IV MRTint,all | elimination_rate | uncommon |
| kel.ivint.last | Elim rate, IV MRTint,last | elimination_rate | uncommon |
| kel.sparse.last | Elim rate, sparse MRTlast | elimination_rate | uncommon |
| cl.obs | Clearance, observed Clast | clearance | common |
| cl.pred | Clearance, predicted Clast | clearance | uncommon |
| cl.int.inf.obs | Clearance, AUCint,inf,obs | clearance | common |
| cl.int.inf.pred | Clearance, AUCint,inf,pred | clearance | uncommon |
| cl.iv.obs | IV clearance, AUCinf,obs | clearance | uncommon |
| cl.iv.pred | IV clearance, AUCinf,pred | clearance | uncommon |
| f.obs | Bioavailability from AUCinf,obs | bioavailability | uncommon |
| f.pred | Bioavailability from AUCinf,pred | bioavailability | uncommon |
| f.int.obs | Bioavailability from AUCint,inf,obs | bioavailability | uncommon |
| f.int.pred | Bioavailability from AUCint,inf,pred | bioavailability | uncommon |
| mrt.obs | MRT to inf, observed Clast | mrt | uncommon |
| mrt.pred | MRT to inf, predicted Clast | mrt | uncommon |
| mrt.int.inf.obs | MRT, interval AUCinf,obs/AUMCinf,obs | mrt | uncommon |
| mrt.int.inf.pred | MRT, interval AUCinf,pred/AUMCinf,pred | mrt | uncommon |
| mrt.iv.obs | IV MRT, AUCinf,obs/AUMCinf,obs | mrt | uncommon |
| mrt.iv.pred | IV MRT, AUCinf,pred/AUMCinf,pred | mrt | uncommon |
| mrt.md.obs | MRT, multi-dose AUCinf,obs/AUMCinf,obs | mrt | uncommon |
| mrt.md.pred | MRT, multi-dose AUCinf,pred/AUMCinf,pred | mrt | uncommon |
| mrt.ivmd.obs | IV MRT, multi-dose, AUCinf,obs | mrt | uncommon |
| mrt.ivmd.pred | IV MRT, multi-dose, AUCinf,pred | mrt | uncommon |
| vz.obs | Vz, observed Clast | volume_z | uncommon |
| vz.pred | Vz, predicted Clast | volume_z | uncommon |
| vz.int.inf.obs | Vz, interval AUCint,inf,obs | volume_z | uncommon |
| vz.int.inf.pred | Vz, interval AUCint,inf,pred | volume_z | uncommon |
| vz.iv.obs | IV Vz, observed AUCinf | volume_z | uncommon |
| vz.iv.pred | IV Vz, predicted AUCinf | volume_z | uncommon |
| vz.sparse.last | Vz from sparse sampling | volume_z | uncommon |
| vss.obs | Vss, observed Clast | volume_ss | uncommon |
| vss.pred | Vss, predicted Clast | volume_ss | uncommon |
| vss.iv.obs | IV Vss, observed Clast | volume_ss | uncommon |
| vss.iv.pred | IV Vss, predicted Clast | volume_ss | uncommon |
| vss.md.obs | Vss, multi-dose, obs | volume_ss | uncommon |
| vss.md.pred | Vss, multi-dose, pred | volume_ss | uncommon |
| vss.ivmd.obs | IV Vss, multi-dose, obs | volume_ss | uncommon |
| vss.ivmd.pred | IV Vss, multi-dose, pred | volume_ss | uncommon |
| vss.int.inf.obs | Vss, calc from interval AUCint,inf,obs | volume_ss | uncommon |
| vss.int.inf.pred | Vss, calc from interval AUCint,inf,pred | volume_ss | uncommon |
| cav.int.inf.obs | Avg conc in interval (AUCint,inf,obs) | average_conc | uncommon |
| cav.int.inf.pred | Avg conc in interval (AUCint,inf,pred) | average_conc | uncommon |
| ratio.aucinf.obs | Ratio of AUCinf,obs to reference | parameter_ratio | uncommon |
| ratio.aucinf.pred | Ratio of AUCinf,pred to reference | parameter_ratio | uncommon |
| thalf.eff.obs | Effective half-life, MRTobs | effective_half_life | uncommon |
| thalf.eff.pred | Effective half-life, MRTpred | effective_half_life | uncommon |
| thalf.eff.iv.obs | Effective half-life, IV MRTobs | effective_half_life | uncommon |
| thalf.eff.iv.pred | Effective half-life, IV MRTpred | effective_half_life | uncommon |
| kel.obs | Elim rate, MRT w/ obs Clast | elimination_rate | uncommon |
| kel.pred | Elim rate, MRT w/ pred Clast | elimination_rate | uncommon |
| kel.iv.obs | Elim rate, IV MRTobs | elimination_rate | uncommon |
| kel.iv.pred | Elim rate, IV MRTpred | elimination_rate | uncommon |
| kel.int.inf.obs | Elim rate, MRTint,inf,obs | elimination_rate | uncommon |
| kel.int.inf.pred | Elim rate, MRTint,inf,pred | elimination_rate | uncommon |
| auclast.dn | Dose-normalized auclast | auc | uncommon |
| aucall.dn | Dose-normalized aucall | auc | uncommon |
| aucinf.obs.dn | Dose-normalized aucinf.obs | auc | uncommon |
| aucinf.pred.dn | Dose-normalized aucinf.pred | auc | uncommon |
| aumclast.dn | Dose-normalized aumclast | aumc | uncommon |
| aumcall.dn | Dose-normalized aumcall | aumc | uncommon |
| aumcinf.obs.dn | Dose-normalized aumcinf.obs | aumc | uncommon |
| aumcinf.pred.dn | Dose-normalized aumcinf.pred | aumc | uncommon |
| cmax.dn | Dose-normalized cmax | peak_conc | uncommon |
| cmin.dn | Dose-normalized cmin | min_conc | uncommon |
| clast.obs.dn | Dose-normalized clast.obs | last_conc | uncommon |
| clast.pred.dn | Dose-normalized clast.pred | last_conc | uncommon |
| cav.dn | Dose-normalized cav | average_conc | uncommon |
| ctrough.dn | Dose-normalized ctrough | trough_conc | uncommon |
| clr.last.dn | Dose-normalized clr.last | renal_clearance | uncommon |
| clr.obs.dn | Dose-normalized clr.obs | renal_clearance | uncommon |
| clr.pred.dn | Dose-normalized clr.pred | renal_clearance | uncommon |
Parameters fall into broad families:
auclast, aucall, aucinf.obs, aucinf.pred, aumclast, aumcall, aumcinf.*, the interval-restricted aucint.* and aumcint.* variants, and aucabove.*cmax, cmin, ctrough, clast.obs, clast.pred, c0, cstart, ceoi, cavtmax, tmin, tlast, tfirst, tlag, time_abovecl.*, vz.*, vss.*, mrt.*, and kel.* families, each in observed, predicted, last, all, interval, and IV forms (for example cl.obs, cl.last, cl.int.inf.obs, cl.iv.obs)half.life, lambda.z, lambda.z.n.points, span.ratio, r.squared, adj.r.squared, lambda.z.corrxy, and the Tobit outputsae, fe, volpk, clr.*, ermax, ertmax, ertlst, erint, erlstdeg.fluc, swing, ptr, mrt.md.*, vss.md.*, mrt.ivmd.*, vss.ivmd.*, thalf.eff.*f.obs, f.pred, f.last, f.int.* and the ratio.* family (see the Secondary Parameters chapter)auclast_se, auclast_df, and the other _se and _df companions, which arrive with the sparse estimates; the catalog also still lists the deprecated sparse_* and *.sparse.last names (see the Sparse Sampling chapter)aucivlast, aucivall, aucivinf.*, aumciv*, aucivpbext*auclast.dn, cmax.dn, and other *.dn variantscount_conc, count_conc_measured, totdoseIf a parameter you need is not in the catalog, you can add it — see the Writing Custom Parameter Functions chapter and the vignette Writing PKNCA Parameter Functions.
get.parameter.deps()Some parameters depend on others being computed first. By default, get.parameter.deps() returns all parameters that use a given parameter as an input, which answers “what becomes invalid if this parameter changes?”:
[1] "aucivall_df" "aucivall_se" "aucivinf.obs_df"
[4] "aucivinf.obs_se" "aucivlast" "aucivlast_df"
[7] "aucivlast_se" "aucivpbextlast" "auclast"
[10] "auclast_df" "auclast_se" "auclast.dn"
[13] "aucpext.obs" "aucpext.pred" "cav"
[16] "cav.dn" "cl.iv.last" "cl.last"
[19] "deg.fluc" "f.last" "kel.iv.last"
[22] "kel.last" "mrt.iv.last" "mrt.ivmd.obs"
[25] "mrt.ivmd.pred" "mrt.last" "mrt.md.obs"
[28] "mrt.md.pred" "ratio.auclast" "thalf.eff.iv.last"
[31] "thalf.eff.last" "vss.iv.last" "vss.ivmd.obs"
[34] "vss.ivmd.pred" "vss.last" "vss.md.obs"
[37] "vss.md.pred" "vz.iv.last" "vz.last"
This is useful when you plan to modify or exclude a parameter and want to know which downstream parameters depend on it. Dependencies are resolved automatically — you do not need to set dependency flags to TRUE manually.
recursive = TRUE (≥ 0.13.0) searches in the other direction, answering “what does this parameter need?”. It follows each dependency back through the intermediate parameters and returns only what they end at: data inputs such as conc, time, and dose, and the other arguments of the calculation functions, such as options (intermediate parameters such as aucinf.obs are not listed):
[1] "conc" "options" "time"
[1] "adj.r.squared.factor" "allow.tmax.in.half.life"
[3] "check" "conc"
[5] "conc.blq" "conc.na"
[7] "dose" "duration.dose"
[9] "first.tmax" "hl_method"
[11] "lloq" "manually.selected.points"
[13] "max.hl.points" "min.hl.points"
[15] "min.hl.start.time" "options"
[17] "r.squared.factor" "time"
[19] "time.dose" "tobit_n_points_penalty"
[21] "tobit_optim_control"
Interval specifications are checked at two levels.
check.interval.specification() checks the specification on its own: that start and end are present and valid (start < end, non-missing start), that known parameter columns hold valid values, and it warns when a row requests no parameters. Unknown extra columns pass through untouched (deliberately, so grouping columns survive).
[1] 237
start end auclast cmax aucinf.obs
1 0 24 TRUE FALSE FALSE
2 0 Inf FALSE TRUE TRUE
An invalid interval (start >= end) is an error; here it is caught to show its class and message:
class message
"pknca_error_interval_start_gte_end" "start must be < end"
assert_intervals() checks a specification against a PKNCAdata object, and set_intervals() checks it and then stores it in the object. They run whenever intervals are given to PKNCAdata(), and pk.nca() runs assert_intervals() again, so intervals assigned directly to o_data$intervals are checked too (≥ 0.13.0). Beyond the checks above, they require that every column is a group column, a parameter, the imputation column, conc_above, tau, interval_id, a _ref column, interval_time_kind, or listed in keep_interval_cols; that every start is finite and not missing; and that every end is after its start (Inf is allowed, but not missing, NaN, or -Inf). The errors name the offending columns or rows:
start end cmax
1 0 Inf TRUE
class
"pknca_error_invalid_interval_columns"
message
"The following columns in 'intervals' are not allowed: visit"
class
"pknca_error_interval_end_invalid"
message
"Interval `end` must not be missing, NaN, or -Inf (Inf is allowed); rows: 1"
class
"pknca_error_interval_end_not_after_start"
message
"Interval `end` must be after `start`; rows: 1"
To carry an extra column such as visit into the results, list it in the keep_interval_cols option instead (see the Workflow chapter).
check.interval.specification() returns the checked, column-completed specification — every registered parameter column filled in with its default — so it can be used inline before passing to PKNCAdata():
o_conc <- PKNCAconc(Theoph, conc ~ Time | Subject)
o_dose <- PKNCAdose(
Theoph |> group_by(Subject) |>
summarise(Dose = Dose[1] * Wt[1], .groups = "drop") |>
mutate(Time = 0),
Dose ~ Time | Subject
)
my_intervals <- check.interval.specification(
data.frame(
start = c(0, 0),
end = c(24, Inf),
auclast = c(TRUE, FALSE),
aucinf.obs = c(FALSE, TRUE),
cmax = c(FALSE, TRUE),
half.life = c(FALSE, TRUE)
)
)
o_data <- PKNCAdata(o_conc, o_dose, intervals = my_intervals)
o_nca <- pk.nca(o_data)
as.data.frame(o_nca) |> head(8)# A tibble: 8 × 7
Subject start end PPTESTCD PPORRES PPANMETH exclude
<ord> <dbl> <dbl> <chr> <dbl> <chr> <chr>
1 6 0 24 auclast 71.7 "AUC: lin up/log down" <NA>
2 6 0 Inf cmax 6.44 "" <NA>
3 6 0 Inf tmax 1.15 "" <NA>
4 6 0 Inf tlast 23.8 "" <NA>
5 6 0 Inf clast.obs 0.92 "" <NA>
6 6 0 Inf lambda.z 0.0878 "" <NA>
7 6 0 Inf r.squared 0.998 "" <NA>
8 6 0 Inf adj.r.squared 0.998 "" <NA>
pkgdown reference: PKNCAconc() · PKNCAdose() · PKNCAdata() · pk.nca() · PKNCA.options() · pknca_interval_table() · pknca_presets() · pknca_parameter_table() · pknca_concepts() · pknca_tiers() · pknca_concept() · pknca_check_parameter_classification() · interval_add_param() · interval_remove_param() · interval_add_impute() · interval_remove_impute() · get_impute_column() · get_impute_method() · setDuration() · get.interval.cols() · get.parameter.deps() · check.interval.specification() · assert_intervals() · set_intervals()
---
title: "Interval Selection and Parameter Catalog"
---
```{r setup, include=FALSE}
library(PKNCA)
library(dplyr)
conflicted::conflicts_prefer(dplyr::filter, dplyr::select, .quiet = TRUE)
```
Intervals tell PKNCA *when* to calculate and *what* to calculate. Every calculated parameter value comes from exactly one interval row, and each row is independent of all others. See also the package vignette [Selection of Calculation Intervals](https://humanpred.github.io/pknca/articles/v03-selection-of-calculation-intervals.html).
---
## The interval data frame structure
An interval specification is a plain R `data.frame` with one row per calculation window. Two columns are required:
| Column | Type | Meaning |
|---------|---------|------------------------------------------------------|
| `start` | numeric | Start of the calculation window (same units as time) |
| `end` | numeric | End of the calculation window; use `Inf` for open-ended windows |
Every remaining column is normally a **parameter flag**: its name must match a known PKNCA parameter name and its value must be `TRUE` (calculate) or `FALSE` (skip). Columns set to `FALSE` are simply ignored, so you only need to list the parameters you actually want. The exceptions are:
- grouping columns used for matching (see the group-matching section below);
- the imputation column, which may have any name and is the column that the `impute` argument of `PKNCAdata()` names (see [Imputation columns](#imputation-columns) below and the [Concentration Imputation chapter](imputation.qmd));
- an `interval_id` column and `<parameter>_ref` columns, which link an interval to a reference interval for secondary parameters such as renal clearance, bioavailability, and ratios (≥ 0.13.0; see the [Secondary Parameters chapter](secondary-parameters.qmd)); and
- value columns that some parameters read from the interval: `conc_above` (the concentration threshold for `time_above`) and `tau` (the dosing interval for `mrt.md.*` and `vss.md.*`, ≥ 0.13.0; see the [Multiple-Dose and Steady-State chapter](multiple-dose.qmd));
- `interval_time_kind`, which `pk.nca()` adds when it converts [date-time intervals](#date-time-intervals); and
- columns carried through to the results via the `keep_interval_cols` option.
Any other column is an error (`pknca_error_invalid_interval_columns`) when the intervals are checked by `PKNCAdata(intervals = )`, `set_intervals()`, or `pk.nca()` (≥ 0.13.0; see [Validating intervals](#validating-intervals)).
```{r interval-structure}
# A minimal interval: AUClast over the first 24 hours
my_intervals <- data.frame(
start = 0,
end = 24,
auclast = TRUE
)
my_intervals
```
You can also request multiple parameters in a single row:
```{r interval-multi-param}
data.frame(
start = 0,
end = Inf,
cmax = TRUE,
tmax = TRUE,
half.life = TRUE,
aucinf.obs = TRUE
)
```
A parameter cannot be named `start`, `end`, or the same as a grouping variable you use in `PKNCAconc()` — a column whose name matches a grouping variable is treated as a matching key, not a parameter flag.
---
## Group matching
PKNCA matches interval rows to concentration data by comparing the **shared column names** between the interval data frame and the grouping columns of the concentration object. Any column that appears in both is used as a matching key.
```{r group-matching}
o_conc <- PKNCAconc(Theoph, conc ~ Time | Subject)
# Intervals with a Subject column — each row applies to exactly one subject
subject_intervals <- data.frame(
Subject = c("1", "2"),
start = c(0, 0),
end = c(24, 24),
auclast = TRUE
)
# Intervals without Subject — this row applies to ALL subjects (default interval)
# Shown for illustration; the run below uses subject_intervals only
default_interval <- data.frame(
start = 0,
end = 24,
auclast = TRUE
)
```
If an interval row has no group columns, it is a **default interval** and is applied to every group present in the concentration data. This is useful when the same calculation windows apply to all subjects and analytes.
Running the subject-specific intervals shows the matching in action. To keep the output short, restrict the concentration data to subjects 1–3. Subject 3 has no matching interval row, so PKNCA warns about it and returns results only for subjects 1 and 2 (no dose object is needed here because `auclast` is dose-independent):
```{r group-matching-run}
o_conc_subset <- PKNCAconc(
Theoph |> filter(Subject %in% c("1", "2", "3")),
conc ~ Time | Subject
)
o_data_subj <- PKNCAdata(o_conc_subset, intervals = subject_intervals)
o_nca_subj <- pk.nca(o_data_subj)
as.data.frame(o_nca_subj) |>
select(Subject, start, end, PPTESTCD, PPORRES)
```
---
## Default intervals with no `intervals` argument
When you call `PKNCAdata()` without an `intervals` argument, PKNCA generates intervals from the dose times of each group. It finds the dosing regimen, places the intervals (after a single dose, after the first dose, over the last dosing interval at steady state), and asks `pknca_interval_table()` (described [below](#building-intervals)) for the parameters and the imputation that suit each interval (≥ 0.13.0). For a single extravascular dose, as in `Theoph`, every subject gets one interval from the dose to infinity:
```{r use-default}
o_dose <- PKNCAdose(
Theoph |> group_by(Subject) |>
summarise(Dose = Dose[1] * Wt[1], .groups = "drop") |>
mutate(Time = 0),
Dose ~ Time | Subject
)
# No intervals argument: intervals are generated automatically
o_data_default <- PKNCAdata(
PKNCAconc(Theoph, conc ~ Time | Subject),
o_dose
)
# Show subject 1, keeping only the columns that request a parameter
o_data_default$intervals |>
filter(Subject == "1") |>
select(where(~ !is.logical(.x) || any(.x)))
```
The row requests `auclast`, `cmax`, `tmax`, `tlag`, `count_conc`, `half.life`, `aucinf.obs`, `aucpext.obs`, and `cl.obs`, and its `impute` column holds `start_predose_conc0`, which keeps a concentration measured at the dose time, carries a predose concentration forward when there is none, and imputes 0 otherwise. An intravenous bolus gets an extra row that back-extrapolates `c0` without imputation, multiple-dose data get rows built on the `aucint.*` family, and a sparse design imputes only a zero at a single dose. The [Automatic Intervals and Dosing Regimens chapter](auto-intervals.qmd) covers how the regimen is detected, the `auto.interval.tolerance` and `tau.choices` options, and the intervals each design gets.
::: {.callout-note}
## Changed in 0.13.0
Before 0.13.0, a single dose got the two rows of the `single.dose.aucs` option instead: `auclast` over 0 to 24 and `cmax`, `tmax`, `half.life`, and `aucinf.obs` over 0 to infinity, with no imputation. The option still exists and is used when `auto.interval.method = "legacy"`:
```{r default-legacy}
o_data_legacy <- PKNCAdata(
PKNCAconc(Theoph, conc ~ Time | Subject),
o_dose,
options = list(auto.interval.method = "legacy")
)
o_data_legacy$intervals |>
filter(Subject == "1") |>
select(where(~ !is.logical(.x) || any(.x)))
```
The 0 to 24 window of `single.dose.aucs` is written for hours; with a time unit other than hours, the legacy method warns (`pknca_warning_single_dose_aucs_unit`). See also [Options for Controlling PKNCA](https://humanpred.github.io/pknca/articles/v40-options-for-controlling-PKNCA.html).
:::
---
## Multiple intervals per group
Each row of the interval data frame is applied **independently**. A single subject (or group) can have any number of interval rows, each with its own time window and parameter set. PKNCA applies every matching row and collects the results.
```{r multiple-intervals}
# Two windows for the same subjects:
# 0–24 h for early exposure; 0–Inf for terminal parameters
multi_intervals <- data.frame(
start = c(0, 0),
end = c(24, Inf),
auclast = c(TRUE, FALSE),
cmax = c(FALSE, TRUE),
half.life = c(FALSE, TRUE),
aucinf.obs = c(FALSE, TRUE)
)
multi_intervals
```
PKNCA processes each row separately: the first row restricts data to $t \in [0, 24]$ for the `auclast` calculation, while the second row uses all available data to derive terminal parameters.
Overlapping intervals are allowed and do not interfere with each other.
---
## Duration-based events
Some sampling designs record a *duration* rather than an instantaneous sample — for example, urine collection periods or IV infusions. PKNCA tracks these via the `duration` argument in `PKNCAconc()` and `PKNCAdose()`.
When a concentration object carries duration information, PKNCA still selects samples for an interval by their recorded time, which is the **start** of the collection period: a collection is included when its start is at or after the interval `start` and at or before the interval `end`. The duration is not consulted during selection, so a collection that starts inside the interval but ends after `end` contributes its full amount to the interval. For results that are simple to interpret, align the collection boundaries with the interval boundaries, as here:
```{r duration-concept}
# Urine collected 0-4, 4-8, and 8-24 h after a 100 mg oral dose
d_urine_conc <- data.frame(
Subject = 1,
time = c(0, 4, 8), # collection start times (h)
duration = c(4, 4, 16), # collection lengths (h)
conc = c(20, 15, 5), # urine concentration (mg/L)
volume = c(0.5, 0.6, 1.2) # collected urine volume (L)
)
o_urine_conc <- PKNCAconc(
d_urine_conc, conc ~ time | Subject,
duration = "duration", volume = "volume"
)
o_urine_dose <- PKNCAdose(
data.frame(Subject = 1, dose = 100, time = 0),
dose ~ time | Subject
)
# end = 24 matches the end of the final collection (8 + 16 = 24)
urine_intervals <- data.frame(start = 0, end = 24, ae = TRUE)
o_urine <- pk.nca(PKNCAdata(o_urine_conc, o_urine_dose, intervals = urine_intervals))
as.data.frame(o_urine)
```
`ae` (amount excreted) is the sum of concentration × volume over the collections in the interval: $20 \times 0.5 + 15 \times 0.6 + 5 \times 1.2 = 25$ mg of the 100 mg dose.
For IV infusions, `setDuration()` on the dose object sets the infusion duration, and `ceoi` (concentration at end of infusion) becomes calculable within an interval when a sample was drawn at the end-of-infusion time within the interval.
---
## Building intervals with `pknca_interval_table()` {#building-intervals}
`pknca_interval_table()` (≥ 0.13.0) builds an interval specification from a description of the analysis instead of a list of parameter names. Given a start, an end, how often the drug was given (`dosing`), and how (`route`), it chooses the parameters usually reported for that context, the AUC they are built on, and the imputation to calculate them from. It is the function the automatic intervals use, so for a single extravascular dose it returns the same row as the default intervals above:
```{r interval-table-single}
pknca_interval_table(start = 0, end = Inf, dosing = "single", route = "extravascular") |>
select(where(~ !is.logical(.x) || any(.x)))
```
The arguments describe the context:
| Argument | Values | Meaning |
|---|---|---|
| `start`, `end` | numbers (vectors allowed) | The interval bounds; vectors give one set of rows per interval |
| `dosing` | `"single"` (default), `"multiple"`, `"steady_state"` | Given once, repeatedly, or repeatedly at steady state (`pknca_dosing()`) |
| `route` | `"extravascular"` (default), `"iv_bolus"`, `"iv_infusion"`, `"iv_continuous_infusion"` | How the drug was given (`pknca_routes()`); note these are not the `"intravascular"` spelling of `PKNCAdose()` |
| `sample_type` | `"spot"` (default), `"interval"` | Samples at a point in time (blood, plasma) or collections over an interval (urine, feces) (`pknca_sample_types()`) |
| `sparse` | `FALSE` (default), `TRUE` | A sparse design keeps the same parameters but imputes only `start_conc0` at a single dose and nothing otherwise |
| `tier` | `"common"` (default), `"all"` | The parameters usually reported, or every parameter the context can calculate |
| `include`, `exclude` | parameter names or concepts | Add to or remove from what the context gives; naming one in both is an error |
| `impute` | `NULL` (default), a method string, or `NA` | `NULL` chooses the imputation from the context; `NA` uses none |
| `preset` | a name from `pknca_presets()` | A named set of the arguments above to start from; explicit arguments override it |
| `clast_type` | `"obs"` (default), `"pred"` | Extrapolate to infinity from the observed or the predicted last concentration |
| `...` | named values | Columns added to every row, typically the groups the interval applies to |
A single dose is built on AUClast and its extrapolation to infinity; a repeated dose is built on the `aucint.*` family, which interpolates at both interval boundaries, with clearance, volume, and MRT chosen to match. At steady state with the fluctuation parameters added (and a group column given through `...`):
```{r interval-table-ss}
pknca_interval_table(
start = 144, end = 168,
dosing = "steady_state", route = "extravascular",
include = "fluctuation",
Subject = "1"
) |>
select(where(~ !is.logical(.x) || any(.x)))
```
`include` and `exclude` accept parameter names or the concepts listed by `pknca_concepts()`, so `include = "mrt"` adds the MRT parameters the single-dose context calculates (`mrt.last` and `mrt.obs` in the output below) and `exclude = "clearance"` drops `cl.obs`:
```{r interval-table-include}
pknca_interval_table(0, Inf, include = c("mrt", "aumclast"), exclude = "clearance") |>
select(where(~ !is.logical(.x) || any(.x)))
```
When an imputed value would become the answer, the parameter is kept out of the imputation by splitting the interval into more than one row. After an intravenous bolus, `c0` is back-extrapolated in a second row with no imputation, so that an imputed concentration at the dose time cannot become C0:
```{r interval-table-iv}
pknca_interval_table(0, Inf, dosing = "single", route = "iv_bolus") |>
select(where(~ !is.logical(.x) || any(.x)))
```
`tier = "all"` gives every parameter the context can calculate (`r sum(vapply(pknca_interval_table(0, Inf, tier = "all"), function(v) is.logical(v) && any(v), logical(1)))` parameters for a single extravascular dose, rather than 9), which is a convenient starting point that you can then trim with `interval_remove_param()`.
The table is an ordinary interval data frame, so it goes straight into `PKNCAdata()`. Its `impute` column is read because `impute` defaults to `NA`, which looks for a column named `"impute"`:
```{r interval-table-run}
o_conc <- PKNCAconc(Theoph, conc ~ Time | Subject)
d_int_table <- pknca_interval_table(0, Inf, include = "aumclast")
o_nca_table <- pk.nca(PKNCAdata(o_conc, o_dose, intervals = d_int_table))
as.data.frame(o_nca_table) |>
filter(Subject == "1") |>
select(Subject, start, end, PPTESTCD, PPORRES)
```
### Presets
`pknca_presets()` gives named argument sets for common analyses. Each is a list of arguments to `pknca_interval_table()`:
```{r presets}
names(pknca_presets())
pknca_presets()$bioequivalence
```
| Preset | Arguments it sets |
|---|---|
| `single_dose` | `dosing = "single"`, `route = "extravascular"` |
| `steady_state` | `dosing = "steady_state"`, `route = "extravascular"` |
| `bioequivalence` | single extravascular dose, `include = c("aucall", "clast.obs", "tlast")` |
| `first_in_human` | single extravascular dose, `include = c("clast.obs", "tlast", "span.ratio")` |
| `mass_balance` | single extravascular dose, `sample_type = "interval"`, `include = "excretion_rate"` |
| `sparse_single_dose` | single extravascular dose, `sparse = TRUE` |
Arguments given directly override the preset, here removing the imputation:
```{r presets-use}
pknca_interval_table(0, Inf, preset = "bioequivalence", impute = NA) |>
select(where(~ !is.logical(.x) || any(.x)))
```
The [Bioequivalence chapter](bioequivalence.qmd) uses the `bioequivalence` preset, and the [Sparse Sampling chapter](sparse.qmd) covers sparse designs.
---
## How parameters are classified with `pknca_parameter_table()`
`pknca_interval_table()` chooses parameters from a classification of every registered parameter (≥ 0.13.0). `pknca_parameter_table()` shows it: the `concept` a parameter computes, its reporting `tier`, its `sample_type`, whether it is a `sparse` estimator output, `secondary` (needs inputs from more than one profile), or `dose_normalized`, and the comma-separated `route` and `dosing` contexts it applies to.
```{r param-table}
pknca_parameter_table(c("auclast", "aucint.last", "cmax", "cl.obs", "ae", "f.obs")) |>
select(parameter, concept, tier, sample_type, secondary, dosing)
```
The vocabularies have their own listing functions: `pknca_concepts()`, `pknca_tiers()`, `pknca_dosing()`, and `pknca_sample_types()` (with `pknca_routes()` for routes).
```{r param-vocab}
pknca_concepts()
pknca_tiers()
```
A parameter's concept is declared on its calculation function with `pknca_concept()`, so a parameter registered by another package (or by you, see the [Writing Custom Parameter Functions chapter](custom-parameters.qmd)) can be chosen automatically too. An unclassified parameter is not an error: it is calculated when you request it by name but is never selected automatically, and `pknca_check_parameter_classification()` lists such parameters (zero rows means every registered parameter is classified).
```{r param-concept}
pknca_concept(pk.calc.cmax)
nrow(pknca_check_parameter_classification())
```
Secondary parameters (`f.obs`, `clr.obs`, `ratio.*`, and others) are never selected automatically, because one interval cannot say which other profile is the reference; request them by name as described in the [Secondary Parameters chapter](secondary-parameters.qmd).
---
## Editing intervals {#editing-intervals}
Four functions edit an interval specification (≥ 0.13.0). Each accepts either a data frame of intervals or a `PKNCAdata` object (whose `$intervals` it edits), so you can start from the automatic intervals or from `pknca_interval_table()` and adjust them:
| Function | What it does | Key arguments |
|---|---|---|
| `interval_add_param()` | Request more parameters | `param` (names), `param_pattern` (regular expressions), `target_groups` |
| `interval_remove_param()` | Stop requesting parameters | `param`, `param_pattern`, `target_groups` |
| `interval_add_impute()` | Add an imputation method | `target_impute`, `after` (position in an existing chain: `0` first, `Inf` last), `target_params`, `target_groups` |
| `interval_remove_impute()` | Remove an imputation method | `target_impute`, `target_params`, `target_groups` |
`target_groups` is a data frame of group values; a row of the intervals is edited when it matches every column of at least one of its rows.
```{r edit-param}
d_edit <- data.frame(start = 0, end = Inf, cmax = TRUE, tmax = TRUE)
# Add parameters by name, or by regular expression
interval_add_param(d_edit, param = c("auclast", "half.life")) |>
select(where(~ !is.logical(.x) || any(.x)))
interval_add_param(d_edit, param_pattern = "^aucint\\.(last|all)$") |>
select(where(~ !is.logical(.x) || any(.x)))
```
Removing every parameter from every interval is an error (`pknca_error_interval_nothing_remains`), since nothing would be left to calculate.
When the parameters of one row no longer share the same imputation, the row is split into as many rows as needed, and rows that come to share every value are merged again. Imputing a start concentration for `auclast` only splits the row:
```{r edit-impute}
d_edit2 <- data.frame(start = 0, end = Inf, cmax = TRUE, auclast = TRUE, half.life = TRUE)
interval_add_impute(d_edit2, target_impute = "start_conc0", target_params = "auclast") |>
select(where(~ !is.logical(.x) || any(.x)))
```
Editing a `PKNCAdata` object changes all of its intervals at once. Starting from the automatic `Theoph` intervals, drop `tlag` and `count_conc`, add `aumclast`, and calculate the half-life without the imputed start concentration:
```{r edit-pkncadata}
o_data_edited <- o_data_default |>
interval_remove_param(param = c("tlag", "count_conc")) |>
interval_add_param(param = "aumclast") |>
interval_remove_impute(target_impute = "start_predose_conc0", target_params = "half.life")
o_data_edited$intervals |>
filter(Subject == "1") |>
select(where(~ !is.logical(.x) || any(.x)))
```
`target_groups` restricts an edit to some groups, here subject 2 only:
```{r edit-groups}
d_edit3 <- data.frame(Subject = c("1", "2"), start = 0, end = Inf, auclast = TRUE)
interval_add_impute(d_edit3, target_impute = "start_conc0",
target_groups = data.frame(Subject = "2"))
```
### Imputation columns {#imputation-columns}
The imputation column of an interval table may have any name (≥ 0.13.0). `PKNCAdata(impute = )` reads it this way:
1. If `impute` names a column of the intervals, each row's method comes from that column.
2. Otherwise, if `impute` is `NA` (the default) and the intervals have a column named `"impute"`, each row's method comes from that column. This is how the automatic intervals and `pknca_interval_table()` carry their imputation.
3. Otherwise, `impute` is itself the method string for every interval (an `NA` with no `"impute"` column means no imputation).
The column must be character (`pknca_error_interval_impute_not_character`), except that a column of only `NA` means no imputation. `get_impute_column()` and `get_impute_method()` apply the same rule, which is useful when you write code around PKNCA objects:
```{r impute-column}
d_int_named <- data.frame(
start = c(0, 0), end = c(24, Inf),
auclast = c(TRUE, FALSE), aucinf.obs = c(FALSE, TRUE),
my_impute = c("start_conc0", "start_predose_conc0")
)
o_data_named <- PKNCAdata(o_conc, o_dose, intervals = d_int_named, impute = "my_impute")
get_impute_column(o_data_named$intervals, impute = o_data_named$impute)
get_impute_method(o_data_named$intervals, impute = o_data_named$impute)
# A method string is not a column
get_impute_column(d_int_named, impute = "start_conc0")
```
`interval_add_impute()` and `interval_remove_impute()` edit whichever column the object's `impute` setting names. The methods themselves are described in the [Concentration Imputation chapter](imputation.qmd).
---
## Date-time intervals {#date-time-intervals}
With date-time (POSIXct or Date) concentration and dose times (≥ 0.13.0), `start` and `end` may also be date-times. `pk.nca()` converts each row to numeric time relative to the time reference (the first dose) of the group it applies to. A row that does not name every reference group becomes one row per group, because one clock-time window is a different relative window for each subject. An `end` of `Inf` stays infinite.
```{r datetime-intervals}
d_conc_dt <- data.frame(
Subject = rep(c("A", "B"), each = 8),
datetime = as.POSIXct("2024-03-04 08:00", tz = "UTC") +
3600 * c(c(0, 0.5, 1, 2, 4, 8, 12, 24), 25.5 + c(0, 0.5, 1, 2, 4, 8, 12, 24)),
conc = c(0, 4.1, 6.3, 5.9, 4.4, 2.6, 1.5, 0.4,
0, 3.2, 5.5, 5.8, 4.6, 2.9, 1.8, 0.6)
)
d_dose_dt <- data.frame(
Subject = c("A", "B"),
datetime = as.POSIXct(c("2024-03-04 08:00", "2024-03-05 09:30"), tz = "UTC"),
dose = 100
)
# One clock-time window for both subjects: from subject A's dose onward
d_int_dt <- data.frame(
start = as.POSIXct("2024-03-04 08:00", tz = "UTC"),
end = Inf,
cmax = TRUE
)
o_nca_dt <- pk.nca(PKNCAdata(
PKNCAconc(d_conc_dt, conc ~ datetime | Subject),
PKNCAdose(d_dose_dt, dose ~ datetime | Subject),
intervals = d_int_dt
))
as.data.frame(o_nca_dt) |>
select(Subject, start, end, PPTESTCD, PPORRES)
```
Subject B was dosed 25.5 hours after subject A, so the same window starts at −25.5 h relative to subject B's dose. The converted intervals, with an `interval_time_kind` column, are in `o_nca_dt$data$intervals`. Date-time bounds mixed with finite numeric bounds, an infinite start, date-time intervals for numeric data, and a time zone that differs from the data are errors. The [Date-Time Data and Time References chapter](datetime.qmd) covers date-time data in full.
---
## Full parameter catalog
The complete list of calculable parameters is available programmatically via `get.interval.cols()`. Each entry carries a description, the calculation function, unit type, and dependency information. The table below joins in the `concept` and `tier` from `pknca_parameter_table()`:
```{r param-catalog}
cols <- get.interval.cols()
param_table <- data.frame(
parameter = names(cols),
description = sapply(cols, function(x) x$desc),
stringsAsFactors = FALSE
)
# Exclude the structural columns start/end from the display
param_table <- param_table[!param_table$parameter %in% c("start", "end"), ]
param_table <- merge(
param_table,
pknca_parameter_table()[, c("parameter", "concept", "tier")],
by = "parameter", sort = FALSE
)
rownames(param_table) <- NULL
knitr::kable(
param_table,
col.names = c("Parameter", "Description", "Concept", "Tier"),
caption = paste0(
"All ", nrow(param_table),
" calculable parameters in PKNCA ", packageVersion("PKNCA")
)
)
```
Parameters fall into broad families:
- **AUC / AUMC** — `auclast`, `aucall`, `aucinf.obs`, `aucinf.pred`, `aumclast`, `aumcall`, `aumcinf.*`, the interval-restricted `aucint.*` and `aumcint.*` variants, and `aucabove.*`
- **Concentration** — `cmax`, `cmin`, `ctrough`, `clast.obs`, `clast.pred`, `c0`, `cstart`, `ceoi`, `cav`
- **Time** — `tmax`, `tmin`, `tlast`, `tfirst`, `tlag`, `time_above`
- **Clearance / volume / MRT** — the `cl.*`, `vz.*`, `vss.*`, `mrt.*`, and `kel.*` families, each in observed, predicted, last, all, interval, and IV forms (for example `cl.obs`, `cl.last`, `cl.int.inf.obs`, `cl.iv.obs`)
- **Elimination** — `half.life`, `lambda.z`, `lambda.z.n.points`, `span.ratio`, `r.squared`, `adj.r.squared`, `lambda.z.corrxy`, and the Tobit outputs
- **Excretion** — `ae`, `fe`, `volpk`, `clr.*`, `ermax`, `ertmax`, `ertlst`, `erint`, `erlst`
- **Steady-state / multiple-dose** — `deg.fluc`, `swing`, `ptr`, `mrt.md.*`, `vss.md.*`, `mrt.ivmd.*`, `vss.ivmd.*`, `thalf.eff.*`
- **Secondary (reference interval needed)** — bioavailability `f.obs`, `f.pred`, `f.last`, `f.int.*` and the `ratio.*` family (see the [Secondary Parameters chapter](secondary-parameters.qmd))
- **Sparse estimator outputs** — `auclast_se`, `auclast_df`, and the other `_se` and `_df` companions, which arrive with the sparse estimates; the catalog also still lists the deprecated `sparse_*` and `*.sparse.last` names (see the [Sparse Sampling chapter](sparse.qmd))
- **IV-specific** — `aucivlast`, `aucivall`, `aucivinf.*`, `aumciv*`, `aucivpbext*`
- **Dose-normalized** — `auclast.dn`, `cmax.dn`, and other `*.dn` variants
- **Counts and dose** — `count_conc`, `count_conc_measured`, `totdose`
If a parameter you need is not in the catalog, you can add it — see the [Writing Custom Parameter Functions chapter](custom-parameters.qmd) and the vignette [Writing PKNCA Parameter Functions](https://humanpred.github.io/pknca/articles/v80-writing-parameter-functions.html).
---
## Checking parameter dependencies with `get.parameter.deps()`
Some parameters depend on others being computed first. By default, `get.parameter.deps()` returns all parameters that use a given parameter as an input, which answers "what becomes invalid if this parameter changes?":
```{r param-deps}
# Which parameters depend on auclast?
get.parameter.deps("auclast")
```
This is useful when you plan to modify or exclude a parameter and want to know which downstream parameters depend on it. Dependencies are resolved automatically — you do not need to set dependency flags to `TRUE` manually.
`recursive = TRUE` (≥ 0.13.0) searches in the other direction, answering "what does this parameter need?". It follows each dependency back through the intermediate parameters and returns only what they end at: data inputs such as `conc`, `time`, and `dose`, and the other arguments of the calculation functions, such as `options` (intermediate parameters such as `aucinf.obs` are not listed):
```{r param-deps-recursive}
get.parameter.deps("auclast", recursive = TRUE)
get.parameter.deps("cl.obs", recursive = TRUE)
```
---
## Validating intervals {#validating-intervals}
Interval specifications are checked at two levels.
`check.interval.specification()` checks the specification on its own: that `start` and `end` are present and valid (`start < end`, non-missing start), that known parameter columns hold valid values, and it warns when a row requests no parameters. Unknown extra columns pass through untouched (deliberately, so grouping columns survive).
```{r check-intervals}
# A valid interval
valid_int <- data.frame(
start = c(0, 0),
end = c(24, Inf),
auclast = c(TRUE, FALSE),
aucinf.obs = c(FALSE, TRUE),
cmax = c(FALSE, TRUE)
)
valid_checked <- check.interval.specification(valid_int)
# Every registered parameter column is filled in ...
ncol(valid_checked)
# ... but only the requested ones are TRUE
valid_checked |>
select(where(~ !is.logical(.x) || any(.x)))
```
An invalid interval (`start >= end`) is an error; here it is caught to show its class and message:
```{r check-invalid}
bad_int <- data.frame(
start = 24,
end = 0,
auclast = TRUE
)
tryCatch(
check.interval.specification(bad_int),
error = function(e) c(class = class(e)[1], message = conditionMessage(e))
)
```
`assert_intervals()` checks a specification against a `PKNCAdata` object, and `set_intervals()` checks it and then stores it in the object. They run whenever intervals are given to `PKNCAdata()`, and `pk.nca()` runs `assert_intervals()` again, so intervals assigned directly to `o_data$intervals` are checked too (≥ 0.13.0). Beyond the checks above, they require that every column is a group column, a parameter, the imputation column, `conc_above`, `tau`, `interval_id`, a `_ref` column, `interval_time_kind`, or listed in `keep_interval_cols`; that every `start` is finite and not missing; and that every `end` is after its `start` (`Inf` is allowed, but not missing, `NaN`, or `-Inf`). The errors name the offending columns or rows:
```{r assert-intervals}
o_data_check <- PKNCAdata(o_conc, o_dose, intervals = valid_int)
# Replace the intervals after checking them
o_data_check <- set_intervals(o_data_check, data.frame(start = 0, end = Inf, cmax = TRUE))
o_data_check$intervals
show_error <- function(expr) {
tryCatch(expr, error = function(e) c(class = class(e)[1], message = conditionMessage(e)))
}
# A column that is neither a group, a parameter, nor kept
show_error(set_intervals(o_data_check, data.frame(start = 0, end = 24, auclast = TRUE, visit = 1)))
# An end that is missing
show_error(set_intervals(o_data_check, data.frame(start = 0, end = NA_real_, auclast = TRUE)))
# An end before its start
show_error(set_intervals(o_data_check, bad_int))
```
To carry an extra column such as `visit` into the results, list it in the `keep_interval_cols` option instead (see the [Workflow chapter](workflow.qmd)).
`check.interval.specification()` returns the checked, column-completed specification — every registered parameter column filled in with its default — so it can be used inline before passing to `PKNCAdata()`:
```{r check-inline}
o_conc <- PKNCAconc(Theoph, conc ~ Time | Subject)
o_dose <- PKNCAdose(
Theoph |> group_by(Subject) |>
summarise(Dose = Dose[1] * Wt[1], .groups = "drop") |>
mutate(Time = 0),
Dose ~ Time | Subject
)
my_intervals <- check.interval.specification(
data.frame(
start = c(0, 0),
end = c(24, Inf),
auclast = c(TRUE, FALSE),
aucinf.obs = c(FALSE, TRUE),
cmax = c(FALSE, TRUE),
half.life = c(FALSE, TRUE)
)
)
o_data <- PKNCAdata(o_conc, o_dose, intervals = my_intervals)
o_nca <- pk.nca(o_data)
as.data.frame(o_nca) |> head(8)
```
---
::: {.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) · [PKNCA.options()](https://humanpred.github.io/pknca/reference/PKNCA.options.html) · [pknca_interval_table()](https://humanpred.github.io/pknca/reference/pknca_interval_table.html) · [pknca_presets()](https://humanpred.github.io/pknca/reference/pknca_presets.html) · [pknca_parameter_table()](https://humanpred.github.io/pknca/reference/pknca_parameter_table.html) · [pknca_concepts()](https://humanpred.github.io/pknca/reference/pknca_concepts.html) · [pknca_tiers()](https://humanpred.github.io/pknca/reference/pknca_concepts.html) · [pknca_concept()](https://humanpred.github.io/pknca/reference/pknca_concept.html) · [pknca_check_parameter_classification()](https://humanpred.github.io/pknca/reference/pknca_check_parameter_classification.html) · [interval_add_param()](https://humanpred.github.io/pknca/reference/interval_add_param.html) · [interval_remove_param()](https://humanpred.github.io/pknca/reference/interval_add_param.html) · [interval_add_impute()](https://humanpred.github.io/pknca/reference/interval_add_impute.html) · [interval_remove_impute()](https://humanpred.github.io/pknca/reference/interval_add_impute.html) · [get_impute_column()](https://humanpred.github.io/pknca/reference/get_impute_column.html) · [get_impute_method()](https://humanpred.github.io/pknca/reference/get_impute_method.html) · [setDuration()](https://humanpred.github.io/pknca/reference/setDuration.html) · [get.interval.cols()](https://humanpred.github.io/pknca/reference/get.interval.cols.html) · [get.parameter.deps()](https://humanpred.github.io/pknca/reference/get.parameter.deps.html) · [check.interval.specification()](https://humanpred.github.io/pknca/reference/check.interval.specification.html) · [assert_intervals()](https://humanpred.github.io/pknca/reference/assert_intervals.html) · [set_intervals()](https://humanpred.github.io/pknca/reference/set_intervals.html)
:::