Scenario: You have been asked to provide a preliminary stock assessment for Western Hake, a demersal species exploited by bottom trawlers on the Western Coast. The only available data is a 40-year catch time series (1984–2023). There is no survey index, no age data, and no length data.
From FishBase, you know the species has “Medium” resilience.
Your task: estimate MSY, evaluate current stock status (B/BMSY, F/FMSY), and provide management advice using the CMSY catch-only method (Froese et al. 2017).
Data file needed:
catch_western_hake.csv
Install and load the required packages. The datalimited2
package implements CMSY and must be installed from GitHub.
if (!require("tidyverse")) install.packages("tidyverse")
if (!require("datalimited2")) {
if (!require("remotes")) install.packages("remotes")
remotes::install_github("cfree14/datalimited2")
}
library(tidyverse)
library(datalimited2)
theme_set(theme_minimal(base_size = 14) +
theme(panel.grid.minor = element_blank(),
plot.title = element_text(face = "bold")))
catch_data <- read.csv("catch_western_hake.csv")
glimpse(catch_data)
#> Rows: 40
#> Columns: 2
#> $ year <int> 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 199…
#> $ catch_tonnes <int> 19, 35, 46, 59, 71, 82, 88, 102, 105, 120, 130, 134, 143,…
Before any modelling, we should understand what the data looks like:
cat("Time series:", min(catch_data$year), "–", max(catch_data$year),
paste0("(", nrow(catch_data), " years)\n"))
#> Time series: 1984 – 2023 (40 years)
cat("Mean catch: ", round(mean(catch_data$catch_tonnes)), "tonnes\n")
#> Mean catch: 69 tonnes
cat("Max catch: ", round(max(catch_data$catch_tonnes)), "tonnes",
paste0("(", catch_data$year[which.max(catch_data$catch_tonnes)], ")\n"))
#> Max catch: 143 tonnes (1996)
cat("Recent catch:", round(tail(catch_data$catch_tonnes, 1)), "tonnes",
paste0("(", max(catch_data$year), ")\n"))
#> Recent catch: 26 tonnes (2023)
This is all the data we have:
ggplot(catch_data, aes(year, catch_tonnes)) +
geom_col(fill = "#1C7293", alpha = 0.8) +
labs(title = "Western Hake — Catch Time Series",
x = "Year", y = "Catch (tonnes)")
Western Hake catch time series. This is the only input to the CMSY model.
Q: Describe the catch trajectory in words. Can you identify distinct phases (development, peak, decline)?
Q: Does the shape of this catch history look “informative”? (Hint: a rise-then-fall pattern constrains what r and K can be. A flat catch would be consistent with many different stock dynamics.)
Q: Based on the catch pattern alone (no model), what would you guess about the current state of the stock?
The CMSY method (Froese et al. 2017) fits a Schaefer surplus production model using only catch data and a prior for the intrinsic growth rate r:
\[B_{t+1} = B_t + r \cdot B_t \left(1 - \frac{B_t}{K}\right) - C_t\]
It samples many (r, K) combinations, projects forward using observed catches, and filters out combinations that produce implausible biomass trajectories. The viable pairs define the posterior for reference points.
Resilience categories from FishBase map to r priors:
| Resilience | r prior range |
|---|---|
| High | 0.6 – 1.5 |
| Medium | 0.2 – 0.8 |
| Low | 0.05 – 0.5 |
| Very low | 0.015 – 0.1 |
We run CMSY with “Medium” resilience — the appropriate category for Western Hake:
cmsy_fit <- cmsy2(
year = catch_data$year,
catch = catch_data$catch_tonnes,
resilience = "Medium"
)
#> startbio= 0.2 0.6 default , intbio= 2019 0.01 0.4 default , endbio= 0.01 0.3 default
#> First Monte Carlo filtering of r-k space with 10000 points...
#>
#> Found 108 viable trajectories for 100 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.407 , 2.5 ]
#> Attempt 1 of 3 with 10000 additional points...
#>
#> Found altogether 396 viable trajectories for 345 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.312 , 2.47 ]
#> Attempt 2 of 3 with 20000 additional points...
#>
#> Found altogether 887 viable trajectories for 752 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.312 , 2.46 ]
#> Attempt 3 of 3 with 30000 additional points...
#>
#> Found altogether 1666 viable trajectories for 1377 r-k pairs
#> Final sampling in the tip area above r = 0.244 with 30000 additional points...
#>
#> Found altogether 1922 viable trajectories for 1614 r-k pairs
#> ---------------------------------------
#> Catch data used from years 1984 - 2023
#> Prior initial relative biomass = 0.2 - 0.6 default
#> Prior intermediate rel. biomass= 0.01 - 0.4 in year 2019 default
#> Prior final relative biomass = 0.01 - 0.3 default
#> Prior range for r = 0.2 - 0.8 default , prior range for k = 0.17 - 2.71
#>
#> Results of CMSY analysis
#> -------------------------
#> Altogether 1922 viable trajectories for 1614 r-k pairs were found
#> r = 0.423 , 95% CL = 0.296 - 0.605 , k = 0.87 , 95% CL = 0.645 - 1.17
#> MSY = 0.092 , 95% CL = 0.0816 - 0.104
#> Relative biomass in last year = 0.117 k, 2.5th perc = 0.0149 , 97.5th perc = 0.291
#> Exploitation F/(r/2) in last year = 1.2
#>
#> -------------------------------------------------------------
#> Fmsy = 0.212 , 95% CL = 0.148 - 0.303 (if B > 1/2 Bmsy then Fmsy = 0.5 r)
#> Fmsy = 0.0994 , 95% CL = 0.0695 - 0.142 (r and Fmsy are linearly reduced if B < 1/2 Bmsy)
#> MSY = 0.092 , 95% CL = 0.0816 - 0.104
#> Bmsy = 0.435 , 95% CL = 0.323 - 0.586
#> Biomass in last year = 0.102 , 2.5th perc = 0.0129 , 97.5 perc = 0.253
#> B/Bmsy in last year = 0.235 , 2.5th perc = 0.0297 , 97.5 perc = 0.582
#> Fishing mortality in last year = 0.255 , 2.5th perc = 0.103 , 97.5 perc = 2.01
#> Exploitation F/Fmsy = 2.56 , 2.5th perc = 1.03 , 97.5 perc = 20.2
ref_pts <- cmsy_fit$ref_pts
ref_ts <- cmsy_fit$ref_ts
r_est <- ref_pts$est[ref_pts$param == "r"]
K_est <- ref_pts$est[ref_pts$param == "k"]
MSY_est <- ref_pts$est[ref_pts$param == "msy"]
cat("Estimated r =", round(r_est, 3), "\n")
#> Estimated r = 0.423
cat("Estimated K =", round(K_est), "tonnes\n")
#> Estimated K = 870 tonnes
cat("Estimated MSY =", round(MSY_est, 1), "tonnes\n")
#> Estimated MSY = 92 tonnes
ref_pts %>% knitr::kable(digits = 3, caption = "CMSY reference point estimates with 95% confidence intervals.")
| param | est | lo | hi |
|---|---|---|---|
| r | 0.423 | 0.296 | 0.605 |
| k | 869.835 | 645.293 | 1172.510 |
| msy | 92.020 | 81.635 | 103.727 |
| fmsy | 0.212 | 0.148 | 0.303 |
| bmsy | 434.918 | 322.647 | 586.255 |
The datalimited2 package provides a built-in multi-panel
diagnostic:
plot_dlm(cmsy_fit)
CMSY diagnostic plot: catch, viable r-K pairs, B/Bmsy and F/Fmsy trajectories, and Kobe plot.
Q: Look at the B/BMSY panel. When did the stock drop below BMSY?
Q: Look at the F/FMSY panel. When was overfishing most severe?
Q: In the Kobe plot, which quadrant is the stock currently in? (Red = overfished + overfishing; Green = healthy)
ggplot(ref_ts, aes(year)) +
geom_ribbon(aes(ymin = bbmsy_lo, ymax = bbmsy_hi),
fill = "#1C7293", alpha = 0.2) +
geom_line(aes(y = bbmsy), colour = "#1C7293", linewidth = 1) +
geom_hline(yintercept = 1, linetype = "dashed", colour = "#E07A5F") +
annotate("text", x = min(ref_ts$year) + 1, y = 1.05,
label = "Bmsy", colour = "#E07A5F") +
labs(title = "Western Hake — Estimated B/Bmsy",
x = "Year", y = expression(B/B[MSY]))
Estimated B/Bmsy with 95% confidence interval. The dashed line marks B = Bmsy.
ggplot(ref_ts, aes(year)) +
geom_ribbon(aes(ymin = ffmsy_lo, ymax = ffmsy_hi),
fill = "#1C7293", alpha = 0.2) +
geom_line(aes(y = ffmsy), colour = "#1C7293", linewidth = 1) +
geom_hline(yintercept = 1, linetype = "dashed", colour = "#E07A5F") +
annotate("text", x = min(ref_ts$year) + 1, y = 1.05,
label = "Fmsy", colour = "#E07A5F") +
labs(title = "Western Hake — Estimated F/Fmsy",
x = "Year", y = expression(F/F[MSY]))
Estimated F/Fmsy with 95% confidence interval. The dashed line marks F = Fmsy.
final <- ref_ts %>% filter(year == max(year))
cat("Stock status in", max(ref_ts$year), ":\n\n")
#> Stock status in 2023 :
cat(" B/Bmsy =", round(final$bbmsy, 2),
paste0(" [95% CI: ", round(final$bbmsy_lo, 2), " – ", round(final$bbmsy_hi, 2), "]\n"))
#> B/Bmsy = 0.23 [95% CI: 0.03 – 0.58]
cat(" F/Fmsy =", round(final$ffmsy, 2),
paste0(" [95% CI: ", round(final$ffmsy_lo, 2), " – ", round(final$ffmsy_hi, 2), "]\n"))
#> F/Fmsy = 2.56 [95% CI: 1.03 – 20.25]
cat(" MSY =", round(MSY_est, 1), "tonnes",
paste0(" [95% CI: ", round(ref_pts$lo[ref_pts$param == "msy"], 1),
" – ", round(ref_pts$hi[ref_pts$param == "msy"], 1), "]\n"))
#> MSY = 92 tonnes [95% CI: 81.6 – 103.7]
if (final$bbmsy < 1 & final$ffmsy > 1) {
cat("→ OVERFISHED and OVERFISHING occurring (red Kobe quadrant)\n")
} else if (final$bbmsy < 1 & final$ffmsy <= 1) {
cat("→ OVERFISHED but overfishing not currently occurring\n")
} else if (final$bbmsy >= 1 & final$ffmsy > 1) {
cat("→ Not overfished but OVERFISHING occurring\n")
} else {
cat("→ Stock in GOOD condition (green Kobe quadrant)\n")
}
#> → OVERFISHED and OVERFISHING occurring (red Kobe quadrant)
Q: Based on CMSY, what catch level would you recommend for next year? Should it be above, at, or below MSY? Why?
Q: How confident are you in this advice? (hint: Look at the width of the 95% CIs for MSY and B/BMSY.
CMSY results depend heavily on the priors. A responsible assessment always tests: “How much do my results change if I change my assumptions?”
We re-run CMSY with different resilience assumptions:
cmsy_low <- cmsy2(year = catch_data$year, catch = catch_data$catch_tonnes,
resilience = "Low")
#> startbio= 0.2 0.6 default , intbio= 2019 0.01 0.4 default , endbio= 0.01 0.3 default
#> First Monte Carlo filtering of r-k space with 10000 points...
#>
#> Found 1982 viable trajectories for 1287 r-k pairs
#> Final sampling in the tip area above r = 0.0826 with 10000 additional points...
#>
#> Found altogether 3572 viable trajectories for 2486 r-k pairs
#> ---------------------------------------
#> Catch data used from years 1984 - 2023
#> Prior initial relative biomass = 0.2 - 0.6 default
#> Prior intermediate rel. biomass= 0.01 - 0.4 in year 2019 default
#> Prior final relative biomass = 0.01 - 0.3 default
#> Prior range for r = 0.05 - 0.5 default , prior range for k = 0.271 - 10.9
#>
#> Results of CMSY analysis
#> -------------------------
#> Altogether 3572 viable trajectories for 2486 r-k pairs were found
#> r = 0.219 , 95% CL = 0.123 - 0.388 , k = 1.58 , 95% CL = 0.827 - 3.04
#> MSY = 0.0867 , 95% CL = 0.0602 - 0.125
#> Relative biomass in last year = 0.117 k, 2.5th perc = 0.0143 , 97.5th perc = 0.289
#> Exploitation F/(r/2) in last year = 1.28
#>
#> -------------------------------------------------------------
#> Fmsy = 0.109 , 95% CL = 0.0617 - 0.194 (if B > 1/2 Bmsy then Fmsy = 0.5 r)
#> Fmsy = 0.0512 , 95% CL = 0.0289 - 0.0907 (r and Fmsy are linearly reduced if B < 1/2 Bmsy)
#> MSY = 0.0867 , 95% CL = 0.0602 - 0.125
#> Bmsy = 0.792 , 95% CL = 0.413 - 1.52
#> Biomass in last year = 0.185 , 2.5th perc = 0.0227 , 97.5 perc = 0.459
#> B/Bmsy in last year = 0.234 , 2.5th perc = 0.0287 , 97.5 perc = 0.579
#> Fishing mortality in last year = 0.14 , 2.5th perc = 0.0567 , 97.5 perc = 1.14
#> Exploitation F/Fmsy = 2.74 , 2.5th perc = 1.11 , 97.5 perc = 22.4
cmsy_narrow <- cmsy2(year = catch_data$year, catch = catch_data$catch_tonnes,
r.low = 0.20, r.hi = 0.40)
#> startbio= 0.2 0.6 default , intbio= 2019 0.01 0.4 default , endbio= 0.01 0.3 default
#> First Monte Carlo filtering of r-k space with 10000 points...
#>
#> Found 237 viable trajectories for 222 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.544 , 2.59 ]
#> Attempt 1 of 3 with 10000 additional points...
#>
#> Found altogether 892 viable trajectories for 766 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.541 , 2.56 ]
#> Attempt 2 of 3 with 20000 additional points...
#>
#> Found altogether 2224 viable trajectories for 1869 r-k pairs
#> ---------------------------------------
#> Catch data used from years 1984 - 2023
#> Prior initial relative biomass = 0.2 - 0.6 default
#> Prior intermediate rel. biomass= 0.01 - 0.4 in year 2019 default
#> Prior final relative biomass = 0.01 - 0.3 default
#> Prior range for r = 0.2 - 0.4 expert, , prior range for k = 0.339 - 2.71
#>
#> Results of CMSY analysis
#> -------------------------
#> Altogether 2224 viable trajectories for 1869 r-k pairs were found
#> r = 0.331 , 95% CL = 0.278 - 0.394 , k = 1.07 , 95% CL = 0.845 - 1.36
#> MSY = 0.0889 , 95% CL = 0.0759 - 0.104
#> Relative biomass in last year = 0.115 k, 2.5th perc = 0.0159 , 97.5th perc = 0.29
#> Exploitation F/(r/2) in last year = 1.27
#>
#> -------------------------------------------------------------
#> Fmsy = 0.166 , 95% CL = 0.139 - 0.197 (if B > 1/2 Bmsy then Fmsy = 0.5 r)
#> Fmsy = 0.0765 , 95% CL = 0.0642 - 0.091 (r and Fmsy are linearly reduced if B < 1/2 Bmsy)
#> MSY = 0.0889 , 95% CL = 0.0759 - 0.104
#> Bmsy = 0.537 , 95% CL = 0.422 - 0.682
#> Biomass in last year = 0.124 , 2.5th perc = 0.0171 , 97.5 perc = 0.311
#> B/Bmsy in last year = 0.231 , 2.5th perc = 0.0318 , 97.5 perc = 0.58
#> Fishing mortality in last year = 0.21 , 2.5th perc = 0.0835 , 97.5 perc = 1.52
#> Exploitation F/Fmsy = 2.74 , 2.5th perc = 1.09 , 97.5 perc = 19.9
get_summary <- function(fit, label) {
rp <- fit$ref_pts
ts <- fit$ref_ts %>% filter(year == max(year))
tibble(
Scenario = label,
r_est = rp$est[rp$param == "r"],
K_est = rp$est[rp$param == "k"],
MSY_est = rp$est[rp$param == "msy"],
MSY_lo = rp$lo[rp$param == "msy"],
MSY_hi = rp$hi[rp$param == "msy"],
BBmsy_now = ts$bbmsy,
FFmsy_now = ts$ffmsy
)
}
sensitivity <- bind_rows(
get_summary(cmsy_fit, "Medium (baseline)"),
get_summary(cmsy_low, "Low resilience"),
get_summary(cmsy_narrow, "Manual r [0.2–0.4]")
)
sensitivity %>%
mutate(across(where(is.numeric), ~round(., 2))) %>%
knitr::kable(caption = "Sensitivity of CMSY results to the resilience prior.")
| Scenario | r_est | K_est | MSY_est | MSY_lo | MSY_hi | BBmsy_now | FFmsy_now |
|---|---|---|---|---|---|---|---|
| Medium (baseline) | 0.42 | 869.84 | 92.02 | 81.63 | 103.73 | 0.23 | 2.56 |
| Low resilience | 0.22 | 1584.92 | 86.66 | 60.24 | 124.67 | 0.23 | 2.74 |
| Manual r [0.2–0.4] | 0.33 | 1073.92 | 88.92 | 75.91 | 104.16 | 0.23 | 2.74 |
ggplot(sensitivity, aes(Scenario, MSY_est)) +
geom_col(fill = "#1C7293", alpha = 0.7, width = 0.6) +
geom_errorbar(aes(ymin = MSY_lo, ymax = MSY_hi), width = 0.2) +
labs(title = "MSY Sensitivity to Resilience Prior",
x = "", y = "MSY (tonnes)") +
theme(axis.text.x = element_text(angle = 20, hjust = 1))
MSY estimates under different resilience priors. Error bars show 95% CIs.
Q: Which prior gives the highest MSY? The lowest?
Q1: Does the management conclusion (overfished or not) change across scenarios? If all scenarios agree, does that increase your confidence?
The depletion prior at the end of the time series anchors the biomass reconstruction. We now will test two extremes:
cmsy_depleted <- cmsy2(year = catch_data$year, catch = catch_data$catch_tonnes,
resilience = "Medium",
endb.low = 0.01, endb.hi = 0.20)
#> startbio= 0.2 0.6 default , intbio= 2019 0.01 0.4 default , endbio= 0.01 0.2 expert
#> First Monte Carlo filtering of r-k space with 10000 points...
#>
#> Found 69 viable trajectories for 66 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.334 , 2.59 ]
#> Attempt 1 of 3 with 10000 additional points...
#>
#> Found altogether 256 viable trajectories for 229 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.334 , 2.53 ]
#> Attempt 2 of 3 with 20000 additional points...
#>
#> Found altogether 623 viable trajectories for 558 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.334 , 2.5 ]
#> Attempt 3 of 3 with 30000 additional points...
#>
#> Found altogether 1201 viable trajectories for 1070 r-k pairs
#> Final sampling in the tip area above r = 0.239 with 30000 additional points...
#>
#> Found altogether 1438 viable trajectories for 1300 r-k pairs
#> ---------------------------------------
#> Catch data used from years 1984 - 2023
#> Prior initial relative biomass = 0.2 - 0.6 default
#> Prior intermediate rel. biomass= 0.01 - 0.4 in year 2019 default
#> Prior final relative biomass = 0.01 - 0.2 expert
#> Prior range for r = 0.2 - 0.8 default , prior range for k = 0.17 - 2.71
#>
#> Results of CMSY analysis
#> -------------------------
#> Altogether 1438 viable trajectories for 1300 r-k pairs were found
#> r = 0.411 , 95% CL = 0.289 - 0.584 , k = 0.898 , 95% CL = 0.665 - 1.21
#> MSY = 0.0922 , 95% CL = 0.08 - 0.106
#> Relative biomass in last year = 0.0891 k, 2.5th perc = 0.0146 , 97.5th perc = 0.19
#> Exploitation F/(r/2) in last year = 1.58
#>
#> -------------------------------------------------------------
#> Fmsy = 0.205 , 95% CL = 0.144 - 0.292 (if B > 1/2 Bmsy then Fmsy = 0.5 r)
#> Fmsy = 0.0732 , 95% CL = 0.0515 - 0.104 (r and Fmsy are linearly reduced if B < 1/2 Bmsy)
#> MSY = 0.0922 , 95% CL = 0.08 - 0.106
#> Bmsy = 0.449 , 95% CL = 0.332 - 0.607
#> Biomass in last year = 0.0801 , 2.5th perc = 0.0131 , 97.5 perc = 0.17
#> B/Bmsy in last year = 0.178 , 2.5th perc = 0.0293 , 97.5 perc = 0.379
#> Fishing mortality in last year = 0.325 , 2.5th perc = 0.153 , 97.5 perc = 1.98
#> Exploitation F/Fmsy = 4.44 , 2.5th perc = 2.09 , 97.5 perc = 27
cmsy_healthy <- cmsy2(year = catch_data$year, catch = catch_data$catch_tonnes,
resilience = "Medium",
endb.low = 0.40, endb.hi = 0.80)
#> startbio= 0.2 0.6 default , intbio= 2019 0.01 0.4 default , endbio= 0.4 0.8 expert
#> First Monte Carlo filtering of r-k space with 10000 points...
#>
#> Found 106 viable trajectories for 95 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.486 , 4.21 ]
#> Attempt 1 of 3 with 10000 additional points...
#>
#> Found altogether 383 viable trajectories for 319 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.464 , 3.18 ]
#> Attempt 2 of 3 with 20000 additional points...
#>
#> Found altogether 993 viable trajectories for 816 r-k pairs
#> Shrinking k space: repeating Monte Carlo in the interval [ 0.421 , 2.77 ]
#> Attempt 3 of 3 with 30000 additional points...
#>
#> Found altogether 1943 viable trajectories for 1582 r-k pairs
#> Final sampling in the tip area above r = 0.251 with 30000 additional points...
#>
#> Found altogether 2238 viable trajectories for 1855 r-k pairs
#> ---------------------------------------
#> Catch data used from years 1984 - 2023
#> Prior initial relative biomass = 0.2 - 0.6 default
#> Prior intermediate rel. biomass= 0.01 - 0.4 in year 2019 default
#> Prior final relative biomass = 0.4 - 0.8 expert
#> Prior range for r = 0.2 - 0.8 default , prior range for k = 0.339 - 8.14
#>
#> Results of CMSY analysis
#> -------------------------
#> Altogether 2238 viable trajectories for 1855 r-k pairs were found
#> r = 0.445 , 95% CL = 0.278 - 0.711 , k = 0.836 , 95% CL = 0.611 - 1.14
#> MSY = 0.0929 , 95% CL = 0.0824 - 0.105
#> Relative biomass in last year = 0.533 k, 2.5th perc = 0.413 , 97.5th perc = 0.681
#> Exploitation F/(r/2) in last year = 0.262
#>
#> -------------------------------------------------------------
#> Fmsy = 0.222 , 95% CL = 0.139 - 0.356 (if B > 1/2 Bmsy then Fmsy = 0.5 r)
#> Fmsy = 0.222 , 95% CL = 0.139 - 0.356 (r and Fmsy are linearly reduced if B < 1/2 Bmsy)
#> MSY = 0.0929 , 95% CL = 0.0824 - 0.105
#> Bmsy = 0.418 , 95% CL = 0.305 - 0.572
#> Biomass in last year = 0.446 , 2.5th perc = 0.345 , 97.5 perc = 0.569
#> B/Bmsy in last year = 1.07 , 2.5th perc = 0.827 , 97.5 perc = 1.36
#> Fishing mortality in last year = 0.0584 , 2.5th perc = 0.0457 , 97.5 perc = 0.0753
#> Exploitation F/Fmsy = 0.262 , 2.5th perc = 0.206 , 97.5 perc = 0.338
depl_sens <- bind_rows(
get_summary(cmsy_fit, "Default depletion"),
get_summary(cmsy_depleted, "Assume very depleted"),
get_summary(cmsy_healthy, "Assume healthy")
)
depl_sens %>%
select(Scenario, MSY_est, BBmsy_now, FFmsy_now) %>%
mutate(across(where(is.numeric), ~round(., 2))) %>%
knitr::kable(caption = "Sensitivity to assumed final depletion level.")
| Scenario | MSY_est | BBmsy_now | FFmsy_now |
|---|---|---|---|
| Default depletion | 92.0 | 0.23 | 2.56 |
| Assume very depleted | 92.2 | 0.18 | 4.44 |
| Assume healthy | 93.0 | 1.07 | 0.26 |
Q: How much does the final depletion assumption change the stock status conclusion? Is this reassuring or concerning?
Q: In a real assessment, what information would help you set the final depletion prior? (Think: expert knowledge, CPUE trends, survey snapshots)
Exercise A — Management summary
Imagine you must brief a fisheries manager. Write a short paragraph (4–5 sentences) stating:
Exercise B — The “declining catch” trap
Your colleague looks at the catch data and says: “Catches have dropped 40% since the peak — clearly the stock is collapsing.”
Do you agree? What alternative explanation exists? (Hint: catch might reflects BOTH stock abundance AND management decisions.)
Exercise C — Time series length
Run CMSY on different windows of the data:
# First 15 years only
cmsy_early <- cmsy2(year = catch_data$year[1:15],
catch = catch_data$catch_tonnes[1:15],
resilience = "Medium")
# Last 15 years only
cmsy_late <- cmsy2(year = catch_data$year[26:40],
catch = catch_data$catch_tonnes[26:40],
resilience = "Medium")
How do results compare to the full 40 years? Which time window is most informative and why?
Exercise D (advanced) — Compare catch-only methods
The datalimited2 package includes several other
catch-only methods:
| Method | Function | Reference |
|---|---|---|
| CMSY | cmsy2() |
Froese et al. 2017 |
| Bayesian surplus production | bsm() |
Froese et al. 2017 |
| Boosted regression tree | zbrt() |
Zhou et al. 2017a |
| Optimized catch-only model | ocom() |
Zhou et al. 2017b |
| Refined ORCS | rorcs() |
Free et al. 2017 |
Try running one additional method and compare its B/BMSY estimate to CMSY. Do the methods agree?