Notes on the Project Workflow
This is part of the "Add sex-structure to FIMS statistical catch-at-age model" Google Summer of Code project. Earlier on in PR #1581 we introduced partitioning infrastructure into the FIMS codebase that can be used for storing partitioned quantities, including sex-specific values. While that PR is still under review, I realized that I can work on the two-sex models in parallel, and after both components (the infrastructure and the two-sex model) are complete, we can then wire them together while addressing issue #1587. I think this workflow can get the project going at a faster pace and hopefully leave us time for implementing the implicit two-sex model as well.
Summary
Introduce the explicit two-sex model for the FIMS catch-at-age population dynamics. In this formulation, life-history processes can differ by sex and evolve over time, while the model keeps a single pooled abundance state $N_{a,y}$ plus a dynamic female proportion $p_{a,y}^{\mathrm{fem}}$.
This issue covers the model formulation, state-transition logic, sex-specific life-history parameters, and user-facing model selection. It does NOT include demand-driven partitioned likelihood wiring (NeedPartitionedLandings, sex-specific expected landings/index). That work stays blocked on the partition infrastructure PR and will be a follow-up addressed in issue #1587.
Current Status
In PR #1581, we've already registered fleet-level observation quantities (e.g. landings/index_numbers_at_age and landings/index_weight_at_age by partition. These are built on the infrastructure added in PR #1581, including a default sex-partition initialized in CatchAtAge::Initialize().
Implementation Details
Model Formulation
State Variables:
-
$N_{a,y}$: Total numbers at age $a$, year $y$
-
$p_{a,y}^{\mathrm{fem}}$: Proportion female at age $a$, year $y$
Sex-specific life-history parameters:
| Parameter |
Current Codebase |
Explicit Two-Sex |
| Natural mortality |
$M_{a,y}$ via log_M
|
$M_{a,y}^{\mathrm{fem}}$, $M_{a,y}^{\mathrm{male}}$
|
| Fishing mortality |
$F_{f,a,y} = F_{f,y}, f_y, S_f(a)$ |
Sex-specific $S_f^{\mathrm{sex}}(a) \rightarrow F_{a,y}^{\mathrm{sex}}$
|
| Total mortality |
$Z_{a,y} = M_{a,y} + F_{a,y}$ |
$Z_{a,y}^{\mathrm{sex}} = M_{a,y}^{\mathrm{sex}} + F_{a,y}^{\mathrm{sex}}$ |
Transition dynamics:
$$
\begin{aligned}
N^{\mathrm{fem}}_{a,y}
&=
p^{\mathrm{fem}}_{a-1,y-1}
N_{a-1,y-1}
e^{-Z^{\mathrm{fem}}_{a-1,y-1}}
\\
N^{\mathrm{male}}_{a,y}
&=
\left(
1 - p^{\mathrm{fem}}_{a-1,y-1}
\right)
N_{a-1,y-1}
e^{-Z^{\mathrm{male}}_{a-1,y-1}}
\\
N_{a,y}
&=
N^{\mathrm{fem}}_{a,y}
+
N^{\mathrm{male}}_{a,y}
\\
p^{\mathrm{fem}}_{a,y}
&=
\frac{N^{\mathrm{fem}}_{a,y}}{N_{a,y}}
\end{aligned}
$$
Initial conditions: users supply $p_{a,0}^{\mathrm{fem}}$ only (age-specific at the initial year). Later $p_{a,y}^{\mathrm{fem}}$ are computed by the update above. This differs from the sex-ratio-at-age and implicit models, where $p_a^{\mathrm{fem}}$ is fixed across years.
Architectural Approach
- Store sex-specific intermediate states in population-level partitioned derived quantities indexed by
IndexLayout::i_stratum_age_year() (e.g. numbers_at_age_by_partition, mortality_M_by_partition, mortality_F_by_partition, mortality_Z_by_partition).
- Keep numbers_at_age as the pooled total $N_{a,y}$.
- Extend proportion_female storage to support year-varying values for explicit mode (e.g.
proportion_female_at_age_year of size n_ages × n_years).
- Branch in
CalculateNumbersAA, CalculateMortality, and related functions on a new sex_structure model option.
- Fleet-level
*_by_partition containers (already registered) will later read from population partitioned state when demand wiring lands.
TODOs
Model option and API surface
Register population-level partitioned life-history containers
Sex-specific parameter inputs
Explicit transition dynamics
stratum_split_factor integration
Notes on the Project Workflow
This is part of the "Add sex-structure to FIMS statistical catch-at-age model" Google Summer of Code project. Earlier on in PR #1581 we introduced partitioning infrastructure into the FIMS codebase that can be used for storing partitioned quantities, including sex-specific values. While that PR is still under review, I realized that I can work on the two-sex models in parallel, and after both components (the infrastructure and the two-sex model) are complete, we can then wire them together while addressing issue #1587. I think this workflow can get the project going at a faster pace and hopefully leave us time for implementing the implicit two-sex model as well.
Summary
Introduce the explicit two-sex model for the FIMS catch-at-age population dynamics. In this formulation, life-history processes can differ by sex and evolve over time, while the model keeps a single pooled abundance state$N_{a,y}$ plus a dynamic female proportion $p_{a,y}^{\mathrm{fem}}$ .
This issue covers the model formulation, state-transition logic, sex-specific life-history parameters, and user-facing model selection. It does NOT include demand-driven partitioned likelihood wiring (
NeedPartitionedLandings, sex-specific expected landings/index). That work stays blocked on the partition infrastructure PR and will be a follow-up addressed in issue #1587.Current Status
In PR #1581, we've already registered fleet-level observation quantities (e.g.
landings/index_numbers_at_ageandlandings/index_weight_at_ageby partition. These are built on the infrastructure added in PR #1581, including a default sex-partition initialized inCatchAtAge::Initialize().Implementation Details
Model Formulation
State Variables:
Sex-specific life-history parameters:
log_MTransition dynamics:
Initial conditions: users supply$p_{a,0}^{\mathrm{fem}}$ only (age-specific at the initial year). Later $p_{a,y}^{\mathrm{fem}}$ are computed by the update above. This differs from the sex-ratio-at-age and implicit models, where $p_a^{\mathrm{fem}}$ is fixed across years.
Architectural Approach
IndexLayout::i_stratum_age_year()(e.g.numbers_at_age_by_partition,mortality_M_by_partition,mortality_F_by_partition,mortality_Z_by_partition).proportion_female_at_age_yearof sizen_ages × n_years).CalculateNumbersAA,CalculateMortality, and related functions on a newsex_structuremodel option.*_by_partitioncontainers (already registered) will later read from population partitioned state when demand wiring lands.TODOs
Model option and API surface
SexStructureenum / string constant (sex_ratio_at_age,implicit_two_sex,explicit_two_sex) on Population or CatchAtAge.sex_ratio_at_age.Register population-level partitioned life-history containers
n_strata × n_years × n_ages):numbers_at_age_by_partitionmortality_M_by_partitionmortality_F_by_partitionmortality_Z_by_partitionproportion_female_at_age_year(sizen_ages × n_years) for dynamicIndexLayout.Note: fleet-level *_by_partition containers already exist, this step adds the upstream population state they will consume.
Sex-specific parameter inputs
log_M. If the user still supplies a pooledlog_Mbut wishes to use the explicit two-sex model, then we will duplicate the pooled values into the sex-specificlog_Mcontainers so that both female and malelog_Muse the pooled values, i.e.mortality_F_by_partition.Prepare()transformations for any new estimated parameters.Explicit transition dynamics
CalculateSpawningBiomassto use year-varyingstratum_split_factorintegrationsex_structure == explicit_two_sex.numbers_at_age_by_partition/numbers_at_ageafter each time step.