Week 5 - Harvesting and bifurcation

In this lab section, we’re going to analyze the budworm population dynamic model from Ludwig et al., 1978.


Part 1 - Stability of the budworm model

In part 1 we’re going to visualize the stability of the budworm model, by plotting the differential equation. We will plot the the differential equation with different initial, which we will see that the number and stability of equilibrium changes when parameter changes.

\[ \dfrac{dN}{dt} = rN(1 - \dfrac{N}{K}) - \dfrac{HN^2}{A^2 + N^2} \]

#### Plotting the functional form for different parameters
#### Parameter setting
r <- 0.055; K <- 10; H <- 0.1; A <- 1

#### Visualize the whole dN/dt with different H
N.vec <- seq(from = 0, to = 10, length = 500)
H.breaks <- c(0.05, 0.12, 0.20)
dat <- outer(X = N.vec, Y = H.breaks,
             function(N, H){r * N * (1 - N / K) - (H * N^2 / (A^2 + N^2))})
matplot(x = N.vec, y = dat, type = "l", 
        xlab = "N", ylab = "dN/dt", col = "blue", lwd = 2, las = 1)
abline(h = 0)
legend("bottomleft", legend = H.breaks, title = "H", col = "blue", lty=1:3, lwd = 2)


Second, we’re going to plot \(harvest\) rate against \(N\) with separate components of \(dN/dt\), which the blue line is \[ \dfrac{HN}{A^2 + N^2} \] with different \(H\), the red line is, \[ r(1 - \dfrac{N}{K}) \] and the points that blue line and red line crosses are the equilibrium points.

#### Visualize separate components of dN/dt with different H
N.vec <- seq(from = 0, to = 10, length = 500)
H.breaks <- c(0.05, 0.12, 0.20)
dat.growth <- outer(X = N.vec, Y = H.breaks,
                    function(N, H){H * N / (A^2 + N^2)}) # Note notation change
matplot(x = N.vec, y = dat.growth, type = "l", ylim = c(0, 0.10), las = 1, 
        xlab = "N", ylab = "harvest rate", col = "blue", lwd = 2)
curve(r * (1 - x/K), add = T, col = "red", lwd = 2) # Just curve since its the same line, and note variable notation change
abline(h = 0)
legend("topright", legend = H.breaks, title = "H", col = "blue", lty=1:3, lwd = 2)


Part 2 - Use rootSolve function gradient and uniroot.all, to solve stability of budworm model

#### Stability of the budworm model, as a function of its parameters
#### Using "rootSolve" function "gradient" and "uniroot.all"
#### Works best for simple models and those with known solutions
########################################################################################################################
library(rootSolve)
#### Parameter setting
r <- 0.055; K <- 10; H <- 0.1; A <- 1

#### Spruce budworm model for rootSolve
Budworm <- function(N, H = 0.1){
  r * N * (1 - N / K) - (H * N^2 / (A^2 + N^2))
}

#### Function of root stability
Stability <- function(H.value = 0.1){
  equilibrium <- uniroot.all(f = Budworm, interval = c(0, K), H = H.value) # finds all roots
  lambda <- vector(mode = "numeric", length = length(equilibrium))
  for(i in 1:length(equilibrium)){
    lambda[i] <- sign(gradient(f = Budworm, x = equilibrium[i], H = H.value))
  }
  return(list(Equilibrium = equilibrium,
              Lambda = lambda))
}

#### Bifurcation diagram for H
H.vec <- seq(0.001, 0.3, by = 0.0001)

## Create plotting frame
plot(0, xlim = range(H.vec), ylim = c(0, 10), type = "n", las = 1,
     xlab = "H", ylab = "Equilibrium density, N*", main = "Budworm model bifurcation along H")
legend("topright", pch = 15, pt.cex = 2, c("stable", "unstable"),
       col = c("darkblue", "lightblue"))

## Calculate number of roots and stability across range of H
for(H in H.vec){
  temp <- Stability(H.value = H)
  points(x = rep(H, length(temp$Equilibrium)),
         y = temp$Equilibrium,
         pch = 15, col = ifelse(temp$Lambda == -1, "darkblue", "lightblue"))
}


Take a look a this website if you’re interested in more details of bifurcation.

Extra materials
Using deSolve function ode to brute-force stable solution

Here we’re going to use deSolve to solve the budworm model,

#### Budworm model for deSolve
BudwormODE <- function(times, state, parms) {
  with(as.list(c(state, parms)), {
    dN_dt = r * N * (1 - N / K) - (H * N^2 / (A^2 + N^2))
    return(list(c(dN_dt)))
  })
}

### Parameters setting
times <- seq(0, 5000, by = 100)
state <- c(N = 10)

#### Bifurcation diagram for H -- the forward branch
### Set first forward simulation and saving space
H.vec.forward <- seq(0.001, 0.3, by = 0.001)
parms <- c(H = H.vec.forward[1], K = 10, r = 0.055, A = 1)
temp <- deSolve::ode(func = BudwormODE, times = times, y = state, parms = parms)
forward <- matrix(rep(unname(c(H.vec.forward[1], temp[length(times), 2])), length(H.vec.forward)), nrow = length(H.vec.forward), ncol = 2, byrow = T)

## Run across forward vector, using previous step equilibrium as new initial state
for(i in 2:length(H.vec.forward)){
  state <- c(N = forward[i-1, 2])
  parms <- c(H = H.vec.forward[i], K = 10, r = 0.055, A = 1)
  temp <- deSolve::ode(func = BudwormODE, times = times, y = state, parms = parms)
  forward[i, ] = unname(c(H.vec.forward[i], temp[length(times), 2]))
}

#### Bifurcation diagram for H -- the backward branch
## Set first backward simulation and saving space
H.vec.backward <- rev(H.vec.forward)
parms <- c(H = H.vec.backward[1], K = 10, r = 0.055, A = 1)
temp <- deSolve::ode(func = BudwormODE, times = times, y = state, parms = parms)
backward <- matrix(rep(unname(c(H.vec.backward[1], temp[length(times), 2])), length(H.vec.backward)),
                   nrow = length(H.vec.backward), ncol = 2, byrow = T)

## Run across backward vector, using previous step equilibrium as new initial state
for(i in 2:length(H.vec.backward)){
  state <- c(N = backward[i-1, 2] + 0.001) #Remember to add a small perturbation on initial
  parms <- c(H = H.vec.backward[i], K = 10, r = 0.055, A = 1)
  temp <- deSolve::ode(func = BudwormODE, times = times, y = state, parms = parms)
  backward[i, ] = unname(c(H.vec.backward[i], temp[length(times), 2]))
}

#### Plot both forward and backward branch
plot(forward[, 1], forward[, 2],
     xlim = range(H.vec.forward), ylim = c(0, 10), las = 1, pch = 1, col = "darkblue", cex = 1.6,
     xlab = "H", ylab = "Equilibrium density, N*", main = "Budworm model bifurcation along H")
points(backward[, 1], backward[, 2], pch = 16, col = "lightblue")
legend("topright", pch = c(1, 16), pt.cex = 1.5, c("forward", "backward"),
       col = c("darkblue", "lightblue"))