Skip to contents
library(marlin)

library(tidyverse)
#> ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
#>  dplyr     1.1.4      readr     2.1.5
#>  forcats   1.0.0      stringr   1.5.1
#>  ggplot2   3.5.1      tibble    3.2.1
#>  lubridate 1.9.3      tidyr     1.3.1
#>  purrr     1.0.2     
#> ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
#>  dplyr::filter() masks stats::filter()
#>  dplyr::lag()    masks stats::lag()
#>  Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

theme_set(marlin::theme_marlin())

In the fisheries literature, “selectivity” generally refers to the vulnerability of different lengths or ages of fish to fishing mortality. The form of selectivity can have a big impact, depending on for example whether fish become vulnerable to the fishery before the age at maturity, or whether market pressures produce “dome shaped” selectivity in which larger fish are avoided.

marlin allows users to simulate selectivity in a number of ways. Importantly, marlin uses what is basically a form of “contact” selectivity, meaning the selectivity of the gear if it happens to interact with a given individual of a given size. This is different from the “population selectivity”, which is the interaction of contact selectivity and the availability of the organism itself. In marlin, the availability of organisms of different sizes can vary based on habitat and ontogenetic shifts, resulting in a net population selectivity.

Importantly, stock assessments generally estimate population selectivity. So, be cautious in inputting estimated selectivities into marlin as contact selectivities, since it might end up double counting the effects of the actual availability of the species.

Logistic Selectivity

We’ll start by setting up a basic system with one species and two fleets, each with logistic selectivity

Both fleets have logistic selectivity, but the commerical fleet has a higher length at initial selectivity and a steeper selectivity ogive.

For the artisinal fleet, we specificy the units of selectivity based on proportions of the length at 50% maturity (sel_unit = "p_of_mat"). In this form sel_start = 0.5 indicates that length at 50% selectivity is at 50% of the length at 50% maturity, and the length at 95% maturity is length at 50% maturity times sel_start + set_delta.

Setting sel_unit = "p_of_mat" is easier when running bulk simulations.

For more individual simulations, setting sel_unit = "length can be more intuitive, since selecitivy is in units of length then.

So, in the commercial case shown below, the length at 50% selectivity is set to sel_start = 22 and the length at 95% selectivity is sel_start + sel_delta.


resolution <- 10

years <- 50

fauna <-
  list(
    "snapper" = create_critter(
      scientific_name = "lutjanus griseus",
      linf = 42,
      adult_diffusion = 10,
      fished_depletion = .25,
      resolution = resolution
    )
  )


fleets <- list(
  "artisanal" = create_fleet(list(
    "snapper" = Metier$new(
      critter = fauna$snapper,
      p_explt = 0.5,
      sel_unit = "p_of_mat",
      sel_start = 0.5,
      sel_delta = 0.1
    )
  ), resolution = resolution),
  "commercial" = create_fleet(list(
    "snapper" = Metier$new(
      critter = fauna$snapper,
      p_explt = 0.5,
      sel_unit = "length",
      sel_start = 22,
      sel_delta = .01
    )
  ), resolution = resolution)
)



sels <- data.frame(
  artisinal = fleets$artisanal$metiers$snapper$sel_at_length
  ,
  commercial = fleets$commercial$metiers$snapper$sel_at_length,
  length = as.numeric(colnames(fauna$snapper$length_at_age_key))
)
 
sels |> 
  pivot_longer(-length, names_to = "fleet", values_to = "selectivity")  |> 
  ggplot(aes(length, selectivity, color = fleet)) + 
  geom_line()

Double Normal

Contact selectivity is not always asymptotic; fish may become less vulnerable to gears as they get bigger for physical (e.g. no longer likely to get tangled in nets) or market reasons (released if too large, though users would need to then consider whether released fish survive).

The most common strategy to model this behavior is a so-called “double normal” model, in which selectivity is modeled using the intersection of two normal distributions.

There are many types of double normal functions, but we employ a fairly simple form used in Carruthers et al. 2014.

The parameters of the double normal in this form are

  • The smallest length at full selectivity

  • The smallest length at 0.05 selectivity

  • The selectivity at Linf

In this case, the artisinal fleet will be specified with sel_unit = "p_of_mat"

The smallest length at full selectivity is then a function of sel_start + sel_delta

The smallest length at 0.05 selectivity is set based on sel05_anchor (in this case units of proportions of the length at 50% maturity). Note that this must be less than the size at full selectivity

The selectivity at linf is set to 0, meaning that largest fish are no longer captured by the gear.

For the commerical fleet, we set sel_unit = "length" and so the values of the parameters are adjusted accordingly. For the commercial fleet, selectivity at Linf is 0.5, meaning lower than the peak, but not zero.



fleets <- list(
  "artisanal" = create_fleet(list(
    "snapper" = Metier$new(
      critter = fauna$snapper,
      sel_form = "double_normal",
      p_explt = 0.5,
      sel_unit = "p_of_mat",
      sel_start = 0.5,
      sel_delta = 0.1,
      sel05_anchor = 0.1,
      sel_at_linf = 0
    )
  ), resolution = resolution),
  "commercial" = create_fleet(list(
    "snapper" = Metier$new(
      critter = fauna$snapper,
      sel_form = "double_normal",
      p_explt = 0.5,
      sel_unit = "length",
      sel_start = 10,
      sel_delta = 0.1,
      sel05_anchor = 5,
      sel_at_linf = 0.5
    )
  ), resolution = resolution)
)

sels <- data.frame(
  artisinal = fleets$artisanal$metiers$snapper$sel_at_length
  ,
  commercial = fleets$commercial$metiers$snapper$sel_at_length,
  length = as.numeric(colnames(fauna$snapper$length_at_age_key))
)
 
sels |> 
  pivot_longer(-length, names_to = "fleet", values_to = "selectivity")  |> 
  ggplot(aes(length, selectivity, color = fleet)) + 
  geom_line()

Manual Selectivity

Selectivity can also be manually supplied. In this case we’ll pretend we have a separately estimated selectivity for the commercial fleet by setting sel_form = "manual" and passing sel_at_age values to the commercial fleet.


commercial_selectivity <- rlnorm(length(fauna$snapper$ages))

commercial_selectivity <- commercial_selectivity / max(commercial_selectivity)

fleets <- list(
  "artisanal" = create_fleet(list(
    "snapper" = Metier$new(
      critter = fauna$snapper,
      sel_form = "double_normal",
      p_explt = 0.5,
      sel_unit = "p_of_mat",
      sel_start = 0.5,
      sel_delta = 0.1,
      sel05_anchor = 0.1,
      sel_at_linf = 0
    )
  ), resolution = resolution),
  "commercial" = create_fleet(list(
    "snapper" = Metier$new(
      critter = fauna$snapper,
      sel_form = "manual",
      sel_at_age = commercial_selectivity
    )
  ), resolution = resolution)
)


sels <- data.frame(
  artisinal = fleets$artisanal$metiers$snapper$sel_at_age
  ,
  commercial = fleets$commercial$metiers$snapper$sel_at_age,
  age = fauna$snapper$ages
)
 
sels |> 
  pivot_longer(-age, names_to = "fleet", values_to = "selectivity")  |> 
  ggplot(aes(age, selectivity, color = fleet)) + 
  geom_line()