NaNs produced in deSolve package

跟風遠走 提交于 2019-12-06 12:14:17

These problems can be tough to diagnose, but I've started by refactoring your function - that is, I simplified the guts and made sure that it gave sufficiently close answers (using all.equal()) to the original.

  • your first 7 gradient values use identical forms, and can be collapsed into a single vectorized call. This is more efficient, easier to read, and easier to debug.
  • to make it easier to see where the problem is occurring, I further broke the expression into a series of simpler expressions (some of which are repeated in the original call: see #1 for advantages of reducing duplication ...)
  • factored out an unnecessary tmp3^2/tmp3 (== tmp3) in the equation
  • I put an if(any(is.na(grad))) test and a browser() call into the function so we can stop when the first NA/NaN value occurs and see what's going on ...
func2 <- function(t,state,parameters, debug=TRUE){
    n <- length(state)
    v <- 1:(n-1)
    grad <- rep(NA,n)
    tmp1 <- (4*3.14*rho[v]*N0[v])
    tmp2 <- 3*state[v]/tmp1
    tmp3 <- tmp2^(1/3)
    grad[v] <- with(as.list(c(state,parameters)),{
        -D*(N0[v]*4*3.14*tmp3)*(Cs-S/V)
    })
    grad[n] <- -sum(grad[v])
    if (debug && any(is.na(grad))) browser()
    return(list(grad))
}
## test near-equality
all.equal(func1(0,state, parameters),func2(0,state, parameters)) ## TRUE

Now try running

out <- ode(y = state, times = times,func = func2, parms = parameters)

This drops us into an interactive browser environment.

First intermediate expression looks OK (large, but finite):

Browse[2]> tmp1
[1]     8724442    28341529   121926846   347177124   640918307  1295801866
[7] 11127053948

The second expression (3*state[v]/tmp1) looks OK, but note the last value is negative - this is presumably because the last (seventh) state variable has gone slightly negative.

 Browse[2]> tmp2
           X1            X2            X3            X4            X5 
 1.289771e-11  6.262837e-12  1.333549e-12  3.037421e-13  2.588684e-14 
           X6            X7 
 3.751315e-15 -4.992697e-18 

Now when we try to take the cube root things go bad: unless a value is defined as a complex type, fractional powers of negative numbers are NaN in R

Browse[2]> tmp3
          X1           X2           X3           X4           X5           X6 
2.345151e-04 1.843276e-04 1.100702e-04 6.722049e-05 2.958192e-05 1.553798e-05 
          X7 
         NaN 

This will quickly spread through and mess up the entire state.

At this point we could try track backward a bit farther and try to understand the floating-point inaccuracy that led to the negative value in the first place; however, it may or may not be easy (or even possible) to rewrite the expressions in a way that makes them sufficiently stable. This question and this question discuss ways of constraining solutions of ODEs to non-negative values ... the simplest (if it makes sense for your problem) is to put in a pmax(tmp3,0) or pmax(tmp3,very_small_positive_number) call to prevent negative values ...

Minor comments:

  • are the factors of 3.14 in your questions supposed to be pi? R has a built-in pi value ...
  • for a given set of parameters, it looks like tmp1 is constant over time. You might want to pre-compute it outside of the gradient function for efficiency ...

To see what was going on I added na.rm=TRUE to the sum as you suggested. I switched to method="euler"; this is less efficient, but simpler since it does very few intermediate calculations between gradient computations.

out <- ode(y = state, times = times,func = func2, parms = parameters,
           debug=FALSE,method="euler")
out <- out[rowSums(is.na(out))<9,]
png("SO_ode.png")
par(las=1)
matplot(out[,-1],type="l",lty=1,log="xy",col=1:8,
        xlab="time",ylab="")
dev.off()

This shows that one component after another is dropping to very small values (and becoming NaN after we try to take the cube root of a negative value ...) Depending on what you were doing, it might be safe to set gradients whose values were NaN to zero ...

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!