The application of the Age-Structured Production Model (ASPM) approach as a diagnostic can help identify misspecification of the production function. If, in the absence of composition data (likelihood weighting set to 0), the ASPM fits well to the indices of abundance that have good contrast, then the production function is likely to drive the stock dynamics and indices will provide information about the absolute abundance (Carvalho et al. 2017). If there is not a good fit to the indices, then the catch data and production function alone cannot explain the trajectories of the indices of relative abundance.
Model inputs
To run a Stock Synthesis model, four input files are required:
starter.ss, forecast.ss, control.ss, and data.ss. The input files for
the example model can be found within the ss3diags
package
and accessed as shown below. Also, if you do not have the
r4ss
package installed, you will need to install it for
this tutorial.
install.packages("pak")
pak::pkg_install("r4ss/r4ss")
library(r4ss)
files_path <- system.file("extdata", package = "ss3diags")
dir_tmp <- tempdir(check = TRUE)
dir_aspm <- file.path(dir_tmp, "aspm")
dir.create(dir_aspm, showWarnings = FALSE, recursive = TRUE)
list.files(files_path)
## [1] "control.ss" "data.ss" "forecast.ss" "starter.ss"
file.copy(from = list.files(files_path, full.names = TRUE), to = dir_tmp)
## [1] TRUE TRUE TRUE TRUE
You will need to make sure you have the SS
executable file either in your path or in the directory you are
running the ASPM from (in this case dir_aspm
). An easy way
to get the latest release of stock synthesis is to use the
r4ss
function get_ss3_exe()
.
r4ss::get_ss3_exe(dir = dir_tmp, version = "v3.30.21")
## The stock synthesis executable for Linux v3.30.21 was downloaded to: /tmp/RtmpyV5HqQ/ss3
ASPM
Once you have the 4 input files, you need to determine what
components need to be turned off to run the ASPM. ASPM only depend on
index of abundance and catch data, so any composition data, recruitment
deviations, etc. need to be turned off. We provide an example that
includes multiple types of data and recruitment deviations, however, the
exact steps necessary for an individual model may vary depending on the
complexity and components included. Therefore these steps may not be
fully comprehensive for your model so be sure to check what other
components you may need to change.
Below, we show how to use the r4ss
functions to make all
the necessary changes to the control.ss
and
ss.par
files.
Generate files
In order to get the ss.par
file, you need to run the
model once. This will also produce a new data and control file that we
will use as the input files. We will run the model in
dir_tmp
then copy the new files over to
dir_aspm
.
r4ss::run(dir = dir_tmp, verbose = FALSE, exe = "ss3")
## [1] "ran model" "ran model" "ran model" "ran model" "ran model"
files <- c("data_echo.ss_new", "control.ss_new", "starter.ss", "forecast.ss", "ss.par", "ss3")
file.copy(from = file.path(dir_tmp, files), to = dir_aspm)
## [1] TRUE TRUE TRUE TRUE TRUE TRUE
Recruitment Deviations
Set the recruitment devations in ss.par
to 0.
par <- SS_readpar_3.30(
parfile = file.path(dir_aspm, "ss.par"),
datsource = file.path(dir_aspm, "data_echo.ss_new"),
ctlsource = file.path(dir_aspm, "control.ss_new"),
verbose = FALSE
)
par$recdev1
## year recdev
## [1,] 2011 -0.06005247
## [2,] 2012 -0.01284866
## [3,] 2013 0.13478706
## [4,] 2014 0.11410144
## [5,] 2015 -0.08325396
## [6,] 2016 0.14556845
## [7,] 2017 -0.12973978
## [8,] 2018 -0.18308123
## [9,] 2019 0.02442762
## [10,] 2020 -0.08979813
## [11,] 2021 -0.07812317
## [12,] 2022 0.21801284
par$recdev_forecast
## year recdev
## [1,] 2023 0
## [2,] 2024 0
## [3,] 2025 0
## [4,] 2026 0
## [5,] 2027 0
## [6,] 2028 0
## [7,] 2029 0
## [8,] 2030 0
## [9,] 2031 0
## [10,] 2032 0
par$recdev1[, "recdev"] <- 0
# Would run if forecasts recdevs were not already 0
# par$recdev_forecast[,"recdev"] <- 0
SS_writepar_3.30(
parlist = par,
outfile = file.path(dir_aspm, "ss.par"),
overwrite = T, verbose = FALSE
)
## $headerlines
## [1] "# Number of parameters = 32 Objective function value = 754.301687441726 Maximum gradient component = 8.77017492766611e-07"
## [2] "# dummy_parm:"
## [3] "1.00000000000"
##
## $MG_parms
## INIT ESTIM
## NatM_p_1_Fem_GP_1 0.10000000 0.10000000
## L_at_Amin_Fem_GP_1 22.76900000 22.76899194
## L_at_Amax_Fem_GP_1 71.80720000 71.80721125
## VonBert_K_Fem_GP_1 0.14216500 0.14216482
## CV_young_Fem_GP_1 0.10000000 0.10000000
## CV_old_Fem_GP_1 0.10000000 0.10000000
## Wtlen_1_Fem_GP_1 0.00000244 0.00000244
## Wtlen_2_Fem_GP_1 3.34694000 3.34694000
## Mat50%_Fem_GP_1 55.00000000 55.00000000
## Mat_slope_Fem_GP_1 -0.25000000 -0.25000000
## Eggs_alpha_Fem_GP_1 1.00000000 1.00000000
## Eggs_beta_Fem_GP_1 0.00000000 0.00000000
## NatM_p_1_Mal_GP_1 0.00000000 0.00000000
## L_at_Amin_Mal_GP_1 0.00000000 0.00000000
## L_at_Amax_Mal_GP_1 0.00000000 0.00000000
## VonBert_K_Mal_GP_1 0.00000000 0.00000000
## CV_young_Mal_GP_1 0.00000000 0.00000000
## CV_old_Mal_GP_1 0.00000000 0.00000000
## Wtlen_1_Mal_GP_1 0.00000244 0.00000244
## Wtlen_2_Mal_GP_1 3.34694000 3.34694000
## CohortGrowDev 1.00000000 1.00000000
## FracFemale_GP_1 0.50000000 0.50000000
##
## $SR_parms
## INIT ESTIM
## SR_LN(R0) 8.9274 8.927395
## SR_BH_steep 0.8000 0.800000
## SR_sigmaR 0.6000 0.600000
## SR_regime 0.0000 0.000000
## SR_autocorr 0.0000 0.000000
##
## $recdev1
## year recdev
## [1,] 2011 0
## [2,] 2012 0
## [3,] 2013 0
## [4,] 2014 0
## [5,] 2015 0
## [6,] 2016 0
## [7,] 2017 0
## [8,] 2018 0
## [9,] 2019 0
## [10,] 2020 0
## [11,] 2021 0
## [12,] 2022 0
##
## $recdev_forecast
## year recdev
## [1,] 2023 0
## [2,] 2024 0
## [3,] 2025 0
## [4,] 2026 0
## [5,] 2027 0
## [6,] 2028 0
## [7,] 2029 0
## [8,] 2030 0
## [9,] 2031 0
## [10,] 2032 0
##
## $init_F
## [1] 0.1
##
## $Q_parms
## INIT ESTIM
## LnQ_base_SURVEY1(2) 0.476759 0.4767585
## Q_extraSD_SURVEY1(2) 0.000000 0.0000000
## LnQ_base_SURVEY2(3) -6.304070 -6.3040672
##
## $S_parms
## INIT ESTIM
## SizeSel_P_1_FISHERY(1) 56.51380 56.513807
## SizeSel_P_2_FISHERY(1) 20.17930 20.179340
## SizeSel_P_1_SURVEY1(2) 36.02330 36.023325
## SizeSel_P_2_SURVEY1(2) 5.33502 5.335021
## AgeSel_P_1_SURVEY2(3) 0.00000 0.000000
## AgeSel_P_2_SURVEY2(3) 0.00000 0.000000
Starter File
Change the starter file to read from ss.par
(init_values_src = 1
) and to use the new data and control
files.
starter <- SS_readstarter(file = file.path(dir_aspm, "starter.ss"), verbose = FALSE)
starter$datfile <- "data_echo.ss_new"
starter$ctlfile <- "control.ss_new"
starter$init_values_src <- 1
SS_writestarter(starter,
dir = dir_aspm,
overwrite = TRUE,
verbose = FALSE
)
Control File
The estimation phases for the following parameters may need to be changed:
- length selectivity
- age selectivity
- size selectivity
- steepness
- sigmaR
- recruitment deviations
Additionally, the likelihood for some components may need to be turned off as well. You can do this using the lambda options in the control file. Some examples include:
- length-composition data
- age-composition data
- size-composition data
- initial F
control <- SS_readctl_3.30(
file = file.path(dir_aspm, "control.ss_new"),
datlist = file.path(dir_aspm, "data_echo.ss_new"),
verbose = FALSE
)
control$SR_parms
## LO HI INIT PRIOR PR_SD PR_type PHASE env_var&link dev_link
## SR_LN(R0) 6.0 12 8.9274 10.3 10.0 0 1 0 0
## SR_BH_steep 0.2 1 0.8000 0.8 1.0 0 -4 0 0
## SR_sigmaR 0.0 2 0.6000 0.8 0.8 0 -4 0 0
## SR_regime -5.0 5 0.0000 0.0 1.0 0 -4 0 0
## SR_autocorr 0.0 0 0.0000 0.0 0.0 0 -99 0 0
## dev_minyr dev_maxyr dev_PH Block Block_Fxn
## SR_LN(R0) 0 0 0 0 0
## SR_BH_steep 0 0 0 0 0
## SR_sigmaR 0 0 0 0 0
## SR_regime 0 0 0 0 0
## SR_autocorr 0 0 0 0 0
# Would need to run if PHASES were positive for "steep" and "sigmaR"
# control$SR_parms[c(2,3),"PHASE"] <- c(-4,-4)
control$age_selex_parms
## LO HI INIT PRIOR PR_SD PR_type PHASE env_var&link
## AgeSel_P_1_SURVEY2(3) 0 20 0 5 99 0 -99 0
## AgeSel_P_2_SURVEY2(3) 0 20 0 6 99 0 -99 0
## dev_link dev_minyr dev_maxyr dev_PH Block Block_Fxn
## AgeSel_P_1_SURVEY2(3) 0 0 0 0 0 0
## AgeSel_P_2_SURVEY2(3) 0 0 0 0 0 0
# would need to run if PHASES were positive for age selectivity
# control$age_selex_parms[,"PHASE"] <- control$age_selex_parms[,"PHASE"] * -1
control$size_selex_parms[, "PHASE"] <- control$size_selex_parms[, "PHASE"] * -1
control$recdev_early_phase <- -4
control$recdev_phase <- -2
new_lambdas <- data.frame(
like_comp = c(4, 4, 5, 5, 7, 7, 9, 9, 9, 10),
fleet = c(1, 2, 1, 2, 1, 2, 1, 2, 3, 1),
phase = rep(1, 10),
value = rep(0, 10),
sizefreq_method = rep(1, 10)
)
new_lambdas
## like_comp fleet phase value sizefreq_method
## 1 4 1 1 0 1
## 2 4 2 1 0 1
## 3 5 1 1 0 1
## 4 5 2 1 0 1
## 5 7 1 1 0 1
## 6 7 2 1 0 1
## 7 9 1 1 0 1
## 8 9 2 1 0 1
## 9 9 3 1 0 1
## 10 10 1 1 0 1
control$lambdas <- new_lambdas
control$N_lambdas <- nrow(new_lambdas)
SS_writectl_3.30(control,
outfile = file.path(dir_aspm, "control.ss_new"),
overwrite = TRUE, verbose = FALSE
)
Run ASPM
r4ss::run(dir = dir_aspm, exe = "ss3", skipfinished = FALSE, verbose = FALSE)
## [1] "ran model" "ran model" "ran model" "ran model" "ran model"
Visualize Results
To compare the ASPM model with the age-structured model, you can use
SSplotComparisons()
. Comparing spawning biomass and F
estimates between the two models and fits to indices of abundance can
help to understand if there is enough information in the indices to
inform the production function.
mods <- SSgetoutput(dirvec = c(
dir_tmp,
dir_aspm
), verbose = FALSE)
mods_sum <- SSsummarize(mods, verbose = FALSE)
SSplotComparisons(mods_sum,
legendlabels = c("Ref", "ASPM"),
subplots = c(2, 8, 14), new = F
)
## showing uncertainty for all models
## subplot 2: spawning biomass with uncertainty intervals
## subplot 8: F value with uncertainty
## subplot 14: index fits on a log scale