diff options
Diffstat (limited to 'CakeModel.R')
-rw-r--r-- | CakeModel.R | 287 |
1 files changed, 101 insertions, 186 deletions
diff --git a/CakeModel.R b/CakeModel.R index ce6bc01..3a32779 100644 --- a/CakeModel.R +++ b/CakeModel.R @@ -1,15 +1,13 @@ # Was Id: mkinmod.R 71 2010-09-12 01:13:36Z jranke -# $Id$ -# The CAKE R modules are based on mkin +# Some of the CAKE R modules are based on mkin # Portions Johannes Ranke, 2010 # Contact: mkin-devel@lists.berlios.de -# This version has been modified to parameterise SFO as k and flow fractions -# Modifications developed by Tessella Plc for Syngenta: Copyright (C) 2011 Syngenta -# Tessella Project Reference: 6245 +# Modifications developed by Tessella for Syngenta: Copyright (C) 2011-2016 Syngenta +# Tessella Project Reference: 6245, 7247, 8361, 7414 -# This program is free software: you can redistribute it and/or modify +# The CAKE R modules are free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. @@ -20,98 +18,80 @@ # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>.” +# along with this program. If not, see <http://www.gnu.org/licenses/>. CakeModel <- function(..., use_of_ff = "max") { spec <- list(...) obs_vars <- names(spec) - if (!use_of_ff %in% c("min", "max")) - stop("The use of formation fractions 'use_of_ff' can only be 'min' or 'max'") + if (!use_of_ff %in% c("min", "max")) stop("The use of formation fractions 'use_of_ff' can only be 'min' or 'max'") + # differential equations, parameter names and a mapping from model variables # to observed variables. If possible, a matrix representation of the # differential equations is included parms <- vector() diffs <- vector() map <- list() - if(spec[[1]]$type %in% c("FOMC", "DFOP", "HS")) { - mat = FALSE - if(!is.null(spec[[1]]$to)) { - message <- paste("Only constant formation fractions over time are implemented.", - "Depending on the reason for the time dependence of degradation, this may be unrealistic", - sep="\n") - warning(message) - } else message <- "ok" - } else mat = TRUE - - mat = FALSE # XYZZY Not implemented yet assuming it should be nlt = list() # Establish list of differential equations for (varname in obs_vars) { - if(is.null(spec[[varname]]$type)) stop( - "Every argument to mkinmod must be a list containing a type component") - if(!spec[[varname]]$type %in% c("SFO", "FOMC", "DFOP", "HS", "SFORB")) stop( - "Available types are SFO, FOMC, DFOP, HS and SFORB only") + if(is.null(spec[[varname]]$type)) stop("Every argument to CakeModel must be a list containing a type component") + if(!spec[[varname]]$type %in% c("SFO", "FOMC", "DFOP", "HS", "IORE")) stop("Available types are SFO, FOMC, DFOP, HS and IORE only") + new_parms <- vector() # New (sub)compartments (boxes) needed for the model type - new_boxes <- switch(spec[[varname]]$type, - SFO = varname, - FOMC = varname, - DFOP = varname, - HS = varname, - SFORB = paste(varname, c("free", "bound"), sep="_") - ) + if (spec[[varname]]$type == "DFOP" && varname != "Parent"){ + # If this is a DFOP metabolite, we need to form a system of two differential equations + # (see FOCUS page 137) + new_boxes <- paste(varname, c("1", "2"), sep="_") + } else{ + new_boxes <- varname + } + map[[varname]] <- new_boxes names(map[[varname]]) <- rep(spec[[varname]]$type, length(new_boxes)) # Start a new differential equation for each new box new_diffs <- paste("d_", new_boxes, " =", sep="") - # Get the name of the box(es) we are working on for the decline term(s) - box_1 = map[[varname]][[1]] # This is the only box unless type is SFORB - # Turn on sink if not specified otherwise if(is.null(spec[[varname]]$sink)) spec[[varname]]$sink <- TRUE - #@@@ADD SFO k HERE !!!!!!!!!!!!! # Construct and add SFO term and add SFO parameters if needed if(spec[[varname]]$type == "SFO") { if (use_of_ff == "min") { # Minimum use of formation fractions if(spec[[varname]]$sink) { - # From p. 53 of the FOCUS kinetics report - k_term <- paste("k", new_boxes[[1]], "sink", sep="_") - nonlinear_term <- paste(k_term, new_boxes[[1]], sep=" * ") - spec[[varname]]$nlt<-nonlinear_term - new_diffs[[1]] <- paste(new_diffs[[1]], "-", nonlinear_term) - new_parms <- k_term - ff <- vector() - decline_term <- paste(nonlinear_term, "*", new_boxes[[1]]) - } else { # otherwise no decline term needed here - decline_term = "0" - } - } else { - k_term <- paste("k", new_boxes[[1]], sep="_") - nonlinear_term <- paste(k_term, new_boxes[[1]], sep=" * ") - spec[[varname]]$nlt<-nonlinear_term - new_diffs[[1]] <- paste(new_diffs[[1]], "-", nonlinear_term) - new_parms <- k_term - ff <- vector() - decline_term <- paste(nonlinear_term, "*", new_boxes[[1]]) - } - } + # From p. 53 of the FOCUS kinetics report + k_term <- paste("k", new_boxes[[1]], "sink", sep="_") + nonlinear_term <- paste(k_term, new_boxes[[1]], sep=" * ") + spec[[varname]]$nlt<-nonlinear_term + new_diffs[[1]] <- paste(new_diffs[[1]], "-", nonlinear_term) + new_parms <- k_term + ff <- vector() + decline_term <- paste(nonlinear_term, "*", new_boxes[[1]]) + } else { # otherwise no decline term needed here + decline_term = "0" + } + } else { + k_term <- paste("k", new_boxes[[1]], sep="_") + nonlinear_term <- paste(k_term, new_boxes[[1]], sep=" * ") + spec[[varname]]$nlt<-nonlinear_term + new_diffs[[1]] <- paste(new_diffs[[1]], "-", nonlinear_term) + new_parms <- k_term + ff <- vector() + decline_term <- paste(nonlinear_term, "*", new_boxes[[1]]) + } + } # Construct and add FOMC term and add FOMC parameters if needed if(spec[[varname]]$type == "FOMC") { if(match(varname, obs_vars) != 1) { stop("Type FOMC is only possible for the first compartment, which is assumed to be the source compartment") } -# if(spec[[varname]]$sink == FALSE) { -# stop("Turning off the sink for the FOMC model is not implemented") -# } # From p. 53 of the FOCUS kinetics report nonlinear_term <- paste("(alpha/beta) * ((time/beta) + 1)^-1 *", new_boxes[[1]]) spec[[varname]]$nlt<-nonlinear_term @@ -122,18 +102,31 @@ CakeModel <- function(..., use_of_ff = "max") # Construct and add DFOP term and add DFOP parameters if needed if(spec[[varname]]$type == "DFOP") { - if(match(varname, obs_vars) != 1) { - stop("Type DFOP is only possible for the first compartment, which is assumed to be the source compartment") - } -# if(spec[[varname]]$sink == FALSE) { -# stop("Turning off the sink for the DFOP model is not implemented") -# } - # From p. 57 of the FOCUS kinetics report - nonlinear_term <- paste("((k1 * g * exp(-k1 * time) + k2 * (1 - g) * exp(-k2 * time)) / (g * exp(-k1 * time) + (1 - g) * exp(-k2 * time))) *", new_boxes[[1]]) - spec[[varname]]$nlt<-nonlinear_term - new_diffs[[1]] <- paste(new_diffs[[1]], "-", nonlinear_term) - new_parms <- c("k1", "k2", "g") + k1_term = paste("k1", varname, sep="_") + k2_term = paste("k2", varname, sep="_") + g_term = paste("g", varname, sep="_") + + new_parms <- c(k1_term, k2_term, g_term) ff <- vector() + + if (varname == "Parent"){ + # From p. 57 of the FOCUS kinetics report + # Looks like this: paste("((k1 * g * exp(-k1 * time) + k2 * (1 - g) * exp(-k2 * time)) / (g * exp(-k1 * time) + (1 - g) * exp(-k2 * time))) *", new_boxes[[1]]) + nonlinear_term <- paste("((", k1_term, " * ", g_term, " * exp(-", k1_term, " * time) + ", k2_term, " * (1 - ", g_term, ") * exp(-", k2_term, " * time)) / (", g_term, " * exp(-", k1_term, " * time) + (1 - ", g_term, ") * exp(-", k2_term, " * time))) *", new_boxes[[1]]) + + spec[[varname]]$nlt<-nonlinear_term + new_diffs[[1]] <- paste(new_diffs[[1]], "-", nonlinear_term) + } else { + # From p. 137 of the FOCUS kinetics report - two sub-compartments with g applied to initial conditions (in ODE pre-processing) and in formation terms. + first_nonlinear_term <- paste(k1_term, new_boxes[[1]], sep=" * ") + second_nonlinear_term <- paste(k2_term, new_boxes[[2]], sep=" * ") + + overall_term_for_formation <- paste("(", g_term, " * ", first_nonlinear_term, " + (1 - ", g_term, ") *", second_nonlinear_term, ")") + spec[[varname]]$nlt <- overall_term_for_formation + + new_diffs[[1]] <- paste(new_diffs[[1]], "-", first_nonlinear_term) + new_diffs[[2]] <- paste(new_diffs[[2]], "-", second_nonlinear_term) + } } # Construct and add HS term and add HS parameters if needed @@ -141,82 +134,52 @@ CakeModel <- function(..., use_of_ff = "max") if(match(varname, obs_vars) != 1) { stop("Type HS is only possible for the first compartment, which is assumed to be the source compartment") } -# if(spec[[varname]]$sink == FALSE) { -# stop("Turning off the sink for the HS model is not implemented") -# } - # From p. 55 of the FOCUS kinetics report -# nonlinear_term <- paste("ifelse(time <= tb, k1, k2)", "*", new_boxes[[1]]) - nonlinear_term <- paste("((k1 - k2) / ( 1 + exp( 10*(time - tb) ) ) + k2)", "*", new_boxes[[1]]) + # From p. 55 of the FOCUS kinetics report: nonlinear_term <- paste("ifelse(time <= tb, k1, k2)", "*", new_boxes[[1]]) + # Replaced this with the smoothed version on the next line to ease convergence. + nonlinear_term <- paste("((k1 - k2) / ( 1 + exp( 300*(time - tb)/(tb + 0.00001) ) ) + k2)", "*", new_boxes[[1]]) spec[[varname]]$nlt<-nonlinear_term new_diffs[[1]] <- paste(new_diffs[[1]], "-", nonlinear_term) new_parms <- c("k1", "k2", "tb") ff <- vector() } - # Construct terms for transfer to sink and add if appropriate - - #@@@@ REMOVE THIS ????? - if(spec[[varname]]$sink) { - # Add first-order sink term to first (or only) box for SFO and SFORB -# if(spec[[varname]]$type %in% c("SFO", "SFORB")) { - if(spec[[varname]]$type == "SFORB") { - k_compound_sink <- paste("k", new_boxes[[1]], "sink", sep="_") - sink_term <- paste("-", k_compound_sink, "*", new_boxes[[1]]) - new_diffs[[1]] <- paste(new_diffs[[1]], sink_term) - new_parms <- k_compound_sink - } + # Construct and add IORE term and add IORE parameters if needed + if(spec[[varname]]$type == "IORE") { + k_term <- paste("k", new_boxes[[1]], sep="_") + nonlinear_term <- paste(k_term, new_boxes[[1]], sep=" * ") + nonlinear_term <- paste(nonlinear_term, "^N") + spec[[varname]]$nlt<-nonlinear_term + new_diffs[[1]] <- paste(new_diffs[[1]], "-", nonlinear_term) + new_parms <- c(k_term, "N") + ff <- vector() } - - # Add reversible binding if appropriate - if(spec[[varname]]$type == "SFORB") { - k_free_bound <- paste("k", varname, "free", "bound", sep="_") - k_bound_free <- paste("k", varname, "bound", "free", sep="_") - reversible_binding_terms <- c( - paste("-", k_free_bound, "*", new_boxes[[1]], "+", k_bound_free, "*", new_boxes[[2]]), - paste("+", k_free_bound, "*", new_boxes[[1]], "-", k_bound_free, "*", new_boxes[[2]])) - new_diffs <- paste(new_diffs, reversible_binding_terms) - new_parms <- c(new_parms, k_free_bound, k_bound_free) - } # Add observed variable to model parms <- c(parms, new_parms) names(new_diffs) <- new_boxes diffs <- c(diffs, new_diffs) } + # Transfer between compartments for (varname in obs_vars) { to <- spec[[varname]]$to + if(!is.null(to)) { - origin_box <- switch(spec[[varname]]$type, - SFO = varname, - FOMC = varname, - DFOP = varname, - HS = varname, - SFORB = paste(varname, "free", sep="_")) fraction_left <- NULL + for (target in to) { - target_box <- switch(spec[[target]]$type, + target_boxes <- switch(spec[[target]]$type, SFO = target, - SFORB = paste(target, "free", sep="_")) - # SFO is no longer special - #if(spec[[varname]]$type %in% c("SFO", "SFORB")) { - if(spec[[varname]]$type == "SFORB") { - k_from_to <- paste("k", origin_box, target_box, sep="_") - diffs[[origin_box]] <- paste(diffs[[origin_box]], "-", - k_from_to, "*", origin_box) - diffs[[target_box]] <- paste(diffs[[target_box]], "+", - k_from_to, "*", origin_box) - parms <- c(parms, k_from_to) - } - # Handle SFO like the others -# if(spec[[varname]]$type %in% c("FOMC", "DFOP", "HS")) { - if(spec[[varname]]$type %in% c("FOMC", "DFOP", "HS", "SFO")) { + DFOP = paste(target, c("1", "2"), sep="_")) + + if(spec[[varname]]$type %in% c("FOMC", "DFOP", "HS", "SFO", "IORE")) { if ( length(to)==1 && !spec[[varname]]$sink ) { # There is only one output, so no need for any flow fractions. Just add the whole flow from the parent - diffs[[target_box]] <- paste(diffs[[target_box]], "+", spec[[varname]]$nlt) + formation_term <- spec[[varname]]$nlt } else { fraction_to_target = paste("f", varname, "to", target, sep="_") fraction_not_to_target = paste("(1 - ", fraction_to_target, ")", sep="") + if(is.null(fraction_left)) { fraction_really_to_target = fraction_to_target fraction_left = fraction_not_to_target @@ -225,86 +188,38 @@ CakeModel <- function(..., use_of_ff = "max") if ( target==tail(to,1) && !spec[[varname]]$sink ) { fraction_really_to_target = fraction_left } else { -# (1-fa)fb version -# fraction_really_to_target = paste(fraction_left, " * ", fraction_to_target, sep="") -# fraction_left = paste(fraction_left, " * ", fraction_not_to_target, sep="") -# fb version fraction_really_to_target = fraction_to_target fraction_left = paste(fraction_left, " - ", fraction_to_target, sep="") } } - ff[target_box] = fraction_really_to_target - diffs[[target_box]] <- paste(diffs[[target_box]], "+", ff[target_box], "*", spec[[varname]]$nlt) + + ff[target] = fraction_really_to_target + formation_term <- paste(ff[target], "*", spec[[varname]]$nlt) + # Add the flow fraction parameter (if it exists) if ( target!=tail(to,1) || spec[[varname]]$sink ) { parms <- c(parms, fraction_to_target) } } + + if (spec[[target]]$type == "DFOP") { + g_term <- paste("g", target, sep="_") + + first_formation_term <- paste(g_term, "*", formation_term) + second_formation_term <- paste("(1 -", g_term, ") *", formation_term) + + diffs[[target_boxes[[1]]]] <- paste(diffs[[target_boxes[[1]]]], "+", first_formation_term) + diffs[[target_boxes[[2]]]] <- paste(diffs[[target_boxes[[2]]]], "+", second_formation_term) + } else{ + diffs[[target_boxes[[1]]]] <- paste(diffs[[target_boxes[[1]]]], "+", formation_term) + } } } } } + model <- list(diffs = diffs, parms = parms, map = map, use_of_ff = use_of_ff) - # Create coefficient matrix if appropriate#{{{ - if (mat) { - boxes <- names(diffs) - n <- length(boxes) - m <- matrix(nrow=n, ncol=n, dimnames=list(boxes, boxes)) - - if (use_of_ff == "min") { # Minimum use of formation fractions - for (from in boxes) { - for (to in boxes) { - if (from == to) { # diagonal elements - k.candidate = paste("k", from, c(boxes, "sink"), sep="_") - k.candidate = sub("free.*bound", "free_bound", k.candidate) - k.candidate = sub("bound.*free", "bound_free", k.candidate) - k.effective = intersect(model$parms, k.candidate) - m[from,to] = ifelse(length(k.effective) > 0, - paste("-", k.effective, collapse = " "), "0") - - } else { # off-diagonal elements - k.candidate = paste("k", from, to, sep="_") - if (sub("_free$", "", from) == sub("_bound$", "", to)) { - k.candidate = paste("k", sub("_free$", "_free_bound", from), sep="_") - } - if (sub("_bound$", "", from) == sub("_free$", "", to)) { - k.candidate = paste("k", sub("_bound$", "_bound_free", from), sep="_") - } - k.effective = intersect(model$parms, k.candidate) - m[to, from] = ifelse(length(k.effective) > 0, - k.effective, "0") - } - } - } - } else { # Use formation fractions where possible - for (from in boxes) { - for (to in boxes) { - if (from == to) { # diagonal elements - k.candidate = paste("k", from, sep="_") - m[from,to] = ifelse(k.candidate %in% model$parms, - paste("-", k.candidate), "0") - if(grepl("_free", from)) { # add transfer to bound compartment for SFORB - m[from,to] = paste(m[from,to], "-", paste("k", from, "bound", sep="_")) - } - if(grepl("_bound", from)) { # add backtransfer to free compartment for SFORB - m[from,to] = paste("- k", from, "free", sep="_") - } - m[from,to] = m[from,to] - } else { # off-diagonal elements - f.candidate = paste("f", from, "to", to, sep="_") - k.candidate = paste("k", from, to, sep="_") - # SFORB with maximum use of formation fractions not implemented, see above - m[to, from] = ifelse(f.candidate %in% model$parms, - paste(f.candidate, " * k_", from, sep=""), - ifelse(k.candidate %in% model$parms, k.candidate, "0")) - } - } - } - } - model$coefmat <- m - } - if (exists("ff")) model$ff = ff class(model) <- "mkinmod" invisible(model) |