| 1 |
# To remove the WARNING |
|
| 2 |
# no visible binding for global variable |
|
| 3 |
utils::globalVariables(c( |
|
| 4 |
"type", "name", "value", "unit", "uncertainty", |
|
| 5 |
"timing", "age", "length", "year", |
|
| 6 |
# Used in initialize_comp dplyr code |
|
| 7 |
"valid_n" |
|
| 8 |
)) |
|
| 9 | ||
| 10 |
#' Initialize a generic module |
|
| 11 |
#' |
|
| 12 |
#' @description |
|
| 13 |
#' Initializes a generic module by setting up its fields based on the provided |
|
| 14 |
#' `module_name`. |
|
| 15 |
#' @param parameters A tibble. Contains parameters and modules required for |
|
| 16 |
#' initialization. |
|
| 17 |
#' @param data An S4 object. FIMS input data. |
|
| 18 |
#' @param module_name A character. Name of the module to initialize (e.g., |
|
| 19 |
#' "Population" or "Fleet"). |
|
| 20 |
#' @param fleet_name A character. Name of the fleet to initialize. If not |
|
| 21 |
#' specified, the module will be initialized without fleet-specific data. |
|
| 22 |
#' @return |
|
| 23 |
#' The initialized module as an object. |
|
| 24 |
#' @noRd |
|
| 25 |
initialize_module <- function(parameters, data, module_name, fleet_name = NA_character_) {
|
|
| 26 | 88x |
module_input <- parameters |> |
| 27 |
# Using !! to unquote the variables |
|
| 28 | 88x |
dplyr::filter(module_name == !!module_name) |
| 29 | ||
| 30 | 88x |
if (!is.na(fleet_name)) {
|
| 31 | 44x |
module_input <- module_input |> |
| 32 | 44x |
dplyr::filter(fleet_name == !!fleet_name) |
| 33 |
} |
|
| 34 | ||
| 35 | 88x |
module_class_name <- module_input |> |
| 36 |
# Combine module_type and module_name into a single string |
|
| 37 | 88x |
dplyr::mutate( |
| 38 | 88x |
temp_name = paste0( |
| 39 |
# Replace NAs with "" |
|
| 40 | 88x |
dplyr::coalesce(module_type, ""), |
| 41 | 88x |
dplyr::coalesce(module_name, "") |
| 42 |
) |
|
| 43 |
) |> |
|
| 44 | 88x |
dplyr::pull(temp_name) |> |
| 45 | 88x |
unique() |
| 46 | ||
| 47 | 88x |
module_class <- get(module_class_name) |
| 48 | 88x |
module_fields <- names(module_class@fields) |
| 49 | 88x |
module <- methods::new(module_class) |
| 50 | ||
| 51 | 88x |
if (module_class_name == "Fleet") {
|
| 52 |
# Remove certain fields for the Fleet module |
|
| 53 | 22x |
module_fields <- setdiff(module_fields, c( |
| 54 | 22x |
"log_index_expected", |
| 55 | 22x |
"log_landings_expected", |
| 56 | 22x |
"index_expected", |
| 57 | 22x |
"landings_expected", |
| 58 | 22x |
"agecomp_expected", |
| 59 | 22x |
"agecomp_proportion", |
| 60 | 22x |
"observed_index_units", |
| 61 | 22x |
"observed_landings_units" |
| 62 |
)) |
|
| 63 | ||
| 64 | 22x |
fleet_types <- get_data(data) |> |
| 65 | 22x |
dplyr::filter(name == fleet_name) |> |
| 66 | 22x |
dplyr::pull(type) |> |
| 67 | 22x |
unique() |
| 68 | ||
| 69 | 22x |
data_distribution_names_for_fleet_i <- parameters |> |
| 70 | 22x |
dplyr::filter(fleet_name == !!fleet_name & distribution_type == "Data") |> |
| 71 | 22x |
dplyr::pull(module_type) |
| 72 | 22x |
if ("age-to-length-conversion" %in% fleet_types &&
|
| 73 | 22x |
"LengthComp" %in% data_distribution_names_for_fleet_i) {
|
| 74 | 16x |
age_to_length_conversion_value <- FIMS::m_age_to_length_conversion(data, fleet_name) |
| 75 | 16x |
module[["age_to_length_conversion"]]$resize(length(age_to_length_conversion_value)) |
| 76 |
# Assign each value to the corresponding position in the parameter vector |
|
| 77 | 16x |
purrr::walk( |
| 78 | 16x |
seq_along(age_to_length_conversion_value), |
| 79 | 16x |
\(x) module[["age_to_length_conversion"]][x][["value"]] <- age_to_length_conversion_value[x] |
| 80 |
) |
|
| 81 | ||
| 82 |
# Set the estimation information for the entire parameter vector |
|
| 83 | 16x |
module[["age_to_length_conversion"]]$set_all_estimable(FALSE) |
| 84 | ||
| 85 | 16x |
module[["age_to_length_conversion"]]$set_all_random(FALSE) |
| 86 |
} else {
|
|
| 87 | 6x |
module_fields <- setdiff(module_fields, c( |
| 88 |
# Right now we can also remove n_lengths because the default is 0 |
|
| 89 | 6x |
"n_lengths" |
| 90 |
)) |
|
| 91 |
} |
|
| 92 | ||
| 93 | 22x |
module_fields <- setdiff(module_fields, c( |
| 94 | 22x |
"age_to_length_conversion", |
| 95 | 22x |
"lengthcomp_expected", |
| 96 | 22x |
"lengthcomp_proportion" |
| 97 |
)) |
|
| 98 |
} |
|
| 99 | ||
| 100 |
# Populate fields based on common and specific settings |
|
| 101 |
# TODO: |
|
| 102 |
# - Population interface |
|
| 103 |
# - Update the Population interface to consistently use n_ages and n_years, |
|
| 104 |
# as done in the S4 data1 object. |
|
| 105 |
# Update as needed. |
|
| 106 |
# - Add n_fleets to data1. Should n_fleets include both |
|
| 107 |
# fishing and survey fleets? Currently, data1@fleets equals 1. |
|
| 108 |
# - Fleet |
|
| 109 |
# - Reconsider exposing `log_expected_index` and |
|
| 110 |
# `agecomp_proportion` to users. Their IDs are linked with |
|
| 111 |
# index and agecomp distributions. No input values are required. |
|
| 112 | ||
| 113 | 88x |
integer_fields <- c( |
| 114 | 88x |
"n_ages", "n_fleets", "n_lengths", |
| 115 | 88x |
"n_years" |
| 116 |
) |
|
| 117 | ||
| 118 | 88x |
boolean_fields <- c( |
| 119 | 88x |
"estimate_prop_female" |
| 120 |
) |
|
| 121 | ||
| 122 | 88x |
real_vector_fields <- c( |
| 123 | 88x |
"ages", "weights" |
| 124 |
) |
|
| 125 | ||
| 126 | 88x |
for (field in module_fields) {
|
| 127 | 335x |
if (field %in% integer_fields) {
|
| 128 | 115x |
module[[field]]$set( |
| 129 | 115x |
switch(field, |
| 130 | 115x |
"n_ages" = get_n_ages(data), |
| 131 | 115x |
"n_fleets" = parameters |> |
| 132 | 115x |
dplyr::filter(module_name == "Fleet") |> |
| 133 | 115x |
dplyr::pull(fleet_name) |> |
| 134 | 115x |
unique() |> |
| 135 | 115x |
length(), |
| 136 |
# Or we can use get_n_fleets(data), |
|
| 137 | 115x |
"n_lengths" = get_n_lengths(data), |
| 138 | 115x |
"n_years" = get_n_years(data) |
| 139 |
) |
|
| 140 |
) |
|
| 141 | 220x |
} else if (field %in% c("ages", "weights")) {
|
| 142 | 33x |
get_value_function <- switch(field, |
| 143 | 33x |
"ages" = get_ages, |
| 144 | 33x |
"weights" = m_weight_at_age |
| 145 |
) |
|
| 146 | 33x |
module[[field]]$resize(get_n_ages(data)) |
| 147 | 33x |
purrr::walk(seq_len(get_n_ages(data)), function(x) {
|
| 148 | 396x |
module[[field]]$set(x - 1, get_value_function(data)[x]) |
| 149 |
}) |
|
| 150 |
} else {
|
|
| 151 | 187x |
set_param_vector( |
| 152 | 187x |
field = field, |
| 153 | 187x |
module = module, |
| 154 | 187x |
module_input = module_input |
| 155 |
) |
|
| 156 |
} |
|
| 157 |
} |
|
| 158 | 88x |
return(module) |
| 159 |
} |
|
| 160 | ||
| 161 |
# TODO: Determine the relationship between distributions and the |
|
| 162 |
# recruitment module, and implement the appropriate logic to retrieve |
|
| 163 |
# distribution information. |
|
| 164 | ||
| 165 |
#' Initialize a distribution module |
|
| 166 |
#' |
|
| 167 |
#' @description |
|
| 168 |
#' Initializes a distribution module by setting up its fields based on the |
|
| 169 |
#' distribution name and type. Supports both "data" and "process" types. |
|
| 170 |
#' @param module_input A list. Contains parameters for initializing the |
|
| 171 |
#' distribution. |
|
| 172 |
#' @param distribution_name A character. Name of the distribution to initialize. |
|
| 173 |
#' @param distribution_type A character. Type of distribution, either "data" or |
|
| 174 |
#' "process". |
|
| 175 |
#' @param linked_ids A vector. Named vector of linked IDs required for the |
|
| 176 |
#' distribution, such as data_link and fleet_link for setting up index |
|
| 177 |
#' distribution. |
|
| 178 |
#' @rdname initialize_module |
|
| 179 |
#' @return |
|
| 180 |
#' The initialized distribution module as an object. |
|
| 181 |
#' @noRd |
|
| 182 |
initialize_distribution <- function( |
|
| 183 |
module_input, |
|
| 184 |
distribution_name, |
|
| 185 |
distribution_type = c("data", "process"),
|
|
| 186 |
linked_ids |
|
| 187 |
) {
|
|
| 188 |
# Input checks |
|
| 189 |
# Check if distribution_name is provided |
|
| 190 | ! |
if (is.null(distribution_name)) {
|
| 191 | ! |
return(NULL) |
| 192 |
} |
|
| 193 |
# Validate module_input |
|
| 194 | ! |
if (!is.list(module_input)) {
|
| 195 | ! |
cli::cli_abort("{.var module_input} must be a list.")
|
| 196 |
} |
|
| 197 |
# Validate distribution_type as "data" or "process" |
|
| 198 | ! |
distribution_type <- rlang::arg_match(distribution_type) |
| 199 |
# Validate linked_ids as a named vector with required elements for "data" type |
|
| 200 | ! |
if (!is.vector(linked_ids) || |
| 201 | ! |
!all(c("data_link", "fleet_link") %in% names(linked_ids))
|
| 202 |
) {
|
|
| 203 | ! |
cli::cli_abort( |
| 204 | ! |
"{.var linked_ids} must be a named vector containing 'data_link' and
|
| 205 | ! |
'fleet_link' for 'data' distribution types." |
| 206 |
) |
|
| 207 |
} |
|
| 208 | ||
| 209 |
# Get distribution value and initialize the module |
|
| 210 | ! |
distribution_value <- get(distribution_name) |
| 211 | ! |
distribution_module <- methods::new(distribution_value) |
| 212 | ! |
distribution_fields <- names(distribution_value@fields) |
| 213 | ! |
if (distribution_type == "data") {
|
| 214 | ! |
distribution_fields <- setdiff( |
| 215 | ! |
distribution_fields, |
| 216 | ! |
c("expected_values", "x", "dims")
|
| 217 |
) |
|
| 218 |
} |
|
| 219 | ||
| 220 | ! |
distribution_input_names <- grep( |
| 221 | ! |
distribution_name, |
| 222 | ! |
names(module_input), |
| 223 | ! |
value = TRUE |
| 224 |
) |
|
| 225 | ! |
for (field in distribution_fields) {
|
| 226 | ! |
set_param_vector( |
| 227 | ! |
field = field, module = distribution_module, |
| 228 | ! |
module_input = module_input[distribution_input_names] |
| 229 |
) |
|
| 230 |
} |
|
| 231 | ||
| 232 | ! |
switch(distribution_type, |
| 233 |
"data" = {
|
|
| 234 |
# Data distribution initialization |
|
| 235 | ! |
distribution_module$set_observed_data(linked_ids["data_link"]) |
| 236 | ! |
distribution_module$set_distribution_links( |
| 237 | ! |
distribution_type, |
| 238 | ! |
linked_ids["fleet_link"] |
| 239 |
) |
|
| 240 |
}, |
|
| 241 |
"process" = {
|
|
| 242 |
# Process distribution initialization |
|
| 243 | ! |
distribution_module$set_distribution_links("random_effects", linked_ids)
|
| 244 |
} |
|
| 245 |
) |
|
| 246 | ||
| 247 |
# Final message to confirm success |
|
| 248 | ! |
cli::cli_inform(c( |
| 249 | ! |
"i" = "{distribution_name} initialized successfully for
|
| 250 | ! |
{names(distribution_name)}."
|
| 251 |
)) |
|
| 252 | ||
| 253 | ! |
return(distribution_module) |
| 254 |
} |
|
| 255 | ||
| 256 |
#' Initialize a recruitment module |
|
| 257 |
#' |
|
| 258 |
#' @description |
|
| 259 |
#' Initializes a recruitment module by setting up fields. This function uses |
|
| 260 |
#' the `initialize_module` function to handle specific requirements for |
|
| 261 |
#' recruitment initialization. |
|
| 262 |
#' @inheritParams initialize_module |
|
| 263 |
#' @return |
|
| 264 |
#' The initialized recruitment module as an object. |
|
| 265 |
#' @noRd |
|
| 266 |
initialize_recruitment <- function(parameters, data) {
|
|
| 267 | 11x |
module <- initialize_module( |
| 268 | 11x |
parameters = parameters, |
| 269 | 11x |
data = data, |
| 270 | 11x |
module_name = "Recruitment" |
| 271 |
) |
|
| 272 |
} |
|
| 273 | ||
| 274 |
#' Initialize a growth module |
|
| 275 |
#' |
|
| 276 |
#' @description |
|
| 277 |
#' Initializes a growth module by setting up fields. This function uses |
|
| 278 |
#' the `initialize_module` function to handle specific requirements for |
|
| 279 |
#' growth initialization. |
|
| 280 |
#' @inheritParams initialize_module |
|
| 281 |
#' @return |
|
| 282 |
#' The initialized growth module as an object. |
|
| 283 |
#' @noRd |
|
| 284 |
initialize_growth <- function(parameters, data) {
|
|
| 285 | 11x |
module <- initialize_module( |
| 286 | 11x |
parameters = parameters, |
| 287 | 11x |
data = data, |
| 288 | 11x |
module_name = "Growth" |
| 289 |
) |
|
| 290 |
} |
|
| 291 | ||
| 292 |
#' Initialize a maturity module |
|
| 293 |
#' |
|
| 294 |
#' @description |
|
| 295 |
#' Initializes a maturity module by setting up fields. This function uses |
|
| 296 |
#' the `initialize_module` function to handle specific requirements for |
|
| 297 |
#' maturity initialization. |
|
| 298 |
#' @inheritParams initialize_module |
|
| 299 |
#' @return |
|
| 300 |
#' The initialized maturity module as an object. |
|
| 301 |
#' @noRd |
|
| 302 |
initialize_maturity <- function(parameters, data) {
|
|
| 303 | 11x |
module <- initialize_module( |
| 304 | 11x |
parameters = parameters, |
| 305 | 11x |
data = data, |
| 306 | 11x |
module_name = "Maturity" |
| 307 |
) |
|
| 308 |
} |
|
| 309 | ||
| 310 |
#' Initialize a population module. |
|
| 311 |
#' |
|
| 312 |
#' @description |
|
| 313 |
#' Initializes a population module by setting up fields. This function uses |
|
| 314 |
#' the `initialize_module` function to handle specific requirements for |
|
| 315 |
#' population initialization. |
|
| 316 |
#' @inheritParams initialize_module |
|
| 317 |
#' @param linked_ids A vector. Named vector of linked IDs required for the |
|
| 318 |
#' population, including IDs for "growth", "maturity", and "recruitment". |
|
| 319 |
#' @return |
|
| 320 |
#' The initialized population module as an object. |
|
| 321 |
#' @noRd |
|
| 322 |
initialize_population <- function(parameters, data, linked_ids) {
|
|
| 323 | 11x |
if (anyNA(linked_ids[c("growth", "maturity", "recruitment")])) {
|
| 324 | ! |
cli::cli_abort(c( |
| 325 | ! |
"{.var linked_ids} for population must include `growth`, `maturity`, and
|
| 326 | ! |
`recruitment` IDs." |
| 327 |
)) |
|
| 328 |
} |
|
| 329 | ||
| 330 | 11x |
module <- initialize_module( |
| 331 | 11x |
parameters = parameters, |
| 332 | 11x |
data = data, |
| 333 | 11x |
module_name = "Population" |
| 334 |
) |
|
| 335 | ||
| 336 |
# Link up the recruitment, growth, and maturity modules with |
|
| 337 |
# this population module |
|
| 338 | 11x |
module$SetGrowthID(linked_ids[["growth"]]) |
| 339 | 11x |
module$SetMaturityID(linked_ids[["maturity"]]) |
| 340 | 11x |
module$SetRecruitmentID(linked_ids[["recruitment"]]) |
| 341 |
# Link fleets to module |
|
| 342 | 11x |
for (i in which(grepl("fleet", names(linked_ids)))) {
|
| 343 | 22x |
module$AddFleet(linked_ids[[i]]) |
| 344 |
} |
|
| 345 | ||
| 346 | 11x |
return(module) |
| 347 |
} |
|
| 348 | ||
| 349 |
#' Initialize a selectivity module. |
|
| 350 |
#' |
|
| 351 |
#' @description |
|
| 352 |
#' Initializes a selectivity module by setting up fields. This function uses |
|
| 353 |
#' the `initialize_module` function to handle specific requirements for |
|
| 354 |
#' population initialization. |
|
| 355 |
#' @inheritParams initialize_module |
|
| 356 |
#' @param fleet_name A character. Name of the fleet to initialize. |
|
| 357 |
#' @return |
|
| 358 |
#' The initialized selectivity module as an object. |
|
| 359 |
#' @noRd |
|
| 360 |
initialize_selectivity <- function(parameters, data, fleet_name) {
|
|
| 361 | 22x |
module_name <- "Selectivity" |
| 362 | 22x |
module <- initialize_module( |
| 363 | 22x |
parameters = parameters, |
| 364 | 22x |
data = data, |
| 365 | 22x |
module_name = module_name, |
| 366 | 22x |
fleet_name = fleet_name |
| 367 |
) |
|
| 368 |
} |
|
| 369 | ||
| 370 |
# TODO: Do we want to put initialize_selectivity(), initialize_index(), and |
|
| 371 |
# initial_age_comp() inside of initialize_fleet()? |
|
| 372 | ||
| 373 |
#' Initialize a fleet module |
|
| 374 |
#' |
|
| 375 |
#' @description |
|
| 376 |
#' Initializes a fleet module by setting up its fields. It links selectivity, |
|
| 377 |
#' index, and age-composition modules. |
|
| 378 |
#' @inheritParams initialize_module |
|
| 379 |
#' @param fleet_name A character. Name of the fleet to initialize. |
|
| 380 |
#' @param linked_ids A vector. Named vector of linked IDs required for the |
|
| 381 |
#' fleet, including IDs for "selectivity", "landings", "index", "age_comp", and "length_comp". |
|
| 382 |
#' @return |
|
| 383 |
#' The initialized fleet module as an object. |
|
| 384 |
#' @noRd |
|
| 385 |
initialize_fleet <- function(parameters, data, fleet_name, linked_ids) {
|
|
| 386 | 22x |
module <- initialize_module( |
| 387 | 22x |
parameters = parameters, |
| 388 | 22x |
data = data, |
| 389 | 22x |
fleet_name = fleet_name, |
| 390 | 22x |
module_name = "Fleet" |
| 391 |
) |
|
| 392 | ||
| 393 | 22x |
module$SetSelectivityID(linked_ids["selectivity"]) |
| 394 | ||
| 395 | 22x |
fleet_types <- get_data(data) |> |
| 396 | 22x |
dplyr::filter(name == fleet_name) |> |
| 397 | 22x |
dplyr::pull(type) |> |
| 398 | 22x |
unique() |
| 399 | ||
| 400 | ||
| 401 | 22x |
distribution_names_for_fleet <- parameters |> |
| 402 | 22x |
dplyr::filter(fleet_name == !!fleet_name & distribution_type == "Data") |> |
| 403 | 22x |
dplyr::pull(module_type) |
| 404 | ||
| 405 |
# Link the observed landings data to the fleet module using its associated ID |
|
| 406 |
# if the data type includes "landings" and if "Landings" exists in the data distribution |
|
| 407 |
# specification |
|
| 408 | 22x |
if ("landings" %in% fleet_types &&
|
| 409 | 22x |
"Landings" %in% distribution_names_for_fleet) {
|
| 410 | 11x |
module$SetObservedLandingsDataID(linked_ids["landings"]) |
| 411 |
} |
|
| 412 | ||
| 413 |
# Link the observed index data to the fleet module using its associated ID |
|
| 414 |
# if the data type includes "index" and if "Index" exists in the data distribution |
|
| 415 |
# specification |
|
| 416 | 22x |
if ("index" %in% fleet_types &&
|
| 417 | 22x |
"Index" %in% distribution_names_for_fleet) {
|
| 418 | 11x |
module$SetObservedIndexDataID(linked_ids["index"]) |
| 419 |
} |
|
| 420 | ||
| 421 |
# Link the observed age composition data to the fleet module using its associated ID |
|
| 422 |
# if the data type includes "age_comp" and if "AgeComp" exists in the data distribution |
|
| 423 |
# specification |
|
| 424 | 22x |
if ("age_comp" %in% fleet_types &&
|
| 425 | 22x |
"AgeComp" %in% distribution_names_for_fleet) {
|
| 426 | 18x |
module$SetObservedAgeCompDataID(linked_ids["age_comp"]) |
| 427 |
} |
|
| 428 | ||
| 429 |
# Link the observed length composition data to the fleet module using its associated ID |
|
| 430 |
# if the data type includes "length_comp" and if "LengthComp" exists in the data |
|
| 431 |
# distribution specification |
|
| 432 | 22x |
if ("length_comp" %in% fleet_types &&
|
| 433 | 22x |
"LengthComp" %in% distribution_names_for_fleet) {
|
| 434 | 16x |
module$SetObservedLengthCompDataID(linked_ids["length_comp"]) |
| 435 |
} |
|
| 436 | 22x |
return(module) |
| 437 |
} |
|
| 438 | ||
| 439 |
#' Initialize a landings module |
|
| 440 |
#' |
|
| 441 |
#' @description |
|
| 442 |
#' Initializes a landings module based on the provided data and fleet name. |
|
| 443 |
#' @inheritParams initialize_module |
|
| 444 |
#' @param fleet_name A character. Name of the fleet for which the landings module |
|
| 445 |
#' is initialized. |
|
| 446 |
#' @return |
|
| 447 |
#' The initialized landings module as an object. |
|
| 448 |
#' @noRd |
|
| 449 |
initialize_landings <- function(data, fleet_name) {
|
|
| 450 |
# Check if the specified fleet exists in the data |
|
| 451 | 11x |
fleet_exists <- any(get_data(data)["name"] == fleet_name) |
| 452 | 11x |
if (!fleet_exists) {
|
| 453 | ! |
cli::cli_abort("Fleet {fleet_name} not found in the data object.")
|
| 454 |
} |
|
| 455 | ||
| 456 | 11x |
fleet_type <- dplyr::filter( |
| 457 | 11x |
.data = as.data.frame(get_data(data)), |
| 458 | 11x |
name == fleet_name |
| 459 |
) |> |
|
| 460 | 11x |
dplyr::distinct(type) |> |
| 461 | 11x |
dplyr::pull(type) |
| 462 | ||
| 463 | 11x |
if ("landings" %in% fleet_type) {
|
| 464 | 11x |
module <- methods::new(Landings, get_n_years(data)) |
| 465 | 11x |
purrr::walk( |
| 466 | 11x |
seq_along(m_landings(data, fleet_name)), |
| 467 | 11x |
\(x) module$landings_data$set(x - 1, m_landings(data, fleet_name)[x]) |
| 468 |
) |
|
| 469 | 11x |
return(module) |
| 470 |
} else {
|
|
| 471 | ! |
return(NULL) |
| 472 |
} |
|
| 473 |
} |
|
| 474 | ||
| 475 |
#' Initialize an index module |
|
| 476 |
#' |
|
| 477 |
#' @description |
|
| 478 |
#' Initializes an index module based on the provided data and fleet name. |
|
| 479 |
#' @inheritParams initialize_module |
|
| 480 |
#' @param fleet_name A character. Name of the fleet for which the index module |
|
| 481 |
#' is initialized. |
|
| 482 |
#' @return |
|
| 483 |
#' The initialized index module as an object. |
|
| 484 |
#' @noRd |
|
| 485 |
initialize_index <- function(data, fleet_name) {
|
|
| 486 |
# Check if the specified fleet exists in the data |
|
| 487 | 11x |
fleet_exists <- any(get_data(data)["name"] == fleet_name) |
| 488 | 11x |
if (!fleet_exists) {
|
| 489 | ! |
cli::cli_abort("Fleet {fleet_name} not found in the data object.")
|
| 490 |
} |
|
| 491 | ||
| 492 | 11x |
fleet_type <- dplyr::filter( |
| 493 | 11x |
.data = as.data.frame(get_data(data)), |
| 494 | 11x |
name == fleet_name |
| 495 |
) |> |
|
| 496 | 11x |
dplyr::distinct(type) |> |
| 497 | 11x |
dplyr::pull(type) |
| 498 | ||
| 499 | 11x |
if ("index" %in% fleet_type) {
|
| 500 | 11x |
module <- methods::new(Index, get_n_years(data)) |
| 501 | 11x |
purrr::walk( |
| 502 | 11x |
seq_along(m_index(data, fleet_name)), |
| 503 | 11x |
\(x) module$index_data$set(x - 1, m_index(data, fleet_name)[x]) |
| 504 |
) |
|
| 505 | 11x |
return(module) |
| 506 |
} else {
|
|
| 507 | ! |
return(NULL) |
| 508 |
} |
|
| 509 |
} |
|
| 510 | ||
| 511 |
#' Initialize a composition module |
|
| 512 |
#' |
|
| 513 |
#' Several types of composition modules exist and this function acts as a |
|
| 514 |
#' generic interface to initialize any type, for example assigning |
|
| 515 |
#' age-composition data to a given fleet would be an example of initializing |
|
| 516 |
#' a composition module. |
|
| 517 |
#' |
|
| 518 |
#' @inheritParams initialize_module |
|
| 519 |
#' @param fleet_name A character specifying the name of the fleet for which |
|
| 520 |
#' composition data is initialized. |
|
| 521 |
#' @param type A character specifying the composition type, where the default |
|
| 522 |
#' is `"AgeComp"`. At the moment, one can initialize `"AgeComp"` or |
|
| 523 |
#' `"LengthComp"` modules. |
|
| 524 |
#' @return |
|
| 525 |
#' The initialized composition module as an object. |
|
| 526 |
#' @noRd |
|
| 527 |
initialize_comp <- function(data, |
|
| 528 |
fleet_name, |
|
| 529 |
type = c("AgeComp", "LengthComp")) {
|
|
| 530 |
# Edit this list if a new type is added |
|
| 531 |
# Set up the specifics for the given type. |
|
| 532 | 38x |
comp_types <- list( |
| 533 | 38x |
"AgeComp" = list( |
| 534 | 38x |
"name" = "age_comp", |
| 535 | 38x |
"comp_data_field" = "age_comp_data", |
| 536 | 38x |
"get_n_function" = get_n_ages, |
| 537 | 38x |
"comp_object" = AgeComp, |
| 538 | 38x |
"m_comp" = m_agecomp |
| 539 |
), |
|
| 540 | 38x |
"LengthComp" = list( |
| 541 | 38x |
"name" = "length_comp", |
| 542 | 38x |
"comp_data_field" = "length_comp_data", |
| 543 | 38x |
"get_n_function" = get_n_lengths, |
| 544 | 38x |
"comp_object" = LengthComp, |
| 545 | 38x |
"m_comp" = m_lengthcomp |
| 546 |
) |
|
| 547 |
) |
|
| 548 | ||
| 549 |
# Ensures the user input matches the options provided, |
|
| 550 |
# if not, then match.arg() throws an error |
|
| 551 | 38x |
type <- match.arg(type) |
| 552 |
# Select the row in comp_types that matches the user's type selection |
|
| 553 | 37x |
comp <- comp_types[[type]] |
| 554 | ||
| 555 |
# Check if the specified fleet exists in the data |
|
| 556 | 37x |
fleet_exists <- any(get_data(data)["name"] == fleet_name) |
| 557 | 37x |
if (!fleet_exists) {
|
| 558 | 1x |
cli::cli_abort("Fleet `{fleet_name}` not found in the data object.")
|
| 559 |
} |
|
| 560 | ||
| 561 | 36x |
get_function <- comp[["get_n_function"]] |
| 562 | 36x |
module <- methods::new( |
| 563 | 36x |
comp[["comp_object"]], |
| 564 | 36x |
get_n_years(data), |
| 565 | 36x |
get_function(data) |
| 566 |
) |
|
| 567 | ||
| 568 |
# Validate that the fleet's composition data is available |
|
| 569 | 36x |
comp_data <- comp[["m_comp"]](data, fleet_name) |
| 570 | 36x |
if (is.null(comp_data) || length(comp_data) == 0) {
|
| 571 | ! |
cli::cli_abort(c( |
| 572 | ! |
"`{comp[['name']]}`-composition data for fleet `{fleet_name}` is
|
| 573 | ! |
unavailable or empty." |
| 574 |
)) |
|
| 575 |
} |
|
| 576 | ||
| 577 | 36x |
model_data <- comp_data * |
| 578 | 36x |
get_data(data) |> |
| 579 | 36x |
dplyr::filter( |
| 580 | 36x |
name == fleet_name, |
| 581 | 36x |
type == comp[["name"]] |
| 582 |
) |> |
|
| 583 | 36x |
dplyr::mutate( |
| 584 | 36x |
valid_n = ifelse(value == -999, 1, uncertainty) |
| 585 |
) |> |
|
| 586 | 36x |
dplyr::pull(valid_n) |
| 587 | ||
| 588 | 36x |
if (length(model_data) != get_n_years(data) * get_function(data)) {
|
| 589 | ! |
bad_data_years <- get_data(data) |> |
| 590 | ! |
dplyr::filter( |
| 591 | ! |
name == fleet_name, |
| 592 | ! |
type == comp[["name"]] |
| 593 |
) |> |
|
| 594 | ! |
dplyr::count(timing) |> |
| 595 | ! |
dplyr::filter(n != get_function(data)) |> |
| 596 | ! |
dplyr::pull(timing) |
| 597 | ||
| 598 | ! |
cli::cli_abort(c( |
| 599 | ! |
"The length of the `{comp[['name']]}`-composition data for fleet
|
| 600 | ! |
`{fleet_name}` does not match the expected dimensions.",
|
| 601 | ! |
i = "Expected length: {get_n_years(data) * get_function(data)}",
|
| 602 | ! |
i = "Actual length: {length(model_data)}",
|
| 603 | ! |
i = "Number of -999 values: {sum(model_data == -999)}",
|
| 604 | ! |
i = "Dates with invalid data: {bad_data_years}"
|
| 605 |
)) |
|
| 606 |
} |
|
| 607 | ||
| 608 | 36x |
purrr::walk( |
| 609 | 36x |
seq_along(model_data), |
| 610 | 36x |
\(x) module[[comp[["comp_data_field"]]]]$set(x - 1, model_data[x]) |
| 611 |
) |
|
| 612 | ||
| 613 | 36x |
return(module) |
| 614 |
} |
|
| 615 | ||
| 616 |
#' Initialize FIMS modules |
|
| 617 |
#' |
|
| 618 |
#' @description |
|
| 619 |
#' Initializes multiple modules within the Fisheries Integrated Modeling System |
|
| 620 |
#' (FIMS), including fleet, recruitment, growth, maturity, and population |
|
| 621 |
#' modules. This function iterates over the provided fleets, setting up |
|
| 622 |
#' necessary sub-modules such as selectivity, index, and age composition. It |
|
| 623 |
#' also sets up distribution models for fishery index and age-composition data. |
|
| 624 |
#' @param parameters A tibble. Contains parameters and modules required for |
|
| 625 |
#' initialization. |
|
| 626 |
#' @param data An S4 object. FIMS input data. |
|
| 627 |
#' @return |
|
| 628 |
#' A list containing parameters for the initialized FIMS modules, ready for use |
|
| 629 |
#' in TMB modeling. |
|
| 630 |
#' @export |
|
| 631 |
initialize_fims <- function(parameters, data) {
|
|
| 632 |
# Validate parameters input |
|
| 633 | 15x |
if (missing(parameters) || !tibble::is_tibble(parameters)) {
|
| 634 | 2x |
cli::cli_abort("The {.var parameters} argument must be a tibble.")
|
| 635 |
} |
|
| 636 | ||
| 637 |
# Check if parameters is a nested tibble. If so, unnest parameters |
|
| 638 | 13x |
if ("data" %in% names(parameters)) {
|
| 639 | ! |
parameters <- parameters |> |
| 640 | ! |
tidyr::unnest(cols = c(data)) |
| 641 |
} |
|
| 642 | ||
| 643 |
# Check if estimation_type is within "constant", "fixed_effect", "random_effect" |
|
| 644 | 13x |
valid_estimation_types <- c("constant", "fixed_effects", "random_effects")
|
| 645 | 13x |
invalid_estimation_types <- parameters |> |
| 646 | 13x |
dplyr::filter(!estimation_type %in% valid_estimation_types) |> |
| 647 | 13x |
dplyr::pull(estimation_type) |> |
| 648 | 13x |
unique() |> |
| 649 | 13x |
na.omit() |
| 650 | ||
| 651 | 13x |
if (length(invalid_estimation_types) > 0) {
|
| 652 | 1x |
cli::cli_abort(c( |
| 653 | 1x |
"The `estimation_type` must be one of: {valid_estimation_types}.",
|
| 654 | 1x |
i = "Invalid values found: {invalid_estimation_types}."
|
| 655 |
)) |
|
| 656 |
} |
|
| 657 | ||
| 658 |
# Clear any previous FIMS settings |
|
| 659 | 12x |
clear() |
| 660 | ||
| 661 | 12x |
fleet_names <- parameters |> |
| 662 | 12x |
dplyr::pull(fleet_name) |> |
| 663 | 12x |
unique() |> |
| 664 | 12x |
na.omit() |
| 665 | ||
| 666 | 12x |
if (length(fleet_names) == 0) {
|
| 667 | 1x |
cli::cli_abort(c( |
| 668 | 1x |
"No fleets found in the provided {.var parameters}."
|
| 669 |
)) |
|
| 670 |
} |
|
| 671 | ||
| 672 |
# Initialize lists to store fleet-related objects |
|
| 673 | 11x |
fleet <- fleet_selectivity <- |
| 674 | 11x |
fleet_landings <- fleet_landings_distribution <- |
| 675 | 11x |
fleet_index <- fleet_index_distribution <- |
| 676 | 11x |
fleet_age_comp <- fleet_agecomp_distribution <- |
| 677 | 11x |
fleet_length_comp <- fleet_lengthcomp_distribution <- |
| 678 | 11x |
vector("list", length(fleet_names))
|
| 679 | ||
| 680 | 11x |
for (i in seq_along(fleet_names)) {
|
| 681 | 22x |
fleet_selectivity[[i]] <- initialize_selectivity( |
| 682 | 22x |
parameters = parameters, |
| 683 | 22x |
data = data, |
| 684 | 22x |
fleet_name = fleet_names[i] |
| 685 |
) |
|
| 686 | ||
| 687 | 22x |
fleet_module_ids <- c( |
| 688 | 22x |
selectivity = fleet_selectivity[[i]]$get_id() |
| 689 |
) |
|
| 690 | ||
| 691 | 22x |
fleet_types <- get_data(data) |> |
| 692 | 22x |
dplyr::filter(name == fleet_names[i]) |> |
| 693 | 22x |
dplyr::pull(type) |> |
| 694 | 22x |
unique() |
| 695 | ||
| 696 | 22x |
data_distribution_names_for_fleet_i <- parameters |> |
| 697 | 22x |
dplyr::filter(fleet_name == fleet_names[i] & distribution_type == "Data") |> |
| 698 | 22x |
dplyr::pull(module_type) |
| 699 | ||
| 700 |
# Initialize landings module if the data type includes "landings" and |
|
| 701 |
# if "Landings" exists in the data distribution specification |
|
| 702 | 22x |
if ("landings" %in% fleet_types &&
|
| 703 | 22x |
"Landings" %in% data_distribution_names_for_fleet_i) {
|
| 704 |
# Initialize landings module for the current fleet |
|
| 705 | 11x |
fleet_landings[[i]] <- initialize_landings( |
| 706 | 11x |
data = data, |
| 707 | 11x |
fleet_name = fleet_names[i] |
| 708 |
) |
|
| 709 | ||
| 710 |
# Add the module ID for the initialized landings to the list of fleet module IDs |
|
| 711 | 11x |
fleet_module_ids <- c( |
| 712 | 11x |
fleet_module_ids, |
| 713 | 11x |
c(landings = fleet_landings[[i]]$get_id()) |
| 714 |
) |
|
| 715 |
} |
|
| 716 | ||
| 717 |
# Initialize index module if the data type includes "index" and |
|
| 718 |
# if "Index" exists in the data distribution specification |
|
| 719 | 22x |
if ("index" %in% fleet_types &&
|
| 720 | 22x |
"Index" %in% data_distribution_names_for_fleet_i) {
|
| 721 |
# Initialize index module for the current fleet |
|
| 722 | 11x |
fleet_index[[i]] <- initialize_index( |
| 723 | 11x |
data = data, |
| 724 | 11x |
fleet_name = fleet_names[i] |
| 725 |
) |
|
| 726 | ||
| 727 |
# Add the module ID for the initialized index to the list of fleet module IDs |
|
| 728 | 11x |
fleet_module_ids <- c( |
| 729 | 11x |
fleet_module_ids, |
| 730 | 11x |
c(index = fleet_index[[i]]$get_id()) |
| 731 |
) |
|
| 732 |
} |
|
| 733 | ||
| 734 |
# Initialize age composition module if the data type includes "age_comp" and |
|
| 735 |
# if "AgeComp" exists in the data distribution specification |
|
| 736 | 22x |
if ("age_comp" %in% fleet_types &&
|
| 737 | 22x |
"AgeComp" %in% data_distribution_names_for_fleet_i) {
|
| 738 |
# Initialize age composition module for the current fleet |
|
| 739 | 18x |
fleet_age_comp[[i]] <- initialize_comp( |
| 740 | 18x |
data = data, |
| 741 | 18x |
fleet_name = fleet_names[i], |
| 742 | 18x |
type = "AgeComp" |
| 743 |
) |
|
| 744 | ||
| 745 |
# Add the module ID for the initialized age composition to the list of fleet module IDs |
|
| 746 | 18x |
fleet_module_ids <- c( |
| 747 | 18x |
fleet_module_ids, |
| 748 | 18x |
c(age_comp = fleet_age_comp[[i]]$get_id()) |
| 749 |
) |
|
| 750 |
} |
|
| 751 | ||
| 752 |
# Initialize length composition module if the data type includes "length_comp" and |
|
| 753 |
# if "LengthComp" exists in the data distribution specification |
|
| 754 | 22x |
if ("length_comp" %in% fleet_types &&
|
| 755 | 22x |
"LengthComp" %in% data_distribution_names_for_fleet_i) {
|
| 756 |
# Initialize length composition module for the current fleet |
|
| 757 | 16x |
fleet_length_comp[[i]] <- initialize_comp( |
| 758 | 16x |
data = data, |
| 759 | 16x |
fleet_name = fleet_names[i], |
| 760 | 16x |
type = "LengthComp" |
| 761 |
) |
|
| 762 | ||
| 763 |
# Add the module ID for the initialized length composition to the list of fleet module IDs |
|
| 764 | 16x |
fleet_module_ids <- c( |
| 765 | 16x |
fleet_module_ids, |
| 766 | 16x |
c(length_comp = fleet_length_comp[[i]]$get_id()) |
| 767 |
) |
|
| 768 |
} |
|
| 769 | ||
| 770 | 22x |
fleet[[i]] <- initialize_fleet( |
| 771 | 22x |
parameters = parameters, |
| 772 | 22x |
data = data, |
| 773 | 22x |
fleet_name = fleet_names[i], |
| 774 |
# TODO: need to remove linked_ids from the function and add module_id to the |
|
| 775 |
# parameters tibble |
|
| 776 | 22x |
linked_ids = fleet_module_ids |
| 777 |
) |
|
| 778 | ||
| 779 | 22x |
fleet_sd_input <- parameters |> |
| 780 | 22x |
dplyr::filter(fleet_name == fleet_names[i] & label == "log_sd") |> |
| 781 | 22x |
dplyr::mutate( |
| 782 | 22x |
label = "sd", |
| 783 | 22x |
value = exp(value) |
| 784 |
) |
|
| 785 | ||
| 786 | 22x |
if (length(fleet_sd_input) == 0) {
|
| 787 | ! |
cli::cli_abort(c( |
| 788 | ! |
"Missing required inputs for `log_sd` in fleet `{fleet_name}`."
|
| 789 |
)) |
|
| 790 |
} |
|
| 791 | ||
| 792 | 22x |
if ("index" %in% fleet_types &&
|
| 793 | 22x |
"Index" %in% data_distribution_names_for_fleet_i) {
|
| 794 | 11x |
fleet_index_distribution[[i]] <- initialize_data_distribution( |
| 795 | 11x |
module = fleet[[i]], |
| 796 |
# TODO: need to update family and match options from the distribution |
|
| 797 |
# column from the parameters tibble |
|
| 798 | 11x |
family = lognormal(link = "log"), |
| 799 | 11x |
sd = fleet_sd_input, |
| 800 | 11x |
data_type = "index" |
| 801 |
) |
|
| 802 |
} |
|
| 803 | ||
| 804 | 22x |
if ("landings" %in% fleet_types &&
|
| 805 | 22x |
"Landings" %in% data_distribution_names_for_fleet_i) {
|
| 806 | 11x |
fleet_landings_distribution[[i]] <- initialize_data_distribution( |
| 807 | 11x |
module = fleet[[i]], |
| 808 |
# TODO: need to update family and match options from the distribution |
|
| 809 |
# column from the parameters tibble |
|
| 810 | 11x |
family = lognormal(link = "log"), |
| 811 | 11x |
sd = fleet_sd_input, |
| 812 | 11x |
data_type = "landings" |
| 813 |
) |
|
| 814 |
} |
|
| 815 | ||
| 816 | 22x |
if ("age_comp" %in% fleet_types &&
|
| 817 | 22x |
"AgeComp" %in% data_distribution_names_for_fleet_i) {
|
| 818 | 18x |
fleet_agecomp_distribution[[i]] <- initialize_data_distribution( |
| 819 | 18x |
module = fleet[[i]], |
| 820 |
# TODO: need to update family and match options from the distribution |
|
| 821 |
# column from the parameters tibble |
|
| 822 | 18x |
family = multinomial(link = "logit"), |
| 823 | 18x |
data_type = "agecomp" |
| 824 |
) |
|
| 825 |
} |
|
| 826 | ||
| 827 | 22x |
if ("length_comp" %in% fleet_types &&
|
| 828 | 22x |
"LengthComp" %in% data_distribution_names_for_fleet_i) {
|
| 829 | 16x |
fleet_lengthcomp_distribution[[i]] <- initialize_data_distribution( |
| 830 | 16x |
module = fleet[[i]], |
| 831 |
# TODO: need to update family and match options from the distribution |
|
| 832 |
# column from the parameters tibble |
|
| 833 | 16x |
family = multinomial(link = "logit"), |
| 834 | 16x |
data_type = "lengthcomp" |
| 835 |
) |
|
| 836 |
} |
|
| 837 |
} |
|
| 838 | ||
| 839 |
# Recruitment |
|
| 840 |
# create new module in the recruitment class (specifically Beverton--Holt, |
|
| 841 |
# when there are other options, this would be where the option would be |
|
| 842 |
# chosen) |
|
| 843 | 11x |
recruitment <- initialize_recruitment( |
| 844 | 11x |
parameters = parameters, |
| 845 | 11x |
data = data |
| 846 |
) |
|
| 847 | ||
| 848 | 11x |
recruitment_process_input <- parameters |> |
| 849 | 11x |
dplyr::filter(module_name == "Recruitment" & distribution_type == "process") |
| 850 | ||
| 851 | 11x |
if (length(recruitment_process_input) == 0) {
|
| 852 |
# TODO: need to revisit initialize_process_structure and add R tests |
|
| 853 | ! |
recruitment_process <- initialize_process_structure( |
| 854 | ! |
module = recruitment, |
| 855 | ! |
par = "log_devs" |
| 856 |
) |
|
| 857 |
} else {
|
|
| 858 | 11x |
pars <- recruitment_process_input |> |
| 859 | 11x |
dplyr::pull(distribution_link) |> |
| 860 | 11x |
unique() |
| 861 | ||
| 862 |
# Initialize_process_distribution for each par |
|
| 863 | 11x |
recruitment_distribution <- purrr::map(pars, function(par) {
|
| 864 | 11x |
sd_input <- recruitment_process_input |> |
| 865 | 11x |
dplyr::filter(distribution_link == par & label == "log_sd") |
| 866 | 11x |
initialize_process_distribution( |
| 867 | 11x |
module = recruitment, |
| 868 | 11x |
par = par, |
| 869 |
# TODO: need to update family and match options from the distribution |
|
| 870 |
# column from the parameters tibble |
|
| 871 | 11x |
family = gaussian(), |
| 872 | 11x |
sd = sd_input, |
| 873 |
# TODO: need to remove is_random_effect and match options from the |
|
| 874 |
# estimation_type from the parameters tibble |
|
| 875 | 11x |
is_random_effect = FALSE |
| 876 |
) |
|
| 877 | ||
| 878 | 11x |
recruitment_process <- initialize_process_structure( |
| 879 | 11x |
module = recruitment, |
| 880 | 11x |
par = par |
| 881 |
) |
|
| 882 |
}) |
|
| 883 |
} |
|
| 884 | ||
| 885 |
# Growth |
|
| 886 | 11x |
growth <- initialize_growth( |
| 887 | 11x |
parameters = parameters, |
| 888 | 11x |
data = data |
| 889 |
) |
|
| 890 | ||
| 891 |
# Maturity |
|
| 892 | 11x |
maturity <- initialize_maturity( |
| 893 | 11x |
parameters = parameters, |
| 894 | 11x |
data = data |
| 895 |
) |
|
| 896 | ||
| 897 | 11x |
population_module_ids <- c( |
| 898 | 11x |
recruitment = recruitment$get_id(), |
| 899 | 11x |
growth = growth$get_id(), |
| 900 | 11x |
maturity = maturity$get_id(), |
| 901 | 11x |
fleets = purrr::map(fleet, \(x) x$get_id()) |
| 902 |
) |
|
| 903 | ||
| 904 |
# Population |
|
| 905 | 11x |
population <- initialize_population( |
| 906 | 11x |
parameters = parameters, |
| 907 | 11x |
data = data, |
| 908 |
# TODO: need to remove linked_ids from the function and add module_id to the |
|
| 909 |
# parameters tibble |
|
| 910 | 11x |
linked_ids = population_module_ids |
| 911 |
) |
|
| 912 | ||
| 913 |
# Set-up TMB |
|
| 914 |
# Hard code to be a catch-at-age model |
|
| 915 | 11x |
fims_model <- methods::new(CatchAtAge) |
| 916 | 11x |
fims_model$AddPopulation(population$get_id()) |
| 917 | ||
| 918 | 11x |
CreateTMBModel() |
| 919 |
# Create parameter list from Rcpp modules |
|
| 920 | 11x |
parameter_list <- list( |
| 921 | 11x |
parameters = list( |
| 922 | 11x |
p = get_fixed(), |
| 923 | 11x |
re = get_random() |
| 924 |
), |
|
| 925 | 11x |
model = fims_model |
| 926 |
) |
|
| 927 | ||
| 928 | 11x |
return(parameter_list) |
| 929 |
} |
|
| 930 | ||
| 931 |
#' Set parameter vector values based on module input |
|
| 932 |
#' |
|
| 933 |
#' @description |
|
| 934 |
#' This function sets the parameter vector values in a module based on the |
|
| 935 |
#' provided module input, including both initial values and estimation |
|
| 936 |
#' information. |
|
| 937 |
#' @param field A character string specifying the field name of the parameter |
|
| 938 |
#' vector to be updated. |
|
| 939 |
#' @param module A module object in which the parameter vector is to be set. |
|
| 940 |
#' @param module_input A list containing input parameters for the module, |
|
| 941 |
#' including value and estimation information for the parameter vector. |
|
| 942 |
#' @return |
|
| 943 |
#' Modified module object. |
|
| 944 |
#' @noRd |
|
| 945 |
set_param_vector <- function(field, module, module_input) {
|
|
| 946 |
# Check if field_name is a non-empty character string |
|
| 947 | 187x |
if (missing(field) || !is.character(field) || nchar(field) == 0) {
|
| 948 | ! |
cli::cli_abort(c( |
| 949 | ! |
"The {.var field} argument must be a non-empty character string."
|
| 950 |
)) |
|
| 951 |
} |
|
| 952 | ||
| 953 |
# Check if module is a reference class |
|
| 954 | 187x |
if (!is(module, "refClass")) {
|
| 955 | ! |
cli::cli_abort(c( |
| 956 | ! |
"The {.var module} argument must be a reference class created by
|
| 957 | ! |
{.fn methods::new}."
|
| 958 |
)) |
|
| 959 |
} |
|
| 960 | ||
| 961 |
# Check if module_input is a list |
|
| 962 | 187x |
if (!tibble::is_tibble(module_input)) {
|
| 963 | ! |
cli::cli_abort("The {.var module_input} argument must be tibble.")
|
| 964 |
} |
|
| 965 | ||
| 966 |
# Extract the value of the parameter vector |
|
| 967 | 187x |
field_value <- module_input |> |
| 968 | 187x |
dplyr::filter(label == field) |> |
| 969 | 187x |
dplyr::pull(value) |
| 970 | ||
| 971 | 187x |
field_estimation_type <- module_input |> |
| 972 | 187x |
dplyr::filter(label == field) |> |
| 973 | 187x |
dplyr::pull(estimation_type) |
| 974 | ||
| 975 |
# Check if both value and estimation information are present |
|
| 976 | 187x |
if (length(field_value) == 0 || length(field_estimation_type) == 0) {
|
| 977 | ! |
cli::cli_abort(c( |
| 978 | ! |
"Missing value or estimation_type information for {.var field}."
|
| 979 |
)) |
|
| 980 |
} |
|
| 981 |
# Resize the field in the module |
|
| 982 | 187x |
module[[field]]$resize(length(field_value)) |
| 983 | ||
| 984 |
# Assign each value to the corresponding position in the parameter vector |
|
| 985 | 187x |
for (i in seq_along(field_value)) {
|
| 986 | 5841x |
module[[field]][i][["value"]] <- field_value[i] |
| 987 | 5841x |
module[[field]][i][["estimation_type"]]$set(field_estimation_type[i]) |
| 988 |
} |
|
| 989 |
} |
| 1 |
# TODO: Document the names/items in each list that are returned |
|
| 2 |
#' Create default parameters for a FIMS model |
|
| 3 |
#' |
|
| 4 |
#' @description |
|
| 5 |
#' This function generates a Fisheries Integrated Modeling System (FIMS) model |
|
| 6 |
#' configuration with detailed parameter specifications. This function takes a |
|
| 7 |
#' high-level configuration `tibble` and generates the corresponding parameters |
|
| 8 |
#' with default initial values and estimation settings required to build and run |
|
| 9 |
#' the model. |
|
| 10 |
#' |
|
| 11 |
#' @details |
|
| 12 |
#' The function processes the input `configurations` tibble, which defines the |
|
| 13 |
#' modules for different model components (e.g., `"Selectivity"`, `"Recruitment"`). |
|
| 14 |
#' For each module specified, it calls internal helper functions to create a |
|
| 15 |
#' default set of parameters. For example, if a fleet's selectivity is configured |
|
| 16 |
#' as `"Logistic"`, it generates initial values for `"inflection_point"` and |
|
| 17 |
#' `"slope"`. |
|
| 18 |
#' |
|
| 19 |
#' @param configurations A tibble of model configurations. Typically created |
|
| 20 |
#' by [create_default_configurations()]. Users can modify this tibble |
|
| 21 |
#' to customize the model structure before generating default parameters. |
|
| 22 |
#' @param data An S4 object. FIMS input data. |
|
| 23 |
#' @return A `tibble` with default model parameters. The tibble has a nested |
|
| 24 |
#' structure with the following top-level columns. |
|
| 25 |
#' \describe{
|
|
| 26 |
#' \item{\code{model_family}:}{The specified model family (e.g.,
|
|
| 27 |
#' "catch_at_age").} |
|
| 28 |
#' \item{\code{module_name}:}{The name of the FIMS module (e.g.,
|
|
| 29 |
#' "Data", "Selectivity", "Recruitment", "Growth", "Maturity").} |
|
| 30 |
#' \item{\code{fleet_name}:}{The name of the fleet the module applies to. This
|
|
| 31 |
#' will be `NA` for non-fleet-specific modules like "Recruitment".} |
|
| 32 |
#' \item{\code{data}:}{A list-column containing a `tibble` with detailed
|
|
| 33 |
#' parameters. Unnesting this column reveals: |
|
| 34 |
#' \describe{
|
|
| 35 |
#' \item{\code{module_type}:}{The specific type of the module (e.g.,
|
|
| 36 |
#' "Logistic" for a "Selectivity" module).} |
|
| 37 |
#' \item{\code{label}:}{The name of the parameter (e.g., "inflection_point").}
|
|
| 38 |
#' \item{\code{distribution_link}:}{The component the distribution module
|
|
| 39 |
#' links to.} |
|
| 40 |
#' \item{\code{age}:}{The age the parameter applies to.}
|
|
| 41 |
#' \item{\code{length}:}{The length bin the parameter applies to.}
|
|
| 42 |
#' \item{\code{time}:}{The time step (i.e., year) the parameter applies to.}
|
|
| 43 |
#' \item{\code{value}:}{The initial value of the parameter.}
|
|
| 44 |
#' \item{\code{estimation_type}:}{The type of estimation (e.g.,
|
|
| 45 |
#' "constant", "fixed_effects", "random_effects").} |
|
| 46 |
#' \item{\code{distribution_type}:}{The type of distribution (e.g., "Data",
|
|
| 47 |
#' "process").} |
|
| 48 |
#' \item{\code{distribution}:}{The name of distribution (e.g.,
|
|
| 49 |
#' "Dlnorm", `Dmultinom`).} |
|
| 50 |
#' } |
|
| 51 |
#' } |
|
| 52 |
#' } |
|
| 53 |
#' @export |
|
| 54 |
#' @seealso |
|
| 55 |
#' * [FIMSFrame()] |
|
| 56 |
#' * [create_default_configurations()] |
|
| 57 |
#' @examples |
|
| 58 |
#' \dontrun{
|
|
| 59 |
#' # Load the example dataset and create a FIMS data frame |
|
| 60 |
#' data("data1")
|
|
| 61 |
#' fims_frame <- FIMSFrame(data1) |
|
| 62 |
#' |
|
| 63 |
#' # Create default configurations |
|
| 64 |
#' default_configurations <- create_default_configurations(fims_frame) |
|
| 65 |
#' |
|
| 66 |
#' # Create default parameters |
|
| 67 |
#' default_parameters <- create_default_parameters( |
|
| 68 |
#' configurations = default_configurations, |
|
| 69 |
#' data = fims_frame |
|
| 70 |
#' ) |> |
|
| 71 |
#' tidyr::unnest(cols = data) |
|
| 72 |
#' |
|
| 73 |
#' # Update selectivity parameters for survey1 |
|
| 74 |
#' updated_parameters <- default_parameters |> |
|
| 75 |
#' dplyr::rows_update( |
|
| 76 |
#' tibble::tibble( |
|
| 77 |
#' fleet_name = "survey1", |
|
| 78 |
#' label = c("inflection_point", "slope"),
|
|
| 79 |
#' value = c(1.5, 2) |
|
| 80 |
#' ), |
|
| 81 |
#' by = c("fleet_name", "label")
|
|
| 82 |
#' ) |
|
| 83 |
#' |
|
| 84 |
#' # Do the same as above except, model fleet1 with double logistic selectivity |
|
| 85 |
#' # To see required parameters for double logistic selectivity, run |
|
| 86 |
#' # show(DoubleLogisticSelectivity) |
|
| 87 |
#' parameters_with_double_logistic <- default_configurations |> |
|
| 88 |
#' tidyr::unnest(cols = data) |> |
|
| 89 |
#' dplyr::rows_update( |
|
| 90 |
#' tibble::tibble( |
|
| 91 |
#' module_name = "Selectivity", |
|
| 92 |
#' fleet_name = "fleet1", |
|
| 93 |
#' module_type = "DoubleLogistic" |
|
| 94 |
#' ), |
|
| 95 |
#' by = c("module_name", "fleet_name")
|
|
| 96 |
#' ) |> |
|
| 97 |
#' create_default_parameters( |
|
| 98 |
#' data = fims_frame |
|
| 99 |
#' ) |
|
| 100 |
#' } |
|
| 101 |
create_default_parameters <- function( |
|
| 102 |
configurations, |
|
| 103 |
data |
|
| 104 |
) {
|
|
| 105 |
# FIXME: use default values if there are no fleets info passed into the |
|
| 106 |
# function or a fleet is not present but it has data? Maybe we don't want the |
|
| 107 |
# latter because it could be that we want to drop a fleet from a model but we |
|
| 108 |
# don't want to alter the data? |
|
| 109 | ||
| 110 |
# Check if configurations is a nested tibble. If so, unnest configurations |
|
| 111 | 3x |
if ("data" %in% names(configurations)) {
|
| 112 | 3x |
unnested_configurations <- tidyr::unnest(configurations, cols = data) |
| 113 |
} else {
|
|
| 114 | ! |
unnested_configurations <- configurations |
| 115 |
} |
|
| 116 | ||
| 117 |
# Create fleet parameters |
|
| 118 | 3x |
fleet_names <- unnested_configurations |> |
| 119 | 3x |
dplyr::pull(fleet_name) |> |
| 120 | 3x |
na.omit() |> |
| 121 | 3x |
unique() |
| 122 | 3x |
fleet_temp <- purrr::map( |
| 123 | 3x |
fleet_names, |
| 124 | 3x |
function(fleet_name_i) {
|
| 125 | 6x |
create_default_fleet( |
| 126 | 6x |
unnested_configurations = unnested_configurations, |
| 127 | 6x |
current_fleet_name = fleet_name_i, |
| 128 | 6x |
data = data |
| 129 |
) |
|
| 130 |
} |
|
| 131 |
) |> |
|
| 132 |
# bind_rows now directly takes the list of tibbles from map() |
|
| 133 | 3x |
dplyr::bind_rows() |
| 134 | ||
| 135 |
# Create recruitment parameters |
|
| 136 | 3x |
recruitment_temp <- create_default_recruitment( |
| 137 | 3x |
unnested_configurations = unnested_configurations, |
| 138 | 3x |
data = data |
| 139 |
) |
|
| 140 | ||
| 141 |
# Create maturity parameters |
|
| 142 | 3x |
maturity_temp <- create_default_maturity( |
| 143 | 3x |
unnested_configurations = unnested_configurations, |
| 144 | 3x |
data = data |
| 145 |
) |
|
| 146 | ||
| 147 |
# Create population parameters |
|
| 148 |
# Handle population parameters based on recruitment form |
|
| 149 | 3x |
log_rzero <- recruitment_temp |> |
| 150 | 3x |
dplyr::filter(label == "log_rzero") |> |
| 151 | 3x |
dplyr::pull(value) |
| 152 | ||
| 153 | 3x |
population_temp <- create_default_Population( |
| 154 | 3x |
unnested_configurations = unnested_configurations, |
| 155 | 3x |
data, |
| 156 | 3x |
log_rzero = log_rzero |
| 157 |
) |
|
| 158 | ||
| 159 |
# Compile temps |
|
| 160 | 3x |
temp <- dplyr::bind_rows( |
| 161 | 3x |
fleet_temp, |
| 162 | 3x |
recruitment_temp, |
| 163 | 3x |
maturity_temp, |
| 164 | 3x |
population_temp |
| 165 |
) |
|
| 166 |
# Merge with configuration_unnest |
|
| 167 | 3x |
expanded_configurations <- dplyr::full_join( |
| 168 | 3x |
temp, |
| 169 | 3x |
unnested_configurations, |
| 170 | 3x |
by = c("module_name", "fleet_name", "module_type", "distribution_link")
|
| 171 |
) |> |
|
| 172 | 3x |
dplyr::mutate( |
| 173 | 3x |
model_family = dplyr::coalesce(model_family.y, model_family.x), |
| 174 | 3x |
distribution_type = dplyr::coalesce(distribution_type.y, distribution_type.x), |
| 175 | 3x |
distribution = dplyr::coalesce(distribution.y, distribution.x) |
| 176 |
) |> |
|
| 177 | 3x |
dplyr::select(-dplyr::ends_with(c(".x", ".y"))) |>
|
| 178 | 3x |
tidyr::fill(model_family) |> |
| 179 | 3x |
dplyr::select( |
| 180 | 3x |
model_family, module_name, module_type, label, distribution_link, dplyr::everything() |
| 181 |
) |> |
|
| 182 | 3x |
tidyr::nest(.by = c(model_family, module_name, fleet_name)) |
| 183 |
} |
|
| 184 | ||
| 185 |
#' Create default parameters for a FIMS model |
|
| 186 |
#' @description |
|
| 187 |
#' This function creates a template for default parameters used in a Fisheries |
|
| 188 |
#' Integrated Modeling System (FIMS) model. The template includes fields for |
|
| 189 |
#' module name, module type, label, fleet name, population name, age, length, |
|
| 190 |
#' time, value, estimation type, distribution type, and distribution. |
|
| 191 |
#' @param n_parameters An integer specifying the number of parameters in the template. |
|
| 192 |
#' @return |
|
| 193 |
#' A tibble template for a FIMS model. |
|
| 194 |
#' @noRd |
|
| 195 |
#' @examples |
|
| 196 |
#' FIMS:::create_default_parameters_template(n_parameters = 3) |
|
| 197 |
create_default_parameters_template <- function(n_parameters = 1) {
|
|
| 198 | 51x |
template <- tibble::tibble( |
| 199 | 51x |
model_family = NA_character_, |
| 200 | 51x |
module_name = NA_character_, |
| 201 | 51x |
module_type = NA_character_, |
| 202 | 51x |
label = NA_character_, |
| 203 | 51x |
distribution_link = NA_character_, |
| 204 | 51x |
fleet_name = NA_character_, |
| 205 | 51x |
age = NA_real_, |
| 206 | 51x |
length = NA_real_, |
| 207 | 51x |
time = NA_integer_, |
| 208 | 51x |
value = NA_real_, |
| 209 | 51x |
estimation_type = NA_character_, |
| 210 | 51x |
distribution_type = NA_character_, |
| 211 | 51x |
distribution = NA_character_ |
| 212 |
) |> |
|
| 213 | 51x |
dplyr::slice(rep(1, each = n_parameters)) |
| 214 |
} |
|
| 215 | ||
| 216 |
#' Create default population parameters |
|
| 217 |
#' |
|
| 218 |
#' @description |
|
| 219 |
#' This function sets up default parameters for a population module. |
|
| 220 |
#' @details |
|
| 221 |
#' The natural log of the initial numbers at age (`log_init_naa.value`) is set based on |
|
| 222 |
#' unexploited recruitment and natural mortality. |
|
| 223 |
#' @param unnested_configurations A tibble of model configurations. Typically created |
|
| 224 |
#' by the `create_default_configurations()`. |
|
| 225 |
#' @param data An S4 object. FIMS input data. |
|
| 226 |
#' @param log_rzero A numeric value representing the natural log of unexploited |
|
| 227 |
#' recruitment. |
|
| 228 |
#' @return |
|
| 229 |
#' A tibble of default population parameters, including initial numbers at |
|
| 230 |
#' age and natural mortality rate. |
|
| 231 |
#' @noRd |
|
| 232 |
create_default_Population <- function( |
|
| 233 |
unnested_configurations, |
|
| 234 |
data, |
|
| 235 |
log_rzero |
|
| 236 |
) {
|
|
| 237 |
# Input checks |
|
| 238 |
# Check if log_rzero is numeric |
|
| 239 | 3x |
if (!is.numeric(log_rzero) || length(log_rzero) != 1) {
|
| 240 | ! |
local_bullets <- c( |
| 241 | ! |
"i" = "{.var log_rzero} argument must be a single numeric value.",
|
| 242 | ! |
"x" = "{.var log_rzero} has a length of {length(log_rzero)}.",
|
| 243 | ! |
"x" = "{.var log_rzero} is of the class {class(log_rzero)}."
|
| 244 |
) |
|
| 245 | ! |
names(local_bullets)[2] <- ifelse(length(log_rzero) > 1, "x", "i") |
| 246 | ! |
names(local_bullets)[3] <- ifelse(inherits(log_rzero, "numeric"), "i", "x") |
| 247 | ! |
cli::cli_abort(local_bullets) |
| 248 |
} |
|
| 249 | ||
| 250 |
# Extract necessary values from data |
|
| 251 | 3x |
n_years <- get_n_years(data) |
| 252 | 3x |
n_ages <- get_n_ages(data) |
| 253 | ||
| 254 |
# Set natural mortality rate |
|
| 255 | 3x |
M_value <- 0.2 |
| 256 | ||
| 257 |
# Calculate initial numbers at age based on log_rzero and M_value |
|
| 258 | 3x |
init_naa <- exp(log_rzero) * exp(-(get_ages(data) - 1) * M_value) |
| 259 | 3x |
init_naa[n_ages] <- init_naa[n_ages] / M_value # sum of infinite series |
| 260 | ||
| 261 |
# Create a list of default parameters |
|
| 262 | 3x |
default <- create_default_parameters_template( |
| 263 | 3x |
n_parameters = n_years * n_ages |
| 264 |
) |> |
|
| 265 |
# Add the module type, label, value, and estimation type |
|
| 266 | 3x |
dplyr::mutate( |
| 267 | 3x |
label = "log_M", |
| 268 | 3x |
value = log(M_value), |
| 269 | 3x |
estimation_type = "constant" |
| 270 |
) |> |
|
| 271 | 3x |
dplyr::add_row( |
| 272 | 3x |
label = "log_init_naa", |
| 273 | 3x |
age = get_ages(data), |
| 274 | 3x |
value = log(init_naa), |
| 275 | 3x |
estimation_type = "fixed_effects" |
| 276 |
) |> |
|
| 277 | 3x |
dplyr::mutate( |
| 278 | 3x |
module_name = "Population" |
| 279 |
) |
|
| 280 |
} |
|
| 281 | ||
| 282 |
#' Create default logistic parameters |
|
| 283 |
#' |
|
| 284 |
#' @description |
|
| 285 |
#' This function sets up default parameters for a logistic function. There are |
|
| 286 |
#' two specified parameters, the inflection point and slope. |
|
| 287 |
#' @return |
|
| 288 |
#' A tibble containing the default logistic parameters, with inflection_point and |
|
| 289 |
#' slope values and their estimation status. |
|
| 290 |
#' @noRd |
|
| 291 |
create_default_Logistic <- function() {
|
|
| 292 |
# Create a template for default parameters |
|
| 293 | 9x |
default <- create_default_parameters_template(n_parameters = 2) |> |
| 294 |
# Add the module type, label, value, and estimation type |
|
| 295 | 9x |
dplyr::mutate( |
| 296 | 9x |
module_type = "Logistic", |
| 297 | 9x |
label = c("inflection_point", "slope"),
|
| 298 | 9x |
value = c(2, 1), |
| 299 | 9x |
estimation_type = "fixed_effects" |
| 300 |
) |
|
| 301 |
} |
|
| 302 | ||
| 303 |
#' Create default double logistic parameters |
|
| 304 |
#' |
|
| 305 |
#' @description |
|
| 306 |
#' This function sets up default parameters for a double logistic function. |
|
| 307 |
#' There four specified parameters, two for the ascending and two for the |
|
| 308 |
#' descending inflection points and slopes. |
|
| 309 |
#' @return |
|
| 310 |
#' A tibble containing the default double logistic parameters, |
|
| 311 |
#' inflection_point_asc, slope_asc, inflection_point_desc, and slope_desc |
|
| 312 |
#' values and their estimation status. |
|
| 313 |
#' @noRd |
|
| 314 |
create_default_DoubleLogistic <- function(module_name = NA_character_) {
|
|
| 315 | ! |
default <- create_default_parameters_template(n_parameters = 4) |> |
| 316 | ! |
dplyr::mutate( |
| 317 | ! |
module_name = !!module_name, |
| 318 | ! |
module_type = "DoubleLogistic", |
| 319 | ! |
label = c("inflection_point_asc", "slope_asc", "inflection_point_desc", "slope_desc"),
|
| 320 |
# TODO: Determine if inflection_point_desc should really be 4? |
|
| 321 | ! |
value = c(2, 1, 4, 1), |
| 322 | ! |
estimation_type = "fixed_effects" |
| 323 |
) |
|
| 324 |
} |
|
| 325 | ||
| 326 |
#' Create default selectivity parameters |
|
| 327 |
#' |
|
| 328 |
#' @description |
|
| 329 |
#' This function sets up default parameters for a selectivity module. |
|
| 330 |
#' @param form A string specifying the desired form of selectivity. Allowable |
|
| 331 |
#' forms include `r toString(formals(create_default_selectivity)[["form"]])` |
|
| 332 |
#' and the default is |
|
| 333 |
#' `r toString(formals(create_default_selectivity)[["form"]][1])`. |
|
| 334 |
#' @return |
|
| 335 |
#' A tibble is returned with the default parameter values for the specified form |
|
| 336 |
#' of selectivity. |
|
| 337 |
#' @noRd |
|
| 338 |
create_default_selectivity <- function( |
|
| 339 |
form = c("Logistic", "DoubleLogistic")
|
|
| 340 |
) {
|
|
| 341 |
# Input checks |
|
| 342 | 6x |
form <- rlang::arg_match(form) |
| 343 |
# NOTE: All new forms of selectivity must be placed in the vector of default |
|
| 344 |
# arguments for `form` and their methods but be placed below in the call to |
|
| 345 |
# `switch` |
|
| 346 | 6x |
default <- switch(form, |
| 347 | 6x |
"Logistic" = create_default_Logistic(), |
| 348 | 6x |
"DoubleLogistic" = create_default_DoubleLogistic() |
| 349 |
) |> |
|
| 350 | 6x |
dplyr::mutate( |
| 351 | 6x |
module_name = "Selectivity" |
| 352 |
) |
|
| 353 |
} |
|
| 354 | ||
| 355 |
#' Create default fleet parameters |
|
| 356 |
#' |
|
| 357 |
#' @description |
|
| 358 |
#' This function sets up default parameters for a fleet module. It compiles |
|
| 359 |
#' selectivity parameters along with distributions for each type of data that |
|
| 360 |
#' are present for the given fleet. |
|
| 361 |
#' |
|
| 362 |
#' @param unnested_configurations A tibble of model configurations. Typically |
|
| 363 |
#' created by the `create_default_configurations()`. |
|
| 364 |
#' @param fleet_name A character. Name of the fleet. |
|
| 365 |
#' @param data An S4 object. FIMS input data. |
|
| 366 |
#' @return |
|
| 367 |
#' A tibble with default parameters for the fleet. |
|
| 368 |
#' @noRd |
|
| 369 |
create_default_fleet <- function(unnested_configurations, |
|
| 370 |
current_fleet_name, |
|
| 371 |
data) {
|
|
| 372 |
# Input checks |
|
| 373 | 6x |
if (length(current_fleet_name) > 1) {
|
| 374 | ! |
cli::cli_abort(c( |
| 375 | ! |
"i" = "{.var current_fleet_name} should have a length of 1.",
|
| 376 | ! |
"x" = "{.var current_fleet_name} has a length of {length(current_fleet_name)}."
|
| 377 |
)) |
|
| 378 |
} |
|
| 379 | 6x |
if (!inherits(current_fleet_name, "character")) {
|
| 380 | ! |
cli::cli_abort(c( |
| 381 | ! |
"i" = "{.var current_fleet_name} should be a string.",
|
| 382 | ! |
"x" = "{.var current_fleet_name} is a {class(current_fleet_name)}."
|
| 383 |
)) |
|
| 384 |
} |
|
| 385 | ||
| 386 |
# Create default selectivity parameters |
|
| 387 | 6x |
selectivity_form <- unnested_configurations |> |
| 388 | 6x |
dplyr::filter(fleet_name == current_fleet_name & module_name == "Selectivity") |> |
| 389 | 6x |
dplyr::pull(module_type) |
| 390 | ||
| 391 | 6x |
selectivity_default <- create_default_selectivity( |
| 392 | 6x |
form = selectivity_form |
| 393 |
) |> |
|
| 394 |
# Add fleet name |
|
| 395 | 6x |
dplyr::mutate( |
| 396 | 6x |
fleet_name = current_fleet_name |
| 397 |
) |
|
| 398 | ||
| 399 |
# Get types of data for this fleet from the data object |
|
| 400 | 6x |
data_types_present <- get_data(data) |> |
| 401 | 6x |
dplyr::filter(name == current_fleet_name) |> |
| 402 | 6x |
dplyr::pull(type) |> |
| 403 | 6x |
unique() |
| 404 | ||
| 405 |
# Get data likelihood distributions assigned for this fleet |
|
| 406 | 6x |
distribution_names_for_fleet <- unnested_configurations |> |
| 407 | 6x |
dplyr::filter(fleet_name == current_fleet_name & module_name == "Data") |> |
| 408 | 6x |
dplyr::pull(module_type) |
| 409 | ||
| 410 |
# Determine default fleet parameters based on types of data present |
|
| 411 | 6x |
if ("index" %in% data_types_present &&
|
| 412 | 6x |
"Index" %in% distribution_names_for_fleet) {
|
| 413 | 3x |
fleet_index <- get_data(data) |> |
| 414 | 3x |
dplyr::filter(type == "index" & name == current_fleet_name) |> |
| 415 | 3x |
dplyr::rename(time = timing) |
| 416 | ||
| 417 | 3x |
q_default <- create_default_parameters_template(n_parameters = 1) |> |
| 418 | 3x |
dplyr::mutate( |
| 419 | 3x |
module_name = "Fleet", |
| 420 | 3x |
label = "log_q", |
| 421 | 3x |
fleet_name = current_fleet_name, |
| 422 | 3x |
value = 0, |
| 423 | 3x |
estimation_type = "fixed_effects" |
| 424 |
) |
|
| 425 | ||
| 426 | 3x |
index_distribution <- unnested_configurations |> |
| 427 | 3x |
dplyr::filter( |
| 428 | 3x |
fleet_name == current_fleet_name & module_name == "Data" & module_type == "Index" |
| 429 |
) |> |
|
| 430 | 3x |
dplyr::pull(distribution) |
| 431 | ||
| 432 | 3x |
index_uncertainty <- get_data(data) |> |
| 433 | 3x |
dplyr::filter(name == current_fleet_name, type %in% c("index")) |>
|
| 434 | 3x |
dplyr::arrange(dplyr::desc(type)) |> |
| 435 | 3x |
dplyr::pull(uncertainty) |
| 436 | ||
| 437 | 3x |
index_distribution_default <- switch(index_distribution, |
| 438 | 3x |
"Dnorm" = create_default_DnormDistribution( |
| 439 | 3x |
value = index_uncertainty, |
| 440 | 3x |
input_type = "data", |
| 441 | 3x |
data = data |
| 442 |
), |
|
| 443 | 3x |
"Dlnorm" = create_default_DlnormDistribution( |
| 444 | 3x |
value = index_uncertainty, |
| 445 | 3x |
input_type = "data", |
| 446 | 3x |
data = data |
| 447 |
) |
|
| 448 |
) |> |
|
| 449 | 3x |
dplyr::mutate( |
| 450 | 3x |
module_name = "Data", |
| 451 | 3x |
module_type = "Index", |
| 452 | 3x |
distribution_link = "Index", |
| 453 | 3x |
fleet_name = current_fleet_name, |
| 454 | 3x |
time = fleet_index[["time"]] |
| 455 |
) |
|
| 456 |
} else {
|
|
| 457 | 3x |
q_default <- create_default_parameters_template(n_parameters = 1) |> |
| 458 | 3x |
dplyr::mutate( |
| 459 | 3x |
module_name = "Fleet", |
| 460 | 3x |
label = "log_q", |
| 461 | 3x |
fleet_name = current_fleet_name, |
| 462 | 3x |
value = 0, |
| 463 | 3x |
estimation_type = "constant" |
| 464 |
) |
|
| 465 | 3x |
index_distribution_default <- NULL |
| 466 |
} |
|
| 467 | ||
| 468 | 6x |
if ("landings" %in% data_types_present &&
|
| 469 | 6x |
"Landings" %in% distribution_names_for_fleet) {
|
| 470 | 3x |
fleet_landings <- get_data(data) |> |
| 471 | 3x |
dplyr::filter(type == "landings" & name == current_fleet_name) |> |
| 472 | 3x |
dplyr::rename(time = timing) |
| 473 | ||
| 474 | 3x |
log_Fmort_default <- create_default_parameters_template( |
| 475 | 3x |
n_parameters = get_n_years(data) |
| 476 |
) |> |
|
| 477 | 3x |
dplyr::mutate( |
| 478 | 3x |
module_name = "Fleet", |
| 479 | 3x |
label = "log_Fmort", |
| 480 | 3x |
fleet_name = current_fleet_name, |
| 481 | 3x |
time = get_start_year(data):get_end_year(data), |
| 482 | 3x |
value = -3, |
| 483 | 3x |
estimation_type = "fixed_effects" |
| 484 |
) |
|
| 485 | ||
| 486 | 3x |
landings_distribution <- unnested_configurations |> |
| 487 | 3x |
dplyr::filter(fleet_name == current_fleet_name & module_name == "Data" & module_type == "Landings") |> |
| 488 | 3x |
dplyr::pull(distribution) |
| 489 | ||
| 490 | 3x |
landings_uncertainty <- get_data(data) |> |
| 491 | 3x |
dplyr::filter(name == current_fleet_name, type %in% c("landings")) |>
|
| 492 | 3x |
dplyr::arrange(dplyr::desc(type)) |> |
| 493 | 3x |
dplyr::pull(uncertainty) |
| 494 | ||
| 495 | 3x |
landings_distribution_default <- switch(landings_distribution, |
| 496 | 3x |
"Dnorm" = create_default_DnormDistribution( |
| 497 | 3x |
value = landings_uncertainty, |
| 498 | 3x |
input_type = "data", |
| 499 | 3x |
data = data |
| 500 |
), |
|
| 501 | 3x |
"Dlnorm" = create_default_DlnormDistribution( |
| 502 | 3x |
value = landings_uncertainty, |
| 503 | 3x |
input_type = "data", |
| 504 | 3x |
data = data |
| 505 |
) |
|
| 506 |
) |> |
|
| 507 | 3x |
dplyr::mutate( |
| 508 | 3x |
module_name = "Data", |
| 509 | 3x |
module_type = "Landings", |
| 510 | 3x |
distribution_link = "Landings", |
| 511 | 3x |
fleet_name = current_fleet_name, |
| 512 | 3x |
time = fleet_landings[["time"]] |
| 513 |
) |
|
| 514 |
} else {
|
|
| 515 | 3x |
fleet_index <- get_data(data) |> |
| 516 | 3x |
dplyr::filter(type == "index" & name == current_fleet_name) |
| 517 | ||
| 518 | 3x |
log_Fmort_default <- create_default_parameters_template( |
| 519 | 3x |
n_parameters = get_n_years(data) |
| 520 |
) |> |
|
| 521 | 3x |
dplyr::mutate( |
| 522 | 3x |
module_name = "Fleet", |
| 523 | 3x |
label = "log_Fmort", |
| 524 | 3x |
fleet_name = current_fleet_name, |
| 525 | 3x |
time = get_start_year(data):get_end_year(data), |
| 526 | 3x |
value = -200, |
| 527 | 3x |
estimation_type = "constant" |
| 528 |
) |
|
| 529 | ||
| 530 | 3x |
landings_distribution_default <- NULL |
| 531 |
} |
|
| 532 | ||
| 533 |
# Compile all default parameters into a single list |
|
| 534 | 6x |
default <- dplyr::bind_rows( |
| 535 | 6x |
selectivity_default, |
| 536 | 6x |
q_default, |
| 537 | 6x |
log_Fmort_default, |
| 538 | 6x |
index_distribution_default, |
| 539 | 6x |
landings_distribution_default |
| 540 |
) |
|
| 541 |
} |
|
| 542 | ||
| 543 |
#' Create default maturity parameters |
|
| 544 |
#' |
|
| 545 |
#' @description |
|
| 546 |
#' This function sets up default parameters for a maturity module. |
|
| 547 |
#' @param form A string specifying the form of maturity (e.g., |
|
| 548 |
#' `"Logistic"`). |
|
| 549 |
#' @return |
|
| 550 |
#' A tibble containing the default maturity parameters. |
|
| 551 |
#' @noRd |
|
| 552 |
create_default_maturity <- function( |
|
| 553 |
unnested_configurations, |
|
| 554 |
data |
|
| 555 |
) {
|
|
| 556 |
# Input checks |
|
| 557 | 3x |
available_forms <- c("Logistic")
|
| 558 | 3x |
form <- unnested_configurations |> |
| 559 | 3x |
dplyr::filter(module_name == "Maturity") |> |
| 560 | 3x |
dplyr::pull(module_type) |
| 561 | 3x |
if (!form %in% available_forms) {
|
| 562 | ! |
cli::cli_abort(c( |
| 563 | ! |
"Invalid `module_type`` for Maturity: {.var {form}}",
|
| 564 | ! |
"i" = "Valid options include: {.var {available_forms}}"
|
| 565 |
)) |
|
| 566 |
} |
|
| 567 | ||
| 568 |
# NOTE: All new forms of maturity must be placed in the vector of default |
|
| 569 |
# arguments for `form` and their methods but be placed below in the call to |
|
| 570 |
# `switch` |
|
| 571 | 3x |
default <- switch(form, |
| 572 | 3x |
"Logistic" = create_default_Logistic() |
| 573 |
) |> |
|
| 574 |
# We don't have an option to input maturity data into FIMS, so the maturity |
|
| 575 |
# parameters aren't really estimable. The parameters should be constant for now. |
|
| 576 |
# See more details from https://github.com/orgs/NOAA-FIMS/discussions/944. |
|
| 577 | 3x |
dplyr::mutate( |
| 578 | 3x |
estimation_type = "constant", |
| 579 | 3x |
module_name = "Maturity" |
| 580 |
) |
|
| 581 |
} |
|
| 582 | ||
| 583 |
#' Create default Beverton--Holt recruitment parameters |
|
| 584 |
#' |
|
| 585 |
#' @description |
|
| 586 |
#' This function sets up default parameters for a Beverton--Holt recruitment |
|
| 587 |
#' relationship. Parameters include the natural log of unfished recruitment, |
|
| 588 |
#' the logit transformation of the slope of the stock--recruitment curve to |
|
| 589 |
#' keep it between zero and one, and the time series of stock--recruitment |
|
| 590 |
#' deviations on the natural log scale. |
|
| 591 |
#' @param data An S4 object. FIMS input data. |
|
| 592 |
#' @return |
|
| 593 |
#' A tibble containing default recruitment parameters. |
|
| 594 |
#' @noRd |
|
| 595 |
create_default_BevertonHoltRecruitment <- function(data) {
|
|
| 596 |
# Create default parameters for Beverton--Holt recruitment |
|
| 597 | 3x |
log_rzero <- create_default_parameters_template( |
| 598 | 3x |
n_parameters = 1 |
| 599 |
) |> |
|
| 600 | 3x |
dplyr::mutate( |
| 601 | 3x |
label = "log_rzero", |
| 602 | 3x |
value = log(1e+06), |
| 603 | 3x |
estimation_type = "fixed_effects" |
| 604 |
) |
|
| 605 | 3x |
logit_steep <- create_default_parameters_template( |
| 606 | 3x |
n_parameters = 1 |
| 607 |
) |> |
|
| 608 | 3x |
dplyr::mutate( |
| 609 | 3x |
label = "logit_steep", |
| 610 | 3x |
value = -log(1.0 - 0.75) + log(0.75 - 0.2), |
| 611 | 3x |
estimation_type = "constant" |
| 612 |
) |
|
| 613 | ||
| 614 |
# TODO: Revisit the settings for log_r. Do we must set up log_r when |
|
| 615 |
# it is not random effect parameters? |
|
| 616 | 3x |
log_r <- create_default_parameters_template( |
| 617 | 3x |
n_parameters = get_n_years(data) - 1 |
| 618 |
) |> |
|
| 619 | 3x |
dplyr::mutate( |
| 620 |
# TODO: should this be LogRecDev to match output? |
|
| 621 | 3x |
label = "log_r", |
| 622 | 3x |
value = 0.0, |
| 623 | 3x |
time = (get_start_year(data) + 1):get_end_year(data), |
| 624 | 3x |
estimation_type = "constant" |
| 625 |
) |
|
| 626 | ||
| 627 | 3x |
log_devs <- create_default_parameters_template( |
| 628 | 3x |
n_parameters = get_n_years(data) - 1 |
| 629 |
) |> |
|
| 630 | 3x |
dplyr::mutate( |
| 631 |
# TODO: should this be LogRecDev to match output? |
|
| 632 | 3x |
label = "log_devs", |
| 633 | 3x |
value = 0.0, |
| 634 | 3x |
time = (get_start_year(data) + 1):get_end_year(data), |
| 635 | 3x |
estimation_type = "fixed_effects" |
| 636 |
) |
|
| 637 | ||
| 638 | 3x |
expected_recruitment <- create_default_parameters_template( |
| 639 | 3x |
n_parameters = get_n_years(data) + 1 |
| 640 |
) |> |
|
| 641 | 3x |
dplyr::mutate( |
| 642 | 3x |
label = "log_expected_recruitment", |
| 643 | 3x |
value = 0.0, |
| 644 | 3x |
estimation_type = "constant" |
| 645 |
) |
|
| 646 | ||
| 647 | 3x |
default <- dplyr::bind_rows( |
| 648 | 3x |
log_rzero, |
| 649 | 3x |
logit_steep, |
| 650 | 3x |
log_r, |
| 651 | 3x |
log_devs, |
| 652 | 3x |
expected_recruitment |
| 653 |
) |> |
|
| 654 | 3x |
dplyr::mutate( |
| 655 | 3x |
module_name = "Recruitment", |
| 656 | 3x |
module_type = "BevertonHolt" |
| 657 |
) |
|
| 658 |
} |
|
| 659 | ||
| 660 |
#' Create default DnormDistribution parameters |
|
| 661 |
#' |
|
| 662 |
#' @description |
|
| 663 |
#' This function sets up default parameters to calculate the density of a |
|
| 664 |
#' normal distribution, i.e., `DnormDistribution`, module. |
|
| 665 |
#' @param value A real number that is passed to `log_sd`. The default value is |
|
| 666 |
#' `0.1`. |
|
| 667 |
#' @param data An S4 object. FIMS input data. |
|
| 668 |
#' @param input_type A string specifying the input type. The available options |
|
| 669 |
#' are |
|
| 670 |
#' `r toString(formals(create_default_DnormDistribution)[["input_type"]])`. |
|
| 671 |
#' The default is |
|
| 672 |
#' `r toString(formals(create_default_DnormDistribution)[["input_type"]][1])`. |
|
| 673 |
#' @return |
|
| 674 |
#' A tibble of default parameters for Dnorm distribution. |
|
| 675 |
#' @noRd |
|
| 676 |
create_default_DnormDistribution <- function( |
|
| 677 |
value = 0.1, |
|
| 678 |
data, |
|
| 679 |
input_type = c("data", "process", "prior")
|
|
| 680 |
) {
|
|
| 681 |
# Input checks |
|
| 682 | 3x |
input_type <- rlang::arg_match(input_type) |
| 683 | ||
| 684 |
# Create default parameters |
|
| 685 | 3x |
default <- create_default_parameters_template( |
| 686 | 3x |
n_parameters = length(value) |
| 687 |
) |> |
|
| 688 |
# Add the module type and label |
|
| 689 | 3x |
dplyr::mutate( |
| 690 | 3x |
label = "log_sd", |
| 691 | 3x |
value = !!value, |
| 692 | 3x |
estimation_type = "constant", |
| 693 | 3x |
distribution_type = input_type, |
| 694 | 3x |
distribution = "Dnorm" |
| 695 |
) |
|
| 696 | ||
| 697 |
# If input_type is 'process', add additional parameters |
|
| 698 | 3x |
if (input_type == "process" | input_type == "prior") {
|
| 699 | 3x |
new_params <- create_default_parameters_template( |
| 700 | 3x |
n_parameters = length(value) |
| 701 |
) |> |
|
| 702 | 3x |
dplyr::mutate(label = "x", value = 0) |> |
| 703 | 3x |
dplyr::add_row( |
| 704 | 3x |
label = "expected_values", |
| 705 | 3x |
value = rep(0, length(value)) |
| 706 |
) |> |
|
| 707 | 3x |
dplyr::mutate( |
| 708 | 3x |
estimation_type = "constant", |
| 709 | 3x |
distribution_type = input_type, |
| 710 | 3x |
distribution = "Dnorm" |
| 711 |
) |
|
| 712 | ||
| 713 | 3x |
default <- dplyr::bind_rows( |
| 714 | 3x |
default, |
| 715 | 3x |
new_params |
| 716 |
) |
|
| 717 |
} |
|
| 718 |
} |
|
| 719 | ||
| 720 |
#' Create default DlnormDistribution parameters |
|
| 721 |
#' |
|
| 722 |
#' @description |
|
| 723 |
#' This function sets up default parameters to calculate the density of a |
|
| 724 |
#' log-normal distribution, i.e., `DlnormDistribution`, module. |
|
| 725 |
#' @param value Default value for `log_sd`. |
|
| 726 |
#' @param data An S4 object. FIMS input data. |
|
| 727 |
#' @param input_type A string specifying the input type. The available options |
|
| 728 |
#' are |
|
| 729 |
#' `r toString(formals(create_default_DlnormDistribution)[["input_type"]])`. |
|
| 730 |
#' The default is |
|
| 731 |
#' `r toString(formals(create_default_DlnormDistribution)[["input_type"]][1])`. |
|
| 732 |
#' @return |
|
| 733 |
#' A tibble of default parameters for Dlnorm distribution. |
|
| 734 |
#' @noRd |
|
| 735 |
create_default_DlnormDistribution <- function( |
|
| 736 |
value = 0.1, |
|
| 737 |
data, |
|
| 738 |
input_type = c("data", "process")
|
|
| 739 |
) {
|
|
| 740 |
# Input checks |
|
| 741 |
# TODO: Determine if value can be a vector? |
|
| 742 | 6x |
if (!is.numeric(value) || any(value <= 0, na.rm = TRUE)) {
|
| 743 | ! |
cli::cli_abort(c( |
| 744 | ! |
"i" = "Inputs to {.var value} must be positive and numeric.",
|
| 745 | ! |
"x" = "{.var value} is {.var {value}}."
|
| 746 |
)) |
|
| 747 |
} |
|
| 748 | 6x |
input_type <- rlang::arg_match(input_type) |
| 749 | ||
| 750 | 6x |
log_value <- log(value) |
| 751 |
# Create the default list with log standard deviation |
|
| 752 | 6x |
default <- create_default_parameters_template( |
| 753 | 6x |
n_parameters = get_n_years(data) |
| 754 |
) |> |
|
| 755 |
# Add the module label and value |
|
| 756 | 6x |
dplyr::mutate( |
| 757 | 6x |
label = "log_sd", |
| 758 | 6x |
value = log_value |
| 759 |
) |
|
| 760 | ||
| 761 |
# Add additional parameters if input_type is "process" |
|
| 762 | 6x |
if (input_type == "process") {
|
| 763 | ! |
default <- default |> |
| 764 | ! |
dplyr::add_row( |
| 765 | ! |
label = "x", |
| 766 | ! |
value = rep(0, get_n_years(data)) |
| 767 |
) |
|
| 768 |
} |
|
| 769 | ||
| 770 | 6x |
default <- default |> |
| 771 | 6x |
dplyr::mutate( |
| 772 | 6x |
estimation_type = "constant", |
| 773 | 6x |
distribution_type = input_type, |
| 774 | 6x |
distribution = "Dlnorm" |
| 775 |
) |
|
| 776 | 6x |
return(default) |
| 777 |
} |
|
| 778 | ||
| 779 |
#' Create default recruitment parameters |
|
| 780 |
#' |
|
| 781 |
#' @description |
|
| 782 |
#' This function sets up default parameters for a recruitment module. |
|
| 783 |
#' |
|
| 784 |
#' @param unnested_configurations A tibble of model configurations. Typically |
|
| 785 |
#' created by the `create_default_configurations()`. |
|
| 786 |
#' @param data An S4 object. FIMS input data. |
|
| 787 |
#' @return |
|
| 788 |
#' A tibble with the default parameters for recruitment. |
|
| 789 |
#' @noRd |
|
| 790 |
create_default_recruitment <- function( |
|
| 791 |
unnested_configurations, |
|
| 792 |
data |
|
| 793 |
) {
|
|
| 794 |
# Input checks |
|
| 795 | 3x |
available_forms <- c("BevertonHolt")
|
| 796 | 3x |
form <- unnested_configurations |> |
| 797 | 3x |
dplyr::filter(module_name == "Recruitment") |> |
| 798 | 3x |
dplyr::pull(module_type) |
| 799 | 3x |
if (!form %in% available_forms) {
|
| 800 | ! |
cli::cli_abort(c( |
| 801 | ! |
"Invalid `module_type` for Recruitment: {.var {form}}",
|
| 802 | ! |
"i" = "Valid options include: {.var {available_forms}}"
|
| 803 |
)) |
|
| 804 |
} |
|
| 805 |
# Create default parameters based on the recruitment form |
|
| 806 |
# NOTE: All new forms of recruitment must be placed in the vector of default |
|
| 807 |
# arguments for `form` and their methods but be placed below in the call to |
|
| 808 |
# `switch` |
|
| 809 | 3x |
form_default <- switch(form, |
| 810 | 3x |
"BevertonHolt" = create_default_BevertonHoltRecruitment(data) |
| 811 |
) |
|
| 812 | ||
| 813 | 3x |
distribution_input <- unnested_configurations |> |
| 814 | 3x |
dplyr::filter(module_name == "Recruitment") |
| 815 | ||
| 816 | 3x |
if (!is.null(distribution_input[["distribution"]])) {
|
| 817 | 3x |
distribution_default <- switch(distribution_input[["distribution"]], |
| 818 | 3x |
"Dnorm" = create_default_DnormDistribution( |
| 819 | 3x |
data = data, |
| 820 | 3x |
input_type = "process" |
| 821 |
) |
|
| 822 |
) |
|
| 823 | ||
| 824 | 3x |
distribution_link <- distribution_input[["distribution_link"]] |
| 825 | 3x |
if (distribution_link == "log_devs") {
|
| 826 | 3x |
distribution_default <- distribution_default |> |
| 827 | 3x |
dplyr::mutate( |
| 828 | 3x |
distribution_link = !!distribution_link |
| 829 |
) |
|
| 830 | ||
| 831 | 3x |
expanded_rows <- distribution_default |> |
| 832 | 3x |
dplyr::filter(label %in% c("x", "expected_values")) |>
|
| 833 |
# Create all combinations of the original rows and years |
|
| 834 | 3x |
tidyr::expand_grid(year = (get_start_year(data) + 1):get_end_year(data)) |> |
| 835 | 3x |
dplyr::mutate( |
| 836 | 3x |
time = year |
| 837 |
) |> |
|
| 838 | 3x |
dplyr::select(-year) |
| 839 | ||
| 840 | 3x |
distribution_default <- distribution_default |> |
| 841 | 3x |
dplyr::filter(label == "log_sd") |> |
| 842 | 3x |
dplyr::bind_rows(expanded_rows) |
| 843 |
} |
|
| 844 |
} |
|
| 845 | ||
| 846 | 3x |
default <- dplyr::bind_rows(form_default, distribution_default) |> |
| 847 | 3x |
tidyr::fill(module_name, module_type) |
| 848 |
} |
| 1 |
# Developers: ---- |
|
| 2 | ||
| 3 |
# This file defines the parent class FIMSFrame and its potential children. The |
|
| 4 |
# class is an S4 class with accessors and validators but no setters. |
|
| 5 |
# |
|
| 6 |
# The top of this file contains the declaration of the FIMSFrame class, which |
|
| 7 |
# is the controller of everything. Then the function FIMSFrame() is how objects |
|
| 8 |
# of that class are created, i.e., the constructor, and how users will interact |
|
| 9 |
# with the class the most. When the returned object from that constructor are |
|
| 10 |
# changed, the call to methods::setClass() that defines the class must also be |
|
| 11 |
# changed. The remainder of the file is set up to help you easily augment this |
|
| 12 |
# class. Follow the step-by-step instructions in order or at least know that |
|
| 13 |
# the functions are present in this order: |
|
| 14 |
# |
|
| 15 |
# 1. Add or remove the slot of interest in the call to `methods::setClass()`, |
|
| 16 |
# e.g., if you are adding a new slot you must declare the slot and the type |
|
| 17 |
# of object that should be expected in that slot; to remove an object from |
|
| 18 |
# the FIMSFrame class you must remove the slot here. |
|
| 19 |
# 2. Add an accessor function, e.g., get_*(), to allow users to access the |
|
| 20 |
# object stored in the new slot; or, remove the accessor function if you |
|
| 21 |
# remove a slot. Some internal accessors are also available, e.g., m_*(), |
|
| 22 |
# and should be used to provide data to a model but should not be used by |
|
| 23 |
# average users. |
|
| 24 |
# 3. If we had setter functions for FIMSFrame, you would add or delete the |
|
| 25 |
# appropriate setter functions next but we do not. Instead, we want users to |
|
| 26 |
# re-run FIMSFrame() when they make any changes to their data, that way all |
|
| 27 |
# of the slots will be updated simultaneously. @nathanvaughan-NOAA mentioned |
|
| 28 |
# during Code club 2024-12-17 that this may be a problem for future use of |
|
| 29 |
# FIMSFrame objects, especially when doing MSE or simulation when there is a |
|
| 30 |
# large overhead in running FIMSFrame and you just want to change a small, |
|
| 31 |
# simple thing in your data and re-run the model. We will cross that bridge |
|
| 32 |
# later. @msupernaw also informed us about the ability to lock an R object |
|
| 33 |
# so it cannot be altered. See https://rdrr.io/r/base/bindenv.html. |
|
| 34 |
# 4. Augment the validator functions to ensure that users do not pass |
|
| 35 |
# incompatible information to FIMSFrame(). |
|
| 36 |
# 5. Augment FIMSFrame() to ensure that the slot is created if you are adding a |
|
| 37 |
# new object or remove the object from the returned object if you are |
|
| 38 |
# removing a slot. |
|
| 39 | ||
| 40 |
# TODO: ---- |
|
| 41 | ||
| 42 |
# TODO: make date_formats a local variable |
|
| 43 |
# TODO: document sorting of information in terms of alphabetized fleet order |
|
| 44 |
# TODO: test implement addition of -999 |
|
| 45 |
# TODO: validate that all length-age combinations exist in the conversion matrix |
|
| 46 | ||
| 47 |
# methods::setClass: ---- |
|
| 48 | ||
| 49 |
# Classes are not currently exported, and therefore, do not need documentation. |
|
| 50 |
# See the following link if we do want to document them in the future: |
|
| 51 |
# https://stackoverflow.com/questions/7368262/how-to-properly-document-s4-class-slots-using-roxygen2 |
|
| 52 | ||
| 53 |
methods::setClass( |
|
| 54 |
Class = "FIMSFrame", |
|
| 55 |
slots = c( |
|
| 56 |
data = "tbl_df", |
|
| 57 |
fleets = "character", |
|
| 58 |
n_years = "integer", |
|
| 59 |
ages = "numeric", |
|
| 60 |
n_ages = "integer", |
|
| 61 |
lengths = "numeric", |
|
| 62 |
n_lengths = "integer", |
|
| 63 |
start_year = "integer", |
|
| 64 |
end_year = "integer" |
|
| 65 |
) |
|
| 66 |
) |
|
| 67 | ||
| 68 |
# methods::setMethod: accessors ---- |
|
| 69 | ||
| 70 |
# Methods for accessing info in the slots using get_*() or m_*() |
|
| 71 | ||
| 72 |
#' Get a slot in a FIMSFrame object |
|
| 73 |
#' |
|
| 74 |
#' There is an accessor function for each slot in the S4 class `FIMSFrame`, |
|
| 75 |
#' where the function is named `get_*()` and the star can be replaced with the |
|
| 76 |
#' slot name, e.g., [get_data()]. These accessor functions are the preferred |
|
| 77 |
#' way to access objects stored in the available slots. |
|
| 78 |
#' |
|
| 79 |
#' @param x An object returned from [FIMSFrame()]. |
|
| 80 |
#' @name get_FIMSFrame |
|
| 81 |
#' @keywords FIMSFrame |
|
| 82 |
NULL |
|
| 83 | ||
| 84 |
#' @return |
|
| 85 |
#' [get_data()] returns a data frame of the class `tbl_df` containing data for |
|
| 86 |
#' a FIMS model in a long format. The tibble will potentially have the |
|
| 87 |
#' following columns depending if it fits to ages and lengths or just one of |
|
| 88 |
#' them: |
|
| 89 |
#' `r glue::glue_collapse(colnames(data1), sep = ", ", last = ", and ")`. |
|
| 90 |
#' @export |
|
| 91 |
#' @rdname get_FIMSFrame |
|
| 92 |
#' @keywords FIMSFrame |
|
| 93 | 220x |
methods::setGeneric("get_data", function(x) standardGeneric("get_data"))
|
| 94 |
#' @rdname get_FIMSFrame |
|
| 95 |
#' @keywords FIMSFrame |
|
| 96 | 220x |
methods::setMethod("get_data", "FIMSFrame", function(x) x@data)
|
| 97 |
#' @rdname get_FIMSFrame |
|
| 98 |
#' @keywords FIMSFrame |
|
| 99 |
methods::setMethod( |
|
| 100 |
"get_data", |
|
| 101 |
"data.frame", |
|
| 102 | ! |
function(x) FIMSFrame(x)@data |
| 103 |
) |
|
| 104 | ||
| 105 |
#' @return |
|
| 106 |
#' [get_fleets()] returns a vector of strings containing the fleet names. |
|
| 107 |
#' @export |
|
| 108 |
#' @rdname get_FIMSFrame |
|
| 109 |
#' @keywords FIMSFrame |
|
| 110 | 2x |
methods::setGeneric("get_fleets", function(x) standardGeneric("get_fleets"))
|
| 111 |
#' @rdname get_FIMSFrame |
|
| 112 |
#' @keywords FIMSFrame |
|
| 113 | 2x |
methods::setMethod("get_fleets", "FIMSFrame", function(x) x@fleets)
|
| 114 |
#' @rdname get_FIMSFrame |
|
| 115 |
#' @keywords FIMSFrame |
|
| 116 |
methods::setMethod( |
|
| 117 |
"get_fleets", |
|
| 118 |
"data.frame", |
|
| 119 | ! |
function(x) FIMSFrame(x)@fleets |
| 120 |
) |
|
| 121 | ||
| 122 |
#' @return |
|
| 123 |
#' [get_n_fleets()] returns an integer specifying the number of fleets in the |
|
| 124 |
#' model, where fleets is inclusive of both fishing fleets and survey vessels. |
|
| 125 |
#' @export |
|
| 126 |
#' @rdname get_FIMSFrame |
|
| 127 |
#' @keywords FIMSFrame |
|
| 128 | 5x |
methods::setGeneric("get_n_fleets", function(x) standardGeneric("get_n_fleets"))
|
| 129 |
#' @rdname get_FIMSFrame |
|
| 130 |
#' @keywords FIMSFrame |
|
| 131 | 5x |
methods::setMethod("get_n_fleets", "FIMSFrame", function(x) length(x@fleets))
|
| 132 |
#' @rdname get_FIMSFrame |
|
| 133 |
#' @keywords FIMSFrame |
|
| 134 |
methods::setMethod( |
|
| 135 |
"get_n_fleets", |
|
| 136 |
"data.frame", |
|
| 137 | ! |
function(x) length(FIMSFrame(x)@fleets) |
| 138 |
) |
|
| 139 | ||
| 140 |
#' @return |
|
| 141 |
#' [get_n_years()] returns an integer specifying the number of years in the |
|
| 142 |
#' model. |
|
| 143 |
#' @export |
|
| 144 |
#' @rdname get_FIMSFrame |
|
| 145 |
#' @keywords FIMSFrame |
|
| 146 | 166x |
methods::setGeneric("get_n_years", function(x) standardGeneric("get_n_years"))
|
| 147 |
#' @rdname get_FIMSFrame |
|
| 148 |
#' @keywords FIMSFrame |
|
| 149 | 166x |
methods::setMethod("get_n_years", "FIMSFrame", function(x) x@n_years)
|
| 150 |
#' @rdname get_FIMSFrame |
|
| 151 |
#' @keywords FIMSFrame |
|
| 152 |
methods::setMethod( |
|
| 153 |
"get_n_years", |
|
| 154 |
"data.frame", |
|
| 155 | ! |
function(x) FIMSFrame(x)@n_years |
| 156 |
) |
|
| 157 | ||
| 158 |
#' @return |
|
| 159 |
#' [get_start_year()] returns an integer specifying the start year of the |
|
| 160 |
#' model. |
|
| 161 |
#' @export |
|
| 162 |
#' @rdname get_FIMSFrame |
|
| 163 |
#' @keywords FIMSFrame |
|
| 164 |
methods::setGeneric( |
|
| 165 |
"get_start_year", |
|
| 166 | 17x |
function(x) standardGeneric("get_start_year")
|
| 167 |
) |
|
| 168 |
#' @rdname get_FIMSFrame |
|
| 169 |
#' @keywords FIMSFrame |
|
| 170 | 17x |
methods::setMethod("get_start_year", "FIMSFrame", function(x) x@start_year)
|
| 171 |
#' @rdname get_FIMSFrame |
|
| 172 |
#' @keywords FIMSFrame |
|
| 173 |
methods::setMethod( |
|
| 174 |
"get_start_year", |
|
| 175 |
"data.frame", |
|
| 176 | ! |
function(x) FIMSFrame(x)@start_year |
| 177 |
) |
|
| 178 | ||
| 179 |
#' @return |
|
| 180 |
#' [get_end_year()] returns an integer specifying the end year of the |
|
| 181 |
#' model. |
|
| 182 |
#' @export |
|
| 183 |
#' @rdname get_FIMSFrame |
|
| 184 |
#' @keywords FIMSFrame |
|
| 185 | 17x |
methods::setGeneric("get_end_year", function(x) standardGeneric("get_end_year"))
|
| 186 |
#' @rdname get_FIMSFrame |
|
| 187 |
#' @keywords FIMSFrame |
|
| 188 | 17x |
methods::setMethod("get_end_year", "FIMSFrame", function(x) x@end_year)
|
| 189 |
#' @rdname get_FIMSFrame |
|
| 190 |
#' @keywords FIMSFrame |
|
| 191 |
methods::setMethod( |
|
| 192 |
"get_end_year", |
|
| 193 |
"data.frame", |
|
| 194 | ! |
function(x) FIMSFrame(x)@end_year |
| 195 |
) |
|
| 196 | ||
| 197 |
#' @return |
|
| 198 |
#' [get_ages()] returns a vector of age bins used in the model. |
|
| 199 |
#' @export |
|
| 200 |
#' @rdname get_FIMSFrame |
|
| 201 |
#' @keywords FIMSFrame |
|
| 202 | 273x |
methods::setGeneric("get_ages", function(x) standardGeneric("get_ages"))
|
| 203 |
#' @rdname get_FIMSFrame |
|
| 204 |
#' @keywords FIMSFrame |
|
| 205 | 273x |
methods::setMethod("get_ages", "FIMSFrame", function(x) x@ages)
|
| 206 |
#' @rdname get_FIMSFrame |
|
| 207 |
#' @keywords FIMSFrame |
|
| 208 |
methods::setMethod( |
|
| 209 |
"get_ages", |
|
| 210 |
"data.frame", |
|
| 211 | ! |
function(x) FIMSFrame(x)@ages |
| 212 |
) |
|
| 213 | ||
| 214 |
#' @return |
|
| 215 |
#' [get_n_ages()] returns an integer specifying the number of age bins used in |
|
| 216 |
#' the model. |
|
| 217 |
#' @export |
|
| 218 |
#' @rdname get_FIMSFrame |
|
| 219 |
#' @keywords FIMSFrame |
|
| 220 | 144x |
methods::setGeneric("get_n_ages", function(x) standardGeneric("get_n_ages"))
|
| 221 |
#' @rdname get_FIMSFrame |
|
| 222 |
#' @keywords FIMSFrame |
|
| 223 | 144x |
methods::setMethod("get_n_ages", "FIMSFrame", function(x) x@n_ages)
|
| 224 |
#' @rdname get_FIMSFrame |
|
| 225 |
#' @keywords FIMSFrame |
|
| 226 |
methods::setMethod( |
|
| 227 |
"get_n_ages", |
|
| 228 |
"data.frame", |
|
| 229 | ! |
function(x) FIMSFrame(x)@n_ages |
| 230 |
) |
|
| 231 | ||
| 232 |
#' @return |
|
| 233 |
#' [get_lengths()] returns a vector of length bins used in the model. |
|
| 234 |
#' @export |
|
| 235 |
#' @rdname get_FIMSFrame |
|
| 236 |
#' @keywords FIMSFrame |
|
| 237 | ! |
methods::setGeneric("get_lengths", function(x) standardGeneric("get_lengths"))
|
| 238 |
#' @rdname get_FIMSFrame |
|
| 239 |
#' @keywords FIMSFrame |
|
| 240 | ! |
methods::setMethod("get_lengths", "FIMSFrame", function(x) x@lengths)
|
| 241 |
#' @rdname get_FIMSFrame |
|
| 242 |
#' @keywords FIMSFrame |
|
| 243 |
methods::setMethod( |
|
| 244 |
"get_lengths", |
|
| 245 |
"data.frame", |
|
| 246 | ! |
function(x) FIMSFrame(x)@lengths |
| 247 |
) |
|
| 248 | ||
| 249 |
#' @return |
|
| 250 |
#' [get_n_lengths()] returns an integer specifying the number of length bins |
|
| 251 |
#' used in the model. |
|
| 252 |
#' @export |
|
| 253 |
#' @rdname get_FIMSFrame |
|
| 254 |
#' @keywords FIMSFrame |
|
| 255 |
methods::setGeneric( |
|
| 256 |
"get_n_lengths", |
|
| 257 | 61x |
function(x) standardGeneric("get_n_lengths")
|
| 258 |
) |
|
| 259 |
#' @rdname get_FIMSFrame |
|
| 260 |
#' @keywords FIMSFrame |
|
| 261 | 61x |
methods::setMethod("get_n_lengths", "FIMSFrame", function(x) x@n_lengths)
|
| 262 |
#' @rdname get_FIMSFrame |
|
| 263 |
#' @keywords FIMSFrame |
|
| 264 |
methods::setMethod( |
|
| 265 |
"get_n_lengths", |
|
| 266 |
"data.frame", |
|
| 267 | ! |
function(x) FIMSFrame(x)@n_lengths |
| 268 |
) |
|
| 269 | ||
| 270 |
#' Get a vector of data to be passed to a FIMS module from a FIMSFrame object |
|
| 271 |
#' |
|
| 272 |
#' There is an accessor function for each data type needed to run a FIMS model. |
|
| 273 |
#' A FIMS model accepts vectors of data and thus each of the `m_*()` functions, |
|
| 274 |
#' where the star can be replaced with the data type separated by underscores, |
|
| 275 |
#' e.g., weight_at_age. These accessor functions are the preferred way to pass |
|
| 276 |
#' data to a FIMS module because the data will have the appropriate indexing. |
|
| 277 |
#' |
|
| 278 |
#' @details |
|
| 279 |
#' Age-to-length-conversion data, i.e., the proportion of age "a" that are |
|
| 280 |
#' length "l", are used to convert lengths (input data) to ages (modeled) as |
|
| 281 |
#' a way to fit length data without estimating growth. |
|
| 282 |
#' |
|
| 283 |
#' @inheritParams get_data |
|
| 284 |
#' @param fleet_name A string, or vector of strings, specifying the name of the |
|
| 285 |
#' fleet(s) of interest that you want landings data for. The strings must |
|
| 286 |
#' exactly match strings in the column `"name"` of `get_data(x)`. |
|
| 287 |
#' @return |
|
| 288 |
#' All of the `m_*()` functions return vectors of data. Currently, the order of |
|
| 289 |
#' the data is the same order as the data frame because no arranging is done in |
|
| 290 |
#' [FIMSFrame()] and the function just extracts the appropriate column. |
|
| 291 |
#' @name m_ |
|
| 292 |
#' @keywords FIMSFrame |
|
| 293 |
NULL |
|
| 294 | ||
| 295 |
#' @export |
|
| 296 |
#' @rdname m_ |
|
| 297 |
#' @keywords FIMSFrame |
|
| 298 |
methods::setGeneric( |
|
| 299 |
"m_landings", |
|
| 300 | 343x |
function(x, fleet_name) standardGeneric("m_landings")
|
| 301 |
) |
|
| 302 |
#' @rdname m_ |
|
| 303 |
#' @keywords FIMSFrame |
|
| 304 |
methods::setMethod( |
|
| 305 |
"m_landings", "FIMSFrame", |
|
| 306 |
function(x, fleet_name) {
|
|
| 307 | 343x |
dplyr::filter( |
| 308 | 343x |
.data = x@data, |
| 309 | 343x |
.data[["type"]] == "landings", |
| 310 | 343x |
.data[["name"]] %in% fleet_name |
| 311 |
) |> |
|
| 312 | 343x |
dplyr::pull(.data[["value"]]) |
| 313 |
} |
|
| 314 |
) |
|
| 315 |
#' @rdname m_ |
|
| 316 |
#' @keywords FIMSFrame |
|
| 317 |
methods::setMethod( |
|
| 318 |
"m_landings", |
|
| 319 |
"data.frame", |
|
| 320 | ! |
function(x, fleet_name) m_landings(FIMSFrame(x), fleet_name) |
| 321 |
) |
|
| 322 | ||
| 323 |
#' @export |
|
| 324 |
#' @rdname m_ |
|
| 325 |
#' @keywords FIMSFrame |
|
| 326 |
methods::setGeneric( |
|
| 327 |
"m_index", |
|
| 328 | 345x |
function(x, fleet_name) standardGeneric("m_index")
|
| 329 |
) |
|
| 330 |
#' @rdname m_ |
|
| 331 |
#' @keywords FIMSFrame |
|
| 332 |
methods::setMethod( |
|
| 333 |
"m_index", "FIMSFrame", |
|
| 334 |
function(x, fleet_name) {
|
|
| 335 | 345x |
dplyr::filter( |
| 336 | 345x |
.data = x@data, |
| 337 | 345x |
.data[["type"]] == "index", |
| 338 | 345x |
.data[["name"]] %in% fleet_name |
| 339 |
) |> |
|
| 340 | 345x |
dplyr::pull(.data[["value"]]) |
| 341 |
} |
|
| 342 |
) |
|
| 343 |
#' @rdname m_ |
|
| 344 |
#' @keywords FIMSFrame |
|
| 345 |
methods::setMethod( |
|
| 346 |
"m_index", |
|
| 347 |
"data.frame", |
|
| 348 | ! |
function(x, fleet_name) m_index(FIMSFrame(x), fleet_name) |
| 349 |
) |
|
| 350 | ||
| 351 |
#' @export |
|
| 352 |
#' @rdname m_ |
|
| 353 |
#' @keywords FIMSFrame |
|
| 354 |
methods::setGeneric( |
|
| 355 |
"m_agecomp", |
|
| 356 | 1461x |
function(x, fleet_name) standardGeneric("m_agecomp")
|
| 357 |
) |
|
| 358 |
#' @rdname m_ |
|
| 359 |
#' @keywords FIMSFrame |
|
| 360 |
methods::setMethod( |
|
| 361 |
"m_agecomp", "FIMSFrame", |
|
| 362 |
function(x, fleet_name) {
|
|
| 363 | 1461x |
dplyr::filter( |
| 364 | 1461x |
.data = x@data, |
| 365 | 1461x |
.data[["type"]] == "age_comp", |
| 366 | 1461x |
.data[["name"]] %in% fleet_name |
| 367 |
) |> |
|
| 368 | 1461x |
dplyr::pull(.data[["value"]]) |
| 369 |
} |
|
| 370 |
) |
|
| 371 |
#' @rdname m_ |
|
| 372 |
#' @keywords FIMSFrame |
|
| 373 |
methods::setMethod( |
|
| 374 |
"m_agecomp", |
|
| 375 |
"data.frame", |
|
| 376 | ! |
function(x, fleet_name) m_agecomp(FIMSFrame(x), fleet_name) |
| 377 |
) |
|
| 378 | ||
| 379 |
#' @export |
|
| 380 |
#' @rdname m_ |
|
| 381 |
#' @keywords FIMSFrame |
|
| 382 |
methods::setGeneric( |
|
| 383 |
"m_lengthcomp", |
|
| 384 | 19x |
function(x, fleet_name) standardGeneric("m_lengthcomp")
|
| 385 |
) |
|
| 386 |
#' @rdname m_ |
|
| 387 |
#' @keywords FIMSFrame |
|
| 388 |
methods::setMethod( |
|
| 389 |
"m_lengthcomp", |
|
| 390 |
"FIMSFrame", |
|
| 391 |
function(x, fleet_name) {
|
|
| 392 | 19x |
dplyr::filter( |
| 393 | 19x |
.data = x@data, |
| 394 | 19x |
.data[["type"]] == "length_comp", |
| 395 | 19x |
.data[["name"]] %in% fleet_name |
| 396 |
) |> |
|
| 397 | 19x |
dplyr::pull(.data[["value"]]) |
| 398 |
} |
|
| 399 |
) |
|
| 400 |
#' @rdname m_ |
|
| 401 |
#' @keywords FIMSFrame |
|
| 402 |
methods::setMethod( |
|
| 403 |
"m_lengthcomp", |
|
| 404 |
"data.frame", |
|
| 405 | ! |
function(x, fleet_name) m_lengthcomp(FIMSFrame(x), fleet_name) |
| 406 |
) |
|
| 407 | ||
| 408 |
#' @export |
|
| 409 |
#' @rdname m_ |
|
| 410 |
#' @keywords FIMSFrame |
|
| 411 |
methods::setGeneric( |
|
| 412 |
"m_weight_at_age", |
|
| 413 | 134x |
function(x) standardGeneric("m_weight_at_age")
|
| 414 |
) |
|
| 415 |
#' @rdname m_ |
|
| 416 |
#' @keywords FIMSFrame |
|
| 417 |
methods::setMethod( |
|
| 418 |
"m_weight_at_age", |
|
| 419 |
"FIMSFrame", |
|
| 420 |
function(x) {
|
|
| 421 | 134x |
dplyr::filter( |
| 422 | 134x |
.data = as.data.frame(x@data), |
| 423 | 134x |
.data[["type"]] == "weight-at-age" |
| 424 |
) |> |
|
| 425 | 134x |
dplyr::group_by(.data[["age"]]) |> |
| 426 | 134x |
dplyr::mutate( |
| 427 | 134x |
value = ifelse(value == -999, NA, value) |
| 428 |
) |> |
|
| 429 | 134x |
dplyr::summarize(mean_value = mean(.data[["value"]], na.rm = TRUE)) |> |
| 430 | 134x |
dplyr::pull(.data[["mean_value"]]) |
| 431 |
} |
|
| 432 |
) |
|
| 433 |
#' @rdname m_ |
|
| 434 |
#' @keywords FIMSFrame |
|
| 435 |
methods::setMethod( |
|
| 436 |
"m_weight_at_age", |
|
| 437 |
"data.frame", |
|
| 438 |
function(x) {
|
|
| 439 | ! |
m_weight_at_age(FIMSFrame(x)) |
| 440 |
} |
|
| 441 |
) |
|
| 442 | ||
| 443 |
#' @export |
|
| 444 |
#' @rdname m_ |
|
| 445 |
#' @keywords FIMSFrame |
|
| 446 |
methods::setGeneric( |
|
| 447 |
"m_age_to_length_conversion", |
|
| 448 | 18x |
function(x, fleet_name) standardGeneric("m_age_to_length_conversion")
|
| 449 |
) |
|
| 450 |
#' @rdname m_ |
|
| 451 |
#' @keywords FIMSFrame |
|
| 452 |
methods::setMethod( |
|
| 453 |
"m_age_to_length_conversion", |
|
| 454 |
"FIMSFrame", |
|
| 455 |
function(x, fleet_name) {
|
|
| 456 | 18x |
if ("length" %in% colnames(x@data)) {
|
| 457 | 18x |
dplyr::filter( |
| 458 | 18x |
.data = as.data.frame(x@data), |
| 459 | 18x |
.data[["type"]] == "age-to-length-conversion", |
| 460 | 18x |
.data[["name"]] %in% fleet_name |
| 461 |
) |> |
|
| 462 | 18x |
dplyr::group_by(.data[["age"]], .data[["length"]]) |> |
| 463 | 18x |
dplyr::summarize( |
| 464 | 18x |
mean_value = mean(as.numeric(.data[["value"]]), na.rm = TRUE) |
| 465 |
) |> |
|
| 466 | 18x |
dplyr::pull(as.numeric(.data[["mean_value"]])) |
| 467 |
} |
|
| 468 |
} |
|
| 469 |
) |
|
| 470 |
#' @rdname m_ |
|
| 471 |
#' @keywords FIMSFrame |
|
| 472 |
methods::setMethod( |
|
| 473 |
"m_age_to_length_conversion", |
|
| 474 |
"data.frame", |
|
| 475 | ! |
function(x, fleet_name) m_age_to_length_conversion(FIMSFrame(x), fleet_name) |
| 476 |
) |
|
| 477 | ||
| 478 |
# methods::setMethod: initialize ---- |
|
| 479 | ||
| 480 |
# Not currently using methods::setMethod(f = "initialize") |
|
| 481 |
# because @kellijohnson-NOAA did not quite understand how they actually work. |
|
| 482 | ||
| 483 |
# methods::setMethod: plot ---- |
|
| 484 | ||
| 485 |
methods::setMethod( |
|
| 486 |
f = "plot", |
|
| 487 |
signature = "FIMSFrame", |
|
| 488 |
definition = function(x, y, ...) {
|
|
| 489 | 1x |
ggplot2::ggplot( |
| 490 | 1x |
data = x@data, |
| 491 | 1x |
mapping = ggplot2::aes( |
| 492 | 1x |
x = .data[["timing"]], |
| 493 | 1x |
y = .data[["value"]], |
| 494 | 1x |
col = .data[["name"]] |
| 495 |
) |
|
| 496 |
) + |
|
| 497 |
# Using Set3 b/c it is the palette with the largest number of colors |
|
| 498 |
# and not {nmfspalette} b/c didn't want to depend on GitHub package
|
|
| 499 | 1x |
ggplot2::scale_color_brewer(palette = "Set3") + |
| 500 | 1x |
ggplot2::facet_wrap("type", scales = "free_y") +
|
| 501 | 1x |
ggplot2::geom_point() + |
| 502 | 1x |
ggplot2::scale_x_date(labels = scales::date_format("%Y-%m-%d")) +
|
| 503 | 1x |
ggplot2::xlab("Start date (Year-Month-Day)") +
|
| 504 | 1x |
ggplot2::ylab("Value") +
|
| 505 | 1x |
ggplot2::theme( |
| 506 | 1x |
axis.text.x = ggplot2::element_text(angle = 15) |
| 507 |
) |
|
| 508 |
} |
|
| 509 |
) |
|
| 510 | ||
| 511 |
# methods::setMethod: show ---- |
|
| 512 | ||
| 513 |
methods::setMethod( |
|
| 514 |
f = "show", |
|
| 515 |
signature = "FIMSFrame", |
|
| 516 |
definition = function(object) {
|
|
| 517 | 1x |
message("tbl_df of class '", class(object), "'")
|
| 518 | 1x |
if (length(object@data) == 0) {
|
| 519 | ! |
return() |
| 520 |
} |
|
| 521 | 1x |
dat_types <- unique(object@data[[which(colnames(object@data) == "type")]]) |
| 522 | 1x |
message("with the following 'types': ", paste0(dat_types, collapse = ", "))
|
| 523 | 1x |
snames <- slotNames(object) |
| 524 | 1x |
ordinnames <- !snames %in% c( |
| 525 | 1x |
"data", |
| 526 | 1x |
".S3Class", |
| 527 | 1x |
"row.names", |
| 528 | 1x |
"names" |
| 529 |
) |
|
| 530 | 1x |
print(utils::head(object@data)) |
| 531 | 1x |
cat("additional slots include the following:")
|
| 532 | 1x |
for (nm in snames[ordinnames]) {
|
| 533 | 8x |
cat(nm, ":\n", sep = "") |
| 534 | 8x |
print(slot(object, nm)) |
| 535 |
} |
|
| 536 |
} |
|
| 537 |
) |
|
| 538 | ||
| 539 |
is.FIMSFrame <- function(x) {
|
|
| 540 | ! |
inherits(x, "FIMSFrame") |
| 541 |
} |
|
| 542 | ||
| 543 |
# methods::setValidity ---- |
|
| 544 | ||
| 545 |
methods::setValidity( |
|
| 546 |
Class = "FIMSFrame", |
|
| 547 |
method = function(object) {
|
|
| 548 |
errors <- character() |
|
| 549 | ||
| 550 |
if (NROW(object@data) == 0) {
|
|
| 551 |
errors <- c(errors, "data must have at least one row") |
|
| 552 |
} |
|
| 553 | ||
| 554 |
# FIMS models currently cannot run without weight-at-age data |
|
| 555 |
weight_at_age_data <- dplyr::filter(object@data, type == "weight-at-age") |
|
| 556 |
if (NROW(weight_at_age_data) == 0) {
|
|
| 557 |
errors <- c(errors, "data must contain data of the type weight-at-age") |
|
| 558 |
} |
|
| 559 | ||
| 560 |
errors <- c(errors, validate_data_colnames(object@data)) |
|
| 561 | ||
| 562 |
# Check the format for acceptable variants of the ideal numeric |
|
| 563 |
if (!all(is.numeric(object@data[["timing"]]))) {
|
|
| 564 |
errors <- c(errors, "timing must be in numeric format") |
|
| 565 |
} |
|
| 566 |
if (!all(as.integer(object@data[["timing"]]) - |
|
| 567 |
object@data[["timing"]] == 0)) {
|
|
| 568 |
errors <- c(errors, "timing can only handle years right now") |
|
| 569 |
} |
|
| 570 | ||
| 571 |
# TODO: Add checks for other slots |
|
| 572 |
# Add validity check for types |
|
| 573 |
allowed_types <- c( |
|
| 574 |
"landings", "index", "age_comp", "length_comp", |
|
| 575 |
"weight-at-age", "age-to-length-conversion" |
|
| 576 |
) |
|
| 577 |
present_types <- unique(object@data[["type"]]) |
|
| 578 | ||
| 579 |
# Issues warning if there are any unrecognized types |
|
| 580 |
unknown_types <- setdiff(present_types, allowed_types) |
|
| 581 |
if (length(unknown_types) > 0) {
|
|
| 582 |
cli::cli_warn(c( |
|
| 583 |
"!" = "Data contains unexpected type(s): {paste(sort(unknown_types), collapse = ', ')}",
|
|
| 584 |
"i" = "Allowed types are: {paste(allowed_types, collapse = ', ')}",
|
|
| 585 |
"i" = paste( |
|
| 586 |
"Model will continue to run,", |
|
| 587 |
"but check that data types are correct." |
|
| 588 |
) |
|
| 589 |
)) |
|
| 590 |
} |
|
| 591 |
# Return |
|
| 592 |
if (length(errors) == 0) {
|
|
| 593 |
return(TRUE) |
|
| 594 |
} else {
|
|
| 595 |
return(errors) |
|
| 596 |
} |
|
| 597 |
} |
|
| 598 |
) |
|
| 599 | ||
| 600 |
validate_data_colnames <- function(data) {
|
|
| 601 | 37x |
the_column_names <- colnames(data) |
| 602 | 37x |
errors <- character() |
| 603 | 37x |
if (!"type" %in% the_column_names) {
|
| 604 | 1x |
errors <- c(errors, "data must contain 'type'") |
| 605 |
} |
|
| 606 | 37x |
if (!"name" %in% the_column_names) {
|
| 607 | 1x |
errors <- c(errors, "data must contain 'name'") |
| 608 |
} |
|
| 609 | 37x |
if (!"timing" %in% the_column_names) {
|
| 610 | 1x |
errors <- c(errors, "data must contain 'timing'") |
| 611 |
} |
|
| 612 | 37x |
if (!"value" %in% the_column_names) {
|
| 613 | 1x |
errors <- c(errors, "data must contain 'value'") |
| 614 |
} |
|
| 615 | 37x |
if (!"unit" %in% the_column_names) {
|
| 616 | 1x |
errors <- c(errors, "data must contain 'unit'") |
| 617 |
} |
|
| 618 | 37x |
if (!any(c("age", "length") %in% the_column_names)) {
|
| 619 | 1x |
errors <- c(errors, "data must contain 'ages' and/or 'lengths'") |
| 620 |
} |
|
| 621 | 37x |
return(errors) |
| 622 |
} |
|
| 623 | ||
| 624 |
# Constructors ---- |
|
| 625 | ||
| 626 |
# All constructors in this file are documented in 1 roxygen file via @rdname. |
|
| 627 | ||
| 628 |
#' Class constructors for `FIMSFrame` and associated child classes |
|
| 629 |
#' |
|
| 630 |
#' All constructor functions take a single input and build an object specific |
|
| 631 |
#' to the needs of each model type within \pkg{FIMS}. `FIMSFrame` is the parent
|
|
| 632 |
#' class. Future, associated child classes will have the additional slots |
|
| 633 |
#' needed for different types of models. |
|
| 634 |
#' |
|
| 635 |
#' @details |
|
| 636 |
#' ## data |
|
| 637 |
#' The input data are both sorted and expanded before returning them in the |
|
| 638 |
#' data slot. |
|
| 639 |
#' ### Sorting |
|
| 640 |
#' It is important that the order of the rows in the data are correct but it is |
|
| 641 |
#' not expected that the user will do this. Instead, the returned data are |
|
| 642 |
#' sorted using [dplyr::arrange()] before placing them in the data slot. Data |
|
| 643 |
#' are first sorted by data type, placing all weight-at-age data next to other |
|
| 644 |
#' weight-at-age data and all landings data next to landings data. Thus, |
|
| 645 |
#' age-composition data will come first because their type is "age" and "a" is |
|
| 646 |
#' first in the alphabet. All other types will follow according to their order |
|
| 647 |
#' in the alphabet. |
|
| 648 |
#' Next, within each type, data are organized by fleet. So, age-composition |
|
| 649 |
#' information for fleet1 will come before survey1. Next, all data within type |
|
| 650 |
#' and fleet are arranged by timing, e.g., by year. That is the end of the |
|
| 651 |
#' sorting for time series data like landings and indices. |
|
| 652 |
#' The biological data are further sorted by bin. Thus, age-composition |
|
| 653 |
#' information will be arranged as follows: |
|
| 654 |
#' |
|
| 655 |
#' | type | name | timing | age | value | |
|
| 656 |
#' |:---- |:--------:|:-------:|:----:|-------:| |
|
| 657 |
#' | age | fleet1 | 2022 | 1 | 0.3 | |
|
| 658 |
#' | age | fleet1 | 2022 | 2 | 0.7 | |
|
| 659 |
#' | age | fleet1 | 2023 | 1 | 0.5 | |
|
| 660 |
#' |
|
| 661 |
#' Length composition-data are sorted the same way but by length bin instead of |
|
| 662 |
#' by age bin. It becomes more complicated for the age-to-length-conversion |
|
| 663 |
#' data, which are sorted by type, name, timing, age, and then length. So, a |
|
| 664 |
#' full set of length, e.g., length 10, length 20, length 30, etc., is placed |
|
| 665 |
#' together for a given age. After that age, another entire set of length |
|
| 666 |
#' information will be provided for that next age. Once the year is complete |
|
| 667 |
#' for a given fleet then the next year will begin. |
|
| 668 |
#' |
|
| 669 |
#' @rdname FIMSFrame |
|
| 670 |
#' |
|
| 671 |
#' @param data A `data.frame` that contains the necessary columns to construct |
|
| 672 |
#' a `FIMSFrame-class` object. Currently, those columns are |
|
| 673 |
#' `r glue::glue_collapse(colnames(data1), sep = ", ", last = ", and ")`. See |
|
| 674 |
#' the data1 object in FIMS, e.g., `data(data1, package = "FIMS")`. |
|
| 675 |
#' |
|
| 676 |
#' @return |
|
| 677 |
#' An object of the S4 class `FIMSFrame` class, or one of its child classes, is |
|
| 678 |
#' validated and then returned. All objects will at a minimum have a slot |
|
| 679 |
#' called `data` to store the input data frame. Additional slots are dependent |
|
| 680 |
#' on the child class. Use [methods::showClass()] to see all available slots. |
|
| 681 |
#' @export |
|
| 682 |
#' @keywords FIMSFrame |
|
| 683 |
FIMSFrame <- function(data) {
|
|
| 684 | 19x |
errors <- validate_data_colnames(data) |
| 685 | 19x |
if (length(errors) > 0) {
|
| 686 | 1x |
stop( |
| 687 | 1x |
"Check the columns of your data, the following are missing:\n", |
| 688 | 1x |
paste(errors, sep = "\n", collapse = "\n") |
| 689 |
) |
|
| 690 |
} |
|
| 691 | ||
| 692 |
# Get the earliest and latest year formatted as integers |
|
| 693 | 18x |
start_year <- as.integer(floor(min(data[["timing"]], na.rm = TRUE))) |
| 694 | 18x |
end_year <- as.integer(floor(max(data[["timing"]], na.rm = TRUE))) |
| 695 | 18x |
n_years <- as.integer(end_year - start_year + 1) |
| 696 | 18x |
years <- start_year:end_year |
| 697 | ||
| 698 |
# Get the fleets represented in the data |
|
| 699 | 18x |
fleets <- unique(data[["name"]]) |
| 700 | 18x |
n_fleets <- length(fleets) |
| 701 | ||
| 702 | 18x |
if ("age" %in% colnames(data)) {
|
| 703 |
# Forced to use annual age bins because the model is on an annual time step |
|
| 704 |
# FUTURE: allow for different age bins rather than 1 year increment |
|
| 705 | 18x |
ages <- min(data[["age"]], na.rm = TRUE):max(data[["age"]], na.rm = TRUE) |
| 706 |
} else {
|
|
| 707 | ! |
ages <- numeric() |
| 708 |
} |
|
| 709 | 18x |
n_ages <- length(ages) |
| 710 | ||
| 711 | 18x |
if ("length" %in% colnames(data)) {
|
| 712 | 15x |
if (all(is.na(data[["length"]]))) {
|
| 713 | ! |
lengths <- numeric() |
| 714 |
} else {
|
|
| 715 | 15x |
lengths <- sort(unique(data[["length"]])) |
| 716 | 15x |
lengths <- lengths[!is.na(lengths)] |
| 717 |
} |
|
| 718 |
} else {
|
|
| 719 | 3x |
lengths <- numeric() |
| 720 |
} |
|
| 721 | 18x |
n_lengths <- length(lengths) |
| 722 | ||
| 723 |
# Work on filling in missing data with -999 and arrange in the correct |
|
| 724 |
# order so that getting information out with m_*() are correct. |
|
| 725 | 18x |
formatted_data <- tibble::as_tibble(data) |
| 726 | 18x |
missing_time_series <- create_missing_data( |
| 727 | 18x |
data = formatted_data, |
| 728 | 18x |
timing = years |
| 729 |
) |
|
| 730 | 18x |
if ("age" %in% colnames(formatted_data)) {
|
| 731 | 18x |
missing_ages <- create_missing_data( |
| 732 | 18x |
data = formatted_data, |
| 733 | 18x |
bins = ages, |
| 734 | 18x |
timing = years, |
| 735 | 18x |
column = age, |
| 736 | 18x |
types = c("weight-at-age", "age_comp")
|
| 737 |
) |
|
| 738 |
} else {
|
|
| 739 | ! |
missing_ages <- missing_time_series[0, ] |
| 740 |
} |
|
| 741 | 18x |
if ("length" %in% colnames(formatted_data)) {
|
| 742 | 15x |
missing_lengths <- create_missing_data( |
| 743 | 15x |
data = formatted_data, |
| 744 | 15x |
bins = lengths, |
| 745 | 15x |
timing = years, |
| 746 | 15x |
column = length, |
| 747 | 15x |
types = "length_comp" |
| 748 |
) |
|
| 749 |
} else {
|
|
| 750 | 3x |
missing_lengths <- missing_time_series[0, ] |
| 751 |
} |
|
| 752 | 18x |
if ("age-to-length-conversion" %in% formatted_data[["type"]]) {
|
| 753 |
# Must do this by hand because it is across two dimensions |
|
| 754 | 15x |
temp_age_to_length_data <- formatted_data |> |
| 755 | 15x |
dplyr::group_by(type, name) |
| 756 | 15x |
missing_age_to_length <- temp_age_to_length_data |> |
| 757 | 15x |
dplyr::group_by(type, name) |> |
| 758 | 15x |
dplyr::filter(type %in% "age-to-length-conversion") |> |
| 759 | 15x |
tidyr::expand(unit, timing = years, age = ages, length = lengths) |> |
| 760 | 15x |
dplyr::anti_join( |
| 761 | 15x |
y = dplyr::select( |
| 762 | 15x |
temp_age_to_length_data, |
| 763 | 15x |
type, name, unit, timing, age, length |
| 764 |
), |
|
| 765 | 15x |
by = dplyr::join_by(type, name, unit, timing, age, length) |
| 766 |
) |> |
|
| 767 | 15x |
dplyr::mutate( |
| 768 | 15x |
value = 0 |
| 769 |
) |> |
|
| 770 | 15x |
dplyr::ungroup() |
| 771 |
} else {
|
|
| 772 | 3x |
missing_age_to_length <- missing_time_series[0, ] |
| 773 |
} |
|
| 774 | 18x |
missing_data <- dplyr::bind_rows( |
| 775 | 18x |
missing_time_series, |
| 776 | 18x |
missing_ages, |
| 777 | 18x |
missing_lengths, |
| 778 | 18x |
missing_age_to_length |
| 779 |
) |
|
| 780 | 18x |
sort_order <- intersect( |
| 781 | 18x |
c("name", "type", "timing", "age", "length"),
|
| 782 | 18x |
colnames(formatted_data) |
| 783 |
) |
|
| 784 | 18x |
complete_data <- dplyr::full_join( |
| 785 | 18x |
formatted_data, |
| 786 | 18x |
missing_data, |
| 787 | 18x |
by = colnames(missing_data) |
| 788 |
) |> |
|
| 789 | 18x |
dplyr::arrange(!!!rlang::parse_exprs(sort_order)) |
| 790 | ||
| 791 |
# Fill the empty data frames with data extracted from the data file |
|
| 792 | 18x |
out <- methods::new("FIMSFrame",
|
| 793 | 18x |
data = complete_data, |
| 794 | 18x |
fleets = fleets, |
| 795 | 18x |
n_years = n_years, |
| 796 | 18x |
start_year = start_year, |
| 797 | 18x |
end_year = end_year, |
| 798 | 18x |
ages = ages, |
| 799 | 18x |
n_ages = n_ages, |
| 800 | 18x |
lengths = lengths, |
| 801 | 18x |
n_lengths = n_lengths |
| 802 |
) |
|
| 803 | 18x |
return(out) |
| 804 |
} |
|
| 805 | ||
| 806 |
# Unexported functions ---- |
|
| 807 |
create_missing_data <- function( |
|
| 808 |
data, |
|
| 809 |
bins, |
|
| 810 |
timings, |
|
| 811 |
column, |
|
| 812 |
types = c("landings", "index")
|
|
| 813 |
) {
|
|
| 814 | 51x |
use_this_data <- data |> |
| 815 | 51x |
dplyr::group_by(type, name) |
| 816 | 51x |
out_data <- if (missing(bins)) {
|
| 817 |
# This only pertains to annual data without bins |
|
| 818 | 18x |
use_this_data |> |
| 819 | 18x |
dplyr::filter(type %in% types) |> |
| 820 | 18x |
tidyr::expand(unit, timing = timings) |> |
| 821 | 18x |
dplyr::anti_join( |
| 822 | 18x |
y = dplyr::select(use_this_data, type, name, unit, timing), |
| 823 | 18x |
by = dplyr::join_by(type, name, unit, timing) |
| 824 |
) |
|
| 825 |
} else {
|
|
| 826 | 33x |
use_this_data |> |
| 827 | 33x |
dplyr::group_by(type, name) |> |
| 828 | 33x |
dplyr::filter(type %in% types) |> |
| 829 | 33x |
tidyr::expand(unit, timing = timings, {{ column }} := bins) |>
|
| 830 | 33x |
dplyr::anti_join( |
| 831 | 33x |
y = dplyr::select(use_this_data, type, name, unit, timing, {{ column }}),
|
| 832 | 33x |
by = dplyr::join_by(type, name, unit, timing, {{ column }})
|
| 833 |
) |
|
| 834 |
} |
|
| 835 | 51x |
out_data |> |
| 836 | 51x |
dplyr::mutate( |
| 837 | 51x |
value = -999 |
| 838 |
) |> |
|
| 839 | 51x |
dplyr::ungroup() |
| 840 |
} |
| 1 |
# To remove the NOTE |
|
| 2 |
# no visible binding for global variable |
|
| 3 |
utils::globalVariables(c( |
|
| 4 |
"parameter_id", "module_name", "module_id", "label", "initial.x", "initial.y", |
|
| 5 |
"estimate.x", "estimate.y", |
|
| 6 |
"derived_quantity_id", |
|
| 7 |
"distribution", "module_type", "n", "type_id", "values", |
|
| 8 |
"module_name.x", "module_name.y", |
|
| 9 |
"module_id.x", "module_id.y", |
|
| 10 |
"module_id_init", |
|
| 11 |
"module_type.x", "module_type.y" |
|
| 12 |
)) |
|
| 13 | ||
| 14 |
# Developers: ---- |
|
| 15 | ||
| 16 |
# This file defines the parent class of FIMSFit and its potential children. The |
|
| 17 |
# class is an S4 class with accessors and validators but no setters. For more |
|
| 18 |
# details on how to create an S4 class in FIMS please see R/fimsframe.R |
|
| 19 | ||
| 20 |
# TODO: ---- |
|
| 21 | ||
| 22 |
# TODO: Fix "no metadata object found to revise superClass" in sdreportOrList |
|
| 23 |
# TODO: Write more validity checks for FIMSFit |
|
| 24 |
# TODO: Better document the return of [get_estimates()], i.e., columns |
|
| 25 |
# TODO: Make a helper function to add lower and upper CI for users in estimates |
|
| 26 | ||
| 27 |
# methods::setClass: ---- |
|
| 28 | ||
| 29 |
# Need to use an S3 class for the following S4 class |
|
| 30 |
methods::setOldClass(Classes = "package_version") |
|
| 31 |
methods::setOldClass(Classes = "difftime") |
|
| 32 |
methods::setOldClass(Classes = "sdreport") |
|
| 33 |
# Join sdreport and list into a class in case the sdreport is not created |
|
| 34 |
methods::setClassUnion("sdreportOrList", members = c("sdreport", "list"))
|
|
| 35 | ||
| 36 |
methods::setClass( |
|
| 37 |
Class = "FIMSFit", |
|
| 38 |
slots = c( |
|
| 39 |
input = "list", |
|
| 40 |
obj = "list", |
|
| 41 |
opt = "list", |
|
| 42 |
max_gradient = "numeric", |
|
| 43 |
report = "list", |
|
| 44 |
sdreport = "sdreportOrList", |
|
| 45 |
number_of_parameters = "integer", |
|
| 46 |
timing = "difftime", |
|
| 47 |
version = "package_version", |
|
| 48 |
model_output = "character" |
|
| 49 |
) |
|
| 50 |
) |
|
| 51 | ||
| 52 |
# methods::setMethod: printers ---- |
|
| 53 |
# TODO: add `get_report`, `get_opt`, etc. to the list of available slots in show()? |
|
| 54 |
methods::setMethod( |
|
| 55 |
f = "show", |
|
| 56 |
signature = "FIMSFit", |
|
| 57 |
definition = function(object) {
|
|
| 58 | ! |
cli::cli_inform(c( |
| 59 | ! |
"i" = "The object is of the class FIMSFit v.{get_version(object)}",
|
| 60 | ! |
"i" = "The slots can be accessed using {.fn get_*} functions, e.g.,",
|
| 61 | ! |
"*" = "{.fn get_model_output}",
|
| 62 | ! |
"*" = "{.fn get_obj}",
|
| 63 | ! |
"*" = "{.fn get_version}",
|
| 64 | ! |
"i" = "The following slots are available: {methods::slotNames(object)}.",
|
| 65 | ! |
"i" = "Use {.fn print} to see a summary of the fit."
|
| 66 |
)) |
|
| 67 |
} |
|
| 68 |
) |
|
| 69 | ||
| 70 |
methods::setMethod( |
|
| 71 |
f = "print", |
|
| 72 |
signature = "FIMSFit", |
|
| 73 |
definition = function(x) {
|
|
| 74 | 9x |
rt <- as.numeric(x@timing[["time_total"]], units = "secs") |
| 75 | 9x |
ru <- "seconds" |
| 76 | 9x |
if (rt > 60 * 60 * 24) {
|
| 77 | 1x |
rt <- rt / (60 * 60 * 24) |
| 78 | 1x |
ru <- "days" |
| 79 | 8x |
} else if (rt > 60 * 60) {
|
| 80 | 1x |
rt <- rt / (60 * 60) |
| 81 | 1x |
ru <- "hours" |
| 82 | 7x |
} else if (rt > 60) {
|
| 83 | 4x |
rt <- rt / 60 |
| 84 | 4x |
ru <- "minutes" |
| 85 |
} |
|
| 86 | ||
| 87 | 9x |
number_of_parameters <- paste( |
| 88 | 9x |
names(x@number_of_parameters), |
| 89 | 9x |
x@number_of_parameters, |
| 90 | 9x |
sep = "=" |
| 91 |
) |
|
| 92 | 9x |
total_parameters <- sum(x@number_of_parameters) |
| 93 | 9x |
all_parameters_info <- c(number_of_parameters, paste( |
| 94 | 9x |
"total", |
| 95 | 9x |
total_parameters, |
| 96 | 9x |
sep = "=" |
| 97 |
)) |
|
| 98 | 9x |
div_digit <- cli::cli_div(theme = list(.val = list(digits = 5))) |
| 99 | 9x |
terminal_ssb <- sapply( |
| 100 | 9x |
x@report[["ssb"]], |
| 101 | 9x |
function(y) utils::tail(y, 1) |
| 102 |
) |
|
| 103 | 9x |
cli::cli_inform(c( |
| 104 | 9x |
"i" = "FIMS model version: {.val {x@version}}",
|
| 105 | 9x |
"i" = "Total run time was {.val {rt}} {ru}",
|
| 106 | 9x |
"i" = "Number of parameters: {all_parameters_info}",
|
| 107 | 9x |
"i" = "Maximum gradient= {.val {x@max_gradient}}",
|
| 108 | 9x |
"i" = "Negative log likelihood (NLL):", |
| 109 | 9x |
"*" = "Marginal NLL= {.val {x@opt$objective}}",
|
| 110 | 9x |
"*" = "Total NLL= {.val {x@report$jnll}}",
|
| 111 | 9x |
"i" = "Terminal SB= {.val {terminal_ssb}}"
|
| 112 |
)) |
|
| 113 | 9x |
cli::cli_end(div_digit) |
| 114 |
} |
|
| 115 |
) |
|
| 116 | ||
| 117 |
# methods::setMethod: accessors ---- |
|
| 118 | ||
| 119 |
# Accessor functions for a FIMSFit object |
|
| 120 |
# 1 methods::setGeneric() per slot but potentially >1 methods::setMethod() per methods::setGeneric() |
|
| 121 | ||
| 122 |
#' Get a slot in a FIMSFit object |
|
| 123 |
#' |
|
| 124 |
#' There is an accessor function for each slot in the S4 class `FIMSFit`, where |
|
| 125 |
#' the function is named `get_*()` and the star can be replaced with the slot |
|
| 126 |
#' name, e.g., [get_input()]. These accessor functions are the preferred way |
|
| 127 |
#' to access objects stored in the available slots. |
|
| 128 |
#' |
|
| 129 |
#' @param x Output returned from [fit_fims()]. |
|
| 130 |
#' @name get_FIMSFit |
|
| 131 |
#' @seealso |
|
| 132 |
#' * [fit_fims()] |
|
| 133 |
#' * [create_default_parameters()] |
|
| 134 |
NULL |
|
| 135 | ||
| 136 |
#' @return |
|
| 137 |
#' [get_input()] returns the list that was used to fit the FIMS model, which |
|
| 138 |
#' is the returned object from [create_default_parameters()]. |
|
| 139 |
#' @export |
|
| 140 |
#' @rdname get_FIMSFit |
|
| 141 |
#' @keywords fit_fims |
|
| 142 | 7x |
methods::setGeneric("get_input", function(x) standardGeneric("get_input"))
|
| 143 |
#' @rdname get_FIMSFit |
|
| 144 |
#' @keywords fit_fims |
|
| 145 | 6x |
methods::setMethod("get_input", "FIMSFit", function(x) x@input)
|
| 146 | ||
| 147 |
#' @return |
|
| 148 |
#' [get_report()] returns the TMB report, where anything that is flagged as |
|
| 149 |
#' reportable in the C++ code is returned. |
|
| 150 |
#' @export |
|
| 151 |
#' @rdname get_FIMSFit |
|
| 152 |
#' @keywords fit_fims |
|
| 153 | 8x |
methods::setGeneric("get_report", function(x) standardGeneric("get_report"))
|
| 154 |
#' @rdname get_FIMSFit |
|
| 155 |
#' @keywords fit_fims |
|
| 156 | 8x |
methods::setMethod("get_report", "FIMSFit", function(x) x@report)
|
| 157 | ||
| 158 |
#' @return |
|
| 159 |
#' [get_obj()] returns the output from [TMB::MakeADFun()]. |
|
| 160 |
#' @export |
|
| 161 |
#' @rdname get_FIMSFit |
|
| 162 |
#' @keywords fit_fims |
|
| 163 | 55x |
methods::setGeneric("get_obj", function(x) standardGeneric("get_obj"))
|
| 164 |
#' @rdname get_FIMSFit |
|
| 165 |
#' @keywords fit_fims |
|
| 166 | 54x |
methods::setMethod("get_obj", "FIMSFit", function(x) x@obj)
|
| 167 | ||
| 168 |
#' @return |
|
| 169 |
#' [get_opt()] returns the output from [nlminb()], which is the minimizer used |
|
| 170 |
#' in [fit_fims()]. |
|
| 171 |
#' @export |
|
| 172 |
#' @rdname get_FIMSFit |
|
| 173 |
#' @keywords fit_fims |
|
| 174 | 31x |
methods::setGeneric("get_opt", function(x) standardGeneric("get_opt"))
|
| 175 |
#' @rdname get_FIMSFit |
|
| 176 |
#' @keywords fit_fims |
|
| 177 | 30x |
methods::setMethod("get_opt", "FIMSFit", function(x) x@opt)
|
| 178 | ||
| 179 |
#' @return |
|
| 180 |
#' [get_max_gradient()] returns the maximum gradient found when optimizing the |
|
| 181 |
#' model. |
|
| 182 |
#' @export |
|
| 183 |
#' @rdname get_FIMSFit |
|
| 184 |
#' @keywords fit_fims |
|
| 185 | 7x |
methods::setGeneric("get_max_gradient", function(x) standardGeneric("get_max_gradient"))
|
| 186 |
#' @rdname get_FIMSFit |
|
| 187 |
#' @keywords fit_fims |
|
| 188 | 6x |
methods::setMethod("get_max_gradient", "FIMSFit", function(x) x@max_gradient)
|
| 189 | ||
| 190 |
#' @return |
|
| 191 |
#' [get_sdreport()] returns the list from [TMB::sdreport()]. |
|
| 192 |
#' @export |
|
| 193 |
#' @rdname get_FIMSFit |
|
| 194 |
#' @keywords fit_fims |
|
| 195 | 31x |
methods::setGeneric("get_sdreport", function(x) standardGeneric("get_sdreport"))
|
| 196 |
#' @rdname get_FIMSFit |
|
| 197 |
#' @keywords fit_fims |
|
| 198 | 30x |
methods::setMethod("get_sdreport", "FIMSFit", function(x) x@sdreport)
|
| 199 | ||
| 200 |
#' @return |
|
| 201 |
#' [get_estimates()] returns a tibble of parameter values and their |
|
| 202 |
#' uncertainties from a fitted model. |
|
| 203 |
#' @export |
|
| 204 |
#' @rdname get_FIMSFit |
|
| 205 |
#' @keywords fit_fims |
|
| 206 | 18x |
methods::setGeneric("get_estimates", function(x) standardGeneric("get_estimates"))
|
| 207 |
#' @rdname get_FIMSFit |
|
| 208 |
#' @keywords fit_fims |
|
| 209 |
methods::setMethod( |
|
| 210 |
"get_estimates", |
|
| 211 |
"FIMSFit", |
|
| 212 |
function(x) {
|
|
| 213 |
# Extract the core TMB components (object, sdreport, optimization result) |
|
| 214 |
# from the fit object. |
|
| 215 | 17x |
obj <- get_obj(x) |
| 216 | 17x |
sdreport <- get_sdreport(x) |
| 217 | 17x |
opt <- get_opt(x) |
| 218 | 17x |
parameter_names <- get_obj(x)[["par"]] |> |
| 219 | 17x |
names() |
| 220 | ||
| 221 |
# Reshape the TMB output into a standardized data frame. |
|
| 222 |
# This serves as the "expected" result to compare against. |
|
| 223 | 17x |
tmb_output <- FIMS:::reshape_tmb_estimates( |
| 224 | 17x |
obj = obj, |
| 225 | 17x |
sdreport = sdreport, |
| 226 | 17x |
opt = opt, |
| 227 | 17x |
parameter_names = parameter_names |
| 228 |
) |
|
| 229 | ||
| 230 |
# Extract the model_output, which contains the JSON-like structure. |
|
| 231 | 17x |
model_output <- get_model_output(x) |
| 232 |
# Reshape the output from the JSON structure into a data frame. |
|
| 233 | 17x |
json_output <- reshape_json_estimates(model_output) |
| 234 | ||
| 235 |
# Join the two outputs on parameter_id to compare and consolidate information. |
|
| 236 | 17x |
estimates <- dplyr::left_join( |
| 237 | 17x |
json_output, |
| 238 | 17x |
tmb_output |> |
| 239 | 17x |
dplyr::filter(!is.na(parameter_id)) |> |
| 240 | 17x |
dplyr::select(-initial, -module_name, -module_id, -estimate, -label), |
| 241 | 17x |
by = c("parameter_id")
|
| 242 |
) |> |
|
| 243 | 17x |
dplyr::mutate( |
| 244 | 17x |
uncertainty = dplyr::coalesce(uncertainty.x, uncertainty.y), |
| 245 | 17x |
.after = "estimation_type" |
| 246 |
) |> |
|
| 247 | 17x |
dplyr::select(-uncertainty.x, -uncertainty.y) |
| 248 |
} |
|
| 249 |
) |
|
| 250 | ||
| 251 |
#' @return |
|
| 252 |
#' [get_number_of_parameters()] returns a vector of integers specifying the |
|
| 253 |
#' number of fixed-effect parameters and the number of random-effect parameters |
|
| 254 |
#' in the model. |
|
| 255 |
#' @export |
|
| 256 |
#' @rdname get_FIMSFit |
|
| 257 |
#' @keywords fit_fims |
|
| 258 |
methods::setGeneric( |
|
| 259 |
"get_number_of_parameters", |
|
| 260 | 9x |
function(x) standardGeneric("get_number_of_parameters")
|
| 261 |
) |
|
| 262 |
#' @rdname get_FIMSFit |
|
| 263 |
#' @keywords fit_fims |
|
| 264 |
methods::setMethod( |
|
| 265 |
"get_number_of_parameters", |
|
| 266 |
"FIMSFit", |
|
| 267 | 8x |
function(x) x@number_of_parameters |
| 268 |
) |
|
| 269 | ||
| 270 |
#' @return |
|
| 271 |
#' [get_timing()] returns the amount of time it took to run the model in |
|
| 272 |
#' seconds as a `difftime` object. |
|
| 273 |
#' @export |
|
| 274 |
#' @rdname get_FIMSFit |
|
| 275 |
#' @keywords fit_fims |
|
| 276 | 7x |
methods::setGeneric("get_timing", function(x) standardGeneric("get_timing"))
|
| 277 |
#' @rdname get_FIMSFit |
|
| 278 |
#' @keywords fit_fims |
|
| 279 | 6x |
methods::setMethod("get_timing", "FIMSFit", function(x) x@timing)
|
| 280 | ||
| 281 |
#' @return |
|
| 282 |
#' [get_version()] returns the `package_version` of FIMS that was used to fit |
|
| 283 |
#' the model. |
|
| 284 |
#' @export |
|
| 285 |
#' @rdname get_FIMSFit |
|
| 286 |
#' @keywords fit_fims |
|
| 287 | 7x |
methods::setGeneric("get_version", function(x) standardGeneric("get_version"))
|
| 288 |
#' @rdname get_FIMSFit |
|
| 289 |
#' @keywords fit_fims |
|
| 290 | 6x |
methods::setMethod("get_version", "FIMSFit", function(x) x@version)
|
| 291 | ||
| 292 |
#' @return |
|
| 293 |
#' [get_model_output()] returns the finalized FIMS output as a JSON list. |
|
| 294 |
#' @export |
|
| 295 |
#' @rdname get_FIMSFit |
|
| 296 |
#' @keywords fit_fims |
|
| 297 | 31x |
methods::setGeneric("get_model_output", function(x) standardGeneric("get_model_output"))
|
| 298 |
#' @rdname get_FIMSFit |
|
| 299 |
#' @keywords fit_fims |
|
| 300 | 31x |
methods::setMethod("get_model_output", "FIMSFit", function(x) x@model_output)
|
| 301 | ||
| 302 |
# methods::setValidity ---- |
|
| 303 | ||
| 304 |
methods::setValidity( |
|
| 305 |
Class = "FIMSFit", |
|
| 306 |
method = function(object) {
|
|
| 307 |
errors <- character() |
|
| 308 | ||
| 309 |
# Check that obj is from TMB::MakeADFun() |
|
| 310 |
TMB_MakeADFun_names <- c( |
|
| 311 |
"par", "fn", "gr", "he", "hessian", "method", "retape", "env", "report", |
|
| 312 |
"simulate" |
|
| 313 |
) |
|
| 314 |
if (!setequal(names(object@obj), TMB_MakeADFun_names)) {
|
|
| 315 |
errors <- c( |
|
| 316 |
errors, |
|
| 317 |
"obj must be a list returned from TMB::MakeADFun() but it does not |
|
| 318 |
appear to be so because it does not have the standard names." |
|
| 319 |
) |
|
| 320 |
} |
|
| 321 | ||
| 322 |
# Return |
|
| 323 |
if (length(errors) == 0) {
|
|
| 324 |
return(TRUE) |
|
| 325 |
} else {
|
|
| 326 |
return(errors) |
|
| 327 |
} |
|
| 328 |
} |
|
| 329 |
) |
|
| 330 | ||
| 331 |
# methods::setMethod: is.FIMSFit ---- |
|
| 332 | ||
| 333 |
#' Check if an object is of class FIMSFit |
|
| 334 |
#' |
|
| 335 |
#' @param x Returned list from [fit_fims()]. |
|
| 336 |
#' @keywords fit_fims |
|
| 337 |
#' @export |
|
| 338 |
is.FIMSFit <- function(x) {
|
|
| 339 | 2x |
inherits(x, "FIMSFit") |
| 340 |
} |
|
| 341 | ||
| 342 |
# Constructors ---- |
|
| 343 | ||
| 344 |
#' Class constructors for class `FIMSFit` and associated child classes |
|
| 345 |
#' |
|
| 346 |
#' Create an object with the class of `FIMSFit` after running a FIMS model. This |
|
| 347 |
#' is typically done within [fit_fims()] but it can be create manually by the |
|
| 348 |
#' user if they have used their own bespoke code to fit a FIMS model. |
|
| 349 |
#' |
|
| 350 |
#' @inheritParams fit_fims |
|
| 351 |
#' @param obj An object returned from [TMB::MakeADFun()]. |
|
| 352 |
#' @param opt An object returned from an optimizer, typically from |
|
| 353 |
#' [stats::nlminb()], used to fit a TMB model. |
|
| 354 |
#' @param sdreport An object of the `sdreport` class as returned from |
|
| 355 |
#' [TMB::sdreport()]. |
|
| 356 |
#' @param timing A vector of at least length one, where all entries are of the |
|
| 357 |
#' `timediff` class and at least one is named "time_total". This information |
|
| 358 |
#' is available in [fit_fims()] and added to this argument internally but if |
|
| 359 |
#' you are a power user you can calculate the time it took to run your model |
|
| 360 |
#' by subtracting two [Sys.time()] objects. |
|
| 361 |
#' @param version The version of FIMS that was used to optimize the model. If |
|
| 362 |
#' [fit_fims()] was not used to optimize the model, then the default is to |
|
| 363 |
#' use the current version of the package that is loaded. |
|
| 364 |
#' |
|
| 365 |
#' @return |
|
| 366 |
#' An object with an S4 class of `FIMSFit` is returned. The object will have the |
|
| 367 |
#' following slots: |
|
| 368 |
#' \describe{
|
|
| 369 |
#' \item{\code{input}:}{
|
|
| 370 |
#' A list containing the model setup in the same form it was passed. |
|
| 371 |
#' } |
|
| 372 |
#' \item{\code{obj}:}{
|
|
| 373 |
#' A list returned from [TMB::MakeADFun()] in the same form it was passed. |
|
| 374 |
#' } |
|
| 375 |
#' \item{\code{opt}:}{
|
|
| 376 |
#' A list containing the optimized model in the same form it was passed. |
|
| 377 |
#' } |
|
| 378 |
#' \item{\code{max_gradient}:}{
|
|
| 379 |
#' The maximum gradient found when optimizing the model. The default is |
|
| 380 |
#' `NA`, which means that the model was not optimized. |
|
| 381 |
#' } |
|
| 382 |
#' \item{\code{report}:}{
|
|
| 383 |
#' A list containing the model report from `obj[["report"]]()`. |
|
| 384 |
#' } |
|
| 385 |
#' \item{\code{sdreport}:}{
|
|
| 386 |
#' An object with the `sdreport` class containing the output from |
|
| 387 |
#' `TMB::sdreport(obj)`. |
|
| 388 |
#' } |
|
| 389 |
#' \item{\code{timing}:}{
|
|
| 390 |
#' The length of time it took to run the model if it was optimized. |
|
| 391 |
#' } |
|
| 392 |
#' \item{\code{version}:}{
|
|
| 393 |
#' The package version of FIMS used to fit the model or at least the |
|
| 394 |
#' version used to create this output, which will not always be the same |
|
| 395 |
#' if you are running this function yourself. |
|
| 396 |
#' } |
|
| 397 |
#' \item{\code{model_output}:}{
|
|
| 398 |
#' The FIMS model output as a JSON string. |
|
| 399 |
#' } |
|
| 400 |
#' } |
|
| 401 |
#' @keywords fit_fims |
|
| 402 |
#' @export |
|
| 403 |
FIMSFit <- function( |
|
| 404 |
input, |
|
| 405 |
obj, |
|
| 406 |
opt = list(), |
|
| 407 |
sdreport = list(), |
|
| 408 |
timing = c("time_total" = as.difftime(0, units = "secs")),
|
|
| 409 |
version = utils::packageVersion("FIMS")
|
|
| 410 |
) {
|
|
| 411 |
# Determine the number of parameters |
|
| 412 | 8x |
n_total <- length(obj[["env"]][["last.par.best"]]) |
| 413 | 8x |
n_fixed_effects <- length(obj[["par"]]) |
| 414 | 8x |
n_random_effects <- length(obj[["env"]][["parList()"]][["re"]]) |
| 415 | 8x |
number_of_parameters <- c( |
| 416 | 8x |
fixed_effects = n_fixed_effects, |
| 417 | 8x |
random_effects = n_random_effects |
| 418 |
) |
|
| 419 | 8x |
rm(n_total, n_fixed_effects, n_random_effects) |
| 420 | ||
| 421 |
# Calculate the maximum gradient |
|
| 422 | 8x |
max_gradient <- if (length(opt) > 0) {
|
| 423 | 6x |
max(abs(obj[["gr"]](opt[["par"]]))) |
| 424 |
} else {
|
|
| 425 | 8x |
NA_real_ |
| 426 |
} |
|
| 427 | ||
| 428 |
# Rename parameters instead of "p" |
|
| 429 | 8x |
parameter_names <- names(get_parameter_names(obj[["par"]])) |
| 430 | 8x |
names(obj[["par"]]) <- parameter_names |
| 431 | 8x |
random_effects_names <- names(get_random_names(obj[["env"]][["parList()"]][["re"]])) |
| 432 | ||
| 433 |
# Get the report |
|
| 434 | 8x |
report <- if (length(opt) == 0) {
|
| 435 | 2x |
obj[["report"]](obj[["env"]][["last.par.best"]]) |
| 436 |
} else {
|
|
| 437 | 6x |
obj[["report"]]() |
| 438 |
} |
|
| 439 | ||
| 440 | 8x |
if (length(sdreport) > 0) {
|
| 441 |
# rename the sdreport |
|
| 442 | 6x |
names(sdreport[["par.fixed"]]) <- parameter_names |
| 443 | 6x |
dimnames(sdreport[["cov.fixed"]]) <- list(parameter_names, parameter_names) |
| 444 |
} |
|
| 445 | ||
| 446 |
# Reshape the TMB estimates |
|
| 447 |
# If the model is not optimized, opt is an empty list and is not used in |
|
| 448 |
# reshape_tmb_estimates(). |
|
| 449 | 8x |
tmb_estimates <- reshape_tmb_estimates( |
| 450 | 8x |
obj = obj, |
| 451 | 8x |
sdreport = sdreport, |
| 452 | 8x |
opt = opt, |
| 453 | 8x |
parameter_names = parameter_names |
| 454 |
) |
|
| 455 | ||
| 456 |
# Create JSON output for FIMS run |
|
| 457 | 8x |
model_output <- input[["model"]]$get_output() |
| 458 |
# Reshape the JSON estimates |
|
| 459 | 8x |
json_estimates <- reshape_json_estimates(model_output) |
| 460 |
# Merge json_estimates into tmb_estimates based on parameter id |
|
| 461 |
# TODO: Need uncertainty from TMB for derived quantities |
|
| 462 |
# TODO: change order of columns |
|
| 463 | 8x |
estimates <- dplyr::left_join( |
| 464 | 8x |
json_estimates, |
| 465 | 8x |
tmb_estimates |> |
| 466 | 8x |
dplyr::filter(!is.na(parameter_id)) |> |
| 467 | 8x |
dplyr::select(-initial, -module_name, -module_id, -estimate, -label), |
| 468 | 8x |
by = c("parameter_id")
|
| 469 |
) |> |
|
| 470 | 8x |
dplyr::mutate( |
| 471 | 8x |
uncertainty = dplyr::coalesce(uncertainty.x, uncertainty.y), |
| 472 | 8x |
.after = "estimation_type" |
| 473 |
) |> |
|
| 474 | 8x |
dplyr::select(-uncertainty.x, -uncertainty.y) |
| 475 | ||
| 476 | 8x |
fit <- methods::new( |
| 477 | 8x |
"FIMSFit", |
| 478 | 8x |
input = input, |
| 479 | 8x |
obj = obj, |
| 480 | 8x |
opt = opt, |
| 481 | 8x |
max_gradient = max_gradient, |
| 482 | 8x |
report = report, |
| 483 | 8x |
sdreport = sdreport, |
| 484 | 8x |
number_of_parameters = number_of_parameters, |
| 485 | 8x |
timing = timing, |
| 486 | 8x |
version = version, |
| 487 | 8x |
model_output = model_output |
| 488 |
) |
|
| 489 | 8x |
fit |
| 490 |
} |
|
| 491 | ||
| 492 |
#' Fit a FIMS model (BETA) |
|
| 493 |
#' |
|
| 494 |
#' @param input Input list as returned by [initialize_fims()]. |
|
| 495 |
#' @param get_sd A boolean specifying if the [TMB::sdreport()] should be |
|
| 496 |
#' calculated? |
|
| 497 |
#' @param save_sd A logical, with the default `TRUE`, indicating whether the |
|
| 498 |
#' sdreport is returned in the output. If `FALSE`, the slot for the report |
|
| 499 |
#' will be empty. |
|
| 500 |
#' @param number_of_loops A positive integer specifying the number of |
|
| 501 |
#' iterations of the optimizer that will be performed to improve the |
|
| 502 |
#' gradient. The default is three, leading to four total optimization steps. |
|
| 503 |
#' @param optimize Optimize (TRUE, default) or (FALSE) build and return |
|
| 504 |
#' a list containing the obj and report slot. |
|
| 505 |
#' @param number_of_newton_steps The number of Newton steps using the inverse |
|
| 506 |
#' Hessian to do after optimization. Not yet implemented. |
|
| 507 |
#' @param control A list of optimizer settings passed to [stats::nlminb()]. The |
|
| 508 |
#' the default is a list of length three with `eval.max = 1000`, |
|
| 509 |
#' `iter.max = 10000`, and `trace = 0`. |
|
| 510 |
#' @param filename Character string giving a file name to save the fitted |
|
| 511 |
#' object as an RDS object. Defaults to 'fit.RDS', and a value of NULL |
|
| 512 |
#' indicates not to save it. If specified, it must end in .RDS. The file is |
|
| 513 |
#' written to folder given by `input[["path"]]`. Not yet implemented. |
|
| 514 |
#' @return |
|
| 515 |
#' An object of class `FIMSFit` is returned, where the structure is the same |
|
| 516 |
#' regardless if `optimize = TRUE` or not. Uncertainty information is only |
|
| 517 |
#' included in the `estimates` slot if `get_sd = TRUE`. |
|
| 518 |
#' @seealso |
|
| 519 |
#' * [FIMSFit()] |
|
| 520 |
#' @details This function is a beta version still and subject to change |
|
| 521 |
#' without warning. |
|
| 522 |
#' @keywords fit_fims |
|
| 523 |
#' @export |
|
| 524 |
fit_fims <- function(input, |
|
| 525 |
get_sd = TRUE, |
|
| 526 |
save_sd = TRUE, |
|
| 527 |
number_of_loops = 3, |
|
| 528 |
optimize = TRUE, |
|
| 529 |
number_of_newton_steps = 0, |
|
| 530 |
control = list( |
|
| 531 |
eval.max = 10000, |
|
| 532 |
iter.max = 10000, |
|
| 533 |
trace = 0 |
|
| 534 |
), |
|
| 535 |
filename = NULL) {
|
|
| 536 |
# See issue 455 of sdmTMB to see what should be used. |
|
| 537 |
# https://github.com/pbs-assess/sdmTMB/issues/455 |
|
| 538 |
# NOTE: When we add implementation for newton step we need to |
|
| 539 |
# review the above github issue to make sure we maintain continuity |
|
| 540 |
# between outputs as last.par may not equal last.par.best due to |
|
| 541 |
# the smallest newton gradient solution not matching the smallest |
|
| 542 |
# likelihood value. This can cause sanity issues in output reporting. |
|
| 543 | 9x |
if (number_of_newton_steps > 0) {
|
| 544 | ! |
cli::cli_abort("Newton steps not implemented yet.")
|
| 545 |
} |
|
| 546 | 9x |
if (number_of_loops < 0) {
|
| 547 | ! |
cli::cli_abort("number_of_loops ({.par {number_of_loops}}) must be >= 0.")
|
| 548 |
} |
|
| 549 |
# If the estimation_type of all parameters is constant, FIMS will abort if |
|
| 550 |
# optimize is set to TRUE |
|
| 551 | 9x |
if (optimize == TRUE & all(purrr::map_vec(input[["parameters"]], length) == 0)) {
|
| 552 | 1x |
cli::cli_abort("FIMS must have at least one parameter to optimize.")
|
| 553 |
} |
|
| 554 | ||
| 555 | 8x |
obj <- TMB::MakeADFun( |
| 556 | 8x |
data = list(), |
| 557 | 8x |
parameters = input$parameters, |
| 558 | 8x |
map = input$map, |
| 559 | 8x |
random = "re", |
| 560 | 8x |
DLL = "FIMS", |
| 561 | 8x |
silent = TRUE |
| 562 |
) |
|
| 563 | 8x |
if (!optimize) {
|
| 564 | 2x |
initial_fit <- FIMSFit( |
| 565 | 2x |
input = input, |
| 566 | 2x |
obj = obj, |
| 567 | 2x |
timing = c("time_total" = as.difftime(0, units = "secs"))
|
| 568 |
) |
|
| 569 | 2x |
return(initial_fit) |
| 570 |
} |
|
| 571 | 6x |
if (!is_fims_verbose()) {
|
| 572 | 6x |
control$trace <- 0 |
| 573 |
} |
|
| 574 |
## optimize and compare |
|
| 575 | 6x |
cli::cli_inform(c("v" = "Starting optimization ..."))
|
| 576 | 6x |
t0 <- Sys.time() |
| 577 | 6x |
opt <- with( |
| 578 | 6x |
obj, |
| 579 | 6x |
nlminb( |
| 580 | 6x |
start = par, |
| 581 | 6x |
objective = fn, |
| 582 | 6x |
gradient = gr, |
| 583 | 6x |
control = control |
| 584 |
) |
|
| 585 |
) |
|
| 586 | 6x |
maxgrad0 <- maxgrad <- max(abs(obj$gr(opt$par))) |
| 587 | 6x |
if (number_of_loops > 0) {
|
| 588 | 6x |
cli::cli_inform(c( |
| 589 | 6x |
"i" = "Restarting optimizer {number_of_loops} times to improve gradient."
|
| 590 |
)) |
|
| 591 | 6x |
for (ii in 1:number_of_loops) {
|
| 592 |
# control$trace is reset to zero regardless of verbosity because the |
|
| 593 |
# differences in values printed out using control$trace will be |
|
| 594 |
# negligible between these different runs and is not worth printing |
|
| 595 | 18x |
control$trace <- 0 |
| 596 | 18x |
opt <- with( |
| 597 | 18x |
obj, |
| 598 | 18x |
nlminb( |
| 599 | 18x |
start = opt[["par"]], |
| 600 | 18x |
objective = fn, |
| 601 | 18x |
gradient = gr, |
| 602 | 18x |
control = control |
| 603 |
) |
|
| 604 |
) |
|
| 605 | 18x |
maxgrad <- max(abs(obj[["gr"]](opt[["par"]]))) |
| 606 |
} |
|
| 607 | 6x |
div_digit <- cli::cli_div(theme = list(.val = list(digits = 5))) |
| 608 | 6x |
cli::cli_inform(c( |
| 609 | 6x |
"i" = "Maximum gradient went from {.val {maxgrad0}} to
|
| 610 | 6x |
{.val {maxgrad}} after {number_of_loops} steps."
|
| 611 |
)) |
|
| 612 | 6x |
cli::cli_end(div_digit) |
| 613 |
} |
|
| 614 | 6x |
time_optimization <- Sys.time() - t0 |
| 615 | 6x |
cli::cli_inform(c("v" = "Finished optimization"))
|
| 616 | 6x |
FIMS::set_fixed(opt$par) |
| 617 | ||
| 618 | 6x |
time_sdreport <- NA |
| 619 | 6x |
if (get_sd) {
|
| 620 | 6x |
t2 <- Sys.time() |
| 621 | 6x |
sdreport <- TMB::sdreport(obj) |
| 622 | 6x |
cli::cli_inform(c("v" = "Finished sdreport"))
|
| 623 | 6x |
time_sdreport <- Sys.time() - t2 |
| 624 |
} else {
|
|
| 625 | ! |
sdreport <- list() |
| 626 | ! |
time_sdreport <- as.difftime(0, units = "secs") |
| 627 |
} |
|
| 628 | ||
| 629 | 6x |
timing <- c( |
| 630 | 6x |
time_optimization = time_optimization, |
| 631 | 6x |
time_sdreport = time_sdreport, |
| 632 | 6x |
time_total = Sys.time() - t0 |
| 633 |
) |
|
| 634 | 6x |
fit <- FIMSFit( |
| 635 | 6x |
input = input, |
| 636 | 6x |
obj = obj, |
| 637 | 6x |
opt = opt, |
| 638 | 6x |
sdreport = sdreport, |
| 639 | 6x |
timing = timing |
| 640 |
) |
|
| 641 | 6x |
print(fit) |
| 642 | 6x |
if (!is.null(filename)) {
|
| 643 | ! |
cli::cli_warn(c( |
| 644 | ! |
"i" = "Saving output to file is not yet implemented." |
| 645 |
)) |
|
| 646 |
# saveRDS(fit, file=file.path(input[["path"]], filename)) |
|
| 647 |
} |
|
| 648 | 6x |
return(fit) |
| 649 |
} |
|
| 650 | ||
| 651 |
# we create an as.list method for this new FIMSFit |
|
| 652 |
methods::setMethod("as.list", signature(x = "FIMSFit"), function(x) {
|
|
| 653 | 2x |
mapply( |
| 654 | 2x |
function(y) {
|
| 655 |
# apply as.list if the slot is again an user-defined object |
|
| 656 |
# therefore, as.list gets applied recursively |
|
| 657 | 20x |
if (inherits(slot(x, y), "FIMSFit")) {
|
| 658 | ! |
as.list(slot(x, y)) |
| 659 |
} else {
|
|
| 660 |
# otherwise just return the slot |
|
| 661 | 20x |
slot(x, y) |
| 662 |
} |
|
| 663 |
}, |
|
| 664 | 2x |
slotNames(class(x)), |
| 665 | 2x |
SIMPLIFY = FALSE |
| 666 |
) |
|
| 667 |
}) |
| 1 |
#' Validity checks for distributions |
|
| 2 |
#' |
|
| 3 |
#' This function checks the validity of arguments passed to functions that |
|
| 4 |
#' relate to distributions within the Fisheries Integrated Modeling System |
|
| 5 |
#' (FIMS). This function is designed to fail early only once, otherwise it goes |
|
| 6 |
#' through many checks before reporting the results in an attempt to give the |
|
| 7 |
#' user the most information possible. If it were to fail on every mistake, |
|
| 8 |
#' then the user might have to iterate through multiple changes to their input |
|
| 9 |
#' values. Sometimes, their mistakes might take quite a bit of time to make it |
|
| 10 |
#' to this function or worse they might be running things on the cloud and not |
|
| 11 |
#' have immediate access to the report. Therefore, we feel that providing the |
|
| 12 |
#' most information possible is the best way forward. |
|
| 13 |
#' |
|
| 14 |
#' @param args A named list of input arguments that must contain at least |
|
| 15 |
#' `family` and `sd`. `data_type` is only needed for some upstream functions. |
|
| 16 |
#' @seealso |
|
| 17 |
#' This function is used in the following functions: |
|
| 18 |
#' * [initialize_data_distribution()] |
|
| 19 |
#' * [initialize_process_distribution()] |
|
| 20 |
#' @noRd |
|
| 21 |
#' @return |
|
| 22 |
#' If successful, `TRUE` is invisibly returned. If unsuccessful, |
|
| 23 |
#' [cli::cli_abort()] is used to return the relevant error messages. |
|
| 24 |
check_distribution_validity <- function(args) {
|
|
| 25 |
# Separate objects from args |
|
| 26 | 83x |
family <- args[["family"]] |
| 27 | 83x |
sd <- args[["sd"]] |
| 28 |
# Optional argument data_type |
|
| 29 | 83x |
data_type <- args[["data_type"]] |
| 30 | 83x |
check_present <- purrr::map_vec(list("family" = family, "sd" = sd), is.null)
|
| 31 | ||
| 32 |
# Set up global rules |
|
| 33 |
# FIXME: Move this to a data item in the package so it can be used everywhere |
|
| 34 |
# Could do a call to all data objects in the package and get unique types that |
|
| 35 |
# are available |
|
| 36 | 83x |
data_type_names <- c("landings", "index", "agecomp", "lengthcomp")
|
| 37 | 83x |
if (is.null(data_type)) {
|
| 38 | 18x |
available_distributions <- c("lognormal", "gaussian")
|
| 39 |
} else {
|
|
| 40 | 65x |
available_distributions <- switch( |
| 41 | 65x |
EXPR = ifelse(grepl("comp", data_type), "composition", data_type),
|
| 42 | 65x |
"landings" = c("lognormal", "gaussian"),
|
| 43 | 65x |
"index" = c("lognormal", "gaussian"),
|
| 44 | 65x |
"composition" = c("multinomial"),
|
| 45 | 65x |
"unavailable data type" |
| 46 |
) |
|
| 47 |
} |
|
| 48 | 83x |
elements_of_sd <- c("value", "estimation_type")
|
| 49 | ||
| 50 |
# Start a bulleted list of errors and add to it in each if statement |
|
| 51 | 83x |
abort_bullets <- c( |
| 52 | 83x |
" " = "The following errors were found in the input argument {.var args}."
|
| 53 |
) |
|
| 54 | 83x |
if (any(check_present)) {
|
| 55 | 1x |
bad <- names(check_present[unlist(check_present)]) |
| 56 | 1x |
abort_bullets <- c( |
| 57 | 1x |
abort_bullets, |
| 58 | 1x |
"x" = "{.var {bad}} {cli::qty(length(bad))} {?is/are} missing from
|
| 59 | 1x |
{.var args}."
|
| 60 |
) |
|
| 61 |
# Abort early because not all of the necessary items were in args |
|
| 62 | 1x |
cli::cli_abort(abort_bullets) |
| 63 |
} |
|
| 64 | ||
| 65 |
# Checks related to the family class |
|
| 66 | 82x |
if (!inherits(family, "family")) {
|
| 67 | 1x |
abort_bullets <- c( |
| 68 | 1x |
abort_bullets, |
| 69 | 1x |
"x" = "The class of {.var family} is incorrect.",
|
| 70 | 1x |
"i" = "{.var family} should be an object of class {.var family},
|
| 71 | 1x |
e.g., `family = gaussian()`, instead of {class(family)}."
|
| 72 |
) |
|
| 73 |
} else {
|
|
| 74 |
if ( |
|
| 75 | 81x |
!(family[["family"]] %in% available_distributions) || |
| 76 | 81x |
"unavailable data type" %in% available_distributions |
| 77 |
) {
|
|
| 78 | 6x |
ifelse_type <- ifelse( |
| 79 | 6x |
is.null(data_type), |
| 80 | 6x |
"distribution", |
| 81 | 6x |
paste(data_type, "data") |
| 82 |
) |
|
| 83 | 6x |
abort_bullets <- c( |
| 84 | 6x |
abort_bullets, |
| 85 | 6x |
"x" = "FIMS currently does not allow the family to be |
| 86 | 6x |
{.code {family[['family']]}}.",
|
| 87 | 6x |
"i" = "The families available for this {ifelse_type} are
|
| 88 | 6x |
{.code {available_distributions}}."
|
| 89 |
) |
|
| 90 |
} |
|
| 91 |
} |
|
| 92 | ||
| 93 |
# Checks related to the type of data |
|
| 94 | 82x |
if (!is.null(data_type)) {
|
| 95 | 64x |
if (!(data_type %in% data_type_names)) {
|
| 96 | ! |
abort_bullets <- c( |
| 97 | ! |
abort_bullets, |
| 98 | ! |
"x" = "The specified {.var data_type} of {.var {data_type}} is not
|
| 99 | ! |
available.", |
| 100 | ! |
"i" = "Allowed values for {.var data_type} are
|
| 101 | ! |
{.code {data_type_names}}."
|
| 102 |
) |
|
| 103 |
} |
|
| 104 |
} |
|
| 105 | ||
| 106 |
# Checks related to standard deviation |
|
| 107 |
# Check if sd has both elements and if yes, then go onto the else statement |
|
| 108 |
# for major checks |
|
| 109 | 82x |
if (!all(elements_of_sd %in% names(sd))) {
|
| 110 | 2x |
abort_bullets <- c( |
| 111 | 2x |
abort_bullets, |
| 112 | 2x |
"x" = "{.var {elements_of_sd}} need to be present in sd.",
|
| 113 | 2x |
"i" = "Only {.code {names(sd)}} {cli::qty(length(sd))} {?is/are} present."
|
| 114 |
) |
|
| 115 |
} else {
|
|
| 116 | 80x |
if (!all(sd[["value"]] > 0, na.rm = TRUE)) {
|
| 117 | 1x |
abort_bullets <- c( |
| 118 | 1x |
abort_bullets, |
| 119 | 1x |
"x" = "Values passed to {.var sd} are out of bounds.",
|
| 120 | 1x |
"i" = "Values passed to {.var sd} {cli::qty(length(sd[['value']]))}
|
| 121 | 1x |
{?is/are} {.code {sd[['value']]}}.",
|
| 122 | 1x |
"i" = "All standard deviation (sd) values need to be positive." |
| 123 |
) |
|
| 124 |
} |
|
| 125 |
if ( |
|
| 126 | 80x |
length(sd[["estimation_type"]]) > 1 && |
| 127 | 80x |
length(sd[["value"]]) != length(sd[["estimation_type"]]) |
| 128 |
) {
|
|
| 129 | 2x |
sd_length <- length(sd[["value"]]) |
| 130 | 2x |
est_length <- length(sd[["estimation_type"]]) |
| 131 | 2x |
abort_bullets <- c( |
| 132 | 2x |
abort_bullets, |
| 133 | 2x |
"x" = "The sizes of {.var value} and {.var estimation_type} within {.var sd}
|
| 134 | 2x |
must match if more than one value is specified for the latter.", |
| 135 | 2x |
"i" = "The length of {.var sd[['value']]} is {.code {sd_length}}.",
|
| 136 | 2x |
"i" = "The length of {.var sd[['estimation_type']]} is
|
| 137 | 2x |
{.code {est_length}}."
|
| 138 |
) |
|
| 139 |
} |
|
| 140 |
} |
|
| 141 | ||
| 142 |
# Return error messages if more than just the default is present |
|
| 143 | 82x |
if (length(abort_bullets) == 1) {
|
| 144 | 70x |
invisible(TRUE) |
| 145 |
} else {
|
|
| 146 | 12x |
cli::cli_abort(abort_bullets) |
| 147 |
} |
|
| 148 |
} |
|
| 149 | ||
| 150 |
#' Return name of expected value |
|
| 151 |
#' |
|
| 152 |
#' The combination of data type, family, and link lead to a specific name for |
|
| 153 |
#' the expected value within the code base. This function looks at the |
|
| 154 |
#' combination of these three objects and specifies the appropriate string for |
|
| 155 |
#' its name going forward. |
|
| 156 |
#' @inheritParams initialize_data_distribution |
|
| 157 |
#' @noRd |
|
| 158 |
#' @return |
|
| 159 |
#' A string specifying the name of the expected value. |
|
| 160 |
#' |
|
| 161 |
get_expected_name <- function(family, data_type) {
|
|
| 162 |
# TODO: Think about if the name of the expected value should change based on |
|
| 163 |
# the link or if it should stay the same? Keeping track of different names in |
|
| 164 |
# the code base might be too complex for the output as well |
|
| 165 | 58x |
family_string <- family[["family"]] |
| 166 | 58x |
link_string <- family[["link"]] |
| 167 | 58x |
expected_name <- dplyr::case_when( |
| 168 | 58x |
data_type == "landings" && |
| 169 | 58x |
grepl("lognormal|gaussian", family_string) &&
|
| 170 | 58x |
link_string == "log" ~ "log_landings_expected", |
| 171 | 58x |
data_type == "landings" && |
| 172 | 58x |
grepl("lognormal|gaussian", family_string) &&
|
| 173 | 58x |
link_string == "identity" ~ "landings_expected", |
| 174 | 58x |
data_type == "index" && |
| 175 | 58x |
grepl("lognormal|gaussian", family_string) &&
|
| 176 | 58x |
link_string == "log" ~ "log_index_expected", |
| 177 | 58x |
data_type == "index" && |
| 178 | 58x |
grepl("lognormal|gaussian", family_string) &&
|
| 179 | 58x |
link_string == "identity" ~ "index_expected", |
| 180 | 58x |
grepl("agecomp", data_type) ~ "agecomp_proportion",
|
| 181 | 58x |
grepl("lengthcomp", data_type) ~ "lengthcomp_proportion",
|
| 182 |
) |
|
| 183 |
# Check combination of entries was okay and led to valid name |
|
| 184 | 58x |
if (is.na(expected_name)) {
|
| 185 | ! |
cli::cli_abort(c( |
| 186 | ! |
"x" = "The combination of data type, family, and link are incompatible in |
| 187 | ! |
some way.", |
| 188 | ! |
"i" = "{.var data_type} is {.var {data_type}}.",
|
| 189 | ! |
"i" = "The family is {.var {family_string}}.",
|
| 190 | ! |
"i" = "The link is {.var {link_string}}."
|
| 191 |
)) |
|
| 192 |
} |
|
| 193 | 58x |
return(expected_name) |
| 194 |
} |
|
| 195 | ||
| 196 |
#' Set up a new distribution for a data type or a process |
|
| 197 |
#' |
|
| 198 |
#' Use [methods::new()] to set up a distribution within an existing module with |
|
| 199 |
#' the necessary linkages between the two. For example, a fleet module will need |
|
| 200 |
#' a distributional assumption for parts of the data associated with it, which |
|
| 201 |
#' requires the use of `initialize_data_distribution()`, and a recruitment |
|
| 202 |
#' module, like the Beverton--Holt stock--recruit relationship, will need a |
|
| 203 |
#' distribution associated with the recruitment deviations, which requires |
|
| 204 |
#' `initialize_process_distribution()`. |
|
| 205 |
#' @param module An identifier to a C++ fleet module that is linked to the data |
|
| 206 |
#' of interest. |
|
| 207 |
#' @param family A description of the error distribution and link function to |
|
| 208 |
#' be used in the model. The argument takes a family class, e.g., |
|
| 209 |
#' `stats::gaussian(link = "identity")`. |
|
| 210 |
#' @param sd A list of length two. The first entry is named `"value"` and it |
|
| 211 |
#' stores the initial values (scalar or vector) for the relevant standard |
|
| 212 |
#' deviations. The default is `value = 1`. The second entry is named |
|
| 213 |
#' `"estimation_type"` and it stores a vector of booleans (default = "constant") is a |
|
| 214 |
#' string indicating whether or not standard deviation is estimated as a fixed effect |
|
| 215 |
#' or held constant. If `"value"` is a vector and `"estimation_type"` is a scalar, |
|
| 216 |
#' the single value specified `"estimation_type"` value will be repeated to match the length of |
|
| 217 |
#' `value`. Otherwise, the dimensions of the two must match. |
|
| 218 |
#' @param data_type A string specifying the type of data that the |
|
| 219 |
#' distribution will be fit to. Allowable types include |
|
| 220 |
#' `r toString(formals(initialize_data_distribution)[["data_type"]])` |
|
| 221 |
#' and the default is |
|
| 222 |
#' `r toString(formals(initialize_data_distribution)[["data_type"]][1])`. |
|
| 223 |
#' @param par A string specifying the parameter name the distribution applies |
|
| 224 |
#' to. Parameters must be members of the specified module. Use |
|
| 225 |
#' `methods::show(module)` to obtain names of parameters within the module. |
|
| 226 |
#' @param is_random_effect A boolean indicating whether or not the process is |
|
| 227 |
#' estimated as a random effect. |
|
| 228 |
#' @return |
|
| 229 |
#' A reference class. is returned. Use [methods::show()] to view the various |
|
| 230 |
#' Rcpp class fields, methods, and documentation. |
|
| 231 |
#' @keywords distribution |
|
| 232 |
#' @export |
|
| 233 |
#' @examples |
|
| 234 |
#' \dontrun{
|
|
| 235 |
#' # Set up a new data distribution |
|
| 236 |
#' n_years <- 30 |
|
| 237 |
#' # Create a new fleet module |
|
| 238 |
#' fleet <- methods::new(Fleet) |
|
| 239 |
#' # Create a distribution for the fleet module |
|
| 240 |
#' fleet_distribution <- initialize_data_distribution( |
|
| 241 |
#' module = fishing_fleet, |
|
| 242 |
#' family = lognormal(link = "log"), |
|
| 243 |
#' sd = list( |
|
| 244 |
#' value = rep(sqrt(log(0.01^2 + 1)), n_years), |
|
| 245 |
#' estimation_type = rep("constant", n_years) # Could also be a single "constant"
|
|
| 246 |
#' ), |
|
| 247 |
#' data_type = "index" |
|
| 248 |
#' ) |
|
| 249 |
#' |
|
| 250 |
#' # Set up a new process distribution |
|
| 251 |
#' # Create a new recruitment module |
|
| 252 |
#' recruitment <- methods::new(BevertonHoltRecruitment) |
|
| 253 |
#' # view parameter names of the recruitment module |
|
| 254 |
#' methods::show(BevertonHoltRecruitment) |
|
| 255 |
#' # Create a distribution for the recruitment module |
|
| 256 |
#' recruitment_distribution <- initialize_process_distribution( |
|
| 257 |
#' module = recruitment, |
|
| 258 |
#' par = "log_devs", |
|
| 259 |
#' family = gaussian(), |
|
| 260 |
#' sd = list(value = 0.4, estimation_type = "constant"), |
|
| 261 |
#' is_random_effect = FALSE |
|
| 262 |
#' ) |
|
| 263 |
#' } |
|
| 264 |
initialize_data_distribution <- function( |
|
| 265 |
module, |
|
| 266 |
family = NULL, |
|
| 267 |
# Create a tibble with value and estimation_type column for sd |
|
| 268 |
sd = tibble::tibble( |
|
| 269 |
value = 1, |
|
| 270 |
estimation_type = "constant" |
|
| 271 |
), |
|
| 272 |
# FIXME: Move this argument to second to match where par is in |
|
| 273 |
# initialize_process_distribution |
|
| 274 |
data_type = c("landings", "index", "agecomp", "lengthcomp")
|
|
| 275 |
) {
|
|
| 276 | 66x |
data_type <- rlang::arg_match(data_type) |
| 277 |
# FIXME: Make the available families a data object |
|
| 278 |
# Could also make the matrix of distributions available per type as a |
|
| 279 |
# data frame where the check could use the stored object. |
|
| 280 | ||
| 281 |
# validity check on user input |
|
| 282 | 65x |
args <- list( |
| 283 | 65x |
family = family, |
| 284 | 65x |
sd = sd, |
| 285 | 65x |
data_type = data_type |
| 286 |
) |
|
| 287 | 65x |
check_distribution_validity(args) |
| 288 | ||
| 289 |
# assign name of observed data based on data_type |
|
| 290 | 58x |
obs_id_name <- glue::glue("observed_{data_type}_data_id")
|
| 291 | ||
| 292 |
# Set up distribution based on `family` argument` |
|
| 293 | 58x |
if (family[["family"]] == "lognormal") {
|
| 294 |
# create new Rcpp module |
|
| 295 | 23x |
new_module <- methods::new(DlnormDistribution) |
| 296 | ||
| 297 |
# populate logged standard deviation parameter with log of input |
|
| 298 |
# Using resize() and then assigning value to each element of log_sd directly |
|
| 299 |
# is correct, as creating a new ParameterVector for log_sd here would |
|
| 300 |
# trigger an error in integration tests with wrappers. |
|
| 301 | 23x |
new_module$log_sd$resize(length(sd[["value"]])) |
| 302 | ||
| 303 | 23x |
purrr::walk( |
| 304 | 23x |
seq_along(sd[["value"]]), |
| 305 | 23x |
\(x) new_module[["log_sd"]][x][["value"]] <- log(sd[["value"]][x]) |
| 306 |
) |
|
| 307 | ||
| 308 | 23x |
purrr::walk( |
| 309 | 23x |
seq_along(sd[["estimation_type"]]), |
| 310 | 23x |
\(x) new_module[["log_sd"]][x][["estimation_type"]]$set(sd[["estimation_type"]][x]) |
| 311 |
) |
|
| 312 |
} |
|
| 313 | ||
| 314 | 58x |
if (family[["family"]] == "gaussian") {
|
| 315 |
# create new Rcpp module |
|
| 316 | 1x |
new_module <- methods::new(DnormDistribution) |
| 317 | ||
| 318 |
# populate logged standard deviation parameter with log of input |
|
| 319 | 1x |
purrr::walk( |
| 320 | 1x |
seq_along(sd[["value"]]), |
| 321 | 1x |
\(x) new_module[["log_sd"]][x][["value"]] <- log(sd[["value"]][x]) |
| 322 |
) |
|
| 323 | ||
| 324 | 1x |
purrr::walk( |
| 325 | 1x |
seq_along(sd[["estimation_type"]]), |
| 326 | 1x |
\(x) new_module[["log_sd"]][x][["estimation_type"]]$set(sd[["estimation_type"]][x]) |
| 327 |
) |
|
| 328 |
} |
|
| 329 | ||
| 330 | 58x |
if (family[["family"]] == "multinomial") {
|
| 331 |
# create new Rcpp module |
|
| 332 | 34x |
new_module <- methods::new(DmultinomDistribution) |
| 333 |
} |
|
| 334 | ||
| 335 |
# setup link to observed data |
|
| 336 | 58x |
if (data_type == "landings") {
|
| 337 | 11x |
new_module$set_observed_data(module$GetObservedLandingsDataID()) |
| 338 |
} |
|
| 339 | 58x |
if (data_type == "index") {
|
| 340 | 13x |
new_module$set_observed_data(module$GetObservedIndexDataID()) |
| 341 |
} |
|
| 342 | 58x |
if (data_type == "agecomp") {
|
| 343 | 18x |
new_module$set_observed_data(module$GetObservedAgeCompDataID()) |
| 344 |
} |
|
| 345 | 58x |
if (data_type == "lengthcomp") {
|
| 346 | 16x |
new_module$set_observed_data(module$GetObservedLengthCompDataID()) |
| 347 |
} |
|
| 348 | ||
| 349 |
# set name of expected values |
|
| 350 | 58x |
expected <- get_expected_name(family, data_type) |
| 351 |
# setup link to expected values |
|
| 352 | 58x |
new_module$set_distribution_links("data", module$field(expected)$get_id())
|
| 353 | ||
| 354 | 58x |
return(new_module) |
| 355 |
} |
|
| 356 | ||
| 357 |
#' @rdname initialize_data_distribution |
|
| 358 |
#' @keywords distribution |
|
| 359 |
#' @export |
|
| 360 |
initialize_process_distribution <- function( |
|
| 361 |
module, |
|
| 362 |
par, |
|
| 363 |
family = NULL, |
|
| 364 |
sd = tibble::tibble( |
|
| 365 |
value = 1, |
|
| 366 |
estimation_type = "constant" |
|
| 367 |
), |
|
| 368 |
is_random_effect = FALSE |
|
| 369 |
) {
|
|
| 370 |
# validity check on user input |
|
| 371 | 18x |
args <- list(family = family, sd = sd) |
| 372 | 18x |
check_distribution_validity(args) |
| 373 | ||
| 374 | 12x |
expected <- switch(paste0(par, "_", class(module)), |
| 375 | 12x |
"log_devs_Rcpp_BevertonHoltRecruitment" = NULL, |
| 376 | 12x |
"log_r_Rcpp_BevertonHoltRecruitment" = "log_expected_recruitment" |
| 377 |
) |
|
| 378 | ||
| 379 |
# Set up distribution based on `family` argument` |
|
| 380 | 12x |
if (family[["family"]] == "lognormal") {
|
| 381 |
# create new Rcpp module |
|
| 382 | ! |
new_module <- methods::new(DlnormDistribution) |
| 383 | ||
| 384 |
# populate logged standard deviation parameter with log of input |
|
| 385 | ! |
new_module$log_sd$resize(length(sd[["value"]])) |
| 386 | ! |
purrr::walk( |
| 387 | ! |
seq_along(sd[["value"]]), |
| 388 | ! |
\(x) new_module[["log_sd"]][x][["value"]] <- log(sd[["value"]][x]) |
| 389 |
) |
|
| 390 | ||
| 391 |
# setup whether or not sd parameter is estimated |
|
| 392 | ! |
if (length(sd[["value"]]) > 1 && length(sd[["estimation_type"]]) == 1) {
|
| 393 | ! |
if (sd[["estimation_type"]] == "constant") {
|
| 394 | ! |
new_module$log_sd$set_all_estimable(FALSE) |
| 395 |
} else {
|
|
| 396 | ! |
new_module$log_sd$set_all_estimable(TRUE) |
| 397 |
} |
|
| 398 |
} else {
|
|
| 399 | ! |
for (i in seq_along(sd[["estimation_type"]])) {
|
| 400 | ! |
new_module$log_sd[i]$estimation_type$set(sd[["estimation_type"]][i]) |
| 401 |
} |
|
| 402 |
} |
|
| 403 |
} |
|
| 404 | ||
| 405 | 12x |
if (family[["family"]] == "gaussian") {
|
| 406 |
# create new Rcpp module |
|
| 407 | 12x |
new_module <- methods::new(DnormDistribution) |
| 408 | ||
| 409 |
# populate logged standard deviation parameter with log of input |
|
| 410 | 12x |
new_module$log_sd$resize(length(sd[["value"]])) |
| 411 | 12x |
for (i in seq_along(sd[["value"]])) {
|
| 412 | 12x |
new_module$log_sd[i]$value <- log(sd[["value"]][i]) |
| 413 |
} |
|
| 414 | ||
| 415 |
# setup whether or not sd parameter is estimated |
|
| 416 | 12x |
if (length(sd[["value"]]) > 1 && length(sd[["estimation_type"]]) == 1) {
|
| 417 | ! |
if (sd[["estimation_type"]] == "constant") {
|
| 418 | ! |
new_module$log_sd$set_all_estimable(FALSE) |
| 419 |
} else {
|
|
| 420 | ! |
new_module$log_sd$set_all_estimable(TRUE) |
| 421 |
} |
|
| 422 |
} else {
|
|
| 423 | 12x |
for (i in seq_along(sd[["estimation_type"]])) {
|
| 424 | 12x |
new_module$log_sd[i]$estimation_type$set(sd[["estimation_type"]][i]) |
| 425 |
} |
|
| 426 |
} |
|
| 427 |
} |
|
| 428 | ||
| 429 | ||
| 430 | 12x |
n_dim <- length(module$field(par)) |
| 431 | ||
| 432 |
# create new Rcpp modules |
|
| 433 | 12x |
new_module$x$resize(n_dim) |
| 434 | 12x |
new_module$expected_values$resize(n_dim) |
| 435 | ||
| 436 |
# initialize values with 0 |
|
| 437 |
# these are overwritten in the code later by user input |
|
| 438 | 12x |
for (i in 1:n_dim) {
|
| 439 | 348x |
new_module$x[i]$value <- 0 |
| 440 | 348x |
new_module$expected_values[i]$value <- 0 |
| 441 |
} |
|
| 442 | ||
| 443 |
# setup links to parameter |
|
| 444 | 12x |
if (is.null(expected)) {
|
| 445 | 12x |
new_module$set_distribution_links( |
| 446 | 12x |
"random_effects", |
| 447 | 12x |
module$field(par)$get_id() |
| 448 |
) |
|
| 449 |
} else {
|
|
| 450 | ! |
new_module$set_distribution_links( |
| 451 | ! |
"random_effects", |
| 452 | ! |
c( |
| 453 | ! |
module$field(par)$get_id(), |
| 454 | ! |
module$field(expected)$get_id() |
| 455 |
) |
|
| 456 |
) |
|
| 457 |
} |
|
| 458 | ||
| 459 | 12x |
return(new_module) |
| 460 |
} |
|
| 461 | ||
| 462 |
#' @rdname initialize_data_distribution |
|
| 463 |
#' @keywords distribution |
|
| 464 |
#' @export |
|
| 465 |
initialize_process_structure <- function(module, par) {
|
|
| 466 | 11x |
new_process_module <- switch(paste0(par, "_", class(module)), |
| 467 | 11x |
"log_devs_Rcpp_BevertonHoltRecruitment" = new(LogDevsRecruitmentProcess), |
| 468 | 11x |
"log_r_Rcpp_BevertonHoltRecruitment" = new(LogRRecruitmentProcess) |
| 469 |
) |
|
| 470 | ||
| 471 | 11x |
module$SetRecruitmentProcessID(new_process_module$get_id()) |
| 472 | ||
| 473 | 11x |
return(new_process_module) |
| 474 |
} |
|
| 475 | ||
| 476 |
#' Distributions not available in the stats package |
|
| 477 |
#' |
|
| 478 |
#' Family objects provide a convenient way to specify the details of the models |
|
| 479 |
#' used by functions such as [stats::glm()]. These functions within this |
|
| 480 |
#' package are not available within the stats package but are designed in a |
|
| 481 |
#' similar manner. |
|
| 482 |
#' |
|
| 483 |
#' @param link A string specifying the model link function. For example, |
|
| 484 |
#' `"identity"` or `"log"` are appropriate names for the [stats::gaussian()] |
|
| 485 |
#' distribution. `"log"` and `"logit"` are the defaults for the lognormal and |
|
| 486 |
#' the multinomial, respectively. |
|
| 487 |
#' @return |
|
| 488 |
#' An object of class `family` (which has a concise print method). This |
|
| 489 |
#' particular family has a truncated length compared to other distributions in |
|
| 490 |
#' [stats::family()]. |
|
| 491 |
#' \item{family}{character: the family name.}
|
|
| 492 |
#' \item{link}{character: the link name.}
|
|
| 493 |
#' |
|
| 494 |
#' @seealso |
|
| 495 |
#' * [stats::family()] |
|
| 496 |
#' * [stats::gaussian()] |
|
| 497 |
#' * [stats::glm()] |
|
| 498 |
#' * [stats::power()] |
|
| 499 |
#' * [stats::make.link()] |
|
| 500 |
#' @keywords distribution |
|
| 501 |
#' @export |
|
| 502 |
#' @examples |
|
| 503 |
#' a_family <- multinomial() |
|
| 504 |
#' a_family[["family"]] |
|
| 505 |
#' a_family[["link"]] |
|
| 506 |
lognormal <- function(link = "log") {
|
|
| 507 | 24x |
family_class <- c( |
| 508 | 24x |
list(family = "lognormal", link = link), |
| 509 | 24x |
stats::make.link(link) |
| 510 |
) |
|
| 511 | 24x |
class(family_class) <- "family" |
| 512 | 24x |
return(family_class) |
| 513 |
} |
|
| 514 | ||
| 515 |
#' @rdname lognormal |
|
| 516 |
#' @keywords distribution |
|
| 517 |
#' @export |
|
| 518 |
multinomial <- function(link = "logit") {
|
|
| 519 | 39x |
family_class <- c( |
| 520 | 39x |
list(family = "multinomial", link = link), |
| 521 | 39x |
stats::make.link(link) |
| 522 |
) |
|
| 523 | 39x |
class(family_class) <- "family" |
| 524 | 39x |
return(family_class) |
| 525 |
} |
| 1 |
#' Create tests/testthat/test-*.R test file |
|
| 2 |
#' |
|
| 3 |
#' This helper function creates a new test file for testthat using a template |
|
| 4 |
#' available within the templates folder of this package. The test file is |
|
| 5 |
#' created under the "tests/testthat" directory with a name based on the input |
|
| 6 |
#' argument `name`. If the test file already exists, an error message is |
|
| 7 |
#' returned and no changes are made. |
|
| 8 |
#' |
|
| 9 |
#' @details |
|
| 10 |
#' There are three minimum testing criteria for FIMS, which should be validated |
|
| 11 |
#' for every R function within the package. The template file sets up a |
|
| 12 |
#' section for each of the three following test criteria: |
|
| 13 |
#' |
|
| 14 |
#' 1. Input and output correctness (IO correctness): ensure that the function |
|
| 15 |
#' behaves as expected with correct inputs and returns the expected outputs. |
|
| 16 |
#' 1. Edge-case handling (Edge handling): validate the function's performance |
|
| 17 |
#' with invalid inputs and unusual scenarios. |
|
| 18 |
#' 1. Built-in errors and warnings (Error handling): confirm that appropriate |
|
| 19 |
#' error and warning messages are triggered under exceptional conditions. |
|
| 20 |
#' |
|
| 21 |
#' Above every expectation within the test file there should be a call to |
|
| 22 |
#' `#' @description` that fits on one line describing the test. The information |
|
| 23 |
#' will be used in the bookdown report of the testing results. |
|
| 24 |
#' |
|
| 25 |
#' @param name A character string providing the name of the R function that you |
|
| 26 |
#' want to test. The name will be used to create the file name, i.e., |
|
| 27 |
#' `tests/testthat/test-{name}.R`. If `name` is not specified, the function
|
|
| 28 |
#' will not be able to create a file name and an error will be returned. |
|
| 29 |
#' |
|
| 30 |
#' @return |
|
| 31 |
#' If successful, this function invisibly returns `TRUE` to allow for the |
|
| 32 |
#' chaining of commands. If the function is unsuccessful, an error message is |
|
| 33 |
#' returned. |
|
| 34 |
#' |
|
| 35 |
#' Two messages are also returned from the usethis package, which is used by |
|
| 36 |
#' this function. The first states where the FIMS project is on your computer. |
|
| 37 |
#' The second states the file path of the newly created file. The file will not |
|
| 38 |
#' be automatically opened. |
|
| 39 |
#' |
|
| 40 |
#' @examples |
|
| 41 |
#' # Create a new test file named "test-new_function" for `new_function()` |
|
| 42 |
#' \dontrun{
|
|
| 43 |
#' FIMS:::use_testthat_template("new_function")
|
|
| 44 |
#' } |
|
| 45 |
#' |
|
| 46 |
#' @keywords developer |
|
| 47 |
use_testthat_template <- function(name) {
|
|
| 48 |
# TODO: add the ability to add a function to a file that already exists |
|
| 49 |
# TODO: add the ability to also pass the arguments for the function or find |
|
| 50 |
# them within the code base and ensure that the template includes the |
|
| 51 |
# necessary structure for each input argument |
|
| 52 | ! |
path <- file.path("tests", "testthat", paste0("test-", name, ".R"))
|
| 53 | ! |
if (!file.exists(path)) {
|
| 54 | ! |
function_name <- gsub("-", "_", name)
|
| 55 | ! |
usethis::use_template( |
| 56 | ! |
template = "testthat_template.R", |
| 57 | ! |
save_as = path, |
| 58 | ! |
data = list(function_name = function_name), |
| 59 | ! |
package = "FIMS" |
| 60 |
) |
|
| 61 |
} else {
|
|
| 62 | ! |
cli::cli_abort("{path} already exists.")
|
| 63 |
} |
|
| 64 | ! |
invisible(TRUE) |
| 65 |
} |
| 1 |
#' Create tests/gtest/test_*.cpp test file and register it in CMakeLists.txt |
|
| 2 |
#' |
|
| 3 |
#' This helper function generates a GoogleTest (gtest) C++ template file for a |
|
| 4 |
#' given function and appends lines to `CMakeLists.txt` to register the test. |
|
| 5 |
#' |
|
| 6 |
#' @param name A string representing the combined name for the C++ test file |
|
| 7 |
#' and CMake executable target. It must follow the format |
|
| 8 |
#' `FileName_ClassName_FunctionName`, where |
|
| 9 |
#' - `FileName` is the C++ source file name (e.g., "Logistic") |
|
| 10 |
#' - `ClassName` is the C++ class name (e.g., "LogisticSelectivity") |
|
| 11 |
#' - `FunctionName` is the C++ function name (e.g., "Evaluate") |
|
| 12 |
#' and use underscores to separate each component. For example: |
|
| 13 |
#' `Logistic_LogisticSelectivity_Evaluate`. |
|
| 14 |
#' |
|
| 15 |
#' If the function is not a member of a class, use a placeholder for |
|
| 16 |
#' `ClassName`. For example: `FIMSMath_ClassName_Logistic`. |
|
| 17 |
#' |
|
| 18 |
#' The default is `FileName_ClassName_FunctionName`. |
|
| 19 |
#' |
|
| 20 |
#' @return |
|
| 21 |
#' If successful, this function invisibly returns `TRUE` to allow for the |
|
| 22 |
#' chaining of commands. If the function is unsuccessful, an error message is |
|
| 23 |
#' returned. |
|
| 24 |
#' |
|
| 25 |
#' Three messages are also returned from the usethis package, which is used by |
|
| 26 |
#' this function. The first states where the FIMS project is on your computer. |
|
| 27 |
#' The second states the file path of the newly created file. The file will not |
|
| 28 |
#' be automatically opened. The third states the test has been registered in |
|
| 29 |
#' `tests/gtest/CMakeLists.txt`. |
|
| 30 |
#' |
|
| 31 |
#' @examples |
|
| 32 |
#' \dontrun{
|
|
| 33 |
#' # Create a new test file named |
|
| 34 |
#' # "test_Logistic_LogisticSelectivity_Evaluate.cpp" for |
|
| 35 |
#' # `LogisticSelectivity::evaluate()` in |
|
| 36 |
#' # `inst/include/population_dynamics/selectivity/functors/logistic.hpp`. |
|
| 37 |
#' |
|
| 38 |
#' FIMS:::use_gtest_template(name = "Logistic_LogisticSelectivity_Evaluate") |
|
| 39 |
#' } |
|
| 40 |
#' |
|
| 41 |
#' @keywords developer |
|
| 42 |
use_gtest_template <- function(name = "FileName_ClassName_FunctionName") {
|
|
| 43 | ! |
cmakelist_path <- file.path("tests", "gtest", "CMakeLists.txt")
|
| 44 |
# Check if the CMakeLists.txt file exists |
|
| 45 | ! |
if (!file.exists(cmakelist_path)) {
|
| 46 | ! |
cli::cli_abort( |
| 47 | ! |
c("{.file {cmakelist_path}} does not exist.",
|
| 48 | ! |
"i" = "Please ensure that the CMakeLists.txt file is present in the |
| 49 | ! |
{.file tests/gtest} directory."
|
| 50 |
) |
|
| 51 |
) |
|
| 52 |
} |
|
| 53 | ||
| 54 |
# TODO: add the ability to add a function to a file that already exists |
|
| 55 |
# TODO: add the ability to also pass the arguments for the function or find |
|
| 56 |
# them within the code base and ensure that the template includes the |
|
| 57 |
# necessary structure for each input argument |
|
| 58 |
# TODO: Change the paste calls to use glue::glue() to increase readability |
|
| 59 | ||
| 60 |
# Validate the name format |
|
| 61 | ! |
name_parts_list <- strsplit(x = name, split = "_")[[1]] |
| 62 | ! |
if (length(name_parts_list) != 3) {
|
| 63 | ! |
cli::cli_abort( |
| 64 | ! |
c("Invalid {.var name} format.",
|
| 65 | ! |
"i" = "Expected format: {.val FileName_ClassName_FunctionName}.",
|
| 66 | ! |
"x" = "Received name: {.val {name}}."
|
| 67 |
) |
|
| 68 |
) |
|
| 69 |
} |
|
| 70 |
# Extract parts from the name |
|
| 71 | ! |
file_name <- name_parts_list[[1]][1] |
| 72 | ! |
class_name <- name_parts_list[[1]][2] |
| 73 | ! |
function_name <- name_parts_list[[1]][3] |
| 74 | ||
| 75 |
# Create the test file |
|
| 76 | ! |
path <- file.path("tests", "gtest", paste0("test_", name, ".cpp"))
|
| 77 | ! |
if (!file.exists(path)) {
|
| 78 | ! |
usethis::use_template( |
| 79 | ! |
template = "gtest_template.cpp", |
| 80 | ! |
save_as = path, |
| 81 | ! |
data = list( |
| 82 | ! |
class_name = class_name, |
| 83 | ! |
function_name = function_name |
| 84 |
), |
|
| 85 | ! |
package = "FIMS" |
| 86 |
) |
|
| 87 |
} else {
|
|
| 88 | ! |
cli::cli_abort("{.file {path}} already exists.")
|
| 89 |
} |
|
| 90 | ||
| 91 |
# Register the test in tests/gtest/CMakeLists.txt |
|
| 92 |
# Open in append mode |
|
| 93 | ! |
CON <- file(cmakelist_path, "a") |
| 94 | ! |
on.exit(close(CON), add = TRUE) |
| 95 | ! |
writeLines( |
| 96 | ! |
c( |
| 97 | ! |
paste0("\n\n# test_", name, ".cpp"),
|
| 98 | ! |
paste0("add_executable(", name),
|
| 99 | ! |
paste0(" test_", name, ".cpp"),
|
| 100 | ! |
paste0(")\n"),
|
| 101 | ! |
paste0("target_link_libraries(", name),
|
| 102 | ! |
paste0(" gtest_main"),
|
| 103 | ! |
paste0(" fims_test"),
|
| 104 | ! |
paste0(")\n"),
|
| 105 | ! |
paste0("gtest_discover_tests(", name, ")")
|
| 106 |
), |
|
| 107 | ! |
CON |
| 108 |
) |
|
| 109 | ! |
cli::cli_alert_success( |
| 110 | ! |
"Registering test {.val {name}} in {.file {cmakelist_path}}."
|
| 111 |
) |
|
| 112 | ||
| 113 | ! |
invisible(TRUE) |
| 114 |
} |
| 1 |
# This file contains many functions to reshape output from get_output() |
|
| 2 |
# To remove the NOTE `no visible binding for global variable` |
|
| 3 |
utils::globalVariables(c( |
|
| 4 |
"module_name", "module_id", "module_type", |
|
| 5 |
"parameter_min", "parameter_max", "label", "label_splits" |
|
| 6 |
)) |
|
| 7 | ||
| 8 |
#' Reshape JSON estimates |
|
| 9 |
#' |
|
| 10 |
#' @description |
|
| 11 |
#' This function processes the finalized FIMS JSON output and reshapes the |
|
| 12 |
#' parameter estimates into a structured tibble for easier analysis and |
|
| 13 |
#' manipulation. |
|
| 14 |
#' |
|
| 15 |
#' @param model_output A JSON object containing the finalized FIMS output as |
|
| 16 |
#' returned from `get_output()`, which is an internal function to each model |
|
| 17 |
#' family. |
|
| 18 |
#' @return A tibble containing the reshaped parameter estimates. |
|
| 19 |
reshape_json_estimates <- function(model_output) {
|
|
| 20 | 32x |
json_list <- jsonlite::fromJSON(model_output, simplifyVector = FALSE) |
| 21 | 32x |
read_list <- purrr::map( |
| 22 | 32x |
json_list[!names(json_list) %in% c( |
| 23 | 32x |
"name", "type", "estimation_framework", "id", "objective_function_value", |
| 24 | 32x |
"max_gradient_component", "gradient", |
| 25 | 32x |
"population_ids", "fleet_ids", "log" |
| 26 |
)], |
|
| 27 | 32x |
\(x) tidyr::unnest_wider(tibble::tibble(json = x), json) |
| 28 |
) |
|
| 29 | ||
| 30 |
# Process the module parameters |
|
| 31 | 32x |
module_information <- purrr::map_df( |
| 32 | 32x |
read_list[ |
| 33 | 32x |
!names(read_list) %in% |
| 34 | 32x |
c( |
| 35 | 32x |
"name", "type", "estimation_framework", "id", |
| 36 | 32x |
"objective_function_value", "populations", "fleets", "data", |
| 37 | 32x |
"density_components", "population_ids", "fleet_ids" |
| 38 |
) |
|
| 39 |
], |
|
| 40 | 32x |
.f = \(y) dplyr::mutate( |
| 41 | 32x |
y, |
| 42 | 32x |
parameters = purrr::map( |
| 43 | 32x |
parameters, |
| 44 | 32x |
\(x) purrr::map_df(x, dimension_folded_to_tibble) |
| 45 |
) |
|
| 46 |
) |
|
| 47 |
) |> |
|
| 48 | 32x |
tidyr::unnest(parameters) |
| 49 | ||
| 50 |
# Process the fleet-level information |
|
| 51 | 32x |
fleet_density_data <- read_list[["fleets"]] |> |
| 52 | 32x |
dplyr::select(module_id, data_ids) |> |
| 53 | 32x |
dplyr::mutate( |
| 54 | 32x |
data_ids = purrr::map( |
| 55 | 32x |
data_ids, |
| 56 | 32x |
\(y) tibble::enframe(unlist(y), name = "data_type", value = "data_id") |
| 57 |
) |
|
| 58 |
) |> |
|
| 59 | 32x |
tidyr::unnest(data_ids) |> |
| 60 | 32x |
dplyr::filter(data_id != -999) |> |
| 61 | 32x |
dplyr::mutate( |
| 62 | 32x |
name = paste(data_type, "expected", sep = "_") |
| 63 |
) |> |
|
| 64 | 32x |
dplyr::left_join( |
| 65 | 32x |
y = read_list[["density_components"]] |> |
| 66 | 32x |
dplyr::filter( |
| 67 | 32x |
observed_data_id != -999 |
| 68 |
) |> |
|
| 69 | 32x |
dplyr::rename(distribution = "module_type") |> |
| 70 | 32x |
dplyr::select(-dplyr::starts_with("module")),
|
| 71 | 32x |
by = c("data_id" = "observed_data_id")
|
| 72 |
) |> |
|
| 73 | 32x |
dplyr::mutate( |
| 74 | 32x |
density_component = purrr::map(density_component, density_to_tibble) |
| 75 |
) |> |
|
| 76 | 32x |
tidyr::unnest(density_component) |> |
| 77 | 32x |
dplyr::select(-dplyr::starts_with("data_")) |>
|
| 78 | 32x |
dplyr::group_by(module_id, name) |> |
| 79 | 32x |
dplyr::mutate(join_by = dplyr::row_number()) |> |
| 80 | 32x |
dplyr::ungroup() |
| 81 | ||
| 82 | 32x |
fleet_information <- read_list[["fleets"]] |> |
| 83 | 32x |
tidyr::pivot_longer( |
| 84 | 32x |
cols = c(parameters, derived_quantities), |
| 85 | 32x |
names_to = "delete_me", |
| 86 | 32x |
values_to = "parameters" |
| 87 |
) |> |
|
| 88 | 32x |
dplyr::select(-delete_me, -data_ids) |> |
| 89 |
# Remove column ids that are not currently needed |
|
| 90 | 32x |
dplyr::select(-dplyr::matches("^n.+s$")) |>
|
| 91 | 32x |
dplyr::mutate( |
| 92 | 32x |
parameters = purrr::map( |
| 93 | 32x |
parameters, |
| 94 | 32x |
\(x) purrr::map_df(x, dimension_folded_to_tibble) |
| 95 |
) |
|
| 96 |
) |> |
|
| 97 | 32x |
tidyr::unnest(parameters) |> |
| 98 | 32x |
dplyr::group_by(module_id, name) |> |
| 99 | 32x |
dplyr::mutate(join_by = dplyr::row_number()) |> |
| 100 | 32x |
dplyr::ungroup() |> |
| 101 | 32x |
dplyr::left_join( |
| 102 | 32x |
fleet_density_data, |
| 103 | 32x |
by = c("module_id", "name", "join_by"),
|
| 104 | 32x |
suffix = c("", "_density")
|
| 105 |
) |> |
|
| 106 | 32x |
dplyr::select(-join_by) |
| 107 | ||
| 108 |
# Process the data components |
|
| 109 |
# TODO: Data component needs actual uncertainty instead of 0 |
|
| 110 | 32x |
data_information <- read_list[["data"]] |> |
| 111 | 32x |
dplyr::mutate( |
| 112 | 32x |
dimensionality = purrr::map(dimensionality, \(x) dimensions_to_tibble(x)) |
| 113 |
) |> |
|
| 114 | 32x |
tidyr::unnest(c(dimensionality, value, uncertainty)) |> |
| 115 | 32x |
dplyr::mutate(value = unlist(value), uncertainty = unlist(uncertainty)) |
| 116 | ||
| 117 |
# Process the density components |
|
| 118 |
# This is done above for fleet information but we will need to do it for |
|
| 119 |
# parameter-level information once we have a link to the parameter id |
|
| 120 | 32x |
density_information <- read_list[["density_components"]] |> |
| 121 | 32x |
dplyr::mutate( |
| 122 | 32x |
density_component = purrr::map(density_component, density_to_tibble) |
| 123 |
) |> |
|
| 124 | 32x |
tidyr::unnest(density_component) |
| 125 | ||
| 126 |
# Process the population data |
|
| 127 | 32x |
population_information <- read_list[["populations"]] |> |
| 128 | 32x |
tidyr::pivot_longer( |
| 129 | 32x |
cols = c(parameters, derived_quantities), |
| 130 | 32x |
names_to = "delete_me", |
| 131 | 32x |
values_to = "parameters" |
| 132 |
) |> |
|
| 133 |
# TODO: Think about these ids when we have more than one population |
|
| 134 | 32x |
dplyr::select(-delete_me, -dplyr::ends_with("_id"), -population) |>
|
| 135 | 32x |
dplyr::mutate( |
| 136 | 32x |
parameters = purrr::map( |
| 137 | 32x |
parameters, |
| 138 | 32x |
\(x) purrr::map_df(x, dimension_folded_to_tibble) |
| 139 |
) |
|
| 140 |
) |> |
|
| 141 | 32x |
tidyr::unnest(parameters) |
| 142 | ||
| 143 |
# TODO: Bring in TMB estimates |
|
| 144 |
# TODO: Change some column names |
|
| 145 |
# Bring everything together |
|
| 146 | 32x |
out <- dplyr::bind_rows( |
| 147 |
# density_information, |
|
| 148 | 32x |
fleet_information, |
| 149 | 32x |
module_information, |
| 150 | 32x |
population_information |
| 151 |
) |> |
|
| 152 | 32x |
dplyr::select( |
| 153 | 32x |
module_name, module_id, module_type, |
| 154 | 32x |
"label" = name, |
| 155 | 32x |
type, type_id, "parameter_id" = id, |
| 156 | 32x |
fleet, dplyr::ends_with("_i"),
|
| 157 | 32x |
"input" = value, estimated = "estimated_value", "expected" = expected_values, |
| 158 | 32x |
"observed" = observed_values, uncertainty, estimation_type, |
| 159 | 32x |
distribution, input_type, lpdf = "lpdf_value", likelihood, |
| 160 | 32x |
dplyr::everything() |
| 161 |
) |
|
| 162 |
} |
|
| 163 | ||
| 164 |
#' Reshape TMB estimates |
|
| 165 |
#' |
|
| 166 |
#' @description |
|
| 167 |
#' This function processes the TMB std and reshapes them into a structured |
|
| 168 |
#' tibble for easier analysis and manipulation. |
|
| 169 |
#' |
|
| 170 |
#' @param obj An object returned from [TMB::MakeADFun()]. |
|
| 171 |
#' @param sdreport An object of the `sdreport` class as returned from |
|
| 172 |
#' [TMB::sdreport()]. |
|
| 173 |
#' @param opt An object returned from an optimizer, typically from |
|
| 174 |
#' [stats::nlminb()], used to fit a TMB model. |
|
| 175 |
#' @param parameter_names A character vector of parameter names. This is used to |
|
| 176 |
#' identify the parameters in the `std` object. |
|
| 177 |
#' @return A tibble containing the reshaped estimates (i.e., parameters and |
|
| 178 |
#' derived quantities). |
|
| 179 |
reshape_tmb_estimates <- function(obj, |
|
| 180 |
sdreport = NULL, |
|
| 181 |
opt = NULL, |
|
| 182 |
parameter_names) {
|
|
| 183 |
# Outline for the estimates table |
|
| 184 | 32x |
estimates_outline <- tibble::tibble( |
| 185 |
# The FIMS Rcpp module |
|
| 186 | 32x |
module_name = character(), |
| 187 |
# The unique ID of the module |
|
| 188 | 32x |
module_id = integer(), |
| 189 |
# The name of the parameter or derived quantity |
|
| 190 | 32x |
label = character(), |
| 191 |
# The unique ID of the parameter |
|
| 192 | 32x |
parameter_id = integer(), |
| 193 |
# The initial value use to start the optimization procedure |
|
| 194 | 32x |
initial = numeric(), |
| 195 |
# The estimated parameter value, which would be the MLE estimate or the value |
|
| 196 |
# used for a given MCMC iteration |
|
| 197 | 32x |
estimate = numeric(), |
| 198 |
# Estimated uncertainty, reported as a standard deviation |
|
| 199 | 32x |
uncertainty = numeric(), |
| 200 |
# The pointwise log-likelihood used for the test or holdout data |
|
| 201 | 32x |
log_like_cv = numeric(), |
| 202 |
# The gradient component for that parameter, NA for derived quantities |
|
| 203 | 32x |
gradient = numeric() |
| 204 |
) |
|
| 205 | ||
| 206 | 32x |
if (length(sdreport) > 0) {
|
| 207 | 25x |
std <- summary(sdreport) |
| 208 |
# Number of rows for derived quantities: based on the difference |
|
| 209 |
# between the total number of rows in std and the length of parameter_names. |
|
| 210 | 25x |
derived_quantity_nrow <- nrow(std) - length(parameter_names) |
| 211 |
# Create a tibble with the data from the std, and then apply transformations. |
|
| 212 | 25x |
estimates <- estimates_outline |> |
| 213 | 25x |
tibble::add_row( |
| 214 | 25x |
label = dimnames(std)[[1]], |
| 215 | 25x |
estimate = std[, "Estimate"], |
| 216 | 25x |
uncertainty = std[, "Std. Error"], |
| 217 |
# Use obj[["env"]][["parameters"]][["p"]] as this will return both initial |
|
| 218 |
# fixed and random effects while obj[["par"]] only returns initial fixed |
|
| 219 |
# effects |
|
| 220 | 25x |
initial = c( |
| 221 | 25x |
obj[["env"]][["parameters"]][["p"]], |
| 222 | 25x |
rep(NA_real_, derived_quantity_nrow) |
| 223 |
), |
|
| 224 | 25x |
gradient = c( |
| 225 | 25x |
obj[["gr"]](opt[["par"]]), |
| 226 | 25x |
rep(NA_real_, derived_quantity_nrow) |
| 227 |
) |
|
| 228 |
) |
|
| 229 |
} else {
|
|
| 230 | 7x |
estimates <- estimates_outline |> |
| 231 | 7x |
tibble::add_row( |
| 232 | 7x |
label = names(obj[["par"]]), |
| 233 | 7x |
initial = obj[["env"]][["parameters"]][["p"]], |
| 234 | 7x |
estimate = obj[["env"]][["parameters"]][["p"]] |
| 235 |
) |
|
| 236 |
} |
|
| 237 | ||
| 238 | 32x |
estimates <- estimates |> |
| 239 |
# Split labels and extract module, id, label, and parameter id |
|
| 240 | 32x |
dplyr::mutate(label_splits = strsplit(label, split = "\\.")) |> |
| 241 | 32x |
dplyr::rowwise() |> |
| 242 |
# TODO: the code could be simplified using tidyr::separate_wider_*(). |
|
| 243 |
# However, doing so would require avoiding pre-specification of these columns |
|
| 244 |
# in the estimates_outline tibble. Consider updating the code if we decide |
|
| 245 |
# not to create the `estimates_outline` tibble in advance. |
|
| 246 | 32x |
dplyr::mutate( |
| 247 | 32x |
module_name = ifelse(length(label_splits) > 1, label_splits[[1]], NA_character_), |
| 248 | 32x |
module_id = ifelse(length(label_splits) > 1, as.integer(label_splits[[2]]), NA_integer_), |
| 249 | 32x |
label = ifelse(length(label_splits) > 1, label_splits[[3]], label), |
| 250 | 32x |
parameter_id = ifelse(length(label_splits) > 1, as.integer(label_splits[[4]]), NA_integer_) |
| 251 |
) |> |
|
| 252 | 32x |
dplyr::select(-label_splits) |> |
| 253 | 32x |
dplyr::ungroup() |
| 254 |
} |
|
| 255 | ||
| 256 |
#' Converts a dimension-folder section into a tibble |
|
| 257 |
#' |
|
| 258 |
#' This is an internal helper function that processes a complex list |
|
| 259 |
#' structure read in from a json file containing dimensionality information, a |
|
| 260 |
#' name, and either explicit values with a type or estimated values with |
|
| 261 |
#' uncertainty. |
|
| 262 |
#' |
|
| 263 |
#' @param section A section of the json file represented as a list. |
|
| 264 |
#' @return |
|
| 265 |
#' A tibble containing the json output in a formatted structure listing the |
|
| 266 |
#' dimensionality as columns rather than just row and column lengths. |
|
| 267 |
#' @noRd |
|
| 268 |
#' |
|
| 269 |
#' @examples |
|
| 270 |
#' # A simple example for a value with uncertainty: |
|
| 271 |
#' section_derived <- list( |
|
| 272 |
#' name = "derived_quantity_name", |
|
| 273 |
#' dimensionality = list( |
|
| 274 |
#' unit = "m", symbol = "L", scale = 1.0, type = "length" |
|
| 275 |
#' ), |
|
| 276 |
#' value = 10.5, |
|
| 277 |
#' uncertainty = 0.5 |
|
| 278 |
#' ) |
|
| 279 |
#' dimension_folded_to_tibble(section_derived) |
|
| 280 |
dimension_folded_to_tibble <- function(section) {
|
|
| 281 | 2184x |
if (length(section) == 0) {
|
| 282 | ! |
return(NA) |
| 283 |
} |
|
| 284 | 2184x |
while (length(section) == 1) {
|
| 285 | ! |
unlist(section, recursive = FALSE) |
| 286 |
} |
|
| 287 | 2184x |
temp <- dimensions_to_tibble(section[["dimensionality"]]) |> |
| 288 | 2184x |
dplyr::mutate(name = section[["name"]]) |
| 289 | 2184x |
if ("type" %in% names(section)) {
|
| 290 | 552x |
temp |> |
| 291 | 552x |
dplyr::mutate( |
| 292 |
# TODO: Need to rename |
|
| 293 | 552x |
type_id = section[["id"]], |
| 294 | 552x |
type = section[["type"]] |
| 295 |
) |> |
|
| 296 | 552x |
dplyr::bind_cols( |
| 297 | 552x |
tibble::tibble(data = section[["values"]]) |> |
| 298 | 552x |
tidyr::unnest_wider(data) |
| 299 |
) |> |
|
| 300 | 552x |
dplyr::select(-min, -max) |
| 301 |
} else {
|
|
| 302 | 1632x |
temp |> |
| 303 | 1632x |
dplyr::bind_cols( |
| 304 | 1632x |
estimated_value = unlist(section[["value"]]), |
| 305 | 1632x |
uncertainty = unlist(section[["uncertainty"]]), |
| 306 | 1632x |
estimation_type = "derived_quantity" |
| 307 |
) |
|
| 308 |
} |
|
| 309 |
} |
|
| 310 | ||
| 311 |
#' Covert the dimension information from a FIMS json output into a tibble |
|
| 312 |
#' |
|
| 313 |
#' Dimensions in the json output are stored as a list of length two, with the |
|
| 314 |
#' header information containing the name of the dimension and the dimensions |
|
| 315 |
#' containing integers specifying the length for each dimension. The result |
|
| 316 |
#' helps interpret how the FIMS output is structured given it is dimension |
|
| 317 |
#' folded into a single vector in the json output. |
|
| 318 |
#' |
|
| 319 |
#' @details |
|
| 320 |
#' The dimension index is returned not the actual year of the model. For |
|
| 321 |
#' example, if the model starts in year 1900, then year_i of 1, which is what |
|
| 322 |
#' is returned from this function will need to map to 1900 and that will need |
|
| 323 |
#' to be done externally. |
|
| 324 |
#' This function will accommodate dimensions of year-1 and year+1 where the |
|
| 325 |
#' indexing of the former will start at 2 instead of 1. |
|
| 326 |
#' @param data A list containing the header and dimensions information from a |
|
| 327 |
#' FIMS json output object. |
|
| 328 |
#' @return |
|
| 329 |
#' A tibble containing ordered rows for each combination of the dimensions. |
|
| 330 |
#' @noRd |
|
| 331 |
#' @examples |
|
| 332 |
#' dummy_dimensions <- list( |
|
| 333 |
#' header = list("n_years", "n_ages"),
|
|
| 334 |
#' dimensions = list(30L, 12L) |
|
| 335 |
#' ) |
|
| 336 |
#' dimensions_to_tibble(dummy_dimensions) |
|
| 337 |
#' # Example with n_years+1 |
|
| 338 |
#' dummy_dimensions <- list( |
|
| 339 |
#' header = list("n_years+1", "n_ages"),
|
|
| 340 |
#' dimensions = list(31L, 12L) |
|
| 341 |
#' ) |
|
| 342 |
#' dimensions_to_tibble(dummy_dimensions) |
|
| 343 |
dimensions_to_tibble <- function(data) {
|
|
| 344 |
#' Replace headers like "n_years" with "year_i". |
|
| 345 |
#' Example: "n_ages+1" → "age_i" |
|
| 346 |
#' This matches names starting with 'n' (with or without an underscore) |
|
| 347 |
#' and shortens them to a simple indexed form. |
|
| 348 | 2336x |
better_names <- unlist(data[["header"]]) |> |
| 349 | 2336x |
gsub(pattern = "^n_?(.+?)s([-\\+]\\d+)?$", replacement = "\\1_i") |
| 350 | 2336x |
names(data[["dimensions"]]) <- better_names |
| 351 | 2336x |
if (length(better_names) == 0) {
|
| 352 |
# When the header is NULL |
|
| 353 | 256x |
return(tibble::add_row(tibble::tibble())) |
| 354 |
} |
|
| 355 | 2080x |
if ("na" %in% better_names && length(better_names) == 1) {
|
| 356 |
# When the dimensions are na because there is no associated indexing |
|
| 357 | 64x |
return(tibble::add_row(tibble::tibble())) |
| 358 |
} |
|
| 359 |
# Accommodate any -1 by creating a different start value |
|
| 360 | 2016x |
test <- grepl("-\\d", data[["header"]])
|
| 361 | 2016x |
addition <- gsub(".+-(\\d)", "\\1", data[["header"]])
|
| 362 | 2016x |
addition[!test] <- 0 |
| 363 | 2016x |
start <- 1 + as.numeric(addition) |
| 364 | 2016x |
data[["dimensions"]][test] <- as.numeric(data[["dimensions"]][test]) + |
| 365 | 2016x |
as.numeric(addition) |
| 366 |
# Create the returned tibble by first sequencing from 1:n for each dimension |
|
| 367 | 2016x |
purrr::map2(start, data[["dimensions"]], seq) |> |
| 368 | 2016x |
purrr::set_names(names(data[["dimensions"]])) |> |
| 369 | 2016x |
expand.grid() |> |
| 370 | 2016x |
tibble::as_tibble() |> |
| 371 | 2016x |
dplyr::arrange(!!!rlang::syms(better_names)) |
| 372 |
} |
|
| 373 | ||
| 374 |
#' Convert the density component information into a tibble |
|
| 375 |
#' |
|
| 376 |
#' The density component information is stored in a single column but contains |
|
| 377 |
#' a list of five elements. This function helps to widen that list into a |
|
| 378 |
#' tibble and expand the `values`, `expected_values`, and `observed_values` |
|
| 379 |
#' into long columns because they are all of the same length. |
|
| 380 |
#' |
|
| 381 |
#' @param data A list of lists from the json output that is titled |
|
| 382 |
#' `density_component`. |
|
| 383 |
#' @return |
|
| 384 |
#' A tibble is returned. |
|
| 385 |
#' @noRd |
|
| 386 |
#' |
|
| 387 |
#' @examples |
|
| 388 |
#' dummy_density <- list( |
|
| 389 |
#' name = "lpdf_vec", |
|
| 390 |
#' lpdf_value = -102.079, |
|
| 391 |
#' values = list( |
|
| 392 |
#' -1.39915, -2.44735, -2.93024, -3.21848, -2.95698, -3.51745 |
|
| 393 |
#' ), |
|
| 394 |
#' expected_values = list( |
|
| 395 |
#' 5.0854, 6.13354, 6.61636, 6.90467, 6.64311, 7.20302 |
|
| 396 |
#' ), |
|
| 397 |
#' observed_values = list( |
|
| 398 |
#' 161.646, 461.089, 747.29, 996.971, 767.548, 1343.86 |
|
| 399 |
#' ) |
|
| 400 |
#' ) |
|
| 401 |
#' density_to_tibble(dummy_density) |
|
| 402 |
#' @noRd |
|
| 403 |
density_to_tibble <- function(data) {
|
|
| 404 | 336x |
data |> |
| 405 | 336x |
tibble::as_tibble() |> |
| 406 | 336x |
tidyr::unnest(c(value, expected_values, observed_values)) |> |
| 407 | 336x |
dplyr::rename(likelihood = value) |
| 408 |
} |
| 1 |
#' Create a default FIMS configuration tibble |
|
| 2 |
#' |
|
| 3 |
#' @description |
|
| 4 |
#' This function generates a default configuration tibble for a Fisheries |
|
| 5 |
#' Integrated Modeling System (FIMS) model based on the data input. It |
|
| 6 |
#' automatically creates configuration entries for data modules (e.g., landings, |
|
| 7 |
#' index, compositions) and, depending on the model family, standard population |
|
| 8 |
#' dynamics modules (recruitment, growth, maturity) and selectivity modules for |
|
| 9 |
#' fleets. |
|
| 10 |
#' |
|
| 11 |
#' @details |
|
| 12 |
#' The function inspects the data to find unique combinations of fleet |
|
| 13 |
#' names and data types. It then maps these to the appropriate FIMS module names |
|
| 14 |
#' and joins them with a predefined template of default settings. When the |
|
| 15 |
#' `model_family` is "catch_at_age", it also adds default configurations for: |
|
| 16 |
#' \itemize{
|
|
| 17 |
#' \item **Selectivity:** A logistic selectivity module for each unique fleet. |
|
| 18 |
#' \item **Recruitment:** A Beverton--Holt recruitment module. |
|
| 19 |
#' \item **Growth:** An empirical weight-at-age (EWAA) growth module. |
|
| 20 |
#' \item **Maturity:** A logistic maturity module. |
|
| 21 |
#' } |
|
| 22 |
#' The final output is a nested tibble, which serves as a starting point for |
|
| 23 |
#' building a complete FIMS model configuration. |
|
| 24 |
#' |
|
| 25 |
#' @param data An S4 object of class `FIMSFrame`. FIMS input data. |
|
| 26 |
#' @param model_family A string specifying the model family. |
|
| 27 |
#' Defaults to `"catch_at_age"`. |
|
| 28 |
#' |
|
| 29 |
#' @return A `tibble` with default model configurations. The tibble has a nested |
|
| 30 |
#' structure with the following top-level columns. |
|
| 31 |
#' \describe{
|
|
| 32 |
#' \item{\code{model_family}:}{The specified model family (e.g.,
|
|
| 33 |
#' "catch_at_age").} |
|
| 34 |
#' \item{\code{module_name}:}{The name of the FIMS module (e.g.,
|
|
| 35 |
#' "Data", "Selectivity", "Recruitment", "Growth", "Maturity").} |
|
| 36 |
#' \item{\code{fleet_name}:}{The name of the fleet the module applies to. This
|
|
| 37 |
#' will be `NA` for non-fleet-specific modules like "Recruitment".} |
|
| 38 |
#' \item{\code{data}:}{A list-column containing a `tibble` with detailed
|
|
| 39 |
#' configurations. Unnesting this column reveals: |
|
| 40 |
#' \describe{
|
|
| 41 |
#' \item{\code{module_type}:}{The specific type of the module (e.g.,
|
|
| 42 |
#' "Logistic" for a "Selectivity" module).} |
|
| 43 |
#' \item{\code{distribution_link}:}{The component the distribution module
|
|
| 44 |
#' links to.} |
|
| 45 |
#' \item{\code{distribution_type}:}{The type of distribution (e.g., "Data",
|
|
| 46 |
#' "process").} |
|
| 47 |
#' \item{\code{distribution}:}{The name of distribution (e.g.,
|
|
| 48 |
#' "Dlnorm", `Dmultinom`).} |
|
| 49 |
#' } |
|
| 50 |
#' } |
|
| 51 |
#' } |
|
| 52 |
#' |
|
| 53 |
#' @export |
|
| 54 |
#' |
|
| 55 |
#' @examples |
|
| 56 |
#' # Load the example dataset and create a FIMS data frame |
|
| 57 |
#' data("data1")
|
|
| 58 |
#' fims_frame <- FIMSFrame(data1) |
|
| 59 |
#' |
|
| 60 |
#' # Create the default model configuration tibble |
|
| 61 |
#' default_configurations <- create_default_configurations(data = fims_frame) |
|
| 62 |
#' |
|
| 63 |
#' # Unnest the data column to see detailed configurations |
|
| 64 |
#' default_configurations_unnest <- default_configurations |> |
|
| 65 |
#' tidyr::unnest(cols = data) |> |
|
| 66 |
#' print() |
|
| 67 |
#' |
|
| 68 |
#' # Model fleet1 with double logistic selectivity |
|
| 69 |
#' configurations_double_logistic <- default_configurations_unnest |> |
|
| 70 |
#' dplyr::rows_update( |
|
| 71 |
#' tibble::tibble( |
|
| 72 |
#' module_name = "Selectivity", |
|
| 73 |
#' fleet_name = "fleet1", |
|
| 74 |
#' module_type = "DoubleLogistic" |
|
| 75 |
#' ), |
|
| 76 |
#' by = c("module_name", "fleet_name")
|
|
| 77 |
#' ) |> |
|
| 78 |
#' print() |
|
| 79 |
create_default_configurations <- function(data, model_family = c("catch_at_age")) {
|
|
| 80 |
# Check if the input object is a FIMSFrame, aborting if not. |
|
| 81 | 11x |
if (!inherits(data, "FIMSFrame")) {
|
| 82 | 1x |
cli::cli_abort( |
| 83 | 1x |
c( |
| 84 | 1x |
"{.var data} must be a {.cls FIMSFrame} object.",
|
| 85 | 1x |
"i" = "Please convert your data before using this function." |
| 86 |
) |
|
| 87 |
) |
|
| 88 |
} |
|
| 89 | ||
| 90 |
# Ensures the user input matches the options provided, |
|
| 91 |
# if not, then match.arg() throws an error |
|
| 92 | 10x |
model_family <- match.arg(model_family) |
| 93 | ||
| 94 |
# Extract unique combinations of fleet names and data types from the data. |
|
| 95 |
# This forms the basis for determining which modules are needed for each fleet. |
|
| 96 | 9x |
unique_fleet_types <- data |> |
| 97 | 9x |
get_data() |> |
| 98 | 9x |
dplyr::distinct(name, type) |> |
| 99 |
# Convert type from snake_case to PascalCase |
|
| 100 | 9x |
dplyr::mutate(module_type = snake_to_pascal(type)) |> |
| 101 |
# Set module_type to NA for weight-at-age and age-to-length-conversion |
|
| 102 | 9x |
dplyr::mutate(module_type = dplyr::case_when( |
| 103 | 9x |
type == "weight-at-age" ~ NA_character_, |
| 104 | 9x |
type == "age-to-length-conversion" ~ NA_character_, |
| 105 | 9x |
TRUE ~ module_type |
| 106 |
)) |> |
|
| 107 |
# Remove any combinations where the type did not match a known module. |
|
| 108 | 9x |
dplyr::filter(!is.na(module_type)) |> |
| 109 | 9x |
dplyr::rename(fleet_name = name) |> |
| 110 | 9x |
dplyr::select(-type) |
| 111 | ||
| 112 |
# Define a template for data modules (comps, landings, index). |
|
| 113 |
# This specifies the default distribution for each type of data. |
|
| 114 | 9x |
data_config_template <- dplyr::tribble( |
| 115 | 9x |
~module_name, ~module_type, ~distribution_link, ~distribution_type, ~distribution, |
| 116 | 9x |
"Data", "Landings", "Landings", "Data", "Dlnorm", |
| 117 | 9x |
"Data", "Index", "Index", "Data", "Dlnorm", |
| 118 | 9x |
"Data", "AgeComp", "AgeComp", "Data", "Dmultinom", |
| 119 | 9x |
"Data", "LengthComp", "LengthComp", "Data", "Dmultinom" |
| 120 |
) |
|
| 121 | ||
| 122 |
# Create data module configurations by joining the unique fleet types |
|
| 123 |
# with the corresponding template entries. |
|
| 124 | 9x |
fleet_data_config <- unique_fleet_types |> |
| 125 | 9x |
dplyr::left_join(data_config_template, by = "module_type") |
| 126 | ||
| 127 |
# Initialize placeholders for conditional configurations. |
|
| 128 | 9x |
selectivity_config <- tibble::tibble() |
| 129 | 9x |
other_config <- tibble::tibble() |
| 130 | ||
| 131 |
# If model_family is "catch_at_age", create selectivity configurations for |
|
| 132 |
# fleets and other configurations for population dynamics. |
|
| 133 | 9x |
if (model_family == "catch_at_age") {
|
| 134 |
# Create these rows by getting distinct fleet names and joining them |
|
| 135 |
# with the selectivity template. |
|
| 136 | 9x |
selectivity_config <- unique_fleet_types |> |
| 137 | 9x |
dplyr::distinct(fleet_name) |> |
| 138 | 9x |
dplyr::mutate( |
| 139 | 9x |
module_name = "Selectivity", |
| 140 | 9x |
module_type = "Logistic" |
| 141 |
) |
|
| 142 | ||
| 143 |
# Define a template for standard, non-fleet-specific modules. |
|
| 144 | 9x |
other_config <- dplyr::tribble( |
| 145 | 9x |
~module_name, ~module_type, ~distribution_link, ~distribution_type, ~distribution, |
| 146 | 9x |
"Recruitment", "BevertonHolt", "log_devs", "process", "Dnorm", |
| 147 | 9x |
"Growth", "EWAA", NA_character_, NA_character_, NA_character_, |
| 148 | 9x |
"Maturity", "Logistic", NA_character_, NA_character_, NA_character_ |
| 149 |
) |
|
| 150 |
} |
|
| 151 | ||
| 152 |
# Combine all configuration pieces into a single tibble. |
|
| 153 |
# The `dplyr::bind_rows` function intelligently handles differing columns |
|
| 154 |
# by filling missing values with NA. |
|
| 155 | 9x |
final_config <- dplyr::bind_rows( |
| 156 | 9x |
fleet_data_config, |
| 157 | 9x |
selectivity_config, |
| 158 | 9x |
other_config |
| 159 |
) |> |
|
| 160 |
# Add model_family column |
|
| 161 | 9x |
dplyr::mutate(model_family = model_family) |> |
| 162 |
# Arrange for readability. |
|
| 163 | 9x |
dplyr::arrange(fleet_name, module_name) |> |
| 164 |
# Reorder columns |
|
| 165 | 9x |
dplyr::select( |
| 166 | 9x |
model_family, module_name, module_type, fleet_name, everything() |
| 167 |
) |> |
|
| 168 |
# Nest the configuration details into a list-column called 'data'. |
|
| 169 |
# This creates the final, structured output format expected by FIMS. |
|
| 170 | 9x |
tidyr::nest(.by = c(model_family, module_name, fleet_name)) |
| 171 |
} |
|
| 172 | ||
| 173 |
#' Convert snake_case strings to PascalCase |
|
| 174 |
#' |
|
| 175 |
#' This function takes a vector of strings in snake_case format and converts |
|
| 176 |
#' them to PascalCase. |
|
| 177 |
#' |
|
| 178 |
#' @param snake_strings A vector of strings in snake_case format. |
|
| 179 |
#' @return A vector of strings in PascalCase format. |
|
| 180 |
#' @examples |
|
| 181 |
#' snake_to_pascal(c("age_comp", "length_comp"))
|
|
| 182 |
#' snake_to_pascal("index")
|
|
| 183 |
#' @noRd |
|
| 184 |
snake_to_pascal <- function(snake_strings) {
|
|
| 185 | 9x |
purrr::map_chr(snake_strings, \(x) {
|
| 186 | 65x |
parts <- strsplit(x, "_")[[1]] |
| 187 | 65x |
paste( |
| 188 | 65x |
toupper(substring(parts, 1, 1)), |
| 189 | 65x |
substring(parts, 2), |
| 190 | 65x |
sep = "", |
| 191 | 65x |
collapse = "" |
| 192 |
) |
|
| 193 |
}) |
|
| 194 |
} |
| 1 |
#' Should FIMS be verbose? |
|
| 2 |
#' |
|
| 3 |
#' Verbosity is set globally for FIMS using |
|
| 4 |
#' `options(rlib_message_verbosity = "quiet")` to stop the printing of messages |
|
| 5 |
#' from `cli::cli_inform()`. Using a global option allows for verbose to not |
|
| 6 |
#' have to be an argument to every function. All `cli::cli_abort()` messages are |
|
| 7 |
#' printed to the console no matter what the global option is set to. |
|
| 8 |
#' |
|
| 9 |
#' @return |
|
| 10 |
#' A logical is returned where `TRUE` ensures messages from `cli::cli_inform()` |
|
| 11 |
#' are printed to the console. |
|
| 12 |
#' |
|
| 13 |
#' @examples |
|
| 14 |
#' # function is not exported |
|
| 15 |
#' \dontrun{
|
|
| 16 |
#' FIMS:::is_fims_verbose() |
|
| 17 |
#' } |
|
| 18 |
is_fims_verbose <- function() {
|
|
| 19 | 9x |
verbose_option <- getOption("rlib_message_verbosity", default = "default")
|
| 20 | 9x |
verbose_boolean <- verbose_option %in% c("default", "verbose")
|
| 21 | 9x |
return(verbose_boolean) |
| 22 |
} |
| 1 |
/** |
|
| 2 |
* @file data_object.hpp |
|
| 3 |
* @brief Sets up a data class to create a generic data object with up to five |
|
| 4 |
* dimensions. The class contains internal vector for data elements and |
|
| 5 |
* uncertainty values. |
|
| 6 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 7 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 8 |
* folder for reuse information. |
|
| 9 |
*/ |
|
| 10 |
#ifndef FIMS_COMMON_DATA_OBJECT_HPP |
|
| 11 |
#define FIMS_COMMON_DATA_OBJECT_HPP |
|
| 12 | ||
| 13 |
#include <exception> |
|
| 14 |
#include <vector> |
|
| 15 | ||
| 16 |
#include "model_object.hpp" |
|
| 17 |
#include "fims_vector.hpp" |
|
| 18 | ||
| 19 |
namespace fims_data_object {
|
|
| 20 | ||
| 21 |
/** |
|
| 22 |
* Container to hold user supplied data. |
|
| 23 |
*/ |
|
| 24 |
template <typename Type> |
|
| 25 |
struct DataObject : public fims_model_object::FIMSObject<Type> {
|
|
| 26 |
static uint32_t id_g; /**< id of the Data Object >*/ |
|
| 27 |
fims::Vector<Type> data; /**< vector of the data >*/ |
|
| 28 |
fims::Vector<Type> uncertainty; /**< vector of the data >*/ |
|
| 29 |
size_t dimensions; /**< dimension of the Data object >*/ |
|
| 30 |
size_t imax; /**< 1st dimension of data object >*/ |
|
| 31 |
size_t jmax; /**< 2nd dimension of data object>*/ |
|
| 32 |
size_t kmax; /**< 3rd dimension of data object>*/ |
|
| 33 |
size_t lmax; /**< 4th dimension of data object>*/ |
|
| 34 |
Type na_value = static_cast<Type>(-999); /**< specifying the NA value >*/ |
|
| 35 | ||
| 36 |
/** |
|
| 37 |
* Constructs a one-dimensional data object. |
|
| 38 |
*/ |
|
| 39 | 152x |
DataObject(size_t imax) : dimensions(1), imax(imax) {
|
| 40 | 152x |
data.resize(imax); |
| 41 | 152x |
uncertainty.resize(imax); |
| 42 | 152x |
this->id = DataObject<Type>::id_g++; |
| 43 |
} |
|
| 44 | ||
| 45 |
/** |
|
| 46 |
* Constructs a two-dimensional data object. |
|
| 47 |
*/ |
|
| 48 | 264x |
DataObject(size_t imax, size_t jmax) : dimensions(2), imax(imax), jmax(jmax) {
|
| 49 | 264x |
data.resize(imax * jmax); |
| 50 | 264x |
uncertainty.resize(imax * jmax); |
| 51 | 264x |
this->id = DataObject<Type>::id_g++; |
| 52 |
} |
|
| 53 | ||
| 54 |
/** |
|
| 55 |
* Constructs a three-dimensional data object. |
|
| 56 |
*/ |
|
| 57 |
DataObject(size_t imax, size_t jmax, size_t kmax) |
|
| 58 |
: dimensions(3), imax(imax), jmax(jmax), kmax(kmax) {
|
|
| 59 |
data.resize(imax * jmax * kmax); |
|
| 60 |
uncertainty.resize(imax * jmax * kmax); |
|
| 61 |
this->id = DataObject<Type>::id_g++; |
|
| 62 |
} |
|
| 63 | ||
| 64 |
/** |
|
| 65 |
* Constructs a four-dimensional data object. |
|
| 66 |
*/ |
|
| 67 |
DataObject(size_t imax, size_t jmax, size_t kmax, size_t lmax) |
|
| 68 |
: dimensions(4), imax(imax), jmax(jmax), kmax(kmax), lmax(lmax) {
|
|
| 69 |
data.resize(imax * jmax * kmax * lmax); |
|
| 70 |
uncertainty.resize(imax * jmax * kmax * lmax); |
|
| 71 |
this->id = DataObject<Type>::id_g++; |
|
| 72 |
} |
|
| 73 | ||
| 74 |
/** |
|
| 75 |
* Retrieve element from 1d data set. |
|
| 76 |
* @param i dimension of 1d data set |
|
| 77 |
* @return the value of the vector at position i |
|
| 78 |
*/ |
|
| 79 |
inline Type operator()(size_t i) { return data[i]; }
|
|
| 80 | ||
| 81 |
/** |
|
| 82 |
* Retrieve element from 1d data set. |
|
| 83 |
* Throws an exception if index is out of bounds. |
|
| 84 |
* @param i dimension of 1d data set |
|
| 85 |
* @return the reference to the value of the vector at position i |
|
| 86 |
*/ |
|
| 87 | 2032190x |
inline Type& at(size_t i) {
|
| 88 | 2032190x |
if (i >= this->data.size()) {
|
| 89 | ! |
throw std::overflow_error("DataObject error:i index out of bounds");
|
| 90 |
} |
|
| 91 | 2032190x |
return data[i]; |
| 92 |
} |
|
| 93 | ||
| 94 |
/** |
|
| 95 |
* Retrieve element from 2d data set. |
|
| 96 |
* @param i 1st dimension of 2d data set |
|
| 97 |
* @param j 2nd dimension of 2d data set |
|
| 98 |
* @return the value of the matrix at position i, j |
|
| 99 |
*/ |
|
| 100 |
inline const Type operator()(size_t i, size_t j) {
|
|
| 101 |
return data[i * jmax + j]; |
|
| 102 |
} |
|
| 103 | ||
| 104 |
/** |
|
| 105 |
* Retrieve element from 2d data set. |
|
| 106 |
* Throws an exception if index is out of bounds. |
|
| 107 |
* @param i 1st dimension of 2d data set |
|
| 108 |
* @param j 2nd dimension of 2d data set |
|
| 109 |
* @return the reference to the value of the matrix at position i, j |
|
| 110 |
*/ |
|
| 111 | 2102178x |
inline Type& at(size_t i, size_t j) {
|
| 112 | 2102178x |
if ((i * jmax + j) >= this->data.size()) {
|
| 113 | ! |
throw std::overflow_error("DataObject error: index out of bounds");
|
| 114 |
} |
|
| 115 | 2102178x |
return data[i * jmax + j]; |
| 116 |
} |
|
| 117 | ||
| 118 |
/** |
|
| 119 |
* Retrieve element from 3d data set. |
|
| 120 |
* @param i 1st dimension of 3d data set |
|
| 121 |
* @param j 2nd dimension of 3d data set |
|
| 122 |
* @param k 3rd dimension of 3d data set |
|
| 123 |
* @return the value of the array at position i, j, k |
|
| 124 |
*/ |
|
| 125 |
inline const Type operator()(size_t i, size_t j, size_t k) {
|
|
| 126 |
return data[i * jmax * kmax + j * kmax + k]; |
|
| 127 |
} |
|
| 128 | ||
| 129 |
/** |
|
| 130 |
* Retrieve element from 3d data set. |
|
| 131 |
* Throws an exception if index is out of bounds. |
|
| 132 |
* @param i 1st dimension of 3d data set |
|
| 133 |
* @param j 2nd dimension of 3d data set |
|
| 134 |
* @param k 3rd dimension of 3d data set |
|
| 135 |
* @return the reference to the value of the array at position i, j, k |
|
| 136 |
*/ |
|
| 137 |
inline Type& at(size_t i, size_t j, size_t k) {
|
|
| 138 |
if ((i * jmax * kmax + j * kmax + k) >= this->data.size()) {
|
|
| 139 |
throw std::overflow_error("DataObject error: index out of bounds");
|
|
| 140 |
} |
|
| 141 |
return data[i * jmax * kmax + j * kmax + k]; |
|
| 142 |
} |
|
| 143 | ||
| 144 |
/** |
|
| 145 |
* Retrieve element from 4d data set. |
|
| 146 |
* @param i 1st dimension of 4d data set |
|
| 147 |
* @param j 2nd dimension of 4d data set |
|
| 148 |
* @param k 3rd dimension of 4d data set |
|
| 149 |
* @param l 4th dimension of 4d data set |
|
| 150 |
* @return the value of the array at position i, j, k, l |
|
| 151 |
*/ |
|
| 152 |
inline const Type operator()(size_t i, size_t j, size_t k, size_t l) {
|
|
| 153 |
return data[i * jmax * kmax * lmax + j * kmax * lmax + k * lmax + l]; |
|
| 154 |
} |
|
| 155 | ||
| 156 |
/** |
|
| 157 |
* Retrieve element from 3d data set. |
|
| 158 |
* Throws an exception if index is out of bounds. |
|
| 159 |
* @param i 1st dimension of 4d data set |
|
| 160 |
* @param j 2nd dimension of 4d data set |
|
| 161 |
* @param k 3rd dimension of 4d data set |
|
| 162 |
* @param l 4th dimension of 4d data set |
|
| 163 |
* @return the reference to the value of the array at position i, j, k, l |
|
| 164 |
*/ |
|
| 165 |
inline Type& at(size_t i, size_t j, size_t k, size_t l) {
|
|
| 166 |
if ((i * jmax * kmax * lmax + j * kmax * lmax + k * lmax + l) >= |
|
| 167 |
this->data.size()) {
|
|
| 168 |
throw std::overflow_error("DataObject error: index out of bounds");
|
|
| 169 |
} |
|
| 170 |
return data[i * jmax * kmax * lmax + j * kmax * lmax + k * lmax + l]; |
|
| 171 |
} |
|
| 172 | ||
| 173 |
/** |
|
| 174 |
* @brief Get the dimensions object |
|
| 175 |
* |
|
| 176 |
* @return size_t |
|
| 177 |
*/ |
|
| 178 |
size_t get_dimensions() const { return dimensions; }
|
|
| 179 | ||
| 180 |
/** |
|
| 181 |
* @brief Get the imax object |
|
| 182 |
* |
|
| 183 |
* @return size_t |
|
| 184 |
*/ |
|
| 185 | 284x |
size_t get_imax() const { return imax; }
|
| 186 | ||
| 187 |
/** |
|
| 188 |
* @brief Get the jmax object |
|
| 189 |
* |
|
| 190 |
* @return size_t |
|
| 191 |
*/ |
|
| 192 | 284x |
size_t get_jmax() const { return jmax; }
|
| 193 | ||
| 194 |
/** |
|
| 195 |
* @brief Get the kmax object |
|
| 196 |
* |
|
| 197 |
* @return size_t |
|
| 198 |
*/ |
|
| 199 |
size_t get_kmax() const { return kmax; }
|
|
| 200 | ||
| 201 |
/** |
|
| 202 |
* @brief Get the lmax object |
|
| 203 |
* |
|
| 204 |
* @return size_t |
|
| 205 |
*/ |
|
| 206 |
size_t get_lmax() const { return lmax; }
|
|
| 207 |
}; |
|
| 208 | ||
| 209 |
template <typename Type> |
|
| 210 |
uint32_t DataObject<Type>::id_g = 0; |
|
| 211 | ||
| 212 |
} // namespace fims_data_object |
|
| 213 | ||
| 214 |
#endif |
| 1 |
/** |
|
| 2 |
* @file def.hpp |
|
| 3 |
* @brief Creates pre-processing macros such as what type of machine you are on |
|
| 4 |
* and creates the log information. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef DEF_HPP |
|
| 10 |
#define DEF_HPP |
|
| 11 |
#include <fstream> |
|
| 12 |
#include <map> |
|
| 13 |
#include <memory> |
|
| 14 |
#include <vector> |
|
| 15 |
#include <string> |
|
| 16 |
#include <unordered_map> |
|
| 17 | ||
| 18 |
#include <cstdlib> |
|
| 19 |
#include <chrono> |
|
| 20 |
#include <sstream> |
|
| 21 |
#include <iostream> |
|
| 22 |
#include <filesystem> |
|
| 23 |
#include <stdlib.h> |
|
| 24 |
#include <fstream> |
|
| 25 |
#include <signal.h> |
|
| 26 |
#include <csignal> |
|
| 27 |
#include <cstring> |
|
| 28 | ||
| 29 |
#include <stdexcept> |
|
| 30 | ||
| 31 |
#if defined(linux) || defined(__linux) || defined(__linux__) |
|
| 32 |
#define FIMS_LINUX |
|
| 33 |
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ |
|
| 34 |
defined(__DragonFly__) |
|
| 35 |
#define FIMS_BSD |
|
| 36 |
#elif defined(sun) || defined(__sun) |
|
| 37 |
#define FIMS_SOLARIS |
|
| 38 |
#elif defined(__sgi) |
|
| 39 |
#define FIMS_IRIX |
|
| 40 |
#elif defined(__hpux) |
|
| 41 |
#define FIMS_HPUX |
|
| 42 |
#elif defined(__CYGWIN__) |
|
| 43 |
#define FIMS_CYGWIN |
|
| 44 |
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) |
|
| 45 |
#define FIMS_WIN32 |
|
| 46 |
#elif defined(_WIN64) || defined(__WIN64__) || defined(WIN64) |
|
| 47 |
#define FIMS_WIN64 |
|
| 48 |
#elif defined(__BEOS__) |
|
| 49 |
#define FIMS_BEOS |
|
| 50 |
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) |
|
| 51 |
#define FIMS_MACOS |
|
| 52 |
#elif defined(__IBMCPP__) || defined(_AIX) |
|
| 53 |
#define FIMS_AIX |
|
| 54 |
#elif defined(__amigaos__) |
|
| 55 |
#define FIMS_AMIGAOS |
|
| 56 |
#elif defined(__QNXNTO__) |
|
| 57 |
#define FIMS_QNXNTO |
|
| 58 |
#endif |
|
| 59 | ||
| 60 |
#if defined(FIMS_WIN32) || defined(FIMS_WIN64) |
|
| 61 |
#define FIMS_WINDOWS |
|
| 62 |
#endif |
|
| 63 | ||
| 64 |
#ifdef FIMS_WINDOWS |
|
| 65 |
#include <Windows.h> |
|
| 66 |
#include <Lmcons.h> // for UNLEN |
|
| 67 |
#elif defined(FIMS_LINUX) || defined(FIMS_MACOS) || defined(FIMS_BSD) |
|
| 68 |
#include <unistd.h> |
|
| 69 |
#include <pwd.h> |
|
| 70 |
#endif |
|
| 71 | ||
| 72 |
#if !defined(__PRETTY_FUNCTION__) && !defined(__GNUC__) |
|
| 73 |
#ifdef FIMS_WINDOWS |
|
| 74 |
#define __PRETTY_FUNCTION__ __FUNCTION__ |
|
| 75 |
#endif |
|
| 76 |
#endif |
|
| 77 | ||
| 78 |
// The following rows initialize default log files for outputting model progress |
|
| 79 |
// comments used to assist in diagnosing model issues and tracking progress. |
|
| 80 |
// These files will only be created if a logs folder is added to the root model |
|
| 81 |
// directory. |
|
| 82 | ||
| 83 |
#ifdef TMB_MODEL |
|
| 84 |
// simplify access to singletons |
|
| 85 |
#define TMB_FIMS_REAL_TYPE double |
|
| 86 |
#ifdef TMBAD_FRAMEWORK |
|
| 87 |
#define TMBAD_FIMS_TYPE TMBad::ad_aug |
|
| 88 |
#else |
|
| 89 |
#define TMB_FIMS_FIRST_ORDER AD<TMB_FIMS_REAL_TYPE> |
|
| 90 |
#define TMB_FIMS_SECOND_ORDER AD<TMB_FIMS_FIRST_ORDER> |
|
| 91 |
#define TMB_FIMS_THIRD_ORDER AD<TMB_FIMS_SECOND_ORDER> |
|
| 92 |
#endif |
|
| 93 |
#endif |
|
| 94 | ||
| 95 |
namespace fims {
|
|
| 96 | ||
| 97 |
/** |
|
| 98 |
* Log entry. |
|
| 99 |
*/ |
|
| 100 |
struct LogEntry {
|
|
| 101 |
/** The date/time that the log entry was created, e.g., "Oct 28 09:18:51 |
|
| 102 |
* 2024". You can track how long it took to work through each portion of the |
|
| 103 |
* model by analyzing the progression of the timestamp through the log file.*/ |
|
| 104 |
std::string timestamp; |
|
| 105 |
/** The description of the log entry, e.g., "Adding Selectivity object to TMB" |
|
| 106 |
* or "Mismatch dimension error", where the descriptions are predefined in the |
|
| 107 |
* C++ code. Please make a GitHub issue or contact a developer if you have |
|
| 108 |
* ideas for a more informative description.*/ |
|
| 109 |
std::string message; |
|
| 110 |
/** The logging level, which is a result of which macro was used to generate |
|
| 111 |
* the message, e.g., FIMS_INFO_LOG(), FIMS_WARNING_LOG(), or FIMS_ERROR_LOG() |
|
| 112 |
* results in "info", "warning", or "error", respectively, in the log file. An |
|
| 113 |
* additional level is available to developers from FIMS_DEBUG_LOG(), |
|
| 114 |
* resulting in a level of "debug", but this macro is only available in |
|
| 115 |
* branches other than main.*/ |
|
| 116 |
std::string level; |
|
| 117 |
/** The message id, directly corresponds to the order in which the entries |
|
| 118 |
* were created, e.g., "1", which is helpful for knowing the order of |
|
| 119 |
* operations within the code base and comparing log files across model |
|
| 120 |
* runs.*/ |
|
| 121 |
size_t rank; |
|
| 122 |
/** The user name registered to the computer where the log file was created, |
|
| 123 |
* e.g., "John.Doe".*/ |
|
| 124 |
std::string user; |
|
| 125 |
/** The working directory for the R environment that created the log file, |
|
| 126 |
* e.g., "C:/github/NOAA-FIMS/FIMS/vignettes" if you are on a Windows machine |
|
| 127 |
* or "/home/oppy/FIMS-Testing/dev/dev_logging/FIMS/vignettes" if you are on a |
|
| 128 |
* linux machine.*/ |
|
| 129 |
std::string wd; |
|
| 130 |
/** The full file path of the file that triggered the log entry, e.g., |
|
| 131 |
* "C:/github/NOAA-FIMS/FIMS/inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp".*/ |
|
| 132 |
std::string file; |
|
| 133 |
/** The function or method that led to the initialization the log entry, e.g., |
|
| 134 |
* "virtual bool LogisticSelectivityInterface::add_to_fims_tmb()". If the |
|
| 135 |
* function is templated, then the function type will be reported here in |
|
| 136 |
* square brackets after the function name, e.g., "bool |
|
| 137 |
* fims_info::Information<Type>::CreateModel() [with Type = double]".*/ |
|
| 138 |
std::string routine; |
|
| 139 |
/** The line in `file` where the log entry was initiated, e.g., "219", which |
|
| 140 |
* will be a line inside of the `routine` listed above.*/ |
|
| 141 |
int line; |
|
| 142 | ||
| 143 |
/** |
|
| 144 |
* Convert this object to a string. |
|
| 145 |
*/ |
|
| 146 | 13148x |
std::string to_string() {
|
| 147 | 13148x |
std::stringstream ss; |
| 148 | 13148x |
ss << "\"timestamp\": " << "\"" << this->timestamp << "\"" << ",\n"; |
| 149 | 13148x |
ss << "\"level\": " << "\"" << this->level << "\",\n"; |
| 150 | 13148x |
ss << "\"message\": " << "\"" << this->message << "\",\n"; |
| 151 | 13148x |
ss << "\"id\": " << "\"" << this->rank << "\",\n"; |
| 152 | 13148x |
ss << "\"user\": " << "\"" << this->user << "\",\n"; |
| 153 | 13148x |
ss << "\"wd\": " << "\"" << this->wd << "\",\n"; |
| 154 | 13148x |
ss << "\"file\": " << "\"" << this->file << "\",\n"; |
| 155 | 13148x |
ss << "\"routine\": " << "\"" << this->routine << "\",\n"; |
| 156 | 13148x |
ss << "\"line\": " << "\"" << this->line << "\"\n"; |
| 157 | 26296x |
return ss.str(); |
| 158 |
} |
|
| 159 |
}; |
|
| 160 | ||
| 161 |
/** |
|
| 162 |
* FIMS logging class. |
|
| 163 |
*/ |
|
| 164 |
class FIMSLog {
|
|
| 165 |
std::vector<std::string> entries; |
|
| 166 |
std::vector<LogEntry> log_entries; |
|
| 167 |
size_t entry_number = 0; |
|
| 168 |
std::string path = "fims.log"; |
|
| 169 |
size_t warning_count = 0; |
|
| 170 |
size_t error_count = 0; |
|
| 171 | ||
| 172 |
/** |
|
| 173 |
* Get username. |
|
| 174 |
* |
|
| 175 |
* @return username. |
|
| 176 |
*/ |
|
| 177 | 20818x |
std::string get_user() {
|
| 178 |
#ifdef FIMS_WINDOWS |
|
| 179 |
char username[UNLEN + 1]; |
|
| 180 |
DWORD username_len = UNLEN + 1; |
|
| 181 |
if (GetUserNameA(username, &username_len)) {
|
|
| 182 |
return std::string(username); |
|
| 183 |
} else {
|
|
| 184 |
return "[unknown user]"; |
|
| 185 |
} |
|
| 186 | ||
| 187 |
#elif defined(FIMS_LINUX) || defined(FIMS_MACOS) || defined(FIMS_BSD) |
|
| 188 | 20818x |
const char* user_env = getenv("USER");
|
| 189 | 62454x |
if (user_env) return std::string(user_env); |
| 190 | ||
| 191 | ! |
uid_t uid = getuid(); |
| 192 | ! |
struct passwd* pw = getpwuid(uid); |
| 193 | ! |
if (pw && pw->pw_name) {
|
| 194 | ! |
return std::string(pw->pw_name); |
| 195 |
} else {
|
|
| 196 | ! |
return "[unknown user]"; |
| 197 |
} |
|
| 198 | ||
| 199 |
#else |
|
| 200 |
return "[unsupported platform]"; |
|
| 201 |
#endif |
|
| 202 |
} |
|
| 203 | ||
| 204 |
public: |
|
| 205 |
/** |
|
| 206 |
* @brief A boolean specifying if the log file is written when the session is |
|
| 207 |
* terminated. The default is TRUE. |
|
| 208 |
* |
|
| 209 |
*/ |
|
| 210 |
bool write_on_exit = true; |
|
| 211 |
/** |
|
| 212 |
* @brief A boolean specifying if the program is stopped upon the first |
|
| 213 |
* error, where the default is FALSE. This allows you go through an entire |
|
| 214 |
* program to collect all error messages. |
|
| 215 |
* |
|
| 216 |
*/ |
|
| 217 |
bool throw_on_error = false; |
|
| 218 |
/** |
|
| 219 |
* @brief A singleton instance of the log, i.e., where there is only one |
|
| 220 |
* log. The object is created when the .dll is loaded and it will never |
|
| 221 |
* be recreated while the .dll is loaded. |
|
| 222 |
* |
|
| 223 |
*/ |
|
| 224 |
static std::shared_ptr<FIMSLog> fims_log; |
|
| 225 | ||
| 226 |
/** |
|
| 227 |
* Default constructor for FIMSLog. |
|
| 228 |
*/ |
|
| 229 | 9x |
FIMSLog() {}
|
| 230 | ||
| 231 |
/** |
|
| 232 |
* Destructor. If write_on_exit is set to true, |
|
| 233 |
* the log will be written to the disk in JSON format. |
|
| 234 |
*/ |
|
| 235 | 3x |
~FIMSLog() {
|
| 236 | 3x |
if (this->write_on_exit) {
|
| 237 | 3x |
std::ofstream log(this->path); |
| 238 | 3x |
log << this->get_log(); |
| 239 | 3x |
log.close(); |
| 240 |
} |
|
| 241 |
} |
|
| 242 | ||
| 243 |
/** |
|
| 244 |
* @brief Get the Absolute Path Without Dot Dot object |
|
| 245 |
* |
|
| 246 |
* Dot dot notation is for relative paths, where this function replaces |
|
| 247 |
* all dot dots with the actual full path. |
|
| 248 |
* |
|
| 249 |
* @param relativePath A path in your file system. |
|
| 250 |
* @return std::filesystem::path |
|
| 251 |
*/ |
|
| 252 | 20818x |
std::filesystem::path getAbsolutePathWithoutDotDot( |
| 253 |
const std::filesystem::path& relativePath) {
|
|
| 254 |
std::filesystem::path absolutePath = |
|
| 255 | 20818x |
std::filesystem::absolute(relativePath); |
| 256 | ||
| 257 | 20818x |
std::filesystem::path result; |
| 258 | 317332x |
for (const auto& part : absolutePath) {
|
| 259 | 296514x |
if (part == "..") {
|
| 260 | 26020x |
if (!result.empty()) {
|
| 261 | 26020x |
result = result.parent_path(); |
| 262 |
} |
|
| 263 |
} else {
|
|
| 264 | 270494x |
result /= part; |
| 265 |
} |
|
| 266 |
} |
|
| 267 | ||
| 268 | 41636x |
return result.generic_string(); |
| 269 |
} |
|
| 270 | ||
| 271 |
/** |
|
| 272 |
* Set a path for the log file. |
|
| 273 |
* |
|
| 274 |
* @param path |
|
| 275 |
*/ |
|
| 276 | ! |
void set_path(std::string path) { this->path = path; }
|
| 277 | ||
| 278 |
/** |
|
| 279 |
* Get the path for the log file. |
|
| 280 |
* |
|
| 281 |
* @return |
|
| 282 |
*/ |
|
| 283 | ! |
std::string get_path() { return this->path; }
|
| 284 | ||
| 285 |
/** |
|
| 286 |
* Add a "info" level message to the log. |
|
| 287 |
* |
|
| 288 |
* @param str |
|
| 289 |
* @param line |
|
| 290 |
* @param file |
|
| 291 |
* @param func |
|
| 292 |
*/ |
|
| 293 | 20805x |
void info_message(std::string str, int line, const char* file, |
| 294 |
const char* func) {
|
|
| 295 | 20805x |
std::filesystem::path relativePath = file; |
| 296 |
std::filesystem::path absolutePath = |
|
| 297 | 20805x |
getAbsolutePathWithoutDotDot(relativePath); |
| 298 | 20805x |
std::filesystem::path cwd = std::filesystem::current_path(); |
| 299 | 20805x |
std::stringstream ss; |
| 300 | 20805x |
auto now = std::chrono::system_clock::now(); |
| 301 | 20805x |
std::time_t now_time = std::chrono::system_clock::to_time_t(now); |
| 302 | 20805x |
std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); |
| 303 | ||
| 304 | 20805x |
LogEntry l; |
| 305 | 20805x |
l.timestamp = ctime_no_newline; |
| 306 | 20805x |
l.message = str; |
| 307 | 20805x |
l.level = "info"; |
| 308 | 20805x |
l.rank = this->log_entries.size(); |
| 309 | 20805x |
l.user = this->get_user(); |
| 310 | 20805x |
l.wd = cwd.generic_string(); |
| 311 | 20805x |
l.file = absolutePath.string(); |
| 312 | 20805x |
l.line = line; |
| 313 | 20805x |
l.routine = func; |
| 314 | 20805x |
this->log_entries.push_back(l); |
| 315 |
} |
|
| 316 | ||
| 317 |
/** |
|
| 318 |
* Add a "debug" level message to the log. |
|
| 319 |
* |
|
| 320 |
* @param str |
|
| 321 |
* @param line |
|
| 322 |
* @param file |
|
| 323 |
* @param func |
|
| 324 |
*/ |
|
| 325 |
void debug_message(std::string str, int line, const char* file, |
|
| 326 |
const char* func) {
|
|
| 327 |
std::filesystem::path relativePath = file; |
|
| 328 |
std::filesystem::path absolutePath = |
|
| 329 |
getAbsolutePathWithoutDotDot(relativePath); |
|
| 330 |
std::filesystem::path cwd = std::filesystem::current_path(); |
|
| 331 |
std::stringstream ss; |
|
| 332 |
auto now = std::chrono::system_clock::now(); |
|
| 333 |
std::time_t now_time = std::chrono::system_clock::to_time_t(now); |
|
| 334 |
std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); |
|
| 335 | ||
| 336 |
LogEntry l; |
|
| 337 |
l.timestamp = ctime_no_newline; |
|
| 338 |
l.message = str; |
|
| 339 |
l.level = "debug"; |
|
| 340 |
l.rank = this->log_entries.size(); |
|
| 341 |
l.user = this->get_user(); |
|
| 342 |
l.wd = cwd.generic_string(); |
|
| 343 |
l.file = absolutePath.string(); |
|
| 344 |
l.line = line; |
|
| 345 |
l.routine = func; |
|
| 346 |
this->log_entries.push_back(l); |
|
| 347 |
} |
|
| 348 | ||
| 349 |
/** |
|
| 350 |
* Add a "error" level message to the log. |
|
| 351 |
* |
|
| 352 |
* @param str |
|
| 353 |
* @param line |
|
| 354 |
* @param file |
|
| 355 |
* @param func |
|
| 356 |
*/ |
|
| 357 | ! |
void error_message(std::string str, int line, const char* file, |
| 358 |
const char* func) {
|
|
| 359 | ! |
this->error_count++; |
| 360 | ! |
std::filesystem::path relativePath = file; |
| 361 |
std::filesystem::path absolutePath = |
|
| 362 | ! |
getAbsolutePathWithoutDotDot(relativePath); |
| 363 | ! |
std::filesystem::path cwd = std::filesystem::current_path(); |
| 364 | ||
| 365 | ! |
std::stringstream ss; |
| 366 | ! |
auto now = std::chrono::system_clock::now(); |
| 367 | ! |
std::time_t now_time = std::chrono::system_clock::to_time_t(now); |
| 368 | ! |
std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); |
| 369 | ||
| 370 | ! |
LogEntry l; |
| 371 | ! |
l.timestamp = ctime_no_newline; |
| 372 | ! |
l.message = str; |
| 373 | ! |
l.level = "error"; |
| 374 | ! |
l.rank = this->log_entries.size(); |
| 375 | ! |
l.user = this->get_user(); |
| 376 | ! |
l.wd = cwd.generic_string(); |
| 377 | ! |
l.file = absolutePath.string(); |
| 378 | ! |
l.line = line; |
| 379 | ! |
l.routine = func; |
| 380 | ! |
this->log_entries.push_back(l); |
| 381 | ||
| 382 | ! |
if (this->throw_on_error) {
|
| 383 | ! |
std::stringstream ss; |
| 384 | ! |
ss << "\n\n" << l.to_string() << "\n\n"; |
| 385 | ! |
throw std::runtime_error(ss.str().c_str()); |
| 386 |
} |
|
| 387 |
} |
|
| 388 | ||
| 389 |
/** |
|
| 390 |
* Add a "warning" level message to the log. |
|
| 391 |
* |
|
| 392 |
* @param str |
|
| 393 |
* @param line |
|
| 394 |
* @param file |
|
| 395 |
* @param func |
|
| 396 |
*/ |
|
| 397 | 13x |
void warning_message(std::string str, int line, const char* file, |
| 398 |
const char* func) {
|
|
| 399 | 13x |
this->warning_count++; |
| 400 | 13x |
std::filesystem::path relativePath = file; |
| 401 |
std::filesystem::path absolutePath = |
|
| 402 | 13x |
getAbsolutePathWithoutDotDot(relativePath); |
| 403 | 13x |
std::filesystem::path cwd = std::filesystem::current_path(); |
| 404 | ||
| 405 | 13x |
std::stringstream ss; |
| 406 | 13x |
auto now = std::chrono::system_clock::now(); |
| 407 | 13x |
std::time_t now_time = std::chrono::system_clock::to_time_t(now); |
| 408 | 13x |
std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); |
| 409 | ||
| 410 | 13x |
LogEntry l; |
| 411 | 13x |
l.timestamp = ctime_no_newline; |
| 412 | 13x |
l.message = str; |
| 413 | 13x |
l.level = "warning"; |
| 414 | 13x |
l.rank = this->log_entries.size(); |
| 415 | 13x |
l.user = this->get_user(); |
| 416 | 13x |
l.wd = cwd.generic_string(); |
| 417 | 13x |
l.file = absolutePath.string(); |
| 418 | 13x |
l.line = line; |
| 419 | 13x |
l.routine = func; |
| 420 | 13x |
this->log_entries.push_back(l); |
| 421 |
} |
|
| 422 | ||
| 423 |
/** |
|
| 424 |
* Get the log as a string object. |
|
| 425 |
* |
|
| 426 |
* @return |
|
| 427 |
*/ |
|
| 428 | 3x |
std::string get_log() {
|
| 429 | 3x |
std::stringstream ss; |
| 430 | 3x |
if (log_entries.size() == 0) {
|
| 431 | 2x |
ss << "[\n]"; |
| 432 |
} else {
|
|
| 433 | 1x |
ss << "[\n"; |
| 434 | 72x |
for (size_t i = 0; i < log_entries.size() - 1; i++) {
|
| 435 | 71x |
ss << "{\n" << this->log_entries[i].to_string() << "},\n";
|
| 436 |
} |
|
| 437 |
ss << "{\n"
|
|
| 438 | 1x |
<< this->log_entries[log_entries.size() - 1].to_string() << "}\n]"; |
| 439 |
} |
|
| 440 | 6x |
return ss.str(); |
| 441 |
} |
|
| 442 | ||
| 443 |
/** |
|
| 444 |
* Return only error entries from the log. |
|
| 445 |
* |
|
| 446 |
* @return |
|
| 447 |
*/ |
|
| 448 | 13x |
std::string get_errors() {
|
| 449 | 13x |
std::stringstream ss; |
| 450 | 13x |
std::vector<LogEntry> errors; |
| 451 | 13089x |
for (size_t i = 0; i < log_entries.size(); i++) {
|
| 452 | 13076x |
if (log_entries[i].level == "error") {
|
| 453 | ! |
errors.push_back(this->log_entries[i]); |
| 454 |
} |
|
| 455 |
} |
|
| 456 | ||
| 457 | 13x |
if (errors.size() == 0) {
|
| 458 | 13x |
ss << "[\n]"; |
| 459 |
} else {
|
|
| 460 | ! |
ss << "[\n"; |
| 461 | ! |
for (size_t i = 0; i < errors.size() - 1; i++) {
|
| 462 | ! |
ss << "{\n" << errors[i].to_string() << "},\n";
|
| 463 |
} |
|
| 464 | ||
| 465 | ! |
ss << "{\n" << errors[errors.size() - 1].to_string() << "}\n]";
|
| 466 |
} |
|
| 467 | 26x |
return ss.str(); |
| 468 |
} |
|
| 469 | ||
| 470 |
/** |
|
| 471 |
* Return only warning entries from the log. |
|
| 472 |
* |
|
| 473 |
* @return |
|
| 474 |
*/ |
|
| 475 | 13x |
std::string get_warnings() {
|
| 476 | 13x |
std::stringstream ss; |
| 477 | 13x |
std::vector<LogEntry> warnings; |
| 478 | 13089x |
for (size_t i = 0; i < log_entries.size(); i++) {
|
| 479 | 13076x |
if (log_entries[i].level == "warning") {
|
| 480 | 13x |
warnings.push_back(this->log_entries[i]); |
| 481 |
} |
|
| 482 |
} |
|
| 483 | ||
| 484 | 13x |
if (warnings.size() == 0) {
|
| 485 | ! |
ss << "[\n]"; |
| 486 |
} else {
|
|
| 487 | 13x |
ss << "[\n"; |
| 488 |
for (size_t i = 0; i < warnings.size() - 1; i++) {
|
|
| 489 | ! |
ss << "{\n" << warnings[i].to_string() << "},\n";
|
| 490 |
} |
|
| 491 | ||
| 492 | 13x |
ss << "{\n" << warnings[warnings.size() - 1].to_string() << "}\n]";
|
| 493 |
} |
|
| 494 | 26x |
return ss.str(); |
| 495 |
} |
|
| 496 | ||
| 497 |
/** |
|
| 498 |
* Return only info entries from the log. |
|
| 499 |
* |
|
| 500 |
* @return |
|
| 501 |
*/ |
|
| 502 | 13x |
std::string get_info() {
|
| 503 | 13x |
std::stringstream ss; |
| 504 | 13x |
std::vector<LogEntry> info; |
| 505 | 13089x |
for (size_t i = 0; i < log_entries.size(); i++) {
|
| 506 | 13076x |
if (log_entries[i].level == "info") {
|
| 507 | 13063x |
info.push_back(this->log_entries[i]); |
| 508 |
} |
|
| 509 |
} |
|
| 510 | ||
| 511 | 13x |
if (info.size() == 0) {
|
| 512 | ! |
ss << "[\n]"; |
| 513 |
} else {
|
|
| 514 | 13x |
ss << "[\n"; |
| 515 | 13063x |
for (size_t i = 0; i < info.size() - 1; i++) {
|
| 516 | 13050x |
ss << "{\n" << info[i].to_string() << "},\n";
|
| 517 |
} |
|
| 518 | ||
| 519 | 13x |
ss << "{\n" << info[info.size() - 1].to_string() << "}\n]";
|
| 520 |
} |
|
| 521 | 26x |
return ss.str(); |
| 522 |
} |
|
| 523 | ||
| 524 |
/** |
|
| 525 |
* Query the log by module. |
|
| 526 |
* |
|
| 527 |
* @param module |
|
| 528 |
* @return |
|
| 529 |
*/ |
|
| 530 | ! |
std::string get_module(const std::string& module) {
|
| 531 | ! |
std::stringstream ss; |
| 532 | ! |
std::vector<LogEntry> info; |
| 533 | ! |
for (size_t i = 0; i < log_entries.size(); i++) {
|
| 534 | ! |
if (log_entries[i].file.find(module) != std::string::npos) {
|
| 535 | ! |
info.push_back(this->log_entries[i]); |
| 536 |
} |
|
| 537 |
} |
|
| 538 | ||
| 539 | ! |
if (info.size() == 0) {
|
| 540 | ! |
ss << "[\n]"; |
| 541 |
} else {
|
|
| 542 | ! |
ss << "[\n"; |
| 543 | ! |
for (size_t i = 0; i < info.size() - 1; i++) {
|
| 544 | ! |
ss << "{\n" << info[i].to_string() << "},\n";
|
| 545 |
} |
|
| 546 | ||
| 547 | ! |
ss << "{\n" << info[info.size() - 1].to_string() << "}\n]";
|
| 548 |
} |
|
| 549 | ! |
return ss.str(); |
| 550 |
} |
|
| 551 | ||
| 552 |
/** |
|
| 553 |
* @brief Get the counts of the number of errors |
|
| 554 |
*/ |
|
| 555 |
size_t get_error_count() const { return error_count; }
|
|
| 556 | ||
| 557 |
/** |
|
| 558 |
* @brief Get the counts of the number of warnings |
|
| 559 |
*/ |
|
| 560 |
size_t get_warning_count() const { return warning_count; }
|
|
| 561 | ||
| 562 |
/** |
|
| 563 |
* @brief Clears all pointers/references of a FIMS model. |
|
| 564 |
* |
|
| 565 |
*/ |
|
| 566 | 111x |
void clear() {
|
| 567 | 111x |
this->entries.clear(); |
| 568 | 111x |
this->log_entries.clear(); |
| 569 | 111x |
this->warning_count = 0; |
| 570 | 111x |
this->entry_number = 0; |
| 571 |
} |
|
| 572 |
}; |
|
| 573 | ||
| 574 |
std::shared_ptr<FIMSLog> FIMSLog::fims_log = std::make_shared<FIMSLog>(); |
|
| 575 | ||
| 576 |
} // namespace fims |
|
| 577 | ||
| 578 |
#ifdef FIMS_DEBUG |
|
| 579 | ||
| 580 |
#define FIMS_DEBUG_LOG(MESSAGE) \ |
|
| 581 |
FIMSLog::fims_log->debug_message(MESSAGE, __LINE__, __FILE__, \ |
|
| 582 |
__PRETTY_FUNCTION__); |
|
| 583 | ||
| 584 |
#else |
|
| 585 | ||
| 586 |
#define FIMS_DEBUG_LOG(MESSAGE) /**< Print MESSAGE to debug log */ |
|
| 587 | ||
| 588 |
#endif |
|
| 589 | ||
| 590 |
#define FIMS_INFO_LOG(MESSAGE) \ |
|
| 591 |
fims::FIMSLog::fims_log->info_message( \ |
|
| 592 |
MESSAGE, __LINE__, __FILE__, \ |
|
| 593 |
__PRETTY_FUNCTION__); /**< Print MESSAGE to info log */ |
|
| 594 | ||
| 595 |
#define FIMS_WARNING_LOG(MESSAGE) \ |
|
| 596 |
fims::FIMSLog::fims_log->warning_message( \ |
|
| 597 |
MESSAGE, __LINE__, __FILE__, \ |
|
| 598 |
__PRETTY_FUNCTION__); /**< Print MESSAGE to warning log */ |
|
| 599 | ||
| 600 |
#define FIMS_ERROR_LOG(MESSAGE) \ |
|
| 601 |
fims::FIMSLog::fims_log->error_message( \ |
|
| 602 |
MESSAGE, __LINE__, __FILE__, \ |
|
| 603 |
__PRETTY_FUNCTION__); /**< Print MESSAGE to error log */ |
|
| 604 | ||
| 605 |
#define FIMS_STR(s) #s /**< String of s */ |
|
| 606 | ||
| 607 |
namespace fims {
|
|
| 608 | ||
| 609 |
/** |
|
| 610 |
* Signal intercept function. Writes the log to the disk before |
|
| 611 |
* a crash occurs. |
|
| 612 |
* |
|
| 613 |
* @param sig |
|
| 614 |
*/ |
|
| 615 | ! |
void WriteAtExit(int sig) {
|
| 616 | ! |
std::string signal_error = "NA"; |
| 617 | ! |
switch (sig) {
|
| 618 | ! |
case SIGSEGV: |
| 619 | ! |
signal_error = "Invalid memory access (segmentation fault)"; |
| 620 | ! |
break; |
| 621 | ! |
case SIGINT: |
| 622 | ! |
signal_error = "External interrupt, possibly initiated by the user."; |
| 623 | ! |
break; |
| 624 | ! |
case SIGABRT: |
| 625 |
signal_error = |
|
| 626 | ! |
"Abnormal termination condition, possible call to std::abort."; |
| 627 | ! |
break; |
| 628 | ! |
case SIGFPE: |
| 629 | ! |
signal_error = "Erroneous arithmetic operation."; |
| 630 | ! |
break; |
| 631 | ! |
case SIGILL: |
| 632 | ! |
signal_error = "Invalid program image or invalid instruction"; |
| 633 | ! |
break; |
| 634 | ! |
case SIGTERM: |
| 635 | ! |
signal_error = "Termination request, sent to the program."; |
| 636 | ! |
break; |
| 637 | ! |
default: |
| 638 | ! |
signal_error = "Unknown signal thrown"; |
| 639 |
} |
|
| 640 | ||
| 641 | ! |
FIMSLog::fims_log->error_message(signal_error, -999, "?", "?"); |
| 642 | ||
| 643 | ! |
if (FIMSLog::fims_log->write_on_exit) {
|
| 644 | ! |
std::ofstream log(FIMSLog::fims_log->get_path()); |
| 645 | ! |
log << FIMSLog::fims_log->get_log(); |
| 646 | ! |
log.close(); |
| 647 |
} |
|
| 648 | ! |
std::signal(sig, SIG_DFL); |
| 649 | ! |
raise(sig); |
| 650 |
} |
|
| 651 | ||
| 652 |
/** |
|
| 653 |
* Converts an object T to a string. |
|
| 654 |
* |
|
| 655 |
* @param v |
|
| 656 |
* @return |
|
| 657 |
*/ |
|
| 658 |
template <typename T> |
|
| 659 | 39595x |
std::string to_string(T v) {
|
| 660 | 39595x |
std::stringstream ss; |
| 661 | 39595x |
ss << v; |
| 662 | 79190x |
return ss.str(); |
| 663 |
} |
|
| 664 | ||
| 665 |
} // namespace fims |
|
| 666 | ||
| 667 |
#endif /* TRAITS_HPP */ |
| 1 |
/** |
|
| 2 |
* @file fims_math.hpp |
|
| 3 |
* @brief A collection of mathematical functions used in FIMS. |
|
| 4 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 5 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 6 |
* folder for reuse information. |
|
| 7 |
*/ |
|
| 8 |
#ifndef FIMS_MATH_HPP |
|
| 9 |
#define FIMS_MATH_HPP |
|
| 10 | ||
| 11 |
// note: this is modeling platform specific, must be controlled by |
|
| 12 |
// preprocessing macros |
|
| 13 |
#include <cmath> |
|
| 14 |
#include <random> |
|
| 15 |
#include <sstream> |
|
| 16 | ||
| 17 |
#include "../interface/interface.hpp" |
|
| 18 |
#include "fims_vector.hpp" |
|
| 19 | ||
| 20 |
namespace fims_math {
|
|
| 21 |
#ifdef STD_LIB |
|
| 22 | ||
| 23 |
/** |
|
| 24 |
* @brief The exponential function. |
|
| 25 |
* |
|
| 26 |
* @param x value to exponentiate. Please use fims_math::exp<double>(x) if x is |
|
| 27 |
* an integer. |
|
| 28 |
* @return the exponentiated value |
|
| 29 |
*/ |
|
| 30 |
template <class Type> |
|
| 31 |
inline const Type exp(const Type &x) {
|
|
| 32 |
return std::exp(x); |
|
| 33 |
} |
|
| 34 | ||
| 35 |
/** |
|
| 36 |
* @brief The natural log function (base e) |
|
| 37 |
* @param x the value to take the log of. Please use fims_math::log<double>(x) |
|
| 38 |
* if x is an integer. |
|
| 39 |
* @return |
|
| 40 |
*/ |
|
| 41 |
template <class Type> |
|
| 42 |
inline const Type log(const Type &x) {
|
|
| 43 |
return std::log(x); |
|
| 44 |
} |
|
| 45 | ||
| 46 |
template <class Type> |
|
| 47 |
inline const Type cos(const Type &x) {
|
|
| 48 |
return std::cos(x); |
|
| 49 |
} |
|
| 50 | ||
| 51 |
template <class Type> |
|
| 52 |
inline const Type sqrt(const Type &x) {
|
|
| 53 |
return std::sqrt(x); |
|
| 54 |
} |
|
| 55 | ||
| 56 |
template <class Type> |
|
| 57 |
inline const Type pow(const Type &x, const Type &y) {
|
|
| 58 |
return std::pow(x, y); |
|
| 59 |
} |
|
| 60 | ||
| 61 |
template <class Type> |
|
| 62 |
inline const Type lgamma(const Type &x) {
|
|
| 63 |
return std::lgamma(x); |
|
| 64 |
} |
|
| 65 |
#endif |
|
| 66 | ||
| 67 |
#ifdef TMB_MODEL |
|
| 68 | ||
| 69 |
// Add the following line to CMakeLists.txt to enable documentation of TMB_MODEL |
|
| 70 |
// in doxygen or none of the following is rendered. |
|
| 71 |
// set(DOXYGEN_PREDEFINED "TMB_MODEL=1" "ENABLE_TMB_CODE") |
|
| 72 | ||
| 73 |
/** |
|
| 74 |
* @brief The exponential function for a TMB model. The function specifically |
|
| 75 |
* uses std::exp, defined in cmath header, instead of ::exp because the |
|
| 76 |
* standard library function works with TMBad library, which is designed to |
|
| 77 |
* recognize and apply its automatic differentiation capabilities to functions |
|
| 78 |
* from the standard library. Also note that this function cannot be tested |
|
| 79 |
* using the compilation flag -DTMB_MODEL through CMake and Google Test. |
|
| 80 |
* @param x The value to exponentiate. Please use fims_math::exp<double>(x) if |
|
| 81 |
* x is an integer. |
|
| 82 |
* @return The exponentiated value of x. |
|
| 83 |
*/ |
|
| 84 |
template <class Type> |
|
| 85 | 2809958x |
inline const Type exp(const Type &x) {
|
| 86 |
// use std::exp for double type, look for TMB version of exp if AD type |
|
| 87 |
using std::exp; |
|
| 88 | 2809958x |
return exp(x); |
| 89 |
} |
|
| 90 | ||
| 91 |
/** |
|
| 92 |
* @brief The natural log function (base e) for a TMB model. The function |
|
| 93 |
* specifically uses std::log, defined in cmath header, instead of ::log |
|
| 94 |
* because the standard library function works with TMBad library, which is |
|
| 95 |
* designed to recognize and apply its automatic differentiation capabilities |
|
| 96 |
* to functions from the standard library. Also note that this function cannot |
|
| 97 |
* be tested using the compilation flag -DTMB_MODEL through CMake and Google |
|
| 98 |
* Test. |
|
| 99 |
* @param x The value to log. Please use fims_math::log<double>(x) if x is an |
|
| 100 |
* integer. |
|
| 101 |
* @return The natural log of x. |
|
| 102 |
*/ |
|
| 103 |
template <class Type> |
|
| 104 | 16550x |
inline const Type log(const Type &x) {
|
| 105 |
// use std::log for double type, look for TMB version of log if AD type |
|
| 106 |
using std::log; |
|
| 107 | 16550x |
return log(x); |
| 108 |
} |
|
| 109 | ||
| 110 |
/** |
|
| 111 |
* @brief The cosine of an angle function for a TMB model. The function |
|
| 112 |
* specifically uses std::cos, defined in cmath header, instead of ::cos |
|
| 113 |
* because the standard library function works with TMBad library, which is |
|
| 114 |
* designed to recognize and apply its automatic differentiation capabilities |
|
| 115 |
* to functions from the standard library. Also note that this function cannot |
|
| 116 |
* be tested using the compilation flag -DTMB_MODEL through CMake and Google |
|
| 117 |
* Test. |
|
| 118 |
* @param x The value to take the cosine of. Please use |
|
| 119 |
* fims_math::cos<double>(x) if x is an integer. |
|
| 120 |
* @return The cosine of the angle x. |
|
| 121 |
*/ |
|
| 122 |
template <class Type> |
|
| 123 |
inline const Type cos(const Type &x) {
|
|
| 124 |
// use std::cos for double type, look for TMB version of cos if AD type |
|
| 125 |
using std::cos; |
|
| 126 |
return cos(x); |
|
| 127 |
} |
|
| 128 | ||
| 129 |
/** |
|
| 130 |
* @brief The square root function for a TMB model. The function specifically |
|
| 131 |
* uses std::sqrt, defined in cmath header, instead of ::sqrt because the |
|
| 132 |
* standard library function works with TMBad library, which is designed to |
|
| 133 |
* recognize and apply its automatic differentiation capabilities to functions |
|
| 134 |
* from the standard library. Also note that this function cannot be tested |
|
| 135 |
* using the compilation flag -DTMB_MODEL through CMake and Google Test. |
|
| 136 |
* @param x The value to take the square root of. Please use |
|
| 137 |
* fims_math::sqrt<double>(x) if x is an integer. |
|
| 138 |
* @return The square root of x. |
|
| 139 |
*/ |
|
| 140 |
template <class Type> |
|
| 141 |
inline const Type sqrt(const Type &x) {
|
|
| 142 |
// use std::std for double type, look for TMB version of std if AD type |
|
| 143 |
using std::sqrt; |
|
| 144 |
return sqrt(x); |
|
| 145 |
} |
|
| 146 | ||
| 147 |
/** |
|
| 148 |
* @brief The power function for a TMB model. The function specifically uses |
|
| 149 |
* std::pow, defined in cmath header, instead of ::pow because the standard |
|
| 150 |
* library function works with TMBad library, which is designed to recognize |
|
| 151 |
* and apply its automatic differentiation capabilities to functions from the |
|
| 152 |
* standard library. Also note that this function cannot be tested using the |
|
| 153 |
* compilation flag -DTMB_MODEL through CMake and Google Test. |
|
| 154 |
* @param x The value to take the power of. Please use |
|
| 155 |
* fims_math::pow<double>(x) if x is an integer. |
|
| 156 |
* @param y The exponent to raise x to. |
|
| 157 |
* @return The power of x. |
|
| 158 |
*/ |
|
| 159 |
template <class Type> |
|
| 160 |
inline const Type pow(const Type &x, const Type &y) {
|
|
| 161 |
// use std::pow for double type, look for TMB version of pow if AD type |
|
| 162 |
using std::pow; |
|
| 163 |
return pow(x, y); |
|
| 164 |
} |
|
| 165 | ||
| 166 |
/** |
|
| 167 |
* @brief Computes the natural logarithm of the absolute value of the [gamma |
|
| 168 |
* function](https://en.wikipedia.org/wiki/Gamma_function) of x for a TMB |
|
| 169 |
* model. The function specifically uses std::lgamma, defined in cmath header, |
|
| 170 |
* instead of ::lgamma because the standard library function works with TMBad |
|
| 171 |
* library, which is designed to recognize and apply its automatic |
|
| 172 |
* differentiation capabilities to functions from the standard library. Also |
|
| 173 |
* note that this function cannot be tested using the compilation flag |
|
| 174 |
* -DTMB_MODEL through CMake and Google Test. |
|
| 175 |
* @param x The value to take the natural logarithm of the absolute value of |
|
| 176 |
* the gamma function of. Please use fims_math::lgamma<double>(x) if x is an |
|
| 177 |
* integer. |
|
| 178 |
* @return The natural logarithm of the absolute value of the gamma function of |
|
| 179 |
* x. |
|
| 180 |
*/ |
|
| 181 |
template <class Type> |
|
| 182 |
inline const Type lgamma(const Type &x) {
|
|
| 183 |
// use std::lgamma for double type, look for TMB version of lgamma if AD type |
|
| 184 |
using std::lgamma; |
|
| 185 |
return lgamma(x); |
|
| 186 |
} |
|
| 187 | ||
| 188 |
#endif |
|
| 189 | ||
| 190 |
/** |
|
| 191 |
* @brief The general logistic function |
|
| 192 |
* |
|
| 193 |
* \f$ \frac{1.0}{ 1.0 + exp(-1.0 * slope (x - inflection_point))} \f$
|
|
| 194 |
* |
|
| 195 |
* @param inflection_point the inflection point of the logistic function |
|
| 196 |
* @param slope the slope of the logistic function |
|
| 197 |
* @param x the index the logistic function should be evaluated at |
|
| 198 |
* @return |
|
| 199 |
*/ |
|
| 200 |
template <class Type> |
|
| 201 | 1443246x |
inline const Type logistic(const Type &inflection_point, const Type &slope, |
| 202 |
const Type &x) {
|
|
| 203 | 273456x |
return static_cast<Type>(1.0) / |
| 204 | 1443246x |
(static_cast<Type>(1.0) + |
| 205 | 1716702x |
exp(Type(-1.0) * slope * (x - inflection_point))); |
| 206 |
} |
|
| 207 | ||
| 208 |
/** |
|
| 209 |
* @brief A logit function for bounding of parameters |
|
| 210 |
* |
|
| 211 |
* \f$ -\mathrm{log}(b-x) + \mathrm{log}(x-a) \f$
|
|
| 212 |
* @param a lower bound |
|
| 213 |
* @param b upper bound |
|
| 214 |
* @param x the parameter in bounded space |
|
| 215 |
* @return the parameter in real space |
|
| 216 |
* |
|
| 217 |
*/ |
|
| 218 |
template <class Type> |
|
| 219 | 5x |
inline const Type logit(const Type &a, const Type &b, const Type &x) {
|
| 220 | 5x |
return -fims_math::log(b - x) + fims_math::log(x - a); |
| 221 |
} |
|
| 222 | ||
| 223 |
/** |
|
| 224 |
* @brief An inverse logit function for bounding of parameters |
|
| 225 |
* |
|
| 226 |
* \f$ a+\frac{b-a}{1+\mathrm{exp}(-\mathrm{logit}(x))}\f$
|
|
| 227 |
* @param a lower bound |
|
| 228 |
* @param b upper bound |
|
| 229 |
* @param logit_x the parameter in real space |
|
| 230 |
* @return the parameter in bounded space |
|
| 231 |
* |
|
| 232 |
*/ |
|
| 233 |
template <class Type> |
|
| 234 | 17114x |
inline const Type inv_logit(const Type &a, const Type &b, const Type &logit_x) {
|
| 235 | 17114x |
return a + (b - a) / (static_cast<Type>(1.0) + fims_math::exp(-logit_x)); |
| 236 |
} |
|
| 237 | ||
| 238 |
/** |
|
| 239 |
* @brief The general double logistic function |
|
| 240 |
* |
|
| 241 |
* \f$ \frac{1.0}{ 1.0 + exp(-1.0 * slope_{asc} (x - inflection_point_{asc}))}
|
|
| 242 |
* \left(1-\frac{1.0}{ 1.0 + exp(-1.0 * slope_{desc} (x -
|
|
| 243 |
* inflection_point_{desc}))} \right)\f$
|
|
| 244 |
* |
|
| 245 |
* @param inflection_point_asc the inflection point of the ascending limb of the |
|
| 246 |
* double logistic function |
|
| 247 |
* @param slope_asc the slope of the ascending limb of the double logistic |
|
| 248 |
* function |
|
| 249 |
* @param inflection_point_desc the inflection point of the descending limb of |
|
| 250 |
* the double logistic function, where inflection_point_desc > |
|
| 251 |
* inflection_point_asc |
|
| 252 |
* @param slope_desc the slope of the descending limb of the double logistic |
|
| 253 |
* function |
|
| 254 |
* @param x the index the logistic function should be evaluated at |
|
| 255 |
* @return |
|
| 256 |
*/ |
|
| 257 | ||
| 258 |
template <class Type> |
|
| 259 |
inline const Type double_logistic(const Type &inflection_point_asc, |
|
| 260 |
const Type &slope_asc, |
|
| 261 |
const Type &inflection_point_desc, |
|
| 262 |
const Type &slope_desc, const Type &x) {
|
|
| 263 |
return (static_cast<Type>(1.0)) / |
|
| 264 |
(static_cast<Type>(1.0) + |
|
| 265 |
exp(Type(-1.0) * slope_asc * (x - inflection_point_asc))) * |
|
| 266 |
(static_cast<Type>(1.0) - |
|
| 267 |
(static_cast<Type>(1.0)) / |
|
| 268 |
(static_cast<Type>(1.0) + |
|
| 269 |
exp(Type(-1.0) * slope_desc * (x - inflection_point_desc)))); |
|
| 270 |
} |
|
| 271 | ||
| 272 |
/** |
|
| 273 |
* |
|
| 274 |
* Used when x could evaluate to zero, which will result in a NaN for |
|
| 275 |
* derivative values. |
|
| 276 |
* |
|
| 277 |
* Evaluates: |
|
| 278 |
* |
|
| 279 |
* \f$ (x^2+C)^.5 \f$ |
|
| 280 |
* |
|
| 281 |
* @param x value to keep positive |
|
| 282 |
* @param C default = 1e-5 |
|
| 283 |
* @return |
|
| 284 |
*/ |
|
| 285 |
template <class Type> |
|
| 286 |
const Type ad_fabs(const Type &x, Type C = 1e-5) {
|
|
| 287 |
return sqrt((x * x) + C); |
|
| 288 |
} |
|
| 289 | ||
| 290 |
/** |
|
| 291 |
* |
|
| 292 |
* Returns the minimum between a and b in a continuous manner using: |
|
| 293 |
* |
|
| 294 |
* (a + b - fims_math::ad_fabs(a - b))*.5; |
|
| 295 |
* Reference: \ref fims_math::ad_fabs() |
|
| 296 |
* |
|
| 297 |
* This is an approximation with minimal error. |
|
| 298 |
* |
|
| 299 |
* @param a |
|
| 300 |
* @param b |
|
| 301 |
* @param C default = 1e-5 |
|
| 302 |
* @return |
|
| 303 |
*/ |
|
| 304 | ||
| 305 |
template <typename Type> |
|
| 306 |
inline const Type ad_min(const Type &a, const Type &b, Type C = 1e-5) {
|
|
| 307 |
return (a + b - fims_math::ad_fabs(a - b, C)) * static_cast<Type>(0.5); |
|
| 308 |
} |
|
| 309 | ||
| 310 |
/** |
|
| 311 |
* Returns the maximum between a and b in a continuous manner using: |
|
| 312 |
* |
|
| 313 |
* (a + b + fims_math::ad_fabs(a - b)) *.5; |
|
| 314 |
* Reference: \ref fims_math::ad_fabs() |
|
| 315 |
* This is an approximation with minimal error. |
|
| 316 |
* |
|
| 317 |
* @param a |
|
| 318 |
* @param b |
|
| 319 |
* @param C default = 1e-5 |
|
| 320 |
* @return |
|
| 321 |
*/ |
|
| 322 |
template <typename Type> |
|
| 323 |
inline const Type ad_max(const Type &a, const Type &b, Type C = 1e-5) {
|
|
| 324 |
return (a + b + fims_math::ad_fabs(a - b, C)) * static_cast<Type>(.5); |
|
| 325 |
} |
|
| 326 | ||
| 327 |
/** |
|
| 328 |
* Sum elements of a vector |
|
| 329 |
* |
|
| 330 |
* @brief |
|
| 331 |
* |
|
| 332 |
* @param v A vector of constants. |
|
| 333 |
* @return A single numeric value. |
|
| 334 |
*/ |
|
| 335 |
template <class T> |
|
| 336 |
T sum(const std::vector<T> &v) {
|
|
| 337 |
T ret = 0.0; |
|
| 338 |
for (int i = 0; i < v.size(); i++) {
|
|
| 339 |
ret += v[i]; |
|
| 340 |
} |
|
| 341 |
return ret; |
|
| 342 |
} |
|
| 343 | ||
| 344 |
/** |
|
| 345 |
* Sum elements of a vector |
|
| 346 |
* |
|
| 347 |
* @brief |
|
| 348 |
* |
|
| 349 |
* @param v A vector of constants. |
|
| 350 |
* @return A single numeric value. |
|
| 351 |
*/ |
|
| 352 |
template <class T> |
|
| 353 |
T sum(const fims::Vector<T> &v) {
|
|
| 354 |
T ret = 0.0; |
|
| 355 |
for (int i = 0; i < v.size(); i++) {
|
|
| 356 |
ret += v[i]; |
|
| 357 |
} |
|
| 358 |
return ret; |
|
| 359 |
} |
|
| 360 | ||
| 361 |
} // namespace fims_math |
|
| 362 | ||
| 363 |
#endif /* FIMS_MATH_HPP */ |
| 1 |
/** |
|
| 2 |
* @file fims_vector.hpp |
|
| 3 |
* @brief Establishes the FIMS Vector class. |
|
| 4 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 5 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 6 |
* folder for reuse information. |
|
| 7 |
*/ |
|
| 8 |
#ifndef FIMS_VECTOR_HPP |
|
| 9 |
#define FIMS_VECTOR_HPP |
|
| 10 | ||
| 11 |
#include "../interface/interface.hpp" |
|
| 12 |
#include <ostream> |
|
| 13 |
#include <iomanip> |
|
| 14 | ||
| 15 |
namespace fims {
|
|
| 16 | ||
| 17 |
/** |
|
| 18 |
* Wrapper class for std::vector types. If this file is compiled with |
|
| 19 |
* -DTMB_MODEL, conversion operators are defined for TMB vector types. |
|
| 20 |
* |
|
| 21 |
* All std::vector functions are copied over from the std library. While some of |
|
| 22 |
* these may not be called explicitly in FIMS, they may be required to run other |
|
| 23 |
* std library functions. |
|
| 24 |
* |
|
| 25 |
*/ |
|
| 26 |
template <typename Type> |
|
| 27 |
class Vector {
|
|
| 28 |
std::vector<Type> vec_m; |
|
| 29 |
/** |
|
| 30 |
* @brief friend comparison operator. Allows the operator to see private |
|
| 31 |
* members of fims::Vector<Type>. |
|
| 32 |
*/ |
|
| 33 |
template <typename T> |
|
| 34 |
friend bool operator==(const fims::Vector<T> &lhs, |
|
| 35 |
const fims::Vector<T> &rhs); |
|
| 36 | ||
| 37 |
public: |
|
| 38 |
// Member Types |
|
| 39 | ||
| 40 |
typedef |
|
| 41 |
typename std::vector<Type>::value_type value_type; /*!<Member type Type>*/ |
|
| 42 |
typedef typename std::vector<Type>::allocator_type |
|
| 43 |
allocator_type; /*!<Allocator for type Type>*/ |
|
| 44 |
typedef typename std::vector<Type>::size_type size_type; /*!<Size type>*/ |
|
| 45 |
typedef typename std::vector<Type>::difference_type |
|
| 46 |
difference_type; /*!<Difference type>*/ |
|
| 47 |
typedef typename std::vector<Type>::reference |
|
| 48 |
reference; /*!<Reference type &Type>*/ |
|
| 49 |
typedef typename std::vector<Type>::const_reference |
|
| 50 |
const_reference; /*!<Constant reference type const &Type>*/ |
|
| 51 |
typedef typename std::vector<Type>::pointer pointer; /*!<Pointer type Type*>*/ |
|
| 52 |
typedef typename std::vector<Type>::const_pointer |
|
| 53 |
const_pointer; /*!<Constant pointer type const Type*>*/ |
|
| 54 |
typedef typename std::vector<Type>::iterator iterator; /*!<Iterator>*/ |
|
| 55 |
typedef typename std::vector<Type>::const_iterator |
|
| 56 |
const_iterator; /*!<Constant iterator>*/ |
|
| 57 |
typedef typename std::vector<Type>::reverse_iterator |
|
| 58 |
reverse_iterator; /*!<Reverse iterator>*/ |
|
| 59 |
typedef typename std::vector<Type>::const_reverse_iterator |
|
| 60 |
const_reverse_iterator; /*!<Constant reverse iterator>*/ |
|
| 61 | ||
| 62 |
// Constructors |
|
| 63 | ||
| 64 |
/** |
|
| 65 |
* Default constructor. |
|
| 66 |
*/ |
|
| 67 | 143364x |
Vector() {}
|
| 68 | ||
| 69 |
/** |
|
| 70 |
* @brief Constructs a Vector of length "size" and sets the elements with the |
|
| 71 |
* value from input "value". |
|
| 72 |
*/ |
|
| 73 | 5078x |
Vector(size_t size, const Type &value = Type()) {
|
| 74 | 5078x |
this->vec_m.resize(size, value); |
| 75 |
} |
|
| 76 | ||
| 77 |
/** |
|
| 78 |
* @brief Copy constructor. |
|
| 79 |
*/ |
|
| 80 | 38728x |
Vector(const Vector<Type> &other) {
|
| 81 | 38728x |
this->vec_m.resize(other.size()); |
| 82 | 1663992x |
for (size_t i = 0; i < this->vec_m.size(); i++) {
|
| 83 | 1625264x |
this->vec_m[i] = other[i]; |
| 84 |
} |
|
| 85 |
} |
|
| 86 | ||
| 87 |
/** |
|
| 88 |
* @brief Assignment operator for fims::Vector. |
|
| 89 |
* |
|
| 90 |
* @details Assigns the contents of another fims::Vector to this |
|
| 91 |
* vector. Cleans up existing contents and performs a deep copy. |
|
| 92 |
* |
|
| 93 |
* @param other The vector to assign from. |
|
| 94 |
* @return Reference to this vector. |
|
| 95 |
*/ |
|
| 96 | 15694x |
Vector &operator=(const Vector &other) {
|
| 97 | 15694x |
if (this != &other) {
|
| 98 |
// clean up existing |
|
| 99 | 15694x |
this->~Vector(); |
| 100 |
// copy construct into *this |
|
| 101 | 15694x |
new (this) Vector(other); |
| 102 |
} |
|
| 103 | 15694x |
return *this; |
| 104 |
} |
|
| 105 | ||
| 106 |
/** |
|
| 107 |
* @brief Initialization constructor from std::vector<Type> type. |
|
| 108 |
*/ |
|
| 109 | 854x |
Vector(const std::vector<Type> &other) { this->vec_m = other; }
|
| 110 | ||
| 111 |
// TMB specific constructor |
|
| 112 |
#ifdef TMB_MODEL |
|
| 113 | ||
| 114 |
/** |
|
| 115 |
* @brief Initialization constructor from tmbutils::vector<Type> type. |
|
| 116 |
*/ |
|
| 117 | 3264x |
Vector(const tmbutils::vector<Type> &other) {
|
| 118 | 3264x |
this->vec_m.resize(other.size()); |
| 119 | 271040x |
for (size_t i = 0; i < this->vec_m.size(); i++) {
|
| 120 | 267776x |
this->vec_m[i] = other[i]; |
| 121 |
} |
|
| 122 |
} |
|
| 123 | ||
| 124 |
#endif |
|
| 125 | ||
| 126 |
/** |
|
| 127 |
* @brief Initialization constructor from std::initializer_list<Type> type. |
|
| 128 |
*/ |
|
| 129 | 7632x |
Vector(std::initializer_list<Type> init) {
|
| 130 | 7632x |
this->vec_m = std::vector<Type>(init); |
| 131 |
} |
|
| 132 | ||
| 133 |
/** |
|
| 134 |
* The following are std::vector functions copied over from the standard |
|
| 135 |
* library. While some of these may not be called explicitly in FIMS, they may |
|
| 136 |
* be required to run other std library functions. |
|
| 137 |
*/ |
|
| 138 | ||
| 139 |
/** |
|
| 140 |
* @brief Returns a reference to the element at specified location pos. No |
|
| 141 |
* bounds checking is performed. |
|
| 142 |
*/ |
|
| 143 | 107561516x |
inline Type &operator[](size_t pos) {
|
| 144 | 107561516x |
if (pos >= this->size()) {
|
| 145 | ! |
throw std::invalid_argument("fims::Vector out of bounds");
|
| 146 |
} |
|
| 147 | 107561516x |
return this->vec_m[pos]; |
| 148 |
} |
|
| 149 | ||
| 150 |
/** |
|
| 151 |
* @brief Returns a constant reference to the element at specified location |
|
| 152 |
* pos. No bounds checking is performed. |
|
| 153 |
*/ |
|
| 154 | 2527606x |
inline const Type &operator[](size_t n) const {
|
| 155 | 2527606x |
if (n >= this->size()) {
|
| 156 | ! |
throw std::invalid_argument("fims::Vector out of bounds");
|
| 157 |
} |
|
| 158 | 2527606x |
return this->vec_m[n]; |
| 159 |
} |
|
| 160 | ||
| 161 |
/** |
|
| 162 |
* @brief Returns a reference to the element at specified location pos. Bounds |
|
| 163 |
* checking is performed. |
|
| 164 |
*/ |
|
| 165 | 461580x |
inline Type &at(size_t n) { return this->vec_m.at(n); }
|
| 166 | ||
| 167 |
/** |
|
| 168 |
* @brief Returns a constant reference to the element at specified location |
|
| 169 |
* pos. Bounds checking is performed. |
|
| 170 |
*/ |
|
| 171 |
inline const Type &at(size_t n) const { return this->vec_m.at(n); }
|
|
| 172 | ||
| 173 |
/** |
|
| 174 |
* @brief If this vector is size 1 and pos is greater than zero, |
|
| 175 |
* the first index is returned. If this vector has size |
|
| 176 |
* greater than 1 and pos is greater than size, a invalid_argument |
|
| 177 |
* exception is thrown. Otherwise, the value at index pos is returned. |
|
| 178 |
* |
|
| 179 |
* @param pos |
|
| 180 |
* @return a constant reference to the element at specified location |
|
| 181 |
*/ |
|
| 182 | 461580x |
inline Type &get_force_scalar(size_t pos) {
|
| 183 | 461580x |
if (this->size() == 1 && pos > 0) {
|
| 184 | 412956x |
return this->at(0); |
| 185 |
} else if (this->size() > 1 && pos >= this->size()) {
|
|
| 186 | ! |
throw std::invalid_argument( |
| 187 |
"force_get fims::Vector index out of bounds."); |
|
| 188 |
} else {
|
|
| 189 | 48624x |
return this->at(pos); |
| 190 |
} |
|
| 191 |
} |
|
| 192 | ||
| 193 |
/** |
|
| 194 |
* @brief Returns a reference to the first element in the container. |
|
| 195 |
*/ |
|
| 196 |
inline reference front() { return this->vec_m.front(); }
|
|
| 197 | ||
| 198 |
/** |
|
| 199 |
* @brief Returns a constant reference to the first element in the container. |
|
| 200 |
*/ |
|
| 201 |
inline const_reference front() const { return this->vec_m.front(); }
|
|
| 202 | ||
| 203 |
/** |
|
| 204 |
* @brief Returns a reference to the last element in the container. |
|
| 205 |
*/ |
|
| 206 |
inline reference back() { return this->vec_m.back(); }
|
|
| 207 | ||
| 208 |
/** |
|
| 209 |
* @brief Returns a constant reference to the last element in the container. |
|
| 210 |
*/ |
|
| 211 |
inline const_reference back() const { return this->vec_m.back(); }
|
|
| 212 | ||
| 213 |
/** |
|
| 214 |
* @brief Returns a pointer to the underlying data array. |
|
| 215 |
*/ |
|
| 216 |
inline pointer data() { return this->vec_m.data(); }
|
|
| 217 | ||
| 218 |
/** |
|
| 219 |
* @brief Returns a constant pointer to the underlying data array. |
|
| 220 |
*/ |
|
| 221 |
inline const_pointer data() const { return this->vec_m.data(); }
|
|
| 222 | ||
| 223 |
// iterators |
|
| 224 | ||
| 225 |
/** |
|
| 226 |
* @brief Returns an iterator to the first element of the vector. |
|
| 227 |
*/ |
|
| 228 | 63566x |
inline iterator begin() { return this->vec_m.begin(); }
|
| 229 | ||
| 230 |
/** |
|
| 231 |
* @brief Returns an iterator to the element following the last element of the |
|
| 232 |
* vector. |
|
| 233 |
*/ |
|
| 234 | 119372x |
inline iterator end() { return this->vec_m.end(); }
|
| 235 | ||
| 236 |
/** |
|
| 237 |
* @brief Returns a reverse iterator to the first element of the reversed |
|
| 238 |
* vector. It corresponds to the last element of the non-reversed vector. |
|
| 239 |
*/ |
|
| 240 |
inline reverse_iterator rbegin() { return this->vec_m.rbegin(); }
|
|
| 241 | ||
| 242 |
/** |
|
| 243 |
* @brief Returns a reverse iterator to the element following the last element |
|
| 244 |
* of the reversed vector. It corresponds to the element preceding the first |
|
| 245 |
* element of the non-reversed vector. |
|
| 246 |
*/ |
|
| 247 |
inline reverse_iterator rend() { return this->vec_m.rend(); }
|
|
| 248 | ||
| 249 |
/** |
|
| 250 |
* @brief Returns a constant reverse iterator to the first element of the |
|
| 251 |
* reversed vector. It corresponds to the last element of the non-reversed |
|
| 252 |
* vector. |
|
| 253 |
*/ |
|
| 254 |
inline const_reverse_iterator rbegin() const { return this->vec_m.rbegin(); }
|
|
| 255 | ||
| 256 |
/** |
|
| 257 |
* @brief Returns a constant reverse iterator to the element following the |
|
| 258 |
* last element of the reversed vector. It corresponds to the element |
|
| 259 |
* preceding the first element of the non-reversed vector. |
|
| 260 |
*/ |
|
| 261 |
inline const_reverse_iterator rend() const { return this->vec_m.rend(); }
|
|
| 262 | ||
| 263 |
// capacity |
|
| 264 | ||
| 265 |
/** |
|
| 266 |
* @brief Checks whether the container is empty. |
|
| 267 |
*/ |
|
| 268 |
inline bool empty() { return this->vec_m.empty(); }
|
|
| 269 | ||
| 270 |
/** |
|
| 271 |
* @brief Returns the number of elements. |
|
| 272 |
*/ |
|
| 273 | 115626362x |
inline size_type size() const { return this->vec_m.size(); }
|
| 274 | ||
| 275 |
/** |
|
| 276 |
* @brief Returns the maximum possible number of elements. |
|
| 277 |
*/ |
|
| 278 |
inline size_type max_size() const { return this->vec_m.max_size(); }
|
|
| 279 | ||
| 280 |
/** |
|
| 281 |
* @brief Reserves storage. |
|
| 282 |
*/ |
|
| 283 |
inline void reserve(size_type cap) { this->vec_m.reserve(cap); }
|
|
| 284 | ||
| 285 |
/** |
|
| 286 |
* @brief Returns the number of elements that can be held in currently |
|
| 287 |
* allocated storage. |
|
| 288 |
*/ |
|
| 289 |
inline size_type capacity() { return this->vec_m.capacity(); }
|
|
| 290 | ||
| 291 |
/** |
|
| 292 |
* @brief Reduces memory usage by freeing unused memory. |
|
| 293 |
*/ |
|
| 294 |
inline void shrink_to_fit() { this->vec_m.shrink_to_fit(); }
|
|
| 295 | ||
| 296 |
// modifiers |
|
| 297 | ||
| 298 |
/** |
|
| 299 |
* @brief Clears the contents. |
|
| 300 |
*/ |
|
| 301 | 2022x |
inline void clear() { this->vec_m.clear(); }
|
| 302 | ||
| 303 |
/** |
|
| 304 |
* @brief Inserts value before pos. |
|
| 305 |
*/ |
|
| 306 |
inline iterator insert(const_iterator pos, const Type &value) {
|
|
| 307 |
return this->vec_m.insert(pos, value); |
|
| 308 |
} |
|
| 309 | ||
| 310 |
/** |
|
| 311 |
* @brief Inserts count copies of the value before pos. |
|
| 312 |
*/ |
|
| 313 | 55806x |
inline iterator insert(const_iterator pos, size_type count, |
| 314 |
const Type &value) {
|
|
| 315 | 55806x |
return this->vec_m.insert(pos, count, value); |
| 316 |
} |
|
| 317 | ||
| 318 |
/** |
|
| 319 |
* @brief Inserts elements from range [first, last) before pos. |
|
| 320 |
*/ |
|
| 321 |
template <class InputIt> |
|
| 322 |
iterator insert(const_iterator pos, InputIt first, InputIt last) {
|
|
| 323 |
return this->vec_m.insert(pos, first, last); |
|
| 324 |
} |
|
| 325 | ||
| 326 |
/** |
|
| 327 |
* @brief Inserts elements from initializer list ilist before pos. |
|
| 328 |
*/ |
|
| 329 | ||
| 330 |
iterator insert(const_iterator pos, std::initializer_list<Type> ilist) {
|
|
| 331 |
return this->vec_m.insert(pos, ilist); |
|
| 332 |
} |
|
| 333 | ||
| 334 |
/** |
|
| 335 |
* @brief Constructs element in-place. |
|
| 336 |
*/ |
|
| 337 |
template <class... Args> |
|
| 338 |
iterator emplace(const_iterator pos, Args &&...args) {
|
|
| 339 |
return this->vec_m.emplace(pos, std::forward<Args>(args)...); |
|
| 340 |
} |
|
| 341 | ||
| 342 |
/** |
|
| 343 |
* @brief Removes the element at pos. |
|
| 344 |
*/ |
|
| 345 |
inline iterator erase(iterator pos) { return this->vec_m.erase(pos); }
|
|
| 346 | ||
| 347 |
/** |
|
| 348 |
* @brief Removes the elements in the range [first, last). |
|
| 349 |
*/ |
|
| 350 |
inline iterator erase(iterator first, iterator last) {
|
|
| 351 |
return this->vec_m.erase(first, last); |
|
| 352 |
} |
|
| 353 | ||
| 354 |
/** |
|
| 355 |
* @brief Adds an element to the end. |
|
| 356 |
*/ |
|
| 357 |
inline void push_back(const Type &&value) { this->vec_m.push_back(value); }
|
|
| 358 | ||
| 359 |
/** |
|
| 360 |
* @brief Constructs an element in-place at the end. |
|
| 361 |
*/ |
|
| 362 |
template <class... Args> |
|
| 363 | 9792x |
void emplace_back(Args &&...args) {
|
| 364 | 9792x |
this->vec_m.emplace_back(std::forward<Args>(args)...); |
| 365 |
} |
|
| 366 | ||
| 367 |
/** |
|
| 368 |
* @brief Removes the last element. |
|
| 369 |
*/ |
|
| 370 |
inline void pop_back() { this->vec_m.pop_back(); }
|
|
| 371 | ||
| 372 |
/** |
|
| 373 |
* @brief Changes the number of elements stored. |
|
| 374 |
*/ |
|
| 375 | 121504x |
inline void resize(size_t s) { this->vec_m.resize(s); }
|
| 376 | ||
| 377 |
/** |
|
| 378 |
* @brief Swaps the contents. |
|
| 379 |
*/ |
|
| 380 |
inline void swap(Vector &other) { this->vec_m.swap(other.vec_m); }
|
|
| 381 | ||
| 382 |
// end std::vector functions |
|
| 383 | ||
| 384 |
/** |
|
| 385 |
* Conversion operators |
|
| 386 |
*/ |
|
| 387 | ||
| 388 |
/** |
|
| 389 |
* @brief Converts fims::Vector<Type> to std::vector<Type> |
|
| 390 |
*/ |
|
| 391 |
inline operator std::vector<Type>() { return this->vec_m; }
|
|
| 392 | ||
| 393 |
#ifdef TMB_MODEL |
|
| 394 | ||
| 395 |
/** |
|
| 396 |
* @brief Converts fims::Vector<Type> to tmbutils::vector<Type> |
|
| 397 |
* |
|
| 398 |
* We provide both: |
|
| 399 |
* 1. An explicit conversion operator (requires static_cast) |
|
| 400 |
* 2. A named method `to_tmb()` for clarity |
|
| 401 |
*/ |
|
| 402 |
explicit operator tmbutils::vector<Type>() const {
|
|
| 403 |
tmbutils::vector<Type> ret(this->vec_m.size()); |
|
| 404 |
for (size_t i = 0; i < this->vec_m.size(); i++) {
|
|
| 405 |
ret[i] = this->vec_m[i]; |
|
| 406 |
} |
|
| 407 |
return ret; |
|
| 408 |
} |
|
| 409 | ||
| 410 |
/** |
|
| 411 |
* @brief Converts fims::Vector<Type> to tmbutils::vector<Type> |
|
| 412 |
*/ |
|
| 413 |
tmbutils::vector<Type> to_tmb() const {
|
|
| 414 |
tmbutils::vector<Type> ret(this->vec_m.size()); |
|
| 415 |
for (size_t i = 0; i < this->vec_m.size(); i++) {
|
|
| 416 |
ret[i] = this->vec_m[i]; |
|
| 417 |
} |
|
| 418 |
return ret; |
|
| 419 |
} |
|
| 420 | ||
| 421 |
/** |
|
| 422 |
* @brief Converts fims::Vector<Type> to tmbutils::vector<Type> |
|
| 423 |
* |
|
| 424 |
* We provide both: |
|
| 425 |
* 1. An explicit conversion operator (requires static_cast) |
|
| 426 |
* 2. A named method `to_tmb()` for clarity |
|
| 427 |
*/ |
|
| 428 |
explicit operator tmbutils::vector<Type>() {
|
|
| 429 |
tmbutils::vector<Type> ret(this->vec_m.size()); |
|
| 430 |
for (size_t i = 0; i < this->vec_m.size(); i++) {
|
|
| 431 |
ret[i] = this->vec_m[i]; |
|
| 432 |
} |
|
| 433 |
return ret; |
|
| 434 |
} |
|
| 435 | ||
| 436 |
/** |
|
| 437 |
* @brief Converts fims::Vector<Type> to tmbutils::vector<Type> |
|
| 438 |
*/ |
|
| 439 | 145958x |
tmbutils::vector<Type> to_tmb() {
|
| 440 | 145958x |
tmbutils::vector<Type> ret(this->vec_m.size()); |
| 441 | 8855080x |
for (size_t i = 0; i < this->vec_m.size(); i++) {
|
| 442 | 8709122x |
ret[i] = this->vec_m[i]; |
| 443 |
} |
|
| 444 | 145958x |
return ret; |
| 445 |
} |
|
| 446 | ||
| 447 |
#else |
|
| 448 | ||
| 449 |
/** |
|
| 450 |
* @brief Convert fims::Vector to std::vector. |
|
| 451 |
* |
|
| 452 |
* @details Returns a standard vector containing the same elements |
|
| 453 |
* as the fims::Vector. |
|
| 454 |
* |
|
| 455 |
* @return std::vector<Type> with the same elements. |
|
| 456 |
*/ |
|
| 457 |
std::vector<Type> to_std() const { return this->vec_m; }
|
|
| 458 | ||
| 459 |
/** |
|
| 460 |
* @brief Convert fims::Vector to TMB vector type. |
|
| 461 |
* |
|
| 462 |
* @details Returns a TMB-compatible vector containing the same |
|
| 463 |
* elements as the fims::Vector. Only available if compiled with |
|
| 464 |
* TMB_MODEL. |
|
| 465 |
* |
|
| 466 |
* @return TMB vector type with the same elements. |
|
| 467 |
*/ |
|
| 468 |
std::vector<Type> to_tmb() const { return this->vec_m; }
|
|
| 469 |
#endif |
|
| 470 | ||
| 471 |
/** |
|
| 472 |
* @brief Gets the tag for the vector. A tag can represent anything |
|
| 473 |
* and is not used internally by FIMS. |
|
| 474 |
* @return The tag. |
|
| 475 |
*/ |
|
| 476 |
std::string get_tag() const { return this->tag_m; }
|
|
| 477 |
/** |
|
| 478 |
* @brief Sets the tag for the vector. A tag can be set to |
|
| 479 |
* any string value and is not used internally by FIMS. |
|
| 480 |
*/ |
|
| 481 |
void set_tag(const std::string &tag) { this->tag_m = tag; }
|
|
| 482 | ||
| 483 |
private: |
|
| 484 |
std::string tag_m; /*!< The tag for the vector. */ |
|
| 485 |
}; // end fims::Vector class |
|
| 486 | ||
| 487 |
/** |
|
| 488 |
* @brief Comparison operator. |
|
| 489 |
*/ |
|
| 490 |
template <class T> |
|
| 491 |
bool operator==(const fims::Vector<T> &lhs, const fims::Vector<T> &rhs) {
|
|
| 492 |
return lhs.vec_m == rhs.vec_m; |
|
| 493 |
} |
|
| 494 | ||
| 495 |
} // namespace fims |
|
| 496 | ||
| 497 |
/** |
|
| 498 |
* @brief Output for std::ostream& for a vector. |
|
| 499 |
* |
|
| 500 |
* @param out The stream. |
|
| 501 |
* @param v A vector. |
|
| 502 |
* @return std::ostream& |
|
| 503 |
*/ |
|
| 504 |
template <typename Type> |
|
| 505 | 639x |
std::ostream &operator<<(std::ostream &out, const fims::Vector<Type> &v) {
|
| 506 | 639x |
out << std::fixed << std::setprecision(10); |
| 507 | 639x |
out << "["; |
| 508 | ||
| 509 | 639x |
if (v.size() == 0) {
|
| 510 | ! |
out << "]"; |
| 511 | ! |
return out; |
| 512 |
} |
|
| 513 | 149723x |
for (size_t i = 0; i < v.size() - 1; i++) {
|
| 514 | 149084x |
if (v[i] != v[i]) {
|
| 515 | ! |
out << "-999" << ","; |
| 516 |
} else {
|
|
| 517 | 149084x |
out << v[i] << ","; |
| 518 |
} |
|
| 519 |
} |
|
| 520 | 639x |
if (v[v.size() - 1] != v[v.size() - 1]) {
|
| 521 | ! |
out << "-999]"; |
| 522 |
} else {
|
|
| 523 | 639x |
out << v[v.size() - 1] << "]"; |
| 524 |
} |
|
| 525 | 639x |
return out; |
| 526 |
} |
|
| 527 | ||
| 528 |
#endif |
| 1 |
/** |
|
| 2 |
* @file information.hpp |
|
| 3 |
* @brief Code to store all objects that are created in FIMS because FIMS uses |
|
| 4 |
* integer representation. Code loops over all model components and sets them |
|
| 5 |
* up based on unique identifiers. |
|
| 6 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 7 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 8 |
* folder for reuse information. |
|
| 9 |
*/ |
|
| 10 | ||
| 11 |
#ifndef FIMS_COMMON_INFORMATION_HPP |
|
| 12 |
#define FIMS_COMMON_INFORMATION_HPP |
|
| 13 | ||
| 14 |
#include <map> |
|
| 15 |
#include <memory> |
|
| 16 |
#include <vector> |
|
| 17 |
#include <algorithm> |
|
| 18 | ||
| 19 |
#include "../distributions/distributions.hpp" |
|
| 20 |
#include "../models/functors/fishery_model_base.hpp" |
|
| 21 |
#include "../population_dynamics/fleet/fleet.hpp" |
|
| 22 |
#include "../population_dynamics/growth/growth.hpp" |
|
| 23 |
#include "../population_dynamics/population/population.hpp" |
|
| 24 |
#include "../population_dynamics/recruitment/recruitment.hpp" |
|
| 25 |
#include "../population_dynamics/selectivity/selectivity.hpp" |
|
| 26 |
#include "def.hpp" |
|
| 27 |
#include "fims_vector.hpp" |
|
| 28 |
#include "model_object.hpp" |
|
| 29 | ||
| 30 |
namespace fims_info {
|
|
| 31 | ||
| 32 |
/** |
|
| 33 |
* @brief Stores FIMS model information and creates model. Contains all objects |
|
| 34 |
* and data pre-model construction |
|
| 35 |
*/ |
|
| 36 |
template <typename Type> |
|
| 37 |
class Information {
|
|
| 38 |
public: |
|
| 39 |
size_t n_years = 0; /**< number of years >*/ |
|
| 40 |
size_t n_ages = 0; /**< number of ages>*/ |
|
| 41 | ||
| 42 |
static std::shared_ptr<Information<Type>> |
|
| 43 |
fims_information; /**< singleton instance >*/ |
|
| 44 |
std::vector<Type *> parameters; /**< list of all estimated parameters >*/ |
|
| 45 |
std::vector<Type *> |
|
| 46 |
random_effects_parameters; /**< list of all random effects parameters >*/ |
|
| 47 |
std::vector<Type *> |
|
| 48 |
fixed_effects_parameters; /**< list of all fixed effects parameters >*/ |
|
| 49 |
std::vector<std::string> parameter_names; /**< list of all parameter names |
|
| 50 |
estimated in the model */ |
|
| 51 |
std::vector<std::string> |
|
| 52 |
random_effects_names; /**< list of all random effects names estimated in |
|
| 53 |
the model */ |
|
| 54 | ||
| 55 |
// data objects |
|
| 56 |
std::map<uint32_t, std::shared_ptr<fims_data_object::DataObject<Type>>> |
|
| 57 |
data_objects; /**< map that holds data objects >*/ |
|
| 58 |
typedef typename std::map< |
|
| 59 |
uint32_t, std::shared_ptr<fims_data_object::DataObject<Type>>>::iterator |
|
| 60 |
data_iterator; /**< iterator for the data objects */ |
|
| 61 | ||
| 62 |
// life history modules |
|
| 63 |
std::map<uint32_t, std::shared_ptr<fims_popdy::RecruitmentBase<Type>>> |
|
| 64 |
recruitment_models; /**<hash map to link each object to its shared |
|
| 65 |
location in memory*/ |
|
| 66 |
typedef typename std::map< |
|
| 67 |
uint32_t, std::shared_ptr<fims_popdy::RecruitmentBase<Type>>>::iterator |
|
| 68 |
recruitment_models_iterator; |
|
| 69 |
/**< iterator for recruitment objects>*/ |
|
| 70 | ||
| 71 |
std::map<uint32_t, std::shared_ptr<fims_popdy::RecruitmentBase<Type>>> |
|
| 72 |
recruitment_process_models; /**<hash map to link each object to its shared |
|
| 73 |
location in memory*/ |
|
| 74 |
typedef typename std::map< |
|
| 75 |
uint32_t, std::shared_ptr<fims_popdy::RecruitmentBase<Type>>>::iterator |
|
| 76 |
recruitment_process_iterator; |
|
| 77 |
/**< iterator for recruitment process objects>*/ |
|
| 78 | ||
| 79 |
std::map<uint32_t, std::shared_ptr<fims_popdy::SelectivityBase<Type>>> |
|
| 80 |
selectivity_models; /**<hash map to link each object to its shared |
|
| 81 |
location in memory*/ |
|
| 82 |
typedef typename std::map< |
|
| 83 |
uint32_t, std::shared_ptr<fims_popdy::SelectivityBase<Type>>>::iterator |
|
| 84 |
selectivity_models_iterator; |
|
| 85 |
/**< iterator for selectivity objects>*/ |
|
| 86 | ||
| 87 |
std::map<uint32_t, std::shared_ptr<fims_popdy::GrowthBase<Type>>> |
|
| 88 |
growth_models; /**<hash map to link each object to its shared location in |
|
| 89 |
memory*/ |
|
| 90 |
typedef |
|
| 91 |
typename std::map<uint32_t, |
|
| 92 |
std::shared_ptr<fims_popdy::GrowthBase<Type>>>::iterator |
|
| 93 |
growth_models_iterator; |
|
| 94 |
/**< iterator for growth objects>*/ |
|
| 95 | ||
| 96 |
std::map<uint32_t, std::shared_ptr<fims_popdy::MaturityBase<Type>>> |
|
| 97 |
maturity_models; /**<hash map to link each object to its shared location |
|
| 98 |
in memory*/ |
|
| 99 |
typedef typename std::map< |
|
| 100 |
uint32_t, std::shared_ptr<fims_popdy::MaturityBase<Type>>>::iterator |
|
| 101 |
maturity_models_iterator; |
|
| 102 |
/**< iterator for maturity objects>*/ |
|
| 103 | ||
| 104 |
// fleet modules |
|
| 105 |
std::map<uint32_t, std::shared_ptr<fims_popdy::Fleet<Type>>> |
|
| 106 |
fleets; /**<hash map to link each object to its shared location in |
|
| 107 |
memory*/ |
|
| 108 |
typedef typename std::map<uint32_t, |
|
| 109 |
std::shared_ptr<fims_popdy::Fleet<Type>>>::iterator |
|
| 110 |
fleet_iterator; |
|
| 111 |
/**< iterator for fleet objects>*/ |
|
| 112 | ||
| 113 |
// populations |
|
| 114 |
std::map<uint32_t, std::shared_ptr<fims_popdy::Population<Type>>> |
|
| 115 |
populations; /**<hash map to link each object to its shared location in |
|
| 116 |
memory*/ |
|
| 117 |
typedef |
|
| 118 |
typename std::map<uint32_t, |
|
| 119 |
std::shared_ptr<fims_popdy::Population<Type>>>::iterator |
|
| 120 |
population_iterator; |
|
| 121 |
/**< iterator for population objects>*/ |
|
| 122 | ||
| 123 |
// distributions |
|
| 124 |
std::map<uint32_t, |
|
| 125 |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>>> |
|
| 126 |
density_components; /**<hash map to link each object to its shared |
|
| 127 |
location in memory*/ |
|
| 128 |
typedef typename std::map< |
|
| 129 |
uint32_t, |
|
| 130 |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>>>::iterator |
|
| 131 |
density_components_iterator; |
|
| 132 |
/**< iterator for distribution objects>*/ |
|
| 133 | ||
| 134 |
std::unordered_map<uint32_t, |
|
| 135 |
std::shared_ptr<fims_popdy::FisheryModelBase<Type>>> |
|
| 136 |
models_map; /**<hash map of fishery models, e.g., CAA, GMACS, Spatial, |
|
| 137 |
etc*/ |
|
| 138 |
typedef typename std::unordered_map< |
|
| 139 |
uint32_t, std::shared_ptr<fims_popdy::FisheryModelBase<Type>>>::iterator |
|
| 140 |
model_map_iterator; /**< iterator for variable map>*/ |
|
| 141 | ||
| 142 |
std::unordered_map<uint32_t, fims::Vector<Type> *> |
|
| 143 |
variable_map; /**<hash map to link a parameter, derived value, or |
|
| 144 |
observation to its shared location in memory */ |
|
| 145 |
typedef typename std::unordered_map<uint32_t, fims::Vector<Type> *>::iterator |
|
| 146 |
variable_map_iterator; /**< iterator for variable map>*/ |
|
| 147 | ||
| 148 | 4x |
Information() {}
|
| 149 | ||
| 150 | 2x |
virtual ~Information() {}
|
| 151 | ||
| 152 |
/** |
|
| 153 |
* @brief Clears all containers. |
|
| 154 |
* |
|
| 155 |
*/ |
|
| 156 | 560x |
void Clear() {
|
| 157 | 560x |
this->data_objects.clear(); |
| 158 | 560x |
this->populations.clear(); |
| 159 | 560x |
this->fixed_effects_parameters.clear(); |
| 160 | 560x |
this->fleets.clear(); |
| 161 | 560x |
this->growth_models.clear(); |
| 162 | 560x |
this->maturity_models.clear(); |
| 163 | 560x |
this->parameter_names.clear(); |
| 164 | 560x |
this->parameters.clear(); |
| 165 | 560x |
this->random_effects_names.clear(); |
| 166 | 560x |
this->random_effects_parameters.clear(); |
| 167 | 560x |
this->recruitment_models.clear(); |
| 168 | 560x |
this->recruitment_process_models.clear(); |
| 169 | 560x |
this->selectivity_models.clear(); |
| 170 | 560x |
this->models_map.clear(); |
| 171 | 560x |
this->n_years = 0; |
| 172 | 560x |
this->n_ages = 0; |
| 173 | ||
| 174 | 1036x |
for (density_components_iterator it = density_components.begin(); |
| 175 | 1036x |
it != density_components.end(); ++it) {
|
| 176 | 476x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 177 | 476x |
(*it).second; |
| 178 | 476x |
if ((d->priors)[0] != NULL) {
|
| 179 | 8x |
d->priors.clear(); |
| 180 |
} |
|
| 181 | 476x |
if (d->re != NULL) {
|
| 182 | 76x |
d->re->clear(); |
| 183 |
} |
|
| 184 | 476x |
if (d->re_expected_values != NULL) {
|
| 185 | 76x |
d->re_expected_values->clear(); |
| 186 |
} |
|
| 187 |
} |
|
| 188 | 560x |
this->density_components.clear(); |
| 189 |
} |
|
| 190 | ||
| 191 |
/** |
|
| 192 |
* @brief Get a summary string of the Information object state. |
|
| 193 |
* |
|
| 194 |
* @details Returns a string containing the sizes and states of all major |
|
| 195 |
* containers and model components in the Information object. Useful for |
|
| 196 |
* debugging and diagnostics. |
|
| 197 |
* |
|
| 198 |
* @return std::string summary of the Information object state. |
|
| 199 |
*/ |
|
| 200 |
std::string State() {
|
|
| 201 |
std::stringstream ss; |
|
| 202 |
ss << "Information object State:\n"; |
|
| 203 |
ss << "data_objects: " << this->data_objects.clear(); |
|
| 204 |
ss << "populations: " << this->populations.size() << std::endl; |
|
| 205 |
ss << "fixed_effects_parameters: " << this->fixed_effects_parameters.size() |
|
| 206 |
<< std::endl; |
|
| 207 |
ss << "fleets: " << this->fleets.size() << std::endl; |
|
| 208 |
ss << "growth_models: " << this->growth_models.size() << std::endl; |
|
| 209 |
ss << "maturity_models: " << this->maturity_models.size() << std::endl; |
|
| 210 |
ss << "parameter_names: " << this->parameter_names.size() << std::endl; |
|
| 211 |
ss << "parameters: " << this->parameters.size() << std::endl; |
|
| 212 |
ss << "random_effects_names: " << this->random_effects_names.size() |
|
| 213 |
<< std::endl; |
|
| 214 |
ss << "random_effects_parameters: " |
|
| 215 |
<< this->random_effects_parameters.size() << std::endl; |
|
| 216 |
ss << "recruitment_models: " << this->recruitment_models.size() |
|
| 217 |
<< std::endl; |
|
| 218 |
ss << "recruitment_process_models: " |
|
| 219 |
<< this->recruitment_process_models.size() << std::endl; |
|
| 220 |
ss << "selectivity_models: " << this->selectivity_models.size() |
|
| 221 |
<< std::endl; |
|
| 222 |
ss << "models_map: " << this->models_map.size() << std::endl; |
|
| 223 |
ss << "n_years: " << this->n_years << std::endl; |
|
| 224 |
ss << "n_ages: " << this->n_ages << std::endl; |
|
| 225 |
ss << "density_components: " << this->density_components.size() |
|
| 226 |
<< std::endl; |
|
| 227 |
return ss.str(); |
|
| 228 |
} |
|
| 229 | ||
| 230 |
/** |
|
| 231 |
* @brief Returns a singleton Information object for type T. |
|
| 232 |
* |
|
| 233 |
* @return singleton for type T |
|
| 234 |
*/ |
|
| 235 | 3626x |
static std::shared_ptr<Information<Type>> GetInstance() {
|
| 236 | 3626x |
if (Information<Type>::fims_information == nullptr) {
|
| 237 | 4x |
Information<Type>::fims_information = |
| 238 |
std::make_shared<fims_info::Information<Type>>(); |
|
| 239 |
} |
|
| 240 | 3626x |
return Information<Type>::fims_information; |
| 241 |
} |
|
| 242 | ||
| 243 |
/** |
|
| 244 |
* @brief Register a parameter as estimable. |
|
| 245 |
* |
|
| 246 |
* @param p parameter |
|
| 247 |
*/ |
|
| 248 | 4048x |
void RegisterParameter(Type &p) {
|
| 249 | 4048x |
this->fixed_effects_parameters.push_back(&p); |
| 250 |
} |
|
| 251 | ||
| 252 |
/** |
|
| 253 |
* @brief Register a random effect as estimable. |
|
| 254 |
* |
|
| 255 |
* @param re random effect |
|
| 256 |
*/ |
|
| 257 | 388x |
void RegisterRandomEffect(Type &re) {
|
| 258 | 388x |
this->random_effects_parameters.push_back(&re); |
| 259 |
} |
|
| 260 | ||
| 261 |
/** |
|
| 262 |
* @brief Register a parameter name. |
|
| 263 |
* |
|
| 264 |
* @param p_name parameter name |
|
| 265 |
*/ |
|
| 266 | 4048x |
void RegisterParameterName(std::string p_name) {
|
| 267 | 4048x |
this->parameter_names.push_back(p_name); |
| 268 |
} |
|
| 269 | ||
| 270 |
/** |
|
| 271 |
* @brief Register a random effects name. |
|
| 272 |
* |
|
| 273 |
* @param re_name random effects name |
|
| 274 |
*/ |
|
| 275 | 388x |
void RegisterRandomEffectName(std::string re_name) {
|
| 276 | 388x |
this->random_effects_names.push_back(re_name); |
| 277 |
} |
|
| 278 | ||
| 279 |
/** |
|
| 280 |
* @brief Loop over distributions and set links to distribution x value if |
|
| 281 |
* distribution is a prior type. |
|
| 282 |
*/ |
|
| 283 | 116x |
void SetupPriors() {
|
| 284 | 592x |
for (density_components_iterator it = density_components.begin(); |
| 285 | 592x |
it != density_components.end(); ++it) {
|
| 286 | 476x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 287 | 476x |
(*it).second; |
| 288 | 476x |
if (d->input_type == "prior") {
|
| 289 | 8x |
FIMS_INFO_LOG("Setup prior for distribution " + fims::to_string(d->id));
|
| 290 | 8x |
variable_map_iterator vmit; |
| 291 | 8x |
FIMS_INFO_LOG("Link prior from distribution " + fims::to_string(d->id) +
|
| 292 |
" to parameter " + fims::to_string(d->key[0])); |
|
| 293 | 8x |
d->priors.resize(d->key.size()); |
| 294 | 24x |
for (size_t i = 0; i < d->key.size(); i++) {
|
| 295 | 16x |
FIMS_INFO_LOG("Link prior from distribution " +
|
| 296 |
fims::to_string(d->id) + " to parameter " + |
|
| 297 |
fims::to_string(d->key[0])); |
|
| 298 | 16x |
vmit = this->variable_map.find(d->key[i]); |
| 299 | 16x |
d->priors[i] = (*vmit).second; |
| 300 |
} |
|
| 301 | 8x |
FIMS_INFO_LOG("Prior size for distribution " + fims::to_string(d->id) +
|
| 302 |
"is: " + fims::to_string(d->x.size())); |
|
| 303 |
} |
|
| 304 |
} |
|
| 305 |
} |
|
| 306 | ||
| 307 |
/** |
|
| 308 |
* @brief Loop over distributions and set links to distribution x value if |
|
| 309 |
* distribution is a random effects type. |
|
| 310 |
*/ |
|
| 311 | 116x |
void SetupRandomEffects() {
|
| 312 | 592x |
for (density_components_iterator it = this->density_components.begin(); |
| 313 | 592x |
it != this->density_components.end(); ++it) {
|
| 314 | 476x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 315 | 476x |
(*it).second; |
| 316 | 476x |
if (d->input_type == "random_effects") {
|
| 317 | 76x |
FIMS_INFO_LOG("Setup random effects for distribution " +
|
| 318 |
fims::to_string(d->id)); |
|
| 319 | 76x |
variable_map_iterator vmit; |
| 320 | 76x |
FIMS_INFO_LOG("Link random effects from distribution " +
|
| 321 |
fims::to_string(d->id) + " to derived value " + |
|
| 322 |
fims::to_string(d->key[0])); |
|
| 323 | 76x |
vmit = this->variable_map.find(d->key[0]); |
| 324 | 76x |
d->re = (*vmit).second; |
| 325 | 76x |
if (d->key.size() == 2) {
|
| 326 | 4x |
vmit = this->variable_map.find(d->key[1]); |
| 327 | 4x |
d->re_expected_values = (*vmit).second; |
| 328 |
} else {
|
|
| 329 | 72x |
d->re_expected_values = &d->expected_values; |
| 330 |
} |
|
| 331 | 76x |
FIMS_INFO_LOG("Random effect size for distribution " +
|
| 332 |
fims::to_string(d->id) + |
|
| 333 |
" is: " + fims::to_string(d->x.size())); |
|
| 334 |
} |
|
| 335 |
} |
|
| 336 |
} |
|
| 337 | ||
| 338 |
/** |
|
| 339 |
* @brief Loop over distributions and set links to distribution expected value |
|
| 340 |
* if distribution is a data type. |
|
| 341 |
*/ |
|
| 342 | 116x |
void SetupData() {
|
| 343 | 592x |
for (density_components_iterator it = this->density_components.begin(); |
| 344 | 592x |
it != this->density_components.end(); ++it) {
|
| 345 | 476x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 346 | 476x |
(*it).second; |
| 347 | 476x |
if (d->input_type == "data") {
|
| 348 | 392x |
FIMS_INFO_LOG("Setup expected value for data distribution " +
|
| 349 |
fims::to_string(d->id)); |
|
| 350 | 392x |
variable_map_iterator vmit; |
| 351 | 392x |
FIMS_INFO_LOG("Link expected value from distribution " +
|
| 352 |
fims::to_string(d->id) + " to derived value " + |
|
| 353 |
fims::to_string(d->key[0])); |
|
| 354 | 392x |
vmit = this->variable_map.find(d->key[0]); |
| 355 | 392x |
d->data_expected_values = (*vmit).second; |
| 356 | 392x |
FIMS_INFO_LOG( |
| 357 |
"Expected value size for distribution " + fims::to_string(d->id) + |
|
| 358 |
" is: " + fims::to_string((*d->data_expected_values).size())); |
|
| 359 |
} |
|
| 360 |
} |
|
| 361 |
} |
|
| 362 | ||
| 363 |
/** |
|
| 364 |
* @brief Set pointers to landings data in the fleet module. |
|
| 365 |
* |
|
| 366 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 367 |
* model is valid. |
|
| 368 |
* @param f shared pointer to fleet module |
|
| 369 |
*/ |
|
| 370 | 152x |
void SetFleetLandingsData(bool &valid_model, |
| 371 |
std::shared_ptr<fims_popdy::Fleet<Type>> f) {
|
|
| 372 | 152x |
if (f->fleet_observed_landings_data_id_m != -999) {
|
| 373 | 72x |
uint32_t observed_landings_id = |
| 374 | 72x |
static_cast<uint32_t>(f->fleet_observed_landings_data_id_m); |
| 375 | 72x |
data_iterator it = this->data_objects.find(observed_landings_id); |
| 376 | 72x |
if (it != this->data_objects.end()) {
|
| 377 | 72x |
f->observed_landings_data = (*it).second; |
| 378 | 72x |
FIMS_INFO_LOG("Landings data for fleet " + fims::to_string(f->id) +
|
| 379 |
" successfully set to " + |
|
| 380 |
fims::to_string(f->observed_landings_data->at(1))); |
|
| 381 |
} else {
|
|
| 382 | ! |
valid_model = false; |
| 383 | ! |
FIMS_ERROR_LOG("Expected landings data not defined for fleet " +
|
| 384 |
fims::to_string(f->id) + ", index " + |
|
| 385 |
fims::to_string(observed_landings_id)); |
|
| 386 |
} |
|
| 387 |
} |
|
| 388 |
} |
|
| 389 | ||
| 390 |
/** |
|
| 391 |
* @brief Set pointers to index data in the fleet module. |
|
| 392 |
* |
|
| 393 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 394 |
* model is valid. |
|
| 395 |
* @param f shared pointer to fleet module |
|
| 396 |
*/ |
|
| 397 | 152x |
void SetFleetIndexData(bool &valid_model, |
| 398 |
std::shared_ptr<fims_popdy::Fleet<Type>> f) {
|
|
| 399 | 152x |
if (f->fleet_observed_index_data_id_m != static_cast<Type>(-999)) {
|
| 400 | 80x |
uint32_t observed_index_id = |
| 401 | 80x |
static_cast<uint32_t>(f->fleet_observed_index_data_id_m); |
| 402 | 80x |
data_iterator it = this->data_objects.find(observed_index_id); |
| 403 | 80x |
if (it != this->data_objects.end()) {
|
| 404 | 80x |
f->observed_index_data = (*it).second; |
| 405 | 80x |
FIMS_INFO_LOG("Index data for fleet " + fims::to_string(f->id) +
|
| 406 |
" successfully set to " + |
|
| 407 |
fims::to_string(f->observed_index_data->at(1))); |
|
| 408 |
} else {
|
|
| 409 | ! |
valid_model = false; |
| 410 | ! |
FIMS_ERROR_LOG("Expected index data not defined for fleet " +
|
| 411 |
fims::to_string(f->id) + ", index " + |
|
| 412 |
fims::to_string(observed_index_id)); |
|
| 413 |
} |
|
| 414 |
} |
|
| 415 |
} |
|
| 416 | ||
| 417 |
/** |
|
| 418 |
* @brief Set pointers to age composition data in the fleet module. |
|
| 419 |
* |
|
| 420 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 421 |
* model is valid. |
|
| 422 |
* @param f shared pointer to fleet module |
|
| 423 |
*/ |
|
| 424 | 152x |
void SetAgeCompositionData(bool &valid_model, |
| 425 |
std::shared_ptr<fims_popdy::Fleet<Type>> f) {
|
|
| 426 | 152x |
if (f->fleet_observed_agecomp_data_id_m != static_cast<Type>(-999)) {
|
| 427 | 136x |
uint32_t observed_agecomp_id = |
| 428 | 136x |
static_cast<uint32_t>(f->fleet_observed_agecomp_data_id_m); |
| 429 | 136x |
data_iterator it = this->data_objects.find(observed_agecomp_id); |
| 430 | 136x |
if (it != this->data_objects.end()) {
|
| 431 | 136x |
f->observed_agecomp_data = (*it).second; |
| 432 | 136x |
FIMS_INFO_LOG("Observed input age-composition data for fleet " +
|
| 433 |
fims::to_string(f->id) + " successfully set to " + |
|
| 434 |
fims::to_string(f->observed_agecomp_data->at(1))); |
|
| 435 |
} else {
|
|
| 436 | ! |
valid_model = false; |
| 437 | ! |
FIMS_ERROR_LOG( |
| 438 |
"Expected age-composition observations not defined for fleet " + |
|
| 439 |
fims::to_string(f->id)); |
|
| 440 |
} |
|
| 441 |
} |
|
| 442 |
} |
|
| 443 | ||
| 444 |
/** |
|
| 445 |
* @brief Set pointers to length composition data in the fleet module. |
|
| 446 |
* |
|
| 447 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 448 |
* model is valid. |
|
| 449 |
* @param f shared pointer to fleet module |
|
| 450 |
*/ |
|
| 451 | 152x |
void SetLengthCompositionData(bool &valid_model, |
| 452 |
std::shared_ptr<fims_popdy::Fleet<Type>> f) {
|
|
| 453 | 152x |
if (f->fleet_observed_lengthcomp_data_id_m != static_cast<Type>(-999)) {
|
| 454 | 128x |
uint32_t observed_lengthcomp_id = |
| 455 | 128x |
static_cast<uint32_t>(f->fleet_observed_lengthcomp_data_id_m); |
| 456 | 128x |
data_iterator it = this->data_objects.find(observed_lengthcomp_id); |
| 457 | 128x |
if (it != this->data_objects.end()) {
|
| 458 | 128x |
f->observed_lengthcomp_data = (*it).second; |
| 459 | 128x |
FIMS_INFO_LOG("Observed input length-composition data for fleet " +
|
| 460 |
fims::to_string(f->id) + " successfully set to " + |
|
| 461 |
fims::to_string(f->observed_lengthcomp_data->at(1))); |
|
| 462 |
} else {
|
|
| 463 | ! |
valid_model = false; |
| 464 | ! |
FIMS_ERROR_LOG( |
| 465 |
"Expected length-composition observations not defined for fleet " + |
|
| 466 |
fims::to_string(f->id)); |
|
| 467 |
} |
|
| 468 |
} |
|
| 469 |
} |
|
| 470 | ||
| 471 |
/** |
|
| 472 |
* @brief Set pointers to the selectivity module referenced in the fleet |
|
| 473 |
* module. |
|
| 474 |
* |
|
| 475 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 476 |
* model is valid. |
|
| 477 |
* @param f shared pointer to fleet module |
|
| 478 |
*/ |
|
| 479 | 152x |
void SetFleetSelectivityModel(bool &valid_model, |
| 480 |
std::shared_ptr<fims_popdy::Fleet<Type>> f) {
|
|
| 481 | 152x |
if (f->fleet_selectivity_id_m != static_cast<Type>(-999)) {
|
| 482 | 152x |
uint32_t sel_id = static_cast<uint32_t>( |
| 483 | 152x |
f->fleet_selectivity_id_m); // cast as unsigned integer |
| 484 | 152x |
selectivity_models_iterator it = this->selectivity_models.find( |
| 485 |
sel_id); // if find, set it, otherwise invalid |
|
| 486 | ||
| 487 | 152x |
if (it != this->selectivity_models.end()) {
|
| 488 | 152x |
f->selectivity = (*it).second; // elements in container held in pair |
| 489 | 152x |
FIMS_INFO_LOG("Selectivity model " +
|
| 490 |
fims::to_string(f->fleet_selectivity_id_m) + |
|
| 491 |
" successfully set to fleet " + fims::to_string(f->id)); |
|
| 492 |
} else {
|
|
| 493 | ! |
valid_model = false; |
| 494 | ! |
FIMS_ERROR_LOG("Expected selectivity pattern not defined for fleet " +
|
| 495 |
fims::to_string(f->id) + ", selectivity pattern " + |
|
| 496 |
fims::to_string(sel_id)); |
|
| 497 |
} |
|
| 498 |
} else {
|
|
| 499 | ! |
FIMS_WARNING_LOG("Warning: No selectivity pattern defined for fleet " +
|
| 500 |
fims::to_string(f->id) + |
|
| 501 |
". FIMS requires selectivity be defined for all fleets " |
|
| 502 |
"when running a catch at age model."); |
|
| 503 |
} |
|
| 504 |
} |
|
| 505 | ||
| 506 |
/** |
|
| 507 |
* @brief Set pointers to the recruitment module referenced in the population |
|
| 508 |
* module. |
|
| 509 |
* |
|
| 510 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 511 |
* model is valid. |
|
| 512 |
* @param p shared pointer to population module |
|
| 513 |
*/ |
|
| 514 | 76x |
void SetRecruitment(bool &valid_model, |
| 515 |
std::shared_ptr<fims_popdy::Population<Type>> p) {
|
|
| 516 | 76x |
if (p->recruitment_id != static_cast<Type>(-999)) {
|
| 517 | 76x |
uint32_t recruitment_uint = static_cast<uint32_t>(p->recruitment_id); |
| 518 | 76x |
FIMS_INFO_LOG("searching for recruitment model " +
|
| 519 |
fims::to_string(recruitment_uint)); |
|
| 520 |
recruitment_models_iterator it = |
|
| 521 | 76x |
this->recruitment_models.find(recruitment_uint); |
| 522 | ||
| 523 | 76x |
if (it != this->recruitment_models.end()) {
|
| 524 | 76x |
p->recruitment = (*it).second; // recruitment defined in population.hpp |
| 525 | 76x |
FIMS_INFO_LOG("Recruitment model " + fims::to_string(recruitment_uint) +
|
| 526 |
" successfully set to population " + |
|
| 527 |
fims::to_string(p->id)); |
|
| 528 |
} else {
|
|
| 529 | ! |
valid_model = false; |
| 530 | ! |
FIMS_ERROR_LOG( |
| 531 |
"Expected recruitment function not defined for " |
|
| 532 |
"population " + |
|
| 533 |
fims::to_string(p->id) + ", recruitment function " + |
|
| 534 |
fims::to_string(recruitment_uint)); |
|
| 535 |
} |
|
| 536 |
} else {
|
|
| 537 | ! |
FIMS_WARNING_LOG( |
| 538 |
"No recruitment function defined for population " + |
|
| 539 |
fims::to_string(p->id) + |
|
| 540 |
". FIMS requires recruitment functions be defined for all " |
|
| 541 |
"populations when running a catch at age model."); |
|
| 542 |
} |
|
| 543 |
} |
|
| 544 | ||
| 545 |
/** |
|
| 546 |
* @brief Set pointers to the recruitment process module referenced in the |
|
| 547 |
* population module. |
|
| 548 |
* |
|
| 549 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 550 |
* model is valid. |
|
| 551 |
* @param p shared pointer to population module |
|
| 552 |
*/ |
|
| 553 | 76x |
void SetRecruitmentProcess(bool &valid_model, |
| 554 |
std::shared_ptr<fims_popdy::Population<Type>> p) {
|
|
| 555 | 76x |
std::shared_ptr<fims_popdy::RecruitmentBase<Type>> r = p->recruitment; |
| 556 |
// if recruitment is defined |
|
| 557 | 76x |
if (r) {
|
| 558 | 76x |
if (r->process_id != -999) {
|
| 559 | 76x |
uint32_t process_uint = static_cast<uint32_t>(r->process_id); |
| 560 |
recruitment_process_iterator it = |
|
| 561 | 76x |
this->recruitment_process_models.find(process_uint); |
| 562 | ||
| 563 | 76x |
if (it != this->recruitment_process_models.end()) {
|
| 564 | 76x |
r->process = (*it).second; // recruitment process |
| 565 | 76x |
FIMS_INFO_LOG( |
| 566 |
"Recruitment Process model " + fims::to_string(process_uint) + |
|
| 567 |
" successfully set to population " + fims::to_string(p->id)); |
|
| 568 | 76x |
(*it).second->recruitment = r; |
| 569 |
} else {
|
|
| 570 | ! |
valid_model = false; |
| 571 | ! |
FIMS_ERROR_LOG( |
| 572 |
"Expected recruitment process function not defined for " |
|
| 573 |
"population " + |
|
| 574 |
fims::to_string(p->id) + ", recruitment process function " + |
|
| 575 |
fims::to_string(process_uint)); |
|
| 576 |
} |
|
| 577 |
} else {
|
|
| 578 | ! |
FIMS_WARNING_LOG( |
| 579 |
"No recruitment process function defined for population " + |
|
| 580 |
fims::to_string(p->id) + |
|
| 581 |
". FIMS requires recruitment process functions be defined for all " |
|
| 582 |
"recruitments when running a catch at age model."); |
|
| 583 |
} |
|
| 584 |
} |
|
| 585 |
} |
|
| 586 | ||
| 587 |
/** |
|
| 588 |
* @brief Set pointers to the growth module referenced in the population |
|
| 589 |
* module. |
|
| 590 |
* |
|
| 591 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 592 |
* model is valid. |
|
| 593 |
* @param p shared pointer to population module |
|
| 594 |
*/ |
|
| 595 | 76x |
void SetGrowth(bool &valid_model, |
| 596 |
std::shared_ptr<fims_popdy::Population<Type>> p) {
|
|
| 597 | 76x |
if (p->growth_id != static_cast<Type>(-999)) {
|
| 598 | 76x |
uint32_t growth_uint = static_cast<uint32_t>(p->growth_id); |
| 599 | 76x |
growth_models_iterator it = this->growth_models.find( |
| 600 |
growth_uint); // growth_models is specified in information.hpp |
|
| 601 |
// and used in rcpp |
|
| 602 |
// at the head of information.hpp; are the |
|
| 603 |
// dimensions of ages defined in rcpp or where? |
|
| 604 | 76x |
if (it != this->growth_models.end()) {
|
| 605 | 76x |
p->growth = |
| 606 | 76x |
(*it).second; // growth defined in population.hpp (the object |
| 607 |
// is called p, growth is within p) |
|
| 608 | 76x |
FIMS_INFO_LOG("Growth model " + fims::to_string(growth_uint) +
|
| 609 |
" successfully set to population " + |
|
| 610 |
fims::to_string(p->id)); |
|
| 611 |
} else {
|
|
| 612 | ! |
valid_model = false; |
| 613 | ! |
FIMS_ERROR_LOG("Expected growth function not defined for population " +
|
| 614 |
fims::to_string(p->id) + ", growth function " + |
|
| 615 |
fims::to_string(growth_uint)); |
|
| 616 |
} |
|
| 617 |
} else {
|
|
| 618 | ! |
FIMS_WARNING_LOG("No growth function defined for population " +
|
| 619 |
fims::to_string(p->id) + |
|
| 620 |
". FIMS requires growth functions be defined for all " |
|
| 621 |
"populations when running a catch at age model."); |
|
| 622 |
} |
|
| 623 |
} |
|
| 624 | ||
| 625 |
/** |
|
| 626 |
* @brief Set pointers to the maturity module referenced in the population |
|
| 627 |
* module. |
|
| 628 |
* |
|
| 629 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 630 |
* model is valid. |
|
| 631 |
* @param p shared pointer to population module |
|
| 632 |
*/ |
|
| 633 | 76x |
void SetMaturity(bool &valid_model, |
| 634 |
std::shared_ptr<fims_popdy::Population<Type>> p) {
|
|
| 635 | 76x |
if (p->maturity_id != static_cast<Type>(-999)) {
|
| 636 | 76x |
uint32_t maturity_uint = static_cast<uint32_t>(p->maturity_id); |
| 637 | 76x |
maturity_models_iterator it = this->maturity_models.find( |
| 638 |
maturity_uint); // >maturity_models is specified in |
|
| 639 |
// information.hpp and used in rcpp |
|
| 640 | 76x |
if (it != this->maturity_models.end()) {
|
| 641 | 76x |
p->maturity = (*it).second; // >maturity defined in population.hpp |
| 642 | 76x |
FIMS_INFO_LOG("Maturity model " + fims::to_string(maturity_uint) +
|
| 643 |
" successfully set to population " + |
|
| 644 |
fims::to_string(p->id)); |
|
| 645 |
} else {
|
|
| 646 | ! |
valid_model = false; |
| 647 | ! |
FIMS_ERROR_LOG( |
| 648 |
"Expected maturity function not defined for population " + |
|
| 649 |
fims::to_string(p->id) + ", maturity function " + |
|
| 650 |
fims::to_string(maturity_uint)); |
|
| 651 |
} |
|
| 652 |
} else {
|
|
| 653 | ! |
FIMS_WARNING_LOG("No maturity function defined for population " +
|
| 654 |
fims::to_string(p->id) + |
|
| 655 |
". FIMS requires maturity functions be defined for all " |
|
| 656 |
"populations when running a catch at age model."); |
|
| 657 |
} |
|
| 658 |
} |
|
| 659 | ||
| 660 |
/** |
|
| 661 |
* @brief Loop over all fleets and set pointers to fleet objects |
|
| 662 |
* |
|
| 663 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 664 |
* model is valid. |
|
| 665 |
*/ |
|
| 666 | 116x |
void CreateFleetObjects(bool &valid_model) {
|
| 667 | 268x |
for (fleet_iterator it = this->fleets.begin(); it != this->fleets.end(); |
| 668 | 152x |
++it) {
|
| 669 | 152x |
std::shared_ptr<fims_popdy::Fleet<Type>> f = (*it).second; |
| 670 | 152x |
FIMS_INFO_LOG("Initializing fleet " + fims::to_string(f->id));
|
| 671 | ||
| 672 | 152x |
SetFleetLandingsData(valid_model, f); |
| 673 | ||
| 674 | 152x |
SetFleetIndexData(valid_model, f); |
| 675 | ||
| 676 | 152x |
SetAgeCompositionData(valid_model, f); |
| 677 | ||
| 678 | 152x |
SetLengthCompositionData(valid_model, f); |
| 679 | ||
| 680 | 152x |
SetFleetSelectivityModel(valid_model, f); |
| 681 |
} |
|
| 682 |
} |
|
| 683 | ||
| 684 |
/** |
|
| 685 |
* @brief Loop over all density components and set pointers to data objects |
|
| 686 |
* |
|
| 687 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 688 |
* model is valid. |
|
| 689 |
*/ |
|
| 690 | 116x |
void SetDataObjects(bool &valid_model) {
|
| 691 | 592x |
for (density_components_iterator it = this->density_components.begin(); |
| 692 | 592x |
it != this->density_components.end(); ++it) {
|
| 693 | 476x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 694 | 476x |
(*it).second; |
| 695 | ||
| 696 |
// set data objects if distribution is a data type |
|
| 697 | 476x |
if (d->input_type == "data") {
|
| 698 | 392x |
if (d->observed_data_id_m != static_cast<Type>(-999)) {
|
| 699 | 392x |
uint32_t observed_data_id = |
| 700 | 392x |
static_cast<uint32_t>(d->observed_data_id_m); |
| 701 | 392x |
data_iterator it = this->data_objects.find(observed_data_id); |
| 702 | ||
| 703 | 392x |
if (it != this->data_objects.end()) {
|
| 704 | 392x |
d->observed_values = (*it).second; |
| 705 | 392x |
FIMS_INFO_LOG("Observed data " + fims::to_string(observed_data_id) +
|
| 706 |
" successfully set to density component " + |
|
| 707 |
fims::to_string(d->id)); |
|
| 708 |
} else {
|
|
| 709 | ! |
valid_model = false; |
| 710 | ! |
FIMS_ERROR_LOG( |
| 711 |
"Expected data observations not defined for density " |
|
| 712 |
"component " + |
|
| 713 |
fims::to_string(d->id) + ", observed data " + |
|
| 714 |
fims::to_string(observed_data_id)); |
|
| 715 |
} |
|
| 716 |
} else {
|
|
| 717 | ! |
valid_model = false; |
| 718 | ! |
FIMS_ERROR_LOG("No data input for density component" +
|
| 719 |
fims::to_string(d->id)); |
|
| 720 |
} |
|
| 721 |
} |
|
| 722 |
} |
|
| 723 |
} |
|
| 724 | ||
| 725 |
/** |
|
| 726 |
* @brief Loop over all populations and set pointers to population objects |
|
| 727 |
* |
|
| 728 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 729 |
* model is valid. |
|
| 730 |
*/ |
|
| 731 | 116x |
void CreatePopulationObjects(bool &valid_model) {
|
| 732 | 116x |
for (population_iterator it = this->populations.begin(); |
| 733 | 192x |
it != this->populations.end(); ++it) {
|
| 734 | 76x |
std::shared_ptr<fims_popdy::Population<Type>> p = (*it).second; |
| 735 | ||
| 736 | 76x |
FIMS_INFO_LOG("Initializing population " + fims::to_string(p->id));
|
| 737 |
// check if population has fleets |
|
| 738 | 76x |
typename std::set<uint32_t>::iterator fleet_ids_it; |
| 739 | ||
| 740 | 76x |
for (fleet_ids_it = p->fleet_ids.begin(); |
| 741 | 220x |
fleet_ids_it != p->fleet_ids.end(); ++fleet_ids_it) {
|
| 742 |
// error check and set population elements |
|
| 743 |
// check me - add another fleet iterator to push information from |
|
| 744 |
// for (fleet_iterator it = this->fleets.begin(); it != |
|
| 745 |
// this->fleets.end(); |
|
| 746 |
// ++it) {
|
|
| 747 | ||
| 748 | 144x |
fleet_iterator it = this->fleets.find(*fleet_ids_it); |
| 749 | ||
| 750 | 144x |
if (it != this->fleets.end()) {
|
| 751 |
// Initialize fleet object |
|
| 752 | 144x |
std::shared_ptr<fims_popdy::Fleet<Type>> f = (*it).second; |
| 753 |
// population to the individual fleets This is to pass catch at age |
|
| 754 |
// from population to fleets? |
|
| 755 |
// any shared member in p (population is pushed into fleets) |
|
| 756 | 144x |
p->fleets.push_back(f); |
| 757 |
} else {
|
|
| 758 | ! |
valid_model = false; |
| 759 | ! |
FIMS_ERROR_LOG("Fleet \"" + fims::to_string(*fleet_ids_it) +
|
| 760 |
"\" undefined, not found for Population \"" + |
|
| 761 |
fims::to_string(p->id) + "\". "); |
|
| 762 |
} |
|
| 763 |
// // error check and set population elements |
|
| 764 |
// // check me - add another fleet iterator to push information from |
|
| 765 |
// for (fleet_iterator it = this->fleets.begin(); it != |
|
| 766 |
// this->fleets.end(); |
|
| 767 |
// ++it) |
|
| 768 |
// {
|
|
| 769 |
// // Initialize fleet object |
|
| 770 |
// std::shared_ptr<fims_popdy::Fleet<Type>> f = (*it).second; |
|
| 771 |
// // population to the individual fleets This is to pass landings |
|
| 772 |
// at age |
|
| 773 |
// // from population to fleets? |
|
| 774 |
// // any shared member in p (population is pushed into fleets) |
|
| 775 |
// p->fleets.push_back(f); |
|
| 776 |
// } |
|
| 777 |
} |
|
| 778 | ||
| 779 |
// set information dimensions |
|
| 780 | 76x |
this->n_years = std::max(this->n_years, p->n_years); |
| 781 | 76x |
this->n_ages = std::max(this->n_ages, p->n_ages); |
| 782 | ||
| 783 | 76x |
SetRecruitment(valid_model, p); |
| 784 | ||
| 785 | 76x |
SetRecruitmentProcess(valid_model, p); |
| 786 | ||
| 787 | 76x |
SetGrowth(valid_model, p); |
| 788 | ||
| 789 | 76x |
SetMaturity(valid_model, p); |
| 790 |
} |
|
| 791 |
} |
|
| 792 | ||
| 793 |
/** |
|
| 794 |
* @brief Loop over all models and set pointers to population objects |
|
| 795 |
*/ |
|
| 796 | 116x |
void CreateModelingObjects(bool &valid_model) {
|
| 797 | 116x |
for (model_map_iterator it = this->models_map.begin(); |
| 798 | 188x |
it != this->models_map.end(); ++it) {
|
| 799 | 72x |
std::shared_ptr<fims_popdy::FisheryModelBase<Type>> &model = (*it).second; |
| 800 | 72x |
std::set<uint32_t>::iterator jt; |
| 801 | ||
| 802 | 72x |
for (jt = model->population_ids.begin(); |
| 803 | 144x |
jt != model->population_ids.end(); ++jt) {
|
| 804 | 72x |
population_iterator pt = this->populations.find((*jt)); |
| 805 | ||
| 806 | 72x |
if (pt != this->populations.end()) {
|
| 807 | 72x |
std::shared_ptr<fims_popdy::Population<Type>> p = (*pt).second; |
| 808 | 72x |
model->populations.push_back(p); |
| 809 | 216x |
for (size_t i = 0; i < p->fleets.size(); i++) {
|
| 810 | 144x |
model->fleets[p->fleets[i]->GetId()] = p->fleets[i]; |
| 811 |
} |
|
| 812 |
} else {
|
|
| 813 | ! |
valid_model = false; |
| 814 | ! |
FIMS_ERROR_LOG("No population object defined for model " +
|
| 815 |
fims::to_string(model->GetId())); |
|
| 816 |
} |
|
| 817 |
} |
|
| 818 | 72x |
model->Initialize(); |
| 819 |
} |
|
| 820 |
} |
|
| 821 | ||
| 822 |
/** |
|
| 823 |
* @brief Create the generalized stock assessment model that will evaluate the |
|
| 824 |
* objective function. Does error checking to make sure the program has |
|
| 825 |
* all necessary components for the model and that they're in the right |
|
| 826 |
* dimensions. This sets up pointers to all memory objects and initializes |
|
| 827 |
* fleet and population objects. |
|
| 828 |
* |
|
| 829 |
* @return True if valid model, False if invalid model, check fims.log for |
|
| 830 |
* errors. |
|
| 831 |
*/ |
|
| 832 | 116x |
bool CreateModel() {
|
| 833 | 116x |
bool valid_model = true; |
| 834 | ||
| 835 | 116x |
CreateFleetObjects(valid_model); |
| 836 | ||
| 837 | 116x |
SetDataObjects(valid_model); |
| 838 | ||
| 839 | 116x |
CreatePopulationObjects(valid_model); |
| 840 | ||
| 841 | 116x |
CreateModelingObjects(valid_model); |
| 842 | ||
| 843 |
// setup priors, random effect, and data density components |
|
| 844 | 116x |
SetupPriors(); |
| 845 | 116x |
SetupRandomEffects(); |
| 846 | 116x |
SetupData(); |
| 847 | ||
| 848 | 116x |
return valid_model; |
| 849 |
} |
|
| 850 | ||
| 851 |
/** |
|
| 852 |
* @brief Get the Nages object |
|
| 853 |
* |
|
| 854 |
* @return size_t |
|
| 855 |
*/ |
|
| 856 |
size_t GetNages() const { return n_ages; }
|
|
| 857 | ||
| 858 |
/** |
|
| 859 |
* @brief Set the Nages object |
|
| 860 |
* |
|
| 861 |
* @param n_ages |
|
| 862 |
*/ |
|
| 863 |
void SetNages(size_t n_ages) { this->n_ages = n_ages; }
|
|
| 864 | ||
| 865 |
/** |
|
| 866 |
* @brief Get the Nyears object |
|
| 867 |
* |
|
| 868 |
* @return size_t |
|
| 869 |
*/ |
|
| 870 |
size_t GetNyears() const { return n_years; }
|
|
| 871 | ||
| 872 |
/** |
|
| 873 |
* @brief Set the Nyears object |
|
| 874 |
* |
|
| 875 |
* @param n_years |
|
| 876 |
*/ |
|
| 877 |
void SetNyears(size_t n_years) { this->n_years = n_years; }
|
|
| 878 | ||
| 879 |
/** |
|
| 880 |
* @brief Get the Parameters object |
|
| 881 |
* |
|
| 882 |
* @return std::vector<Type*>& |
|
| 883 |
*/ |
|
| 884 |
std::vector<Type *> &GetParameters() { return parameters; }
|
|
| 885 | ||
| 886 |
/** |
|
| 887 |
* @brief Get the Fixed Effects Parameters object |
|
| 888 |
* |
|
| 889 |
* @return std::vector<Type*>& |
|
| 890 |
*/ |
|
| 891 |
std::vector<Type *> &GetFixedEffectsParameters() {
|
|
| 892 |
return fixed_effects_parameters; |
|
| 893 |
} |
|
| 894 | ||
| 895 |
/** |
|
| 896 |
* @brief Get the Random Effects Parameters object |
|
| 897 |
* |
|
| 898 |
* @return std::vector<Type*>& |
|
| 899 |
*/ |
|
| 900 |
std::vector<Type *> &GetRandomEffectsParameters() {
|
|
| 901 |
return random_effects_parameters; |
|
| 902 |
} |
|
| 903 | ||
| 904 |
/** |
|
| 905 |
* @brief Checks to make sure all required modules are present for specified |
|
| 906 |
* model |
|
| 907 |
* |
|
| 908 |
* @return True if valid model, False if invalid model, check fims.log for |
|
| 909 |
* errors. |
|
| 910 |
*/ |
|
| 911 | 29x |
bool CheckModel() {
|
| 912 | 29x |
bool valid_model = true; |
| 913 | 29x |
for (model_map_iterator it = this->models_map.begin(); |
| 914 | 47x |
it != this->models_map.end(); ++it) {
|
| 915 | 18x |
std::shared_ptr<fims_popdy::FisheryModelBase<Type>> &model = (*it).second; |
| 916 | 18x |
std::set<uint32_t>::iterator jt; |
| 917 | ||
| 918 | 18x |
for (jt = model->population_ids.begin(); |
| 919 | 36x |
jt != model->population_ids.end(); ++jt) {
|
| 920 | 18x |
population_iterator pt = this->populations.find((*jt)); |
| 921 | ||
| 922 | 18x |
if (pt != this->populations.end()) {
|
| 923 | 18x |
std::shared_ptr<fims_popdy::Population<Type>> p = (*pt).second; |
| 924 | ||
| 925 | 18x |
if (model->model_type_m == "caa") {
|
| 926 | 18x |
typename std::set<uint32_t>::iterator fleet_ids_it; |
| 927 | 18x |
for (fleet_ids_it = p->fleet_ids.begin(); |
| 928 | 54x |
fleet_ids_it != p->fleet_ids.end(); ++fleet_ids_it) {
|
| 929 | 36x |
fleet_iterator it = this->fleets.find(*fleet_ids_it); |
| 930 | ||
| 931 | 36x |
if (it != this->fleets.end()) {
|
| 932 |
// Initialize fleet object |
|
| 933 | 36x |
std::shared_ptr<fims_popdy::Fleet<Type>> f = (*it).second; |
| 934 | ||
| 935 | 36x |
if (f->fleet_selectivity_id_m == -999) {
|
| 936 | ! |
valid_model = false; |
| 937 | ! |
FIMS_ERROR_LOG( |
| 938 |
"No selectivity pattern defined for fleet " + |
|
| 939 |
fims::to_string(f->id) + |
|
| 940 |
". FIMS requires selectivity be defined for all fleets " |
|
| 941 |
"when running a catch at age model."); |
|
| 942 |
} |
|
| 943 |
} |
|
| 944 |
} |
|
| 945 | ||
| 946 | 18x |
if (p->recruitment_id == -999) {
|
| 947 | ! |
valid_model = false; |
| 948 | ! |
FIMS_ERROR_LOG( |
| 949 |
"No recruitment function defined for population " + |
|
| 950 |
fims::to_string(p->id) + |
|
| 951 |
". FIMS requires recruitment functions be defined for all " |
|
| 952 |
"populations when running a catch at age model."); |
|
| 953 |
} |
|
| 954 | ||
| 955 | 18x |
std::shared_ptr<fims_popdy::RecruitmentBase<Type>> r = |
| 956 | 18x |
p->recruitment; |
| 957 | 18x |
r = p->recruitment; |
| 958 | 18x |
if (r->process_id == -999) {
|
| 959 | ! |
valid_model = false; |
| 960 | ! |
FIMS_ERROR_LOG( |
| 961 |
"No recruitment process function defined for population " + |
|
| 962 |
fims::to_string(p->id) + |
|
| 963 |
". FIMS requires recruitment process functions be defined " |
|
| 964 |
"for all " |
|
| 965 |
"recruitments when running a catch at age model."); |
|
| 966 |
} |
|
| 967 | ||
| 968 | 18x |
if (p->growth_id == -999) {
|
| 969 | ! |
valid_model = false; |
| 970 | ! |
FIMS_ERROR_LOG( |
| 971 |
"No growth function defined for population " + |
|
| 972 |
fims::to_string(p->id) + |
|
| 973 |
". FIMS requires growth functions be defined for all " |
|
| 974 |
"populations when running a catch at age model."); |
|
| 975 |
} |
|
| 976 | ||
| 977 | 18x |
if (p->maturity_id == -999) {
|
| 978 | ! |
valid_model = false; |
| 979 | ||
| 980 | ! |
FIMS_WARNING_LOG( |
| 981 |
"No maturity function defined for population " + |
|
| 982 |
fims::to_string(p->id) + |
|
| 983 |
". FIMS requires maturity functions be defined for all " |
|
| 984 |
"populations when running a catch at age model."); |
|
| 985 |
} |
|
| 986 |
} |
|
| 987 |
} |
|
| 988 |
} |
|
| 989 |
} |
|
| 990 | 29x |
return valid_model; |
| 991 |
} |
|
| 992 |
}; |
|
| 993 | ||
| 994 |
template <typename Type> |
|
| 995 |
std::shared_ptr<Information<Type>> Information<Type>::fims_information = |
|
| 996 |
nullptr; // singleton instance |
|
| 997 | ||
| 998 |
} // namespace fims_info |
|
| 999 | ||
| 1000 |
#endif /* FIMS_COMMON_INFORMATION_HPP */ |
| 1 |
/** |
|
| 2 |
* @file model_object.hpp |
|
| 3 |
* @brief Definition of the FIMSObject structure. |
|
| 4 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 5 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 6 |
* folder for reuse information. |
|
| 7 |
*/ |
|
| 8 | ||
| 9 |
#ifndef FIMS_COMMON_MODEL_OBJECT_HPP |
|
| 10 |
#define FIMS_COMMON_MODEL_OBJECT_HPP |
|
| 11 | ||
| 12 |
#include <stdint.h> |
|
| 13 | ||
| 14 |
#include <vector> |
|
| 15 | ||
| 16 |
#include "def.hpp" |
|
| 17 |
#include "fims_vector.hpp" |
|
| 18 | ||
| 19 |
namespace fims_model_object {
|
|
| 20 | ||
| 21 |
/** |
|
| 22 |
* @brief FIMSObject struct that defines member types and returns the unique id |
|
| 23 |
*/ |
|
| 24 |
template <typename Type> |
|
| 25 |
struct FIMSObject {
|
|
| 26 |
uint32_t id; /**< unique identifier assigned for all fims objects */ |
|
| 27 |
std::vector<Type*> parameters; /**< list of estimable parameters */ |
|
| 28 |
std::vector<Type*> |
|
| 29 |
random_effects_parameters; /**< list of all random effects parameters */ |
|
| 30 |
std::vector<Type*> |
|
| 31 |
fixed_effects_parameters; /**< list of fixed effects parameters */ |
|
| 32 | ||
| 33 | 806x |
virtual ~FIMSObject() {}
|
| 34 | ||
| 35 |
/** |
|
| 36 |
* @brief Getter that returns the unique id for parameters in the model |
|
| 37 |
*/ |
|
| 38 | 4777236x |
uint32_t GetId() const { return id; }
|
| 39 | ||
| 40 |
/** |
|
| 41 |
* @brief Check the dimensions of an object |
|
| 42 |
* |
|
| 43 |
* @param actual The actual dimensions. |
|
| 44 |
* @param expected The expected dimensions. |
|
| 45 |
* @return true |
|
| 46 |
* @return false |
|
| 47 |
*/ |
|
| 48 |
inline bool CheckDimensions(size_t actual, size_t expected) {
|
|
| 49 |
if (actual != expected) {
|
|
| 50 |
return false; |
|
| 51 |
} |
|
| 52 | ||
| 53 |
return true; |
|
| 54 |
} |
|
| 55 | ||
| 56 |
/** |
|
| 57 |
* @brief Create a map of report vectors for the object. |
|
| 58 |
* used to populate the report_vectors map in FisheryModelBase. |
|
| 59 |
*/ |
|
| 60 | ! |
virtual void create_report_vectors( |
| 61 |
std::map<std::string, fims::Vector<fims::Vector<Type>>>& report_vectors) {
|
|
| 62 |
} |
|
| 63 |
/** |
|
| 64 |
* @brief Get the report vector count object. |
|
| 65 |
* used to get the length of each report vector for populating the |
|
| 66 |
* UncertaintyReportInfo struct in FisheryModelBase. |
|
| 67 |
*/ |
|
| 68 | ! |
virtual void get_report_vector_count( |
| 69 | ! |
std::map<std::string, size_t>& report_vector_count) {}
|
| 70 |
}; |
|
| 71 | ||
| 72 |
} // namespace fims_model_object |
|
| 73 | ||
| 74 |
#endif /* FIMS_COMMON_MODEL_OBJECT_HPP */ |
| 1 |
/** |
|
| 2 |
* @file model.hpp |
|
| 3 |
* @brief : Loops over model components and returns the negative log-likelihood |
|
| 4 |
* function. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_COMMON_MODEL_HPP |
|
| 10 |
#define FIMS_COMMON_MODEL_HPP |
|
| 11 | ||
| 12 |
#include <future> |
|
| 13 |
#include <memory> |
|
| 14 | ||
| 15 |
#include "information.hpp" |
|
| 16 | ||
| 17 |
namespace fims_model {
|
|
| 18 | ||
| 19 |
/** |
|
| 20 |
* @brief Model class. FIMS objective function. |
|
| 21 |
*/ |
|
| 22 |
template <typename Type> |
|
| 23 |
class Model { // may need singleton
|
|
| 24 |
public: |
|
| 25 |
static std::shared_ptr<Model<Type>> |
|
| 26 |
fims_model; /**< Create a shared fims_model as a pointer to Model*/ |
|
| 27 |
std::shared_ptr<fims_info::Information<Type>> |
|
| 28 |
fims_information; /**< Create a shared fims_information as a pointer to |
|
| 29 |
Information*/ |
|
| 30 | ||
| 31 |
#ifdef TMB_MODEL |
|
| 32 |
bool do_tmb_reporting = true; |
|
| 33 |
::objective_function<Type> *of; |
|
| 34 |
#endif |
|
| 35 | ||
| 36 |
// constructor |
|
| 37 | ||
| 38 | 2x |
virtual ~Model() {}
|
| 39 | ||
| 40 |
/** |
|
| 41 |
* Returns a single Information object for type Type. |
|
| 42 |
* |
|
| 43 |
* @return singleton for type Type |
|
| 44 |
*/ |
|
| 45 | 788x |
static std::shared_ptr<Model<Type>> GetInstance() {
|
| 46 | 788x |
if (Model<Type>::fims_model == nullptr) {
|
| 47 | 4x |
Model<Type>::fims_model = std::make_shared<fims_model::Model<Type>>(); |
| 48 | 4x |
Model<Type>::fims_model->fims_information = |
| 49 |
fims_info::Information<Type>::GetInstance(); |
|
| 50 |
} |
|
| 51 | 788x |
return Model<Type>::fims_model; |
| 52 |
} |
|
| 53 | ||
| 54 |
/** |
|
| 55 |
* @brief Evaluate. Calculates the joint negative log-likelihood function. |
|
| 56 |
*/ |
|
| 57 | 730x |
const Type Evaluate() {
|
| 58 |
// jnll = negative-log-likelihood (the objective function) |
|
| 59 | 730x |
Type jnll = static_cast<Type>(0.0); |
| 60 | 730x |
typename fims_info::Information<Type>::model_map_iterator m_it; |
| 61 |
// Check if fims_information is set |
|
| 62 | 730x |
if (this->fims_information == nullptr) {
|
| 63 | ! |
FIMS_ERROR_LOG( |
| 64 |
"fims_information is not set. Please set fims_information before " |
|
| 65 |
"calling Evaluate()."); |
|
| 66 | ! |
return jnll; |
| 67 |
} |
|
| 68 | ||
| 69 |
// Create vector for reporting out nll components |
|
| 70 | 878x |
fims::Vector<Type> nll_vec( |
| 71 | 730x |
this->fims_information->density_components.size(), 0.0); |
| 72 | ||
| 73 | 1300x |
for (m_it = this->fims_information->models_map.begin(); |
| 74 | 1300x |
m_it != this->fims_information->models_map.end(); ++m_it) {
|
| 75 |
//(*m_it).second points to the Model module |
|
| 76 | 570x |
std::shared_ptr<fims_popdy::FisheryModelBase<Type>> m = (*m_it).second; |
| 77 | 570x |
m->of = this->of; // link to TMB objective function |
| 78 | 570x |
m->Prepare(); |
| 79 | 570x |
m->Evaluate(); |
| 80 |
} |
|
| 81 | ||
| 82 |
// Loop over densities and evaluate joint negative log densities for priors |
|
| 83 | 730x |
typename fims_info::Information<Type>::density_components_iterator d_it; |
| 84 | 730x |
int nll_vec_idx = 0; |
| 85 | 730x |
size_t n_priors = 0; |
| 86 | 1460x |
FIMS_INFO_LOG("Begin evaluating prior densities.")
|
| 87 | 4324x |
for (d_it = this->fims_information->density_components.begin(); |
| 88 | 4324x |
d_it != this->fims_information->density_components.end(); ++d_it) {
|
| 89 | 3594x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 90 | 3594x |
(*d_it).second; |
| 91 |
#ifdef TMB_MODEL |
|
| 92 | 3594x |
d->of = this->of; |
| 93 |
#endif |
|
| 94 | 3594x |
if (d->input_type == "prior") {
|
| 95 | 16x |
nll_vec[nll_vec_idx] = -d->evaluate(); |
| 96 | 16x |
jnll += nll_vec[nll_vec_idx]; |
| 97 | 16x |
n_priors += 1; |
| 98 | 16x |
nll_vec_idx += 1; |
| 99 |
} |
|
| 100 |
} |
|
| 101 | 730x |
FIMS_INFO_LOG( |
| 102 |
"Model: Finished evaluating prior distributions. The jnll after " |
|
| 103 |
"evaluating " + |
|
| 104 |
fims::to_string(n_priors) + " priors is: " + fims::to_string(jnll)); |
|
| 105 | ||
| 106 |
// Loop over densities and evaluate joint negative log-likelihoods for |
|
| 107 |
// random effects |
|
| 108 | 730x |
size_t n_random_effects = 0; |
| 109 | 4324x |
for (d_it = this->fims_information->density_components.begin(); |
| 110 | 4324x |
d_it != this->fims_information->density_components.end(); ++d_it) {
|
| 111 | 3594x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 112 | 3594x |
(*d_it).second; |
| 113 |
#ifdef TMB_MODEL |
|
| 114 | 3594x |
d->of = this->of; |
| 115 |
#endif |
|
| 116 | 3594x |
if (d->input_type == "random_effects") {
|
| 117 | 578x |
nll_vec[nll_vec_idx] = -d->evaluate(); |
| 118 | 578x |
jnll += nll_vec[nll_vec_idx]; |
| 119 | 578x |
n_random_effects += 1; |
| 120 | 578x |
nll_vec_idx += 1; |
| 121 |
} |
|
| 122 |
} |
|
| 123 | 730x |
FIMS_INFO_LOG( |
| 124 |
"Model: Finished evaluating random effect distributions. The jnll " |
|
| 125 |
"after evaluating priors and " + |
|
| 126 |
fims::to_string(n_random_effects) + |
|
| 127 |
" random_effects is: " + fims::to_string(jnll)); |
|
| 128 | ||
| 129 |
// Loop over and evaluate data joint negative log-likelihoods |
|
| 130 | 730x |
int n_data = 0; |
| 131 | 4324x |
for (d_it = this->fims_information->density_components.begin(); |
| 132 | 4324x |
d_it != this->fims_information->density_components.end(); ++d_it) {
|
| 133 | 3594x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 134 | 3594x |
(*d_it).second; |
| 135 |
#ifdef TMB_MODEL |
|
| 136 | 3594x |
d->of = this->of; |
| 137 |
// d->keep = this->keep; |
|
| 138 |
#endif |
|
| 139 | 3594x |
if (d->input_type == "data") {
|
| 140 | 3000x |
nll_vec[nll_vec_idx] = -d->evaluate(); |
| 141 | 3000x |
jnll += nll_vec[nll_vec_idx]; |
| 142 | 3000x |
n_data += 1; |
| 143 | 3000x |
nll_vec_idx += 1; |
| 144 |
} |
|
| 145 |
} |
|
| 146 | ||
| 147 |
// report out nll components |
|
| 148 |
#ifdef TMB_MODEL |
|
| 149 | 730x |
vector<Type> nll_components = nll_vec.to_tmb(); |
| 150 | 582x |
FIMS_REPORT_F(nll_components, this->of); |
| 151 | 582x |
FIMS_REPORT_F(jnll, this->of); |
| 152 |
#endif |
|
| 153 | ||
| 154 |
// report out model family objects |
|
| 155 | 1300x |
for (m_it = this->fims_information->models_map.begin(); |
| 156 | 1300x |
m_it != this->fims_information->models_map.end(); ++m_it) {
|
| 157 |
//(*m_it).second points to the Model module |
|
| 158 | 570x |
std::shared_ptr<fims_popdy::FisheryModelBase<Type>> m = (*m_it).second; |
| 159 | 570x |
m->Report(); |
| 160 |
} |
|
| 161 | ||
| 162 | 730x |
return jnll; |
| 163 |
} |
|
| 164 |
}; |
|
| 165 | ||
| 166 |
// Create singleton instance of Model class |
|
| 167 |
template <typename Type> |
|
| 168 |
std::shared_ptr<Model<Type>> Model<Type>::fims_model = |
|
| 169 |
nullptr; // singleton instance |
|
| 170 |
} // namespace fims_model |
|
| 171 | ||
| 172 |
#endif /* FIMS_COMMON_MODEL_HPP */ |
| 1 | ||
| 2 |
/** |
|
| 3 |
* @file density_components_base.hpp |
|
| 4 |
* @brief Declares the DensityComponentBase class, which is the base class for |
|
| 5 |
* all distribution functors. |
|
| 6 |
* @details Defines guards for distributions module outline to define the |
|
| 7 |
* density_components_base hpp file if not already defined. |
|
| 8 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 9 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 10 |
* folder for reuse information. |
|
| 11 |
*/ |
|
| 12 |
#ifndef DENSITY_COMPONENT_BASE_HPP |
|
| 13 |
#define DENSITY_COMPONENT_BASE_HPP |
|
| 14 | ||
| 15 |
#include "../../common/data_object.hpp" |
|
| 16 |
#include "../../common/model_object.hpp" |
|
| 17 |
#include "../../interface/interface.hpp" |
|
| 18 |
#include "../../common/fims_vector.hpp" |
|
| 19 |
#include "../../common/fims_math.hpp" |
|
| 20 | ||
| 21 |
namespace fims_distributions {
|
|
| 22 | ||
| 23 |
/** |
|
| 24 |
* Container to hold density components including pointers to density inputs. |
|
| 25 |
*/ |
|
| 26 |
template <typename Type> |
|
| 27 |
struct DistributionElementObject {
|
|
| 28 |
std::string input_type; /**< string classifies the type of the negative |
|
| 29 |
log-likelihood; options are: "priors", |
|
| 30 |
"random_effects", and "data" */ |
|
| 31 |
std::shared_ptr<fims_data_object::DataObject<Type>> |
|
| 32 |
observed_values; /**< observed data*/ |
|
| 33 |
fims::Vector<Type> |
|
| 34 |
expected_values; /**< expected value of distribution function*/ |
|
| 35 |
fims::Vector<Type>* re = NULL; /**< pointer to random effects vector*/ |
|
| 36 |
fims::Vector<Type>* re_expected_values = |
|
| 37 |
NULL; /**< expected value of random effects*/ |
|
| 38 |
fims::Vector<Type>* data_expected_values = NULL; /**< expected value of data*/ |
|
| 39 |
std::vector<fims::Vector<Type>*> |
|
| 40 |
priors; /**< vector of pointers where each points to a prior parameter */ |
|
| 41 |
fims::Vector<Type> x; /**< input value of distribution function for priors or |
|
| 42 |
random effects*/ |
|
| 43 |
// std::shared_ptr<DistributionElementObject<Type>> expected; /**< expected |
|
| 44 |
// value of distribution function */ |
|
| 45 | ||
| 46 |
/** |
|
| 47 |
* Retrieve element from observed data set, random effect, or prior. |
|
| 48 |
* @param i index referencing vector or pointer |
|
| 49 |
* @return the reference to the value of the vector or pointer at position i |
|
| 50 |
*/ |
|
| 51 | 121682x |
inline Type& get_observed(size_t i) {
|
| 52 | 121682x |
if (this->input_type == "data") {
|
| 53 | 103908x |
return observed_values->at(i); |
| 54 |
} |
|
| 55 | 17774x |
if (this->input_type == "random_effects") {
|
| 56 | 17516x |
return (*re)[i]; |
| 57 |
} |
|
| 58 | 258x |
if (this->input_type == "prior") {
|
| 59 | 32x |
return (*(priors[i]))[0]; |
| 60 |
} |
|
| 61 | 113x |
return x[i]; |
| 62 |
} |
|
| 63 | ||
| 64 |
/** |
|
| 65 |
* Retrieve element from observed data set, random effect, or prior. |
|
| 66 |
* @param i index referencing row |
|
| 67 |
* @param j index referencing column |
|
| 68 |
* @return the reference to the row and column at position i, j |
|
| 69 |
*/ |
|
| 70 | 1964898x |
inline Type& get_observed(size_t i, size_t j) {
|
| 71 | 1964898x |
if (this->input_type == "data") {
|
| 72 | 1964898x |
return observed_values->at(i, j); |
| 73 |
} |
|
| 74 | ! |
if (this->input_type == "random_effects") {
|
| 75 | ! |
return (*re)[i, j]; |
| 76 |
} |
|
| 77 | ! |
if (this->input_type == "prior") {
|
| 78 | ! |
return (*(priors[i, j]))[0]; |
| 79 |
} |
|
| 80 | ! |
return x[i]; |
| 81 |
} |
|
| 82 | ||
| 83 |
/** |
|
| 84 |
* Retrieve expected element given data, random effect, or prior. |
|
| 85 |
* @param i index referencing vector or pointer |
|
| 86 |
* @return the reference to the value of the vector or pointer at position i |
|
| 87 |
*/ |
|
| 88 | 1057458x |
inline Type& get_expected(size_t i) {
|
| 89 | 1057458x |
if (this->input_type == "data") {
|
| 90 | 1039740x |
return (*data_expected_values)[i]; |
| 91 |
} |
|
| 92 | 17718x |
if (this->input_type == "random_effects") {
|
| 93 | 17516x |
return (*re_expected_values)[i]; |
| 94 |
} else {
|
|
| 95 | 202x |
return this->expected_values.get_force_scalar(i); |
| 96 |
} |
|
| 97 |
} |
|
| 98 | ||
| 99 |
/** |
|
| 100 |
* Retrieve expected element size given data, random effect, or prior. |
|
| 101 |
* @return The size of the element. |
|
| 102 |
*/ |
|
| 103 | 1830x |
inline size_t get_n_x() {
|
| 104 | 1830x |
if (this->input_type == "data") {
|
| 105 | 1192x |
return this->observed_values->data.size(); |
| 106 |
} |
|
| 107 | 638x |
if (this->input_type == "random_effects") {
|
| 108 | 578x |
return (*re).size(); |
| 109 |
} |
|
| 110 | 60x |
if (this->input_type == "prior") {
|
| 111 | 16x |
return this->expected_values.size(); |
| 112 |
} |
|
| 113 | 22x |
return x.size(); |
| 114 |
} |
|
| 115 |
}; |
|
| 116 | ||
| 117 |
/** @brief Base class for all module_name functors. |
|
| 118 |
* |
|
| 119 |
* @tparam Type The type of the module_name functor. |
|
| 120 |
* |
|
| 121 |
*/ |
|
| 122 |
template <typename Type> |
|
| 123 |
struct DensityComponentBase : public fims_model_object::FIMSObject<Type>, |
|
| 124 |
public DistributionElementObject<Type> {
|
|
| 125 |
// id_g is the ID of the instance of the DensityComponentBase class. |
|
| 126 |
// this is like a memory tracker. |
|
| 127 |
// Assigning each one its own ID is a way to keep track of |
|
| 128 |
// all the instances of the DensityComponentBase class. |
|
| 129 |
static uint32_t |
|
| 130 |
id_g; /**< global unique identifier for distribution modules */ |
|
| 131 |
int observed_data_id_m = -999; /*!< id of observed data component*/ |
|
| 132 |
fims::Vector<Type> lpdf_vec; /**< vector to record observation level negative |
|
| 133 |
log-likelihood values */ |
|
| 134 |
fims::Vector<Type> report_lpdf_vec; /**< vector to record observation level |
|
| 135 |
negative log-likelihood values */ |
|
| 136 |
bool osa_flag = false; /**< Boolean; if true, osa residuals are calculated */ |
|
| 137 |
bool simulate_flag = |
|
| 138 |
false; /**< Boolean; if true, data are simulated from the distribution */ |
|
| 139 |
std::vector<uint32_t> |
|
| 140 |
key; /**< unique id for variable map that points to a fims::Vector */ |
|
| 141 | ||
| 142 |
#ifdef TMB_MODEL |
|
| 143 |
::objective_function<Type>* of; /**< Pointer to the TMB objective function */ |
|
| 144 |
#endif |
|
| 145 | ||
| 146 |
/** @brief Constructor. |
|
| 147 |
*/ |
|
| 148 | 530x |
DensityComponentBase() {
|
| 149 |
// initialize the priors vector with a size of 1 and set the first element |
|
| 150 |
// to NULL |
|
| 151 | 530x |
this->priors.resize(1); |
| 152 | 530x |
this->priors[0] = NULL; |
| 153 | 530x |
this->id = DensityComponentBase::id_g++; |
| 154 |
} |
|
| 155 | ||
| 156 | 265x |
virtual ~DensityComponentBase() {}
|
| 157 |
/** |
|
| 158 |
* @brief Generic probability density function. Calculates the pdf at the |
|
| 159 |
* independent variable value. |
|
| 160 |
*/ |
|
| 161 |
virtual const Type evaluate() = 0; |
|
| 162 |
}; |
|
| 163 | ||
| 164 |
/** @brief Default id of the singleton distribution class |
|
| 165 |
*/ |
|
| 166 |
template <typename Type> |
|
| 167 |
uint32_t DensityComponentBase<Type>::id_g = 0; |
|
| 168 | ||
| 169 |
} // namespace fims_distributions |
|
| 170 | ||
| 171 |
#endif /* DENSITY_COMPONENT_BASE_HPP */ |
| 1 |
/** |
|
| 2 |
* @file lognormal_lpdf.hpp |
|
| 3 |
* @brief Lognormal Log Probability Density Function (LPDF) defines the |
|
| 4 |
* Lognormal LPDF class and its fields and returns the log probability density |
|
| 5 |
* function. |
|
| 6 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 7 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 8 |
* folder for reuse information. |
|
| 9 |
*/ |
|
| 10 |
#ifndef LOGNORMAL_LPDF |
|
| 11 |
#define LOGNORMAL_LPDF |
|
| 12 | ||
| 13 |
#include "density_components_base.hpp" |
|
| 14 |
#include "../../common/fims_vector.hpp" |
|
| 15 |
#include "../../common/def.hpp" |
|
| 16 | ||
| 17 |
namespace fims_distributions {
|
|
| 18 |
/** |
|
| 19 |
* LogNormal Log Probability Density Function |
|
| 20 |
*/ |
|
| 21 |
template <typename Type> |
|
| 22 |
struct LogNormalLPDF : public DensityComponentBase<Type> {
|
|
| 23 |
fims::Vector<Type> |
|
| 24 |
log_sd; /**< natural log of the standard deviation of the distribution on |
|
| 25 |
the log scale; can be a vector or scalar */ |
|
| 26 |
Type lpdf = static_cast<Type>(0.0); /**< total log probability density |
|
| 27 |
contribution of the distribution */ |
|
| 28 |
// data_indicator<tmbutils::vector<Type> , Type> keep; /**< Indicator used in |
|
| 29 |
// TMB one-step-ahead residual calculations */ |
|
| 30 | ||
| 31 |
/** @brief Constructor. |
|
| 32 |
*/ |
|
| 33 | 166x |
LogNormalLPDF() : DensityComponentBase<Type>() {}
|
| 34 | ||
| 35 |
/** @brief Destructor. |
|
| 36 |
*/ |
|
| 37 | 83x |
virtual ~LogNormalLPDF() {}
|
| 38 | ||
| 39 |
/** |
|
| 40 |
* @brief Evaluates the lognormal probability density function |
|
| 41 |
*/ |
|
| 42 | 1162x |
virtual const Type evaluate() {
|
| 43 |
// set vector size based on input type (prior, process, or data) |
|
| 44 | 1162x |
size_t n_x = this->get_n_x(); |
| 45 |
// setup vector for recording the log probability density function values |
|
| 46 | 1162x |
this->lpdf_vec.resize(n_x); |
| 47 | 1162x |
this->report_lpdf_vec.resize(n_x); |
| 48 | 1162x |
std::fill(this->lpdf_vec.begin(), this->lpdf_vec.end(), |
| 49 | 1162x |
static_cast<Type>(0)); |
| 50 | 1162x |
std::fill(this->report_lpdf_vec.begin(), this->report_lpdf_vec.end(), |
| 51 | 1162x |
static_cast<Type>(0)); |
| 52 | 1162x |
this->lpdf = static_cast<Type>(0); |
| 53 | ||
| 54 |
// Dimension checks |
|
| 55 |
/* TODO: fix dimension check as expected values no longer used for data |
|
| 56 |
if (n_x != this->expected_values.size()) {
|
|
| 57 |
throw std::invalid_argument( |
|
| 58 |
"LognormalLPDF::Vector index out of bounds. The size of observed " |
|
| 59 |
"data does not equal the size of expected values. The observed data " |
|
| 60 |
"vector is of size " + |
|
| 61 |
fims::to_string(n_x) + " and the expected vector is of size " + |
|
| 62 |
fims::to_string(this->expected_values.size())); |
|
| 63 |
}*/ |
|
| 64 | 473x |
if (this->log_sd.size() > 1 && n_x != this->log_sd.size()) {
|
| 65 | 1x |
throw std::invalid_argument( |
| 66 |
"LognormalLPDF::Vector index out of bounds. The size of observed " |
|
| 67 |
"data does not equal the size of the log_sd vector. The observed " |
|
| 68 |
"data vector is of size " + |
|
| 69 |
fims::to_string(n_x) + " and the log_sd vector is of size " + |
|
| 70 |
fims::to_string(this->log_sd.size())); |
|
| 71 |
} |
|
| 72 | ||
| 73 | 35416x |
for (size_t i = 0; i < n_x; i++) {
|
| 74 |
#ifdef TMB_MODEL |
|
| 75 | 34256x |
if (this->input_type == "data") {
|
| 76 |
// if data, check if there are any NA values and skip lpdf calculation |
|
| 77 |
// if there are See Deroba and Miller, 2016 |
|
| 78 |
// (https://doi.org/10.1016/j.fishres.2015.12.002) for the use of |
|
| 79 |
// lognormal constant |
|
| 80 | 34200x |
if (this->get_observed(i) != this->observed_values->na_value) {
|
| 81 | 34074x |
this->lpdf_vec[i] = |
| 82 | 34074x |
dnorm(log(this->get_observed(i)), this->get_expected(i), |
| 83 | 40530x |
fims_math::exp(log_sd.get_force_scalar(i)), true) - |
| 84 | 40530x |
log(this->get_observed(i)); |
| 85 |
} else {
|
|
| 86 | 126x |
this->lpdf_vec[i] = 0; |
| 87 |
} |
|
| 88 |
} else {
|
|
| 89 | 28x |
if (this->input_type == "random_effects") {
|
| 90 |
// if random effects, no lognormal constant needs to be applied |
|
| 91 | ! |
this->lpdf_vec[i] = |
| 92 | ! |
dnorm(log(this->get_observed(i)), this->get_expected(i), |
| 93 | ! |
fims_math::exp(log_sd.get_force_scalar(i)), true); |
| 94 |
} else {
|
|
| 95 | 28x |
this->lpdf_vec[i] = |
| 96 | 28x |
dnorm(log(this->get_observed(i)), this->get_expected(i), |
| 97 | 28x |
fims_math::exp(log_sd.get_force_scalar(i)), true) - |
| 98 | 28x |
log(this->get_observed(i)); |
| 99 |
} |
|
| 100 |
} |
|
| 101 | ||
| 102 | 34256x |
this->report_lpdf_vec[i] = this->lpdf_vec[i]; |
| 103 | 34256x |
lpdf += this->lpdf_vec[i]; |
| 104 | 34256x |
if (this->simulate_flag) {
|
| 105 | ! |
FIMS_SIMULATE_F(this->of) { // preprocessor definition in interface.hpp
|
| 106 |
// this simulates data that is mean biased |
|
| 107 | ! |
if (this->input_type == "data") {
|
| 108 | ! |
this->observed_values->at(i) = fims_math::exp( |
| 109 | ! |
rnorm(this->get_expected(i), |
| 110 | ! |
fims_math::exp(log_sd.get_force_scalar(i)))); |
| 111 |
} |
|
| 112 | ! |
if (this->input_type == "random_effects") {
|
| 113 | ! |
(*this->re)[i] = fims_math::exp( |
| 114 | ! |
rnorm(this->get_expected(i), |
| 115 | ! |
fims_math::exp(log_sd.get_force_scalar(i)))); |
| 116 |
} |
|
| 117 | ! |
if (this->input_type == "prior") {
|
| 118 | ! |
(*(this->priors[i]))[0] = fims_math::exp( |
| 119 | ! |
rnorm(this->get_expected(i), |
| 120 | ! |
fims_math::exp(log_sd.get_force_scalar(i)))); |
| 121 |
} |
|
| 122 |
} |
|
| 123 |
} |
|
| 124 |
#endif |
|
| 125 |
} |
|
| 126 |
#ifdef TMB_MODEL |
|
| 127 | 1160x |
vector<Type> lognormal_x = this->x.to_tmb(); |
| 128 |
// FIMS_REPORT_F(lognormal_x, this->of); |
|
| 129 |
#endif |
|
| 130 | 1160x |
return (lpdf); |
| 131 |
} |
|
| 132 |
}; |
|
| 133 |
} // namespace fims_distributions |
|
| 134 |
#endif |
| 1 |
/** |
|
| 2 |
* @file multinomial_lpmf.hpp |
|
| 3 |
* @brief Multinomial Log Probability Mass Function (LPMF) module file defines |
|
| 4 |
* the Multinomial LPMF class and its fields and returns the log probability |
|
| 5 |
* mass function. |
|
| 6 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 7 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 8 |
* folder for reuse information. |
|
| 9 |
*/ |
|
| 10 |
#ifndef MULTINOMIAL_LPMF |
|
| 11 |
#define MULTINOMIAL_LPMF |
|
| 12 | ||
| 13 |
#include "density_components_base.hpp" |
|
| 14 |
#include "../../common/fims_vector.hpp" |
|
| 15 |
#include "../../common/def.hpp" |
|
| 16 | ||
| 17 |
namespace fims_distributions {
|
|
| 18 |
/** |
|
| 19 |
* Multinomial Log Probability Mass Function |
|
| 20 |
*/ |
|
| 21 |
template <typename Type> |
|
| 22 |
struct MultinomialLPMF : public DensityComponentBase<Type> {
|
|
| 23 |
Type lpdf = static_cast<Type>(0.0); /**< total negative log-likelihood |
|
| 24 |
contribution of the distribution */ |
|
| 25 |
fims::Vector<size_t> dims; /**< Dimensions of the number of rows and columns |
|
| 26 |
of the multivariate dataset */ |
|
| 27 | ||
| 28 |
/** @brief Constructor. |
|
| 29 |
*/ |
|
| 30 | 258x |
MultinomialLPMF() : DensityComponentBase<Type>() {}
|
| 31 | ||
| 32 |
/** @brief Destructor. |
|
| 33 |
*/ |
|
| 34 | 129x |
virtual ~MultinomialLPMF() {}
|
| 35 | ||
| 36 |
/** |
|
| 37 |
* @brief Evaluates the multinomial probability mass function |
|
| 38 |
*/ |
|
| 39 | 935x |
virtual const Type evaluate() {
|
| 40 |
// set dims using observed_values if no user input |
|
| 41 | 935x |
if (dims.size() != 2) {
|
| 42 | 100x |
dims.resize(2); |
| 43 | 100x |
dims[0] = this->observed_values->get_imax(); |
| 44 | 100x |
dims[1] = this->observed_values->get_jmax(); |
| 45 |
} |
|
| 46 | ||
| 47 |
// setup vector for recording the log probability density function values |
|
| 48 | 935x |
Type lpdf = static_cast<Type>(0.0); /**< total log probability mass |
| 49 |
contribution of the distribution */ |
|
| 50 | 935x |
this->lpdf_vec.resize(dims[0]); |
| 51 | 935x |
this->report_lpdf_vec.clear(); |
| 52 | 935x |
std::fill(this->lpdf_vec.begin(), this->lpdf_vec.end(), 0); |
| 53 | ||
| 54 |
// Dimension checks |
|
| 55 | 935x |
if (this->input_type == "data") {
|
| 56 | 930x |
if (this->data_expected_values) {
|
| 57 | 930x |
if (dims[0] * dims[1] != this->data_expected_values->size()) {
|
| 58 | ! |
throw std::invalid_argument( |
| 59 |
"MultinomialLPDF: Vector index out of bounds. The dimension of " |
|
| 60 |
"the " |
|
| 61 |
"number of rows times the number of columns is of size " + |
|
| 62 | ! |
fims::to_string(dims[0] * dims[1]) + |
| 63 |
" and the expected vector is of size " + |
|
| 64 | ! |
fims::to_string(this->data_expected_values->size())); |
| 65 |
} |
|
| 66 |
} |
|
| 67 |
} else {
|
|
| 68 |
if (dims[0] * dims[1] != this->x.size()) {
|
|
| 69 |
throw std::invalid_argument( |
|
| 70 |
"MultinomialLPDF: Vector index out of bounds. The dimension of the " |
|
| 71 |
"number of rows times the number of columns is of size " + |
|
| 72 |
fims::to_string(dims[0] * dims[1]) + |
|
| 73 |
" and the observed vector is of size " + |
|
| 74 |
fims::to_string(this->x.size())); |
|
| 75 |
} |
|
| 76 |
if (this->x.size() != this->expected_values.size()) {
|
|
| 77 |
throw std::invalid_argument( |
|
| 78 |
"MultinomialLPDF: Vector index out of bounds. The dimension of the " |
|
| 79 |
"observed vector of size " + |
|
| 80 |
fims::to_string(this->x.size()) + |
|
| 81 |
" and the expected vector is of size " + |
|
| 82 |
fims::to_string(this->expected_values.size())); |
|
| 83 |
} |
|
| 84 |
} |
|
| 85 | ||
| 86 | 28836x |
for (size_t i = 0; i < dims[0]; i++) {
|
| 87 |
// for each row, create new x and prob vectors |
|
| 88 | 27903x |
fims::Vector<Type> x_vector; |
| 89 | 27903x |
fims::Vector<Type> prob_vector; |
| 90 | 27903x |
x_vector.resize(dims[1]); |
| 91 | 27903x |
prob_vector.resize(dims[1]); |
| 92 | ||
| 93 | 27903x |
bool containsNA = false; /**< skips the entire row if any values are NA */ |
| 94 | ||
| 95 |
#ifdef TMB_MODEL |
|
| 96 | 508266x |
for (size_t j = 0; j < dims[1]; j++) {
|
| 97 | 480426x |
if (this->input_type == "data") {
|
| 98 |
// if data, check if there are any NA values and skip lpdf calculation |
|
| 99 |
// for entire row if there are |
|
| 100 | 480396x |
if (this->get_observed(i, j) == this->observed_values->na_value) {
|
| 101 | 63x |
containsNA = true; |
| 102 | 63x |
break; |
| 103 |
} |
|
| 104 | 480333x |
if (!containsNA) {
|
| 105 | 480333x |
size_t idx = (i * dims[1]) + j; |
| 106 | 480333x |
x_vector[j] = this->get_observed(i, j); |
| 107 | 480333x |
prob_vector[j] = this->get_expected(idx); |
| 108 |
} |
|
| 109 |
} else {
|
|
| 110 |
// if not data (i.e. prior or process), use x vector instead of |
|
| 111 |
// observed_values |
|
| 112 |
size_t idx = (i * dims[1]) + j; |
|
| 113 |
x_vector[j] = this->get_observed(idx); |
|
| 114 |
prob_vector[j] = this->get_expected(idx); |
|
| 115 |
} |
|
| 116 |
} |
|
| 117 | ||
| 118 | 27903x |
if (!containsNA) {
|
| 119 | 50412x |
this->lpdf_vec[i] = |
| 120 | 33108x |
dmultinom(x_vector.to_tmb(), prob_vector.to_tmb(), true); |
| 121 |
} else {
|
|
| 122 | 63x |
this->lpdf_vec[i] = 0; |
| 123 |
} |
|
| 124 |
// track the values for output, e.g., report_lpdf_vec |
|
| 125 | 27903x |
this->report_lpdf_vec.insert(this->report_lpdf_vec.end(), dims[1], |
| 126 | 27903x |
this->lpdf_vec[i]); |
| 127 | 27903x |
lpdf += this->lpdf_vec[i]; |
| 128 |
/* |
|
| 129 |
if (this->simulate_flag) |
|
| 130 |
{
|
|
| 131 |
FIMS_SIMULATE_F(this->of) |
|
| 132 |
{
|
|
| 133 |
fims::Vector<Type> sim_observed; |
|
| 134 |
sim_observed.resize(dims[1]); |
|
| 135 |
sim_observed = rmultinom(prob_vector); |
|
| 136 |
sim_observed.resize(this->x); |
|
| 137 |
for (size_t j = 0; j < dims[1]; j++) |
|
| 138 |
{
|
|
| 139 |
idx = (i * dims[1]) + j; |
|
| 140 |
this->x[idx] = sim_observed[j]; |
|
| 141 |
} |
|
| 142 |
} |
|
| 143 |
} |
|
| 144 |
*/ |
|
| 145 |
#endif |
|
| 146 |
} |
|
| 147 | ||
| 148 |
#ifdef TMB_MODEL |
|
| 149 |
#endif |
|
| 150 | 933x |
this->lpdf = lpdf; |
| 151 | 933x |
return (lpdf); |
| 152 |
} |
|
| 153 |
}; |
|
| 154 |
} // namespace fims_distributions |
|
| 155 |
#endif |
| 1 |
/** |
|
| 2 |
* @file normal_lpdf.hpp |
|
| 3 |
* @brief Normal Log Probability Density Function (LPDF) module file defines |
|
| 4 |
* the Normal LPDF class and its fields and returns the log probability density |
|
| 5 |
* function. |
|
| 6 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 7 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 8 |
* folder for reuse information. |
|
| 9 |
*/ |
|
| 10 | ||
| 11 |
#ifndef NORMAL_LPDF |
|
| 12 |
#define NORMAL_LPDF |
|
| 13 | ||
| 14 |
#include "density_components_base.hpp" |
|
| 15 |
#include "../../common/fims_vector.hpp" |
|
| 16 |
#include "../../common/def.hpp" |
|
| 17 | ||
| 18 |
namespace fims_distributions {
|
|
| 19 |
/** |
|
| 20 |
* Normal Log Probability Density Function |
|
| 21 |
*/ |
|
| 22 |
template <typename Type> |
|
| 23 |
struct NormalLPDF : public DensityComponentBase<Type> {
|
|
| 24 |
fims::Vector<Type> log_sd; /**< the natural log of the standard deviation of |
|
| 25 |
the distribution; can be a vector or scalar */ |
|
| 26 |
Type lpdf = static_cast<Type>(0.0); /**< total log probability density |
|
| 27 |
contribution of the distribution */ |
|
| 28 | ||
| 29 |
/** @brief Constructor. |
|
| 30 |
*/ |
|
| 31 | 106x |
NormalLPDF() : DensityComponentBase<Type>() {}
|
| 32 | ||
| 33 |
/** @brief Destructor. |
|
| 34 |
*/ |
|
| 35 | 53x |
virtual ~NormalLPDF() {}
|
| 36 | ||
| 37 |
/** |
|
| 38 |
* @brief Evaluates the normal probability density function |
|
| 39 |
*/ |
|
| 40 | 616x |
virtual const Type evaluate() {
|
| 41 |
// set vector size based on input type (prior, process, or data) |
|
| 42 | 616x |
size_t n_x = this->get_n_x(); |
| 43 |
// setup vector for recording the log probability density function values |
|
| 44 | 616x |
this->lpdf_vec.resize(n_x); |
| 45 | 616x |
this->report_lpdf_vec.resize(n_x); |
| 46 | 616x |
std::fill(this->lpdf_vec.begin(), this->lpdf_vec.end(), |
| 47 | 616x |
static_cast<Type>(0)); |
| 48 | 616x |
std::fill(this->report_lpdf_vec.begin(), this->report_lpdf_vec.end(), |
| 49 | 616x |
static_cast<Type>(0)); |
| 50 | 616x |
lpdf = static_cast<Type>(0); |
| 51 | ||
| 52 |
// Dimension checks |
|
| 53 | 616x |
if (n_x != this->expected_values.size()) {
|
| 54 | 1x |
throw std::invalid_argument( |
| 55 |
"NormalLPDF::Vector index out of bounds. The size of observed data " |
|
| 56 |
"does not equal the size of expected values. The observed data " |
|
| 57 |
"vector is of size " + |
|
| 58 |
fims::to_string(n_x) + " and the expected vector is of size " + |
|
| 59 |
fims::to_string(this->expected_values.size())); |
|
| 60 |
} |
|
| 61 | 250x |
if (this->log_sd.size() > 1 && n_x != this->log_sd.size()) {
|
| 62 | 1x |
throw std::invalid_argument( |
| 63 |
"NormalLPDF::Vector index out of bounds. The size of observed data " |
|
| 64 |
"does not equal the size of the log_sd vector. The observed data " |
|
| 65 |
"vector is of size " + |
|
| 66 |
fims::to_string(n_x) + " and the log_sd vector is of size " + |
|
| 67 |
fims::to_string(this->log_sd.size())); |
|
| 68 |
} |
|
| 69 | ||
| 70 | 17460x |
for (size_t i = 0; i < n_x; i++) {
|
| 71 |
#ifdef TMB_MODEL |
|
| 72 | 16848x |
if (this->input_type == "data") {
|
| 73 |
// if data, check if there are any NA values and skip lpdf calculation |
|
| 74 |
// if there are |
|
| 75 | ! |
if (this->get_observed(i) != this->observed_values->na_value) {
|
| 76 | ! |
this->lpdf_vec[i] = |
| 77 | ! |
dnorm(this->get_observed(i), this->get_expected(i), |
| 78 | ! |
fims_math::exp(log_sd.get_force_scalar(i)), true); |
| 79 |
} else {
|
|
| 80 | ! |
this->lpdf_vec[i] = 0; |
| 81 |
} |
|
| 82 |
// if not data (i.e. prior or process), use x vector instead of |
|
| 83 |
// observed_values |
|
| 84 |
} else {
|
|
| 85 | 16848x |
this->lpdf_vec[i] = |
| 86 | 16848x |
dnorm(this->get_observed(i), this->get_expected(i), |
| 87 | 16848x |
fims_math::exp(log_sd.get_force_scalar(i)), true); |
| 88 |
} |
|
| 89 | 16848x |
this->report_lpdf_vec[i] = this->lpdf_vec[i]; |
| 90 | 16848x |
lpdf += this->lpdf_vec[i]; |
| 91 | 16848x |
if (this->simulate_flag) {
|
| 92 | ! |
FIMS_SIMULATE_F(this->of) {
|
| 93 | ! |
if (this->input_type == "data") {
|
| 94 | ! |
this->observed_values->at(i) = |
| 95 | ! |
rnorm(this->get_expected(i), |
| 96 | ! |
fims_math::exp(log_sd.get_force_scalar(i))); |
| 97 |
} |
|
| 98 | ! |
if (this->input_type == "random_effects") {
|
| 99 | ! |
(*this->re)[i] = rnorm(this->get_expected(i), |
| 100 | ! |
fims_math::exp(log_sd.get_force_scalar(i))); |
| 101 |
} |
|
| 102 | ! |
if (this->input_type == "prior") {
|
| 103 | ! |
(*(this->priors[i]))[0] = |
| 104 | ! |
rnorm(this->get_expected(i), |
| 105 | ! |
fims_math::exp(log_sd.get_force_scalar(i))); |
| 106 |
} |
|
| 107 |
} |
|
| 108 |
} |
|
| 109 |
#endif |
|
| 110 |
/* osa not working yet |
|
| 111 |
if(osa_flag){//data observation type implements osa residuals
|
|
| 112 |
//code for osa cdf method |
|
| 113 |
this->lpdf_vec[i] = this->keep.cdf_lower[i] * log( pnorm(this->x[i], |
|
| 114 |
this->get_expected(i), sd[i]) ); this->lpdf_vec[i] = |
|
| 115 |
this->keep.cdf_upper[i] * log( 1.0 - pnorm(this->x[i], |
|
| 116 |
this->get_expected(i), sd[i]) ); |
|
| 117 |
} */ |
|
| 118 |
} |
|
| 119 |
#ifdef TMB_MODEL |
|
| 120 | 612x |
vector<Type> normal_x = this->x.to_tmb(); |
| 121 |
#endif |
|
| 122 | 612x |
return (lpdf); |
| 123 |
} |
|
| 124 |
}; |
|
| 125 | ||
| 126 |
} // namespace fims_distributions |
|
| 127 |
#endif |
| 1 |
/** |
|
| 2 |
* @file interface.hpp |
|
| 3 |
* @brief An interface to the modeling platforms, e.g., TMB. |
|
| 4 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 5 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 6 |
* folder for reuse information. |
|
| 7 |
*/ |
|
| 8 | ||
| 9 |
#ifndef FIMS_INTERFACE_HPP |
|
| 10 |
#define FIMS_INTERFACE_HPP |
|
| 11 | ||
| 12 |
/* |
|
| 13 |
* @brief Interface file. Uses pre-processing macros |
|
| 14 |
* to interface with multiple modeling platforms. |
|
| 15 |
*/ |
|
| 16 | ||
| 17 |
// traits for interfacing with TMB |
|
| 18 | ||
| 19 |
#ifdef TMB_MODEL |
|
| 20 |
// use isnan macro in math.h instead of TMB's isnan for fixing the r-cmd-check |
|
| 21 |
// issue |
|
| 22 |
#include <math.h> |
|
| 23 | ||
| 24 |
#include <TMB.hpp> |
|
| 25 | ||
| 26 |
// define REPORT, ADREPORT, and SIMULATE |
|
| 27 |
#define FIMS_REPORT_F(name, F) \ |
|
| 28 |
if (isDouble<Type>::value && \ |
|
| 29 |
F->current_parallel_region < static_cast<Type>(0)) { \
|
|
| 30 |
Rf_defineVar(Rf_install(#name), PROTECT(asSEXP(name)), F->report); \ |
|
| 31 |
UNPROTECT(1); \ |
|
| 32 |
} |
|
| 33 | ||
| 34 |
#define FIMS_REPORT_F_(name, obj, F) \ |
|
| 35 |
if (isDouble<Type>::value && \ |
|
| 36 |
F->current_parallel_region < static_cast<Type>(0)) { \
|
|
| 37 |
Rf_defineVar(Rf_install(name), PROTECT(asSEXP(obj)), F->report); \ |
|
| 38 |
UNPROTECT(1); \ |
|
| 39 |
} |
|
| 40 | ||
| 41 |
#define ADREPORT_F(name, F) F->reportvector.push(name, #name); |
|
| 42 | ||
| 43 |
template <typename Type> |
|
| 44 | 17408x |
vector<Type> ADREPORTvector(vector<vector<Type> > x) {
|
| 45 | 17408x |
int outer_dim = x.size(); |
| 46 | 17408x |
int dim = 0; |
| 47 | 45152x |
for (int i = 0; i < outer_dim; i++) {
|
| 48 | 27744x |
dim += x(i).size(); |
| 49 |
} |
|
| 50 | 17408x |
vector<Type> res(dim); |
| 51 | 17408x |
int idx = 0; |
| 52 | 45152x |
for (int i = 0; i < outer_dim; i++) {
|
| 53 | 27744x |
int inner_dim = x(i).size(); |
| 54 | 6323648x |
for (int j = 0; j < inner_dim; j++) {
|
| 55 | 6295904x |
res(idx) = x(i)(j); |
| 56 | 6295904x |
idx += 1; |
| 57 |
} |
|
| 58 |
} |
|
| 59 | 17408x |
return res; |
| 60 |
} |
|
| 61 | ||
| 62 |
#define FIMS_SIMULATE_F(F) if (isDouble<Type>::value && F->do_simulate) |
|
| 63 | ||
| 64 |
#endif /* TMB_MODEL */ |
|
| 65 | ||
| 66 |
#ifndef TMB_MODEL |
|
| 67 |
/** |
|
| 68 |
* @brief TMB macro that simulates data. |
|
| 69 |
*/ |
|
| 70 |
#define FIMS_SIMULATE_F(F) |
|
| 71 |
/** |
|
| 72 |
* @brief TMB macro that reports variables. |
|
| 73 |
*/ |
|
| 74 |
#define FIMS_REPORT_F(name, F) |
|
| 75 |
/** |
|
| 76 |
* @brief TMB macro that reports variables and uncertainties. |
|
| 77 |
*/ |
|
| 78 |
#define ADREPORT_F(name, F) |
|
| 79 |
#endif |
|
| 80 | ||
| 81 |
#endif /* FIMS_INTERFACE_HPP */ |
| 1 |
/** |
|
| 2 |
* @file rcpp_interface.hpp |
|
| 3 |
* @brief The Rcpp interface to declare things. |
|
| 4 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 5 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 6 |
* folder for reuse information. |
|
| 7 |
*/ |
|
| 8 |
#ifndef FIMS_INTERFACE_RCPP_INTERFACE_HPP |
|
| 9 |
#define FIMS_INTERFACE_RCPP_INTERFACE_HPP |
|
| 10 |
#include "../../common/model.hpp" |
|
| 11 |
#include "../../utilities/fims_json.hpp" |
|
| 12 |
#include "rcpp_objects/rcpp_data.hpp" |
|
| 13 |
#include "rcpp_objects/rcpp_distribution.hpp" |
|
| 14 |
#include "rcpp_objects/rcpp_fleet.hpp" |
|
| 15 |
#include "rcpp_objects/rcpp_growth.hpp" |
|
| 16 |
#include "rcpp_objects/rcpp_interface_base.hpp" |
|
| 17 |
#include "rcpp_objects/rcpp_maturity.hpp" |
|
| 18 |
#include "rcpp_objects/rcpp_models.hpp" |
|
| 19 |
#include "rcpp_objects/rcpp_natural_mortality.hpp" |
|
| 20 |
#include "rcpp_objects/rcpp_population.hpp" |
|
| 21 |
#include "rcpp_objects/rcpp_recruitment.hpp" |
|
| 22 |
#include "rcpp_objects/rcpp_selectivity.hpp" |
|
| 23 | ||
| 24 |
/** |
|
| 25 |
* Initializes the logging system, setting all signal handling. |
|
| 26 |
*/ |
|
| 27 | 29x |
void init_logging() {
|
| 28 | 29x |
std::signal(SIGSEGV, &fims::WriteAtExit); |
| 29 | 29x |
std::signal(SIGINT, &fims::WriteAtExit); |
| 30 | 29x |
std::signal(SIGABRT, &fims::WriteAtExit); |
| 31 | 29x |
std::signal(SIGFPE, &fims::WriteAtExit); |
| 32 | 29x |
std::signal(SIGILL, &fims::WriteAtExit); |
| 33 | 29x |
std::signal(SIGTERM, &fims::WriteAtExit); |
| 34 |
} |
|
| 35 | ||
| 36 |
/** |
|
| 37 |
* @brief Creates the TMB model object and adds interface objects to it. |
|
| 38 |
* |
|
| 39 |
* @details |
|
| 40 |
* This function is called within `initialize_fims()` from R and is not |
|
| 41 |
* typically called by the user directly. |
|
| 42 |
*/ |
|
| 43 | 29x |
bool CreateTMBModel() {
|
| 44 | 29x |
init_logging(); |
| 45 | ||
| 46 |
// clear first |
|
| 47 |
// base model |
|
| 48 |
#ifdef TMBAD_FRAMEWORK |
|
| 49 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> info0 = |
|
| 50 | 29x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 51 | 29x |
info0->Clear(); |
| 52 | ||
| 53 |
std::shared_ptr<fims_info::Information<TMBAD_FIMS_TYPE>> info = |
|
| 54 | 29x |
fims_info::Information<TMBAD_FIMS_TYPE>::GetInstance(); |
| 55 | 29x |
info->Clear(); |
| 56 | ||
| 57 |
#else |
|
| 58 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> info0 = |
|
| 59 |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
|
| 60 |
info0->Clear() |
|
| 61 | ||
| 62 |
// first-order derivative |
|
| 63 |
std::shared_ptr<fims_info::Information<TMB_FIMS_FIRST_ORDER>> |
|
| 64 |
info1 = fims_info::Information<TMB_FIMS_FIRST_ORDER>::GetInstance(); |
|
| 65 |
info1->Clear(); |
|
| 66 | ||
| 67 |
// second-order derivative |
|
| 68 |
std::shared_ptr<fims_info::Information<TMB_FIMS_SECOND_ORDER>> info2 = |
|
| 69 |
fims_info::Information<TMB_FIMS_SECOND_ORDER>::GetInstance(); |
|
| 70 |
info2->Clear(); |
|
| 71 | ||
| 72 |
// third-order derivative |
|
| 73 |
std::shared_ptr<fims_info::Information<TMB_FIMS_THIRD_ORDER>> info3 = |
|
| 74 |
fims_info::Information<TMB_FIMS_THIRD_ORDER>::GetInstance(); |
|
| 75 |
info3->Clear(); |
|
| 76 |
#endif |
|
| 77 | ||
| 78 | 29x |
FIMS_INFO_LOG( |
| 79 |
"Adding FIMS objects to TMB, " + |
|
| 80 |
fims::to_string(FIMSRcppInterfaceBase::fims_interface_objects.size()) + |
|
| 81 |
" objects"); |
|
| 82 | 451x |
for (size_t i = 0; i < FIMSRcppInterfaceBase::fims_interface_objects.size(); |
| 83 |
i++) {
|
|
| 84 | 422x |
FIMSRcppInterfaceBase::fims_interface_objects[i]->add_to_fims_tmb(); |
| 85 |
} |
|
| 86 | ||
| 87 |
// base model |
|
| 88 |
#ifdef TMBAD_FRAMEWORK |
|
| 89 | ||
| 90 | 29x |
info0->CreateModel(); |
| 91 | 29x |
info0->CheckModel(); |
| 92 | ||
| 93 | 29x |
info->CreateModel(); |
| 94 | ||
| 95 |
#else |
|
| 96 | ||
| 97 |
info0->CreateModel(); |
|
| 98 |
info0->CheckModel(); |
|
| 99 | ||
| 100 |
info1->CreateModel(); |
|
| 101 | ||
| 102 |
// second-order derivative |
|
| 103 | ||
| 104 |
info2->CreateModel(); |
|
| 105 | ||
| 106 |
// third-order derivative |
|
| 107 | ||
| 108 |
info3->CreateModel(); |
|
| 109 |
#endif |
|
| 110 | ||
| 111 |
// instantiate the model? TODO: Ask Matthew what this does |
|
| 112 |
std::shared_ptr<fims_model::Model<TMB_FIMS_REAL_TYPE>> m0 = |
|
| 113 | 29x |
fims_model::Model<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 114 | ||
| 115 | 29x |
return true; |
| 116 |
} |
|
| 117 | ||
| 118 |
/** |
|
| 119 |
* @brief Sets the fixed parameters vector object. |
|
| 120 |
* Updates the internal parameter values for the model base |
|
| 121 |
* of type TMB_FIMS_REAL_TYPE. Typically called before |
|
| 122 |
* finalize or get_output to ensure the correct values are used. |
|
| 123 |
* |
|
| 124 |
* Usage example: |
|
| 125 |
* \code{.R}
|
|
| 126 |
* set_fixed_parameters(c(1, 2, 3)) |
|
| 127 |
* catch_at_age$get_output() |
|
| 128 |
* \endcode |
|
| 129 |
* |
|
| 130 |
* @param par A vector of parameter values. |
|
| 131 |
*/ |
|
| 132 | 11x |
void set_fixed_parameters(Rcpp::NumericVector par) {
|
| 133 |
// base model |
|
| 134 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> info0 = |
|
| 135 | 11x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 136 | ||
| 137 | 541x |
for (size_t i = 0; i < info0->fixed_effects_parameters.size(); i++) {
|
| 138 | 530x |
*info0->fixed_effects_parameters[i] = par[i]; |
| 139 |
} |
|
| 140 |
} |
|
| 141 | ||
| 142 |
/** |
|
| 143 |
* @brief Gets the fixed parameters vector object. |
|
| 144 |
* |
|
| 145 |
* @return Rcpp::NumericVector |
|
| 146 |
*/ |
|
| 147 | 25x |
Rcpp::NumericVector get_fixed_parameters_vector() {
|
| 148 |
// base model |
|
| 149 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> info0 = |
|
| 150 | 25x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 151 | ||
| 152 | 25x |
Rcpp::NumericVector p; |
| 153 | ||
| 154 | 1037x |
for (size_t i = 0; i < info0->fixed_effects_parameters.size(); i++) {
|
| 155 | 1012x |
p.push_back(*info0->fixed_effects_parameters[i]); |
| 156 |
} |
|
| 157 | ||
| 158 | 50x |
return p; |
| 159 |
} |
|
| 160 | ||
| 161 |
/** |
|
| 162 |
* @brief Sets the random parameters vector object. |
|
| 163 |
* Updates the internal random effects parameter values for |
|
| 164 |
* the model base of TMB_FIMS_REAL_TYPE. Typically called before |
|
| 165 |
* finalize or get_output to ensure the correct values are used. |
|
| 166 |
* |
|
| 167 |
* Usage example: |
|
| 168 |
* \code{.R}
|
|
| 169 |
* set_random_parameters(c(1, 2, 3)) |
|
| 170 |
* catch_at_age$get_output() |
|
| 171 |
* \endcode |
|
| 172 |
* |
|
| 173 |
* @param par A vector of parameter values. |
|
| 174 |
*/ |
|
| 175 | ! |
void set_random_parameters(Rcpp::NumericVector par) {
|
| 176 |
// base model |
|
| 177 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> info0 = |
|
| 178 | ! |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 179 | ||
| 180 | ! |
for (size_t i = 0; i < info0->random_effects_parameters.size(); i++) {
|
| 181 | ! |
*info0->random_effects_parameters[i] = par[i]; |
| 182 |
} |
|
| 183 |
} |
|
| 184 | ||
| 185 |
/** |
|
| 186 |
* @brief Gets the random parameters vector object. |
|
| 187 |
* |
|
| 188 |
* @return Rcpp::NumericVector |
|
| 189 |
*/ |
|
| 190 | 25x |
Rcpp::NumericVector get_random_parameters_vector() {
|
| 191 |
// base model |
|
| 192 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> d0 = |
|
| 193 | 25x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 194 | ||
| 195 | 25x |
Rcpp::NumericVector p; |
| 196 | ||
| 197 | 122x |
for (size_t i = 0; i < d0->random_effects_parameters.size(); i++) {
|
| 198 | 97x |
p.push_back(*d0->random_effects_parameters[i]); |
| 199 |
} |
|
| 200 | ||
| 201 | 50x |
return p; |
| 202 |
} |
|
| 203 | ||
| 204 |
/** |
|
| 205 |
* @brief Gets the parameter names object. |
|
| 206 |
* |
|
| 207 |
* @param pars |
|
| 208 |
* @return Rcpp::List |
|
| 209 |
*/ |
|
| 210 | 16x |
Rcpp::List get_parameter_names(Rcpp::List pars) {
|
| 211 |
// base model |
|
| 212 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> d0 = |
|
| 213 | 16x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 214 | ||
| 215 | 32x |
pars.attr("names") = d0->parameter_names;
|
| 216 | ||
| 217 | 32x |
return pars; |
| 218 |
} |
|
| 219 | ||
| 220 |
/** |
|
| 221 |
* @brief Gets the random effects names object. |
|
| 222 |
* |
|
| 223 |
* @param pars |
|
| 224 |
* @return Rcpp::List |
|
| 225 |
*/ |
|
| 226 | 8x |
Rcpp::List get_random_names(Rcpp::List pars) {
|
| 227 |
// base model |
|
| 228 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> d0 = |
|
| 229 | 8x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 230 | ||
| 231 | 16x |
pars.attr("names") = d0->random_effects_names;
|
| 232 | ||
| 233 | 16x |
return pars; |
| 234 |
} |
|
| 235 | ||
| 236 |
/** |
|
| 237 |
* @brief Clears the internal objects. |
|
| 238 |
* |
|
| 239 |
* @tparam Type |
|
| 240 |
*/ |
|
| 241 |
template <typename Type> |
|
| 242 | 444x |
void clear_internal() {
|
| 243 | 444x |
std::shared_ptr<fims_info::Information<Type>> d0 = |
| 244 |
fims_info::Information<Type>::GetInstance(); |
|
| 245 | 444x |
d0->Clear(); |
| 246 |
} |
|
| 247 | ||
| 248 |
/** |
|
| 249 |
* @brief Clears the vector of independent variables. |
|
| 250 |
*/ |
|
| 251 | 111x |
void clear() {
|
| 252 | 222x |
FIMS_INFO_LOG("Clearing FIMS objects from interface stack");
|
| 253 |
// rcpp_interface_base.hpp |
|
| 254 | 111x |
FIMSRcppInterfaceBase::fims_interface_objects.clear(); |
| 255 | ||
| 256 |
// Parameter and ParameterVector |
|
| 257 | 111x |
Parameter::id_g = 1; |
| 258 | 111x |
ParameterVector::id_g = 1; |
| 259 |
// rcpp_data.hpp |
|
| 260 | 111x |
DataInterfaceBase::id_g = 1; |
| 261 | 111x |
DataInterfaceBase::live_objects.clear(); |
| 262 | ||
| 263 | 111x |
AgeCompDataInterface::id_g = 1; |
| 264 | 111x |
AgeCompDataInterface::live_objects.clear(); |
| 265 | ||
| 266 | 111x |
LengthCompDataInterface::id_g = 1; |
| 267 | 111x |
LengthCompDataInterface::live_objects.clear(); |
| 268 | ||
| 269 | 111x |
LandingsDataInterface::id_g = 1; |
| 270 | 111x |
LandingsDataInterface::live_objects.clear(); |
| 271 | ||
| 272 | 111x |
IndexDataInterface::id_g = 1; |
| 273 | 111x |
IndexDataInterface::live_objects.clear(); |
| 274 | ||
| 275 |
// rcpp_fleets.hpp |
|
| 276 | 111x |
FleetInterfaceBase::id_g = 1; |
| 277 | 111x |
FleetInterfaceBase::live_objects.clear(); |
| 278 | ||
| 279 | 111x |
FleetInterface::id_g = 1; |
| 280 | 111x |
FleetInterface::live_objects.clear(); |
| 281 | ||
| 282 |
// rcpp_growth.hpp |
|
| 283 | 111x |
GrowthInterfaceBase::id_g = 1; |
| 284 | 111x |
GrowthInterfaceBase::live_objects.clear(); |
| 285 | ||
| 286 | 111x |
EWAAGrowthInterface::id_g = 1; |
| 287 | 111x |
EWAAGrowthInterface::live_objects.clear(); |
| 288 | ||
| 289 |
// rcpp_maturity.hpp |
|
| 290 | 111x |
MaturityInterfaceBase::id_g = 1; |
| 291 | 111x |
MaturityInterfaceBase::live_objects.clear(); |
| 292 | ||
| 293 | 111x |
LogisticMaturityInterface::id_g = 1; |
| 294 | 111x |
LogisticMaturityInterface::live_objects.clear(); |
| 295 | ||
| 296 |
// rcpp_population.hpp |
|
| 297 | 111x |
PopulationInterfaceBase::id_g = 1; |
| 298 | 111x |
PopulationInterfaceBase::live_objects.clear(); |
| 299 | ||
| 300 | 111x |
PopulationInterface::id_g = 1; |
| 301 | 111x |
PopulationInterface::live_objects.clear(); |
| 302 | ||
| 303 |
// rcpp_recruitment.hpp |
|
| 304 | 111x |
RecruitmentInterfaceBase::id_g = 1; |
| 305 | 111x |
RecruitmentInterfaceBase::live_objects.clear(); |
| 306 | ||
| 307 | 111x |
BevertonHoltRecruitmentInterface::id_g = 1; |
| 308 | 111x |
BevertonHoltRecruitmentInterface::live_objects.clear(); |
| 309 | ||
| 310 |
// rcpp_selectivity.hpp |
|
| 311 | 111x |
SelectivityInterfaceBase::id_g = 1; |
| 312 | 111x |
SelectivityInterfaceBase::live_objects.clear(); |
| 313 | ||
| 314 | 111x |
LogisticSelectivityInterface::id_g = 1; |
| 315 | 111x |
LogisticSelectivityInterface::live_objects.clear(); |
| 316 | ||
| 317 | 111x |
DoubleLogisticSelectivityInterface::id_g = 1; |
| 318 | 111x |
DoubleLogisticSelectivityInterface::live_objects.clear(); |
| 319 | ||
| 320 |
// rcpp_distribution.hpp |
|
| 321 | 111x |
DistributionsInterfaceBase::id_g = 1; |
| 322 | 111x |
DistributionsInterfaceBase::live_objects.clear(); |
| 323 | ||
| 324 | 111x |
DnormDistributionsInterface::id_g = 1; |
| 325 | 111x |
DnormDistributionsInterface::live_objects.clear(); |
| 326 | ||
| 327 | 111x |
DlnormDistributionsInterface::id_g = 1; |
| 328 | 111x |
DlnormDistributionsInterface::live_objects.clear(); |
| 329 | ||
| 330 | 111x |
DmultinomDistributionsInterface::id_g = 1; |
| 331 | 111x |
DmultinomDistributionsInterface::live_objects.clear(); |
| 332 | ||
| 333 | 111x |
FisheryModelInterfaceBase::id_g = 1; |
| 334 | 111x |
FisheryModelInterfaceBase::live_objects.clear(); |
| 335 | ||
| 336 |
#ifdef TMBAD_FRAMEWORK |
|
| 337 | 111x |
clear_internal<TMB_FIMS_REAL_TYPE>(); |
| 338 | 111x |
clear_internal<TMBAD_FIMS_TYPE>(); |
| 339 |
#else |
|
| 340 |
clear_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 341 |
clear_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 342 |
clear_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 343 |
clear_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 344 |
#endif |
|
| 345 | ||
| 346 | 111x |
fims::FIMSLog::fims_log->clear(); |
| 347 |
} |
|
| 348 | ||
| 349 |
/** |
|
| 350 |
* @brief Gets the log entries as a string in JSON format. |
|
| 351 |
*/ |
|
| 352 | ! |
std::string get_log() { return fims::FIMSLog::fims_log->get_log(); }
|
| 353 | ||
| 354 |
/** |
|
| 355 |
* @brief Gets the error entries from the log as a string in JSON format. |
|
| 356 |
*/ |
|
| 357 | ! |
std::string get_log_errors() { return fims::FIMSLog::fims_log->get_errors(); }
|
| 358 | ||
| 359 |
/** |
|
| 360 |
* @brief Gets the warning entries from the log as a string in JSON format. |
|
| 361 |
*/ |
|
| 362 | ! |
std::string get_log_warnings() {
|
| 363 | ! |
return fims::FIMSLog::fims_log->get_warnings(); |
| 364 |
} |
|
| 365 | ||
| 366 |
/** |
|
| 367 |
* @brief Gets the info entries from the log as a string in JSON format. |
|
| 368 |
*/ |
|
| 369 | ! |
std::string get_log_info() { return fims::FIMSLog::fims_log->get_info(); }
|
| 370 | ||
| 371 |
/** |
|
| 372 |
* @brief Gets log entries by module as a string in JSON format. |
|
| 373 |
*/ |
|
| 374 | ! |
std::string get_log_module(const std::string &module) {
|
| 375 | ! |
return fims::FIMSLog::fims_log->get_module(module); |
| 376 |
} |
|
| 377 | ||
| 378 |
/** |
|
| 379 |
* @brief If true, writes the log on exit. |
|
| 380 |
*/ |
|
| 381 | ! |
void write_log(bool write) {
|
| 382 | ! |
FIMS_INFO_LOG("Setting FIMS write log: " + fims::to_string(write));
|
| 383 | ! |
fims::FIMSLog::fims_log->write_on_exit = write; |
| 384 |
} |
|
| 385 | ||
| 386 |
/** |
|
| 387 |
* @brief Sets the path for the log file to be written to. |
|
| 388 |
*/ |
|
| 389 | ! |
void set_log_path(const std::string &path) {
|
| 390 | ! |
FIMS_INFO_LOG("Setting FIMS log path: " + path);
|
| 391 | ! |
fims::FIMSLog::fims_log->set_path(path); |
| 392 |
} |
|
| 393 | ||
| 394 |
/** |
|
| 395 |
* @brief If true, throws a runtime exception when an error is logged. |
|
| 396 |
*/ |
|
| 397 | ! |
void set_log_throw_on_error(bool throw_on_error) {
|
| 398 | ! |
fims::FIMSLog::fims_log->throw_on_error = throw_on_error; |
| 399 |
} |
|
| 400 | ||
| 401 |
/** |
|
| 402 |
* @brief Adds an info entry to the log from the R environment. |
|
| 403 |
*/ |
|
| 404 | ! |
void log_info(std::string log_entry) {
|
| 405 | ! |
fims::FIMSLog::fims_log->info_message(log_entry, -1, "R_env", |
| 406 |
"R_script_entry"); |
|
| 407 |
} |
|
| 408 | ||
| 409 |
/** |
|
| 410 |
* @brief Adds a warning entry to the log from the R environment. |
|
| 411 |
*/ |
|
| 412 | ! |
void log_warning(std::string log_entry) {
|
| 413 | ! |
fims::FIMSLog::fims_log->warning_message(log_entry, -1, "R_env", |
| 414 |
"R_script_entry"); |
|
| 415 |
} |
|
| 416 | ||
| 417 |
/** |
|
| 418 |
* @brief Escapes quotations. |
|
| 419 |
* |
|
| 420 |
* @param input A string. |
|
| 421 |
* @return std::string |
|
| 422 |
*/ |
|
| 423 | ! |
std::string escapeQuotes(const std::string &input) {
|
| 424 | ! |
std::string result = input; |
| 425 | ! |
std::string search = "\""; |
| 426 | ! |
std::string replace = "\\\""; |
| 427 | ||
| 428 |
// Find each occurrence of `"` and replace it with `\"` |
|
| 429 | ! |
size_t pos = result.find(search); |
| 430 | ! |
while (pos != std::string::npos) {
|
| 431 | ! |
result.replace(pos, search.size(), replace); |
| 432 | ! |
pos = result.find(search, |
| 433 | ! |
pos + replace.size()); // Move past the replaced position |
| 434 |
} |
|
| 435 | ! |
return result; |
| 436 |
} |
|
| 437 | ||
| 438 |
/** |
|
| 439 |
* @brief Adds a error entry to the log from the R environment. |
|
| 440 |
*/ |
|
| 441 | ! |
void log_error(std::string log_entry) {
|
| 442 | ! |
std::stringstream ss; |
| 443 | ! |
ss << "capture.output(traceback(4))"; |
| 444 |
SEXP expression, result; |
|
| 445 |
ParseStatus status; |
|
| 446 | ||
| 447 | ! |
PROTECT(expression = R_ParseVector(Rf_mkString(ss.str().c_str()), 1, &status, |
| 448 |
R_NilValue)); |
|
| 449 | ! |
if (status != PARSE_OK) {
|
| 450 | ! |
Rcpp::Rcout << "Error parsing expression" << std::endl; |
| 451 | ! |
UNPROTECT(1); |
| 452 |
} |
|
| 453 | ! |
Rcpp::Rcout << "before call."; |
| 454 | ! |
PROTECT(result = Rf_eval(VECTOR_ELT(expression, 0), R_GlobalEnv)); |
| 455 | ! |
Rcpp::Rcout << "after call."; |
| 456 | ! |
UNPROTECT(2); |
| 457 | ! |
std::stringstream ss_ret; |
| 458 | ! |
ss_ret << "traceback: "; |
| 459 | ! |
for (int j = 0; j < LENGTH(result); j++) {
|
| 460 | ! |
std::string str(CHAR(STRING_ELT(result, j))); |
| 461 | ! |
ss_ret << escapeQuotes(str) << "\\n"; |
| 462 |
} |
|
| 463 | ||
| 464 |
std::string ret = |
|
| 465 | ! |
ss_ret.str(); //"find error";//Rcpp::as<std::string>(result); |
| 466 | ||
| 467 | ! |
fims::FIMSLog::fims_log->error_message(log_entry, -1, "R_env", ret.c_str()); |
| 468 |
} |
|
| 469 |
#endif // FIMS_INTERFACE_RCPP_INTERFACE_HPP |
| 1 |
/** |
|
| 2 |
* @file rcpp_data.hpp |
|
| 3 |
* @brief The Rcpp interface to declare different types of data, e.g., |
|
| 4 |
* age-composition and index data. Allows for the use of methods::new() in R. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_DATA_HPP |
|
| 10 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_DATA_HPP |
|
| 11 | ||
| 12 |
#include "../../../common/information.hpp" |
|
| 13 |
#include "rcpp_interface_base.hpp" |
|
| 14 | ||
| 15 |
/** |
|
| 16 |
* @brief Rcpp interface that serves as the parent class for Rcpp data |
|
| 17 |
* interfaces. This type should be inherited and not called from R directly. |
|
| 18 |
*/ |
|
| 19 |
class DataInterfaceBase : public FIMSRcppInterfaceBase {
|
|
| 20 |
public: |
|
| 21 |
/** |
|
| 22 |
* @brief The vector of data that is being passed from R. |
|
| 23 |
*/ |
|
| 24 |
Rcpp::NumericVector observed_data; |
|
| 25 |
/** |
|
| 26 |
* @brief The vector of uncertainty that is being passed from R. |
|
| 27 |
*/ |
|
| 28 |
Rcpp::NumericVector uncertainty; |
|
| 29 |
/** |
|
| 30 |
* @brief The static id of the DataInterfaceBase object. |
|
| 31 |
*/ |
|
| 32 |
static uint32_t id_g; |
|
| 33 |
/** |
|
| 34 |
* @brief The local id of the DataInterfaceBase object. |
|
| 35 |
* |
|
| 36 |
*/ |
|
| 37 |
uint32_t id; |
|
| 38 |
/** |
|
| 39 |
* @brief The map associating the IDs of DataInterfaceBase to the objects. |
|
| 40 |
* This is a live object, which is an object that has been created and lives |
|
| 41 |
* in memory. |
|
| 42 |
*/ |
|
| 43 |
static std::map<uint32_t, std::shared_ptr<DataInterfaceBase>> live_objects; |
|
| 44 | ||
| 45 |
/** |
|
| 46 |
* @brief The constructor. |
|
| 47 |
*/ |
|
| 48 | 113x |
DataInterfaceBase() {
|
| 49 | 113x |
this->id = DataInterfaceBase::id_g++; |
| 50 |
/* Create instance of map: key is id and value is pointer to |
|
| 51 |
DataInterfaceBase */ |
|
| 52 |
// DataInterfaceBase::live_objects[this->id] = this; |
|
| 53 |
} |
|
| 54 | ||
| 55 |
/** |
|
| 56 |
* @brief Construct a new Data Interface Base object |
|
| 57 |
* |
|
| 58 |
* @param other |
|
| 59 |
*/ |
|
| 60 | 113x |
DataInterfaceBase(const DataInterfaceBase &other) |
| 61 | 226x |
: observed_data(other.observed_data), |
| 62 | 113x |
uncertainty(other.uncertainty), |
| 63 | 226x |
id(other.id) {}
|
| 64 | ||
| 65 |
/** |
|
| 66 |
* @brief The destructor. |
|
| 67 |
*/ |
|
| 68 | 226x |
virtual ~DataInterfaceBase() {}
|
| 69 | ||
| 70 |
/** |
|
| 71 |
* @brief Get the ID for the child data interface objects to inherit. |
|
| 72 |
*/ |
|
| 73 | ! |
virtual uint32_t get_id() { return this->id; }
|
| 74 | ||
| 75 |
/** |
|
| 76 |
* @brief Adds the parameters to the TMB model. |
|
| 77 |
*/ |
|
| 78 | ! |
virtual bool add_to_fims_tmb() { return true; };
|
| 79 |
}; |
|
| 80 |
// static id of the DataInterfaceBase object |
|
| 81 |
uint32_t DataInterfaceBase::id_g = 1; |
|
| 82 |
// local id of the DataInterfaceBase object map relating the ID of the |
|
| 83 |
// DataInterfaceBase to the DataInterfaceBase objects |
|
| 84 |
std::map<uint32_t, std::shared_ptr<DataInterfaceBase>> |
|
| 85 |
DataInterfaceBase::live_objects; |
|
| 86 | ||
| 87 |
/** |
|
| 88 |
* @brief The Rcpp interface for AgeComp to instantiate the object from R: |
|
| 89 |
* acomp <- methods::new(AgeComp). |
|
| 90 |
*/ |
|
| 91 |
class AgeCompDataInterface : public DataInterfaceBase {
|
|
| 92 |
public: |
|
| 93 |
/** |
|
| 94 |
* @brief The first dimension of the data, which relates to the number of age |
|
| 95 |
* bins. |
|
| 96 |
*/ |
|
| 97 |
fims_int amax = 0; |
|
| 98 |
/** |
|
| 99 |
* @brief The second dimension of the data, which relates to the number of |
|
| 100 |
* time steps or years. |
|
| 101 |
*/ |
|
| 102 |
fims_int ymax = 0; |
|
| 103 |
/** |
|
| 104 |
* @brief The vector of age-composition data that is being passed from R. |
|
| 105 |
*/ |
|
| 106 |
RealVector age_comp_data; |
|
| 107 |
/** |
|
| 108 |
* @brief The vector of age-composition uncertainty that is being passed from |
|
| 109 |
* R. |
|
| 110 |
*/ |
|
| 111 |
RealVector uncertainty; |
|
| 112 | ||
| 113 |
/** |
|
| 114 |
* @brief The constructor. |
|
| 115 |
*/ |
|
| 116 | 39x |
AgeCompDataInterface(int ymax = 0, int amax = 0) : DataInterfaceBase() {
|
| 117 | 39x |
this->amax = amax; |
| 118 | 39x |
this->ymax = ymax; |
| 119 | 39x |
this->age_comp_data.resize(amax * ymax); |
| 120 | 39x |
this->uncertainty.resize(amax * ymax); |
| 121 | 39x |
DataInterfaceBase::live_objects[this->id] = |
| 122 | 78x |
std::make_shared<AgeCompDataInterface>(*this); |
| 123 | 39x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 124 | 39x |
DataInterfaceBase::live_objects[this->id]); |
| 125 |
} |
|
| 126 | ||
| 127 |
/** |
|
| 128 |
* @brief Construct a new Age Comp Data Interface object |
|
| 129 |
* |
|
| 130 |
* @param other |
|
| 131 |
*/ |
|
| 132 | 39x |
AgeCompDataInterface(const AgeCompDataInterface &other) |
| 133 | 39x |
: DataInterfaceBase(other), |
| 134 | 39x |
amax(other.amax), |
| 135 | 39x |
ymax(other.ymax), |
| 136 | 39x |
age_comp_data(other.age_comp_data), |
| 137 | 78x |
uncertainty(other.uncertainty) {}
|
| 138 | ||
| 139 |
/** |
|
| 140 |
* @brief The destructor. |
|
| 141 |
*/ |
|
| 142 | 234x |
virtual ~AgeCompDataInterface() {}
|
| 143 | ||
| 144 |
/** |
|
| 145 |
* @brief Gets the ID of the interface base object. |
|
| 146 |
* @return The ID. |
|
| 147 |
*/ |
|
| 148 | 34x |
virtual uint32_t get_id() { return this->id; }
|
| 149 | ||
| 150 |
/** |
|
| 151 |
* @brief Converts the data to json representation for the output. |
|
| 152 |
* @return A string is returned specifying that the module relates to the |
|
| 153 |
* data interface with age-composition data. It also returns the ID, the rank |
|
| 154 |
* of 2, the dimensions by printing ymax and amax, followed by the data values |
|
| 155 |
* themselves. This string is formatted for a json file. |
|
| 156 |
*/ |
|
| 157 | 22x |
virtual std::string to_json() {
|
| 158 | 22x |
std::stringstream ss; |
| 159 | ||
| 160 | 22x |
ss << "{\n";
|
| 161 | 22x |
ss << " \"name\": \"AgeComp\",\n"; |
| 162 | 22x |
ss << " \"id\":" << this->id << ",\n"; |
| 163 | 22x |
ss << " \"type\": \"data\",\n"; |
| 164 | 22x |
ss << " \"dimensionality\": {\n";
|
| 165 | 22x |
ss << " \"header\": [" << "\"n_ages\", \"n_years\"" << "],\n"; |
| 166 | 22x |
ss << " \"dimensions\": [" << amax << ", " << ymax << "]\n},\n"; |
| 167 | 22x |
ss << " \"value\": ["; |
| 168 | 7920x |
for (R_xlen_t i = 0; i < age_comp_data.size() - 1; i++) {
|
| 169 | 7898x |
ss << age_comp_data[i] << ", "; |
| 170 |
} |
|
| 171 | 22x |
ss << age_comp_data[age_comp_data.size() - 1] << "],\n"; |
| 172 | 22x |
ss << "\"uncertainty\":[ "; |
| 173 | 7920x |
for (R_xlen_t i = 0; i < uncertainty.size() - 1; i++) {
|
| 174 | 7898x |
ss << uncertainty[i] << ", "; |
| 175 |
} |
|
| 176 | 22x |
ss << uncertainty[uncertainty.size() - 1] << "]\n"; |
| 177 | 22x |
ss << "}"; |
| 178 | 44x |
return ss.str(); |
| 179 |
} |
|
| 180 | ||
| 181 |
#ifdef TMB_MODEL |
|
| 182 | ||
| 183 |
template <typename Type> |
|
| 184 | 136x |
bool add_to_fims_tmb_internal() {
|
| 185 | 136x |
std::shared_ptr<fims_data_object::DataObject<Type>> age_comp_data = |
| 186 | 136x |
std::make_shared<fims_data_object::DataObject<Type>>(this->ymax, |
| 187 | 136x |
this->amax); |
| 188 | ||
| 189 | 136x |
age_comp_data->id = this->id; |
| 190 | 4216x |
for (int y = 0; y < ymax; y++) {
|
| 191 | 53040x |
for (int a = 0; a < amax; a++) {
|
| 192 | 48960x |
int i_age_year = y * amax + a; |
| 193 | 48960x |
age_comp_data->at(y, a) = this->age_comp_data[i_age_year]; |
| 194 | 48960x |
age_comp_data->uncertainty[i_age_year] = this->uncertainty[i_age_year]; |
| 195 |
} |
|
| 196 |
} |
|
| 197 | ||
| 198 | 136x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 199 |
fims_info::Information<Type>::GetInstance(); |
|
| 200 | ||
| 201 | 136x |
info->data_objects[this->id] = age_comp_data; |
| 202 | ||
| 203 | 136x |
return true; |
| 204 |
} |
|
| 205 | ||
| 206 |
/** |
|
| 207 |
* @brief Adds the parameters to the TMB model. |
|
| 208 |
* @return A boolean of true. |
|
| 209 |
*/ |
|
| 210 | 34x |
virtual bool add_to_fims_tmb() {
|
| 211 |
#ifdef TMBAD_FRAMEWORK |
|
| 212 | 34x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 213 | 34x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 214 |
#else |
|
| 215 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 216 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 217 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 218 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 219 |
#endif |
|
| 220 | ||
| 221 | 34x |
return true; |
| 222 |
} |
|
| 223 | ||
| 224 |
#endif |
|
| 225 |
}; |
|
| 226 | ||
| 227 |
/** |
|
| 228 |
* @brief The Rcpp interface for LengthComp to instantiate the object from R: |
|
| 229 |
* lcomp <- methods::new(LengthComp). |
|
| 230 |
*/ |
|
| 231 |
class LengthCompDataInterface : public DataInterfaceBase {
|
|
| 232 |
public: |
|
| 233 |
/** |
|
| 234 |
* @brief The first dimension of the data, which relates to the number of |
|
| 235 |
* length bins. |
|
| 236 |
*/ |
|
| 237 |
fims_int lmax = 0; |
|
| 238 |
/** |
|
| 239 |
* @brief The second dimension of the data, which relates to the number of |
|
| 240 |
* time steps or years. |
|
| 241 |
*/ |
|
| 242 |
fims_int ymax = 0; |
|
| 243 |
/** |
|
| 244 |
* @brief The vector of length-composition data that is being passed from R. |
|
| 245 |
*/ |
|
| 246 |
RealVector length_comp_data; |
|
| 247 |
/** |
|
| 248 |
* @brief The vector of length-composition uncertainty that is being passed |
|
| 249 |
* from R. |
|
| 250 |
*/ |
|
| 251 |
RealVector uncertainty; |
|
| 252 | ||
| 253 |
/** |
|
| 254 |
* @brief The constructor. |
|
| 255 |
*/ |
|
| 256 | 33x |
LengthCompDataInterface(int ymax = 0, int lmax = 0) : DataInterfaceBase() {
|
| 257 | 33x |
this->lmax = lmax; |
| 258 | 33x |
this->ymax = ymax; |
| 259 | 33x |
this->length_comp_data.resize(lmax * ymax); |
| 260 | 33x |
this->uncertainty.resize(lmax * ymax); |
| 261 | 33x |
DataInterfaceBase::live_objects[this->id] = |
| 262 | 66x |
std::make_shared<LengthCompDataInterface>(*this); |
| 263 | 33x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 264 | 33x |
DataInterfaceBase::live_objects[this->id]); |
| 265 |
} |
|
| 266 | ||
| 267 |
/** |
|
| 268 |
* @brief Construct a new Length Comp Data Interface object |
|
| 269 |
* |
|
| 270 |
* @param other |
|
| 271 |
*/ |
|
| 272 | 33x |
LengthCompDataInterface(const LengthCompDataInterface &other) |
| 273 | 33x |
: DataInterfaceBase(other), |
| 274 | 33x |
lmax(other.lmax), |
| 275 | 33x |
ymax(other.ymax), |
| 276 | 33x |
length_comp_data(other.length_comp_data), |
| 277 | 66x |
uncertainty(other.uncertainty) {}
|
| 278 | ||
| 279 |
/** |
|
| 280 |
* @brief The destructor. |
|
| 281 |
*/ |
|
| 282 | 198x |
virtual ~LengthCompDataInterface() {}
|
| 283 | ||
| 284 |
/** |
|
| 285 |
* @brief Gets the ID of the interface base object. |
|
| 286 |
* @return The ID. |
|
| 287 |
*/ |
|
| 288 | 32x |
virtual uint32_t get_id() { return this->id; }
|
| 289 | ||
| 290 |
/** |
|
| 291 |
* @brief Converts the data to json representation for the output. |
|
| 292 |
* @return A string is returned specifying that the module relates to the |
|
| 293 |
* data interface with length-composition data. It also returns the ID, the |
|
| 294 |
* rank of 2, the dimensions by printing ymax and lmax, followed by the data |
|
| 295 |
* values themselves. This string is formatted for a json file. |
|
| 296 |
*/ |
|
| 297 | 20x |
virtual std::string to_json() {
|
| 298 | 20x |
std::stringstream ss; |
| 299 | ||
| 300 | 20x |
ss << "{\n";
|
| 301 | 20x |
ss << " \"name\": \"LengthComp\",\n"; |
| 302 | 20x |
ss << " \"id\":" << this->id << ",\n"; |
| 303 | 20x |
ss << " \"type\": \"data\",\n"; |
| 304 | 20x |
ss << " \"dimensionality\": {\n";
|
| 305 | 20x |
ss << " \"header\": [" << "\"n_lengths\", \"n_years\"" << "],\n"; |
| 306 | 20x |
ss << " \"dimensions\": [" << lmax << ", " << ymax << "]\n},\n"; |
| 307 | 20x |
ss << " \"value\": ["; |
| 308 | 13800x |
for (R_xlen_t i = 0; i < length_comp_data.size() - 1; i++) {
|
| 309 | 13780x |
ss << length_comp_data[i] << ", "; |
| 310 |
} |
|
| 311 | 20x |
ss << length_comp_data[length_comp_data.size() - 1] << "],\n"; |
| 312 | 20x |
ss << "\"uncertainty\": [ "; |
| 313 | 13800x |
for (R_xlen_t i = 0; i < uncertainty.size() - 1; i++) {
|
| 314 | 13780x |
ss << uncertainty[i] << ", "; |
| 315 |
} |
|
| 316 | 20x |
ss << uncertainty[uncertainty.size() - 1] << "]\n"; |
| 317 | 20x |
ss << "}"; |
| 318 | 40x |
return ss.str(); |
| 319 |
} |
|
| 320 | ||
| 321 |
#ifdef TMB_MODEL |
|
| 322 |
template <typename Type> |
|
| 323 | 128x |
bool add_to_fims_tmb_internal() {
|
| 324 | 128x |
std::shared_ptr<fims_data_object::DataObject<Type>> length_comp_data = |
| 325 | 128x |
std::make_shared<fims_data_object::DataObject<Type>>(this->ymax, |
| 326 | 128x |
this->lmax); |
| 327 | 128x |
length_comp_data->id = this->id; |
| 328 | 3968x |
for (int y = 0; y < ymax; y++) {
|
| 329 | 92160x |
for (int l = 0; l < lmax; l++) {
|
| 330 | 88320x |
int i_length_year = y * lmax + l; |
| 331 | 88320x |
length_comp_data->at(y, l) = this->length_comp_data[i_length_year]; |
| 332 | 88320x |
length_comp_data->uncertainty[i_length_year] = |
| 333 |
this->uncertainty[i_length_year]; |
|
| 334 |
} |
|
| 335 |
} |
|
| 336 | 128x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 337 |
fims_info::Information<Type>::GetInstance(); |
|
| 338 | 128x |
info->data_objects[this->id] = length_comp_data; |
| 339 | 128x |
return true; |
| 340 |
} |
|
| 341 | ||
| 342 |
/** |
|
| 343 |
* @brief Adds the parameters to the TMB model. |
|
| 344 |
* @return A boolean of true. |
|
| 345 |
*/ |
|
| 346 | 32x |
virtual bool add_to_fims_tmb() {
|
| 347 |
#ifdef TMBAD_FRAMEWORK |
|
| 348 | 32x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 349 | 32x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 350 |
#else |
|
| 351 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 352 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 353 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 354 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 355 |
#endif |
|
| 356 | ||
| 357 | 32x |
return true; |
| 358 |
} |
|
| 359 |
#endif |
|
| 360 |
}; |
|
| 361 | ||
| 362 |
/** |
|
| 363 |
* @brief The Rcpp interface for Index to instantiate the object from R: |
|
| 364 |
* fleet <- methods::new(Index). |
|
| 365 |
*/ |
|
| 366 |
class IndexDataInterface : public DataInterfaceBase {
|
|
| 367 |
public: |
|
| 368 |
/** |
|
| 369 |
* @brief An integer that specifies the second dimension of the data. |
|
| 370 |
*/ |
|
| 371 |
fims_int ymax = 0; |
|
| 372 |
/** |
|
| 373 |
* @brief The vector of index data that is being passed from R. |
|
| 374 |
*/ |
|
| 375 |
RealVector index_data; |
|
| 376 |
/** |
|
| 377 |
* @brief The vector of index uncertainty that is being passed from |
|
| 378 |
* R. |
|
| 379 |
*/ |
|
| 380 |
RealVector uncertainty; |
|
| 381 | ||
| 382 |
/** |
|
| 383 |
* @brief The constructor. |
|
| 384 |
*/ |
|
| 385 | 23x |
IndexDataInterface(int ymax = 0) : DataInterfaceBase() {
|
| 386 | 23x |
this->ymax = ymax; |
| 387 | 23x |
this->index_data.resize(ymax); |
| 388 | 23x |
this->uncertainty.resize(ymax); |
| 389 | 23x |
DataInterfaceBase::live_objects[this->id] = |
| 390 | 46x |
std::make_shared<IndexDataInterface>(*this); |
| 391 | 23x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 392 | 23x |
DataInterfaceBase::live_objects[this->id]); |
| 393 |
} |
|
| 394 | ||
| 395 |
/** |
|
| 396 |
* @brief Construct a new Index Data Interface object |
|
| 397 |
* |
|
| 398 |
* @param other |
|
| 399 |
*/ |
|
| 400 | 23x |
IndexDataInterface(const IndexDataInterface &other) |
| 401 | 23x |
: DataInterfaceBase(other), |
| 402 | 23x |
ymax(other.ymax), |
| 403 | 23x |
index_data(other.index_data), |
| 404 | 46x |
uncertainty(other.uncertainty) {}
|
| 405 | ||
| 406 |
/** |
|
| 407 |
* @brief The destructor. |
|
| 408 |
*/ |
|
| 409 | 138x |
virtual ~IndexDataInterface() {}
|
| 410 | ||
| 411 |
/** |
|
| 412 |
* @brief Gets the ID of the interface base object. |
|
| 413 |
* @return The ID. |
|
| 414 |
*/ |
|
| 415 | 21x |
virtual uint32_t get_id() { return this->id; }
|
| 416 | ||
| 417 |
/** |
|
| 418 |
* @brief Converts the data to json representation for the output. |
|
| 419 |
* @return A string is returned specifying that the module relates to the |
|
| 420 |
* data interface with index data. It also returns the ID, the rank of 1, the |
|
| 421 |
* dimensions by printing ymax, followed by the data values themselves. This |
|
| 422 |
* string is formatted for a json file. |
|
| 423 |
*/ |
|
| 424 | 13x |
virtual std::string to_json() {
|
| 425 | 13x |
std::stringstream ss; |
| 426 | ||
| 427 | 13x |
ss << "{\n";
|
| 428 | 13x |
ss << " \"name\": \"Index\",\n"; |
| 429 | 13x |
ss << " \"id\": " << this->id << ",\n"; |
| 430 | 13x |
ss << " \"type\": \"data\",\n"; |
| 431 | 13x |
ss << " \"dimensionality\": {\n";
|
| 432 | 13x |
ss << " \"header\": [" << "\"n_years\"" << "],\n"; |
| 433 | 13x |
ss << " \"dimensions\": [" << ymax << "]\n},\n"; |
| 434 | 13x |
ss << " \"value\": ["; |
| 435 | 390x |
for (R_xlen_t i = 0; i < index_data.size() - 1; i++) {
|
| 436 | 377x |
ss << index_data[i] << ", "; |
| 437 |
} |
|
| 438 | 13x |
ss << index_data[index_data.size() - 1] << "],\n"; |
| 439 | 13x |
ss << "\"uncertainty\": [ "; |
| 440 | 390x |
for (R_xlen_t i = 0; i < uncertainty.size() - 1; i++) {
|
| 441 | 377x |
ss << uncertainty[i] << ", "; |
| 442 |
} |
|
| 443 | 13x |
ss << uncertainty[uncertainty.size() - 1] << "]\n"; |
| 444 | 13x |
ss << "}"; |
| 445 | 26x |
return ss.str(); |
| 446 |
} |
|
| 447 | ||
| 448 |
#ifdef TMB_MODEL |
|
| 449 | ||
| 450 |
template <typename Type> |
|
| 451 | 80x |
bool add_to_fims_tmb_internal() {
|
| 452 | 80x |
std::shared_ptr<fims_data_object::DataObject<Type>> data = |
| 453 | 80x |
std::make_shared<fims_data_object::DataObject<Type>>(this->ymax); |
| 454 | ||
| 455 | 80x |
data->id = this->id; |
| 456 | ||
| 457 | 2480x |
for (int y = 0; y < ymax; y++) {
|
| 458 | 2400x |
data->at(y) = this->index_data[y]; |
| 459 | 2400x |
data->uncertainty[y] = this->uncertainty[y]; |
| 460 |
} |
|
| 461 | ||
| 462 | 80x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 463 |
fims_info::Information<Type>::GetInstance(); |
|
| 464 | ||
| 465 | 80x |
info->data_objects[this->id] = data; |
| 466 | 80x |
return true; |
| 467 |
} |
|
| 468 | ||
| 469 |
/** |
|
| 470 |
* @brief Adds the parameters to the TMB model. |
|
| 471 |
* @return A boolean of true. |
|
| 472 |
*/ |
|
| 473 | 20x |
virtual bool add_to_fims_tmb() {
|
| 474 |
#ifdef TMBAD_FRAMEWORK |
|
| 475 | 20x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 476 | 20x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 477 |
#else |
|
| 478 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 479 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 480 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 481 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 482 |
#endif |
|
| 483 | ||
| 484 | 20x |
return true; |
| 485 |
} |
|
| 486 | ||
| 487 |
#endif |
|
| 488 |
}; |
|
| 489 | ||
| 490 |
/** |
|
| 491 |
* @brief The Rcpp interface for Landings to instantiate the object from R: |
|
| 492 |
* fleet <- methods::new(Landings). |
|
| 493 |
*/ |
|
| 494 |
class LandingsDataInterface : public DataInterfaceBase {
|
|
| 495 |
public: |
|
| 496 |
/** |
|
| 497 |
* @brief An integer that specifies the second dimension of the data. |
|
| 498 |
*/ |
|
| 499 |
fims_int ymax = 0; |
|
| 500 |
/** |
|
| 501 |
* @brief The vector of landings data that is being passed from R. |
|
| 502 |
*/ |
|
| 503 |
RealVector landings_data; |
|
| 504 |
/** |
|
| 505 |
* @brief The vector of landings uncertainty that is being passed from |
|
| 506 |
* R. |
|
| 507 |
*/ |
|
| 508 |
RealVector uncertainty; |
|
| 509 | ||
| 510 |
/** |
|
| 511 |
* @brief The constructor. |
|
| 512 |
*/ |
|
| 513 | 18x |
LandingsDataInterface(int ymax = 0) : DataInterfaceBase() {
|
| 514 | 18x |
this->ymax = ymax; |
| 515 | 18x |
this->landings_data.resize(ymax); |
| 516 | 18x |
this->uncertainty.resize(ymax); |
| 517 | 18x |
DataInterfaceBase::live_objects[this->id] = |
| 518 | 36x |
std::make_shared<LandingsDataInterface>(*this); |
| 519 | 18x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 520 | 18x |
DataInterfaceBase::live_objects[this->id]); |
| 521 |
} |
|
| 522 | ||
| 523 |
/** |
|
| 524 |
* @brief Construct a new Landings Data Interface object |
|
| 525 |
* |
|
| 526 |
* @param other |
|
| 527 |
*/ |
|
| 528 | 18x |
LandingsDataInterface(const LandingsDataInterface &other) |
| 529 | 18x |
: DataInterfaceBase(other), |
| 530 | 18x |
ymax(other.ymax), |
| 531 | 18x |
landings_data(other.landings_data), |
| 532 | 36x |
uncertainty(other.uncertainty) {}
|
| 533 | ||
| 534 |
/** |
|
| 535 |
* @brief The destructor. |
|
| 536 |
*/ |
|
| 537 | 108x |
virtual ~LandingsDataInterface() {}
|
| 538 | ||
| 539 |
/** |
|
| 540 |
* @brief Gets the ID of the interface base object. |
|
| 541 |
* @return The ID. |
|
| 542 |
*/ |
|
| 543 | 18x |
virtual uint32_t get_id() { return this->id; }
|
| 544 | ||
| 545 |
/** |
|
| 546 |
* @brief Converts the data to json representation for the output. |
|
| 547 |
* @return A string is returned specifying that the module relates to the |
|
| 548 |
* data interface with landings data. It also returns the ID, the rank of 1, |
|
| 549 |
* the dimensions by printing ymax, followed by the data values themselves. |
|
| 550 |
* This string is formatted for a json file. |
|
| 551 |
*/ |
|
| 552 | 13x |
virtual std::string to_json() {
|
| 553 | 13x |
std::stringstream ss; |
| 554 | ||
| 555 | 13x |
ss << "{\n";
|
| 556 | 13x |
ss << " \"name\": \"Landings\",\n"; |
| 557 | 13x |
ss << " \"id\": " << this->id << ",\n"; |
| 558 | 13x |
ss << " \"type\": \"data\",\n"; |
| 559 | 13x |
ss << " \"dimensionality\": {\n";
|
| 560 | 13x |
ss << " \"header\": [" << "\"n_years\"" << "],\n"; |
| 561 | 13x |
ss << " \"dimensions\": [" << ymax << "]\n},\n"; |
| 562 | 13x |
ss << " \"value\": ["; |
| 563 | 390x |
for (R_xlen_t i = 0; i < landings_data.size() - 1; i++) {
|
| 564 | 377x |
ss << landings_data[i] << ", "; |
| 565 |
} |
|
| 566 | 13x |
ss << landings_data[landings_data.size() - 1] << "],\n"; |
| 567 | 13x |
ss << "\"uncertainty\": [ "; |
| 568 | 390x |
for (R_xlen_t i = 0; i < uncertainty.size() - 1; i++) {
|
| 569 | 377x |
ss << uncertainty[i] << ", "; |
| 570 |
} |
|
| 571 | 13x |
ss << uncertainty[uncertainty.size() - 1] << "]\n"; |
| 572 | 13x |
ss << "}"; |
| 573 | 26x |
return ss.str(); |
| 574 |
} |
|
| 575 | ||
| 576 |
#ifdef TMB_MODEL |
|
| 577 | ||
| 578 |
template <typename Type> |
|
| 579 | 72x |
bool add_to_fims_tmb_internal() {
|
| 580 | 72x |
std::shared_ptr<fims_data_object::DataObject<Type>> data = |
| 581 | 72x |
std::make_shared<fims_data_object::DataObject<Type>>(this->ymax); |
| 582 | ||
| 583 | 72x |
data->id = this->id; |
| 584 | ||
| 585 | 2232x |
for (int y = 0; y < ymax; y++) {
|
| 586 | 2160x |
data->at(y) = this->landings_data[y]; |
| 587 | 2160x |
data->uncertainty[y] = this->uncertainty[y]; |
| 588 |
} |
|
| 589 | ||
| 590 | 72x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 591 |
fims_info::Information<Type>::GetInstance(); |
|
| 592 | ||
| 593 | 72x |
info->data_objects[this->id] = data; |
| 594 | 72x |
return true; |
| 595 |
} |
|
| 596 | ||
| 597 |
/** |
|
| 598 |
* @brief Adds the parameters to the TMB model. |
|
| 599 |
* @return A boolean of true. |
|
| 600 |
*/ |
|
| 601 | 18x |
virtual bool add_to_fims_tmb() {
|
| 602 |
#ifdef TMBAD_FRAMEWORK |
|
| 603 | 18x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 604 | 18x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 605 |
#else |
|
| 606 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 607 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 608 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 609 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 610 |
#endif |
|
| 611 | ||
| 612 | 18x |
return true; |
| 613 |
} |
|
| 614 | ||
| 615 |
#endif |
|
| 616 |
}; |
|
| 617 | ||
| 618 |
#endif |
| 1 |
/** |
|
| 2 |
* @file rcpp_distribution.hpp |
|
| 3 |
* @brief The Rcpp interface to declare different distributions, e.g., |
|
| 4 |
* normal and log normal. Allows for the use of methods::new() in R. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_DISTRIBUTION_HPP |
|
| 10 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_DISTRIBUTION_HPP |
|
| 11 | ||
| 12 |
#include "../../../distributions/distributions.hpp" |
|
| 13 |
#include "../../interface.hpp" |
|
| 14 |
#include "rcpp_interface_base.hpp" |
|
| 15 | ||
| 16 |
/** |
|
| 17 |
* @brief Rcpp interface that serves as the parent class for Rcpp distribution |
|
| 18 |
* interfaces. This type should be inherited and not called from R directly. |
|
| 19 |
*/ |
|
| 20 |
class DistributionsInterfaceBase : public FIMSRcppInterfaceBase {
|
|
| 21 |
public: |
|
| 22 |
/** |
|
| 23 |
* @brief The static ID of the DistributionsInterfaceBase object. |
|
| 24 |
*/ |
|
| 25 |
static uint32_t id_g; |
|
| 26 |
/** |
|
| 27 |
* @brief The local ID of the DistributionsInterfaceBase object. |
|
| 28 |
*/ |
|
| 29 |
uint32_t id_m; |
|
| 30 |
/** |
|
| 31 |
* @brief The unique ID for the variable map that points to a fims::Vector. |
|
| 32 |
*/ |
|
| 33 |
std::shared_ptr<std::vector<uint32_t>> key_m; |
|
| 34 |
/** |
|
| 35 |
* @brief The type of density input. The options are prior, re, or data. |
|
| 36 |
*/ |
|
| 37 |
SharedString input_type_m; |
|
| 38 |
/** |
|
| 39 |
* @brief The map associating the ID of the DistributionsInterfaceBase to the |
|
| 40 |
DistributionsInterfaceBase objects. This is a live object, which is an |
|
| 41 |
object that has been created and lives in memory. |
|
| 42 |
*/ |
|
| 43 |
static std::map<uint32_t, std::shared_ptr<DistributionsInterfaceBase>> |
|
| 44 |
live_objects; |
|
| 45 |
/** |
|
| 46 |
* @brief The ID of the observed data object, which is set to -999. |
|
| 47 |
*/ |
|
| 48 |
SharedInt interface_observed_data_id_m = -999; |
|
| 49 | ||
| 50 |
/** |
|
| 51 |
* @brief The log probability density function value. |
|
| 52 |
*/ |
|
| 53 |
double lpdf_value = 0; |
|
| 54 |
/** |
|
| 55 |
* @brief The constructor. |
|
| 56 |
*/ |
|
| 57 | 150x |
DistributionsInterfaceBase() {
|
| 58 | 150x |
this->key_m = std::make_shared<std::vector<uint32_t>>(); |
| 59 | 150x |
this->id_m = DistributionsInterfaceBase::id_g++; |
| 60 |
/* Create instance of map: key is id and value is pointer to |
|
| 61 |
DistributionsInterfaceBase */ |
|
| 62 |
// DistributionsInterfaceBase::live_objects[this->id_m] = this; |
|
| 63 |
} |
|
| 64 | ||
| 65 |
/** |
|
| 66 |
* @brief Construct a new Distributions Interface Base object |
|
| 67 |
* |
|
| 68 |
* @param other |
|
| 69 |
*/ |
|
| 70 | 150x |
DistributionsInterfaceBase(const DistributionsInterfaceBase &other) |
| 71 | 300x |
: id_m(other.id_m), |
| 72 | 150x |
key_m(other.key_m), |
| 73 | 150x |
input_type_m(other.input_type_m), |
| 74 | 300x |
interface_observed_data_id_m(other.interface_observed_data_id_m) {}
|
| 75 | ||
| 76 |
/** |
|
| 77 |
* @brief The destructor. |
|
| 78 |
*/ |
|
| 79 | 300x |
virtual ~DistributionsInterfaceBase() {}
|
| 80 | ||
| 81 |
/** |
|
| 82 |
* @brief Get the ID for the child distribution interface objects to inherit. |
|
| 83 |
*/ |
|
| 84 |
virtual uint32_t get_id() = 0; |
|
| 85 | ||
| 86 |
/** |
|
| 87 |
* @brief Sets pointers for data observations, random effects, or priors. |
|
| 88 |
* |
|
| 89 |
* @param input_type String that sets whether the distribution type is for |
|
| 90 |
* priors, random effects, or data. |
|
| 91 |
* @param ids Vector of unique ids for each linked parameter(s), derived |
|
| 92 |
* value(s), or observed data vector. |
|
| 93 |
*/ |
|
| 94 | ! |
virtual bool set_distribution_links(std::string input_type, |
| 95 |
Rcpp::IntegerVector ids) {
|
|
| 96 | ! |
return false; |
| 97 |
} |
|
| 98 | ||
| 99 |
/** |
|
| 100 |
* @brief Set the unique ID for the observed data object. |
|
| 101 |
* |
|
| 102 |
* @param observed_data_id Unique ID for the Observed Age Comp Data |
|
| 103 |
* object |
|
| 104 |
*/ |
|
| 105 | ! |
virtual bool set_observed_data(int observed_data_id) { return false; }
|
| 106 | ||
| 107 |
/** |
|
| 108 |
* @brief A method for each child distribution interface object to inherit so |
|
| 109 |
* each distribution can have an evaluate() function. |
|
| 110 |
*/ |
|
| 111 |
virtual double evaluate() = 0; |
|
| 112 |
}; |
|
| 113 |
// static id of the DistributionsInterfaceBase object |
|
| 114 |
uint32_t DistributionsInterfaceBase::id_g = 1; |
|
| 115 |
// local id of the DistributionsInterfaceBase object map relating the ID of the |
|
| 116 |
// DistributionsInterfaceBase to the DistributionsInterfaceBase objects |
|
| 117 |
std::map<uint32_t, std::shared_ptr<DistributionsInterfaceBase>> |
|
| 118 |
DistributionsInterfaceBase::live_objects; |
|
| 119 | ||
| 120 |
/** |
|
| 121 |
* @brief The Rcpp interface for Dnorm to instantiate from R: |
|
| 122 |
* dnorm_ <- methods::new(DnormDistribution). |
|
| 123 |
*/ |
|
| 124 |
class DnormDistributionsInterface : public DistributionsInterfaceBase {
|
|
| 125 |
public: |
|
| 126 |
/** |
|
| 127 |
* @brief Observed data. |
|
| 128 |
*/ |
|
| 129 |
ParameterVector x; |
|
| 130 |
/** |
|
| 131 |
* @brief The expected values, which would be the mean of x for this |
|
| 132 |
* distribution. |
|
| 133 |
*/ |
|
| 134 |
ParameterVector expected_values; |
|
| 135 |
/** |
|
| 136 |
* @brief The uncertainty, which would be the standard deviation of x for the |
|
| 137 |
* normal distribution. |
|
| 138 |
*/ |
|
| 139 |
ParameterVector log_sd; |
|
| 140 |
/** |
|
| 141 |
* @brief Vector that records the individual log probability function for each |
|
| 142 |
* observation. |
|
| 143 |
*/ |
|
| 144 |
RealVector lpdf_vec; /**< The vector*/ |
|
| 145 | ||
| 146 |
/** |
|
| 147 |
* @brief The constructor. |
|
| 148 |
*/ |
|
| 149 | 34x |
DnormDistributionsInterface() : DistributionsInterfaceBase() {
|
| 150 | 34x |
DistributionsInterfaceBase::live_objects[this->id_m] = |
| 151 | 68x |
std::make_shared<DnormDistributionsInterface>(*this); |
| 152 | 34x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 153 | 34x |
DistributionsInterfaceBase::live_objects[this->id_m]); |
| 154 |
} |
|
| 155 | ||
| 156 |
/** |
|
| 157 |
* @brief Construct a new Dnorm Distributions Interface object |
|
| 158 |
* |
|
| 159 |
* @param other |
|
| 160 |
*/ |
|
| 161 | 34x |
DnormDistributionsInterface(const DnormDistributionsInterface &other) |
| 162 | 34x |
: DistributionsInterfaceBase(other), |
| 163 | 34x |
x(other.x), |
| 164 | 34x |
expected_values(other.expected_values), |
| 165 | 34x |
log_sd(other.log_sd), |
| 166 | 68x |
lpdf_vec(other.lpdf_vec) {}
|
| 167 | ||
| 168 |
/** |
|
| 169 |
* @brief The destructor. |
|
| 170 |
*/ |
|
| 171 | 204x |
virtual ~DnormDistributionsInterface() {}
|
| 172 | ||
| 173 |
/** |
|
| 174 |
* @brief Gets the ID of the interface base object. |
|
| 175 |
* @return The ID. |
|
| 176 |
*/ |
|
| 177 | ! |
virtual uint32_t get_id() { return this->id_m; }
|
| 178 | ||
| 179 |
/** |
|
| 180 |
* @brief Set the unique ID for the observed data object. |
|
| 181 |
* @param observed_data_id Unique ID for the observed data object. |
|
| 182 |
*/ |
|
| 183 | 1x |
virtual bool set_observed_data(int observed_data_id) {
|
| 184 | 1x |
this->interface_observed_data_id_m.set(observed_data_id); |
| 185 | 1x |
return true; |
| 186 |
} |
|
| 187 | ||
| 188 |
/** |
|
| 189 |
* @brief Sets pointers for data observations, random effects, or priors. |
|
| 190 |
* |
|
| 191 |
* @param input_type String that sets whether the distribution type is for |
|
| 192 |
* priors, random effects, or data. |
|
| 193 |
* @param ids Vector of unique ids for each linked parameter(s), derived |
|
| 194 |
* value(s), or observed data vector. |
|
| 195 |
*/ |
|
| 196 | 23x |
virtual bool set_distribution_links(std::string input_type, |
| 197 |
Rcpp::IntegerVector ids) {
|
|
| 198 | 23x |
this->input_type_m.set(input_type); |
| 199 | 23x |
this->key_m->resize(ids.size()); |
| 200 | 49x |
for (int i = 0; i < ids.size(); i++) {
|
| 201 | 26x |
this->key_m->at(i) = ids[i]; |
| 202 |
} |
|
| 203 | 23x |
return true; |
| 204 |
} |
|
| 205 | ||
| 206 |
/** |
|
| 207 |
* @brief Evaluate normal probability density function (pdf). The natural log |
|
| 208 |
* of the pdf is returned. |
|
| 209 |
* @return The natural log of the probability density function (pdf) is |
|
| 210 |
* returned. |
|
| 211 |
*/ |
|
| 212 | 11x |
virtual double evaluate() {
|
| 213 | 11x |
fims_distributions::NormalLPDF<double> dnorm; |
| 214 | 11x |
dnorm.x.resize(this->x.size()); |
| 215 | 11x |
dnorm.expected_values.resize(this->expected_values.size()); |
| 216 | 11x |
dnorm.log_sd.resize(this->log_sd.size()); |
| 217 | 58x |
for (size_t i = 0; i < x.size(); i++) {
|
| 218 | 47x |
dnorm.x[i] = this->x[i].initial_value_m; |
| 219 |
} |
|
| 220 | 59x |
for (size_t i = 0; i < expected_values.size(); i++) {
|
| 221 | 48x |
dnorm.expected_values[i] = this->expected_values[i].initial_value_m; |
| 222 |
} |
|
| 223 | 42x |
for (size_t i = 0; i < log_sd.size(); i++) {
|
| 224 | 31x |
dnorm.log_sd[i] = this->log_sd[i].initial_value_m; |
| 225 |
} |
|
| 226 | 20x |
return dnorm.evaluate(); |
| 227 |
} |
|
| 228 | ||
| 229 |
/** |
|
| 230 |
* @brief Extracts the derived quantities from `Information` to the Rcpp |
|
| 231 |
* object. |
|
| 232 |
*/ |
|
| 233 | 13x |
virtual void finalize() {
|
| 234 | 13x |
if (this->finalized) {
|
| 235 |
// log warning that finalize has been called more than once. |
|
| 236 | ! |
FIMS_WARNING_LOG("DnormDistribution " + fims::to_string(this->id_m) +
|
| 237 |
" has been finalized already."); |
|
| 238 |
} |
|
| 239 | ||
| 240 | 13x |
this->finalized = true; // indicate this has been called already |
| 241 | ||
| 242 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 243 | 13x |
fims_info::Information<double>::GetInstance(); |
| 244 | ||
| 245 | 13x |
fims_info::Information<double>::density_components_iterator it; |
| 246 | ||
| 247 |
// search for density component in Information |
|
| 248 | 13x |
it = info->density_components.find(this->id_m); |
| 249 |
// if not found, just return |
|
| 250 | 13x |
if (it == info->density_components.end()) {
|
| 251 | ! |
FIMS_WARNING_LOG("DnormDistribution " + fims::to_string(this->id_m) +
|
| 252 |
" not found in Information."); |
|
| 253 | ! |
return; |
| 254 |
} else {
|
|
| 255 |
std::shared_ptr<fims_distributions::NormalLPDF<double>> dnorm = |
|
| 256 |
std::dynamic_pointer_cast<fims_distributions::NormalLPDF<double>>( |
|
| 257 | 13x |
it->second); |
| 258 | ||
| 259 | 13x |
this->lpdf_value = dnorm->lpdf; |
| 260 | ||
| 261 | 26x |
for (size_t i = 0; i < this->log_sd.size(); i++) {
|
| 262 | 13x |
if (this->log_sd[i].estimation_type_m.get() == "constant") {
|
| 263 | 11x |
this->log_sd[i].final_value_m = this->log_sd[i].initial_value_m; |
| 264 |
} else {
|
|
| 265 | 2x |
this->log_sd[i].final_value_m = dnorm->log_sd[i]; |
| 266 |
} |
|
| 267 |
} |
|
| 268 | ||
| 269 | 13x |
this->lpdf_vec = RealVector(dnorm->report_lpdf_vec.size()); |
| 270 | 13x |
if (this->expected_values.size() == 1) {
|
| 271 | ! |
this->expected_values.resize(dnorm->expected_values.size()); |
| 272 |
} |
|
| 273 | 13x |
if (this->x.size() == 1) {
|
| 274 | ! |
size_t nx = dnorm->get_n_x(); |
| 275 | ! |
this->x.resize(nx); |
| 276 |
} |
|
| 277 | ||
| 278 | 390x |
for (R_xlen_t i = 0; i < this->lpdf_vec.size(); i++) {
|
| 279 | 377x |
this->lpdf_vec[i] = dnorm->report_lpdf_vec[i]; |
| 280 | 377x |
this->expected_values[i].final_value_m = dnorm->get_expected(i); |
| 281 | 377x |
this->x[i].final_value_m = dnorm->get_observed(i); |
| 282 |
} |
|
| 283 |
} |
|
| 284 |
} |
|
| 285 | ||
| 286 |
/** |
|
| 287 |
* @brief Converts the data to json representation for the output. |
|
| 288 |
* @return A string is returned specifying that the module relates to the |
|
| 289 |
* distribution interface with a normal distribution. It also returns the ID |
|
| 290 |
* and the natural log of the probability density function values themselves. |
|
| 291 |
* This string is formatted for a json file. |
|
| 292 |
*/ |
|
| 293 | 13x |
virtual std::string to_json() {
|
| 294 | 13x |
std::stringstream ss; |
| 295 | ||
| 296 | 13x |
ss << "{\n";
|
| 297 | 13x |
ss << " \"module_name\": \"density\",\n"; |
| 298 | 13x |
ss << " \"module_id\": " << this->id_m << ",\n"; |
| 299 | 13x |
ss << " \"module_type\": \"normal\",\n"; |
| 300 | 13x |
ss << " \"observed_data_id\" : " << this->interface_observed_data_id_m |
| 301 | 13x |
<< ",\n"; |
| 302 | 13x |
ss << " \"input_type\" : \"" << this->input_type_m << "\",\n"; |
| 303 | 13x |
ss << " \"density_component\": {\n";
|
| 304 | 13x |
ss << " \"lpdf_value\": " << this->lpdf_value << ",\n"; |
| 305 | 13x |
ss << " \"value\":["; |
| 306 | 13x |
if (this->lpdf_vec.size() == 0) {
|
| 307 | ! |
ss << "],\n"; |
| 308 |
} else {
|
|
| 309 | 377x |
for (R_xlen_t i = 0; i < this->lpdf_vec.size() - 1; i++) {
|
| 310 | 364x |
ss << this->value_to_string(this->lpdf_vec[i]); |
| 311 | 364x |
ss << ", "; |
| 312 |
} |
|
| 313 | 13x |
ss << this->value_to_string(this->lpdf_vec[this->lpdf_vec.size() - 1]); |
| 314 | ||
| 315 | 13x |
ss << "],\n"; |
| 316 |
} |
|
| 317 | 13x |
ss << " \"expected_values\":["; |
| 318 | 13x |
if (this->expected_values.size() == 0) {
|
| 319 | ! |
ss << "],\n"; |
| 320 |
} else {
|
|
| 321 | 377x |
for (R_xlen_t i = 0; i < this->expected_values.size() - 1; i++) {
|
| 322 | 728x |
ss << this->value_to_string(this->expected_values[i].final_value_m) |
| 323 |
<< ", "; |
|
| 324 |
} |
|
| 325 | 13x |
ss << this->value_to_string( |
| 326 | 13x |
this->expected_values[this->expected_values.size() - 1] |
| 327 | 13x |
.final_value_m); |
| 328 | 13x |
ss << "],\n"; |
| 329 |
} |
|
| 330 | 13x |
ss << " \"observed_values\":["; |
| 331 | 13x |
if (this->x.size() == 0) {
|
| 332 | ! |
ss << "]\n"; |
| 333 |
} else {
|
|
| 334 | 377x |
for (R_xlen_t i = 0; i < this->x.size() - 1; i++) {
|
| 335 | 364x |
ss << this->x[i].final_value_m << ", "; |
| 336 |
} |
|
| 337 | 13x |
ss << this->x[this->x.size() - 1].final_value_m << "]\n"; |
| 338 |
} |
|
| 339 | 13x |
ss << " }}\n"; |
| 340 | ||
| 341 | 26x |
return ss.str(); |
| 342 |
} |
|
| 343 | ||
| 344 |
#ifdef TMB_MODEL |
|
| 345 | ||
| 346 |
template <typename Type> |
|
| 347 | 84x |
bool add_to_fims_tmb_internal() {
|
| 348 | 84x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 349 |
fims_info::Information<Type>::GetInstance(); |
|
| 350 | ||
| 351 | 84x |
std::shared_ptr<fims_distributions::NormalLPDF<Type>> distribution = |
| 352 |
std::make_shared<fims_distributions::NormalLPDF<Type>>(); |
|
| 353 | ||
| 354 |
// interface to data/parameter value |
|
| 355 | ||
| 356 | 84x |
distribution->observed_data_id_m = interface_observed_data_id_m; |
| 357 | 84x |
std::stringstream ss; |
| 358 | 84x |
distribution->input_type = this->input_type_m; |
| 359 | 84x |
distribution->key.resize(this->key_m->size()); |
| 360 | 180x |
for (size_t i = 0; i < this->key_m->size(); i++) {
|
| 361 | 96x |
distribution->key[i] = this->key_m->at(i); |
| 362 |
} |
|
| 363 | 84x |
distribution->id = this->id_m; |
| 364 | 84x |
distribution->x.resize(this->x.size()); |
| 365 | 2296x |
for (size_t i = 0; i < this->x.size(); i++) {
|
| 366 | 2212x |
distribution->x[i] = this->x[i].initial_value_m; |
| 367 |
} |
|
| 368 |
// set relative info |
|
| 369 | 84x |
distribution->expected_values.resize(this->expected_values.size()); |
| 370 | 2304x |
for (size_t i = 0; i < this->expected_values.size(); i++) {
|
| 371 | 2220x |
distribution->expected_values[i] = |
| 372 | 2220x |
this->expected_values[i].initial_value_m; |
| 373 |
} |
|
| 374 | 84x |
distribution->log_sd.resize(this->log_sd.size()); |
| 375 | 168x |
for (size_t i = 0; i < this->log_sd.size(); i++) {
|
| 376 | 84x |
distribution->log_sd[i] = this->log_sd[i].initial_value_m; |
| 377 | 84x |
if (this->log_sd[i].estimation_type_m.get() == "fixed_effects") {
|
| 378 | 12x |
ss.str("");
|
| 379 | 12x |
ss << "dnorm." << this->id_m << ".log_sd." << this->log_sd[i].id_m; |
| 380 | 12x |
info->RegisterParameterName(ss.str()); |
| 381 | 12x |
info->RegisterParameter(distribution->log_sd[i]); |
| 382 |
} |
|
| 383 | 84x |
if (this->log_sd[i].estimation_type_m.get() == "random_effects") {
|
| 384 | ! |
FIMS_ERROR_LOG("standard deviations cannot be set to random effects");
|
| 385 |
} |
|
| 386 |
} |
|
| 387 | 84x |
info->variable_map[this->log_sd.id_m] = &(distribution)->log_sd; |
| 388 | ||
| 389 | 84x |
info->density_components[distribution->id] = distribution; |
| 390 | ||
| 391 | 84x |
return true; |
| 392 |
} |
|
| 393 | ||
| 394 |
/** |
|
| 395 |
* @brief Adds the parameters to the TMB model. |
|
| 396 |
* @return A boolean of true. |
|
| 397 |
*/ |
|
| 398 | 21x |
virtual bool add_to_fims_tmb() {
|
| 399 |
#ifdef TMBAD_FRAMEWORK |
|
| 400 | 21x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 401 | 21x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 402 |
#else |
|
| 403 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 404 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 405 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 406 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 407 |
#endif |
|
| 408 | ||
| 409 | 21x |
return true; |
| 410 |
} |
|
| 411 | ||
| 412 |
#endif |
|
| 413 |
}; |
|
| 414 | ||
| 415 |
/** |
|
| 416 |
* @brief The Rcpp interface for Dlnorm to instantiate from R: |
|
| 417 |
* dlnorm_ <- methods::new(DlnormDistribution). |
|
| 418 |
*/ |
|
| 419 |
class DlnormDistributionsInterface : public DistributionsInterfaceBase {
|
|
| 420 |
public: |
|
| 421 |
/** |
|
| 422 |
* @brief Observed data. |
|
| 423 |
*/ |
|
| 424 |
ParameterVector x; |
|
| 425 |
/** |
|
| 426 |
* @brief The expected values, which would be the mean of log(x) for this |
|
| 427 |
* distribution. |
|
| 428 |
*/ |
|
| 429 |
ParameterVector expected_values; |
|
| 430 |
/** |
|
| 431 |
* @brief The uncertainty, which would be the natural logarithm of the |
|
| 432 |
standard deviation (sd) of log(x) for this distribution. The natural log |
|
| 433 |
of the standard deviation is necessary because the exponential link |
|
| 434 |
function is applied to the log transformed standard deviation to insure |
|
| 435 |
standard deviation is positive. |
|
| 436 |
*/ |
|
| 437 |
ParameterVector log_sd; |
|
| 438 |
/** |
|
| 439 |
* @brief Vector that records the individual log probability function for each |
|
| 440 |
* observation. |
|
| 441 |
*/ |
|
| 442 |
RealVector lpdf_vec; /**< The vector */ |
|
| 443 | ||
| 444 |
/** |
|
| 445 |
* @brief The constructor. |
|
| 446 |
*/ |
|
| 447 | 49x |
DlnormDistributionsInterface() : DistributionsInterfaceBase() {
|
| 448 | 49x |
DistributionsInterfaceBase::live_objects[this->id_m] = |
| 449 | 98x |
std::make_shared<DlnormDistributionsInterface>(*this); |
| 450 | 49x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 451 | 49x |
DistributionsInterfaceBase::live_objects[this->id_m]); |
| 452 |
} |
|
| 453 | ||
| 454 |
/** |
|
| 455 |
* @brief Construct a new Dlnorm Distributions Interface object |
|
| 456 |
* |
|
| 457 |
* @param other |
|
| 458 |
*/ |
|
| 459 | 49x |
DlnormDistributionsInterface(const DlnormDistributionsInterface &other) |
| 460 | 49x |
: DistributionsInterfaceBase(other), |
| 461 | 49x |
x(other.x), |
| 462 | 49x |
expected_values(other.expected_values), |
| 463 | 49x |
log_sd(other.log_sd), |
| 464 | 98x |
lpdf_vec(other.lpdf_vec) {}
|
| 465 | ||
| 466 |
/** |
|
| 467 |
* @brief The destructor. |
|
| 468 |
*/ |
|
| 469 | 294x |
virtual ~DlnormDistributionsInterface() {}
|
| 470 | ||
| 471 |
/** |
|
| 472 |
* @brief Gets the ID of the interface base object. |
|
| 473 |
* @return The ID. |
|
| 474 |
*/ |
|
| 475 | ! |
virtual uint32_t get_id() { return this->id_m; }
|
| 476 | ||
| 477 |
/** |
|
| 478 |
* @brief Set the unique ID for the observed data object. |
|
| 479 |
* @param observed_data_id Unique ID for the observed data object. |
|
| 480 |
*/ |
|
| 481 | 37x |
virtual bool set_observed_data(int observed_data_id) {
|
| 482 | 37x |
this->interface_observed_data_id_m.set(observed_data_id); |
| 483 | 37x |
return true; |
| 484 |
} |
|
| 485 | ||
| 486 |
/** |
|
| 487 |
* @brief Sets pointers for data observations, random effects, or priors. |
|
| 488 |
* |
|
| 489 |
* @param input_type String that sets whether the distribution type is for |
|
| 490 |
* priors, random effects, or data. |
|
| 491 |
* @param ids Vector of unique ids for each linked parameter(s), derived |
|
| 492 |
* value(s), or observed data vector. |
|
| 493 |
*/ |
|
| 494 | 37x |
virtual bool set_distribution_links(std::string input_type, |
| 495 |
Rcpp::IntegerVector ids) {
|
|
| 496 | 37x |
this->input_type_m.set(input_type); |
| 497 | 37x |
this->key_m->resize(ids.size()); |
| 498 | 74x |
for (int i = 0; i < ids.size(); i++) {
|
| 499 | 37x |
this->key_m->at(i) = ids[i]; |
| 500 |
} |
|
| 501 | 37x |
return true; |
| 502 |
} |
|
| 503 | ||
| 504 |
/** |
|
| 505 |
* @brief Evaluate lognormal probability density function (pdf). The natural |
|
| 506 |
* log of the pdf is returned. |
|
| 507 |
* @return The natural log of the probability density function (pdf) is |
|
| 508 |
* returned. |
|
| 509 |
*/ |
|
| 510 | 11x |
virtual double evaluate() {
|
| 511 | 11x |
fims_distributions::LogNormalLPDF<double> dlnorm; |
| 512 | 11x |
dlnorm.x.resize(this->x.size()); |
| 513 | 11x |
dlnorm.expected_values.resize(this->expected_values.size()); |
| 514 | 11x |
dlnorm.log_sd.resize(this->log_sd.size()); |
| 515 |
// dlnorm.input_type = "prior"; |
|
| 516 | 49x |
for (size_t i = 0; i < x.size(); i++) {
|
| 517 | 38x |
dlnorm.x[i] = this->x[i].initial_value_m; |
| 518 |
} |
|
| 519 | 49x |
for (size_t i = 0; i < expected_values.size(); i++) {
|
| 520 | 38x |
dlnorm.expected_values[i] = this->expected_values[i].initial_value_m; |
| 521 |
} |
|
| 522 | 33x |
for (size_t i = 0; i < log_sd.size(); i++) {
|
| 523 | 22x |
dlnorm.log_sd[i] = this->log_sd[i].initial_value_m; |
| 524 |
} |
|
| 525 | 21x |
return dlnorm.evaluate(); |
| 526 |
} |
|
| 527 | ||
| 528 |
/** |
|
| 529 |
* @brief Extracts the derived quantities from `Information` to the Rcpp |
|
| 530 |
* object. |
|
| 531 |
*/ |
|
| 532 | 26x |
virtual void finalize() {
|
| 533 | 26x |
if (this->finalized) {
|
| 534 |
// log warning that finalize has been called more than once. |
|
| 535 | ! |
FIMS_WARNING_LOG("LogNormalLPDF " + fims::to_string(this->id_m) +
|
| 536 |
" has been finalized already."); |
|
| 537 |
} |
|
| 538 | ||
| 539 | 26x |
this->finalized = true; // indicate this has been called already |
| 540 | ||
| 541 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 542 | 26x |
fims_info::Information<double>::GetInstance(); |
| 543 | ||
| 544 | 26x |
fims_info::Information<double>::density_components_iterator it; |
| 545 | ||
| 546 |
// search for density component in Information |
|
| 547 | 26x |
it = info->density_components.find(this->id_m); |
| 548 |
// if not found, just return |
|
| 549 | 26x |
if (it == info->density_components.end()) {
|
| 550 | ! |
FIMS_WARNING_LOG("LogNormalLPDF " + fims::to_string(this->id_m) +
|
| 551 |
" not found in Information."); |
|
| 552 | ! |
return; |
| 553 |
} else {
|
|
| 554 |
std::shared_ptr<fims_distributions::LogNormalLPDF<double>> dlnorm = |
|
| 555 |
std::dynamic_pointer_cast<fims_distributions::LogNormalLPDF<double>>( |
|
| 556 | 26x |
it->second); |
| 557 | ||
| 558 | 26x |
this->lpdf_value = dlnorm->lpdf; |
| 559 | ||
| 560 | 806x |
for (size_t i = 0; i < this->log_sd.size(); i++) {
|
| 561 | 780x |
if (this->log_sd[i].estimation_type_m.get() == "constant") {
|
| 562 | 780x |
this->log_sd[i].final_value_m = this->log_sd[i].initial_value_m; |
| 563 |
} else {
|
|
| 564 | ! |
this->log_sd[i].final_value_m = dlnorm->log_sd[i]; |
| 565 |
} |
|
| 566 |
} |
|
| 567 | ||
| 568 | 26x |
this->lpdf_vec = RealVector(dlnorm->report_lpdf_vec.size()); |
| 569 | 26x |
if (this->expected_values.size() == 1) {
|
| 570 | 26x |
this->expected_values.resize( |
| 571 |
this->lpdf_vec.size()); // dlnorm->expected_values.size()); |
|
| 572 |
} |
|
| 573 | 26x |
if (this->x.size() == 1) {
|
| 574 | 26x |
size_t nx = dlnorm->get_n_x(); |
| 575 | 26x |
this->x.resize(nx); |
| 576 |
} |
|
| 577 | 806x |
for (R_xlen_t i = 0; i < this->lpdf_vec.size(); i++) {
|
| 578 | 780x |
this->lpdf_vec[i] = dlnorm->report_lpdf_vec[i]; |
| 579 | 780x |
this->expected_values[i].final_value_m = dlnorm->get_expected(i); |
| 580 | 780x |
this->x[i].final_value_m = dlnorm->get_observed(i); |
| 581 |
} |
|
| 582 |
} |
|
| 583 |
} |
|
| 584 | ||
| 585 |
/** |
|
| 586 |
* @brief Converts the data to json representation for the output. |
|
| 587 |
* @return A string is returned specifying that the module relates to the |
|
| 588 |
* distribution interface with a log_normal distribution. It also returns the |
|
| 589 |
* ID and the natural log of the probability density function values |
|
| 590 |
* themselves. This string is formatted for a json file. |
|
| 591 |
*/ |
|
| 592 | 26x |
virtual std::string to_json() {
|
| 593 | 26x |
std::stringstream ss; |
| 594 | ||
| 595 | 26x |
ss << "{\n";
|
| 596 | 26x |
ss << " \"module_name\": \"density\",\n"; |
| 597 | 26x |
ss << " \"module_id\": " << this->id_m << ",\n"; |
| 598 | 26x |
ss << " \"module_type\": \"log_normal\",\n"; |
| 599 | 26x |
ss << " \"observed_data_id\" : " << this->interface_observed_data_id_m |
| 600 | 26x |
<< ",\n"; |
| 601 | 26x |
ss << " \"input_type\" : \"" << this->input_type_m << "\",\n"; |
| 602 | 26x |
ss << " \"density_component\": {\n";
|
| 603 | 26x |
ss << " \"lpdf_value\": " << this->lpdf_value << ",\n"; |
| 604 | 26x |
ss << " \"value\":["; |
| 605 | 26x |
if (this->lpdf_vec.size() == 0) {
|
| 606 | ! |
ss << "]\n"; |
| 607 |
} else {
|
|
| 608 | 780x |
for (R_xlen_t i = 0; i < this->lpdf_vec.size() - 1; i++) {
|
| 609 | 754x |
ss << this->value_to_string(this->lpdf_vec[i]) << ", "; |
| 610 |
} |
|
| 611 | 26x |
ss << this->value_to_string(this->lpdf_vec[this->lpdf_vec.size() - 1]); |
| 612 | ||
| 613 | 26x |
ss << "],\n"; |
| 614 |
} |
|
| 615 | 26x |
ss << " \"expected_values\":["; |
| 616 | 26x |
if (this->expected_values.size() == 0) {
|
| 617 | ! |
ss << "],\n"; |
| 618 |
} else {
|
|
| 619 | 780x |
for (R_xlen_t i = 0; i < this->expected_values.size() - 1; i++) {
|
| 620 | 1508x |
ss << this->value_to_string(this->expected_values[i].final_value_m) |
| 621 |
<< ", "; |
|
| 622 |
} |
|
| 623 | 26x |
ss << this->value_to_string( |
| 624 | 26x |
this->expected_values[this->expected_values.size() - 1] |
| 625 | 26x |
.final_value_m); |
| 626 | ||
| 627 | 26x |
ss << "],\n"; |
| 628 |
} |
|
| 629 | 26x |
ss << " \"observed_values\":["; |
| 630 | 26x |
if (this->x.size() == 0) {
|
| 631 | ! |
ss << "]\n"; |
| 632 |
} else {
|
|
| 633 | 780x |
for (R_xlen_t i = 0; i < this->x.size() - 1; i++) {
|
| 634 | 754x |
ss << this->x[i].final_value_m << ", "; |
| 635 |
} |
|
| 636 | 26x |
ss << this->x[this->x.size() - 1].final_value_m << "]\n"; |
| 637 |
} |
|
| 638 | 26x |
ss << " }}\n"; |
| 639 | 52x |
return ss.str(); |
| 640 |
} |
|
| 641 | ||
| 642 |
#ifdef TMB_MODEL |
|
| 643 | ||
| 644 |
template <typename Type> |
|
| 645 | 144x |
bool add_to_fims_tmb_internal() {
|
| 646 | 144x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 647 |
fims_info::Information<Type>::GetInstance(); |
|
| 648 | ||
| 649 | 144x |
std::shared_ptr<fims_distributions::LogNormalLPDF<Type>> distribution = |
| 650 |
std::make_shared<fims_distributions::LogNormalLPDF<Type>>(); |
|
| 651 | ||
| 652 |
// set relative info |
|
| 653 | 144x |
distribution->id = this->id_m; |
| 654 | 144x |
std::stringstream ss; |
| 655 | 144x |
distribution->observed_data_id_m = interface_observed_data_id_m; |
| 656 | 144x |
distribution->input_type = this->input_type_m; |
| 657 | 144x |
distribution->key.resize(this->key_m->size()); |
| 658 | 288x |
for (size_t i = 0; i < this->key_m->size(); i++) {
|
| 659 | 144x |
distribution->key[i] = this->key_m->at(i); |
| 660 |
} |
|
| 661 | 144x |
distribution->x.resize(this->x.size()); |
| 662 | 288x |
for (size_t i = 0; i < this->x.size(); i++) {
|
| 663 | 144x |
distribution->x[i] = this->x[i].initial_value_m; |
| 664 |
} |
|
| 665 |
// set relative info |
|
| 666 | 144x |
distribution->expected_values.resize(this->expected_values.size()); |
| 667 | 288x |
for (size_t i = 0; i < this->expected_values.size(); i++) {
|
| 668 | 144x |
distribution->expected_values[i] = |
| 669 | 144x |
this->expected_values[i].initial_value_m; |
| 670 |
} |
|
| 671 | 144x |
distribution->log_sd.resize(this->log_sd.size()); |
| 672 | 4464x |
for (size_t i = 0; i < this->log_sd.size(); i++) {
|
| 673 | 4320x |
distribution->log_sd[i] = this->log_sd[i].initial_value_m; |
| 674 | 4320x |
if (this->log_sd[i].estimation_type_m.get() == "fixed_effects") {
|
| 675 | ! |
ss.str("");
|
| 676 | ! |
ss << "dlnorm." << this->id_m << ".log_sd." << this->log_sd[i].id_m; |
| 677 | ! |
info->RegisterParameterName(ss.str()); |
| 678 | ! |
info->RegisterParameter(distribution->log_sd[i]); |
| 679 |
} |
|
| 680 | 4320x |
if (this->log_sd[i].estimation_type_m.get() == "random_effects") {
|
| 681 | ! |
FIMS_ERROR_LOG("standard deviations cannot be set to random effects");
|
| 682 |
} |
|
| 683 |
} |
|
| 684 | 144x |
info->variable_map[this->log_sd.id_m] = &(distribution)->log_sd; |
| 685 | ||
| 686 | 144x |
info->density_components[distribution->id] = distribution; |
| 687 | ||
| 688 | 144x |
return true; |
| 689 |
} |
|
| 690 | ||
| 691 |
/** |
|
| 692 |
* @brief Adds the parameters to the TMB model. |
|
| 693 |
* @return A boolean of true. |
|
| 694 |
*/ |
|
| 695 | 36x |
virtual bool add_to_fims_tmb() {
|
| 696 |
#ifdef TMBAD_FRAMEWORK |
|
| 697 | 36x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 698 | 36x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 699 |
#else |
|
| 700 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 701 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 702 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 703 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 704 |
#endif |
|
| 705 | ||
| 706 | 36x |
return true; |
| 707 |
} |
|
| 708 | ||
| 709 |
#endif |
|
| 710 |
}; |
|
| 711 | ||
| 712 |
/** |
|
| 713 |
* @brief The Rcpp interface for Dmultinom to instantiate from R: |
|
| 714 |
* dmultinom_ <- methods::new(DmultinomDistribution). |
|
| 715 |
*/ |
|
| 716 |
class DmultinomDistributionsInterface : public DistributionsInterfaceBase {
|
|
| 717 |
public: |
|
| 718 |
/** |
|
| 719 |
* @brief Observed data, which should be a vector of length K of integers. |
|
| 720 |
*/ |
|
| 721 |
ParameterVector x; |
|
| 722 |
/** |
|
| 723 |
* @brief The expected values, which should be a vector of length K where |
|
| 724 |
* each value specifies the probability of class k. Note that, unlike in R, |
|
| 725 |
* these probabilities must sum to 1.0. |
|
| 726 |
*/ |
|
| 727 |
ParameterVector expected_values; |
|
| 728 |
/** |
|
| 729 |
* @brief The dimensions of the number of rows and columns of the |
|
| 730 |
* multivariate dataset. |
|
| 731 |
*/ |
|
| 732 |
RealVector dims; |
|
| 733 |
/** |
|
| 734 |
* @brief Vector that records the individual log probability function for each |
|
| 735 |
* observation. |
|
| 736 |
*/ |
|
| 737 |
RealVector lpdf_vec; /**< The vector */ |
|
| 738 | ||
| 739 |
/** |
|
| 740 |
* @brief TODO: document this. |
|
| 741 |
* |
|
| 742 |
*/ |
|
| 743 |
SharedString notes; |
|
| 744 | ||
| 745 |
/** |
|
| 746 |
* @brief The constructor. |
|
| 747 |
*/ |
|
| 748 | 67x |
DmultinomDistributionsInterface() : DistributionsInterfaceBase() {
|
| 749 | 67x |
DistributionsInterfaceBase::live_objects[this->id_m] = |
| 750 | 134x |
std::make_shared<DmultinomDistributionsInterface>(*this); |
| 751 | 67x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 752 | 67x |
DistributionsInterfaceBase::live_objects[this->id_m]); |
| 753 |
} |
|
| 754 | ||
| 755 |
/** |
|
| 756 |
* @brief Construct a new Dmultinom Distributions Interface object |
|
| 757 |
* |
|
| 758 |
* @param other |
|
| 759 |
*/ |
|
| 760 | 67x |
DmultinomDistributionsInterface(const DmultinomDistributionsInterface &other) |
| 761 | 67x |
: DistributionsInterfaceBase(other), |
| 762 | 67x |
x(other.x), |
| 763 | 67x |
expected_values(other.expected_values), |
| 764 | 67x |
dims(other.dims), |
| 765 | 67x |
lpdf_vec(other.lpdf_vec), |
| 766 | 134x |
notes(other.notes) {}
|
| 767 | ||
| 768 |
/** |
|
| 769 |
* @brief The destructor. |
|
| 770 |
*/ |
|
| 771 | 402x |
virtual ~DmultinomDistributionsInterface() {}
|
| 772 |
/** |
|
| 773 |
* @brief Gets the ID of the interface base object. |
|
| 774 |
* @return The ID. |
|
| 775 |
*/ |
|
| 776 | ! |
virtual uint32_t get_id() { return this->id_m; }
|
| 777 | ||
| 778 |
/** |
|
| 779 |
* @brief Set the unique ID for the observed data object. |
|
| 780 |
* @param observed_data_id Unique ID for the observed data object. |
|
| 781 |
*/ |
|
| 782 | 62x |
virtual bool set_observed_data(int observed_data_id) {
|
| 783 | 62x |
this->interface_observed_data_id_m.set(observed_data_id); |
| 784 | 62x |
return true; |
| 785 |
} |
|
| 786 | ||
| 787 |
/** |
|
| 788 |
* @brief Sets pointers for data observations, random effects, or priors. |
|
| 789 |
* |
|
| 790 |
* @param input_type String that sets whether the distribution type is for |
|
| 791 |
* priors, random effects, or data. |
|
| 792 |
* @param ids Vector of unique ids for each linked parameter(s), derived |
|
| 793 |
* value(s), or observed data vector. |
|
| 794 |
*/ |
|
| 795 | 62x |
virtual bool set_distribution_links(std::string input_type, |
| 796 |
Rcpp::IntegerVector ids) {
|
|
| 797 | 62x |
this->input_type_m.set(input_type); |
| 798 | 62x |
this->key_m->resize(ids.size()); |
| 799 | 124x |
for (int i = 0; i < ids.size(); i++) {
|
| 800 | 62x |
this->key_m->at(i) = ids[i]; |
| 801 |
} |
|
| 802 | 62x |
return true; |
| 803 |
} |
|
| 804 | ||
| 805 |
/** |
|
| 806 |
* @brief Set the note object |
|
| 807 |
* |
|
| 808 |
* @param note |
|
| 809 |
*/ |
|
| 810 | 7x |
void set_note(std::string note) { this->notes.set(note); }
|
| 811 | ||
| 812 |
/** |
|
| 813 |
* @brief |
|
| 814 |
* |
|
| 815 |
* @return double |
|
| 816 |
*/ |
|
| 817 | 5x |
virtual double evaluate() {
|
| 818 | 5x |
fims_distributions::MultinomialLPMF<double> dmultinom; |
| 819 |
// Declare TMBVector in this scope |
|
| 820 | 5x |
dmultinom.x.resize(this->x.size()); |
| 821 | 5x |
dmultinom.expected_values.resize(this->expected_values.size()); |
| 822 | 56x |
for (size_t i = 0; i < x.size(); i++) {
|
| 823 | 51x |
dmultinom.x[i] = this->x[i].initial_value_m; |
| 824 |
} |
|
| 825 | 57x |
for (size_t i = 0; i < expected_values.size(); i++) {
|
| 826 | 52x |
dmultinom.expected_values[i] = this->expected_values[i].initial_value_m; |
| 827 |
} |
|
| 828 | 5x |
dmultinom.dims.resize(2); |
| 829 | 5x |
dmultinom.dims[0] = this->dims[0]; |
| 830 | 5x |
dmultinom.dims[1] = this->dims[1]; |
| 831 | 8x |
return dmultinom.evaluate(); |
| 832 |
} |
|
| 833 | ||
| 834 | 42x |
void finalize() {
|
| 835 | 42x |
if (this->finalized) {
|
| 836 |
// log warning that finalize has been called more than once. |
|
| 837 | ! |
FIMS_WARNING_LOG("DmultinomDistributions " +
|
| 838 |
fims::to_string(this->id_m) + |
|
| 839 |
" has been finalized already."); |
|
| 840 |
} |
|
| 841 | ||
| 842 | 42x |
this->finalized = true; // indicate this has been called already |
| 843 | ||
| 844 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 845 | 42x |
fims_info::Information<double>::GetInstance(); |
| 846 | ||
| 847 | 42x |
fims_info::Information<double>::density_components_iterator it; |
| 848 | ||
| 849 |
// search for density component in Information |
|
| 850 | 42x |
it = info->density_components.find(this->id_m); |
| 851 |
// if not found, just return |
|
| 852 | 42x |
if (it == info->density_components.end()) {
|
| 853 | ! |
FIMS_WARNING_LOG("DmultinomDistributions " + fims::to_string(this->id_m) +
|
| 854 |
" not found in Information."); |
|
| 855 | ! |
return; |
| 856 |
} else {
|
|
| 857 |
std::shared_ptr<fims_distributions::MultinomialLPMF<double>> dmultinom = |
|
| 858 |
std::dynamic_pointer_cast< |
|
| 859 | 42x |
fims_distributions::MultinomialLPMF<double>>(it->second); |
| 860 | ||
| 861 | 42x |
this->lpdf_value = dmultinom->lpdf; |
| 862 | ||
| 863 | 42x |
size_t nx = dmultinom->report_lpdf_vec.size(); |
| 864 | 42x |
this->lpdf_vec = Rcpp::NumericVector(nx); |
| 865 | 42x |
if (this->expected_values.size() != nx) {
|
| 866 | 42x |
this->expected_values.resize(nx); |
| 867 |
} |
|
| 868 | 42x |
if (this->x.size() != nx) {
|
| 869 | 42x |
this->x.resize(nx); |
| 870 |
} |
|
| 871 | 21762x |
for (R_xlen_t i = 0; i < this->lpdf_vec.size(); i++) {
|
| 872 | 21720x |
this->lpdf_vec[i] = dmultinom->report_lpdf_vec[i]; |
| 873 | 21720x |
this->expected_values[i].final_value_m = dmultinom->get_expected(i); |
| 874 | 21720x |
if (dmultinom->input_type != "data") {
|
| 875 | ! |
this->x[i].final_value_m = dmultinom->get_observed(i); |
| 876 |
} |
|
| 877 |
} |
|
| 878 | 42x |
if (dmultinom->input_type == "data") {
|
| 879 | 42x |
dims.resize(2); |
| 880 | 42x |
dims[0] = dmultinom->observed_values->get_imax(); |
| 881 | 42x |
dims[1] = dmultinom->observed_values->get_jmax(); |
| 882 | 1302x |
for (size_t i = 0; i < dims[0]; i++) {
|
| 883 | 22980x |
for (size_t j = 0; j < dims[1]; j++) {
|
| 884 | 21720x |
size_t idx = (i * dims[1]) + j; |
| 885 | 21720x |
this->x[idx].final_value_m = dmultinom->get_observed(i, j); |
| 886 |
} |
|
| 887 |
} |
|
| 888 |
} |
|
| 889 |
} |
|
| 890 |
} |
|
| 891 | ||
| 892 |
/** |
|
| 893 |
* @brief Converts the data to json representation for the output. |
|
| 894 |
* @return A string is returned specifying that the module relates to the |
|
| 895 |
* distribution interface with a log_normal distribution. It also returns the |
|
| 896 |
* ID and the natural log of the probability density function values |
|
| 897 |
* themselves. This string is formatted for a json file. |
|
| 898 |
*/ |
|
| 899 | 42x |
virtual std::string to_json() {
|
| 900 | 42x |
std::stringstream ss; |
| 901 | ||
| 902 | 42x |
ss << "{\n";
|
| 903 | 42x |
ss << " \"module_name\": \"density\",\n"; |
| 904 | 42x |
ss << " \"module_id\": " << this->id_m << ",\n"; |
| 905 | 42x |
ss << " \"module_type\": \"multinomial\",\n"; |
| 906 | 42x |
ss << "\"observed_data_id\" : " << this->interface_observed_data_id_m |
| 907 | 42x |
<< ",\n"; |
| 908 | 42x |
ss << " \"input_type\" : \"" << this->input_type_m << "\",\n"; |
| 909 | 42x |
ss << " \"density_component\": {\n";
|
| 910 | 42x |
ss << " \"lpdf_value\": " << this->lpdf_value << ",\n"; |
| 911 | 42x |
ss << " \"value\":["; |
| 912 | 42x |
if (this->lpdf_vec.size() == 0) {
|
| 913 | ! |
ss << "],\n"; |
| 914 |
} else {
|
|
| 915 | 21720x |
for (R_xlen_t i = 0; i < this->lpdf_vec.size() - 1; i++) {
|
| 916 | 21678x |
ss << this->value_to_string(this->lpdf_vec[i]); |
| 917 | 21678x |
ss << ", "; |
| 918 |
} |
|
| 919 | 42x |
ss << this->value_to_string(this->lpdf_vec[this->lpdf_vec.size() - 1]); |
| 920 | ||
| 921 | 42x |
ss << "],\n"; |
| 922 |
} |
|
| 923 | 42x |
ss << " \"expected_values\":["; |
| 924 | 42x |
if (this->expected_values.size() == 0) {
|
| 925 | ! |
ss << "],\n"; |
| 926 |
} else {
|
|
| 927 | 21720x |
for (R_xlen_t i = 0; i < this->expected_values.size() - 1; i++) {
|
| 928 | 43356x |
ss << this->value_to_string(this->expected_values[i].final_value_m) |
| 929 |
<< ", "; |
|
| 930 |
} |
|
| 931 | 42x |
ss << this->value_to_string( |
| 932 | 42x |
this->expected_values[this->expected_values.size() - 1] |
| 933 | 42x |
.final_value_m); |
| 934 | ||
| 935 | 42x |
ss << "],\n"; |
| 936 |
} |
|
| 937 | 42x |
ss << " \"observed_values\":["; |
| 938 | 42x |
if (this->x.size() == 0) {
|
| 939 | ! |
ss << "]\n"; |
| 940 |
} else {
|
|
| 941 | 21720x |
for (R_xlen_t i = 0; i < this->x.size() - 1; i++) {
|
| 942 | 21678x |
ss << this->x[i].final_value_m << ", "; |
| 943 |
} |
|
| 944 | 42x |
ss << this->x[this->x.size() - 1].final_value_m << "]\n"; |
| 945 |
} |
|
| 946 | 42x |
ss << " }}\n"; |
| 947 | 84x |
return ss.str(); |
| 948 |
} |
|
| 949 | ||
| 950 |
#ifdef TMB_MODEL |
|
| 951 | ||
| 952 |
template <typename Type> |
|
| 953 | 248x |
bool add_to_fims_tmb_internal() {
|
| 954 | 496x |
FIMS_INFO_LOG("Adding multinomial to FIMS.");
|
| 955 | 248x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 956 |
fims_info::Information<Type>::GetInstance(); |
|
| 957 | ||
| 958 | 248x |
std::shared_ptr<fims_distributions::MultinomialLPMF<Type>> distribution = |
| 959 |
std::make_shared<fims_distributions::MultinomialLPMF<Type>>(); |
|
| 960 | ||
| 961 | 248x |
distribution->id = this->id_m; |
| 962 | 248x |
distribution->observed_data_id_m = interface_observed_data_id_m; |
| 963 | 248x |
distribution->input_type = this->input_type_m; |
| 964 | 248x |
distribution->key.resize(this->key_m->size()); |
| 965 | 496x |
for (size_t i = 0; i < this->key_m->size(); i++) {
|
| 966 | 248x |
distribution->key[i] = this->key_m->at(i); |
| 967 |
} |
|
| 968 | 248x |
distribution->x.resize(this->x.size()); |
| 969 | 496x |
for (size_t i = 0; i < this->x.size(); i++) {
|
| 970 | 248x |
distribution->x[i] = this->x[i].initial_value_m; |
| 971 |
} |
|
| 972 |
// set relative info |
|
| 973 | 248x |
distribution->expected_values.resize(this->expected_values.size()); |
| 974 | 496x |
for (size_t i = 0; i < this->expected_values.size(); i++) {
|
| 975 | 248x |
distribution->expected_values[i] = |
| 976 | 248x |
this->expected_values[i].initial_value_m; |
| 977 |
} |
|
| 978 | ||
| 979 | 248x |
info->density_components[distribution->id] = distribution; |
| 980 | 496x |
FIMS_INFO_LOG("Done adding multinomial to FIMS.");
|
| 981 | 248x |
return true; |
| 982 |
} |
|
| 983 | ||
| 984 | 62x |
virtual bool add_to_fims_tmb() {
|
| 985 |
#ifdef TMBAD_FRAMEWORK |
|
| 986 | 62x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 987 | 62x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 988 |
#else |
|
| 989 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 990 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 991 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 992 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 993 |
#endif |
|
| 994 | ||
| 995 | 62x |
return true; |
| 996 |
} |
|
| 997 | ||
| 998 |
#endif |
|
| 999 |
}; |
|
| 1000 | ||
| 1001 |
#endif |
| 1 |
/** |
|
| 2 |
* @file rcpp_fleet.hpp |
|
| 3 |
* @brief The Rcpp interface to declare fleets. Allows for the use of |
|
| 4 |
* methods::new() in R. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_FLEET_HPP |
|
| 10 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_FLEET_HPP |
|
| 11 | ||
| 12 |
#include "../../../common/def.hpp" |
|
| 13 |
#include "../../../population_dynamics/fleet/fleet.hpp" |
|
| 14 |
#include "rcpp_interface_base.hpp" |
|
| 15 | ||
| 16 |
/** |
|
| 17 |
* @brief Rcpp interface that serves as the parent class for Rcpp fleet |
|
| 18 |
* interfaces. This type should be inherited and not called from R directly. |
|
| 19 |
*/ |
|
| 20 |
class FleetInterfaceBase : public FIMSRcppInterfaceBase {
|
|
| 21 |
public: |
|
| 22 |
/** |
|
| 23 |
* @brief The static id of the FleetInterfaceBase object. |
|
| 24 |
*/ |
|
| 25 |
static uint32_t id_g; |
|
| 26 |
/** |
|
| 27 |
* @brief The local id of the FleetInterfaceBase object. |
|
| 28 |
*/ |
|
| 29 |
uint32_t id; |
|
| 30 |
/** |
|
| 31 |
* @brief The map associating the IDs of FleetInterfaceBase to the objects. |
|
| 32 |
* This is a live object, which is an object that has been created and lives |
|
| 33 |
* in memory. |
|
| 34 |
*/ |
|
| 35 |
static std::map<uint32_t, std::shared_ptr<FleetInterfaceBase>> live_objects; |
|
| 36 | ||
| 37 |
/** |
|
| 38 |
* @brief The constructor. |
|
| 39 |
*/ |
|
| 40 | 42x |
FleetInterfaceBase() {
|
| 41 | 42x |
this->id = FleetInterfaceBase::id_g++; |
| 42 |
/* Create instance of map: key is id and value is pointer to |
|
| 43 |
FleetInterfaceBase */ |
|
| 44 |
// FleetInterfaceBase::live_objects[this->id] = this; |
|
| 45 |
} |
|
| 46 | ||
| 47 |
/** |
|
| 48 |
* @brief Construct a new Fleet Interface Base object |
|
| 49 |
* |
|
| 50 |
* @param other |
|
| 51 |
*/ |
|
| 52 | 42x |
FleetInterfaceBase(const FleetInterfaceBase &other) : id(other.id) {}
|
| 53 | ||
| 54 |
/** |
|
| 55 |
* @brief The destructor. |
|
| 56 |
*/ |
|
| 57 | 84x |
virtual ~FleetInterfaceBase() {}
|
| 58 | ||
| 59 |
/** |
|
| 60 |
* @brief Get the ID for the child fleet interface objects to inherit. |
|
| 61 |
*/ |
|
| 62 |
virtual uint32_t get_id() = 0; |
|
| 63 |
}; |
|
| 64 |
// static id of the FleetInterfaceBase object |
|
| 65 |
uint32_t FleetInterfaceBase::id_g = 1; |
|
| 66 |
// local id of the FleetInterfaceBase object map relating the ID of the |
|
| 67 |
// FleetInterfaceBase to the FleetInterfaceBase objects |
|
| 68 |
std::map<uint32_t, std::shared_ptr<FleetInterfaceBase>> |
|
| 69 |
FleetInterfaceBase::live_objects; |
|
| 70 |
/** |
|
| 71 |
* @brief The Rcpp interface for Fleet to instantiate from R: |
|
| 72 |
* fleet <- methods::new(Fleet) |
|
| 73 |
*/ |
|
| 74 |
class FleetInterface : public FleetInterfaceBase {
|
|
| 75 |
/** |
|
| 76 |
* @brief The ID of the observed age-composition data object. |
|
| 77 |
*/ |
|
| 78 |
SharedInt interface_observed_agecomp_data_id_m = -999; |
|
| 79 |
/** |
|
| 80 |
* @brief The ID of the observed length-composition data object. |
|
| 81 |
*/ |
|
| 82 |
SharedInt interface_observed_lengthcomp_data_id_m = -999; |
|
| 83 |
/** |
|
| 84 |
* @brief The ID of the observed index data object. |
|
| 85 |
*/ |
|
| 86 |
SharedInt interface_observed_index_data_id_m = -999; |
|
| 87 |
/** |
|
| 88 |
* @brief The ID of the observed landings data object. |
|
| 89 |
*/ |
|
| 90 |
SharedInt interface_observed_landings_data_id_m = -999; |
|
| 91 |
/** |
|
| 92 |
* @brief The ID of the selectivity object. |
|
| 93 |
*/ |
|
| 94 |
SharedInt interface_selectivity_id_m = -999; |
|
| 95 | ||
| 96 |
public: |
|
| 97 |
/** |
|
| 98 |
* @brief The name of the fleet. |
|
| 99 |
*/ |
|
| 100 |
SharedString name = fims::to_string("NA");
|
|
| 101 |
/** |
|
| 102 |
* @brief The number of age bins in the fleet data. |
|
| 103 |
*/ |
|
| 104 |
SharedInt n_ages = 0; |
|
| 105 |
/** |
|
| 106 |
* @brief The number of length bins in the fleet data. |
|
| 107 |
*/ |
|
| 108 |
SharedInt n_lengths = 0; |
|
| 109 |
/** |
|
| 110 |
* @brief The number of years in the fleet data. |
|
| 111 |
*/ |
|
| 112 |
SharedInt n_years = 0; |
|
| 113 |
/** |
|
| 114 |
* @brief What units are the observed landings for this fleet measured in. |
|
| 115 |
* Options are weight or numbers, default is weight. |
|
| 116 |
*/ |
|
| 117 |
SharedString observed_landings_units = fims::to_string("weight");
|
|
| 118 |
/** |
|
| 119 |
* @brief What units is the observed index of abundance for this fleet |
|
| 120 |
* measured in. Options are weight or numbers, default is weight. |
|
| 121 |
*/ |
|
| 122 |
SharedString observed_index_units = fims::to_string("weight");
|
|
| 123 |
/** |
|
| 124 |
* @brief The natural log of the index of abundance scaling parameter |
|
| 125 |
* for this fleet. |
|
| 126 |
*/ |
|
| 127 |
ParameterVector log_q; |
|
| 128 |
/** |
|
| 129 |
* @brief The vector of the natural log of fishing mortality rates for this |
|
| 130 |
* fleet. |
|
| 131 |
*/ |
|
| 132 |
ParameterVector log_Fmort; |
|
| 133 |
/** |
|
| 134 |
* @brief The vector of natural log of the expected total landings for |
|
| 135 |
* the fleet. |
|
| 136 |
*/ |
|
| 137 |
ParameterVector log_landings_expected; |
|
| 138 |
/** |
|
| 139 |
* @brief The vector of natural log of the expected index of abundance |
|
| 140 |
* for the fleet. |
|
| 141 |
*/ |
|
| 142 |
ParameterVector log_index_expected; |
|
| 143 |
/** |
|
| 144 |
* @brief The vector of expected landings-at-age in numbers for the fleet. |
|
| 145 |
*/ |
|
| 146 |
ParameterVector agecomp_expected; |
|
| 147 |
/** |
|
| 148 |
* @brief The vector of expected landings-at-length in numbers for the fleet. |
|
| 149 |
*/ |
|
| 150 |
ParameterVector lengthcomp_expected; |
|
| 151 |
/** |
|
| 152 |
* @brief The vector of expected landings-at-age in numbers for the fleet. |
|
| 153 |
*/ |
|
| 154 |
ParameterVector agecomp_proportion; |
|
| 155 |
/** |
|
| 156 |
* @brief The vector of expected landings-at-length in numbers for the fleet. |
|
| 157 |
*/ |
|
| 158 |
ParameterVector lengthcomp_proportion; |
|
| 159 |
/** |
|
| 160 |
* @brief The vector of conversions to go from age to length, i.e., the |
|
| 161 |
* age-to-length-conversion matrix. |
|
| 162 |
*/ |
|
| 163 |
ParameterVector age_to_length_conversion; |
|
| 164 | ||
| 165 |
// derived quantities |
|
| 166 |
/** |
|
| 167 |
* @brief Derived landings-at-age in numbers. |
|
| 168 |
*/ |
|
| 169 |
Rcpp::NumericVector derived_landings_naa; |
|
| 170 |
/** |
|
| 171 |
* @brief Derived landings-at-length in numbers. |
|
| 172 |
*/ |
|
| 173 |
Rcpp::NumericVector derived_landings_nal; |
|
| 174 |
/** |
|
| 175 |
* @brief Derived landings-at-age in weight (mt). |
|
| 176 |
*/ |
|
| 177 |
Rcpp::NumericVector derived_landings_waa; |
|
| 178 |
/** |
|
| 179 |
* @brief Derived landings in observed units. |
|
| 180 |
*/ |
|
| 181 |
Rcpp::NumericVector derived_landings_expected; |
|
| 182 |
/** |
|
| 183 |
* @brief Derived landings in weight. |
|
| 184 |
*/ |
|
| 185 |
Rcpp::NumericVector derived_landings_w; |
|
| 186 |
/** |
|
| 187 |
* @brief Derived landings in numbers. |
|
| 188 |
*/ |
|
| 189 |
Rcpp::NumericVector derived_landings_n; |
|
| 190 |
/** |
|
| 191 |
* @brief Derived landings-at-age in numbers. |
|
| 192 |
*/ |
|
| 193 |
Rcpp::NumericVector derived_index_naa; |
|
| 194 |
/** |
|
| 195 |
* @brief Derived landings-at-length in numbers. |
|
| 196 |
*/ |
|
| 197 |
Rcpp::NumericVector derived_index_nal; |
|
| 198 |
/** |
|
| 199 |
* @brief Derived landings-at-age in weight (mt). |
|
| 200 |
*/ |
|
| 201 |
Rcpp::NumericVector derived_index_waa; |
|
| 202 |
/** |
|
| 203 |
* @brief Derived index in observed units. |
|
| 204 |
*/ |
|
| 205 |
Rcpp::NumericVector derived_index_expected; |
|
| 206 |
/** |
|
| 207 |
* @brief Derived index in weight. |
|
| 208 |
*/ |
|
| 209 |
Rcpp::NumericVector derived_index_w; |
|
| 210 |
/** |
|
| 211 |
* @brief Derived index in numbers. |
|
| 212 |
*/ |
|
| 213 |
Rcpp::NumericVector derived_index_n; |
|
| 214 |
/** |
|
| 215 |
* @brief Derived age composition proportions. |
|
| 216 |
*/ |
|
| 217 |
Rcpp::NumericVector derived_agecomp_proportion; |
|
| 218 |
/** |
|
| 219 |
* @brief Derived length composition proportions. |
|
| 220 |
*/ |
|
| 221 |
Rcpp::NumericVector derived_lengthcomp_proportion; |
|
| 222 |
/** |
|
| 223 |
* @brief Derived age compositions. |
|
| 224 |
*/ |
|
| 225 |
Rcpp::NumericVector derived_agecomp_expected; |
|
| 226 |
/** |
|
| 227 |
* @brief Derived length compositions. |
|
| 228 |
*/ |
|
| 229 |
Rcpp::NumericVector derived_lengthcomp_expected; |
|
| 230 | ||
| 231 |
/** |
|
| 232 |
* @brief The constructor. |
|
| 233 |
*/ |
|
| 234 | 42x |
FleetInterface() : FleetInterfaceBase() {
|
| 235 |
std::shared_ptr<FleetInterface> fleet = |
|
| 236 | 42x |
std::make_shared<FleetInterface>(*this); |
| 237 | 42x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back(fleet); |
| 238 |
/* Create instance of map: key is id and value is pointer to |
|
| 239 |
FleetInterfaceBase */ |
|
| 240 | 42x |
FleetInterfaceBase::live_objects[this->id] = fleet; |
| 241 |
} |
|
| 242 | ||
| 243 |
/** |
|
| 244 |
* @brief Construct a new Fleet Interface object |
|
| 245 |
* |
|
| 246 |
* @param other |
|
| 247 |
*/ |
|
| 248 | 42x |
FleetInterface(const FleetInterface &other) |
| 249 | 42x |
: FleetInterfaceBase(other), |
| 250 | 42x |
interface_observed_agecomp_data_id_m( |
| 251 | 42x |
other.interface_observed_agecomp_data_id_m), |
| 252 | 42x |
interface_observed_lengthcomp_data_id_m( |
| 253 | 42x |
other.interface_observed_lengthcomp_data_id_m), |
| 254 | 42x |
interface_observed_index_data_id_m( |
| 255 | 42x |
other.interface_observed_index_data_id_m), |
| 256 | 42x |
interface_observed_landings_data_id_m( |
| 257 | 42x |
other.interface_observed_landings_data_id_m), |
| 258 | 42x |
interface_selectivity_id_m(other.interface_selectivity_id_m), |
| 259 | 42x |
name(other.name), |
| 260 | 42x |
n_ages(other.n_ages), |
| 261 | 42x |
n_lengths(other.n_lengths), |
| 262 | 42x |
n_years(other.n_years), |
| 263 | 42x |
log_q(other.log_q), |
| 264 | 42x |
log_Fmort(other.log_Fmort), |
| 265 | 42x |
log_index_expected(other.log_index_expected), |
| 266 | 42x |
log_landings_expected(other.log_landings_expected), |
| 267 | 42x |
agecomp_proportion(other.agecomp_proportion), |
| 268 | 42x |
lengthcomp_proportion(other.lengthcomp_proportion), |
| 269 | 42x |
agecomp_expected(other.agecomp_expected), |
| 270 | 42x |
lengthcomp_expected(other.lengthcomp_expected), |
| 271 | 42x |
age_to_length_conversion(other.age_to_length_conversion), |
| 272 | 42x |
observed_landings_units(other.observed_landings_units), |
| 273 | 42x |
observed_index_units(other.observed_index_units), |
| 274 | 42x |
derived_landings_naa(other.derived_landings_naa), |
| 275 | 42x |
derived_landings_nal(other.derived_landings_nal), |
| 276 | 42x |
derived_landings_waa(other.derived_landings_waa), |
| 277 | 42x |
derived_index_expected(other.derived_index_expected), |
| 278 | 42x |
derived_index_w(other.derived_index_w), |
| 279 | 42x |
derived_index_n(other.derived_index_n), |
| 280 | 42x |
derived_landings_expected(other.derived_landings_expected), |
| 281 | 42x |
derived_landings_w(other.derived_landings_w), |
| 282 | 42x |
derived_landings_n(other.derived_landings_n), |
| 283 | 42x |
derived_agecomp_proportion(other.derived_agecomp_proportion), |
| 284 | 42x |
derived_lengthcomp_proportion(other.derived_lengthcomp_proportion), |
| 285 | 42x |
derived_agecomp_expected(other.derived_agecomp_expected), |
| 286 | 126x |
derived_lengthcomp_expected(other.derived_lengthcomp_expected) {}
|
| 287 | ||
| 288 |
/** |
|
| 289 |
* @brief The destructor. |
|
| 290 |
*/ |
|
| 291 | 252x |
virtual ~FleetInterface() {}
|
| 292 | ||
| 293 |
/** |
|
| 294 |
* @brief Gets the ID of the interface base object. |
|
| 295 |
* @return The ID. |
|
| 296 |
*/ |
|
| 297 | 114x |
virtual uint32_t get_id() { return this->id; }
|
| 298 | ||
| 299 |
/** |
|
| 300 |
* @brief Sets the name of the fleet. |
|
| 301 |
* @param name The name to set. |
|
| 302 |
*/ |
|
| 303 | ! |
void SetName(const std::string &name) { this->name.set(name); }
|
| 304 | ||
| 305 |
/** |
|
| 306 |
* @brief Gets the name of the fleet. |
|
| 307 |
* @return The name. |
|
| 308 |
*/ |
|
| 309 | ! |
std::string GetName() const { return this->name.get(); }
|
| 310 | ||
| 311 |
/** |
|
| 312 |
* @brief Set the unique ID for the observed age-composition data object. |
|
| 313 |
* @param observed_agecomp_data_id Unique ID for the observed data object. |
|
| 314 |
*/ |
|
| 315 | 35x |
void SetObservedAgeCompDataID(int observed_agecomp_data_id) {
|
| 316 | 35x |
interface_observed_agecomp_data_id_m.set(observed_agecomp_data_id); |
| 317 |
} |
|
| 318 | ||
| 319 |
/** |
|
| 320 |
* @brief Set the unique ID for the observed length-composition data object. |
|
| 321 |
* @param observed_lengthcomp_data_id Unique ID for the observed data object. |
|
| 322 |
*/ |
|
| 323 | 32x |
void SetObservedLengthCompDataID(int observed_lengthcomp_data_id) {
|
| 324 | 32x |
interface_observed_lengthcomp_data_id_m.set(observed_lengthcomp_data_id); |
| 325 |
} |
|
| 326 | ||
| 327 |
/** |
|
| 328 |
* @brief Set the unique ID for the observed index data object. |
|
| 329 |
* @param observed_index_data_id Unique ID for the observed data object. |
|
| 330 |
*/ |
|
| 331 | 22x |
void SetObservedIndexDataID(int observed_index_data_id) {
|
| 332 | 22x |
interface_observed_index_data_id_m.set(observed_index_data_id); |
| 333 |
} |
|
| 334 | ||
| 335 |
/** |
|
| 336 |
* @brief Set the unique ID for the observed landings data object. |
|
| 337 |
* @param observed_landings_data_id Unique ID for the observed data object. |
|
| 338 |
*/ |
|
| 339 | 18x |
void SetObservedLandingsDataID(int observed_landings_data_id) {
|
| 340 | 18x |
interface_observed_landings_data_id_m.set(observed_landings_data_id); |
| 341 |
} |
|
| 342 |
/** |
|
| 343 |
* @brief Set the unique ID for the selectivity object. |
|
| 344 |
* @param selectivity_id Unique ID for the observed object. |
|
| 345 |
*/ |
|
| 346 | 40x |
void SetSelectivityID(int selectivity_id) {
|
| 347 | 40x |
interface_selectivity_id_m.set(selectivity_id); |
| 348 |
} |
|
| 349 | ||
| 350 |
/** |
|
| 351 |
* @brief Get the unique ID for the selectivity object. |
|
| 352 |
* |
|
| 353 |
* @return uint32_t |
|
| 354 |
*/ |
|
| 355 | 26x |
uint32_t GetSelectivityID() { return interface_selectivity_id_m.get(); }
|
| 356 | ||
| 357 |
/** |
|
| 358 |
* @brief Get the unique ID for the observed age-composition data object. |
|
| 359 |
*/ |
|
| 360 | 59x |
int GetObservedAgeCompDataID() {
|
| 361 | 59x |
return interface_observed_agecomp_data_id_m.get(); |
| 362 |
} |
|
| 363 | ||
| 364 |
/** |
|
| 365 |
* @brief Get the unique ID for the observed length-composition data |
|
| 366 |
* object. |
|
| 367 |
*/ |
|
| 368 | 56x |
int GetObservedLengthCompDataID() {
|
| 369 | 56x |
return interface_observed_lengthcomp_data_id_m.get(); |
| 370 |
} |
|
| 371 | ||
| 372 |
/** |
|
| 373 |
* @brief Get the unique id for the observed index data object. |
|
| 374 |
*/ |
|
| 375 | 47x |
int GetObservedIndexDataID() {
|
| 376 | 47x |
return interface_observed_index_data_id_m.get(); |
| 377 |
} |
|
| 378 | ||
| 379 |
/** |
|
| 380 |
* @brief Get the unique id for the observed landings data object. |
|
| 381 |
*/ |
|
| 382 | 44x |
int GetObservedLandingsDataID() {
|
| 383 | 44x |
return interface_observed_landings_data_id_m.get(); |
| 384 |
} |
|
| 385 |
/** |
|
| 386 |
* @brief Extracts the derived quantities from `Information` to the Rcpp |
|
| 387 |
* object. |
|
| 388 |
*/ |
|
| 389 | 13x |
virtual void finalize() {
|
| 390 | 13x |
if (this->finalized) {
|
| 391 |
// log warning that finalize has been called more than once. |
|
| 392 | ! |
FIMS_WARNING_LOG("Fleet " + fims::to_string(this->id) +
|
| 393 |
" has been finalized already."); |
|
| 394 |
} |
|
| 395 | ||
| 396 | 13x |
this->finalized = true; // indicate this has been called already |
| 397 | ||
| 398 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 399 | 13x |
fims_info::Information<double>::GetInstance(); |
| 400 | ||
| 401 | 13x |
fims_info::Information<double>::fleet_iterator it; |
| 402 | ||
| 403 | 13x |
it = info->fleets.find(this->id); |
| 404 | ||
| 405 | 13x |
if (it == info->fleets.end()) {
|
| 406 | ! |
FIMS_WARNING_LOG("Fleet " + fims::to_string(this->id) +
|
| 407 |
" not found in Information."); |
|
| 408 | ! |
return; |
| 409 |
} else {
|
|
| 410 |
std::shared_ptr<fims_popdy::Fleet<double>> fleet = |
|
| 411 | 13x |
std::dynamic_pointer_cast<fims_popdy::Fleet<double>>(it->second); |
| 412 | ||
| 413 | 403x |
for (size_t i = 0; i < this->log_Fmort.size(); i++) {
|
| 414 | 390x |
if (this->log_Fmort[i].estimation_type_m.get() == "constant") {
|
| 415 | 30x |
this->log_Fmort[i].final_value_m = this->log_Fmort[i].initial_value_m; |
| 416 |
} else {
|
|
| 417 | 360x |
this->log_Fmort[i].final_value_m = fleet->log_Fmort[i]; |
| 418 |
} |
|
| 419 |
} |
|
| 420 | ||
| 421 | 26x |
for (size_t i = 0; i < this->log_q.size(); i++) {
|
| 422 | 13x |
if (this->log_q[i].estimation_type_m.get() == "constant") {
|
| 423 | 13x |
this->log_q[i].final_value_m = this->log_q[i].initial_value_m; |
| 424 |
} else {
|
|
| 425 | ! |
this->log_q[i].final_value_m = fleet->log_q[i]; |
| 426 |
} |
|
| 427 |
} |
|
| 428 | ||
| 429 | 2773x |
for (size_t i = 0; i < fleet->age_to_length_conversion.size(); i++) {
|
| 430 | 2760x |
if (this->age_to_length_conversion[i].estimation_type_m.get() == |
| 431 |
"constant") {
|
|
| 432 | 2760x |
this->age_to_length_conversion[i].final_value_m = |
| 433 | 2760x |
this->age_to_length_conversion[i].initial_value_m; |
| 434 |
} else {
|
|
| 435 | ! |
this->age_to_length_conversion[i].final_value_m = |
| 436 | ! |
fleet->age_to_length_conversion[i]; |
| 437 |
} |
|
| 438 |
} |
|
| 439 |
} |
|
| 440 |
} |
|
| 441 | ||
| 442 |
#ifdef TMB_MODEL |
|
| 443 | ||
| 444 |
template <typename Type> |
|
| 445 | 152x |
bool add_to_fims_tmb_internal() {
|
| 446 | 152x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 447 |
fims_info::Information<Type>::GetInstance(); |
|
| 448 | ||
| 449 | 152x |
std::shared_ptr<fims_popdy::Fleet<Type>> fleet = |
| 450 |
std::make_shared<fims_popdy::Fleet<Type>>(); |
|
| 451 | ||
| 452 | 152x |
std::stringstream ss; |
| 453 | ||
| 454 |
// set relative info |
|
| 455 | 152x |
fleet->id = this->id; |
| 456 | 152x |
fleet->n_ages = this->n_ages.get(); |
| 457 | 152x |
fleet->n_lengths = this->n_lengths.get(); |
| 458 | 152x |
fleet->n_years = this->n_years.get(); |
| 459 | 152x |
fleet->observed_landings_units = this->observed_landings_units; |
| 460 | 152x |
fleet->observed_index_units = this->observed_index_units; |
| 461 | ||
| 462 | 152x |
fleet->fleet_observed_agecomp_data_id_m = |
| 463 | 152x |
interface_observed_agecomp_data_id_m.get(); |
| 464 | ||
| 465 | 152x |
fleet->fleet_observed_lengthcomp_data_id_m = |
| 466 | 152x |
interface_observed_lengthcomp_data_id_m.get(); |
| 467 | ||
| 468 | 152x |
fleet->fleet_observed_index_data_id_m = |
| 469 | 152x |
interface_observed_index_data_id_m.get(); |
| 470 | 152x |
fleet->fleet_observed_landings_data_id_m = |
| 471 | 152x |
interface_observed_landings_data_id_m.get(); |
| 472 | ||
| 473 | 152x |
fleet->fleet_selectivity_id_m = interface_selectivity_id_m.get(); |
| 474 | ||
| 475 | 152x |
fleet->log_q.resize(this->log_q.size()); |
| 476 | 304x |
for (size_t i = 0; i < this->log_q.size(); i++) {
|
| 477 | 152x |
fleet->log_q[i] = this->log_q[i].initial_value_m; |
| 478 | ||
| 479 | 152x |
if (this->log_q[i].estimation_type_m.get() == "fixed_effects") {
|
| 480 | 72x |
ss.str("");
|
| 481 | 72x |
ss << "Fleet." << this->id << ".log_q." << this->log_q[i].id_m; |
| 482 | 72x |
info->RegisterParameterName(ss.str()); |
| 483 | 72x |
info->RegisterParameter(fleet->log_q[i]); |
| 484 |
} |
|
| 485 | 152x |
if (this->log_q[i].estimation_type_m.get() == "random_effects") {
|
| 486 | ! |
ss.str("");
|
| 487 | ! |
ss << "Fleet." << this->id << ".log_q." << this->log_q[i].id_m; |
| 488 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 489 | ! |
info->RegisterRandomEffect(fleet->log_q[i]); |
| 490 |
} |
|
| 491 |
} |
|
| 492 | ||
| 493 | 304x |
FIMS_INFO_LOG("adding Fleet fmort object to TMB");
|
| 494 | 152x |
fleet->log_Fmort.resize(this->log_Fmort.size()); |
| 495 | 4596x |
for (size_t i = 0; i < log_Fmort.size(); i++) {
|
| 496 | 4444x |
fleet->log_Fmort[i] = this->log_Fmort[i].initial_value_m; |
| 497 | ||
| 498 | 4444x |
if (this->log_Fmort[i].estimation_type_m.get() == "fixed_effects") {
|
| 499 | 2160x |
ss.str("");
|
| 500 | 2160x |
ss << "Fleet." << this->id << ".log_Fmort." << this->log_Fmort[i].id_m; |
| 501 | 2160x |
info->RegisterParameterName(ss.str()); |
| 502 | 2160x |
info->RegisterParameter(fleet->log_Fmort[i]); |
| 503 |
} |
|
| 504 | 4444x |
if (this->log_Fmort[i].estimation_type_m.get() == "random_effects") {
|
| 505 | ! |
ss.str("");
|
| 506 | ! |
ss << "Fleet." << this->id << ".log_Fmort." << this->log_Fmort[i].id_m; |
| 507 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 508 | ! |
info->RegisterRandomEffect(fleet->log_Fmort[i]); |
| 509 |
} |
|
| 510 |
} |
|
| 511 |
// add to variable_map |
|
| 512 | 152x |
info->variable_map[this->log_Fmort.id_m] = &(fleet)->log_Fmort; |
| 513 | ||
| 514 | 152x |
if (this->n_lengths.get() > 0) {
|
| 515 | 128x |
fleet->age_to_length_conversion.resize( |
| 516 |
this->age_to_length_conversion.size()); |
|
| 517 | ||
| 518 | 128x |
if (this->age_to_length_conversion.size() != |
| 519 | 128x |
(this->n_ages.get() * this->n_lengths.get())) {
|
| 520 | ! |
FIMS_ERROR_LOG( |
| 521 |
"age_to_length_conversion don't match, " + |
|
| 522 |
fims::to_string(this->age_to_length_conversion.size()) + " != " + |
|
| 523 |
fims::to_string((this->n_ages.get() * this->n_lengths.get()))); |
|
| 524 |
} |
|
| 525 | ||
| 526 | 35456x |
for (size_t i = 0; i < fleet->age_to_length_conversion.size(); i++) {
|
| 527 | 35328x |
fleet->age_to_length_conversion[i] = |
| 528 | 35328x |
this->age_to_length_conversion[i].initial_value_m; |
| 529 | 35328x |
FIMS_INFO_LOG(" adding Fleet length object to TMB in loop " +
|
| 530 |
fims::to_string(i) + " of " + |
|
| 531 |
fims::to_string(fleet->age_to_length_conversion.size())); |
|
| 532 | ||
| 533 | 35328x |
if (this->age_to_length_conversion[i].estimation_type_m.get() == |
| 534 |
"fixed_effects") {
|
|
| 535 | ! |
ss.str("");
|
| 536 | ! |
ss << "Fleet." << this->id << ".age_to_length_conversion." |
| 537 | ! |
<< this->age_to_length_conversion[i].id_m; |
| 538 | ! |
info->RegisterParameterName(ss.str()); |
| 539 | ! |
info->RegisterParameter(fleet->age_to_length_conversion[i]); |
| 540 |
} |
|
| 541 | 35328x |
if (this->age_to_length_conversion[i].estimation_type_m.get() == |
| 542 |
"random_effects") {
|
|
| 543 | ! |
FIMS_ERROR_LOG( |
| 544 |
"age_to_length_conversion cannot be set to random effects"); |
|
| 545 |
} |
|
| 546 |
} |
|
| 547 | ||
| 548 | 128x |
info->variable_map[this->age_to_length_conversion.id_m] = |
| 549 | 128x |
&(fleet)->age_to_length_conversion; |
| 550 |
} |
|
| 551 | ||
| 552 |
// add to Information |
|
| 553 | 152x |
info->fleets[fleet->id] = fleet; |
| 554 | 304x |
FIMS_INFO_LOG("done adding Fleet object to TMB");
|
| 555 | 152x |
return true; |
| 556 |
} |
|
| 557 | ||
| 558 |
/** |
|
| 559 |
* @brief Adds the parameters to the TMB model. |
|
| 560 |
* @return A boolean of true. |
|
| 561 |
*/ |
|
| 562 | 38x |
virtual bool add_to_fims_tmb() {
|
| 563 |
#ifdef TMBAD_FRAMEWORK |
|
| 564 | 38x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 565 | 38x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 566 |
#else |
|
| 567 |
FIMS_INFO_LOG("adding Fleet object to TMB");
|
|
| 568 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 569 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 570 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 571 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 572 |
#endif |
|
| 573 | ||
| 574 | 38x |
return true; |
| 575 |
} |
|
| 576 | ||
| 577 |
#endif |
|
| 578 |
}; |
|
| 579 | ||
| 580 |
#endif |
| 1 |
/** |
|
| 2 |
* @file rcpp_growth.hpp |
|
| 3 |
* @brief The Rcpp interface to declare different types of growth, e.g., |
|
| 4 |
* empirical weight-at-age data. Allows for the use of methods::new() in R. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_GROWTH_HPP |
|
| 10 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_GROWTH_HPP |
|
| 11 | ||
| 12 |
#include "../../../population_dynamics/growth/growth.hpp" |
|
| 13 |
#include "rcpp_interface_base.hpp" |
|
| 14 | ||
| 15 |
/** |
|
| 16 |
* @brief Rcpp interface that serves as the parent class for Rcpp growth |
|
| 17 |
* interfaces. This type should be inherited and not called from R directly. |
|
| 18 |
*/ |
|
| 19 |
class GrowthInterfaceBase : public FIMSRcppInterfaceBase {
|
|
| 20 |
public: |
|
| 21 |
/** |
|
| 22 |
* @brief The static id of the GrowthInterfaceBase object. |
|
| 23 |
*/ |
|
| 24 |
static uint32_t id_g; |
|
| 25 |
/** |
|
| 26 |
* @brief The local id of the GrowthInterfaceBase object. |
|
| 27 |
*/ |
|
| 28 |
uint32_t id; |
|
| 29 |
/** |
|
| 30 |
* @brief The map associating the IDs of GrowthInterfaceBase to the objects. |
|
| 31 |
* This is a live object, which is an object that has been created and lives |
|
| 32 |
* in memory. |
|
| 33 |
*/ |
|
| 34 |
static std::map<uint32_t, std::shared_ptr<GrowthInterfaceBase>> live_objects; |
|
| 35 | ||
| 36 |
/** |
|
| 37 |
* @brief The constructor. |
|
| 38 |
*/ |
|
| 39 | 24x |
GrowthInterfaceBase() {
|
| 40 | 24x |
this->id = GrowthInterfaceBase::id_g++; |
| 41 |
/* Create instance of map: key is id and value is pointer to |
|
| 42 |
GrowthInterfaceBase */ |
|
| 43 |
// GrowthInterfaceBase::live_objects[this->id] = |
|
| 44 |
// std::make_shared<GrowthInterfaceBase>(*this); |
|
| 45 |
} |
|
| 46 | ||
| 47 |
/** |
|
| 48 |
* @brief Construct a new Growth Interface Base object |
|
| 49 |
* |
|
| 50 |
* @param other |
|
| 51 |
*/ |
|
| 52 | 48x |
GrowthInterfaceBase(const GrowthInterfaceBase &other) : id(other.id) {}
|
| 53 | ||
| 54 |
/** |
|
| 55 |
* @brief The destructor. |
|
| 56 |
*/ |
|
| 57 | 72x |
virtual ~GrowthInterfaceBase() {}
|
| 58 | ||
| 59 |
/** |
|
| 60 |
* @brief Get the ID for the child growth interface objects to inherit. |
|
| 61 |
*/ |
|
| 62 |
virtual uint32_t get_id() = 0; |
|
| 63 | ||
| 64 |
/** |
|
| 65 |
* @brief A method for each child growth interface object to inherit so |
|
| 66 |
* each growth option can have an evaluate() function. |
|
| 67 |
*/ |
|
| 68 |
virtual double evaluate(double age) = 0; |
|
| 69 |
}; |
|
| 70 |
// static id of the GrowthInterfaceBase object |
|
| 71 |
uint32_t GrowthInterfaceBase::id_g = 1; |
|
| 72 |
// local id of the GrowthInterfaceBase object map relating the ID of the |
|
| 73 |
// GrowthInterfaceBase to the GrowthInterfaceBase objects |
|
| 74 |
std::map<uint32_t, std::shared_ptr<GrowthInterfaceBase>> |
|
| 75 |
GrowthInterfaceBase::live_objects; |
|
| 76 | ||
| 77 |
/** |
|
| 78 |
* @brief Rcpp interface for EWAAGrowth to instantiate the object from R: |
|
| 79 |
* ewaa <- methods::new(EWAAGrowth). Where, EWAA stands for empirical weight at |
|
| 80 |
* age and growth is not actually estimated. |
|
| 81 |
*/ |
|
| 82 |
class EWAAGrowthInterface : public GrowthInterfaceBase {
|
|
| 83 |
public: |
|
| 84 |
/** |
|
| 85 |
* @brief Weights (mt) for each age class. |
|
| 86 |
*/ |
|
| 87 |
RealVector weights; |
|
| 88 |
/** |
|
| 89 |
* @brief Ages (years) for each age class. |
|
| 90 |
*/ |
|
| 91 |
RealVector ages; |
|
| 92 |
/** |
|
| 93 |
* @brief A map of empirical weight-at-age values allowing multiple modules to |
|
| 94 |
* access and modify the weights without copying values between modules. |
|
| 95 |
*/ |
|
| 96 |
std::shared_ptr<std::map<double, double>> ewaa; |
|
| 97 |
/** |
|
| 98 |
* @brief Have weight and age vectors been set? The default is false. |
|
| 99 |
*/ |
|
| 100 |
bool initialized = false; |
|
| 101 | ||
| 102 |
/** |
|
| 103 |
* @brief The constructor. |
|
| 104 |
*/ |
|
| 105 | 24x |
EWAAGrowthInterface() : GrowthInterfaceBase() {
|
| 106 | 24x |
this->ewaa = std::make_shared<std::map<double, double>>(); |
| 107 | 24x |
GrowthInterfaceBase::live_objects[this->id] = |
| 108 | 48x |
std::make_shared<EWAAGrowthInterface>(*this); |
| 109 | 24x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 110 | 48x |
std::make_shared<EWAAGrowthInterface>(*this)); |
| 111 |
} |
|
| 112 | ||
| 113 |
/** |
|
| 114 |
* @brief Construct a new EWAAGrowthInterface object |
|
| 115 |
* |
|
| 116 |
* @param other |
|
| 117 |
*/ |
|
| 118 | 48x |
EWAAGrowthInterface(const EWAAGrowthInterface &other) |
| 119 | 48x |
: GrowthInterfaceBase(other), |
| 120 | 48x |
weights(other.weights), |
| 121 | 48x |
ages(other.ages), |
| 122 | 48x |
ewaa(other.ewaa), |
| 123 | 48x |
initialized(other.initialized) {}
|
| 124 | ||
| 125 |
/** |
|
| 126 |
* @brief The destructor. |
|
| 127 |
*/ |
|
| 128 | 192x |
virtual ~EWAAGrowthInterface() {}
|
| 129 | ||
| 130 |
/** |
|
| 131 |
* @brief Gets the ID of the interface base object. |
|
| 132 |
* @return The ID. |
|
| 133 |
*/ |
|
| 134 | 22x |
virtual uint32_t get_id() { return this->id; }
|
| 135 | ||
| 136 |
/** |
|
| 137 |
* @brief Create a map of input numeric vectors. |
|
| 138 |
* @param weights Type vector of weights. |
|
| 139 |
* @param ages Type vector of ages. |
|
| 140 |
* @return std::map<T, T>. |
|
| 141 |
*/ |
|
| 142 | 39x |
inline std::map<double, double> make_map(RealVector ages, |
| 143 |
RealVector weights) {
|
|
| 144 | 39x |
std::map<double, double> mymap; |
| 145 | 507x |
for (uint32_t i = 0; i < ages.size(); i++) {
|
| 146 | 468x |
mymap.insert(std::pair<double, double>(ages[i], weights[i])); |
| 147 |
} |
|
| 148 | 39x |
return mymap; |
| 149 |
} |
|
| 150 | ||
| 151 |
/** |
|
| 152 |
* @brief Evaluate the growth using empirical weight at age. |
|
| 153 |
* @param age The age at of the individual to evaluate weight. |
|
| 154 |
* @details This can be called from R using ewaagrowth.evaluate(age). |
|
| 155 |
*/ |
|
| 156 | 3x |
virtual double evaluate(double age) {
|
| 157 | 3x |
fims_popdy::EWAAGrowth<double> EWAAGrowth; |
| 158 | ||
| 159 | 3x |
if (initialized == false) {
|
| 160 |
// Check that ages and weights vector are the same length |
|
| 161 | 3x |
if (this->ages.size() != this->weights.size()) {
|
| 162 | 2x |
Rcpp::stop("ages and weights must be the same length");
|
| 163 |
} |
|
| 164 | 1x |
EWAAGrowth.ewaa = make_map(this->ages, this->weights); |
| 165 | 1x |
initialized = true; |
| 166 |
} else {
|
|
| 167 | ! |
Rcpp::stop("this empirical weight at age object is already initialized");
|
| 168 |
} |
|
| 169 | 2x |
return EWAAGrowth.evaluate(age); |
| 170 |
} |
|
| 171 | ||
| 172 |
/** |
|
| 173 |
* @brief Converts the data to json representation for the output. |
|
| 174 |
* @return A string is returned specifying that the module relates to the |
|
| 175 |
* growth interface with empirical weight at age. It also returns the ID, the |
|
| 176 |
* rank of 1, the dimensions, age bins, and the calculated values themselves. |
|
| 177 |
* This string is formatted for a json file. |
|
| 178 |
*/ |
|
| 179 | 13x |
virtual std::string to_json() {
|
| 180 | 13x |
std::stringstream ss; |
| 181 | 13x |
ss << "{\n";
|
| 182 | 13x |
ss << " \"module_name\": \"Growth\",\n"; |
| 183 | 13x |
ss << " \"module_type\": \"EWAA\",\n"; |
| 184 | 13x |
ss << " \"module_id\":" << this->id << ",\n"; |
| 185 | 13x |
ss << " \"parameters\": [\n{\n";
|
| 186 | 13x |
ss << " \"name\": null,\n"; |
| 187 | 13x |
ss << " \"id\": null,\n"; |
| 188 | 13x |
ss << " \"type\": \"vector\",\n"; |
| 189 | 13x |
ss << " \"dimensionality\": {\n";
|
| 190 | 13x |
ss << " \"header\": [\"n_ages\"],\n"; |
| 191 | 13x |
ss << " \"dimensions\": [" << this->ages.size() << "]\n},\n"; |
| 192 | ||
| 193 | 13x |
ss << " \"values\": [\n"; |
| 194 | 156x |
for (size_t i = 0; i < weights.size() - 1; i++) {
|
| 195 | 143x |
ss << "{\n";
|
| 196 | 143x |
ss << "\"id\": null,\n"; |
| 197 | 143x |
ss << "\"value\": " << weights[i] << ",\n"; |
| 198 | 143x |
ss << "\"estimated_value\": " << weights[i] << ",\n"; |
| 199 | 143x |
ss << "\"uncertainty\": " << 0 << ",\n"; |
| 200 | 143x |
ss << "\"min\": \"-Infinity\",\n"; |
| 201 | 143x |
ss << "\"max\": \"Infinity\",\n"; |
| 202 | 143x |
ss << "\"estimation_type\": \"constant\"\n"; |
| 203 | 143x |
ss << "},\n"; |
| 204 |
} |
|
| 205 | 13x |
ss << "{\n";
|
| 206 | 13x |
ss << "\"id\": null,\n"; |
| 207 | 13x |
ss << "\"value\": " << weights[weights.size() - 1] << ",\n"; |
| 208 | 13x |
ss << "\"estimated_value\": " << weights[weights.size() - 1] << ",\n"; |
| 209 | 13x |
ss << "\"uncertainty\": " << 0 << ",\n"; |
| 210 | 13x |
ss << "\"min\": \"-Infinity\",\n"; |
| 211 | 13x |
ss << "\"max\": \"Infinity\",\n"; |
| 212 | 13x |
ss << "\"estimation_type\": \"constant\"\n"; |
| 213 | 13x |
ss << "}\n]\n"; |
| 214 | 13x |
ss << "}\n]\n}\n"; |
| 215 | 26x |
return ss.str(); |
| 216 |
} |
|
| 217 | ||
| 218 |
#ifdef TMB_MODEL |
|
| 219 | ||
| 220 |
template <typename Type> |
|
| 221 | 76x |
bool add_to_fims_tmb_internal() {
|
| 222 | 76x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 223 |
fims_info::Information<Type>::GetInstance(); |
|
| 224 | ||
| 225 | 76x |
std::shared_ptr<fims_popdy::EWAAGrowth<Type>> ewaa_growth = |
| 226 |
std::make_shared<fims_popdy::EWAAGrowth<Type>>(); |
|
| 227 | ||
| 228 |
// set relative info |
|
| 229 | 76x |
ewaa_growth->id = this->id; |
| 230 | 76x |
ewaa_growth->ewaa = make_map(this->ages, this->weights); // this->ewaa; |
| 231 |
// add to Information |
|
| 232 | 76x |
info->growth_models[ewaa_growth->id] = ewaa_growth; |
| 233 | ||
| 234 | 76x |
return true; |
| 235 |
} |
|
| 236 | ||
| 237 |
/** |
|
| 238 |
* @brief Adds the parameters to the TMB model. |
|
| 239 |
* @return A boolean of true. |
|
| 240 |
*/ |
|
| 241 | 19x |
virtual bool add_to_fims_tmb() {
|
| 242 | 19x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 243 |
#ifdef TMBAD_FRAMEWORK |
|
| 244 | 19x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 245 |
#else |
|
| 246 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 247 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 248 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 249 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 250 |
#endif |
|
| 251 | ||
| 252 | 19x |
return true; |
| 253 |
} |
|
| 254 | ||
| 255 |
#endif |
|
| 256 |
}; |
|
| 257 | ||
| 258 |
#endif |
| 1 |
/** |
|
| 2 |
* @file rcpp_interface_base.hpp |
|
| 3 |
* @brief The Rcpp interface to declare objects that are used ubiquitously |
|
| 4 |
* throughout the Rcpp interface, e.g., Parameters and ParameterVectors. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_INTERFACE_BASE_HPP |
|
| 10 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_INTERFACE_BASE_HPP |
|
| 11 | ||
| 12 |
#include <RcppCommon.h> |
|
| 13 |
#include <map> |
|
| 14 |
#include <vector> |
|
| 15 | ||
| 16 |
#include "../../../common/def.hpp" |
|
| 17 |
#include "../../../common/information.hpp" |
|
| 18 |
#include "../../interface.hpp" |
|
| 19 |
#include "rcpp_shared_primitive.hpp" |
|
| 20 |
#include <limits> |
|
| 21 | ||
| 22 |
#define RCPP_NO_SUGAR |
|
| 23 |
#include <Rcpp.h> |
|
| 24 | ||
| 25 |
/** |
|
| 26 |
* @brief An Rcpp interface that defines the Parameter class. |
|
| 27 |
* |
|
| 28 |
* @details An Rcpp interface class that defines the interface between R and |
|
| 29 |
* C++ for a parameter type. |
|
| 30 |
*/ |
|
| 31 |
class Parameter {
|
|
| 32 |
public: |
|
| 33 |
/** |
|
| 34 |
* @brief The static ID of the Parameter object. |
|
| 35 |
*/ |
|
| 36 |
static uint32_t id_g; |
|
| 37 |
/** |
|
| 38 |
* @brief The local ID of the Parameter object. |
|
| 39 |
*/ |
|
| 40 |
uint32_t id_m; |
|
| 41 |
/** |
|
| 42 |
* @brief The initial value of the parameter. |
|
| 43 |
*/ |
|
| 44 |
double initial_value_m = 0.0; |
|
| 45 |
/** |
|
| 46 |
* @brief The final value of the parameter. |
|
| 47 |
*/ |
|
| 48 |
double final_value_m = 0.0; |
|
| 49 | ||
| 50 |
/** |
|
| 51 |
* @brief The standard error of the parameter estimate, where the default is |
|
| 52 |
* -999.0. |
|
| 53 |
*/ |
|
| 54 |
double uncertainty_m = -999.0; |
|
| 55 |
/** |
|
| 56 |
* @brief The minimum possible parameter value, where the default is negative |
|
| 57 |
* infinity. |
|
| 58 |
*/ |
|
| 59 |
double min_m = -std::numeric_limits<double>::infinity(); |
|
| 60 |
/** |
|
| 61 |
* @brief The maximum possible parameter value, where the default is positive |
|
| 62 |
* infinity. |
|
| 63 |
*/ |
|
| 64 |
double max_m = std::numeric_limits<double>::infinity(); |
|
| 65 |
/** |
|
| 66 |
* @brief A string indicating the estimation type. Options are: constant, |
|
| 67 |
* fixed_effects, or random_effects, where the default is constant. |
|
| 68 |
*/ |
|
| 69 |
SharedString estimation_type_m = SharedString("constant");
|
|
| 70 | ||
| 71 |
/** |
|
| 72 |
* @brief The constructor for initializing a parameter. |
|
| 73 |
*/ |
|
| 74 |
Parameter(double value, double min, double max, std::string estimation_type) |
|
| 75 |
: id_m(Parameter::id_g++), |
|
| 76 |
initial_value_m(value), |
|
| 77 |
min_m(min), |
|
| 78 |
max_m(max), |
|
| 79 |
estimation_type_m(estimation_type) {}
|
|
| 80 | ||
| 81 |
/** |
|
| 82 |
* @brief The constructor for initializing a parameter. |
|
| 83 |
*/ |
|
| 84 | 59058x |
Parameter(const Parameter& other) |
| 85 | 59058x |
: id_m(other.id_m), |
| 86 | 59058x |
initial_value_m(other.initial_value_m), |
| 87 | 59058x |
final_value_m(other.final_value_m), |
| 88 | 59058x |
min_m(other.min_m), |
| 89 | 59058x |
max_m(other.max_m), |
| 90 | 59058x |
estimation_type_m(other.estimation_type_m) {}
|
| 91 | ||
| 92 |
/** |
|
| 93 |
* @brief The constructor for initializing a parameter. |
|
| 94 |
*/ |
|
| 95 | 21751x |
Parameter& operator=(const Parameter& right) {
|
| 96 |
// Check for self-assignment! |
|
| 97 | 21751x |
if (this == &right) // Same object? |
| 98 | ! |
return *this; // Yes, so skip assignment, and just return *this. |
| 99 | 21751x |
this->id_m = right.id_m; |
| 100 | 21751x |
this->initial_value_m = right.initial_value_m; |
| 101 | 21751x |
this->estimation_type_m = right.estimation_type_m; |
| 102 | 21751x |
this->min_m = right.min_m; |
| 103 | 21751x |
this->max_m = right.max_m; |
| 104 | 21751x |
return *this; |
| 105 |
} |
|
| 106 | ||
| 107 |
/** |
|
| 108 |
* @brief The constructor for initializing a parameter. |
|
| 109 |
*/ |
|
| 110 | 2x |
Parameter(double value) {
|
| 111 | 1x |
initial_value_m = value; |
| 112 | 1x |
id_m = Parameter::id_g++; |
| 113 |
} |
|
| 114 | ||
| 115 |
/** |
|
| 116 |
* @brief The constructor for initializing a parameter. |
|
| 117 |
* @details Set value to 0 when there is no input value. |
|
| 118 |
*/ |
|
| 119 | 134576x |
Parameter() {
|
| 120 | 67288x |
initial_value_m = 0; |
| 121 | 67288x |
id_m = Parameter::id_g++; |
| 122 |
} |
|
| 123 |
}; |
|
| 124 |
/** |
|
| 125 |
* @brief The unique ID for the variable map that points to a fims::Vector. |
|
| 126 |
*/ |
|
| 127 |
uint32_t Parameter::id_g = 0; |
|
| 128 | ||
| 129 |
/** |
|
| 130 |
* @brief Output for std::ostream& for a parameter. |
|
| 131 |
* |
|
| 132 |
* @param out The stream. |
|
| 133 |
* @param p A parameter. |
|
| 134 |
* @return std::ostream& |
|
| 135 |
*/ |
|
| 136 | 11615x |
std::ostream& operator<<(std::ostream& out, const Parameter& p) {
|
| 137 | 11615x |
out << "{\"id\": " << p.id_m << ",\n\"value\": " << p.initial_value_m
|
| 138 | 11615x |
<< ",\n\"estimated_value\": " << p.final_value_m |
| 139 | 11615x |
<< ",\n\"uncertainty\": " << p.uncertainty_m << ",\n\"min\": "; |
| 140 | 11615x |
if (p.min_m == -std::numeric_limits<double>::infinity()) {
|
| 141 | 11615x |
out << "\"-Infinity\""; |
| 142 |
} else {
|
|
| 143 | ! |
out << p.min_m; |
| 144 |
} |
|
| 145 | 11615x |
out << ",\n\"max\": "; |
| 146 | 11615x |
if (p.max_m == std::numeric_limits<double>::infinity()) {
|
| 147 | 11615x |
out << "\"Infinity\""; |
| 148 |
} else {
|
|
| 149 | ! |
out << p.max_m; |
| 150 |
} |
|
| 151 | ||
| 152 | 11615x |
out << ",\n\"estimation_type\": \"" << p.estimation_type_m << "\"\n}"; |
| 153 | ||
| 154 | 11615x |
return out; |
| 155 |
} |
|
| 156 | ||
| 157 |
/** |
|
| 158 |
* @brief An Rcpp interface class that defines the ParameterVector class. |
|
| 159 |
* |
|
| 160 |
* @details An Rcpp interface class that defines the interface between R and |
|
| 161 |
* C++ for a parameter vector type. |
|
| 162 |
*/ |
|
| 163 |
class ParameterVector {
|
|
| 164 |
public: |
|
| 165 |
/** |
|
| 166 |
* @brief The static ID of the Parameter object. |
|
| 167 |
*/ |
|
| 168 |
static uint32_t id_g; |
|
| 169 |
/** |
|
| 170 |
* @brief Parameter storage. |
|
| 171 |
*/ |
|
| 172 |
std::shared_ptr<std::vector<Parameter>> storage_m; |
|
| 173 |
/** |
|
| 174 |
* @brief The local ID of the Parameter object. |
|
| 175 |
*/ |
|
| 176 |
uint32_t id_m; |
|
| 177 | ||
| 178 |
/** |
|
| 179 |
* @brief The constructor. |
|
| 180 |
*/ |
|
| 181 | 1150x |
ParameterVector() {
|
| 182 | 1150x |
this->id_m = ParameterVector::id_g++; |
| 183 | 1150x |
this->storage_m = std::make_shared<std::vector<Parameter>>(); |
| 184 | 1150x |
this->storage_m->resize(1); // push_back(Rcpp::wrap(p)); |
| 185 |
} |
|
| 186 | ||
| 187 |
/** |
|
| 188 |
* @brief The constructor. |
|
| 189 |
*/ |
|
| 190 | 51364x |
ParameterVector(const ParameterVector& other) |
| 191 | 51364x |
: storage_m(other.storage_m), id_m(other.id_m) {}
|
| 192 | ||
| 193 |
/** |
|
| 194 |
* @brief The constructor. |
|
| 195 |
*/ |
|
| 196 | 27x |
ParameterVector(size_t size) {
|
| 197 | 27x |
this->id_m = ParameterVector::id_g++; |
| 198 | 27x |
this->storage_m = std::make_shared<std::vector<Parameter>>(); |
| 199 | 27x |
this->storage_m->resize(size); |
| 200 | 288x |
for (size_t i = 0; i < size; i++) {
|
| 201 | 261x |
storage_m->at(i) = Parameter(); |
| 202 |
} |
|
| 203 |
} |
|
| 204 | ||
| 205 |
/** |
|
| 206 |
* @brief The constructor for initializing a parameter vector. |
|
| 207 |
* @param x A numeric vector. |
|
| 208 |
* @param size The number of elements to copy over. |
|
| 209 |
*/ |
|
| 210 | 2x |
ParameterVector(Rcpp::NumericVector x, size_t size) {
|
| 211 | 2x |
if (x.size() < size) {
|
| 212 |
throw std::invalid_argument( |
|
| 213 |
"Error in call to ParameterVector(Rcpp::NumericVector x, size_t " |
|
| 214 | 1x |
"size): x.size() < size argument."); |
| 215 |
} else {
|
|
| 216 | 1x |
this->id_m = ParameterVector::id_g++; |
| 217 | 1x |
this->storage_m = std::make_shared<std::vector<Parameter>>(); |
| 218 | 1x |
this->storage_m->resize(size); |
| 219 | 11x |
for (size_t i = 0; i < size; i++) {
|
| 220 | 10x |
storage_m->at(i).initial_value_m = x[i]; |
| 221 |
} |
|
| 222 |
} |
|
| 223 |
} |
|
| 224 | ||
| 225 |
/** |
|
| 226 |
* @brief The constructor for initializing a parameter vector. |
|
| 227 |
* @param v A vector of doubles. |
|
| 228 |
*/ |
|
| 229 |
ParameterVector(const fims::Vector<double>& v) {
|
|
| 230 |
this->id_m = ParameterVector::id_g++; |
|
| 231 |
this->storage_m = std::make_shared<std::vector<Parameter>>(); |
|
| 232 |
this->storage_m->resize(v.size()); |
|
| 233 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 234 |
storage_m->at(i).initial_value_m = v[i]; |
|
| 235 |
} |
|
| 236 |
} |
|
| 237 | ||
| 238 |
/** |
|
| 239 |
* @brief Destroy the Parameter Vector object. |
|
| 240 |
* |
|
| 241 |
*/ |
|
| 242 | 163174x |
virtual ~ParameterVector() {}
|
| 243 | ||
| 244 |
/** |
|
| 245 |
* @brief Gets the ID of the ParameterVector object. |
|
| 246 |
*/ |
|
| 247 | 125x |
virtual uint32_t get_id() { return this->id_m; }
|
| 248 | ||
| 249 |
/** |
|
| 250 |
* @brief The accessor where the first index starts is zero. |
|
| 251 |
* @param pos The position of the ParameterVector that you want returned. |
|
| 252 |
*/ |
|
| 253 | 259838x |
inline Parameter& operator[](size_t pos) { return this->storage_m->at(pos); }
|
| 254 | ||
| 255 |
/** |
|
| 256 |
* @brief The accessor where the first index starts at one. This function is |
|
| 257 |
* for calling accessing from R. |
|
| 258 |
* @param pos The position of the ParameterVector that you want returned. |
|
| 259 |
*/ |
|
| 260 | 2x |
SEXP at(R_xlen_t pos) {
|
| 261 | 4x |
if (static_cast<size_t>(pos) == 0 || |
| 262 | 2x |
static_cast<size_t>(pos) > this->storage_m->size()) {
|
| 263 | 1x |
throw std::invalid_argument("ParameterVector: Index out of range");
|
| 264 |
FIMS_ERROR_LOG(fims::to_string(pos) + "!<" + |
|
| 265 |
fims::to_string(this->size())); |
|
| 266 |
return NULL; |
|
| 267 |
} |
|
| 268 | 1x |
return Rcpp::wrap(this->storage_m->at(pos - 1)); |
| 269 |
} |
|
| 270 | ||
| 271 |
/** |
|
| 272 |
* @brief An internal accessor for calling a position of a ParameterVector |
|
| 273 |
* from R. |
|
| 274 |
* @param pos An integer specifying the position of the ParameterVector |
|
| 275 |
* you want returned. The first position is one and the last position is |
|
| 276 |
* the same as the size of the ParameterVector. |
|
| 277 |
*/ |
|
| 278 | 29329x |
Parameter& get(size_t pos) {
|
| 279 | 29329x |
if (pos >= this->storage_m->size()) {
|
| 280 | 1x |
throw std::invalid_argument("ParameterVector: Index out of range");
|
| 281 |
} |
|
| 282 | 29328x |
return (this->storage_m->at(pos)); |
| 283 |
} |
|
| 284 | ||
| 285 |
/** |
|
| 286 |
* @brief An internal setter for setting a position of a ParameterVector |
|
| 287 |
* from R. |
|
| 288 |
* @param pos An integer specifying the position of the ParameterVector |
|
| 289 |
* you want to set. The first position is one and the last position is the |
|
| 290 |
* same as the size of the ParameterVector. |
|
| 291 |
* @param p A numeric value specifying the value to set position `pos` to |
|
| 292 |
* in the ParameterVector. |
|
| 293 |
*/ |
|
| 294 | 21490x |
void set(size_t pos, const Parameter& p) { this->storage_m->at(pos) = p; }
|
| 295 | ||
| 296 |
/** |
|
| 297 |
* @brief Returns the size of a ParameterVector. |
|
| 298 |
*/ |
|
| 299 | 82194x |
size_t size() { return this->storage_m->size(); }
|
| 300 | ||
| 301 |
/** |
|
| 302 |
* @brief Resizes a ParameterVector to the desired length. |
|
| 303 |
* @param size An integer specifying the desired length for the |
|
| 304 |
* ParameterVector to be resized to. |
|
| 305 |
*/ |
|
| 306 | 532x |
void resize(size_t size) { this->storage_m->resize(size); }
|
| 307 | ||
| 308 |
/** |
|
| 309 |
* @brief Sets all Parameters within a ParameterVector as estimable. |
|
| 310 |
* |
|
| 311 |
* @param estimable A boolean specifying if all Parameters within the |
|
| 312 |
* ParameterVector should be estimated within the model. A value of true |
|
| 313 |
* leads to all Parameters being estimated. |
|
| 314 |
*/ |
|
| 315 | 84x |
void set_all_estimable(bool estimable) {
|
| 316 | 12971x |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 317 | 12887x |
if (estimable) {
|
| 318 | 1602x |
this->storage_m->at(i).estimation_type_m.set("fixed_effects");
|
| 319 |
} else {
|
|
| 320 | 37059x |
this->storage_m->at(i).estimation_type_m.set("constant");
|
| 321 |
} |
|
| 322 |
} |
|
| 323 |
} |
|
| 324 | ||
| 325 |
/** |
|
| 326 |
* @brief Sets all Parameters within a ParameterVector as random effects. |
|
| 327 |
* |
|
| 328 |
* @param random A boolean specifying if all Parameters within the |
|
| 329 |
* ParameterVector should be designated as random effects. A value of true |
|
| 330 |
* leads to all Parameters being random effects. |
|
| 331 |
*/ |
|
| 332 | 36x |
void set_all_random(bool random) {
|
| 333 | 8984x |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 334 | 8948x |
if (random) {
|
| 335 | 348x |
this->storage_m->at(i).estimation_type_m.set("random_effects");
|
| 336 |
} else {
|
|
| 337 | 26496x |
this->storage_m->at(i).estimation_type_m.set("constant");
|
| 338 |
} |
|
| 339 |
} |
|
| 340 |
} |
|
| 341 | ||
| 342 |
/** |
|
| 343 |
* @brief Sets the value of all Parameters in the ParameterVector to the |
|
| 344 |
* provided value. |
|
| 345 |
* |
|
| 346 |
* @param value A double specifying the value to set all Parameters to |
|
| 347 |
* within the ParameterVector. |
|
| 348 |
*/ |
|
| 349 | 1x |
void fill(double value) {
|
| 350 | 11x |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 351 | 10x |
storage_m->at(i).initial_value_m = value; |
| 352 |
} |
|
| 353 |
} |
|
| 354 | ||
| 355 |
/** |
|
| 356 |
* @brief Assigns the given values to the minimum value of all elements in |
|
| 357 |
* the vector. |
|
| 358 |
* |
|
| 359 |
* @param value The value to be assigned. |
|
| 360 |
*/ |
|
| 361 |
void fill_min(double value) {
|
|
| 362 |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
|
| 363 |
storage_m->at(i).min_m = value; |
|
| 364 |
} |
|
| 365 |
} |
|
| 366 | ||
| 367 |
/** |
|
| 368 |
* @brief Assigns the given values to the maximum value of all elements in |
|
| 369 |
* the vector. |
|
| 370 |
* |
|
| 371 |
* @param value The value to be assigned. |
|
| 372 |
*/ |
|
| 373 |
void fill_max(double value) {
|
|
| 374 |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
|
| 375 |
storage_m->at(i).max_m = value; |
|
| 376 |
} |
|
| 377 |
} |
|
| 378 | ||
| 379 |
/** |
|
| 380 |
* @brief The printing methods for a ParameterVector. |
|
| 381 |
* |
|
| 382 |
*/ |
|
| 383 | ! |
void show() {
|
| 384 | ! |
Rcpp::Rcout << this->storage_m->data() << "\n"; |
| 385 | ||
| 386 | ! |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 387 | ! |
Rcpp::Rcout << storage_m->at(i) << " "; |
| 388 |
} |
|
| 389 |
} |
|
| 390 |
}; |
|
| 391 |
uint32_t ParameterVector::id_g = 0; |
|
| 392 | ||
| 393 |
/** |
|
| 394 |
* @brief Output for std::ostream& for a ParameterVector. |
|
| 395 |
* |
|
| 396 |
* @param out The stream. |
|
| 397 |
* @param v A ParameterVector. |
|
| 398 |
* @return std::ostream& |
|
| 399 |
*/ |
|
| 400 | 215x |
std::ostream& operator<<(std::ostream& out, ParameterVector& v) {
|
| 401 | 215x |
out << "["; |
| 402 | 215x |
size_t size = v.size(); |
| 403 | 11615x |
for (size_t i = 0; i < size - 1; i++) {
|
| 404 | 11400x |
out << v[i] << ", "; |
| 405 |
} |
|
| 406 | 215x |
out << v[size - 1] << "]"; |
| 407 | 215x |
return out; |
| 408 |
} |
|
| 409 | ||
| 410 |
/** |
|
| 411 |
* @brief An Rcpp interface class that defines the RealVector class. |
|
| 412 |
* |
|
| 413 |
* @details An Rcpp interface class that defines the interface between R and |
|
| 414 |
* C++ for a real vector type. Underlying values are held in a shared pointer |
|
| 415 |
* and are carried over to any copies of this vector. |
|
| 416 |
*/ |
|
| 417 |
class RealVector {
|
|
| 418 |
public: |
|
| 419 |
/** |
|
| 420 |
* @brief The static ID of the RealVector object. |
|
| 421 |
*/ |
|
| 422 |
static uint32_t id_g; |
|
| 423 |
/** |
|
| 424 |
* @brief real storage. |
|
| 425 |
*/ |
|
| 426 |
std::shared_ptr<std::vector<double>> storage_m; |
|
| 427 |
/** |
|
| 428 |
* @brief The local ID of the RealVector object. |
|
| 429 |
*/ |
|
| 430 |
uint32_t id_m; |
|
| 431 | ||
| 432 |
/** |
|
| 433 |
* @brief The constructor. |
|
| 434 |
*/ |
|
| 435 | 536x |
RealVector() {
|
| 436 | 536x |
this->id_m = RealVector::id_g++; |
| 437 | 536x |
this->storage_m = std::make_shared<std::vector<double>>(); |
| 438 | 536x |
this->storage_m->resize(1); |
| 439 |
} |
|
| 440 | ||
| 441 |
/** |
|
| 442 |
* @brief The constructor. |
|
| 443 |
*/ |
|
| 444 | 39483x |
RealVector(const RealVector& other) |
| 445 | 39483x |
: storage_m(other.storage_m), id_m(other.id_m) {}
|
| 446 | ||
| 447 |
/** |
|
| 448 |
* @brief The constructor. |
|
| 449 |
*/ |
|
| 450 | 39x |
RealVector(size_t size) {
|
| 451 | 39x |
this->id_m = RealVector::id_g++; |
| 452 | 39x |
this->storage_m = std::make_shared<std::vector<double>>(); |
| 453 | 39x |
this->storage_m->resize(size); |
| 454 |
} |
|
| 455 | ||
| 456 |
/** |
|
| 457 |
* @brief The constructor for initializing a real vector. |
|
| 458 |
* @param x A numeric vector. |
|
| 459 |
* @param size The number of elements to copy over. |
|
| 460 |
*/ |
|
| 461 | ! |
RealVector(Rcpp::NumericVector x, size_t size) {
|
| 462 | ! |
this->id_m = RealVector::id_g++; |
| 463 | ! |
this->storage_m = std::make_shared<std::vector<double>>(); |
| 464 | ! |
this->resize(x.size()); |
| 465 | ! |
for (size_t i = 0; i < x.size(); i++) {
|
| 466 | ! |
storage_m->at(i) = x[i]; |
| 467 |
} |
|
| 468 |
} |
|
| 469 | ||
| 470 |
/** |
|
| 471 |
* @brief The constructor for initializing a real vector. |
|
| 472 |
* @param v A vector of doubles. |
|
| 473 |
*/ |
|
| 474 |
RealVector(const fims::Vector<double>& v) {
|
|
| 475 |
this->id_m = RealVector::id_g++; |
|
| 476 |
this->storage_m = std::make_shared<std::vector<double>>(); |
|
| 477 |
this->storage_m->resize(v.size()); |
|
| 478 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 479 |
storage_m->at(i) = v[i]; |
|
| 480 |
} |
|
| 481 |
} |
|
| 482 | ||
| 483 |
/** |
|
| 484 |
* @brief Destroy the real Vector object. |
|
| 485 |
* |
|
| 486 |
*/ |
|
| 487 | 157758x |
virtual ~RealVector() {}
|
| 488 | ||
| 489 |
/** |
|
| 490 |
* @brief |
|
| 491 |
* |
|
| 492 |
* @param v |
|
| 493 |
* @return RealVector& |
|
| 494 |
*/ |
|
| 495 | 42x |
RealVector& operator=(const Rcpp::NumericVector& v) {
|
| 496 | 42x |
this->storage_m->resize(v.size()); |
| 497 | 21762x |
for (size_t i = 0; i < v.size(); i++) {
|
| 498 | 21720x |
storage_m->at(i) = v[i]; |
| 499 |
} |
|
| 500 | 42x |
return *this; |
| 501 |
} |
|
| 502 | ||
| 503 |
/** |
|
| 504 |
* @brief Gets the ID of the RealVector object. |
|
| 505 |
*/ |
|
| 506 | ! |
virtual uint32_t get_id() { return this->id_m; }
|
| 507 | ||
| 508 |
/** |
|
| 509 |
* @brief |
|
| 510 |
* |
|
| 511 |
* @param orig |
|
| 512 |
*/ |
|
| 513 | ! |
void fromRVector(const Rcpp::NumericVector& orig) {
|
| 514 | ! |
this->storage_m->resize(orig.size()); |
| 515 | ! |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 516 | ! |
this->storage_m->at(i) = orig[i]; |
| 517 |
} |
|
| 518 |
} |
|
| 519 | ||
| 520 |
/** |
|
| 521 |
* @brief |
|
| 522 |
* |
|
| 523 |
* @return Rcpp::NumericVector |
|
| 524 |
*/ |
|
| 525 | 2x |
Rcpp::NumericVector toRVector() {
|
| 526 | 2x |
Rcpp::NumericVector ret(this->storage_m->size()); |
| 527 | 1052x |
for (size_t i = 0; i < this->size(); i++) {
|
| 528 | 1050x |
ret[i] = this->storage_m->at(i); |
| 529 |
} |
|
| 530 | ||
| 531 | 2x |
return ret; |
| 532 |
} |
|
| 533 | ||
| 534 |
/** |
|
| 535 |
* @brief The accessor where the first index starts is zero. |
|
| 536 |
* @param pos The position of the RealVector that you want returned. |
|
| 537 |
*/ |
|
| 538 | 280394x |
inline double& operator[](size_t pos) { return this->storage_m->at(pos); }
|
| 539 | ||
| 540 |
/** |
|
| 541 |
* @brief The accessor where the first index starts at one. This function is |
|
| 542 |
* for calling accessing from R. |
|
| 543 |
* @param pos The position of the ParameterVector that you want returned. |
|
| 544 |
*/ |
|
| 545 | ! |
SEXP at(R_xlen_t pos) {
|
| 546 | ! |
if (static_cast<size_t>(pos) == 0 || |
| 547 | ! |
static_cast<size_t>(pos) > this->storage_m->size()) {
|
| 548 | ! |
throw std::invalid_argument("RealVector: Index out of range");
|
| 549 |
FIMS_ERROR_LOG(fims::to_string(pos) + "!<" + |
|
| 550 |
fims::to_string(this->size())); |
|
| 551 |
return NULL; |
|
| 552 |
} |
|
| 553 | ! |
return Rcpp::wrap(this->storage_m->at(pos - 1)); |
| 554 |
} |
|
| 555 | ||
| 556 |
/** |
|
| 557 |
* @brief An internal accessor for calling a position of a RealVector |
|
| 558 |
* from R. |
|
| 559 |
* @param pos An integer specifying the position of the RealVector |
|
| 560 |
* you want returned. The first position is one and the last position is |
|
| 561 |
* the same as the size of the RealVector. |
|
| 562 |
*/ |
|
| 563 | 2x |
double& get(size_t pos) {
|
| 564 | 2x |
if (pos >= this->storage_m->size()) {
|
| 565 | ! |
throw std::invalid_argument("RealVector: Index out of range");
|
| 566 |
} |
|
| 567 | 2x |
return (this->storage_m->at(pos)); |
| 568 |
} |
|
| 569 | ||
| 570 |
/** |
|
| 571 |
* @brief An internal setter for setting a position of a RealVector |
|
| 572 |
* from R. |
|
| 573 |
* @param pos An integer specifying the position of the RealVector |
|
| 574 |
* you want to set. The first position is one and the last position is the |
|
| 575 |
* same as the size of the RealVector. |
|
| 576 |
* @param p A numeric value specifying the value to set position `pos` to |
|
| 577 |
* in the RealVector. |
|
| 578 |
*/ |
|
| 579 | 38747x |
void set(size_t pos, const double& p) { this->storage_m->at(pos) = p; }
|
| 580 | ||
| 581 |
/** |
|
| 582 |
* @brief Returns the size of a RealVector. |
|
| 583 |
*/ |
|
| 584 | 93451x |
size_t size() { return this->storage_m->size(); }
|
| 585 | ||
| 586 |
/** |
|
| 587 |
* @brief Resizes a RealVector to the desired length. |
|
| 588 |
* @param size An integer specifying the desired length for the |
|
| 589 |
* RealVector to be resized to. |
|
| 590 |
*/ |
|
| 591 | 336x |
void resize(size_t size) { this->storage_m->resize(size); }
|
| 592 | ||
| 593 |
/** |
|
| 594 |
* @brief Sets the value of all elements in the RealVector to the |
|
| 595 |
* provided value. |
|
| 596 |
* |
|
| 597 |
* @param value A double specifying the value to set all elements to |
|
| 598 |
* within the RealVector. |
|
| 599 |
*/ |
|
| 600 |
void fill(double value) {
|
|
| 601 |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
|
| 602 |
storage_m->at(i) = value; |
|
| 603 |
} |
|
| 604 |
} |
|
| 605 | ||
| 606 |
/** |
|
| 607 |
* @brief The printing methods for a RealVector. |
|
| 608 |
* |
|
| 609 |
*/ |
|
| 610 | ! |
void show() {
|
| 611 | ! |
Rcpp::Rcout << this->storage_m->data() << "\n"; |
| 612 | ||
| 613 | ! |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 614 | ! |
Rcpp::Rcout << storage_m->at(i) << " "; |
| 615 |
} |
|
| 616 |
} |
|
| 617 |
}; |
|
| 618 |
uint32_t RealVector::id_g = 0; |
|
| 619 | ||
| 620 |
/** |
|
| 621 |
*@brief Base class for all interface objects. |
|
| 622 |
*/ |
|
| 623 |
class FIMSRcppInterfaceBase {
|
|
| 624 |
public: |
|
| 625 |
/** |
|
| 626 |
* @brief Is the object already finalized? The default is false. |
|
| 627 |
*/ |
|
| 628 |
bool finalized = false; |
|
| 629 |
/** |
|
| 630 |
* @brief FIMS interface object vectors. |
|
| 631 |
*/ |
|
| 632 |
static std::vector<std::shared_ptr<FIMSRcppInterfaceBase>> |
|
| 633 |
fims_interface_objects; |
|
| 634 | ||
| 635 |
/** |
|
| 636 |
* @brief A virtual method to inherit to add objects to the TMB model. |
|
| 637 |
*/ |
|
| 638 | ! |
virtual bool add_to_fims_tmb() {
|
| 639 |
Rcpp::Rcout << "fims_rcpp_interface_base::add_to_fims_tmb(): Not yet " |
|
| 640 | ! |
"implemented.\n"; |
| 641 | ! |
return false; |
| 642 |
} |
|
| 643 | ||
| 644 |
/** |
|
| 645 |
* @brief Extracts derived quantities back to the Rcpp interface object from |
|
| 646 |
* the Information object. |
|
| 647 |
*/ |
|
| 648 | 81x |
virtual void finalize() {}
|
| 649 | ||
| 650 |
/** |
|
| 651 |
* @brief Convert the data to json representation for the output. |
|
| 652 |
*/ |
|
| 653 | ! |
virtual std::string to_json() {
|
| 654 | ! |
FIMS_WARNING_LOG("Method not yet defined.");
|
| 655 | ! |
return "{\"name\": \"not yet implemented\"}";
|
| 656 |
} |
|
| 657 |
/** |
|
| 658 |
* @brief Method to extract standard error values from the se_values |
|
| 659 |
* working map. |
|
| 660 |
*/ |
|
| 661 | 215x |
void get_se_values(std::string name, |
| 662 |
std::map<std::string, std::vector<double>>& se_values, |
|
| 663 |
fims::Vector<double>& values) {
|
|
| 664 | 215x |
auto se_vals = se_values.find(name); |
| 665 | 215x |
if (se_vals != se_values.end()) {
|
| 666 | 215x |
std::vector<double>& se_vals_vector = (*se_vals).second; |
| 667 |
std::vector<double> uncertainty_std( |
|
| 668 | 215x |
se_vals_vector.begin(), se_vals_vector.begin() + values.size()); |
| 669 | 430x |
std::vector<double> temp(se_vals_vector.begin() + values.size(), |
| 670 | 430x |
se_vals_vector.end()); |
| 671 | 215x |
se_vals_vector = temp; |
| 672 | 215x |
fims::Vector<double> uncertainty(uncertainty_std); |
| 673 | 215x |
values = uncertainty; |
| 674 |
} else {
|
|
| 675 | ! |
std::fill(values.begin(), values.end(), -999); |
| 676 |
} |
|
| 677 |
} |
|
| 678 | ||
| 679 |
/** |
|
| 680 |
* @brief Set uncertainty values for the interface object. |
|
| 681 |
* |
|
| 682 |
* @details This virtual method is intended to be overridden in derived |
|
| 683 |
* classes to set uncertainty (standard error) values |
|
| 684 |
* for model parameters or quantities using the provided map of standard |
|
| 685 |
* error values. The default implementation logs a warning. |
|
| 686 |
* |
|
| 687 |
* @param se_values A map from parameter names to vectors of standard error |
|
| 688 |
* values. |
|
| 689 |
*/ |
|
| 690 | 13x |
virtual void set_uncertainty( |
| 691 |
std::map<std::string, std::vector<double>>& se_values) {
|
|
| 692 | 26x |
FIMS_WARNING_LOG("Method not yet defined.");
|
| 693 |
} |
|
| 694 | ||
| 695 |
/** |
|
| 696 |
* @brief Report the parameter value as a string. |
|
| 697 |
* |
|
| 698 |
* @param value |
|
| 699 |
* @return std::string |
|
| 700 |
*/ |
|
| 701 | 45754x |
std::string value_to_string(double value) {
|
| 702 | 45754x |
std::stringstream ss; |
| 703 | 45754x |
if (value == std::numeric_limits<double>::infinity()) {
|
| 704 | ! |
ss << "\"Infinity\""; |
| 705 | 45754x |
} else if (value == -std::numeric_limits<double>::infinity()) {
|
| 706 | ! |
ss << "\"-Infinity\""; |
| 707 | 45754x |
} else if (value != value) {
|
| 708 | ! |
ss << "\"NaN\""; |
| 709 |
} else {
|
|
| 710 | 45754x |
ss << value; |
| 711 |
} |
|
| 712 | 91508x |
return ss.str(); |
| 713 |
} |
|
| 714 |
/** |
|
| 715 |
* @brief Make a string of dimensions for the model. |
|
| 716 |
*/ |
|
| 717 |
std::string make_dimensions(uint32_t start, uint32_t end, uint32_t rep = 1) {
|
|
| 718 |
std::stringstream ss; |
|
| 719 | ||
| 720 |
for (size_t i = 0; i < rep; i++) {
|
|
| 721 |
for (size_t j = start; j < end; j++) {
|
|
| 722 |
ss << j << ", "; |
|
| 723 |
} |
|
| 724 |
if (i < (rep - 1)) {
|
|
| 725 |
ss << end << ", "; |
|
| 726 |
} else {
|
|
| 727 |
ss << end; |
|
| 728 |
} |
|
| 729 |
} |
|
| 730 |
return ss.str(); |
|
| 731 |
} |
|
| 732 |
}; |
|
| 733 |
std::vector<std::shared_ptr<FIMSRcppInterfaceBase>> |
|
| 734 |
FIMSRcppInterfaceBase::fims_interface_objects; |
|
| 735 | ||
| 736 |
#endif |
| 1 |
/** |
|
| 2 |
* @file rcpp_math.hpp |
|
| 3 |
* @brief The Rcpp interface to declare different mathematical functions that |
|
| 4 |
* are written in C++ but can be used within R. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_MATH_HPP |
|
| 10 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_MATH_HPP |
|
| 11 | ||
| 12 |
#include "rcpp_interface_base.hpp" |
|
| 13 |
#include "../../../common/fims_math.hpp" |
|
| 14 | ||
| 15 |
/** |
|
| 16 |
* @brief A rcpp interface to the logit function. |
|
| 17 |
* |
|
| 18 |
* @param a Lower bound of the logit function, typically 0.0. |
|
| 19 |
* @param b Upper bound of the logit function, typically 1.0. |
|
| 20 |
* @param x A single numeric value (double) to be transformed on the real line. |
|
| 21 |
* @return A double in real space rather than the bounded space. |
|
| 22 |
*/ |
|
| 23 | 5x |
double logit_rcpp(double a, double b, double x) {
|
| 24 | 5x |
return fims_math::logit<double>(a, b, x); |
| 25 |
} |
|
| 26 | ||
| 27 |
/** |
|
| 28 |
* @brief A rcpp interface to the inverse-logit function. |
|
| 29 |
* |
|
| 30 |
* @param a Lower bound of the logit function, typically 0.0. |
|
| 31 |
* @param b Upper bound of the logit function, typically 1.0. |
|
| 32 |
* @param logit_x A single numeric value (double) in real space. |
|
| 33 |
* @return A double in the bounded space rather than real space. |
|
| 34 |
*/ |
|
| 35 | 5x |
double inv_logit_rcpp(double a, double b, double logit_x) {
|
| 36 | 5x |
return fims_math::inv_logit<double>(a, b, logit_x); |
| 37 |
} |
|
| 38 | ||
| 39 |
#endif |
| 1 |
/** |
|
| 2 |
* @file rcpp_maturity.hpp |
|
| 3 |
* @brief The Rcpp interface to declare different maturity options, e.g., |
|
| 4 |
* logistic. Allows for the use of methods::new() in R. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_MATURITY_HPP |
|
| 10 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_MATURITY_HPP |
|
| 11 | ||
| 12 |
#include "../../../population_dynamics/maturity/maturity.hpp" |
|
| 13 |
#include "rcpp_interface_base.hpp" |
|
| 14 | ||
| 15 |
/** |
|
| 16 |
* @brief Rcpp interface that serves as the parent class for Rcpp maturity |
|
| 17 |
* interfaces. This type should be inherited and not called from R directly. |
|
| 18 |
*/ |
|
| 19 |
class MaturityInterfaceBase : public FIMSRcppInterfaceBase {
|
|
| 20 |
public: |
|
| 21 |
/** |
|
| 22 |
* @brief The static id of the MaturityInterfaceBase object. |
|
| 23 |
*/ |
|
| 24 |
static uint32_t id_g; |
|
| 25 |
/** |
|
| 26 |
* @brief The local id of the MaturityInterfaceBase object. |
|
| 27 |
*/ |
|
| 28 |
uint32_t id; |
|
| 29 |
/** |
|
| 30 |
* @brief The map associating the IDs of MaturityInterfaceBase to the objects. |
|
| 31 |
* This is a live object, which is an object that has been created and lives |
|
| 32 |
* in memory. |
|
| 33 |
*/ |
|
| 34 |
static std::map<uint32_t, std::shared_ptr<MaturityInterfaceBase>> |
|
| 35 |
live_objects; |
|
| 36 | ||
| 37 |
/** |
|
| 38 |
* @brief The constructor. |
|
| 39 |
*/ |
|
| 40 | 21x |
MaturityInterfaceBase() {
|
| 41 | 21x |
this->id = MaturityInterfaceBase::id_g++; |
| 42 |
/* Create instance of map: key is id and value is pointer to |
|
| 43 |
MaturityInterfaceBase */ |
|
| 44 |
// MaturityInterfaceBase::live_objects[this->id] = this; |
|
| 45 |
} |
|
| 46 | ||
| 47 |
/** |
|
| 48 |
* @brief Construct a new Maturity Interface Base object |
|
| 49 |
* |
|
| 50 |
* @param other |
|
| 51 |
*/ |
|
| 52 | 21x |
MaturityInterfaceBase(const MaturityInterfaceBase& other) : id(other.id) {}
|
| 53 | ||
| 54 |
/** |
|
| 55 |
* @brief The destructor. |
|
| 56 |
*/ |
|
| 57 | 42x |
virtual ~MaturityInterfaceBase() {}
|
| 58 | ||
| 59 |
/** |
|
| 60 |
* @brief Get the ID for the child maturity interface objects to inherit. |
|
| 61 |
*/ |
|
| 62 |
virtual uint32_t get_id() = 0; |
|
| 63 | ||
| 64 |
/** |
|
| 65 |
* @brief A method for each child maturity interface object to inherit so |
|
| 66 |
* each maturity option can have an evaluate() function. |
|
| 67 |
*/ |
|
| 68 |
virtual double evaluate(double x) = 0; |
|
| 69 |
}; |
|
| 70 |
// static id of the MaturityInterfaceBase object |
|
| 71 |
uint32_t MaturityInterfaceBase::id_g = 1; |
|
| 72 |
// local id of the MaturityInterfaceBase object map relating the ID of the |
|
| 73 |
// MaturityInterfaceBase to the MaturityInterfaceBase objects |
|
| 74 |
std::map<uint32_t, std::shared_ptr<MaturityInterfaceBase>> |
|
| 75 |
MaturityInterfaceBase::live_objects; |
|
| 76 | ||
| 77 |
/** |
|
| 78 |
* @brief Rcpp interface for logistic maturity to instantiate the object from R: |
|
| 79 |
* logistic_maturity <- methods::new(logistic_maturity). |
|
| 80 |
*/ |
|
| 81 |
class LogisticMaturityInterface : public MaturityInterfaceBase {
|
|
| 82 |
public: |
|
| 83 |
/** |
|
| 84 |
* @brief The index value at which the response reaches 0.5. |
|
| 85 |
*/ |
|
| 86 |
ParameterVector inflection_point; |
|
| 87 |
/** |
|
| 88 |
* @brief The width of the curve at the inflection point. |
|
| 89 |
*/ |
|
| 90 |
ParameterVector slope; |
|
| 91 | ||
| 92 |
/** |
|
| 93 |
* @brief The constructor. |
|
| 94 |
*/ |
|
| 95 | 21x |
LogisticMaturityInterface() : MaturityInterfaceBase() {
|
| 96 | 21x |
MaturityInterfaceBase::live_objects[this->id] = |
| 97 | 42x |
std::make_shared<LogisticMaturityInterface>(*this); |
| 98 | 21x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 99 | 21x |
MaturityInterfaceBase::live_objects[this->id]); |
| 100 |
} |
|
| 101 | ||
| 102 |
/** |
|
| 103 |
* @brief Construct a new Logistic Maturity Interface object |
|
| 104 |
* |
|
| 105 |
* @param other |
|
| 106 |
*/ |
|
| 107 | 21x |
LogisticMaturityInterface(const LogisticMaturityInterface& other) |
| 108 | 21x |
: MaturityInterfaceBase(other), |
| 109 | 21x |
inflection_point(other.inflection_point), |
| 110 | 21x |
slope(other.slope) {}
|
| 111 | ||
| 112 |
/** |
|
| 113 |
* @brief The destructor. |
|
| 114 |
*/ |
|
| 115 | 126x |
virtual ~LogisticMaturityInterface() {}
|
| 116 | ||
| 117 |
/** |
|
| 118 |
* @brief Gets the ID of the interface base object. |
|
| 119 |
* @return The ID. |
|
| 120 |
*/ |
|
| 121 | 21x |
virtual uint32_t get_id() { return this->id; }
|
| 122 | ||
| 123 |
/** |
|
| 124 |
* @brief Evaluate maturity using the logistic function. |
|
| 125 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 126 |
* size in maturity). |
|
| 127 |
*/ |
|
| 128 | 1x |
virtual double evaluate(double x) {
|
| 129 | 1x |
fims_popdy::LogisticMaturity<double> LogisticMat; |
| 130 | 1x |
LogisticMat.inflection_point.resize(1); |
| 131 | 1x |
LogisticMat.inflection_point[0] = this->inflection_point[0].initial_value_m; |
| 132 | 1x |
LogisticMat.slope.resize(1); |
| 133 | 1x |
LogisticMat.slope[0] = this->slope[0].initial_value_m; |
| 134 | 2x |
return LogisticMat.evaluate(x); |
| 135 |
} |
|
| 136 | ||
| 137 |
/** |
|
| 138 |
* @brief Extracts derived quantities back to the Rcpp interface object from |
|
| 139 |
* the Information object. |
|
| 140 |
*/ |
|
| 141 | 13x |
virtual void finalize() {
|
| 142 | 13x |
if (this->finalized) {
|
| 143 |
// log warning that finalize has been called more than once. |
|
| 144 | ! |
FIMS_WARNING_LOG("Logistic Maturity " + fims::to_string(this->id) +
|
| 145 |
" has been finalized already."); |
|
| 146 |
} |
|
| 147 | ||
| 148 | 13x |
this->finalized = true; // indicate this has been called already |
| 149 | ||
| 150 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 151 | 13x |
fims_info::Information<double>::GetInstance(); |
| 152 | ||
| 153 | 13x |
fims_info::Information<double>::maturity_models_iterator it; |
| 154 | ||
| 155 |
// search for maturity in Information |
|
| 156 | 13x |
it = info->maturity_models.find(this->id); |
| 157 |
// if not found, just return |
|
| 158 | 13x |
if (it == info->maturity_models.end()) {
|
| 159 | ! |
FIMS_WARNING_LOG("Logistic Maturity " + fims::to_string(this->id) +
|
| 160 |
" not found in Information."); |
|
| 161 | ! |
return; |
| 162 |
} else {
|
|
| 163 |
std::shared_ptr<fims_popdy::LogisticMaturity<double>> mat = |
|
| 164 |
std::dynamic_pointer_cast<fims_popdy::LogisticMaturity<double>>( |
|
| 165 | 13x |
it->second); |
| 166 | ||
| 167 | 26x |
for (size_t i = 0; i < inflection_point.size(); i++) {
|
| 168 | 13x |
if (this->inflection_point[i].estimation_type_m.get() == "constant") {
|
| 169 | 13x |
this->inflection_point[i].final_value_m = |
| 170 | 13x |
this->inflection_point[i].initial_value_m; |
| 171 |
} else {
|
|
| 172 | ! |
this->inflection_point[i].final_value_m = mat->inflection_point[i]; |
| 173 |
} |
|
| 174 |
} |
|
| 175 | ||
| 176 | 26x |
for (size_t i = 0; i < slope.size(); i++) {
|
| 177 | 13x |
if (this->slope[i].estimation_type_m.get() == "constant") {
|
| 178 | 13x |
this->slope[i].final_value_m = this->slope[i].initial_value_m; |
| 179 |
} else {
|
|
| 180 | ! |
this->slope[i].final_value_m = mat->slope[i]; |
| 181 |
} |
|
| 182 |
} |
|
| 183 |
} |
|
| 184 |
} |
|
| 185 | ||
| 186 |
/** |
|
| 187 |
* @brief Set uncertainty values for logistic maturity parameters. |
|
| 188 |
* |
|
| 189 |
* @details Sets the standard error values for the inflection point and slope |
|
| 190 |
* parameters using the provided map. |
|
| 191 |
* @param se_values A map from parameter names to vectors of standard error |
|
| 192 |
* values. |
|
| 193 |
*/ |
|
| 194 | 13x |
virtual void set_uncertainty( |
| 195 |
std::map<std::string, std::vector<double>>& se_values) {
|
|
| 196 |
fims::Vector<double> inflection_point_uncertainty( |
|
| 197 | 13x |
this->inflection_point.size(), -999); |
| 198 | 13x |
fims::Vector<double> slope_uncertainty(this->slope.size(), -999); |
| 199 | 26x |
this->get_se_values("inflection_point", se_values,
|
| 200 |
inflection_point_uncertainty); |
|
| 201 | 26x |
this->get_se_values("slope", se_values, slope_uncertainty);
|
| 202 | ||
| 203 | 26x |
for (size_t i = 0; i < this->inflection_point.size(); i++) {
|
| 204 | 13x |
this->inflection_point[i].uncertainty_m = inflection_point_uncertainty[i]; |
| 205 |
} |
|
| 206 | 26x |
for (size_t i = 0; i < this->slope.size(); i++) {
|
| 207 | 13x |
this->slope[i].uncertainty_m = slope_uncertainty[i]; |
| 208 |
} |
|
| 209 |
} |
|
| 210 | ||
| 211 |
/** |
|
| 212 |
* @brief Converts the data to json representation for the output. |
|
| 213 |
* @return A string is returned specifying that the module relates to the |
|
| 214 |
* maturity interface with logistic maturity. It also returns the ID and the |
|
| 215 |
* parameters. This string is formatted for a json file. |
|
| 216 |
*/ |
|
| 217 | 13x |
virtual std::string to_json() {
|
| 218 | 13x |
std::stringstream ss; |
| 219 | 13x |
ss << "{\n";
|
| 220 | 13x |
ss << " \"module_name\": \"Maturity\",\n"; |
| 221 | 13x |
ss << " \"module_type\": \"Logistic\",\n"; |
| 222 | 13x |
ss << " \"module_id\": " << this->id << ",\n"; |
| 223 | ||
| 224 | 13x |
ss << " \"parameters\": [\n{\n";
|
| 225 | 13x |
ss << " \"name\": \"inflection_point\",\n"; |
| 226 | 13x |
ss << " \"id\":" << this->inflection_point.id_m << ",\n"; |
| 227 | 13x |
ss << " \"type\": \"vector\",\n"; |
| 228 | 13x |
ss << " \"dimensionality\": {\n";
|
| 229 | 13x |
ss << " \"header\": [null],\n"; |
| 230 | 13x |
ss << " \"dimensions\": [1]\n},\n"; |
| 231 | 13x |
ss << " \"values\":" << this->inflection_point << "},\n "; |
| 232 | ||
| 233 | 13x |
ss << "{\n";
|
| 234 | 13x |
ss << " \"name\": \"slope\",\n"; |
| 235 | 13x |
ss << " \"id\":" << this->slope.id_m << ",\n"; |
| 236 | 13x |
ss << " \"type\": \"vector\",\n"; |
| 237 | 13x |
ss << " \"dimensionality\": {\n";
|
| 238 | 13x |
ss << " \"header\": [null],\n"; |
| 239 | 13x |
ss << " \"dimensions\": [1]\n},\n"; |
| 240 | 13x |
ss << " \"values\":" << this->slope << "}]\n"; |
| 241 | ||
| 242 | 13x |
ss << "}"; |
| 243 | ||
| 244 | 26x |
return ss.str(); |
| 245 |
} |
|
| 246 | ||
| 247 |
#ifdef TMB_MODEL |
|
| 248 | ||
| 249 |
template <typename Type> |
|
| 250 | 76x |
bool add_to_fims_tmb_internal() {
|
| 251 | 76x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 252 |
fims_info::Information<Type>::GetInstance(); |
|
| 253 | ||
| 254 | 76x |
std::shared_ptr<fims_popdy::LogisticMaturity<Type>> maturity = |
| 255 |
std::make_shared<fims_popdy::LogisticMaturity<Type>>(); |
|
| 256 | ||
| 257 |
// set relative info |
|
| 258 | 76x |
maturity->id = this->id; |
| 259 | 76x |
std::stringstream ss; |
| 260 | 76x |
maturity->inflection_point.resize(this->inflection_point.size()); |
| 261 | 152x |
for (size_t i = 0; i < this->inflection_point.size(); i++) {
|
| 262 | 76x |
maturity->inflection_point[i] = this->inflection_point[i].initial_value_m; |
| 263 | 76x |
if (this->inflection_point[i].estimation_type_m.get() == |
| 264 |
"fixed_effects") {
|
|
| 265 | ! |
ss.str("");
|
| 266 | ! |
ss << "Maturity." << this->id << ".inflection_point." |
| 267 | ! |
<< this->inflection_point[i].id_m; |
| 268 | ! |
info->RegisterParameterName(ss.str()); |
| 269 | ! |
info->RegisterParameter(maturity->inflection_point[i]); |
| 270 |
} |
|
| 271 | 76x |
if (this->inflection_point[i].estimation_type_m.get() == |
| 272 |
"random_effects") {
|
|
| 273 | ! |
ss.str("");
|
| 274 | ! |
ss << "Maturity." << this->id << ".inflection_point." |
| 275 | ! |
<< this->inflection_point[i].id_m; |
| 276 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 277 | ! |
info->RegisterRandomEffect(maturity->inflection_point[i]); |
| 278 |
} |
|
| 279 |
} |
|
| 280 | ||
| 281 | 76x |
maturity->slope.resize(this->slope.size()); |
| 282 | 152x |
for (size_t i = 0; i < this->slope.size(); i++) {
|
| 283 | 76x |
maturity->slope[i] = this->slope[i].initial_value_m; |
| 284 | 76x |
if (this->slope[i].estimation_type_m.get() == "fixed_effects") {
|
| 285 | ! |
ss.str("");
|
| 286 | ! |
ss << "Maturity." << this->id << ".slope." << this->slope[i].id_m; |
| 287 | ! |
info->RegisterParameterName(ss.str()); |
| 288 | ! |
info->RegisterParameter(maturity->slope[i]); |
| 289 |
} |
|
| 290 | 76x |
if (this->slope[i].estimation_type_m.get() == "random_effects") {
|
| 291 | ! |
ss.str("");
|
| 292 | ! |
ss << "Maturity." << this->id << ".slope." << this->slope[i].id_m; |
| 293 | ! |
info->RegisterRandomEffect(maturity->slope[i]); |
| 294 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 295 |
} |
|
| 296 |
} |
|
| 297 | ||
| 298 |
// add to Information |
|
| 299 | 76x |
info->maturity_models[maturity->id] = maturity; |
| 300 | ||
| 301 | 76x |
return true; |
| 302 |
} |
|
| 303 | ||
| 304 |
/** |
|
| 305 |
* @brief Adds the parameters to the TMB model. |
|
| 306 |
* @return A boolean of true. |
|
| 307 |
*/ |
|
| 308 | 19x |
virtual bool add_to_fims_tmb() {
|
| 309 |
#ifdef TMBAD_FRAMEWORK |
|
| 310 | 19x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 311 | 19x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 312 |
#else |
|
| 313 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 314 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 315 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 316 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 317 |
#endif |
|
| 318 | ||
| 319 | 19x |
return true; |
| 320 |
} |
|
| 321 | ||
| 322 |
#endif |
|
| 323 |
}; |
|
| 324 | ||
| 325 |
#endif |
| 1 |
/** |
|
| 2 |
* @file rcpp_models.hpp |
|
| 3 |
* @brief The Rcpp interface to declare different types of models. Allows |
|
| 4 |
* for the use of methods::new() in R. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_MODELS_HPP |
|
| 10 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_MODELS_HPP |
|
| 11 | ||
| 12 |
#include <set> |
|
| 13 |
#include "../../../common/def.hpp" |
|
| 14 |
#include "../../../models/fisheries_models.hpp" |
|
| 15 |
#include "../../../utilities/fims_json.hpp" |
|
| 16 |
#include "rcpp_population.hpp" |
|
| 17 | ||
| 18 |
#include "rcpp_interface_base.hpp" |
|
| 19 |
#include "rcpp_population.hpp" |
|
| 20 |
#include "rcpp_fleet.hpp" |
|
| 21 |
#include "rcpp_maturity.hpp" |
|
| 22 |
#include "rcpp_recruitment.hpp" |
|
| 23 |
#include "rcpp_selectivity.hpp" |
|
| 24 |
#include <valarray> |
|
| 25 |
#include <cmath> |
|
| 26 |
#include <mutex> |
|
| 27 | ||
| 28 |
/** |
|
| 29 |
* @brief The FisheryModelInterfaceBase class is the base class for all fishery |
|
| 30 |
* models in the FIMS Rcpp interface. It inherits from the |
|
| 31 |
* FIMSRcppInterfaceBase. |
|
| 32 |
* |
|
| 33 |
*/ |
|
| 34 |
class FisheryModelInterfaceBase : public FIMSRcppInterfaceBase {
|
|
| 35 |
public: |
|
| 36 |
/** |
|
| 37 |
* @brief The static id of the FleetInterfaceBase object. |
|
| 38 |
*/ |
|
| 39 |
static uint32_t id_g; |
|
| 40 |
/** |
|
| 41 |
* @brief The local id of the FleetInterfaceBase object. |
|
| 42 |
*/ |
|
| 43 |
uint32_t id; |
|
| 44 |
/** |
|
| 45 |
* @brief The map associating the IDs of FleetInterfaceBase to the objects. |
|
| 46 |
* This is a live object, which is an object that has been created and lives |
|
| 47 |
* in memory. |
|
| 48 |
*/ |
|
| 49 |
static std::map<uint32_t, std::shared_ptr<FisheryModelInterfaceBase>> |
|
| 50 |
live_objects; |
|
| 51 | ||
| 52 |
/** |
|
| 53 |
* @brief The constructor. |
|
| 54 |
*/ |
|
| 55 | 18x |
FisheryModelInterfaceBase() {
|
| 56 | 18x |
this->id = FisheryModelInterfaceBase::id_g++; |
| 57 |
/* Create instance of map: key is id and value is pointer to |
|
| 58 |
FleetInterfaceBase */ |
|
| 59 |
// FisheryModelInterfaceBase::live_objects[this->id] = this; |
|
| 60 |
} |
|
| 61 | ||
| 62 |
/** |
|
| 63 |
* @brief Construct a new Data Interface Base object |
|
| 64 |
* |
|
| 65 |
* @param other |
|
| 66 |
*/ |
|
| 67 | 18x |
FisheryModelInterfaceBase(const FisheryModelInterfaceBase &other) |
| 68 | 18x |
: id(other.id) {}
|
| 69 | ||
| 70 |
/** |
|
| 71 |
* @brief The destructor. |
|
| 72 |
*/ |
|
| 73 | 36x |
virtual ~FisheryModelInterfaceBase() {}
|
| 74 | ||
| 75 | ! |
virtual std::string to_json() {
|
| 76 | ! |
return "std::string to_json() not yet implemented."; |
| 77 |
} |
|
| 78 | ||
| 79 |
/** |
|
| 80 |
* @brief A function to calculate reference points for the fishery model. |
|
| 81 |
* |
|
| 82 |
* @return Rcpp::List |
|
| 83 |
*/ |
|
| 84 | ! |
virtual Rcpp::List calculate_reference_points() {
|
| 85 | ! |
Rcpp::List result; |
| 86 | ! |
return result; |
| 87 |
} |
|
| 88 | ||
| 89 |
/** |
|
| 90 |
* @brief Get the ID for the child fleet interface objects to inherit. |
|
| 91 |
*/ |
|
| 92 |
virtual uint32_t get_id() = 0; |
|
| 93 |
}; |
|
| 94 |
// static id of the FleetInterfaceBase object |
|
| 95 |
uint32_t FisheryModelInterfaceBase::id_g = 1; |
|
| 96 | ||
| 97 |
// FleetInterfaceBase to the FleetInterfaceBase objects |
|
| 98 |
std::map<uint32_t, std::shared_ptr<FisheryModelInterfaceBase>> |
|
| 99 |
FisheryModelInterfaceBase::live_objects; |
|
| 100 | ||
| 101 |
/** |
|
| 102 |
* @brief The CatchAtAgeInterface class is used to interface with the |
|
| 103 |
* CatchAtAge model. It inherits from the FisheryModelInterfaceBase class. |
|
| 104 |
*/ |
|
| 105 |
class CatchAtAgeInterface : public FisheryModelInterfaceBase {
|
|
| 106 |
/** |
|
| 107 |
* @brief The set of population ids that this catch at age model operates on. |
|
| 108 |
*/ |
|
| 109 |
std::shared_ptr<std::set<uint32_t>> population_ids; |
|
| 110 |
/** |
|
| 111 |
* @brief Iterator for population ids. |
|
| 112 |
*/ |
|
| 113 |
typedef typename std::set<uint32_t>::iterator population_id_iterator; |
|
| 114 | ||
| 115 |
/** |
|
| 116 |
* @brief A private working map of standard error values for all |
|
| 117 |
* concatenated derived quantities. Elements are extracted in the |
|
| 118 |
* to_json method. |
|
| 119 |
*/ |
|
| 120 |
std::map<std::string, std::vector<double>> se_values; |
|
| 121 | ||
| 122 |
public: |
|
| 123 |
/** |
|
| 124 |
* @brief The constructor. |
|
| 125 |
*/ |
|
| 126 | 18x |
CatchAtAgeInterface() : FisheryModelInterfaceBase() {
|
| 127 | 18x |
this->population_ids = std::make_shared<std::set<uint32_t>>(); |
| 128 |
std::shared_ptr<CatchAtAgeInterface> caa = |
|
| 129 | 18x |
std::make_shared<CatchAtAgeInterface>(*this); |
| 130 | 18x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back(caa); |
| 131 | 18x |
FisheryModelInterfaceBase::live_objects[this->id] = caa; |
| 132 |
} |
|
| 133 | ||
| 134 |
/** |
|
| 135 |
* @brief Construct a new Catch At Age Interface object |
|
| 136 |
* |
|
| 137 |
* @param other |
|
| 138 |
*/ |
|
| 139 | 18x |
CatchAtAgeInterface(const CatchAtAgeInterface &other) |
| 140 | 18x |
: FisheryModelInterfaceBase(other), |
| 141 | 18x |
population_ids(other.population_ids) {}
|
| 142 | ||
| 143 |
/** |
|
| 144 |
* Method to add a population id to the set of population ids. |
|
| 145 |
*/ |
|
| 146 | 18x |
void AddPopulation(uint32_t id) {
|
| 147 | 18x |
this->population_ids->insert(id); |
| 148 | ||
| 149 | 18x |
std::map<uint32_t, std::shared_ptr<PopulationInterfaceBase>>::iterator pit; |
| 150 | 18x |
pit = PopulationInterfaceBase::live_objects.find(id); |
| 151 | 18x |
if (pit != PopulationInterfaceBase::live_objects.end()) {
|
| 152 | 18x |
std::shared_ptr<PopulationInterfaceBase> &pop = (*pit).second; |
| 153 | 18x |
pop->initialize_catch_at_age.set(true); |
| 154 |
} else {
|
|
| 155 | ! |
FIMS_ERROR_LOG("Population with id " + fims::to_string(id) +
|
| 156 |
" not found."); |
|
| 157 |
} |
|
| 158 |
} |
|
| 159 | ||
| 160 |
/** |
|
| 161 |
* @brief Enable or disable reporting for the CatchAtAge model. |
|
| 162 |
* |
|
| 163 |
* @details This method is used to control whether reporting is performed for |
|
| 164 |
* the CatchAtAge model. The implementation may depend on TMB_MODEL. |
|
| 165 |
* @param report Boolean flag to enable (true) or disable (false) reporting. |
|
| 166 |
*/ |
|
| 167 | ! |
void DoReporting(bool report) {
|
| 168 |
#ifdef TMB_MODEL |
|
| 169 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 170 | ! |
fims_info::Information<double>::GetInstance(); |
| 171 | ! |
typename fims_info::Information<double>::model_map_iterator model_it; |
| 172 | ! |
model_it = info->models_map.find(this->get_id()); |
| 173 | ! |
if (model_it != info->models_map.end()) {
|
| 174 |
std::shared_ptr<fims_popdy::CatchAtAge<double>> model_ptr = |
|
| 175 |
std::dynamic_pointer_cast<fims_popdy::CatchAtAge<double>>( |
|
| 176 | ! |
(*model_it).second); |
| 177 | ! |
model_ptr->do_reporting = report; |
| 178 |
} |
|
| 179 |
#endif |
|
| 180 |
} |
|
| 181 | ||
| 182 |
/** |
|
| 183 |
* @brief Check if reporting is enabled for the CatchAtAge model. |
|
| 184 |
* |
|
| 185 |
* @details Returns true if reporting is enabled, false otherwise. The |
|
| 186 |
* implementation may depend on TMB_MODEL. |
|
| 187 |
* @return Boolean indicating reporting status. |
|
| 188 |
*/ |
|
| 189 | ! |
bool IsReporting() {
|
| 190 |
#ifdef TMB_MODEL |
|
| 191 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 192 | ! |
fims_info::Information<double>::GetInstance(); |
| 193 | ! |
typename fims_info::Information<double>::model_map_iterator model_it; |
| 194 | ! |
model_it = info->models_map.find(this->get_id()); |
| 195 | ! |
if (model_it != info->models_map.end()) {
|
| 196 |
std::shared_ptr<fims_popdy::CatchAtAge<double>> model_ptr = |
|
| 197 |
std::dynamic_pointer_cast<fims_popdy::CatchAtAge<double>>( |
|
| 198 | ! |
(*model_it).second); |
| 199 | ! |
return model_ptr->do_reporting; |
| 200 |
} |
|
| 201 | ! |
return false; |
| 202 |
#else |
|
| 203 |
return false; |
|
| 204 |
#endif |
|
| 205 |
} |
|
| 206 | ||
| 207 |
/** |
|
| 208 |
* @brief Method to get this id. |
|
| 209 |
*/ |
|
| 210 | 101x |
virtual uint32_t get_id() { return this->id; }
|
| 211 | ||
| 212 |
/** |
|
| 213 |
* |
|
| 214 |
*/ |
|
| 215 | ! |
virtual void finalize() {}
|
| 216 | ||
| 217 |
/** |
|
| 218 |
* @brief Method to convert a population to a JSON string. |
|
| 219 |
*/ |
|
| 220 | 13x |
std::string population_to_json(PopulationInterface *population_interface) {
|
| 221 | 13x |
std::stringstream ss; |
| 222 | ||
| 223 |
typename std::map<uint32_t, |
|
| 224 |
std::shared_ptr<PopulationInterfaceBase>>::iterator |
|
| 225 | 13x |
pi_it; // population interface iterator |
| 226 | 13x |
pi_it = PopulationInterfaceBase::live_objects.find( |
| 227 | 13x |
population_interface->get_id()); |
| 228 | 13x |
if (pi_it == PopulationInterfaceBase::live_objects.end()) {
|
| 229 | ! |
FIMS_ERROR_LOG("Population with id " +
|
| 230 |
fims::to_string(population_interface->get_id()) + |
|
| 231 |
" not found in live objects."); |
|
| 232 | ! |
return "{}"; // Return empty JSON
|
| 233 |
} |
|
| 234 | ||
| 235 |
std::shared_ptr<PopulationInterface> population_interface_ptr = |
|
| 236 | 13x |
std::dynamic_pointer_cast<PopulationInterface>((*pi_it).second); |
| 237 | ||
| 238 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 239 | 13x |
fims_info::Information<double>::GetInstance(); |
| 240 | ||
| 241 | 13x |
typename fims_info::Information<double>::model_map_iterator model_it; |
| 242 | 13x |
model_it = info->models_map.find(this->get_id()); |
| 243 |
std::shared_ptr<fims_popdy::CatchAtAge<double>> model_ptr = |
|
| 244 |
std::dynamic_pointer_cast<fims_popdy::CatchAtAge<double>>( |
|
| 245 | 13x |
(*model_it).second); |
| 246 | ||
| 247 | 13x |
typename fims_info::Information<double>::population_iterator pit; |
| 248 | ||
| 249 | 13x |
pit = info->populations.find(population_interface->get_id()); |
| 250 | ||
| 251 | 13x |
if (pit != info->populations.end()) {
|
| 252 | 13x |
std::shared_ptr<fims_popdy::Population<double>> &pop = (*pit).second; |
| 253 | 13x |
ss << "{\n";
|
| 254 | ||
| 255 | 13x |
ss << " \"module_name\": \"Population\",\n"; |
| 256 | 13x |
ss << " \"population\": \"" << population_interface->name << "\",\n"; |
| 257 | 13x |
ss << " \"module_id\": " << population_interface->id << ",\n"; |
| 258 | 13x |
ss << " \"recruitment_id\": " << population_interface->recruitment_id |
| 259 | 13x |
<< ",\n"; |
| 260 | 13x |
ss << " \"growth_id\": " << population_interface->growth_id << ",\n"; |
| 261 | 13x |
ss << " \"maturity_id\": " << population_interface->maturity_id << ",\n"; |
| 262 | ||
| 263 | 13x |
ss << " \"parameters\": [\n"; |
| 264 | 13x |
fims::Vector<double> log_M_uncertainty(pop->log_M.size(), -999); |
| 265 | 26x |
this->get_se_values("log_M", this->se_values, log_M_uncertainty);
|
| 266 | 4693x |
for (size_t i = 0; i < pop->log_M.size(); i++) {
|
| 267 | 4680x |
population_interface_ptr->log_M[i].final_value_m = pop->log_M[i]; |
| 268 | 4680x |
population_interface_ptr->log_M[i].uncertainty_m = log_M_uncertainty[i]; |
| 269 |
} |
|
| 270 | ||
| 271 | 13x |
ss << "{\n \"name\": \"log_M\",\n";
|
| 272 | 13x |
ss << " \"id\":" << population_interface->log_M.id_m << ",\n"; |
| 273 | 13x |
ss << " \"type\": \"vector\",\n"; |
| 274 | 13x |
ss << " \"dimensionality\": {\n";
|
| 275 | 13x |
ss << " \"header\": [" << "\"n_years\", \"n_ages\"" << "],\n"; |
| 276 | 13x |
ss << " \"dimensions\": [" << population_interface->n_years.get() << ", " |
| 277 | 13x |
<< population_interface->n_ages.get() << "]\n},\n"; |
| 278 | 13x |
ss << " \"values\": " << population_interface->log_M << "\n\n"; |
| 279 | 13x |
ss << "},\n"; |
| 280 | ||
| 281 | 13x |
fims::Vector<double> log_init_naa_uncertainty(pop->log_init_naa.size(), |
| 282 | 13x |
-999); |
| 283 | 26x |
this->get_se_values("log_init_naa", this->se_values,
|
| 284 |
log_init_naa_uncertainty); |
|
| 285 | 169x |
for (size_t i = 0; i < pop->log_init_naa.size(); i++) {
|
| 286 | 156x |
population_interface_ptr->log_init_naa[i].final_value_m = |
| 287 | 156x |
pop->log_init_naa[i]; |
| 288 | 156x |
population_interface_ptr->log_init_naa[i].uncertainty_m = |
| 289 | 156x |
log_init_naa_uncertainty[i]; |
| 290 |
} |
|
| 291 | 13x |
ss << " {\n\"name\": \"log_init_naa\",\n";
|
| 292 | 13x |
ss << " \"id\":" << population_interface->log_init_naa.id_m << ",\n"; |
| 293 | 13x |
ss << " \"type\": \"vector\",\n"; |
| 294 | 13x |
ss << " \"dimensionality\": {\n";
|
| 295 | 13x |
ss << " \"header\": [" << "\"n_ages\"" << "],\n"; |
| 296 | 13x |
ss << " \"dimensions\": [" << population_interface->n_ages.get() |
| 297 | 13x |
<< "]\n},\n"; |
| 298 | ||
| 299 | 13x |
ss << " \"values\":" << population_interface->log_init_naa << "\n"; |
| 300 | 13x |
ss << "}],\n"; |
| 301 | ||
| 302 | 13x |
ss << " \"derived_quantities\": [\n"; |
| 303 | ||
| 304 |
std::map<std::string, fims::Vector<double>> dqs = |
|
| 305 | 26x |
model_ptr->GetPopulationDerivedQuantities( |
| 306 | 26x |
population_interface->get_id()); |
| 307 | ||
| 308 |
std::map<std::string, fims_popdy::DimensionInfo> dim_info = |
|
| 309 | 13x |
model_ptr->GetPopulationDimensionInfo(population_interface->get_id()); |
| 310 | 26x |
ss << this->derived_quantities_component_to_json(dqs, dim_info) |
| 311 | 13x |
<< " ]}\n"; |
| 312 |
} else {
|
|
| 313 | ! |
ss << "{\n";
|
| 314 | ! |
ss << " \"name\": \"Population\",\n"; |
| 315 | ||
| 316 | ! |
ss << " \"type\": \"population\",\n"; |
| 317 | ! |
ss << " \"tag\": \"" << population_interface->get_id() |
| 318 | ! |
<< " not found in Information.\",\n"; |
| 319 | ! |
ss << " \"id\": " << population_interface->get_id() << ",\n"; |
| 320 | ! |
ss << " \"recruitment_id\": " << population_interface->recruitment_id |
| 321 | ! |
<< ",\n"; |
| 322 | ! |
ss << " \"growth_id\": " << population_interface->growth_id << ",\n"; |
| 323 | ! |
ss << " \"maturity_id\": " << population_interface->maturity_id << ",\n"; |
| 324 | ! |
ss << " \"derived_quantities\": []}\n"; |
| 325 |
} |
|
| 326 | ||
| 327 | 13x |
return ss.str(); |
| 328 |
} |
|
| 329 | ||
| 330 |
/** |
|
| 331 |
* This function is used to convert the derived quantities of a population or |
|
| 332 |
* fleet to a JSON string. This function is used to create the JSON output for |
|
| 333 |
* the CatchAtAge model. |
|
| 334 |
*/ |
|
| 335 | 663x |
std::string derived_quantity_to_json( |
| 336 |
std::map<std::string, fims::Vector<double>>::iterator it, |
|
| 337 |
const fims_popdy::DimensionInfo &dim_info) {
|
|
| 338 | 663x |
std::stringstream ss; |
| 339 | 663x |
std::string name = (*it).first; |
| 340 | 663x |
fims::Vector<double> &dq = (*it).second; |
| 341 | 663x |
std::stringstream dim_entry; |
| 342 | 663x |
bool has_se = false; |
| 343 |
typename std::map<std::string, std::vector<double>>::iterator se_vals = |
|
| 344 | 663x |
this->se_values.find(name); |
| 345 | ||
| 346 | 663x |
if (se_vals != this->se_values.end()) {
|
| 347 | 639x |
has_se = true; |
| 348 |
} |
|
| 349 |
// gather dimension information |
|
| 350 | 663x |
switch (dim_info.ndims) {
|
| 351 | 325x |
case 1: |
| 352 | 325x |
dim_entry << "\"dimensionality\": {\n";
|
| 353 | 325x |
dim_entry << " \"header\": [\"" << dim_info.dim_names[0] << "\"],\n"; |
| 354 | 325x |
dim_entry << " \"dimensions\": ["; |
| 355 | 650x |
for (size_t i = 0; i < dim_info.dims.size(); ++i) {
|
| 356 |
if (i > 0) dim_entry << ", "; |
|
| 357 | 325x |
dim_entry << dim_info.dims[i]; |
| 358 |
} |
|
| 359 | 325x |
dim_entry << "]\n"; |
| 360 | 325x |
dim_entry << "}"; |
| 361 | 325x |
break; |
| 362 | 338x |
case 2: |
| 363 | 338x |
dim_entry << "\"dimensionality\": {\n";
|
| 364 |
dim_entry << " \"header\": [\"" << dim_info.dim_names[0] << "\", \"" |
|
| 365 | 338x |
<< dim_info.dim_names[1] << "\"],\n"; |
| 366 | 338x |
dim_entry << " \"dimensions\": ["; |
| 367 | 1014x |
for (size_t i = 0; i < dim_info.dims.size(); ++i) {
|
| 368 | 676x |
if (i > 0) dim_entry << ", "; |
| 369 | 676x |
dim_entry << dim_info.dims[i]; |
| 370 |
} |
|
| 371 | 338x |
dim_entry << "]\n"; |
| 372 | 338x |
dim_entry << "}"; |
| 373 | 338x |
break; |
| 374 | ! |
case 3: |
| 375 | ! |
dim_entry << "\"dimensionality\": {\n";
|
| 376 |
dim_entry << " \"header\": [\"" << dim_info.dim_names[0] << "\", \"" |
|
| 377 |
<< dim_info.dim_names[1] << "\", \"" << dim_info.dim_names[2] |
|
| 378 | ! |
<< "\"],\n"; |
| 379 | ! |
dim_entry << " \"dimensions\": ["; |
| 380 | ! |
for (size_t i = 0; i < dim_info.dims.size(); ++i) {
|
| 381 | ! |
if (i > 0) dim_entry << ", "; |
| 382 | ! |
dim_entry << dim_info.dims[i]; |
| 383 |
} |
|
| 384 | ! |
dim_entry << "]\n"; |
| 385 | ! |
dim_entry << "}"; |
| 386 | ! |
break; |
| 387 | ! |
default: |
| 388 | ! |
dim_entry << "\"dimensionality\": {\n";
|
| 389 | ! |
dim_entry << " \"header\": [],\n"; |
| 390 | ! |
dim_entry << " \"dimensions\": []\n"; |
| 391 | ! |
dim_entry << "}"; |
| 392 | ! |
break; |
| 393 |
} |
|
| 394 | ||
| 395 |
// build JSON string |
|
| 396 | 663x |
ss << "{\n";
|
| 397 | 663x |
ss << "\"name\":\"" << (*it).first << "\",\n"; |
| 398 | 663x |
ss << dim_entry.str() << ",\n"; |
| 399 | 663x |
ss << "\"value\":["; |
| 400 | 663x |
ss << std::fixed << std::setprecision(10); |
| 401 | 663x |
if (dq.size() > 0) {
|
| 402 | 149723x |
for (size_t i = 0; i < dq.size() - 1; i++) {
|
| 403 | 149084x |
if (dq[i] != dq[i]) // check for NaN |
| 404 |
{
|
|
| 405 | ! |
ss << "\"-999\", "; |
| 406 |
} else {
|
|
| 407 | 149084x |
ss << dq[i] << ", "; |
| 408 |
} |
|
| 409 |
} |
|
| 410 | 639x |
if (dq[dq.size() - 1] != dq[dq.size() - 1]) // check for NaN |
| 411 |
{
|
|
| 412 | ! |
ss << "\"-999\""; |
| 413 |
} else {
|
|
| 414 | 639x |
ss << dq[dq.size() - 1] << "],\n"; |
| 415 |
} |
|
| 416 |
} else {
|
|
| 417 | 24x |
ss << "],\n"; |
| 418 |
} |
|
| 419 | 663x |
if (has_se) {
|
| 420 |
try {
|
|
| 421 | 639x |
std::vector<double> &se_vals_vector = (*se_vals).second; |
| 422 | 639x |
if (se_vals_vector.size() < dq.size()) {
|
| 423 |
throw std::runtime_error( |
|
| 424 |
"Standard error vector size is smaller than derived quantity " |
|
| 425 | ! |
"size for derived quantity " + |
| 426 | ! |
name); |
| 427 |
} |
|
| 428 |
std::vector<double> uncertainty_std(se_vals_vector.begin(), |
|
| 429 | 639x |
se_vals_vector.begin() + dq.size()); |
| 430 | 1278x |
std::vector<double> temp(se_vals_vector.begin() + dq.size(), |
| 431 | 1278x |
se_vals_vector.end()); |
| 432 | 639x |
se_vals_vector = temp; |
| 433 | 639x |
fims::Vector<double> uncertainty(uncertainty_std); |
| 434 | 639x |
ss << "\"uncertainty\": " << uncertainty << "\n"; |
| 435 | 639x |
} catch (const std::exception &e) {
|
| 436 |
throw std::runtime_error( |
|
| 437 |
"Error processing uncertainty for derived quantity " + name + ": " + |
|
| 438 |
e.what()); |
|
| 439 |
} |
|
| 440 |
} else {
|
|
| 441 | 24x |
ss << "\"uncertainty\": ["; |
| 442 |
for (size_t i = 0; i < dq.size(); ++i) {
|
|
| 443 | ! |
ss << "-999.0"; // Placeholder for uncertainty values |
| 444 | ! |
if (i < dq.size() - 1) {
|
| 445 | ! |
ss << ", "; |
| 446 |
} |
|
| 447 |
} |
|
| 448 | 24x |
ss << "]\n"; |
| 449 |
} |
|
| 450 | 663x |
ss << "}"; |
| 451 | ||
| 452 | 1326x |
return ss.str(); |
| 453 |
} |
|
| 454 | ||
| 455 |
/** |
|
| 456 |
* @brief Send the fleet-based derived quantities to the json file. |
|
| 457 |
* @return std::string |
|
| 458 |
*/ |
|
| 459 | 39x |
std::string derived_quantities_component_to_json( |
| 460 |
std::map<std::string, fims::Vector<double>> &dqs, |
|
| 461 |
std::map<std::string, fims_popdy::DimensionInfo> &dim_info) {
|
|
| 462 | 39x |
std::stringstream ss; |
| 463 | 39x |
std::map<std::string, fims_popdy::DimensionInfo>::iterator dim_info_it; |
| 464 | 39x |
std::map<std::string, fims::Vector<double>>::iterator it; |
| 465 | 39x |
std::map<std::string, fims::Vector<double>>::iterator end_it; |
| 466 | 39x |
end_it = dqs.end(); |
| 467 |
typename std::map<std::string, fims::Vector<double>>::iterator |
|
| 468 | 39x |
second_to_last; |
| 469 | 39x |
second_to_last = dqs.end(); |
| 470 | 39x |
if (it != end_it) {
|
| 471 | 39x |
second_to_last--; |
| 472 |
} |
|
| 473 | ||
| 474 | 39x |
it = dqs.begin(); |
| 475 | 663x |
for (; it != second_to_last; ++it) {
|
| 476 | 624x |
dim_info_it = dim_info.find(it->first); |
| 477 | 624x |
ss << this->derived_quantity_to_json(it, dim_info_it->second) << ",\n"; |
| 478 |
} |
|
| 479 | ||
| 480 | 39x |
dim_info_it = dim_info.find(second_to_last->first); |
| 481 | 39x |
if (dim_info_it != dim_info.end()) {
|
| 482 | 78x |
ss << this->derived_quantity_to_json(second_to_last, dim_info_it->second) |
| 483 | 39x |
<< "\n"; |
| 484 |
} else {
|
|
| 485 | ! |
ss << "{}";
|
| 486 |
// Handle case where dimension info is not found |
|
| 487 |
} |
|
| 488 | 78x |
return ss.str(); |
| 489 |
} |
|
| 490 | ||
| 491 |
/** |
|
| 492 |
* @brief Method to convert a fleet to a JSON string. |
|
| 493 |
*/ |
|
| 494 | 26x |
std::string fleet_to_json(FleetInterface *fleet_interface) {
|
| 495 | 26x |
std::stringstream ss; |
| 496 | ||
| 497 | 26x |
if (!fleet_interface) {
|
| 498 | ! |
FIMS_ERROR_LOG("Fleet with id " +
|
| 499 |
fims::to_string(fleet_interface->get_id()) + |
|
| 500 |
" not found in live objects."); |
|
| 501 | ! |
return "{}"; // Return empty JSON
|
| 502 |
} |
|
| 503 | ||
| 504 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 505 | 26x |
fims_info::Information<double>::GetInstance(); |
| 506 | ||
| 507 | 26x |
typename fims_info::Information<double>::model_map_iterator model_it; |
| 508 | 26x |
model_it = info->models_map.find(this->get_id()); |
| 509 |
std::shared_ptr<fims_popdy::CatchAtAge<double>> model_ptr = |
|
| 510 |
std::dynamic_pointer_cast<fims_popdy::CatchAtAge<double>>( |
|
| 511 | 26x |
(*model_it).second); |
| 512 | ||
| 513 | 26x |
typename fims_info::Information<double>::fleet_iterator fit; |
| 514 | ||
| 515 | 26x |
fit = info->fleets.find(fleet_interface->get_id()); |
| 516 | ||
| 517 | 26x |
if (fit != info->fleets.end()) {
|
| 518 | 26x |
std::shared_ptr<fims_popdy::Fleet<double>> &fleet = (*fit).second; |
| 519 | ||
| 520 | 26x |
ss << "{\n";
|
| 521 | 26x |
ss << " \"module_name\": \"Fleet\",\n"; |
| 522 | 26x |
ss << " \"fleet\": \"" << fleet_interface->name << "\",\n"; |
| 523 | 26x |
ss << " \"module_id\": " << fleet_interface->id << ",\n"; |
| 524 | 26x |
ss << " \"n_ages\": " << fleet_interface->n_ages.get() << ",\n"; |
| 525 | 26x |
ss << " \"n_years\": " << fleet_interface->n_years.get() << ",\n"; |
| 526 | 26x |
ss << " \"n_lengths\": " << fleet_interface->n_lengths.get() << ",\n"; |
| 527 | 26x |
ss << "\"data_ids\" : [\n"; |
| 528 | 26x |
ss << "{\"agecomp\": " << fleet_interface->GetObservedAgeCompDataID()
|
| 529 | 26x |
<< "},\n"; |
| 530 | 26x |
ss << "{\"lengthcomp\": "
|
| 531 | 26x |
<< fleet_interface->GetObservedLengthCompDataID() << "},\n"; |
| 532 | 26x |
ss << "{\"index\": " << fleet_interface->GetObservedIndexDataID()
|
| 533 | 26x |
<< "},\n"; |
| 534 | 26x |
ss << "{\"landings\": " << fleet_interface->GetObservedLandingsDataID()
|
| 535 | 26x |
<< "}\n"; |
| 536 | 26x |
ss << "],\n"; |
| 537 | 26x |
ss << "\"parameters\": [\n"; |
| 538 | 26x |
ss << "{\n";
|
| 539 | 26x |
fims::Vector<double> log_Fmort_uncertainty(fleet->log_Fmort.size(), -999); |
| 540 | 52x |
this->get_se_values("log_Fmort", this->se_values, log_Fmort_uncertainty);
|
| 541 | 806x |
for (size_t i = 0; i < fleet_interface->log_Fmort.size(); i++) {
|
| 542 | 780x |
fleet_interface->log_Fmort[i].final_value_m = fleet->log_Fmort[i]; |
| 543 | 780x |
fleet_interface->log_Fmort[i].uncertainty_m = log_Fmort_uncertainty[i]; |
| 544 |
} |
|
| 545 | ||
| 546 | 26x |
ss << " \"name\": \"log_Fmort\",\n"; |
| 547 | 26x |
ss << " \"id\":" << fleet_interface->log_Fmort.id_m << ",\n"; |
| 548 | 26x |
ss << " \"type\": \"vector\",\n"; |
| 549 | 26x |
ss << " \"dimensionality\": {\n";
|
| 550 | 26x |
ss << " \"header\": [\"" << "n_years" << "\"],\n"; |
| 551 | 26x |
ss << " \"dimensions\": [" << fleet_interface->n_years.get() |
| 552 | 26x |
<< "]\n},\n"; |
| 553 | 26x |
ss << " \"values\": " << fleet_interface->log_Fmort << "},\n"; |
| 554 | ||
| 555 | 26x |
ss << " {\n";
|
| 556 | 26x |
fims::Vector<double> log_q_uncertainty(fleet->log_q.size(), -999); |
| 557 | 52x |
this->get_se_values("log_q", this->se_values, log_q_uncertainty);
|
| 558 | 52x |
for (size_t i = 0; i < fleet->log_q.size(); i++) {
|
| 559 | 26x |
fleet_interface->log_q[i].final_value_m = fleet->log_q[i]; |
| 560 | 26x |
fleet_interface->log_q[i].uncertainty_m = log_q_uncertainty[i]; |
| 561 |
} |
|
| 562 | 26x |
ss << " \"name\": \"log_q\",\n"; |
| 563 | 26x |
ss << " \"id\":" << fleet_interface->log_q.id_m << ",\n"; |
| 564 | 26x |
ss << " \"type\": \"vector\",\n"; |
| 565 | 26x |
ss << " \"dimensionality\": {\n";
|
| 566 | 26x |
ss << " \"header\": [\"" << "na" << "\"],\n"; |
| 567 | 26x |
ss << " \"dimensions\": [" << fleet->log_q.size() << "]\n},\n"; |
| 568 | ||
| 569 | 26x |
ss << " \"values\": " << fleet_interface->log_q << "}\n"; |
| 570 | ||
| 571 | 26x |
if (fleet_interface->n_lengths > 0) {
|
| 572 | 20x |
ss << " ,{\n";
|
| 573 |
fims::Vector<double> age_to_length_conversion_uncertainty( |
|
| 574 | 20x |
fleet->age_to_length_conversion.size(), -999); |
| 575 | 40x |
this->get_se_values("age_to_length_conversion", this->se_values,
|
| 576 |
age_to_length_conversion_uncertainty); |
|
| 577 | 5540x |
for (size_t i = 0; i < fleet_interface->age_to_length_conversion.size(); |
| 578 |
i++) {
|
|
| 579 | 11040x |
fleet_interface->age_to_length_conversion[i].final_value_m = |
| 580 | 5520x |
fleet->age_to_length_conversion[i]; |
| 581 | 5520x |
fleet_interface->age_to_length_conversion[i].uncertainty_m = |
| 582 | 5520x |
age_to_length_conversion_uncertainty[i]; |
| 583 |
} |
|
| 584 | 20x |
ss << " \"name\": \"age_to_length_conversion\",\n"; |
| 585 | 20x |
ss << " \"id\":" << fleet_interface->age_to_length_conversion.id_m |
| 586 | 20x |
<< ",\n"; |
| 587 | 20x |
ss << " \"type\": \"vector\",\n"; |
| 588 | 20x |
ss << " \"dimensionality\": {\n";
|
| 589 | 20x |
ss << " \"header\": [" << "\"n_ages\", \"n_lengths\"" << "],\n"; |
| 590 | 20x |
ss << " \"dimensions\": [" << fleet_interface->n_ages.get() << ", " |
| 591 | 20x |
<< fleet_interface->n_lengths.get() << "]\n},\n"; |
| 592 | ||
| 593 | 20x |
ss << " \"values\": " << fleet_interface->age_to_length_conversion |
| 594 | 20x |
<< "\n"; |
| 595 | ||
| 596 | 20x |
ss << "\n}\n"; |
| 597 |
} |
|
| 598 | ||
| 599 | 26x |
ss << "], \"derived_quantities\": ["; |
| 600 | ||
| 601 |
std::map<std::string, fims::Vector<double>> dqs = |
|
| 602 | 26x |
model_ptr->GetFleetDerivedQuantities(fleet_interface->get_id()); |
| 603 |
std::map<std::string, fims_popdy::DimensionInfo> dim_info = |
|
| 604 | 26x |
model_ptr->GetFleetDimensionInfo(fleet_interface->get_id()); |
| 605 | 26x |
ss << this->derived_quantities_component_to_json(dqs, dim_info) << "]}\n"; |
| 606 |
} else {
|
|
| 607 | ! |
ss << "{\n";
|
| 608 | ! |
ss << " \"name\": \"Fleet\",\n"; |
| 609 | ! |
ss << " \"type\": \"fleet\",\n"; |
| 610 | ! |
ss << " \"tag\": \"" << fleet_interface->get_id() |
| 611 | ! |
<< " not found in Information.\",\n"; |
| 612 | ! |
ss << " \"derived_quantities\": []}\n"; |
| 613 |
} |
|
| 614 | 26x |
return ss.str(); |
| 615 |
} |
|
| 616 | ||
| 617 |
/** |
|
| 618 |
* @brief Get the vector of fixed effect parameters for the CatchAtAge model. |
|
| 619 |
* |
|
| 620 |
* @details Returns a numeric vector containing the fixed effect parameters |
|
| 621 |
* used in the model. |
|
| 622 |
* @return Rcpp::NumericVector of fixed effect parameters. |
|
| 623 |
*/ |
|
| 624 | 39x |
Rcpp::NumericVector get_fixed_parameters_vector() {
|
| 625 |
// base model |
|
| 626 |
std::shared_ptr<fims_info::Information<double>> info0 = |
|
| 627 | 39x |
fims_info::Information<double>::GetInstance(); |
| 628 | ||
| 629 | 39x |
Rcpp::NumericVector p; |
| 630 | ||
| 631 | 1860x |
for (size_t i = 0; i < info0->fixed_effects_parameters.size(); i++) {
|
| 632 | 1821x |
p.push_back(*info0->fixed_effects_parameters[i]); |
| 633 |
} |
|
| 634 | ||
| 635 | 78x |
return p; |
| 636 |
} |
|
| 637 | ||
| 638 |
/** |
|
| 639 |
* @brief Get the vector of random effect parameters for the CatchAtAge model. |
|
| 640 |
* |
|
| 641 |
* @details Returns a numeric vector containing the random effect parameters |
|
| 642 |
* used in the model. |
|
| 643 |
* @return Rcpp::NumericVector of random effect parameters. |
|
| 644 |
*/ |
|
| 645 | 13x |
Rcpp::NumericVector get_random_parameters_vector() {
|
| 646 |
// base model |
|
| 647 |
std::shared_ptr<fims_info::Information<double>> d0 = |
|
| 648 | 13x |
fims_info::Information<double>::GetInstance(); |
| 649 | ||
| 650 | 13x |
Rcpp::NumericVector p; |
| 651 | ||
| 652 | 71x |
for (size_t i = 0; i < d0->random_effects_parameters.size(); i++) {
|
| 653 | 58x |
p.push_back(*d0->random_effects_parameters[i]); |
| 654 |
} |
|
| 655 | ||
| 656 | 26x |
return p; |
| 657 |
} |
|
| 658 | ||
| 659 |
/** |
|
| 660 |
* @brief Get the report output for the CatchAtAge model. |
|
| 661 |
* |
|
| 662 |
* @details Returns a list containing the report results for the CatchAtAge |
|
| 663 |
* model, including derived quantities and diagnostics. |
|
| 664 |
* @return Rcpp::List containing the report output. |
|
| 665 |
*/ |
|
| 666 | 13x |
Rcpp::List get_report() {
|
| 667 | 13x |
Rcpp::Environment base = Rcpp::Environment::base_env(); |
| 668 | 26x |
Rcpp::Function summary = base["summary"]; |
| 669 | ||
| 670 |
// Grab needed R functions |
|
| 671 | 26x |
Rcpp::Environment TMB = Rcpp::Environment::namespace_env("TMB");
|
| 672 | 26x |
Rcpp::Function MakeADFun = TMB["MakeADFun"]; |
| 673 | 13x |
Rcpp::Function sdreport = TMB["sdreport"]; |
| 674 |
// Grab your helpers from R global environment |
|
| 675 | 13x |
Rcpp::Environment global = Rcpp::Environment::global_env(); |
| 676 |
// Build parameters list |
|
| 677 |
Rcpp::List parameters = Rcpp::List::create( |
|
| 678 | 52x |
Rcpp::Named("p") = this->get_fixed_parameters_vector(),
|
| 679 | 65x |
Rcpp::Named("re") = this->get_random_parameters_vector());
|
| 680 |
// Call MakeADFun with map = NULL |
|
| 681 |
Rcpp::List obj = MakeADFun( |
|
| 682 | 52x |
Rcpp::Named("data") = Rcpp::List::create(),
|
| 683 | 52x |
Rcpp::Named("parameters") = parameters, Rcpp::Named("DLL") = "FIMS",
|
| 684 | 52x |
Rcpp::Named("silent") = true, Rcpp::Named("map") = R_NilValue,
|
| 685 | 52x |
Rcpp::Named("random") = "re");
|
| 686 |
// Call obj$report() |
|
| 687 | 26x |
Rcpp::Function report = obj["report"]; |
| 688 | 26x |
Rcpp::Function func = obj["fn"]; |
| 689 | 13x |
Rcpp::Function gradient = obj["gr"]; |
| 690 | 13x |
Rcpp::NumericVector grad = gradient(this->get_fixed_parameters_vector()); |
| 691 | 13x |
double maxgc = -999; |
| 692 | 620x |
for (R_xlen_t i = 0; i < grad.size(); i++) {
|
| 693 | 607x |
if (std::fabs(grad[i]) > maxgc) {
|
| 694 | 62x |
maxgc = std::fabs(grad[i]); |
| 695 |
} |
|
| 696 |
} |
|
| 697 |
double of_value = |
|
| 698 | 13x |
Rcpp::as<double>(func(this->get_fixed_parameters_vector())); |
| 699 | 13x |
Rcpp::List rep = report(); |
| 700 | 13x |
SEXP sdr = sdreport(obj); |
| 701 | 13x |
Rcpp::RObject sdr_summary = summary(sdr, "report"); |
| 702 | ||
| 703 | 13x |
Rcpp::NumericMatrix mat(sdr_summary); |
| 704 | 13x |
Rcpp::List dimnames = mat.attr("dimnames");
|
| 705 | 13x |
Rcpp::CharacterVector rownames = dimnames[0]; |
| 706 | 13x |
Rcpp::CharacterVector colnames = dimnames[1]; |
| 707 | ||
| 708 |
// ---- Group into map ---- |
|
| 709 | 13x |
std::map<std::string, std::vector<double>> grouped; |
| 710 | 13x |
int nrow = mat.nrow(); |
| 711 | 161616x |
for (int i = 0; i < nrow; i++) {
|
| 712 | 161603x |
std::string key = Rcpp::as<std::string>(rownames[i]); |
| 713 | 161603x |
double val = mat(i, 1); // col 1 = "Std. Error" |
| 714 | 161603x |
grouped[key].push_back(val); |
| 715 |
} |
|
| 716 | ||
| 717 |
// ---- Convert map -> R list ---- |
|
| 718 | 13x |
Rcpp::List grouped_out; |
| 719 | 557x |
for (auto const &kv : grouped) {
|
| 720 | 544x |
grouped_out[kv.first] = Rcpp::wrap(kv.second); |
| 721 |
} |
|
| 722 | ||
| 723 |
// Example: grab "Estimate" for first row |
|
| 724 | 13x |
double first_est = mat(0, 0); |
| 725 | ||
| 726 |
return Rcpp::List::create( |
|
| 727 | 26x |
Rcpp::Named("objective_function_value") = of_value,
|
| 728 | 26x |
Rcpp::Named("gradient") = grad,
|
| 729 | 26x |
Rcpp::Named("max_gradient_component") = maxgc,
|
| 730 | 52x |
Rcpp::Named("report") = rep, Rcpp::Named("sdr_summary") = sdr_summary,
|
| 731 | 26x |
Rcpp::Named("sdr_summary_matrix") = mat,
|
| 732 | 26x |
Rcpp::Named("first_est") = first_est,
|
| 733 | 52x |
Rcpp::Named("rownames") = rownames, Rcpp::Named("colnames") = colnames,
|
| 734 | 52x |
Rcpp::Named("grouped_se") = grouped_out);
|
| 735 |
} |
|
| 736 |
/** |
|
| 737 |
* @brief Method to convert the model to a JSON string. |
|
| 738 |
*/ |
|
| 739 | 13x |
virtual std::string to_json() {
|
| 740 | 13x |
Rcpp::List report = get_report(); |
| 741 | 26x |
Rcpp::List grouped_out = report["grouped_se"]; |
| 742 | 26x |
double max_gc = Rcpp::as<double>(report["max_gradient_component"]); |
| 743 | 26x |
Rcpp::NumericVector grad = report["gradient"]; |
| 744 | 13x |
double of_value = Rcpp::as<double>(report["objective_function_value"]); |
| 745 | ||
| 746 | 13x |
fims::Vector<double> gradient(grad.size()); |
| 747 | 620x |
for (int i = 0; i < grad.size(); i++) {
|
| 748 | 607x |
gradient[i] = grad[i]; |
| 749 |
} |
|
| 750 |
// Assume grouped_out is an Rcpp::List |
|
| 751 | 13x |
std::map<std::string, std::vector<double>> grouped_cpp; |
| 752 | 13x |
Rcpp::CharacterVector names = grouped_out.names(); |
| 753 | 557x |
for (int i = 0; i < grouped_out.size(); i++) {
|
| 754 | 544x |
std::string key = Rcpp::as<std::string>(names[i]); |
| 755 |
Rcpp::NumericVector vec = |
|
| 756 | 544x |
grouped_out[i]; // each element is a numeric vector |
| 757 | 544x |
std::vector<double> vec_std(vec.size()); |
| 758 | 162147x |
for (int j = 0; j < vec.size(); j++) {
|
| 759 | 161603x |
vec_std[j] = vec[j]; |
| 760 |
} |
|
| 761 | 544x |
grouped_cpp[key] = vec_std; |
| 762 |
} |
|
| 763 | 13x |
this->se_values = grouped_cpp; |
| 764 | ||
| 765 | 13x |
std::set<uint32_t> recruitment_ids; |
| 766 | 13x |
std::set<uint32_t> growth_ids; |
| 767 | 13x |
std::set<uint32_t> maturity_ids; |
| 768 | 13x |
std::set<uint32_t> selectivity_ids; |
| 769 | 13x |
std::set<uint32_t> fleet_ids; |
| 770 |
// gather sub-module info from population and fleets |
|
| 771 | 13x |
typename std::set<uint32_t>::iterator module_id_it; // generic |
| 772 | 13x |
typename std::set<uint32_t>::iterator pit; |
| 773 | 13x |
typename std::set<uint32_t>::iterator fids; |
| 774 | 13x |
for (pit = this->population_ids->begin(); |
| 775 | 26x |
pit != this->population_ids->end(); pit++) {
|
| 776 |
std::shared_ptr<PopulationInterface> population_interface = |
|
| 777 |
std::dynamic_pointer_cast<PopulationInterface>( |
|
| 778 | 13x |
PopulationInterfaceBase::live_objects[*pit]); |
| 779 | 13x |
if (population_interface) {
|
| 780 | 13x |
recruitment_ids.insert(population_interface->recruitment_id.get()); |
| 781 | 13x |
growth_ids.insert(population_interface->growth_id.get()); |
| 782 | 13x |
maturity_ids.insert(population_interface->maturity_id.get()); |
| 783 | ||
| 784 | 13x |
for (fids = population_interface->fleet_ids->begin(); |
| 785 | 39x |
fids != population_interface->fleet_ids->end(); fids++) {
|
| 786 | 26x |
fleet_ids.insert(*fids); |
| 787 |
} |
|
| 788 |
} |
|
| 789 |
} |
|
| 790 | ||
| 791 | 39x |
for (fids = fleet_ids.begin(); fids != fleet_ids.end(); fids++) {
|
| 792 |
std::shared_ptr<FleetInterface> fleet_interface = |
|
| 793 |
std::dynamic_pointer_cast<FleetInterface>( |
|
| 794 | 26x |
FleetInterfaceBase::live_objects[*fids]); |
| 795 | 26x |
if (fleet_interface) {
|
| 796 | 26x |
selectivity_ids.insert(fleet_interface->GetSelectivityID()); |
| 797 |
} |
|
| 798 |
} |
|
| 799 | ||
| 800 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 801 | 13x |
fims_info::Information<double>::GetInstance(); |
| 802 | ||
| 803 |
std::shared_ptr<fims_popdy::CatchAtAge<double>> model = |
|
| 804 |
std::dynamic_pointer_cast<fims_popdy::CatchAtAge<double>>( |
|
| 805 | 13x |
info->models_map[this->get_id()]); |
| 806 | ||
| 807 |
std::shared_ptr<fims_model::Model<double>> model_internal = |
|
| 808 | 13x |
fims_model::Model<double>::GetInstance(); |
| 809 | ||
| 810 |
#ifdef TMB_MODEL |
|
| 811 | 13x |
model->do_reporting = false; |
| 812 |
#endif |
|
| 813 | ||
| 814 | 13x |
double value = model_internal->Evaluate(); |
| 815 | ||
| 816 | 13x |
std::stringstream ss; |
| 817 | ||
| 818 | 13x |
ss.str("");
|
| 819 | ||
| 820 | 13x |
ss << "{\n";
|
| 821 | 13x |
ss << " \"name\": \"CatchAtAge\",\n"; |
| 822 | 13x |
ss << " \"type\": \"model\",\n"; |
| 823 | 13x |
ss << " \"estimation_framework\": "; |
| 824 |
#ifdef TMB_MODEL |
|
| 825 | 13x |
ss << "\"Template_Model_Builder (TMB)\","; |
| 826 |
#else |
|
| 827 |
ss << "\"FIMS\","; |
|
| 828 |
#endif |
|
| 829 | 13x |
ss << " \"id\": " << this->get_id() << ",\n"; |
| 830 | 13x |
ss << " \"objective_function_value\": " << value << ",\n"; |
| 831 | 13x |
ss << "\"growth\":[\n"; |
| 832 | 26x |
for (module_id_it = growth_ids.begin(); module_id_it != growth_ids.end(); |
| 833 | 13x |
module_id_it++) {
|
| 834 |
std::shared_ptr<GrowthInterfaceBase> growth_interface = |
|
| 835 | 13x |
GrowthInterfaceBase::live_objects[*module_id_it]; |
| 836 | ||
| 837 | 13x |
if (growth_interface != NULL) {
|
| 838 | 13x |
growth_interface->set_uncertainty(this->se_values); |
| 839 | 13x |
growth_interface->finalize(); |
| 840 | 13x |
ss << growth_interface->to_json(); |
| 841 | 26x |
if (std::next(module_id_it) != growth_ids.end()) {
|
| 842 | ! |
ss << ", "; |
| 843 |
} |
|
| 844 |
} |
|
| 845 |
} |
|
| 846 | ||
| 847 | 13x |
ss << "],\n"; |
| 848 | ||
| 849 | 13x |
ss << "\"recruitment\": [\n"; |
| 850 | 13x |
for (module_id_it = recruitment_ids.begin(); |
| 851 | 26x |
module_id_it != recruitment_ids.end(); module_id_it++) {
|
| 852 |
std::shared_ptr<RecruitmentInterfaceBase> recruitment_interface = |
|
| 853 | 13x |
RecruitmentInterfaceBase::live_objects[*module_id_it]; |
| 854 | 13x |
if (recruitment_interface) {
|
| 855 | 13x |
recruitment_interface->set_uncertainty(this->se_values); |
| 856 | 13x |
recruitment_interface->finalize(); |
| 857 | 13x |
ss << recruitment_interface->to_json(); |
| 858 | 26x |
if (std::next(module_id_it) != recruitment_ids.end()) {
|
| 859 | ! |
ss << ", "; |
| 860 |
} |
|
| 861 |
} |
|
| 862 |
} |
|
| 863 | 13x |
ss << "],\n"; |
| 864 | ||
| 865 | 13x |
ss << "\"maturity\": [\n"; |
| 866 | 13x |
for (module_id_it = maturity_ids.begin(); |
| 867 | 26x |
module_id_it != maturity_ids.end(); module_id_it++) {
|
| 868 |
std::shared_ptr<MaturityInterfaceBase> maturity_interface = |
|
| 869 | 13x |
MaturityInterfaceBase::live_objects[*module_id_it]; |
| 870 | 13x |
if (maturity_interface) {
|
| 871 | 13x |
maturity_interface->set_uncertainty(this->se_values); |
| 872 | 13x |
maturity_interface->finalize(); |
| 873 | 13x |
ss << maturity_interface->to_json(); |
| 874 | 26x |
if (std::next(module_id_it) != maturity_ids.end()) {
|
| 875 | ! |
ss << ", "; |
| 876 |
} |
|
| 877 |
} |
|
| 878 |
} |
|
| 879 | 13x |
ss << "],\n"; |
| 880 | ||
| 881 | 13x |
ss << "\"selectivity\": [\n"; |
| 882 | 13x |
for (module_id_it = selectivity_ids.begin(); |
| 883 | 39x |
module_id_it != selectivity_ids.end(); module_id_it++) {
|
| 884 |
std::shared_ptr<SelectivityInterfaceBase> selectivity_interface = |
|
| 885 | 26x |
SelectivityInterfaceBase::live_objects[*module_id_it]; |
| 886 | 26x |
if (selectivity_interface) {
|
| 887 | 26x |
selectivity_interface->set_uncertainty(this->se_values); |
| 888 | 26x |
selectivity_interface->finalize(); |
| 889 | 26x |
ss << selectivity_interface->to_json(); |
| 890 | 52x |
if (std::next(module_id_it) != selectivity_ids.end()) {
|
| 891 | 13x |
ss << ", "; |
| 892 |
} |
|
| 893 |
} |
|
| 894 |
} |
|
| 895 | 13x |
ss << "],\n"; |
| 896 | ||
| 897 | 13x |
ss << " \"population_ids\": ["; |
| 898 | 13x |
for (pit = this->population_ids->begin(); |
| 899 | 26x |
pit != this->population_ids->end(); pit++) {
|
| 900 | 13x |
ss << *pit; |
| 901 | 26x |
if (std::next(pit) != this->population_ids->end()) {
|
| 902 | ! |
ss << ", "; |
| 903 |
} |
|
| 904 |
} |
|
| 905 | 13x |
ss << "],\n"; |
| 906 | 13x |
ss << " \"fleet_ids\": ["; |
| 907 | ||
| 908 | 39x |
for (fids = fleet_ids.begin(); fids != fleet_ids.end(); fids++) {
|
| 909 | 26x |
ss << *fids; |
| 910 | 52x |
if (std::next(fids) != fleet_ids.end()) {
|
| 911 | 13x |
ss << ", "; |
| 912 |
} |
|
| 913 |
} |
|
| 914 | 13x |
ss << "],\n"; |
| 915 | 13x |
ss << "\"populations\": [\n"; |
| 916 | 13x |
typename std::set<uint32_t>::iterator pop_it; |
| 917 | 13x |
typename std::set<uint32_t>::iterator pop_end_it; |
| 918 | 13x |
pop_end_it = this->population_ids->end(); |
| 919 | 13x |
typename std::set<uint32_t>::iterator pop_second_to_last_it; |
| 920 | 13x |
if (pop_end_it != this->population_ids->begin()) {
|
| 921 | 13x |
pop_second_to_last_it = std::prev(pop_end_it); |
| 922 |
} else {
|
|
| 923 | ! |
pop_second_to_last_it = pop_end_it; |
| 924 |
} |
|
| 925 | 13x |
for (pop_it = this->population_ids->begin(); |
| 926 |
pop_it != pop_second_to_last_it; pop_it++) {
|
|
| 927 |
std::shared_ptr<PopulationInterface> population_interface = |
|
| 928 |
std::dynamic_pointer_cast<PopulationInterface>( |
|
| 929 | ! |
PopulationInterfaceBase::live_objects[*pop_it]); |
| 930 | ! |
if (population_interface) {
|
| 931 | ! |
std::set<uint32_t>::iterator fids; |
| 932 | ! |
for (fids = population_interface->fleet_ids->begin(); |
| 933 | ! |
fids != population_interface->fleet_ids->end(); fids++) {
|
| 934 | ! |
fleet_ids.insert(*fids); |
| 935 |
} |
|
| 936 | ! |
population_interface->finalize(); |
| 937 | ! |
ss << this->population_to_json(population_interface.get()) << ","; |
| 938 |
} else {
|
|
| 939 | ! |
FIMS_ERROR_LOG("Population with id " + fims::to_string(*pop_it) +
|
| 940 |
" not found in live objects."); |
|
| 941 | ! |
ss << "{}"; // Return empty JSON for this population
|
| 942 |
} |
|
| 943 |
} |
|
| 944 | ||
| 945 |
std::shared_ptr<PopulationInterface> population_interface = |
|
| 946 |
std::dynamic_pointer_cast<PopulationInterface>( |
|
| 947 | 13x |
PopulationInterfaceBase::live_objects[*pop_second_to_last_it]); |
| 948 | 13x |
if (population_interface) {
|
| 949 | 13x |
std::set<uint32_t>::iterator fids; |
| 950 | 13x |
for (fids = population_interface->fleet_ids->begin(); |
| 951 | 39x |
fids != population_interface->fleet_ids->end(); fids++) {
|
| 952 | 26x |
fleet_ids.insert(*fids); |
| 953 |
} |
|
| 954 | 13x |
ss << this->population_to_json(population_interface.get()); |
| 955 |
} else {
|
|
| 956 | ! |
FIMS_ERROR_LOG("Population with id " + fims::to_string(*pop_it) +
|
| 957 |
" not found in live objects."); |
|
| 958 | ! |
ss << "{}"; // Return empty JSON for this population
|
| 959 |
} |
|
| 960 | ||
| 961 | 13x |
ss << "]"; |
| 962 | 13x |
ss << ",\n"; |
| 963 | 13x |
ss << "\"fleets\": [\n"; |
| 964 | ||
| 965 | 13x |
typename std::set<uint32_t>::iterator fleet_it; |
| 966 | 13x |
typename std::set<uint32_t>::iterator fleet_end_it; |
| 967 | 13x |
fleet_end_it = fleet_ids.end(); |
| 968 | 13x |
typename std::set<uint32_t>::iterator fleet_second_to_last_it; |
| 969 | ||
| 970 | 13x |
if (fleet_end_it != fleet_ids.begin()) {
|
| 971 | 13x |
fleet_second_to_last_it = std::prev(fleet_end_it); |
| 972 |
} |
|
| 973 | 26x |
for (fleet_it = fleet_ids.begin(); fleet_it != fleet_second_to_last_it; |
| 974 | 13x |
fleet_it++) {
|
| 975 |
std::shared_ptr<FleetInterface> fleet_interface = |
|
| 976 |
std::dynamic_pointer_cast<FleetInterface>( |
|
| 977 | 13x |
FleetInterfaceBase::live_objects[*fleet_it]); |
| 978 | 13x |
if (fleet_interface) {
|
| 979 | 13x |
fleet_interface->finalize(); |
| 980 | 13x |
ss << this->fleet_to_json(fleet_interface.get()) << ","; |
| 981 |
} else {
|
|
| 982 | ! |
FIMS_ERROR_LOG("Fleet with id " + fims::to_string(*fleet_it) +
|
| 983 |
" not found in live objects."); |
|
| 984 | ! |
ss << "{}"; // Return empty JSON for this fleet
|
| 985 |
} |
|
| 986 |
} |
|
| 987 |
std::shared_ptr<FleetInterface> fleet_interface = |
|
| 988 |
std::dynamic_pointer_cast<FleetInterface>( |
|
| 989 | 13x |
FleetInterfaceBase::live_objects[*fleet_second_to_last_it]); |
| 990 | 13x |
if (fleet_interface) {
|
| 991 | 13x |
ss << this->fleet_to_json(fleet_interface.get()); |
| 992 |
} else {
|
|
| 993 | ! |
FIMS_ERROR_LOG("Fleet with id " + fims::to_string(*fleet_it) +
|
| 994 |
" not found in live objects."); |
|
| 995 | ! |
ss << "{}"; // Return empty JSON for this fleet
|
| 996 |
} |
|
| 997 | ||
| 998 | 13x |
ss << "],\n"; |
| 999 | ||
| 1000 | 13x |
ss << "\"density_components\": [\n"; |
| 1001 | ||
| 1002 |
typename std::map< |
|
| 1003 | 13x |
uint32_t, std::shared_ptr<DistributionsInterfaceBase>>::iterator dit; |
| 1004 | 13x |
for (dit = DistributionsInterfaceBase::live_objects.begin(); |
| 1005 | 94x |
dit != DistributionsInterfaceBase::live_objects.end(); ++dit) {
|
| 1006 |
std::shared_ptr<DistributionsInterfaceBase> dist_interface = |
|
| 1007 | 81x |
(*dit).second; |
| 1008 | 81x |
if (dist_interface) {
|
| 1009 | 81x |
dist_interface->finalize(); |
| 1010 | 81x |
ss << dist_interface->to_json(); |
| 1011 | 162x |
if (std::next(dit) != DistributionsInterfaceBase::live_objects.end()) {
|
| 1012 | 68x |
ss << ",\n"; |
| 1013 |
} |
|
| 1014 |
} |
|
| 1015 |
} |
|
| 1016 | 13x |
ss << "\n],\n"; |
| 1017 | 13x |
ss << "\"data\": [\n"; |
| 1018 |
typename std::map<uint32_t, std::shared_ptr<DataInterfaceBase>>::iterator |
|
| 1019 | 13x |
d_it; |
| 1020 | 13x |
for (d_it = DataInterfaceBase::live_objects.begin(); |
| 1021 | 81x |
d_it != DataInterfaceBase::live_objects.end(); ++d_it) {
|
| 1022 | 68x |
std::shared_ptr<DataInterfaceBase> data_interface = (*d_it).second; |
| 1023 | 68x |
if (data_interface) {
|
| 1024 | 68x |
data_interface->finalize(); |
| 1025 | 68x |
ss << data_interface->to_json(); |
| 1026 | 136x |
if (std::next(d_it) != DataInterfaceBase::live_objects.end()) {
|
| 1027 | 55x |
ss << ",\n"; |
| 1028 |
} |
|
| 1029 |
} |
|
| 1030 |
} |
|
| 1031 | 13x |
ss << "\n],\n"; |
| 1032 |
// add log |
|
| 1033 | 13x |
ss << " \"log\": {\n";
|
| 1034 | 13x |
ss << "\"info\": " << fims::FIMSLog::fims_log->get_info() << "," |
| 1035 | 26x |
<< "\"warnings\": " << fims::FIMSLog::fims_log->get_warnings() << "," |
| 1036 | 39x |
<< "\"errors\": " << fims::FIMSLog::fims_log->get_errors() << "}}"; |
| 1037 |
#ifdef TMB_MODEL |
|
| 1038 | 13x |
model->do_reporting = true; |
| 1039 |
#endif |
|
| 1040 | 26x |
return fims::JsonParser::PrettyFormatJSON(ss.str()); |
| 1041 |
} |
|
| 1042 | ||
| 1043 |
/** |
|
| 1044 |
* @brief Sum method to calculate the sum of an array or vector of doubles. |
|
| 1045 |
* |
|
| 1046 |
* @param v |
|
| 1047 |
* @return double |
|
| 1048 |
*/ |
|
| 1049 |
double sum(const std::valarray<double> &v) {
|
|
| 1050 |
double sum = 0.0; |
|
| 1051 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 1052 |
sum += v[i]; |
|
| 1053 |
} |
|
| 1054 |
return sum; |
|
| 1055 |
} |
|
| 1056 | ||
| 1057 |
/** |
|
| 1058 |
* @brief Sum method for a vector of doubles. |
|
| 1059 |
* |
|
| 1060 |
* @param v |
|
| 1061 |
* @return double |
|
| 1062 |
*/ |
|
| 1063 |
double sum(const std::vector<double> &v) {
|
|
| 1064 |
double sum = 0.0; |
|
| 1065 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 1066 |
sum += v[i]; |
|
| 1067 |
} |
|
| 1068 |
return sum; |
|
| 1069 |
} |
|
| 1070 | ||
| 1071 |
/** |
|
| 1072 |
* @brief Minimum method to calculate the minimum of an array or vector |
|
| 1073 |
* of doubles. |
|
| 1074 |
* |
|
| 1075 |
* @param v |
|
| 1076 |
* @return double |
|
| 1077 |
*/ |
|
| 1078 |
double min(const std::valarray<double> &v) {
|
|
| 1079 |
double min = v[0]; |
|
| 1080 |
for (size_t i = 1; i < v.size(); i++) {
|
|
| 1081 |
if (v[i] < min) {
|
|
| 1082 |
min = v[i]; |
|
| 1083 |
} |
|
| 1084 |
} |
|
| 1085 |
return min; |
|
| 1086 |
} |
|
| 1087 |
/** |
|
| 1088 |
* @brief A function to compute the absolute value of a value array of |
|
| 1089 |
* floating-point values. It is a wrapper around std::fabs. |
|
| 1090 |
* |
|
| 1091 |
* @param v A value array of floating-point values, where floating-point |
|
| 1092 |
* values is anything with decimals. |
|
| 1093 |
* @return std::valarray<double> |
|
| 1094 |
*/ |
|
| 1095 |
std::valarray<double> fabs(const std::valarray<double> &v) {
|
|
| 1096 |
std::valarray<double> result(v.size()); |
|
| 1097 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 1098 |
result[i] = std::fabs(v[i]); |
|
| 1099 |
} |
|
| 1100 |
return result; |
|
| 1101 |
} |
|
| 1102 | ||
| 1103 |
#ifdef TMB_MODEL |
|
| 1104 | ||
| 1105 |
template <typename Type> |
|
| 1106 | 72x |
bool add_to_fims_tmb_internal() {
|
| 1107 | 72x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 1108 |
fims_info::Information<Type>::GetInstance(); |
|
| 1109 | ||
| 1110 | 72x |
std::shared_ptr<fims_popdy::CatchAtAge<Type>> model = |
| 1111 |
std::make_shared<fims_popdy::CatchAtAge<Type>>(); |
|
| 1112 | ||
| 1113 | 72x |
population_id_iterator it; |
| 1114 | ||
| 1115 | 144x |
for (it = this->population_ids->begin(); it != this->population_ids->end(); |
| 1116 | 72x |
++it) {
|
| 1117 | 72x |
model->AddPopulation((*it)); |
| 1118 |
} |
|
| 1119 | ||
| 1120 | 72x |
std::set<uint32_t> fleet_ids; // all fleets in the model |
| 1121 |
typedef typename std::set<uint32_t>::iterator fleet_ids_iterator; |
|
| 1122 | ||
| 1123 |
// add to Information |
|
| 1124 | 72x |
info->models_map[this->get_id()] = model; |
| 1125 | ||
| 1126 | 216x |
for (it = this->population_ids->begin(); it != this->population_ids->end(); |
| 1127 | 72x |
++it) {
|
| 1128 | 72x |
auto it2 = PopulationInterfaceBase::live_objects.find(*it); |
| 1129 | 72x |
if (it2 == PopulationInterfaceBase::live_objects.end()) {
|
| 1130 | ! |
throw std::runtime_error("Population ID " + std::to_string(*it) +
|
| 1131 |
" not found in live_objects"); |
|
| 1132 |
} |
|
| 1133 | 72x |
auto population = |
| 1134 | 72x |
std::dynamic_pointer_cast<PopulationInterface>(it2->second); |
| 1135 | 72x |
model->InitializePopulationDerivedQuantities(population->id); |
| 1136 |
std::map<std::string, fims::Vector<Type>> &derived_quantities = |
|
| 1137 | 72x |
model->GetPopulationDerivedQuantities(population->id); |
| 1138 | ||
| 1139 |
std::map<std::string, fims_popdy::DimensionInfo> |
|
| 1140 |
&derived_quantities_dim_info = |
|
| 1141 | 72x |
model->GetPopulationDimensionInfo(population->id); |
| 1142 | ||
| 1143 | 72x |
std::stringstream ss; |
| 1144 | ||
| 1145 | 72x |
derived_quantities["total_landings_weight"] = |
| 1146 | 144x |
fims::Vector<Type>(population->n_years.get()); |
| 1147 | ||
| 1148 | 72x |
derived_quantities_dim_info["total_landings_weight"] = |
| 1149 | 288x |
fims_popdy::DimensionInfo( |
| 1150 |
"total_landings_weight", |
|
| 1151 | 72x |
fims::Vector<int>{(int)population->n_years.get()},
|
| 1152 | 144x |
fims::Vector<std::string>{"n_years"});
|
| 1153 | ||
| 1154 | 72x |
derived_quantities["total_landings_numbers"] = |
| 1155 | 144x |
fims::Vector<Type>(population->n_years.get()); |
| 1156 | ||
| 1157 | 72x |
derived_quantities_dim_info["total_landings_numbers"] = |
| 1158 | 288x |
fims_popdy::DimensionInfo( |
| 1159 |
"total_landings_numbers", |
|
| 1160 | 72x |
fims::Vector<int>{population->n_years.get()},
|
| 1161 | 144x |
fims::Vector<std::string>{"n_years"});
|
| 1162 | ||
| 1163 | 144x |
derived_quantities["mortality_F"] = fims::Vector<Type>( |
| 1164 | 72x |
population->n_years.get() * population->n_ages.get()); |
| 1165 | 360x |
derived_quantities_dim_info["mortality_F"] = fims_popdy::DimensionInfo( |
| 1166 |
"mortality_F", |
|
| 1167 | 72x |
fims::Vector<int>{population->n_years.get(),
|
| 1168 | 72x |
population->n_ages.get()}, |
| 1169 | 216x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1170 | ||
| 1171 | 144x |
derived_quantities["mortality_Z"] = fims::Vector<Type>( |
| 1172 | 72x |
population->n_years.get() * population->n_ages.get()); |
| 1173 | 360x |
derived_quantities_dim_info["mortality_Z"] = fims_popdy::DimensionInfo( |
| 1174 |
"mortality_Z", |
|
| 1175 | 72x |
fims::Vector<int>{population->n_years.get(),
|
| 1176 | 72x |
population->n_ages.get()}, |
| 1177 | 216x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1178 | ||
| 1179 | 144x |
derived_quantities["numbers_at_age"] = fims::Vector<Type>( |
| 1180 | 72x |
(population->n_years.get() + 1) * population->n_ages.get()); |
| 1181 | 360x |
derived_quantities_dim_info["numbers_at_age"] = fims_popdy::DimensionInfo( |
| 1182 |
"numbers_at_age", |
|
| 1183 | 72x |
fims::Vector<int>{(population->n_years.get() + 1),
|
| 1184 | 72x |
population->n_ages.get()}, |
| 1185 | 216x |
fims::Vector<std::string>{"n_years+1", "n_ages"});
|
| 1186 | ||
| 1187 | 144x |
derived_quantities["unfished_numbers_at_age"] = fims::Vector<Type>( |
| 1188 | 72x |
(population->n_years.get() + 1) * population->n_ages.get()); |
| 1189 | 72x |
derived_quantities_dim_info["unfished_numbers_at_age"] = |
| 1190 | 288x |
fims_popdy::DimensionInfo( |
| 1191 |
"unfished_numbers_at_age", |
|
| 1192 | 72x |
fims::Vector<int>{(population->n_years.get() + 1),
|
| 1193 | 72x |
population->n_ages.get()}, |
| 1194 | 216x |
fims::Vector<std::string>{"n_years+1", "n_ages"});
|
| 1195 | ||
| 1196 | 72x |
derived_quantities["biomass"] = |
| 1197 | 144x |
fims::Vector<Type>((population->n_years.get() + 1)); |
| 1198 | 288x |
derived_quantities_dim_info["biomass"] = fims_popdy::DimensionInfo( |
| 1199 | 72x |
"biomass", fims::Vector<int>{(population->n_years.get() + 1)},
|
| 1200 | 144x |
fims::Vector<std::string>{"n_years+1"});
|
| 1201 | ||
| 1202 | 72x |
derived_quantities["spawning_biomass"] = |
| 1203 | 144x |
fims::Vector<Type>((population->n_years.get() + 1)); |
| 1204 | 72x |
derived_quantities_dim_info["spawning_biomass"] = |
| 1205 | 216x |
fims_popdy::DimensionInfo( |
| 1206 |
"spawning_biomass", |
|
| 1207 | 72x |
fims::Vector<int>{(population->n_years.get() + 1)},
|
| 1208 | 144x |
fims::Vector<std::string>{"n_years+1"});
|
| 1209 | ||
| 1210 | 72x |
derived_quantities["unfished_biomass"] = |
| 1211 | 144x |
fims::Vector<Type>((population->n_years.get() + 1)); |
| 1212 | 72x |
derived_quantities_dim_info["unfished_biomass"] = |
| 1213 | 216x |
fims_popdy::DimensionInfo( |
| 1214 |
"unfished_biomass", |
|
| 1215 | 72x |
fims::Vector<int>{(population->n_years.get() + 1)},
|
| 1216 | 144x |
fims::Vector<std::string>{"n_years+1"});
|
| 1217 | ||
| 1218 | 72x |
derived_quantities["unfished_spawning_biomass"] = |
| 1219 | 144x |
fims::Vector<Type>((population->n_years.get() + 1)); |
| 1220 | 72x |
derived_quantities_dim_info["unfished_spawning_biomass"] = |
| 1221 | 216x |
fims_popdy::DimensionInfo( |
| 1222 |
"unfished_spawning_biomass", |
|
| 1223 | 72x |
fims::Vector<int>{(population->n_years.get() + 1)},
|
| 1224 | 144x |
fims::Vector<std::string>{"n_years+1"});
|
| 1225 | ||
| 1226 | 144x |
derived_quantities["proportion_mature_at_age"] = fims::Vector<Type>( |
| 1227 | 72x |
(population->n_years.get() + 1) * population->n_ages.get()); |
| 1228 | 72x |
derived_quantities_dim_info["proportion_mature_at_age"] = |
| 1229 | 288x |
fims_popdy::DimensionInfo( |
| 1230 |
"proportion_mature_at_age", |
|
| 1231 | 72x |
fims::Vector<int>{(population->n_years.get() + 1),
|
| 1232 | 72x |
population->n_ages.get()}, |
| 1233 | 216x |
fims::Vector<std::string>{"n_years+1", "n_ages"});
|
| 1234 | ||
| 1235 | 72x |
derived_quantities["expected_recruitment"] = |
| 1236 | 144x |
fims::Vector<Type>((population->n_years.get() + 1)); |
| 1237 | 72x |
derived_quantities_dim_info["expected_recruitment"] = |
| 1238 | 216x |
fims_popdy::DimensionInfo( |
| 1239 |
"expected_recruitment", |
|
| 1240 | 72x |
fims::Vector<int>{(population->n_years.get() + 1)},
|
| 1241 | 144x |
fims::Vector<std::string>{"n_years+1"});
|
| 1242 | ||
| 1243 | 144x |
derived_quantities["sum_selectivity"] = fims::Vector<Type>( |
| 1244 | 72x |
population->n_years.get() * population->n_ages.get()); |
| 1245 | 72x |
derived_quantities_dim_info["sum_selectivity"] = |
| 1246 | 288x |
fims_popdy::DimensionInfo( |
| 1247 |
"sum_selectivity", |
|
| 1248 | 72x |
fims::Vector<int>{population->n_years.get(),
|
| 1249 | 72x |
population->n_ages.get()}, |
| 1250 | 216x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1251 | ||
| 1252 |
// replace elements in the variable map |
|
| 1253 | 72x |
info->variable_map[population->numbers_at_age.id_m] = |
| 1254 | 144x |
&(derived_quantities["numbers_at_age"]); |
| 1255 | ||
| 1256 | 72x |
for (fleet_ids_iterator fit = population->fleet_ids->begin(); |
| 1257 | 216x |
fit != population->fleet_ids->end(); ++fit) {
|
| 1258 | 144x |
fleet_ids.insert(*fit); |
| 1259 |
} |
|
| 1260 |
} |
|
| 1261 | ||
| 1262 | 216x |
for (fleet_ids_iterator it = fleet_ids.begin(); it != fleet_ids.end(); |
| 1263 | 144x |
++it) {
|
| 1264 | 144x |
std::shared_ptr<FleetInterface> fleet_interface = |
| 1265 | 144x |
std::dynamic_pointer_cast<FleetInterface>( |
| 1266 | 144x |
FleetInterfaceBase::live_objects[(*it)]); |
| 1267 | 144x |
model->InitializeFleetDerivedQuantities(fleet_interface->id); |
| 1268 |
std::map<std::string, fims::Vector<Type>> &derived_quantities = |
|
| 1269 | 144x |
model->GetFleetDerivedQuantities(fleet_interface->id); |
| 1270 | ||
| 1271 |
std::map<std::string, fims_popdy::DimensionInfo> |
|
| 1272 |
&derived_quantities_dim_info = |
|
| 1273 | 144x |
model->GetFleetDimensionInfo(fleet_interface->id); |
| 1274 | ||
| 1275 |
// initialize derive quantities |
|
| 1276 |
// landings |
|
| 1277 | 360x |
derived_quantities["landings_numbers_at_age"] = fims::Vector<Type>( |
| 1278 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1279 | 144x |
derived_quantities_dim_info["landings_numbers_at_age"] = |
| 1280 | 576x |
fims_popdy::DimensionInfo( |
| 1281 |
"landings_numbers_at_age", |
|
| 1282 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1283 | 144x |
fleet_interface->n_ages.get()}, |
| 1284 | 432x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1285 | ||
| 1286 | 288x |
derived_quantities["landings_weight_at_age"] = fims::Vector<Type>( |
| 1287 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1288 | 144x |
derived_quantities_dim_info["landings_weight_at_age"] = |
| 1289 | 576x |
fims_popdy::DimensionInfo( |
| 1290 |
"landings_weight_at_age", |
|
| 1291 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1292 | 144x |
fleet_interface->n_ages.get()}, |
| 1293 | 432x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1294 | ||
| 1295 | 288x |
derived_quantities["landings_numbers_at_length"] = fims::Vector<Type>( |
| 1296 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_lengths.get()); |
| 1297 | 144x |
derived_quantities_dim_info["landings_numbers_at_length"] = |
| 1298 | 576x |
fims_popdy::DimensionInfo( |
| 1299 |
"landings_numbers_at_length", |
|
| 1300 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1301 | 144x |
fleet_interface->n_lengths.get()}, |
| 1302 | 432x |
fims::Vector<std::string>{"n_years", "n_lengths"});
|
| 1303 | ||
| 1304 | 144x |
derived_quantities["landings_weight"] = |
| 1305 | 288x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1306 | 144x |
derived_quantities_dim_info["landings_weight"] = |
| 1307 | 576x |
fims_popdy::DimensionInfo( |
| 1308 |
"landings_weight", |
|
| 1309 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1310 | 288x |
fims::Vector<std::string>{"n_years"});
|
| 1311 | ||
| 1312 | 144x |
derived_quantities["landings_numbers"] = |
| 1313 | 288x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1314 | 144x |
derived_quantities_dim_info["landings_numbers"] = |
| 1315 | 576x |
fims_popdy::DimensionInfo( |
| 1316 |
"landings_numbers", |
|
| 1317 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1318 | 288x |
fims::Vector<std::string>{"n_years"});
|
| 1319 | ||
| 1320 | 144x |
derived_quantities["landings_expected"] = |
| 1321 | 288x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1322 | 144x |
derived_quantities_dim_info["landings_expected"] = |
| 1323 | 576x |
fims_popdy::DimensionInfo( |
| 1324 |
"landings_expected", |
|
| 1325 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1326 | 288x |
fims::Vector<std::string>{"n_years"});
|
| 1327 | ||
| 1328 | 144x |
derived_quantities["log_landings_expected"] = |
| 1329 | 288x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1330 | 144x |
derived_quantities_dim_info["log_landings_expected"] = |
| 1331 | 576x |
fims_popdy::DimensionInfo( |
| 1332 |
"log_landings_expected", |
|
| 1333 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1334 | 288x |
fims::Vector<std::string>{"n_years"});
|
| 1335 | ||
| 1336 | 288x |
derived_quantities["agecomp_proportion"] = fims::Vector<Type>( |
| 1337 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1338 | 144x |
derived_quantities_dim_info["agecomp_proportion"] = |
| 1339 | 576x |
fims_popdy::DimensionInfo( |
| 1340 |
"agecomp_proportion", |
|
| 1341 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1342 | 144x |
fleet_interface->n_ages.get()}, |
| 1343 | 432x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1344 | ||
| 1345 | 288x |
derived_quantities["lengthcomp_proportion"] = fims::Vector<Type>( |
| 1346 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_lengths.get()); |
| 1347 | 144x |
derived_quantities_dim_info["lengthcomp_proportion"] = |
| 1348 | 576x |
fims_popdy::DimensionInfo( |
| 1349 |
"lengthcomp_proportion", |
|
| 1350 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1351 | 144x |
fleet_interface->n_lengths.get()}, |
| 1352 | 432x |
fims::Vector<std::string>{"n_years", "n_lengths"});
|
| 1353 | ||
| 1354 |
// index |
|
| 1355 | 288x |
derived_quantities["index_numbers_at_age"] = fims::Vector<Type>( |
| 1356 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1357 | 144x |
derived_quantities_dim_info["index_numbers_at_age"] = |
| 1358 | 576x |
fims_popdy::DimensionInfo( |
| 1359 |
"index_numbers_at_age", |
|
| 1360 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1361 | 144x |
fleet_interface->n_ages.get()}, |
| 1362 | 432x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1363 | ||
| 1364 | 288x |
derived_quantities["index_weight_at_age"] = fims::Vector<Type>( |
| 1365 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1366 | 144x |
derived_quantities_dim_info["index_weight_at_age"] = |
| 1367 | 576x |
fims_popdy::DimensionInfo( |
| 1368 |
"index_weight_at_age", |
|
| 1369 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1370 | 144x |
fleet_interface->n_ages.get()}, |
| 1371 | 432x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1372 | ||
| 1373 | 288x |
derived_quantities["index_weight_at_age"] = fims::Vector<Type>( |
| 1374 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1375 | 144x |
derived_quantities_dim_info["index_weight_at_age"] = |
| 1376 | 576x |
fims_popdy::DimensionInfo( |
| 1377 |
"index_weight_at_age", |
|
| 1378 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1379 | 144x |
fleet_interface->n_ages.get()}, |
| 1380 | 432x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1381 | ||
| 1382 | 288x |
derived_quantities["index_numbers_at_length"] = fims::Vector<Type>( |
| 1383 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_lengths.get()); |
| 1384 | 144x |
derived_quantities_dim_info["index_numbers_at_length"] = |
| 1385 | 576x |
fims_popdy::DimensionInfo( |
| 1386 |
"index_numbers_at_length", |
|
| 1387 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1388 | 144x |
fleet_interface->n_lengths.get()}, |
| 1389 | 432x |
fims::Vector<std::string>{"n_years", "n_lengths"});
|
| 1390 | 144x |
derived_quantities["index_weight"] = |
| 1391 | 288x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1392 | 720x |
derived_quantities_dim_info["index_weight"] = fims_popdy::DimensionInfo( |
| 1393 | 144x |
"index_weight", fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1394 | 288x |
fims::Vector<std::string>{"n_years"});
|
| 1395 | ||
| 1396 | 144x |
derived_quantities["index_numbers"] = |
| 1397 | 288x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1398 | 720x |
derived_quantities_dim_info["index_numbers"] = fims_popdy::DimensionInfo( |
| 1399 | 144x |
"index_numbers", fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1400 | 288x |
fims::Vector<std::string>{"n_years"});
|
| 1401 | ||
| 1402 | 144x |
derived_quantities["index_expected"] = |
| 1403 | 288x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1404 | 720x |
derived_quantities_dim_info["index_expected"] = fims_popdy::DimensionInfo( |
| 1405 | 144x |
"index_expected", fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1406 | 288x |
fims::Vector<std::string>{"n_years"});
|
| 1407 | ||
| 1408 | 144x |
derived_quantities["log_index_expected"] = |
| 1409 | 288x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1410 | 144x |
derived_quantities_dim_info["log_index_expected"] = |
| 1411 | 576x |
fims_popdy::DimensionInfo( |
| 1412 |
"log_index_expected", |
|
| 1413 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1414 | 288x |
fims::Vector<std::string>{"n_years"});
|
| 1415 | ||
| 1416 | 144x |
derived_quantities["catch_index"] = |
| 1417 | 288x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1418 | 720x |
derived_quantities_dim_info["catch_index"] = fims_popdy::DimensionInfo( |
| 1419 | 144x |
"catch_index", fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1420 | 288x |
fims::Vector<std::string>{"n_years"});
|
| 1421 | ||
| 1422 | 288x |
derived_quantities["agecomp_expected"] = fims::Vector<Type>( |
| 1423 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1424 | 144x |
derived_quantities_dim_info["agecomp_expected"] = |
| 1425 | 576x |
fims_popdy::DimensionInfo( |
| 1426 |
"agecomp_expected", |
|
| 1427 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1428 | 144x |
(fleet_interface->n_ages.get())}, |
| 1429 | 432x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1430 | ||
| 1431 | 288x |
derived_quantities["lengthcomp_expected"] = fims::Vector<Type>( |
| 1432 | 144x |
fleet_interface->n_years.get() * fleet_interface->n_lengths.get()); |
| 1433 | 144x |
derived_quantities_dim_info["lengthcomp_expected"] = |
| 1434 | 576x |
fims_popdy::DimensionInfo( |
| 1435 |
"lengthcomp_expected", |
|
| 1436 | 144x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1437 | 144x |
(fleet_interface->n_lengths.get())}, |
| 1438 | 432x |
fims::Vector<std::string>{"n_years", "n_lengths"});
|
| 1439 | ||
| 1440 |
// replace elements in the variable map |
|
| 1441 | 144x |
info->variable_map[fleet_interface->log_landings_expected.id_m] = |
| 1442 | 432x |
&(derived_quantities["log_landings_expected"]); |
| 1443 | 144x |
info->variable_map[fleet_interface->log_index_expected.id_m] = |
| 1444 | 432x |
&(derived_quantities["log_index_expected"]); |
| 1445 | 144x |
info->variable_map[fleet_interface->agecomp_expected.id_m] = |
| 1446 | 432x |
&(derived_quantities["agecomp_expected"]); |
| 1447 | 144x |
info->variable_map[fleet_interface->agecomp_proportion.id_m] = |
| 1448 | 432x |
&(derived_quantities["agecomp_proportion"]); |
| 1449 | 144x |
info->variable_map[fleet_interface->lengthcomp_expected.id_m] = |
| 1450 | 432x |
&(derived_quantities["lengthcomp_expected"]); |
| 1451 |
// if (fleet_interface->n_lengths.get() > 0) |
|
| 1452 |
// {
|
|
| 1453 |
// info->variable_map[fleet_interface->age_to_length_conversion.id_m] = |
|
| 1454 |
// &(derived_quantities["age_to_length_conversion"]); |
|
| 1455 |
// } |
|
| 1456 |
// info->variable_map[fleet_interface->lengthcomp_expected.id_m] = |
|
| 1457 |
// &(derived_quantities["length_comp_expected"]); |
|
| 1458 | 144x |
info->variable_map[fleet_interface->lengthcomp_proportion.id_m] = |
| 1459 | 432x |
&(derived_quantities["lengthcomp_proportion"]); |
| 1460 |
} |
|
| 1461 | ||
| 1462 | 72x |
return true; |
| 1463 |
} |
|
| 1464 | ||
| 1465 | 18x |
virtual bool add_to_fims_tmb() {
|
| 1466 | 18x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 1467 |
#ifdef TMBAD_FRAMEWORK |
|
| 1468 | 18x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 1469 |
#else |
|
| 1470 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 1471 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 1472 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 1473 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 1474 |
#endif |
|
| 1475 | 18x |
return true; |
| 1476 |
} |
|
| 1477 | ||
| 1478 |
#endif |
|
| 1479 |
}; |
|
| 1480 | ||
| 1481 |
#endif |
| 1 |
/** |
|
| 2 |
* @file rcpp_population.hpp |
|
| 3 |
* @brief The Rcpp interface to declare different types of populations. Allows |
|
| 4 |
* for the use of methods::new() in R. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_POPULATION_HPP |
|
| 10 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_POPULATION_HPP |
|
| 11 | ||
| 12 |
#include "../../../population_dynamics/population/population.hpp" |
|
| 13 |
#include "rcpp_interface_base.hpp" |
|
| 14 | ||
| 15 |
/** |
|
| 16 |
* @brief Rcpp interface that serves as the parent class for Rcpp population |
|
| 17 |
* interfaces. This type should be inherited and not called from R directly. |
|
| 18 |
*/ |
|
| 19 |
class PopulationInterfaceBase : public FIMSRcppInterfaceBase {
|
|
| 20 |
public: |
|
| 21 |
/** |
|
| 22 |
* @brief The static id of the PopulationInterfaceBase object. |
|
| 23 |
*/ |
|
| 24 |
static uint32_t id_g; |
|
| 25 |
/** |
|
| 26 |
* @brief The local id of the PopulationInterfaceBase object. |
|
| 27 |
*/ |
|
| 28 |
uint32_t id; |
|
| 29 |
/** |
|
| 30 |
* @brief The map associating the IDs of PopulationInterfaceBase to the |
|
| 31 |
* objects. This is a live object, which is an object that has been created |
|
| 32 |
* and lives in memory. |
|
| 33 |
*/ |
|
| 34 |
static std::map<uint32_t, std::shared_ptr<PopulationInterfaceBase>> |
|
| 35 |
live_objects; |
|
| 36 | ||
| 37 |
/** |
|
| 38 |
* @brief Initialize the catch at age model. |
|
| 39 |
* |
|
| 40 |
*/ |
|
| 41 |
SharedBoolean initialize_catch_at_age; |
|
| 42 |
/** |
|
| 43 |
* @brief Initialize the surplus production model. |
|
| 44 |
* |
|
| 45 |
*/ |
|
| 46 |
SharedBoolean initialize_surplus_production; |
|
| 47 |
/** |
|
| 48 |
* @brief The constructor. |
|
| 49 |
*/ |
|
| 50 | 20x |
PopulationInterfaceBase() {
|
| 51 | 20x |
this->id = PopulationInterfaceBase::id_g++; |
| 52 |
/* Create instance of map: key is id and value is pointer to |
|
| 53 |
PopulationInterfaceBase */ |
|
| 54 |
// PopulationInterfaceBase::live_objects[this->id] = this; |
|
| 55 |
} |
|
| 56 | ||
| 57 |
/** |
|
| 58 |
* @brief Construct a new Population Interface Base object |
|
| 59 |
* |
|
| 60 |
* @param other |
|
| 61 |
*/ |
|
| 62 | 20x |
PopulationInterfaceBase(const PopulationInterfaceBase &other) |
| 63 | 20x |
: id(other.id) {}
|
| 64 | ||
| 65 |
/** |
|
| 66 |
* @brief The destructor. |
|
| 67 |
*/ |
|
| 68 | 40x |
virtual ~PopulationInterfaceBase() {}
|
| 69 | ||
| 70 |
/** |
|
| 71 |
* @brief Get the ID for the child population interface objects to inherit. |
|
| 72 |
*/ |
|
| 73 |
virtual uint32_t get_id() = 0; |
|
| 74 |
}; |
|
| 75 |
// static id of the PopulationInterfaceBase object |
|
| 76 |
uint32_t PopulationInterfaceBase::id_g = 1; |
|
| 77 |
// local id of the PopulationInterfaceBase object map relating the ID of the |
|
| 78 |
// PopulationInterfaceBase to the PopulationInterfaceBase objects |
|
| 79 |
std::map<uint32_t, std::shared_ptr<PopulationInterfaceBase>> |
|
| 80 |
PopulationInterfaceBase::live_objects; |
|
| 81 | ||
| 82 |
/** |
|
| 83 |
* @brief Rcpp interface for a new Population to instantiate from R: |
|
| 84 |
* population <- methods::new(population) |
|
| 85 |
*/ |
|
| 86 |
class PopulationInterface : public PopulationInterfaceBase {
|
|
| 87 |
public: |
|
| 88 |
/** |
|
| 89 |
* @brief The number of age bins. |
|
| 90 |
*/ |
|
| 91 |
SharedInt n_ages = 0; |
|
| 92 |
/** |
|
| 93 |
* @brief The number of fleets. |
|
| 94 |
*/ |
|
| 95 |
SharedInt n_fleets; |
|
| 96 |
/** |
|
| 97 |
* list of fleets that operate on this population. |
|
| 98 |
*/ |
|
| 99 |
std::shared_ptr<std::set<uint32_t>> fleet_ids; |
|
| 100 |
/** |
|
| 101 |
* Iterator for fleet ids. |
|
| 102 |
*/ |
|
| 103 |
typedef typename std::set<uint32_t>::iterator fleet_ids_iterator; |
|
| 104 |
/** |
|
| 105 |
* @brief The number of years. |
|
| 106 |
*/ |
|
| 107 |
SharedInt n_years; |
|
| 108 |
/** |
|
| 109 |
* @brief The number of length bins. |
|
| 110 |
*/ |
|
| 111 |
SharedInt n_lengths; |
|
| 112 |
/** |
|
| 113 |
* @brief The ID of the maturity module. |
|
| 114 |
*/ |
|
| 115 |
SharedInt maturity_id; |
|
| 116 |
/** |
|
| 117 |
* @brief The ID of the growth module. |
|
| 118 |
*/ |
|
| 119 |
SharedInt growth_id; |
|
| 120 |
/** |
|
| 121 |
* @brief The ID of the recruitment module. |
|
| 122 |
*/ |
|
| 123 |
SharedInt recruitment_id; |
|
| 124 |
/** |
|
| 125 |
* @brief The ID of the recruitment process module. |
|
| 126 |
*/ |
|
| 127 |
SharedInt recruitment_err_id; |
|
| 128 |
/** |
|
| 129 |
* @brief The natural log of the natural mortality for each year. |
|
| 130 |
*/ |
|
| 131 |
ParameterVector log_M; |
|
| 132 |
/** |
|
| 133 |
* @brief The natural log of the initial numbers at age. |
|
| 134 |
*/ |
|
| 135 |
ParameterVector log_init_naa; |
|
| 136 |
/** |
|
| 137 |
* @brief Numbers at age. |
|
| 138 |
*/ |
|
| 139 |
ParameterVector numbers_at_age; |
|
| 140 |
/** |
|
| 141 |
* @brief random effect for recruitment. |
|
| 142 |
*/ |
|
| 143 |
ParameterVector log_r; |
|
| 144 |
/** |
|
| 145 |
* @brief Ages that are modeled in the population, the length of this vector |
|
| 146 |
* should equal \"n_ages\". |
|
| 147 |
*/ |
|
| 148 |
RealVector ages; |
|
| 149 |
/** |
|
| 150 |
* @brief Derived spawning biomass. |
|
| 151 |
* TODO: This should be sb not ssb if left as an acronym. |
|
| 152 |
*/ |
|
| 153 |
Rcpp::NumericVector derived_ssb; |
|
| 154 |
/** |
|
| 155 |
* @brief Derived numbers at age. |
|
| 156 |
*/ |
|
| 157 |
Rcpp::NumericVector derived_naa; |
|
| 158 |
/** |
|
| 159 |
* @brief Derived biomass (mt). |
|
| 160 |
*/ |
|
| 161 |
Rcpp::NumericVector derived_biomass; |
|
| 162 |
/** |
|
| 163 |
* @brief Derived recruitment in numbers. |
|
| 164 |
*/ |
|
| 165 |
Rcpp::NumericVector derived_recruitment; |
|
| 166 |
/** |
|
| 167 |
* @brief The name for the population. |
|
| 168 |
*/ |
|
| 169 |
SharedString name = fims::to_string("NA");
|
|
| 170 | ||
| 171 |
/** |
|
| 172 |
* @brief The constructor. |
|
| 173 |
*/ |
|
| 174 | 20x |
PopulationInterface() : PopulationInterfaceBase() {
|
| 175 | 20x |
this->fleet_ids = std::make_shared<std::set<uint32_t>>(); |
| 176 |
std::shared_ptr<PopulationInterface> population = |
|
| 177 | 20x |
std::make_shared<PopulationInterface>(*this); |
| 178 | 20x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back(population); |
| 179 | 20x |
PopulationInterfaceBase::live_objects[this->id] = population; |
| 180 |
} |
|
| 181 | ||
| 182 |
/** |
|
| 183 |
* @brief Construct a new Population Interface object |
|
| 184 |
* |
|
| 185 |
* @param other |
|
| 186 |
*/ |
|
| 187 | 20x |
PopulationInterface(const PopulationInterface &other) |
| 188 | 20x |
: PopulationInterfaceBase(other), |
| 189 | 20x |
fleet_ids(other.fleet_ids), |
| 190 | 20x |
n_ages(other.n_ages), |
| 191 | 20x |
n_fleets(other.n_fleets), |
| 192 | 20x |
n_years(other.n_years), |
| 193 | 20x |
n_lengths(other.n_lengths), |
| 194 | 20x |
maturity_id(other.maturity_id), |
| 195 | 20x |
growth_id(other.growth_id), |
| 196 | 20x |
recruitment_id(other.recruitment_id), |
| 197 | 20x |
log_M(other.log_M), |
| 198 | 20x |
log_init_naa(other.log_init_naa), |
| 199 | 20x |
numbers_at_age(other.numbers_at_age), |
| 200 | 20x |
ages(other.ages), |
| 201 | 20x |
derived_ssb(other.derived_ssb), |
| 202 | 20x |
derived_naa(other.derived_naa), |
| 203 | 20x |
derived_biomass(other.derived_biomass), |
| 204 | 20x |
derived_recruitment(other.derived_recruitment), |
| 205 | 80x |
name(other.name) {}
|
| 206 | ||
| 207 |
/** |
|
| 208 |
* @brief The destructor. |
|
| 209 |
*/ |
|
| 210 | 120x |
virtual ~PopulationInterface() {}
|
| 211 | ||
| 212 |
/** |
|
| 213 |
* @brief Gets the ID of the interface base object. |
|
| 214 |
* @return The ID. |
|
| 215 |
*/ |
|
| 216 | 71x |
virtual uint32_t get_id() { return this->id; }
|
| 217 | ||
| 218 |
/** |
|
| 219 |
* @brief Sets the name of the population. |
|
| 220 |
* @param name The name to set. |
|
| 221 |
*/ |
|
| 222 | ! |
void SetName(const std::string &name) { this->name.set(name); }
|
| 223 | ||
| 224 |
/** |
|
| 225 |
* @brief Gets the name of the population. |
|
| 226 |
* @return The name. |
|
| 227 |
*/ |
|
| 228 | ! |
std::string GetName() const { return this->name.get(); }
|
| 229 | ||
| 230 |
/** |
|
| 231 |
* @brief Sets the unique ID for the Maturity object. |
|
| 232 |
* @param maturity_id Unique ID for the Maturity object. |
|
| 233 |
*/ |
|
| 234 | 19x |
void SetMaturityID(uint32_t maturity_id) {
|
| 235 | 19x |
this->maturity_id.set(maturity_id); |
| 236 |
} |
|
| 237 | ||
| 238 |
/** |
|
| 239 |
* @brief Set the unique ID for the growth object. |
|
| 240 |
* @param growth_id Unique ID for the growth object. |
|
| 241 |
*/ |
|
| 242 | 19x |
void SetGrowthID(uint32_t growth_id) { this->growth_id.set(growth_id); }
|
| 243 | ||
| 244 |
/** |
|
| 245 |
* @brief Set the unique ID for the recruitment object. |
|
| 246 |
* @param recruitment_id Unique ID for the recruitment object. |
|
| 247 |
*/ |
|
| 248 | 19x |
void SetRecruitmentID(uint32_t recruitment_id) {
|
| 249 | 19x |
this->recruitment_id.set(recruitment_id); |
| 250 |
} |
|
| 251 | ||
| 252 |
/** |
|
| 253 |
* @brief Add a fleet id to the list of fleets |
|
| 254 |
* operating on this population. |
|
| 255 |
*/ |
|
| 256 | 36x |
void AddFleet(uint32_t fleet_id) { this->fleet_ids->insert(fleet_id); }
|
| 257 | ||
| 258 |
/** |
|
| 259 |
* @brief Extracts derived quantities back to the Rcpp interface object from |
|
| 260 |
* the Information object. |
|
| 261 |
*/ |
|
| 262 | ! |
virtual void finalize() {
|
| 263 | ! |
if (this->finalized) {
|
| 264 |
// log warning that finalize has been called more than once. |
|
| 265 | ! |
FIMS_WARNING_LOG("Population " + fims::to_string(this->id) +
|
| 266 |
" has been finalized already."); |
|
| 267 |
} |
|
| 268 | ||
| 269 | ! |
this->finalized = true; // indicate this has been called already |
| 270 | ||
| 271 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 272 | ! |
fims_info::Information<double>::GetInstance(); |
| 273 | ||
| 274 | ! |
fims_info::Information<double>::population_iterator it; |
| 275 | ||
| 276 | ! |
it = info->populations.find(this->id); |
| 277 | ||
| 278 |
std::shared_ptr<fims_popdy::Population<double>> pop = |
|
| 279 | ! |
info->populations[this->id]; |
| 280 | ! |
it = info->populations.find(this->id); |
| 281 | ! |
if (it == info->populations.end()) {
|
| 282 | ! |
FIMS_WARNING_LOG("Population " + fims::to_string(this->id) +
|
| 283 |
" not found in Information."); |
|
| 284 | ! |
return; |
| 285 |
} else {
|
|
| 286 | ! |
for (size_t i = 0; i < this->log_M.size(); i++) {
|
| 287 | ! |
if (this->log_M[i].estimation_type_m.get() == "constant") {
|
| 288 | ! |
this->log_M[i].final_value_m = this->log_M[i].initial_value_m; |
| 289 |
} else {
|
|
| 290 | ! |
this->log_M[i].final_value_m = pop->log_M[i]; |
| 291 |
} |
|
| 292 |
} |
|
| 293 | ||
| 294 | ! |
for (size_t i = 0; i < this->log_init_naa.size(); i++) {
|
| 295 | ! |
if (this->log_init_naa[i].estimation_type_m.get() == "constant") {
|
| 296 | ! |
this->log_init_naa[i].final_value_m = |
| 297 | ! |
this->log_init_naa[i].initial_value_m; |
| 298 |
} else {
|
|
| 299 | ! |
this->log_init_naa[i].final_value_m = pop->log_init_naa[i]; |
| 300 |
} |
|
| 301 |
} |
|
| 302 |
} |
|
| 303 |
} |
|
| 304 | ||
| 305 |
#ifdef TMB_MODEL |
|
| 306 | ||
| 307 |
template <typename Type> |
|
| 308 | 76x |
bool add_to_fims_tmb_internal() {
|
| 309 | 76x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 310 |
fims_info::Information<Type>::GetInstance(); |
|
| 311 | ||
| 312 | 76x |
std::shared_ptr<fims_popdy::Population<Type>> population = |
| 313 |
std::make_shared<fims_popdy::Population<Type>>(); |
|
| 314 | ||
| 315 | 76x |
std::stringstream ss; |
| 316 | ||
| 317 |
// set relative info |
|
| 318 | 76x |
population->id = this->id; |
| 319 | 76x |
population->n_years = this->n_years.get(); |
| 320 | 76x |
population->n_fleets = this->n_fleets.get(); |
| 321 |
// only define ages if n_ages greater than 0 |
|
| 322 | 76x |
if (this->n_ages.get() > 0) {
|
| 323 | 76x |
population->n_ages = this->n_ages.get(); |
| 324 | 76x |
if (this->n_ages.get() == this->ages.size()) {
|
| 325 | 76x |
population->ages.resize(this->n_ages.get()); |
| 326 |
} else {
|
|
| 327 | ! |
warning("The ages vector is not of size n_ages.");
|
| 328 |
} |
|
| 329 |
} |
|
| 330 | ||
| 331 | 76x |
fleet_ids_iterator it; |
| 332 | 220x |
for (it = this->fleet_ids->begin(); it != this->fleet_ids->end(); it++) {
|
| 333 | 144x |
population->fleet_ids.insert(*it); |
| 334 |
} |
|
| 335 | ||
| 336 | 76x |
population->growth_id = this->growth_id.get(); |
| 337 | 76x |
population->recruitment_id = this->recruitment_id.get(); |
| 338 | 76x |
population->maturity_id = this->maturity_id.get(); |
| 339 | 76x |
population->log_M.resize(this->log_M.size()); |
| 340 | 76x |
population->log_init_naa.resize(this->log_init_naa.size()); |
| 341 | 27436x |
for (size_t i = 0; i < log_M.size(); i++) {
|
| 342 | 27360x |
population->log_M[i] = this->log_M[i].initial_value_m; |
| 343 | 27360x |
if (this->log_M[i].estimation_type_m.get() == "fixed_effects") {
|
| 344 | ! |
ss.str("");
|
| 345 | ! |
ss << "Population." << this->id << ".log_M." << this->log_M[i].id_m; |
| 346 | ! |
info->RegisterParameterName(ss.str()); |
| 347 | ! |
info->RegisterParameter(population->log_M[i]); |
| 348 |
} |
|
| 349 | 27360x |
if (this->log_M[i].estimation_type_m.get() == "random_effects") {
|
| 350 | ! |
ss.str("");
|
| 351 | ! |
ss << "Population." << this->id << ".log_M." << this->log_M[i].id_m; |
| 352 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 353 | ! |
info->RegisterRandomEffect(population->log_M[i]); |
| 354 |
} |
|
| 355 |
} |
|
| 356 | 76x |
info->variable_map[this->log_M.id_m] = &(population)->log_M; |
| 357 | ||
| 358 | 988x |
for (size_t i = 0; i < log_init_naa.size(); i++) {
|
| 359 | 912x |
population->log_init_naa[i] = this->log_init_naa[i].initial_value_m; |
| 360 | 912x |
if (this->log_init_naa[i].estimation_type_m.get() == "fixed_effects") {
|
| 361 | 864x |
ss.str("");
|
| 362 | 864x |
ss << "Population." << this->id << ".log_init_naa." |
| 363 | 864x |
<< this->log_init_naa[i].id_m; |
| 364 | 864x |
info->RegisterParameterName(ss.str()); |
| 365 | 864x |
info->RegisterParameter(population->log_init_naa[i]); |
| 366 |
} |
|
| 367 | 912x |
if (this->log_init_naa[i].estimation_type_m.get() == "random_effects") {
|
| 368 | ! |
ss.str("");
|
| 369 | ! |
ss << "Population." << this->id << ".log_init_naa." |
| 370 | ! |
<< this->log_init_naa[i].id_m; |
| 371 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 372 | ! |
info->RegisterRandomEffect(population->log_init_naa[i]); |
| 373 |
} |
|
| 374 |
} |
|
| 375 | 76x |
info->variable_map[this->log_init_naa.id_m] = &(population)->log_init_naa; |
| 376 | ||
| 377 | 988x |
for (int i = 0; i < ages.size(); i++) {
|
| 378 | 912x |
population->ages[i] = this->ages[i]; |
| 379 |
} |
|
| 380 | ||
| 381 |
// add to Information |
|
| 382 | 76x |
info->populations[population->id] = population; |
| 383 | ||
| 384 | 76x |
return true; |
| 385 |
} |
|
| 386 | ||
| 387 |
/** |
|
| 388 |
* @brief Adds the parameters to the TMB model. |
|
| 389 |
* @return A boolean of true. |
|
| 390 |
*/ |
|
| 391 | 19x |
virtual bool add_to_fims_tmb() {
|
| 392 |
#ifdef TMBAD_FRAMEWORK |
|
| 393 | 19x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 394 | 19x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 395 |
#else |
|
| 396 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 397 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 398 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 399 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 400 |
#endif |
|
| 401 | ||
| 402 | 19x |
return true; |
| 403 |
} |
|
| 404 | ||
| 405 |
#endif |
|
| 406 |
}; |
|
| 407 | ||
| 408 |
#endif |
| 1 |
/** |
|
| 2 |
* @file rcpp_recruitment.hpp |
|
| 3 |
* @brief The Rcpp interface to declare different types of recruitment, e.g., |
|
| 4 |
* Beverton--Holt stock--recruitment relationship. Allows for the use of |
|
| 5 |
* methods::new() in R. |
|
| 6 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 7 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 8 |
* folder for reuse information. |
|
| 9 |
*/ |
|
| 10 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_RECRUITMENT_HPP |
|
| 11 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_RECRUITMENT_HPP |
|
| 12 | ||
| 13 |
#include "../../../population_dynamics/recruitment/recruitment.hpp" |
|
| 14 |
#include "rcpp_interface_base.hpp" |
|
| 15 | ||
| 16 |
/** |
|
| 17 |
* @brief Rcpp interface that serves as the parent class for Rcpp recruitment |
|
| 18 |
* interfaces. This type should be inherited and not called from R directly. |
|
| 19 |
*/ |
|
| 20 |
class RecruitmentInterfaceBase : public FIMSRcppInterfaceBase {
|
|
| 21 |
public: |
|
| 22 |
/** |
|
| 23 |
* @brief The static id of the RecruitmentInterfaceBase object. |
|
| 24 |
*/ |
|
| 25 |
static uint32_t id_g; |
|
| 26 |
/** |
|
| 27 |
* @brief The local id of the RecruitmentInterfaceBase object. |
|
| 28 |
*/ |
|
| 29 |
uint32_t id; |
|
| 30 |
/** |
|
| 31 |
* @brief The process id of the RecruitmentInterfaceBase object. |
|
| 32 |
*/ |
|
| 33 |
SharedInt process_id = -999; |
|
| 34 |
/** |
|
| 35 |
* @brief The map associating the IDs of RecruitmentInterfaceBase to the |
|
| 36 |
* objects. This is a live object, which is an object that has been created |
|
| 37 |
* and lives in memory. |
|
| 38 |
*/ |
|
| 39 |
static std::map<uint32_t, std::shared_ptr<RecruitmentInterfaceBase>> |
|
| 40 |
live_objects; |
|
| 41 | ||
| 42 |
/** |
|
| 43 |
* @brief The constructor. |
|
| 44 |
*/ |
|
| 45 | 45x |
RecruitmentInterfaceBase() {
|
| 46 | 45x |
this->id = RecruitmentInterfaceBase::id_g++; |
| 47 |
/* Create instance of map: key is id and value is pointer to |
|
| 48 |
RecruitmentInterfaceBase */ |
|
| 49 |
// RecruitmentInterfaceBase::live_objects[this->id] = this; |
|
| 50 |
} |
|
| 51 | ||
| 52 |
/** |
|
| 53 |
* @brief Construct a new Recruitment Interface Base object |
|
| 54 |
* |
|
| 55 |
* @param other |
|
| 56 |
*/ |
|
| 57 | 45x |
RecruitmentInterfaceBase(const RecruitmentInterfaceBase &other) |
| 58 | 45x |
: id(other.id), process_id(other.process_id) {}
|
| 59 | ||
| 60 |
/** |
|
| 61 |
* @brief The destructor. |
|
| 62 |
*/ |
|
| 63 | 90x |
virtual ~RecruitmentInterfaceBase() {}
|
| 64 | ||
| 65 |
/** |
|
| 66 |
* @brief Get the ID for the child recruitment interface objects to inherit. |
|
| 67 |
*/ |
|
| 68 |
virtual uint32_t get_id() = 0; |
|
| 69 | ||
| 70 |
/** |
|
| 71 |
* @brief A method for each child recruitment interface object to inherit so |
|
| 72 |
* each recruitment option can have an evaluate_mean() function. |
|
| 73 |
*/ |
|
| 74 |
virtual double evaluate_mean(double spawners, double ssbzero) = 0; |
|
| 75 | ||
| 76 |
/** |
|
| 77 |
* @brief A method for each child recruitment process interface object to |
|
| 78 |
* inherit so each recruitment process option can have a evaluate_process() |
|
| 79 |
* function. |
|
| 80 |
*/ |
|
| 81 |
virtual double evaluate_process(size_t pos) = 0; |
|
| 82 |
}; |
|
| 83 |
// static id of the RecruitmentInterfaceBase object |
|
| 84 |
uint32_t RecruitmentInterfaceBase::id_g = 1; |
|
| 85 |
// local id of the RecruitmentInterfaceBase object map relating the ID of the |
|
| 86 |
// RecruitmentInterfaceBase to the RecruitmentInterfaceBase objects |
|
| 87 |
std::map<uint32_t, std::shared_ptr<RecruitmentInterfaceBase>> |
|
| 88 |
RecruitmentInterfaceBase::live_objects; |
|
| 89 | ||
| 90 |
/** |
|
| 91 |
* @brief Rcpp interface for Beverton--Holt to instantiate from R: |
|
| 92 |
* beverton_holt <- methods::new(beverton_holt). |
|
| 93 |
*/ |
|
| 94 |
class BevertonHoltRecruitmentInterface : public RecruitmentInterfaceBase {
|
|
| 95 |
public: |
|
| 96 |
/** |
|
| 97 |
* @brief The number of years. |
|
| 98 |
*/ |
|
| 99 |
SharedInt n_years; |
|
| 100 |
/** |
|
| 101 |
* @brief The logistic transformation of steepness (h; productivity of the |
|
| 102 |
* population), where the parameter is transformed to constrain it between |
|
| 103 |
* 0.2 and 1.0. |
|
| 104 |
*/ |
|
| 105 |
ParameterVector logit_steep; |
|
| 106 |
/** |
|
| 107 |
* @brief The natural log of recruitment at unfished biomass. |
|
| 108 |
*/ |
|
| 109 |
ParameterVector log_rzero; |
|
| 110 |
/** |
|
| 111 |
* @brief The natural log of recruitment deviations. |
|
| 112 |
*/ |
|
| 113 |
ParameterVector log_devs; |
|
| 114 |
/** |
|
| 115 |
* @brief The recruitment random effect parameter on the natural log scale. |
|
| 116 |
*/ |
|
| 117 |
ParameterVector log_r; |
|
| 118 |
/** |
|
| 119 |
* @brief Expectation of the recruitment process. |
|
| 120 |
*/ |
|
| 121 |
ParameterVector log_expected_recruitment; |
|
| 122 |
/** |
|
| 123 |
* @brief The estimate of the logit transformation of steepness. |
|
| 124 |
*/ |
|
| 125 |
fims_double estimated_logit_steep; |
|
| 126 |
/** |
|
| 127 |
* @brief The estimate of the natural log of recruitment at unfished biomass. |
|
| 128 |
*/ |
|
| 129 |
fims_double estimated_log_rzero; |
|
| 130 |
/** |
|
| 131 |
* @brief The estimates of the natural log of recruitment deviations. |
|
| 132 |
*/ |
|
| 133 |
RealVector estimated_log_devs; |
|
| 134 | ||
| 135 |
/** |
|
| 136 |
* @brief The constructor. |
|
| 137 |
*/ |
|
| 138 | 25x |
BevertonHoltRecruitmentInterface() : RecruitmentInterfaceBase() {
|
| 139 | 25x |
RecruitmentInterfaceBase::live_objects[this->id] = |
| 140 | 50x |
std::make_shared<BevertonHoltRecruitmentInterface>(*this); |
| 141 | 25x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 142 | 25x |
RecruitmentInterfaceBase::live_objects[this->id]); |
| 143 |
} |
|
| 144 | ||
| 145 |
/** |
|
| 146 |
* @brief Construct a new Beverton--Holt Recruitment Interface object. |
|
| 147 |
* |
|
| 148 |
* @param other The passed object to copy. |
|
| 149 |
*/ |
|
| 150 | 25x |
BevertonHoltRecruitmentInterface( |
| 151 |
const BevertonHoltRecruitmentInterface &other) |
|
| 152 | 25x |
: RecruitmentInterfaceBase(other), |
| 153 | 25x |
n_years(other.n_years), |
| 154 | 25x |
logit_steep(other.logit_steep), |
| 155 | 25x |
log_rzero(other.log_rzero), |
| 156 | 25x |
log_devs(other.log_devs), |
| 157 | 25x |
log_r(other.log_r), |
| 158 | 25x |
log_expected_recruitment(other.log_expected_recruitment), |
| 159 | 25x |
estimated_logit_steep(other.estimated_logit_steep), |
| 160 | 25x |
estimated_log_rzero(other.estimated_log_rzero), |
| 161 | 50x |
estimated_log_devs(other.estimated_log_devs) {}
|
| 162 | ||
| 163 |
/** |
|
| 164 |
* @brief The destructor. |
|
| 165 |
*/ |
|
| 166 | 150x |
virtual ~BevertonHoltRecruitmentInterface() {}
|
| 167 | ||
| 168 |
/** |
|
| 169 |
* @brief Gets the ID of the interface base object. |
|
| 170 |
* @return The ID. |
|
| 171 |
*/ |
|
| 172 | 21x |
virtual uint32_t get_id() { return this->id; }
|
| 173 | ||
| 174 |
/** |
|
| 175 |
* @brief Set the unique ID for the recruitment process object. |
|
| 176 |
* @param process_id Unique ID for the recruitment process object. |
|
| 177 |
*/ |
|
| 178 | 19x |
void SetRecruitmentProcessID(uint32_t process_id) {
|
| 179 | 19x |
this->process_id.set(process_id); |
| 180 |
} |
|
| 181 | ||
| 182 |
/** |
|
| 183 |
* @brief Evaluate recruitment using the Beverton--Holt stock--recruitment |
|
| 184 |
* relationship. |
|
| 185 |
* @param spawners Spawning biomass per time step. |
|
| 186 |
* @param ssbzero The biomass at unfished levels. |
|
| 187 |
* TODO: Change to sbzero if continuing to use acronyms. |
|
| 188 |
*/ |
|
| 189 | 2x |
virtual double evaluate_mean(double spawners, double ssbzero) {
|
| 190 | 2x |
fims_popdy::SRBevertonHolt<double> BevHolt; |
| 191 | 2x |
BevHolt.logit_steep.resize(1); |
| 192 | 2x |
BevHolt.logit_steep[0] = this->logit_steep[0].initial_value_m; |
| 193 | 2x |
if (this->logit_steep[0].initial_value_m == 1.0) {
|
| 194 | 1x |
warning( |
| 195 |
"Steepness is subject to a logit transformation. " |
|
| 196 |
"Fixing it at 1.0 is not currently possible."); |
|
| 197 |
} |
|
| 198 | 2x |
BevHolt.log_rzero.resize(1); |
| 199 | 2x |
BevHolt.log_rzero[0] = this->log_rzero[0].initial_value_m; |
| 200 | ||
| 201 | 4x |
return BevHolt.evaluate_mean(spawners, ssbzero); |
| 202 |
} |
|
| 203 | ||
| 204 |
/** |
|
| 205 |
* @brief Evaluate recruitment process - returns 0 in this module. |
|
| 206 |
* @param pos Position index, e.g., which year. |
|
| 207 |
*/ |
|
| 208 | ! |
virtual double evaluate_process(size_t pos) { return 0; }
|
| 209 | ||
| 210 |
/** |
|
| 211 |
* @brief Extracts derived quantities back to the Rcpp interface object from |
|
| 212 |
* the Information object. |
|
| 213 |
*/ |
|
| 214 | 13x |
virtual void finalize() {
|
| 215 | 13x |
if (this->finalized) {
|
| 216 |
// log warning that finalize has been called more than once. |
|
| 217 | ! |
FIMS_WARNING_LOG("Beverton-Holt Recruitment " +
|
| 218 |
fims::to_string(this->id) + |
|
| 219 |
" has been finalized already."); |
|
| 220 |
} |
|
| 221 | ||
| 222 | 13x |
this->finalized = true; // indicate this has been called already |
| 223 | ||
| 224 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 225 | 13x |
fims_info::Information<double>::GetInstance(); |
| 226 | ||
| 227 | 13x |
fims_info::Information<double>::recruitment_models_iterator it; |
| 228 | ||
| 229 | 13x |
it = info->recruitment_models.find(this->id); |
| 230 | ||
| 231 | 13x |
if (it == info->recruitment_models.end()) {
|
| 232 | ! |
FIMS_WARNING_LOG("Beverton-Holt Recruitment " +
|
| 233 |
fims::to_string(this->id) + |
|
| 234 |
" not found in Information."); |
|
| 235 | ! |
return; |
| 236 |
} else {
|
|
| 237 |
std::shared_ptr<fims_popdy::SRBevertonHolt<double>> recr = |
|
| 238 |
std::dynamic_pointer_cast<fims_popdy::SRBevertonHolt<double>>( |
|
| 239 | 13x |
it->second); |
| 240 | ||
| 241 | 26x |
for (size_t i = 0; i < this->logit_steep.size(); i++) {
|
| 242 | 13x |
if (this->logit_steep[i].estimation_type_m.get() == "constant") {
|
| 243 | 13x |
this->logit_steep[i].final_value_m = |
| 244 | 13x |
this->logit_steep[i].initial_value_m; |
| 245 |
} else {
|
|
| 246 | ! |
this->logit_steep[i].final_value_m = recr->logit_steep[i]; |
| 247 |
} |
|
| 248 |
} |
|
| 249 | ||
| 250 | 26x |
for (size_t i = 0; i < log_rzero.size(); i++) {
|
| 251 | 13x |
if (log_rzero[i].estimation_type_m.get() == "constant") {
|
| 252 | 1x |
this->log_rzero[i].final_value_m = this->log_rzero[i].initial_value_m; |
| 253 |
} else {
|
|
| 254 | 12x |
this->log_rzero[i].final_value_m = recr->log_rzero[i]; |
| 255 |
} |
|
| 256 |
} |
|
| 257 | ||
| 258 | 362x |
for (R_xlen_t i = 0; i < this->log_devs.size(); i++) {
|
| 259 | 349x |
if (this->log_devs[i].estimation_type_m.get() == "constant") {
|
| 260 | 291x |
this->log_devs[i].final_value_m = this->log_devs[i].initial_value_m; |
| 261 |
} else {
|
|
| 262 | 58x |
this->log_devs[i].final_value_m = recr->log_recruit_devs[i]; |
| 263 |
} |
|
| 264 |
} |
|
| 265 | ||
| 266 | 278x |
for (R_xlen_t i = 0; i < this->log_r.size(); i++) {
|
| 267 | 265x |
if (this->log_r[i].estimation_type_m.get() == "constant") {
|
| 268 | 236x |
this->log_r[i].final_value_m = this->log_r[i].initial_value_m; |
| 269 |
} else {
|
|
| 270 | 29x |
this->log_r[i].final_value_m = recr->log_r[i]; |
| 271 |
} |
|
| 272 |
} |
|
| 273 |
} |
|
| 274 |
} |
|
| 275 |
/** |
|
| 276 |
* @brief Sets the uncertainty values for the parameters from the standard |
|
| 277 |
* error values passed from R. |
|
| 278 |
* @param se_values A map of parameter names and their associated standard |
|
| 279 |
* error values. |
|
| 280 |
*/ |
|
| 281 | 13x |
virtual void set_uncertainty( |
| 282 |
std::map<std::string, std::vector<double>> &se_values) {
|
|
| 283 |
fims::Vector<double> logit_steep_uncertainty(this->logit_steep.size(), |
|
| 284 | 13x |
-99999999); |
| 285 | 26x |
this->get_se_values("logit_steep", se_values, logit_steep_uncertainty);
|
| 286 |
fims::Vector<double> log_rzero_uncertainty(this->log_rzero.size(), |
|
| 287 | 13x |
-999999999); |
| 288 | 26x |
this->get_se_values("log_rzero", se_values, log_rzero_uncertainty);
|
| 289 |
fims::Vector<double> log_devs_uncertainty(this->log_devs.size(), |
|
| 290 | 13x |
-999999999); |
| 291 | 26x |
this->get_se_values("log_devs", se_values, log_devs_uncertainty);
|
| 292 | 26x |
for (size_t i = 0; i < this->logit_steep.size(); i++) {
|
| 293 | 13x |
this->logit_steep[i].uncertainty_m = logit_steep_uncertainty[i]; |
| 294 |
} |
|
| 295 | 26x |
for (size_t i = 0; i < this->log_rzero.size(); i++) {
|
| 296 | 13x |
this->log_rzero[i].uncertainty_m = log_rzero_uncertainty[i]; |
| 297 |
} |
|
| 298 | 362x |
for (size_t i = 0; i < this->log_devs.size(); i++) {
|
| 299 | 349x |
this->log_devs[i].uncertainty_m = log_devs_uncertainty[i]; |
| 300 |
} |
|
| 301 |
} |
|
| 302 | ||
| 303 |
/** |
|
| 304 |
* @brief Converts the data to json representation for the output. |
|
| 305 |
* @return A string is returned specifying that the module relates to the |
|
| 306 |
* recruitment interface with Beverton--Holt stock--recruitment relationship. |
|
| 307 |
* It also returns the ID and the parameters. This string is formatted for a |
|
| 308 |
* json file. |
|
| 309 |
*/ |
|
| 310 | 13x |
virtual std::string to_json() {
|
| 311 | 13x |
std::stringstream ss; |
| 312 | ||
| 313 | 13x |
ss << "{\n";
|
| 314 | 13x |
ss << " \"module_name\": \"Recruitment\",\n"; |
| 315 | 13x |
ss << " \"module_type\": \"Beverton-Holt\",\n"; |
| 316 | 13x |
ss << " \"module_id\": " << this->id << ",\n"; |
| 317 | ||
| 318 | 13x |
ss << " \"parameters\": [\n{\n";
|
| 319 | 13x |
ss << " \"name\": \"logit_steep\",\n"; |
| 320 | 13x |
ss << " \"id\":" << this->logit_steep.id_m << ",\n"; |
| 321 | 13x |
ss << " \"type\": \"vector\",\n"; |
| 322 | 13x |
ss << " \"dimensionality\": {\n";
|
| 323 | 13x |
ss << " \"header\": [null],\n"; |
| 324 | 13x |
ss << " \"dimensions\": [" << this->logit_steep.size() << "]\n},\n"; |
| 325 | 13x |
ss << " \"values\":" << this->logit_steep << "},\n"; |
| 326 | ||
| 327 | 13x |
ss << "{\n";
|
| 328 | 13x |
ss << " \"name\": \"log_rzero\",\n"; |
| 329 | 13x |
ss << " \"id\":" << this->log_rzero.id_m << ",\n"; |
| 330 | 13x |
ss << " \"type\": \"vector\",\n"; |
| 331 | 13x |
ss << " \"dimensionality\": {\n";
|
| 332 | 13x |
ss << " \"header\": [null],\n"; |
| 333 | 13x |
ss << " \"dimensions\": [" << this->log_rzero.size() << "]\n},\n"; |
| 334 | 13x |
ss << " \"values\":" << this->log_rzero << "},\n"; |
| 335 | ||
| 336 | 13x |
ss << "{\n";
|
| 337 | 13x |
ss << " \"name\": \"log_devs\",\n"; |
| 338 | 13x |
ss << " \"id\":" << this->log_devs.id_m << ",\n"; |
| 339 | 13x |
ss << " \"type\": \"vector\",\n"; |
| 340 | 13x |
ss << " \"dimensionality\": {\n";
|
| 341 | 13x |
ss << " \"header\": [\"n_years-1\"],\n"; |
| 342 | 13x |
ss << " \"dimensions\": [" << this->log_devs.size() << "]\n},\n"; |
| 343 | 13x |
ss << " \"values\":" << this->log_devs << "}]\n"; |
| 344 | 13x |
ss << "}"; |
| 345 | 26x |
return ss.str(); |
| 346 |
} |
|
| 347 | ||
| 348 |
#ifdef TMB_MODEL |
|
| 349 | ||
| 350 |
template <typename Type> |
|
| 351 | 84x |
bool add_to_fims_tmb_internal() {
|
| 352 | 84x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 353 |
fims_info::Information<Type>::GetInstance(); |
|
| 354 | ||
| 355 | 84x |
std::shared_ptr<fims_popdy::SRBevertonHolt<Type>> recruitment = |
| 356 |
std::make_shared<fims_popdy::SRBevertonHolt<Type>>(); |
|
| 357 | ||
| 358 | 84x |
std::stringstream ss; |
| 359 | ||
| 360 |
// set relative info |
|
| 361 | 84x |
recruitment->id = this->id; |
| 362 | 84x |
recruitment->process_id = this->process_id.get(); |
| 363 |
// set logit_steep |
|
| 364 | 84x |
recruitment->logit_steep.resize(this->logit_steep.size()); |
| 365 | 168x |
for (size_t i = 0; i < this->logit_steep.size(); i++) {
|
| 366 | 84x |
recruitment->logit_steep[i] = this->logit_steep[i].initial_value_m; |
| 367 | ||
| 368 | 84x |
if (this->logit_steep[i].estimation_type_m.get() == "fixed_effects") {
|
| 369 | 4x |
ss.str("");
|
| 370 | 4x |
ss << "Recruitment." << this->id << ".logit_steep." |
| 371 | 4x |
<< this->logit_steep[i].id_m; |
| 372 | 4x |
info->RegisterParameterName(ss.str()); |
| 373 | 4x |
info->RegisterParameter(recruitment->logit_steep[i]); |
| 374 |
} |
|
| 375 | 84x |
if (this->logit_steep[i].estimation_type_m.get() == "random_effects") {
|
| 376 | 4x |
ss.str("");
|
| 377 | 4x |
ss << "Recruitment." << this->id << ".logit_steep." |
| 378 | 4x |
<< this->logit_steep[i].id_m; |
| 379 | 4x |
info->RegisterRandomEffectName(ss.str()); |
| 380 | 4x |
info->RegisterRandomEffect(recruitment->logit_steep[i]); |
| 381 |
} |
|
| 382 |
} |
|
| 383 | 84x |
info->variable_map[this->logit_steep.id_m] = &(recruitment)->logit_steep; |
| 384 | ||
| 385 |
// set log_rzero |
|
| 386 | 84x |
recruitment->log_rzero.resize(this->log_rzero.size()); |
| 387 | 168x |
for (size_t i = 0; i < this->log_rzero.size(); i++) {
|
| 388 | 84x |
recruitment->log_rzero[i] = this->log_rzero[i].initial_value_m; |
| 389 | ||
| 390 | 84x |
if (this->log_rzero[i].estimation_type_m.get() == "fixed_effects") {
|
| 391 | 76x |
ss.str("");
|
| 392 | 76x |
ss << "Recruitment." << this->id << ".log_rzero." |
| 393 | 76x |
<< this->log_rzero[i].id_m; |
| 394 | 76x |
info->RegisterParameterName(ss.str()); |
| 395 | 76x |
info->RegisterParameter(recruitment->log_rzero[i]); |
| 396 |
} |
|
| 397 | 84x |
if (this->log_rzero[i].estimation_type_m.get() == "random_effects") {
|
| 398 | 4x |
ss.str("");
|
| 399 | 4x |
ss << "Recruitment." << this->id << ".log_rzero." |
| 400 | 4x |
<< this->log_rzero[i].id_m; |
| 401 | 4x |
info->RegisterRandomEffectName(ss.str()); |
| 402 | 4x |
info->RegisterRandomEffect(recruitment->log_rzero[i]); |
| 403 |
} |
|
| 404 |
} |
|
| 405 | 84x |
info->variable_map[this->log_rzero.id_m] = &(recruitment)->log_rzero; |
| 406 |
// set log_recruit_devs |
|
| 407 | 84x |
recruitment->log_recruit_devs.resize(this->log_devs.size()); |
| 408 | 2184x |
for (size_t i = 0; i < this->log_devs.size(); i++) {
|
| 409 | 2100x |
recruitment->log_recruit_devs[i] = this->log_devs[i].initial_value_m; |
| 410 | ||
| 411 | 2100x |
if (this->log_devs[i].estimation_type_m.get() == "fixed_effects") {
|
| 412 | 540x |
ss.str("");
|
| 413 | 540x |
ss << "Recruitment." << this->id << ".log_devs." |
| 414 | 540x |
<< this->log_devs[i].id_m; |
| 415 | 540x |
info->RegisterParameterName(ss.str()); |
| 416 | 540x |
info->RegisterParameter(recruitment->log_recruit_devs[i]); |
| 417 |
} |
|
| 418 | 2100x |
if (this->log_devs[i].estimation_type_m.get() == "random_effects") {
|
| 419 | 232x |
ss.str("");
|
| 420 | 232x |
ss << "Recruitment." << this->id << ".log_devs." |
| 421 | 232x |
<< this->log_devs[i].id_m; |
| 422 | 232x |
info->RegisterRandomEffectName(ss.str()); |
| 423 | 232x |
info->RegisterRandomEffect(recruitment->log_recruit_devs[i]); |
| 424 |
} |
|
| 425 |
} |
|
| 426 | ||
| 427 | 84x |
info->variable_map[this->log_devs.id_m] = &(recruitment)->log_recruit_devs; |
| 428 | ||
| 429 |
// set log_r |
|
| 430 | 84x |
recruitment->log_r.resize(this->log_r.size()); |
| 431 | 1512x |
for (size_t i = 0; i < log_r.size(); i++) {
|
| 432 | 1428x |
recruitment->log_r[i] = this->log_r[i].initial_value_m; |
| 433 | ||
| 434 | 1428x |
if (this->log_r[i].estimation_type_m.get() == "fixed_effects") {
|
| 435 | ! |
ss.str("");
|
| 436 | ! |
ss << "Recruitment." << this->id << ".log_r." << this->log_r[i].id_m; |
| 437 | ! |
info->RegisterParameterName(ss.str()); |
| 438 | ! |
info->RegisterParameter(recruitment->log_r[i]); |
| 439 |
} |
|
| 440 | 1428x |
if (this->log_r[i].estimation_type_m.get() == "random_effects") {
|
| 441 | 116x |
ss.str("");
|
| 442 | 116x |
ss << "Recruitment." << this->id << ".log_r." << this->log_r[i].id_m; |
| 443 | 116x |
info->RegisterRandomEffectName(ss.str()); |
| 444 | 116x |
info->RegisterRandomEffect(recruitment->log_r[i]); |
| 445 |
} |
|
| 446 |
} |
|
| 447 | ||
| 448 | 84x |
info->variable_map[this->log_r.id_m] = &(recruitment)->log_r; |
| 449 |
// set log_expected_recruitment |
|
| 450 | 84x |
recruitment->log_expected_recruitment.resize(this->n_years.get() + 1); |
| 451 | 2448x |
for (size_t i = 0; i < this->n_years.get() + 1; i++) {
|
| 452 | 2364x |
recruitment->log_expected_recruitment[i] = 0; |
| 453 |
} |
|
| 454 | 84x |
info->variable_map[this->log_expected_recruitment.id_m] = |
| 455 | 84x |
&(recruitment)->log_expected_recruitment; |
| 456 | ||
| 457 |
// add to Information |
|
| 458 | 84x |
info->recruitment_models[recruitment->id] = recruitment; |
| 459 | ||
| 460 | 84x |
return true; |
| 461 |
} |
|
| 462 | ||
| 463 |
/** |
|
| 464 |
* @brief Adds the parameters to the TMB model. |
|
| 465 |
* @return A boolean of true. |
|
| 466 |
*/ |
|
| 467 | 21x |
virtual bool add_to_fims_tmb() {
|
| 468 |
#ifdef TMBAD_FRAMEWORK |
|
| 469 | 21x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 470 | 21x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 471 |
#else |
|
| 472 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 473 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 474 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 475 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 476 |
#endif |
|
| 477 | ||
| 478 | 21x |
return true; |
| 479 |
} |
|
| 480 | ||
| 481 |
#endif |
|
| 482 |
}; |
|
| 483 | ||
| 484 |
/** |
|
| 485 |
* @brief Rcpp interface for Log--Devs to instantiate from R: |
|
| 486 |
* log_devs <- methods::new(log_devs). |
|
| 487 |
*/ |
|
| 488 |
class LogDevsRecruitmentInterface : public RecruitmentInterfaceBase {
|
|
| 489 |
public: |
|
| 490 |
/** |
|
| 491 |
* @brief The constructor. |
|
| 492 |
*/ |
|
| 493 | 19x |
LogDevsRecruitmentInterface() : RecruitmentInterfaceBase() {
|
| 494 | 19x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 495 | 38x |
std::make_shared<LogDevsRecruitmentInterface>(*this)); |
| 496 |
} |
|
| 497 | ||
| 498 |
/** |
|
| 499 |
* @brief The destructor. |
|
| 500 |
*/ |
|
| 501 | 114x |
virtual ~LogDevsRecruitmentInterface() {}
|
| 502 | ||
| 503 |
/** |
|
| 504 |
* @brief Gets the ID of the interface base object. |
|
| 505 |
* @return The ID. |
|
| 506 |
*/ |
|
| 507 | 18x |
virtual uint32_t get_id() { return this->id; }
|
| 508 | ||
| 509 |
/** |
|
| 510 |
* @brief Evaluate mean - returns empty function for this module. |
|
| 511 |
* @param spawners Spawning biomass per time step. |
|
| 512 |
* @param ssbzero The biomass at unfished levels. |
|
| 513 |
*/ |
|
| 514 | ! |
virtual double evaluate_mean(double spawners, double ssbzero) { return 0; }
|
| 515 | ||
| 516 |
/** |
|
| 517 |
* @brief Evaluate recruitment process using the Log--Devs approach. |
|
| 518 |
* @param pos Position index, e.g., which year. |
|
| 519 |
*/ |
|
| 520 | ! |
virtual double evaluate_process(size_t pos) {
|
| 521 | ! |
fims_popdy::LogDevs<double> LogDevs; |
| 522 | ||
| 523 | ! |
return LogDevs.evaluate_process(pos); |
| 524 |
} |
|
| 525 | ||
| 526 |
#ifdef TMB_MODEL |
|
| 527 | ||
| 528 |
template <typename Type> |
|
| 529 | 72x |
bool add_to_fims_tmb_internal() {
|
| 530 | 72x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 531 |
fims_info::Information<Type>::GetInstance(); |
|
| 532 | ||
| 533 | 72x |
std::shared_ptr<fims_popdy::LogDevs<Type>> recruitment_process = |
| 534 |
std::make_shared<fims_popdy::LogDevs<Type>>(); |
|
| 535 | ||
| 536 | 72x |
recruitment_process->id = this->id; |
| 537 | ||
| 538 |
// add to Information |
|
| 539 | 72x |
info->recruitment_process_models[recruitment_process->id] = |
| 540 |
recruitment_process; |
|
| 541 | ||
| 542 | 72x |
return true; |
| 543 |
} |
|
| 544 | ||
| 545 |
/** |
|
| 546 |
* @brief Adds the parameters to the TMB model. |
|
| 547 |
* @return A boolean of true. |
|
| 548 |
*/ |
|
| 549 | 18x |
virtual bool add_to_fims_tmb() {
|
| 550 |
#ifdef TMBAD_FRAMEWORK |
|
| 551 | 18x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 552 | 18x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 553 |
#else |
|
| 554 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 555 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 556 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 557 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 558 |
#endif |
|
| 559 | ||
| 560 | 18x |
return true; |
| 561 |
} |
|
| 562 | ||
| 563 |
#endif |
|
| 564 |
}; |
|
| 565 | ||
| 566 |
/** |
|
| 567 |
* @brief Rcpp interface for Log--R to instantiate from R: |
|
| 568 |
* log_r <- methods::new(log_r). |
|
| 569 |
*/ |
|
| 570 |
class LogRRecruitmentInterface : public RecruitmentInterfaceBase {
|
|
| 571 |
public: |
|
| 572 |
/** |
|
| 573 |
* @brief The constructor. |
|
| 574 |
*/ |
|
| 575 | 1x |
LogRRecruitmentInterface() : RecruitmentInterfaceBase() {
|
| 576 | 1x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 577 | 2x |
std::make_shared<LogRRecruitmentInterface>(*this)); |
| 578 |
} |
|
| 579 | ||
| 580 |
/** |
|
| 581 |
* @brief The destructor. |
|
| 582 |
*/ |
|
| 583 | 6x |
virtual ~LogRRecruitmentInterface() {}
|
| 584 | ||
| 585 |
/** |
|
| 586 |
* @brief Gets the ID of the interface base object. |
|
| 587 |
* @return The ID. |
|
| 588 |
*/ |
|
| 589 | 1x |
virtual uint32_t get_id() { return this->id; }
|
| 590 | ||
| 591 |
/** |
|
| 592 |
* @brief Evaluate mean - returns empty function for this module. |
|
| 593 |
* @param spawners Spawning biomass per time step. |
|
| 594 |
* @param ssbzero The biomass at unfished levels. |
|
| 595 |
*/ |
|
| 596 | ! |
virtual double evaluate_mean(double spawners, double ssbzero) { return 0; }
|
| 597 | ||
| 598 |
/** |
|
| 599 |
* @brief Evaluate recruitment process using the Log--R approach. |
|
| 600 |
* @param pos Position index, e.g., which year. |
|
| 601 |
*/ |
|
| 602 | ! |
virtual double evaluate_process(size_t pos) {
|
| 603 | ! |
fims_popdy::LogR<double> LogR; |
| 604 | ||
| 605 | ! |
return LogR.evaluate_process(pos); |
| 606 |
} |
|
| 607 | ||
| 608 |
#ifdef TMB_MODEL |
|
| 609 | ||
| 610 |
template <typename Type> |
|
| 611 | 4x |
bool add_to_fims_tmb_internal() {
|
| 612 | 4x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 613 |
fims_info::Information<Type>::GetInstance(); |
|
| 614 | ||
| 615 | 4x |
std::shared_ptr<fims_popdy::LogR<Type>> recruitment_process = |
| 616 |
std::make_shared<fims_popdy::LogR<Type>>(); |
|
| 617 | ||
| 618 | 4x |
recruitment_process->id = this->id; |
| 619 | ||
| 620 |
// add to Information |
|
| 621 | 4x |
info->recruitment_process_models[recruitment_process->id] = |
| 622 |
recruitment_process; |
|
| 623 | ||
| 624 | 4x |
return true; |
| 625 |
} |
|
| 626 | ||
| 627 |
/** |
|
| 628 |
* @brief Adds the parameters to the TMB model. |
|
| 629 |
* @return A boolean of true. |
|
| 630 |
*/ |
|
| 631 | 1x |
virtual bool add_to_fims_tmb() {
|
| 632 |
#ifdef TMBAD_FRAMEWORK |
|
| 633 | 1x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 634 | 1x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 635 |
#else |
|
| 636 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 637 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 638 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 639 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 640 |
#endif |
|
| 641 | ||
| 642 | 1x |
return true; |
| 643 |
} |
|
| 644 | ||
| 645 |
#endif |
|
| 646 |
}; |
|
| 647 | ||
| 648 |
#endif |
| 1 |
/** |
|
| 2 |
* @file rcpp_selectivity.hpp |
|
| 3 |
* @brief The Rcpp interface to declare different types of selectivity, e.g., |
|
| 4 |
* logistic and double logistic. Allows for the use of methods::new() in R. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_SELECTIVITY_HPP |
|
| 10 |
#define FIMS_INTERFACE_RCPP_RCPP_OBJECTS_RCPP_SELECTIVITY_HPP |
|
| 11 | ||
| 12 |
#include "../../../population_dynamics/selectivity/selectivity.hpp" |
|
| 13 |
#include "rcpp_interface_base.hpp" |
|
| 14 | ||
| 15 |
/** |
|
| 16 |
* @brief Rcpp interface that serves as the parent class for Rcpp selectivity |
|
| 17 |
* interfaces. This type should be inherited and not called from R directly. |
|
| 18 |
*/ |
|
| 19 |
class SelectivityInterfaceBase : public FIMSRcppInterfaceBase {
|
|
| 20 |
public: |
|
| 21 |
/** |
|
| 22 |
* @brief The static id of the SelectivityInterfaceBase. |
|
| 23 |
*/ |
|
| 24 |
static uint32_t id_g; |
|
| 25 |
/** |
|
| 26 |
* @brief The local id of the SelectivityInterfaceBase object. |
|
| 27 |
*/ |
|
| 28 |
uint32_t id; |
|
| 29 |
/** |
|
| 30 |
* @brief The map associating the IDs of SelectivityInterfaceBase to the |
|
| 31 |
* objects. This is a live object, which is an object that has been created |
|
| 32 |
* and lives in memory. |
|
| 33 |
*/ |
|
| 34 |
static std::map<uint32_t, std::shared_ptr<SelectivityInterfaceBase>> |
|
| 35 |
live_objects; |
|
| 36 | ||
| 37 |
/** |
|
| 38 |
* @brief The constructor. |
|
| 39 |
*/ |
|
| 40 | 55x |
SelectivityInterfaceBase() {
|
| 41 | 55x |
this->id = SelectivityInterfaceBase::id_g++; |
| 42 |
/* Create instance of map: key is id and value is pointer to |
|
| 43 |
SelectivityInterfaceBase */ |
|
| 44 |
// SelectivityInterfaceBase::live_objects[this->id] = this; |
|
| 45 |
} |
|
| 46 | ||
| 47 |
/** |
|
| 48 |
* @brief Construct a new Selectivity Interface Base object |
|
| 49 |
* |
|
| 50 |
* @param other |
|
| 51 |
*/ |
|
| 52 | 55x |
SelectivityInterfaceBase(const SelectivityInterfaceBase &other) |
| 53 | 55x |
: id(other.id) {}
|
| 54 | ||
| 55 |
/** |
|
| 56 |
* @brief The destructor. |
|
| 57 |
*/ |
|
| 58 | 110x |
virtual ~SelectivityInterfaceBase() {}
|
| 59 | ||
| 60 |
/** |
|
| 61 |
* @brief Get the ID for the child selectivity interface objects to inherit. |
|
| 62 |
*/ |
|
| 63 |
virtual uint32_t get_id() = 0; |
|
| 64 | ||
| 65 |
/** |
|
| 66 |
* @brief A method for each child selectivity interface object to inherit so |
|
| 67 |
* each selectivity option can have an evaluate() function. |
|
| 68 |
*/ |
|
| 69 |
virtual double evaluate(double x) = 0; |
|
| 70 |
}; |
|
| 71 |
// static id of the SelectivityInterfaceBase object |
|
| 72 |
uint32_t SelectivityInterfaceBase::id_g = 1; |
|
| 73 |
// local id of the SelectivityInterfaceBase object map relating the ID of the |
|
| 74 |
// SelectivityInterfaceBase to the SelectivityInterfaceBase objects |
|
| 75 |
std::map<uint32_t, std::shared_ptr<SelectivityInterfaceBase>> |
|
| 76 |
SelectivityInterfaceBase::live_objects; |
|
| 77 | ||
| 78 |
/** |
|
| 79 |
* @brief Rcpp interface for logistic selectivity to instantiate the object |
|
| 80 |
* from R: |
|
| 81 |
* logistic_selectivity <- methods::new(logistic_selectivity). |
|
| 82 |
*/ |
|
| 83 |
class LogisticSelectivityInterface : public SelectivityInterfaceBase {
|
|
| 84 |
public: |
|
| 85 |
/** |
|
| 86 |
* @brief The index value at which the response reaches 0.5. |
|
| 87 |
*/ |
|
| 88 |
ParameterVector inflection_point; |
|
| 89 |
/** |
|
| 90 |
* @brief The width of the curve at the inflection point. |
|
| 91 |
*/ |
|
| 92 |
ParameterVector slope; |
|
| 93 | ||
| 94 |
/** |
|
| 95 |
* @brief The constructor. |
|
| 96 |
*/ |
|
| 97 | 50x |
LogisticSelectivityInterface() : SelectivityInterfaceBase() {
|
| 98 | 50x |
SelectivityInterfaceBase::live_objects[this->id] = |
| 99 | 100x |
std::make_shared<LogisticSelectivityInterface>(*this); |
| 100 | 50x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 101 | 50x |
SelectivityInterfaceBase::live_objects[this->id]); |
| 102 |
} |
|
| 103 | ||
| 104 |
/** |
|
| 105 |
* @brief Construct a new Logistic Selectivity Interface object |
|
| 106 |
* |
|
| 107 |
* @param other |
|
| 108 |
*/ |
|
| 109 | 50x |
LogisticSelectivityInterface(const LogisticSelectivityInterface &other) |
| 110 | 50x |
: SelectivityInterfaceBase(other), |
| 111 | 50x |
inflection_point(other.inflection_point), |
| 112 | 50x |
slope(other.slope) {}
|
| 113 | ||
| 114 |
/** |
|
| 115 |
* @brief The destructor. |
|
| 116 |
*/ |
|
| 117 | 300x |
virtual ~LogisticSelectivityInterface() {}
|
| 118 | ||
| 119 |
/** |
|
| 120 |
* @brief Gets the ID of the interface base object. |
|
| 121 |
* @return The ID. |
|
| 122 |
*/ |
|
| 123 | 45x |
virtual uint32_t get_id() { return this->id; }
|
| 124 | ||
| 125 |
/** |
|
| 126 |
* @brief Evaluate selectivity using the logistic function. |
|
| 127 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 128 |
* size in selectivity). |
|
| 129 |
*/ |
|
| 130 | 2x |
virtual double evaluate(double x) {
|
| 131 | 2x |
fims_popdy::LogisticSelectivity<double> LogisticSel; |
| 132 | 2x |
LogisticSel.inflection_point.resize(1); |
| 133 | 2x |
LogisticSel.inflection_point[0] = this->inflection_point[0].initial_value_m; |
| 134 | 2x |
LogisticSel.slope.resize(1); |
| 135 | 2x |
LogisticSel.slope[0] = this->slope[0].initial_value_m; |
| 136 | 4x |
return LogisticSel.evaluate(x); |
| 137 |
} |
|
| 138 | ||
| 139 |
/** |
|
| 140 |
* @brief Extracts derived quantities back to the Rcpp interface object from |
|
| 141 |
* the Information object. |
|
| 142 |
*/ |
|
| 143 | 26x |
virtual void finalize() {
|
| 144 | 26x |
if (this->finalized) {
|
| 145 |
// log warning that finalize has been called more than once. |
|
| 146 | ! |
FIMS_WARNING_LOG("Logistic Selectivity " + fims::to_string(this->id) +
|
| 147 |
" has been finalized already."); |
|
| 148 |
} |
|
| 149 | ||
| 150 | 26x |
this->finalized = true; // indicate this has been called already |
| 151 | ||
| 152 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 153 | 26x |
fims_info::Information<double>::GetInstance(); |
| 154 | ||
| 155 | 26x |
fims_info::Information<double>::selectivity_models_iterator it; |
| 156 | ||
| 157 |
// search for maturity in Information |
|
| 158 | 26x |
it = info->selectivity_models.find(this->id); |
| 159 |
// if not found, just return |
|
| 160 | 26x |
if (it == info->selectivity_models.end()) {
|
| 161 | ! |
FIMS_WARNING_LOG("Logistic Selectivity " + fims::to_string(this->id) +
|
| 162 |
" not found in Information."); |
|
| 163 | ! |
return; |
| 164 |
} else {
|
|
| 165 |
std::shared_ptr<fims_popdy::LogisticSelectivity<double>> sel = |
|
| 166 |
std::dynamic_pointer_cast<fims_popdy::LogisticSelectivity<double>>( |
|
| 167 | 26x |
it->second); |
| 168 | ||
| 169 | 52x |
for (size_t i = 0; i < inflection_point.size(); i++) {
|
| 170 | 26x |
if (this->inflection_point[i].estimation_type_m.get() == "constant") {
|
| 171 | 2x |
this->inflection_point[i].final_value_m = |
| 172 | 2x |
this->inflection_point[i].initial_value_m; |
| 173 |
} else {
|
|
| 174 | 24x |
this->inflection_point[i].final_value_m = sel->inflection_point[i]; |
| 175 |
} |
|
| 176 |
} |
|
| 177 | ||
| 178 | 52x |
for (size_t i = 0; i < slope.size(); i++) {
|
| 179 | 26x |
if (this->slope[i].estimation_type_m.get() == "constant") {
|
| 180 | 2x |
this->slope[i].final_value_m = this->slope[i].initial_value_m; |
| 181 |
} else {
|
|
| 182 | 24x |
this->slope[i].final_value_m = sel->slope[i]; |
| 183 |
} |
|
| 184 |
} |
|
| 185 |
} |
|
| 186 |
} |
|
| 187 |
/** |
|
| 188 |
* @brief Set uncertainty values for selectivity parameters. |
|
| 189 |
* |
|
| 190 |
* @details Sets the standard error values for the inflection point and slope |
|
| 191 |
* parameters using the provided map. |
|
| 192 |
* @param se_values A map from parameter names to vectors of standard error |
|
| 193 |
* values. |
|
| 194 |
*/ |
|
| 195 | 26x |
virtual void set_uncertainty( |
| 196 |
std::map<std::string, std::vector<double>> &se_values) {
|
|
| 197 |
fims::Vector<double> inflection_point_uncertainty( |
|
| 198 | 26x |
this->inflection_point.size(), -999); |
| 199 | 52x |
this->get_se_values("inflection_point", se_values,
|
| 200 |
inflection_point_uncertainty); |
|
| 201 | 26x |
fims::Vector<double> slope_uncertainty(this->slope.size(), -999); |
| 202 | 52x |
this->get_se_values("slope", se_values, slope_uncertainty);
|
| 203 | 52x |
for (size_t i = 0; i < this->inflection_point.size(); i++) {
|
| 204 | 26x |
this->inflection_point[i].uncertainty_m = inflection_point_uncertainty[i]; |
| 205 |
} |
|
| 206 | 52x |
for (size_t i = 0; i < this->slope.size(); i++) {
|
| 207 | 26x |
this->slope[i].uncertainty_m = slope_uncertainty[i]; |
| 208 |
} |
|
| 209 |
} |
|
| 210 | ||
| 211 |
/** |
|
| 212 |
* @brief Converts the data to json representation for the output. |
|
| 213 |
* @return A string is returned specifying that the module relates to the |
|
| 214 |
* selectivity interface with logistic selectivity. It also returns the ID |
|
| 215 |
* and the parameters. This string is formatted for a json file. |
|
| 216 |
*/ |
|
| 217 | 26x |
virtual std::string to_json() {
|
| 218 | 26x |
std::stringstream ss; |
| 219 | ||
| 220 | 26x |
ss << "{\n";
|
| 221 | 26x |
ss << " \"module_name\":\"Selectivity\",\n"; |
| 222 | 26x |
ss << " \"module_type\": \"Logistic\",\n"; |
| 223 | 26x |
ss << " \"module_id\": " << this->id << ",\n"; |
| 224 | ||
| 225 | 26x |
ss << " \"parameters\": [\n{\n";
|
| 226 | 26x |
ss << " \"name\": \"inflection_point\",\n"; |
| 227 | 26x |
ss << " \"id\":" << this->inflection_point.id_m << ",\n"; |
| 228 | 26x |
ss << " \"type\": \"vector\",\n"; |
| 229 | 26x |
ss << " \"dimensionality\": {\n";
|
| 230 | 26x |
ss << " \"header\": [null],\n"; |
| 231 | 26x |
ss << " \"dimensions\": [1]\n},\n"; |
| 232 | 26x |
ss << " \"values\":" << this->inflection_point << "},\n "; |
| 233 | ||
| 234 | 26x |
ss << "{\n";
|
| 235 | 26x |
ss << " \"name\": \"slope\",\n"; |
| 236 | 26x |
ss << " \"id\":" << this->slope.id_m << ",\n"; |
| 237 | 26x |
ss << " \"type\": \"vector\",\n"; |
| 238 | 26x |
ss << " \"dimensionality\": {\n";
|
| 239 | 26x |
ss << " \"header\": [null],\n"; |
| 240 | 26x |
ss << " \"dimensions\": [1]\n},\n"; |
| 241 | 26x |
ss << " \"values\":" << this->slope << "}]\n"; |
| 242 | ||
| 243 | 26x |
ss << "}"; |
| 244 | ||
| 245 | 52x |
return ss.str(); |
| 246 |
} |
|
| 247 | ||
| 248 |
#ifdef TMB_MODEL |
|
| 249 | ||
| 250 |
template <typename Type> |
|
| 251 | 176x |
bool add_to_fims_tmb_internal() {
|
| 252 | 176x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 253 |
fims_info::Information<Type>::GetInstance(); |
|
| 254 | ||
| 255 | 176x |
std::shared_ptr<fims_popdy::LogisticSelectivity<Type>> selectivity = |
| 256 |
std::make_shared<fims_popdy::LogisticSelectivity<Type>>(); |
|
| 257 | 176x |
std::stringstream ss; |
| 258 |
// set relative info |
|
| 259 | 176x |
selectivity->id = this->id; |
| 260 | 176x |
selectivity->inflection_point.resize(this->inflection_point.size()); |
| 261 | 352x |
for (size_t i = 0; i < this->inflection_point.size(); i++) {
|
| 262 | 176x |
selectivity->inflection_point[i] = |
| 263 | 176x |
this->inflection_point[i].initial_value_m; |
| 264 | 176x |
if (this->inflection_point[i].estimation_type_m.get() == |
| 265 |
"fixed_effects") {
|
|
| 266 | 152x |
ss.str("");
|
| 267 | 152x |
ss << "Selectivity." << this->id << ".inflection_point." |
| 268 | 152x |
<< this->inflection_point[i].id_m; |
| 269 | 152x |
info->RegisterParameterName(ss.str()); |
| 270 | 152x |
info->RegisterParameter(selectivity->inflection_point[i]); |
| 271 |
} |
|
| 272 | 176x |
if (this->inflection_point[i].estimation_type_m.get() == |
| 273 |
"random_effects") {
|
|
| 274 | 8x |
ss.str("");
|
| 275 | 8x |
ss << "Selectivity." << this->id << ".inflection_point." |
| 276 | 8x |
<< this->inflection_point[i].id_m; |
| 277 | 8x |
info->RegisterRandomEffect(selectivity->inflection_point[i]); |
| 278 | 8x |
info->RegisterRandomEffectName(ss.str()); |
| 279 |
} |
|
| 280 |
} |
|
| 281 | 176x |
info->variable_map[this->inflection_point.id_m] = |
| 282 | 176x |
&(selectivity)->inflection_point; |
| 283 | ||
| 284 | 176x |
selectivity->slope.resize(this->slope.size()); |
| 285 | 352x |
for (size_t i = 0; i < this->slope.size(); i++) {
|
| 286 | 176x |
selectivity->slope[i] = this->slope[i].initial_value_m; |
| 287 | 176x |
if (this->slope[i].estimation_type_m.get() == "fixed_effects") {
|
| 288 | 156x |
ss.str("");
|
| 289 | 156x |
ss << "Selectivity." << this->id << ".slope." << this->slope[i].id_m; |
| 290 | 156x |
info->RegisterParameterName(ss.str()); |
| 291 | 156x |
info->RegisterParameter(selectivity->slope[i]); |
| 292 |
} |
|
| 293 | 176x |
if (this->slope[i].estimation_type_m.get() == "random_effects") {
|
| 294 | 12x |
ss.str("");
|
| 295 | 12x |
ss << "Selectivity." << this->id << ".slope." << this->slope[i].id_m; |
| 296 | 12x |
info->RegisterRandomEffectName(ss.str()); |
| 297 | 12x |
info->RegisterRandomEffect(selectivity->slope[i]); |
| 298 |
} |
|
| 299 |
} |
|
| 300 | 176x |
info->variable_map[this->slope.id_m] = &(selectivity)->slope; |
| 301 | ||
| 302 |
// add to Information |
|
| 303 | 176x |
info->selectivity_models[selectivity->id] = selectivity; |
| 304 | ||
| 305 | 176x |
return true; |
| 306 |
} |
|
| 307 | ||
| 308 |
/** |
|
| 309 |
* @brief Adds the parameters to the TMB model. |
|
| 310 |
* @return A boolean of true. |
|
| 311 |
*/ |
|
| 312 | 44x |
virtual bool add_to_fims_tmb() {
|
| 313 |
#ifdef TMBAD_FRAMEWORK |
|
| 314 | 44x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 315 | 44x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 316 |
#else |
|
| 317 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 318 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 319 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 320 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 321 |
#endif |
|
| 322 | ||
| 323 | 44x |
return true; |
| 324 |
} |
|
| 325 | ||
| 326 |
#endif |
|
| 327 |
}; |
|
| 328 | ||
| 329 |
/** |
|
| 330 |
* @brief Rcpp interface for logistic selectivity as an S4 object. To |
|
| 331 |
* instantiate from R: logistic_selectivity <- |
|
| 332 |
* methods::new(logistic_selectivity) |
|
| 333 |
*/ |
|
| 334 |
class DoubleLogisticSelectivityInterface : public SelectivityInterfaceBase {
|
|
| 335 |
public: |
|
| 336 |
ParameterVector inflection_point_asc; /**< the index value at which the |
|
| 337 |
response reaches .5 */ |
|
| 338 |
ParameterVector |
|
| 339 |
slope_asc; /**< the width of the curve at the inflection_point */ |
|
| 340 |
ParameterVector inflection_point_desc; /**< the index value at which the |
|
| 341 |
response reaches .5 */ |
|
| 342 |
ParameterVector |
|
| 343 |
slope_desc; /**< the width of the curve at the inflection_point */ |
|
| 344 | ||
| 345 | 5x |
DoubleLogisticSelectivityInterface() : SelectivityInterfaceBase() {
|
| 346 | 5x |
SelectivityInterfaceBase::live_objects[this->id] = |
| 347 | 10x |
std::make_shared<DoubleLogisticSelectivityInterface>(*this); |
| 348 | 5x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 349 | 5x |
SelectivityInterfaceBase::live_objects[this->id]); |
| 350 |
} |
|
| 351 | ||
| 352 |
/** |
|
| 353 |
* @brief Construct a new Double Logistic Selectivity Interface object |
|
| 354 |
* |
|
| 355 |
* @param other |
|
| 356 |
*/ |
|
| 357 | 5x |
DoubleLogisticSelectivityInterface( |
| 358 |
const DoubleLogisticSelectivityInterface &other) |
|
| 359 | 5x |
: SelectivityInterfaceBase(other), |
| 360 | 5x |
inflection_point_asc(other.inflection_point_asc), |
| 361 | 5x |
slope_asc(other.slope_asc), |
| 362 | 5x |
inflection_point_desc(other.inflection_point_desc), |
| 363 | 10x |
slope_desc(other.slope_desc) {}
|
| 364 | ||
| 365 | 30x |
virtual ~DoubleLogisticSelectivityInterface() {}
|
| 366 | ||
| 367 |
/** @brief returns the id for the double logistic selectivity interface */ |
|
| 368 | 2x |
virtual uint32_t get_id() { return this->id; }
|
| 369 | ||
| 370 |
/** @brief evaluate the double logistic selectivity function |
|
| 371 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 372 |
* size in selectivity). |
|
| 373 |
*/ |
|
| 374 | 3x |
virtual double evaluate(double x) {
|
| 375 | 3x |
fims_popdy::DoubleLogisticSelectivity<double> DoubleLogisticSel; |
| 376 | 3x |
DoubleLogisticSel.inflection_point_asc.resize(1); |
| 377 | 6x |
DoubleLogisticSel.inflection_point_asc[0] = |
| 378 | 3x |
this->inflection_point_asc[0].initial_value_m; |
| 379 | 3x |
DoubleLogisticSel.slope_asc.resize(1); |
| 380 | 3x |
DoubleLogisticSel.slope_asc[0] = this->slope_asc[0].initial_value_m; |
| 381 | 3x |
DoubleLogisticSel.inflection_point_desc.resize(1); |
| 382 | 6x |
DoubleLogisticSel.inflection_point_desc[0] = |
| 383 | 3x |
this->inflection_point_desc[0].initial_value_m; |
| 384 | 3x |
DoubleLogisticSel.slope_desc.resize(1); |
| 385 | 3x |
DoubleLogisticSel.slope_desc[0] = this->slope_desc[0].initial_value_m; |
| 386 | 6x |
return DoubleLogisticSel.evaluate(x); |
| 387 |
} |
|
| 388 |
/** |
|
| 389 |
* @brief finalize function. Extracts derived quantities back to |
|
| 390 |
* the Rcpp interface object from the Information object. |
|
| 391 |
*/ |
|
| 392 | ! |
virtual void finalize() {
|
| 393 | ! |
if (this->finalized) {
|
| 394 |
// log warning that finalize has been called more than once. |
|
| 395 | ! |
FIMS_WARNING_LOG("Double Logistic Selectivity " +
|
| 396 |
fims::to_string(this->id) + |
|
| 397 |
" has been finalized already."); |
|
| 398 |
} |
|
| 399 | ||
| 400 | ! |
this->finalized = true; // indicate this has been called already |
| 401 | ||
| 402 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 403 | ! |
fims_info::Information<double>::GetInstance(); |
| 404 | ||
| 405 | ! |
fims_info::Information<double>::selectivity_models_iterator it; |
| 406 | ||
| 407 |
// search for maturity in Information |
|
| 408 | ! |
it = info->selectivity_models.find(this->id); |
| 409 |
// if not found, just return |
|
| 410 | ! |
if (it == info->selectivity_models.end()) {
|
| 411 | ! |
FIMS_WARNING_LOG("Double Logistic Selectivity " +
|
| 412 |
fims::to_string(this->id) + |
|
| 413 |
" not found in Information."); |
|
| 414 | ! |
return; |
| 415 |
} else {
|
|
| 416 |
std::shared_ptr<fims_popdy::DoubleLogisticSelectivity<double>> sel = |
|
| 417 |
std::dynamic_pointer_cast< |
|
| 418 | ! |
fims_popdy::DoubleLogisticSelectivity<double>>(it->second); |
| 419 | ||
| 420 | ! |
for (size_t i = 0; i < inflection_point_asc.size(); i++) {
|
| 421 | ! |
if (this->inflection_point_asc[i].estimation_type_m.get() == |
| 422 |
"constant") {
|
|
| 423 | ! |
this->inflection_point_asc[i].final_value_m = |
| 424 | ! |
this->inflection_point_asc[i].initial_value_m; |
| 425 |
} else {
|
|
| 426 | ! |
this->inflection_point_asc[i].final_value_m = |
| 427 | ! |
sel->inflection_point_asc[i]; |
| 428 |
} |
|
| 429 |
} |
|
| 430 | ||
| 431 | ! |
for (size_t i = 0; i < slope_asc.size(); i++) {
|
| 432 | ! |
if (this->slope_asc[i].estimation_type_m.get() == "constant") {
|
| 433 | ! |
this->slope_asc[i].final_value_m = this->slope_asc[i].initial_value_m; |
| 434 |
} else {
|
|
| 435 | ! |
this->slope_asc[i].final_value_m = sel->slope_asc[i]; |
| 436 |
} |
|
| 437 |
} |
|
| 438 | ||
| 439 | ! |
for (size_t i = 0; i < inflection_point_desc.size(); i++) {
|
| 440 | ! |
if (this->inflection_point_desc[i].estimation_type_m.get() == |
| 441 |
"constant") {
|
|
| 442 | ! |
this->inflection_point_desc[i].final_value_m = |
| 443 | ! |
this->inflection_point_desc[i].initial_value_m; |
| 444 |
} else {
|
|
| 445 | ! |
this->inflection_point_desc[i].final_value_m = |
| 446 | ! |
sel->inflection_point_desc[i]; |
| 447 |
} |
|
| 448 |
} |
|
| 449 | ||
| 450 | ! |
for (size_t i = 0; i < slope_desc.size(); i++) {
|
| 451 | ! |
if (this->slope_desc[i].estimation_type_m.get() == "constant") {
|
| 452 | ! |
this->slope_desc[i].final_value_m = |
| 453 | ! |
this->slope_desc[i].initial_value_m; |
| 454 |
} else {
|
|
| 455 | ! |
this->slope_desc[i].final_value_m = sel->slope_desc[i]; |
| 456 |
} |
|
| 457 |
} |
|
| 458 |
} |
|
| 459 |
} |
|
| 460 | ||
| 461 |
/** |
|
| 462 |
* @brief Set uncertainty values for double logistic selectivity parameters. |
|
| 463 |
* |
|
| 464 |
* @details Sets the standard error values for the ascending and descending |
|
| 465 |
* inflection points and slopes using the provided map. |
|
| 466 |
* @param se_values A map from parameter names to vectors of standard error |
|
| 467 |
* values. |
|
| 468 |
*/ |
|
| 469 | ! |
virtual void set_uncertainty( |
| 470 |
std::map<std::string, std::vector<double>> &se_values) {
|
|
| 471 |
fims::Vector<double> inflection_point_asc_uncertainty( |
|
| 472 | ! |
this->inflection_point_asc.size(), -999); |
| 473 | ! |
this->get_se_values("inflection_point_asc", se_values,
|
| 474 |
inflection_point_asc_uncertainty); |
|
| 475 | ! |
fims::Vector<double> slope_asc_uncertainty(this->slope_asc.size(), -999); |
| 476 | ! |
this->get_se_values("slope_asc", se_values, slope_asc_uncertainty);
|
| 477 |
fims::Vector<double> inflection_point_desc_uncertainty( |
|
| 478 | ! |
this->inflection_point_desc.size(), -999); |
| 479 | ! |
this->get_se_values("inflection_point_desc", se_values,
|
| 480 |
inflection_point_desc_uncertainty); |
|
| 481 | ! |
fims::Vector<double> slope_desc_uncertainty(this->slope_desc.size(), -999); |
| 482 | ! |
this->get_se_values("slope_desc", se_values, slope_desc_uncertainty);
|
| 483 | ! |
for (size_t i = 0; i < this->inflection_point_asc.size(); i++) {
|
| 484 | ! |
this->inflection_point_asc[i].uncertainty_m = |
| 485 | ! |
inflection_point_asc_uncertainty[i]; |
| 486 |
} |
|
| 487 | ! |
for (size_t i = 0; i < this->slope_asc.size(); i++) {
|
| 488 | ! |
this->slope_asc[i].uncertainty_m = slope_asc_uncertainty[i]; |
| 489 |
} |
|
| 490 | ! |
for (size_t i = 0; i < this->inflection_point_desc.size(); i++) {
|
| 491 | ! |
this->inflection_point_desc[i].uncertainty_m = |
| 492 | ! |
inflection_point_desc_uncertainty[i]; |
| 493 |
} |
|
| 494 | ! |
for (size_t i = 0; i < this->slope_desc.size(); i++) {
|
| 495 | ! |
this->slope_desc[i].uncertainty_m = slope_desc_uncertainty[i]; |
| 496 |
} |
|
| 497 |
} |
|
| 498 | ||
| 499 |
/** |
|
| 500 |
* @brief Convert the data to json representation for the output. |
|
| 501 |
*/ |
|
| 502 | ! |
virtual std::string to_json() {
|
| 503 | ! |
std::stringstream ss; |
| 504 | ||
| 505 | ! |
ss << "{\n";
|
| 506 | ! |
ss << " \"module_name\": \"Selectivity\",\n"; |
| 507 | ! |
ss << " \"module_type\": \"DoubleLogistic\",\n"; |
| 508 | ! |
ss << " \"module_id\": " << this->id << ",\n"; |
| 509 | ||
| 510 | ! |
ss << " \"parameters\":[\n{\n";
|
| 511 | ! |
ss << " \"name\": \"inflection_point_asc\",\n"; |
| 512 | ! |
ss << " \"id\":" << this->inflection_point_asc.id_m << ",\n"; |
| 513 | ! |
ss << " \"type\": \"vector\",\n"; |
| 514 | ! |
ss << " \"dimensionality\": {\n";
|
| 515 | ! |
ss << " \"header\": [null],\n"; |
| 516 | ! |
ss << " \"dimensions\": [1]\n},\n"; |
| 517 | ! |
ss << " \"values\":" << this->inflection_point_asc << "},\n"; |
| 518 | ||
| 519 | ! |
ss << "{\n";
|
| 520 | ! |
ss << " \"name\": \"slope_asc\",\n"; |
| 521 | ! |
ss << " \"id\":" << this->slope_asc.id_m << ",\n"; |
| 522 | ! |
ss << " \"type\": \"vector\",\n"; |
| 523 | ! |
ss << " \"dimensionality\": {\n";
|
| 524 | ! |
ss << " \"header\": [null],\n"; |
| 525 | ! |
ss << " \"dimensions\": [1]\n},\n"; |
| 526 | ! |
ss << " \"values\":" << this->slope_asc << "},\n"; |
| 527 | ||
| 528 | ! |
ss << " {\n";
|
| 529 | ! |
ss << " \"name\": \"inflection_point_desc\",\n"; |
| 530 | ! |
ss << " \"id\":" << this->inflection_point_desc.id_m << ",\n"; |
| 531 | ! |
ss << " \"type\": \"vector\",\n"; |
| 532 | ! |
ss << " \"dimensionality\": {\n";
|
| 533 | ! |
ss << " \"header\": [null],\n"; |
| 534 | ! |
ss << " \"dimensions\": [1]\n},\n"; |
| 535 | ! |
ss << " \"values\":" << this->inflection_point_desc << "},\n"; |
| 536 | ||
| 537 | ! |
ss << "{\n";
|
| 538 | ! |
ss << " \"name\": \"slope_desc\",\n"; |
| 539 | ! |
ss << " \"id\":" << this->slope_desc.id_m << ",\n"; |
| 540 | ! |
ss << " \"type\": \"vector\",\n"; |
| 541 | ! |
ss << " \"dimensionality\": {\n";
|
| 542 | ! |
ss << " \"header\": [null],\n"; |
| 543 | ! |
ss << " \"dimensions\": [1]\n},\n"; |
| 544 | ! |
ss << " \"values\":" << this->slope_desc << "}]\n"; |
| 545 | ||
| 546 | ! |
ss << "}"; |
| 547 | ||
| 548 | ! |
return ss.str(); |
| 549 |
} |
|
| 550 | ||
| 551 |
#ifdef TMB_MODEL |
|
| 552 | ||
| 553 |
template <typename Type> |
|
| 554 | 8x |
bool add_to_fims_tmb_internal() {
|
| 555 | 8x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 556 |
fims_info::Information<Type>::GetInstance(); |
|
| 557 | ||
| 558 | 8x |
std::shared_ptr<fims_popdy::DoubleLogisticSelectivity<Type>> selectivity = |
| 559 |
std::make_shared<fims_popdy::DoubleLogisticSelectivity<Type>>(); |
|
| 560 | ||
| 561 | 8x |
std::stringstream ss; |
| 562 |
// set relative info |
|
| 563 | 8x |
selectivity->id = this->id; |
| 564 | 8x |
selectivity->inflection_point_asc.resize(this->inflection_point_asc.size()); |
| 565 | 16x |
for (size_t i = 0; i < this->inflection_point_asc.size(); i++) {
|
| 566 | 8x |
selectivity->inflection_point_asc[i] = |
| 567 | 8x |
this->inflection_point_asc[i].initial_value_m; |
| 568 | 8x |
if (this->inflection_point_asc[i].estimation_type_m.get() == |
| 569 |
"fixed_effects") {
|
|
| 570 | 4x |
ss.str("");
|
| 571 | 4x |
ss << "Selectivity." << this->id << ".inflection_point_asc." |
| 572 | 4x |
<< this->inflection_point_asc[i].id_m; |
| 573 | 4x |
info->RegisterParameterName(ss.str()); |
| 574 | 4x |
info->RegisterParameter(selectivity->inflection_point_asc[i]); |
| 575 |
} |
|
| 576 | 8x |
if (this->inflection_point_asc[i].estimation_type_m.get() == |
| 577 |
"random_effects") {
|
|
| 578 | 4x |
ss.str("");
|
| 579 | 4x |
ss << "Selectivity." << this->id << ".inflection_point_asc." |
| 580 | 4x |
<< this->inflection_point_asc[i].id_m; |
| 581 | 4x |
info->RegisterRandomEffectName(ss.str()); |
| 582 | 4x |
info->RegisterRandomEffect(selectivity->inflection_point_asc[i]); |
| 583 |
} |
|
| 584 |
} |
|
| 585 | 8x |
info->variable_map[this->inflection_point_asc.id_m] = |
| 586 | 8x |
&(selectivity)->inflection_point_asc; |
| 587 | ||
| 588 | 8x |
selectivity->slope_asc.resize(this->slope_asc.size()); |
| 589 | 16x |
for (size_t i = 0; i < this->slope_asc.size(); i++) {
|
| 590 | 8x |
selectivity->slope_asc[i] = this->slope_asc[i].initial_value_m; |
| 591 | ||
| 592 | 8x |
if (this->slope_asc[i].estimation_type_m.get() == "fixed_effects") {
|
| 593 | ! |
ss.str("");
|
| 594 | ! |
ss << "Selectivity." << this->id << ".slope_asc." |
| 595 | ! |
<< this->slope_asc[i].id_m; |
| 596 | ! |
info->RegisterParameterName(ss.str()); |
| 597 | ! |
info->RegisterParameter(selectivity->slope_asc[i]); |
| 598 |
} |
|
| 599 | 8x |
if (this->slope_asc[i].estimation_type_m.get() == "random_effects") {
|
| 600 | ! |
ss.str("");
|
| 601 | ! |
ss << "Selectivity." << this->id << ".slope_asc." |
| 602 | ! |
<< this->slope_asc[i].id_m; |
| 603 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 604 | ! |
info->RegisterRandomEffect(selectivity->slope_asc[i]); |
| 605 |
} |
|
| 606 |
} |
|
| 607 | 8x |
info->variable_map[this->slope_asc.id_m] = &(selectivity)->slope_asc; |
| 608 | ||
| 609 | 8x |
selectivity->inflection_point_desc.resize( |
| 610 |
this->inflection_point_desc.size()); |
|
| 611 | 16x |
for (size_t i = 0; i < this->inflection_point_desc.size(); i++) {
|
| 612 | 8x |
selectivity->inflection_point_desc[i] = |
| 613 | 8x |
this->inflection_point_desc[i].initial_value_m; |
| 614 | ||
| 615 | 8x |
if (this->inflection_point_desc[i].estimation_type_m.get() == |
| 616 |
"fixed_effects") {
|
|
| 617 | 4x |
ss.str("");
|
| 618 | 4x |
ss << "Selectivity." << this->id << ".inflection_point_desc." |
| 619 | 4x |
<< this->inflection_point_desc[i].id_m; |
| 620 | 4x |
info->RegisterParameterName(ss.str()); |
| 621 | 4x |
info->RegisterParameter(selectivity->inflection_point_desc[i]); |
| 622 |
} |
|
| 623 | 8x |
if (this->inflection_point_desc[i].estimation_type_m.get() == |
| 624 |
"random_effects") {
|
|
| 625 | 4x |
ss.str("");
|
| 626 | 4x |
ss << "Selectivity." << this->id << ".inflection_point_desc." |
| 627 | 4x |
<< this->inflection_point_desc[i].id_m; |
| 628 | 4x |
info->RegisterRandomEffectName(ss.str()); |
| 629 | 4x |
info->RegisterRandomEffect(selectivity->inflection_point_desc[i]); |
| 630 |
} |
|
| 631 |
} |
|
| 632 | 8x |
info->variable_map[this->inflection_point_desc.id_m] = |
| 633 | 8x |
&(selectivity)->inflection_point_desc; |
| 634 | ||
| 635 | 8x |
selectivity->slope_desc.resize(this->slope_desc.size()); |
| 636 | 16x |
for (size_t i = 0; i < this->slope_desc.size(); i++) {
|
| 637 | 8x |
selectivity->slope_desc[i] = this->slope_desc[i].initial_value_m; |
| 638 | ||
| 639 | 8x |
if (this->slope_desc[i].estimation_type_m.get() == "fixed_effects") {
|
| 640 | 4x |
ss.str("");
|
| 641 | 4x |
ss << "Selectivity." << this->id << ".slope_desc." |
| 642 | 4x |
<< this->slope_desc[i].id_m; |
| 643 | 4x |
info->RegisterParameterName(ss.str()); |
| 644 | 4x |
info->RegisterParameter(selectivity->slope_desc[i]); |
| 645 |
} |
|
| 646 | 8x |
if (this->slope_desc[i].estimation_type_m.get() == "random_effects") {
|
| 647 | 4x |
ss.str("");
|
| 648 | 4x |
ss << "Selectivity." << this->id << ".slope_desc." |
| 649 | 4x |
<< this->slope_desc[i].id_m; |
| 650 | 4x |
info->RegisterRandomEffectName(ss.str()); |
| 651 | 4x |
info->RegisterRandomEffect(selectivity->slope_desc[i]); |
| 652 |
} |
|
| 653 |
} |
|
| 654 | ||
| 655 | 8x |
info->variable_map[this->slope_desc.id_m] = &(selectivity)->slope_desc; |
| 656 | ||
| 657 |
// add to Information |
|
| 658 | 8x |
info->selectivity_models[selectivity->id] = selectivity; |
| 659 | ||
| 660 | 8x |
return true; |
| 661 |
} |
|
| 662 | ||
| 663 |
/** |
|
| 664 |
* @brief Adds the parameters to the TMB model. |
|
| 665 |
* @return A boolean of true. |
|
| 666 |
*/ |
|
| 667 | 2x |
virtual bool add_to_fims_tmb() {
|
| 668 |
#ifdef TMBAD_FRAMEWORK |
|
| 669 | 2x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 670 | 2x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 671 |
#else |
|
| 672 |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
|
| 673 |
this->add_to_fims_tmb_internal<TMB_FIMS_FIRST_ORDER>(); |
|
| 674 |
this->add_to_fims_tmb_internal<TMB_FIMS_SECOND_ORDER>(); |
|
| 675 |
this->add_to_fims_tmb_internal<TMB_FIMS_THIRD_ORDER>(); |
|
| 676 |
#endif |
|
| 677 | ||
| 678 | 2x |
return true; |
| 679 |
} |
|
| 680 | ||
| 681 |
#endif |
|
| 682 |
}; |
|
| 683 | ||
| 684 |
#endif |
| 1 |
/** |
|
| 2 |
* @file catch_at_age.hpp |
|
| 3 |
* @brief Code to specify the catch-at-age model. |
|
| 4 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 5 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 6 |
* folder for reuse information. |
|
| 7 |
*/ |
|
| 8 |
#ifndef FIMS_MODELS_CATCH_AT_AGE_HPP |
|
| 9 |
#define FIMS_MODELS_CATCH_AT_AGE_HPP |
|
| 10 | ||
| 11 |
#include <set> |
|
| 12 |
#include <regex> |
|
| 13 | ||
| 14 |
#include "fishery_model_base.hpp" |
|
| 15 | ||
| 16 |
namespace fims_popdy {
|
|
| 17 | ||
| 18 |
template <typename Type> |
|
| 19 |
/** |
|
| 20 |
* @brief CatchAtAge is a class containing a catch-at-age model, which is |
|
| 21 |
* just one of many potential fishery models that can be used in FIMS. The |
|
| 22 |
* CatchAtAge class inherits from the FisheryModelBase class and can be used |
|
| 23 |
* to fit both age and length data even though it is called CatchAtAge. |
|
| 24 |
* |
|
| 25 |
*/ |
|
| 26 |
class CatchAtAge : public FisheryModelBase<Type> {
|
|
| 27 |
public: |
|
| 28 |
/** |
|
| 29 |
* @brief The name of the model. |
|
| 30 |
* |
|
| 31 |
*/ |
|
| 32 |
std::string name_m; |
|
| 33 | ||
| 34 |
/** |
|
| 35 |
* @brief Iterate the derived quantities. |
|
| 36 |
* |
|
| 37 |
*/ |
|
| 38 |
typedef typename std::map<std::string, fims::Vector<Type>>::iterator |
|
| 39 |
derived_quantities_iterator; |
|
| 40 | ||
| 41 |
/** |
|
| 42 |
* @brief Used to iterate through fleet-based derived quantities. |
|
| 43 |
* |
|
| 44 |
*/ |
|
| 45 |
typedef typename std::map<uint32_t, |
|
| 46 |
std::map<std::string, fims::Vector<Type>>>::iterator |
|
| 47 |
fleet_derived_quantities_iterator; |
|
| 48 | ||
| 49 |
/** |
|
| 50 |
* @brief Used to iterate through fleet-based derived quantities dimensions. |
|
| 51 |
*/ |
|
| 52 |
typedef |
|
| 53 |
typename std::map<uint32_t, |
|
| 54 |
std::map<std::string, fims::Vector<size_t>>>::iterator |
|
| 55 |
fleet_derived_quantities_dims_iterator; |
|
| 56 |
/** |
|
| 57 |
* @brief Used to iterate through population-based derived quantities. |
|
| 58 |
* |
|
| 59 |
*/ |
|
| 60 |
typedef typename std::map<uint32_t, |
|
| 61 |
std::map<std::string, fims::Vector<Type>>>::iterator |
|
| 62 |
population_derived_quantities_iterator; |
|
| 63 | ||
| 64 |
/** |
|
| 65 |
* @brief Used to iterate through population-based derived quantities |
|
| 66 |
* dimensions. |
|
| 67 |
*/ |
|
| 68 |
typedef |
|
| 69 |
typename std::map<uint32_t, |
|
| 70 |
std::map<std::string, fims::Vector<size_t>>>::iterator |
|
| 71 |
population_derived_quantities_dims_iterator; |
|
| 72 | ||
| 73 |
/** |
|
| 74 |
* @brief Iterate through fleets. |
|
| 75 |
* |
|
| 76 |
*/ |
|
| 77 |
typedef typename std::map<uint32_t, |
|
| 78 |
std::shared_ptr<fims_popdy::Fleet<Type>>>::iterator |
|
| 79 |
fleet_iterator; |
|
| 80 |
/** |
|
| 81 |
* @brief Iterate through derived quantities. |
|
| 82 |
* |
|
| 83 |
*/ |
|
| 84 |
typedef |
|
| 85 |
typename std::map<std::string, fims::Vector<Type>>::iterator dq_iterator; |
|
| 86 |
/** |
|
| 87 |
* @brief A map of report vectors for the object. |
|
| 88 |
* used to populate the report_vectors map in for submodule |
|
| 89 |
* parameters. |
|
| 90 |
*/ |
|
| 91 |
std::map<std::string, fims::Vector<fims::Vector<Type>>> report_vectors; |
|
| 92 | ||
| 93 |
public: |
|
| 94 |
std::vector<Type> ages; /*!< vector of the ages for referencing*/ |
|
| 95 |
/** |
|
| 96 |
* Constructor for the CatchAtAge class. This constructor initializes the |
|
| 97 |
* name of the model and sets the id of the model. |
|
| 98 |
*/ |
|
| 99 | 72x |
CatchAtAge() : FisheryModelBase<Type>() {
|
| 100 | 72x |
std::stringstream ss; |
| 101 | 72x |
ss << "caa_" << this->GetId() << "_"; |
| 102 | 72x |
this->name_m = ss.str(); |
| 103 | 72x |
this->model_type_m = "caa"; |
| 104 |
} |
|
| 105 | ||
| 106 |
/** |
|
| 107 |
* @brief Copy constructor for the CatchAtAge class. |
|
| 108 |
* |
|
| 109 |
* @param other The other CatchAtAge object to copy from. |
|
| 110 |
*/ |
|
| 111 |
CatchAtAge(const CatchAtAge &other) |
|
| 112 |
: FisheryModelBase<Type>(other), name_m(other.name_m), ages(other.ages) {
|
|
| 113 |
this->model_type_m = "caa"; |
|
| 114 |
} |
|
| 115 | ||
| 116 |
/** |
|
| 117 |
* @brief Destroy the Catch At Age object. |
|
| 118 |
* |
|
| 119 |
*/ |
|
| 120 | 36x |
virtual ~CatchAtAge() {}
|
| 121 | ||
| 122 |
/** |
|
| 123 |
* This function is called once at the beginning of the model run. It |
|
| 124 |
* initializes the derived quantities for the populations and fleets. |
|
| 125 |
*/ |
|
| 126 | 72x |
virtual void Initialize() {
|
| 127 | 144x |
for (size_t p = 0; p < this->populations.size(); p++) {
|
| 128 | 144x |
this->populations[p]->proportion_female.resize( |
| 129 | 72x |
this->populations[p]->n_ages); |
| 130 | ||
| 131 | 72x |
this->populations[p]->M.resize(this->populations[p]->n_years * |
| 132 | 72x |
this->populations[p]->n_ages); |
| 133 |
} |
|
| 134 | ||
| 135 | 216x |
for (fleet_iterator fit = this->fleets.begin(); fit != this->fleets.end(); |
| 136 | 144x |
++fit) {
|
| 137 | 144x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 138 | ||
| 139 | 144x |
if (fleet->log_q.size() == 0) {
|
| 140 | ! |
fleet->log_q.resize(1); |
| 141 | ! |
fleet->log_q[0] = static_cast<Type>(0.0); |
| 142 |
} |
|
| 143 | 144x |
fleet->q.resize(fleet->log_q.size()); |
| 144 | 144x |
fleet->Fmort.resize(fleet->n_years); |
| 145 |
} |
|
| 146 |
} |
|
| 147 | ||
| 148 |
/** |
|
| 149 |
* This function is used to reset the derived quantities of a population or |
|
| 150 |
* fleet to a given value. |
|
| 151 |
*/ |
|
| 152 | 1140x |
virtual void Prepare() {
|
| 153 | 2280x |
for (size_t p = 0; p < this->populations.size(); p++) {
|
| 154 |
std::shared_ptr<fims_popdy::Population<Type>> &population = |
|
| 155 | 1140x |
this->populations[p]; |
| 156 | ||
| 157 |
auto &derived_quantities = |
|
| 158 | 1140x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 159 | ||
| 160 |
// Reset the derived quantities for the population |
|
| 161 | 15960x |
for (auto &kv : derived_quantities) {
|
| 162 | 14820x |
this->ResetVector(kv.second); |
| 163 |
} |
|
| 164 | ||
| 165 |
// Prepare proportion_female |
|
| 166 | 14820x |
for (size_t age = 0; age < population->n_ages; age++) {
|
| 167 | 13680x |
population->proportion_female[age] = 0.5; |
| 168 |
} |
|
| 169 | ||
| 170 |
// Transformation Section |
|
| 171 | 14820x |
for (size_t age = 0; age < population->n_ages; age++) {
|
| 172 | 424080x |
for (size_t year = 0; year < population->n_years; year++) {
|
| 173 | 410400x |
size_t i_age_year = age * population->n_years + year; |
| 174 | 410400x |
population->M[i_age_year] = |
| 175 | 410400x |
fims_math::exp(population->log_M[i_age_year]); |
| 176 |
} |
|
| 177 |
} |
|
| 178 |
} |
|
| 179 | ||
| 180 | 3420x |
for (fleet_iterator fit = this->fleets.begin(); fit != this->fleets.end(); |
| 181 | 2280x |
++fit) {
|
| 182 | 2280x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 183 |
auto &derived_quantities = |
|
| 184 | 2280x |
this->GetFleetDerivedQuantities(fleet->GetId()); |
| 185 | ||
| 186 | 45600x |
for (auto &kv : derived_quantities) {
|
| 187 | 43320x |
this->ResetVector(kv.second); |
| 188 |
} |
|
| 189 | ||
| 190 |
// Transformation Section |
|
| 191 | 4560x |
for (size_t i = 0; i < fleet->log_q.size(); i++) {
|
| 192 | 2280x |
fleet->q[i] = fims_math::exp(fleet->log_q[i]); |
| 193 |
} |
|
| 194 | ||
| 195 | 70680x |
for (size_t year = 0; year < fleet->n_years; year++) {
|
| 196 | 68400x |
fleet->Fmort[year] = fims_math::exp(fleet->log_Fmort[year]); |
| 197 |
} |
|
| 198 |
// // TODO: does this age_length_to_conversion need to be a dq and |
|
| 199 |
// parameter |
|
| 200 |
// // of fleet? |
|
| 201 |
// for (size_t i_length_age = 0; |
|
| 202 |
// i_length_age < fleet->age_to_length_conversion.size(); |
|
| 203 |
// i_length_age++) |
|
| 204 |
// {
|
|
| 205 |
// derived_quantities["age_to_length_conversion"][i_length_age] = |
|
| 206 |
// fleet->age_to_length_conversion[i_length_age]; |
|
| 207 |
// } |
|
| 208 |
} |
|
| 209 |
} |
|
| 210 |
/** |
|
| 211 |
* This function is used to add a population id to the set of population ids. |
|
| 212 |
*/ |
|
| 213 | 72x |
void AddPopulation(uint32_t id) { this->population_ids.insert(id); }
|
| 214 | ||
| 215 |
/** |
|
| 216 |
* @brief Get the population ids of the model. |
|
| 217 |
*/ |
|
| 218 |
std::set<uint32_t> &GetPopulationIds() { return this->population_ids; }
|
|
| 219 | ||
| 220 |
/** |
|
| 221 |
* This function is used to get the populations of the model. It returns a |
|
| 222 |
* vector of shared pointers to the populations. |
|
| 223 |
* @return std::vector<std::shared_ptr<fims_popdy::Population<Type>>>& |
|
| 224 |
*/ |
|
| 225 |
std::vector<std::shared_ptr<fims_popdy::Population<Type>>> &GetPopulations() {
|
|
| 226 |
return this->populations; |
|
| 227 |
} |
|
| 228 | ||
| 229 |
/** |
|
| 230 |
* This method is used to calculate the initial numbers at age for a |
|
| 231 |
* population. It takes a population object and an age as input and |
|
| 232 |
* calculates the initial numbers at age for that population. |
|
| 233 |
* @param population |
|
| 234 |
* @param i_age_year |
|
| 235 |
* @param a |
|
| 236 |
*/ |
|
| 237 | 6840x |
void CalculateInitialNumbersAA( |
| 238 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 239 |
size_t i_age_year, size_t a) {
|
|
| 240 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 241 | 6840x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 242 | ||
| 243 | 6840x |
dq_["numbers_at_age"][i_age_year] = |
| 244 | 6840x |
fims_math::exp(population->log_init_naa[a]); |
| 245 |
} |
|
| 246 | ||
| 247 |
/** |
|
| 248 |
* * This method is used to calculate the numbers at age for a |
|
| 249 |
* population. It takes a population object, the index of the age |
|
| 250 |
* in the current year, the index of the age in the previous year, |
|
| 251 |
* and the age as input and calculates the numbers at age for that |
|
| 252 |
* population. |
|
| 253 |
* @param population |
|
| 254 |
* @param i_age_year |
|
| 255 |
* @param i_agem1_yearm1 |
|
| 256 |
* @param age |
|
| 257 |
*/ |
|
| 258 | 188100x |
void CalculateNumbersAA( |
| 259 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 260 |
size_t i_age_year, size_t i_agem1_yearm1, size_t age) {
|
|
| 261 |
// using Z from previous age/year |
|
| 262 | ||
| 263 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 264 | 188100x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 265 | ||
| 266 | 188100x |
dq_["numbers_at_age"][i_age_year] = |
| 267 | 376200x |
dq_["numbers_at_age"][i_agem1_yearm1] * |
| 268 | 528660x |
(fims_math::exp(-dq_["mortality_Z"][i_agem1_yearm1])); |
| 269 | ||
| 270 |
// Plus group calculation |
|
| 271 | 188100x |
if (age == (population->n_ages - 1)) {
|
| 272 | 17100x |
dq_["numbers_at_age"][i_age_year] = |
| 273 | 34200x |
dq_["numbers_at_age"][i_age_year] + |
| 274 | 48060x |
dq_["numbers_at_age"][i_agem1_yearm1 + 1] * |
| 275 | 51300x |
(fims_math::exp(-dq_["mortality_Z"][i_agem1_yearm1 + 1])); |
| 276 |
} |
|
| 277 |
} |
|
| 278 | ||
| 279 |
/** |
|
| 280 |
* This method is used to calculate the unfished numbers at age for a |
|
| 281 |
* population. It takes a population object, the index of the age |
|
| 282 |
* in the current year, the index of the age in the previous year, |
|
| 283 |
* and the age as input and calculates the unfished numbers at age |
|
| 284 |
* for that population. |
|
| 285 |
* @param population |
|
| 286 |
* @param i_age_year |
|
| 287 |
* @param i_agem1_yearm1 |
|
| 288 |
* @param age |
|
| 289 |
*/ |
|
| 290 | 194370x |
void CalculateUnfishedNumbersAA( |
| 291 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 292 |
size_t i_age_year, size_t i_agem1_yearm1, size_t age) {
|
|
| 293 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 294 | 194370x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 295 | ||
| 296 |
// using M from previous age/year |
|
| 297 | 194370x |
dq_["unfished_numbers_at_age"][i_age_year] = |
| 298 | 388740x |
dq_["unfished_numbers_at_age"][i_agem1_yearm1] * |
| 299 | 351912x |
(fims_math::exp(-population->M[i_agem1_yearm1])); |
| 300 | ||
| 301 |
// Plus group calculation |
|
| 302 | 194370x |
if (age == (population->n_ages - 1)) {
|
| 303 | 17670x |
dq_["unfished_numbers_at_age"][i_age_year] = |
| 304 | 35340x |
dq_["unfished_numbers_at_age"][i_age_year] + |
| 305 | 49662x |
dq_["unfished_numbers_at_age"][i_agem1_yearm1 + 1] * |
| 306 | 35340x |
(fims_math::exp(-population->M[i_agem1_yearm1 + 1])); |
| 307 |
} |
|
| 308 |
} |
|
| 309 | ||
| 310 |
/** |
|
| 311 |
* * This method is used to calculate the mortality for a population. It takes |
|
| 312 |
* a population object, the index of the age in the current year, the year, |
|
| 313 |
* and the age as input and calculates the mortality for that population. |
|
| 314 |
* @param population |
|
| 315 |
* @param i_age_year |
|
| 316 |
* @param year |
|
| 317 |
* @param age |
|
| 318 |
*/ |
|
| 319 | 205200x |
void CalculateMortality( |
| 320 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 321 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 322 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 323 | 205200x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 324 | ||
| 325 | 615600x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 326 |
// evaluate is a member function of the selectivity class |
|
| 327 | 488160x |
Type s = population->fleets[fleet_]->selectivity->evaluate( |
| 328 | 410400x |
population->ages[age]); |
| 329 | ||
| 330 | 743040x |
dq_["mortality_F"][i_age_year] += |
| 331 | 488160x |
population->fleets[fleet_]->Fmort[year] * s; |
| 332 | ||
| 333 | 820800x |
dq_["sum_selectivity"][i_age_year] += s; |
| 334 |
} |
|
| 335 | 205200x |
dq_["mortality_Z"][i_age_year] = |
| 336 | 576720x |
population->M[i_age_year] + dq_["mortality_F"][i_age_year]; |
| 337 |
} |
|
| 338 | ||
| 339 |
/** |
|
| 340 |
* * This method is used to calculate the biomass for a population. It takes a |
|
| 341 |
* population object, the index of the age in the current year, the year, |
|
| 342 |
* and the age as input and calculates the biomass for that population. |
|
| 343 |
* @param population |
|
| 344 |
* @param i_age_year |
|
| 345 |
* @param year |
|
| 346 |
* @param age |
|
| 347 |
*/ |
|
| 348 | 212040x |
void CalculateBiomass( |
| 349 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 350 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 351 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 352 | 212040x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 353 | ||
| 354 | 636120x |
dq_["biomass"][year] += dq_["numbers_at_age"][i_age_year] * |
| 355 | 212040x |
population->growth->evaluate(population->ages[age]); |
| 356 |
} |
|
| 357 | ||
| 358 |
/** |
|
| 359 |
* * This method is used to calculate the unfished biomass for a population. |
|
| 360 |
* It takes a population object, the index of the age in the current year, the |
|
| 361 |
* year, and the age as input and calculates the unfished biomass for that |
|
| 362 |
* population. |
|
| 363 |
* @param population |
|
| 364 |
* @param i_age_year |
|
| 365 |
* @param year |
|
| 366 |
* @param age |
|
| 367 |
*/ |
|
| 368 | 212040x |
void CalculateUnfishedBiomass( |
| 369 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 370 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 371 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 372 | 212040x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 373 | ||
| 374 | 212040x |
dq_["unfished_biomass"][year] += |
| 375 | 424080x |
dq_["unfished_numbers_at_age"][i_age_year] * |
| 376 | 212040x |
population->growth->evaluate(population->ages[age]); |
| 377 |
} |
|
| 378 | ||
| 379 |
/** |
|
| 380 |
* * This method is used to calculate the spawning biomass for a population. |
|
| 381 |
* It takes a population object, the index of the age in the current year, the |
|
| 382 |
* year, and the age as input and calculates the spawning biomass for that |
|
| 383 |
* population. |
|
| 384 |
* @param population |
|
| 385 |
* @param i_age_year |
|
| 386 |
* @param year |
|
| 387 |
* @param age |
|
| 388 |
*/ |
|
| 389 | 212040x |
void CalculateSpawningBiomass( |
| 390 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 391 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 392 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 393 | 212040x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 394 | ||
| 395 | 212040x |
dq_["spawning_biomass"][year] += |
| 396 | 424080x |
population->proportion_female[age] * dq_["numbers_at_age"][i_age_year] * |
| 397 | 636120x |
dq_["proportion_mature_at_age"][i_age_year] * |
| 398 | 212040x |
population->growth->evaluate(population->ages[age]); |
| 399 |
} |
|
| 400 | ||
| 401 |
/** |
|
| 402 |
* This method is used to calculate the unfished spawning biomass for a |
|
| 403 |
* population. It takes a population object, the index of the age in the |
|
| 404 |
* current year, the year, and the age as input and calculates the unfished |
|
| 405 |
* spawning biomass for that population. |
|
| 406 |
* @param population |
|
| 407 |
* @param i_age_year |
|
| 408 |
* @param year |
|
| 409 |
* @param age |
|
| 410 |
*/ |
|
| 411 | 212040x |
void CalculateUnfishedSpawningBiomass( |
| 412 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 413 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 414 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 415 | 212040x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 416 | ||
| 417 | 212040x |
dq_["unfished_spawning_biomass"][year] += |
| 418 | 212040x |
population->proportion_female[age] * |
| 419 | 292392x |
dq_["unfished_numbers_at_age"][i_age_year] * |
| 420 | 636120x |
dq_["proportion_mature_at_age"][i_age_year] * |
| 421 | 212040x |
population->growth->evaluate(population->ages[age]); |
| 422 |
} |
|
| 423 | ||
| 424 |
/** |
|
| 425 |
* This method is used to calculate the spawning biomass per recruit for a |
|
| 426 |
* population. It takes a population object. |
|
| 427 |
*/ |
|
| 428 | 17100x |
Type CalculateSBPR0( |
| 429 |
std::shared_ptr<fims_popdy::Population<Type>> &population) {
|
|
| 430 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 431 | 17100x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 432 | ||
| 433 | 17100x |
std::vector<Type> numbers_spr(population->n_ages, 1.0); |
| 434 | 17100x |
Type phi_0 = 0.0; |
| 435 | 20340x |
phi_0 += numbers_spr[0] * population->proportion_female[0] * |
| 436 | 23580x |
dq_["proportion_mature_at_age"][0] * |
| 437 | 17100x |
population->growth->evaluate(population->ages[0]); |
| 438 | 188100x |
for (size_t a = 1; a < (population->n_ages - 1); a++) {
|
| 439 | 171000x |
numbers_spr[a] = numbers_spr[a - 1] * fims_math::exp(-population->M[a]); |
| 440 | 203400x |
phi_0 += numbers_spr[a] * population->proportion_female[a] * |
| 441 | 374400x |
dq_["proportion_mature_at_age"][a] * |
| 442 | 203400x |
population->growth->evaluate(population->ages[a]); |
| 443 |
} |
|
| 444 | ||
| 445 | 17100x |
numbers_spr[population->n_ages - 1] = |
| 446 | 17100x |
(numbers_spr[population->n_ages - 2] * |
| 447 | 20340x |
fims_math::exp(-population->M[population->n_ages - 2])) / |
| 448 | 17100x |
(1 - fims_math::exp(-population->M[population->n_ages - 1])); |
| 449 | 17100x |
phi_0 += |
| 450 | 17100x |
numbers_spr[population->n_ages - 1] * |
| 451 | 20340x |
population->proportion_female[population->n_ages - 1] * |
| 452 | 23580x |
dq_["proportion_mature_at_age"][population->n_ages - 1] * |
| 453 | 17100x |
population->growth->evaluate(population->ages[population->n_ages - 1]); |
| 454 | ||
| 455 | 17100x |
return phi_0; |
| 456 |
} |
|
| 457 | ||
| 458 |
/** |
|
| 459 |
* This method is used to calculate the recruitment for a population. |
|
| 460 |
* |
|
| 461 |
*/ |
|
| 462 | 17100x |
void CalculateRecruitment( |
| 463 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 464 |
size_t i_age_year, size_t year, size_t i_dev) {
|
|
| 465 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 466 | 17100x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 467 | ||
| 468 | 17100x |
Type phi0 = CalculateSBPR0(population); |
| 469 | ||
| 470 | 17100x |
if (i_dev == population->n_years) {
|
| 471 | 570x |
dq_["numbers_at_age"][i_age_year] = |
| 472 | 1032x |
population->recruitment->evaluate_mean( |
| 473 | 1710x |
dq_["spawning_biomass"][year - 1], phi0); |
| 474 |
/*the final year of the time series has no data to inform recruitment |
|
| 475 |
devs, so this value is set to the mean recruitment.*/ |
|
| 476 |
} else {
|
|
| 477 |
// Why are we using evaluate_mean, how come a virtual function was |
|
| 478 |
// changed? AMH: there are now two virtual functions: evaluate_mean and |
|
| 479 |
// evaluate_process (see below) |
|
| 480 | 16530x |
population->recruitment->log_expected_recruitment[year - 1] = |
| 481 | 33060x |
fims_math::log(population->recruitment->evaluate_mean( |
| 482 | 33060x |
dq_["spawning_biomass"][year - 1], phi0)); |
| 483 | ||
| 484 | 19662x |
dq_["numbers_at_age"][i_age_year] = fims_math::exp( |
| 485 | 33060x |
population->recruitment->process->evaluate_process(year - 1)); |
| 486 |
} |
|
| 487 | ||
| 488 | 51300x |
dq_["expected_recruitment"][year] = dq_["numbers_at_age"][i_age_year]; |
| 489 |
} |
|
| 490 | ||
| 491 |
/** |
|
| 492 |
* This method is used to calculate the maturity at age for a population. It |
|
| 493 |
* takes a population object, the index of the age in the current year, the |
|
| 494 |
* age as input and calculates the maturity at age for that population. |
|
| 495 |
* @param population |
|
| 496 |
* @param i_age_year |
|
| 497 |
* @param age |
|
| 498 |
*/ |
|
| 499 | 212040x |
void CalculateMaturityAA( |
| 500 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 501 |
size_t i_age_year, size_t age) {
|
|
| 502 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 503 | 212040x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 504 | ||
| 505 | 212040x |
dq_["proportion_mature_at_age"][i_age_year] = |
| 506 | 212040x |
population->maturity->evaluate(population->ages[age]); |
| 507 |
} |
|
| 508 | ||
| 509 |
/** |
|
| 510 |
* This method is used to calculate the landings for a population and adds to |
|
| 511 |
* existing expected total landings by fleet. It takes a population object, |
|
| 512 |
* the year, and the age as input and calculates the landings for that |
|
| 513 |
* population. |
|
| 514 |
* @param population |
|
| 515 |
* @param year |
|
| 516 |
* @param age |
|
| 517 |
*/ |
|
| 518 | 205200x |
void CalculateLandings( |
| 519 |
std::shared_ptr<fims_popdy::Population<Type>> &population, size_t year, |
|
| 520 |
size_t age) {
|
|
| 521 |
std::map<std::string, fims::Vector<Type>> &pdq_ = |
|
| 522 | 205200x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 523 | ||
| 524 | 615600x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 525 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 526 | 410400x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 527 | 410400x |
size_t i_age_year = year * population->n_ages + age; |
| 528 | ||
| 529 | 410400x |
pdq_["total_landings_weight"][year] += |
| 530 | 1231200x |
fdq_["landings_weight_at_age"][i_age_year]; |
| 531 | ||
| 532 | 410400x |
fdq_["landings_weight"][year] += |
| 533 | 1231200x |
fdq_["landings_weight_at_age"][i_age_year]; |
| 534 | ||
| 535 | 410400x |
pdq_["total_landings_numbers"][year] += |
| 536 | 1231200x |
fdq_["landings_numbers_at_age"][i_age_year]; |
| 537 | ||
| 538 | 410400x |
fdq_["landings_numbers"][year] += |
| 539 | 1231200x |
fdq_["landings_numbers_at_age"][i_age_year]; |
| 540 |
} |
|
| 541 |
} |
|
| 542 | ||
| 543 |
/** |
|
| 544 |
* This method is used to calculate the catch weight at age for a population. |
|
| 545 |
* It takes a population object, the index of the age in the current year, the |
|
| 546 |
* year, and the age as input and calculates the weight at age for that |
|
| 547 |
* population. |
|
| 548 |
* @param population |
|
| 549 |
* @param year |
|
| 550 |
* @param age |
|
| 551 |
*/ |
|
| 552 | 205200x |
void CalculateLandingsWeightAA( |
| 553 |
std::shared_ptr<fims_popdy::Population<Type>> &population, size_t year, |
|
| 554 |
size_t age) {
|
|
| 555 | 205200x |
int i_age_year = year * population->n_ages + age; |
| 556 | 615600x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 557 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 558 | 410400x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 559 | ||
| 560 | 410400x |
fdq_["landings_weight_at_age"][i_age_year] = |
| 561 | 1153440x |
fdq_["landings_numbers_at_age"][i_age_year] * |
| 562 | 488160x |
population->growth->evaluate(population->ages[age]); |
| 563 |
} |
|
| 564 |
} |
|
| 565 | ||
| 566 |
/** |
|
| 567 |
* @brief Calculate the numbers at age for landings in a population. |
|
| 568 |
* |
|
| 569 |
* @param population The population. |
|
| 570 |
* @param i_age_year The index of the age and year. |
|
| 571 |
* @param year The year. |
|
| 572 |
* @param age The age. |
|
| 573 |
*/ |
|
| 574 | 205200x |
void CalculateLandingsNumbersAA( |
| 575 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 576 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 577 |
std::map<std::string, fims::Vector<Type>> &pdq_ = |
|
| 578 | 205200x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 579 | ||
| 580 | 615600x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 581 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 582 | 410400x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 583 | ||
| 584 |
// Baranov Catch Equation |
|
| 585 | 410400x |
fdq_["landings_numbers_at_age"][i_age_year] += |
| 586 | 410400x |
(population->fleets[fleet_]->Fmort[year] * |
| 587 | 820800x |
population->fleets[fleet_]->selectivity->evaluate( |
| 588 | 488160x |
population->ages[age])) / |
| 589 | 1719360x |
pdq_["mortality_Z"][i_age_year] * pdq_["numbers_at_age"][i_age_year] * |
| 590 | 1231200x |
(1 - fims_math::exp(-(pdq_["mortality_Z"][i_age_year]))); |
| 591 |
} |
|
| 592 |
} |
|
| 593 | ||
| 594 |
/** |
|
| 595 |
* @brief Calculate the index for a population. |
|
| 596 |
* |
|
| 597 |
* @param population The population. |
|
| 598 |
* @param i_age_year The index of the year and age. |
|
| 599 |
* @param year The year. |
|
| 600 |
* @param age The age. |
|
| 601 |
*/ |
|
| 602 | 205200x |
void CalculateIndex(std::shared_ptr<fims_popdy::Population<Type>> &population, |
| 603 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 604 | 615600x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 605 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 606 | 410400x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 607 | ||
| 608 | 1641600x |
fdq_["index_weight"][year] += fdq_["index_weight_at_age"][i_age_year]; |
| 609 | ||
| 610 | 1641600x |
fdq_["index_numbers"][year] += fdq_["index_numbers_at_age"][i_age_year]; |
| 611 |
} |
|
| 612 |
} |
|
| 613 | ||
| 614 |
/** |
|
| 615 |
* @brief Calculate the numbers at age for an index in the population. |
|
| 616 |
* |
|
| 617 |
* @param population The population. |
|
| 618 |
* @param i_age_year The index of the year and age. |
|
| 619 |
* @param year The year. |
|
| 620 |
* @param age The age. |
|
| 621 |
*/ |
|
| 622 | 205200x |
void CalculateIndexNumbersAA( |
| 623 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 624 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 625 |
std::map<std::string, fims::Vector<Type>> &pdq_ = |
|
| 626 | 205200x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 627 | ||
| 628 | 615600x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 629 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 630 | 410400x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 631 | ||
| 632 | 410400x |
fdq_["index_numbers_at_age"][i_age_year] += |
| 633 | 410400x |
(population->fleets[fleet_]->q.get_force_scalar(year) * |
| 634 | 820800x |
population->fleets[fleet_]->selectivity->evaluate( |
| 635 | 488160x |
population->ages[age])) * |
| 636 | 1231200x |
pdq_["numbers_at_age"][i_age_year]; |
| 637 |
} |
|
| 638 |
} |
|
| 639 | ||
| 640 |
/** |
|
| 641 |
* @brief Calculate the weight at age for an index in a population. |
|
| 642 |
* |
|
| 643 |
* @param population The population. |
|
| 644 |
* @param year The year. |
|
| 645 |
* @param age The age. |
|
| 646 |
*/ |
|
| 647 | 205200x |
void CalculateIndexWeightAA( |
| 648 |
std::shared_ptr<fims_popdy::Population<Type>> &population, size_t year, |
|
| 649 |
size_t age) {
|
|
| 650 | 205200x |
int i_age_year = year * population->n_ages + age; |
| 651 | 615600x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 652 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 653 | 410400x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 654 | ||
| 655 | 410400x |
fdq_["index_weight_at_age"][i_age_year] = |
| 656 | 1153440x |
fdq_["index_numbers_at_age"][i_age_year] * |
| 657 | 488160x |
population->growth->evaluate(population->ages[age]); |
| 658 |
} |
|
| 659 |
} |
|
| 660 | ||
| 661 |
/** |
|
| 662 |
* Evaluate the proportion of landings numbers at age. |
|
| 663 |
*/ |
|
| 664 | 570x |
void evaluate_age_comp() {
|
| 665 | 570x |
fleet_iterator fit; |
| 666 | 1710x |
for (fit = this->fleets.begin(); fit != this->fleets.end(); ++fit) {
|
| 667 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 668 | 1140x |
this->GetFleetDerivedQuantities((*fit).second->GetId()); |
| 669 | ||
| 670 | 1140x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 671 | 35340x |
for (size_t y = 0; y < fleet->n_years; y++) {
|
| 672 | 34200x |
Type sum = static_cast<Type>(0.0); |
| 673 | 34200x |
Type sum_obs = static_cast<Type>(0.0); |
| 674 |
// robust_add is a small value to add to expected composition |
|
| 675 |
// proportions at age to stabilize likelihood calculations |
|
| 676 |
// when the expected proportions are close to zero. |
|
| 677 |
// Type robust_add = static_cast<Type>(0.0); // zeroed out before |
|
| 678 |
// testing 0.0001; sum robust is used to calculate the total sum of |
|
| 679 |
// robust additions to ensure that proportions sum to 1. Type robust_sum |
|
| 680 |
// = static_cast<Type>(1.0); |
|
| 681 | ||
| 682 | 444600x |
for (size_t a = 0; a < fleet->n_ages; a++) {
|
| 683 | 410400x |
size_t i_age_year = y * fleet->n_ages + a; |
| 684 |
// Here we have a check to determine if the age comp |
|
| 685 |
// should be calculated from the retained landings or |
|
| 686 |
// the total population. These values are slightly different. |
|
| 687 |
// In the future this will have more impact as we implement |
|
| 688 |
// timing rather than everything occurring at the start of |
|
| 689 |
// the year. |
|
| 690 | 410400x |
if (fleet->fleet_observed_landings_data_id_m == -999) {
|
| 691 | 205200x |
fdq_["agecomp_expected"][i_age_year] = |
| 692 | 615600x |
fdq_["index_numbers_at_age"][i_age_year]; |
| 693 |
} else {
|
|
| 694 | 205200x |
fdq_["agecomp_expected"][i_age_year] = |
| 695 | 615600x |
fdq_["landings_numbers_at_age"][i_age_year]; |
| 696 |
} |
|
| 697 | 410400x |
sum += fdq_["agecomp_expected"][i_age_year]; |
| 698 |
// robust_sum -= robust_add; |
|
| 699 | ||
| 700 |
// This sums over the observed age composition data so that |
|
| 701 |
// the expected age composition can be rescaled to match the |
|
| 702 |
// total number observed. The check for na values should not |
|
| 703 |
// be needed as individual years should not have missing data. |
|
| 704 |
// This is need to be re-explored if/when we modify FIMS to |
|
| 705 |
// allow for composition bins that do not match the population |
|
| 706 |
// bins. |
|
| 707 | 410400x |
if (fleet->fleet_observed_agecomp_data_id_m != -999) {
|
| 708 | 349920x |
if (fleet->observed_agecomp_data->at(i_age_year) != |
| 709 | 349920x |
fleet->observed_agecomp_data->na_value) {
|
| 710 | 348912x |
sum_obs += fleet->observed_agecomp_data->at(i_age_year); |
| 711 |
} |
|
| 712 |
} |
|
| 713 |
} |
|
| 714 | 444600x |
for (size_t a = 0; a < fleet->n_ages; a++) {
|
| 715 | 410400x |
size_t i_age_year = y * fleet->n_ages + a; |
| 716 | 410400x |
fdq_["agecomp_proportion"][i_age_year] = |
| 717 | 820800x |
fdq_["agecomp_expected"][i_age_year] / sum; |
| 718 |
// robust_add + robust_sum * this->agecomp_expected[i_age_year] / sum; |
|
| 719 | ||
| 720 | 410400x |
if (fleet->fleet_observed_agecomp_data_id_m != -999) {
|
| 721 | 349920x |
fdq_["agecomp_expected"][i_age_year] = |
| 722 | 1049760x |
fdq_["agecomp_proportion"][i_age_year] * sum_obs; |
| 723 |
} |
|
| 724 |
} |
|
| 725 |
} |
|
| 726 |
} |
|
| 727 |
} |
|
| 728 | ||
| 729 |
/** |
|
| 730 |
* Evaluate the proportion of landings numbers at length. |
|
| 731 |
*/ |
|
| 732 | 570x |
void evaluate_length_comp() {
|
| 733 | 570x |
fleet_iterator fit; |
| 734 | 1710x |
for (fit = this->fleets.begin(); fit != this->fleets.end(); ++fit) {
|
| 735 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 736 | 1140x |
this->GetFleetDerivedQuantities((*fit).second->GetId()); |
| 737 | ||
| 738 | 1140x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 739 | ||
| 740 | 1140x |
if (fleet->n_lengths > 0) {
|
| 741 | 27528x |
for (size_t y = 0; y < fleet->n_years; y++) {
|
| 742 | 26640x |
Type sum = static_cast<Type>(0.0); |
| 743 | 26640x |
Type sum_obs = static_cast<Type>(0.0); |
| 744 |
// robust_add is a small value to add to expected composition |
|
| 745 |
// proportions at age to stabilize likelihood calculations |
|
| 746 |
// when the expected proportions are close to zero. |
|
| 747 |
// Type robust_add = static_cast<Type>(0.0); // 0.0001; zeroed out |
|
| 748 |
// before testing sum robust is used to calculate the total sum of |
|
| 749 |
// robust additions to ensure that proportions sum to 1. Type |
|
| 750 |
// robust_sum = static_cast<Type>(1.0); |
|
| 751 | 639360x |
for (size_t l = 0; l < fleet->n_lengths; l++) {
|
| 752 | 612720x |
size_t i_length_year = y * fleet->n_lengths + l; |
| 753 | 7965360x |
for (size_t a = 0; a < fleet->n_ages; a++) {
|
| 754 | 7352640x |
size_t i_age_year = y * fleet->n_ages + a; |
| 755 | 7352640x |
size_t i_length_age = a * fleet->n_lengths + l; |
| 756 | 7352640x |
fdq_["lengthcomp_expected"][i_length_year] += |
| 757 | 20666880x |
fdq_["agecomp_expected"][i_age_year] * |
| 758 | 7352640x |
fleet->age_to_length_conversion[i_length_age]; |
| 759 | ||
| 760 | 7352640x |
fdq_["landings_numbers_at_length"][i_length_year] += |
| 761 | 20666880x |
fdq_["landings_numbers_at_age"][i_age_year] * |
| 762 | 7352640x |
fleet->age_to_length_conversion[i_length_age]; |
| 763 | ||
| 764 | 7352640x |
fdq_["index_numbers_at_length"][i_length_year] += |
| 765 | 22057920x |
fdq_["index_numbers_at_age"][i_age_year] * |
| 766 | 7352640x |
fleet->age_to_length_conversion[i_length_age]; |
| 767 |
} |
|
| 768 | ||
| 769 | 612720x |
sum += fdq_["lengthcomp_expected"][i_length_year]; |
| 770 |
// robust_sum -= robust_add; |
|
| 771 | ||
| 772 | 612720x |
if (fleet->fleet_observed_lengthcomp_data_id_m != -999) {
|
| 773 | 612720x |
if (fleet->observed_lengthcomp_data->at(i_length_year) != |
| 774 | 612720x |
fleet->observed_lengthcomp_data->na_value) {
|
| 775 | 611754x |
sum_obs += fleet->observed_lengthcomp_data->at(i_length_year); |
| 776 |
} |
|
| 777 |
} |
|
| 778 |
} |
|
| 779 | 639360x |
for (size_t l = 0; l < fleet->n_lengths; l++) {
|
| 780 | 612720x |
size_t i_length_year = y * fleet->n_lengths + l; |
| 781 | 612720x |
fdq_["lengthcomp_proportion"][i_length_year] = |
| 782 | 1225440x |
fdq_["lengthcomp_expected"][i_length_year] / sum; |
| 783 |
// robust_add + robust_sum * |
|
| 784 |
// this->lengthcomp_expected[i_length_year] / sum; |
|
| 785 | 612720x |
if (fleet->fleet_observed_lengthcomp_data_id_m != -999) {
|
| 786 | 612720x |
fdq_["lengthcomp_expected"][i_length_year] = |
| 787 | 1838160x |
fdq_["lengthcomp_proportion"][i_length_year] * sum_obs; |
| 788 |
} |
|
| 789 |
} |
|
| 790 |
} |
|
| 791 |
} |
|
| 792 |
} |
|
| 793 |
} |
|
| 794 | ||
| 795 |
/** |
|
| 796 |
* Evaluate the natural log of the expected index. |
|
| 797 |
*/ |
|
| 798 | 570x |
void evaluate_index() {
|
| 799 | 570x |
fleet_iterator fit; |
| 800 | 1710x |
for (fit = this->fleets.begin(); fit != this->fleets.end(); ++fit) {
|
| 801 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 802 | 1140x |
this->GetFleetDerivedQuantities((*fit).second->GetId()); |
| 803 | 1140x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 804 | ||
| 805 | 71820x |
for (size_t i = 0; i < fdq_["index_numbers"].size(); i++) {
|
| 806 | 34200x |
if (fleet->observed_index_units == "number") {
|
| 807 | ! |
fdq_["index_expected"][i] = fdq_["index_numbers"][i]; |
| 808 |
} else {
|
|
| 809 | 136800x |
fdq_["index_expected"][i] = fdq_["index_weight"][i]; |
| 810 |
} |
|
| 811 | 136800x |
fdq_["log_index_expected"][i] = log(fdq_["index_expected"][i]); |
| 812 |
} |
|
| 813 |
} |
|
| 814 |
} |
|
| 815 | ||
| 816 |
/** |
|
| 817 |
* Evaluate the natural log of the expected landings. |
|
| 818 |
*/ |
|
| 819 | 570x |
void evaluate_landings() {
|
| 820 | 570x |
fleet_iterator fit; |
| 821 | 1710x |
for (fit = this->fleets.begin(); fit != this->fleets.end(); ++fit) {
|
| 822 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 823 | 1140x |
this->GetFleetDerivedQuantities((*fit).second->GetId()); |
| 824 | 1140x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 825 | ||
| 826 | 71820x |
for (size_t i = 0; i < fdq_["landings_weight"].size(); i++) {
|
| 827 | 34200x |
if (fleet->observed_landings_units == "number") {
|
| 828 | ! |
fdq_["landings_expected"][i] = fdq_["landings_numbers"][i]; |
| 829 |
} else {
|
|
| 830 | 136800x |
fdq_["landings_expected"][i] = fdq_["landings_weight"][i]; |
| 831 |
} |
|
| 832 | 136800x |
fdq_["log_landings_expected"][i] = log(fdq_["landings_expected"][i]); |
| 833 |
} |
|
| 834 |
} |
|
| 835 |
} |
|
| 836 | ||
| 837 | 570x |
virtual void Evaluate() {
|
| 838 |
/* |
|
| 839 |
Sets derived vectors to zero |
|
| 840 |
Performs parameters transformations |
|
| 841 |
Sets recruitment deviations to mean 0. |
|
| 842 |
*/ |
|
| 843 | 570x |
Prepare(); |
| 844 |
/* |
|
| 845 |
start at year=0, age=0; |
|
| 846 |
here year 0 is the estimated initial population structure and age 0 are |
|
| 847 |
recruits loops start at zero with if statements inside to specify unique |
|
| 848 |
code for initial structure and recruitment 0 loops. Could also have started |
|
| 849 |
loops at 1 with initial structure and recruitment setup outside the loops. |
|
| 850 | ||
| 851 |
year loop is extended to <= n_years because SSB is calculated as the start |
|
| 852 |
of the year value and by extending one extra year we get estimates of the |
|
| 853 |
population structure at the end of the final year. An alternative approach |
|
| 854 |
would be to keep initial numbers at age in it's own vector and each year to |
|
| 855 |
include the population structure at the end of the year. This is likely a |
|
| 856 |
null point given that we are planning to modify to an event/stanza based |
|
| 857 |
structure in later milestones which will eliminate this confusion by |
|
| 858 |
explicitly referencing the exact date (or period of averaging) at which any |
|
| 859 |
calculation or output is being made. |
|
| 860 |
*/ |
|
| 861 | 1140x |
for (size_t p = 0; p < this->populations.size(); p++) {
|
| 862 |
std::shared_ptr<fims_popdy::Population<Type>> &population = |
|
| 863 | 570x |
this->populations[p]; |
| 864 |
std::map<std::string, fims::Vector<Type>> &pdq_ = |
|
| 865 | 570x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 866 |
// CAAPopulationProxy<Type>& population = this->populations_proxies[p]; |
|
| 867 | ||
| 868 | 18240x |
for (size_t y = 0; y <= population->n_years; y++) {
|
| 869 | 229710x |
for (size_t a = 0; a < population->n_ages; a++) {
|
| 870 |
/* |
|
| 871 |
index naming defines the dimensional folding structure |
|
| 872 |
i.e. i_age_year is referencing folding over years and ages. |
|
| 873 |
*/ |
|
| 874 | 212040x |
size_t i_age_year = y * population->n_ages + a; |
| 875 |
/* |
|
| 876 |
Mortality rates are not estimated in the final year which is |
|
| 877 |
used to show expected population structure at the end of the model |
|
| 878 |
period. This is because biomass in year i represents biomass at the |
|
| 879 |
start of the year. Should we add complexity to track more values such |
|
| 880 |
as start, mid, and end biomass in all years where, start biomass=end |
|
| 881 |
biomass of the previous year? Referenced above, this is probably not |
|
| 882 |
worth exploring as later milestone changes will eliminate this |
|
| 883 |
confusion. |
|
| 884 |
*/ |
|
| 885 | 212040x |
if (y < population->n_years) {
|
| 886 |
/* |
|
| 887 |
First thing we need is total mortality aggregated across all fleets |
|
| 888 |
to inform the subsequent catch and change in numbers at age |
|
| 889 |
calculations. This is only calculated for years < n_years as these |
|
| 890 |
are the model estimated years with data. The year loop extends to |
|
| 891 |
y=n_years so that population numbers at age and SSB can be |
|
| 892 |
calculated at the end of the last year of the model |
|
| 893 |
*/ |
|
| 894 | 205200x |
CalculateMortality(population, i_age_year, y, a); |
| 895 |
} |
|
| 896 | 212040x |
CalculateMaturityAA(population, i_age_year, a); |
| 897 |
/* if statements needed because some quantities are only needed |
|
| 898 |
for the first year and/or age, so these steps are included here. |
|
| 899 |
*/ |
|
| 900 | 212040x |
if (y == 0) {
|
| 901 |
// Initial numbers at age is a user input or estimated parameter |
|
| 902 |
// vector. |
|
| 903 | 6840x |
CalculateInitialNumbersAA(population, i_age_year, a); |
| 904 | ||
| 905 | 6840x |
if (a == 0) {
|
| 906 | 1140x |
pdq_["unfished_numbers_at_age"][i_age_year] = |
| 907 | 570x |
fims_math::exp(population->recruitment->log_rzero[0]); |
| 908 |
} else {
|
|
| 909 | 6270x |
CalculateUnfishedNumbersAA(population, i_age_year, a - 1, a); |
| 910 |
} |
|
| 911 | ||
| 912 |
/* |
|
| 913 |
Fished and unfished biomass vectors are summing biomass at |
|
| 914 |
age across ages. |
|
| 915 |
*/ |
|
| 916 | ||
| 917 | 6840x |
CalculateBiomass(population, i_age_year, y, a); |
| 918 | ||
| 919 | 6840x |
CalculateUnfishedBiomass(population, i_age_year, y, a); |
| 920 | ||
| 921 |
/* |
|
| 922 |
Fished and unfished spawning biomass vectors are summing biomass at |
|
| 923 |
age across ages to allow calculation of recruitment in the next |
|
| 924 |
year. |
|
| 925 |
*/ |
|
| 926 | ||
| 927 | 6840x |
CalculateSpawningBiomass(population, i_age_year, y, a); |
| 928 | ||
| 929 | 6840x |
CalculateUnfishedSpawningBiomass(population, i_age_year, y, a); |
| 930 | ||
| 931 |
/* |
|
| 932 |
Expected recruitment in year 0 is numbers at age 0 in year 0. |
|
| 933 |
*/ |
|
| 934 | ||
| 935 | 6840x |
pdq_["expected_recruitment"][i_age_year] = |
| 936 | 20520x |
pdq_["numbers_at_age"][i_age_year]; |
| 937 |
} else {
|
|
| 938 | 205200x |
if (a == 0) {
|
| 939 |
// Set the nrecruits for age a=0 year y (use pointers instead of |
|
| 940 |
// functional returns) assuming fecundity = 1 and 50:50 sex ratio |
|
| 941 | 17100x |
CalculateRecruitment(population, i_age_year, y, y); |
| 942 | 34200x |
pdq_["unfished_numbers_at_age"][i_age_year] = |
| 943 | 17100x |
fims_math::exp(population->recruitment->log_rzero[0]); |
| 944 |
} else {
|
|
| 945 | 188100x |
size_t i_agem1_yearm1 = (y - 1) * population->n_ages + (a - 1); |
| 946 | 188100x |
CalculateNumbersAA(population, i_age_year, i_agem1_yearm1, a); |
| 947 | 188100x |
CalculateUnfishedNumbersAA(population, i_age_year, i_agem1_yearm1, |
| 948 |
a); |
|
| 949 |
} |
|
| 950 | 205200x |
CalculateBiomass(population, i_age_year, y, a); |
| 951 | 205200x |
CalculateSpawningBiomass(population, i_age_year, y, a); |
| 952 | ||
| 953 | 205200x |
CalculateUnfishedBiomass(population, i_age_year, y, a); |
| 954 | 205200x |
CalculateUnfishedSpawningBiomass(population, i_age_year, y, a); |
| 955 |
} |
|
| 956 | ||
| 957 |
/* |
|
| 958 |
Here composition, total catch, and index values are calculated for all |
|
| 959 |
years with reference data. They are not calculated for y=n_years as |
|
| 960 |
there is this is just to get final population structure at the end of |
|
| 961 |
the terminal year. |
|
| 962 |
*/ |
|
| 963 | 212040x |
if (y < population->n_years) {
|
| 964 | 205200x |
CalculateLandingsNumbersAA(population, i_age_year, y, a); |
| 965 | 205200x |
CalculateLandingsWeightAA(population, y, a); |
| 966 | 205200x |
CalculateLandings(population, y, a); |
| 967 | ||
| 968 | 205200x |
CalculateIndexNumbersAA(population, i_age_year, y, a); |
| 969 | 205200x |
CalculateIndexWeightAA(population, y, a); |
| 970 | 205200x |
CalculateIndex(population, i_age_year, y, a); |
| 971 |
} |
|
| 972 |
} |
|
| 973 |
} |
|
| 974 |
} |
|
| 975 | 570x |
evaluate_age_comp(); |
| 976 | 570x |
evaluate_length_comp(); |
| 977 | 570x |
evaluate_index(); |
| 978 | 570x |
evaluate_landings(); |
| 979 |
} |
|
| 980 |
/** |
|
| 981 |
* * This method is used to generate TMB reports from the population dynamics |
|
| 982 |
* model. |
|
| 983 |
*/ |
|
| 984 | 570x |
virtual void Report() {
|
| 985 | 570x |
int n_fleets = this->fleets.size(); |
| 986 | 570x |
int n_pops = this->populations.size(); |
| 987 |
#ifdef TMB_MODEL |
|
| 988 | 570x |
if (this->do_reporting == true) {
|
| 989 | 544x |
report_vectors.clear(); |
| 990 |
// std::shared_ptr<UncertaintyReportInfoMap> |
|
| 991 |
// population_uncertainty_report_info_map = |
|
| 992 |
// this->GetPopulationUncertaintyReportInfoMap(); |
|
| 993 | ||
| 994 |
// std::shared_ptr<UncertaintyReportInfoMap> |
|
| 995 |
// fleet_uncertainty_report_info_map = |
|
| 996 |
// this->GetFleetUncertaintyReportInfoMap(); |
|
| 997 | ||
| 998 |
// initialize population vectors |
|
| 999 | 544x |
vector<vector<Type>> biomass_p(n_pops); |
| 1000 | 544x |
vector<vector<Type>> expected_recruitment_p(n_pops); |
| 1001 | 544x |
vector<vector<Type>> mortality_F_p(n_pops); |
| 1002 | 544x |
vector<vector<Type>> mortality_Z_p(n_pops); |
| 1003 | 544x |
vector<vector<Type>> numbers_at_age_p(n_pops); |
| 1004 | 544x |
vector<vector<Type>> proportion_mature_at_age_p(n_pops); |
| 1005 | 544x |
vector<vector<Type>> spawning_biomass_p(n_pops); |
| 1006 | 544x |
vector<vector<Type>> sum_selectivity_p(n_pops); |
| 1007 | 544x |
vector<vector<Type>> total_landings_numbers_p(n_pops); |
| 1008 | 544x |
vector<vector<Type>> total_landings_weight_p(n_pops); |
| 1009 | 544x |
vector<vector<Type>> unfished_biomass_p(n_pops); |
| 1010 | 544x |
vector<vector<Type>> unfished_numbers_at_age_p(n_pops); |
| 1011 | 544x |
vector<vector<Type>> unfished_spawning_biomass_p(n_pops); |
| 1012 | 544x |
vector<vector<Type>> log_M_p(n_pops); |
| 1013 | 544x |
vector<vector<Type>> log_init_naa_p(n_pops); |
| 1014 | ||
| 1015 |
// initialize fleet vectors |
|
| 1016 | 544x |
vector<vector<Type>> agecomp_expected_f(n_fleets); |
| 1017 | 544x |
vector<vector<Type>> agecomp_proportion_f(n_fleets); |
| 1018 | 544x |
vector<vector<Type>> catch_index_f(n_fleets); |
| 1019 | 544x |
vector<vector<Type>> index_expected_f(n_fleets); |
| 1020 | 544x |
vector<vector<Type>> index_numbers_f(n_fleets); |
| 1021 | 544x |
vector<vector<Type>> index_numbers_at_age_f(n_fleets); |
| 1022 | 544x |
vector<vector<Type>> index_numbers_at_length_f(n_fleets); |
| 1023 | 544x |
vector<vector<Type>> index_weight_f(n_fleets); |
| 1024 | 544x |
vector<vector<Type>> index_weight_at_age_f(n_fleets); |
| 1025 | 544x |
vector<vector<Type>> landings_expected_f(n_fleets); |
| 1026 | 544x |
vector<vector<Type>> landings_numbers_f(n_fleets); |
| 1027 | 544x |
vector<vector<Type>> landings_numbers_at_age_f(n_fleets); |
| 1028 | 544x |
vector<vector<Type>> landings_numbers_at_length_f(n_fleets); |
| 1029 | 544x |
vector<vector<Type>> landings_weight_f(n_fleets); |
| 1030 | 544x |
vector<vector<Type>> landings_weight_at_age_f(n_fleets); |
| 1031 | 544x |
vector<vector<Type>> lengthcomp_expected_f(n_fleets); |
| 1032 | 544x |
vector<vector<Type>> lengthcomp_proportion_f(n_fleets); |
| 1033 | 544x |
vector<vector<Type>> log_index_expected_f(n_fleets); |
| 1034 | 544x |
vector<vector<Type>> log_landings_expected_f(n_fleets); |
| 1035 | ||
| 1036 |
// initiate population index for structuring report out objects |
|
| 1037 | 544x |
int pop_idx = 0; |
| 1038 | 1088x |
for (size_t p = 0; p < this->populations.size(); p++) {
|
| 1039 | 544x |
this->populations[p]->create_report_vectors(report_vectors); |
| 1040 |
// std::shared_ptr<fims_popdy::Population<Type>> &population = |
|
| 1041 |
// this->populations[p]; |
|
| 1042 |
std::map<std::string, fims::Vector<Type>> &derived_quantities = |
|
| 1043 | 544x |
this->GetPopulationDerivedQuantities(this->populations[p]->GetId()); |
| 1044 | 544x |
this->populations[p]->maturity->create_report_vectors(report_vectors); |
| 1045 | 544x |
this->populations[p]->growth->create_report_vectors(report_vectors); |
| 1046 | 544x |
this->populations[p]->recruitment->create_report_vectors( |
| 1047 | 544x |
report_vectors); |
| 1048 | 1088x |
biomass_p(pop_idx) = derived_quantities["biomass"].to_tmb(); |
| 1049 | 544x |
expected_recruitment_p(pop_idx) = |
| 1050 | 1632x |
derived_quantities["expected_recruitment"].to_tmb(); |
| 1051 | 1088x |
mortality_F_p(pop_idx) = derived_quantities["mortality_F"].to_tmb(); |
| 1052 | 1088x |
mortality_Z_p(pop_idx) = derived_quantities["mortality_Z"].to_tmb(); |
| 1053 | 544x |
numbers_at_age_p(pop_idx) = |
| 1054 | 1632x |
derived_quantities["numbers_at_age"].to_tmb(); |
| 1055 | 544x |
proportion_mature_at_age_p(pop_idx) = |
| 1056 | 1632x |
derived_quantities["proportion_mature_at_age"].to_tmb(); |
| 1057 | 544x |
spawning_biomass_p(pop_idx) = |
| 1058 | 1632x |
derived_quantities["spawning_biomass"].to_tmb(); |
| 1059 | 544x |
sum_selectivity_p(pop_idx) = |
| 1060 | 1632x |
derived_quantities["sum_selectivity"].to_tmb(); |
| 1061 | 544x |
total_landings_numbers_p(pop_idx) = |
| 1062 | 1632x |
derived_quantities["total_landings_numbers"].to_tmb(); |
| 1063 | 544x |
total_landings_weight_p(pop_idx) = |
| 1064 | 1632x |
derived_quantities["total_landings_weight"].to_tmb(); |
| 1065 | 544x |
unfished_biomass_p(pop_idx) = |
| 1066 | 1632x |
derived_quantities["unfished_biomass"].to_tmb(); |
| 1067 | 544x |
unfished_numbers_at_age_p(pop_idx) = |
| 1068 | 1632x |
derived_quantities["unfished_numbers_at_age"].to_tmb(); |
| 1069 | 544x |
unfished_spawning_biomass_p(pop_idx) = |
| 1070 | 1088x |
derived_quantities["unfished_spawning_biomass"].to_tmb(); |
| 1071 | 544x |
log_M_p(pop_idx) = this->populations[pop_idx]->log_M.to_tmb(); |
| 1072 | 544x |
log_init_naa_p(pop_idx) = |
| 1073 | 544x |
this->populations[pop_idx]->log_init_naa.to_tmb(); |
| 1074 | ||
| 1075 | 544x |
pop_idx += 1; |
| 1076 |
} |
|
| 1077 | ||
| 1078 |
// initiate fleet index for structuring report out objects |
|
| 1079 | 544x |
int fleet_idx = 0; |
| 1080 | 544x |
fleet_iterator fit; |
| 1081 | 1632x |
for (fit = this->fleets.begin(); fit != this->fleets.end(); ++fit) {
|
| 1082 | 1088x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 1083 | 1088x |
fleet->create_report_vectors(report_vectors); |
| 1084 | 1088x |
fleet->selectivity->create_report_vectors(report_vectors); |
| 1085 |
std::map<std::string, fims::Vector<Type>> &derived_quantities = |
|
| 1086 | 1088x |
this->GetFleetDerivedQuantities(fleet->GetId()); |
| 1087 | ||
| 1088 | 1088x |
agecomp_expected_f(fleet_idx) = |
| 1089 | 3264x |
derived_quantities["agecomp_expected"].to_tmb(); |
| 1090 | 1088x |
agecomp_proportion_f(fleet_idx) = |
| 1091 | 3264x |
derived_quantities["agecomp_proportion"].to_tmb(); |
| 1092 | 2176x |
catch_index_f(fleet_idx) = derived_quantities["catch_index"].to_tmb(); |
| 1093 | 1088x |
index_expected_f(fleet_idx) = |
| 1094 | 3264x |
derived_quantities["index_expected"].to_tmb(); |
| 1095 | 1088x |
index_numbers_f(fleet_idx) = |
| 1096 | 3264x |
derived_quantities["index_numbers"].to_tmb(); |
| 1097 | 1088x |
index_numbers_at_age_f(fleet_idx) = |
| 1098 | 3264x |
derived_quantities["index_numbers_at_age"].to_tmb(); |
| 1099 | 1088x |
index_numbers_at_length_f(fleet_idx) = |
| 1100 | 3264x |
derived_quantities["index_numbers_at_length"].to_tmb(); |
| 1101 | 2176x |
index_weight_f(fleet_idx) = derived_quantities["index_weight"].to_tmb(); |
| 1102 | 1088x |
index_weight_at_age_f(fleet_idx) = |
| 1103 | 3264x |
derived_quantities["index_weight_at_age"].to_tmb(); |
| 1104 | 1088x |
landings_expected_f(fleet_idx) = |
| 1105 | 3264x |
derived_quantities["landings_expected"].to_tmb(); |
| 1106 | 1088x |
landings_numbers_f(fleet_idx) = |
| 1107 | 3264x |
derived_quantities["landings_numbers"].to_tmb(); |
| 1108 | 1088x |
landings_numbers_at_age_f(fleet_idx) = |
| 1109 | 3264x |
derived_quantities["landings_numbers_at_age"].to_tmb(); |
| 1110 | 1088x |
landings_numbers_at_length_f(fleet_idx) = |
| 1111 | 3264x |
derived_quantities["landings_numbers_at_length"].to_tmb(); |
| 1112 | 1088x |
landings_weight_f(fleet_idx) = |
| 1113 | 3264x |
derived_quantities["landings_weight"].to_tmb(); |
| 1114 | 1088x |
landings_weight_at_age_f(fleet_idx) = |
| 1115 | 3264x |
derived_quantities["landings_weight_at_age"].to_tmb(); |
| 1116 |
// length_comp_expected_f(fleet_idx) = |
|
| 1117 |
// derived_quantities["length_comp_expected"]; |
|
| 1118 |
// length_comp_proportion_f(fleet_idx) = |
|
| 1119 |
// derived_quantities["length_comp_proportion"]; |
|
| 1120 | 1088x |
lengthcomp_expected_f(fleet_idx) = |
| 1121 | 3264x |
derived_quantities["lengthcomp_expected"].to_tmb(); |
| 1122 | 1088x |
lengthcomp_proportion_f(fleet_idx) = |
| 1123 | 3264x |
derived_quantities["lengthcomp_proportion"].to_tmb(); |
| 1124 | 1088x |
log_index_expected_f(fleet_idx) = |
| 1125 | 3264x |
derived_quantities["log_index_expected"].to_tmb(); |
| 1126 | 1088x |
log_landings_expected_f(fleet_idx) = |
| 1127 | 2176x |
derived_quantities["log_landings_expected"].to_tmb(); |
| 1128 | 1088x |
fleet_idx += 1; |
| 1129 |
} |
|
| 1130 | ||
| 1131 | 544x |
vector<Type> biomass = ADREPORTvector(biomass_p); |
| 1132 | 544x |
vector<Type> expected_recruitment = |
| 1133 |
ADREPORTvector(expected_recruitment_p); |
|
| 1134 | 544x |
vector<Type> mortality_F = ADREPORTvector(mortality_F_p); |
| 1135 | 544x |
vector<Type> mortality_Z = ADREPORTvector(mortality_Z_p); |
| 1136 | 544x |
vector<Type> numbers_at_age = ADREPORTvector(numbers_at_age_p); |
| 1137 | 544x |
vector<Type> proportion_mature_at_age = |
| 1138 |
ADREPORTvector(proportion_mature_at_age_p); |
|
| 1139 | 544x |
vector<Type> spawning_biomass = ADREPORTvector(spawning_biomass_p); |
| 1140 | 544x |
vector<Type> sum_selectivity = ADREPORTvector(sum_selectivity_p); |
| 1141 | 544x |
vector<Type> total_landings_numbers = |
| 1142 |
ADREPORTvector(total_landings_numbers_p); |
|
| 1143 | 544x |
vector<Type> total_landings_weight = |
| 1144 |
ADREPORTvector(total_landings_weight_p); |
|
| 1145 | 544x |
vector<Type> unfished_biomass = ADREPORTvector(unfished_biomass_p); |
| 1146 | 544x |
vector<Type> unfished_numbers_at_age = |
| 1147 |
ADREPORTvector(unfished_numbers_at_age_p); |
|
| 1148 | 544x |
vector<Type> unfished_spawning_biomass = |
| 1149 |
ADREPORTvector(unfished_spawning_biomass_p); |
|
| 1150 | ||
| 1151 | 544x |
vector<Type> agecomp_expected = ADREPORTvector(agecomp_expected_f); |
| 1152 | 544x |
vector<Type> agecomp_proportion = ADREPORTvector(agecomp_proportion_f); |
| 1153 | 544x |
vector<Type> catch_index = ADREPORTvector(catch_index_f); |
| 1154 | 544x |
vector<Type> index_expected = ADREPORTvector(index_expected_f); |
| 1155 | 544x |
vector<Type> index_numbers = ADREPORTvector(index_numbers_f); |
| 1156 | 544x |
vector<Type> index_numbers_at_age = |
| 1157 |
ADREPORTvector(index_numbers_at_age_f); |
|
| 1158 | 544x |
vector<Type> index_numbers_at_length = |
| 1159 |
ADREPORTvector(index_numbers_at_length_f); |
|
| 1160 | 544x |
vector<Type> index_weight = ADREPORTvector(index_weight_f); |
| 1161 | 544x |
vector<Type> index_weight_at_age = ADREPORTvector(index_weight_at_age_f); |
| 1162 | 544x |
vector<Type> landings_expected = ADREPORTvector(landings_expected_f); |
| 1163 | 544x |
vector<Type> landings_numbers = ADREPORTvector(landings_numbers_f); |
| 1164 | 544x |
vector<Type> landings_numbers_at_age = |
| 1165 |
ADREPORTvector(landings_numbers_at_age_f); |
|
| 1166 | 544x |
vector<Type> landings_numbers_at_length = |
| 1167 |
ADREPORTvector(landings_numbers_at_length_f); |
|
| 1168 | 544x |
vector<Type> landings_weight = ADREPORTvector(landings_weight_f); |
| 1169 | 544x |
vector<Type> landings_weight_at_age = |
| 1170 |
ADREPORTvector(landings_weight_at_age_f); |
|
| 1171 |
// vector<Type> length_comp_expected = |
|
| 1172 |
// ADREPORTvector(length_comp_expected_f); vector<Type> |
|
| 1173 |
// length_comp_proportion = ADREPORTvector(length_comp_proportion_f); |
|
| 1174 | 544x |
vector<Type> lengthcomp_expected = ADREPORTvector(lengthcomp_expected_f); |
| 1175 | 544x |
vector<Type> lengthcomp_proportion = |
| 1176 |
ADREPORTvector(lengthcomp_proportion_f); |
|
| 1177 | 544x |
vector<Type> log_index_expected = ADREPORTvector(log_index_expected_f); |
| 1178 | 544x |
vector<Type> log_landings_expected = |
| 1179 |
ADREPORTvector(log_landings_expected_f); |
|
| 1180 |
// populations |
|
| 1181 |
// report |
|
| 1182 | 436x |
FIMS_REPORT_F_("biomass", biomass_p, this->of);
|
| 1183 | 436x |
FIMS_REPORT_F_("expected_recruitment", expected_recruitment_p, this->of);
|
| 1184 | 436x |
FIMS_REPORT_F_("mortality_F", mortality_F_p, this->of);
|
| 1185 | 436x |
FIMS_REPORT_F_("mortality_Z", mortality_Z_p, this->of);
|
| 1186 | 436x |
FIMS_REPORT_F_("numbers_at_age", numbers_at_age_p, this->of);
|
| 1187 | 436x |
FIMS_REPORT_F_("proportion_mature_at_age", proportion_mature_at_age_p,
|
| 1188 |
this->of); |
|
| 1189 | 436x |
FIMS_REPORT_F_("spawning_biomass", spawning_biomass_p, this->of);
|
| 1190 | 436x |
FIMS_REPORT_F_("sum_selectivity", sum_selectivity_p, this->of);
|
| 1191 | 436x |
FIMS_REPORT_F_("total_landings_numbers", total_landings_numbers_p,
|
| 1192 |
this->of); |
|
| 1193 | 436x |
FIMS_REPORT_F_("total_landings_weight", total_landings_weight_p,
|
| 1194 |
this->of); |
|
| 1195 | 436x |
FIMS_REPORT_F_("unfished_biomass", unfished_biomass_p, this->of);
|
| 1196 | 436x |
FIMS_REPORT_F_("unfished_numbers_at_age", unfished_numbers_at_age_p,
|
| 1197 |
this->of); |
|
| 1198 | 436x |
FIMS_REPORT_F_("unfished_spawning_biomass", unfished_spawning_biomass_p,
|
| 1199 |
this->of); |
|
| 1200 | 436x |
FIMS_REPORT_F_("log_M", log_M_p, this->of);
|
| 1201 | 436x |
FIMS_REPORT_F_("log_init_naa", log_init_naa_p, this->of);
|
| 1202 | ||
| 1203 |
// adreport |
|
| 1204 | 544x |
ADREPORT_F(biomass, this->of); |
| 1205 | 544x |
ADREPORT_F(expected_recruitment, this->of); |
| 1206 | 544x |
ADREPORT_F(mortality_F, this->of); |
| 1207 | 544x |
ADREPORT_F(mortality_Z, this->of); |
| 1208 | 544x |
ADREPORT_F(numbers_at_age, this->of); |
| 1209 | 544x |
ADREPORT_F(proportion_mature_at_age, this->of); |
| 1210 | 544x |
ADREPORT_F(spawning_biomass, this->of); |
| 1211 | 544x |
ADREPORT_F(sum_selectivity, this->of); |
| 1212 | 544x |
ADREPORT_F(total_landings_numbers, this->of); |
| 1213 | 544x |
ADREPORT_F(total_landings_weight, this->of); |
| 1214 | 544x |
ADREPORT_F(unfished_biomass, this->of); |
| 1215 | 544x |
ADREPORT_F(unfished_numbers_at_age, this->of); |
| 1216 | 544x |
ADREPORT_F(unfished_spawning_biomass, this->of); |
| 1217 | ||
| 1218 |
// fleets |
|
| 1219 |
// report |
|
| 1220 | 436x |
FIMS_REPORT_F_("agecomp_expected", agecomp_expected_f, this->of);
|
| 1221 | 436x |
FIMS_REPORT_F_("agecomp_proportion", agecomp_proportion_f, this->of);
|
| 1222 | 436x |
FIMS_REPORT_F_("catch_index", catch_index_f, this->of);
|
| 1223 | 436x |
FIMS_REPORT_F_("index_expected", index_expected_f, this->of);
|
| 1224 | 436x |
FIMS_REPORT_F_("index_numbers", index_numbers_f, this->of);
|
| 1225 | 436x |
FIMS_REPORT_F_("index_numbers_at_age", index_numbers_at_age_f, this->of);
|
| 1226 | 436x |
FIMS_REPORT_F_("index_numbers_at_length", index_numbers_at_length_f,
|
| 1227 |
this->of); |
|
| 1228 | 436x |
FIMS_REPORT_F_("index_weight", index_weight_f, this->of);
|
| 1229 | 436x |
FIMS_REPORT_F_("index_weight_at_age", index_weight_at_age_f, this->of);
|
| 1230 | 436x |
FIMS_REPORT_F_("landings_expected", landings_expected_f, this->of);
|
| 1231 | 436x |
FIMS_REPORT_F_("landings_numbers", landings_numbers_f, this->of);
|
| 1232 | 436x |
FIMS_REPORT_F_("landings_numbers_at_age", landings_numbers_at_age_f,
|
| 1233 |
this->of); |
|
| 1234 | 436x |
FIMS_REPORT_F_("landings_numbers_at_length", landings_numbers_at_length_f,
|
| 1235 |
this->of); |
|
| 1236 | 436x |
FIMS_REPORT_F_("landings_weight", landings_weight_f, this->of);
|
| 1237 | 436x |
FIMS_REPORT_F_("landings_weight_at_age", landings_weight_at_age_f,
|
| 1238 |
this->of); |
|
| 1239 | 436x |
FIMS_REPORT_F_("lengthcomp_expected", lengthcomp_expected_f, this->of);
|
| 1240 | 436x |
FIMS_REPORT_F_("lengthcomp_proportion", lengthcomp_proportion_f,
|
| 1241 |
this->of); |
|
| 1242 | 436x |
FIMS_REPORT_F_("log_index_expected", log_index_expected_f, this->of);
|
| 1243 | 436x |
FIMS_REPORT_F_("log_landings_expected", log_landings_expected_f,
|
| 1244 |
this->of); |
|
| 1245 |
// adreport |
|
| 1246 | 544x |
ADREPORT_F(agecomp_expected, this->of); |
| 1247 | 544x |
ADREPORT_F(agecomp_proportion, this->of); |
| 1248 | 544x |
ADREPORT_F(catch_index, this->of); |
| 1249 | 544x |
ADREPORT_F(index_expected, this->of); |
| 1250 | 544x |
ADREPORT_F(index_numbers, this->of); |
| 1251 | 544x |
ADREPORT_F(index_numbers_at_age, this->of); |
| 1252 | 544x |
ADREPORT_F(index_numbers_at_length, this->of); |
| 1253 | 544x |
ADREPORT_F(index_weight, this->of); |
| 1254 | 544x |
ADREPORT_F(index_weight_at_age, this->of); |
| 1255 | 544x |
ADREPORT_F(landings_expected, this->of); |
| 1256 | 544x |
ADREPORT_F(landings_numbers, this->of); |
| 1257 | 544x |
ADREPORT_F(landings_numbers_at_age, this->of); |
| 1258 | 544x |
ADREPORT_F(landings_numbers_at_length, this->of); |
| 1259 | 544x |
ADREPORT_F(landings_weight, this->of); |
| 1260 | 544x |
ADREPORT_F(landings_weight_at_age, this->of); |
| 1261 | 544x |
ADREPORT_F(lengthcomp_expected, this->of); |
| 1262 | 544x |
ADREPORT_F(lengthcomp_proportion, this->of); |
| 1263 | 544x |
ADREPORT_F(log_index_expected, this->of); |
| 1264 | 544x |
ADREPORT_F(log_landings_expected, this->of); |
| 1265 | 544x |
std::stringstream var_name; |
| 1266 |
typename std::map<std::string, fims::Vector<fims::Vector<Type>>>::iterator |
|
| 1267 | 544x |
rvit; |
| 1268 | 6528x |
for (rvit = report_vectors.begin(); rvit != report_vectors.end(); |
| 1269 | 5984x |
++rvit) {
|
| 1270 | 5984x |
auto &x = rvit->second; |
| 1271 | ||
| 1272 | 5984x |
int outer_dim = x.size(); |
| 1273 | 5984x |
int dim = 0; |
| 1274 | 15776x |
for (int i = 0; i < outer_dim; i++) {
|
| 1275 | 9792x |
dim += x[i].size(); |
| 1276 |
} |
|
| 1277 | 5984x |
vector<Type> res(dim); |
| 1278 | 5984x |
int idx = 0; |
| 1279 | 15776x |
for (int i = 0; i < outer_dim; i++) {
|
| 1280 | 9792x |
int inner_dim = x[i].size(); |
| 1281 | 509120x |
for (int j = 0; j < inner_dim; j++) {
|
| 1282 | 499328x |
res(idx) = x[i][j]; |
| 1283 | 499328x |
idx += 1; |
| 1284 |
} |
|
| 1285 |
} |
|
| 1286 | 5984x |
this->of->reportvector.push(res, rvit->first.c_str()); |
| 1287 |
} |
|
| 1288 |
} |
|
| 1289 |
#endif |
|
| 1290 |
} |
|
| 1291 |
}; |
|
| 1292 | ||
| 1293 |
} // namespace fims_popdy |
|
| 1294 | ||
| 1295 |
#endif |
| 1 |
/** |
|
| 2 |
* @file fishery_model_base.hpp |
|
| 3 |
* @brief Defines the base class for all fishery models within the FIMS |
|
| 4 |
* framework. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_MODELS_FISHERY_MODEL_BASE_HPP |
|
| 10 |
#define FIMS_MODELS_FISHERY_MODEL_BASE_HPP |
|
| 11 | ||
| 12 |
#include "../../common/model_object.hpp" |
|
| 13 |
#include "../../common/fims_math.hpp" |
|
| 14 |
#include "../../common/fims_vector.hpp" |
|
| 15 |
#include "../../population_dynamics/population/population.hpp" |
|
| 16 |
/** |
|
| 17 |
* @brief The population dynamics of FIMS. |
|
| 18 |
* |
|
| 19 |
*/ |
|
| 20 |
namespace fims_popdy {
|
|
| 21 | ||
| 22 |
/** |
|
| 23 |
* @brief Structure to hold dimension information for derived quantities. |
|
| 24 |
*/ |
|
| 25 |
struct DimensionInfo {
|
|
| 26 |
std::string name; /*!< name of the derived quantity */ |
|
| 27 |
int ndims; /*!< number of dimensions */ |
|
| 28 |
fims::Vector<int> dims; /*!< vector of dimensions */ |
|
| 29 |
fims::Vector<std::string> dim_names; /*!< vector of dimension names */ |
|
| 30 |
fims::Vector<double> se_values_m; /*!< final values of the report vector */ |
|
| 31 | ||
| 32 |
/** |
|
| 33 |
* @brief Default constructor for dimension information. |
|
| 34 |
*/ |
|
| 35 | 1836x |
DimensionInfo() : ndims(0) {}
|
| 36 | ||
| 37 |
/** |
|
| 38 |
* @brief Constructor with parameters. |
|
| 39 |
* @param name The name of the derived quantity. |
|
| 40 |
* @param dims A vector of integers representing the dimensions. |
|
| 41 |
* @param dim_names A vector of strings representing the names of the |
|
| 42 |
* dimensions. |
|
| 43 |
*/ |
|
| 44 | 1908x |
DimensionInfo(const std::string &name, const fims::Vector<int> &dims, |
| 45 |
const fims::Vector<std::string> &dim_names) |
|
| 46 | 1908x |
: name(name), ndims(dims.size()), dims(dims), dim_names(dim_names) {}
|
| 47 | ||
| 48 |
/** |
|
| 49 |
* Copy constructor |
|
| 50 |
*/ |
|
| 51 | 663x |
DimensionInfo(const DimensionInfo &other) |
| 52 | 663x |
: name(other.name), |
| 53 | 663x |
ndims(other.dims.size()), |
| 54 | 663x |
dims(other.dims), |
| 55 | 663x |
dim_names(other.dim_names) {}
|
| 56 | ||
| 57 |
/** |
|
| 58 |
* @brief Assignment operator for DimensionInfo. |
|
| 59 |
*/ |
|
| 60 | 1908x |
DimensionInfo &operator=(const DimensionInfo &other) {
|
| 61 | 1908x |
if (this != &other) {
|
| 62 | 1908x |
name = other.name; |
| 63 | 1908x |
ndims = other.ndims; |
| 64 | 1908x |
dims = other.dims; |
| 65 | 1908x |
dim_names = other.dim_names; |
| 66 | 1908x |
se_values_m = other.se_values_m; |
| 67 |
} |
|
| 68 | 1908x |
return *this; |
| 69 |
} |
|
| 70 |
}; |
|
| 71 | ||
| 72 |
/** |
|
| 73 |
* TMB sdreport values are returned as a single vector, if there are multiple |
|
| 74 |
* populations or fleets then the report vectors are concatenated together. |
|
| 75 |
* This struct is used to store the name, id, and length of each report |
|
| 76 |
* vector so that they can be extracted from the single report vector. |
|
| 77 |
*/ |
|
| 78 |
struct UncertaintyReportInfo {
|
|
| 79 |
/** |
|
| 80 |
* * name of the report vector |
|
| 81 |
*/ |
|
| 82 |
std::string name; |
|
| 83 |
/** |
|
| 84 |
* * id of the population or fleet the report is associated with |
|
| 85 |
*/ |
|
| 86 |
uint32_t id_m; |
|
| 87 |
/** |
|
| 88 |
* * starting index of the report vector in the overall report vector |
|
| 89 |
*/ |
|
| 90 |
size_t start_m; |
|
| 91 |
/** |
|
| 92 |
* * length of the report vector |
|
| 93 |
*/ |
|
| 94 |
size_t length_m; |
|
| 95 | ||
| 96 |
/** |
|
| 97 |
* @brief Default constructor for UncertaintyReportInfo. |
|
| 98 |
*/ |
|
| 99 |
UncertaintyReportInfo() : id_m(0), start_m(0), length_m(0) {}
|
|
| 100 | ||
| 101 |
/** |
|
| 102 |
* @brief Constructor with parameters. |
|
| 103 |
* @param name The name of the report vector. |
|
| 104 |
* @param id The id of the population or fleet the report is associated with. |
|
| 105 |
* @param start The starting index of the report vector in the overall report |
|
| 106 |
* vector. |
|
| 107 |
* @param length The length of the report vector. |
|
| 108 |
*/ |
|
| 109 |
UncertaintyReportInfo(const std::string &name, uint32_t id, size_t start, |
|
| 110 |
size_t length) |
|
| 111 |
: name(name), id_m(id), start_m(start), length_m(length) {}
|
|
| 112 | ||
| 113 |
/** |
|
| 114 |
* @brief Copy constructor. |
|
| 115 |
* @param other The UncertaintyReportInfo object to copy from. |
|
| 116 |
*/ |
|
| 117 |
UncertaintyReportInfo(const UncertaintyReportInfo &other) |
|
| 118 |
: name(other.name), |
|
| 119 |
id_m(other.id_m), |
|
| 120 |
start_m(other.start_m), |
|
| 121 |
length_m(other.length_m) {}
|
|
| 122 |
}; |
|
| 123 | ||
| 124 |
/** |
|
| 125 |
* @brief FisheryModelBase is a base class for fishery models in FIMS. |
|
| 126 |
* |
|
| 127 |
*/ |
|
| 128 |
template <typename Type> |
|
| 129 |
class FisheryModelBase : public fims_model_object::FIMSObject<Type> {
|
|
| 130 |
static uint32_t id_g; /*!< global id where unique id is drawn from for fishery |
|
| 131 |
model object*/ |
|
| 132 |
uint32_t id; /*!< unique identifier assigned for fishery model object */ |
|
| 133 | ||
| 134 |
public: |
|
| 135 |
#ifdef TMB_MODEL |
|
| 136 |
bool do_reporting = |
|
| 137 |
true; /*!< flag to control reporting of derived quantities */ |
|
| 138 |
#endif |
|
| 139 |
/** |
|
| 140 |
* @brief A string specifying the model type. |
|
| 141 |
* |
|
| 142 |
*/ |
|
| 143 |
std::string model_type_m; |
|
| 144 |
/** |
|
| 145 |
* @brief Unique identifier for the fishery model. |
|
| 146 |
* |
|
| 147 |
*/ |
|
| 148 |
std::set<uint32_t> population_ids; |
|
| 149 |
/** |
|
| 150 |
* @brief A vector of populations in the fishery model. |
|
| 151 |
* |
|
| 152 |
*/ |
|
| 153 |
std::vector<std::shared_ptr<fims_popdy::Population<Type>>> populations; |
|
| 154 |
/** |
|
| 155 |
* @brief A map of fleets in the fishery model, indexed by fleet id. |
|
| 156 |
* Unique instances to eliminate duplicate initialization. |
|
| 157 |
* |
|
| 158 |
*/ |
|
| 159 |
std::map<uint32_t, std::shared_ptr<fims_popdy::Fleet<Type>>> fleets; |
|
| 160 |
/** |
|
| 161 |
* @brief Fleet-based iterator. |
|
| 162 |
* |
|
| 163 |
*/ |
|
| 164 |
typedef typename std::map<uint32_t, |
|
| 165 |
std::shared_ptr<fims_popdy::Fleet<Type>>>::iterator |
|
| 166 |
fleet_iterator; |
|
| 167 | ||
| 168 |
/** |
|
| 169 |
* @brief Type definitions for derived quantities and dimension information |
|
| 170 |
* maps. |
|
| 171 |
*/ |
|
| 172 |
typedef typename std::map<uint32_t, std::map<std::string, fims::Vector<Type>>> |
|
| 173 |
DerivedQuantitiesMap; |
|
| 174 | ||
| 175 |
/** |
|
| 176 |
* @brief Iterator for the derived quantities map. |
|
| 177 |
*/ |
|
| 178 |
typedef typename DerivedQuantitiesMap::iterator DerivedQuantitiesMapIterator; |
|
| 179 | ||
| 180 |
/** |
|
| 181 |
* @brief Shared pointer for the fleet derived quantities map. |
|
| 182 |
*/ |
|
| 183 |
std::shared_ptr<DerivedQuantitiesMap> fleet_derived_quantities; |
|
| 184 | ||
| 185 |
/** |
|
| 186 |
* @brief Shared pointer for the population derived quantities map. |
|
| 187 |
*/ |
|
| 188 |
std::shared_ptr<DerivedQuantitiesMap> population_derived_quantities; |
|
| 189 | ||
| 190 |
/** |
|
| 191 |
* @brief Type definitions for dimension information maps. |
|
| 192 |
*/ |
|
| 193 |
typedef typename std::map<uint32_t, std::map<std::string, DimensionInfo>> |
|
| 194 |
DimensionInfoMap; |
|
| 195 | ||
| 196 |
/** |
|
| 197 |
* @brief Shared pointer for the fleet dimension information map. |
|
| 198 |
*/ |
|
| 199 |
std::shared_ptr<DimensionInfoMap> fleet_dimension_info; |
|
| 200 | ||
| 201 |
/** |
|
| 202 |
* @brief Shared pointer for the population dimension information map. |
|
| 203 |
*/ |
|
| 204 |
std::shared_ptr<DimensionInfoMap> population_dimension_info; |
|
| 205 | ||
| 206 |
/** |
|
| 207 |
* @brief Type definition for the uncertainty report information map. |
|
| 208 |
*/ |
|
| 209 |
typedef |
|
| 210 |
typename std::map<uint32_t, std::map<std::string, UncertaintyReportInfo>> |
|
| 211 |
UncertaintyReportInfoMap; |
|
| 212 | ||
| 213 |
/** |
|
| 214 |
* @brief Shared pointer for the uncertainty report information map. |
|
| 215 |
*/ |
|
| 216 |
std::shared_ptr<UncertaintyReportInfoMap> fleet_uncertainty_report_info; |
|
| 217 | ||
| 218 |
/** |
|
| 219 |
* @brief Shared pointer for the population uncertainty report information |
|
| 220 |
* map. |
|
| 221 |
*/ |
|
| 222 |
std::shared_ptr<UncertaintyReportInfoMap> population_uncertainty_report_info; |
|
| 223 | ||
| 224 |
#ifdef TMB_MODEL |
|
| 225 |
::objective_function<Type> *of; |
|
| 226 |
#endif |
|
| 227 |
/** |
|
| 228 |
* @brief Construct a new Fishery Model Base object. |
|
| 229 |
* |
|
| 230 |
*/ |
|
| 231 | 72x |
FisheryModelBase() : id(FisheryModelBase::id_g++) {
|
| 232 | 72x |
fleet_derived_quantities = std::make_shared<DerivedQuantitiesMap>(); |
| 233 | 72x |
population_derived_quantities = std::make_shared<DerivedQuantitiesMap>(); |
| 234 | 72x |
fleet_dimension_info = std::make_shared<DimensionInfoMap>(); |
| 235 | 72x |
population_dimension_info = std::make_shared<DimensionInfoMap>(); |
| 236 |
} |
|
| 237 | ||
| 238 |
/** |
|
| 239 |
* @brief Construct a new Fishery Model Base object. |
|
| 240 |
* |
|
| 241 |
* @param other |
|
| 242 |
*/ |
|
| 243 |
FisheryModelBase(const FisheryModelBase &other) |
|
| 244 |
: id(other.id), |
|
| 245 |
population_ids(other.population_ids), |
|
| 246 |
populations(other.populations), |
|
| 247 |
fleet_derived_quantities(other.fleet_derived_quantities), |
|
| 248 |
population_derived_quantities(other.population_derived_quantities), |
|
| 249 |
fleet_dimension_info(other.fleet_dimension_info), |
|
| 250 |
population_dimension_info(other.population_dimension_info) {}
|
|
| 251 | ||
| 252 |
/** |
|
| 253 |
* @brief Destroy the Fishery Model Base object. |
|
| 254 |
* |
|
| 255 |
*/ |
|
| 256 | 36x |
virtual ~FisheryModelBase() {}
|
| 257 | ||
| 258 |
/** |
|
| 259 |
* @brief Get the fleet dimension information. |
|
| 260 |
* |
|
| 261 |
* @return std::map<uint32_t, std::map<std::string, DimensionInfo>> |
|
| 262 |
*/ |
|
| 263 |
std::map<uint32_t, std::map<std::string, DimensionInfo>> & |
|
| 264 |
GetFleetDimensionInfo() {
|
|
| 265 |
return *fleet_dimension_info; |
|
| 266 |
} |
|
| 267 | ||
| 268 |
/** |
|
| 269 |
* @brief Get the population dimension information. |
|
| 270 |
* |
|
| 271 |
* @return std::map<uint32_t, std::map<std::string, DimensionInfo>> |
|
| 272 |
*/ |
|
| 273 |
std::map<uint32_t, std::map<std::string, DimensionInfo>> & |
|
| 274 |
GetPopulationDimensionInfo() {
|
|
| 275 |
return *population_dimension_info; |
|
| 276 |
} |
|
| 277 | ||
| 278 |
/** |
|
| 279 |
* @brief Get the fleet derived quantities. |
|
| 280 |
* |
|
| 281 |
* @return DerivedQuantitiesMap |
|
| 282 |
*/ |
|
| 283 |
DerivedQuantitiesMap &GetFleetDerivedQuantities() {
|
|
| 284 |
return *fleet_derived_quantities; |
|
| 285 |
} |
|
| 286 | ||
| 287 |
/** |
|
| 288 |
* @brief Get the population derived quantities. |
|
| 289 |
* |
|
| 290 |
* @return DerivedQuantitiesMap |
|
| 291 |
*/ |
|
| 292 |
DerivedQuantitiesMap &GetPopulationDerivedQuantities() {
|
|
| 293 |
return *population_derived_quantities; |
|
| 294 |
} |
|
| 295 | ||
| 296 |
/** |
|
| 297 |
* @brief Get the fleet derived quantities for a specified fleet. |
|
| 298 |
* |
|
| 299 |
* @param fleet_id The ID of the fleet. |
|
| 300 |
* @return std::map<std::string, fims::Vector<Type>>& |
|
| 301 |
*/ |
|
| 302 | 2470524x |
std::map<std::string, fims::Vector<Type>> &GetFleetDerivedQuantities( |
| 303 |
uint32_t fleet_id) {
|
|
| 304 | 2470524x |
if (!fleet_derived_quantities) {
|
| 305 | ! |
throw std::runtime_error( |
| 306 |
"GetFleetDerivedQuantities: fleet_derived_quantities is null"); |
|
| 307 |
} |
|
| 308 | 2470524x |
auto &outer = *fleet_derived_quantities; |
| 309 | 2470524x |
auto it = outer.find(fleet_id); |
| 310 | 2470524x |
if (it == outer.end()) {
|
| 311 | ! |
std::stringstream ss; |
| 312 | ||
| 313 | ! |
ss << "GetFleetDerivedQuantities: fleet_id " << fleet_id |
| 314 | ! |
<< " not found in fleet_derived_quantities"; |
| 315 | ! |
throw std::out_of_range(ss.str()); |
| 316 |
} |
|
| 317 | 4941048x |
return it->second; |
| 318 |
} |
|
| 319 | ||
| 320 |
/** |
|
| 321 |
* @brief Initialize the derived quantities map for a fleet. |
|
| 322 |
* |
|
| 323 |
* @details Ensures the derived quantities map for the specified fleet |
|
| 324 |
* exists. If not, creates an empty map for the fleet ID. |
|
| 325 |
* |
|
| 326 |
* @param fleet_id The ID of the fleet to initialize. |
|
| 327 |
*/ |
|
| 328 | 144x |
void InitializeFleetDerivedQuantities(uint32_t fleet_id) {
|
| 329 |
// Ensure the shared_ptr exists |
|
| 330 | 144x |
if (!fleet_derived_quantities) {
|
| 331 | ! |
fleet_derived_quantities = std::make_shared< |
| 332 |
std::map<uint32_t, std::map<std::string, fims::Vector<Type>>>>(); |
|
| 333 |
} |
|
| 334 | ||
| 335 | 144x |
auto &outer = *fleet_derived_quantities; |
| 336 | ||
| 337 |
// Insert only if not already present |
|
| 338 | 144x |
if (outer.find(fleet_id) == outer.end()) {
|
| 339 | 144x |
outer.emplace(fleet_id, std::map<std::string, fims::Vector<Type>>{});
|
| 340 |
} |
|
| 341 |
} |
|
| 342 | ||
| 343 |
/** |
|
| 344 |
* @brief Initialize the derived quantities map for a population. |
|
| 345 |
* |
|
| 346 |
* @details Ensures the derived quantities map for the specified |
|
| 347 |
* population exists. If not, creates an empty map for the population ID. |
|
| 348 |
* |
|
| 349 |
* @param population_id The ID of the population to initialize. |
|
| 350 |
*/ |
|
| 351 | 72x |
void InitializePopulationDerivedQuantities(uint32_t population_id) {
|
| 352 |
// Ensure the shared_ptr exists |
|
| 353 | 72x |
if (!population_derived_quantities) {
|
| 354 | ! |
population_derived_quantities = std::make_shared< |
| 355 |
std::map<uint32_t, std::map<std::string, fims::Vector<Type>>>>(); |
|
| 356 |
} |
|
| 357 | ||
| 358 | 72x |
auto &outer = *population_derived_quantities; |
| 359 | ||
| 360 |
// Insert only if not already present |
|
| 361 | 72x |
if (outer.find(population_id) == outer.end()) {
|
| 362 | 72x |
outer.emplace(population_id, std::map<std::string, fims::Vector<Type>>{});
|
| 363 |
} |
|
| 364 |
} |
|
| 365 | ||
| 366 |
/** |
|
| 367 |
* @brief Get the population derived quantities for a specified population. |
|
| 368 |
* |
|
| 369 |
* @param population_id The ID of the population. |
|
| 370 |
* @return std::map<std::string, fims::Vector<Type>>& |
|
| 371 |
*/ |
|
| 372 | 2306862x |
std::map<std::string, fims::Vector<Type>> &GetPopulationDerivedQuantities( |
| 373 |
uint32_t population_id) {
|
|
| 374 | 2306862x |
if (!population_derived_quantities) {
|
| 375 | ! |
throw std::runtime_error( |
| 376 |
"GetPopulationDerivedQuantities: population_derived_quantities is " |
|
| 377 |
"null"); |
|
| 378 |
} |
|
| 379 | 2306862x |
auto &outer = *population_derived_quantities; |
| 380 | 2306862x |
auto it = outer.find(population_id); |
| 381 | 2306862x |
if (it == outer.end()) {
|
| 382 | ! |
std::ostringstream ss; |
| 383 | ! |
ss << "GetPopulationDerivedQuantities: population_id " << population_id |
| 384 | ! |
<< " not found in population_derived_quantities"; |
| 385 | ! |
throw std::out_of_range(ss.str()); |
| 386 |
} |
|
| 387 | 4613724x |
return it->second; |
| 388 |
} |
|
| 389 | ||
| 390 |
/** |
|
| 391 |
* @brief Get the fleet dimension information for a specified fleet. |
|
| 392 |
* |
|
| 393 |
* @param fleet_id The ID of the fleet. |
|
| 394 |
* @return std::map<std::string, DimensionInfo> |
|
| 395 |
*/ |
|
| 396 | 196x |
std::map<std::string, DimensionInfo> &GetFleetDimensionInfo( |
| 397 |
uint32_t fleet_id) {
|
|
| 398 | 196x |
return (*fleet_dimension_info)[fleet_id]; |
| 399 |
} |
|
| 400 | ||
| 401 |
/** |
|
| 402 |
* @brief Get the population dimension information for a specified population. |
|
| 403 |
* |
|
| 404 |
* @param population_id The ID of the population. |
|
| 405 |
* @return std::map<std::string, DimensionInfo> |
|
| 406 |
*/ |
|
| 407 | 98x |
std::map<std::string, DimensionInfo> &GetPopulationDimensionInfo( |
| 408 |
uint32_t population_id) {
|
|
| 409 | 98x |
return (*population_dimension_info)[population_id]; |
| 410 |
} |
|
| 411 | ||
| 412 |
/** |
|
| 413 |
* @brief Get the fleet uncertainty report information. |
|
| 414 |
*/ |
|
| 415 |
UncertaintyReportInfoMap &GetFleetUncertaintyReportInfo() {
|
|
| 416 |
return *fleet_uncertainty_report_info; |
|
| 417 |
} |
|
| 418 | ||
| 419 |
/** |
|
| 420 |
* @brief Get the population uncertainty report information. |
|
| 421 |
*/ |
|
| 422 |
UncertaintyReportInfoMap &GetPopulationUncertaintyReportInfo() {
|
|
| 423 |
return *population_uncertainty_report_info; |
|
| 424 |
} |
|
| 425 | ||
| 426 |
/** |
|
| 427 |
* @brief Get the fleet uncertainty report information for a specified fleet. |
|
| 428 |
* |
|
| 429 |
* @param fleet_id The ID of the fleet. |
|
| 430 |
* @return std::map<std::string, UncertaintyReportInfo>& |
|
| 431 |
*/ |
|
| 432 |
std::map<std::string, UncertaintyReportInfo> &GetFleetUncertaintyReportInfo( |
|
| 433 |
uint32_t fleet_id) {
|
|
| 434 |
return (*fleet_uncertainty_report_info)[fleet_id]; |
|
| 435 |
} |
|
| 436 | ||
| 437 |
/** |
|
| 438 |
* @brief Get the population uncertainty report information for a specified |
|
| 439 |
* population. |
|
| 440 |
* |
|
| 441 |
* @param population_id The ID of the population. |
|
| 442 |
* @return std::map<std::string, UncertaintyReportInfo>& |
|
| 443 |
*/ |
|
| 444 |
std::map<std::string, UncertaintyReportInfo> & |
|
| 445 |
GetPopulationUncertaintyReportInfo(uint32_t population_id) {
|
|
| 446 |
return (*population_uncertainty_report_info)[population_id]; |
|
| 447 |
} |
|
| 448 | ||
| 449 |
/** |
|
| 450 |
* @brief Initialize a model. |
|
| 451 |
* |
|
| 452 |
*/ |
|
| 453 | ! |
virtual void Initialize() {}
|
| 454 | ||
| 455 |
/** |
|
| 456 |
* @brief Prepare the model. |
|
| 457 |
* |
|
| 458 |
*/ |
|
| 459 | ! |
virtual void Prepare() {}
|
| 460 | ||
| 461 |
/** |
|
| 462 |
* @brief Reset a vector from start to end with a value. |
|
| 463 |
* |
|
| 464 |
* @param v A vector to reset. |
|
| 465 |
* @param value The value you want to use for all elements in the |
|
| 466 |
* vector. The default is 0.0. |
|
| 467 |
*/ |
|
| 468 | 58140x |
virtual void ResetVector(fims::Vector<Type> &v, Type value = 0.0) {
|
| 469 | 58140x |
std::fill(v.begin(), v.end(), value); |
| 470 |
} |
|
| 471 | ||
| 472 |
/** |
|
| 473 |
* @brief Evaluate the model. |
|
| 474 |
* |
|
| 475 |
*/ |
|
| 476 | ! |
virtual void Evaluate() {}
|
| 477 | ||
| 478 |
/** |
|
| 479 |
* @brief Report the model results via TMB. |
|
| 480 |
* |
|
| 481 |
*/ |
|
| 482 | ! |
virtual void Report() {}
|
| 483 | ||
| 484 |
/** |
|
| 485 |
* @brief Get the Id object. |
|
| 486 |
* |
|
| 487 |
* @return uint32_t |
|
| 488 |
*/ |
|
| 489 | 72x |
uint32_t GetId() { return this->id; }
|
| 490 |
}; |
|
| 491 | ||
| 492 |
template <typename Type> |
|
| 493 |
uint32_t FisheryModelBase<Type>::id_g = 0; |
|
| 494 | ||
| 495 |
} // namespace fims_popdy |
|
| 496 |
#endif |
| 1 |
/** |
|
| 2 |
* @file fleet.hpp |
|
| 3 |
* @brief Declare the fleet functor class which is the base class for all fleet |
|
| 4 |
* functors. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_POPULATION_DYNAMICS_FLEET_HPP |
|
| 10 |
#define FIMS_POPULATION_DYNAMICS_FLEET_HPP |
|
| 11 | ||
| 12 |
#include "../../common/data_object.hpp" |
|
| 13 |
#include "../../common/fims_vector.hpp" |
|
| 14 |
#include "../../common/model_object.hpp" |
|
| 15 |
#include "../../distributions/distributions.hpp" |
|
| 16 |
#include "../selectivity/selectivity.hpp" |
|
| 17 | ||
| 18 |
namespace fims_popdy {
|
|
| 19 | ||
| 20 |
/** @brief Base class for all fleets. |
|
| 21 |
* |
|
| 22 |
* @tparam Type The type of the fleet object. |
|
| 23 |
*/ |
|
| 24 |
template <class Type> |
|
| 25 |
struct Fleet : public fims_model_object::FIMSObject<Type> {
|
|
| 26 |
static uint32_t id_g; /*!< reference id for fleet object*/ |
|
| 27 |
size_t n_years; /*!< the number of years in the model*/ |
|
| 28 |
size_t n_ages; /*!< the number of ages in the model*/ |
|
| 29 |
size_t n_lengths; /*!< the number of lengths in the model*/ |
|
| 30 | ||
| 31 |
// selectivity |
|
| 32 |
int fleet_selectivity_id_m = -999; /*!< id of selectivity component*/ |
|
| 33 |
std::shared_ptr<SelectivityBase<Type>> |
|
| 34 |
selectivity; /*!< selectivity component*/ |
|
| 35 | ||
| 36 |
// landings data |
|
| 37 |
int fleet_observed_landings_data_id_m = -999; /*!< id of landings data */ |
|
| 38 |
std::shared_ptr<fims_data_object::DataObject<Type>> |
|
| 39 |
observed_landings_data; /*!< observed landings data*/ |
|
| 40 | ||
| 41 |
std::string observed_landings_units; /*!< is this fleet landings in weight*/ |
|
| 42 | ||
| 43 |
// index data |
|
| 44 |
int fleet_observed_index_data_id_m = -999; /*!< id of index data */ |
|
| 45 |
std::shared_ptr<fims_data_object::DataObject<Type>> |
|
| 46 |
observed_index_data; /*!< observed index data*/ |
|
| 47 | ||
| 48 |
std::string observed_index_units; /*!< is this fleet index in weight*/ |
|
| 49 | ||
| 50 |
// age comp data |
|
| 51 |
int fleet_observed_agecomp_data_id_m = -999; /*!< id of age comp data */ |
|
| 52 |
std::shared_ptr<fims_data_object::DataObject<Type>> |
|
| 53 |
observed_agecomp_data; /*!< observed agecomp data*/ |
|
| 54 | ||
| 55 |
// length comp data |
|
| 56 |
int fleet_observed_lengthcomp_data_id_m = -999; /*!< id of length comp data */ |
|
| 57 |
std::shared_ptr<fims_data_object::DataObject<Type>> |
|
| 58 |
observed_lengthcomp_data; /*!< observed lengthcomp data*/ |
|
| 59 | ||
| 60 |
// Mortality and catchability |
|
| 61 |
fims::Vector<Type> |
|
| 62 |
log_Fmort; /*!< estimated parameter: log Fishing mortality*/ |
|
| 63 |
fims::Vector<Type> |
|
| 64 |
log_q; /*!< estimated parameter: catchability of the fleet */ |
|
| 65 | ||
| 66 |
fims::Vector<Type> Fmort; /*!< transformed parameter: Fishing mortality*/ |
|
| 67 |
fims::Vector<Type> |
|
| 68 |
q; /*!< transformed parameter: the catchability of the fleet */ |
|
| 69 | ||
| 70 |
fims::Vector<Type> age_to_length_conversion; /*!<derived quantity age to |
|
| 71 |
length conversion matrix*/ |
|
| 72 | ||
| 73 |
/** |
|
| 74 |
* @brief Constructor. |
|
| 75 |
*/ |
|
| 76 | 152x |
Fleet() { this->id = Fleet::id_g++; }
|
| 77 | ||
| 78 |
/** |
|
| 79 |
* @brief Destructor. |
|
| 80 |
*/ |
|
| 81 | 76x |
virtual ~Fleet() {}
|
| 82 | ||
| 83 |
/** |
|
| 84 |
* @brief Prepare to run the fleet module. Called at each model |
|
| 85 |
* iteration, and used to exponentiate the natural log of q and Fmort |
|
| 86 |
* parameters prior to evaluation. |
|
| 87 |
* |
|
| 88 |
*/ |
|
| 89 |
void Prepare() {
|
|
| 90 |
// for(size_t fleet_ = 0; fleet_ <= this->n_fleets; fleet_++) {
|
|
| 91 |
// this -> Fmort[fleet_] = fims_math::exp(this -> log_Fmort[fleet_]); |
|
| 92 | ||
| 93 |
for (size_t i = 0; i < this->log_q.size(); i++) {
|
|
| 94 |
this->q[i] = fims_math::exp(this->log_q[i]); |
|
| 95 |
} |
|
| 96 | ||
| 97 |
for (size_t year = 0; year < this->n_years; year++) {
|
|
| 98 |
this->Fmort[year] = fims_math::exp(this->log_Fmort[year]); |
|
| 99 |
} |
|
| 100 |
} |
|
| 101 | ||
| 102 |
/** |
|
| 103 |
* Create a map of report vectors for the object. |
|
| 104 |
*/ |
|
| 105 | 1088x |
virtual void create_report_vectors( |
| 106 |
std::map<std::string, fims::Vector<fims::Vector<Type>>>& report_vectors) {
|
|
| 107 | 2176x |
report_vectors["log_Fmort"].emplace_back(this->log_Fmort.to_tmb()); |
| 108 | 2176x |
report_vectors["log_q"].emplace_back(this->log_q.to_tmb()); |
| 109 | 1088x |
report_vectors["age_to_length_conversion"].emplace_back( |
| 110 |
this->age_to_length_conversion.to_tmb()); |
|
| 111 |
} |
|
| 112 | ||
| 113 |
/** |
|
| 114 |
* Get the report vector count object. |
|
| 115 |
*/ |
|
| 116 | ! |
virtual void get_report_vector_count( |
| 117 |
std::map<std::string, size_t>& report_vector_count) {
|
|
| 118 | ! |
report_vector_count["log_Fmort"] += 1; |
| 119 | ! |
report_vector_count["log_q"] += 1; |
| 120 |
} |
|
| 121 |
}; |
|
| 122 | ||
| 123 |
// default id of the singleton fleet class |
|
| 124 |
template <class Type> |
|
| 125 |
uint32_t Fleet<Type>::id_g = 0; |
|
| 126 | ||
| 127 |
} // end namespace fims_popdy |
|
| 128 | ||
| 129 |
#endif /* FIMS_POPULATION_DYNAMICS_FLEET_HPP */ |
| 1 |
/** |
|
| 2 |
* @file ewaa.hpp |
|
| 3 |
* @brief Defines the EWAAGrowth class, which inherits from the GrowthBase |
|
| 4 |
* class. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef POPULATION_DYNAMICS_GROWTH_EWAA_HPP |
|
| 10 |
#define POPULATION_DYNAMICS_GROWTH_EWAA_HPP |
|
| 11 | ||
| 12 |
// #include "../../../interface/interface.hpp" |
|
| 13 |
#include <map> |
|
| 14 | ||
| 15 |
#include "growth_base.hpp" |
|
| 16 | ||
| 17 |
namespace fims_popdy {
|
|
| 18 | ||
| 19 |
/** |
|
| 20 |
* @brief EWAAGrowth class that returns the EWAA function value. |
|
| 21 |
*/ |
|
| 22 |
template <typename Type> |
|
| 23 |
struct EWAAGrowth : public GrowthBase<Type> {
|
|
| 24 |
// add submodule class members here |
|
| 25 |
// these include parameters of the submodule |
|
| 26 |
// a map looks up values based on a reference key |
|
| 27 |
// in this case, our key is age (first double), and |
|
| 28 |
// the value is the weight at that age (second double) |
|
| 29 |
std::map<double, double> ewaa; /**<map of doubles for EWAA values by age, |
|
| 30 |
where age starts at zero > */ |
|
| 31 |
typedef typename std::map<double, double>::iterator |
|
| 32 |
weight_iterator; /**< Iterator for ewaa map object > */ |
|
| 33 | ||
| 34 | 82x |
EWAAGrowth() : GrowthBase<Type>() {}
|
| 35 | ||
| 36 | 41x |
virtual ~EWAAGrowth() {}
|
| 37 | ||
| 38 |
/** |
|
| 39 |
* @brief Returns the weight at age a (in kg) from the input vector. |
|
| 40 |
* |
|
| 41 |
* @param a age of the fish, the age vector must start at zero |
|
| 42 |
*/ |
|
| 43 | 1874162x |
virtual const Type evaluate(const double& a) {
|
| 44 | 1874162x |
weight_iterator it = this->ewaa.find(a); |
| 45 | 1874162x |
if (it == this->ewaa.end()) {
|
| 46 | ! |
return 0.0; |
| 47 |
} |
|
| 48 | 1874162x |
Type ret = (*it).second; // itewaa[a]; |
| 49 | 1874162x |
return ret; |
| 50 |
} |
|
| 51 | ||
| 52 |
/** |
|
| 53 |
* @brief Create a map of report vectors for the growth object. |
|
| 54 |
*/ |
|
| 55 | 544x |
virtual void create_report_vectors( |
| 56 |
std::map<std::string, fims::Vector<fims::Vector<Type>>>& report_vectors) {
|
|
| 57 |
// fims::Vector<Type> ewaa_vector; |
|
| 58 |
// for (auto const& pair : ewaa) {
|
|
| 59 |
// ewaa_vector.push_back(pair.second); |
|
| 60 |
// } |
|
| 61 |
// report_vectors["ewaa"] = ewaa_vector; |
|
| 62 |
} |
|
| 63 |
}; |
|
| 64 |
} // namespace fims_popdy |
|
| 65 |
#endif /* POPULATION_DYNAMICS_GROWTH_EWAA_HPP */ |
| 1 |
/** |
|
| 2 |
* @file growth_base.hpp |
|
| 3 |
* @brief Declares the GrowthBase class which is the base class for all growth |
|
| 4 |
* functors. |
|
| 5 |
* @details Defines guards for growth module outline to define the |
|
| 6 |
* module_name_base hpp file if not already defined. |
|
| 7 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 8 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 9 |
* folder for reuse information. |
|
| 10 |
*/ |
|
| 11 |
#ifndef POPULATION_DYNAMICS_GROWTH_BASE_HPP |
|
| 12 |
#define POPULATION_DYNAMICS_GROWTH_BASE_HPP |
|
| 13 | ||
| 14 |
#include "../../../common/model_object.hpp" |
|
| 15 | ||
| 16 |
namespace fims_popdy {
|
|
| 17 | ||
| 18 |
/** |
|
| 19 |
* @brief Base class for all growth functors. |
|
| 20 |
* |
|
| 21 |
* @tparam Type The type of the growth functor. |
|
| 22 |
*/ |
|
| 23 |
template <typename Type> |
|
| 24 |
struct GrowthBase : public fims_model_object::FIMSObject<Type> {
|
|
| 25 |
// id_g is the ID of the instance of the growthBase class. |
|
| 26 |
// this is like a memory tracker. |
|
| 27 |
// Assigning each one its own ID is a way to keep track of |
|
| 28 |
// all the instances of the growthBase class. |
|
| 29 |
static uint32_t id_g; /**< reference id for growth object*/ |
|
| 30 | ||
| 31 |
/** |
|
| 32 |
* @brief Constructor. |
|
| 33 |
*/ |
|
| 34 | 82x |
GrowthBase() { this->id = GrowthBase::id_g++; }
|
| 35 | ||
| 36 | 41x |
virtual ~GrowthBase() {}
|
| 37 | ||
| 38 |
/** |
|
| 39 |
* @brief Calculates the growth at the independent variable value. |
|
| 40 |
* @param a The age at which to return weight of the fish (in kg). |
|
| 41 |
*/ |
|
| 42 |
virtual const Type evaluate(const double& a) = 0; |
|
| 43 |
}; |
|
| 44 | ||
| 45 |
template <typename Type> |
|
| 46 |
uint32_t GrowthBase<Type>::id_g = 0; |
|
| 47 | ||
| 48 |
} // namespace fims_popdy |
|
| 49 | ||
| 50 |
#endif /* POPULATION_DYNAMICS_GROWTH_BASE_HPP */ |
| 1 |
/** |
|
| 2 |
* @file logistic.hpp |
|
| 3 |
* @brief Defines the LogisticMaturity class, which inherits from the |
|
| 4 |
* MaturityBase class. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
* |
|
| 9 |
*/ |
|
| 10 |
#ifndef POPULATION_DYNAMICS_MATURITY_LOGISTIC_HPP |
|
| 11 |
#define POPULATION_DYNAMICS_MATURITY_LOGISTIC_HPP |
|
| 12 | ||
| 13 |
#include "../../../common/fims_math.hpp" |
|
| 14 |
#include "../../../common/fims_vector.hpp" |
|
| 15 |
#include "maturity_base.hpp" |
|
| 16 | ||
| 17 |
namespace fims_popdy {
|
|
| 18 | ||
| 19 |
/** |
|
| 20 |
* @brief LogisticMaturity class that returns the logistic function value |
|
| 21 |
* from fims_math. |
|
| 22 |
*/ |
|
| 23 |
template <typename Type> |
|
| 24 |
struct LogisticMaturity : public MaturityBase<Type> {
|
|
| 25 |
fims::Vector<Type> |
|
| 26 |
inflection_point; /**< 50 percent quantile of the value of the quantity of |
|
| 27 |
interest (x); e.g. age at which 50 percent of the fish are mature */ |
|
| 28 |
fims::Vector<Type> slope; /**<scalar multiplier of difference between quantity |
|
| 29 |
of interest value (x) and inflection_point */ |
|
| 30 | ||
| 31 | 78x |
LogisticMaturity() : MaturityBase<Type>() {}
|
| 32 | ||
| 33 |
/** |
|
| 34 |
* @brief Method of the logistic maturity class that implements the |
|
| 35 |
* logistic function from FIMS math. |
|
| 36 |
* |
|
| 37 |
* \f[ \frac{1.0}{ 1.0 + exp(-1.0 * slope (x - inflection_point))} \f]
|
|
| 38 |
* |
|
| 39 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 40 |
* size at maturity). |
|
| 41 |
*/ |
|
| 42 | ||
| 43 | 212042x |
virtual const Type evaluate(const Type& x) {
|
| 44 | 212042x |
return fims_math::logistic<Type>(inflection_point[0], slope[0], x); |
| 45 |
} |
|
| 46 | ||
| 47 |
/** |
|
| 48 |
* @brief Method of the logistic maturity class that implements the |
|
| 49 |
* logistic function from FIMS math. |
|
| 50 |
* |
|
| 51 |
* \f[ \frac{1.0}{ 1.0 + exp(-1.0 * slope_t (x - {inflection\_point}_t))} \f]
|
|
| 52 |
* |
|
| 53 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 54 |
* size in selectivity). |
|
| 55 |
* @param pos Position index, e.g., which year. |
|
| 56 |
*/ |
|
| 57 | ! |
virtual const Type evaluate(const Type& x, size_t pos) {
|
| 58 | ! |
return fims_math::logistic<Type>(inflection_point.get_force_scalar(pos), |
| 59 | ! |
slope.get_force_scalar(pos), x); |
| 60 |
} |
|
| 61 | ||
| 62 |
/** |
|
| 63 |
* @brief Create a map of report vectors for the maturity object. |
|
| 64 |
*/ |
|
| 65 | 544x |
virtual void create_report_vectors( |
| 66 |
std::map<std::string, fims::Vector<fims::Vector<Type>>>& report_vectors) {
|
|
| 67 | 1088x |
report_vectors["inflection_point"].emplace_back(inflection_point); |
| 68 | 544x |
report_vectors["slope"].emplace_back(slope); |
| 69 |
} |
|
| 70 | ! |
virtual void get_report_vector_count( |
| 71 |
std::map<std::string, size_t>& report_vector_count) {
|
|
| 72 | ! |
report_vector_count["inflection_point"] += 1; |
| 73 | ! |
report_vector_count["slope"] += 1; |
| 74 |
} |
|
| 75 |
}; |
|
| 76 | ||
| 77 |
} // namespace fims_popdy |
|
| 78 | ||
| 79 |
#endif /* POPULATION_DYNAMICS_MATURITY_LOGISTIC_HPP */ |
| 1 |
/** |
|
| 2 |
* @file maturity_base.hpp |
|
| 3 |
* @brief Declares the MaturityBase class which is the base class for all |
|
| 4 |
* maturity functors. |
|
| 5 |
* @details Defines guards for maturity module outline to define the maturity |
|
| 6 |
* hpp file if not already defined. |
|
| 7 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 8 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 9 |
* folder for reuse information. |
|
| 10 |
*/ |
|
| 11 |
#ifndef POPULATION_DYNAMICS_MATURITY_BASE_HPP |
|
| 12 |
#define POPULATION_DYNAMICS_MATURITY_BASE_HPP |
|
| 13 | ||
| 14 |
#include "../../../common/model_object.hpp" |
|
| 15 | ||
| 16 |
namespace fims_popdy {
|
|
| 17 | ||
| 18 |
/** @brief Base class for all maturity functors. |
|
| 19 |
* |
|
| 20 |
* @tparam Type The type of the maturity functor. |
|
| 21 |
*/ |
|
| 22 | ||
| 23 |
template <typename Type> |
|
| 24 |
struct MaturityBase : public fims_model_object::FIMSObject<Type> {
|
|
| 25 |
// id_g is the ID of the instance of the MaturityBase class. |
|
| 26 |
// this is like a memory tracker. |
|
| 27 |
// Assigning each one its own ID is a way to keep track of |
|
| 28 |
// all the instances of the MaturityBase class. |
|
| 29 |
static uint32_t id_g; /**< The ID of the instance of the MaturityBase class */ |
|
| 30 | ||
| 31 |
/** @brief Constructor. |
|
| 32 |
*/ |
|
| 33 | 78x |
MaturityBase() {
|
| 34 |
// increment id of the singleton maturity class |
|
| 35 | 78x |
this->id = MaturityBase::id_g++; |
| 36 |
} |
|
| 37 | ||
| 38 |
/** |
|
| 39 |
* @brief Calculates the maturity. |
|
| 40 |
* @param x The independent variable in the maturity function (e.g., logistic |
|
| 41 |
* maturity at age or size). |
|
| 42 |
*/ |
|
| 43 |
virtual const Type evaluate(const Type& x) = 0; |
|
| 44 |
/** |
|
| 45 |
* @brief Calculates the selectivity. |
|
| 46 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 47 |
* size in selectivity). |
|
| 48 |
* @param pos Position index, e.g., which year. |
|
| 49 |
*/ |
|
| 50 |
virtual const Type evaluate(const Type& x, size_t pos) = 0; |
|
| 51 |
}; |
|
| 52 | ||
| 53 |
// default id of the singleton maturity class |
|
| 54 |
template <typename Type> |
|
| 55 |
uint32_t MaturityBase<Type>::id_g = 0; |
|
| 56 | ||
| 57 |
} // namespace fims_popdy |
|
| 58 | ||
| 59 |
#endif /* POPULATION_DYNAMICS_MATURITY_BASE_HPP */ |
| 1 |
/** |
|
| 2 |
* @file population.hpp |
|
| 3 |
* @brief Defines the Population class and its fields and methods. |
|
| 4 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 5 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 6 |
* folder for reuse information. |
|
| 7 |
*/ |
|
| 8 |
#ifndef FIMS_POPULATION_DYNAMICS_POPULATION_HPP |
|
| 9 |
#define FIMS_POPULATION_DYNAMICS_POPULATION_HPP |
|
| 10 | ||
| 11 |
#include "../../common/model_object.hpp" |
|
| 12 |
#include "../fleet/fleet.hpp" |
|
| 13 |
#include "../growth/growth.hpp" |
|
| 14 |
#include "../recruitment/recruitment.hpp" |
|
| 15 |
#include "../../interface/interface.hpp" |
|
| 16 |
#include "../maturity/maturity.hpp" |
|
| 17 | ||
| 18 |
namespace fims_popdy {
|
|
| 19 | ||
| 20 |
/** |
|
| 21 |
* @brief Population class. Contains subpopulations |
|
| 22 |
* that are divided into generic partitions (e.g., sex, area). |
|
| 23 |
*/ |
|
| 24 |
template <typename Type> |
|
| 25 |
struct Population : public fims_model_object::FIMSObject<Type> {
|
|
| 26 |
static uint32_t id_g; /*!< reference id for population object*/ |
|
| 27 |
size_t n_years; /*!< total number of years in the fishery*/ |
|
| 28 |
size_t n_ages; /*!< total number of ages in the population*/ |
|
| 29 |
size_t n_fleets; /*!< total number of fleets in the fishery*/ |
|
| 30 | ||
| 31 |
// parameters are estimated; after initialize in create_model, push_back to |
|
| 32 |
// parameter list - in information.hpp (same for initial F in fleet) |
|
| 33 |
fims::Vector<Type> |
|
| 34 |
log_init_naa; /*!< estimated parameter: natural log of numbers at age*/ |
|
| 35 |
fims::Vector<Type> |
|
| 36 |
log_M; /*!< estimated parameter: natural log of Natural Mortality*/ |
|
| 37 |
fims::Vector<Type> proportion_female = fims::Vector<Type>( |
|
| 38 | 19x |
1, static_cast<Type>(0.5)); /*!< proportion female by age */ |
| 39 | ||
| 40 |
// Transformed values |
|
| 41 |
fims::Vector<Type> M; /*!< transformed parameter: natural mortality*/ |
|
| 42 | ||
| 43 |
fims::Vector<double> ages; /*!< vector of the ages for referencing*/ |
|
| 44 |
fims::Vector<double> years; /*!< vector of years for referencing*/ |
|
| 45 | ||
| 46 |
/// recruitment |
|
| 47 |
int recruitment_id = -999; /*!< id of recruitment model object*/ |
|
| 48 |
std::shared_ptr<fims_popdy::RecruitmentBase<Type>> |
|
| 49 |
recruitment; /*!< shared pointer to recruitment module */ |
|
| 50 | ||
| 51 |
// growth |
|
| 52 |
int growth_id = -999; /*!< id of growth model object*/ |
|
| 53 |
std::shared_ptr<fims_popdy::GrowthBase<Type>> |
|
| 54 |
growth; /*!< shared pointer to growth module */ |
|
| 55 | ||
| 56 |
// maturity |
|
| 57 |
int maturity_id = -999; /*!< id of maturity model object*/ |
|
| 58 |
std::shared_ptr<fims_popdy::MaturityBase<Type>> |
|
| 59 |
maturity; /*!< shared pointer to maturity module */ |
|
| 60 | ||
| 61 |
// fleet |
|
| 62 |
std::set<uint32_t> fleet_ids; /*!< id of fleet model object*/ |
|
| 63 |
std::vector<std::shared_ptr<fims_popdy::Fleet<Type>>> |
|
| 64 |
fleets; /*!< shared pointer to fleet module */ |
|
| 65 | ||
| 66 |
/** |
|
| 67 |
* @brief Constructor. |
|
| 68 |
*/ |
|
| 69 | 76x |
Population() { this->id = Population::id_g++; }
|
| 70 | ||
| 71 |
/** |
|
| 72 |
* @brief Create a map of report vectors for the object. |
|
| 73 |
*/ |
|
| 74 | 544x |
virtual void create_report_vectors( |
| 75 |
std::map<std::string, fims::Vector<fims::Vector<Type>>>& report_vectors) {
|
|
| 76 | 1088x |
report_vectors["log_init_naa"].emplace_back(this->log_init_naa); |
| 77 | 544x |
report_vectors["log_M"].emplace_back(this->log_M); |
| 78 |
} |
|
| 79 | ||
| 80 |
/** |
|
| 81 |
* @brief Get the report vector count object. |
|
| 82 |
*/ |
|
| 83 | ! |
virtual void get_report_vector_count( |
| 84 |
std::map<std::string, size_t>& report_vector_count) {
|
|
| 85 | ! |
report_vector_count["log_init_naa"] += 1; |
| 86 | ! |
report_vector_count["log_M"] += 1; |
| 87 |
} |
|
| 88 |
}; |
|
| 89 |
template <class Type> |
|
| 90 |
uint32_t Population<Type>::id_g = 0; |
|
| 91 | ||
| 92 |
} // namespace fims_popdy |
|
| 93 | ||
| 94 |
#endif /* FIMS_POPULATION_DYNAMICS_POPULATION_HPP */ |
| 1 |
/** |
|
| 2 |
* @file log_devs.hpp |
|
| 3 |
* @brief Incorporates error using the log recruitment deviations approach. |
|
| 4 |
* @details This function inherits from recruitment base. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_POPULATION_DYNAMICS_RECRUITMENT_LOG_DEVS_HPP |
|
| 10 |
#define FIMS_POPULATION_DYNAMICS_RECRUITMENT_LOG_DEVS_HPP |
|
| 11 | ||
| 12 |
#include "recruitment_base.hpp" |
|
| 13 |
#include "../../../common/fims_vector.hpp" |
|
| 14 | ||
| 15 |
namespace fims_popdy {
|
|
| 16 | ||
| 17 |
/** @brief Log Devs class that returns the log of the input added to the log of |
|
| 18 |
* the recruitment deviations. |
|
| 19 |
*/ |
|
| 20 |
template <typename Type> |
|
| 21 |
struct LogDevs : public RecruitmentBase<Type> {
|
|
| 22 | 72x |
LogDevs() : RecruitmentBase<Type>() {}
|
| 23 | ||
| 24 | ! |
virtual ~LogDevs() {}
|
| 25 | ||
| 26 |
/** @brief Log of the recruitment deviations approach to adding error to |
|
| 27 |
* expected recruitment. |
|
| 28 |
* |
|
| 29 |
* The Log Recruitment Deviation implementation: |
|
| 30 |
* \f$ \text{log expected recruitment} + log_devs \f$
|
|
| 31 |
* |
|
| 32 |
* @param pos Position index, e.g., which year. |
|
| 33 |
*/ |
|
| 34 | 15312x |
virtual const Type evaluate_process(size_t pos) {
|
| 35 | 15312x |
return this->recruitment->log_expected_recruitment[pos] + |
| 36 | 18212x |
this->recruitment->log_recruit_devs[pos]; |
| 37 |
} |
|
| 38 | ||
| 39 |
/** Empty return of base class function */ |
|
| 40 | ! |
virtual const Type evaluate_mean(const Type& spawners, const Type& phi_0) {
|
| 41 | ! |
return 0; |
| 42 |
} |
|
| 43 |
/** |
|
| 44 |
* @brief Create a map of report vectors for the recruitment object. |
|
| 45 |
*/ |
|
| 46 |
virtual std::map<std::string, fims::Vector<Type>> |
|
| 47 | ! |
create_report_vectors_map() {
|
| 48 | ! |
std::map<std::string, fims::Vector<Type>> report_vectors; |
| 49 | ! |
return report_vectors; |
| 50 |
} |
|
| 51 |
}; |
|
| 52 | ||
| 53 |
} // namespace fims_popdy |
|
| 54 | ||
| 55 |
#endif /* FIMS_POPULATION_DYNAMICS_RECRUITMENT_LOG_DEVS_HPP */ |
| 1 |
/** |
|
| 2 |
* @file log_r.hpp |
|
| 3 |
* @brief Incorporates error using the log recruitment approach. |
|
| 4 |
* @details This function inherits from recruitment base. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef FIMS_POPULATION_DYNAMICS_RECRUITMENT_LOG_R_HPP |
|
| 10 |
#define FIMS_POPULATION_DYNAMICS_RECRUITMENT_LOG_R_HPP |
|
| 11 | ||
| 12 |
#include "recruitment_base.hpp" |
|
| 13 |
#include "../../../common/fims_vector.hpp" |
|
| 14 | ||
| 15 |
namespace fims_popdy {
|
|
| 16 | ||
| 17 |
/** @brief Log Devs class that returns the log of the input added to the log of |
|
| 18 |
* the recruitment deviations. |
|
| 19 |
*/ |
|
| 20 |
template <typename Type> |
|
| 21 |
struct LogR : public RecruitmentBase<Type> {
|
|
| 22 | 4x |
LogR() : RecruitmentBase<Type>() {}
|
| 23 | ||
| 24 | ! |
virtual ~LogR() {}
|
| 25 | ||
| 26 |
/** @brief Log of recruitment approach to adding error to expected |
|
| 27 |
* recruitment. |
|
| 28 |
* |
|
| 29 |
* The Log Recruitment implementation: |
|
| 30 |
* \f$ \text{log expected recruitment} \f$
|
|
| 31 |
* |
|
| 32 |
* @param pos Position index, e.g., which year. |
|
| 33 |
*/ |
|
| 34 | 1218x |
virtual const Type evaluate_process(size_t pos) {
|
| 35 | 1218x |
return this->recruitment->log_r[pos]; |
| 36 |
} |
|
| 37 | ||
| 38 |
/** Empty return of base class function */ |
|
| 39 | ! |
virtual const Type evaluate_mean(const Type& spawners, const Type& phi_0) {
|
| 40 | ! |
return 0; |
| 41 |
} |
|
| 42 |
}; |
|
| 43 | ||
| 44 |
} // namespace fims_popdy |
|
| 45 | ||
| 46 |
#endif /* FIMS_POPULATION_DYNAMICS_RECRUITMENT_LOG_R_HPP */ |
| 1 |
/** |
|
| 2 |
* @file recruitment_base.hpp |
|
| 3 |
* @brief Serves as the parent class where recruitment functions are called. |
|
| 4 |
* @details Defines guards for recruitment base outline to define the |
|
| 5 |
* recruitment hpp file if not already defined. |
|
| 6 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 7 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 8 |
* folder for reuse information. |
|
| 9 |
*/ |
|
| 10 |
#ifndef FIMS_POPULATION_DYNAMICS_RECRUITMENT_BASE_HPP |
|
| 11 |
#define FIMS_POPULATION_DYNAMICS_RECRUITMENT_BASE_HPP |
|
| 12 | ||
| 13 |
#include <cmath> // for using std::pow and M_PI |
|
| 14 | ||
| 15 |
#include "../../../common/fims_math.hpp" // for using fims_math::log() |
|
| 16 |
#include "../../../common/fims_vector.hpp" |
|
| 17 |
#include "../../../common/model_object.hpp" |
|
| 18 |
#include "../../../distributions/distributions.hpp" |
|
| 19 | ||
| 20 |
namespace fims_popdy {
|
|
| 21 | ||
| 22 |
/** @brief Base class for all recruitment functors. |
|
| 23 |
* |
|
| 24 |
* @tparam Type The type of the recruitment functor. |
|
| 25 |
* |
|
| 26 |
*/ |
|
| 27 |
template <class Type> |
|
| 28 |
struct RecruitmentBase : public fims_model_object::FIMSObject<Type> {
|
|
| 29 |
static uint32_t id_g; /**< reference id for recruitment object*/ |
|
| 30 | ||
| 31 |
fims::Vector<Type> log_recruit_devs; /*!< A vector of the natural log of |
|
| 32 |
recruitment deviations */ |
|
| 33 |
bool constrain_deviations = false; /*!< A flag to indicate if recruitment |
|
| 34 |
deviations are summing to zero or not */ |
|
| 35 | ||
| 36 |
fims::Vector<Type> log_rzero; /**< Natural log of unexploited recruitment.*/ |
|
| 37 |
fims::Vector<Type> |
|
| 38 |
log_r; /**< Natural log of recruitment used for random effects */ |
|
| 39 |
fims::Vector<Type> |
|
| 40 |
log_expected_recruitment; /**< Expectation of the recruitment process */ |
|
| 41 | ||
| 42 |
bool estimate_log_recruit_devs = true; /*!< A flag to indicate if recruitment |
|
| 43 |
deviations are estimated or not */ |
|
| 44 | ||
| 45 |
int process_id = -999; /*!< id of recruitment process model object*/ |
|
| 46 |
std::shared_ptr<fims_popdy::RecruitmentBase<Type>> |
|
| 47 |
process; /*!< shared pointer to recruitment processmodule */ |
|
| 48 |
std::shared_ptr<fims_popdy::RecruitmentBase<Type>> |
|
| 49 |
recruitment; /*!< shared pointer to recruitment module */ |
|
| 50 | ||
| 51 |
/** @brief Constructor. |
|
| 52 |
*/ |
|
| 53 | 164x |
RecruitmentBase() { this->id = RecruitmentBase::id_g++; }
|
| 54 | ||
| 55 | 6x |
virtual ~RecruitmentBase() {}
|
| 56 | ||
| 57 |
/** |
|
| 58 |
* @brief Prepares the recruitment deviations vector. |
|
| 59 |
* |
|
| 60 |
*/ |
|
| 61 |
void Prepare() {
|
|
| 62 |
// this->PrepareConstrainedDeviations(); |
|
| 63 |
std::fill(log_expected_recruitment.begin(), log_expected_recruitment.end(), |
|
| 64 |
0.0); |
|
| 65 |
} |
|
| 66 | ||
| 67 |
/** @brief Calculates the expected recruitment for a given spawning input. |
|
| 68 |
* |
|
| 69 |
* @param spawners A measure for spawning output. |
|
| 70 |
* @param ssbzero A measure for spawning output in unfished population. |
|
| 71 |
* |
|
| 72 |
*/ |
|
| 73 |
virtual const Type evaluate_mean( |
|
| 74 |
const Type &spawners, |
|
| 75 |
const Type &ssbzero) = 0; // need to add input parameter values |
|
| 76 | ||
| 77 |
/** @brief Handle error in recruitment |
|
| 78 |
* |
|
| 79 |
* @param pos Position index, e.g., which year. |
|
| 80 |
*/ |
|
| 81 |
virtual const Type evaluate_process(size_t pos) = 0; |
|
| 82 | ||
| 83 |
/** @brief Prepare constrained recruitment deviations. |
|
| 84 |
* Based on ADMB sum-to-zero constraint implementation. We still |
|
| 85 |
* need to add an additional penalty to the PrepareConstrainedDeviations |
|
| 86 |
* method. More discussion can be found here: |
|
| 87 |
* https://groups.google.com/a/ADMB-project.org/g/users/c/63YJmYGEPuE |
|
| 88 |
*/ |
|
| 89 |
void PrepareConstrainedDeviations() {
|
|
| 90 |
if (!this->constrain_deviations) {
|
|
| 91 |
return; |
|
| 92 |
} |
|
| 93 | ||
| 94 |
Type sum = static_cast<Type>(0.0); |
|
| 95 | ||
| 96 |
for (size_t i = 0; i < this->log_recruit_devs.size(); i++) {
|
|
| 97 |
sum += this->log_recruit_devs[i]; |
|
| 98 |
} |
|
| 99 | ||
| 100 |
for (size_t i = 0; i < this->log_recruit_devs.size(); i++) {
|
|
| 101 |
this->log_recruit_devs[i] -= sum / (this->log_recruit_devs.size()); |
|
| 102 |
} |
|
| 103 |
} |
|
| 104 |
}; |
|
| 105 | ||
| 106 |
template <class Type> |
|
| 107 |
uint32_t RecruitmentBase<Type>::id_g = 0; |
|
| 108 |
} // namespace fims_popdy |
|
| 109 | ||
| 110 |
#endif /* FIMS_POPULATION_DYNAMICS_RECRUITMENT_BASE_HPP */ |
| 1 |
/** |
|
| 2 |
* @file sr_beverton_holt.hpp |
|
| 3 |
* @brief Calls the Beverton--Holt stock--recruitment function from fims_math |
|
| 4 |
* and does the calculation. |
|
| 5 |
* @details This function inherits from recruitment base. |
|
| 6 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 7 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 8 |
* folder for reuse information. |
|
| 9 |
*/ |
|
| 10 |
#ifndef FIMS_POPULATION_DYNAMICS_RECRUITMENT_SR_BEVERTON_HOLT_HPP |
|
| 11 |
#define FIMS_POPULATION_DYNAMICS_RECRUITMENT_SR_BEVERTON_HOLT_HPP |
|
| 12 | ||
| 13 |
#include "recruitment_base.hpp" |
|
| 14 |
#include "../../../common/fims_vector.hpp" |
|
| 15 | ||
| 16 |
namespace fims_popdy {
|
|
| 17 | ||
| 18 |
/** @brief BevertonHolt class that returns the Beverton--Holt |
|
| 19 |
* stock--recruitment from fims_math. |
|
| 20 |
* |
|
| 21 |
* @param logit_steep Recruitment relative to unfished recruitment at 20 |
|
| 22 |
* percent of unfished spawning biomass. Steepness is subject to a logit |
|
| 23 |
* transformation to keep it between 0.2 and 1.0. |
|
| 24 |
*/ |
|
| 25 |
template <typename Type> |
|
| 26 |
struct SRBevertonHolt : public RecruitmentBase<Type> {
|
|
| 27 |
// Here we define the members that will be used in the Beverton--Holt |
|
| 28 |
// stock--recruitment function. These members are needed by the Beverton--Holt |
|
| 29 |
// stock--recruitment function but will not be common to all recruitment |
|
| 30 |
// functions like spawners is below. |
|
| 31 |
fims::Vector<Type> logit_steep; /**< Transformed value of recruitment |
|
| 32 |
relative to unfished |
|
| 33 |
recruitment at 20 percent of unfished |
|
| 34 |
spawning biomass.*/ |
|
| 35 | ||
| 36 | 88x |
SRBevertonHolt() : RecruitmentBase<Type>() {}
|
| 37 | ||
| 38 | 6x |
virtual ~SRBevertonHolt() {}
|
| 39 | ||
| 40 |
/** @brief Beverton--Holt implementation of the stock--recruitment function. |
|
| 41 |
* |
|
| 42 |
* The Beverton--Holt stock--recruitment implementation: |
|
| 43 |
* \f$ \frac{0.8 R_{0} h S_{t-1}}{0.2 R_{0} \phi_{0} (1 - h) + S_{t-1} (h -
|
|
| 44 |
* 0.2)} \f$ |
|
| 45 |
* |
|
| 46 |
* @param spawners A measure of spawning output. |
|
| 47 |
* @param phi_0 Number of spawners per recruit of an unfished population |
|
| 48 |
*/ |
|
| 49 | 17104x |
virtual const Type evaluate_mean(const Type& spawners, const Type& phi_0) {
|
| 50 | 3240x |
Type recruits; |
| 51 | 3240x |
Type steep; |
| 52 | 17104x |
Type steep_lo = static_cast<Type>(0.2); |
| 53 | 17104x |
Type steep_hi = static_cast<Type>(1.0); |
| 54 | 3240x |
Type rzero; |
| 55 | ||
| 56 |
// Transform input parameters |
|
| 57 | 17104x |
steep = fims_math::inv_logit(steep_lo, steep_hi, this->logit_steep[0]); |
| 58 | 17104x |
rzero = fims_math::exp(this->log_rzero[0]); |
| 59 | ||
| 60 | 17104x |
recruits = (static_cast<Type>(0.8) * rzero * steep * spawners) / |
| 61 | 17104x |
(static_cast<Type>(0.2) * phi_0 * rzero * |
| 62 | 20344x |
(static_cast<Type>(1.0) - steep) + |
| 63 | 17104x |
spawners * (steep - static_cast<Type>(0.2))); |
| 64 | ||
| 65 | 17104x |
return recruits; |
| 66 |
} |
|
| 67 | ||
| 68 |
/** Empty return of base class function |
|
| 69 |
* @param pos position index |
|
| 70 |
*/ |
|
| 71 | ! |
virtual const Type evaluate_process(size_t pos) { return 0; }
|
| 72 | ||
| 73 |
/** |
|
| 74 |
* @brief Create a map of report vectors for the recruitment object. |
|
| 75 |
*/ |
|
| 76 | 544x |
virtual void create_report_vectors( |
| 77 |
std::map<std::string, fims::Vector<fims::Vector<Type>>>& report_vectors) {
|
|
| 78 | 1088x |
report_vectors["logit_steep"].emplace_back(this->logit_steep); |
| 79 | 1088x |
report_vectors["log_rzero"].emplace_back(this->log_rzero); |
| 80 | 1088x |
report_vectors["log_r"].emplace_back(this->log_r); |
| 81 | 544x |
report_vectors["log_devs"].emplace_back(this->log_recruit_devs); |
| 82 |
} |
|
| 83 | ||
| 84 | ! |
virtual void get_report_vector_count( |
| 85 |
std::map<std::string, size_t>& report_vector_count) {
|
|
| 86 | ! |
report_vector_count["logit_steep"] += 1; |
| 87 | ! |
report_vector_count["log_rzero"] += 1; |
| 88 | ! |
report_vector_count["log_r"] += 1; |
| 89 | ! |
report_vector_count["log_recruit_devs"] += 1; |
| 90 |
} |
|
| 91 |
}; |
|
| 92 | ||
| 93 |
} // namespace fims_popdy |
|
| 94 | ||
| 95 |
#endif /* FIMS_POPULATION_DYNAMICS_RECRUITMENT_SR_BEVERTON_HOLT_HPP */ |
| 1 |
/** |
|
| 2 |
* @file double_logistic.hpp |
|
| 3 |
* @brief Declares the DoubleLogisticSelectivity class which implements the |
|
| 4 |
* logistic function from fims_math in the selectivity module. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef POPULATION_DYNAMICS_SELECTIVITY_DOUBLE_LOGISTIC_HPP |
|
| 10 |
#define POPULATION_DYNAMICS_SELECTIVITY_DOUBLE_LOGISTIC_HPP |
|
| 11 | ||
| 12 |
// #include "../../../interface/interface.hpp" |
|
| 13 |
#include "../../../common/fims_math.hpp" |
|
| 14 |
#include "../../../common/fims_vector.hpp" |
|
| 15 |
#include "selectivity_base.hpp" |
|
| 16 | ||
| 17 |
namespace fims_popdy {
|
|
| 18 | ||
| 19 |
/** |
|
| 20 |
* @brief DoubleLogisticSelectivity class that returns the double logistic |
|
| 21 |
* function value from fims_math. |
|
| 22 |
*/ |
|
| 23 |
template <typename Type> |
|
| 24 |
struct DoubleLogisticSelectivity : public SelectivityBase<Type> {
|
|
| 25 |
fims::Vector<Type> inflection_point_asc; /**< 50% quantile of the value of the |
|
| 26 |
quantity of interest (x) on the ascending limb of the double |
|
| 27 |
logistic curve; e.g. age at which 50% of the fish are selected */ |
|
| 28 |
fims::Vector<Type> slope_asc; /**<scalar multiplier of difference between |
|
| 29 |
quantity of interest value (x) and inflection_point on the |
|
| 30 |
ascending limb of the double logistic curve*/ |
|
| 31 |
fims::Vector<Type> inflection_point_desc; /**< 50% quantile of the value of |
|
| 32 |
the quantity of interest (x) on the descending limb of the double |
|
| 33 |
logistic curve; e.g. age at which 50% of the fish are selected */ |
|
| 34 |
fims::Vector<Type> slope_desc; /**<scalar multiplier of difference between |
|
| 35 |
quantity of interest value (x) and inflection_point on the |
|
| 36 |
descending limb of the double logistic curve */ |
|
| 37 | ||
| 38 | 14x |
DoubleLogisticSelectivity() : SelectivityBase<Type>() {}
|
| 39 | ||
| 40 | 7x |
virtual ~DoubleLogisticSelectivity() {}
|
| 41 | ||
| 42 |
/** |
|
| 43 |
* @brief Method of the double logistic selectivity class that implements the |
|
| 44 |
* double logistic function from FIMS math. |
|
| 45 |
* |
|
| 46 |
* \f$ \frac{1.0}{ 1.0 + exp(-1.0 * slope\_asc (x - inflection_point\_asc))}
|
|
| 47 |
* \left(1.0-\frac{1.0}{ 1.0 + exp(-1.0 * slope\_desc (x -
|
|
| 48 |
* inflection_point\_desc))} \right)\f$ |
|
| 49 |
* |
|
| 50 |
* @param x The independent variable in the double logistic function (e.g., |
|
| 51 |
* age or size in selectivity). |
|
| 52 |
*/ |
|
| 53 | 3x |
virtual const Type evaluate(const Type& x) {
|
| 54 | 3x |
return fims_math::double_logistic<Type>( |
| 55 | 3x |
inflection_point_asc[0], slope_asc[0], inflection_point_desc[0], |
| 56 | 6x |
slope_desc[0], x); |
| 57 |
} |
|
| 58 | ||
| 59 |
/** |
|
| 60 |
* @brief Method of the double logistic selectivity class that implements the |
|
| 61 |
* double logistic function from FIMS math. |
|
| 62 |
* |
|
| 63 |
* \f$ \frac{1.0}{ 1.0 + exp(-1.0 * slope\_asc_t (x -
|
|
| 64 |
* inflection_point\_asc_t))} \left(1.0-\frac{1.0}{ 1.0 + exp(-1.0 *
|
|
| 65 |
* slope\_desc_t (x - inflection_point\_desc_t))} \right)\f$ |
|
| 66 |
* |
|
| 67 |
* @param x The independent variable in the double logistic function (e.g., |
|
| 68 |
* age or size in selectivity). |
|
| 69 |
* @param pos Position index, e.g., which year. |
|
| 70 |
*/ |
|
| 71 | ! |
virtual const Type evaluate(const Type& x, size_t pos) {
|
| 72 | ! |
return fims_math::double_logistic<Type>( |
| 73 | ! |
inflection_point_asc.get_force_scalar(pos), |
| 74 | ! |
slope_asc.get_force_scalar(pos), |
| 75 | ! |
inflection_point_desc.get_force_scalar(pos), |
| 76 | ! |
slope_desc.get_force_scalar(pos), x); |
| 77 |
} |
|
| 78 | ||
| 79 |
/** |
|
| 80 |
* @brief Create a map of report vectors for the selectivity object. |
|
| 81 |
*/ |
|
| 82 | ! |
virtual void create_report_vectors( |
| 83 |
std::map<std::string, fims::Vector<fims::Vector<Type>>>& report_vectors) {
|
|
| 84 | ! |
report_vectors["inflection_point_asc"].emplace_back( |
| 85 |
inflection_point_asc.to_tmb()); |
|
| 86 | ! |
report_vectors["slope_asc"].emplace_back(slope_asc.to_tmb()); |
| 87 | ! |
report_vectors["inflection_point_desc"].emplace_back( |
| 88 |
inflection_point_desc.to_tmb()); |
|
| 89 | ! |
report_vectors["slope_desc"].emplace_back(slope_desc.to_tmb()); |
| 90 |
} |
|
| 91 | ||
| 92 | ! |
virtual void get_report_vector_count( |
| 93 |
std::map<std::string, size_t>& report_vector_count) {
|
|
| 94 | ! |
report_vector_count["inflection_point_asc"] += 1; |
| 95 | ! |
report_vector_count["slope_asc"] += 1; |
| 96 | ! |
report_vector_count["inflection_point_desc"] += 1; |
| 97 | ! |
report_vector_count["slope_desc"] += 1; |
| 98 |
} |
|
| 99 |
}; |
|
| 100 | ||
| 101 |
} // namespace fims_popdy |
|
| 102 | ||
| 103 |
#endif /* POPULATION_DYNAMICS_SELECTIVITY_DOUBLE_LOGISTIC_HPP */ |
| 1 |
/** |
|
| 2 |
* @file logistic.hpp |
|
| 3 |
* @brief Declares the LogisticSelectivity class which implements the logistic |
|
| 4 |
* function from fims_math in the selectivity module. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef POPULATION_DYNAMICS_SELECTIVITY_LOGISTIC_HPP |
|
| 10 |
#define POPULATION_DYNAMICS_SELECTIVITY_LOGISTIC_HPP |
|
| 11 | ||
| 12 |
// #include "../../../interface/interface.hpp" |
|
| 13 |
#include "../../../common/fims_math.hpp" |
|
| 14 |
#include "../../../common/fims_vector.hpp" |
|
| 15 |
#include "selectivity_base.hpp" |
|
| 16 | ||
| 17 |
namespace fims_popdy {
|
|
| 18 | ||
| 19 |
/** |
|
| 20 |
* @brief LogisticSelectivity class that returns the logistic function value |
|
| 21 |
* from fims_math. |
|
| 22 |
*/ |
|
| 23 |
template <typename Type> |
|
| 24 |
struct LogisticSelectivity : public SelectivityBase<Type> {
|
|
| 25 |
fims::Vector<Type> |
|
| 26 |
inflection_point; /**< 50% quantile of the value of the quantity of |
|
| 27 |
interest (x); e.g. age at which 50% of the fish are selected */ |
|
| 28 |
fims::Vector<Type> slope; /**<scalar multiplier of difference between quantity |
|
| 29 |
of interest value (x) and inflection_point */ |
|
| 30 | ||
| 31 | 180x |
LogisticSelectivity() : SelectivityBase<Type>() {}
|
| 32 | ||
| 33 | 90x |
virtual ~LogisticSelectivity() {}
|
| 34 | ||
| 35 |
/** |
|
| 36 |
* @brief Method of the logistic selectivity class that implements the |
|
| 37 |
* logistic function from FIMS math. |
|
| 38 |
* |
|
| 39 |
* \f[ \frac{1.0}{ 1.0 + exp(-1.0 * slope (x - inflection\_point))} \f]
|
|
| 40 |
* |
|
| 41 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 42 |
* size in selectivity). |
|
| 43 |
*/ |
|
| 44 | 1231204x |
virtual const Type evaluate(const Type &x) {
|
| 45 | 1231204x |
return fims_math::logistic<Type>(inflection_point[0], slope[0], x); |
| 46 |
} |
|
| 47 | ||
| 48 |
/** |
|
| 49 |
* @brief Method of the logistic selectivity class that implements the |
|
| 50 |
* logistic function from FIMS math. |
|
| 51 |
* |
|
| 52 |
* \f[ \frac{1.0}{ 1.0 + exp(-1.0 * slope_t (x - {inflection\_point}_t))} \f]
|
|
| 53 |
* |
|
| 54 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 55 |
* size in selectivity). |
|
| 56 |
* @param pos Position index, e.g., which year. |
|
| 57 |
*/ |
|
| 58 | ! |
virtual const Type evaluate(const Type &x, size_t pos) {
|
| 59 | ! |
return fims_math::logistic<Type>(inflection_point.get_force_scalar(pos), |
| 60 | ! |
slope.get_force_scalar(pos), x); |
| 61 |
} |
|
| 62 | ||
| 63 | 1088x |
virtual void create_report_vectors( |
| 64 |
std::map<std::string, fims::Vector<fims::Vector<Type>>> &report_vectors) {
|
|
| 65 | 2176x |
report_vectors["inflection_point"].emplace_back(inflection_point); |
| 66 | 1088x |
report_vectors["slope"].emplace_back(slope); |
| 67 |
} |
|
| 68 | ||
| 69 | ! |
virtual void get_report_vector_count( |
| 70 |
std::map<std::string, size_t> &report_vector_count) {
|
|
| 71 | ! |
report_vector_count["inflection_point"] += 1; |
| 72 | ! |
report_vector_count["slope"] += 1; |
| 73 |
} |
|
| 74 |
}; |
|
| 75 | ||
| 76 |
} // namespace fims_popdy |
|
| 77 | ||
| 78 |
#endif /* POPULATION_DYNAMICS_SELECTIVITY_LOGISTIC_HPP */ |
| 1 |
/** |
|
| 2 |
* @file selectivity_base.hpp |
|
| 3 |
* @brief Declares the SelectivityBase class which is the base class for all |
|
| 4 |
* selectivity functors. |
|
| 5 |
* @details Defines guards for selectivity module outline to define the |
|
| 6 |
* selectivity hpp file if not already defined. |
|
| 7 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 8 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 9 |
* folder for reuse information. |
|
| 10 |
*/ |
|
| 11 |
#ifndef POPULATION_DYNAMICS_SELECTIVITY_BASE_HPP |
|
| 12 |
#define POPULATION_DYNAMICS_SELECTIVITY_BASE_HPP |
|
| 13 | ||
| 14 |
#include "../../../common/model_object.hpp" |
|
| 15 | ||
| 16 |
namespace fims_popdy {
|
|
| 17 | ||
| 18 |
/** @brief Base class for all selectivity functors. |
|
| 19 |
* |
|
| 20 |
* @tparam Type The type of the selectivity functor. |
|
| 21 |
*/ |
|
| 22 | ||
| 23 |
template <typename Type> |
|
| 24 |
struct SelectivityBase : public fims_model_object::FIMSObject<Type> {
|
|
| 25 |
// id_g is the ID of the instance of the SelectivityBase class. |
|
| 26 |
// this is like a memory tracker. |
|
| 27 |
// Assigning each one its own ID is a way to keep track of |
|
| 28 |
// all the instances of the SelectivityBase class. |
|
| 29 |
static uint32_t |
|
| 30 |
id_g; /**< The ID of the instance of the SelectivityBase class */ |
|
| 31 | ||
| 32 |
/** @brief Constructor. |
|
| 33 |
*/ |
|
| 34 | 194x |
SelectivityBase() {
|
| 35 |
// increment id of the singleton selectivity class |
|
| 36 | 194x |
this->id = SelectivityBase::id_g++; |
| 37 |
} |
|
| 38 | ||
| 39 | 97x |
virtual ~SelectivityBase() {}
|
| 40 | ||
| 41 |
/** |
|
| 42 |
* @brief Calculates the selectivity. |
|
| 43 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 44 |
* size in selectivity). |
|
| 45 |
*/ |
|
| 46 |
virtual const Type evaluate(const Type& x) = 0; |
|
| 47 | ||
| 48 |
/** |
|
| 49 |
* @brief Calculates the selectivity. |
|
| 50 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 51 |
* size in selectivity). |
|
| 52 |
* @param pos Position index, e.g., which year. |
|
| 53 |
*/ |
|
| 54 |
virtual const Type evaluate(const Type& x, size_t pos) = 0; |
|
| 55 |
}; |
|
| 56 | ||
| 57 |
// default id of the singleton selectivity class |
|
| 58 |
template <typename Type> |
|
| 59 |
uint32_t SelectivityBase<Type>::id_g = 0; |
|
| 60 | ||
| 61 |
} // namespace fims_popdy |
|
| 62 | ||
| 63 |
#endif /* POPULATION_DYNAMICS_SELECTIVITY_BASE_HPP */ |
| 1 |
#ifndef FIMS_JSON_HPP |
|
| 2 |
#define FIMS_JSON_HPP |
|
| 3 | ||
| 4 |
/** |
|
| 5 |
* @file fims_json.hpp |
|
| 6 |
* @brief A simple JSON parsing and generation library. |
|
| 7 |
* @details This library provides classes and functions for parsing JSON |
|
| 8 |
* strings and generating JSON data structures. |
|
| 9 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 10 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 11 |
* folder for reuse information. |
|
| 12 |
*/ |
|
| 13 |
#include <cctype> |
|
| 14 |
#include <iostream> |
|
| 15 |
#include <fstream> |
|
| 16 |
#include <map> |
|
| 17 |
#include <sstream> |
|
| 18 |
#include <string> |
|
| 19 |
#include <algorithm> |
|
| 20 |
#include <vector> |
|
| 21 | ||
| 22 |
namespace fims {
|
|
| 23 |
class JsonValue; |
|
| 24 | ||
| 25 |
/** |
|
| 26 |
* Alias for a JSON object, mapping strings to JSON values. |
|
| 27 |
*/ |
|
| 28 |
using JsonObject = std::map<std::string, JsonValue>; |
|
| 29 | ||
| 30 |
/** |
|
| 31 |
* Alias for a JSON array, containing a sequence of JSON values. |
|
| 32 |
*/ |
|
| 33 |
using JsonArray = std::vector<JsonValue>; |
|
| 34 | ||
| 35 |
/** |
|
| 36 |
* Represents different types of JSON values. |
|
| 37 |
*/ |
|
| 38 |
enum JsonValueType {
|
|
| 39 |
Null = 0, /**< Null JSON value. */ |
|
| 40 |
Number, /**< Numeric JSON value. */ |
|
| 41 |
String, /**< String JSON value. */ |
|
| 42 |
Bool, /**< Boolean JSON value. */ |
|
| 43 |
Object, /**< JSON object. */ |
|
| 44 |
JArray /**< JSON array. */ |
|
| 45 |
}; |
|
| 46 | ||
| 47 |
/** |
|
| 48 |
* Represents a JSON value. |
|
| 49 |
*/ |
|
| 50 |
class JsonValue {
|
|
| 51 |
public: |
|
| 52 |
/** Default constructor, initializes to Null value. */ |
|
| 53 | ! |
JsonValue() : type(JsonValueType::Null) {}
|
| 54 | ||
| 55 |
/** Constructor for numeric JSON value (i.e., integer). */ |
|
| 56 | ! |
JsonValue(int num) : type(JsonValueType::Number), number(num) {}
|
| 57 | ||
| 58 |
/** Constructor for numeric JSON value (i.e., double). */ |
|
| 59 | ! |
JsonValue(double num) : type(JsonValueType::Number), number(num) {}
|
| 60 | ||
| 61 |
/** Constructor for string JSON value. */ |
|
| 62 | ! |
JsonValue(const std::string& str) : type(JsonValueType::String), str(str) {}
|
| 63 | ||
| 64 |
/** Constructor for boolean JSON value. */ |
|
| 65 | ! |
JsonValue(bool b) : type(JsonValueType::Bool), boolean(b) {}
|
| 66 | ||
| 67 |
/** Constructor for JSON object value. */ |
|
| 68 | ! |
JsonValue(const JsonObject& obj) : type(JsonValueType::Object), object(obj) {}
|
| 69 | ||
| 70 |
/** Constructor for JSON array value. */ |
|
| 71 | ! |
JsonValue(const JsonArray& arr) : type(JsonValueType::JArray), array(arr) {}
|
| 72 | ||
| 73 |
/** Get the type of the JSON value. */ |
|
| 74 | ! |
JsonValueType GetType() const { return type; }
|
| 75 | ||
| 76 |
/** Get the numeric value as an integer. */ |
|
| 77 |
int GetInt() const { return static_cast<int>(number); }
|
|
| 78 | ||
| 79 |
/** Get the numeric value as a double. */ |
|
| 80 | ! |
double GetDouble() const { return number; }
|
| 81 | ||
| 82 |
/** Get the string value. */ |
|
| 83 | ! |
const std::string& GetString() const { return str; }
|
| 84 | ||
| 85 |
/** Get the boolean value. */ |
|
| 86 | ! |
bool GetBool() const { return boolean; }
|
| 87 | ||
| 88 |
/** Get the JSON object. */ |
|
| 89 | ! |
JsonObject& GetObject() { return object; }
|
| 90 | ||
| 91 |
/** Get the JSON array. */ |
|
| 92 | ! |
JsonArray& GetArray() { return array; }
|
| 93 | ||
| 94 |
private: |
|
| 95 |
JsonValueType type; /**< Type of the JSON value. */ |
|
| 96 |
double number; /**< Numeric value. */ |
|
| 97 |
std::string str; /**< String value. */ |
|
| 98 |
bool boolean; /**< Boolean value. */ |
|
| 99 |
JsonObject object; /**< JSON object. */ |
|
| 100 |
JsonArray array; /**< JSON array. */ |
|
| 101 |
}; |
|
| 102 | ||
| 103 |
/** |
|
| 104 |
* Parses JSON strings and generates JSON values. |
|
| 105 |
*/ |
|
| 106 |
class JsonParser {
|
|
| 107 |
public: |
|
| 108 |
/** Parse a JSON string and return the corresponding JSON value. */ |
|
| 109 |
JsonValue Parse(const std::string& json); |
|
| 110 |
/** Write a JSON value to a file. */ |
|
| 111 |
void WriteToFile(const std::string& filename, JsonValue jsonValue); |
|
| 112 |
/** Display a JSON value to the standard output. */ |
|
| 113 |
void Show(JsonValue jsonValue); |
|
| 114 | ||
| 115 |
/** Remove whitespace in JSON. */ |
|
| 116 | 13x |
static std::string removeWhitespace(const std::string& input) {
|
| 117 | 13x |
std::string result = input; |
| 118 | 13x |
result.erase(std::remove_if(result.begin(), result.end(), ::isspace), |
| 119 | 13x |
result.end()); |
| 120 | 13x |
return result; |
| 121 |
} |
|
| 122 | ||
| 123 |
/** |
|
| 124 |
* @brief Formats a JSON string. |
|
| 125 |
* @param json |
|
| 126 |
* @return |
|
| 127 |
*/ |
|
| 128 | 13x |
static std::string PrettyFormatJSON(const std::string& json) {
|
| 129 | 13x |
std::string result; |
| 130 | 13x |
std::string input = JsonParser::removeWhitespace(json); |
| 131 | 13x |
int indentLevel = 0; |
| 132 | 13x |
bool inQuotes = false; |
| 133 | ||
| 134 | 12100040x |
for (size_t i = 0; i < input.size(); ++i) {
|
| 135 | 12100027x |
char current = input[i]; |
| 136 | ||
| 137 | 12100027x |
switch (current) {
|
| 138 | 44558x |
case '{':
|
| 139 |
case '[': |
|
| 140 | 44558x |
result += current; |
| 141 | 44558x |
if (!inQuotes) {
|
| 142 | 31350x |
result += '\n'; |
| 143 | 31350x |
indentLevel++; |
| 144 | 62700x |
result += std::string(indentLevel * 4, ' '); |
| 145 |
} |
|
| 146 | 44558x |
break; |
| 147 | ||
| 148 | 44558x |
case '}': |
| 149 |
case ']': |
|
| 150 | 44558x |
if (!inQuotes) {
|
| 151 | 31350x |
result += '\n'; |
| 152 | 31350x |
indentLevel--; |
| 153 | 62700x |
result += std::string(indentLevel * 4, ' '); |
| 154 |
} |
|
| 155 | 44558x |
result += current; |
| 156 | 44558x |
break; |
| 157 | ||
| 158 | 618999x |
case ',': |
| 159 | 618999x |
result += current; |
| 160 | 618999x |
if (!inQuotes) {
|
| 161 | 618624x |
result += '\n'; |
| 162 | 1237248x |
result += std::string(indentLevel * 4, ' '); |
| 163 |
} |
|
| 164 | 618999x |
break; |
| 165 | ||
| 166 | 291436x |
case ':': |
| 167 | 291436x |
result += current; |
| 168 | 291436x |
if (!inQuotes) result += " "; |
| 169 | 291436x |
break; |
| 170 | ||
| 171 | 727910x |
case '"': |
| 172 | 727910x |
result += current; |
| 173 |
// Toggle inQuotes when we encounter a double-quote |
|
| 174 |
if (i == 0 || input[i - 1] != '\\') {
|
|
| 175 | 727910x |
inQuotes = !inQuotes; |
| 176 |
} |
|
| 177 | 727910x |
break; |
| 178 | ||
| 179 | 10372566x |
default: |
| 180 | 10372566x |
result += current; |
| 181 | 10372566x |
break; |
| 182 |
} |
|
| 183 |
} |
|
| 184 | 26x |
return result; |
| 185 |
} |
|
| 186 | ||
| 187 |
private: |
|
| 188 |
/** Skip whitespace characters in the input string. */ |
|
| 189 |
void SkipWhitespace(); |
|
| 190 |
/** Parse a JSON value. */ |
|
| 191 |
JsonValue ParseValue(); |
|
| 192 |
/** Parse a numeric JSON value. */ |
|
| 193 |
JsonValue ParseNumber(); |
|
| 194 |
/** Parse a string JSON value. */ |
|
| 195 |
JsonValue ParseString(); |
|
| 196 |
/** Parse a boolean JSON value. */ |
|
| 197 |
JsonValue ParseBool(); |
|
| 198 |
/** Parse a null JSON value. */ |
|
| 199 |
JsonValue ParseNull(); |
|
| 200 |
/** Parse a JSON object. */ |
|
| 201 |
JsonValue ParseObject(); |
|
| 202 |
/** Parse a JSON array. */ |
|
| 203 |
JsonValue ParseArray(); |
|
| 204 |
/** Write a JSON value to an output file stream. */ |
|
| 205 |
void WriteJsonValue(std::ofstream& outputFile, JsonValue jsonValue); |
|
| 206 |
/** Display a JSON value to an output stream. */ |
|
| 207 |
void PrintJsonValue(std::ostream& outputFile, JsonValue jsonValue); |
|
| 208 |
/** Indentation helper for printing JSON values in an output file stream. */ |
|
| 209 |
void Indent(std::ostream& outputFile, int level); |
|
| 210 |
/** Indentation helper for printing JSON values in an output stream. */ |
|
| 211 |
void Indent(std::ofstream& outputFile, int level); |
|
| 212 | ||
| 213 |
std::string data; /**< Input JSON data. */ |
|
| 214 |
size_t position; /**< Current position in the data. */ |
|
| 215 |
}; |
|
| 216 | ||
| 217 |
/** |
|
| 218 |
* Parse a JSON string and return the corresponding JSON value. |
|
| 219 |
* @param json The JSON string to parse. |
|
| 220 |
* @return The parsed JSON value. |
|
| 221 |
*/ |
|
| 222 | ! |
JsonValue JsonParser::Parse(const std::string& json) {
|
| 223 | ! |
data = json; |
| 224 | ! |
position = 0; |
| 225 | ! |
return ParseValue(); |
| 226 |
} |
|
| 227 | ||
| 228 |
/** |
|
| 229 |
* @brief Skip the white space. |
|
| 230 |
* |
|
| 231 |
*/ |
|
| 232 | ! |
void JsonParser::SkipWhitespace() {
|
| 233 | ! |
while (position < data.size() && std::isspace(data[position])) {
|
| 234 | ! |
position++; |
| 235 |
} |
|
| 236 |
} |
|
| 237 | ||
| 238 |
/** |
|
| 239 |
* Parse a JSON value. |
|
| 240 |
* @return The parsed JSON value. |
|
| 241 |
*/ |
|
| 242 | ! |
JsonValue JsonParser::ParseValue() {
|
| 243 |
/** Skip whitespace characters in the input string. */ |
|
| 244 | ! |
SkipWhitespace(); |
| 245 | ! |
char current = data[position]; |
| 246 | ! |
if (current == '{') {
|
| 247 | ! |
return ParseObject(); |
| 248 | ! |
} else if (current == '[') {
|
| 249 | ! |
return ParseArray(); |
| 250 | ! |
} else if (current == '"') {
|
| 251 | ! |
return ParseString(); |
| 252 | ! |
} else if (current == 't' || current == 'f') {
|
| 253 | ! |
return ParseBool(); |
| 254 | ! |
} else if (current == 'n') {
|
| 255 | ! |
return ParseNull(); |
| 256 |
} else {
|
|
| 257 | ! |
return ParseNumber(); |
| 258 |
} |
|
| 259 |
} |
|
| 260 | ||
| 261 |
/** |
|
| 262 |
* Parse a numeric JSON value. |
|
| 263 |
* @return The parsed JSON value. |
|
| 264 |
*/ |
|
| 265 | ! |
JsonValue JsonParser::ParseNumber() {
|
| 266 | ! |
size_t end_pos = position; |
| 267 | ! |
bool is_float = false; |
| 268 | ! |
while (end_pos < data.size() && |
| 269 | ! |
(std::isdigit(data[end_pos]) || data[end_pos] == '.' || |
| 270 | ! |
data[end_pos] == '-' || data[end_pos] == 'e' || |
| 271 | ! |
data[end_pos] == 'E')) {
|
| 272 | ! |
if (data[end_pos] == '.' || data[end_pos] == 'e' || data[end_pos] == 'E') {
|
| 273 | ! |
is_float = true; |
| 274 |
} |
|
| 275 | ! |
end_pos++; |
| 276 |
} |
|
| 277 | ||
| 278 | ! |
std::string num_str = data.substr(position, end_pos - position); |
| 279 | ! |
position = end_pos; |
| 280 | ||
| 281 | ! |
if (is_float) {
|
| 282 |
double num; |
|
| 283 | ! |
std::istringstream(num_str) >> num; |
| 284 | ! |
return JsonValue(num); |
| 285 |
} else {
|
|
| 286 |
int num; |
|
| 287 | ! |
std::istringstream(num_str) >> num; |
| 288 | ! |
return JsonValue(num); |
| 289 |
} |
|
| 290 |
} |
|
| 291 | ||
| 292 |
/** |
|
| 293 |
* Parse a string JSON value. |
|
| 294 |
* @return The parsed JSON value. |
|
| 295 |
*/ |
|
| 296 | ! |
JsonValue JsonParser::ParseString() {
|
| 297 | ! |
position++; // Skip the initial '"' |
| 298 | ! |
size_t end_pos = data.find('"', position);
|
| 299 | ! |
std::string str = data.substr(position, end_pos - position); |
| 300 | ! |
position = end_pos + 1; |
| 301 | ! |
return JsonValue(str); |
| 302 |
} |
|
| 303 | ||
| 304 |
/** |
|
| 305 |
* Parse a boolean JSON value. |
|
| 306 |
* @return The parsed JSON value. |
|
| 307 |
*/ |
|
| 308 | ! |
JsonValue JsonParser::ParseBool() {
|
| 309 | ! |
if (data.compare(position, 4, "true") == 0) {
|
| 310 | ! |
position += 4; |
| 311 | ! |
return JsonValue(true); |
| 312 | ! |
} else if (data.compare(position, 5, "false") == 0) {
|
| 313 | ! |
position += 5; |
| 314 | ! |
return JsonValue(false); |
| 315 |
} else {
|
|
| 316 |
// Invalid boolean value |
|
| 317 | ! |
return JsonValue(); |
| 318 |
} |
|
| 319 |
} |
|
| 320 | ||
| 321 |
/** |
|
| 322 |
* Parse a null JSON value. |
|
| 323 |
* @return The parsed JSON value. |
|
| 324 |
*/ |
|
| 325 | ! |
JsonValue JsonParser::ParseNull() {
|
| 326 | ! |
if (data.compare(position, 4, "null") == 0) {
|
| 327 | ! |
position += 4; |
| 328 | ! |
return JsonValue(); |
| 329 |
} else {
|
|
| 330 |
// Invalid null value |
|
| 331 | ! |
return JsonValue(); |
| 332 |
} |
|
| 333 |
} |
|
| 334 | ||
| 335 |
/** |
|
| 336 |
* Parse a JSON object. |
|
| 337 |
* @return The parsed JSON value representing the object. |
|
| 338 |
*/ |
|
| 339 | ! |
JsonValue JsonParser::ParseObject() {
|
| 340 | ! |
JsonObject obj; |
| 341 | ! |
position++; // Skip the initial '{'
|
| 342 | ||
| 343 | ! |
while (data[position] != '}') {
|
| 344 | ! |
SkipWhitespace(); |
| 345 | ! |
std::string key = ParseString().GetString(); |
| 346 | ||
| 347 | ! |
position++; // Skip the ':' |
| 348 | ! |
SkipWhitespace(); |
| 349 | ! |
JsonValue value = ParseValue(); |
| 350 | ! |
obj[key] = value; |
| 351 | ||
| 352 | ! |
SkipWhitespace(); |
| 353 | ! |
if (data[position] == ',') {
|
| 354 | ! |
position++; |
| 355 |
} |
|
| 356 |
} |
|
| 357 | ||
| 358 | ! |
position++; // Skip the trailing '}' |
| 359 | ! |
return JsonValue(obj); |
| 360 |
} |
|
| 361 | ||
| 362 |
/** |
|
| 363 |
* Parse a JSON array. |
|
| 364 |
* @return The parsed JSON value representing the array. |
|
| 365 |
*/ |
|
| 366 | ! |
JsonValue JsonParser::ParseArray() {
|
| 367 | ! |
JsonArray arr; |
| 368 | ! |
position++; // Skip the initial '[' |
| 369 | ||
| 370 | ! |
while (data[position] != ']') {
|
| 371 | ! |
SkipWhitespace(); |
| 372 | ! |
JsonValue value = ParseValue(); |
| 373 | ! |
arr.push_back(value); |
| 374 | ||
| 375 | ! |
SkipWhitespace(); |
| 376 | ! |
if (data[position] == ',') {
|
| 377 | ! |
position++; |
| 378 |
} |
|
| 379 |
} |
|
| 380 | ||
| 381 | ! |
position++; // Skip the trailing ']' |
| 382 | ! |
return JsonValue(arr); |
| 383 |
} |
|
| 384 | ||
| 385 |
/** |
|
| 386 |
* Write a JSON value to an output file. |
|
| 387 |
* @param filename The name of the output file. |
|
| 388 |
* @param jsonValue The JSON value to write. |
|
| 389 |
*/ |
|
| 390 | ! |
void JsonParser::WriteToFile(const std::string& filename, JsonValue jsonValue) {
|
| 391 | ! |
std::ofstream outputFile(filename); |
| 392 | ! |
if (!outputFile) {
|
| 393 | ! |
std::cerr << "Error: Unable to open file " << filename << " for writing." |
| 394 | ! |
<< std::endl; |
| 395 | ! |
return; |
| 396 |
} |
|
| 397 | ||
| 398 |
/** Call a private helper function to write JSON values recursively */ |
|
| 399 | ! |
WriteJsonValue(outputFile, jsonValue); |
| 400 |
} |
|
| 401 | ||
| 402 |
/** |
|
| 403 |
* Write a JSON value to an output file. |
|
| 404 |
* Private helper function to write JSON values recursively |
|
| 405 |
* @param outputFile The output file stream. |
|
| 406 |
* @param jsonValue The JSON value to write. |
|
| 407 |
*/ |
|
| 408 | ! |
void JsonParser::WriteJsonValue(std::ofstream& outputFile, |
| 409 |
JsonValue jsonValue) {
|
|
| 410 | ! |
switch (jsonValue.GetType()) {
|
| 411 | ! |
case JsonValueType::Null: |
| 412 | ! |
outputFile << "null"; |
| 413 | ! |
break; |
| 414 | ! |
case JsonValueType::Number: |
| 415 | ! |
outputFile << jsonValue.GetDouble(); |
| 416 | ! |
break; |
| 417 | ! |
case JsonValueType::String: |
| 418 | ! |
outputFile << "\"" << jsonValue.GetString() << "\""; |
| 419 | ! |
break; |
| 420 | ! |
case JsonValueType::Bool: |
| 421 | ! |
outputFile << (jsonValue.GetBool() ? "true" : "false"); |
| 422 | ! |
break; |
| 423 | ! |
case JsonValueType::Object: {
|
| 424 | ! |
JsonObject& obj = jsonValue.GetObject(); |
| 425 | ! |
outputFile << "{";
|
| 426 | ! |
bool first = true; |
| 427 | ! |
for (const auto& pair : obj) {
|
| 428 | ! |
if (!first) {
|
| 429 | ! |
outputFile << ","; |
| 430 |
} |
|
| 431 | ! |
first = false; |
| 432 | ! |
outputFile << "\"" << pair.first << "\":"; |
| 433 | ! |
WriteJsonValue(outputFile, pair.second); |
| 434 |
} |
|
| 435 | ! |
outputFile << "}"; |
| 436 | ! |
} break; |
| 437 | ! |
case JsonValueType::JArray: {
|
| 438 | ! |
JsonArray& arr = jsonValue.GetArray(); |
| 439 | ! |
outputFile << "["; |
| 440 | ! |
bool first = true; |
| 441 | ! |
for (const auto& value : arr) {
|
| 442 | ! |
if (!first) {
|
| 443 | ! |
outputFile << ","; |
| 444 |
} |
|
| 445 | ! |
first = false; |
| 446 | ! |
WriteJsonValue(outputFile, value); |
| 447 |
} |
|
| 448 | ! |
outputFile << "]"; |
| 449 | ! |
} break; |
| 450 |
} |
|
| 451 |
} |
|
| 452 | ||
| 453 |
/** |
|
| 454 |
* Display a JSON value to the standard output. |
|
| 455 |
* @param jsonValue The JSON value to display. |
|
| 456 |
*/ |
|
| 457 | ! |
void JsonParser::Show(JsonValue jsonValue) {
|
| 458 | ! |
this->PrintJsonValue(std::cout, jsonValue); |
| 459 | ! |
std::cout << std::endl; |
| 460 |
} |
|
| 461 | ||
| 462 |
/** |
|
| 463 |
* Display a JSON value to an output stream. |
|
| 464 |
* @param output The output stream. |
|
| 465 |
* @param jsonValue The JSON value to display. |
|
| 466 |
*/ |
|
| 467 | ! |
void JsonParser::PrintJsonValue(std::ostream& output, JsonValue jsonValue) {
|
| 468 | ! |
switch (jsonValue.GetType()) {
|
| 469 | ! |
case JsonValueType::Null: |
| 470 | ! |
output << "null"; |
| 471 | ! |
break; |
| 472 | ! |
case JsonValueType::Number: |
| 473 | ! |
output << jsonValue.GetDouble(); |
| 474 | ! |
break; |
| 475 | ! |
case JsonValueType::String: |
| 476 | ! |
output << "\"" << jsonValue.GetString() << "\""; |
| 477 | ! |
break; |
| 478 | ! |
case JsonValueType::Bool: |
| 479 | ! |
output << (jsonValue.GetBool() ? "true" : "false"); |
| 480 | ! |
break; |
| 481 | ! |
case JsonValueType::Object: {
|
| 482 | ! |
JsonObject& obj = jsonValue.GetObject(); |
| 483 | ! |
output << "{";
|
| 484 | ! |
bool first = true; |
| 485 | ! |
for (const auto& pair : obj) {
|
| 486 | ! |
if (!first) {
|
| 487 | ! |
output << ","; |
| 488 |
} |
|
| 489 | ! |
first = false; |
| 490 | ! |
output << "\"" << pair.first << "\":"; |
| 491 | ! |
PrintJsonValue(output, pair.second); |
| 492 |
} |
|
| 493 | ! |
output << "}"; |
| 494 | ! |
} break; |
| 495 | ! |
case JsonValueType::JArray: {
|
| 496 | ! |
JsonArray& arr = jsonValue.GetArray(); |
| 497 | ! |
output << "["; |
| 498 | ! |
bool first = true; |
| 499 | ! |
for (const auto& value : arr) {
|
| 500 | ! |
if (!first) {
|
| 501 | ! |
output << ","; |
| 502 |
} |
|
| 503 | ! |
first = false; |
| 504 | ! |
PrintJsonValue(output, value); |
| 505 |
} |
|
| 506 | ! |
output << "]"; |
| 507 | ! |
} break; |
| 508 |
} |
|
| 509 |
} |
|
| 510 |
} // namespace fims |
|
| 511 |
#endif |
| 1 |
/** |
|
| 2 |
* @file fims_modules.hpp |
|
| 3 |
* @brief Rcpp module definitions. Allows for the use of |
|
| 4 |
* methods::new() in R. |
|
| 5 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 6 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 7 |
* folder for reuse information. |
|
| 8 |
*/ |
|
| 9 |
#ifndef SRC_FIMS_MODULES_HPP |
|
| 10 |
#define SRC_FIMS_MODULES_HPP |
|
| 11 | ||
| 12 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_data.hpp" |
|
| 13 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_fleet.hpp" |
|
| 14 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_growth.hpp" |
|
| 15 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_math.hpp" |
|
| 16 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_maturity.hpp" |
|
| 17 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_natural_mortality.hpp" |
|
| 18 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_population.hpp" |
|
| 19 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_recruitment.hpp" |
|
| 20 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp" |
|
| 21 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_distribution.hpp" |
|
| 22 |
#include "../inst/include/interface/rcpp/rcpp_objects/rcpp_interface_base.hpp" |
|
| 23 |
#include "../inst/include/interface/rcpp/rcpp_interface.hpp" |
|
| 24 | ||
| 25 |
RCPP_EXPOSED_CLASS(Parameter) |
|
| 26 |
RCPP_EXPOSED_CLASS(ParameterVector) |
|
| 27 |
RCPP_EXPOSED_CLASS(RealVector) |
|
| 28 |
RCPP_EXPOSED_CLASS(SharedInt) |
|
| 29 |
RCPP_EXPOSED_CLASS(SharedString) |
|
| 30 |
RCPP_EXPOSED_CLASS(SharedReal) |
|
| 31 |
RCPP_EXPOSED_CLASS(SharedBoolean) |
|
| 32 | ||
| 33 |
/** |
|
| 34 |
* @brief The `fims` Rcpp module construct, providing declarative code of what |
|
| 35 |
* the module exposes to R. |
|
| 36 |
* |
|
| 37 |
* @details Each element included in the module should have a name, a pointer, |
|
| 38 |
* and a description separated by commas in that order. Both the name and the |
|
| 39 |
* description should be wrapped in quotes. The description is printed to the |
|
| 40 |
* screen when the R function `methods::show()` is used on the object. The |
|
| 41 |
* available description should exactly match the information found in the |
|
| 42 |
* brief tag where the function, class, etc. is documented. See the Rcpp |
|
| 43 |
* vignette for more information on documenting modules, particularly how to |
|
| 44 |
* include lists for parameters to a function. Each of the functions included |
|
| 45 |
* in this module should be exported by manually exporting them in |
|
| 46 |
* R/FIMS-package.R. |
|
| 47 |
* |
|
| 48 |
*/ |
|
| 49 | 18x |
RCPP_MODULE(fims) {
|
| 50 | 6x |
Rcpp::function( |
| 51 |
"CreateTMBModel", &CreateTMBModel, |
|
| 52 |
"Creates the TMB model object and adds interface objects to it."); |
|
| 53 | 6x |
Rcpp::function("set_fixed", &set_fixed_parameters,
|
| 54 |
"Sets the fixed parameters vector object."); |
|
| 55 | 6x |
Rcpp::function("get_fixed", &get_fixed_parameters_vector,
|
| 56 |
"Gets the fixed parameters vector object."); |
|
| 57 | 6x |
Rcpp::function("set_random", &set_random_parameters,
|
| 58 |
"Sets the random parameters vector object."); |
|
| 59 | 6x |
Rcpp::function("get_random", &get_random_parameters_vector,
|
| 60 |
"Gets the random parameters vector object."); |
|
| 61 | 6x |
Rcpp::function("get_parameter_names", &get_parameter_names,
|
| 62 |
"Gets the parameter names object."); |
|
| 63 | 6x |
Rcpp::function("get_random_names", &get_random_names,
|
| 64 |
"Gets the random effects names object."); |
|
| 65 | 6x |
Rcpp::function("clear", clear,
|
| 66 |
"Clears all pointers/references of a FIMS model."); |
|
| 67 | 6x |
Rcpp::function("get_log", get_log,
|
| 68 |
"Gets the log entries as a string in JSON format."); |
|
| 69 | 6x |
Rcpp::function( |
| 70 |
"get_log_errors", get_log_errors, |
|
| 71 |
"Gets the error entries from the log as a string in JSON format."); |
|
| 72 | 6x |
Rcpp::function( |
| 73 |
"get_log_warnings", get_log_warnings, |
|
| 74 |
"Gets the warning entries from the log as a string in JSON format."); |
|
| 75 | 6x |
Rcpp::function( |
| 76 |
"get_log_info", get_log_info, |
|
| 77 |
"Gets the info entries from the log as a string in JSON format."); |
|
| 78 | 6x |
Rcpp::function("get_log_module", get_log_module,
|
| 79 |
"Gets log entries by module as a string in JSON format."); |
|
| 80 | 6x |
Rcpp::function("write_log", write_log, "If true, writes the log on exit.");
|
| 81 | 6x |
Rcpp::function("set_log_path", set_log_path,
|
| 82 |
"Sets the path for the log file to be written to."); |
|
| 83 | 6x |
Rcpp::function( |
| 84 |
"init_logging", init_logging, |
|
| 85 |
"Initializes the logging system, setting all signal handling."); |
|
| 86 | 6x |
Rcpp::function( |
| 87 |
"set_log_throw_on_error", set_log_throw_on_error, |
|
| 88 |
"If true, throws a runtime exception when an error is logged."); |
|
| 89 | 6x |
Rcpp::function("log_info", log_info,
|
| 90 |
"Adds an info entry to the log from the R environment."); |
|
| 91 | 6x |
Rcpp::function("log_warning", log_warning,
|
| 92 |
"Adds a warning entry to the log from the R environment."); |
|
| 93 | 6x |
Rcpp::function("log_error", log_error,
|
| 94 |
"Adds a error entry to the log from the R environment."); |
|
| 95 | 6x |
Rcpp::function("logit", logit_rcpp,
|
| 96 |
"Applies the logit transformation: -log(b - x) + log(x - a)."); |
|
| 97 | 6x |
Rcpp::function( |
| 98 |
"inv_logit", inv_logit_rcpp, |
|
| 99 |
"Applies the inverse of the logit transformation to a bounded space."); |
|
| 100 | 12x |
Rcpp::class_<Parameter>( |
| 101 |
"Parameter", "An RcppInterface class that defines the Parameter class.") |
|
| 102 | 6x |
.constructor() |
| 103 | 6x |
.constructor<double>() |
| 104 | 6x |
.constructor<Parameter>() |
| 105 | 6x |
.field("value", &Parameter::initial_value_m,
|
| 106 |
"A numeric value specifying the initial value of the parameter.") |
|
| 107 | 6x |
.field("value", &Parameter::final_value_m,
|
| 108 |
"A numeric value specifying the final value of the parameter.") |
|
| 109 | 6x |
.field("min", &Parameter::min_m,
|
| 110 |
"A numeric value specifying the minimum possible parameter value, " |
|
| 111 |
"where the default is negative infinity.") |
|
| 112 | 6x |
.field("max", &Parameter::max_m,
|
| 113 |
"A numeric value specifying the maximum possible parameter value, " |
|
| 114 |
"where the default is positive infinity.") |
|
| 115 | 6x |
.field("id", &Parameter::id_m, "unique id for parameter class")
|
| 116 | 6x |
.field("estimation_type", &Parameter::estimation_type_m,
|
| 117 |
"A string that takes three arguments: constant, indicating a " |
|
| 118 |
"parameter is not estimated; fixed_effects, indicating a " |
|
| 119 |
"parameter is estimated; and random_effects, indicating a " |
|
| 120 |
"parameter is estimated; the default is constant."); |
|
| 121 | ||
| 122 | 12x |
Rcpp::class_<ParameterVector>( |
| 123 |
"ParameterVector", |
|
| 124 |
"An RcppInterface class that defines the ParameterVector class.") |
|
| 125 | 6x |
.constructor() |
| 126 | 6x |
.constructor<size_t>() |
| 127 | 6x |
.constructor<Rcpp::NumericVector, size_t>() |
| 128 | 6x |
.method("get", &ParameterVector::get,
|
| 129 |
"An internal accessor for calling a position of a " |
|
| 130 |
"ParameterVector from R.") |
|
| 131 | 6x |
.method("set", &ParameterVector::set,
|
| 132 |
"An internal setter for setting a position of a ParameterVector " |
|
| 133 |
"from R.") |
|
| 134 | 6x |
.method("show", &ParameterVector::show,
|
| 135 |
"The printing methods for a ParameterVector.") |
|
| 136 | 6x |
.method("at", &ParameterVector::at,
|
| 137 |
"Returns a Parameter at the indicated position given the index " |
|
| 138 |
"argument.") |
|
| 139 | 6x |
.method("size", &ParameterVector::size,
|
| 140 |
"Returns the size of a ParameterVector.") |
|
| 141 | 6x |
.method("resize", &ParameterVector::resize,
|
| 142 |
"Resizes a ParameterVector to the desired length.") |
|
| 143 | 6x |
.method("set_all_estimable", &ParameterVector::set_all_estimable,
|
| 144 |
"Sets all Parameters within a ParameterVector as estimable.") |
|
| 145 | 6x |
.method("set_all_random", &ParameterVector::set_all_random,
|
| 146 |
"Sets all Parameters within a ParameterVector as random effects.") |
|
| 147 | 6x |
.method("fill", &ParameterVector::fill,
|
| 148 |
"Sets the value of all Parameters in the ParameterVector to the " |
|
| 149 |
"provided value.") |
|
| 150 | 6x |
.method("get_id", &ParameterVector::get_id,
|
| 151 |
"Gets the ID of the ParameterVector object."); |
|
| 152 | 12x |
Rcpp::class_<RealVector>( |
| 153 |
"RealVector", "An RcppInterface class that defines the RealVector class.") |
|
| 154 | 6x |
.constructor() |
| 155 | 6x |
.constructor<size_t>() |
| 156 | 6x |
.constructor<Rcpp::NumericVector, size_t>() |
| 157 | 6x |
.method( |
| 158 |
"get", &RealVector::get, |
|
| 159 |
"An internal accessor for calling a position of a RealVector from R.") |
|
| 160 | 6x |
.method( |
| 161 |
"set", &RealVector::set, |
|
| 162 |
"An internal setter for setting a position of a RealVector from R.") |
|
| 163 | 6x |
.method("fromRVector", &RealVector::fromRVector,
|
| 164 |
"Initializes the RealVector from the values of a R vector.") |
|
| 165 | 6x |
.method("toRVector", &RealVector::toRVector,
|
| 166 |
"Returns values as a R vector.") |
|
| 167 | 6x |
.method("show", &RealVector::show,
|
| 168 |
"The printing methods for a RealVector.") |
|
| 169 | 6x |
.method("at", &RealVector::at,
|
| 170 |
"Returns a double at the indicated position given the index " |
|
| 171 |
"argument.") |
|
| 172 | 6x |
.method("size", &RealVector::size, "Returns the size of a RealVector.")
|
| 173 | 6x |
.method("resize", &RealVector::resize,
|
| 174 |
"Resizes a RealVector to the desired length.") |
|
| 175 | 6x |
.method("get_id", &RealVector::get_id,
|
| 176 |
"Gets the ID of the RealVector object."); |
|
| 177 | ||
| 178 | 12x |
Rcpp::class_<SharedInt>( |
| 179 |
"SharedInt", "An RcppInterface class that defines the SharedInt class.") |
|
| 180 | 6x |
.constructor() |
| 181 | 6x |
.constructor<int>() |
| 182 | 6x |
.method("get", &SharedInt::get)
|
| 183 | 6x |
.method("set", &SharedInt::set);
|
| 184 | ||
| 185 | 12x |
Rcpp::class_<SharedString>( |
| 186 |
"SharedString", |
|
| 187 |
"An RcppInterface class that defines the SharedString class.") |
|
| 188 | 6x |
.constructor() |
| 189 | 6x |
.constructor<std::string>() |
| 190 | 6x |
.method("get", &SharedString::get)
|
| 191 | 6x |
.method("set", &SharedString::set);
|
| 192 | ||
| 193 | 12x |
Rcpp::class_<SharedBoolean>( |
| 194 |
"SharedBoolean", |
|
| 195 |
"An RcppInterface class that defines the SharedBoolean class.") |
|
| 196 | 6x |
.constructor() |
| 197 | 6x |
.constructor<bool>() |
| 198 | 6x |
.method("get", &SharedBoolean::get)
|
| 199 | 6x |
.method("set", &SharedBoolean::set);
|
| 200 | ||
| 201 | 12x |
Rcpp::class_<SharedReal>( |
| 202 |
"SharedReal", "An RcppInterface class that defines the SharedReal class.") |
|
| 203 | 6x |
.constructor() |
| 204 | 6x |
.constructor<double>() |
| 205 | 6x |
.method("get", &SharedReal::get)
|
| 206 | 6x |
.method("set", &SharedReal::set);
|
| 207 | ||
| 208 | 12x |
Rcpp::class_<BevertonHoltRecruitmentInterface>("BevertonHoltRecruitment")
|
| 209 | 6x |
.constructor() |
| 210 | 6x |
.field("logit_steep", &BevertonHoltRecruitmentInterface::logit_steep)
|
| 211 | 6x |
.field("log_rzero", &BevertonHoltRecruitmentInterface::log_rzero)
|
| 212 | 6x |
.field("log_devs", &BevertonHoltRecruitmentInterface::log_devs)
|
| 213 | 6x |
.field("log_r", &BevertonHoltRecruitmentInterface::log_r,
|
| 214 |
"recruitment as a random effect on the natural log scale") |
|
| 215 | 6x |
.field("log_expected_recruitment",
|
| 216 |
&BevertonHoltRecruitmentInterface::log_expected_recruitment, |
|
| 217 |
"expected recruitment as a random effect on the natural log scale") |
|
| 218 | 6x |
.field("n_years", &BevertonHoltRecruitmentInterface::n_years,
|
| 219 |
"Number of years") |
|
| 220 | 6x |
.method("get_id", &BevertonHoltRecruitmentInterface::get_id)
|
| 221 | 6x |
.method("SetRecruitmentProcessID",
|
| 222 |
&BevertonHoltRecruitmentInterface::SetRecruitmentProcessID, |
|
| 223 |
"Set unique ID for recruitment process") |
|
| 224 | 6x |
.method("evaluate_mean",
|
| 225 |
&BevertonHoltRecruitmentInterface::evaluate_mean); |
|
| 226 | ||
| 227 | 12x |
Rcpp::class_<LogDevsRecruitmentInterface>("LogDevsRecruitmentProcess")
|
| 228 | 6x |
.constructor() |
| 229 | 6x |
.method("get_id", &LogDevsRecruitmentInterface::get_id)
|
| 230 | 6x |
.method("evaluate_process",
|
| 231 |
&LogDevsRecruitmentInterface::evaluate_process); |
|
| 232 | ||
| 233 | 12x |
Rcpp::class_<LogRRecruitmentInterface>("LogRRecruitmentProcess")
|
| 234 | 6x |
.constructor() |
| 235 | 6x |
.method("get_id", &LogRRecruitmentInterface::get_id)
|
| 236 | 6x |
.method("evaluate_process", &LogRRecruitmentInterface::evaluate_process);
|
| 237 | ||
| 238 | 12x |
Rcpp::class_<FleetInterface>("Fleet")
|
| 239 | 6x |
.constructor() |
| 240 | 6x |
.field("log_q", &FleetInterface::log_q)
|
| 241 | 6x |
.field("log_Fmort", &FleetInterface::log_Fmort)
|
| 242 | 6x |
.field("n_ages", &FleetInterface::n_ages)
|
| 243 | 6x |
.field("n_years", &FleetInterface::n_years)
|
| 244 | 6x |
.field("n_lengths", &FleetInterface::n_lengths)
|
| 245 | 6x |
.field("observed_landings_units",
|
| 246 |
&FleetInterface::observed_landings_units) |
|
| 247 | 6x |
.field("observed_index_units", &FleetInterface::observed_index_units)
|
| 248 | 6x |
.field("index_expected", &FleetInterface::derived_index_expected)
|
| 249 | 6x |
.field("landings_expected", &FleetInterface::derived_landings_expected)
|
| 250 | 6x |
.field("log_index_expected", &FleetInterface::log_index_expected)
|
| 251 | 6x |
.field("log_landings_expected", &FleetInterface::log_landings_expected)
|
| 252 | 6x |
.field("agecomp_expected", &FleetInterface::agecomp_expected)
|
| 253 | 6x |
.field("lengthcomp_expected", &FleetInterface::lengthcomp_expected)
|
| 254 | 6x |
.field("agecomp_proportion", &FleetInterface::agecomp_proportion)
|
| 255 | 6x |
.field("lengthcomp_proportion", &FleetInterface::lengthcomp_proportion)
|
| 256 | 6x |
.field("age_to_length_conversion",
|
| 257 |
&FleetInterface::age_to_length_conversion) |
|
| 258 | 6x |
.method("get_id", &FleetInterface::get_id)
|
| 259 | 6x |
.method("SetName", &FleetInterface::SetName)
|
| 260 | 6x |
.method("GetName", &FleetInterface::GetName)
|
| 261 | 6x |
.method("SetObservedAgeCompDataID",
|
| 262 |
&FleetInterface::SetObservedAgeCompDataID) |
|
| 263 | 6x |
.method("GetObservedAgeCompDataID",
|
| 264 |
&FleetInterface::GetObservedAgeCompDataID) |
|
| 265 | 6x |
.method("SetObservedLengthCompDataID",
|
| 266 |
&FleetInterface::SetObservedLengthCompDataID) |
|
| 267 | 6x |
.method("GetObservedLengthCompDataID",
|
| 268 |
&FleetInterface::GetObservedLengthCompDataID) |
|
| 269 | 6x |
.method("SetObservedIndexDataID", &FleetInterface::SetObservedIndexDataID)
|
| 270 | 6x |
.method("GetObservedIndexDataID", &FleetInterface::GetObservedIndexDataID)
|
| 271 | 6x |
.method("SetObservedLandingsDataID",
|
| 272 |
&FleetInterface::SetObservedLandingsDataID) |
|
| 273 | 6x |
.method("GetObservedLandingsDataID",
|
| 274 |
&FleetInterface::GetObservedLandingsDataID) |
|
| 275 | 6x |
.method("SetSelectivityID", &FleetInterface::SetSelectivityID);
|
| 276 | ||
| 277 | 12x |
Rcpp::class_<AgeCompDataInterface>("AgeComp")
|
| 278 | 6x |
.constructor<int, int>() |
| 279 | 6x |
.field("age_comp_data", &AgeCompDataInterface::age_comp_data)
|
| 280 | 6x |
.method("get_id", &AgeCompDataInterface::get_id);
|
| 281 | ||
| 282 | 12x |
Rcpp::class_<LengthCompDataInterface>("LengthComp")
|
| 283 | 6x |
.constructor<int, int>() |
| 284 | 6x |
.field("length_comp_data", &LengthCompDataInterface::length_comp_data)
|
| 285 | 6x |
.method("get_id", &LengthCompDataInterface::get_id);
|
| 286 | ||
| 287 | 12x |
Rcpp::class_<LandingsDataInterface>("Landings")
|
| 288 | 6x |
.constructor<int>() |
| 289 | 6x |
.field("landings_data", &LandingsDataInterface::landings_data)
|
| 290 | 6x |
.method("get_id", &LandingsDataInterface::get_id);
|
| 291 | ||
| 292 | 12x |
Rcpp::class_<IndexDataInterface>("Index")
|
| 293 | 6x |
.constructor<int>() |
| 294 | 6x |
.field("index_data", &IndexDataInterface::index_data)
|
| 295 | 6x |
.method("get_id", &IndexDataInterface::get_id);
|
| 296 | ||
| 297 | 12x |
Rcpp::class_<PopulationInterface>("Population")
|
| 298 | 6x |
.constructor() |
| 299 | 6x |
.method("get_id", &PopulationInterface::get_id, "get population ID")
|
| 300 | 6x |
.field("n_ages", &PopulationInterface::n_ages, "number of ages")
|
| 301 | 6x |
.field("n_fleets", &PopulationInterface::n_fleets, "number of fleets")
|
| 302 | 6x |
.field("n_years", &PopulationInterface::n_years, "number of years")
|
| 303 | 6x |
.field("n_lengths", &PopulationInterface::n_lengths, "number of lengths")
|
| 304 | 6x |
.field("log_M", &PopulationInterface::log_M,
|
| 305 |
"natural log of the natural mortality of the population") |
|
| 306 | 6x |
.field("log_init_naa", &PopulationInterface::log_init_naa,
|
| 307 |
"natural log of the initial numbers at age") |
|
| 308 | 6x |
.field("ages", &PopulationInterface::ages,
|
| 309 |
"vector of ages in the population; length n_ages") |
|
| 310 | 6x |
.method("SetMaturityID", &PopulationInterface::SetMaturityID,
|
| 311 |
"Set the unique id for the Maturity object") |
|
| 312 | 6x |
.method("SetGrowthID", &PopulationInterface::SetGrowthID,
|
| 313 |
"Set the unique id for the growth object") |
|
| 314 | 6x |
.method("SetRecruitmentID", &PopulationInterface::SetRecruitmentID,
|
| 315 |
"Set the unique id for the Recruitment object") |
|
| 316 | 6x |
.method("AddFleet", &PopulationInterface::AddFleet,
|
| 317 |
"Set a unique fleet id to the list of fleets operating on this " |
|
| 318 |
"population") |
|
| 319 | 6x |
.method("SetName", &PopulationInterface::SetName,
|
| 320 |
"Set the name of the population") |
|
| 321 | 6x |
.method("GetName", &PopulationInterface::GetName,
|
| 322 |
"Get the name of the population"); |
|
| 323 | ||
| 324 | 12x |
Rcpp::class_<LogisticMaturityInterface>("LogisticMaturity")
|
| 325 | 6x |
.constructor() |
| 326 | 6x |
.field("inflection_point", &LogisticMaturityInterface::inflection_point)
|
| 327 | 6x |
.field("slope", &LogisticMaturityInterface::slope)
|
| 328 | 6x |
.method("get_id", &LogisticMaturityInterface::get_id)
|
| 329 | 6x |
.method("evaluate", &LogisticMaturityInterface::evaluate);
|
| 330 | ||
| 331 | 12x |
Rcpp::class_<LogisticSelectivityInterface>("LogisticSelectivity")
|
| 332 | 6x |
.constructor() |
| 333 | 6x |
.field("inflection_point",
|
| 334 |
&LogisticSelectivityInterface::inflection_point) |
|
| 335 | 6x |
.field("slope", &LogisticSelectivityInterface::slope)
|
| 336 | 6x |
.method("get_id", &LogisticSelectivityInterface::get_id)
|
| 337 | 6x |
.method("evaluate", &LogisticSelectivityInterface::evaluate);
|
| 338 | ||
| 339 | 12x |
Rcpp::class_<DoubleLogisticSelectivityInterface>("DoubleLogisticSelectivity")
|
| 340 | 6x |
.constructor() |
| 341 | 6x |
.field("inflection_point_asc",
|
| 342 |
&DoubleLogisticSelectivityInterface::inflection_point_asc, |
|
| 343 |
"50 percent quantile of the value of the quantity of interest (x) " |
|
| 344 |
" on the ascending limb of the double logistic curve; e.g., age " |
|
| 345 |
"at which 50 percent of the fish are selected.") |
|
| 346 | 6x |
.field("slope_asc", &DoubleLogisticSelectivityInterface::slope_asc,
|
| 347 |
"Scalar multiplier of difference between quantity of interest " |
|
| 348 |
"value (x) and inflection_point on the ascending limb of the " |
|
| 349 |
"double logistic curve.") |
|
| 350 | 6x |
.field("inflection_point_desc",
|
| 351 |
&DoubleLogisticSelectivityInterface::inflection_point_desc, |
|
| 352 |
"50 percent quantile of the value of the quantity of interest (x) " |
|
| 353 |
"on the descending limb of the double logistic curve; e.g. age at " |
|
| 354 |
"which 50 percent of the fish are selected.") |
|
| 355 | 6x |
.field("slope_desc", &DoubleLogisticSelectivityInterface::slope_desc,
|
| 356 |
"Scalar multiplier of difference between quantity of interest " |
|
| 357 |
"value (x) and inflection_point on the descending limb of the " |
|
| 358 |
"double logistic curve.") |
|
| 359 | 6x |
.method("get_id", &DoubleLogisticSelectivityInterface::get_id,
|
| 360 |
"Returns a unique ID for the selectivity class.") |
|
| 361 | 6x |
.method("evaluate", &DoubleLogisticSelectivityInterface::evaluate,
|
| 362 |
"Evaluates the double logistic selectivity given input value " |
|
| 363 |
"(e.g., age or size in selectivity)."); |
|
| 364 | ||
| 365 | 12x |
Rcpp::class_<EWAAGrowthInterface>("EWAAGrowth")
|
| 366 | 6x |
.constructor() |
| 367 | 6x |
.field("ages", &EWAAGrowthInterface::ages, "Ages for each age class.")
|
| 368 | 6x |
.field("weights", &EWAAGrowthInterface::weights,
|
| 369 |
"Weights for each age class.") |
|
| 370 | 6x |
.method("get_id", &EWAAGrowthInterface::get_id)
|
| 371 | 6x |
.method("evaluate", &EWAAGrowthInterface::evaluate);
|
| 372 | ||
| 373 | 12x |
Rcpp::class_<DnormDistributionsInterface>("DnormDistribution")
|
| 374 | 6x |
.constructor() |
| 375 | 6x |
.method("get_id", &DnormDistributionsInterface::get_id,
|
| 376 |
"Returns a unique ID for the Dnorm distribution class.") |
|
| 377 | 6x |
.method("evaluate", &DnormDistributionsInterface::evaluate,
|
| 378 |
"Evaluates the normal distribution given input data and " |
|
| 379 |
"parameter values.") |
|
| 380 | 6x |
.method("set_observed_data",
|
| 381 |
&DnormDistributionsInterface::set_observed_data, |
|
| 382 |
"Accepts a unique ID for a given Data Object class to link the " |
|
| 383 |
"data with the distribution.") |
|
| 384 | 6x |
.method("set_distribution_links",
|
| 385 |
&DnormDistributionsInterface::set_distribution_links, |
|
| 386 |
"Accepts a unique ID for a given parameter to link the parameter " |
|
| 387 |
"with the distribution.") |
|
| 388 | 6x |
.field("x", &DnormDistributionsInterface::x,
|
| 389 |
"Input for distribution when not observations, e.g., prior or " |
|
| 390 |
"random effect.") |
|
| 391 | 6x |
.field("expected_values", &DnormDistributionsInterface::expected_values,
|
| 392 |
"Mean of the distribution.") |
|
| 393 | 6x |
.field("log_sd", &DnormDistributionsInterface::log_sd,
|
| 394 |
"The natural log of the standard deviation."); |
|
| 395 | ||
| 396 | 12x |
Rcpp::class_<DlnormDistributionsInterface>("DlnormDistribution")
|
| 397 | 6x |
.constructor() |
| 398 | 6x |
.method("get_id", &DlnormDistributionsInterface::get_id,
|
| 399 |
"Returns a unique ID for the Dnorm distribution class.") |
|
| 400 | 6x |
.method("evaluate", &DlnormDistributionsInterface::evaluate,
|
| 401 |
"Evaluates the normal distribution given input data and " |
|
| 402 |
"parameter values.") |
|
| 403 | 6x |
.method("set_observed_data",
|
| 404 |
&DlnormDistributionsInterface::set_observed_data, |
|
| 405 |
"Accepts a unique ID for a given Data Object class to link the " |
|
| 406 |
"data with the distribution.") |
|
| 407 | 6x |
.method("set_distribution_links",
|
| 408 |
&DlnormDistributionsInterface::set_distribution_links, |
|
| 409 |
"Accepts a unique ID for a given parameter to link the parameter " |
|
| 410 |
"with the distribution.") |
|
| 411 | 6x |
.field("x", &DlnormDistributionsInterface::x,
|
| 412 |
"Input for distribution when not observations, e.g., prior or " |
|
| 413 |
"random effect.") |
|
| 414 | 6x |
.field("expected_values", &DlnormDistributionsInterface::expected_values,
|
| 415 |
"Mean of the distribution on the natural log scale.") |
|
| 416 | 6x |
.field("log_sd", &DlnormDistributionsInterface::log_sd,
|
| 417 |
"The natural log of the standard deviation of the distribution on " |
|
| 418 |
"the natural log scale."); |
|
| 419 | ||
| 420 | 12x |
Rcpp::class_<DmultinomDistributionsInterface>("DmultinomDistribution")
|
| 421 | 6x |
.constructor() |
| 422 | 6x |
.method("get_id", &DmultinomDistributionsInterface::get_id,
|
| 423 |
"Returns a unique ID for the Dnorm distribution class.") |
|
| 424 | 6x |
.method("evaluate", &DmultinomDistributionsInterface::evaluate,
|
| 425 |
"Evaluates the normal distribution given input data and " |
|
| 426 |
"parameter values.") |
|
| 427 | 6x |
.method("set_observed_data",
|
| 428 |
&DmultinomDistributionsInterface::set_observed_data, |
|
| 429 |
"Accepts a unique ID for a given Data Object class to link the " |
|
| 430 |
"data with the distribution.") |
|
| 431 | 6x |
.method("set_distribution_links",
|
| 432 |
&DmultinomDistributionsInterface::set_distribution_links, |
|
| 433 |
"Accepts a unique ID for a given parameter to link the parameter " |
|
| 434 |
"with the distribution.") |
|
| 435 | 6x |
.method("set_note", &DmultinomDistributionsInterface::set_note)
|
| 436 | 6x |
.field("x", &DmultinomDistributionsInterface::x,
|
| 437 |
"Input for distribution when not observations, e.g., prior or " |
|
| 438 |
"random effect.") |
|
| 439 | 6x |
.field("expected_values",
|
| 440 |
&DmultinomDistributionsInterface::expected_values, |
|
| 441 |
"numeric non-negative vector of length K, specifying the " |
|
| 442 |
"probability for the K classes.") |
|
| 443 | 6x |
.field( |
| 444 |
"dims", &DmultinomDistributionsInterface::dims, |
|
| 445 |
"dimension of the multivariate input, e.g., c(num rows, num cols)."); |
|
| 446 | ||
| 447 | 12x |
Rcpp::class_<CatchAtAgeInterface>("CatchAtAge")
|
| 448 | 6x |
.constructor() |
| 449 | 6x |
.method("AddPopulation", &CatchAtAgeInterface::AddPopulation)
|
| 450 | 6x |
.method("get_output", &CatchAtAgeInterface::to_json)
|
| 451 | 6x |
.method("GetReport", &CatchAtAgeInterface::get_report)
|
| 452 | 6x |
.method("GetId", &CatchAtAgeInterface::get_id)
|
| 453 | 6x |
.method("DoReporting", &CatchAtAgeInterface::DoReporting)
|
| 454 | 6x |
.method("IsReporting", &CatchAtAgeInterface::IsReporting);
|
| 455 |
} |
|
| 456 | ||
| 457 |
#endif /* SRC_FIMS_MODULES_HPP */ |
| 1 | ||
| 2 |
#include <cmath> |
|
| 3 | ||
| 4 |
#include "../inst/include/interface/rcpp/rcpp_interface.hpp" |
|
| 5 |
#include "../inst/include/interface/interface.hpp" |
|
| 6 |
#include "init.hpp" |
|
| 7 |
#include "fims_modules.hpp" |
|
| 8 |
#include "../inst/include/common/model.hpp" |
|
| 9 | ||
| 10 |
/// @cond |
|
| 11 |
/** |
|
| 12 |
* @brief TMB objective function |
|
| 13 |
* |
|
| 14 |
* @return Returns a joint negative log likelihood |
|
| 15 |
*/ |
|
| 16 |
template<class Type> |
|
| 17 | 704x |
Type objective_function<Type>::operator()() {
|
| 18 | ||
| 19 | ||
| 20 | 704x |
PARAMETER_VECTOR(p); |
| 21 | 704x |
PARAMETER_VECTOR(re); |
| 22 | ||
| 23 |
// code below copied from ModularTMBExample/src/tmb_objective_function.cpp |
|
| 24 | ||
| 25 |
// get the singleton instance for Model Class |
|
| 26 | 704x |
std::shared_ptr<fims_model::Model<Type>> model = |
| 27 |
fims_model::Model<Type>::GetInstance(); |
|
| 28 |
// get the singleton instance for Information Class |
|
| 29 | 704x |
std::shared_ptr<fims_info::Information<Type>> information = |
| 30 |
fims_info::Information<Type>::GetInstance(); |
|
| 31 | ||
| 32 |
//update the fixed effects parameter values |
|
| 33 | 26924x |
for(size_t i =0; i < information->fixed_effects_parameters.size(); i++){
|
| 34 | 26220x |
*information->fixed_effects_parameters[i] = p[i]; |
| 35 |
} |
|
| 36 |
//update the random effects parameter values |
|
| 37 | 3604x |
for(size_t i =0; i < information->random_effects_parameters.size(); i++){
|
| 38 | 2900x |
*information->random_effects_parameters[i] = re[i]; |
| 39 |
} |
|
| 40 | 704x |
model -> of = this; |
| 41 | ||
| 42 |
//evaluate the model objective function value |
|
| 43 | 704x |
Type nll = model->Evaluate(); |
| 44 | ||
| 45 | 704x |
return nll; |
| 46 | ||
| 47 |
} |
|
| 48 |
/// @endcond |
| 1 |
/** |
|
| 2 |
* @file init.hpp |
|
| 3 |
* @brief An interface to dynamically load the functions. |
|
| 4 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 5 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 6 |
* folder for reuse information. |
|
| 7 |
*/ |
|
| 8 |
#ifndef SRC_INIT_HPP |
|
| 9 |
#define SRC_INIT_HPP |
|
| 10 |
#include <R_ext/Rdynload.h> |
|
| 11 |
#include <stdlib.h> |
|
| 12 | ||
| 13 |
extern "C" {
|
|
| 14 | ||
| 15 |
/** |
|
| 16 |
* @brief TODO: Handles the initialization of the fims rcpp module. |
|
| 17 |
* |
|
| 18 |
* @return SEXP |
|
| 19 |
*/ |
|
| 20 |
SEXP _rcpp_module_boot_fims(); |
|
| 21 | ||
| 22 |
/** |
|
| 23 |
* @brief Callback definition to load the FIMS module. |
|
| 24 |
*/ |
|
| 25 |
static const R_CallMethodDef CallEntries[] = {
|
|
| 26 |
TMB_CALLDEFS, |
|
| 27 |
{"_rcpp_module_boot_fims", (DL_FUNC)&_rcpp_module_boot_fims, 0},
|
|
| 28 |
{NULL, NULL, 0}};
|
|
| 29 | ||
| 30 |
/** |
|
| 31 |
* @brief FIMS shared object initializer. |
|
| 32 |
* @param dll TODO: provide a brief description. |
|
| 33 |
* |
|
| 34 |
*/ |
|
| 35 | 3x |
void R_init_FIMS(DllInfo *dll) {
|
| 36 | 3x |
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); |
| 37 | 3x |
R_useDynamicSymbols(dll, FALSE); |
| 38 |
#ifdef TMB_CCALLABLES |
|
| 39 | 3x |
TMB_CCALLABLES("FIMS");
|
| 40 |
#endif |
|
| 41 |
} |
|
| 42 |
} |
|
| 43 | ||
| 44 |
#endif // SRC_INIT_HPP |