Grind uses the R-package deSolve for numerical integration (Soetaert, 2010) and that package requires a function returning the derivatives of a model as a list. The form of that function is \(f(t,s,p)\), where \(t\) is time, \(s\) is the state, and \(p\) are the parameters. For the Lotka-Volterra model, \(R'=rR(1-R/K)-aRN\), and \(N'=caRN-dN\), the state, \(s\), is a vector of two variables, \(R\) and \(N\), and the parameters, \(p\), form a vector of 5 values. In Grind both are defined as named vectors s <- c(R=1,N=0.01) and p <- c(r=1,K=1,a=1,c=1,d=0.5), respectively.

Here is the Lotka-Volterra model in a deSolve() format

model <- function(t, state, parms) {
  with(as.list(c(state,parms)), {
    dR <- r*R*(1 - R/K) - a*R*N
    dN <- c*a*R*N - d*N
    return(list(c(dR, dN)))  
  }) 
}
s <- c(R=1,N=0.01)
p <- c(r=1,K=1,a=1,c=1,d=0.5)
model(0,s,p)
## [[1]]
## [1] -0.010  0.005

Thanks to the with(as.list(c(state,parms)), ) one can write the ODEs just using the names of the variables and parameters.

Without the with() one would have to write something like

model <- function(t, s, p) {
  R <- s["R"]
  N <- s["N"]
  dR <- p["r"]*R*(1 - R/p["K"]) - p["a"]*R*N
  dN <- p["c"]*p["a"]*R*N - p["d"]*N
  return(list(c(dR, dN)))
}
model(0,s,p)
## [[1]]
##      r      c 
## -0.010  0.005

which returns the same derivatives, but the notation of the model is much more cumbersome.

With()

The R-function with() is used to evaluate expressions within some environment like a list (or a data.frame). For instance

with(as.list(p),r+K)
## [1] 2

prints the sum of \(r\) and \(K\) from the vector p. And

with(as.list(c(s,p)),r*R)
## [1] 1

prints the value of \(rR\).

References

Soetaert, K., Petzoldt, T., and Setzer, R. W., 2010. Solving differential equations in R: Package deSolve. Journal of Statistical Software 33:1-25.