16 Specifying Biological and Fleet Schedules
Several subcomponent objects in openMSE share a common structure for specifying parameter schedules across simulations and years. This structure applies to the biological subcomponents of Stock:Length, Weight, NaturalMortality, Maturity, and Fecundity, and to the Fleet subcomponents Selectivity and Retention.
Each of these objects has the same three core slots:
-
Pars: a named list of model parameters -
Model: a model function that mapsParsto a schedule -
MeanAt*: aSim × Age × Year(orSim × Class × Year) array of the resulting schedule
This chapter describes the two ways to populate a schedule, the accepted input formats for Pars, the dimension conventions for MeanAt* arrays, and how to supply custom model functions.
16.1 Two Ways to Specify a Schedule
There are two approaches for specifying a biological or fleet schedule. They are mutually exclusive: if Pars contains valid parameter values that can be matched to a model, it takes precedence and any values already in MeanAt* slots will be overwritten.
16.1.1 Option 1: Model-based (recommended)
Supply Pars as a named list whose element names match the arguments of a built-in model function. The model is resolved internally by scanning the candidate models for the object class (e.g., LengthModels) and finds the one whose formal argument names match the names in Pars. You may also set Model explicitly to a character string or a custom R function (see Section 16.6).
When model-based, Pars are expanded to Sim × Year arrays by Populate(), the model function is called to produce MeanAtAge (or MeanAtLength/MeanAtWeight for size-based models), and any existing values in MeanAt* slots are overwritten. The mechanics of Populate() are covered in Chapter 17.
16.1.2 Option 2: Direct array
Leave Pars = list() (the default) and supply MeanAtAge, MeanAtLength, or MeanAtWeight directly as a numeric array. No model is inferred and no overwriting occurs.
16.2 Input Formats for Pars
Each element of Pars may be supplied in any of the following forms. All are converted internally to Sim × Year arrays by Populate() before the model function is called.
16.2.1 Scalar
A single value applied identically to all simulations and years:
Pars = list(M = 0.2)16.2.2 Length-2 bounds vector
Values are sampled independently for each simulation from Uniform(lower, upper), producing inter-simulation uncertainty in the parameter. When nSim = 1, the mean of the bounds is used:
This is the most common format for reflecting parameter uncertainty in an operating model, and is used throughout the built-in example objects.
16.2.3 Length-nSim vector
One value per simulation, held constant across all years. Used when simulation-specific values have already been determined (e.g., drawn from a posterior distribution):
16.2.4 Sim × Year array with named dimensions
A fully time-varying specification. Only the years at which the parameter changes need to be included; Extend() forward-fills all intermediate and future years automatically from the most recently supplied value:
A single-simulation array (Sim dimension of length 1) is replicated to all nSim simulations automatically.
16.2.5 Temporal random walk
Append a companion entry named <ParName>SD to Pars. A mean-preserving log-normal random walk is then applied to the base parameter value across years, generating inter-annual variation within each simulation. The SD entry is removed from Pars after use:
Pars = list(M = 0.2, MSD = 0.1)
# M varies around 0.2 from year to year with log-normal SD of 0.1This can be combined with any of the above formats for the base parameter. For example, a length-2 bounds vector for M with MSD produces a schedule where the mean level of \(M\) differs across simulations and varies randomly within each simulation over time.
16.3 MeanAt* Array Formats and Dimension Conventions
All MeanAt* arrays use named dimensions. The expected dimension names depend on the type of schedule:
| Array | Dimensions |
|---|---|
MeanAtAge |
Sim × Age × Year |
MeanAtLength |
Sim × Class × Year |
MeanAtWeight |
Sim × Class × Year |
As with Pars, only the years at which the schedule changes need to be supplied; Extend() forward-fills all other years. A single-simulation array is replicated to all nSim simulations automatically.
A plain numeric vector of length nAge is also accepted for MeanAtAge and is promoted to a 1 × nAge × 1 array automatically.
16.4 How MeanAtLength and MeanAtWeight Relate to MeanAtAge
openMSE uses age-based accounting internally, so MeanAtAge is ultimately what the model requires. MeanAtLength and MeanAtWeight serve two roles:
- Generating size-structured data: observed length and weight compositions, length-based indices, and similar outputs are produced from the size-based schedules.
-
Conversion to
MeanAtAge: when a schedule is expressed in terms of size (e.g., a length-based maturity ogive or length-based selectivity curve),MeanAtLengthorMeanAtWeightis converted toMeanAtAgevia the age-length key (ALK) or age-weight key (AWK).
The conversion rules are:
- If
MeanAtLengthis populated andMeanAtAgeis not,Populate()convertsMeanAtLength→MeanAtAgevia theALK. - If
MeanAtWeightis populated andMeanAtAgeis not,Populate()convertsMeanAtWeight→MeanAtAgevia theAWK. - If
MeanAtAgeis already populated it is not overwritten by this conversion. - If both
MeanAtLengthandMeanAtAgeare populated,MeanAtAgetakes precedence andMeanAtLengthis used only for size-based outputs.
For model-based specifications, whether the model populates MeanAtAge directly or via MeanAtLength depends on the model function’s signature: models that accept a Length argument produce MeanAtLength first and then convert to MeanAtAge via the ALK; age-based models populate MeanAtAge directly.
16.5 Model Resolution
When Pars is non-empty and Model is NULL, the model internally scans the candidate model functions for the object class — for example, all functions registered as "LengthModel" for a Length object — and finds the one whose formal argument names match the names in Pars exactly (excluding auxiliary arguments such as Ages, Length, and Weight, and ignoring any SD-suffixed entries used for random walks).
If no unique match is found, an informative error is thrown directing the user to the relevant *Models() function (e.g., ?LengthModels, ?MaturityModels).
You may bypass automatic inference by setting Model explicitly:
- Character string: the name of a built-in model (must exist as an exported function of the appropriate class).
-
R function: a custom function whose formal arguments match the names in
Pars; see Section 16.6.
If Model is already a function object (from a previous call), FindModel() returns it unchanged.
16.6 Custom Models
Any R function can be used as a model by passing it to Model. The function must:
- accept arguments whose names match the elements of
Pars; - accept any required auxiliary arguments (
Ages,Length,Weight, etc.) as appropriate for the schedule type; - return a named array with dimensions
Sim × Age × Year(for age-based outputs) orSim × Class × Year(for size-based outputs).
For example, the following custom natural mortality function produces an age-declining \(M\) schedule:
Here M is sampled from U(0.3, 0.5) across simulations, and declining_M maps each simulated value to an age-varying schedule that declines from M at the youngest age to M/2 at the oldest.
Custom models follow the same Pars input format rules described above, so M can be a scalar, a length-2 bounds vector, a length-nSim vector, or a Sim × Year array. The Pars expansion to Sim × Year arrays is handled by Populate() before the custom function is called, so the function receives a single numeric value for each parameter, not an array.
16.7 Summary
| Want to specify… | Use |
|---|---|
| A single fixed value for all sims and years | Scalar in Pars
|
| Uniform distribution across simulations | Length-2 bounds vector in Pars
|
| Pre-determined per-simulation values | Length-nSim vector in Pars
|
| A step-change at a known year |
Sim × Year array in Pars
|
| Inter-annual random variation within sims |
<Par>SD companion entry in Pars
|
| A fully custom schedule | Direct MeanAt* array, or Pars + custom Model function |
