Introduction to population dynamics

Population dynamics
Calculus
Differential Equations

1 Population dynamics modelling

We can use calculus to study how populations change in time. In the examples below we consider an illustrative model of population dynamics in a class room. The developed concepts can be used to study population dynamics of infectious disease transmission.

1.1 Background

You might have previously encountered differentiation. Suppose that \(y\) is some function of \(x\).

Consider the differential equation

\[ \frac{dy}{dx}=1 \]

Upon integration

\[ y(x)=x+C \] where \(C\) is an integration constant.

What if \[ \frac{dy}{dx}=x \]

Can you integrate this ordinary differential equation?

2 Formulating model of population dynamics

2.1 Constant entry rate

Let’s consider a model for the number of people in a classroom at a given time. Let \(t\) represent time and \(N(t)\) represent the number of people in the room at time \(t\).

Suppose that there are initially no people in the room, but people enter at a constant rate, \(k\).

We could formulate a model of population dynamics given by

\[ \frac{dN}{dt}=k, \quad N(0)=0. \]

  • Can you integrate this ODE (hint: it is mathematically equivalent to the ODE introduced in Section 1.1)?

  • Can you use the model to determine the amount of time taken for the number of people in the room to reach capacity, \(N_C\).

  • The app in Figure 1 allows you to explore the solution of the model. Can you identify what the entry rate needs to be such that the room reaches capacity of 40 people after 20 minutes?

#| standalone: true
#| components: [viewer]
#| viewerHeight: 500

from shiny import App, Inputs, Outputs, Session, render, ui
from shiny import reactive

import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
from scipy.integrate import odeint

app_ui = ui.page_fluid(
    ui.layout_sidebar(
        ui.panel_sidebar(
    ui.input_slider(id="k",label="Entry rate (per minute)",min=0.01,max=3,value=0.1,step=0.00001),
    ui.input_slider(id="N0",label="initial pop",min=0.0,max=20.0,value=0.1,step=1.0),
    
    ui.input_slider(id="T",label="Simulation time (minutes)",min=0.0,max=60.0,value=20.0,step=0.5),
    ui.input_slider(id="max_inf",label="Max. num",min=0.0,max=100.0,value=40.0,step=1.5),             
          
            ),

        ui.panel_main(ui.output_plot("plot"),),
    ),
)

def server(input, output, session):
    
    @render.plot
    def plot():
        fig, ax = plt.subplots()
        #ax.set_ylim([-2, 2])
        # Filter fata
        
        
        k=float(input.k())
        N_0=float(input.N0())
        T=float(input.T())
        max_inf=float(input.max_inf())

        
        # Define rhs of LV ODEs
        def rhs_pop_model(x,t,k,r):
          rhs=np.zeros_like(x,dtype=float)
          N=x[0]
          dN_dt=k
          rhs[0]=dN_dt
          return rhs

        # Define discretised t domain
        t = np.linspace(0, T, 1000)

        # define initial conditions
        init_cond=[N_0]
        
        # Compute numerical solution of ODEs
        sol1 = odeint(rhs_pop_model, init_cond,t,args=(k,1))

        # Plot results
        N=sol1[:,0]
        
        
        ax.plot(t, N)
        ax.plot(t,max_inf*np.ones_like(t),'--')
        ax.legend(['N','Max. room occupancy'],loc='best')
        ax.set_xlabel('$t$ (minutes)')
        ax.set_ylim([0,max_inf*1.4])

        #plt.grid()
        #plt.show()
    
app = App(app_ui, server)
Figure 1

2.2 What if people enter the room at a constant rate but also leave the room at random?

Taking the previous model as a starting point, we now assume that people leave the room at a rate proportional to the number of people in the room

The model equation is now given by

\[ \frac{dN}{dt}=k - dN, \quad N(0)=0. \]

Can you integrate this ODE (hint: try a technique called separation of variables)?

If so, can you use the model to determine the amount of time taken for the number of people in the room to reach capacity, \(N_C\).

The app in Figure 2 allows you to explore the solution of the model. Can you identify what the entry rate needs to be such that the room reaches capacity of 40 people after 20 minutes given \(d=0.1\)?

#| standalone: true
#| components: [viewer]
#| viewerHeight: 600

from shiny import App, Inputs, Outputs, Session, render, ui
from shiny import reactive

import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
from scipy.integrate import odeint

app_ui = ui.page_fluid(
    ui.layout_sidebar(
        ui.panel_sidebar(
    ui.input_slider(id="k",label="Entry rate (per minute)",min=0.01,max=10,value=0.1,step=0.00001),
    ui.input_slider(id="d",label="exit rate (per minute)",min=0.01,max=3,value=0.1,step=0.00001),
    ui.input_slider(id="N0",label="initial pop",min=0.0,max=20.0,value=0.1,step=1.0),
    
    ui.input_slider(id="T",label="Simulation time (minutes)",min=0.0,max=60.0,value=20.0,step=0.5),
    ui.input_slider(id="max_inf",label="Max. num",min=0.0,max=100.0,value=40.0,step=1.5),             
          
            ),

        ui.panel_main(ui.output_plot("plot"),),
    ),
)

def server(input, output, session):
    
    @render.plot
    def plot():
        fig, ax = plt.subplots()
        #ax.set_ylim([-2, 2])
        # Filter fata
        
        
        k=float(input.k())
        d=float(input.d())

        N_0=float(input.N0())
        T=float(input.T())
        max_inf=float(input.max_inf())

        
        # Define rhs of LV ODEs
        def rhs_pop_model(x,t,k,d):
          rhs=np.zeros_like(x,dtype=float)
          N=x[0]
          dN_dt=k-d*N
          rhs[0]=dN_dt
          return rhs

        # Define discretised t domain
        t = np.linspace(0, T, 1000)

        # define initial conditions
        init_cond=[N_0]
        
        # Compute numerical solution of ODEs
        sol1 = odeint(rhs_pop_model, init_cond,t,args=(k,d))

        # Plot results
        N=sol1[:,0]
        
        
        ax.plot(t, N)
        ax.plot(t,max_inf*np.ones_like(t),'--')
        ax.legend(['N','Max. room occupancy'],loc='best')
        ax.set_xlabel('$t$ (minutes)')
        ax.set_ylim([0,max_inf*1.4])

        #plt.grid()
        #plt.show()
    
app = App(app_ui, server)
Figure 2
Note

At Dundee, core concepts from calculus (e.g. differential equations) are studied in the modules Maths 1A and Maths 1B and developed further in the modules Maths 2A and Maths 2B.

At Level 2 in the modules Computer algebra and dynamical systems and Introduction to Programming you would be introduced to techniques that are used to compute numerical solutions to differential equations.

At Level 3 in the module Differential Equations you would extend your knowledge of differential equations to include concepts such as Fourier Series and Partial Differential Equations. In the modules Mathematical Biology I and Mathematical Biology II you would also learn how to formulate and study mathematical models of biological systems.

You can find out more about these modules here.