Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ the dosing including dose amount and route.

# Development version

* Bug fix: `pk.nca()` no longer errors on unsorted concentration-time data.
Group-level concentration data are now sorted by time before calculation, so
parameters that use the full group (e.g. `aucint.all` and the other `aucint*`
parameters) work when the input rows are not in time order (#568).

* Business functions (used for calculations of means, etc.) now return NA_real_
for empty inputs rather than giving an error (#559).

Expand Down
6 changes: 6 additions & 0 deletions R/pk.calc.all.R
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ pk.nca.intervals <- function(data_conc, data_dose, data_intervals, sparse,
# No intervals; potentially placebo data
return(rlang::warning_cnd(class="pknca_no_intervals", message="No intervals for data"))
}
# Sort the group-level concentration data in time order. The interval-level
# data are sorted below (per interval), but the group-level data are passed
# as-is to parameters that use `conc.group`/`time.group` (e.g. aucint*), and
# several of those (via interp.extrap.conc()) require time-sorted input. See
# https://github.com/humanpred/pknca/issues/568.
data_conc <- data_conc[order(data_conc$time), , drop=FALSE]
# Hoist the debug check: options is already the fully-merged options object
# (merged at the top of pk.nca()), so there is no need to re-query
# PKNCA.options() from the environment on every iteration.
Expand Down
46 changes: 46 additions & 0 deletions tests/testthat/test-pk.calc.all.R
Original file line number Diff line number Diff line change
Expand Up @@ -1050,3 +1050,49 @@ test_that("pk.nca.interval covers route, volume.group, duration.conc.group, dose
result <- pk.nca(o_data)
expect_true("pknca_test_grp_args_cov_col_" %in% as.data.frame(result)$PPTESTCD)
})

test_that("pk.nca sorts group data by time so unsorted input works (#568)", {
conc_data <-
data.frame(
MRRLT = c(16, -0.8, 3, 6, 8, 12, 20, 25),
AVAL = c(120, 260, 340, 300, 210, 150, 110, 90)
)
conc_sorted <- conc_data[order(conc_data$MRRLT), ]
dose_data <- data.frame(EXDOSE = 1)

run_nca <- function(cdat) {
o_conc <- PKNCAconc(cdat, AVAL ~ MRRLT)
o_dose <- PKNCAdose(dose_data, EXDOSE ~ .)
intervals <-
data.frame(
start = 0, end = 24,
aucint.all = TRUE, aucint.last = TRUE, aucint.inf.obs = TRUE,
cmax = TRUE, half.life = TRUE
)
o_data <-
PKNCAdata(
o_conc, o_dose, intervals = intervals,
options = list(auc.method = "linear")
)
as.data.frame(suppressWarnings(pk.nca(o_data)))
}

# Previously errored with "Assertion on 'time' failed: Must be sorted."
res_unsorted <- expect_no_error(run_nca(conc_data))
res_sorted <- run_nca(conc_sorted)

# aucint* parameters (which use the group-level time/conc) are calculable and
# identical regardless of the input ordering.
expect_equal(
res_unsorted$PPORRES[res_unsorted$PPTESTCD == "aucint.all"],
4523.263157894737
)
# Every parameter matches the pre-sorted calculation.
merged <-
merge(
res_unsorted[, c("PPTESTCD", "PPORRES")],
res_sorted[, c("PPTESTCD", "PPORRES")],
by = "PPTESTCD", suffixes = c(".uns", ".srt")
)
expect_equal(merged$PPORRES.uns, merged$PPORRES.srt)
})
Loading