Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ok-landscape
GitHub Repository: Ok-landscape/computational-pipeline
Path: blob/main/latex-templates/templates/marine-biology/fisheries_models.tex
51 views
unlisted
1
% Fisheries Population Models Template
2
% Topics: Stock-recruitment, surplus production, MSY, age-structured models, overfishing
3
% Style: Fisheries management report with computational analysis
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{Fisheries Population Models:\\Stock-Recruitment Dynamics and Sustainable Harvesting}
22
\author{Marine Biology and Fisheries Management Group}
23
\date{\today}
24
25
\begin{document}
26
\maketitle
27
28
\begin{abstract}
29
This report presents a comprehensive computational analysis of fisheries population models
30
used in sustainable fisheries management. We examine surplus production models including
31
the Schaefer and Fox formulations, calculate maximum sustainable yield (MSY) and optimal
32
fishing effort, analyze stock-recruitment relationships through Beverton-Holt and Ricker
33
models, and investigate age-structured population dynamics. The analysis demonstrates
34
critical thresholds for overfishing, equilibrium biomass levels, and yield-per-recruit
35
optimization for effective fisheries conservation.
36
\end{abstract}
37
38
\section{Introduction}
39
40
Fisheries population models provide the scientific foundation for sustainable fisheries
41
management. These models describe how fish stocks respond to fishing pressure and
42
environmental variation, enabling managers to set harvest limits that balance economic
43
productivity with long-term population viability. Understanding stock dynamics is crucial
44
for preventing overfishing and ensuring food security for coastal communities worldwide.
45
46
\begin{definition}[Sustainable Yield]
47
The sustainable yield is the harvest rate that can be maintained indefinitely without
48
depleting the stock. Maximum sustainable yield (MSY) represents the largest average catch
49
that can be taken from a stock under existing environmental conditions.
50
\end{definition}
51
52
\section{Surplus Production Models}
53
54
Surplus production models describe population biomass dynamics without explicit age
55
structure. These models assume that fish populations grow logistically until limited by
56
carrying capacity, and that fishing removes a portion of the biomass proportional to
57
fishing effort and stock size.
58
59
\subsection{The Schaefer Model}
60
61
\begin{definition}[Schaefer Model]
62
The Schaefer model assumes logistic population growth with fishing mortality proportional
63
to effort and biomass:
64
\begin{equation}
65
\frac{dB}{dt} = rB\left(1 - \frac{B}{K}\right) - qEB
66
\end{equation}
67
where $B$ is biomass (tonnes), $r$ is intrinsic growth rate (year$^{-1}$), $K$ is carrying
68
capacity (tonnes), $E$ is fishing effort (boat-days), and $q$ is catchability coefficient
69
(boat-days$^{-1}$).
70
\end{definition}
71
72
\begin{theorem}[Maximum Sustainable Yield]
73
At equilibrium ($dB/dt = 0$), the Schaefer model yields:
74
\begin{equation}
75
MSY = \frac{rK}{4}, \quad B_{MSY} = \frac{K}{2}, \quad E_{MSY} = \frac{r}{2q}
76
\end{equation}
77
The maximum sustainable yield occurs at half the carrying capacity with fishing effort
78
equal to half the intrinsic growth rate divided by catchability.
79
\end{theorem}
80
81
\subsection{The Fox Model}
82
83
\begin{definition}[Fox Model]
84
The Fox model assumes Gompertz growth rather than logistic:
85
\begin{equation}
86
\frac{dB}{dt} = rB\ln\left(\frac{K}{B}\right) - qEB
87
\end{equation}
88
This formulation better describes populations with compensatory mortality at low densities.
89
\end{definition}
90
91
\section{Computational Analysis: Surplus Production}
92
93
We implement the Schaefer and Fox models to analyze a hypothetical demersal fish stock
94
under varying fishing pressure. The analysis demonstrates how fishing effort affects
95
equilibrium biomass, sustainable yield, and the risk of stock collapse. Understanding
96
these relationships is essential for setting total allowable catch (TAC) limits in
97
fisheries management plans.
98
99
\begin{pycode}
100
import numpy as np
101
import matplotlib.pyplot as plt
102
from scipy.integrate import odeint
103
from scipy.optimize import fsolve, minimize_scalar
104
105
np.random.seed(42)
106
107
# Schaefer model parameters (typical demersal fish stock)
108
r = 0.8 # intrinsic growth rate (year^-1)
109
K = 100000 # carrying capacity (tonnes)
110
q = 0.0001 # catchability coefficient (boat-days^-1)
111
112
# Calculate MSY analytically
113
MSY = r * K / 4
114
B_MSY = K / 2
115
E_MSY = r / (2 * q)
116
117
print(f"Schaefer Model Parameters:")
118
print(f"MSY = {MSY:.0f} tonnes/year")
119
print(f"Biomass at MSY = {B_MSY:.0f} tonnes")
120
print(f"Optimal effort = {E_MSY:.0f} boat-days/year")
121
122
# Schaefer differential equation
123
def schaefer(B, t, r, K, q, E):
124
dBdt = r * B * (1 - B / K) - q * E * B
125
return dBdt
126
127
# Fox differential equation
128
def fox(B, t, r, K, q, E):
129
if B <= 0:
130
return 0
131
dBdt = r * B * np.log(K / B) - q * E * B
132
return dBdt
133
134
# Time array
135
t = np.linspace(0, 50, 500)
136
137
# Different fishing effort levels
138
effort_levels = np.array([0, 2000, 4000, 6000, 8000, 10000])
139
140
# Initial biomass (virgin stock)
141
B0 = K
142
143
# Simulate trajectories
144
schaefer_trajectories = {}
145
fox_trajectories = {}
146
147
for E in effort_levels:
148
B_schaefer = odeint(schaefer, B0, t, args=(r, K, q, E))
149
B_fox = odeint(fox, B0, t, args=(r, K, q, E))
150
schaefer_trajectories[E] = B_schaefer.flatten()
151
fox_trajectories[E] = B_fox.flatten()
152
153
# Equilibrium biomass and yield curves
154
effort_range = np.linspace(0, 12000, 200)
155
B_eq_schaefer = K * (1 - q * effort_range / r)
156
B_eq_schaefer[B_eq_schaefer < 0] = 0
157
yield_schaefer = q * effort_range * B_eq_schaefer
158
159
# Fox equilibrium (numerical solution)
160
def fox_equilibrium(B, E, r, K, q):
161
if B <= 0:
162
return 1e10
163
return r * np.log(K / B) - q * E
164
165
B_eq_fox = []
166
for E in effort_range:
167
if E < r / q:
168
B_eq_fox.append(fsolve(fox_equilibrium, K/2, args=(E, r, K, q))[0])
169
else:
170
B_eq_fox.append(0)
171
B_eq_fox = np.array(B_eq_fox)
172
yield_fox = q * effort_range * B_eq_fox
173
174
# Create first figure: biomass trajectories and equilibrium curves
175
fig = plt.figure(figsize=(14, 10))
176
177
# Plot 1: Schaefer biomass trajectories
178
ax1 = fig.add_subplot(2, 3, 1)
179
colors = plt.cm.viridis(np.linspace(0, 0.9, len(effort_levels)))
180
for i, E in enumerate(effort_levels):
181
ax1.plot(t, schaefer_trajectories[E], linewidth=2, color=colors[i],
182
label=f'E = {E:.0f}')
183
ax1.axhline(y=B_MSY, color='red', linestyle='--', linewidth=1.5, alpha=0.7,
184
label=f'$B_{{MSY}}$ = {B_MSY:.0f}')
185
ax1.set_xlabel('Time (years)', fontsize=11)
186
ax1.set_ylabel('Biomass (tonnes)', fontsize=11)
187
ax1.set_title('Schaefer Model: Biomass Trajectories', fontsize=12, fontweight='bold')
188
ax1.legend(fontsize=8, loc='right')
189
ax1.grid(True, alpha=0.3)
190
ax1.set_ylim(0, K * 1.1)
191
192
# Plot 2: Equilibrium biomass vs effort
193
ax2 = fig.add_subplot(2, 3, 2)
194
ax2.plot(effort_range, B_eq_schaefer, 'b-', linewidth=2.5, label='Schaefer')
195
ax2.plot(effort_range, B_eq_fox, 'g-', linewidth=2.5, label='Fox')
196
ax2.axhline(y=B_MSY, color='red', linestyle='--', linewidth=1.5, alpha=0.7)
197
ax2.axvline(x=E_MSY, color='red', linestyle='--', linewidth=1.5, alpha=0.7)
198
ax2.fill_between(effort_range, 0, B_eq_schaefer, where=(B_eq_schaefer < 0.2 * K),
199
alpha=0.2, color='red', label='Overfished')
200
ax2.set_xlabel('Fishing Effort (boat-days/year)', fontsize=11)
201
ax2.set_ylabel('Equilibrium Biomass (tonnes)', fontsize=11)
202
ax2.set_title('Equilibrium Stock Size', fontsize=12, fontweight='bold')
203
ax2.legend(fontsize=9)
204
ax2.grid(True, alpha=0.3)
205
206
# Plot 3: Yield vs effort (production curve)
207
ax3 = fig.add_subplot(2, 3, 3)
208
ax3.plot(effort_range, yield_schaefer, 'b-', linewidth=2.5, label='Schaefer')
209
ax3.plot(effort_range, yield_fox, 'g-', linewidth=2.5, label='Fox')
210
ax3.axhline(y=MSY, color='red', linestyle='--', linewidth=1.5, alpha=0.7,
211
label=f'MSY = {MSY:.0f}')
212
ax3.axvline(x=E_MSY, color='red', linestyle='--', linewidth=1.5, alpha=0.7)
213
ax3.scatter([E_MSY], [MSY], s=150, c='red', marker='*', zorder=5, edgecolor='black')
214
ax3.set_xlabel('Fishing Effort (boat-days/year)', fontsize=11)
215
ax3.set_ylabel('Sustainable Yield (tonnes/year)', fontsize=11)
216
ax3.set_title('Production Curve', fontsize=12, fontweight='bold')
217
ax3.legend(fontsize=9)
218
ax3.grid(True, alpha=0.3)
219
220
# Plot 4: Yield vs biomass
221
ax4 = fig.add_subplot(2, 3, 4)
222
ax4.plot(B_eq_schaefer, yield_schaefer, 'b-', linewidth=2.5, label='Schaefer')
223
ax4.plot(B_eq_fox, yield_fox, 'g-', linewidth=2.5, label='Fox')
224
ax4.scatter([B_MSY], [MSY], s=150, c='red', marker='*', zorder=5, edgecolor='black',
225
label='MSY point')
226
ax4.axvline(x=0.2*K, color='orange', linestyle=':', linewidth=2, alpha=0.7,
227
label='Overfished threshold')
228
ax4.set_xlabel('Stock Biomass (tonnes)', fontsize=11)
229
ax4.set_ylabel('Sustainable Yield (tonnes/year)', fontsize=11)
230
ax4.set_title('Yield vs Stock Size', fontsize=12, fontweight='bold')
231
ax4.legend(fontsize=9)
232
ax4.grid(True, alpha=0.3)
233
234
# Plot 5: Fishing mortality rate
235
ax5 = fig.add_subplot(2, 3, 5)
236
F_range = q * effort_range
237
F_MSY = q * E_MSY
238
ax5.plot(F_range, yield_schaefer, 'b-', linewidth=2.5)
239
ax5.axvline(x=F_MSY, color='red', linestyle='--', linewidth=1.5, alpha=0.7,
240
label=f'$F_{{MSY}}$ = {F_MSY:.3f}')
241
ax5.axvline(x=r, color='orange', linestyle=':', linewidth=2, alpha=0.7,
242
label=f'$F = r$ (collapse)')
243
ax5.fill_between(F_range, 0, yield_schaefer, where=(F_range > r),
244
alpha=0.3, color='red', label='Overfishing')
245
ax5.set_xlabel('Fishing Mortality Rate (year$^{-1}$)', fontsize=11)
246
ax5.set_ylabel('Sustainable Yield (tonnes/year)', fontsize=11)
247
ax5.set_title('Yield vs Fishing Mortality', fontsize=12, fontweight='bold')
248
ax5.legend(fontsize=9)
249
ax5.grid(True, alpha=0.3)
250
ax5.set_xlim(0, 1.2)
251
252
# Plot 6: Stock depletion levels
253
ax6 = fig.add_subplot(2, 3, 6)
254
depletion = B_eq_schaefer / K * 100
255
ax6.plot(effort_range, depletion, 'b-', linewidth=2.5)
256
ax6.axhline(y=50, color='red', linestyle='--', linewidth=1.5, alpha=0.7,
257
label='50% (MSY)')
258
ax6.axhline(y=20, color='orange', linestyle='--', linewidth=1.5, alpha=0.7,
259
label='20% (overfished)')
260
ax6.axhline(y=10, color='darkred', linestyle='--', linewidth=1.5, alpha=0.7,
261
label='10% (critical)')
262
ax6.fill_between(effort_range, 0, depletion, where=(depletion < 20),
263
alpha=0.3, color='red')
264
ax6.set_xlabel('Fishing Effort (boat-days/year)', fontsize=11)
265
ax6.set_ylabel('Stock Depletion Level (\\%)', fontsize=11)
266
ax6.set_title('Depletion vs Effort', fontsize=12, fontweight='bold')
267
ax6.legend(fontsize=8, loc='upper right')
268
ax6.grid(True, alpha=0.3)
269
ax6.set_ylim(0, 105)
270
271
plt.tight_layout()
272
plt.savefig('fisheries_models_production.pdf', dpi=150, bbox_inches='tight')
273
plt.close()
274
\end{pycode}
275
276
\begin{figure}[htbp]
277
\centering
278
\includegraphics[width=\textwidth]{fisheries_models_production.pdf}
279
\caption{Surplus production model analysis showing biomass trajectories under different
280
fishing effort levels, equilibrium relationships between effort and stock size, and the
281
classic dome-shaped production curve. The Schaefer model predicts MSY at 50\% of carrying
282
capacity with effort = \py{f"{E_MSY:.0f}"} boat-days/year. The red shaded regions indicate
283
overfished conditions where stock biomass falls below 20\% of carrying capacity, risking
284
recruitment failure and economic collapse of the fishery.}
285
\label{fig:production}
286
\end{figure}
287
288
The surplus production analysis reveals that fishing effort above \py{f"{E_MSY:.0f}"}
289
boat-days/year drives the stock below the MSY biomass level, reducing long-term catch.
290
At extreme effort levels exceeding \py{f"{r/q:.0f}"} boat-days/year, the fishing
291
mortality rate surpasses the intrinsic growth rate, causing inevitable stock collapse.
292
This demonstrates the biological and economic irrationality of overfishing.
293
294
\section{Stock-Recruitment Relationships}
295
296
Stock-recruitment models describe how spawning stock biomass (SSB) determines the
297
abundance of recruits entering the fishery. These models capture density-dependent
298
mortality in early life stages and are essential for understanding population resilience.
299
300
\subsection{The Beverton-Holt Model}
301
302
\begin{definition}[Beverton-Holt Recruitment]
303
The Beverton-Holt model describes asymptotic recruitment with density dependence:
304
\begin{equation}
305
R = \frac{\alpha S}{1 + \beta S}
306
\end{equation}
307
where $R$ is recruitment, $S$ is spawning stock biomass, $\alpha$ is maximum recruits
308
per spawner at low density, and $\beta$ controls density dependence.
309
\end{definition}
310
311
\subsection{The Ricker Model}
312
313
\begin{definition}[Ricker Recruitment]
314
The Ricker model allows for overcompensation at high spawning stock:
315
\begin{equation}
316
R = \alpha S e^{-\beta S}
317
\end{equation}
318
This formulation can produce a recruitment maximum at intermediate spawning stock levels
319
due to cannibalism or disease transmission.
320
\end{definition}
321
322
\section{Computational Analysis: Stock-Recruitment}
323
324
We analyze stock-recruitment relationships to identify critical thresholds for population
325
replacement and assess the risk of recruitment overfishing. The comparison of Beverton-Holt
326
and Ricker models illustrates how different density-dependent mechanisms affect population
327
stability and optimal spawning stock levels.
328
329
\begin{pycode}
330
# Stock-recruitment parameters
331
alpha_BH = 50 # recruits per tonne SSB at low density
332
beta_BH = 0.01 # density dependence (tonne^-1)
333
alpha_Ricker = 20 # low-density productivity
334
beta_Ricker = 0.00005 # density dependence
335
336
# Spawning stock biomass range
337
SSB = np.linspace(0, 50000, 500)
338
339
# Beverton-Holt recruitment
340
R_BH = (alpha_BH * SSB) / (1 + beta_BH * SSB)
341
342
# Ricker recruitment
343
R_Ricker = alpha_BH * SSB * np.exp(-beta_Ricker * SSB)
344
345
# Replacement line (R = S with survival rate)
346
survival_rate = 0.05 # fraction of recruits surviving to spawn
347
replacement = SSB / survival_rate
348
349
# Find equilibrium points
350
def find_equilibria(SSB_range, R_model, survival):
351
equil_points = []
352
R_vals = R_model(SSB_range) if callable(R_model) else R_model
353
for i in range(len(SSB_range) - 1):
354
if (R_vals[i] * survival - SSB_range[i]) * (R_vals[i+1] * survival - SSB_range[i+1]) < 0:
355
equil_points.append(SSB_range[i])
356
return equil_points
357
358
# Spawning potential ratio (SPR) analysis
359
fishing_mortality = np.linspace(0, 2.0, 100)
360
SPR = np.exp(-fishing_mortality) # simplified SPR
361
reference_SPR = np.exp(-0.4) # F40% reference point
362
363
# Calculate recruits per spawning stock (R/S)
364
R_per_S_BH = R_BH / (SSB + 1e-6)
365
R_per_S_Ricker = R_Ricker / (SSB + 1e-6)
366
367
# Find Ricker optimum
368
SSB_opt_Ricker = 1 / beta_Ricker
369
R_opt_Ricker = alpha_BH * SSB_opt_Ricker * np.exp(-1)
370
371
# Create second figure: stock-recruitment
372
fig2 = plt.figure(figsize=(14, 10))
373
374
# Plot 1: Stock-recruitment curves
375
ax1 = fig2.add_subplot(2, 3, 1)
376
ax1.plot(SSB, R_BH, 'b-', linewidth=2.5, label='Beverton-Holt')
377
ax1.plot(SSB, R_Ricker, 'g-', linewidth=2.5, label='Ricker')
378
ax1.plot(SSB, replacement, 'r--', linewidth=2, alpha=0.7, label='Replacement')
379
ax1.scatter([SSB_opt_Ricker], [R_opt_Ricker], s=150, c='green', marker='o',
380
zorder=5, edgecolor='black', label='Ricker optimum')
381
ax1.set_xlabel('Spawning Stock Biomass (tonnes)', fontsize=11)
382
ax1.set_ylabel('Recruitment (millions of individuals)', fontsize=11)
383
ax1.set_title('Stock-Recruitment Relationships', fontsize=12, fontweight='bold')
384
ax1.legend(fontsize=9)
385
ax1.grid(True, alpha=0.3)
386
387
# Plot 2: Recruits per spawner
388
ax2 = fig2.add_subplot(2, 3, 2)
389
ax2.plot(SSB, R_per_S_BH, 'b-', linewidth=2.5, label='Beverton-Holt')
390
ax2.plot(SSB, R_per_S_Ricker, 'g-', linewidth=2.5, label='Ricker')
391
ax2.axhline(y=1/survival_rate, color='red', linestyle='--', linewidth=2, alpha=0.7,
392
label='Replacement level')
393
ax2.set_xlabel('Spawning Stock Biomass (tonnes)', fontsize=11)
394
ax2.set_ylabel('Recruits per Tonne SSB', fontsize=11)
395
ax2.set_title('Density-Dependent Recruitment', fontsize=12, fontweight='bold')
396
ax2.legend(fontsize=9)
397
ax2.grid(True, alpha=0.3)
398
ax2.set_ylim(0, 60)
399
400
# Plot 3: Phase diagram (SSB dynamics)
401
ax3 = fig2.add_subplot(2, 3, 3)
402
SSB_next_BH = R_BH * survival_rate
403
SSB_next_Ricker = R_Ricker * survival_rate
404
ax3.plot(SSB, SSB_next_BH, 'b-', linewidth=2.5, label='Beverton-Holt')
405
ax3.plot(SSB, SSB_next_Ricker, 'g-', linewidth=2.5, label='Ricker')
406
ax3.plot(SSB, SSB, 'r--', linewidth=2, alpha=0.7, label='1:1 line')
407
ax3.fill_between(SSB, 0, SSB_next_BH, where=(SSB_next_BH > SSB),
408
alpha=0.2, color='green', label='Increasing')
409
ax3.fill_between(SSB, 0, SSB_next_BH, where=(SSB_next_BH < SSB),
410
alpha=0.2, color='red', label='Decreasing')
411
ax3.set_xlabel('Current SSB (tonnes)', fontsize=11)
412
ax3.set_ylabel('Next Generation SSB (tonnes)', fontsize=11)
413
ax3.set_title('Population Dynamics Phase Diagram', fontsize=12, fontweight='bold')
414
ax3.legend(fontsize=8, loc='upper left')
415
ax3.grid(True, alpha=0.3)
416
417
# Plot 4: Spawning potential ratio
418
ax4 = fig2.add_subplot(2, 3, 4)
419
ax4.plot(fishing_mortality, SPR * 100, 'b-', linewidth=2.5)
420
ax4.axhline(y=40, color='red', linestyle='--', linewidth=2, alpha=0.7,
421
label='F40% reference')
422
ax4.axhline(y=20, color='orange', linestyle='--', linewidth=2, alpha=0.7,
423
label='F20% limit')
424
ax4.fill_between(fishing_mortality, 0, SPR * 100, where=(SPR * 100 < 20),
425
alpha=0.3, color='red', label='Overfished')
426
ax4.set_xlabel('Fishing Mortality Rate (year$^{-1}$)', fontsize=11)
427
ax4.set_ylabel('Spawning Potential Ratio (\\%)', fontsize=11)
428
ax4.set_title('SPR-Based Reference Points', fontsize=12, fontweight='bold')
429
ax4.legend(fontsize=9)
430
ax4.grid(True, alpha=0.3)
431
ax4.set_xlim(0, 2)
432
433
# Plot 5: Recruitment with environmental stochasticity
434
ax5 = fig2.add_subplot(2, 3, 5)
435
np.random.seed(123)
436
n_years = 50
437
SSB_sim = np.zeros(n_years)
438
R_sim = np.zeros(n_years)
439
SSB_sim[0] = 20000
440
sigma_R = 0.4 # recruitment variability
441
442
for year in range(n_years - 1):
443
R_mean = (alpha_BH * SSB_sim[year]) / (1 + beta_BH * SSB_sim[year])
444
R_sim[year] = R_mean * np.exp(sigma_R * np.random.randn() - 0.5 * sigma_R**2)
445
SSB_sim[year + 1] = R_sim[year] * survival_rate * 0.7 # with fishing
446
447
ax5.plot(range(n_years), SSB_sim, 'b-', linewidth=2, label='SSB')
448
ax5_twin = ax5.twinx()
449
ax5_twin.bar(range(n_years - 1), R_sim[:-1], alpha=0.5, color='green', label='Recruitment')
450
ax5.axhline(y=B_MSY/5, color='red', linestyle='--', linewidth=1.5, alpha=0.7,
451
label='Limit reference')
452
ax5.set_xlabel('Year', fontsize=11)
453
ax5.set_ylabel('SSB (tonnes)', color='blue', fontsize=11)
454
ax5_twin.set_ylabel('Recruitment (millions)', color='green', fontsize=11)
455
ax5.set_title('Stochastic Recruitment Simulation', fontsize=12, fontweight='bold')
456
ax5.legend(loc='upper left', fontsize=9)
457
ax5_twin.legend(loc='upper right', fontsize=9)
458
ax5.grid(True, alpha=0.3)
459
460
# Plot 6: Allee effect threshold
461
ax6 = fig2.add_subplot(2, 3, 6)
462
# Modified Ricker with Allee effect
463
SSB_allee = np.linspace(0, 50000, 500)
464
S_critical = 5000 # critical depensation threshold
465
allee_factor = SSB_allee / (SSB_allee + S_critical)
466
R_allee = alpha_BH * SSB_allee * np.exp(-beta_Ricker * SSB_allee) * allee_factor
467
468
ax6.plot(SSB_allee, R_allee * survival_rate, 'purple', linewidth=2.5,
469
label='With Allee effect')
470
ax6.plot(SSB, R_Ricker * survival_rate, 'g--', linewidth=2, alpha=0.6,
471
label='Without Allee effect')
472
ax6.plot(SSB_allee, SSB_allee, 'r--', linewidth=2, alpha=0.7, label='Replacement')
473
ax6.axvline(x=S_critical, color='orange', linestyle=':', linewidth=2, alpha=0.7,
474
label=f'Critical threshold')
475
ax6.fill_between(SSB_allee, 0, 50000, where=(SSB_allee < S_critical),
476
alpha=0.2, color='red', label='Collapse risk')
477
ax6.set_xlabel('Spawning Stock Biomass (tonnes)', fontsize=11)
478
ax6.set_ylabel('Next Generation SSB (tonnes)', fontsize=11)
479
ax6.set_title('Depensation and Allee Effects', fontsize=12, fontweight='bold')
480
ax6.legend(fontsize=8, loc='upper left')
481
ax6.grid(True, alpha=0.3)
482
483
plt.tight_layout()
484
plt.savefig('fisheries_models_recruitment.pdf', dpi=150, bbox_inches='tight')
485
plt.close()
486
\end{pycode}
487
488
\begin{figure}[htbp]
489
\centering
490
\includegraphics[width=\textwidth]{fisheries_models_recruitment.pdf}
491
\caption{Stock-recruitment analysis demonstrating density-dependent recruitment dynamics
492
in fish populations. The Beverton-Holt model shows asymptotic recruitment approaching a
493
maximum, while the Ricker model exhibits overcompensation with peak recruitment at
494
\py{f"{SSB_opt_Ricker:.0f}"} tonnes of spawning stock. Phase diagrams reveal stable
495
equilibria and population trajectories under fishing. The spawning potential ratio (SPR)
496
framework identifies F40\% as a precautionary reference point maintaining recruitment
497
capacity. Stochastic simulations show recruitment variability's impact on stock dynamics,
498
while Allee effect analysis demonstrates critical thresholds below \py{f"{S_critical:.0f}"}
499
tonnes where recruitment failure becomes likely.}
500
\label{fig:recruitment}
501
\end{figure}
502
503
Stock-recruitment analysis demonstrates that maintaining spawning stock above critical
504
thresholds is essential for population persistence. The Beverton-Holt formulation suggests
505
resilience to overfishing, while the Ricker model with Allee effects reveals collapse
506
risk when spawning biomass falls below \py{f"{S_critical:.0f}"} tonnes.
507
508
\section{Age-Structured Models: Yield-Per-Recruit}
509
510
Age-structured models explicitly track cohorts through their life history, accounting
511
for size-dependent growth, natural mortality, and fishing selectivity. Yield-per-recruit
512
(YPR) analysis optimizes fishing patterns to maximize lifetime catch from each cohort.
513
514
\begin{pycode}
515
# Age-structured model parameters
516
ages = np.arange(0, 21) # age classes 0-20 years
517
L_inf = 80 # asymptotic length (cm)
518
K_growth = 0.15 # von Bertalanffy growth coefficient
519
t0 = -1.0 # theoretical age at zero length
520
a_length_weight = 0.01 # length-weight coefficient
521
b_length_weight = 3.0 # length-weight exponent
522
M = 0.2 # natural mortality (year^-1)
523
524
# Fishing mortality rates to test
525
F_values = np.linspace(0, 1.5, 100)
526
527
# Selectivity (logistic with 50% selection at age 3)
528
age_50 = 3.0
529
selectivity_slope = 1.5
530
selectivity = 1 / (1 + np.exp(-selectivity_slope * (ages - age_50)))
531
532
# von Bertalanffy growth
533
lengths = L_inf * (1 - np.exp(-K_growth * (ages - t0)))
534
weights = a_length_weight * lengths**b_length_weight / 1000 # kg
535
536
# Calculate yield-per-recruit for different F
537
YPR = np.zeros(len(F_values))
538
SPR_values = np.zeros(len(F_values))
539
540
for i, F in enumerate(F_values):
541
survivors = np.zeros(len(ages))
542
survivors[0] = 1.0 # start with 1 recruit
543
544
cumulative_catch = 0
545
cumulative_spawners = 0
546
547
for age_idx in range(1, len(ages)):
548
F_age = F * selectivity[age_idx]
549
Z = M + F_age # total mortality
550
survivors[age_idx] = survivors[age_idx - 1] * np.exp(-Z)
551
catch = survivors[age_idx - 1] * (F_age / Z) * (1 - np.exp(-Z))
552
cumulative_catch += catch * weights[age_idx]
553
cumulative_spawners += survivors[age_idx] * weights[age_idx]
554
555
YPR[i] = cumulative_catch
556
SPR_values[i] = cumulative_spawners
557
558
# Find F_max and F_0.1
559
F_max_idx = np.argmax(YPR)
560
F_max = F_values[F_max_idx]
561
562
# F_0.1: fishing mortality where slope is 10% of origin slope
563
origin_slope = (YPR[1] - YPR[0]) / (F_values[1] - F_values[0])
564
target_slope = 0.1 * origin_slope
565
slopes = np.diff(YPR) / np.diff(F_values)
566
F_01_idx = np.argmin(np.abs(slopes - target_slope))
567
F_01 = F_values[F_01_idx]
568
569
# F_40: fishing mortality giving 40% SPR
570
SPR_unfished = SPR_values[0]
571
SPR_40_target = 0.4 * SPR_unfished
572
F_40_idx = np.argmin(np.abs(SPR_values - SPR_40_target))
573
F_40 = F_values[F_40_idx]
574
575
# Create third figure: age-structured analysis
576
fig3 = plt.figure(figsize=(14, 10))
577
578
# Plot 1: Growth curve
579
ax1 = fig3.add_subplot(2, 3, 1)
580
ax1.plot(ages, lengths, 'b-', linewidth=2.5)
581
ax1.axhline(y=L_inf, color='red', linestyle='--', linewidth=1.5, alpha=0.7,
582
label=f'$L_\\infty$ = {L_inf} cm')
583
ax1.scatter(ages[::2], lengths[::2], s=50, c='blue', edgecolor='black', zorder=5)
584
ax1.set_xlabel('Age (years)', fontsize=11)
585
ax1.set_ylabel('Length (cm)', fontsize=11)
586
ax1.set_title('von Bertalanffy Growth Curve', fontsize=12, fontweight='bold')
587
ax1.legend(fontsize=9)
588
ax1.grid(True, alpha=0.3)
589
590
# Plot 2: Weight-at-age
591
ax2 = fig3.add_subplot(2, 3, 2)
592
ax2.plot(ages, weights, 'g-', linewidth=2.5)
593
ax2.scatter(ages[::2], weights[::2], s=50, c='green', edgecolor='black', zorder=5)
594
ax2.set_xlabel('Age (years)', fontsize=11)
595
ax2.set_ylabel('Weight (kg)', fontsize=11)
596
ax2.set_title('Weight-at-Age', fontsize=12, fontweight='bold')
597
ax2.grid(True, alpha=0.3)
598
599
# Plot 3: Selectivity curve
600
ax3 = fig3.add_subplot(2, 3, 3)
601
ax3.plot(ages, selectivity, 'purple', linewidth=2.5)
602
ax3.axhline(y=0.5, color='gray', linestyle=':', linewidth=1.5, alpha=0.7)
603
ax3.axvline(x=age_50, color='gray', linestyle=':', linewidth=1.5, alpha=0.7,
604
label=f'$a_{{50}}$ = {age_50} years')
605
ax3.set_xlabel('Age (years)', fontsize=11)
606
ax3.set_ylabel('Selectivity', fontsize=11)
607
ax3.set_title('Fishing Gear Selectivity', fontsize=12, fontweight='bold')
608
ax3.legend(fontsize=9)
609
ax3.grid(True, alpha=0.3)
610
ax3.set_ylim(0, 1.1)
611
612
# Plot 4: Yield-per-recruit curve
613
ax4 = fig3.add_subplot(2, 3, 4)
614
ax4.plot(F_values, YPR, 'b-', linewidth=2.5)
615
ax4.scatter([F_max], [YPR[F_max_idx]], s=200, c='red', marker='*', zorder=5,
616
edgecolor='black', label=f'$F_{{max}}$ = {F_max:.3f}')
617
ax4.scatter([F_01], [YPR[F_01_idx]], s=150, c='orange', marker='o', zorder=5,
618
edgecolor='black', label=f'$F_{{0.1}}$ = {F_01:.3f}')
619
ax4.axvline(x=F_max, color='red', linestyle='--', linewidth=1.5, alpha=0.5)
620
ax4.axvline(x=F_01, color='orange', linestyle='--', linewidth=1.5, alpha=0.5)
621
ax4.axvline(x=F_40, color='green', linestyle='--', linewidth=1.5, alpha=0.5,
622
label=f'$F_{{40}}$ = {F_40:.3f}')
623
ax4.set_xlabel('Fishing Mortality (year$^{-1}$)', fontsize=11)
624
ax4.set_ylabel('Yield-per-Recruit (kg)', fontsize=11)
625
ax4.set_title('Yield-per-Recruit Analysis', fontsize=12, fontweight='bold')
626
ax4.legend(fontsize=9, loc='upper right')
627
ax4.grid(True, alpha=0.3)
628
629
# Plot 5: Spawning potential ratio
630
ax5 = fig3.add_subplot(2, 3, 5)
631
ax5.plot(F_values, SPR_values / SPR_unfished * 100, 'g-', linewidth=2.5)
632
ax5.axhline(y=40, color='red', linestyle='--', linewidth=2, alpha=0.7,
633
label='40% SPR reference')
634
ax5.axhline(y=20, color='orange', linestyle='--', linewidth=2, alpha=0.7,
635
label='20% SPR limit')
636
ax5.axvline(x=F_40, color='green', linestyle='--', linewidth=1.5, alpha=0.5)
637
ax5.fill_between(F_values, 0, SPR_values / SPR_unfished * 100,
638
where=(SPR_values / SPR_unfished * 100 < 20),
639
alpha=0.3, color='red', label='Overfished')
640
ax5.set_xlabel('Fishing Mortality (year$^{-1}$)', fontsize=11)
641
ax5.set_ylabel('Spawning Potential Ratio (\\%)', fontsize=11)
642
ax5.set_title('SPR vs Fishing Mortality', fontsize=12, fontweight='bold')
643
ax5.legend(fontsize=9)
644
ax5.grid(True, alpha=0.3)
645
ax5.set_xlim(0, 1.5)
646
647
# Plot 6: Cohort survival
648
ax6 = fig3.add_subplot(2, 3, 6)
649
F_test_values = [0, 0.2, 0.5, 1.0]
650
colors_cohort = plt.cm.plasma(np.linspace(0.2, 0.9, len(F_test_values)))
651
652
for i, F in enumerate(F_test_values):
653
survivors_cohort = np.zeros(len(ages))
654
survivors_cohort[0] = 1000 # cohort size
655
for age_idx in range(1, len(ages)):
656
F_age = F * selectivity[age_idx]
657
Z = M + F_age
658
survivors_cohort[age_idx] = survivors_cohort[age_idx - 1] * np.exp(-Z)
659
ax6.plot(ages, survivors_cohort, linewidth=2.5, color=colors_cohort[i],
660
label=f'F = {F:.2f}')
661
662
ax6.set_xlabel('Age (years)', fontsize=11)
663
ax6.set_ylabel('Cohort Survivors', fontsize=11)
664
ax6.set_title('Cohort Survival Curves', fontsize=12, fontweight='bold')
665
ax6.legend(fontsize=9)
666
ax6.grid(True, alpha=0.3)
667
ax6.set_yscale('log')
668
669
plt.tight_layout()
670
plt.savefig('fisheries_models_age_structured.pdf', dpi=150, bbox_inches='tight')
671
plt.close()
672
\end{pycode}
673
674
\begin{figure}[htbp]
675
\centering
676
\includegraphics[width=\textwidth]{fisheries_models_age_structured.pdf}
677
\caption{Age-structured fisheries analysis incorporating von Bertalanffy growth,
678
weight-at-age relationships, and logistic gear selectivity. Yield-per-recruit (YPR)
679
analysis identifies optimal fishing mortality at F\textsubscript{max} = \py{f"{F_max:.3f}"}
680
year\textsuperscript{-1}, though the more precautionary F\textsubscript{0.1} reference
681
point of \py{f"{F_01:.3f}"} is recommended to account for recruitment uncertainty.
682
Spawning potential ratio (SPR) analysis shows that F\textsubscript{40} = \py{f"{F_40:.3f}"}
683
maintains 40\% of unfished spawning biomass. Cohort survival curves demonstrate the
684
exponential decay of abundance with age under different fishing pressure levels, with
685
natural mortality M = \py{f"{M:.2f}"} year\textsuperscript{-1} representing baseline
686
mortality from predation, disease, and senescence.}
687
\label{fig:age_structured}
688
\end{figure}
689
690
Yield-per-recruit analysis demonstrates that fishing mortality of \py{f"{F_max:.3f}"}
691
year\textsuperscript{-1} maximizes catch per cohort, but the F\textsubscript{0.1}
692
reference point of \py{f"{F_01:.3f}"} provides a more sustainable target that maintains
693
spawning potential and accounts for recruitment variability in fluctuating environments.
694
695
\section{Results Summary}
696
697
\begin{pycode}
698
print(r"\begin{table}[htbp]")
699
print(r"\centering")
700
print(r"\caption{Key Fisheries Reference Points and Model Parameters}")
701
print(r"\begin{tabular}{llc}")
702
print(r"\toprule")
703
print(r"Model & Parameter & Value \\")
704
print(r"\midrule")
705
print(f"Schaefer & MSY & {MSY:.0f} tonnes/year \\\\")
706
print(f" & Biomass at MSY & {B_MSY:.0f} tonnes \\\\")
707
print(f" & Optimal effort & {E_MSY:.0f} boat-days/year \\\\")
708
print(f" & Fishing mortality at MSY & {q * E_MSY:.3f} year$^{{-1}}$ \\\\")
709
print(r"\midrule")
710
print(f"Stock-Recruitment & Beverton-Holt $\\alpha$ & {alpha_BH:.1f} recruits/tonne \\\\")
711
print(f" & Critical SSB threshold & {S_critical:.0f} tonnes \\\\")
712
print(f" & Ricker optimum SSB & {SSB_opt_Ricker:.0f} tonnes \\\\")
713
print(r"\midrule")
714
print(f"Age-Structured & $F_{{max}}$ & {F_max:.3f} year$^{{-1}}$ \\\\")
715
print(f" & $F_{{0.1}}$ & {F_01:.3f} year$^{{-1}}$ \\\\")
716
print(f" & $F_{{40\\%}}$ (SPR) & {F_40:.3f} year$^{{-1}}$ \\\\")
717
print(f" & Age at 50\\% selectivity & {age_50:.1f} years \\\\")
718
print(f" & Natural mortality & {M:.2f} year$^{{-1}}$ \\\\")
719
print(f" & Asymptotic length & {L_inf:.0f} cm \\\\")
720
print(r"\bottomrule")
721
print(r"\end{tabular}")
722
print(r"\label{tab:reference_points}")
723
print(r"\end{table}")
724
\end{pycode}
725
726
\section{Discussion and Management Implications}
727
728
\begin{remark}[Precautionary Approach]
729
Modern fisheries management adopts precautionary reference points that account for
730
scientific uncertainty. While F\textsubscript{max} maximizes yield-per-recruit, the
731
F\textsubscript{0.1} and F\textsubscript{40\%} reference points provide buffers against
732
recruitment failure and environmental variability. The comparison reveals that sustainable
733
fishing mortality should be approximately \py{f"{F_01:.3f}"} year\textsuperscript{-1},
734
substantially below levels that would maximize short-term catch.
735
\end{remark}
736
737
\begin{example}[Rebuilding Overfished Stocks]
738
For a stock depleted to 15\% of carrying capacity (below the overfished threshold of 20\%),
739
managers must reduce fishing effort from current levels to allow biomass recovery. Setting
740
effort below \py{f"{E_MSY/2:.0f}"} boat-days/year creates positive population growth,
741
enabling stock rebuilding to MSY biomass levels within 10-15 years depending on
742
recruitment strength.
743
\end{example}
744
745
\subsection{Climate Change Considerations}
746
747
Climate-driven changes in ocean temperature and productivity affect all model parameters.
748
Warming waters may increase growth rates (higher $r$ and $K$) for some species while
749
reducing carrying capacity for others. Stock-recruitment relationships become more
750
variable as environmental stochasticity increases, necessitating lower target fishing
751
mortality rates to maintain resilience.
752
753
\subsection{Ecosystem-Based Fisheries Management}
754
755
Single-species models provide essential guidance but ignore predator-prey interactions,
756
habitat degradation, and multispecies harvesting effects. Integrated ecosystem models
757
extending these frameworks account for trophic dynamics, making harvest recommendations
758
that sustain ecosystem function rather than maximizing yield from individual species.
759
760
\section{Conclusions}
761
762
This comprehensive analysis of fisheries population models demonstrates:
763
764
\begin{enumerate}
765
\item The Schaefer surplus production model predicts maximum sustainable yield of
766
\py{f"{MSY:.0f}"} tonnes/year at optimal fishing effort of \py{f"{E_MSY:.0f}"}
767
boat-days/year, with equilibrium biomass at 50\% of carrying capacity
768
769
\item Stock-recruitment analysis reveals critical spawning biomass thresholds below which
770
recruitment fails, with the Allee effect creating a collapse threshold at
771
\py{f"{S_critical:.0f}"} tonnes for this stock
772
773
\item Yield-per-recruit analysis identifies F\textsubscript{0.1} = \py{f"{F_01:.3f}"}
774
year\textsuperscript{-1} as the precautionary fishing mortality target, maintaining
775
spawning potential while approaching maximum catch efficiency
776
777
\item Age-structured models incorporating growth, selectivity, and natural mortality
778
provide more realistic management advice than biomass-only models, particularly for
779
long-lived species with delayed maturity
780
\end{enumerate}
781
782
Sustainable fisheries management requires maintaining spawning stock above critical
783
thresholds, limiting fishing mortality to precautionary levels below F\textsubscript{MSY},
784
and adapting to environmental change through regular stock assessments. The models
785
presented here form the scientific foundation for Total Allowable Catch (TAC) limits,
786
effort restrictions, and rebuilding plans that sustain both fish populations and fishing
787
communities.
788
789
\section*{References}
790
791
\begin{itemize}
792
\item Schaefer, M. B. (1954). Some aspects of the dynamics of populations important to
793
the management of commercial marine fisheries. \textit{Bulletin of the Inter-American
794
Tropical Tuna Commission}, 1(2), 27-56.
795
796
\item Beverton, R. J. H., \& Holt, S. J. (1957). \textit{On the Dynamics of Exploited
797
Fish Populations}. Chapman and Hall, London.
798
799
\item Ricker, W. E. (1954). Stock and recruitment. \textit{Journal of the Fisheries
800
Research Board of Canada}, 11(5), 559-623.
801
802
\item Hilborn, R., \& Walters, C. J. (1992). \textit{Quantitative Fisheries Stock
803
Assessment: Choice, Dynamics and Uncertainty}. Chapman and Hall, New York.
804
805
\item Quinn, T. J., \& Deriso, R. B. (1999). \textit{Quantitative Fish Dynamics}.
806
Oxford University Press, Oxford.
807
808
\item Fox, W. W. (1970). An exponential surplus-yield model for optimizing exploited
809
fish populations. \textit{Transactions of the American Fisheries Society}, 99(1), 80-88.
810
811
\item Clark, C. W. (1990). \textit{Mathematical Bioeconomics: The Optimal Management
812
of Renewable Resources}, 2nd ed. Wiley-Interscience, New York.
813
814
\item Haddon, M. (2011). \textit{Modelling and Quantitative Methods in Fisheries}, 2nd ed.
815
Chapman \& Hall/CRC Press, Boca Raton.
816
817
\item Walters, C., \& Martell, S. J. D. (2004). \textit{Fisheries Ecology and Management}.
818
Princeton University Press, Princeton.
819
820
\item Mace, P. M., \& Sissenwine, M. P. (1993). How much spawning per recruit is enough?
821
\textit{Canadian Special Publication of Fisheries and Aquatic Sciences}, 120, 101-118.
822
823
\item Punt, A. E., \& Smith, A. D. M. (1999). Harvest strategy evaluation for the
824
eastern stock of gemfish (\textit{Rexea solandri}). \textit{ICES Journal of Marine
825
Science}, 56(6), 860-875.
826
827
\item Goodyear, C. P. (1993). Spawning stock biomass per recruit in fisheries management:
828
foundation and current use. \textit{Canadian Special Publication of Fisheries and Aquatic
829
Sciences}, 120, 67-81.
830
831
\item Myers, R. A., Barrowman, N. J., Hutchings, J. A., \& Rosenberg, A. A. (1995).
832
Population dynamics of exploited fish stocks at low population levels. \textit{Science},
833
269(5227), 1106-1108.
834
835
\item Hilborn, R. (2007). Managing fisheries is managing people: what has been learned?
836
\textit{Fish and Fisheries}, 8(4), 285-296.
837
838
\item Pauly, D., Christensen, V., Guénette, S., et al. (2002). Towards sustainability
839
in world fisheries. \textit{Nature}, 418(6898), 689-695.
840
841
\item Worm, B., Hilborn, R., Baum, J. K., et al. (2009). Rebuilding global fisheries.
842
\textit{Science}, 325(5940), 578-585.
843
844
\item Costello, C., Ovando, D., Hilborn, R., et al. (2012). Status and solutions for
845
the world's unassessed fisheries. \textit{Science}, 338(6106), 517-520.
846
847
\item Thorson, J. T., Minto, C., Minte-Vera, C. V., Kleisner, K. M., \& Longo, C. (2013).
848
A new role for effort dynamics in the theory of harvested populations and data-poor stock
849
assessment. \textit{Canadian Journal of Fisheries and Aquatic Sciences}, 70(12), 1829-1844.
850
851
\item Free, C. M., Thorson, J. T., Pinsky, M. L., et al. (2019). Impacts of historical
852
warming on marine fisheries production. \textit{Science}, 363(6430), 979-983.
853
854
\item Froese, R., Winker, H., Coro, G., et al. (2018). Status and rebuilding of European
855
fisheries. \textit{Marine Policy}, 93, 159-170.
856
\end{itemize}
857
858
\end{document}
859
860