Add partition spec and index layout infrastructure for sex strata#1581
Add partition spec and index layout infrastructure for sex strata#1581szu-yun-ko wants to merge 11 commits into
Conversation
🎨 Chore: code formatting workflowOur automated workflows cannot run on forks because of permission issues, and thus, we ask that you run the following code locally and push any changes that are created to your feature branch. You will only be reminded of this once per PR. Thank you! Format C++ code
Format R code
styler::style_pkg() # Style R code
roxygen2::roxygenise() # Update documentation
styler::style_pkg() # Style R code again
roxygen2::roxygenise() # Update documentation again
usethis::use_tidy_description() # Style DESCRIPTION filePush changes
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1581 +/- ##
==========================================
+ Coverage 87.32% 87.69% +0.36%
==========================================
Files 100 103 +3
Lines 9060 9307 +247
Branches 539 596 +57
==========================================
+ Hits 7912 8162 +250
+ Misses 1111 1105 -6
- Partials 37 40 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@awilnoaa @nathanvaughan-NOAA @Andrea-Havron-NOAA This PR should be ready for an initial review. This PR addresses the tasks mentioned in issue #1557, after the review comments are addressed, I will continue tackling tasks in issue #1587 in this same PR. Partition representation:
Wiring into population:
Partitioned derived-quantity storage:
Tests added:GTest
testthat
|
7a0195e to
e8169b0
Compare
There was a problem hiding this comment.
Pull request overview
Adds the first layer of partition/indexing infrastructure to support sex strata in population dynamics (as groundwork for future partitioned state/derived quantities), and exposes the new stratum dimension through the R output reshaping and related tests.
Changes:
- Introduces partition primitives (
Axis,GroupSelector,PartitionSpec) and indexing helpers (IndexLayout) plus a default sex partition spec. - Stores
partition_specandindex_layoutonPopulationand initializes default sex partition/index layout inCatchAtAge::Initialize(). - Adds partitioned fleet derived-quantity containers (storage only), updates R output dimension naming (
stratum_i), and updates/extends gtests + testthat snapshots.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/testthat/test-get_estimates.R | Updates expected estimate columns to include stratum_i. |
| tests/testthat/_snaps/get_estimates.md | Updates snapshot output for new column and row/col counts. |
| tests/gtest/test_population_test_fixture.hpp | Initializes partitioned fleet age-based derived quantity vectors in fixtures. |
| tests/gtest/test_population_Subpopulation.cpp | Adds unit tests for PartitionSpec and IndexLayout. |
| tests/gtest/test_population_CatchAtAge_InitializePartition.cpp | Adds fixture-based test for default partition/index layout initialization in CatchAtAge::Initialize(). |
| tests/gtest/test_fleet_Fleet_InitializePrepare.cpp | Extends fleet DQ size/reset expectations to include partitioned vectors. |
| tests/gtest/CMakeLists.txt | Registers the two new gtest executables. |
| R/reshape_output.R | Maps n_strata dimension header to stratum_i for tidy output. |
| inst/include/population_dynamics/population/subpopulation.hpp | Implements partition spec structures, indexing layout, and default sex partition helper. |
| inst/include/population_dynamics/population/population.hpp | Adds partition_spec and index_layout members to Population. |
| inst/include/models/functors/catch_at_age.hpp | Initializes default sex partition spec and index layout during model initialization. |
| inst/include/interface/rcpp/rcpp_objects/rcpp_models.hpp | Adds partitioned fleet DQ vectors + dimension metadata for R interface output. |
Comments suppressed due to low confidence (1)
inst/include/interface/rcpp/rcpp_objects/rcpp_models.hpp:1276
index_weight_at_age(and itsDimensionInfo) are initialized a second time immediately afterindex_weight_at_age_by_partition. This duplicate block is redundant and likely accidental; it should be removed to avoid confusion and to ensure future edits don’t update only one copy.
derived_quantities["index_weight_at_age"] = fims::Vector<Type>(
fleet_interface->n_years.get() * fleet_interface->n_ages.get());
derived_quantities_dim_info["index_weight_at_age"] =
fims_popdy::DimensionInfo(
"index_weight_at_age",
88bc528 to
006edbf
Compare
Keep PartitionSpec axis-agnostic with stratum_split_factor() for precomputed per-stratum weights. Add SexStratumSplitFactors() as a companion to MakeDefaultSexPartitionSpec() so proportion_female is supplied at evaluation time, not stored on the spec.
Map n_strata to stratum_i in reshape_output and update snapshots for partitioned fleet derived quantities on top of current main.
364d010 to
a7e0ab9
Compare
|
This PR already adds partition structure (
// Pooled write (unchanged)
const Type pooled = (Fmort * f_multiplier * selectivity) / Z
* N_aa * (1 - exp(-Z));
fdq_["landings_numbers_at_age"][i_age_year] += pooled;
// Partitioned write (future; sex-only Model 1)
const auto split_factors = SexStratumSplitFactors(
population->partition_spec,
population->proportion_female.get_force_scalar(age));
for (size_t s = 0; s < population->partition_spec.n_strata(); ++s) {
const size_t i_part =
population->index_layout.i_stratum_age_year(s, year, age);
fdq_["landings_numbers_at_age_by_partition"][i_part] +=
pooled * population->partition_spec.stratum_split_factor(s, split_factors);
}The changes in this PR so far addresses all tasks mentioned in issue #1557 and I'll proceed to work on #1587 after the current work is reviewed. |
| } | ||
|
|
||
| /** | ||
| * @brief Encode one level per axis as a flat stratum index. |
There was a problem hiding this comment.
Add a more detailed description here using the example of male/female for sex. Do the same for all functions in subpopulations.hpp that are missing a @details section.
| &derived_quantities["landings_numbers_at_age"]; | ||
|
|
||
| // partitioned landings and index at age (storage only; not filled yet) | ||
| derived_quantities["landings_numbers_at_age_by_partition"] = |
There was a problem hiding this comment.
It doesn't look like any of these partitioned derived quantities are being pushed back to info->variable_map. In order to do that I think they will also need to be initialized as VariableVectors in the fleet and population .hpp files. You could look at how their respective non-partitioned quantities are handled to figure out which files are appropriate.
| * @details Pooled quantities use i_age_year(). Partitioned quantities add | ||
| * stratum as the leading dimension via i_stratum_age_year(). | ||
| */ | ||
| struct IndexLayout { |
There was a problem hiding this comment.
The code here looks to be limited to a single new axis layer with hard coded years/ages axes. Do you have a plan for extending this to nested axes such as sex and area?
There was a problem hiding this comment.
Great question! Multi-axis nesting (e.g. sex × area) is handled by PartitionSpec, not by nesting more dimensions into IndexLayout. PartitionSpec holds a vector of axes, and n_strata() is the product of each axis’s level count (ref. subpopulation.hpp around line 47). Adding area (or season) increases n_strata and it does not require nested helpers like i_sex_area_year_age. The current wiring pulls n_strata from the spec in CatchAtAge::Initialize() (ref. catch_at_age.hpp around line 160):
this->populations[p]->partition_spec = MakeDefaultSexPartitionSpec();
this->populations[p]->index_layout.n_years = this->populations[p]->n_years;
this->populations[p]->index_layout.n_ages = this->populations[p]->n_ages;
this->populations[p]->index_layout.n_strata =
this->populations[p]->partition_spec.n_strata();
What is the feature?
This PR adds the first layer of partition infrastructure for population dynamics. It addresses parts 1–2 of issue #1557 only (representation of sex and indexing layout). Model dynamics, partitioned derived quantities, and likelihood wiring are intentionally deferred to follow-up PRs.
How have you implemented the solution?
subpopulation.hppwithAxis,GroupSelector,PartitionSpec,IndexLayout, andMakeDefaultSexPartitionSpec()(female/male sex axis).partition_specandindex_layoutmembers toPopulation.CatchAtAge::Initialize().CatchAtAge::Initialize().Design Notes
subpopulation.hpp, matching existing documentation that subpopulations represent generic partitions.IndexLayout::i_age_year()preserves the existing pooled (year, age) layout;i_stratum_age_year()adds stratum as the leading dimension for future partitioned containers (n_strata × n_years × n_ages).Does the PR impact any other area of the project, maybe another repo?
Instructions for code reviewer
👋Hello reviewer👋, thank you for taking the time to review this PR!
nit:(for nitpicking) as the comment type. For example,nit:I prefer using adata.frame()instead of amatrixbecause ...This PR is now ready to be merged.Checklist