#' Function to solve out numbers of fish in the forecast to equal
#' match management ABC values. If a fleet in your model has removals
#' specified as numbers of fish (1,000s), SS will expect numbers of fish
#' to be used in the forecast file for that fleet is there are pre-specified
#' forecast removals. This creates challenges when attempting to determine the
#' right number of fish that will meet the harvest specified ABC values. This
#' function does a bisection approach to iteratively determine the number of fish
#' that will match the fleet specified removals in terms of biomass.
#'
#' @param mod_dir the directory of your model - all runs will be conducted in this folder
#' make sure you are alright if the SS files are changed.
#' @param fore_yrs a vector of forecast years where removals are pre-specified
#' @param fleet_abc a vector of fleet specific abc values for the fleet that is currently
#' in terms of numbers of fish.
#' @param fleet fleet number within SS3 of the fleet that has removals in terms of numbers of
#' fish.
#' @param thresh Percent difference that controls if the model should be run again. The
#' default value of 0.01 results in the code identifying a solution as correct that is within
#' 1 percent above or below the input fleet_abc value. The model will only be rerun once. This
#' threshold may need to be increased if the catch values are very small.
#' @param exe The executable name for Stock Synthesis to be passed to the r4ss::run function.
#' @author Chantel Wetzel
#' @export
#'
#' @examples
#' \dontrun{
#' solve_numbers(mod_dir = "C:/Models/my_model",
#' fore_yrs = 2021:2022,
#' fleet_abc = c(5.5, 5),
#' fleet = 4)
#'}
#'
solve_numbers <- function(mod_dir, fore_yrs, fleet_abc, fleet = NULL, exe = "ss", thresh = 0.01){
# Set the wd to run the model
setwd(mod_dir)
if(!file.exists("ss.par")){
stop("There is no par file in mod_dir. Please run the model.")
}
if(length(fore_yrs) != length(fleet_abc)) {
stop("The length of fore_yrs and fleet_abc need to be the same.")
}
yrs = fore_yrs
abc = fleet_abc
if(is.null(fleet)){
dat = r4ss::SS_readdat("data.ss_new")
fleet = which(dat$fleetinfo$units == 2)
if(length(fleet) > 1){
stop("There appears to be more than one fleet with catches in numbers. \n
Function currently only does one fleet at a time. \n
Specify the fleet input in the function to specify which fleet to do.")
}
}
# Turn max phase to 0 and read from par file
starter = r4ss::SS_readstarter(file.path(mod_dir, "starter.ss"))
use_par = starter$init_values_src
starter$init_values_src = 1
max_phase = starter$last_estimation_phase
starter$last_estimation_phase = 0
r4ss::SS_writestarter(starter, dir = mod_dir, overwrite = TRUE, verbose = FALSE)
r4ss::run(exe = exe, extras = "-nohess -maxfun 0", skipfinished = FALSE)
for(i in 1:length(yrs)){
fore = r4ss::SS_readforecast(file.path(mod_dir, "forecast.ss"), verbose = FALSE)
find = which(fore$ForeCatch$Fleet == fleet & fore$ForeCatch$Year == yrs[i])
fore$ForeCatch[find, "Catch or F"] = abc[i]
r4ss::SS_writeforecast(fore, dir = mod_dir, overwrite = TRUE)
r4ss::run(exe = exe, extras = "-nohess -maxfun 0", skipfinished = FALSE)
rep = r4ss::SS_output(mod_dir, printstats = FALSE, verbose = FALSE, covar = FALSE)
bio = rep$timeseries[rep$timeseries$Yr == yrs[i], paste0("dead(B):_", fleet)]
num = rep$timeseries[rep$timeseries$Yr == yrs[i], paste0("dead(N):_", fleet)]
wt <- bio/num
input_num <- abc[i]/wt
fore = r4ss::SS_readforecast(file.path(mod_dir, "forecast.ss"), verbose = FALSE)
find = which(fore$ForeCatch$Fleet == fleet & fore$ForeCatch$Year == yrs[i])
# Write out the solved input numbers based on the average weight and the abc
fore$ForeCatch[find, "Catch or F"] = input_num
r4ss::SS_writeforecast(fore, dir = mod_dir, overwrite = TRUE)
# Rerun the model
r4ss::run(exe = exe, extras = "-nohess -maxfun 0", skipfinished = FALSE)
rep = r4ss::SS_output(mod_dir, covar = FALSE, verbose = FALSE, printstats = FALSE)
bio = rep$timeseries[rep$timeseries$Yr == yrs[i], paste0("dead(B):_", fleet)]
print(paste0("!!!!!!!!!!!!!!!!! Biomass = ", bio, " ABC = ", abc[i], "!!!!!!!!!!!!!!!!"))
if(bio/abc[i] < (1 - thresh) | bio/abc[i] > (1 + thres)){
bio = rep$timeseries[rep$timeseries$Yr == yrs[i], paste0("dead(B):_", fleet)]
num = rep$timeseries[rep$timeseries$Yr == yrs[i], paste0("dead(N):_", fleet)]
wt <- bio/num
input_num <- abc[i]/wt
fore = r4ss::SS_readforecast(file.path(mod_dir, "forecast.ss"), verbose = FALSE)
find = which(fore$ForeCatch$Fleet == fleet & fore$ForeCatch$Year == yrs[i])
# Write out the solved input numbers based on the average weight and the abc
fore$ForeCatch[find, "Catch or F"] = input_num
r4ss::SS_writeforecast(fore, dir = mod_dir, overwrite = TRUE)
# Rerun the model
r4ss::run(exe = exe, extras = "-nohess -maxfun 0", skipfinished = FALSE)
rep = r4ss::SS_output(mod_dir, covar = FALSE, verbose = FALSE, printstats = FALSE)
bio = rep$timeseries[rep$timeseries$Yr == yrs[i], paste0("dead(B):_", fleet)]
print(paste0("!!!!!!!!!!!!!!!!! Biomass = ", bio, " ABC = ", abc[i], "!!!!!!!!!!!!!!!!"))
}
}
# Change the max phase back to the original value
starter = r4ss::SS_readstarter(file.path(mod_dir, "starter.ss"))
starter$init_values_src = use_par
starter$last_estimation_phase = max_phase
r4ss::SS_writestarter(starter, dir = mod_dir, overwrite = TRUE, verbose = FALSE)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.