Allow catchability to vary among groups or through time without fitting an
unrelated fixed coefficient for every value. Use these markers as additive
terms in index_settings$q_form, F_settings$mu_form, or
M_settings$mu_form, catch_settings$sd_form, or index_settings$sd_form;
ordinary formula terms supply the baseline.
Recruitment uses a separate named residual process in rec_settings;
see recruitment_formulas for its initial-state convention.
Usage
iid(x, by = NULL, sd = NULL)
rw(x, by = NULL, sd = NULL)
ar1(x, by = NULL, sd = NULL, phi = NULL)Details
iid(x) gives each level an independent, mean-zero Normal effect.
(1 | group) is shorthand for iid(group). rw(x) allows changes to persist:
its first effect is zero and successive increments are independent Normal
variables. ar1(x) describes fluctuations that tend to return to zero; its
first state has the stationary Normal distribution. Estimated AR1 correlation
is between zero and one. Integer numeric coordinates preserve calendar gaps;
ordered factors use their declared order. RWs and AR1 need ordered coordinates.
Gaussian effects are added on the selected log/logit scale, not the q scale.
Numeric by multiplies one shared trajectory by that covariate. Factor or
character by gives independent group trajectories sharing one SD and, for
AR1, one correlation. IID/AR1 effects are not forcibly centered. SD is estimated
unless supplied: marginal SD for IID, increment/innovation SD for RW/AR1.
Terms must be additive, with bare column names. Unsupported aliases and
observation-specific IID effects indistinguishable from estimated observation
error are rejected. For sparse data, simpler formulas or supplied process SDs
may be necessary. Passing design checks does not establish biological
identifiability; inspect check_tam().
With a logit link, fitting warns when observation-specific IID variation and
observation SD are both estimated: the nonlinear link does not guarantee
useful separation. Groups with fewer than five observed effect levels are
also flagged when process SD or correlation is estimated. These are
descriptive cautions, not additional model restrictions. Projection years,
missing/zero observations and zero numeric multipliers do not supply support.
Forecast states follow the same normalized process density and are integrated out when there are no observations. At the fitted mode, new IID levels have zero effect, RW holds its last level, and AR1 decays toward zero. Simulation includes future process variation. These are conditional predictions on the link scale, not marginal response-scale means.
For F and M means, effects are added to log mean mortality. The absolute
latent states remain log_f and log_m; their residuals are calculated
relative to the resulting mean surfaces. A shared rw(year) or ar1(year)
can describe a population-wide change while process = "iid" represents
independent residual fluctuations by age (F) or age block (M).
M also supports structured means with process = "off".
Existing supplied M is an offset: ~ 0 + rw(year) modifies it without
estimating another baseline. Effects must be constant within each fitted
M age block. Use a categorical age column for separate trajectories;
numeric by = age instead multiplies one shared trajectory by age.
One temporal mean term is permitted on each set of applicable F/M rows,
with IID residuals or the residual process off. Disjoint for_fleet() scopes
can therefore have different temporal means. Structured means with RW/AR1 residuals are
rejected pending evidence that both temporal components can be separated,
except for the age-group M random slopes described below.
Two estimated IID variances on the same states are also rejected.
Known design redundancies are checked, but sparse observations and the
trade-off between F, M, recruitment and catchability can still make a
numerically converged model weakly identified. Use recovery simulations
before interpreting separate process components.
Fitting warns when M mean and IID residual SDs are both estimated, or when
both F and M mean SDs are estimated. Recovery experiments found weak
separation of small M components and imprecise AR1 persistence; begin with
mean-only M and add residual variation only when supported by the data.
check_tam() retains these cautions and flags wide SD/correlation intervals.
Warnings do not change the fitted model or establish non-identifiability.
M covariate slopes with AR1 residuals
M_settings$process = "ar1" also permits one
iid(age_group, by = covariate) mean term. Each age-defined group receives
one slope, reused across years; the numeric covariate multiplies it.
Store both columns in data$pop_covariates. Group membership must be constant
through time at each age. Supplied M, ordinary terms and random slopes must
all agree within each M state block: age_breaks still pools actual M,
not just its unexplained deviations. Use finer breaks for distinct age slopes.
For example, ~ 0 + capelin + iid(M_age_group, by = capelin) gives
$$\log M_{t,b} = \log M^{supplied}_{t,b}
+ (\beta + u_{g(b)})x_{t,b} + \eta_{t,b},
\qquad u_g \sim N(0,\tau^2).$$
The residual matrix \(\eta\) retains the existing stationary age/year AR1
distribution and innovation-scale SD. Random slopes are independent of it.
The ordinary covariate term estimates the common slope \(\beta\); omit
that term to centre slopes on zero. No common slope, covariate centring,
sign restriction or covariate transformation is added automatically.
Supplied covariates remain external inputs, not functions recalculated from
the fitted population. Simulation draws one slope per group before drawing
the M states. Forecast covariates retain the existing terminal-value rule.
This combination is experimental. Persistent covariates may be difficult to
distinguish from persistent M deviations. Fitting and check_tam() flag it,
and flag fewer than five informative slope groups when estimating their SD.
Several ages sharing one M state do not increase the number of independent
groups. Inspect uncertainty and compare a common fixed-slope model.
With a positive-definite uncertainty calculation, check_tam() also applies
the existing wide-SD and AR1-interval cautions to these M residual parameters.
Other Gaussian means with AR1 residuals, multiple random-slope terms and the
corresponding F extension remain unsupported.
In observation SD formulas, Gaussian effects modify log SD:
\(\log \sigma_i = \log \sigma_{supplied,i} + X_i\beta + z_i\).
A positive effect increases residual spread; it does not change the expected
log observation. For example, ~ iid(age) partially pools SDs across ages,
while ~ survey + rw(age, by = survey) gives separate smooth age patterns.
SD remains positive. Supplied SDs are offsets and remove the ordinary
intercept, as for fixed SD formulas. The effect's process SD describes
variation in log SD, not observation error itself. There is no requirement
that the age curve rise at either tail; a quadratic fixed age term is also
a useful simpler alternative when that pattern is expected.
One RW/AR1 term is initially allowed per observation SD surface. mono()
and logistic() remain catchability curves. Replication across years at each
age helps estimate residual spread; a few ages give little information about
AR1 persistence. Fitting warns about levels with fewer than three observations
and estimated processes with fewer than five observed levels per group.
These descriptive cautions exclude missing/zero observations and projections.
Observation-specific random SDs are scale mixtures, not the same variance
component as an additive Gaussian random mean; they are permitted with a
sparse-support warning. SD effects are integrated using RTMB's Laplace
approximation, so recovery checks are especially useful with sparse data.
This extension does not introduce formulas for latent N/F/M process SDs.
Estimated catch-SD age random walks also trigger an advisory: full-model
recovery simulations frequently failed when F was estimated jointly, despite
good isolated recovery. Compare IID age effects or a fixed age curve and
inspect numerical diagnostics. This caution does not forbid the model.
Examples
~ survey + iid(year, by = survey)
#> ~survey + iid(year, by = survey)
#> <environment: 0x5edf816bb4d0>
~ survey + rw(year, by = survey)
#> ~survey + rw(year, by = survey)
#> <environment: 0x5edf816bb4d0>
~ survey + ar1(year, by = survey)
#> ~survey + ar1(year, by = survey)
#> <environment: 0x5edf816bb4d0>
~ survey + (1 | vessel)
#> ~survey + (1 | vessel)
#> <environment: 0x5edf816bb4d0>
# F_settings = list(process = "iid", mu_form = ~ factor(age) + rw(year))
# M_settings = list(process = "off", mu_supplied = ~ I(0.2),
# mu_form = ~ 0 + ar1(year))
# M_settings = list(process = "ar1", mu_supplied = ~ I(0.3),
# mu_form = ~ 0 + capelin + iid(M_age_group, by = capelin))
# catch_settings = list(sd_form = ~ iid(age))
# index_settings = list(q_form = ~ survey,
# sd_form = ~ survey + ar1(age, by = survey))