20 Spatial Structure
openMSE supports spatially structured operating models with an arbitrary number of discrete areas. Fish move between areas according to a movement probability matrix, and fishing effort can be distributed across areas either dynamically or according to a fixed allocation (see Section 20.8). Management can be applied differentially by area through spatial closures, area-specific selectivity and retention, and area-specific discard mortality.
The Spatial subcomponent of a Stock object defines the spatial structure. It is optional; if omitted the model assumes a single well-mixed area with no spatial dynamics.
This chapter describes the available approaches for specifying spatial structure, from the simplest two-area case through to models with age-varying movement and three or more areas. All Stock objects within an operating model must share the same spatial configuration (i.e., the same number of areas).
20.1 Single-Area Models
For a non-spatial model, simply omit the Spatial subcomponent entirely. Populate() will create a default single-area structure automatically:
# No Spatial subcomponent — single well-mixed area assumed
stock <- Stock(Name = "My Stock")
# Spatial(stock) is NULL; Populate() will assign a single-area default20.2 Two-Area Models
Two-area models are a common spatial configuration. They require three inputs: the unfished biomass distribution across areas, the probability of remaining in an area, and the relative size of each area.
For two-area models, UnfishedDist and RelativeSize each specify Area 1 only; the corresponding Area 2 values are derived as 1 - x. Similarly, ProbStaying specifies Area 1 only; the Area 2 staying probability is solved internally so that the asymptotic movement equilibrium reproduces the target UnfishedDist.
Each parameter accepts a scalar (constant across all simulations), a length-2 bounds vector (sampled from Uniform(lower, upper) independently for each simulation), or a full Sim × Area × Age × Year array:
# Fixed — same across all simulations
Spatial(stock) <- Spatial(
UnfishedDist = 0.3,
ProbStaying = 0.7,
RelativeSize = 0.4
)20.3 Relative Area Size
RelativeSize controls how biomass is converted to density for the purpose of spatial effort allocation. Fleets are attracted to areas with high biomass density (biomass per unit area), so RelativeSize affects where effort concentrates even when biomass is held constant.
Three options are available:
Fixed proportion: a scalar or bounds vector giving the fraction of total habitat in Area 1 (Area 2 = 1 - RelativeSize):
RelativeSize = 0.4 # Area 1 is 40% of total habitatEqual density: setting RelativeSize = "EqualDensity" sets each area’s relative size equal to its mean unfished biomass share across ages and years. This ensures that unfished biomass density is equal across areas:
Spatial(stock) <- Spatial(
UnfishedDist = 0.3,
ProbStaying = 0.7,
RelativeSize = "EqualDensity"
)Equal size: when RelativeSize is omitted (NULL), all areas are assumed equal in size (1 / nArea each).
20.4 How the Movement Matrix is Derived
When UnfishedDist and ProbStaying are supplied, Populate() derives the movement probability matrix by numerical optimisation. For each simulation, age, and year, the matrix diagonal (staying probabilities) and off-diagonal elements (movement probabilities) are fitted to simultaneously satisfy:
- The asymptotic distribution implied by the movement matrix matches the target
UnfishedDist. - The diagonal elements match the target
ProbStaying.
For two-area models this system has a closed-form solution. For models with three or more areas, a penalty-based optimisation is used (see Section 20.6).
The resulting Movement array has dimensions Sim × FromArea × ToArea × Age × Year. Row [i, ] gives the probabilities of moving from area i to each other area, and rows sum to 1. See Section 27.6 for the full mathematical treatment of movement in the population dynamics.
20.5 Age-Varying Movement
Movement rates can vary by age by supplying UnfishedDist and/or ProbStaying as arrays with an Age dimension. The movement matrix is then fitted independently for each age class.
An example application is ontogenetic habitat shift, where juveniles and adults occupy different areas:
ages <- Ages(MaxAge = 10)
nage <- nAge(ages)
# Juveniles concentrate in Area 1; adults spread to Area 2
area1_frac <- seq(0.8, 0.2, length.out = nage)
ud <- array(
c(area1_frac, 1 - area1_frac),
dim = c(1, 2, nage),
dimnames = list(Sim = 1, Area = 1:2, Age = Classes(ages))
)
Spatial(stock) <- Spatial(
UnfishedDist = ud,
ProbStaying = 0.9
)20.6 Multi-Area Models
Models with three or more areas require UnfishedDist to be supplied as an array summing to 1 across the Area dimension, and additionally require FracOther to guide the movement optimisation.
FracOther is a Sim × FromArea × ToArea array (optionally extended with Age and Year dimensions) where off-diagonal element [i, j] gives the relative probability of moving from area i to area j. Diagonal elements must be NA as the staying probability is taken from ProbStaying. The values in FracOther need not sum to 1; they are normalised internally.
nArea <- 3
# Unfished biomass: 50% in Area 1, 20% in Area 2, 30% in Area 3
ud <- matrix(c(0.5, 0.2, 0.3), nrow = 1, ncol = nArea)
# FracOther: relative movement probabilities between areas
# Area 1 mostly connects to Area 2, weakly to Area 3
# Area 2 connects equally to Areas 1 and 3
# Area 3 mostly connects to Area 2, weakly to Area 1
fo <- array(NA, dim = c(1, nArea, nArea))
fo[1, 1, ] <- c(NA, 1, 0.1)
fo[1, 2, ] <- c(1, NA, 1 )
fo[1, 3, ] <- c(0.1, 1, NA )
Spatial(stock) <- Spatial(
UnfishedDist = ud,
ProbStaying = c(0.9, 0.2, 0.9),
FracOther = fo,
RelativeSize = c(0.1, 0.4, 0.5)
)See Section 27.6.1 for the technical details regarding how the movement matrix is calculated.
20.7 Supplying a Movement Matrix Directly
As an alternative to specifying UnfishedDist and ProbStaying and letting Populate() derive the movement matrix, the movement matrix can be supplied directly. This is useful when the matrix has been estimated externally (e.g., from a tagging study or a spatially-explicit model).
The matrix must have dimensions Sim × FromArea × ToArea, optionally extended to Sim × FromArea × ToArea × Age × Year. When Movement is supplied, the asymptotic unfished distribution is back-calculated from the matrix and assigned to UnfishedDist, overwriting any values already present:
20.8 Spatial Effort Allocation
Spatial structure in the Stock object defines where fish are. How fishing effort is distributed across areas is controlled by the Effort subcomponent of each Fleet object, specifically the Distribution and Targeting slots.
When Distribution is not specified, effort is allocated dynamically each year based on relative exploitable biomass density across areas, with the degree of concentration controlled by the Targeting parameter. A value of 0 produces uniform effort allocation regardless of biomass distribution; larger values concentrate effort more strongly in the highest-density area. The default Targeting value is 0.8.
Users can fix effort to a specific spatial allocation by supplying Distribution as a Sim × Year × Area array, bypassing the dynamic allocation algorithm entirely. Any cells set to a non-NA value are treated as fixed overrides and are not modified.
See ?Effort for full documentation of Distribution and Targeting, and Section 27.2 for the mathematical specification of the spatial effort allocation algorithm. Area-specific selectivity, retention, and discard mortality are documented in Chapter 25.
20.9 Summary
| Scenario | Approach |
|---|---|
| No spatial structure | Omit Spatial entirely |
| Two areas, constant movement | Scalar UnfishedDist, ProbStaying, RelativeSize
|
| Two areas, uncertain movement | Length-2 bounds vectors for each parameter |
| Two areas, age-varying movement |
Sim × Area × Age array for UnfishedDist
|
| Three or more areas | Array UnfishedDist + FracOther
|
| Known movement matrix | Supply Movement directly |
| Equal biomass density across areas | RelativeSize = "EqualDensity" |
