Skip to content

[Review view] SDTM Phase 1: R conversion functions + tests#1328

Draft
Gero1999 wants to merge 1 commit into
mainfrom
sdtm-phase1-r-functions
Draft

[Review view] SDTM Phase 1: R conversion functions + tests#1328
Gero1999 wants to merge 1 commit into
mainfrom
sdtm-phase1-r-functions

Conversation

@Gero1999

Copy link
Copy Markdown
Collaborator

⚠️ Review-only PR — do not merge

This is a review view into the SDTM changes from #1318. It isolates the R package conversion functions for focused code review. The actual merge will happen via #1318.

Scope

New R functions in R/sdtm_to_pknca.R that convert CDISC SDTM domain data (PC, EX, DM) into PKNCAdata objects:

Function Purpose
sdtm_to_PKNCAdata(pc, ex, dm, metabolites) Top-level entry point, returns PKNCAdata
pc_to_PKNCAconc(pc, ex, dm) PC domain → PKNCAconc with timing derivations
ex_to_PKNCAdose(ex) EX domain → PKNCAdose with duration/route parsing
parse_iso8601_duration(x) ISO 8601 duration → numeric hours
route_cdisc_to_pknca(routes) CDISC route terms → PKNCA values
std_dtc_to_rdate(dtc) ISO 8601 datetime → POSIXct

Plus internal helpers: .check_required_cols(), .prepare_dose_table(), .assign_doses_to_conc().

Files changed

  • R/sdtm_to_pknca.R — 537 lines, all new
  • NAMESPACE — 4 new exports
  • man/ — 9 new .Rd files
  • tests/testthat/test-sdtm_to_pknca.R — 908 lines, 60+ tests

What to review

  • Correctness of timing variable derivations (AFRLT, ARRLT, NFRLT, NRRLT)
  • Dose assignment logic (DOSNOA, ATPTREF)
  • ISO 8601 parsing edge cases
  • Route mapping completeness
  • Test coverage

New R functions to convert CDISC SDTM domain data (PC, EX, DM) into
PKNCAdata objects for NCA computation:

- sdtm_to_PKNCAdata(): top-level entry point
- pc_to_PKNCAconc(): PC domain to PKNCAconc with timing derivations
- ex_to_PKNCAdose(): EX domain to PKNCAdose with duration/route parsing
- parse_iso8601_duration(): ISO 8601 duration string to numeric hours
- route_cdisc_to_pknca(): CDISC route terms to PKNCA route values
- std_dtc_to_rdate(): ISO 8601 datetime string to POSIXct

Includes 60+ unit tests covering standard usage, edge cases,
multi-dose scenarios, metabolite handling, and error conditions.

Co-authored-by: Ona <no-reply@ona.com>
Comment thread R/sdtm_to_pknca.R
Comment on lines +95 to +107
if ("EXDUR" %in% names(ex)) {
adosedur <- if (is.character(ex$EXDUR)) {
parse_iso8601_duration(ex$EXDUR)
} else {
as.numeric(ex$EXDUR)
}
} else if ("EXENDTC" %in% names(ex)) {
end_posix <- std_dtc_to_rdate(ex$EXENDTC)
dur <- as.numeric(difftime(end_posix, exstdtc_posix, units = "hours"))
adosedur <- ifelse(is.na(dur), 0, dur)
} else {
adosedur <- rep(0, nrow(ex))
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we modify the duration calculation logic to prevent crashes when EXDUR column is present but entirely empty (containing only NAs or blank strings). Like instead falling through to EXENDTC which might have actual values ?

Suggested change
if ("EXDUR" %in% names(ex)) {
adosedur <- if (is.character(ex$EXDUR)) {
parse_iso8601_duration(ex$EXDUR)
} else {
as.numeric(ex$EXDUR)
}
} else if ("EXENDTC" %in% names(ex)) {
end_posix <- std_dtc_to_rdate(ex$EXENDTC)
dur <- as.numeric(difftime(end_posix, exstdtc_posix, units = "hours"))
adosedur <- ifelse(is.na(dur), 0, dur)
} else {
adosedur <- rep(0, nrow(ex))
}
if ("EXDUR" %in% names(ex) && !all(is.na(ex$EXDUR) | !nzchar(ex$EXDUR))) {
adosedur <- if (is.character(ex$EXDUR)) {
parse_iso8601_duration(ex$EXDUR)
} else {
as.numeric(ex$EXDUR)
}
} else if ("EXENDTC" %in% names(ex)) {
end_posix <- std_dtc_to_rdate(ex$EXENDTC)
adosedur <- as.numeric(difftime(end_posix, exstdtc_posix, units = "hours"))
} else {
adosedur <- rep(0, nrow(ex))
}
adosedur <- ifelse(is.na(adosedur), 0, adosedur)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants