Skip to content

Commit

Permalink
More unit testing, updates to calc_* functions (#67)
Browse files Browse the repository at this point in the history
* Fix 'simulate_exposure' to always return a matrix

* Minor document changes

* Updated 'calc_internal_dose'

* typo

* Updated 'calc_invitro_concentration'

* Added '.check_types' function

* Renamed 'tp_b_mult' to 'max_mult'

* Added renv ignores

* Updated 'calc_concentration_response'
  • Loading branch information
SkylarMarvel authored Oct 28, 2024
1 parent a460362 commit c2086cc
Show file tree
Hide file tree
Showing 29 changed files with 460 additions and 167 deletions.
3 changes: 3 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
^renv$
^renv\.lock$
^\.Rprofile$
^GeoTox\.Rproj$
^\.Rproj\.user$
^LICENSE\.md$
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
*.Rproj
.Rproj.user/

# renv files
renv/
renv.lock
.Rprofile

# produced vignettes
vignettes/*.html
vignettes/*.pdf
Expand Down
2 changes: 1 addition & 1 deletion R/GeoTox.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ GeoTox <- function() {
internal_dose = list(time = 1,
BW = 1,
scaling = 1),
resp = list(tp_b_mult = 1.5)
resp = list(max_mult = 1.5)
)
),
class = "GeoTox")
Expand Down
45 changes: 19 additions & 26 deletions R/calc_concentration_response.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#'
#' @param C_invitro in vitro concentrations
#' @param hill_params output from `fit_hill()`
#' @param tp_b_mult upper bound multiplier for tp rtruncnorm
#' @param max_mult upper bound multiplier for max response
#' @param fixed if TRUE, sd = 0
#'
#' @description
Expand All @@ -16,14 +16,13 @@
#' @export
calc_concentration_response <- function(C_invitro,
hill_params,
tp_b_mult = 1.5,
max_mult = 1.5,
fixed = FALSE) {

if (!any(c("matrix", "list") %in% class(C_invitro))) {
stop("C_invitro must be a matrix or list")
}
if (!is.list(C_invitro)) C_invitro <- list(C_invitro)

C_invitro <- .check_types(C_invitro,
"matrix",
"`C_invitro` must be a matrix or list of matrices.")

# Split hill_params by assay
if ("assay" %in% names(hill_params)) {
hill_params <- split(hill_params, ~assay)
Expand All @@ -34,9 +33,7 @@ calc_concentration_response <- function(C_invitro,
# Calculate response for each assay
lapply(C_invitro, \(C_invitro_i) {
lapply(hill_params, \(hill_params_j) {
if (ncol(C_invitro_i) == 1 & nrow(hill_params_j) == 1) {
.calc_concentration_response(C_invitro_i, hill_params_j, tp_b_mult, fixed)
} else {
if (ncol(C_invitro_i) != 1 | nrow(hill_params_j) != 1) {
if (!"chem" %in% names(hill_params_j)) {
stop("'hill_params' must contain a 'chem' column", call. = FALSE)
}
Expand All @@ -45,35 +42,33 @@ calc_concentration_response <- function(C_invitro,
stop("'hill_params' chemicals missing in 'C_invitro'", call. = FALSE)
}
C_invitro_i <- C_invitro_i[, chems, drop = FALSE]
res <- .calc_concentration_response(C_invitro_i,
hill_params_j,
tp_b_mult,
fixed) |>
dplyr::mutate(sample = dplyr::row_number(), .before = 1)
if ("assay" %in% names(hill_params_j)) {
res <- res |>
dplyr::mutate(assay = hill_params_j$assay[[1]], .before = 1)
}
res
}
res <- .calc_concentration_response(C_invitro_i,
hill_params_j,
max_mult,
fixed) |>
dplyr::mutate(sample = dplyr::row_number(), .before = 1)
if ("assay" %in% names(hill_params_j)) {
res <- res |>
dplyr::mutate(assay = hill_params_j$assay[[1]], .before = 1)
}
res
}) |>
dplyr::bind_rows()
})
}

.calc_concentration_response <- function(
C_invitro, hill_params, tp_b_mult, fixed
C_invitro, hill_params, max_mult, fixed
) {

interval <- c(-50,50)

# TODO value of b not consistent
# grep "tp.sim <-" ~/github/GeoToxMIE/*.R
tp <- lapply(1:nrow(C_invitro), function(x) {
truncnorm::rtruncnorm(
1,
a = 0,
b = hill_params$resp_max * tp_b_mult,
b = hill_params$resp_max * max_mult,
mean = hill_params$tp,
sd = if (fixed) 0 else hill_params$tp.sd
)
Expand Down Expand Up @@ -117,7 +112,6 @@ calc_concentration_response <- function(C_invitro,
AC50 = AC50_i)
GCA.eff[i] <- exp(mixture.result$minimum)

# TODO replace with positive control value if given
Emax_resp <- stats::optimize(obj_GCA,
interval = interval,
conc = C_i * 10^14,
Expand Down Expand Up @@ -148,7 +142,6 @@ calc_concentration_response <- function(C_invitro,

}


data.frame(
"GCA.Eff" = GCA.eff, "IA.Eff" = IA.eff,
"GCA.HQ.10" = GCA.HQ.10, "IA.HQ.10" = IA.HQ.10
Expand Down
2 changes: 1 addition & 1 deletion R/calc_independent_action.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#' @details
#' The concentration is computed as:
#' \deqn{
#' IA = E_{max}
#' IA = E_{max} \times
#' \left(
#' 1 - \prod\limits_{i} \left(1 - \frac{x_i}{E_{max}}\right)
#' \right),
Expand Down
44 changes: 23 additions & 21 deletions R/calc_internal_dose.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,41 +11,43 @@
#' @param scaling scaling factor encompassing any required unit adjustments
#'
#' @details
#' TODO Additional details...
#' \deqn{D_{int} = \frac{C_{ext} \,\times\, IR \,\times\, time}{BW}}
#' Input `C_ext` must be a matrix or list of matrices. Input `IR` must be an
#' atomic vector or list of atomic vectors. The `time`, `BW` and `scaling`
#' arguments are scalars.
#'
#' The internal dose is calculated as:
#' \deqn{D_{int} = \frac{C_{ext} \times IR \times time}{BW} \times scaling}
#'
#' @return internal chemical dose in \eqn{\frac{mg}{kg}}
#' @return list of matrices containing internal chemical doses in
#' \eqn{\frac{mg}{kg}}
#'
#' @examples
#' n_chem <- 3
#' n_sample <- 5
#'
#' # Single population
#' C_ext <- matrix(runif(n_sample * n_chem), ncol = n_chem)
#' IR <- runif(n_sample)
#' C_ext <- matrix(1:15, ncol = 3)
#' IR <- 1:5
#' calc_internal_dose(C_ext, IR)
#'
#' # Multiple populations
#' C_ext <- list(
#' "a" = matrix(runif(n_sample * n_chem), ncol = n_chem),
#' "b" = matrix(runif(n_sample * n_chem), ncol = n_chem)
#' "a" = matrix(1:15 / 10, ncol = 3),
#' "b" = matrix(1:8, ncol = 2)
#' )
#' IR <- list(runif(n_sample), runif(n_sample))
#' IR <- list(1:5, 1:4 / 2)
#' calc_internal_dose(C_ext, IR)
#'
#' @export
calc_internal_dose <- function(C_ext, IR, time = 1, BW = 1, scaling = 1) {
# TODO How to handle inputs with different units?
# e.g. simulated inhalation rate is in m^3/(day * kg), so BW isn't needed
# TODO paper states t = 365 in section 2.3, also states that C_ss achieved
# in 1 day and repeated exposure accumulates additively. Computation done
# with t = 1, is that correct?

C_ext <- .check_types(C_ext,
"matrix",
"`C_ext` must be a matrix or a list of matrices.")

IR <- .check_types(IR,
c("numeric", "integer"),
paste("`IR` must be a numeric atomic vector or a list of",
"atomic vectors."))

if ("matrix" %in% class(C_ext)) {
.calc_internal_dose(C_ext, IR, time, BW, scaling)
} else {
mapply(.calc_internal_dose, C_ext, IR, time, BW, scaling, SIMPLIFY = FALSE)
}
mapply(.calc_internal_dose, C_ext, IR, time, BW, scaling, SIMPLIFY = FALSE)
}

.calc_internal_dose <- function(C_ext, IR, time, BW, scaling) {
Expand Down
48 changes: 34 additions & 14 deletions R/calc_invitro_concentration.R
Original file line number Diff line number Diff line change
@@ -1,34 +1,54 @@
#' Calculate \emph{in vitro} concentration
#'
#' @description
#' TODO A short description...
#' Estimate the \emph{in vitro} equivalent plasma concentration given internal
#' chemical dose and steady-state plasma concentration.
#'
#' @param D_int internal chemical dose in \eqn{\frac{mg}{kg}}
#' @param C_ss steady-state plasma concentration in \eqn{\frac{\mu M}{mg / kg}}
#'
#' @details
#' TODO Additional details...
#' \deqn{C_{plasma} = C_{ss} \,\times\, D_{int}}
#' Input `D_int` must be a matrix or list of matrices. Input `C_ss` must be a
#' numeric atomic vector or matrix, or a list of those types.
#'
#' The \emph{in vitro} equivalent plasma concentration is calculated as:
#' \deqn{C_{plasma} = C_{ss} \times D_{int}}
#'
#' @return list of matrices containing concentrations in \eqn{\mu M}
#'
#' @examples
#' # Single population
#' D_int <- matrix(1:15, ncol = 3)
#' C_ss <- 1:5
#' calc_invitro_concentration(D_int, C_ss)
#'
#' # Multiple populations
#' D_int <- list(
#' "a" = matrix(1:15 / 10, ncol = 3),
#' "b" = matrix(1:8, ncol = 2)
#' )
#' C_ss <- list(1:5, 1:4 / 2)
#' calc_invitro_concentration(D_int, C_ss)
#'
#' @return \emph{in vitro} equivalent plasma concentration in \eqn{\mu M}
#' @export
calc_invitro_concentration <- function(D_int, C_ss = NULL) {

D_int <- .check_types(D_int,
"matrix",
"`D_int` must be a matrix or a list of matrices.")

if (is.null(C_ss)) {
# TODO add real-time computation of Css values
stop("real-time computation of C_ss values has not been implemented")
}

C_ss <- .check_types(C_ss,
c("matrix", "numeric", "integer"),
paste("`C_ss` must be a matrix or numeric atomic",
"vector, or a list of those types."))

# TODO the current C_ss data passed into this for step 01-Sensitivity.R
# doesn't match the ages that were simulated?

if ("matrix" %in% class(D_int)) {
.calc_invitro_concentration(D_int, C_ss)
} else {
mapply(.calc_invitro_concentration, D_int, C_ss, SIMPLIFY = FALSE)
}
mapply(.calc_invitro_concentration, D_int, C_ss, SIMPLIFY = FALSE)
}

.calc_invitro_concentration <- function(D_int, C_ss) {
as.matrix(D_int * C_ss)
D_int * C_ss
}
6 changes: 3 additions & 3 deletions R/calculate_response.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#'
#' @details
#' Additional parameters include `time`, `BW`, and `scaling` for
#' [calc_internal_dose], and `tp_b_mult` for [calc_concentration_response].
#' [calc_internal_dose], and `max_mult` for [calc_concentration_response].
#'
#' @return The same object with additional fields added or updated
#' @export
Expand All @@ -21,7 +21,7 @@ calculate_response <- function(x, ...) {
x$par$internal_dose$time <- dots$time %||% x$par$internal_dose$time
x$par$internal_dose$BW <- dots$BW %||% x$par$internal_dose$BW
x$par$internal_dose$scaling <- dots$scaling %||% x$par$internal_dose$scaling
x$par$resp$tp_b_mult <- dots$tp_b_mult %||% x$par$resp$tp_b_mult
x$par$resp$max_mult <- dots$max_mult %||% x$par$resp$max_mult

# Internal dose
if (is.null(x$IR) | is.null(x$C_ext)) {
Expand All @@ -45,7 +45,7 @@ calculate_response <- function(x, ...) {
}
x$resp <- calc_concentration_response(x$C_invitro,
x$hill_params,
tp_b_mult = x$par$resp$tp_b_mult,
max_mult = x$par$resp$max_mult,
fixed = FALSE)

x
Expand Down
23 changes: 23 additions & 0 deletions R/check_types.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#' Check types
#'
#' @param x object to check
#' @param types allowed types
#' @param msg error message
#'
#' @keywords internal
#'
#' @return list version of input
.check_types <- function(x, types, msg = "Incorrect type") {
err <- FALSE
if (inherits(x, types)) {
x <- list(x)
} else if (inherits(x, "list")) {
if (!all(sapply(x, inherits, types))) {
err <- TRUE
}
} else {
err <- TRUE
}
if (err) stop(msg, call. = FALSE)
x
}
10 changes: 5 additions & 5 deletions R/compute_sensitivity.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
#'
#' @param x GeoTox object.
#' @param vary which parameter to vary.
#' @param tp_b_mult input for [calc_concentration_response] step.
#' @param max_mult input for [calc_concentration_response] step.
#'
#' @return output from [calc_concentration_response]
#' @export
compute_sensitivity <- function(x,
vary = c("age", "obesity", "css_params",
"fit_params", "C_ext"),
tp_b_mult = NULL) {
max_mult = NULL) {

vary <- match.arg(vary)

Expand All @@ -19,8 +19,8 @@ compute_sensitivity <- function(x,
css_params = x$css_sensitivity$params,
x$css_sensitivity$other)

if (is.null(tp_b_mult)) {
tp_b_mult <- x$par$resp$tp_b_mult
if (is.null(max_mult)) {
max_mult <- x$par$resp$max_mult
}

if (is.null(x$age)) {
Expand Down Expand Up @@ -62,7 +62,7 @@ compute_sensitivity <- function(x,
C_invitro <- calc_invitro_concentration(D_int, C_ss)
resp <- calc_concentration_response(C_invitro,
x$hill_params,
tp_b_mult = tp_b_mult,
max_mult = max_mult,
fixed = vary != "fit_params")

resp
Expand Down
Loading

0 comments on commit c2086cc

Please sign in to comment.