Skip to content

Introduce the explicit two-sex model for the FIMS catch-at-age population dynamics #1625

Description

@szu-yun-ko

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

  • Define SexStructure enum / string constant (sex_ratio_at_age, implicit_two_sex, explicit_two_sex) on Population or CatchAtAge.
  • Expose via PopulationInterface + src/rcpp_population.cpp + initialize_modules.R.
  • Document option in roxygen and default to sex_ratio_at_age.
  • Add validation: explicit mode rejects incompatible configurations with a clear error.

Register population-level partitioned life-history containers

  • Register population derived quantities (size n_strata × n_years × n_ages):
    • numbers_at_age_by_partition
    • mortality_M_by_partition
    • mortality_F_by_partition
    • mortality_Z_by_partition
  • Register year-varying proportion_female_at_age_year (size n_ages × n_years) for dynamic $p_{a,y}^{\mathrm{fem}}$.
  • Wire dimensions in rcpp_models.hpp using existing IndexLayout.
    Note: fleet-level *_by_partition containers already exist, this step adds the upstream population state they will consume.

Sex-specific parameter inputs

  • Natural mortality: allow sex-specific log_M. If the user still supplies a pooled log_M but wishes to use the explicit two-sex model, then we will duplicate the pooled values into the sex-specific log_M containers so that both female and male log_M use the pooled values, i.e. $M_{a,y}^{\mathrm{fem}}$ = $M_{a,y}^{\mathrm{male}} = M_{a,y}^{\mathrm{(pooled)}}$.
  • Selectivity / F: sex-specific selectivity per flee, update CalculateMortality to fill mortality_F_by_partition.
  • Growth / weight: sex-specific weight-at-age.
  • Update Prepare() transformations for any new estimated parameters.

Explicit transition dynamics

  • Implement explicit branch in CalculateNumbersAA with formulas above, including plus-group handling for both sexes before summing to $N_{a,y}$.
  • Implement dynamic $p_{a,y}^{\mathrm{fem}}$ update after abundance calculation.
  • Age-0 / recruitment: define how $p_{0,y}^{\mathrm{fem}}$ enters (initial user input at $y=0$; align recruitment sex-split rule with mentors).
  • Update CalculateSpawningBiomass to use year-varying $p_{a,y}^{\mathrm{fem}}$ and sex-appropriate weight in explicit mode.

stratum_split_factor integration

  • Update split-factor call sites to read dynamically updated $p_{a,y}^{\mathrm{fem}}$ when sex_structure == explicit_two_sex.
  • Ensure split factors are consistent with numbers_at_age_by_partition / numbers_at_age after each time step.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions