---
title: "Setting up the logbook simulator: a user guide"
author: "Henning Winker
FAO Fisheries and Aquaculture Division, Assessment and Management Team (NFIFM)
henning.winker@fao.org"
output:
rmarkdown::html_document:
toc: true
toc_float: true
theme: readable
vignette: >
%\VignetteIndexEntry{Setting up the logbook simulator: a user guide}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r setup, include = FALSE}
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE,
fig.width = 8, fig.height = 4.5, dpi = 110,
eval = requireNamespace("cluster", quietly = TRUE))
library(cpueTargeting)
library(ggplot2)
```
`simulate_logbook()` generates the kind of logbook an analyst receives from a
mixed demersal-pelagic fishery, together with the truth that is never in a
real logbook: where and with which tactic each trip fished, which vessel type
made it, and how the stocks really changed. This guide walks through the
simulator layer by layer, explains the settings that matter for targeting,
and shows the basic mechanics: what the principal components (PCs) and
clusters of the catch composition pick up when we know the truth.
The standardisation of three species from this logbook is shown in
*Standardising a realistic logbook: two worked examples*.
| Layer | What it does | Main settings |
|---|---|---|
| Environment | shelf-to-slope depth, reef patches in sediment, SST gradient | `grid`, `shelf_depth`, `reef_share`, `reef_scale`, `sst_range` |
| Species | demersal: depth x substrate; pelagic: SST, depth and season | `species` (one row per species) |
| Tactics | gear catchability of each species | `tactics` (tactic x species) |
| Fleet | vessel types, home tactics and loyalty, entry and exit | `vessel_types`, `home`, `loyalty`, `entry_share`, `exit_share` |
| Behaviour | trips go where expected value is high | `price_periods`, `preference`, `closure` |
| Dynamics | Schaefer production, movement, monthly removals | `r`, `B0`, `B_start`, `dispersal` |
| Reporting | trip records, two-set trips, coarse positions, rounding, under-reporting, synonyms | `logbook` |
# 1. Settings
All settings are in one list. Change any element and pass the list to
`simulate_logbook()`; `species`, `tactics`, `price`, `trips`, `closure`,
`vessel_types`, `home` and `loyalty` are replaced as a whole, the others are
merged with the defaults.
```{r settings}
s <- logbook_settings()
names(s)
knitr::kable(s$species[, c("species", "group", "habitat", "depth_mu", "reef",
"sediment", "sst_mu", "season_amp", "price")],
row.names = FALSE)
```
```{r simulate}
sim <- simulate_logbook(s, seed = 1)
```
# 2. Environment
Depth increases offshore (to the right) with random bumps; reef patches are
the highest values of a smooth random field; sea temperature increases from
north (top, cool) to south (bottom, warm), as in the Southern Hemisphere.
```{r env, fig.height = 4}
sim$Plots$env
sim$Plots$sst
```
**Reef patches.** `reef_share` is the share of cells that are reef and
`reef_scale` the size (correlation length, in cells) of the patches.
* Lower `reef_share` or `reef_scale`: fewer or smaller, scattered patches.
When patches are smaller than the reporting blocks (`logbook$obs_res`,
5 x 5 cells), reef and sediment trips share the same reported position, so
a spatial term cannot separate them and only the catch composition can.
* Higher values: larger, connected reef areas that a spatial term on the
reported positions can resolve.
The default (`reef_scale = 2.5`) deliberately makes patches about the size
of a reporting block or smaller.
```{r reef-scale, fig.height = 3.6}
reef_maps <- do.call(rbind, lapply(c(1, 2.5, 6), function(sc) {
e <- simulate_logbook(modifyList(s, list(reef_scale = sc, n_years = 4)),
seed = 1, plots = FALSE)$env
data.frame(e, reef_scale = paste("reef_scale =", sc))
}))
ggplot(reef_maps, aes(x = x, y = y, fill = substrate)) +
geom_raster() + facet_wrap(~reef_scale) + coord_equal() +
geom_vline(xintercept = seq(0.5, 40.5, by = 5), colour = "white", linewidth = 0.2) +
geom_hline(yintercept = seq(0.5, 40.5, by = 5), colour = "white", linewidth = 0.2) +
scale_fill_manual(values = c(reef = "#7570b3", sediment = "#e6ab02")) +
labs(x = NULL, y = NULL, fill = NULL, subtitle = "white grid: 5 x 5 reporting blocks") +
theme_bw()
```
# 3. Species and habitats
Demersal densities are the product of a depth preference (lognormal,
`depth_mu`, `depth_cv`) and a substrate affinity (`reef`, `sediment`), so
shallow reef, deep reef, shallow sediment and deep sediment arise as
continuous gradients rather than sharp classes. Pelagic species follow sea
temperature (`sst_mu`, `sst_sd`) and depth, and their availability changes
over the year (`season_amp`, `season_peak`): dolphinfish and albacore are
summer-autumn migrants.
```{r density, fig.height = 4.5}
sim$Plots$density
```
# 4. Tactics
A tactic is a gear used in a particular way. Its catchability of each species
(`tactics`) is the gear selectivity; where the gear is used decides which
species are available. The reef handline catches reef species, the bottom
longline sediment species, and pelagic trolling the pelagic species, with
some overlap (conger is caught by both bottom gears; amberjack by reef
handline and trolling).
```{r tactics, fig.height = 2.8}
q <- as.data.frame(as.table(s$tactics))
names(q) <- c("tactic", "species", "catchability")
ggplot(q, aes(x = species, y = tactic, fill = catchability)) +
geom_tile(colour = "white") +
geom_text(aes(label = catchability), size = 2.8) +
scale_fill_viridis_c(option = "rocket", direction = -1, trans = "sqrt") +
labs(x = NULL, y = NULL) + theme_bw() +
theme(axis.text.x = element_text(angle = 30, hjust = 1, size = 7))
```
# 5. Fleet: specialists, mixed vessels and loyalty
Three vessel types (`vessel_types`) fish with different flexibility:
* **demersal specialists**: home tactics reef and sediment;
* **pelagic specialists**: home tactic pelagic;
* **mixed vessels**: no home preference.
Each month, a share `loyalty` of a specialist's trips (default 0.8) is
restricted to its home tactics; the remaining trips, and all trips of mixed
vessels, choose among all tactics by expected value. Specialists therefore
mostly stick to their gear but follow good opportunities, e.g. demersal
boats trolling for dolphinfish in a good summer.
```{r fleet}
s$home
s$loyalty
tr <- sim$trips
round(prop.table(table(type = tr$vessel_type, tactic = tr$tactic), 1), 2)
tapply(tr$loyal, tr$vessel_type, mean)
```
Why it matters for standardisation: a specialist's targeting barely changes,
so a vessel effect absorbs it. Mixed vessels (and the non-loyal trips of
specialists) switch tactics *within* the same vessel as prices change, which
is the targeting that the catch composition has to capture.
* `loyalty = 1`: specialists never leave their home tactics.
* `loyalty = 0` for all types: every vessel behaves as a mixed vessel, the
strongest targeting shifts.
* `preference`: how strongly trips concentrate on the most valuable cells and
tactics (higher = more decisive skippers).
# 6. Prices, closure and fleet changes
Prices change in three periods: demersal species are expensive in 2000-2007,
pelagic species boom in 2008-2015, then prices are neutral. From 2016 the
bottom longline is banned deeper than 300 m and effort is cut by 20%. Some
vessels enter later (and are more efficient, `creep`), others leave.
```{r prices, fig.height = 3.5}
sim$Plots$prices
sim$Plots$tactics
sim$Plots$effort
```
The result is that nominal CPUE (orange) departs from the true biomass
(black) in different ways for each species:
```{r cpue, fig.height = 5}
sim$Plots$cpue
```
# 7. Reporting: from sets to a logbook
The logbook records **trips**, not sets. A share `logbook$two_sets` of trips
(default 0.3) makes a second set, and with probability
`logbook$switch_tactic` (default 0.7) the second set uses another tactic.
The catches of both sets are summed into one record at the position of the
first set, so these trips mix two catch compositions, as in many real
logbooks.
```{r mixed}
mixed <- !is.na(tr$tactic2) & tr$tactic2 != tr$tactic
mean(mixed) # share of trips that mix tactics
round(tapply(mixed, tr$vessel_type, mean), 3)
```
Pelagic specialists make mixed trips only on their non-loyal trips. Further
reporting settings:
| Setting | Default | Effect |
|---|---|---|
| `obs_res` | 5 | positions reported as centres of 5 x 5 blocks |
| `missing_position` | 0.02 | share of trips without position |
| `round_to` | 0.5 | catches rounded to 0.5 kg |
| `underreport` | small catches (< 2 kg) of cheap species (price <= 3) | dropped with probability 0.5 |
| `synonyms`, `synonym_rate` | blackspot seabream | 10% recorded under its common name |
```{r logbook}
head(sim$logbook, 8)
```
# 8. Basic mechanics: what the PCs and clusters capture
We now take the logbook through the first steps of the toolbox and compare
the targeting covariates with the truth.
```{r toolbox}
x <- cpue_data(sim$logbook, year = "year", species = "species", catch = "kg",
effort = "hours", id = "trip", vessel = "vessel",
lon = "lon", lat = "lat", covariates = "month",
synonyms = c("Blackspot seabream" = "Pagellus bogaraveo"))
x <- subset(x, !is.na(lon), note = "positions reported")
x <- select_species(x, threshold = 0.95)
x <- add_targeting(x)
x$targeting$pca
```
Attach the truth of each trip (never available in real data):
```{r truth}
truth <- sim$trips[match(x$data$trip, sim$trips$trip), ]
x$data$true_tactic <- truth$tactic
x$data$habitat <- ifelse(truth$tactic == "Pelagic", "pelagic", truth$habitat)
x$data$depth <- truth$depth
x$data$mixed <- ifelse(!is.na(truth$tactic2) & truth$tactic2 != truth$tactic,
"two tactics", "one tactic")
x$data$X <- truth$X
x$data$Y <- truth$Y
```
## PCs against tactic and habitat
```{r pcs-tactic, fig.height = 5}
plot_biplot(x, colour_by = "true_tactic")
plot_biplot(x, pcs = c(2, 3), colour_by = "habitat")
```
Read the axes from the species arrows (loadings). In this fishery the first
PC typically separates pelagic from demersal trips, and the next PCs reef
from sediment and shallow from deep: the PCA recovers tactic and habitat from
the catch alone, without being told either. Which PC carries which contrast
can change between runs and settings, so always check the loadings.
## PCs against depth and the true position
```{r pcs-depth, fig.height = 3.8}
demersal_trips <- x$data$true_tactic != "Pelagic"
ggplot(x$data[demersal_trips, ], aes(x = depth, y = PC2, colour = true_tactic)) +
geom_point(alpha = 0.3, size = 0.7) + scale_x_log10() +
labs(x = "Depth of the first set (m, log scale)", colour = "True tactic",
title = "Demersal trips: PC2 against depth") + theme_bw()
```
If depth is carried by another PC in your run, replace `PC2` by that PC.
Averaged by the **true** cell, the PC scores map the habitat at a finer
scale than the reported positions; the reported 5 x 5 blocks blur it.
```{r pcs-map, fig.height = 4}
cell_pc <- aggregate(cbind(PC1, PC2) ~ X + Y, data = x$data, FUN = mean)
pm <- rbind(data.frame(X = cell_pc$X, Y = cell_pc$Y, score = cell_pc$PC1, pc = "PC1"),
data.frame(X = cell_pc$X, Y = cell_pc$Y, score = cell_pc$PC2, pc = "PC2"))
ggplot(pm, aes(x = X, y = Y, fill = score)) +
geom_raster() + facet_wrap(~pc) + coord_equal() +
scale_fill_gradient2(low = "#2166ac", mid = "grey95", high = "#b2182b") +
labs(x = "x (offshore ->)", y = "y", fill = "Mean score",
title = "Mean PC score by true cell") + theme_bw()
plot_targeting(x, res = 0.5)$map_pc
```
## Mixed trips lie between the clusters
```{r mixed-pcs, fig.height = 5}
plot_biplot(x, colour_by = "mixed")
```
Trips that combine two tactics have intermediate compositions. PCs place them
continuously; clusters have to assign each to one tactic.
## Clusters against the true tactic
```{r clusters}
tactic_table(x)
round(prop.table(table(cluster = x$data$FT, tactic = x$data$true_tactic), 1), 2)
round(prop.table(table(cluster = x$data$FT, habitat = x$data$habitat), 1), 2)
```
Clusters describe the catch composition, which reflects both the gear and
where it was used, so they rarely match tactics one to one: mixed trips,
gear overlap and neighbouring habitats blur the link.
## Targeting over time
```{r time, fig.height = 4}
pt <- plot_targeting(x, res = 0.5)
pt$time
pt$pcs_time
sim$Plots$tactics
```
The clusters and PCs change in **steps** at the price changes (2008, 2016) and
the closure (2016), as the true tactic shares do.
## Vessel profiles against the true vessel type
```{r vessels, fig.height = 4}
groups <- split(sim$settings$species$species, sim$settings$species$group)
type <- tapply(sim$trips$vessel_type, sprintf("V%02d", sim$trips$vessel),
function(z) z[1])
plot_vessel_profile(x, groups = groups, by = type)
```
Specialists sit at the ends (almost all demersal or almost all pelagic
catch), mixed vessels in between. With loyalty 0.8 the specialists are clear
but not pure, so rules on the catch of the target species
(`select_vessels()`) recover them only approximately.
# Things to try
* **Reef patches:** `reef_scale = 1` against `6`, and compare `Base+S` with
`DPC+S` in the standardisation: the gap shrinks as patches grow larger than
the reporting blocks.
* **Loyalty:** `loyalty = c(demersal = 1, pelagic = 1, mixed = 0)` (strict
specialists) or all zero (every vessel mixed).
* **Mixed trips:** `logbook = list(two_sets = 0)` (one set per trip) or
`switch_tactic = 1`; see how the clusters separate and how the PC biplot
changes.
* **Reporting:** `obs_res = 1` (exact positions) against 10 (very coarse).
* **Stock trends:** change `B_start` or `r` so that species trends diverge,
and check whether the PCs start absorbing them (compare `n_pc`).
# References
Winker, H., Kerwath, S.E. and Attwood, C.G. (2014) Proof of concept for a
novel procedure to standardize multispecies catch and effort data. Fisheries
Research 155: 149-159.
Thorson, J.T., Fonner, R., Haltuch, M.A., Ono, K. and Winker, H. (2017)
Accounting for spatiotemporal variation and fisher targeting when estimating
abundance from multispecies fishery data. Canadian Journal of Fisheries and
Aquatic Sciences 74: 1794-1807.