Skip to contents

CMSY++ (Froese et al. 2023), the successor of CMSY (Froese et al. 2017), estimates MSY, Bmsy and Fmsy, and the relative stock size (B/Bmsy) and exploitation (F/Fmsy) of every year, from a catch series, a prior for the intrinsic growth rate r and priors for the relative biomass B/k. The package bundles the official CMSY++ code (CMSY++16.R, January 2021), its neural network and its user guide (Froese et al. 2021), and a few functions take care of everything from installing JAGS (Plummer 2003) to drawing the charts. The CMSY++ runs shown in this article were made beforehand; building the article does not run CMSY++.

FishStat has catches only, no CPUE. The FAO capture statistics have no abundance index (CPUE or survey biomass), so every stock is assessed with the catch-only part of CMSY++ (CMSY, btype = "None") and the Bayesian Schaefer model (BSM) does not run. The results then depend mostly on the B/k priors, and independent tests found that catch-only methods classify stock status poorly with default priors (Free et al. 2020; Ovando et al. 2021; Kell et al. 2022). The results are indicative and do not replace stock assessments. As in FAO (2026), the status has two classes only: maximally sustainably fished (B/Bmsy at least 0.8 in the last year) or overfished (below 0.8); catch-only results do not make a stock “underfished”.

Disclaimer and source of CMSY++. CMSY++ was developed by Rainer Froese and colleagues (Froese et al. 2021, 2023). faofishingreport is not affiliated with or endorsed by the authors of CMSY++. The package bundles the authors’ unmodified March 2021 release (GEOMAR OceanRep, record 52147, CC BY 4.0), whose code is also published on GitHub at https://github.com/SISTA16/cmsyPlusPlus. cmsy_run() runs a copy of it with only the changes listed in code_changes.csv of each run folder (operating-system settings, no automatic package installation), which leave the method unchanged. Questions on the method go to the authors of CMSY++; problems with how this package runs it go to the faofishingreport issues. Users are responsible for checking and interpreting the results.

⚙️ Common arguments

These arguments have the same meaning in all CMSY functions that have them; the tables of each function below list its other arguments.

Argument Meaning Default
stocks Stocks to use: Stock identifiers (e.g. "PRA_27") or species, by English or Chinese FAO name, scientific name or FAO 3-alpha code (all stocks of the species) NULL: all stocks
table Save the tables (in tables/cmsy/) TRUE
lang Language of the chart text, names and table columns: "en", "zh" or "both" NULL: the language of fao_settings() ("en" unless changed)
pptx Also save the charts as editable PowerPoint files (in figures/pptx/cmsy/) FALSE; fao_settings(pptx = TRUE) changes it for all functions
plot_show Also draw each chart in the plot window (e.g. the Plots pane of RStudio) as it is saved FALSE, or plot_show of fao_settings()
annotations Text added to the axis titles and labels: FALSE none, TRUE all, or any of "title", "subtitle", "caption", "legend" and "labels" (text inside the chart) FALSE; options(faofishingreport.cmsy_annotations = TRUE) changes it for the session
silent Print no progress bars and messages FALSE; fao_settings(silent = TRUE) changes it for the session
data_dir Folder where downloads are kept fao_data_dir()

🚀 One step: cmsy_area()

cmsy_setup()                                                     # once: JAGS and the R packages
area27 <- cmsy_area("Atlantic, Northeast", top = 10)

cmsy_area() does Steps 4 to 7 and Step 9 below in one call: it takes the top species with the largest catch of the last recent_years years of a fishing area (or the species given in species), prepares the input, runs CMSY++, draws all charts, projects the stocks and writes the tables, with a progress bar for each step. Main species that cannot be assessed (e.g. without an r prior) are listed with the reason. area can name several areas; each gets its own folder in out_dir, sorted into:

cmsy_areas/Atlantic__Eastern_Central/
├── input/      CMSY++ catch and ID files (catch.csv, id.csv), the stocks assessed (stocks.csv)
│               and the main species left out with the reason (excluded.csv)
├── runs/       CMSY++ output of each stock (JPEG charts, cmsy_output.csv, log.txt), the changed
│               code and the list of changes (code_changes.csv)
├── figures/    a folder of charts per stock and summary/ (figures_pptx/ with pptx = TRUE)
└── tables/     results.csv, series.csv, priors_table.csv, results_table.csv, forecast.csv,
                forecast_share.csv, settings_used.csv and sources.csv
Argument Meaning Default
area FAO major fishing area name(s), as in fishing_area_data() (e.g. "Atlantic, Eastern Central"), or FAO catch data such as fishing_area_data()$area_data required
top Number of species with the largest catch to assess 10
species Species to assess instead of the top ones: English or Chinese name, scientific name or FAO 3-alpha code NULL
recent_years Species are ranked by their mean catch over the last recent_years years of the data 10
out_dir Folder in which a folder per area is made "cmsy_areas"
auto_start Start a stock in the year suggested by CMSY++ when its start biomass is ambiguous (see Step 5) TRUE (FALSE in cmsy_run())
seed Random seed, so runs can be repeated with the same results 1
parallel Number of stocks run at the same time; each uses two more processes for its two MCMC chains NULL: half the processor cores
settings CMSY++ settings that replace its defaults (see The settings of CMSY++) list(): none
charts Charts to draw (see Step 6) all charts
classes Status classes: "fao" (two) or "palomares" (five) "fao"
forecast Also project the stocks under the default scenarios of cmsy_forecast() TRUE
annotations, lang, pptx, silent See Common arguments
... Further arguments of cmsy_input(), e.g. priors, default_resilience or min_years

cmsy_area() runs CMSY++ without the retrospective analysis, so its retrospective chart is skipped (see Step 5). It returns the result of cmsy_run() with input, forecast, tables and dir (the folder of the area); for several areas, a list of these named by area. On a Mac with Apple silicon, the ten main species of area 27 take about a minute from input to tables.

💻 Step 1: check the computer and adapt the settings

The CMSY++ code was written on Windows. Its user guide (step 12) tells Mac users to change every windows() to quartz() and antialias = "cleartype" to "default". The code tests for Windows with grepl("win", sysname), which is also true for macOS (“Darwin”), so on a Mac it calls windows() and stops. cmsy_system() finds the operating system, R version, processor, JAGS and R packages, and shows the settings cmsy_run() will use:

sys <- cmsy_system()
show_table(sys$changes)
change applies_to what
Package installation all Lines that install missing packages on every run are removed (cmsy_setup() installs them).
snpar all library(snpar) is removed and snpar::runs.test() is replaced by the same approximate runs test, reproduced from snpar 1.0 (Debin Qiu, GPL >= 2; archived on CRAN on 2022-05-10: https://cran.r-project.org/src/contrib/Archive/snpar/; source mirror: https://github.com/cran/snpar).
Working directory all setwd(rstudioapi::getActiveDocumentContext()$path) is removed, so RStudio is not needed; each stock runs in its own folder.
Settings all File names, the stock, the chart switches and the general settings (CMSY++ defaults unless changed with cmsy_run(settings = ), including the MCMC iterations of the JAGS call) are set by cmsy_run() after the original settings section.
Chart windows linux The test grepl(“win”, sysname), which is also true on macOS (“Darwin”), is replaced; windows(): changed to an off-screen device, so charts are drawn and saved without opening windows.
JPEG antialias linux antialias = “cleartype” (Windows only) is changed to “default” (user guide, step 12).
Results for charts all After the main analysis of a stock, its priors, the posterior draws of r, k and B/k, the yearly estimates with 95% limits and the last-year Kobe draws are saved to cmsy_extra.rds (retrospective runs to cmsy_retro.rds) for cmsy_plot(); no calculation is changed.

The changes are made to a copy of the code written into each run folder (CMSY++16_faofishingreport.R, with the list in code_changes.csv); the bundled original never changes. Charts are drawn on an off-screen device by default, which saves the JPEG files on every system without opening windows; device = "screen" uses the system’s own window instead (windows(), quartz() or x11()). If the detection is wrong, set the system:

cmsy_system(os = "windows")                       # settings used on Windows
options(faofishingreport.cmsy_os = "macos")       # for the whole session
Argument Meaning Default
os Operating system whose settings are used: "auto" (detect it), "windows", "macos" or "linux" "auto"
device Where CMSY++ draws its charts before saving them as JPEG files: "file" (an off-screen device that works on every system and in batch runs) or "screen" (the system’s own window) "file"
jags JAGS version to recommend: "recommended" (the newest JAGS 4 for this R version, which works with rjags from CRAN), "latest" (JAGS 5.0.0, which needs rjags 5 from SourceForge) or a version number such as "4.3.2" "recommended"
silent See Common arguments

It returns the system (os, os_detected, arch, r_version), the installed jags and rjags versions, the packages table, the recommended jags_installer and rjags_source, the chart device and antialias, and the changes made to the CMSY++ code.

🧰 Step 2: install JAGS and the R packages

cmsy_setup() asks before installing anything, then:

  1. installs the missing R packages from CRAN (R2jags, rjags, coda, gplots, mvtnorm, neuralnet, conicfit); snpar, archived on CRAN on 2022-05-10, is replaced by the same approximate runs test, reproduced from snpar 1.0 (Debin Qiu, GPL ≥ 2; CRAN archive, source mirror https://github.com/cran/snpar);
  2. downloads the JAGS installer for the system and R version from its pinned link, checks its size and MD5 checksum and opens it (.exe on Windows, .pkg on macOS; on Linux it downloads the source and shows the commands). JAGS is a separate program: restart R after installing it and run cmsy_setup() again to check;
  3. checks the bundled CMSY++ files.
Argument Meaning Default
jags JAGS version: "recommended", "latest" or a version number (as in cmsy_system()) "recommended"
os Operating system: "auto", "windows", "macos" or "linux" "auto"
ask Ask before installing anything; in a non-interactive session nothing is installed when ask is TRUE TRUE
data_dir, silent See Common arguments

It returns the result of cmsy_system() after the installation. JAGS 4.3.2 (4.3.1 for older R versions) is the default because rjags on CRAN (4-17) needs JAGS 4. The newest JAGS, 5.0.0, needs rjags 5-3 from SourceForge: cmsy_setup(jags = "latest"). Installers copied into inst/jags/ of the package source are used instead of downloading. Versions, links, sizes, checksums, licences and references of every component are listed by cmsy_sources():

src <- cmsy_sources()
show_table(src[, c("component", "version", "platform", "file", "license", "url")], n = 30)
component version platform file license url
CMSY++ code 16 (January 2021) all CMSY++16.R CC BY 4.0 https://oceanrep.geomar.de/id/eprint/52147/4/UserGuideCodeDataMarch2021.zip
CMSY++ neural network 16 (January 2021) all ffnn.bin CC BY 4.0 https://oceanrep.geomar.de/id/eprint/52147/4/UserGuideCodeDataMarch2021.zip
CMSY++ user guide March 2021 all CMSYUserGuideMarch2021.pdf CC BY 4.0 https://oceanrep.geomar.de/id/eprint/52147/4/UserGuideCodeDataMarch2021.zip
CMSY++ training data (catch) 9e all Train_Catch_9e.csv CC BY 4.0 https://oceanrep.geomar.de/id/eprint/52147/4/UserGuideCodeDataMarch2021.zip
CMSY++ training data (stocks) 9e all Train_ID_9e.csv CC BY 4.0 https://oceanrep.geomar.de/id/eprint/52147/4/UserGuideCodeDataMarch2021.zip
JAGS 4.3.2 windows JAGS-4.3.2.exe GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/JAGS/4.x/Windows/JAGS-4.3.2.exe
JAGS 4.3.1 windows JAGS-4.3.1.exe GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/JAGS/4.x/Windows/JAGS-4.3.1.exe
JAGS 4.3.2 macos JAGS-4.3.2.pkg GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/JAGS/4.x/Mac%20OS%20X/JAGS-4.3.2.pkg
JAGS 4.3.1 macos JAGS-4.3.1.pkg GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/JAGS/4.x/Mac%20OS%20X/JAGS-4.3.1.pkg
JAGS 4.3.2 source JAGS-4.3.2.tar.gz GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/JAGS/4.x/Source/JAGS-4.3.2.tar.gz
JAGS 5.0.0 windows JAGS-5.0.0.exe GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/JAGS/5.x/Windows/Rtools45/JAGS-5.0.0.exe
JAGS 5.0.0 macos JAGS-5.0.0-universal.pkg GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/JAGS/5.x/macOS/JAGS-5.0.0-universal.pkg
JAGS 5.0.0 source JAGS-5.0.0.tar.gz GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/JAGS/5.x/Source/JAGS-5.0.0.tar.gz
rjags 4-17 all rjags GPL-2 https://cran.r-project.org/package=rjags
rjags 5-3 windows rjags_5-3.zip GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/rjags/5/Windows/Rtools45/rjags_5-3.zip
rjags 5-3 macos-arm64 rjags_5-3-R4.6.1-arm64.tgz GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/rjags/5/macOS/rjags_5-3-R4.6.1-arm64.tgz
rjags 5-3 macos-x86_64 rjags_5-3-R4.6.1-x86_64.tgz GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/rjags/5/macOS/rjags_5-3-R4.6.1-x86_64.tgz
rjags 5-3 source rjags_5-3.tar.gz GPL-2 https://downloads.sourceforge.net/project/mcmc-jags/rjags/5/Source/rjags_5-3.tar.gz
snpar (runs test reproduced in cmsy_run()) 1.0 all snpar_1.0.tar.gz GPL (>= 2) https://cran.r-project.org/src/contrib/Archive/snpar/snpar_1.0.tar.gz
R2jags 0.8-9 all R2jags GPL (> 2) https://cran.r-project.org/package=R2jags
coda 0.19-4.1 all coda GPL (>= 2) https://cran.r-project.org/package=coda
gplots 3.3.0 all gplots GPL-2 https://cran.r-project.org/package=gplots
mvtnorm 1.4-2 all mvtnorm GPL-2 https://cran.r-project.org/package=mvtnorm
neuralnet 1.44.2 all neuralnet GPL (>= 2) https://cran.r-project.org/package=neuralnet
conicfit 1.0.4 all conicfit GPL (>= 3) https://cran.r-project.org/package=conicfit
FishBase 26.06 all species, synonyms, stocks, estimate CC BY-NC 4.0 (FishBase.org team, as stated for the snapshots) https://data.source.coop/cboettig/fishbase/fb/v26.06/parquet/
SeaLifeBase 26.06 all species, synonyms, stocks, estimate CC BY-NC 4.0 (FishBase.org team, as stated for the snapshots) https://data.source.coop/cboettig/fishbase/slb/v26.06/parquet/
Argument Meaning Default
component Text to keep only matching components, e.g. "JAGS" or "CMSY" NULL: all

The table also gives page, size, md5, sha256, released, requires and citation (the reference to cite) of each component.

The R version and the JAGS version must match

JAGS is a separate program that rjags uses for the MCMC. On Windows and macOS each JAGS installer is built for a range of R versions; with the wrong one rjags cannot be loaded and CMSY++ cannot run. rjags on CRAN (4-17) needs JAGS 4. The matches (JAGS 4 is the default):

System R version JAGS installer rjags
Windows 4.5, 4.6 JAGS-4.3.2.exe 4-17 (CRAN)
Windows 4.2 to 4.4 JAGS-4.3.1.exe 4-17 (CRAN)
macOS 4.3 and later JAGS-4.3.2.pkg 4-17 (CRAN)
macOS 4.2 JAGS-4.3.1.pkg 4-15 or later (the CRAN binary for R 4.2 stays at 4-15)
Linux any the system package (e.g. sudo apt-get install jags) or JAGS-4.3.2.tar.gz 4-17 (CRAN, built from source)
Windows 4.5, 4.6 JAGS-5.0.0.exe (optional, newest) 5-3 (SourceForge, not yet on CRAN)
macOS 4.3 and later JAGS-5.0.0-universal.pkg (optional) 5-3 (SourceForge: binary for R 4.6, else from source)

The rules come from the README of the JAGS downloads (e.g. the Windows build of JAGS 4.3.2 “was built with Rtools45 and is suitable for interfacing with R 4.5.x”; “JAGS-4.3.2.pkg for compatibility with R version 4.3.0 and later”; “JAGS-4.3.1.pkg for compatibility with R versions 4.0.x to 4.2.x”), and each combination is installed and run with CMSY++ by the package’s GitHub Actions workflow. cmsy_jags_versions() gives the table, marks the row for this computer and gives the evidence and README link of each rule:

jv <- cmsy_jags_versions()
show_table(jv[, c("system", "r_versions", "jags", "installer", "rjags", "default", "this_computer")], n = 10)
system r_versions jags installer rjags default this_computer
Windows 4.5 to 4.6.x 4.3.2 JAGS-4.3.2.exe 4-17 (CRAN) TRUE FALSE
Windows 4.2 to 4.4.x 4.3.1 JAGS-4.3.1.exe 4-17 (CRAN) TRUE FALSE
macOS >= 4.3 4.3.2 JAGS-4.3.2.pkg 4-17 (CRAN) TRUE FALSE
macOS 4.0 to 4.2.x 4.3.1 JAGS-4.3.1.pkg 4-15 or later (CRAN; its binary for R 4.2 is 4-15) TRUE FALSE
Linux >= 4.2 4.3.2 JAGS-4.3.2.tar.gz 4-17 (CRAN, built from source) TRUE TRUE
Windows 4.5 to 4.6.x 5.0.0 JAGS-5.0.0.exe 5-3 (SourceForge, Windows binary) FALSE FALSE
macOS >= 4.3 5.0.0 JAGS-5.0.0-universal.pkg 5-3 (SourceForge: binary for R 4.6, else source) FALSE FALSE
Linux >= 4.2 5.0.0 JAGS-5.0.0.tar.gz 5-3 (SourceForge, source) FALSE FALSE
Argument Meaning Default
os "all", or one system: "auto" (this computer), "windows", "macos" or "linux" "all"
r_version R version marked as this_computer getRversion(): the running R
silent Do not print the match for this computer see Common arguments

No need to look it up: cmsy_download_jags() picks the installer for the system, R version and processor, downloads it and checks its size, MD5 and SHA-256; for JAGS 5 it also downloads rjags 5-3. The files are kept in fao_data_dir()/cmsy/downloads, so they are downloaded only once. It can also download for other systems or R versions, e.g. to prepare installers for computers without internet. cmsy_install_jags() downloads the installer and opens it:

cmsy_download_jags()                                        # the JAGS for this computer
cmsy_download_jags(version = "latest")                      # JAGS 5.0.0 and rjags 5-3
cmsy_download_jags(os = "all", r_version = "4.4.1", dest = "jags_installers")   # all systems, R 4.4
cmsy_install_jags()                                         # download and open the installer

cmsy_download_jags():

Argument Meaning Default
version "recommended" (JAGS 4 for this R version), "latest" (JAGS 5.0.0 with rjags 5-3) or a JAGS version such as "4.3.1" "recommended"
os "auto" (this computer), "windows", "macos", "linux" or "all" (the installers of the three systems for r_version) "auto"
r_version R version the installer is for getRversion(): the running R
arch Processor, for the rjags 5 binary on macOS: "auto", "arm64" (Apple silicon) or "x86_64" (Intel) "auto"
dest Folder to copy the files to NULL: none
rjags Also download the rjags package needed by JAGS 5 (rjags 4-17 for JAGS 4 comes from CRAN through cmsy_setup()) TRUE
data_dir, silent See Common arguments

It returns a table with one row per file: system, R version, component, version, file, local path, link, SHA-256 and whether the checksums matched.

cmsy_install_jags():

Argument Meaning Default
version "recommended", "latest" or a version number "recommended"
os "auto", "windows", "macos" or "linux" "auto"
open Open the installer (.exe on Windows, .pkg on macOS; on Linux the commands to install JAGS are shown) TRUE
data_dir, silent See Common arguments

It returns the path of the downloaded installer; an installer placed in inst/jags/ of the package source is used instead of downloading.

🐟 Step 3: priors for r from FishBase and SeaLifeBase

A built-in table gives the resilience and prior r of the 3,155 species-level items of the FAO capture statistics in FishBase or SeaLifeBase (release 26.06). It can be searched offline by English, Chinese or scientific name or by 3-alpha code, and every row links to its source page (open = TRUE opens the pages). How FishBase and SeaLifeBase data are obtained and matched to FAO names is explained in 🐠 FishBase and SeaLifeBase traits.

cod <- cmsy_priors("Gadus morhua")
show_table(cod[, c("species_name", "scientific_name", "SpecCode", "resilience", "prior_r",
                   "r_low", "r_high", "r_source", "url")])
species_name scientific_name SpecCode resilience prior_r r_low r_high r_source url
Atlantic cod Gadus morhua 69 Medium 0.51 0.34 0.76 FishBase prior r, 95% CL (Based on 66 full stock assessments.) https://www.fishbase.se/summary/69

The r range follows the CMSY++ user guide:

Case r range Source
The species has a prior r in FishBase or SeaLifeBase (“Estimates based on models”) The 95% confidence limits of the prior r User guide Table 1 (“alternatively and better”)
Only the resilience is known High 0.6–1.5; Medium 0.2–0.8; Low 0.05–0.5; Very low 0.015–0.1 User guide Table 2
Neither No default: the user gives it (e.g. r close to 2M or 2Fmsy) User guide Table 1

FAO names are matched as valid species names, then through each database’s own synonym table; ambiguous synonyms and genus or family items get no values. When FishBase lists several stocks of a species with different resilience, the species-wide value is used and the others are given in resilience_note.

priors <- cmsy_priors()
table(priors$match_type)
#> 
#> ambiguous synonym             exact     not a species         not found 
#>                 3              3071                 2                43 
#>           synonym 
#>                36
table(!is.na(priors$r_source))
#> 
#> FALSE  TRUE 
#>   462  2693

Species can be named by English or Chinese FAO name, both together (as shown with lang = "both"), scientific name or FAO 3-alpha code, in cmsy_priors(), cmsy_input(species = ), cmsy_run(stocks = ) and cmsy_plot(stocks = ): full names are matched first (ignoring case), then parts of names; if several species match, they are listed so a more precise name or code can be given. lang sets the language of the results; species_en and species_zh always give both names.

p <- cmsy_priors(c("COD", "Clupea harengus", "Atlantic mackerel", "小鳍鳕"), lang = "both")
show_table(p[, c("species_name", "scientific_name", "alpha3", "r_low", "r_high", "url", "data_url", "rule_url")])
species_name scientific_name alpha3 r_low r_high url data_url rule_url
大西洋鳕 Atlantic cod Gadus morhua COD 0.34 0.76 https://www.fishbase.se/summary/69 https://data.source.coop/cboettig/fishbase/fb/v26.06/parquet/estimate.parquet https://oceanrep.geomar.de/id/eprint/52147/
大西洋鲱 Atlantic herring Clupea harengus HER 0.29 0.65 https://www.fishbase.se/summary/24 https://data.source.coop/cboettig/fishbase/fb/v26.06/parquet/estimate.parquet https://oceanrep.geomar.de/id/eprint/52147/
大西洋鲭 Atlantic mackerel Scomber scombrus MAC 0.28 0.64 https://www.fishbase.se/summary/118 https://data.source.coop/cboettig/fishbase/fb/v26.06/parquet/estimate.parquet https://oceanrep.geomar.de/id/eprint/52147/
小鳍鳕 Blue whiting(=Poutassou) Micromesistius poutassou WHB 0.31 0.70 https://www.fishbase.se/summary/31 https://data.source.coop/cboettig/fishbase/fb/v26.06/parquet/estimate.parquet https://oceanrep.geomar.de/id/eprint/52147/
Argument Meaning Default
species Names to search for: English, Chinese or scientific names, FAO 3-alpha codes, or parts of them (e.g. "Atlantic cod", "Gadus morhua", "COD", "cod") NULL: all rows
open Open the FishBase or SeaLifeBase pages of the rows found (at most 10) in the browser FALSE
lang Language of the species_name column: "en", "zh" or "both" NULL: the language of fao_settings()

Every row links to its sources: url, the FishBase or SeaLifeBase page of the species (where resilience and prior r can be checked); data_url, the FishBase or SeaLifeBase table the value was read from (estimate for prior r, stocks for resilience); and rule_url, the CMSY++ user guide, whose Tables 1 and 2 turn the values into the r range. The results of cmsy_input() and cmsy_run() add fao_data_url, the FAO data release used.

🧾 Step 4: FAO data to CMSY++ input files

input <- cmsy_input(FAO27$area_data)
input
#> CMSY++ input from FAO capture 2026.1.0: 220 stocks ready, 534 left out
#>   Stock                  species_en                area first_year last_year
#>  HER_27            Atlantic herring Atlantic, Northeast       1950      2024
#>  COD_27                Atlantic cod Atlantic, Northeast       1950      2024
#>  CAP_27                     Capelin Atlantic, Northeast       1950      2024
#>  WHB_27    Blue whiting(=Poutassou) Atlantic, Northeast       1950      2024
#>  MAC_27           Atlantic mackerel Atlantic, Northeast       1950      2024
#>  SPR_27              European sprat Atlantic, Northeast       1950      2024
#>  POK_27            Saithe(=Pollock) Atlantic, Northeast       1950      2024
#>  HAD_27                     Haddock Atlantic, Northeast       1950      2024
#>  NOP_27                 Norway pout Atlantic, Northeast       1959      2024
#>  PIL_27 European pilchard(=Sardine) Atlantic, Northeast       1950      2024
#>  Resilience r.low  r.hi
#>      Medium 0.288 0.654
#>      Medium 0.336 0.764
#>      Medium 0.412 0.937
#>      Medium 0.307 0.698
#>      Medium 0.283 0.644
#>      Medium 0.318 0.722
#>      Medium 0.344 0.781
#>      Medium 0.328 0.746
#>      Medium 0.329 0.747
#>      Medium 0.415 0.942

cmsy_input() makes the two input tables of CMSY++: the catch file (Stock, yr, ct, bt) and the ID file (one row per stock, with its priors and settings). It also returns the table of stocks (stocks) and of stocks left out with the reason (excluded), and with table = TRUE saves the four tables in tables/cmsy/ (<area>_cmsy_catch.csv, ..._id.csv, ..._stocks.csv and ..._excluded.csv). Following the user guide:

  • Stock: the catch of one species item in one fishing area summed over countries (by = "area"); by = "country" keeps countries apart. Only items identified to species and measured in tonnes are used.
  • Years: years are consecutive. A stock runs from its first to its last year with catch, and missing or zero years in between are interpolated (and counted in filled_years).
  • Left out: stocks with fewer than min_years years (CMSY++ uses the first and last ten years for its default priors), less than min_catch tonnes, more than max_filled years filled, or no r prior.
show_table(input$stocks[, c("Stock", "species_name", "first_year", "last_year", "filled_years",
                            "Resilience", "r.low", "r.hi", "r_source")])
Stock species_name first_year last_year filled_years Resilience r.low r.hi r_source
HER_27 Atlantic herring 1950 2024 0 Medium 0.29 0.65 FishBase prior r, 95% CL (Based on 53 full stock assessments.)
COD_27 Atlantic cod 1950 2024 0 Medium 0.34 0.76 FishBase prior r, 95% CL (Based on 66 full stock assessments.)
CAP_27 Capelin 1950 2024 0 Medium 0.41 0.94 FishBase prior r, 95% CL (Based on 5 full stock assessments.)
WHB_27 Blue whiting(=Poutassou) 1950 2024 0 Medium 0.31 0.70 FishBase prior r, 95% CL (Based on 9 full stock assessments.)
MAC_27 Atlantic mackerel 1950 2024 0 Medium 0.28 0.64 FishBase prior r, 95% CL (Based on 10 full stock assessments.)
SPR_27 European sprat 1950 2024 0 Medium 0.32 0.72 FishBase prior r, 95% CL (Based on 17 full stock assessments.)
POK_27 Saithe(=Pollock) 1950 2024 0 Medium 0.34 0.78 FishBase prior r, 95% CL (Based on 21 full stock assessments.)
HAD_27 Haddock 1950 2024 0 Medium 0.33 0.75 FishBase prior r, 95% CL (Based on 41 full stock assessments.)
NOP_27 Norway pout 1959 2024 0 Medium 0.33 0.75 FishBase prior r, 95% CL (Based on 3 full stock assessments.)
PIL_27 European pilchard(=Sardine) 1950 2024 0 Medium 0.42 0.94 FishBase prior r, 95% CL (Based on 26 full stock assessments.)
table(input$excluded$reason)
#> 
#>                                                       fewer than 10 years 
#>                                                                        10 
#>                                             more than 20% of years filled 
#>                                                                        20 
#> no resilience or r prior: give it in `priors` or set `default_resilience` 
#>                                                                        22 
#>                                                  total catch below 1000 t 
#>                                                                       482

Expert priors replace the defaults, e.g. a B/k prior for the last year as in Table 3 of the user guide, or a resilience for species without a FishBase value:

input <- cmsy_input(FAO27$area_data, priors = data.frame(
  alpha3   = c("HER", "MAC"),
  endb.low = c(0.2, 0.01),
  endb.hi  = c(0.6, 0.4)
))
input <- cmsy_input(FAO27$area_data, default_resilience = "Medium")  # stocks without a FishBase value
Argument Meaning Default
area_data FAO catch data: fishing_area_data()$area_data, or any subset of load_fao_data() required
species Species to keep: English or Chinese FAO name, both together, scientific name or FAO 3-alpha code NULL: all species
by "area": one stock per species item and fishing area, summed over countries; "country": one stock per species item, area and country "area"
priors Data frame of priors and settings that replace the defaults, one row per stock or species, identified by a Stock, alpha3, species_en or species column, with any of the ID file columns Resilience, r.low, r.hi, stb.low, stb.hi, int.yr, intb.low, intb.hi, endb.low, endb.hi, StartYear, EndYear and Comment (recorded as “user”) NULL
default_resilience Resilience ("High", "Medium", "Low" or "Very low") for stocks whose species has no resilience or prior r NULL: such stocks are left out, since the user guide gives no default
min_years Minimum number of years from the first to the last year with catch 10
min_catch Minimum total catch of a stock (tonnes) 1000
max_filled Maximum share of the years of a stock filled by interpolation 0.2
label Name at the start of the table file names NULL: the fishing area (or country) of the data
table, lang, silent See Common arguments

▶️ Step 5: run CMSY++

result <- cmsy_run(input, stocks = "Pandalus borealis", auto_start = TRUE, seed = 1,
                   plots = c("analysis", "management", "kobe", "prior_posterior", "retrospective"))
result$summary

Each stock runs in its own folder, cmsy/<area>_cmsy/<stock>/ (e.g. cmsy/Atlantic__Northeast_cmsy/PRA_27/), and R process; the folders keep CMSY++’s own output (_AN.jpg, _MAN.jpg, _KOBE.jpg, cmsy_output.csv, log.txt), and the folder of the run has the changed code, code_changes.csv, settings_used.csv and sources.csv. parallel sets how many stocks run at the same time, and a progress bar shows the stocks finished, the elapsed and the remaining time (see “Progress bars and silent” below).

Many FAO series start in 1950 with low catches, which CMSY++ flags as ambiguous (depleted or unexploited) and for which it suggests a start year: the first year with 40% of the maximum catch. auto_start = TRUE uses that year (CMSY++’s own auto.start stops with an error in CMSY++16.R, so the same rule is applied to the start year before the run, and not used if fewer than ten years would remain). The user guide prefers setting StartYear or the start B/k prior (stb.low, stb.hi) yourself in cmsy_input(priors = ).

Argument Meaning Default
input The result of cmsy_input() required
stocks Stocks to run (see Common arguments) NULL: all stocks of input
out_dir Folder for the CMSY++ output "cmsy" in the working directory
parallel Number of stocks run at the same time; each uses two more processes for its two MCMC chains NULL: half the processor cores
plots CMSY++ charts saved as JPEG files: any of "analysis", "management", "kobe", "prior_posterior" and "retrospective" (the last two are needed by the charts of the same name in Step 6) c("analysis", "management", "kobe")
os, device Operating system and chart device (as in cmsy_system()) "auto", "file"
seed Random seed, so runs can be repeated with the same results NULL
auto_start Start each stock in the year suggested by CMSY++ when its start biomass is ambiguous FALSE, as in CMSY++
settings CMSY++ settings that replace its defaults (see The settings of CMSY++) list(): none
timeout Maximum time for one stock (seconds); a stock still running after it is reported as failed 3600
table, lang, silent See Common arguments; the tables are tables/cmsy/<area>_cmsy_results.csv, ..._series.csv and ..._sources.csv

The example is the 30 stocks with the largest catch in 2015–2024 in FAO area 27 (Northeast Atlantic), run with the start years suggested by CMSY++ (p_green: probability of the green Kobe quadrant, B ≥ Bmsy and F ≤ Fmsy, in the last year):

top30 <- read.csv(file.path(fig_dir, "..", "top30_area27.csv"), check.names = FALSE)
top30$species <- fao_translate(top30$species_en, "species", getOption("faofishingreport.lang", "en"))
show_table(top30[, c("rank", "Stock", "species", "scientific_name", "first_year", "B_Bmsy", "F_Fmsy", "p_green", "status")],
           n = 30, digits = 2)
rank Stock species scientific_name first_year B_Bmsy F_Fmsy p_green status
1 HER_27 Atlantic herring Clupea harengus 1950 0.64 1.02 0.03 overfished
2 WHB_27 Blue whiting(=Poutassou) Micromesistius poutassou 1980 0.77 1.62 0.03 overfished
3 COD_27 Atlantic cod Gadus morhua 1950 0.67 0.83 0.03 overfished
4 MAC_27 Atlantic mackerel Scomber scombrus 1966 0.87 1.34 0.14 maximally sustainably fished
5 SPR_27 European sprat Sprattus sprattus 1972 0.66 1.02 0.03 overfished
6 POK_27 Saithe(=Pollock) Pollachius virens 1963 0.72 1.00 0.06 overfished
7 CAP_27 Capelin Mallotus villosus 1970 0.26 1.05 0.00 overfished
8 HAD_27 Haddock Melanogrammus aeglefinus 1955 0.71 1.09 0.05 overfished
9 HKE_27 European hake Merluccius merluccius 1950 0.73 0.84 0.09 overfished
10 HOM_27 Atlantic horse mackerel Trachurus trachurus 1971 0.27 0.99 0.00 overfished
11 PIL_27 European pilchard(=Sardine) Sardina pilchardus 1950 1.35 0.48 0.98 maximally sustainably fished
12 REB_27 Beaked redfish Sebastes mentella 2000 0.94 1.22 0.23 maximally sustainably fished
13 PLE_27 European plaice Pleuronectes platessa 1950 0.42 0.94 0.01 overfished
14 PRA_27 Northern prawn Pandalus borealis 1980 1.39 0.58 0.99 maximally sustainably fished
15 SCE_27 Great Atlantic scallop Pecten maximus 1973 1.05 1.11 0.36 maximally sustainably fished
16 NOP_27 Norway pout Trisopterus esmarkii 1968 0.20 0.51 0.00 overfished
17 REG_27 Golden redfish Sebastes norvegicus 1998 0.93 0.99 0.33 maximally sustainably fished
18 GHL_27 Greenland halibut Reinhardtius hippoglossoides 1965 1.28 0.60 0.94 maximally sustainably fished
19 NEP_27 Norway lobster Nephrops norvegicus 1966 0.98 0.92 0.42 maximally sustainably fished
20 VMA_27 Atlantic chub mackerel Scomber colias 2011 0.64 0.79 0.01 overfished
21 CRE_27 Edible crab Cancer pagurus 1970 0.81 1.06 0.17 maximally sustainably fished
22 LIN_27 Ling Molva molva 1950 0.92 0.82 0.36 maximally sustainably fished
23 ANE_27 European anchovy Engraulis encrasicolus 1950 0.64 1.03 0.01 overfished
24 WHE_27 Whelk Buccinum undatum 1996 0.92 0.94 0.32 maximally sustainably fished
25 MUS_27 Blue mussel Mytilus edulis 1978 0.29 0.89 0.00 overfished
26 WHG_27 Whiting Merlangius merlangus 1950 0.26 0.96 0.00 overfished
27 CSH_27 Common shrimp Crangon crangon 1950 0.57 0.73 0.02 overfished
28 MON_27 Angler(=Monk) Lophius piscatorius 1984 0.99 1.10 0.32 maximally sustainably fished
29 ALB_27 Albacore Thunnus alalunga 1950 0.67 0.93 0.02 overfished
30 COC_27 Common edible cockle Cerastoderma edule 1981 0.34 1.14 0.00 overfished
ex <- read.csv(file.path(fig_dir, "..", "example_values.csv"), check.names = FALSE)
green <- ex[ex$example == "green", ]
over <- ex[ex$example == "overfished", ]

Two stocks are shown in detail below: the healthiest and the most clearly overfished.

  • Healthy: northern prawn (Pandalus borealis, PRA_27, 14th by catch): last-year B/Bmsy 1.39 (95% CI 1.08–1.63), F/Fmsy 0.58, a 99% probability of the green quadrant.
  • Overfished: capelin (Mallotus villosus, CAP_27, 7th by catch): last-year B/Bmsy 0.26 (95% CI 0.10–0.54), F/Fmsy 1.05, a 100% probability that B/Bmsy is below 0.8 and 52% of the red quadrant.

Capelin is a short-lived fish whose stocks rise and fall with recruitment, and fisheries on it have been closed in some years; a catch-only model reads such falls in catch as falls in biomass. These are completed CMSY++ runs with the B/k priors of the neural network, not validated stock assessments; compare them with the assessments of ICES before using them.

Their priors and results tables, from cmsy_tables() (Step 9), northern prawn first:

show_table(read.csv(file.path(fig_dir, "green_priors_table.csv"), check.names = FALSE))
Stock Species Scientific name Years r prior Source of the r prior k prior (t) MSY prior (t) B/k prior, first year B/k prior, intermediate year B/k prior, last year FishBase / SeaLifeBase page
PRA_27 Northern prawn Pandalus borealis 1980-2024 0.408-0.927 SeaLifeBase prior r, 95% CL (Based on 7 full stock assessments.) 354,482-1,504,879 112,898 0.202-0.608 (neural network) 2013: 0.0857-0.361 (neural network) 0.466-0.837 (neural network) https://www.sealifebase.se/summary/25892
show_table(read.csv(file.path(fig_dir, "green_results_table.csv"), check.names = FALSE))
Stock Species r (95% CI) k (t, 95% CI) MSY (t, 95% CI) Fmsy (95% CI) Bmsy (t, 95% CI) Last-year B/Bmsy (95% CI) Last-year F/Fmsy (95% CI) P(green quadrant) P(red quadrant) Status (FAO) Status (Palomares et al. 2018)
PRA_27 Northern prawn 0.502 (0.356-0.615) 985,962 (786,871-1,437,661) 123,757 (110,512-143,108) 0.251 (0.178-0.308) 492,981 (393,435-718,830) 1.39 (1.08-1.63) 0.579 (0.395-0.866) 99% 0% Maximally sustainably fished Healthy
show_table(read.csv(file.path(fig_dir, "overfished_priors_table.csv"), check.names = FALSE))
Stock Species Scientific name Years r prior Source of the r prior k prior (t) MSY prior (t) B/k prior, first year B/k prior, intermediate year B/k prior, last year FishBase / SeaLifeBase page
CAP_27 Capelin Mallotus villosus 1970-2024 0.412-0.937 FishBase prior r, 95% CL (Based on 5 full stock assessments.) 7,217,484-30,658,265 2,322,843 0.156-0.509 (neural network) 2019: 0.0239-0.23 (neural network) 0.0372-0.258 (neural network) https://www.fishbase.se/summary/252
show_table(read.csv(file.path(fig_dir, "overfished_results_table.csv"), check.names = FALSE))
Stock Species r (95% CI) k (t, 95% CI) MSY (t, 95% CI) Fmsy (95% CI) Bmsy (t, 95% CI) Last-year B/Bmsy (95% CI) Last-year F/Fmsy (95% CI) P(green quadrant) P(red quadrant) Status (FAO) Status (Palomares et al. 2018)
CAP_27 Capelin 0.423 (0.31-0.517) 23,255,085 (18,563,960-35,085,235) 2,456,458 (2,070,092-3,026,716) 0.211 (0.155-0.258) 11,627,543 (9,281,980-17,542,618) 0.255 (0.0975-0.541) 1.05 (0.238-7.44) 0% 52% Overfished Grossly overfished

result$summary has one row per stock: MSY, Bmsy, Fmsy, r and k with their 95% limits, the last-year B/Bmsy, F/Fmsy and biomass with their limits, the probability of each Kobe quadrant and of B/Bmsy below 0.8 (p_overfished), the status in two schemes (status, FAO; status_palomares, Palomares et al. 2018), all priors with their sources and CMSY++’s own notes (such as suggested_start_year). result$series gives catch, predicted catch, B/k, biomass, B/Bmsy, F and F/Fmsy by year with 95% limits; result$kobe the last-year draws; result$details the posterior draws of r, k and B/k, the prior parameters and the retrospective runs; result$settings the CMSY++ settings used; result$changes the changes to the code; and result$sources the versions and links of CMSY++, JAGS, R, the R packages, the FAO data and FishBase used.

📊 Step 6: charts

cmsy_plot(result)

Based on a survey of the charts of 54 CMSY application papers, cmsy_plot() draws, for each stock, every chart of the CMSY++ user guide, and the usual summaries of several stocks, in figures/png/cmsy/<stock>/ and figures/png/cmsy/summary/ (and as PowerPoint with pptx = TRUE). It returns the ggplot objects.

By default only axis titles and labels are shown, so charts can take report captions of their own. Titles, subtitles, captions (method, data and prior sources), legends and text in the charts (quadrant probabilities, PPVR, Mohn’s rho) are switched on with annotations: TRUE for all, or e.g. c("title", "legend"); options(faofishingreport.cmsy_annotations = TRUE) changes the session default.

Chart Content
analysis The six panels of the CMSY++ analysis chart (user guide Figure 1): catch and MSY, explored r-k pairs with the prior box, viable r-k pairs, B/k with its three priors, F/Fmsy, equilibrium curve
catch, rk, biomass, b_bmsy, exploitation, equilibrium The same panels as single charts, and B/Bmsy (lines at Bmsy, 0.8 Bmsy, 0.5 Bmsy)
management The four management panels (Figure 2): catch and MSY, B/Bmsy, F/Fmsy, Kobe plot
kobe Kobe plot (Figure 3): path from the first (square) through the intermediate (circle) to the last year (triangle), 50/80/95% regions of the last-year draws, quadrant probabilities
prior_posterior Prior and posterior of r, k, MSY and B/k in three years, with PPVR (Figure 4)
retrospective B/Bmsy and F/Fmsy without the last 1–3 years, with Mohn’s rho (Mohn 1999; Figure 5; needs cmsy_run(plots = "retrospective"))
overview, kobe_all Last-year B/Bmsy of each stock with limits; Kobe plot of all stocks (sized by catch)
status, status_time, histogram Share of stocks and of catch by status, in the last year and every year; distribution of last-year B/Bmsy
b_bmsy_all, trend, aggregate Small multiples of B/Bmsy; median B/Bmsy and share below 0.8 Bmsy; total catch / total MSY and total biomass / total Bmsy
map Median last-year B/Bmsy by FAO fishing area
Argument Meaning Default
result The result of cmsy_run() required
stocks Stocks to draw (see Common arguments) NULL: all stocks that ran
charts Charts to draw (table above) all charts
classes Status classes: "fao" (two classes) or "palomares" (five classes) "fao"
annotations, lang, pptx, silent See Common arguments

Status follows FAO (2026) for Tier 3 (data-limited) assessments by default: maximally sustainably fished (B/Bmsy ≥ 0.8) or overfished. classes = "palomares" uses the five classes of Palomares et al. (2018), common in CMSY studies: healthy (≥ 1), slightly overfished (0.8–1), overfished (0.5–0.8), grossly overfished (0.2–0.5), collapsed (< 0.2).

The CMSY++ analysis chart (no annotations, the default), northern prawn and capelin:

green_analysis.png
overfished_analysis.png

Management charts:

green_management.png
overfished_management.png

Kobe plots with annotations = TRUE:

green_kobe.png
overfished_kobe.png

Prior and posterior distributions; the smaller the PPVR, the more the data added to the prior:

green_prior_posterior.png
overfished_prior_posterior.png

Retrospective analyses:

green_retrospective.png
overfished_retrospective.png

Summaries of the 30 stocks of area 27 (annotations = "legend"):

area27_overview.png
area27_kobe_all.png
area27_status_time.png
area27_map.png

🔁 MCMC: settings and convergence

mcmc <- cmsy_mcmc(result)
mcmc$settings        # chains, iterations, burn-in, thinning and draws kept of each stock
mcmc$diagnostics     # posterior summary, Rhat and effective sample size of each parameter
cmsy_mcmc(result, colors = c("grey30", "#D7191C"))   # other colours for the chains

CMSY++ samples the posterior with JAGS by Markov chain Monte Carlo (MCMC). cmsy_run() keeps the draws of each chain of r, k, B/k, B/Bmsy and F/Fmsy (MSY is computed from r and k, as in CMSY++16.R), and cmsy_mcmc() checks them. Rhat (Gelman and Rubin 1992) compares the variance between chains with the variance within them; at most 1.1 the chains are taken as converged (Gelman et al. 2013). The effective sample size (n_eff, computed with coda; Plummer et al. 2006) is the number of independent draws that the autocorrelated draws are worth; below 400 (Vehtari et al. 2021) the 95% limits are imprecise. Stocks that did not converge and stocks with too few effective draws are reported apart. The chart shows the draws of each chain in the order they were kept (trace: chains that mix well overlap with no trend) and their densities (which should agree).

The two example stocks, with the settings of CMSY++16.R (2 chains of 60,000 iterations, the first 30,000 discarded as burn-in, one draw in 10 kept) and with 4 chains of 300,000 iterations (150,000 burn-in, one draw in 50 kept; columns _long):

mc <- rbind(cbind(stock = "PRA_27", read.csv(file.path(fig_dir, "green_mcmc.csv"), check.names = FALSE)),
            cbind(stock = "CAP_27", read.csv(file.path(fig_dir, "overfished_mcmc.csv"), check.names = FALSE)))
mc <- mc[mc$parameter != "deviance", ]
rk <- mc[mc$parameter %in% c("r", "k", "msy"), ]
shown <- mc[, c("stock", "label", "median", "rhat", "n_eff", "median_long", "rhat_long", "n_eff_long")]
shown[c("median", "median_long")] <- lapply(shown[c("median", "median_long")], function(x)
  vapply(signif(x, 3), format, character(1), big.mark = ",", scientific = FALSE))
shown[c("rhat", "rhat_long")] <- lapply(shown[c("rhat", "rhat_long")], sprintf, fmt = "%.3f")
shown[c("n_eff", "n_eff_long")] <- lapply(shown[c("n_eff", "n_eff_long")], function(x) format(round(x), big.mark = ","))
show_table(data.frame(shown, row.names = NULL), n = 20, digits = 3)
stock label median rhat n_eff median_long rhat_long n_eff_long
PRA_27 Intrinsic growth rate r 0.459 1.003 183 0.468 1.001 1,471
PRA_27 Carrying capacity k (t) 1,070,000 1.002 164 1,050,000 1.001 1,254
PRA_27 MSY (t) 124,000 1.000 151 123,000 1.001 1,451
PRA_27 B/k in the first year 0.424 1.003 262 0.432 1.000 1,929
PRA_27 B/k in the last year 0.697 1.008 230 0.693 1.000 1,528
PRA_27 B/Bmsy in the last year 1.39 1.008 230 1.39 1.000 1,528
PRA_27 F/Fmsy in the last year 0.579 1.001 492 0.588 1.000 2,811
CAP_27 Intrinsic growth rate r 0.386 1.055 256 0.383 1.001 2,105
CAP_27 Carrying capacity k (t) 25,400,000 1.094 124 25,800,000 1.001 703
CAP_27 MSY (t) 2,460,000 1.034 80 2,480,000 1.000 524
CAP_27 B/k in the first year 0.331 1.034 216 0.326 1.000 867
CAP_27 B/k in the last year 0.128 1.018 142 0.13 1.007 1,437
CAP_27 B/Bmsy in the last year 0.255 1.018 142 0.259 1.007 1,437
CAP_27 F/Fmsy in the last year 1.05 1.082 262 1.03 1.022 1,926

With the default settings the chains converged (Rhat at most 1.09), but the effective sample size of r, k and MSY was only 80 to 256: successive draws of r and k are strongly correlated. With the longer chains it rose to 524 to 2105, while the medians hardly changed (last-year B/Bmsy of northern prawn 1.395 and 1.386, of capelin 0.255 and 0.259), and the runs took about five times as long (4 chains instead of 2 run side by side, but each five times longer). For results to report, run CMSY++ with longer and more chains and check them:

result <- cmsy_run(input, seed = 1, auto_start = TRUE,
                   settings = list(n.chains = 4, n.iter = 300000, n.burnin = 150000, n.thin = 50))
cmsy_mcmc(result)

Trace and density of each chain, northern prawn and capelin (default settings):

green_mcmc.png
overfished_mcmc.png
Argument Meaning Default
result The result of cmsy_run() or cmsy_area() required
stocks Stocks to check (see Common arguments) NULL: all stocks that ran
rhat_max Largest Rhat taken as converged 1.1
n_eff_min Smallest effective sample size (all chains together) taken as enough 400
plot, table Save the chart figures/png/cmsy/<stock>/mcmc.png and the tables tables/cmsy/mcmc_settings.csv and mcmc_diagnostics.csv TRUE
colors Colours of the chains: NULL (Okabe-Ito colours), a palette name (e.g. "npg", "Set1", "viridis") or one colour per chain NULL
lang, pptx, silent See Common arguments

The same chart is the "mcmc" chart of cmsy_plot() (colours with mcmc_colors). Results of earlier versions of the package have no draws: run CMSY++ again to check them. Converged chains do not mean that the priors or the model fit the stock.

🔮 Step 7: projections under fishing scenarios

projection <- cmsy_forecast(result, catch = 100000)

CMSY++16.R has no projection, so cmsy_forecast() projects with the CMSY++ model itself (Schaefer surplus production with productivity declining below 0.25 k), from the posterior draws of r, k and last-year B/k of the same MCMC iterations, with lognormal process error of standard deviation sigma (0.1 by default, the value CMSY++16.R gives to its setting sigmaR, which the model itself does not use: it estimates its process error). As in CMSY++, the biomass of a year is the biomass before that year’s catch, F is the catch divided by that biomass, and F/Fmsy uses an Fmsy reduced linearly below half of Bmsy. The last year of the data keeps its catch; from the first projected year on, the catch of an F scenario is the scenario F times the biomass of the same year, so F/Fmsy is the scenario value. The default scenarios are 0.5, 0.6, 0.8 and 0.95 Fmsy (as in Froese et al. 2018) and the last-year fishing mortality; constant catches can be added (catch). Stocks whose data end in different years are each projected from their own last year to the same final year.

Argument Meaning Default
result The result of cmsy_run() required
stocks Stocks to project (see Common arguments) NULL: all stocks that ran
years Number of years to project after the latest last year of the stocks 10
f Fishing mortality scenarios as multiples of Fmsy c(0.5, 0.6, 0.8, 0.95)
status_quo Also project the last-year fishing mortality TRUE
catch Constant catches to project (tonnes per year) NULL
sigma Standard deviation of the lognormal process error 0.1
seed Random seed NULL
plot Save the charts figures/png/cmsy/<stock>/forecast.png and figures/png/cmsy/summary/forecast_share.png TRUE
table Save tables/cmsy/forecast.csv and forecast_share.csv TRUE
lang, annotations, pptx, silent See Common arguments

It returns projection (by stock, scenario and year: median B/Bmsy, F/Fmsy and catch with 95% limits, and the probability that B is at least Bmsy) and share (by scenario and year: share of stocks at or above Bmsy, with 95% limits, and the number of stocks n_stocks; from the latest last year of the stocks on).

With constant catches near the MSY of each stock (100,000 t for northern prawn, 2,000,000 t for capelin) and the F scenarios:

green_forecast.png
overfished_forecast.png

🔍 Step 8: compare runs or other assessments

result_1950 <- cmsy_run(input, stocks = "PRA_27", seed = 1)        # starting in 1950
cmsy_compare(`1950` = result_1950, `CMSY++` = result, stocks = "PRA_27")

cmsy_compare() draws several runs (e.g. different start years or priors, a sensitivity analysis) and other estimates (external, e.g. B/Bmsy from ICES, JABBA or a paper) together and lists their last-year values. The start year matters. Started in 1950, northern prawn has a last-year B/Bmsy of 0.82, below Bmsy; started in 1980 as CMSY++ suggests, 1.39, above it. Capelin is overfished from either start year (0.25 from 1950, 0.26 from 1970):

green_compare.png
overfished_compare.png
Argument Meaning Default
... Results of cmsy_run(), named or not (e.g. default = run1, start_1980 = run2)
stocks Stocks to draw (see Common arguments) NULL: all stocks that ran
external Data frame of other estimates, with columns Stock, Year, B_Bmsy (optionally F_Fmsy) and source (the name shown in the legend) NULL
lang, annotations, pptx, silent See Common arguments

The charts are saved as figures/png/cmsy/compare/<stock>.png; the function returns last_year (one row per stock and run) and plots.

📋 Step 9: tables for reports

tables <- cmsy_tables(result)

cmsy_tables() makes the two tables of CMSY papers, the priors table and the results table shown in Step 5, rounded, with ranges as “low-high” and column names in the chosen language, saved as tables/cmsy/cmsy_priors_table.csv and cmsy_results_table.csv. The results give the status in the two classes of FAO (2026) and in the five classes of Palomares et al. (2018).

Argument Meaning Default
result The result of cmsy_run() required
stocks Stocks in the tables (see Common arguments) NULL: all stocks that ran
table, lang, silent See Common arguments

⚙️ The settings of CMSY++

CMSY++ has a set of general settings, such as the catch observation error CV.C and the number of MCMC chains and iterations. Two of them, sigmaR and ni, are set in CMSY++16.R but not used by its code (the model estimates its process error with the prior itau2 ~ dgamma(4, 0.01)): they are listed as “not used” and cannot be changed, so that a run is not mistaken for a sensitivity analysis of the process error. cmsy_run() keeps the CMSY++ values unless they are changed; cmsy_defaults() lists each one with its CMSY++ default, the value used and what it does:

show_table(cmsy_defaults()[, c("setting", "cmsy_default", "applies_to", "description")], n = 30)
setting cmsy_default applies_to description
CV.C 0.15 all Coefficient of variation of the catch (observation error)
CV.cpue 0.2 BSM Minimum realistic coefficient of variation of CPUE
sigmaR 0.1 not used Not used by CMSY++16.R: the code sets it (sigR <- sigmaR) but never uses it; the model estimates its process error with the prior itau2 ~ dgamma(4, 0.01). It cannot be changed
cor.log.rk -0.76 charts Correlation of log r and log k, used only in charts
rk.cor.beta 2.52, 3.37 all Beta prior of the r-k correlation plus 1
nbk 3 BSM Number of B/k priors used by BSM: 1 (first year), 2 (and intermediate year), 3 (and last year)
bt4pr FALSE BSM Use the abundance data to set the B/k priors
ct_MSY.lim 1.21 all Ratio of catch to the MSY prior above which the B/k prior is kept constant
q.biomass.pr 0.9, 1.1 BSM Prior range of q when the abundance data are biomass
n 5000 charts Number of points of the r-k cloud in the analysis chart
ni 3 not used Not used by CMSY++16.R: the code sets it but never uses it. It cannot be changed
nab 3 BSM Minimum number of years with abundance data to run BSM
bw 3 all Bandwidth of ksmooth() for smoothing the catch
e.creep.line TRUE charts Show the CPUE not corrected for effort creep in the biomass chart
select.yr NA output Year for which B, F, B/Bmsy and F/Fmsy are also reported (NA: none)
n.chains 2 all Number of MCMC chains (JAGS)
n.iter 60000 all Number of MCMC iterations per chain (JAGS)
n.burnin 30000 all Number of burn-in iterations (JAGS)
n.thin 10 all Thinning of the MCMC chains (JAGS)

Settings marked “BSM” only matter with abundance data (CPUE or biomass); with FAO catch data only those marked “all” affect the results. To change some, give only those in settings; the others keep their CMSY++ values, and every value is checked (name, range, enough MCMC draws):

cmsy_defaults(list(CV.C = 0.2, n.iter = 100000, n.burnin = 50000))[c(1, 17, 18), c("setting", "cmsy_default", "used", "changed")]
#>     setting cmsy_default   used changed
#> 1      CV.C         0.15    0.2    TRUE
#> 17   n.iter        60000 100000    TRUE
#> 18 n.burnin        30000  50000    TRUE
result <- cmsy_run(input, stocks = "PRA_27", seed = 1, auto_start = TRUE,
                   settings = list(CV.C = 0.2, n.iter = 100000, n.burnin = 50000))
result$settings[result$settings$changed, ]          # the changed settings
Argument Meaning Default
settings Named list of changed settings, e.g. list(CV.C = 0.2), shown next to the defaults and checked list()
lang Language of the description column: "en", "zh" or "both" NULL: the language of fao_settings()

The settings used are saved in settings_used.csv of the run folder and recorded in result$settings and result$sources. The chart and output switches of CMSY++ (mgraphs, kobe.plot, retros, …) are set by the plots argument of cmsy_run(), not in settings.

🖥️ Windows, macOS and Linux

The same code runs on all three systems: cmsy_system() detects the system and makes the changes it needs (on macOS, no windows() and no antialias = "cleartype"; see Step 1), and the JAGS installer is chosen for the system and R version. Each change to the CMSY code is checked by the GitHub Actions workflow “CMSY-cross-platform” on Windows, macOS and Linux: it downloads and installs the matching JAGS with cmsy_download_jags(), runs CMSY++ for real, runs all CMSY tests and keeps the output of each system.

Results of the check in October 2026, made on two stocks of area 34, the example area of this article at the time (all 170 tests pass for each combination; same seed; cmsy_area() on bigeye grunt GRB_34 and sardine PIL_34):

System R JAGS rjags GRB_34 B/Bmsy GRB_34 F/Fmsy PIL_34 B/Bmsy PIL_34 F/Fmsy
Windows 4.6.1 4.3.2 4-17 1.422 0.639 0.706 1.391
Windows 4.4.3 4.3.1 4-17 1.422 0.639 0.706 1.391
Windows 4.3.3 4.3.1 4-17 1.422 0.639 0.706 1.391
Windows 4.2.3 4.3.1 4-17 1.422 0.639 0.706 1.391
macOS (Apple silicon) 4.6.1 4.3.2 4-17 1.422 0.639 0.706 1.391
Ubuntu 4.6.1 4.3.2 (apt) 4-17 1.422 0.639 0.706 1.391
macOS (Apple silicon) 4.2.3 4.3.1 4-15 1.366 0.663 0.745 1.306
Windows 4.6.1 5.0.0 5-3 1.392 0.672 0.740 1.317
macOS (Apple silicon) 4.6.1 5.0.0 5-3 1.392 0.672 0.740 1.317

With the same JAGS 4.3.x and rjags 4-17, the results are identical on all three systems. JAGS 5 or an older rjags draws different MCMC samples, so the numbers differ slightly (B/Bmsy of GRB_34 from 1.37 to 1.42, all inside its 95% interval 1.08–1.65), but the status of both stocks is the same: GRB_34 maximally sustainably fished, PIL_34 overfished. To repeat a result exactly, use the same JAGS and rjags versions; they are recorded in result$sources and tables/sources.csv.

⏱️ Progress bars and silent

cmsy_run(), cmsy_plot(), cmsy_forecast() and cmsy_area() show progress bars such as

CMSY++ [==================            ] 18/30 ( 60%) 00:51 elapsed, 00:34 left COD_27

All CMSY functions that print have a silent argument: with silent = TRUE they print no progress bars or messages (cmsy_setup() still asks before installing). fao_settings(silent = TRUE) sets the session default.

📝 In the Word report

fao_report() assesses the main species of the area with CMSY++ when cmsy = TRUE (see 📝 Assessment report: Word, LaTeX and PDF), and adds a part on the assessment with the results of every species and appendix tables of the reference points, the priors and their sources. It runs cmsy_area() on the top_n main species of the report (10 by default), without projections. The settings of cmsy_area() and cmsy_input() are given with the prefix cmsy_, e.g. cmsy_top = 5, cmsy_default_resilience = "Medium" or cmsy_settings = list(n.iter = 100000). All CMSY++ results (runs, charts and tables) are kept in the folder cmsy/ next to the report, with cmsy_result.rds, so the report can be written again without running CMSY++: cmsy = readRDS("cmsy/<area>/cmsy_result.rds"), with the path from the working directory (by default reports/cmsy/<area>/cmsy_result.rds). The result of an earlier cmsy_area() run can be given in the same way.

report <- fao_report(27, cmsy = TRUE, cmsy_top = 5)
report$cmsy_reference_points                  # r, k, MSY, B/Bmsy, ... with 95% limits
fao_report(27, cmsy = readRDS("reports/cmsy/Atlantic__Northeast/cmsy_result.rds"))

📖 References

Boettiger, C., Lang, D.T. and Wainwright, P.C. (2012). rfishbase: exploring, manipulating and visualizing FishBase data from R. Journal of Fish Biology 81(6): 2030–2039. doi:10.1111/j.1095-8649.2012.03464.x. Source code: https://github.com/ropensci/rfishbase

FAO (2026). Global Capture Production 1950–2024, release 2026.1.0. In: Fisheries and Aquaculture. Rome: FAO. https://www.fao.org/fishery/collection/capture/en. Licence: CC BY 4.0. Release file: https://www.fao.org/fishery/static/Data/Capture_2026.1.0.zip

FAO (2026). The State of World Fisheries and Aquaculture 2026 – Blue Transformation: turning vision into impact. Rome: FAO. doi:10.4060/cd8357en. Section “The status of fishery resources”, Box 1.3 (assessment tiers and status classes): https://openknowledge.fao.org/server/api/core/bitstreams/09d03e2f-7097-4d59-bf94-db65e95f44fd/content/sofia-2026/the-status-fishery-resources.html

Free, C.M., Jensen, O.P., Anderson, S.C., Gutierrez, N.L., Kleisner, K.M., Longo, C., Minto, C., Osio, G.C. and Walsh, J.C. (2020). Blood from a stone: performance of catch-only methods in estimating stock biomass status. Fisheries Research 223: 105452. doi:10.1016/j.fishres.2019.105452

Froese, R., Demirel, N., Coro, G., Kleisner, K.M. and Winker, H. (2017). Estimating fisheries reference points from catch and resilience. Fish and Fisheries 18: 506–526. doi:10.1111/faf.12190

Froese, R., Demirel, N., Coro, G. and Winker, H. (2021). User Guide for CMSY++. GEOMAR, Germany, 17 pp. https://oceanrep.geomar.de/id/eprint/52147/ (bundled with the package: system.file("cmsy", "CMSYUserGuideMarch2021.pdf", package = "faofishingreport"))

Froese, R. and Pauly, D. (Eds.) (2026). FishBase. World Wide Web electronic publication. Version (06/2026). https://www.fishbase.se

Froese, R., Winker, H., Coro, G., Demirel, N., Tsikliras, A.C., Dimarchopoulou, D., Scarcella, G., Quaas, M. and Matz-Lück, N. (2018). Status and rebuilding of European fisheries. Marine Policy 93: 159–170. doi:10.1016/j.marpol.2018.04.018

Froese, R., Winker, H., Coro, G., Palomares, M.L.D., Tsikliras, A.C., Dimarchopoulou, D., Touloumis, K., Demirel, N., Vianna, G.M.S., Scarcella, G., Schijns, R., Liang, C. and Pauly, D. (2023). New developments in the analysis of catch time series as the basis for fish stock assessments: the CMSY++ method. Acta Ichthyologica et Piscatoria 53: 173–189. doi:10.3897/aiep.53.105910

Gelman, A., Carlin, J.B., Stern, H.S., Dunson, D.B., Vehtari, A. and Rubin, D.B. (2013). Bayesian Data Analysis, 3rd edition. Boca Raton: CRC Press. doi:10.1201/b16018

Gelman, A. and Rubin, D.B. (1992). Inference from iterative simulation using multiple sequences. Statistical Science 7(4): 457–472. doi:10.1214/ss/1177011136

Kell, L.T., Sharma, R. and Winker, H. (2022). Artefact and artifice: evaluation of the skill of catch-only methods for classifying stock status. Frontiers in Marine Science 9: 762203. doi:10.3389/fmars.2022.762203

Mohn, R. (1999). The retrospective problem in sequential population analysis: an investigation using cod fishery and simulated data. ICES Journal of Marine Science 56: 473–488. doi:10.1006/jmsc.1999.0481

Ovando, D., Hilborn, R., Monnahan, C., Rudd, M., Sharma, R., Thorson, J.T., Rousseau, Y. and Ye, Y. (2021). Improving estimates of the state of global fisheries depends on better data. Fish and Fisheries 22: 1377–1391. doi:10.1111/faf.12593

Palomares, M.L.D., Froese, R., Derrick, B., Nöel, S.-L., Tsui, G., Woroniak, J. and Pauly, D. (2018). A preliminary global assessment of the status of exploited marine fish and invertebrate populations. A report prepared by the Sea Around Us for OCEANA. University of British Columbia and GEOMAR. https://www.fishbase.de/rfroese/OceanaFinalReport_V7a.pdf

Palomares, M.L.D. and Pauly, D. (Eds.) (2026). SeaLifeBase. World Wide Web electronic publication. Version (06/2026). https://www.sealifebase.se

Plummer, M. (2003). JAGS: a program for analysis of Bayesian graphical models using Gibbs sampling. In: Proceedings of the 3rd International Workshop on Distributed Statistical Computing (DSC 2003), Vienna, 1–10. https://www.r-project.org/conferences/DSC-2003/Proceedings/Plummer.pdf; JAGS: https://mcmc-jags.sourceforge.io/

Plummer, M., Best, N., Cowles, K. and Vines, K. (2006). CODA: convergence diagnosis and output analysis for MCMC. R News 6(1): 7–11. https://journal.r-project.org/articles/RN-2006-002/

Plummer, M. (2025). rjags: Bayesian Graphical Models using MCMC. R package version 4-17. doi:10.32614/CRAN.package.rjags

Su, Y. and Yajima, M. (2024). R2jags: Using R to Run ‘JAGS’. R package version 0.8-9. doi:10.32614/CRAN.package.R2jags

Vehtari, A., Gelman, A., Simpson, D., Carpenter, B. and Bürkner, P.-C. (2021). Rank-normalization, folding, and localization: an improved Rhat for assessing convergence of MCMC. Bayesian Analysis 16(2): 667–718. doi:10.1214/20-BA1221