2. Bounded growth (Phase line, Stable equilibrium)

2.3 Reaction time (Euler's Method)

Problem

Back to the rainbowfish for another modelling cycle. Now we want to know how long it takes to breed them. Do you have to invest years to grow a good-sized population, or can it be done in a few weeks?

In section 1 the number of rainbowfish in the aquarium was modelled with a limited growth rate. At last, the solution is plausible, also after an infinitely long time.

In this section we focus on answering the following question:

How long does it take for the rainbowfish population to get into its equilibrium state?

Do you have to invest years to grow a good-sized population, or is the business up and running in a few weeks?


Mathematical model

To recapitulate, the new problem is:

How long does it take for the rainbowfish population to get into its equilibrium state?

Earlier modelling cycles have resulted in the following information:

  • P(t) is the number of rainbowfish in the aquarium, with t in days.
  • We start with 30 fish. The unbounded birth rate of the fish is b=0.7 per day.
  • The death rate is ignored: d≈0.
  • The tank can sustain a population of  750 rainbowfish.
  • Each day 20 fish are sold.

The resulting initial value problem is:

\(\dfrac{dP}{dt} = 0.7 P (1 - \dfrac{P}{750} - 20\), \(P(0) = 30\).

The differential equation has two equilibrium solutions, namely an unstable one of approximately 29.75 and a stable one of approximately 720.25. The second one is relevant for the new problem.

How long does it take to reach that equilibrium? Mathematically, the answer is: "infinitely long" ;-). The nearer P gets to the equilibrium, the lower the value of the derivative (but it stays positive), so the growth will keep slowing down, never reaching zero growth, and P will never reach its equilibrium value.

Luckily, living fish come in units, so we rephrase the question:

How long does it take for the rainbowfish population to reach the last integer before the mathematical equilibrium?

This means that we want to find time teq such that P(teq)=720.

The direction field of P and some possible solutions are shown below.

The direction field of P and some possible solutions

As you can see, many solutions are possible, each of which reaches 720 at a different time. In an exercise of § 2.1 you have estimated the value of teq by imagining one of the solution curves. As you can see, it is rather easy to guess how quickly P rises in the middle. It is much more difficult to guess how long the beginning and the end phase take.

On the following pages, you will learn a method to approximate the solutions in a computer simulation, and then you can estimate much more precisely how long everything will take.


Calculation (Euler's method)

The differential equation for the rainbowfish that we have now, could still be solved by hand. It would give you the analytical solution, which is exact. However, we are not doing that in this course, as we want to focus on the modelling, and not on analytical solution methods. We also do not want to limit our models to equations that can be solved analytically.

So, we will approximate the solutions of the differential equation with a numerical method, and we choose Euler's method. In the next video, this method is explained.

Euler's method



Calculation (with Python)

Python program for Euler's Method

In the previous section Euler's Method was introduced, and now you can approximate the solution of a differential equation. Of course calculations by hand are inefficient. The method is very suitable to implement in a computer program: much faster and probably more accurate. So in this section, you will use Python to simulate the same solutions.

The basic code for Euler's method is:

# Program      : Euler's method
# Author       : MOOC team Mathematical Modelling Basics
# Created      : April, 2017

import numpy as np
import matplotlib.pyplot as plt

print("Solution for dP/dt = 0.7*P")	# in Python 2.7: use no brackets

# Initializations

Dt = 0.1                                # timestep Delta t
P_init = 10                             # initial population 
t_init = 0                              # initial time
t_end = 5                               # stopping time
n_steps = int(round((t_end-t_init)/Dt)) # total number of timesteps

t_arr = np.zeros(n_steps + 1)           # create an array of zeros for t
P_arr = np.zeros(n_steps + 1)           # create an array of zeros for P
t_arr[0] = t_init                       # add the initial P to the array
P_arr[0] = P_init                       # add the initial t to the array

# Euler's method

for i in range (1, n_steps + 1):
    P = P_arr[i-1]
    t = t_arr[i-1]
    dPdt = 0.7*P                        # calculate the derivative 
    P_arr[i] = P + Dt*dPdt              # calculate P on the next time step
    t_arr[i] = t + Dt                   # adding the new t-value to the list

# Plot the results

fig = plt.figure()                      # create figure
plt.plot(t_arr, P_arr, linewidth = 4)   # plot population vs. time

plt.title('dP/dt = 0.7P, P(0)=10', fontsize = 25)  
plt.xlabel('t (in days)', fontsize = 20)
plt.ylabel('P(t)', fontsize = 20)

plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.grid(True)                          # show grid 
plt.axis([0, 5, 0, 200])                # define the axes
plt.show()                              # show the plot
# save the figure as .jpg
fig.savefig('Rainbowfish.jpg', dpi=fig.dpi, bbox_inches = "tight")


Run it, and see what it does!

Basic_Euler.py: header and initialisations

# Program      : Euler's Method
# Author       : MOOC team Mathematical Modelling Basics
# Created      : April, 2017

import numpy as np
import matplotlib.pyplot as plt

print("Solution for dP/dt = 0.7*P")

Dt = 0.1         # timestep Delta t  
P_init = 10      # initial population
t_init = 0       # initial time
t_end = 5        # stopping time
n_steps = int(round((t_end-t_init)/Dt)) # total number of timesteps

P_arr = np.zeros(n_steps + 1)   # create an array of zeros for P
t_arr = np.zeros(n_steps + 1)   # create an array of zeros for t
t_arr[0] = t_init               # add the initial t to the array
P_arr[0] = P_init               # add the initial P to the array

Basic_Euler.py: Iterations Euler's Method

for i in range (1, n_steps + 1):
    P = P_arr[i-1]
    t = t_arr[i-1]
    dPdt = 0.7*P              # calculate the derivative
    P_arr[i] = P + Dt*dPdt    # calculate P on the next time step
    t_arr[i] = t + Dt         # adding the new t-value to the list

Basic_Euler.py: Plotting the results

fig = plt.figure()                      # create figure
plt.plot(t_arr, P_arr, linewidth = 4)   # plot population vs. time

plt.title('dP/dt = 0.7P, P(0)=10', fontsize = 25)
plt.xlabel('t (in days)', fontsize = 20)
plt.ylabel('P(t)', fontsize = 20)

plt.xticks(fontsize = 15)
plt.yticks(fontsize = 15)
plt.grid(True)                          # show grid
plt.axis([0, 5, 0, 200])                # define the axes
plt.show()                              # show the plot
# save the figure as .jpg
fig.savefig('Rainbowfish.jpg', dpi=fig.dpi, bbox_inches = "tight")

As you have seen in the previous section, a large time step of 7 days leads to results that are not valid for the rainbowfish population. In the next video you will see what happens when the stepsize is reduced.

Euler's method