Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ok-landscape
GitHub Repository: Ok-landscape/computational-pipeline
Path: blob/main/latex-templates/templates/biology/logistic_growth.tex
51 views
unlisted
1
% Logistic Growth Model Template
2
% Topics: Carrying capacity, Allee effect, competition, harvesting
3
% Style: Research article with ecological applications
4
5
\documentclass[a4paper, 11pt]{article}
6
\usepackage[utf8]{inputenc}
7
\usepackage[T1]{fontenc}
8
\usepackage{amsmath, amssymb}
9
\usepackage{graphicx}
10
\usepackage{siunitx}
11
\usepackage{booktabs}
12
\usepackage{subcaption}
13
\usepackage[makestderr]{pythontex}
14
15
% Theorem environments
16
\newtheorem{definition}{Definition}[section]
17
\newtheorem{theorem}{Theorem}[section]
18
\newtheorem{example}{Example}[section]
19
\newtheorem{remark}{Remark}[section]
20
21
\title{Logistic Growth Models: Density Dependence and Population Regulation}
22
\author{Quantitative Ecology Research}
23
\date{\today}
24
25
\begin{document}
26
\maketitle
27
28
\begin{abstract}
29
This study presents a comprehensive analysis of logistic population growth models and
30
their extensions. We examine the classic logistic equation, the Allee effect (positive
31
density dependence at low populations), interspecific competition, and sustainable
32
harvesting strategies. Computational analysis demonstrates population dynamics under
33
various parameter regimes and identifies optimal management strategies for harvested
34
populations.
35
\end{abstract}
36
37
\section{Introduction}
38
39
The logistic growth model represents a fundamental advance over exponential growth by
40
incorporating density-dependent regulation through carrying capacity. Extensions of this
41
model address important ecological phenomena including Allee effects and species competition.
42
43
\begin{definition}[Logistic Growth]
44
The logistic growth equation describes population dynamics with density-dependent regulation:
45
\begin{equation}
46
\frac{dN}{dt} = rN\left(1 - \frac{N}{K}\right)
47
\end{equation}
48
where $r$ is the intrinsic growth rate and $K$ is the carrying capacity.
49
\end{definition}
50
51
\section{Theoretical Framework}
52
53
\subsection{Classic Logistic Model}
54
55
\begin{theorem}[Logistic Solution]
56
The analytical solution of the logistic equation is:
57
\begin{equation}
58
N(t) = \frac{K}{1 + \left(\frac{K - N_0}{N_0}\right)e^{-rt}}
59
\end{equation}
60
The population approaches $K$ asymptotically with an inflection point at $N = K/2$.
61
\end{theorem}
62
63
\begin{remark}[Maximum Sustainable Yield]
64
The growth rate $dN/dt$ is maximized when $N = K/2$, yielding the maximum sustainable
65
yield (MSY): $\text{MSY} = rK/4$.
66
\end{remark}
67
68
\subsection{Allee Effect}
69
70
\begin{definition}[Allee Effect]
71
The Allee effect describes reduced per capita growth rate at low population densities due
72
to difficulties in mate finding, reduced group defense, or inbreeding. A strong Allee
73
effect creates a critical population threshold $A$ below which extinction occurs:
74
\begin{equation}
75
\frac{dN}{dt} = rN\left(1 - \frac{N}{K}\right)\left(\frac{N}{A} - 1\right)
76
\end{equation}
77
\end{definition}
78
79
\subsection{Competition Models}
80
81
\begin{theorem}[Lotka-Volterra Competition]
82
For two competing species:
83
\begin{align}
84
\frac{dN_1}{dt} &= r_1 N_1 \left(1 - \frac{N_1 + \alpha_{12} N_2}{K_1}\right) \\
85
\frac{dN_2}{dt} &= r_2 N_2 \left(1 - \frac{N_2 + \alpha_{21} N_1}{K_2}\right)
86
\end{align}
87
where $\alpha_{ij}$ is the competition coefficient (effect of species $j$ on species $i$).
88
\end{theorem}
89
90
\subsection{Harvesting}
91
92
\begin{definition}[Harvesting Strategies]
93
Common harvesting models include:
94
\begin{itemize}
95
\item \textbf{Constant harvest}: $dN/dt = rN(1 - N/K) - H$
96
\item \textbf{Proportional harvest}: $dN/dt = rN(1 - N/K) - qEN$
97
\item \textbf{Threshold harvest}: Harvest only when $N > N_{threshold}$
98
\end{itemize}
99
where $H$ is harvest rate, $q$ is catchability, and $E$ is effort.
100
\end{definition}
101
102
\section{Computational Analysis}
103
104
\begin{pycode}
105
import numpy as np
106
import matplotlib.pyplot as plt
107
from scipy.integrate import odeint
108
from scipy.optimize import fsolve
109
110
np.random.seed(42)
111
112
# Model definitions
113
def logistic(N, t, r, K):
114
return r * N * (1 - N/K)
115
116
def allee(N, t, r, K, A):
117
if N <= 0:
118
return 0
119
return r * N * (1 - N/K) * (N/A - 1)
120
121
def logistic_harvest(N, t, r, K, H):
122
return r * N * (1 - N/K) - H
123
124
def competition(y, t, r1, K1, r2, K2, alpha12, alpha21):
125
N1, N2 = y
126
dN1 = r1 * N1 * (1 - (N1 + alpha12*N2)/K1)
127
dN2 = r2 * N2 * (1 - (N2 + alpha21*N1)/K2)
128
return [dN1, dN2]
129
130
# Parameters
131
r = 0.5
132
K = 1000
133
N0 = 50
134
A = 100 # Allee threshold
135
136
# Time arrays
137
t_short = np.linspace(0, 30, 500)
138
t_long = np.linspace(0, 50, 500)
139
140
# Basic logistic
141
N_logistic = odeint(logistic, N0, t_long, args=(r, K))[:, 0]
142
143
# Exponential comparison
144
N_exp = N0 * np.exp(r * t_long)
145
146
# Different growth rates
147
r_values = [0.3, 0.5, 0.8, 1.0]
148
N_r_vary = {}
149
for r_val in r_values:
150
N_r_vary[r_val] = odeint(logistic, N0, t_long, args=(r_val, K))[:, 0]
151
152
# Allee effect
153
N_allee_above = odeint(allee, 150, t_long, args=(r, K, A))[:, 0]
154
N_allee_below = odeint(allee, 80, t_long, args=(r, K, A))[:, 0]
155
N_allee_threshold = odeint(allee, A, t_long, args=(r, K, A))[:, 0]
156
157
# Harvesting analysis
158
H_values = [0, 30, 60, 90, 120]
159
N_harvest = {}
160
for H in H_values:
161
N_harvest[H] = odeint(logistic_harvest, 800, t_long, args=(r, K, H))[:, 0]
162
163
# MSY calculation
164
MSY = r * K / 4
165
N_MSY = K / 2
166
167
# Competition outcomes
168
# Coexistence
169
N_coex = odeint(competition, [100, 100], t_long, args=(0.5, 1000, 0.5, 1000, 0.5, 0.5))
170
# Competitive exclusion
171
N_excl = odeint(competition, [100, 100], t_long, args=(0.5, 1000, 0.4, 800, 1.2, 1.5))
172
173
# Growth rate vs population
174
N_range = np.linspace(0, K, 200)
175
dN_dt_logistic = r * N_range * (1 - N_range/K)
176
dN_dt_allee = r * N_range * (1 - N_range/K) * (N_range/A - 1)
177
178
# Per capita growth rate
179
per_capita_logistic = r * (1 - N_range/K)
180
per_capita_allee = np.where(N_range > 0, r * (1 - N_range/K) * (N_range/A - 1), 0)
181
182
# Create figure
183
fig = plt.figure(figsize=(14, 12))
184
185
# Plot 1: Logistic vs exponential
186
ax1 = fig.add_subplot(3, 3, 1)
187
ax1.plot(t_long, N_logistic, 'b-', linewidth=2, label='Logistic')
188
ax1.plot(t_long, np.clip(N_exp, 0, 2500), 'r--', linewidth=2, label='Exponential')
189
ax1.axhline(y=K, color='gray', linestyle='--', alpha=0.7, label=f'K = {K}')
190
ax1.set_xlabel('Time')
191
ax1.set_ylabel('Population $N$')
192
ax1.set_title('Logistic vs Exponential Growth')
193
ax1.legend(fontsize=8)
194
ax1.set_ylim([0, 1500])
195
196
# Plot 2: Growth rate vs population
197
ax2 = fig.add_subplot(3, 3, 2)
198
ax2.plot(N_range, dN_dt_logistic, 'b-', linewidth=2, label='Logistic')
199
ax2.plot(N_range, dN_dt_allee, 'r-', linewidth=2, label='Allee')
200
ax2.axvline(x=K/2, color='blue', linestyle=':', alpha=0.7)
201
ax2.axvline(x=A, color='red', linestyle=':', alpha=0.7)
202
ax2.axhline(y=0, color='black', linewidth=0.5)
203
ax2.set_xlabel('Population $N$')
204
ax2.set_ylabel('$dN/dt$')
205
ax2.set_title('Population Growth Rate')
206
ax2.legend(fontsize=8)
207
208
# Plot 3: Effect of growth rate
209
ax3 = fig.add_subplot(3, 3, 3)
210
colors = plt.cm.viridis(np.linspace(0, 0.8, len(r_values)))
211
for i, r_val in enumerate(r_values):
212
ax3.plot(t_long, N_r_vary[r_val], color=colors[i], linewidth=2, label=f'r = {r_val}')
213
ax3.axhline(y=K, color='gray', linestyle='--', alpha=0.7)
214
ax3.set_xlabel('Time')
215
ax3.set_ylabel('Population $N$')
216
ax3.set_title('Effect of Growth Rate')
217
ax3.legend(fontsize=8)
218
219
# Plot 4: Allee effect
220
ax4 = fig.add_subplot(3, 3, 4)
221
ax4.plot(t_long, N_allee_above, 'g-', linewidth=2, label=f'$N_0 = 150 > A$')
222
ax4.plot(t_long, N_allee_below, 'r-', linewidth=2, label=f'$N_0 = 80 < A$')
223
ax4.plot(t_long, N_allee_threshold, 'orange', linewidth=2, label=f'$N_0 = A$')
224
ax4.axhline(y=K, color='gray', linestyle='--', alpha=0.7)
225
ax4.axhline(y=A, color='black', linestyle=':', alpha=0.7)
226
ax4.set_xlabel('Time')
227
ax4.set_ylabel('Population $N$')
228
ax4.set_title(f'Allee Effect (A = {A})')
229
ax4.legend(fontsize=8)
230
ax4.set_ylim([0, 1200])
231
232
# Plot 5: Harvesting
233
ax5 = fig.add_subplot(3, 3, 5)
234
colors_h = plt.cm.plasma(np.linspace(0, 0.8, len(H_values)))
235
for i, H in enumerate(H_values):
236
ax5.plot(t_long, N_harvest[H], color=colors_h[i], linewidth=2, label=f'H = {H}')
237
ax5.axhline(y=0, color='black', linewidth=0.5)
238
ax5.set_xlabel('Time')
239
ax5.set_ylabel('Population $N$')
240
ax5.set_title('Constant Harvest Rate')
241
ax5.legend(fontsize=8, loc='upper right')
242
ax5.set_ylim([0, 1000])
243
244
# Plot 6: Yield curve
245
ax6 = fig.add_subplot(3, 3, 6)
246
N_eq = np.linspace(0, K, 200)
247
yield_curve = r * N_eq * (1 - N_eq/K)
248
ax6.plot(N_eq, yield_curve, 'b-', linewidth=2)
249
ax6.axvline(x=N_MSY, color='red', linestyle='--', alpha=0.7)
250
ax6.axhline(y=MSY, color='red', linestyle='--', alpha=0.7)
251
ax6.scatter([N_MSY], [MSY], s=100, c='red', zorder=5, label=f'MSY = {MSY:.0f}')
252
ax6.set_xlabel('Equilibrium population $N^*$')
253
ax6.set_ylabel('Sustainable yield')
254
ax6.set_title('Maximum Sustainable Yield')
255
ax6.legend(fontsize=8)
256
257
# Plot 7: Competition - coexistence
258
ax7 = fig.add_subplot(3, 3, 7)
259
ax7.plot(t_long, N_coex[:, 0], 'b-', linewidth=2, label='Species 1')
260
ax7.plot(t_long, N_coex[:, 1], 'r-', linewidth=2, label='Species 2')
261
ax7.set_xlabel('Time')
262
ax7.set_ylabel('Population')
263
ax7.set_title('Competition: Coexistence')
264
ax7.legend(fontsize=8)
265
266
# Plot 8: Competition - exclusion
267
ax8 = fig.add_subplot(3, 3, 8)
268
ax8.plot(t_long, N_excl[:, 0], 'b-', linewidth=2, label='Species 1')
269
ax8.plot(t_long, N_excl[:, 1], 'r-', linewidth=2, label='Species 2')
270
ax8.set_xlabel('Time')
271
ax8.set_ylabel('Population')
272
ax8.set_title('Competition: Exclusion')
273
ax8.legend(fontsize=8)
274
275
# Plot 9: Per capita growth rate
276
ax9 = fig.add_subplot(3, 3, 9)
277
ax9.plot(N_range, per_capita_logistic, 'b-', linewidth=2, label='Logistic')
278
ax9.plot(N_range, per_capita_allee, 'r-', linewidth=2, label='Allee')
279
ax9.axhline(y=0, color='black', linewidth=0.5)
280
ax9.axvline(x=A, color='red', linestyle=':', alpha=0.7)
281
ax9.set_xlabel('Population $N$')
282
ax9.set_ylabel('Per capita growth rate')
283
ax9.set_title('Density Dependence')
284
ax9.legend(fontsize=8)
285
286
plt.tight_layout()
287
plt.savefig('logistic_growth_analysis.pdf', dpi=150, bbox_inches='tight')
288
plt.close()
289
290
# Calculate key values
291
t_inflection = np.log((K - N0) / N0) / r
292
doubling_time = np.log(2) / r
293
\end{pycode}
294
295
\begin{figure}[htbp]
296
\centering
297
\includegraphics[width=\textwidth]{logistic_growth_analysis.pdf}
298
\caption{Logistic growth analysis: (a) Comparison with exponential growth; (b) Population
299
growth rate showing inflection points; (c) Effect of intrinsic growth rate; (d) Allee
300
effect dynamics; (e) Constant harvest scenarios; (f) Maximum sustainable yield curve;
301
(g-h) Competition outcomes; (i) Per capita growth rate showing density dependence.}
302
\label{fig:logistic}
303
\end{figure}
304
305
\section{Results}
306
307
\subsection{Model Parameters}
308
309
\begin{pycode}
310
print(r"\begin{table}[htbp]")
311
print(r"\centering")
312
print(r"\caption{Logistic Growth Model Parameters and Key Values}")
313
print(r"\begin{tabular}{lcc}")
314
print(r"\toprule")
315
print(r"Parameter & Symbol & Value \\")
316
print(r"\midrule")
317
print(f"Intrinsic growth rate & $r$ & {r} \\\\")
318
print(f"Carrying capacity & $K$ & {K} \\\\")
319
print(f"Initial population & $N_0$ & {N0} \\\\")
320
print(f"Allee threshold & $A$ & {A} \\\\")
321
print(r"\midrule")
322
print(f"MSY population & $N_{{MSY}}$ & {N_MSY:.0f} \\\\")
323
print(f"Maximum sustainable yield & MSY & {MSY:.1f} \\\\")
324
print(f"Time to inflection & $t_{{infl}}$ & {t_inflection:.2f} \\\\")
325
print(f"Doubling time & $t_d$ & {doubling_time:.2f} \\\\")
326
print(r"\bottomrule")
327
print(r"\end{tabular}")
328
print(r"\label{tab:parameters}")
329
print(r"\end{table}")
330
\end{pycode}
331
332
\subsection{Harvesting Outcomes}
333
334
\begin{pycode}
335
print(r"\begin{table}[htbp]")
336
print(r"\centering")
337
print(r"\caption{Equilibrium Populations Under Different Harvest Rates}")
338
print(r"\begin{tabular}{ccc}")
339
print(r"\toprule")
340
print(r"Harvest rate $H$ & Equilibrium $N^*$ & Sustainable? \\")
341
print(r"\midrule")
342
343
for H in H_values:
344
N_final = N_harvest[H][-1]
345
if N_final > 1:
346
sustainable = "Yes"
347
else:
348
sustainable = "No (collapse)"
349
print(f"{H} & {N_final:.0f} & {sustainable} \\\\")
350
351
print(r"\bottomrule")
352
print(r"\end{tabular}")
353
print(r"\label{tab:harvest}")
354
print(r"\end{table}")
355
\end{pycode}
356
357
\section{Discussion}
358
359
\begin{example}[Maximum Sustainable Yield]
360
For fisheries management, the MSY occurs at $N = K/2$:
361
\begin{equation}
362
\text{MSY} = r \cdot \frac{K}{2} \cdot \left(1 - \frac{K/2}{K}\right) = \frac{rK}{4} = \py{f"{MSY:.1f}"}
363
\end{equation}
364
Harvesting at rates exceeding MSY leads to population collapse.
365
\end{example}
366
367
\begin{remark}[Allee Effect and Conservation]
368
The Allee effect has critical implications for conservation:
369
\begin{itemize}
370
\item Small populations face extinction risk even without external threats
371
\item Minimum viable population size must exceed the Allee threshold
372
\item Reintroduction programs must establish populations above this threshold
373
\item Habitat fragmentation increases Allee effect risks
374
\end{itemize}
375
\end{remark}
376
377
\begin{example}[Competition Outcomes]
378
The outcome of Lotka-Volterra competition depends on $\alpha$ values:
379
\begin{itemize}
380
\item Coexistence: $\alpha_{12} < K_1/K_2$ and $\alpha_{21} < K_2/K_1$
381
\item Species 1 wins: $\alpha_{12} < K_1/K_2$ and $\alpha_{21} > K_2/K_1$
382
\item Species 2 wins: $\alpha_{12} > K_1/K_2$ and $\alpha_{21} < K_2/K_1$
383
\item Unstable: Both inequalities reversed
384
\end{itemize}
385
\end{example}
386
387
\section{Conclusions}
388
389
This analysis demonstrates key aspects of logistic population dynamics:
390
\begin{enumerate}
391
\item The population approaches carrying capacity $K = \py{f"{K}"}$ with inflection at $K/2$
392
\item MSY of $\py{f"{MSY:.1f}"}$ occurs when harvesting maintains population at $K/2$
393
\item The Allee effect creates an extinction threshold at $A = \py{f"{A}"}$
394
\item Competition outcomes depend on relative competition coefficients
395
\item Per capita growth rate decreases linearly with population in the logistic model
396
\end{enumerate}
397
398
\section*{Further Reading}
399
400
\begin{itemize}
401
\item Gotelli, N.J. \textit{A Primer of Ecology}, 4th ed. Sinauer Associates, 2008.
402
\item Courchamp, F. et al. \textit{Allee Effects in Ecology and Conservation}. Oxford, 2008.
403
\item Clark, C.W. \textit{Mathematical Bioeconomics}, 3rd ed. Wiley-Interscience, 2010.
404
\end{itemize}
405
406
\end{document}
407
408