Now that you have started to use R’s numerical solver, I want you to
be able to see its solutions compared to the analytic one that is found
by integration. To this end, and to give you some practice using
ode()
and plotting functions in R, please do the following
exercises.
1.1. Let’s first start with density-independent growth. Please plot 4
time series in the same plot: a numerical solution for \(r>0\), an analytically solution for
\(r>0\), a numerical solution for
\(r<0\), and an analytically
solution for \(r<0\). First, plot
the time series for density-independent growth using ode()
.
Set \(N(0) = 10\) and \(r = 0.2\). Then, use the analytic solution
to the density-independent differential equation to generate a time
series and add it to the plot using lines()
(hint: see
problem 2 from the last problem set to plot a vector of an independent
variable against a dependent one.) In lines()
, add
, col = "red", lty = 2, lwd = 5
to make the line dotted and
thick (lwd
is the argument for line
width). Next, repeat what you just did
in the previous 2 steps, but with \(r =
-0.2\). Add them to the same graph and make sure that your
vertical axis shows all of the curves completely.
1.2. Do the same thing as above, but with the logistic equation. Fist, plot the logistic equation’s numerical solution (black, solid line) and analytic solution (red, dotted line). The logistic Do this with \(N(0) = 10\), \(r = 0.2\), and \(K = 75\).
In this course we are studying general population models. You have seen various models used to represent different types of biological scenarios, like populations that change in a density-independent manner, populations that change in a density-dependent manner, populations that change in steps, populations that change continuously, etc. But once we have a model, what then? Well, then we study the model.
In Botsford et al. (the chapter that we read in week 2), they argued that understanding and prediction are the two most important things that we we get out of models. Prediction is important, but beyond the scope of this course, unless this course was years long and we would build models, evaluate their predictive power, modify the model, evaluate, etc. But to understand population ecology through models, this entails analyzing them, which can really mean anything.
So far in this course you have done some flavors of analysis. First, you’ve done graphical analysis of our models. You have taken the dynamic models and their solutions and graphed them. Time series are a form of analysis, which many of you presumably saw since many of your potential remodeling projects had time series figures. Second, you’ve taken your dynamic models and plotted them as functions of density. That is a form of analysis, as important population biology is revealed (e.g., \(r\) is the maximum per-capita growth rate, population growth rate and per-capita growth rate both intercept the horizontal axis as the same point [\(K\), \(r/\alpha\), etc.], etc.). Third, you’ve done equilibrium analysis by finding \(N\) for which the rate of change is 0; i.e., where the population is not changing. Fourth and last, you’ve taken dynamic models and their solutions, and you have varied parameter values to see how that changes the model behavior/output. In the last problem set, for instance, you took the logistic model from Stevens text and found that by modifying \(r_d\) that the population may approach a single value, that it may oscillate around a value before settling on it, that it may oscillate around the value forever, or it may change chaotically/aperiodically. Note you will be learning another type of analysis this week where we evaluate a model’s behavior around equilibria, which is what we call stability analysis. So, pat yourselves on the back for analyzing models without being explicit about it.
For this problem, I will ask you to a more extensive and more formal analysis of model parameters. This is, essentially, the most significant type of analysis that you can do to learn from most population models because mathematical analysis is often limited and not useful. An example of a mathematical analysis that is not useful might be when you find an equilibrium value for a model, but it has a dozen+ terms that are difficult to make sense of mathematically or biologically.
2.1. Let’s first pick a model to analyse: we’ll use the \(r\)-\(\alpha\) logistic equation: \[ \frac{\mathrm{d}N}{\mathrm{d}t} = N(r - \alpha
N).\] Imagine that this is your first time seeing this model and
you don’t know anything about it. If you were trying to understand the
model, an important and primary question might be: how do the
parameters, \(r\) and \(\alpha\) affect the model behavior? Well,
let’s see. First, take any 3 values of \(r\) and plot the three numerical solutions
on the same time series. Use whatever \(N_0\), \(\alpha\), and length of time you desire/is
useful for observing the model’s behavior. Second, make a plot with the
3 values of \(r\) on the horizontal
axis and the final density from the 3 numerical
solutions on the vertical axis. As suggestion for a better practice, try
not just copying and pasting the final value, but index the last value
by taking the second column of the last row. So for instance, if you
saved your numerical solution as ralpha_1
, I would index
the value like this: ralpha_1[nrow(ralpha_1), 2]
. Last,
comment in one or more sentences on the effect of \(r\) on density.
2.2. Now, do the same thing with \(\alpha\). First, take any 3 values of \(\alpha\) and plot the three numerical solutions on the same time series. Use whatever \(N_0\), \(r\), and length of time you desire/is useful for observing the model’s behavior. Second, make a plot with the 3 values of \(\alpha\) on the horizontal axis and the final density from the 3 numerical solutions on the vertical axis. Last, comment in one or more sentences on the effect of \(\alpha\) on density.
2.3. You’re going to be annoyed with me for this, for which I
apologize in advance 😬. For the 3 values of \(r\) and 3 values of \(\alpha\) above, I want you to first plot
all 9 combinations. Second, I want you to save all nine final
density values in a matrix. To do this, first, make a matrix.
I’ll do this for you: ‘ralpha_mat <- matrix(data = NA, nrow = 3, ncol
= 3)’. Now, just for the sake of helping you know where to save the
final densities, let’s label the rows and columns like
this: rownames(ralpha_mat) <- paste0("r", 1:3)
and
colnames(ralpha_mat) <- paste0("alpha", 1:3)
. Now, when
you look at ralpha_mat
, you see:
## alpha1 alpha2 alpha3
## r1 NA NA NA
## r2 NA NA NA
## r3 NA NA NA
You know how to index rows and columns, but as a reminder, if I had a
matrix called le_matrix
, I could save a value in its third
row and fourth column like le_matrix[3, 4]
. Third and last,
once you have the matrix filled, I want you to plot the final densities
of \(r\) against \(\alpha\) using a heat map. Do this by
using the function image()
that comes in R’s base graphics.
If you just throw in your matrix, you’ll notice the axes are flipped:
that’s annoying but I have no control over this. So, a necessary step
you’ll need to take is to first rotate the matrix using (called a
transposition in matrix-speak):
le_matrix1 <- t(le_matrix1)
. Then, inside of
image()
, give the following arguments:
y =
: put a vector of your \(\alpha\) values in; e.g.,
image(y = c(0.1, 1, 10))
x =
: put a vector of your \(r\) values inz =
: this is where you enter your matrixcol = heat.colors(n = 100)
: this sets the color palette
such that large values are white and small values are red; I can show
you how to make your own color palettes easily, later, if you’d
likelas =
: because we always do this for the sake of
people’s necksAfter you make your beautiful heat map, take a moment to revel and reflect. Write a sentence or few on it.
So, hopefully you’re seeing the point of what we’re trying to do with
parameter analysis. But, you might be thinking: Chris, this is
amazing, but WTH am I going to do with more than a handful a parameters?
It seems like it’d be a huge pain in the neck! And with all of your
preaching about las = 1
, you are against pains in the
neck! It is true, I am against pains in the neck. So, let’s scale
this 💩 up! (Yes, I’ve been drinking a lot of ☕: how can you tell?)
Our computers can be our friends; especially when we harness their power to do work for us! We’re going to do this below using a type of iterative iterative process called a loop. Loops are your friends: you give them a condition, like Hey loop, go fetch me the final densities of a million values of \(r\) using my numerical solver., and they just do it. They’re really good friends.
Loops come in a variety of forms, but we are essentially just going to be using what we call for loops to repeat a calculations over a set of values, like in a vector. You basically tell R to perform some set of actions and over how many times. A simple loop to, say, calculate the area of a rectangle if we have a length of 2 and 5 lengths would be:
# One length and 5 width values
length_rec <- 2
width_rec <- 2:6
# I have the number of iterations I want to do, which is the length of the width vector
n_widths <- length(width_rec)
# Create a data structure to save the area values
area_vec <- rep(x = NA, times = n_widths)
# The for loop
for (i in 1:n_widths) {
width_i <- width_rec[i]
area_i <- length_rec*width_i
area_vec[i] <- area_i
}
# Let's plot and look at what we just did
# (Note I make the axes 1:1 to better observe how a 1 unit change in width corresponds to change in area)
plot(x = width_rec, y = area_vec, las = 1, xlab = "Width", ylab = "Area", pch = 19, xlim = c(2, 12), ylim = c(2, 12))
lines(x = width_rec, y = area_vec)
Cool, huh! I’ll first say that for this very simple problem, the
simplest way to actually do this is just
length_rec*width_rec
: that will give you the same result as
the for loop. But, this example was supposed to be illustrative or what
you could potentially do. Second, study the code. Several
things should pop out:
n_widths
that tells us
how many iterations we want to run.area_vec
to
save the output from each time the loop ran.i
in the parentheses of the for loop is essentially
an object that takes on the values of the vector, in this case
1:n_widths
, at each iteration.i
taking on the values of each
iteration is that we can extract the first, second, third, etc. values
of the width vectors, width_rec[i]
, AND we can save the
areas in the first, second, third, etc. places in our empty area vector,
area_vec[i]
, to fill it up.i
in the console, it should take on the value it was last
assigned, which, in this case, is 5.3.1. Hopefully when reading the example loop above you were thinking
about how you might do this with the parameter values from question 2.
Well, that’s what I want you to do. For this problem, do the same thing
that you did in 2.1, but instead of choosing 3 arbitrary \(r\) values, create a vector of 100 values.
Start and end at some arbitrary value of \(r\) and create a sequence of 100. If I
arbitrarily started at -1 and ended at 10, I would create my sequence
as:
r_seq <- seq(from = -1, to = 10, length.out = 100)
.
3.2. Similar to the previous problem, recreate 2.2, but with \(\alpha\). Choose arbitrary values to start and stop, and analyze 100 values. Please use \(\alpha >0\), because, unlike \(r\), switching the sign of \(\alpha\) to be \(>0\) doesn’t make biological sense for the logistic model.
3.3. (Optional and recommended if you can make the time) I imagine that it took a bit of effort to complete 3.1. and 3.2. Pat yourself on the back for a job well done: you deserve it. For this final problem, as you guessed, I want you to do the same thing as 2.3. To do this, we need to do a just few things differently. First, you need to write a loop within a loop—this is what we call a nested loop. It looks like this:
for (i in 1:10) {
# Here is where i is being indexed
for (j in 1:10) {
# Here's where j is being indexed
# Here's where you put your calculations
}
}
You can see that the first difference compared with above is that
there is now a loop nested in another. Another thing that we need to do
differently is to give the nested loop variable a different value; here,
we use j
. What happens here is that i
takes
the value 1, then j
is looped over to take 1, 2, … 10.
Then, i
takes the value 2, then j
is looped
over to take 1, 2, … 10. This happens until i
takes on the
value 10, then j
is looped over to take 1, 2, … 10. The
last thing that we need to do differently is create a data structure
that can take all the combinations of i
and j
:
you probably guessed it, a matrix.
Here is an example again using nested loops to find the area of a rectangle, where I loop over length and width:
# I create a named value for the number of length and width values I want to use
n_vals <- 100
# Create vectors for the lengths and widths
length_vec <- seq(from = 0, to = 20, length.out = n_vals)
width_vec <- seq(from = 0, to = 20, length.out = n_vals)
# Create a matrix to save the values in
area_mat <- matrix(data = NA, nrow = n_vals, ncol = n_vals)
rownames(area_mat) <- paste0("l", 1:n_vals)
colnames(area_mat) <- paste0("w", 1:n_vals)
# Uncomment to check out the first 5 rows and columns and see that we want lengths in rows, widths in columns
# area_mat[1:5, 1:5]
# The loop
for (i in 1:n_vals) {
# Here is where length i is being indexed
l_i <- length_vec[i]
for (j in 1:n_vals) {
# Here's where width j is being indexed
w_j <- length_vec[j]
# Here's where you put your calculations
area <- l_i*w_j
# Here is where we save the ith row for length and jth column for width
area_mat[i, j] <- area
}
}
# Transpose the matricx and plot
area_mat1 <- t(area_mat)
image(x = width_vec, y = length_vec, z = area_mat1, las = 1, col = heat.colors(n = 100), xlab = "Width", ylab = "Length")
# Note there are different functions that allow you to plot 3D data like these, including contour() and filled.contour(). Uncomment to see what they look like:
# contour(x = width_vec, y = length_vec, z = area_mat1, las = 1, xlab = "Width", ylab = "Length")
#filled.contour(x = width_vec, y = length_vec, z = area_mat1, las = 1, xlab = "Width", ylab = "Length")
Isn’t that just sooooo coooooool 😎. So, do this with the \(r\)-\(\alpha\) logistic equation. I’m eager to see your heat maps!