Fitting OMs
An example MSE using the northern rockfish stock assessment.
library(Rceattle)
data("NorthernRockfish2022")
nrdata <- NorthernRockfish2022
nrdata$fleet_control$proj_F_prop <- 1
om <- Rceattle::fit_mod(
data_list = nrdata,
estimateMode = 0, # Estimate
initMode = 1, # Assume unfished equilibrium
M1Fun = build_M1(
M1_model = "sex_age_invariant",
linkages = list(
log_M1 = linkage_spec(
formula = ~ 1,
priors = list(
"(Intercept)" = normal(log(0.06), 0.05)
)
)
)
),
fit_control = fit_control(phase = TRUE)
)Fitting EMs (Tier 3 HCR)
We can use the HCR = build_hcr() argument in
fit_mod to specify the HCR and BRPs of our management
strategy. A variety of HCRs and BRPs are included and can be found by
?build_hcr.
em <- Rceattle::fit_mod(
data_list = nrdata,
estimateMode = 0, # Estimate
initMode = 1, # Assume unfished equilibrium
M1Fun = build_M1(
M1_model = "sex_age_invariant",
linkages = list(
log_M1 = linkage_spec(
formula = ~ 1,
priors = list(
"(Intercept)" = normal(log(0.06), 0.05)
)
)
)
),
HCR = build_hcr(HCR = "NPFMC", # Tier3 HCR
Ftarget = 0.4, # F40%
Flimit = 0.35, # F35%
Plimit = 0.2, # No fishing when SB<SB20
Alpha = 0.05),
fit_control = fit_control(verbose = 1, phase = TRUE)
)Running MSEs
mse1 <- run_mse(
om = om, em = em,
nsim = 10,
assessment_period = 2,
# Fishery = fleet 1 (annual), BTS = fleet 2 (biannual)
sampling_period = c(1, 2),
seed = 666 # default; per-sim seed = seed + sim
)Reproducibility
run_mse() accepts two seed arguments, both with default
seed = 666:
-
seedcontrols the random draws inside each simulated trajectory (recruitment, observation error, composition resampling). Each simulation worker callsset.seed(seed + sim), so simulation1uses seed667, simulation2uses668, and so on. Re-running the samerun_mse()call with the sameseedreproduces the trajectory bit-for-bit. -
regenerate_seed(defaults toseed) controls the optionalregenerate_past = TRUEstep that re-fits the EM to OM-simulated historical data. Set this separately if you want to vary past-data realizations while holding the projection draws fixed.
The MSE uses a PSOCK cluster (parallel::parLapply) by
default, so worker processes are clean and only see the explicit objects
shipped by clusterExport() — there is no leakage from the
parent’s .GlobalEnv RNG state. As a result the seed
plumbing above is the only thing that controls reproducibility:
there is no need to call set.seed() before
run_mse() for the simulation results to be deterministic.
(You may still want set.seed() for any plotting code that
draws random colours or jitter.)
For management-facing runs, record
packageVersion("Rceattle") and the seed
alongside the saved .rds so a later reviewer can rerun the
exact same trajectories from the same package tag.
Evaluating MSEs via plots
plot_depletionSSB(lapply(mse1, function(x) x$OM))
plot_depletionSSB(
c(mse1$Sim_1$EM, # EMs
list(mse1$Sim_1$OM, # OM
mse1$Sim_1$OM_no_F # OM w/ no fishing
)),
line_col = c(
paste0("grey", round(seq(80, 50, length.out = 15))),
1, 3
)
)Alternative scenarios
Different BRPs
em2 <- Rceattle::fit_mod(
data_list = nrdata,
estimateMode = 0, # Estimate
initMode = 1, # Assume unfished equilibrium
M1Fun = build_M1(
M1_model = "sex_age_invariant",
linkages = list(
log_M1 = linkage_spec(
formula = ~ 1,
priors = list(
"(Intercept)" = normal(log(0.06), 0.05)
)
)
)
),
HCR = build_hcr(HCR = "NPFMC", # Tier3 HCR
Ftarget = 0.30,# F40%
Flimit = 0.10, # F35%
Plimit = 0, # No limit
Alpha = 0.1),
fit_control = fit_control(verbose = 1, phase = TRUE)
)
mse2 <- run_mse(
om = om, em = em2,
nsim = 10,
assessment_period = 2,
sampling_period = c(1, 2) # Fishery = fleet 1, BTS = fleet 2
)Triannual BTS
mse3 <- run_mse(
om = om, em = em,
nsim = 10,
assessment_period = 2,
sampling_period = c(1, 3) # Fishery = fleet 1, BTS = fleet 2
)4-year cycle and 50% sampling
mse4 <- run_mse(
om = om, em = em,
nsim = 10,
fut_sample = 0.5,
assessment_period = 4,
sampling_period = c(1, 2) # Fishery = fleet 1, BTS = fleet 2
)Climate MSE
Climate linked OM
# Fit OM
om2 <- Rceattle::fit_mod(
data_list = nrdata,
estimateMode = 0, # Estimate
initMode = 1, # Assume unfished equilibrium
M1Fun = build_M1(
M1_model = "sex_age_invariant",
linkages = list(
log_M1 = linkage_spec(
formula = ~ 1,
priors = list(
"(Intercept)" = normal(log(0.06), 0.05)
)
)
)
),
recFun = build_srr(
srr_fun = "mean", # Mean R with covariates
linkages = list(
log_R0 = linkage_spec(formula = ~ Temp)
)),
fit_control = fit_control(phase = TRUE)
)
plot_biomass(om2, incl_proj = TRUE)Overall summary
mse_summ$MSE = 1
mse_summ2 <- mse_summary(mse2); mse_summ2$MSE = 2
knitr::kable(do.call("rbind", list(mse_summ, mse_summ2)) |>
dplyr::relocate(MSE), digits = 2)