Starting Values and Fixing (and Sharing) Parameters
j_starting_mapping.RmdIn addition to the Setup_xxx functions, users can access
several advanced model features. These include:
- Specifying starting values (closely tied to parameter fixing)
- Fixing parameters
- Sharing parameters across model partitions
Starting Values
Starting values can be specified in two ways:
- Directly within the
Setup_xxxfunctions. Each setup function accepts starting values through the...argument. The inputs must match the model’s parameter names and dimensions exactly. For more information on parameter dimensions, see the Description of Model Parameters vignette.
Setup_Mod_Rec
ln_global_R0, rec_region_prop_pars, rec_seas_prop_pars, steepness_h, ln_InitDevs, ln_RecDevs, ln_sigmaRSetup_Mod_Biologicals
ln_M, M_offsetSetup_Mod_Movement
move_pars, move_devs, move_pe_pars, log_move_diffusion_pars, move_preference_parsSetup_Mod_Tagging
ln_init_conv_tag_mort, ln_conv_tag_shed, ln_conv_fish_tag_theta, conv_tag_fish_reporting_parsSetup_Mod_Catch_and_F
ln_sigmaC, ln_sigmaF, ln_F_mean, ln_F_devsSetup_Mod_FishIdx_and_Comps
ln_FishAge_theta, FishAge_corr_pars, ln_FishAge_theta_agg, FishAge_corr_pars_agg,
ln_FishLen_theta, FishLen_corr_pars, ln_FishLen_theta_agg, FishLen_corr_pars_aggSetup_Mod_SrvIdx_and_Comps
ln_SrvAge_theta, SrvAge_corr_pars, ln_SrvAge_theta_agg, SrvAge_corr_pars_agg,
ln_SrvLen_theta, SrvLen_corr_pars, ln_SrvLen_theta_agg, SrvLen_corr_pars_aggSetup_Mod_Fishsel_and_Q
fish_fixed_sel_pars, ln_fish_q, fishsel_pe_pars, ln_fishsel_devsSetup_Mod_Srvsel_and_Q
ln_srv_fixed_sel_pars, ln_srv_q, srvsel_pe_pars, ln_srvsel_devs
- Post-hoc modification of starting values. Alternatively, you can
first call the setup functions without specifying starting values, then
access and modify the internally created parameter list
(
input_list$par) before running the model.
In the following, we will illustrate both methods using the
recruitment module (Setup_Mod_Rec) and specify starting
values for ln_global_R0 and ln_sigmaR. First
let us load in the package and define the model dimensions.
# Load in packages
library(SPoRC)
data("sgl_rg_sable_data") # load in data
input_list <- Setup_Mod_Dim(years = 1:length(sgl_rg_sable_data$years), # vector of years
# (corresponds to year 1960 - 2024)
ages = 1:length(sgl_rg_sable_data$ages), # vector of ages
lens = seq(41,99,2), # number of lengths
n_regions = 1, # number of regions
n_sexes = sgl_rg_sable_data$n_sexes, # number of sexes == 1,
# female, == 2 male
n_fish_fleets = sgl_rg_sable_data$n_fish_fleets, # number of fishery
# fleet == 1, fixed gear, == 2 trawl gear
n_srv_fleets = sgl_rg_sable_data$n_srv_fleets, # number of survey fleets
n_pop = sgl_rg_sable_data$n_pop, # number of populations
verbose = FALSE
)We can specify starting values directly using the
Setup_Mod_Rec function. Note that all inputs passed via the
... argument must exactly match the parameter names and
their expected dimensions in the model (see the Description of Model
Parameters vignette for details).
input_list <- Setup_Mod_Rec(
input_list = input_list, # input data list from above
# Model options
do_rec_bias_ramp = 0, # disable bias ramp
sigmaR_switch = as.integer(length(1960:1975)), # switch from early to late sigmaR
dont_est_recdev_last = 1, # do not estimate last recruitment deviate
rec_model = "mean_rec", # recruitment model type
init_age_strc = 1, # geometric series for initial age structure
# Specify starting values
ln_global_R0 = log(30), # starting value for global R0
ln_sigmaR = array(log(1.5), dim = c(2, input_list$data$n_pop, input_list$data$n_regions)) # starting values for early and late sigmaR
)In this example, the starting value for ln_global_R0 is set
to log(30), while ln_sigmaR is set to
log(1.5) for both the early (index 1 along the first
dimension) and late (index 2) periods across all populations and
regions.
Alternatively, starting values can be assigned after running the setup functions. Users can extract the internal parameter list and modify starting values as needed:
input_list <- Setup_Mod_Rec(input_list = input_list, # input data list from above
# Model options
do_rec_bias_ramp = 0, # don't do bias ramp
sigmaR_switch = as.integer(length(1960:1975)), # when to switch from early to late sigmaR
dont_est_recdev_last = 1, # don't estimate last recruitment deviate
rec_model = "mean_rec", # recruitment model
init_age_strc = 1 # geometric series to derive age structure
)
# Specify starting values post-hoc
# R0
input_list$par$ln_global_R0 # default starting value
#> [1] 2.70805
input_list$par$ln_global_R0 <- log(30) # user specified starting value
# sigmaR
input_list$par$ln_sigmaR # default starting value
#> , , 1
#>
#> [,1]
#> [1,] 0
#> [2,] 0
input_list$par$ln_sigmaR[,,] <- log(1.5) # user specified starting valueMapping
Mapping is a core feature of TMB and RTMB models that controls which
parameters are estimated and how they relate to each other. It works
through a named list (input_list$map) where each entry
corresponds to a parameter array flattened into a vector of factors. The
rules are simple:
-
factor(NA)at a position means that parameter is fixed — it is held at its value ininput_list$parand not estimated. - Shared integers at two or more positions means those parameters are constrained to be equal during estimation — only one value is estimated for the group.
- Unique integers at each position means each parameter is independently estimated.
Because fixing a parameter holds it at its current value in
input_list$par, starting values and fixing must always be
set together. If you fix a parameter without also setting a starting
value, it will be held at the default value, which may not be what you
intend.
Fixing Parameters
The Setup_xxx functions include arguments that allow
certain parameters to be fixed. As an example, we use
Setup_Mod_Rec to show how ln_sigmaR can be fixed
using the convenience argument sigmaR_spec = "fix".
input_list <- Setup_Mod_Rec(input_list = input_list, # input data list from above
# Model options
do_rec_bias_ramp = 0, # don't do bias ramp
sigmaR_switch = as.integer(length(1960:1975)), # when to switch from early to late sigmaR
dont_est_recdev_last = 1, # don't estimate last recruitment deviate
rec_model = "mean_rec", # recruitment model
init_age_strc = 1, # geometric series to derive age structure
# Parameter Fixing
sigmaR_spec = 'fix'
)
input_list$map$ln_sigmaR # both values are fixed and not estimated (specified as factor(rep(NA, 2)))
#> [1] <NA> <NA>
#> Levels:
input_list$par$ln_sigmaR # ln_sigmaR is then fixed at the default starting value
#> , , 1
#>
#> [,1]
#> [1,] 0
#> [2,] 0To fix ln_sigmaR at a specific value rather than the default, supply the desired starting value at the same time:
input_list <- Setup_Mod_Rec(input_list = input_list, # input data list from above
# Model options
do_rec_bias_ramp = 0, # don't do bias ramp
sigmaR_switch = as.integer(length(1960:1975)), # when to switch from early to late sigmaR
dont_est_recdev_last = 1, # don't estimate last recruitment deviate
rec_model = "mean_rec", # recruitment model
init_age_strc = 1, # geometric series to derive age structure
# Parameter Fixing
sigmaR_spec = 'fix',
ln_sigmaR = array(log(1.5), dim = c(2, input_list$data$n_pop, input_list$data$n_regions)) # starting values for early and late sigmaR
)
input_list$map$ln_sigmaR # both values are fixed and not estimated (specified as factor(rep(NA, 2)))
#> [1] <NA> <NA>
#> Levels:
input_list$par$ln_sigmaR # ln_sigmaR is then fixed at the user specified starting value
#> , , 1
#>
#> [,1]
#> [1,] 0.4054651
#> [2,] 0.4054651Not all parameters have a convenience argument like
sigmaR_spec = "fix". For example, ln_global_R0
does not. In such cases, you can fix the parameter manually by setting
its map entry to NA and assigning the desired value in the
parameter list. Remember: the map entry fixes the parameter at whatever
is currently in input_list$par, so always set the starting
value first.
input_list <- Setup_Mod_Rec(input_list = input_list, # input data list from above
# Model options
do_rec_bias_ramp = 0, # don't do bias ramp
sigmaR_switch = as.integer(length(1960:1975)), # when to switch from early to late sigmaR
dont_est_recdev_last = 1, # don't estimate last recruitment deviate
rec_model = "mean_rec", # recruitment model
init_age_strc = 1, # geometric series to derive age structure
)
input_list$map$ln_global_R0 <- factor(NA)
input_list$par$ln_global_R0 <- log(30)Sharing Parameters
The Setup_xxx functions also support sharing parameters
across model partitions via built-in convenience arguments. These cover
common sharing structures (e.g., sharing selectivity across sexes or
regions), but for finer control — such as sharing a subset of parameters
while estimating others independently — users can construct the map
manually.
Below, we demonstrate both approaches using fishery selectivity as an example. We define two fishery fleets: Fleet 1 uses a logistic selectivity model (2 parameters: a50 and slope), and Fleet 2 uses a gamma dome-shaped model (2 parameters: amax and slope).
Built-in sharing: estimate all parameters independently
We first use fish_fixed_sel_pars_spec = "est_all" to
estimate all selectivity parameters independently across all model
partitions. With 2 sexes, 2 parameters per fleet, and 2 fleets, we
expect 8 unique values in the map.
input_list <- SPoRC::Setup_Mod_Fishsel_and_Q(input_list = input_list,
# Model options
cont_tv_fish_sel = c("none_Fleet_1", "none_Fleet_2"),
fish_sel_blocks = c("none_Fleet_1", "none_Fleet_2"),
fish_sel_model = c("logist1_Fleet_1", "gamma_Fleet_2"),
fish_q_blocks = c("none_Fleet_1", "none_Fleet_2"),
fish_q_spec = c("fix", "fix"),
# Share selectivity parameters across all partitions
fish_fixed_sel_pars_spec = c("est_all", "est_all"))
input_list$map$fish_fixed_sel_pars # 8 unique numbers, 4 for each sex and fleet combination
#> [1] <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> Levels:Built-in sharing: share parameters across sexes
Using fish_fixed_sel_pars_spec = "est_shared_s" links
selectivity parameters between sexes within each fleet. The same two
parameters are used for both sexes, so we expect only 4 unique values (2
per fleet).
input_list <- SPoRC::Setup_Mod_Fishsel_and_Q(input_list = input_list,
# Model options
cont_tv_fish_sel = c("none_Fleet_1", "none_Fleet_2"),
fish_sel_blocks = c("none_Fleet_1", "none_Fleet_2"),
fish_sel_model = c("logist1_Fleet_1", "gamma_Fleet_2"),
fish_q_blocks = c("none_Fleet_1", "none_Fleet_2"),
fish_q_spec = c("fix", "fix"),
# Share selectivity parameters across all partitions
fish_fixed_sel_pars_spec = c("est_shared_s", "est_shared_s"))
input_list$map$fish_fixed_sel_pars # 4 unique numbers, 2 for each sex and fleet combination
#> [1] <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
#> Levels:Manual sharing: fine-grained control
For sharing structures not supported by the convenience arguments, the map can be constructed manually. In this example, we want:
- Fleet 1 (logistic): a50 is sex-specific, but the slope is shared across sexes
- Fleet 2 (gamma): all parameters are sex-specific
We start from est_all to get the correctly dimensioned
parameter array, then overwrite the map. The parameter array
fish_fixed_sel_pars has dimensions
[n_regions, n_max_sel_pars, n_max_sel_blocks, n_sexes, n_fish_fleets]
— in this example 1 × 2 × 1 × 2 × 2. The table below
summarises the intended sharing structure before we implement it:
| Fleet | Parameter | Female index | Male index | Shared? |
|---|---|---|---|---|
| 1 | a50 | 1 | 2 | No |
| 1 | slope | 3 | 3 | Yes |
| 2 | amax | 4 | 5 | No |
| 2 | slope | 6 | 7 | No |
input_list <- Setup_Mod_Fishsel_and_Q(
input_list = input_list,
cont_tv_fish_sel = c("none_Fleet_1", "none_Fleet_2"),
fish_sel_blocks = c("none_Fleet_1", "none_Fleet_2"),
fish_sel_model = c("logist1_Fleet_1", "gamma_Fleet_2"),
fish_q_blocks = c("none_Fleet_1", "none_Fleet_2"),
fish_q_spec = c("fix", "fix"),
fish_fixed_sel_pars_spec = c("est_all", "est_all") # start with all independent
)
# Extract the parameter array to use as a mapping template
map_fish_fixed_sel_pars <- input_list$par$fish_fixed_sel_pars
# Fleet 1 (logistic): a50 sex-specific, slope shared
map_fish_fixed_sel_pars[1, 1, 1, , 1] <- c(1, 2) # a50: unique per sex
map_fish_fixed_sel_pars[1, 2, 1, , 1] <- c(3, 3) # slope: same integer = shared
# Fleet 2 (gamma): all parameters sex-specific
map_fish_fixed_sel_pars[1, 1, 1, , 2] <- c(4, 5) # amax: unique per sex
map_fish_fixed_sel_pars[1, 2, 1, , 2] <- c(6, 7) # slope: unique per sex
# Flatten to a factor vector and assign to the map
input_list$map$fish_fixed_sel_pars <- factor(as.vector(map_fish_fixed_sel_pars))
# Inspect: 7 unique integers (slope for Fleet 1 appears twice with the same value)
input_list$map$fish_fixed_sel_pars
#> [1] 1 3 2 3 4 6 5 7
#> Levels: 1 2 3 4 5 6 7This custom mapping approach gives full control over parameter
sharing structures beyond what the high-level convenience arguments
provide. The key principle is always the same: positions in the
flattened map with the same integer are estimated as a single shared
parameter, while NA positions are fixed at their value in
input_list$par.