Skip to content

CASES I: Population Models

CASE: Single-Species Population Growth


Simple Difference Equation (Unbounded):

Nt+1 = Nt ( 1 + r )


Simple Difference Equation (Unbounded, over time period):

Nt = N0 ( 1 + r )t


Differential Model (Differential Change):


Differential Model (Change over time period):

Nt = N0ert

Simplest Population Models

Most organisms reproduce themselves as discrete units and population growth is an integer process. In addition to this, births and deaths are not perfectly continuous or doesn't proceed as smoothly as indicated by 'r'; but instead occur sequentially.

Adding these two together makes a random process of births and deaths. The following code aims to model this process:

doubling_time_1 = round(np.log(2) / 0.05, 2)
doubling_time_1

#doubling_time_2 = np.log10(2) / np.log10(1.05)
#doubling_time_2
# Demographic Stochasticity

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Set ecological parameters (measurement based from long-term study)
b = 0.55
d = 0.50
r = b - d
doubling_time = round(np.log(2) / r, 2)

# Define stochastic parameters
P_birth = b / (b + d)
P_death = d / (b + d)

# Euler method of tracking population movement
def pop_growth_w_demog_stochasticity(P_birth, P_death, N0, pop_seq = 50, n_pop = 4):

    #create dataframe to store results
    df = pd.DataFrame()

    for pop in range(n_pop):
        N_list = [N0, ]
        
        for instance in range(pop_seq):
            delta = np.random.choice([1, -1], size=1, p=[P_birth, P_death])[0]
            Nt = N_list[-1] + delta
            N_list.append(Nt)

        column_name = f"Population {pop}"
        df[column_name] = N_list

    return df

# Create data
data = pop_growth_w_demog_stochasticity(P_birth, P_death, 10)
print(data)

# Print results
        
# Reshape for seaborn plotting
long_data = data.reset_index().melt(id_vars='index', var_name='Population', value_name='Size')
long_data.rename(columns={'index': 'Timestep'}, inplace=True)

# Plot with seaborn
plt.figure(figsize=(10, 6))
sns.lineplot(data=long_data, x='Timestep', y='Size', hue='Population')
plt.title('Demographic Stochasticity in Population Growth')
plt.xlabel('Cumulative Sum of Birth-Death Sequence')
plt.ylabel('Population Size')
plt.legend(title='Population')
plt.show()

Density-Dependent Population Growth (1 species)

Basic Model

Logistic Growth Model

  • dampening of growth rate, based on state wrt carrying capacity, K

Discrete


Continuous


Scaled Logistic Growth (Discrete)

# Preliminaries
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.integrate import solve_ivp

# Define logistic growth equation
def logistic_n(t, N0, r, K):
    dN_dt = r * N0 * (1 - N0 / K)
    return dN_dt

# Set initial conditions
N0 = [200]

# Set parameter values
params = {'r': 0.10,
         'K': 100}
t_span = (0, 100)
t_eval = np.arange(0, 100, 0.1)

# Run differential equation solver
Nt = solve_ivp(logistic_n, t_span, N0, args=tuple(params.values()), t_eval=t_eval)

#print(Nt)

# Plot the time series
sns.set()
plt.plot(Nt.t, Nt.y[0], color='blue')
plt.xlabel('Time (t)')
plt.ylabel('Population Size (N)')
plt.axhline(100, color="red", linestyle="--", label="Carrying Capacity")
plt.legend()
plt.show()
# Scaled Logistic Growth (Discrete)

# Preliminaries
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.integrate import solve_ivp

# Define scaled logistic growth equation
def logistic_n_scaled(t, X0, a):
    X1 = a * X0 * (1 - X0)
    return X1

# Set initial conditions and ecological parameters
N0 = 5
r = 0.10
K = 100

# Scaled initial conditions and ecological parameters
a = 1 + r
b = r / K
X0 = N0 * (b/a)

# Set integral parameters
params = {'a': a }
t_span = (0, 100)
t_eval = np.arange(0, 100, 0.1)

# Run differential equation solver
Xt = solve_ivp(logistic_n_scaled, t_span, [X0], args=tuple(params.values()), t_eval=t_eval)

#print(Xt)

# Plot the time series
sns.set()
plt.plot(Xt.t, Xt.y[0], color='blue')
plt.xlabel('Time (t)')
plt.ylabel('Scaled Population Variable (Xt)')
plt.title("Scaled Population Growth, with respect to K")
plt.legend()
plt.show()

Logistic Growth with Time Lag

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.integrate import odeint

# Define logistic growth with time delay
def logistic_delay(N, t, r, K, tau, N_tau):
    dN_dt = r * N * (1 - N_tau / K)
    return dN_dt

# Define history function (for t < 0)
def N_history(t):
    return 500  # Initial condition before t=0

# Solve the DDE using Euler's method for approximation
def solve_logistic_delay(r, K, tau, N0, t_max, dt):
    t_values = np.arange(0, t_max, dt)
    N_values = np.zeros_like(t_values)
    
    # Set initial condition
    N_values[0] = N0

    # Numerical approximation (Euler-like method)
    for i in range(1, len(t_values)):
        t = t_values[i]
        t_lag = t - tau

        # Approximate the delayed value by looking at previous steps
        if t_lag < 0:
            N_tau = N_history(t_lag)
        else:
            N_tau = N_values[int((t_lag) / dt)]  # Nearest previous point

        # Compute the next value using logistic equation with delay
        dN_dt = logistic_delay(N_values[i - 1], t, r, K, tau, N_tau)
        N_values[i] = N_values[i - 1] + dN_dt * dt

    return t_values, N_values

# Define parameters
r = 1.2
K = 10000
tau = 1
N0 = 1000
t_max = 24
dt = 0.1

# Solve the DDE
t, N = solve_logistic_delay(r, K, tau, N0, t_max, dt)

# Plot results
sns.set()
plt.plot(t, N, label=f'Logistic Growth with Time Lag (τ={tau})', color='blue')
plt.axhline(K, label="Carrying Capacity (K)", linestyle="--", color="red")
plt.xticks(np.arange(0, t_max+1, 2))
plt.xlabel('Time (t)')
plt.ylabel('Population Size (N)')
plt.legend(loc="upper right")
plt.title("Delayed Logistic Growth")
plt.show()

Logistic growth with time lag is characterized by two factors: (1) time lag, tau; and (2) "response time"

Logistic Growth with no time delay-like

0 < r < 0.368

Damped Delayed Logistic Growth

0.368 < r < 0.1.570

Delayed Logistic Growth with Stable Limit Cycle

r > 0.1.570