summaryrefslogblamecommitdiff
path: root/CakePlot.R
blob: 63dc76a19ab8b18c67af7ee32a1d74d98caf4971 (plain) (tree)
1
2
3
4
5
6


                                                  

                                                                             
                                                           















                                                                                
                       





                                                              
    

                                          

                                        



                                                                                 












                                                             
                                                   


                                                                





                                                                             

             



                                                                 
                                                                  
                                                           

             

                                                                              
            




                                                                                             
                









                                                                                              
             


                                                           











                                   

                                                         
 









                                                    
 










                                                                            
 







































                                                                                                                               
   











                                                                                  
   















                                                                                

   










                                                                         


                                                      

                                                                                                                    

     
                                                                                                 

   
                                
 
#$Id$
# Generates fitted curves so the GUI can plot them
# Based on code in IRLSkinfit
# Modifications developed by Hybrid Intelligence (formerly Tessella), part of
# Capgemini Engineering, for Syngenta, Copyright (C) 2011-2022 Syngenta
# Tessella Project Reference: 6245, 7247, 8361, 7414, 10091
#
#    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.
# 
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    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/>.

CakeDoPlot <- function(fit, xlim = range(fit$data$time), ...)
{
    original_fit <- fit
    t.map.names <- names(fit$map)
    metabolites <- grep("[A-Z]\\d", t.map.names, value = TRUE)
    t.map.rest  <- setdiff(t.map.names, metabolites)
    
    # Generate the normal graphs.
    final <- CakeSinglePlot(fit, xlim)
    
    if (length(metabolites) > 0) {
        for (i in 1:length(metabolites)) {
            metabolite <- metabolites[i]
            
            fit_method = names(fit$map[[metabolite]])[1]
            if (fit_method != "SFO" && fit_method != "DFOP") {
                # Only SFO and DFOP are current compatible with the process below
                # so skip this metabolite.
                next
            }
            
            fixed <- fit$fixed$value
            names(fixed) <- rownames(fit$fixed)
            parms.all <- c(fit$par, fixed)
            ininames <- c(
                rownames(subset(fit$start, type == "state")),
                rownames(subset(fit$fixed, type == "state")))
            odeini <- parms.all[ininames]
            
            metabolite0Parameter <- metabolite
            
            if (!(metabolite %in% names(odeini))) {
                metabolite0Parameter <- paste0(metabolite, "_0")
            }
            
            # If the metabolite is DFOP, we should find a k2_ decay variable,
            # otherwise we can fall back to the SFO k_ variant
            decay_var <- paste("k2", metabolite, sep="_")
            if (!(decay_var %in% names(fit$par)) &&
                !(decay_var %in% rownames(fit$fixed))) {
                decay_var <- paste("k", metabolite, sep="_")
            }
            
            # Generate the curve for DT50=1000 and ffm as fitted.
            if (decay_var %in% names(fit$par)) {
                fit$par[decay_var] <- log(2)/1000
            } else {
                # If decay_var was fixed, need to modify it there.
                fit$fixed[decay_var,"value"] <- log(2)/1000
            }
            
            new_col_name <- paste(metabolite, "DT50_1000_FFM_FITTED", sep="_")
            final[, new_col_name] <- CakeSinglePlot(fit, xlim)[metabolite]
            
            ffm1_fit <- SetFormationFractionsToOne(fit, metabolite)
            if (!is.null(ffm1_fit)) {
                # It was possible to set the formation fractions to 1, so generate the curves
                new_col_name <- paste(metabolite, "DT50_1000_FFM_1", sep="_")
                final[, new_col_name] <- CakeSinglePlot(ffm1_fit, xlim)[metabolite]
                
                # Reset the k values back to their originals
                # Then we can generate the curve for DT50 as fitted and ffm=1
                if (decay_var %in% names(ffm1_fit$par)) {
                    ffm1_fit$par[decay_var] <- original_fit$par[decay_var]
                } else {
                    ffm1_fit$fixed[decay_var,"value"] <- original_fit$fixed[decay_var,"value"]
                }
    
                new_col_name <- paste(metabolite, "DT50_FITTED_FFM_1", sep="_")
                final[, new_col_name] <- CakeSinglePlot(ffm1_fit, xlim)[metabolite]
            }
            
            # Finally reset the fit for the next metabolite
            fit <- original_fit
        }
    }
    
    cat("<PLOT MODEL START>\n")
    
    write.table(final, quote=FALSE)
    
    cat("<PLOT MODEL END>\n")

    # View(final)
}

# Get the immediate parents of a metabolite in a topology
GetParents <- function(topology, metabolite)
{
  parents <- NULL
  
  for (topo_metab in names(topology)) {
    if (metabolite %in% topology[[topo_metab]]$to) {
      parents <- append(parents, topo_metab)
    }
  }
  
  return (parents)
}

# Get all the ancestors of a metabolite in a topology
GetAncestors <- function(topology, metabolite, ancestors = NULL)
{
  for (parent in GetParents(topology, metabolite)) {
    if (!(parent %in% ancestors)) {
      ancestors <- GetAncestors(topology, parent, append(ancestors, parent))
    }
  }
  
  return (ancestors)
}

# Set the formation leading to the metabolite to 1 from each parent
# Returns the updated fit or NULL if the metabolite can't be updated for FFM=1
SetFormationFractionsToOne <- function(fit, metabolite)
{
  parents <- GetParents(fit$topology, metabolite)

  for (parent in parents) {
    if (any(GetAncestors(fit$topology, parent) %in% parents)) {
      # Reject metabolites where any parent is also an ancestor of another parent
      return (NULL)
    }
    
    # Try to find the formation fraction in the fitted and fixed parameters
    ffm_var <- paste("f",  parent, "to", metabolite, sep="_")
    updated_fit <- SetFfmVariable(fit, ffm_var, 1)
    if (!is.null(updated_fit)) {
      # Formation fraction was found and set to 1
      fit <- updated_fit
      next
    }
    
    # The formation fraction for this metabolite is implicitly 1 minus all the others from this parent
    # We need to iterate other formation fractions from the parent and set them to zero
    for (other_metabolite in fit$topology[[parent]]$to) {
      if (other_metabolite == metabolite) {
        # Skip the metabolite itself because we know there isn't a formation fraction for it
        next
      }
      
      other_ffm_var <- paste("f", parent, "to", other_metabolite, sep="_")
      updated_fit <- SetFfmVariable(fit, other_ffm_var, 0)
      
      # The updated fit shouldn't be able to be null because otherwise the topology was invalid
      # or didn't match the parameters in the fit.  If it does, we'll throw an error.
      if (is.null(updated_fit)) {
        stop(paste("The updated fit was NULL. The formation fraction '", other_ffm_var, "' doesn't exist in the fit.", sep=""))
      }
      
      fit <- updated_fit
    }
  }
  
  return (fit)
}

# Set the value of ffm_var in the fit, looking in both fitted and fixed parameters
# Returns the updated fit or NULL if the ffm_var couldn't be found
SetFfmVariable <- function(fit, ffm_var, value)
{
  if (ffm_var %in% names(fit$par)) {
    # The ffm_var was found as a fitted parameter
    fit$par[ffm_var] <- value
    return (fit)
  }
  
  if (ffm_var %in% rownames(fit$fixed)) {
    # The ffm_var was found as a fixed parameter
    fit$fixed[ffm_var,"value"] <- value
    return (fit)
  }
  
  # ffm_var was not found in the fit
  return (NULL)
}

CakeSinglePlot <- function(fit, xlim = range(fit$data$time), scale_x = 1.0, ...)
{
  solution <- fit$solution
  if ( is.null(solution) ) {
    solution <- "deSolve"
  }
  
  atol <- fit$atol
  if ( is.null(atol) ) {
    atol <- 1.0e-5
  }

  outtimes <- seq(0, xlim[2], length.out=CAKE.plots.resolution) * scale_x

  # Solve the system
  odeResult <- CakeOdeSolve(fit, outtimes, solution, atol)
  
  odeResult_transformed <- PostProcessOdeOutput(odeResult, fit, atol)
  
  # Replace values that are incalculably small with 0.
  for (compartment.name in names(fit$map)) {
    if (length(odeResult_transformed[, compartment.name][!is.nan(odeResult_transformed[, compartment.name])]) > 0) {
        odeResult_transformed[, compartment.name][is.nan(odeResult_transformed[, compartment.name])] <- 0
    }
    
    odeResult_transformed[, compartment.name][odeResult_transformed[, compartment.name] < 0] <- 0
  }
  
  return (odeResult_transformed)
}

Contact - Imprint