18  Utility Functions

18.1 Overview

PKNCA exports several lower-level utility functions useful for data preparation, interval validation, and direct computation outside the full PKNCAdatapk.nca() pipeline.


18.2 BLQ concentration handling: clean.conc.blq()

Applies the BLQ-handling rule to a concentration vector before fitting. The full analysis pipeline applies this automatically, but clean.conc.blq() is useful for pre-processing or testing your own rule.

conc <- c(0.5, 0.3, 0,    0.1, 0,    0.0, 0.02)
time <- c(0,   1,   2,    3,   4,    5,   6   )

# Drop BLQ (0) values
clean.conc.blq(conc, time, conc.blq = "drop")
  conc time
1 0.50    0
2 0.30    1
4 0.10    3
7 0.02    6
# Replace BLQ with half the LLOQ (= 0.05 here)
clean.conc.blq(conc, time, conc.blq = 0.05)
  conc time
1 0.50    0
2 0.30    1
3 0.05    2
4 0.10    3
5 0.05    4
6 0.05    5
7 0.02    6

The conc.blq argument accepts: - "drop" — remove BLQ rows - "keep" — keep BLQ rows as-is - A number — substitute BLQ values with that number


18.3 NA concentration handling: clean.conc.na()

Removes or replaces NA concentrations. Internally called before AUC computation.

conc_na <- c(0.5, NA, 0.3, 0.1, NA)
time_na <- c(0,   1,   2,   3,   4)

# Default: drop NAs
clean.conc.na(conc_na, time_na, conc.na = "drop")
  conc time
1  0.5    0
3  0.3    2
4  0.1    3
# Replace NAs with 0
clean.conc.na(conc_na, time_na, conc.na = 0)
  conc time
1  0.5    0
2  0.0    1
3  0.3    2
4  0.1    3
5  0.0    4

18.4 Concentration interpolation / extrapolation: interp.extrap.conc()

Interpolates or extrapolates a concentration at a target time given a known concentration-time profile. Used internally when an interval boundary falls between two observed timepoints.

conc_ex <- c(10, 8, 5, 2.5, 1)
time_ex <- c(0,  1, 2, 4,   8)

# Interpolate at t = 3 (between t=2 and t=4)
interp.extrap.conc(conc = conc_ex, time = time_ex, time.out = 3)
[1] 3.535534
# Extrapolate beyond the last sample (t = 12)
interp.extrap.conc(conc = conc_ex, time = time_ex, time.out = 12)
[1] NA

The method (linear vs log-linear) follows the auc.method setting. Extrapolation uses the terminal log-linear slope (requires at least 3 points for λz estimation).


18.5 Direct half-life computation: pk.calc.half.life()

Runs the full curve-stripping algorithm on raw concentration-time data and returns the selected half-life, λz, and associated diagnostics. Useful for batch processing outside the standard pipeline.

subj1 <- as.data.frame(Theoph) |> filter(Subject == "1")

hl_result <- pk.calc.half.life(
  conc    = subj1$conc,
  time    = subj1$Time,
  options = PKNCA.options()
)

hl_result[c("half.life", "lambda.z", "r.squared", "lambda.z.n.points",
            "lambda.z.time.first", "span.ratio")]
  half.life lambda.z r.squared lambda.z.n.points lambda.z.time.first span.ratio
1  14.30438 0.048457 0.9999997                 3                9.05   1.071001

This is the same function called internally by pk.nca() when half.life = TRUE.


18.6 Direct AUC computation: pk.calc.auc.all()

Computes AUC (trapezoid rule) directly on a concentration-time vector. Returns the scalar AUC value.

pk.calc.auc.all(
  conc   = subj1$conc,
  time   = subj1$Time,
  method = "lin up/log down"
)
[1] 147.2347

Other direct AUC functions:

Function AUC type
pk.calc.auc.last() AUC to last measurable concentration
pk.calc.auc.all() AUC to last, treating BLQ as 0
pk.calc.auc.inf.obs() AUC extrapolated to ∞ (observed Clast)
pk.calc.auc.inf.pred() AUC extrapolated to ∞ (predicted Clast)

These are the building blocks behind every AUC parameter in the registry.


18.7 Validating interval specifications: check.interval.specification()

Validates an intervals data frame before passing it to PKNCAdata(). Returns the data frame with all parameter columns filled in (missing columns defaulted to FALSE).

my_intervals <- data.frame(
  start    = 0,
  end      = Inf,
  auclast  = TRUE,
  cmax     = TRUE
)

# Returns the full expanded interval spec
expanded <- check.interval.specification(my_intervals)

# Which parameters are requested?
names(expanded)[as.logical(expanded[1, ])]
[1] "end"     "auclast" "cmax"   
# Invalid specification — missing start column — raises an error
tryCatch(
  check.interval.specification(data.frame(end = Inf, auclast = TRUE)),
  error = function(e) cat("Error:", conditionMessage(e), "\n")
)
Error: Column(s) 'start' missing from interval specification 

This is useful for debugging custom interval definitions before running the full analysis.


18.8 Listing all available parameters

cols <- get.interval.cols()
cat("Total registered parameters:", length(cols), "\n")
Total registered parameters: 203 
# Show first few with their dependency lists
lapply(head(cols, 5), function(x) x$depends)
$start
NULL

$end
NULL

$auclast
NULL

$aucall
NULL

$aumclast
NULL
# All dose-normalized parameters
dn_params <- names(cols)[endsWith(names(cols), ".dn")]
cat("Dose-normalized parameters:\n")
Dose-normalized parameters:
cat(paste(" -", dn_params), sep = "\n")
 - auclast.dn
 - aucall.dn
 - aucinf.obs.dn
 - aucinf.pred.dn
 - aumclast.dn
 - aumcall.dn
 - aumcinf.obs.dn
 - aumcinf.pred.dn
 - cmax.dn
 - cmin.dn
 - clast.obs.dn
 - clast.pred.dn
 - cav.dn
 - ctrough.dn
 - clr.last.dn
 - clr.obs.dn
 - clr.pred.dn

18.9 Modifying PKNCAdose after creation: setRoute() and setDuration()

After creating a PKNCAdose object, you can change the route or infusion duration without rebuilding from scratch.

d_dose_u <- data.frame(subject = "1", dose = 100, time = 0)
o_dose_u <- PKNCAdose(d_dose_u, dose ~ time | subject, route = "extravascular")

# Change to intravascular
o_dose_iv <- setRoute(o_dose_u, route = "intravascular")
Found column named route, using it for the attribute of the same name.
# Add infusion duration (0.5 h = 30 min)
o_dose_inf <- setDuration(o_dose_iv, duration = 0.5)
Found column named duration, using it for the attribute of the same name.
# Verify
o_dose_inf$data[c("route", "duration")]
          route duration
1 intravascular      0.5

This is useful when you want to test how route assumption changes affect MRT or Vss calculations without rebuilding the full PKNCAdata object.


18.10 Getting parameter dependencies: get.parameter.deps()

Returns the upstream parameters that a given parameter depends on. Useful when debugging why a parameter is NA (a dependency may have failed).

get.parameter.deps("vss.obs")
[1] "vss.obs"
get.parameter.deps("half.life")
 [1] "adj_tobit_residual"    "adj.r.squared"         "aucinf.obs"           
 [4] "aucinf.obs.dn"         "aucinf.pred"           "aucinf.pred.dn"       
 [7] "aucint.inf.obs"        "aucint.inf.obs.dose"   "aucint.inf.pred"      
[10] "aucint.inf.pred.dose"  "aucivinf.obs"          "aucivinf.pred"        
[13] "aucivpbextinf.obs"     "aucivpbextinf.pred"    "aucpext.obs"          
[16] "aucpext.pred"          "aumcinf.obs"           "aumcinf.obs.dn"       
[19] "aumcinf.pred"          "aumcinf.pred.dn"       "aumcint.inf.obs"      
[22] "aumcint.inf.obs.dose"  "aumcint.inf.pred"      "aumcint.inf.pred.dose"
[25] "aumcivinf.obs"         "aumcivinf.pred"        "cav.int.inf.obs"      
[28] "cav.int.inf.pred"      "cl.int.inf.obs"        "cl.int.inf.pred"      
[31] "cl.iv.obs"             "cl.iv.pred"            "cl.obs"               
[34] "cl.pred"               "clast.pred"            "clast.pred.dn"        
[37] "half.life"             "kel.int.inf.obs"       "kel.int.inf.pred"     
[40] "kel.iv.obs"            "kel.iv.pred"           "kel.obs"              
[43] "kel.pred"              "lambda.z"              "lambda.z.corrxy"      
[46] "lambda.z.n.points"     "lambda.z.n.points_blq" "lambda.z.time.first"  
[49] "lambda.z.time.last"    "mrt.int.inf.obs"       "mrt.int.inf.pred"     
[52] "mrt.iv.obs"            "mrt.iv.pred"           "mrt.md.obs"           
[55] "mrt.md.pred"           "mrt.obs"               "mrt.pred"             
[58] "r.squared"             "span.ratio"            "thalf.eff.iv.obs"     
[61] "thalf.eff.iv.pred"     "thalf.eff.obs"         "thalf.eff.pred"       
[64] "tobit_residual"        "vss.int.inf.obs"       "vss.int.inf.pred"     
[67] "vss.iv.obs"            "vss.iv.pred"           "vss.md.obs"           
[70] "vss.md.pred"           "vss.obs"               "vss.pred"             
[73] "vz.all"                "vz.int.all"            "vz.int.inf.obs"       
[76] "vz.int.inf.pred"       "vz.int.last"           "vz.iv.all"            
[79] "vz.iv.last"            "vz.iv.obs"             "vz.iv.pred"           
[82] "vz.ivint.all"          "vz.ivint.last"         "vz.last"              
[85] "vz.obs"                "vz.pred"              

18.11 Listing all current option values: PKNCA.options()

PKNCA.options() with no arguments returns the full named list of current settings:

PKNCA.options()
$adj.r.squared.factor
[1] 1e-04

$max.missing
[1] 0.5

$auc.method
[1] "lin up/log down"

$conc.na
[1] "drop"

$conc.blq
$conc.blq$first
[1] "keep"

$conc.blq$middle
[1] "drop"

$conc.blq$last
[1] "keep"


$debug
NULL

$first.tmax
[1] TRUE

$first.tmin
[1] TRUE

$allow.tmax.in.half.life
[1] FALSE

$keep_interval_cols
NULL

$min.hl.points
[1] 3

$min.span.ratio
[1] 2

$max.aucinf.pext
[1] 20

$min.hl.r.squared
[1] 0.9

$progress
[1] TRUE

$tau.choices
[1] NA

$single.dose.aucs
  start end auclast aucall aumclast aumcall aucint.last aucint.last.dose
1     0  24    TRUE  FALSE    FALSE   FALSE       FALSE            FALSE
2     0 Inf   FALSE  FALSE    FALSE   FALSE       FALSE            FALSE
  aucint.all aucint.all.dose aumcint.last aumcint.last.dose aumcint.all
1      FALSE           FALSE        FALSE             FALSE       FALSE
2      FALSE           FALSE        FALSE             FALSE       FALSE
  aumcint.all.dose    c0  cmax  cmin  tmax  tmin tlast tfirst clast.obs cl.last
1            FALSE FALSE FALSE FALSE FALSE FALSE FALSE  FALSE     FALSE   FALSE
2            FALSE FALSE  TRUE FALSE  TRUE FALSE FALSE  FALSE     FALSE   FALSE
  cl.all cl.int.all cl.int.last     f mrt.last mrt.all mrt.int.all mrt.int.last
1  FALSE      FALSE       FALSE FALSE    FALSE   FALSE       FALSE        FALSE
2  FALSE      FALSE       FALSE FALSE    FALSE   FALSE       FALSE        FALSE
  mrt.iv.last vss.last vss.iv.last vss.all vss.int.all vss.int.last   cav
1       FALSE    FALSE       FALSE   FALSE       FALSE        FALSE FALSE
2       FALSE    FALSE       FALSE   FALSE       FALSE        FALSE FALSE
  cav.int.last cav.int.all ctrough cstart   ptr  tlag deg.fluc swing  ceoi
1        FALSE       FALSE   FALSE  FALSE FALSE FALSE    FALSE FALSE FALSE
2        FALSE       FALSE   FALSE  FALSE FALSE FALSE    FALSE FALSE FALSE
  aucabove.predose.all aucabove.trough.all count_conc count_conc_measured
1                FALSE               FALSE      FALSE               FALSE
2                FALSE               FALSE      FALSE               FALSE
  totdose volpk    ae clr.last clr.obs clr.pred    fe ertlst ermax ertmax
1   FALSE FALSE FALSE    FALSE   FALSE    FALSE FALSE  FALSE FALSE  FALSE
2   FALSE FALSE FALSE    FALSE   FALSE    FALSE FALSE  FALSE FALSE  FALSE
  sparse_auclast sparse_auc_se sparse_auc_df sparse_aumclast sparse_aumc_se
1          FALSE         FALSE         FALSE           FALSE          FALSE
2          FALSE         FALSE         FALSE           FALSE          FALSE
  sparse_aumc_df time_above aucivlast aucivall aucivint.last aucivint.all
1          FALSE      FALSE     FALSE    FALSE         FALSE        FALSE
2          FALSE      FALSE     FALSE    FALSE         FALSE        FALSE
  aucivpbextlast aucivpbextall aucivpbextint.last aucivpbextint.all aumcivlast
1          FALSE         FALSE              FALSE             FALSE      FALSE
2          FALSE         FALSE              FALSE             FALSE      FALSE
  aumcivall aumcivint.last aumcivint.all half.life r.squared adj.r.squared
1     FALSE          FALSE         FALSE     FALSE     FALSE         FALSE
2     FALSE          FALSE         FALSE      TRUE     FALSE         FALSE
  lambda.z.corrxy lambda.z lambda.z.time.first lambda.z.time.last
1           FALSE    FALSE               FALSE              FALSE
2           FALSE    FALSE               FALSE              FALSE
  lambda.z.n.points clast.pred span.ratio tobit_residual adj_tobit_residual
1             FALSE      FALSE      FALSE          FALSE              FALSE
2             FALSE      FALSE      FALSE          FALSE              FALSE
  lambda.z.n.points_blq thalf.eff.last thalf.eff.iv.last kel.last kel.iv.last
1                 FALSE          FALSE             FALSE    FALSE       FALSE
2                 FALSE          FALSE             FALSE    FALSE       FALSE
  kel.all kel.int.all kel.int.last cl.iv.all cl.iv.last cl.ivint.all
1   FALSE       FALSE        FALSE     FALSE      FALSE        FALSE
2   FALSE       FALSE        FALSE     FALSE      FALSE        FALSE
  cl.ivint.last cl.sparse.last mrt.sparse.last mrt.iv.all mrt.ivint.all
1         FALSE          FALSE           FALSE      FALSE         FALSE
2         FALSE          FALSE           FALSE      FALSE         FALSE
  mrt.ivint.last vz.all vz.int.all vz.int.last vz.iv.all vz.iv.last
1          FALSE  FALSE      FALSE       FALSE     FALSE      FALSE
2          FALSE  FALSE      FALSE       FALSE     FALSE      FALSE
  vz.ivint.all vz.ivint.last vz.last vss.iv.all vss.ivint.all vss.ivint.last
1        FALSE         FALSE   FALSE      FALSE         FALSE          FALSE
2        FALSE         FALSE   FALSE      FALSE         FALSE          FALSE
  vss.sparse.last aucinf.obs aucinf.pred aumcinf.obs aumcinf.pred
1           FALSE      FALSE       FALSE       FALSE        FALSE
2           FALSE       TRUE       FALSE       FALSE        FALSE
  aucint.inf.obs aucint.inf.obs.dose aucint.inf.pred aucint.inf.pred.dose
1          FALSE               FALSE           FALSE                FALSE
2          FALSE               FALSE           FALSE                FALSE
  aumcint.inf.obs aumcint.inf.obs.dose aumcint.inf.pred aumcint.inf.pred.dose
1           FALSE                FALSE            FALSE                 FALSE
2           FALSE                FALSE            FALSE                 FALSE
  aucivinf.obs aucivinf.pred aucivpbextinf.obs aucivpbextinf.pred aumcivinf.obs
1        FALSE         FALSE             FALSE              FALSE         FALSE
2        FALSE         FALSE             FALSE              FALSE         FALSE
  aumcivinf.pred aucpext.obs aucpext.pred kel.iv.all kel.ivint.all
1          FALSE       FALSE        FALSE      FALSE         FALSE
2          FALSE       FALSE        FALSE      FALSE         FALSE
  kel.ivint.last kel.sparse.last cl.obs cl.pred cl.int.inf.obs cl.int.inf.pred
1          FALSE           FALSE  FALSE   FALSE          FALSE           FALSE
2          FALSE           FALSE  FALSE   FALSE          FALSE           FALSE
  cl.iv.obs cl.iv.pred mrt.obs mrt.pred mrt.int.inf.obs mrt.int.inf.pred
1     FALSE      FALSE   FALSE    FALSE           FALSE            FALSE
2     FALSE      FALSE   FALSE    FALSE           FALSE            FALSE
  mrt.iv.obs mrt.iv.pred mrt.md.obs mrt.md.pred vz.obs vz.pred vz.int.inf.obs
1      FALSE       FALSE      FALSE       FALSE  FALSE   FALSE          FALSE
2      FALSE       FALSE      FALSE       FALSE  FALSE   FALSE          FALSE
  vz.int.inf.pred vz.iv.obs vz.iv.pred vz.sparse.last vss.obs vss.pred
1           FALSE     FALSE      FALSE          FALSE   FALSE    FALSE
2           FALSE     FALSE      FALSE          FALSE   FALSE    FALSE
  vss.iv.obs vss.iv.pred vss.md.obs vss.md.pred vss.int.inf.obs
1      FALSE       FALSE      FALSE       FALSE           FALSE
2      FALSE       FALSE      FALSE       FALSE           FALSE
  vss.int.inf.pred cav.int.inf.obs cav.int.inf.pred thalf.eff.obs
1            FALSE           FALSE            FALSE         FALSE
2            FALSE           FALSE            FALSE         FALSE
  thalf.eff.pred thalf.eff.iv.obs thalf.eff.iv.pred kel.obs kel.pred kel.iv.obs
1          FALSE            FALSE             FALSE   FALSE    FALSE      FALSE
2          FALSE            FALSE             FALSE   FALSE    FALSE      FALSE
  kel.iv.pred kel.int.inf.obs kel.int.inf.pred auclast.dn aucall.dn
1       FALSE           FALSE            FALSE      FALSE     FALSE
2       FALSE           FALSE            FALSE      FALSE     FALSE
  aucinf.obs.dn aucinf.pred.dn aumclast.dn aumcall.dn aumcinf.obs.dn
1         FALSE          FALSE       FALSE      FALSE          FALSE
2         FALSE          FALSE       FALSE      FALSE          FALSE
  aumcinf.pred.dn cmax.dn cmin.dn clast.obs.dn clast.pred.dn cav.dn ctrough.dn
1           FALSE   FALSE   FALSE        FALSE         FALSE  FALSE      FALSE
2           FALSE   FALSE   FALSE        FALSE         FALSE  FALSE      FALSE
  clr.last.dn clr.obs.dn clr.pred.dn
1       FALSE      FALSE       FALSE
2       FALSE      FALSE       FALSE

$allow_partial_missing_units
[1] FALSE

$hl_method
[1] "log-linear"

$tobit_n_points_penalty
[1] 0

$tobit_optim_control
list()

Note: PKNCA.options.describe() is exported but non-functional in PKNCA 0.12.1 (raises an error). Use PKNCA.options() to inspect current settings, and see the Workflow Overview page for the full option reference table.


18.12 Choosing an option value: PKNCA.choose.option()

Selects a value from either the local options list passed to PKNCAdata() or the global PKNCA.options() defaults. Useful when writing custom parameter functions that need to respect session-level settings.

# With no local override, returns the global default
PKNCA.choose.option("min.hl.points", options = list())
[1] 3
# With a local override, the local value wins
PKNCA.choose.option("min.hl.points", options = list(min.hl.points = 5))
[1] 5