Search code examples
rif-statementodedifferential-equations

avoid negative values when resolving a ODE


I am trying to model the behavior of a made-up networks of 5 genes, but I have the problem that I get negative values, which it has not sense biologically speaking.

Is there a way to limit the values to zero?

I managed to do it when I represent the graph, but I don't know how to use the ifelse in the main equation.

Thank you very much-1

###################################################
###preliminaries
###################################################

library(deSolve)
library(ggplot2)
library(reshape2)

###################################################
### Initial values
###################################################

values <- c(A = 1,
            B = 1,
            D = 1,
            E = 20,
            R = 1)

###################################################
### Set of constants
###################################################

constants <- c(a = 1.2,
               b = 0.5,
               c = 1.2,
               d = 1.5,
               e = 0.3,
               f = 0.5,
               g = 1.5,
               h = 0.9,
               i = 1.3,
               j = 1.3,
               m = 0.8,
               n = 0.6,
               q = 1,
               t = 0.0075,
               u = 0.0009,
               Pa = 100,
               Pb = 0.05,
               Pd = 0.1,
               Pe = 10)

###################################################
### differential equations
###################################################

Dynamic_Model<-function(t, values, constants) {
  with(as.list(c(values, constants)),{
    
    dA <- Pa + a*D - j*A - R
    dB <- Pb + b*A + e*E - m*B 
    dD <- Pd + d*B + f*E - g*A - n*D
    dE <- Pe - h*B + i*E - q*E
    dR <- t*A*B - u*D*E 
    
    list(c(dA, dB, dD, dE, dR))
  })   
}

###################################################
### time
###################################################

times <- seq(0, 200, by = 0.01)

###################################################
### print ## Ploting
###################################################

out <- ode(y = values, times = times, func = Dynamic_Model, parms = constants)

out2 <- ifelse(out<0, 0, out)

out.df = as.data.frame(out2) 

out.m = melt(out.df, id.vars='time') 
p <- ggplot(out.m, aes(time, value, color = variable)) + geom_point(size=0.5) + ggtitle("Dynamic Model")

Solution

  • I agree completely with @Lutz Lehmann, that the negative values are a result of the structure of the model.

    The system of equations allows that derivatives still become negative, even if the states are already below zero, i.e. the states can further decrease. We don't have information about what the states are, so the following is only a technical demonstration. Here a dimensionless Monod-type feedback function fb is implemented as a safeguard. It is normally close to one. The km value should be small enough to act only for state values close to zero, and it should not be too small to avoid numerical errors. It can be formulated individually for each state. Other function types are also possible.

    library(deSolve)
    library(ggplot2)
    library(reshape2)
    
    values <- c(A = 1,
                B = 1,
                D = 1,
                E = 20,
                R = 1)
    
    constants <- c(a = 1.2,
                   b = 0.5,
                   c = 1.2,
                   d = 1.5,
                   e = 0.3,
                   f = 0.5,
                   g = 1.5,
                   h = 0.9,
                   i = 1.3,
                   j = 1.3,
                   m = 0.8,
                   n = 0.6,
                   q = 1,
                   t = 0.0075,
                   u = 0.0009,
                   Pa = 100,
                   Pb = 0.05,
                   Pd = 0.1,
                   Pe = 10,
                   km = 0.001)
    
    Dynamic_Model<-function(t, values, constants) {
      with(as.list(c(values, constants)),{
        
        fb <- function(x) x / (x+km) # feedback
        
        dA <- (Pa + a*D - j*A - R)         * fb(A)
        dB <- (Pb + b*A + e*E - m*B)       * fb(B)
        dD <- (Pd + d*B + f*E - g*A - n*D) * fb(D)
        dE <- (Pe - h*B + i*E - q*E)       * fb(E)
        dR <- (t*A*B - u*D*E)              * fb(R)
        
        list(c(dA, dB, dD, dE, dR))
      })   
    }
    
    times <- seq(0, 200, by = 0.1)
    
    out <- ode(y = values, times = times, func = Dynamic_Model, parms = constants)
    plot(out)
    

    Additional hints:

    • Removal of negative values afterwards (out2 <- ifelse(out<0, 0, out)) is just wrong.
    • Removal of negative values in the model function, i.e.

    use the ifelse in the main

    would also be wrong as it can lead to a severe violation of mass balance.

    • the time steps don't need to be very small. They are automatically adapted anyway by the solver. Too small time steps make your model slow and you get more outputs as needed.
    • some of your parameters are quite large, so that the model becomes very stiff.