FIMS  v0.11.0
Loading...
Searching...
No Matches
growth_derived_size_provider.hpp
Go to the documentation of this file.
1
9#ifndef FIMS_POPULATION_DYNAMICS_GROWTH_DERIVED_SIZE_PROVIDER_HPP
10#define FIMS_POPULATION_DYNAMICS_GROWTH_DERIVED_SIZE_PROVIDER_HPP
11
12#include <cstddef>
13#include <memory>
14#include <stdexcept>
15
18#include "size_products.hpp"
19#include "../../common/def.hpp"
21
22namespace fims_popdy {
23
35template <typename Type>
36class GrowthDerivedSizeProvider : public SizeDistributionProviderBase<Type> {
37 public:
38 GrowthDerivedSizeProvider() = default;
39
46 std::shared_ptr<GrowthDerivedObservationBase<Type>> growth)
47 : growth_observation_(growth) {}
48
49 const SizeGrid* TryGetSizeGrid() const override {
50 return population_size_grid_;
51 }
52
53 void SetPopulationSizeGrid(const SizeGrid* population_size_grid) override {
54 population_size_grid_ = population_size_grid;
55 size_products_prepared_ = false;
56 plus_group_warning_emitted_ = false;
57 }
58
59 void SetPopulationDimensions(std::size_t n_years,
60 std::size_t n_ages) override {
61 n_years_ = n_years;
62 n_ages_ = n_ages;
63 size_products_prepared_ = false;
64 plus_group_warning_emitted_ = false;
65 }
66
67 void PrepareSizeProducts() override {
68 if (!population_size_grid_) {
69 throw std::runtime_error(
70 "GrowthDerivedSizeProvider requires a population biological size "
71 "grid");
72 }
73
74 if (!population_size_grid_->IsConsistent()) {
75 throw std::runtime_error(
76 "GrowthDerivedSizeProvider requires a consistent population "
77 "biological size grid");
78 }
79
80 if (population_size_grid_->n_bins == 0) {
81 throw std::runtime_error(
82 "GrowthDerivedSizeProvider requires a population biological size grid"
83 " with at least one bin");
84 }
85
86 if (n_years_ == 0 || n_ages_ == 0) {
87 throw std::runtime_error(
88 "GrowthDerivedSizeProvider requires nonzero population dimensions");
89 }
90
91 const GrowthProducts<Type>& growth_products = PreparedGrowthProducts();
92
93 if (growth_products.n_years != n_years_ ||
94 growth_products.n_ages != n_ages_) {
95 throw std::runtime_error(
96 "GrowthDerivedSizeProvider growth products do not match "
97 "configured population dimensions");
98 }
99
100 if (growth_products.n_sexes != 1) {
101 throw std::runtime_error(
102 "GrowthDerivedSizeProvider currently requires pooled growth "
103 "products with n_sexes == 1");
104 }
105
106 size_products_.ResizeProbSizeOnly(n_years_, n_ages_,
107 population_size_grid_->n_bins);
108
109 const Type plus_group_warning_threshold = static_cast<Type>(0.01);
110 bool plus_group_warning_needed = false;
111 std::size_t warning_year_index = 0;
112 std::size_t warning_age_index = 0;
113
114 for (std::size_t year_index = 0; year_index < n_years_; ++year_index) {
115 for (std::size_t age_index = 0; age_index < n_ages_; ++age_index) {
116 fims::Vector<Type> prob_row(population_size_grid_->n_bins);
117 Type row_sum = static_cast<Type>(0.0);
118 const Type minimum_bin_prob = static_cast<Type>(1e-12);
119
120 for (std::size_t size_bin_index = 0;
121 size_bin_index < population_size_grid_->n_bins; ++size_bin_index) {
122 Type bin_prob = PopulationSizeBinProb(growth_products, year_index,
123 age_index, size_bin_index) +
124 minimum_bin_prob;
125
126 prob_row[size_bin_index] = bin_prob;
127 row_sum += bin_prob;
128 }
129
130 for (std::size_t size_bin_index = 0;
131 size_bin_index < population_size_grid_->n_bins; ++size_bin_index) {
132 size_products_.ProbSize(year_index, age_index, size_bin_index) =
133 prob_row[size_bin_index] / row_sum;
134 }
135
136 const Type plus_group_prob = size_products_.ProbSize(
137 year_index, age_index, population_size_grid_->n_bins - 1);
138
139 if (!plus_group_warning_needed &&
140 plus_group_prob > plus_group_warning_threshold) {
141 plus_group_warning_needed = true;
142 warning_year_index = year_index;
143 warning_age_index = age_index;
144 }
145 }
146 }
147
148 if (plus_group_warning_needed && !plus_group_warning_emitted_) {
150 "Growth-derived size preparation placed more than 0.01 "
151 "probability in the terminal biological plus-group bin for at "
152 "least one year-age row. First occurrence was year index " +
153 fims::to_string(warning_year_index) + ", age index " +
154 fims::to_string(warning_age_index) +
155 ". The population biological size grid may need to be widened.");
156 plus_group_warning_emitted_ = true;
157 }
158
159 // Weight depends only on length, so it is evaluated once per bin. The
160 // first and last bins are weighted at their centers even though they hold
161 // the lower and upper tails, as in SS3.
162 fims::Vector<Type> weight_at_bin(population_size_grid_->n_bins);
163 for (std::size_t size_bin_index = 0;
164 size_bin_index < population_size_grid_->n_bins; ++size_bin_index) {
165 weight_at_bin[size_bin_index] =
166 growth_observation_->EvaluateWeightAtLength(static_cast<Type>(
167 population_size_grid_->centers[size_bin_index]));
168 }
169
170 mean_weight_at_age_.resize(n_years_ * n_ages_);
171 for (std::size_t year_index = 0; year_index < n_years_; ++year_index) {
172 for (std::size_t age_index = 0; age_index < n_ages_; ++age_index) {
173 Type mean_weight = static_cast<Type>(0.0);
174 for (std::size_t size_bin_index = 0;
175 size_bin_index < population_size_grid_->n_bins; ++size_bin_index) {
176 mean_weight +=
177 size_products_.ProbSize(year_index, age_index, size_bin_index) *
178 weight_at_bin[size_bin_index];
179 }
180 mean_weight_at_age_[year_index * n_ages_ + age_index] = mean_weight;
181 }
182 }
183
184 size_products_prepared_ = true;
185 }
186
188 size_products_prepared_ = false;
189 }
190
191 const Type& MeanLAA(std::size_t year_index,
192 std::size_t age_index) const override {
193 return PreparedGrowthProducts().MeanLAA(year_index, age_index, 0);
194 }
195
196 const Type& SdLAA(std::size_t year_index,
197 std::size_t age_index) const override {
198 return PreparedGrowthProducts().SdLAA(year_index, age_index, 0);
199 }
200
201 const Type& ProbSize(std::size_t year_index, std::size_t age_index,
202 std::size_t size_bin_index) const override {
203 if (!size_products_prepared_) {
204 throw std::runtime_error(
205 "GrowthDerivedSizeProvider requires prepared size products");
206 }
207
208 return size_products_.ProbSize(year_index, age_index, size_bin_index);
209 }
210
229 const Type& MeanWeightAtAge(std::size_t year_index,
230 std::size_t age_index) const override {
231 if (!size_products_prepared_) {
232 throw std::runtime_error(
233 "GrowthDerivedSizeProvider requires prepared size products");
234 }
235
236 if (year_index >= n_years_ || age_index >= n_ages_) {
237 throw std::out_of_range(
238 "GrowthDerivedSizeProvider mean weight-at-age index out of range");
239 }
240
241 return mean_weight_at_age_[year_index * n_ages_ + age_index];
242 }
243
249 void SetGrowth(std::shared_ptr<GrowthDerivedObservationBase<Type>> growth) {
250 growth_observation_ = growth;
251 size_products_prepared_ = false;
252 plus_group_warning_emitted_ = false;
253 }
254
255 private:
256 Type PopulationSizeBinProb(const GrowthProducts<Type>& growth_products,
257 std::size_t year_index, std::size_t age_index,
258 std::size_t size_bin_index) const {
259 if (!population_size_grid_ || population_size_grid_->n_bins == 0) {
260 throw std::runtime_error(
261 "GrowthDerivedSizeProvider requires a population biological size grid"
262 " before computing ProbSize");
263 }
264
265 const Type mean_laa = growth_products.MeanLAA(year_index, age_index, 0);
266 const Type sd_laa =
267 fims_math::ad_max(growth_products.SdLAA(year_index, age_index, 0),
268 static_cast<Type>(1e-8));
269
270 if (population_size_grid_->n_bins == 1) {
271 return static_cast<Type>(1.0);
272 }
273
274 if (size_bin_index == 0) {
275 const Type upper = static_cast<Type>(population_size_grid_->edges[1]);
276 return fims_math::pnorm(upper, mean_laa, sd_laa);
277 }
278
279 if (size_bin_index + 1 == population_size_grid_->n_bins) {
280 const Type lower = static_cast<Type>(
281 population_size_grid_->edges[population_size_grid_->n_bins - 1]);
282 return fims_math::pnorm(static_cast<Type>(2.0) * mean_laa - lower,
283 mean_laa, sd_laa);
284 }
285
286 const Type lower =
287 static_cast<Type>(population_size_grid_->edges[size_bin_index]);
288 const Type upper =
289 static_cast<Type>(population_size_grid_->edges[size_bin_index + 1]);
290
291 return fims_math::pnorm(upper, mean_laa, sd_laa) -
292 fims_math::pnorm(lower, mean_laa, sd_laa);
293 }
294
295 const GrowthProducts<Type>& PreparedGrowthProducts() const {
296 if (!growth_observation_) {
297 throw std::runtime_error(
298 "GrowthDerivedSizeProvider requires a linked growth object");
299 }
300
301 const GrowthProducts<Type>* growth_products =
302 growth_observation_->TryGetPreparedGrowthProducts();
303
304 if (!growth_products) {
305 throw std::runtime_error(
306 "GrowthDerivedSizeProvider requires prepared growth products");
307 }
308
309 return *growth_products;
310 }
311
312 std::shared_ptr<GrowthDerivedObservationBase<Type>> growth_observation_;
313 const SizeGrid* population_size_grid_ = nullptr;
314 std::size_t n_years_ = 0;
315 std::size_t n_ages_ = 0;
316 bool size_products_prepared_ = false;
317 bool plus_group_warning_emitted_ = false;
318 SizeProducts<Type> size_products_;
319 fims::Vector<Type> mean_weight_at_age_;
320};
321
322} // namespace fims_popdy
323
324#endif /* FIMS_POPULATION_DYNAMICS_GROWTH_DERIVED_SIZE_PROVIDER_HPP */
Definition fims_vector.hpp:27
Generic capability interface for growth models that can feed the growth-derived age-to-length convers...
Definition growth_model_adapter.hpp:26
void PrepareSizeProducts() override
Prepare size products for the current model state.
Definition growth_derived_size_provider.hpp:67
const Type & MeanWeightAtAge(std::size_t year_index, std::size_t age_index) const override
Mean weight-at-age averaged over the population length-at-age distribution.
Definition growth_derived_size_provider.hpp:229
void SetPopulationDimensions(std::size_t n_years, std::size_t n_ages) override
Configure the provider dimensions for prepared size products.
Definition growth_derived_size_provider.hpp:59
void SetPopulationSizeGrid(const SizeGrid *population_size_grid) override
Configure the provider to use the canonical population size grid.
Definition growth_derived_size_provider.hpp:53
const Type & MeanLAA(std::size_t year_index, std::size_t age_index) const override
Read prepared mean length-at-age.
Definition growth_derived_size_provider.hpp:191
void SetGrowth(std::shared_ptr< GrowthDerivedObservationBase< Type > > growth)
Replace the Growth-derived observation object used by this provider.
Definition growth_derived_size_provider.hpp:249
GrowthDerivedSizeProvider(std::shared_ptr< GrowthDerivedObservationBase< Type > > growth)
Construct a provider linked to a Growth-derived observation object.
Definition growth_derived_size_provider.hpp:45
const SizeGrid * TryGetSizeGrid() const override
Return the biological size grid used by this provider.
Definition growth_derived_size_provider.hpp:49
const Type & SdLAA(std::size_t year_index, std::size_t age_index) const override
Read prepared spread of length-at-age.
Definition growth_derived_size_provider.hpp:196
const Type & ProbSize(std::size_t year_index, std::size_t age_index, std::size_t size_bin_index) const override
Read prepared age-to-size probability on the population grid.
Definition growth_derived_size_provider.hpp:201
void InvalidatePreparedSizeProducts() override
Invalidate any prepared size state held by this provider.
Definition growth_derived_size_provider.hpp:187
Platform macros and the core FIMS logging system.
#define FIMS_WARNING_LOG(MESSAGE)
Definition def.hpp:648
std::string to_string(T v)
Definition def.hpp:735
A collection of mathematical functions used in FIMS.
const Type ad_max(const Type &a, const Type &b, Type C=1e-5)
Definition fims_math.hpp:380
adapts product-style growth models to the GrowthBase interface used by caa.
The population dynamics of FIMS.
Definition catch_at_age.hpp:45
Defines the SizeDistributionProviderBase interface for prepared population-level size products.
Defines the SizeProducts container for cached population-level size outputs on the biological size gr...
Growth "products" in a consistent (year, age, sex) space.
Definition growth_products.hpp:26
Type & MeanLAA(std::size_t y, std::size_t a, std::size_t s)
Access mean length-at-age by reference.
Definition growth_products.hpp:90
std::size_t n_years
Definition growth_products.hpp:27
Type & SdLAA(std::size_t y, std::size_t a, std::size_t s)
Access standard deviation of length-at-age by reference.
Definition growth_products.hpp:101
std::size_t n_sexes
Definition growth_products.hpp:29
std::size_t n_ages
Definition growth_products.hpp:28
Population-level biological size grid.
Definition size_grid.hpp:26
std::size_t n_bins
Definition size_grid.hpp:27