vignettes/ex12_multistock.Rmd
ex12_multistock.Rmd
In this vignette we show how to create inputs for 2 stocks and 2 regions with 5 seasons within the year and configure movement that is constant or with age or annual random effects.
Load wham library and set up a directory for work
Create inputs and fitting model for a two stock model without movement
prepare_wham_input
and model
component functions (e.g., set_move
)Create inputs and fitting model with movement of 1 stock
prepare_wham_input
and model
component functionsCreate inputs and fitting model with age-varying movement
prepare_wham_input
and model
component functionsCreate inputs and fitting model with time-varying movement
prepare_wham_input
and model
component functionsCreate inputs and fitting model with a prior distribution on movement
prepare_wham_input
and model
component functionsIf you have not already installed wham
, see the Introduction for
instructions.
Open R and load the wham
package:
Create a directory for this analysis:
# choose a location to save output, otherwise will be saved in working directory
write.dir <- "choose/where/to/save/output" #e.g., tempdir(check=TRUE)
dir.create(write.dir)
setwd(write.dir)
For a clean, runnable .R
script, look at
ex12_multistock.R
in the example_scripts
folder of the wham
package. You can run this entire example
script with:
wham.dir <- find.package("wham")
source(file.path(wham.dir, "example_scripts", "ex12_multistock.R"))
Read the ASAP3 .dat files into R and create an input. Note any number of asap dat files can be read in and by default a model will be created with a stock and its own region for each .dat file and no connectivity. So, one could fit the same single stock model a number times simultaneously by reading in the same dat file multiple times.
path_to_examples <- system.file("extdata", package="wham")
diff_stocks_asap <- read_asap3_dat(file.path(path_to_examples,c("north.dat","south.dat")))
selectivity <- list(model = rep(c("logistic", "age-specific"),c(8,4)), n_selblocks = 12,
fix_pars = c(rep(list(NULL),8), list(2:8,3:8,3:8,2:8)),
initial_pars = c(rep(list(c(2,0.2)),8),list(rep(c(0.5,1),c(1,7)), rep(c(0.5,1),c(2,6)),rep(c(0.5,1),c(2,6)),rep(c(0.5,1),c(1,7)))))
diff_stocks_input <- prepare_wham_input(diff_stocks_asap, selectivity = selectivity)
fit_diff_stocks <- fit_wham(diff_stocks_input, do.osa = FALSE, do.retro= FALSE, do.sdrep = FALSE)
We will use diff_stocks_asap
throughout this vignette,
but changing movement and parameter assumptions along the way.
We will use the asap inputs, but we will also specify some elements
of the basic_info
argument to
prepare_wham_input
that provides a list of various “basic”
model structure information:
input <- diff_stocks_input
basic_info <- list(
n_stocks = input$data$n_stocks,
n_regions = input$data$n_regions,
region_names <- c("North_r", "South_r"), #n_regions
stock_names <- c("North_s", "South_s"), #n_stocks
ages = 1:input$data$n_ages,
n_fleets = input$data$n_fleets,
maturity = input$data$mature, #n_stocks x n_years x n_ages
years = as.integer(input$years),
waa = input$data$waa, #any no. x n_years x n_ages
waa_pointer_ssb = input$data$waa_pointer_ssb, #n_stocks
spawn_regions = input$data$spawn_regions #n_stocks
)
We define the first stock to be a northern stock and stock 2 to be a
southern stock. The spatial regions have the same name and order. Note
we can supply names for regions, stocks, fleets (in
catch_info$fleet_names
), and indices (in
index_info$index_names
) that are used in generating more
descriptive model output.
Below we specify the seasonal information: number, what fraction of the year for each season, which season spawning occurs, and the fraction of the year where spawning occurs.
basic_info$n_seasons <- 5L
basic_info$fracyr_seasons <- rep(1/5,5) #does not have to be equal lengths.
basic_info$spawn_seasons <- c(3,3)
basic_info$fracyr_SSB <- input$data$fracyr_SSB#-2/5 # this should be fixed in prepare_wham_input
Below we specify which ages can be where on January 1 of each year. Currently, WHAM only models spawning and recruitment for each stock in only 1 region (natal homing). So that the northern stock only spawns in the northern region. Spawning age fish may occur in other regions during the spawning season, but are assumed to not be part of the spawning population. We are going to assume movement only for the northern stock.
n_ages <- length(basic_info$ages)
#each age other than 1 (recruitment) for north stock can be in either region on Jan 1
basic_info$NAA_where <- array(1, dim = c(2,2,n_ages)) #n_stocks x n_regions x n_ages
basic_info$NAA_where[1,2,1] <- 0 #stock 1, age 1 can't be in region 2 on Jan 1
basic_info$NAA_where[2,1,] <- 0 #stock 2, any age can't be in region 1 2 on Jan 1 (stock 2 doesn't move)
Next, we configure 5 equal length seasons and define movement only
for the northern stock (stock_move
) to be separable (and
sequential to) from mortality (separable = TRUE
). We use
must_move
and can_move
(0s and 1s) to
constrain movement between regions each season. When values of
must_move = 1
fish must move from the region, so
must_move[1,3,2] = 1 would mean that the northern stock must move from
the south at the end of the 3rd season. can_move=1
defines
that movement is possible to a particular region from another, so
can_move[1,4,2]=0 would mean that the northern stock cannot move to the
south at the end of the 4th season. Note that the when the last two
indices are the same e.g., can_move[1,2,r,r]
where
r
is any region is not used because the probability of
staying in each region is calculated as 1 - the sum of the probabilities
of movement out of the region.
We will define that north stock fish must move back to region 1 at the end of the second season before spawning in the third season and that fish can only move out of the north in the other seasons.
n_seasons <- basic_info$n_seasons
move = list(stock_move = c(TRUE,FALSE), #n_stocks
separable = TRUE) #north moves, south doesn't
move$must_move <- array(0,dim = c(2,n_seasons,2)) #n_stocks x n_seasons x n_regions
#if north stock in region 2 (south) must move back to region 1 (north) at the end of interval 2 before spawning
move$must_move[1,2,2] <- 1 #stock 1 must move at the end of season 2 from region 2
move$can_move <- array(0, dim = c(2,n_seasons,2,2))
move$can_move[1,c(1,4:5),1,2] <- 1 #only north stock can move in seasons outside of spawning and only from north to south (except at the end of season 2)
move$can_move[1,2,2,] <- 1 #north stock can (and must) move in second/last season prior to spawning back to north
We also can provide initial (or fixed) values for movement
parameters. Below we initialize the mean or constant movement
probabilities/proportions to all be 0.3 and
mean_model = "stock_constant"
defines constant movement
parameters between each region, but that they differ by stock. This
difference between stocks is necessary here because we want to define no
movement at all for the southern stock.
mus <- array(0, dim = c(2,n_seasons,2,1))
mus[1,1:n_seasons,1,1] <- 0.3 #initial value proportion moving to south = 0.3 (mean of prior)
mus[1,1:n_seasons,2,1] <- 0.3 #initial value proportion north to south = 0.3 (will not be used)
move$mean_vals <- mus
move$mean_model <- matrix("stock_constant", 2,1)
Although not necessary because we are using
diff_stocks_asap
, below we define the fixed natural
mortality for each stock and intiial values for fully selected fishing
mortality for the fleets and catchability for the indices. We define
process errrors on both recruitment and annual transitions of older ages
and we specify an equilibrium assumption for the initial numbers at age.
This simplyfing equilibrium assumption (rather than estimating each
initial abundance at age as a separate parameter) may often be necessary
because of the lack of information on abundance of individuals in each
region for each stock.
MAA <- exp(input$par$M_re)
for(i in 1:2) for(j in 1:2) MAA[i,j,,] <- MAA[i,j,,]*exp(matrix(input$par$Mpars[i,j,], length(basic_info$years), length(basic_info$ages), byrow = TRUE))
M_in <- list(initial_MAA = MAA)
F_in <- list(F = matrix(0.3, length(basic_info$years), input$data$n_fleets))
q_in <- list(initial_q = rep(1e-6, input$data$n_indices))
NAA_list <- list(sigma = "rec+1", N1_model = rep("equilibrium",2))
input_move <- prepare_wham_input(diff_stocks_asap,
basic_info = basic_info,
NAA_re = NAA_list,
selectivity = selectivity,
M = M_in,
F = F_in,
catchability = q_in,
move = move)
Now we create an unfit model just to examine how the individuals for the northern stock are moving and surviving each season.
nofit_move <- fit_wham(input_move, do.fit = FALSE, do.brps = FALSE)
WHAM calculates and reports various items in the $rep
element of the model, including the probability transition matrices for
each season in the terminal year
($rep$seasonal_Ps_terminal
, an array with dimensions:
n_stocks x n_seasons x n_ages x n_states x n_states). When there are two
stocks, 2 regions and 4 fleets, there will be 7 possible states in this
order: - alive in each region (2) - dead due to fishing by each fleet
(4) - dead due to natural mortality (1) The rows correspond to the state
at the beginning of the season and the columns correspond to the state
at the end of the season. So for the first season for the northern stock
(stock 1):
#first season
nofit_move$rep$seasonal_Ps_terminal[1,1,8,,]
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,] 0.5731115 0.2456192 0.05438077 0.05438077 0.00000000 0.00000000 0.0725077
#> [2,] 0.0000000 0.8187308 0.00000000 0.00000000 0.05438077 0.05438077 0.0725077
#> [3,] 0.0000000 0.0000000 1.00000000 0.00000000 0.00000000 0.00000000 0.0000000
#> [4,] 0.0000000 0.0000000 0.00000000 1.00000000 0.00000000 0.00000000 0.0000000
#> [5,] 0.0000000 0.0000000 0.00000000 0.00000000 1.00000000 0.00000000 0.0000000
#> [6,] 0.0000000 0.0000000 0.00000000 0.00000000 0.00000000 1.00000000 0.0000000
#> [7,] 0.0000000 0.0000000 0.00000000 0.00000000 0.00000000 0.00000000 1.0000000
Note we have specifed the PTM for first season and age 8, but the PTMs are the same across ages because as we configured in the input. There is a probability of surviving and occuring in the same region at the end of the season = 0.573 and a probability of being in the south = 0.246. There are only non-zero probabilities of capture in the northern fleets (row 1) because movement is sequential to survival and occurs at the end of the season. Starting the season in the south, there is no probabilty of surviving and being in the north because movement to the north is not allowed.
For season 2 we can see that all fish in the south must move back to the north as we specified.
#second season
nofit_move$rep$seasonal_Ps_terminal[1,2,8,,]
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,] 0.8187308 0 0.05438077 0.05438077 0.00000000 0.00000000 0.0725077
#> [2,] 0.8187308 0 0.00000000 0.00000000 0.05438077 0.05438077 0.0725077
#> [3,] 0.0000000 0 1.00000000 0.00000000 0.00000000 0.00000000 0.0000000
#> [4,] 0.0000000 0 0.00000000 1.00000000 0.00000000 0.00000000 0.0000000
#> [5,] 0.0000000 0 0.00000000 0.00000000 1.00000000 0.00000000 0.0000000
#> [6,] 0.0000000 0 0.00000000 0.00000000 0.00000000 1.00000000 0.0000000
#> [7,] 0.0000000 0 0.00000000 0.00000000 0.00000000 0.00000000 1.0000000
We can also see that there is no movement for the southern stock. They probabilities proportions in each state are always defined by the second row of the matrix because they never move from the south:
#1st season, southern stock
nofit_move$rep$seasonal_Ps_terminal[2,1,8,,]
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,] 0.8187308 0.0000000 0.05438077 0.05438077 0.00000000 0.00000000 0.0725077
#> [2,] 0.0000000 0.8187308 0.00000000 0.00000000 0.05438077 0.05438077 0.0725077
#> [3,] 0.0000000 0.0000000 1.00000000 0.00000000 0.00000000 0.00000000 0.0000000
#> [4,] 0.0000000 0.0000000 0.00000000 1.00000000 0.00000000 0.00000000 0.0000000
#> [5,] 0.0000000 0.0000000 0.00000000 0.00000000 1.00000000 0.00000000 0.0000000
#> [6,] 0.0000000 0.0000000 0.00000000 0.00000000 0.00000000 1.00000000 0.0000000
#> [7,] 0.0000000 0.0000000 0.00000000 0.00000000 0.00000000 0.00000000 1.0000000
WHAM also calculates and reports the annual probability transition
matrices ($rep$annual_Ps
, an array with dimensions:
n_stocks x n_years x n_ages x n_states x n_states) that are used to
define the numbers at age on January 1 each year and we can see that
indeed they are equal to the product of the seasonal matrices:
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,] 0.1802609 0.1876185 0.16894875 0.16894875 0.02068742 0.02068742 0.2528482
#> [2,] 0.1802609 0.1876185 0.08340172 0.08340172 0.10623444 0.10623444 0.2528482
#> [3,] 0.0000000 0.0000000 1.00000000 0.00000000 0.00000000 0.00000000 0.0000000
#> [4,] 0.0000000 0.0000000 0.00000000 1.00000000 0.00000000 0.00000000 0.0000000
#> [5,] 0.0000000 0.0000000 0.00000000 0.00000000 1.00000000 0.00000000 0.0000000
#> [6,] 0.0000000 0.0000000 0.00000000 0.00000000 0.00000000 1.00000000 0.0000000
#> [7,] 0.0000000 0.0000000 0.00000000 0.00000000 0.00000000 0.00000000 1.0000000
nofit_move$rep$annual_Ps[1,33,8,,]
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,] 0.1802609 0.1876185 0.16894875 0.16894875 0.02068742 0.02068742 0.2528482
#> [2,] 0.1802609 0.1876185 0.08340172 0.08340172 0.10623444 0.10623444 0.2528482
#> [3,] 0.0000000 0.0000000 1.00000000 0.00000000 0.00000000 0.00000000 0.0000000
#> [4,] 0.0000000 0.0000000 0.00000000 1.00000000 0.00000000 0.00000000 0.0000000
#> [5,] 0.0000000 0.0000000 0.00000000 0.00000000 1.00000000 0.00000000 0.0000000
#> [6,] 0.0000000 0.0000000 0.00000000 0.00000000 0.00000000 1.00000000 0.0000000
#> [7,] 0.0000000 0.0000000 0.00000000 0.00000000 0.00000000 0.00000000 1.0000000
#for the southern stock
P <- diag(7)
for(i in 1:5) P <- P %*% nofit_move$rep$seasonal_Ps_terminal[2,i,8,,]
P
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,] 0.3678794 0.0000000 0.1896362 0.1896362 0.0000000 0.0000000 0.2528482
#> [2,] 0.0000000 0.3678794 0.0000000 0.0000000 0.1896362 0.1896362 0.2528482
#> [3,] 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 0.0000000
#> [4,] 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000
#> [5,] 0.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000
#> [6,] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000
#> [7,] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 1.0000000
nofit_move$rep$annual_Ps[2,33,8,,]
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,] 0.3678794 0.0000000 0.1896362 0.1896362 0.0000000 0.0000000 0.2528482
#> [2,] 0.0000000 0.3678794 0.0000000 0.0000000 0.1896362 0.1896362 0.2528482
#> [3,] 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 0.0000000
#> [4,] 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000
#> [5,] 0.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000
#> [6,] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000
#> [7,] 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 1.0000000
To fit the model, first we will fix the movement parameter from south
to north for the northern stock because it is never used. No movement is
allowed by $can_move
except the complete movement of any
fish in the south back to the north at the end of the second season is
forced by $must_move
. Unfortunately,
prepare_wham_input
and set_move
are not clever
enough to figure this out yet so, we must manually edit the
$map
that is used for the map
argument to
TMB::MakeADFun
(see help file for
TMB::MakeADFun
for more details of the map argument).
input$par$trans_mu
is the array (n_stocks x n_seasons x
n_regions x n_regions-1) of movement parameters estimated on a
transformed (dependent on the whether movement is sequential or
simultaneous to mortality) scale that does not require bounds. So
trans_mu[1,,2,1]
is the movement parameters for stock 1
(northern) across all seasons (blank index is equal to specifying all
seasons 1:5) moving from region 2 (south) to region 1 (north).
x <- input_move$par$trans_mu #n_stocks x n_seasons x n_regions x n_regions - 1
x[] <- as.integer(input_move$map$trans_mu)
x[1,,2,1] <- NA
input_move$map$trans_mu <- factor(x)
There are only n_regions - 1 estimated parameters for movement for each stock, season, and starting region because the probabity of being in a given region is 1 - the sum of the probabilities of being in each of the other regions.
Now, we can fit the model and WHAM reports the movement rates
estimates as probabilities/proportions (conditional on surviving the
seasonal interval) in $rep$mu
, an array (n_stocks x n_ages
x n_seasons x n_years x n_regions x n_regions). The single estimated
seasonal movement parameter is from north to south for the northern
stock and is the estimate is very small (0.0093).
fit_move <- fit_wham(input_move, do.osa = FALSE, do.retro = FALSE, do.sdrep = FALSE, do.brps = FALSE)
#estimated movement
fit_move$rep$mu[1,8,1,1,1,2]
#> [1] 0.009262632
Next we will demonstrate estimation of age-varying movement as random
effects. We configure random effects across age using the
age_re
element of the move
argument to
prepare_wham_input
and set_move
.
age_re
is a character matrix (n_regions x n_regions - 1)
defining whether to model age-varying random effects for each movement
parameter. There is an interaction with $can_move
and
$mean_model
to define whether random effects (like the mean
fixed effects) are common across stocks, seasons, etc, and are excluded
for regions where movement is not allowed. We will specify uncorrelated
randome effects (iid
) for the movement from north to
south:
#age-specific RE
move_age <- move
move_age$age_re <- matrix("none",2,1)
move_age$age_re[1,1] <- "iid"
input_move_age <- prepare_wham_input(diff_stocks_asap,
basic_info = basic_info,
NAA_re = NAA_list,
selectivity = selectivity,
M = M_in,
F = F_in,
catchability = q_in,
move = move_age)
length(unique(input_move_age$map$mu_re)) #+1 for NAs
#> [1] 9
In our model only movement from the north to the south for the northern stock is allowed and it is constant across seasons so there will only be 8 random effects estimated and applied to all seasons (other map values are NA hence 9 unique values).
Creating the unfit model still performs the inner optimization of the random effects given the initial values of the fixed effects, so we can see that in fact there are different movement rates by age
nofit_move_age <- fit_wham(input_move_age, do.fit = FALSE, do.brps = FALSE)
#age-specific movement rates assuming initial values for fixed effects
nofit_move_age$rep$mu[1,1:8,1,1,1,2]
#> [1] 0.95778313 0.04871062 0.07582687 0.14948953 0.04344924 0.04013569 0.06542450
#> [8] 0.71981107
Fitting the model, again we must fix the movement rate parameters from south to north, and we can see that the minimized negative log-likelihood is lower allowing the age-varying random effects:
x <- input_move_age$par$trans_mu
x[] <- as.integer(input_move_age$map$trans_mu)
x[1,,2,1] <- NA
input_move_age$map$trans_mu <- factor(x)
input_move_age$par <- fit_move$parList
fit_move_age <- fit_wham(input_move_age, do.osa = FALSE, do.retro = FALSE, do.sdrep = FALSE, do.brps = FALSE)
c(fit_move$opt$obj,fit_move_age$opt$obj)
#different
#> [1] 3000.896 2998.567
And the estimated movement rates for each age are all very small like the mean in the constant model except that age 8+ jumps up to almost 0.02:
#age-specific movement rates
fit_move_age$rep$mu[1,,1,1,1,2]
#> [1] 0.001615753 0.002705349 0.004283258 0.004370262 0.004373432 0.003817055
#> [7] 0.003568121 0.019743605
Next we will demonstrate estimation of year-varying movement as
random effects. Configuring random effects across year is similar to
age. Like $age_re
, $year_re
is a character
matrix (n_regions x n_regions - 1) defining whether to model
year-varying random effects for each movement parameter. There is an
interaction with $can_move
and $mean_model
to
define whether random effects (like the mean fixed effects) are common
across stocks, seasons, etc, and are excluded for regions where movement
is not allowed. We will specify uncorrelated randome effects
(iid
) for the movement from north to south:
#year-specific RE
move_year <- move
move_year$year_re <- matrix("none",2,1)
move_year$year_re[1,1] <- "iid"
input_move_year <- prepare_wham_input(diff_stocks_asap,
basic_info = basic_info,
NAA_re = NAA_list,
selectivity = selectivity,
M = M_in,
F = F_in,
catchability = q_in,
move = move_year)
length(unique(input_move_year$map$mu_re)) #+1 for NAs
#> [1] 34
There will be n_years = 33 random effects estimated and applied to all seasons (other map values are NA hence 34 unique values).
Creating the unfit model still performs the inner optimization of the random effects given the initial values of the fixed effects, so we can see that in fact there are different movement rates by year
nofit_move_year <- fit_wham(input_move_year, do.fit = FALSE, do.brps = FALSE)
#year-specific movement rates assuming initial values for fixed effects
nofit_move_year$rep$mu[1,8,1,,1,2]
#> [1] 0.977658316 0.916290634 0.935465907 0.947032457 0.942886244 0.952737096
#> [7] 0.955271979 0.941363997 0.944740880 0.916477535 0.913576456 0.833965222
#> [13] 0.015695348 0.574161417 0.678061883 0.648547566 0.023100255 0.019701635
#> [19] 0.016110491 0.930937979 0.011090300 0.574918902 0.011525765 0.007294352
#> [25] 0.006467400 0.003884297 0.004724370 0.004253718 0.002759932 0.003336883
#> [31] 0.004775211 0.005615943 0.025153004
Fitting the model (again we must fix the movement rate parameters from south to north), we can see that the minimized negative log-likelihood allowing the year-varying random effects is the same as that when movement is constant:
x <- input_move_year$par$trans_mu
x[] <- as.integer(input_move_year$map$trans_mu)
x[1,,2,1] <- NA
input_move_year$map$trans_mu <- factor(x)
input_move_year$par <- fit_move$parList
fit_move_year <- fit_wham(input_move_year, do.osa = FALSE, do.retro = FALSE, do.sdrep = FALSE, do.brps = FALSE)
c(fit_move$opt$obj, fit_move_year$opt$obj)
#the same
#> [1] 3000.896 3000.896
The random effects collapse to annual movement rates to the constant
value and there estimated variance approaches 0 (mu_repars
is an array holding variance and correlation parameters for movement
random effects):
fit_move_year$rep$mu[1,8,1,,1,2]
#> [1] 0.009262631 0.009262632 0.009262632 0.009262632 0.009262632 0.009262631
#> [7] 0.009262632 0.009262632 0.009262631 0.009262632 0.009262631 0.009262631
#> [13] 0.009262632 0.009262631 0.009262632 0.009262632 0.009262631 0.009262632
#> [19] 0.009262632 0.009262632 0.009262632 0.009262632 0.009262631 0.009262631
#> [25] 0.009262631 0.009262631 0.009262631 0.009262632 0.009262632 0.009262631
#> [31] 0.009262632 0.009262632 0.009262632
#the log(sd) of the RE
fit_move_year$parList$mu_repars[1,1,1,1,1]
#> [1] -7.520988
Because WHAM currently has no ability to include tagging data to
inform movement and mortality rates, options to configure prior
distributions for mean movement rates are provided. The prior
distributions ideally would be based on results from external analyses
of tagging data, but here we just assume a distribution to demonstrate
the option. Prior distributions are all normal distributions on the
transformed scale of the movement paramters We specify the central
tendency using the $mean_vals
of the move
argument and $prior_sigma
is the standard devation. The
mean_vals
are not transformed but the normal distribution
will have a mean assumed with the appropriate transformation. For
example, here with the sequential assumption for movement the parameters
are all additive logit transformed so the movement rates have a logistic
normal distribution (like the age composition likelihood option) where
the same logit transformation is applied to the mean for the expectation
of the normal distribution. The estimated movement rate will be a random
effect with this distribution and used to define the estimated mean
(transformed) movement.
Different prior distributions could be used for each stock, season
and region to region parameter ($use_prior
is a n_stocks x
n_seasons x n_regions x n_regions-1 array). Because our model assumed
movement is constant across seasons, we need to make sure there is only
one random effect applied to all seasons. We wil assume the prior mean
is defined by the starting value already provided above (0.3) and
standard deviation of the normal prior is 0.2.
#just use prior once because it is constant over all seasons.
move_prior <- move
move_prior$use_prior <- array(0, dim = c(2,n_seasons,2,1))
#movement is not used in first season, but the parameter is constant across seasons. Could use it in any (single) season
move_prior$use_prior[1,1,1,1] <- 1
# sd on logit scale
move_prior$prior_sigma <- array(0, dim = c(2,n_seasons,2,1))
move_prior$prior_sigma[1,1,1,1] <- 0.2
move_prior$mean_vals[1,1,1,1] #transform (inverse logit here) of mean of the prior distribution
#> [1] 0.3
input_move_prior <- prepare_wham_input(diff_stocks_asap,
basic_info = basic_info,
NAA_re = NAA_list,
selectivity = selectivity,
M = M_in,
F = F_in,
catchability = q_in,
move = move_prior)
c(length(unique(input_move_prior$map$mu_re)), #+1 for NAs
length(unique(input_move_prior$map$mu_prior_re))) #+1 for NAs
#> [1] 1 2
We can see there are no age- or time-varying random effects for
movement and there is a single random effect for mean movement
(mu_prior_re
)
Again we must fix the movement rate parameters from south to north:
x <- input_move_prior$par$trans_mu
x[] <- as.integer(input_move_prior$map$trans_mu)
x[1,,2,1] <- NA
input_move_prior$map$trans_mu <- factor(x)
To expedite the fit, we can start at the parameters estimated by the model with movement estimated without the prior.
#fixed effect estimated in fit_move, use all estimates except the estimated mean movement parameter.
ind <- names(fit_move$parList)[!names(fit_move$parList) %in% "trans_mu"]
input_move_prior$par[ind] <- fit_move$parList[ind]
fit_move_prior <- fit_wham(input_move_prior, do.osa = FALSE, do.retro = FALSE, do.sdrep = FALSE, do.brps = FALSE)
#estimated movement
fit_move$rep$mu[1,1,1,1,1,2]
#> [1] 0.009262632
fit_move_prior$rep$mu[1,1,1,1,1,2]
#> [1] 0.1848194
When using the prior, the estimated movement rate is much greater because of the 0.3 used to parameterize the mean of the prior and the small standard deviation assumed.