| 1 |
# To remove the NOTE |
|
| 2 |
# no visible binding for global variable |
|
| 3 |
utils::globalVariables(c( |
|
| 4 |
"name", "timing", "value" |
|
| 5 |
)) |
|
| 6 | ||
| 7 |
# Developers: ---- |
|
| 8 | ||
| 9 |
# This file defines the parent class FIMSFrame and its potential children. The |
|
| 10 |
# class is an S4 class with accessors and validators but no setters. |
|
| 11 |
# |
|
| 12 |
# The top of this file contains the declaration of the FIMSFrame class, which |
|
| 13 |
# is the controller of everything. Then the function FIMSFrame() is how objects |
|
| 14 |
# of that class are created, i.e., the constructor, and how users will interact |
|
| 15 |
# with the class the most. When the returned object from that constructor are |
|
| 16 |
# changed, the call to methods::setClass() that defines the class must also be |
|
| 17 |
# changed. The remainder of the file is set up to help you easily augment this |
|
| 18 |
# class. Follow the step-by-step instructions in order or at least know that |
|
| 19 |
# the functions are present in this order: |
|
| 20 |
# |
|
| 21 |
# 1. Add or remove the slot of interest in the call to `methods::setClass()`, |
|
| 22 |
# e.g., if you are adding a new slot you must declare the slot and the type |
|
| 23 |
# of object that should be expected in that slot; to remove an object from |
|
| 24 |
# the FIMSFrame class you must remove the slot here. |
|
| 25 |
# 2. Add an accessor function, e.g., get_*(), to allow users to access the |
|
| 26 |
# object stored in the new slot; or, remove the accessor function if you |
|
| 27 |
# remove a slot. Some accessors are also available for data types, e.g., |
|
| 28 |
# model_*(), that provide vectorized data to use in a module. |
|
| 29 |
# 3. If we had setter functions for FIMSFrame, you would add or delete the |
|
| 30 |
# appropriate setter functions next but we do not. Instead, we want users to |
|
| 31 |
# re-run FIMSFrame() when they make any changes to their data, that way all |
|
| 32 |
# of the slots will be updated simultaneously. @nathanvaughan-NOAA mentioned |
|
| 33 |
# during Code club 2024-12-17 that this may be a problem for future use of |
|
| 34 |
# FIMSFrame objects, especially when doing MSE or simulation when there is a |
|
| 35 |
# large overhead in running FIMSFrame and you just want to change a small, |
|
| 36 |
# simple thing in your data and re-run the model. We will cross that bridge |
|
| 37 |
# later. @msupernaw also informed us about the ability to lock an R object |
|
| 38 |
# so it cannot be altered. See https://rdrr.io/r/base/bindenv.html. |
|
| 39 |
# 4. Augment the validator functions to ensure that users do not pass |
|
| 40 |
# incompatible information to FIMSFrame(). |
|
| 41 |
# 5. Augment FIMSFrame() to ensure that the slot is created if you are adding a |
|
| 42 |
# new object or remove the object from the returned object if you are |
|
| 43 |
# removing a slot. |
|
| 44 | ||
| 45 |
# TODO: ---- |
|
| 46 | ||
| 47 |
# TODO: make date_formats a local variable |
|
| 48 |
# TODO: document sorting of information in terms of alphabetized fleet order |
|
| 49 |
# TODO: test implement addition of -999 |
|
| 50 |
# TODO: validate that all length-age combinations exist in the conversion matrix |
|
| 51 | ||
| 52 |
# methods::setClass: ---- |
|
| 53 | ||
| 54 |
# Classes are not currently exported, and therefore, do not need documentation. |
|
| 55 |
# See the following link if we do want to document them in the future: |
|
| 56 |
# https://stackoverflow.com/questions/7368262/how-to-properly-document-s4-class-slots-using-roxygen2 |
|
| 57 | ||
| 58 |
methods::setClass( |
|
| 59 |
Class = "FIMSFrame", |
|
| 60 |
slots = c( |
|
| 61 |
data = "tbl_df", |
|
| 62 |
fleets = "character", |
|
| 63 |
n_years = "integer", |
|
| 64 |
ages = "numeric", |
|
| 65 |
n_ages = "integer", |
|
| 66 |
lengths = "numeric", |
|
| 67 |
n_lengths = "integer", |
|
| 68 |
start_year = "integer", |
|
| 69 |
end_year = "integer" |
|
| 70 |
) |
|
| 71 |
) |
|
| 72 | ||
| 73 |
# methods::setMethod: accessors ---- |
|
| 74 | ||
| 75 |
# Methods for accessing info in the slots using get_*() or model_*() |
|
| 76 | ||
| 77 |
#' Get a slot in a FIMSFrame object |
|
| 78 |
#' |
|
| 79 |
#' There is an accessor function for each slot in the S4 class `FIMSFrame`, |
|
| 80 |
#' where the function is named `get_*()` and the star can be replaced with the |
|
| 81 |
#' slot name, e.g., [get_data()]. These accessor functions are the preferred |
|
| 82 |
#' way to access objects stored in the available slots. |
|
| 83 |
#' |
|
| 84 |
#' @param x An object returned from [FIMSFrame()]. |
|
| 85 |
#' @name get_FIMSFrame |
|
| 86 |
#' @keywords FIMSFrame |
|
| 87 |
NULL |
|
| 88 | ||
| 89 |
#' @return |
|
| 90 |
#' [get_data()] returns a data frame of the class `tbl_df` containing data for |
|
| 91 |
#' a FIMS model in a long format. The tibble will potentially have the |
|
| 92 |
#' following columns depending if it fits to ages and lengths or just one of |
|
| 93 |
#' them: |
|
| 94 |
#' `r glue::glue_collapse(colnames(data_big), sep = ", ", last = ", and ")`. |
|
| 95 |
#' @export |
|
| 96 |
#' @rdname get_FIMSFrame |
|
| 97 |
#' @keywords FIMSFrame |
|
| 98 | 392x |
methods::setGeneric("get_data", function(x) standardGeneric("get_data"))
|
| 99 |
#' @rdname get_FIMSFrame |
|
| 100 |
#' @keywords FIMSFrame |
|
| 101 | 390x |
methods::setMethod("get_data", "FIMSFrame", function(x) x@data)
|
| 102 |
#' @rdname get_FIMSFrame |
|
| 103 |
#' @keywords FIMSFrame |
|
| 104 |
methods::setMethod( |
|
| 105 |
"get_data", |
|
| 106 |
"data.frame", |
|
| 107 | 2x |
function(x) FIMSFrame(x)@data |
| 108 |
) |
|
| 109 | ||
| 110 |
#' @return |
|
| 111 |
#' [get_fleets()] returns a vector of strings containing the fleet names. |
|
| 112 |
#' @export |
|
| 113 |
#' @rdname get_FIMSFrame |
|
| 114 |
#' @keywords FIMSFrame |
|
| 115 | 4x |
methods::setGeneric("get_fleets", function(x) standardGeneric("get_fleets"))
|
| 116 |
#' @rdname get_FIMSFrame |
|
| 117 |
#' @keywords FIMSFrame |
|
| 118 | 2x |
methods::setMethod("get_fleets", "FIMSFrame", function(x) x@fleets)
|
| 119 |
#' @rdname get_FIMSFrame |
|
| 120 |
#' @keywords FIMSFrame |
|
| 121 |
methods::setMethod( |
|
| 122 |
"get_fleets", |
|
| 123 |
"data.frame", |
|
| 124 | 2x |
function(x) FIMSFrame(x)@fleets |
| 125 |
) |
|
| 126 | ||
| 127 |
#' @return |
|
| 128 |
#' [get_n_fleets()] returns an integer specifying the number of fleets in the |
|
| 129 |
#' model, where fleets is inclusive of both fishing fleets and survey vessels. |
|
| 130 |
#' @export |
|
| 131 |
#' @rdname get_FIMSFrame |
|
| 132 |
#' @keywords FIMSFrame |
|
| 133 | 5x |
methods::setGeneric("get_n_fleets", function(x) standardGeneric("get_n_fleets"))
|
| 134 |
#' @rdname get_FIMSFrame |
|
| 135 |
#' @keywords FIMSFrame |
|
| 136 | 5x |
methods::setMethod("get_n_fleets", "FIMSFrame", function(x) length(x@fleets))
|
| 137 |
#' @rdname get_FIMSFrame |
|
| 138 |
#' @keywords FIMSFrame |
|
| 139 |
methods::setMethod( |
|
| 140 |
"get_n_fleets", |
|
| 141 |
"data.frame", |
|
| 142 | ! |
function(x) length(FIMSFrame(x)@fleets) |
| 143 |
) |
|
| 144 | ||
| 145 |
#' @return |
|
| 146 |
#' [get_n_years()] returns an integer specifying the number of years in the |
|
| 147 |
#' model. |
|
| 148 |
#' @export |
|
| 149 |
#' @rdname get_FIMSFrame |
|
| 150 |
#' @keywords FIMSFrame |
|
| 151 | 7782x |
methods::setGeneric("get_n_years", function(x) standardGeneric("get_n_years"))
|
| 152 |
#' @rdname get_FIMSFrame |
|
| 153 |
#' @keywords FIMSFrame |
|
| 154 | 7779x |
methods::setMethod("get_n_years", "FIMSFrame", function(x) x@n_years)
|
| 155 |
#' @rdname get_FIMSFrame |
|
| 156 |
#' @keywords FIMSFrame |
|
| 157 |
methods::setMethod( |
|
| 158 |
"get_n_years", |
|
| 159 |
"data.frame", |
|
| 160 | 3x |
function(x) FIMSFrame(x)@n_years |
| 161 |
) |
|
| 162 | ||
| 163 |
#' @return |
|
| 164 |
#' [get_start_year()] returns an integer specifying the start year of the |
|
| 165 |
#' model. |
|
| 166 |
#' @export |
|
| 167 |
#' @rdname get_FIMSFrame |
|
| 168 |
#' @keywords FIMSFrame |
|
| 169 |
methods::setGeneric( |
|
| 170 |
"get_start_year", |
|
| 171 | 34x |
function(x) standardGeneric("get_start_year")
|
| 172 |
) |
|
| 173 |
#' @rdname get_FIMSFrame |
|
| 174 |
#' @keywords FIMSFrame |
|
| 175 | 32x |
methods::setMethod("get_start_year", "FIMSFrame", function(x) x@start_year)
|
| 176 |
#' @rdname get_FIMSFrame |
|
| 177 |
#' @keywords FIMSFrame |
|
| 178 |
methods::setMethod( |
|
| 179 |
"get_start_year", |
|
| 180 |
"data.frame", |
|
| 181 | 2x |
function(x) FIMSFrame(x)@start_year |
| 182 |
) |
|
| 183 | ||
| 184 |
#' @return |
|
| 185 |
#' [get_end_year()] returns an integer specifying the end year of the |
|
| 186 |
#' model. |
|
| 187 |
#' @export |
|
| 188 |
#' @rdname get_FIMSFrame |
|
| 189 |
#' @keywords FIMSFrame |
|
| 190 | 34x |
methods::setGeneric("get_end_year", function(x) standardGeneric("get_end_year"))
|
| 191 |
#' @rdname get_FIMSFrame |
|
| 192 |
#' @keywords FIMSFrame |
|
| 193 | 32x |
methods::setMethod("get_end_year", "FIMSFrame", function(x) x@end_year)
|
| 194 |
#' @rdname get_FIMSFrame |
|
| 195 |
#' @keywords FIMSFrame |
|
| 196 |
methods::setMethod( |
|
| 197 |
"get_end_year", |
|
| 198 |
"data.frame", |
|
| 199 | 2x |
function(x) FIMSFrame(x)@end_year |
| 200 |
) |
|
| 201 | ||
| 202 |
#' @return |
|
| 203 |
#' [get_ages()] returns a vector of age bins used in the model. |
|
| 204 |
#' @export |
|
| 205 |
#' @rdname get_FIMSFrame |
|
| 206 |
#' @keywords FIMSFrame |
|
| 207 | 487x |
methods::setGeneric("get_ages", function(x) standardGeneric("get_ages"))
|
| 208 |
#' @rdname get_FIMSFrame |
|
| 209 |
#' @keywords FIMSFrame |
|
| 210 | 486x |
methods::setMethod("get_ages", "FIMSFrame", function(x) x@ages)
|
| 211 |
#' @rdname get_FIMSFrame |
|
| 212 |
#' @keywords FIMSFrame |
|
| 213 |
methods::setMethod( |
|
| 214 |
"get_ages", |
|
| 215 |
"data.frame", |
|
| 216 | 1x |
function(x) FIMSFrame(x)@ages |
| 217 |
) |
|
| 218 | ||
| 219 |
#' @return |
|
| 220 |
#' [get_n_ages()] returns an integer specifying the number of age bins used in |
|
| 221 |
#' the model. |
|
| 222 |
#' @export |
|
| 223 |
#' @rdname get_FIMSFrame |
|
| 224 |
#' @keywords FIMSFrame |
|
| 225 | 7646x |
methods::setGeneric("get_n_ages", function(x) standardGeneric("get_n_ages"))
|
| 226 |
#' @rdname get_FIMSFrame |
|
| 227 |
#' @keywords FIMSFrame |
|
| 228 | 7643x |
methods::setMethod("get_n_ages", "FIMSFrame", function(x) x@n_ages)
|
| 229 |
#' @rdname get_FIMSFrame |
|
| 230 |
#' @keywords FIMSFrame |
|
| 231 |
methods::setMethod( |
|
| 232 |
"get_n_ages", |
|
| 233 |
"data.frame", |
|
| 234 | 3x |
function(x) FIMSFrame(x)@n_ages |
| 235 |
) |
|
| 236 | ||
| 237 |
#' @return |
|
| 238 |
#' [get_lengths()] returns a vector of length bins used in the model. |
|
| 239 |
#' @export |
|
| 240 |
#' @rdname get_FIMSFrame |
|
| 241 |
#' @keywords FIMSFrame |
|
| 242 | ! |
methods::setGeneric("get_lengths", function(x) standardGeneric("get_lengths"))
|
| 243 |
#' @rdname get_FIMSFrame |
|
| 244 |
#' @keywords FIMSFrame |
|
| 245 | ! |
methods::setMethod("get_lengths", "FIMSFrame", function(x) x@lengths)
|
| 246 |
#' @rdname get_FIMSFrame |
|
| 247 |
#' @keywords FIMSFrame |
|
| 248 |
methods::setMethod( |
|
| 249 |
"get_lengths", |
|
| 250 |
"data.frame", |
|
| 251 | ! |
function(x) FIMSFrame(x)@lengths |
| 252 |
) |
|
| 253 | ||
| 254 |
#' @return |
|
| 255 |
#' [get_n_lengths()] returns an integer specifying the number of length bins |
|
| 256 |
#' used in the model. |
|
| 257 |
#' @export |
|
| 258 |
#' @rdname get_FIMSFrame |
|
| 259 |
#' @keywords FIMSFrame |
|
| 260 |
methods::setGeneric( |
|
| 261 |
"get_n_lengths", |
|
| 262 | 106x |
function(x) standardGeneric("get_n_lengths")
|
| 263 |
) |
|
| 264 |
#' @rdname get_FIMSFrame |
|
| 265 |
#' @keywords FIMSFrame |
|
| 266 | 106x |
methods::setMethod("get_n_lengths", "FIMSFrame", function(x) x@n_lengths)
|
| 267 |
#' @rdname get_FIMSFrame |
|
| 268 |
#' @keywords FIMSFrame |
|
| 269 |
methods::setMethod( |
|
| 270 |
"get_n_lengths", |
|
| 271 |
"data.frame", |
|
| 272 | ! |
function(x) FIMSFrame(x)@n_lengths |
| 273 |
) |
|
| 274 | ||
| 275 |
#' Get a vector of data to be passed to a FIMS module from a FIMSFrame object |
|
| 276 |
#' |
|
| 277 |
#' There is an accessor function for each data type needed to run a FIMS model. |
|
| 278 |
#' A FIMS model accepts vectors of data and thus each of the `model_*()` |
|
| 279 |
#' functions, where the star can be replaced with the data type separated by |
|
| 280 |
#' underscores, e.g., weight_at_age. These accessor functions are the preferred |
|
| 281 |
#' way to pass data to a FIMS module because the data will have the appropriate |
|
| 282 |
#' indexing. |
|
| 283 |
#' |
|
| 284 |
#' @details |
|
| 285 |
#' `Age_to_length_conversion` data, i.e., the proportion of age "a" that are |
|
| 286 |
#' length "l", are used to convert lengths (input data) to ages (modeled) as |
|
| 287 |
#' a way to fit length data without estimating growth. |
|
| 288 |
#' |
|
| 289 |
#' @inheritParams get_data |
|
| 290 |
#' @param fleet_name A string, or vector of strings, specifying the name of the |
|
| 291 |
#' fleet(s) of interest that you want landings data for. The strings must |
|
| 292 |
#' exactly match strings in the column `"name"` of `get_data(x)`. |
|
| 293 |
#' @return |
|
| 294 |
#' All of the `model_*()` functions return vectors of data. Currently, the |
|
| 295 |
#' order of the data is the same order as the data frame because no arranging |
|
| 296 |
#' is done in [FIMSFrame()] and the function just extracts the appropriate |
|
| 297 |
#' column. |
|
| 298 |
#' @name model_ |
|
| 299 |
#' @keywords FIMSFrame |
|
| 300 |
NULL |
|
| 301 | ||
| 302 |
#' @export |
|
| 303 |
#' @rdname model_ |
|
| 304 |
#' @keywords FIMSFrame |
|
| 305 |
methods::setGeneric( |
|
| 306 |
"model_landings", |
|
| 307 | 655x |
function(x, fleet_name) standardGeneric("model_landings")
|
| 308 |
) |
|
| 309 |
#' @rdname model_ |
|
| 310 |
#' @keywords FIMSFrame |
|
| 311 |
methods::setMethod( |
|
| 312 |
"model_landings", "FIMSFrame", |
|
| 313 |
function(x, fleet_name) {
|
|
| 314 | 654x |
dplyr::filter( |
| 315 | 654x |
.data = x@data, |
| 316 | 654x |
.data[["type"]] == "landings", |
| 317 | 654x |
.data[["name"]] %in% fleet_name |
| 318 |
) |> |
|
| 319 | 654x |
dplyr::pull(.data[["value"]]) |
| 320 |
} |
|
| 321 |
) |
|
| 322 |
#' @rdname model_ |
|
| 323 |
#' @keywords FIMSFrame |
|
| 324 |
methods::setMethod( |
|
| 325 |
"model_landings", |
|
| 326 |
"data.frame", |
|
| 327 | 1x |
function(x, fleet_name) model_landings(FIMSFrame(x), fleet_name) |
| 328 |
) |
|
| 329 | ||
| 330 |
#' @export |
|
| 331 |
#' @rdname model_ |
|
| 332 |
#' @keywords FIMSFrame |
|
| 333 |
methods::setGeneric( |
|
| 334 |
"model_index", |
|
| 335 | 595x |
function(x, fleet_name) standardGeneric("model_index")
|
| 336 |
) |
|
| 337 |
#' @rdname model_ |
|
| 338 |
#' @keywords FIMSFrame |
|
| 339 |
methods::setMethod( |
|
| 340 |
"model_index", "FIMSFrame", |
|
| 341 |
function(x, fleet_name) {
|
|
| 342 | 594x |
dplyr::filter( |
| 343 | 594x |
.data = x@data, |
| 344 | 594x |
.data[["type"]] == "index", |
| 345 | 594x |
.data[["name"]] %in% fleet_name |
| 346 |
) |> |
|
| 347 | 594x |
dplyr::pull(.data[["value"]]) |
| 348 |
} |
|
| 349 |
) |
|
| 350 |
#' @rdname model_ |
|
| 351 |
#' @keywords FIMSFrame |
|
| 352 |
methods::setMethod( |
|
| 353 |
"model_index", |
|
| 354 |
"data.frame", |
|
| 355 | 1x |
function(x, fleet_name) model_index(FIMSFrame(x), fleet_name) |
| 356 |
) |
|
| 357 | ||
| 358 |
#' @export |
|
| 359 |
#' @rdname model_ |
|
| 360 |
#' @keywords FIMSFrame |
|
| 361 |
methods::setGeneric( |
|
| 362 |
"model_age_comp", |
|
| 363 | 1482x |
function(x, fleet_name) standardGeneric("model_age_comp")
|
| 364 |
) |
|
| 365 |
#' @rdname model_ |
|
| 366 |
#' @keywords FIMSFrame |
|
| 367 |
methods::setMethod( |
|
| 368 |
"model_age_comp", "FIMSFrame", |
|
| 369 |
function(x, fleet_name) {
|
|
| 370 | 1480x |
dplyr::filter( |
| 371 | 1480x |
.data = x@data, |
| 372 | 1480x |
.data[["type"]] == "age_comp", |
| 373 | 1480x |
.data[["name"]] %in% fleet_name |
| 374 |
) |> |
|
| 375 | 1480x |
dplyr::pull(.data[["value"]]) |
| 376 |
} |
|
| 377 |
) |
|
| 378 |
#' @rdname model_ |
|
| 379 |
#' @keywords FIMSFrame |
|
| 380 |
methods::setMethod( |
|
| 381 |
"model_age_comp", |
|
| 382 |
"data.frame", |
|
| 383 | 2x |
function(x, fleet_name) model_age_comp(FIMSFrame(x), fleet_name) |
| 384 |
) |
|
| 385 | ||
| 386 |
#' @export |
|
| 387 |
#' @rdname model_ |
|
| 388 |
#' @keywords FIMSFrame |
|
| 389 |
methods::setGeneric( |
|
| 390 |
"model_length_comp", |
|
| 391 | 33x |
function(x, fleet_name) standardGeneric("model_length_comp")
|
| 392 |
) |
|
| 393 |
#' @rdname model_ |
|
| 394 |
#' @keywords FIMSFrame |
|
| 395 |
methods::setMethod( |
|
| 396 |
"model_length_comp", |
|
| 397 |
"FIMSFrame", |
|
| 398 |
function(x, fleet_name) {
|
|
| 399 | 32x |
conversion_data <- dplyr::filter( |
| 400 | 32x |
.data = x@data, |
| 401 | 32x |
.data[["type"]] == "age_to_length_conversion" |
| 402 |
) |
|
| 403 | 32x |
if (NROW(conversion_data) == 0) {
|
| 404 | ! |
cli::cli_abort(c( |
| 405 | ! |
"There are no {.var age_to_length_conversion} data present, therefore
|
| 406 | ! |
you cannot fit to {.var length_comp} data."
|
| 407 |
)) |
|
| 408 |
} |
|
| 409 | 32x |
dplyr::filter( |
| 410 | 32x |
.data = x@data, |
| 411 | 32x |
.data[["type"]] == "length_comp", |
| 412 | 32x |
.data[["name"]] %in% fleet_name |
| 413 |
) |> |
|
| 414 | 32x |
dplyr::pull(.data[["value"]]) |
| 415 |
} |
|
| 416 |
) |
|
| 417 |
#' @rdname model_ |
|
| 418 |
#' @keywords FIMSFrame |
|
| 419 |
methods::setMethod( |
|
| 420 |
"model_length_comp", |
|
| 421 |
"data.frame", |
|
| 422 | 1x |
function(x, fleet_name) model_length_comp(FIMSFrame(x), fleet_name) |
| 423 |
) |
|
| 424 | ||
| 425 |
#' @export |
|
| 426 |
#' @rdname model_ |
|
| 427 |
#' @keywords FIMSFrame |
|
| 428 |
methods::setGeneric( |
|
| 429 |
"model_weight_at_age", |
|
| 430 | 7444x |
function(x) standardGeneric("model_weight_at_age")
|
| 431 |
) |
|
| 432 |
#' @rdname model_ |
|
| 433 |
#' @keywords FIMSFrame |
|
| 434 |
methods::setMethod( |
|
| 435 |
"model_weight_at_age", |
|
| 436 |
"FIMSFrame", |
|
| 437 |
function(x) {
|
|
| 438 | 7443x |
model_data <- dplyr::filter( |
| 439 | 7443x |
.data = as.data.frame(x@data), |
| 440 | 7443x |
.data[["type"]] == "weight_at_age" |
| 441 |
) |
|
| 442 | 7443x |
if (NROW(model_data) == 0) {
|
| 443 | ! |
cli::cli_abort( |
| 444 | ! |
message = "No weight_at_age data found in FIMSFrame object." |
| 445 |
) |
|
| 446 |
} |
|
| 447 | 7443x |
fleet_names <- unique(model_data[["name"]]) |
| 448 | 7443x |
if (length(fleet_names) > 1) {
|
| 449 | ! |
cli::cli_warn(c( |
| 450 | ! |
"x" = "Multiple fleets found in weight_at_age data.", |
| 451 | ! |
"i" = "{.fn model_weight_at_age} will average values across fleets."
|
| 452 |
)) |
|
| 453 | ! |
model_data <- dplyr::group_by( |
| 454 | ! |
.data = model_data, |
| 455 | ! |
.data[["timing"]], |
| 456 | ! |
.data[["age"]] |
| 457 |
) |> |
|
| 458 | ! |
dplyr::mutate( |
| 459 | ! |
value = ifelse(.data[["value"]] == -999, NA, .data[["value"]]) |
| 460 |
) |> |
|
| 461 | ! |
dplyr::summarize( |
| 462 | ! |
value = mean(.data[["value"]], na.rm = TRUE) |
| 463 |
) |> |
|
| 464 | ! |
dplyr::mutate( |
| 465 | ! |
value = ifelse(is.nan(.data[["value"]]), -999, .data[["value"]]) |
| 466 |
) |
|
| 467 |
} |
|
| 468 |
# Create time-series vector if only available by age |
|
| 469 | 7443x |
n_rows <- NROW(dplyr::filter(model_data, value != -999)) |
| 470 | 7443x |
n_rows_needed <- get_n_ages(x) * (get_n_years(x) + 1) |
| 471 | 7443x |
if (n_rows < n_rows_needed) {
|
| 472 | ! |
if (n_rows == get_n_ages(x)) {
|
| 473 | ! |
model_data <- dplyr::bind_rows( |
| 474 | ! |
replicate( |
| 475 |
# Adds a year for terminal year + 1 because to calculate |
|
| 476 |
# spawning biomass after fishing in terminal year |
|
| 477 | ! |
get_n_years(x) + 1, |
| 478 | ! |
dplyr::filter(model_data, value != -999), |
| 479 | ! |
simplify = FALSE |
| 480 |
) |
|
| 481 |
) |
|
| 482 |
} else {
|
|
| 483 | ! |
cli::cli_abort( |
| 484 | ! |
"Too few rows of weight_at_age data found, you need at least |
| 485 | ! |
{n_rows_needed}, one for every year and age combination."
|
| 486 |
) |
|
| 487 |
} |
|
| 488 |
} |
|
| 489 | 7443x |
model_data |> |
| 490 | 7443x |
dplyr::pull(.data[["value"]]) |
| 491 |
} |
|
| 492 |
) |
|
| 493 |
#' @rdname model_ |
|
| 494 |
#' @keywords FIMSFrame |
|
| 495 |
methods::setMethod( |
|
| 496 |
"model_weight_at_age", |
|
| 497 |
"data.frame", |
|
| 498 |
function(x) {
|
|
| 499 | 1x |
model_weight_at_age(FIMSFrame(x)) |
| 500 |
} |
|
| 501 |
) |
|
| 502 | ||
| 503 |
#' @export |
|
| 504 |
#' @rdname model_ |
|
| 505 |
#' @keywords FIMSFrame |
|
| 506 |
methods::setGeneric( |
|
| 507 |
"model_age_to_length_conversion", |
|
| 508 | 33x |
function(x, fleet_name) standardGeneric("model_age_to_length_conversion")
|
| 509 |
) |
|
| 510 |
#' @rdname model_ |
|
| 511 |
#' @keywords FIMSFrame |
|
| 512 |
methods::setMethod( |
|
| 513 |
"model_age_to_length_conversion", |
|
| 514 |
"FIMSFrame", |
|
| 515 |
function(x, fleet_name) {
|
|
| 516 | 32x |
if ("length" %in% colnames(x@data)) {
|
| 517 | 32x |
if (!"age" %in% colnames(x@data)) {
|
| 518 | ! |
cli::cli_abort("The age column is not present in your data.")
|
| 519 |
} |
|
| 520 | 32x |
dplyr::filter( |
| 521 | 32x |
.data = as.data.frame(x@data), |
| 522 | 32x |
.data[["type"]] == "age_to_length_conversion", |
| 523 | 32x |
.data[["name"]] %in% fleet_name |
| 524 |
) |> |
|
| 525 | 32x |
dplyr::group_by(.data[["age"]], .data[["length"]]) |> |
| 526 | 32x |
dplyr::summarize( |
| 527 | 32x |
mean_value = mean(as.numeric(.data[["value"]]), na.rm = TRUE) |
| 528 |
) |> |
|
| 529 | 32x |
dplyr::pull(as.numeric(.data[["mean_value"]])) |
| 530 |
} else {
|
|
| 531 | ! |
cli::cli_abort( |
| 532 | ! |
"The length column is not present in your data." |
| 533 |
) |
|
| 534 |
} |
|
| 535 |
} |
|
| 536 |
) |
|
| 537 |
#' @rdname model_ |
|
| 538 |
#' @keywords FIMSFrame |
|
| 539 |
methods::setMethod( |
|
| 540 |
"model_age_to_length_conversion", |
|
| 541 |
"data.frame", |
|
| 542 | 1x |
function(x, fleet_name) model_age_to_length_conversion( |
| 543 | 1x |
FIMSFrame(x), |
| 544 | 1x |
fleet_name |
| 545 |
) |
|
| 546 |
) |
|
| 547 | ||
| 548 |
# methods::setMethod: initialize ---- |
|
| 549 | ||
| 550 |
# Not currently using methods::setMethod(f = "initialize") |
|
| 551 |
# because @kellijohnson-NOAA did not quite understand how they actually work. |
|
| 552 | ||
| 553 |
# methods::setMethod: plot ---- |
|
| 554 |
#' Plot a `FIMSFrame` object |
|
| 555 |
#' |
|
| 556 |
#' Use `ggplot2::geom_point()` to plot the information stored in the data slot |
|
| 557 |
#' of the `FIMSFrame` class. |
|
| 558 |
#' |
|
| 559 |
#' @param x A `FIMSFrame` object. |
|
| 560 |
#' @param y Unused (inherited from R base). |
|
| 561 |
#' @param ... Unused (inherited from R base). |
|
| 562 |
#' |
|
| 563 |
#' @return |
|
| 564 |
#' A \pkg{ggplot2} object is returned that uses [stockplotr::theme_noaa()].
|
|
| 565 |
#' There will be one panel per input type with fleet-specific information |
|
| 566 |
#' denoted using colors. |
|
| 567 |
#' @examples |
|
| 568 |
#' \dontrun{
|
|
| 569 |
#' data("data_big", package = "FIMS")
|
|
| 570 |
#' data_4_model <- FIMSFrame(data_big) |
|
| 571 |
#' plot(data_4_model) |
|
| 572 |
#' } |
|
| 573 |
#' |
|
| 574 |
#' @export |
|
| 575 |
#' @method plot FIMSFrame |
|
| 576 |
#' @rdname plot |
|
| 577 |
#' @aliases plot,FIMSFrame,missing-method |
|
| 578 |
#' @exportMethod plot |
|
| 579 |
setGeneric("plot", function(x, y, ...)
|
|
| 580 |
standardGeneric("plot")
|
|
| 581 |
) |
|
| 582 |
methods::setMethod( |
|
| 583 |
f = "plot", |
|
| 584 |
signature = c(x = "FIMSFrame", y = "missing"), |
|
| 585 |
definition = function(x, y, ...) {
|
|
| 586 | 1x |
data_for_plot <- get_data(x) |> |
| 587 | 1x |
dplyr::mutate( |
| 588 | 1x |
type = gsub("_", " ", type)
|
| 589 |
) |
|
| 590 | 1x |
ggplot2::ggplot( |
| 591 | 1x |
data = data_for_plot, |
| 592 | 1x |
mapping = ggplot2::aes( |
| 593 | 1x |
x = timing, |
| 594 | 1x |
y = value, |
| 595 | 1x |
col = name |
| 596 |
) |
|
| 597 |
) + |
|
| 598 |
# Using Set3 b/c it is the palette with the largest number of colors |
|
| 599 |
# and not {nmfspalette} b/c didn't want to depend on GitHub package
|
|
| 600 | 1x |
ggplot2::scale_color_brewer(palette = "Set3") + |
| 601 | 1x |
ggplot2::facet_wrap( |
| 602 | 1x |
"type", |
| 603 | 1x |
scales = "free_y", |
| 604 | 1x |
labeller = ggplot2::label_wrap_gen(width = 10) |
| 605 |
) + |
|
| 606 | 1x |
ggplot2::geom_point(alpha = 0.8) + |
| 607 | 1x |
ggplot2::xlab("Timing") +
|
| 608 | 1x |
ggplot2::ylab("Value") +
|
| 609 | 1x |
ggplot2::theme( |
| 610 | 1x |
axis.text.x = ggplot2::element_text(angle = 15) |
| 611 |
) + |
|
| 612 | 1x |
stockplotr::theme_noaa() |
| 613 |
} |
|
| 614 |
) |
|
| 615 | ||
| 616 |
# methods::setMethod: show ---- |
|
| 617 | ||
| 618 |
methods::setMethod( |
|
| 619 |
f = "show", |
|
| 620 |
signature = "FIMSFrame", |
|
| 621 |
definition = function(object) {
|
|
| 622 | 1x |
message("tbl_df of class '", class(object), "'")
|
| 623 | 1x |
dat_types <- unique(object@data[[which(colnames(object@data) == "type")]]) |
| 624 | 1x |
message("with the following 'types': ", paste0(dat_types, collapse = ", "))
|
| 625 | 1x |
snames <- slotNames(object) |
| 626 | 1x |
ordinnames <- !snames %in% c( |
| 627 | 1x |
"data", |
| 628 | 1x |
".S3Class", |
| 629 | 1x |
"row.names", |
| 630 | 1x |
"names" |
| 631 |
) |
|
| 632 | 1x |
print(utils::head(object@data)) |
| 633 | 1x |
cat("additional slots include the following:")
|
| 634 | 1x |
for (nm in snames[ordinnames]) {
|
| 635 | 8x |
cat(nm, ":\n", sep = "") |
| 636 | 8x |
print(slot(object, nm)) |
| 637 |
} |
|
| 638 |
} |
|
| 639 |
) |
|
| 640 | ||
| 641 |
is.FIMSFrame <- function(x) {
|
|
| 642 | 2x |
inherits(x, "FIMSFrame") |
| 643 |
} |
|
| 644 | ||
| 645 |
# methods::setValidity ---- |
|
| 646 | ||
| 647 |
methods::setValidity( |
|
| 648 |
Class = "FIMSFrame", |
|
| 649 |
method = function(object) {
|
|
| 650 |
errors <- character() |
|
| 651 | ||
| 652 |
if (NROW(object@data) == 0) {
|
|
| 653 |
errors <- c(errors, "data must have at least one row") |
|
| 654 |
} |
|
| 655 | ||
| 656 |
# FIMS models currently cannot run without weight_at_age data |
|
| 657 |
weight_at_age_data <- dplyr::filter(object@data, type == "weight_at_age") |
|
| 658 |
if (NROW(weight_at_age_data) == 0) {
|
|
| 659 |
errors <- c(errors, "data must contain data of the type weight_at_age") |
|
| 660 |
} |
|
| 661 | ||
| 662 |
errors <- c(errors, validate_data_colnames(object@data)) |
|
| 663 | ||
| 664 |
# Check the format for acceptable variants of the ideal numeric |
|
| 665 |
if (!all(is.numeric(object@data[["timing"]]))) {
|
|
| 666 |
errors <- c(errors, "timing must be in numeric format") |
|
| 667 |
} |
|
| 668 |
if (!all(as.integer(object@data[["timing"]]) - |
|
| 669 |
object@data[["timing"]] == 0)) {
|
|
| 670 |
errors <- c(errors, "timing can only handle years right now") |
|
| 671 |
} |
|
| 672 | ||
| 673 |
# TODO: Add checks for other slots |
|
| 674 |
# Add validity check for types |
|
| 675 |
present_types <- unique(object@data[["type"]]) |
|
| 676 | ||
| 677 |
# Issues warning if there are any unrecognized types |
|
| 678 |
unknown_types <- sort(setdiff(present_types, fims_input_types)) |
|
| 679 |
if (length(unknown_types) > 0) {
|
|
| 680 |
cli::cli_warn(c( |
|
| 681 |
"!" = "Data contains unexpected type(s): {unknown_types}",
|
|
| 682 |
"i" = "Allowed types are: {fims_input_types}",
|
|
| 683 |
"i" = "Model will run but check that data types are correct." |
|
| 684 |
)) |
|
| 685 |
} |
|
| 686 | ||
| 687 |
# Ensure composition data sum to 1.0 per group if units are proportions |
|
| 688 |
for (present_type in grep("_comp", present_types, value = TRUE)) {
|
|
| 689 |
test <- object@data |> |
|
| 690 |
dplyr::filter(type == present_type, value != -999) |> |
|
| 691 |
dplyr::group_by(name, timing, .drop = FALSE) |> |
|
| 692 |
dplyr::group_map(.keep = TRUE, \(.x, .y) {
|
|
| 693 |
validate_composition_data(.x) |
|
| 694 |
}) |
|
| 695 |
if (sum(unlist(test)) > 0) {
|
|
| 696 |
cli::cli_abort( |
|
| 697 |
"The above errors were found in your {present_type}."
|
|
| 698 |
) |
|
| 699 |
} |
|
| 700 |
} |
|
| 701 |
} |
|
| 702 |
) |
|
| 703 | ||
| 704 |
validate_data_colnames <- function(data) {
|
|
| 705 | 95x |
the_column_names <- colnames(data) |
| 706 | 95x |
errors <- character() |
| 707 | 95x |
if (!"type" %in% the_column_names) {
|
| 708 | 1x |
errors <- c(errors, "data must contain 'type'") |
| 709 |
} |
|
| 710 | 95x |
if (!"name" %in% the_column_names) {
|
| 711 | 1x |
errors <- c(errors, "data must contain 'name'") |
| 712 |
} |
|
| 713 | 95x |
if (!"timing" %in% the_column_names) {
|
| 714 | 1x |
errors <- c(errors, "data must contain 'timing'") |
| 715 |
} |
|
| 716 | 95x |
if (!"value" %in% the_column_names) {
|
| 717 | 1x |
errors <- c(errors, "data must contain 'value'") |
| 718 |
} |
|
| 719 | 95x |
if (!"unit" %in% the_column_names) {
|
| 720 | 1x |
errors <- c(errors, "data must contain 'unit'") |
| 721 |
} |
|
| 722 | 95x |
if (!any(c("age", "length") %in% the_column_names)) {
|
| 723 | 1x |
errors <- c(errors, "data must contain 'ages' and/or 'lengths'") |
| 724 |
} |
|
| 725 | 95x |
return(errors) |
| 726 |
} |
|
| 727 | ||
| 728 |
validate_composition_data <- function(data) {
|
|
| 729 | 4737x |
composition_type <- pretty_type(unique(data[["type"]])) |
| 730 | 4737x |
if (all(data[["value"]] == -999)) {
|
| 731 | ! |
return(0) |
| 732 |
} |
|
| 733 | 4737x |
groupings <- names(data)[ |
| 734 | 4737x |
sapply( |
| 735 | 4737x |
data, |
| 736 | 4737x |
function(x) dplyr::n_distinct(x, na.rm = FALSE) == 1 & !all(is.na(x))) |
| 737 |
] |
|
| 738 | 4737x |
grouping_message <- glue::glue("{groupings} = {data[1, groupings]}")
|
| 739 | 4737x |
names(grouping_message) <- rep("*", length(grouping_message))
|
| 740 | 4737x |
units <- unique(data[["unit"]]) |
| 741 | 4737x |
errors <- vector() |
| 742 | 4737x |
if (length(units) != 1) {
|
| 743 | ! |
errors <- c( |
| 744 | ! |
errors, |
| 745 | ! |
"x" = "There should only be one unit per grouping, units are {units}."
|
| 746 |
) |
|
| 747 |
} |
|
| 748 | 4737x |
sum_of_value <- sum(data[["value"]]) |
| 749 | 4737x |
if (all(units == "proportion") && abs(sum_of_value - 1.0) > 1e-8) {
|
| 750 | 120x |
errors <- c( |
| 751 | 120x |
errors, |
| 752 | 120x |
"x" = "The sum is equal to {sum_of_value}, not 1.0."
|
| 753 |
) |
|
| 754 |
} |
|
| 755 | 4737x |
if (length(errors) > 0) {
|
| 756 | 120x |
cli::cli_bullets(c( |
| 757 | 120x |
" " = "Group-level information for {composition_type} errors",
|
| 758 | 120x |
grouping_message, |
| 759 | 120x |
"!" = "Errors are as follows:", |
| 760 | 120x |
errors |
| 761 |
)) |
|
| 762 | 120x |
return(1) |
| 763 |
} else {
|
|
| 764 | 4617x |
return(0) |
| 765 |
} |
|
| 766 |
} |
|
| 767 | ||
| 768 |
# Constructors ---- |
|
| 769 | ||
| 770 |
# All constructors in this file are documented in 1 roxygen file via @rdname. |
|
| 771 | ||
| 772 |
#' Class constructors for `FIMSFrame` and associated child classes |
|
| 773 |
#' |
|
| 774 |
#' All constructor functions take a single input and build an object specific |
|
| 775 |
#' to the needs of each model type within \pkg{FIMS}. `FIMSFrame` is the parent
|
|
| 776 |
#' class. Future, associated child classes will have the additional slots |
|
| 777 |
#' needed for different types of models. |
|
| 778 |
#' |
|
| 779 |
#' @details |
|
| 780 |
#' ## data |
|
| 781 |
#' The input data are both sorted and expanded before returning them in the |
|
| 782 |
#' data slot. |
|
| 783 |
#' ### Sorting |
|
| 784 |
#' It is important that the order of the rows in the data are correct but it is |
|
| 785 |
#' not expected that the user will do this. Instead, the returned data are |
|
| 786 |
#' sorted using [dplyr::arrange()] before placing them in the data slot. Data |
|
| 787 |
#' are first sorted by data type, placing all `weight_at_age` data next to |
|
| 788 |
#' other `weight_at_age` data and all landings data next to landings data. |
|
| 789 |
#' Thus, `age_comp` data will come first because their type is "age" and "a" is |
|
| 790 |
#' first in the alphabet. All other types will follow according to their order |
|
| 791 |
#' in the alphabet. |
|
| 792 |
#' Next, within each type, data are organized by fleet. So, `age_comp` |
|
| 793 |
#' information for fleet1 will come before survey1. Next, all data within type |
|
| 794 |
#' and fleet are arranged by timing, e.g., by year. That is the end of the |
|
| 795 |
#' sorting for time series data like landings and indices. The biological data |
|
| 796 |
#' are further sorted by bin. Thus, `age_comp` information will be arranged as |
|
| 797 |
#' follows: |
|
| 798 |
#' |
|
| 799 |
#' | type | name | timing | age | value | |
|
| 800 |
#' |:-------- |:--------:|:-------:|:----:|-------:| |
|
| 801 |
#' | age_comp | fleet1 | 2022 | 1 | 0.3 | |
|
| 802 |
#' | age_comp | fleet1 | 2022 | 2 | 0.7 | |
|
| 803 |
#' | age_comp | fleet1 | 2023 | 1 | 0.5 | |
|
| 804 |
#' |
|
| 805 |
#' `length_comp` data are sorted the same way but by length bin instead of |
|
| 806 |
#' by age bin. It becomes more complicated for the `age_to_length_conversion` |
|
| 807 |
#' data, which are sorted by type, name, timing, age, and then length. So, a |
|
| 808 |
#' full set of length, e.g., length 10, length 20, length 30, etc., is placed |
|
| 809 |
#' together for a given age. After that age, another entire set of length |
|
| 810 |
#' information will be provided for that next age. Once the year is complete |
|
| 811 |
#' for a given fleet then the next year will begin. |
|
| 812 |
#' |
|
| 813 |
#' @rdname FIMSFrame |
|
| 814 |
#' |
|
| 815 |
#' @param data A `data.frame` that contains the necessary columns to construct |
|
| 816 |
#' a `FIMSFrame-class` object. Currently, those columns are |
|
| 817 |
#' `r glue::glue_collapse(colnames(data_big), sep = ", ", last = ", and ")`. |
|
| 818 |
#' See the `data_big` object in FIMS, e.g., `data(data_big, package = "FIMS")`. |
|
| 819 |
#' |
|
| 820 |
#' @return |
|
| 821 |
#' An object of the S4 class `FIMSFrame` class, or one of its child classes, is |
|
| 822 |
#' validated and then returned. All objects will at a minimum have a slot |
|
| 823 |
#' called `data` to store the input data frame. Additional slots are dependent |
|
| 824 |
#' on the child class. Use [methods::showClass()] to see all available slots. |
|
| 825 |
#' @export |
|
| 826 |
#' @keywords FIMSFrame |
|
| 827 |
FIMSFrame <- function(data) {
|
|
| 828 | 50x |
errors <- validate_data_colnames(data) |
| 829 | 50x |
if (length(errors) > 0) {
|
| 830 | 1x |
stop( |
| 831 | 1x |
"Check the columns of your data, the following are missing:\n", |
| 832 | 1x |
paste(errors, sep = "\n", collapse = "\n") |
| 833 |
) |
|
| 834 |
} |
|
| 835 | 49x |
if (NROW(data) == 0) {
|
| 836 | 1x |
cli::cli_abort( |
| 837 | 1x |
"{.var data} has 0 rows of data and cannot be used to make a FIMSFrame."
|
| 838 |
) |
|
| 839 |
} |
|
| 840 | ||
| 841 |
# Get the earliest and latest year formatted as integers |
|
| 842 | 48x |
data_to_use_4_timing <- dplyr::filter( |
| 843 | 48x |
data, |
| 844 | 48x |
type != "weight_at_age" |
| 845 |
) |> |
|
| 846 | 48x |
dplyr::pull(timing) |
| 847 | 48x |
start_year <- as.integer(floor(min(data_to_use_4_timing, na.rm = TRUE))) |
| 848 | 48x |
end_year <- as.integer(floor(max(data_to_use_4_timing, na.rm = TRUE))) |
| 849 | 48x |
n_years <- as.integer(end_year - start_year + 1) |
| 850 | 48x |
years <- start_year:end_year |
| 851 | ||
| 852 |
# Get the fleets represented in the data |
|
| 853 | 48x |
fleets <- unique(data[["name"]]) |
| 854 | 48x |
n_fleets <- length(fleets) |
| 855 | ||
| 856 | 48x |
if ("age" %in% colnames(data)) {
|
| 857 | 46x |
if (all(is.na(data[["age"]]))) {
|
| 858 | 1x |
cli::cli_abort( |
| 859 | 1x |
message = "The `age` column exists in `data` but they are all `NA`." |
| 860 |
) |
|
| 861 |
} else {
|
|
| 862 |
# Forced to use annual age bins because the model has an annual time step |
|
| 863 |
# FUTURE: allow for different age bins rather than 1 year increment |
|
| 864 | 45x |
ages <- min(data[["age"]], na.rm = TRUE):max(data[["age"]], na.rm = TRUE) |
| 865 |
} |
|
| 866 |
} else {
|
|
| 867 | 2x |
ages <- numeric() |
| 868 |
} |
|
| 869 | 47x |
n_ages <- length(ages) |
| 870 | ||
| 871 | 47x |
if ("length" %in% colnames(data)) {
|
| 872 | 42x |
if (all(is.na(data[["length"]]))) {
|
| 873 | ! |
lengths <- numeric() |
| 874 |
} else {
|
|
| 875 | 42x |
lengths <- sort(unique(data[["length"]])) |
| 876 | 42x |
lengths <- lengths[!is.na(lengths)] |
| 877 |
} |
|
| 878 |
} else {
|
|
| 879 | 5x |
lengths <- numeric() |
| 880 |
} |
|
| 881 | 47x |
n_lengths <- length(lengths) |
| 882 | ||
| 883 |
# Work on filling in missing data with -999 and arrange in the correct |
|
| 884 |
# order so that getting information out with model_*() are correct. |
|
| 885 | 47x |
formatted_data <- tibble::as_tibble(data) |
| 886 | 47x |
missing_time_series <- create_missing_data( |
| 887 | 47x |
data = formatted_data, |
| 888 | 47x |
timings = years |
| 889 |
) |
|
| 890 | 47x |
if ("age" %in% colnames(formatted_data)) {
|
| 891 | 45x |
missing_ages <- create_missing_data( |
| 892 | 45x |
data = formatted_data, |
| 893 | 45x |
bins = ages, |
| 894 | 45x |
timings = years, |
| 895 | 45x |
column = age, |
| 896 | 45x |
types = c("weight_at_age", "age_comp")
|
| 897 |
) |
|
| 898 |
} else {
|
|
| 899 | 2x |
missing_ages <- missing_time_series[0, ] |
| 900 |
} |
|
| 901 | 47x |
if ("length" %in% colnames(formatted_data)) {
|
| 902 | 42x |
missing_lengths <- create_missing_data( |
| 903 | 42x |
data = formatted_data, |
| 904 | 42x |
bins = lengths, |
| 905 | 42x |
timings = years, |
| 906 | 42x |
column = length, |
| 907 | 42x |
types = "length_comp" |
| 908 |
) |
|
| 909 |
} else {
|
|
| 910 | 5x |
missing_lengths <- missing_time_series[0, ] |
| 911 |
} |
|
| 912 | 47x |
if ("age_to_length_conversion" %in% formatted_data[["type"]]) {
|
| 913 | 42x |
if (!"age" %in% colnames(data)) {
|
| 914 | 1x |
cli::cli_abort( |
| 915 | 1x |
"age is a required column if you have age_to_length_conversion data." |
| 916 |
) |
|
| 917 |
} |
|
| 918 | 41x |
if (!"length" %in% colnames(data)) {
|
| 919 | 1x |
cli::cli_abort( |
| 920 | 1x |
"length is a required column if you have age_to_length_conversion data." |
| 921 |
) |
|
| 922 |
} |
|
| 923 |
# Must do this by hand because it is across two dimensions |
|
| 924 | 40x |
temp_age_to_length_data <- formatted_data |> |
| 925 | 40x |
dplyr::group_by(type, name) |
| 926 | 40x |
missing_age_to_length <- temp_age_to_length_data |> |
| 927 | 40x |
dplyr::group_by(type, name) |> |
| 928 | 40x |
dplyr::filter(type %in% "age_to_length_conversion") |> |
| 929 | 40x |
tidyr::expand(unit, timing = years, age = ages, length = lengths) |> |
| 930 | 40x |
dplyr::anti_join( |
| 931 | 40x |
y = dplyr::select( |
| 932 | 40x |
temp_age_to_length_data, |
| 933 | 40x |
type, name, unit, timing, age, length |
| 934 |
), |
|
| 935 | 40x |
by = dplyr::join_by(type, name, unit, timing, age, length) |
| 936 |
) |> |
|
| 937 | 40x |
dplyr::mutate( |
| 938 | 40x |
value = 0 |
| 939 |
) |> |
|
| 940 | 40x |
dplyr::ungroup() |
| 941 |
} else {
|
|
| 942 | 5x |
missing_age_to_length <- missing_time_series[0, ] |
| 943 |
} |
|
| 944 | 45x |
missing_data <- dplyr::bind_rows( |
| 945 | 45x |
missing_time_series, |
| 946 | 45x |
missing_ages, |
| 947 | 45x |
missing_lengths, |
| 948 | 45x |
missing_age_to_length |
| 949 |
) |
|
| 950 | 45x |
sort_order <- intersect( |
| 951 | 45x |
c("name", "type", "timing", "age", "length"),
|
| 952 | 45x |
colnames(formatted_data) |
| 953 |
) |
|
| 954 | 45x |
complete_data <- dplyr::full_join( |
| 955 | 45x |
formatted_data, |
| 956 | 45x |
missing_data, |
| 957 | 45x |
by = colnames(missing_data) |
| 958 |
) |> |
|
| 959 | 45x |
dplyr::arrange(!!!rlang::parse_exprs(sort_order)) |
| 960 | ||
| 961 |
# Fill the empty data frames with data extracted from the data file |
|
| 962 | 45x |
out <- methods::new("FIMSFrame",
|
| 963 | 45x |
data = complete_data, |
| 964 | 45x |
fleets = fleets, |
| 965 | 45x |
n_years = n_years, |
| 966 | 45x |
start_year = start_year, |
| 967 | 45x |
end_year = end_year, |
| 968 | 45x |
ages = ages, |
| 969 | 45x |
n_ages = n_ages, |
| 970 | 45x |
lengths = lengths, |
| 971 | 45x |
n_lengths = n_lengths |
| 972 |
) |
|
| 973 | 43x |
return(out) |
| 974 |
} |
|
| 975 | ||
| 976 |
# Unexported functions ---- |
|
| 977 |
create_missing_data <- function( |
|
| 978 |
data, |
|
| 979 |
bins, |
|
| 980 |
timings, |
|
| 981 |
column, |
|
| 982 |
types = c("landings", "index")
|
|
| 983 |
) {
|
|
| 984 | 134x |
use_this_data <- data |> |
| 985 | 134x |
dplyr::group_by(type, name) |
| 986 | 134x |
out_data <- if (missing(bins)) {
|
| 987 |
# This only pertains to annual data without bins |
|
| 988 | 47x |
use_this_data |> |
| 989 | 47x |
dplyr::filter(type %in% types) |> |
| 990 | 47x |
tidyr::expand(unit, timing = timings) |> |
| 991 | 47x |
dplyr::anti_join( |
| 992 | 47x |
y = dplyr::select(use_this_data, type, name, unit, timing), |
| 993 | 47x |
by = dplyr::join_by(type, name, unit, timing) |
| 994 |
) |
|
| 995 |
} else {
|
|
| 996 | 87x |
use_this_data |> |
| 997 | 87x |
dplyr::group_by(type, name) |> |
| 998 | 87x |
dplyr::filter(type %in% types) |> |
| 999 | 87x |
tidyr::expand(unit, timing = timings, {{ column }} := bins) |>
|
| 1000 | 87x |
dplyr::anti_join( |
| 1001 | 87x |
y = dplyr::select(use_this_data, type, name, unit, timing, {{ column }}),
|
| 1002 | 87x |
by = dplyr::join_by(type, name, unit, timing, {{ column }})
|
| 1003 |
) |
|
| 1004 |
} |
|
| 1005 | 134x |
out_data |> |
| 1006 | 134x |
dplyr::mutate( |
| 1007 | 134x |
value = -999 |
| 1008 |
) |> |
|
| 1009 | 134x |
dplyr::ungroup() |
| 1010 |
} |
|
| 1011 | ||
| 1012 |
pretty_type <- function(x) {
|
|
| 1013 | 4738x |
gsub("comp", "composition", x) |>
|
| 1014 | 4738x |
gsub(pattern = "_", replacement = " ") |
| 1015 |
} |
| 1 |
# To remove the WARNING |
|
| 2 |
# no visible binding for global variable |
|
| 3 |
utils::globalVariables(c( |
|
| 4 |
"distribution_link", "distribution_type", |
|
| 5 |
"fleet_name", |
|
| 6 |
"type", "name", "value", "unit", "uncertainty", |
|
| 7 |
"timing", "age", "length", "year", |
|
| 8 |
"temp_name", |
|
| 9 |
"valid_n" |
|
| 10 |
)) |
|
| 11 | ||
| 12 |
#' Initialize a generic module |
|
| 13 |
#' |
|
| 14 |
#' @description |
|
| 15 |
#' Initializes a generic module by setting up its fields based on the provided |
|
| 16 |
#' `module_name`. |
|
| 17 |
#' @param parameters A tibble. Contains parameters and modules required for |
|
| 18 |
#' initialization. |
|
| 19 |
#' @param data An S4 object. FIMS input data. |
|
| 20 |
#' @param module_name A character. Name of the module to initialize (e.g., |
|
| 21 |
#' "Population" or "Fleet"). |
|
| 22 |
#' @param fleet_name A character. Name of the fleet to initialize. If not |
|
| 23 |
#' specified, the module will be initialized without fleet-specific data. |
|
| 24 |
#' @return |
|
| 25 |
#' The initialized module as an object. |
|
| 26 |
#' @noRd |
|
| 27 |
initialize_module <- function(parameters, data, module_name, fleet_name = NA_character_) {
|
|
| 28 | 158x |
module_input <- parameters |> |
| 29 |
# Using !! to unquote the variables |
|
| 30 | 158x |
dplyr::filter(module_name == !!module_name) |
| 31 | ||
| 32 | 158x |
if (!is.na(fleet_name)) {
|
| 33 | 79x |
module_input <- module_input |> |
| 34 | 79x |
dplyr::filter(fleet_name == !!fleet_name) |
| 35 |
} |
|
| 36 | ||
| 37 | 158x |
module_class_name <- module_input |> |
| 38 |
# Combine module_type and module_name into a single string |
|
| 39 | 158x |
dplyr::mutate( |
| 40 | 158x |
temp_name = paste0( |
| 41 |
# Replace NAs with "" |
|
| 42 | 158x |
dplyr::coalesce(module_type, ""), |
| 43 | 158x |
dplyr::coalesce(module_name, "") |
| 44 |
) |
|
| 45 |
) |> |
|
| 46 | 158x |
dplyr::pull(temp_name) |> |
| 47 | 158x |
unique() |
| 48 | ||
| 49 | 158x |
module_class <- get(module_class_name) |
| 50 | 158x |
module_fields <- names(module_class@fields) |
| 51 | 158x |
module <- methods::new(module_class) |
| 52 | ||
| 53 | 158x |
if (module_class_name == "Population") {
|
| 54 | 19x |
module_fields <- setdiff(module_fields, c( |
| 55 | 19x |
"log_f_multiplier", |
| 56 | 19x |
"spawning_biomass_ratio" |
| 57 |
)) |
|
| 58 |
} |
|
| 59 | ||
| 60 | 158x |
if (module_class_name == "Fleet") {
|
| 61 |
# Remove certain fields for the Fleet module |
|
| 62 | 39x |
module_fields <- setdiff(module_fields, c( |
| 63 | 39x |
"log_index_expected", |
| 64 | 39x |
"log_landings_expected", |
| 65 | 39x |
"index_expected", |
| 66 | 39x |
"landings_expected", |
| 67 | 39x |
"agecomp_expected", |
| 68 | 39x |
"agecomp_proportion", |
| 69 | 39x |
"observed_index_units", |
| 70 | 39x |
"observed_landings_units" |
| 71 |
)) |
|
| 72 | ||
| 73 | 39x |
fleet_types <- get_data(data) |> |
| 74 | 39x |
dplyr::filter(name == fleet_name) |> |
| 75 | 39x |
dplyr::pull(type) |> |
| 76 | 39x |
unique() |
| 77 | ||
| 78 | 39x |
data_distribution_names_for_fleet_i <- parameters |> |
| 79 | 39x |
dplyr::filter(fleet_name == !!fleet_name & distribution_type == "Data") |> |
| 80 | 39x |
dplyr::pull(module_type) |
| 81 | 39x |
if ("age_to_length_conversion" %in% fleet_types &&
|
| 82 | 39x |
"LengthComp" %in% data_distribution_names_for_fleet_i) {
|
| 83 | 29x |
age_to_length_conversion_value <- model_age_to_length_conversion(data, fleet_name) |
| 84 | 29x |
module[["age_to_length_conversion"]]$resize(length(age_to_length_conversion_value)) |
| 85 |
# Assign each value to the corresponding position in the parameter vector |
|
| 86 | 29x |
purrr::walk( |
| 87 | 29x |
seq_along(age_to_length_conversion_value), |
| 88 | 29x |
\(x) module[["age_to_length_conversion"]][x][["value"]] <- age_to_length_conversion_value[x] |
| 89 |
) |
|
| 90 | ||
| 91 |
# Set the estimation information for the entire parameter vector |
|
| 92 | 29x |
module[["age_to_length_conversion"]]$set_all_estimable(FALSE) |
| 93 | ||
| 94 | 29x |
module[["age_to_length_conversion"]]$set_all_random(FALSE) |
| 95 |
} else {
|
|
| 96 | 10x |
module_fields <- setdiff(module_fields, c( |
| 97 |
# Right now we can also remove n_lengths because the default is 0 |
|
| 98 | 10x |
"n_lengths" |
| 99 |
)) |
|
| 100 |
} |
|
| 101 | ||
| 102 | 39x |
module_fields <- setdiff(module_fields, c( |
| 103 | 39x |
"age_to_length_conversion", |
| 104 | 39x |
"lengthcomp_expected", |
| 105 | 39x |
"lengthcomp_proportion" |
| 106 |
)) |
|
| 107 |
} |
|
| 108 | ||
| 109 |
# Populate fields based on common and specific settings |
|
| 110 |
# TODO: |
|
| 111 |
# - Population interface |
|
| 112 |
# - Update the Population interface to consistently use n_ages and n_years, |
|
| 113 |
# as done in the S4 data_big object. |
|
| 114 |
# Update as needed. |
|
| 115 |
# - Add n_fleets to data_big. Should n_fleets include both |
|
| 116 |
# fishing and survey fleets? Currently, data_big@fleets equals 1. |
|
| 117 |
# - Fleet |
|
| 118 |
# - Reconsider exposing `log_expected_index` and |
|
| 119 |
# `agecomp_proportion` to users. Their IDs are linked with |
|
| 120 |
# index and agecomp distributions. No input values are required. |
|
| 121 | ||
| 122 | 158x |
integer_fields <- c( |
| 123 | 158x |
"n_ages", "n_fleets", "n_lengths", |
| 124 | 158x |
"n_years" |
| 125 |
) |
|
| 126 | ||
| 127 | 158x |
boolean_fields <- c( |
| 128 | 158x |
"estimate_prop_female" |
| 129 |
) |
|
| 130 | ||
| 131 | 158x |
real_vector_fields <- c( |
| 132 | 158x |
"ages", "weights" |
| 133 |
) |
|
| 134 | ||
| 135 | 158x |
for (field in module_fields) {
|
| 136 | 618x |
if (field %in% integer_fields) {
|
| 137 | 223x |
module[[field]]$set( |
| 138 | 223x |
switch(field, |
| 139 | 223x |
"n_ages" = get_n_ages(data), |
| 140 | 223x |
"n_fleets" = parameters |> |
| 141 | 223x |
dplyr::filter(module_name == "Fleet") |> |
| 142 | 223x |
dplyr::pull(fleet_name) |> |
| 143 | 223x |
unique() |> |
| 144 | 223x |
length(), |
| 145 |
# Or we can use get_n_fleets(data), |
|
| 146 | 223x |
"n_lengths" = get_n_lengths(data), |
| 147 | 223x |
"n_years" = get_n_years(data) |
| 148 |
) |
|
| 149 |
) |
|
| 150 | 395x |
} else if (field %in% c("ages", "weights")) {
|
| 151 | 59x |
get_value_function <- switch(field, |
| 152 | 59x |
"ages" = get_ages, |
| 153 | 59x |
"weights" = model_weight_at_age |
| 154 |
) |
|
| 155 | 59x |
module_length <- switch(field, |
| 156 | 59x |
"ages" = get_n_ages(data), |
| 157 | 59x |
"weights" = get_n_ages(data) * (get_n_years(data) + 1) |
| 158 |
) |
|
| 159 | 59x |
module[[field]]$resize(module_length) |
| 160 | 59x |
purrr::walk( |
| 161 | 59x |
seq(module_length), |
| 162 | 59x |
function(x) {
|
| 163 | 7908x |
module[[field]]$set(x - 1, get_value_function(data)[x]) |
| 164 |
}) |
|
| 165 |
} else {
|
|
| 166 | 336x |
set_param_vector( |
| 167 | 336x |
field = field, |
| 168 | 336x |
module = module, |
| 169 | 336x |
module_input = module_input |
| 170 |
) |
|
| 171 |
} |
|
| 172 |
} |
|
| 173 | 158x |
return(module) |
| 174 |
} |
|
| 175 | ||
| 176 |
# TODO: Determine the relationship between distributions and the |
|
| 177 |
# recruitment module, and implement the appropriate logic to retrieve |
|
| 178 |
# distribution information. |
|
| 179 | ||
| 180 |
#' Initialize a distribution module |
|
| 181 |
#' |
|
| 182 |
#' @description |
|
| 183 |
#' Initializes a distribution module by setting up its fields based on the |
|
| 184 |
#' distribution name and type. Supports both "data" and "process" types. |
|
| 185 |
#' @param module_input A list. Contains parameters for initializing the |
|
| 186 |
#' distribution. |
|
| 187 |
#' @param distribution_name A character. Name of the distribution to initialize. |
|
| 188 |
#' @param distribution_type A character. Type of distribution, either "data" or |
|
| 189 |
#' "process". |
|
| 190 |
#' @param linked_ids A vector. Named vector of linked IDs required for the |
|
| 191 |
#' distribution, such as data_link and fleet_link for setting up index |
|
| 192 |
#' distribution. |
|
| 193 |
#' @rdname initialize_module |
|
| 194 |
#' @return |
|
| 195 |
#' The initialized distribution module as an object. |
|
| 196 |
#' @noRd |
|
| 197 |
initialize_distribution <- function( |
|
| 198 |
module_input, |
|
| 199 |
distribution_name, |
|
| 200 |
distribution_type = c("data", "process"),
|
|
| 201 |
linked_ids |
|
| 202 |
) {
|
|
| 203 |
# Input checks |
|
| 204 |
# Check if distribution_name is provided |
|
| 205 | ! |
if (is.null(distribution_name)) {
|
| 206 | ! |
return(NULL) |
| 207 |
} |
|
| 208 |
# Validate module_input |
|
| 209 | ! |
if (!is.list(module_input)) {
|
| 210 | ! |
cli::cli_abort("{.var module_input} must be a list.")
|
| 211 |
} |
|
| 212 |
# Validate distribution_type as "data" or "process" |
|
| 213 | ! |
distribution_type <- rlang::arg_match(distribution_type) |
| 214 |
# Validate linked_ids as a named vector with required elements for "data" type |
|
| 215 | ! |
if (!is.vector(linked_ids) || |
| 216 | ! |
!all(c("data_link", "fleet_link") %in% names(linked_ids))
|
| 217 |
) {
|
|
| 218 | ! |
cli::cli_abort( |
| 219 | ! |
"{.var linked_ids} must be a named vector containing 'data_link' and
|
| 220 | ! |
'fleet_link' for 'data' distribution types." |
| 221 |
) |
|
| 222 |
} |
|
| 223 | ||
| 224 |
# Get distribution value and initialize the module |
|
| 225 | ! |
distribution_value <- get(distribution_name) |
| 226 | ! |
distribution_module <- methods::new(distribution_value) |
| 227 | ! |
distribution_fields <- names(distribution_value@fields) |
| 228 | ! |
if (distribution_type == "data") {
|
| 229 | ! |
distribution_fields <- setdiff( |
| 230 | ! |
distribution_fields, |
| 231 | ! |
c("expected_values", "observed_values", "dims")
|
| 232 |
) |
|
| 233 |
} |
|
| 234 | ||
| 235 | ! |
distribution_input_names <- grep( |
| 236 | ! |
distribution_name, |
| 237 | ! |
names(module_input), |
| 238 | ! |
value = TRUE |
| 239 |
) |
|
| 240 | ! |
for (field in distribution_fields) {
|
| 241 | ! |
set_param_vector( |
| 242 | ! |
field = field, module = distribution_module, |
| 243 | ! |
module_input = module_input[distribution_input_names] |
| 244 |
) |
|
| 245 |
} |
|
| 246 | ||
| 247 | ! |
switch(distribution_type, |
| 248 |
"data" = {
|
|
| 249 |
# Data distribution initialization |
|
| 250 | ! |
distribution_module$set_observed_data(linked_ids["data_link"]) |
| 251 | ! |
distribution_module$set_distribution_links( |
| 252 | ! |
distribution_type, |
| 253 | ! |
linked_ids["fleet_link"] |
| 254 |
) |
|
| 255 |
}, |
|
| 256 |
"process" = {
|
|
| 257 |
# Process distribution initialization |
|
| 258 | ! |
distribution_module$set_distribution_links("random_effects", linked_ids)
|
| 259 |
} |
|
| 260 |
) |
|
| 261 | ||
| 262 |
# Final message to confirm success |
|
| 263 | ! |
cli::cli_inform(c( |
| 264 | ! |
"i" = "{distribution_name} initialized successfully for
|
| 265 | ! |
{names(distribution_name)}."
|
| 266 |
)) |
|
| 267 | ||
| 268 | ! |
return(distribution_module) |
| 269 |
} |
|
| 270 | ||
| 271 |
#' Initialize a recruitment module |
|
| 272 |
#' |
|
| 273 |
#' @description |
|
| 274 |
#' Initializes a recruitment module by setting up fields. This function uses |
|
| 275 |
#' the `initialize_module` function to handle specific requirements for |
|
| 276 |
#' recruitment initialization. |
|
| 277 |
#' @inheritParams initialize_module |
|
| 278 |
#' @return |
|
| 279 |
#' The initialized recruitment module as an object. |
|
| 280 |
#' @noRd |
|
| 281 |
initialize_recruitment <- function(parameters, data) {
|
|
| 282 | 20x |
module <- initialize_module( |
| 283 | 20x |
parameters = parameters, |
| 284 | 20x |
data = data, |
| 285 | 20x |
module_name = "Recruitment" |
| 286 |
) |
|
| 287 | 20x |
return(module) |
| 288 |
} |
|
| 289 | ||
| 290 |
#' Initialize a growth module |
|
| 291 |
#' |
|
| 292 |
#' @description |
|
| 293 |
#' Initializes a growth module by setting up fields. This function uses |
|
| 294 |
#' the `initialize_module` function to handle specific requirements for |
|
| 295 |
#' growth initialization. |
|
| 296 |
#' @inheritParams initialize_module |
|
| 297 |
#' @return |
|
| 298 |
#' The initialized growth module as an object. |
|
| 299 |
#' @noRd |
|
| 300 |
initialize_growth <- function(parameters, data) {
|
|
| 301 | 20x |
module <- initialize_module( |
| 302 | 20x |
parameters = parameters, |
| 303 | 20x |
data = data, |
| 304 | 20x |
module_name = "Growth" |
| 305 |
) |
|
| 306 | 20x |
return(module) |
| 307 |
} |
|
| 308 | ||
| 309 |
#' Initialize a maturity module |
|
| 310 |
#' |
|
| 311 |
#' @description |
|
| 312 |
#' Initializes a maturity module by setting up fields. This function uses |
|
| 313 |
#' the `initialize_module` function to handle specific requirements for |
|
| 314 |
#' maturity initialization. |
|
| 315 |
#' @inheritParams initialize_module |
|
| 316 |
#' @return |
|
| 317 |
#' The initialized maturity module as an object. |
|
| 318 |
#' @noRd |
|
| 319 |
initialize_maturity <- function(parameters, data) {
|
|
| 320 | 20x |
module <- initialize_module( |
| 321 | 20x |
parameters = parameters, |
| 322 | 20x |
data = data, |
| 323 | 20x |
module_name = "Maturity" |
| 324 |
) |
|
| 325 | 20x |
return(module) |
| 326 |
} |
|
| 327 | ||
| 328 |
#' Initialize a population module. |
|
| 329 |
#' |
|
| 330 |
#' @description |
|
| 331 |
#' Initializes a population module by setting up fields. This function uses |
|
| 332 |
#' the `initialize_module` function to handle specific requirements for |
|
| 333 |
#' population initialization. |
|
| 334 |
#' @inheritParams initialize_module |
|
| 335 |
#' @param linked_ids A vector. Named vector of linked IDs required for the |
|
| 336 |
#' population, including IDs for "growth", "maturity", and "recruitment". |
|
| 337 |
#' @return |
|
| 338 |
#' The initialized population module as an object. |
|
| 339 |
#' @noRd |
|
| 340 |
initialize_population <- function(parameters, data, linked_ids) {
|
|
| 341 | 20x |
if (anyNA(linked_ids[c("growth", "maturity", "recruitment")])) {
|
| 342 | 1x |
cli::cli_abort(c( |
| 343 | 1x |
"{.var linked_ids} for population must include `growth`, `maturity`, and
|
| 344 | 1x |
`recruitment` IDs." |
| 345 |
)) |
|
| 346 |
} |
|
| 347 | ||
| 348 | 19x |
module <- initialize_module( |
| 349 | 19x |
parameters = parameters, |
| 350 | 19x |
data = data, |
| 351 | 19x |
module_name = "Population" |
| 352 |
) |
|
| 353 | ||
| 354 |
# Link up the recruitment, growth, and maturity modules with |
|
| 355 |
# this population module |
|
| 356 | 19x |
module$SetGrowthID(linked_ids[["growth"]]) |
| 357 | 19x |
module$SetMaturityID(linked_ids[["maturity"]]) |
| 358 | 19x |
module$SetRecruitmentID(linked_ids[["recruitment"]]) |
| 359 |
# Link fleets to module |
|
| 360 | 19x |
for (i in which(grepl("fleet", names(linked_ids)))) {
|
| 361 | 36x |
module$AddFleet(linked_ids[[i]]) |
| 362 |
} |
|
| 363 | ||
| 364 | 19x |
return(module) |
| 365 |
} |
|
| 366 | ||
| 367 |
#' Initialize a selectivity module. |
|
| 368 |
#' |
|
| 369 |
#' @description |
|
| 370 |
#' Initializes a selectivity module by setting up fields. This function uses |
|
| 371 |
#' the `initialize_module` function to handle specific requirements for |
|
| 372 |
#' population initialization. |
|
| 373 |
#' |
|
| 374 |
#' For logistic selectivity, the curve can be either ascending or descending |
|
| 375 |
#' based on the sign of the slope parameter. A positive slope creates an |
|
| 376 |
#' ascending logistic curve where selectivity increases from 0 to 1 with |
|
| 377 |
#' increasing values of the independent variable (e.g., age or size). A |
|
| 378 |
#' negative slope creates a descending logistic curve where selectivity |
|
| 379 |
#' decreases from 1 to 0. |
|
| 380 |
#' |
|
| 381 |
#' @inheritParams initialize_module |
|
| 382 |
#' @param fleet_name A character. Name of the fleet to initialize. |
|
| 383 |
#' @return |
|
| 384 |
#' The initialized selectivity module as an object. |
|
| 385 |
#' @noRd |
|
| 386 |
initialize_selectivity <- function(parameters, data, fleet_name) {
|
|
| 387 | 40x |
module_name <- "Selectivity" |
| 388 | 40x |
module <- initialize_module( |
| 389 | 40x |
parameters = parameters, |
| 390 | 40x |
data = data, |
| 391 | 40x |
module_name = module_name, |
| 392 | 40x |
fleet_name = fleet_name |
| 393 |
) |
|
| 394 | 40x |
return(module) |
| 395 |
} |
|
| 396 | ||
| 397 |
# TODO: Do we want to put initialize_selectivity(), initialize_index(), and |
|
| 398 |
# initial_age_comp() inside of initialize_fleet()? |
|
| 399 | ||
| 400 |
#' Initialize a fleet module |
|
| 401 |
#' |
|
| 402 |
#' @description |
|
| 403 |
#' Initializes a fleet module by setting up its fields. It links selectivity, |
|
| 404 |
#' index, and age-composition modules. |
|
| 405 |
#' @inheritParams initialize_module |
|
| 406 |
#' @param fleet_name A character. Name of the fleet to initialize. |
|
| 407 |
#' @param linked_ids A vector. Named vector of linked IDs required for the |
|
| 408 |
#' fleet, including IDs for "selectivity", "landings", "index", "age_comp", and "length_comp". |
|
| 409 |
#' @return |
|
| 410 |
#' The initialized fleet module as an object. |
|
| 411 |
#' @noRd |
|
| 412 |
initialize_fleet <- function(parameters, data, fleet_name, linked_ids) {
|
|
| 413 | 39x |
module <- initialize_module( |
| 414 | 39x |
parameters = parameters, |
| 415 | 39x |
data = data, |
| 416 | 39x |
fleet_name = fleet_name, |
| 417 | 39x |
module_name = "Fleet" |
| 418 |
) |
|
| 419 | ||
| 420 | 39x |
module$SetSelectivityID(linked_ids["selectivity"]) |
| 421 | ||
| 422 | 39x |
fleet_types <- get_data(data) |> |
| 423 | 39x |
dplyr::filter(name == fleet_name) |> |
| 424 | 39x |
dplyr::pull(type) |> |
| 425 | 39x |
unique() |
| 426 | ||
| 427 | ||
| 428 | 39x |
distribution_names_for_fleet <- parameters |> |
| 429 | 39x |
dplyr::filter(fleet_name == !!fleet_name & distribution_type == "Data") |> |
| 430 | 39x |
dplyr::pull(module_type) |
| 431 | ||
| 432 |
# Link the observed landings data to the fleet module using its associated ID |
|
| 433 |
# if the data type includes "landings" and if "Landings" exists in the data distribution |
|
| 434 |
# specification |
|
| 435 | 39x |
if ("landings" %in% fleet_types &&
|
| 436 | 39x |
"Landings" %in% distribution_names_for_fleet) {
|
| 437 | 21x |
module$SetObservedLandingsDataID(linked_ids["landings"]) |
| 438 |
} |
|
| 439 | ||
| 440 |
# Link the observed index data to the fleet module using its associated ID |
|
| 441 |
# if the data type includes "index" and if "Index" exists in the data distribution |
|
| 442 |
# specification |
|
| 443 | 39x |
if ("index" %in% fleet_types &&
|
| 444 | 39x |
"Index" %in% distribution_names_for_fleet) {
|
| 445 | 18x |
module$SetObservedIndexDataID(linked_ids["index"]) |
| 446 |
} |
|
| 447 | ||
| 448 |
# Link the observed age composition data to the fleet module using its associated ID |
|
| 449 |
# if the data type includes "age_comp" and if "AgeComp" exists in the data distribution |
|
| 450 |
# specification |
|
| 451 | 39x |
if ("age_comp" %in% fleet_types &&
|
| 452 | 39x |
"AgeComp" %in% distribution_names_for_fleet) {
|
| 453 | 35x |
module$SetObservedAgeCompDataID(linked_ids["age_comp"]) |
| 454 |
} |
|
| 455 | ||
| 456 |
# Link the observed length composition data to the fleet module using its associated ID |
|
| 457 |
# if the data type includes "length_comp" and if "LengthComp" exists in the data |
|
| 458 |
# distribution specification |
|
| 459 | 39x |
if ("length_comp" %in% fleet_types &&
|
| 460 | 39x |
"LengthComp" %in% distribution_names_for_fleet) {
|
| 461 | 29x |
module$SetObservedLengthCompDataID(linked_ids["length_comp"]) |
| 462 |
} |
|
| 463 | 39x |
return(module) |
| 464 |
} |
|
| 465 | ||
| 466 |
#' Initialize a landings module |
|
| 467 |
#' |
|
| 468 |
#' @description |
|
| 469 |
#' Initializes a landings module based on the provided data and fleet name. |
|
| 470 |
#' @inheritParams initialize_module |
|
| 471 |
#' @param fleet_name A character. Name of the fleet for which the landings module |
|
| 472 |
#' is initialized. |
|
| 473 |
#' @return |
|
| 474 |
#' The initialized landings module as an object. |
|
| 475 |
#' @noRd |
|
| 476 |
initialize_landings <- function(data, fleet_name) {
|
|
| 477 |
# Check if the specified fleet exists in the data |
|
| 478 | 23x |
fleet_exists <- any(get_data(data)["name"] == fleet_name) |
| 479 | 23x |
if (!fleet_exists) {
|
| 480 | 1x |
cli::cli_abort("Fleet {fleet_name} not found in the data object.")
|
| 481 |
} |
|
| 482 | ||
| 483 | 22x |
fleet_type <- dplyr::filter( |
| 484 | 22x |
.data = as.data.frame(get_data(data)), |
| 485 | 22x |
name == fleet_name |
| 486 |
) |> |
|
| 487 | 22x |
dplyr::distinct(type) |> |
| 488 | 22x |
dplyr::pull(type) |
| 489 | ||
| 490 | 22x |
if ("landings" %in% fleet_type) {
|
| 491 | 21x |
module <- methods::new(Landings, get_n_years(data)) |
| 492 | 21x |
purrr::walk( |
| 493 | 21x |
seq_along(model_landings(data, fleet_name)), |
| 494 | 21x |
\(x) module$landings_data$set(x - 1, model_landings(data, fleet_name)[x]) |
| 495 |
) |
|
| 496 | 21x |
return(module) |
| 497 |
} else {
|
|
| 498 | 1x |
return(NULL) |
| 499 |
} |
|
| 500 |
} |
|
| 501 | ||
| 502 |
#' Initialize an index module |
|
| 503 |
#' |
|
| 504 |
#' @description |
|
| 505 |
#' Initializes an index module based on the provided data and fleet name. |
|
| 506 |
#' @inheritParams initialize_module |
|
| 507 |
#' @param fleet_name A character. Name of the fleet for which the index module |
|
| 508 |
#' is initialized. |
|
| 509 |
#' @return |
|
| 510 |
#' The initialized index module as an object. |
|
| 511 |
#' @noRd |
|
| 512 |
initialize_index <- function(data, fleet_name) {
|
|
| 513 |
# Check if the specified fleet exists in the data |
|
| 514 | 21x |
fleet_exists <- any(get_data(data)["name"] == fleet_name) |
| 515 | 21x |
if (!fleet_exists) {
|
| 516 | 1x |
cli::cli_abort("Fleet {fleet_name} not found in the data object.")
|
| 517 |
} |
|
| 518 | ||
| 519 | 20x |
fleet_type <- dplyr::filter( |
| 520 | 20x |
.data = as.data.frame(get_data(data)), |
| 521 | 20x |
name == fleet_name |
| 522 |
) |> |
|
| 523 | 20x |
dplyr::distinct(type) |> |
| 524 | 20x |
dplyr::pull(type) |
| 525 | ||
| 526 | 20x |
if ("index" %in% fleet_type) {
|
| 527 | 19x |
module <- methods::new(Index, get_n_years(data)) |
| 528 | 19x |
purrr::walk( |
| 529 | 19x |
seq_along(model_index(data, fleet_name)), |
| 530 | 19x |
\(x) module$index_data$set(x - 1, model_index(data, fleet_name)[x]) |
| 531 |
) |
|
| 532 | 19x |
return(module) |
| 533 |
} else {
|
|
| 534 | 1x |
return(NULL) |
| 535 |
} |
|
| 536 |
} |
|
| 537 | ||
| 538 |
#' Initialize a composition module |
|
| 539 |
#' |
|
| 540 |
#' Several types of composition modules exist and this function acts as a |
|
| 541 |
#' generic interface to initialize any type, for example assigning |
|
| 542 |
#' age-composition data to a given fleet would be an example of initializing |
|
| 543 |
#' a composition module. |
|
| 544 |
#' |
|
| 545 |
#' @inheritParams initialize_module |
|
| 546 |
#' @param fleet_name A character specifying the name of the fleet for which |
|
| 547 |
#' composition data is initialized. |
|
| 548 |
#' @param type A character specifying the composition type, where the default |
|
| 549 |
#' is `"AgeComp"`. At the moment, one can initialize `"AgeComp"` or |
|
| 550 |
#' `"LengthComp"` modules. |
|
| 551 |
#' @return |
|
| 552 |
#' The initialized composition module as an object. |
|
| 553 |
#' @noRd |
|
| 554 |
initialize_comp <- function(data, |
|
| 555 |
fleet_name, |
|
| 556 |
type = c("AgeComp", "LengthComp")) {
|
|
| 557 |
# Edit this list if a new type is added |
|
| 558 |
# Set up the specifics for the given type. |
|
| 559 | 68x |
comp_types <- list( |
| 560 | 68x |
"AgeComp" = list( |
| 561 | 68x |
"name" = "age_comp", |
| 562 | 68x |
"comp_data_field" = "age_comp_data", |
| 563 | 68x |
"get_n_function" = get_n_ages, |
| 564 | 68x |
"comp_object" = AgeComp, |
| 565 | 68x |
"m_comp" = model_age_comp |
| 566 |
), |
|
| 567 | 68x |
"LengthComp" = list( |
| 568 | 68x |
"name" = "length_comp", |
| 569 | 68x |
"comp_data_field" = "length_comp_data", |
| 570 | 68x |
"get_n_function" = get_n_lengths, |
| 571 | 68x |
"comp_object" = LengthComp, |
| 572 | 68x |
"m_comp" = model_length_comp |
| 573 |
) |
|
| 574 |
) |
|
| 575 | ||
| 576 |
# Ensures the user input matches the options provided, |
|
| 577 |
# if not, then match.arg() throws an error |
|
| 578 | 68x |
type <- match.arg(type) |
| 579 |
# Select the row in comp_types that matches the user's type selection |
|
| 580 | 67x |
comp <- comp_types[[type]] |
| 581 | ||
| 582 |
# Check if the specified fleet exists in the data |
|
| 583 | 67x |
fleet_exists <- any(get_data(data)["name"] == fleet_name) |
| 584 | 67x |
if (!fleet_exists) {
|
| 585 | 1x |
cli::cli_abort("Fleet `{fleet_name}` not found in the data object.")
|
| 586 |
} |
|
| 587 | ||
| 588 | 66x |
get_function <- comp[["get_n_function"]] |
| 589 | 66x |
module <- methods::new( |
| 590 | 66x |
comp[["comp_object"]], |
| 591 | 66x |
get_n_years(data), |
| 592 | 66x |
get_function(data) |
| 593 |
) |
|
| 594 | ||
| 595 |
# Validate that the fleet's composition data is available |
|
| 596 | 66x |
comp_data <- comp[["m_comp"]](data, fleet_name) |
| 597 | 66x |
pretty_comp_name <- gsub("_comp", "-composition", comp[['name']])
|
| 598 | 66x |
if (is.null(comp_data) || length(comp_data) == 0) {
|
| 599 | 1x |
cli::cli_abort(c( |
| 600 | 1x |
"The {pretty_comp_name} data for fleet {.var {fleet_name}} is
|
| 601 | 1x |
unavailable or empty." |
| 602 |
)) |
|
| 603 |
} |
|
| 604 | ||
| 605 | 65x |
model_data <- comp_data * |
| 606 | 65x |
get_data(data) |> |
| 607 | 65x |
dplyr::filter( |
| 608 | 65x |
name == fleet_name, |
| 609 | 65x |
type == comp[["name"]] |
| 610 |
) |> |
|
| 611 | 65x |
dplyr::mutate( |
| 612 | 65x |
valid_n = ifelse(value == -999, 1, uncertainty) |
| 613 |
) |> |
|
| 614 | 65x |
dplyr::pull(valid_n) |
| 615 | ||
| 616 | 65x |
if (length(model_data) != get_n_years(data) * get_function(data)) {
|
| 617 | 1x |
bad_data_years <- get_data(data) |> |
| 618 | 1x |
dplyr::filter( |
| 619 | 1x |
name == fleet_name, |
| 620 | 1x |
type == comp[["name"]] |
| 621 |
) |> |
|
| 622 | 1x |
dplyr::count(timing) |> |
| 623 | 1x |
dplyr::filter(n != get_function(data)) |> |
| 624 | 1x |
dplyr::pull(timing) |
| 625 | ||
| 626 | 1x |
cli::cli_abort(c( |
| 627 | 1x |
"The length of the `{comp[['name']]}`-composition data for fleet
|
| 628 | 1x |
`{fleet_name}` does not match the expected dimensions.",
|
| 629 | 1x |
i = "Expected length: {get_n_years(data) * get_function(data)}",
|
| 630 | 1x |
i = "Actual length: {length(model_data)}",
|
| 631 | 1x |
i = "Number of -999 values: {sum(model_data == -999)}",
|
| 632 | 1x |
i = "Dates with invalid data: {bad_data_years}"
|
| 633 |
)) |
|
| 634 |
} |
|
| 635 | ||
| 636 | 64x |
purrr::walk( |
| 637 | 64x |
seq_along(model_data), |
| 638 | 64x |
\(x) module[[comp[["comp_data_field"]]]]$set(x - 1, model_data[x]) |
| 639 |
) |
|
| 640 | ||
| 641 | 64x |
return(module) |
| 642 |
} |
|
| 643 | ||
| 644 |
#' Initialize C++ modules via Rcpp for a FIMS model |
|
| 645 |
#' |
|
| 646 |
#' @description |
|
| 647 |
#' This function uses information from a parameter data frame that stores the |
|
| 648 |
#' model specifications and a`FIMSFrame` object that stores the data to |
|
| 649 |
#' instantiate, i.e., create an instance of a class, the required C++ modules. |
|
| 650 |
#' Several C++ modules are needed to run a FIMS model and the required modules |
|
| 651 |
#' will be different for each model type. For example, for a catch-at-age |
|
| 652 |
#' model one needs to instantiate recruitment, growth, and maturity modules and |
|
| 653 |
#' at least one fleet and population module. |
|
| 654 |
#' |
|
| 655 |
#' @param parameters A tibble returned from [create_default_parameters()]. The |
|
| 656 |
#' tibble can be nested, i.e., contain a data column, or unnested, i.e., |
|
| 657 |
#' `tidyr::unnest(create_default_parameters(), cols = "data")`. Regardless, it |
|
| 658 |
#' is the primary source of information for what is initialized. That is, if a |
|
| 659 |
#' fleet exists in the data but parameter information for how to specify |
|
| 660 |
#' selectivity for that fleet is not provided, then selectivity will not be |
|
| 661 |
#' initialized for that fleet. |
|
| 662 |
#' @param data An S4 object with the `FIMSFrame` class, which is returned from |
|
| 663 |
#' [FIMSFrame()]. Passing the data is required because initialization of the |
|
| 664 |
#' modules requires passing the data and information regarding the uncertainty |
|
| 665 |
#' of that data, i.e., input sample sizes for the multinomial distribution. |
|
| 666 |
#' @return |
|
| 667 |
#' A list is returned with two elements, `parameters` and `model`. The list can |
|
| 668 |
#' be passed to the `input` argument of [fit_fims()] to fit the model. The first |
|
| 669 |
#' element of the list can also be passed to the `parameters` argument of |
|
| 670 |
#' [TMB::MakeADFun()] if you wish to have more control over the model-fitting |
|
| 671 |
#' process. |
|
| 672 |
#' The model element of the returned list stores the instantiated C++ model |
|
| 673 |
#' module, e.g., the results of `methods::new(CatchAtAge)` for a catch-at-age |
|
| 674 |
#' model. |
|
| 675 |
#' It is important that you only have one FIMS model initialized in your R |
|
| 676 |
#' workspace at a time. Thus, after you initialize and fit the model, you should |
|
| 677 |
#' run [clear()]. |
|
| 678 |
#' @export |
|
| 679 |
#' @seealso |
|
| 680 |
#' * [create_default_configurations()] |
|
| 681 |
#' * [create_default_parameters()] |
|
| 682 |
#' * [FIMSFrame()] |
|
| 683 |
#' * [fit_fims()] |
|
| 684 |
#' * [clear()] |
|
| 685 |
#' @examples |
|
| 686 |
#' \dontrun{
|
|
| 687 |
#' # Prepare data for FIMS model |
|
| 688 |
#' data("data_big", package = "FIMS")
|
|
| 689 |
#' data_4_model <- FIMSFrame(data_big) |
|
| 690 |
#' # Instantiate modules |
|
| 691 |
#' parameters_list <- data_4_model |> |
|
| 692 |
#' create_default_configurations() |> |
|
| 693 |
#' create_default_parameters(data = data_4_model) |> |
|
| 694 |
#' initialize_fims(data = data_4_model) |
|
| 695 |
#' clear() |
|
| 696 |
#' } |
|
| 697 |
initialize_fims <- function(parameters, data) {
|
|
| 698 |
# Validate parameters input |
|
| 699 | 24x |
if (missing(parameters) || !tibble::is_tibble(parameters)) {
|
| 700 | 2x |
cli::cli_abort("The {.var parameters} argument must be a tibble.")
|
| 701 |
} |
|
| 702 | ||
| 703 |
# Check if parameters is a nested tibble. If so, unnest parameters |
|
| 704 | 22x |
if ("data" %in% names(parameters)) {
|
| 705 | 1x |
parameters <- parameters |> |
| 706 | 1x |
tidyr::unnest(cols = c(data)) |
| 707 |
} |
|
| 708 | ||
| 709 |
# Check if estimation_type is within "constant", "fixed_effect", "random_effect" |
|
| 710 |
# Validates supported estimation types to avoid errors later when |
|
| 711 |
# |
|
| 712 | 22x |
valid_estimation_types <- c("constant", "fixed_effects", "random_effects")
|
| 713 | 22x |
invalid_estimation_types <- parameters |> |
| 714 | 22x |
dplyr::filter(!estimation_type %in% valid_estimation_types) |> |
| 715 | 22x |
dplyr::pull(estimation_type) |> |
| 716 | 22x |
unique() |> |
| 717 | 22x |
na.omit() |
| 718 | ||
| 719 | 22x |
if (length(invalid_estimation_types) > 0) {
|
| 720 | 1x |
cli::cli_abort(c( |
| 721 | 1x |
"The `estimation_type` must be one of: {valid_estimation_types}.",
|
| 722 | 1x |
i = "Invalid values found: {invalid_estimation_types}."
|
| 723 |
)) |
|
| 724 |
} |
|
| 725 | ||
| 726 |
# Clear any previous FIMS settings |
|
| 727 | 21x |
clear() |
| 728 | ||
| 729 | 21x |
fleet_names <- parameters |> |
| 730 | 21x |
dplyr::pull(fleet_name) |> |
| 731 | 21x |
unique() |> |
| 732 | 21x |
na.omit() |
| 733 | ||
| 734 | 21x |
if (length(fleet_names) == 0) {
|
| 735 | 1x |
cli::cli_abort(c( |
| 736 | 1x |
"No fleets found in the provided {.var parameters}."
|
| 737 |
)) |
|
| 738 |
} |
|
| 739 | ||
| 740 |
# Initialize lists to store fleet-related objects |
|
| 741 | 20x |
fleet <- fleet_selectivity <- |
| 742 | 20x |
fleet_landings <- fleet_landings_distribution <- |
| 743 | 20x |
fleet_index <- fleet_index_distribution <- |
| 744 | 20x |
fleet_age_comp <- fleet_agecomp_distribution <- |
| 745 | 20x |
fleet_length_comp <- fleet_lengthcomp_distribution <- |
| 746 | 20x |
vector("list", length(fleet_names))
|
| 747 | ||
| 748 | 20x |
for (i in seq_along(fleet_names)) {
|
| 749 | 38x |
fleet_selectivity[[i]] <- initialize_selectivity( |
| 750 | 38x |
parameters = parameters, |
| 751 | 38x |
data = data, |
| 752 | 38x |
fleet_name = fleet_names[i] |
| 753 |
) |
|
| 754 | ||
| 755 | 38x |
fleet_module_ids <- c( |
| 756 | 38x |
selectivity = fleet_selectivity[[i]]$get_id() |
| 757 |
) |
|
| 758 | ||
| 759 | 38x |
fleet_types <- get_data(data) |> |
| 760 | 38x |
dplyr::filter(name == fleet_names[i]) |> |
| 761 | 38x |
dplyr::pull(type) |> |
| 762 | 38x |
unique() |
| 763 | ||
| 764 | 38x |
data_distribution_names_for_fleet_i <- parameters |> |
| 765 | 38x |
dplyr::filter(fleet_name == fleet_names[i] & distribution_type == "Data") |> |
| 766 | 38x |
dplyr::pull(module_type) |
| 767 | ||
| 768 |
# Initialize landings module if the data type includes "landings" and |
|
| 769 |
# if "Landings" exists in the data distribution specification |
|
| 770 | 38x |
if ("landings" %in% fleet_types &&
|
| 771 | 38x |
"Landings" %in% data_distribution_names_for_fleet_i) {
|
| 772 |
# Initialize landings module for the current fleet |
|
| 773 | 20x |
fleet_landings[[i]] <- initialize_landings( |
| 774 | 20x |
data = data, |
| 775 | 20x |
fleet_name = fleet_names[i] |
| 776 |
) |
|
| 777 | ||
| 778 |
# Add the module ID for the initialized landings to the list of fleet module IDs |
|
| 779 | 20x |
fleet_module_ids <- c( |
| 780 | 20x |
fleet_module_ids, |
| 781 | 20x |
c(landings = fleet_landings[[i]]$get_id()) |
| 782 |
) |
|
| 783 |
} |
|
| 784 | ||
| 785 |
# Initialize index module if the data type includes "index" and |
|
| 786 |
# if "Index" exists in the data distribution specification |
|
| 787 | 38x |
if ("index" %in% fleet_types &&
|
| 788 | 38x |
"Index" %in% data_distribution_names_for_fleet_i) {
|
| 789 |
# Initialize index module for the current fleet |
|
| 790 | 18x |
fleet_index[[i]] <- initialize_index( |
| 791 | 18x |
data = data, |
| 792 | 18x |
fleet_name = fleet_names[i] |
| 793 |
) |
|
| 794 | ||
| 795 |
# Add the module ID for the initialized index to the list of fleet module IDs |
|
| 796 | 18x |
fleet_module_ids <- c( |
| 797 | 18x |
fleet_module_ids, |
| 798 | 18x |
c(index = fleet_index[[i]]$get_id()) |
| 799 |
) |
|
| 800 |
} |
|
| 801 | ||
| 802 |
# Initialize age composition module if the data type includes "age_comp" and |
|
| 803 |
# if "AgeComp" exists in the data distribution specification |
|
| 804 | 38x |
if ("age_comp" %in% fleet_types &&
|
| 805 | 38x |
"AgeComp" %in% data_distribution_names_for_fleet_i) {
|
| 806 |
# Initialize age composition module for the current fleet |
|
| 807 | 34x |
fleet_age_comp[[i]] <- initialize_comp( |
| 808 | 34x |
data = data, |
| 809 | 34x |
fleet_name = fleet_names[i], |
| 810 | 34x |
type = "AgeComp" |
| 811 |
) |
|
| 812 | ||
| 813 |
# Add the module ID for the initialized age composition to the list of fleet module IDs |
|
| 814 | 34x |
fleet_module_ids <- c( |
| 815 | 34x |
fleet_module_ids, |
| 816 | 34x |
c(age_comp = fleet_age_comp[[i]]$get_id()) |
| 817 |
) |
|
| 818 |
} |
|
| 819 | ||
| 820 |
# Initialize length composition module if the data type includes "length_comp" and |
|
| 821 |
# if "LengthComp" exists in the data distribution specification |
|
| 822 | 38x |
if ("length_comp" %in% fleet_types &&
|
| 823 | 38x |
"LengthComp" %in% data_distribution_names_for_fleet_i) {
|
| 824 |
# Initialize length composition module for the current fleet |
|
| 825 | 28x |
fleet_length_comp[[i]] <- initialize_comp( |
| 826 | 28x |
data = data, |
| 827 | 28x |
fleet_name = fleet_names[i], |
| 828 | 28x |
type = "LengthComp" |
| 829 |
) |
|
| 830 | ||
| 831 |
# Add the module ID for the initialized length composition to the list of fleet module IDs |
|
| 832 | 28x |
fleet_module_ids <- c( |
| 833 | 28x |
fleet_module_ids, |
| 834 | 28x |
c(length_comp = fleet_length_comp[[i]]$get_id()) |
| 835 |
) |
|
| 836 |
} |
|
| 837 | ||
| 838 | 38x |
fleet[[i]] <- initialize_fleet( |
| 839 | 38x |
parameters = parameters, |
| 840 | 38x |
data = data, |
| 841 | 38x |
fleet_name = fleet_names[i], |
| 842 |
# TODO: need to remove linked_ids from the function and add module_id to the |
|
| 843 |
# parameters tibble |
|
| 844 | 38x |
linked_ids = fleet_module_ids |
| 845 |
) |
|
| 846 | ||
| 847 | 38x |
fleet_sd_input <- parameters |> |
| 848 | 38x |
dplyr::filter(fleet_name == fleet_names[i] & label == "log_sd") |> |
| 849 | 38x |
dplyr::mutate( |
| 850 | 38x |
label = "sd", |
| 851 | 38x |
value = exp(value) |
| 852 |
) |
|
| 853 | ||
| 854 | 38x |
if (length(fleet_sd_input) == 0) {
|
| 855 | ! |
cli::cli_abort(c( |
| 856 | ! |
"Missing required inputs for `log_sd` in fleet `{fleet_name}`."
|
| 857 |
)) |
|
| 858 |
} |
|
| 859 | ||
| 860 | 38x |
if ("index" %in% fleet_types &&
|
| 861 | 38x |
"Index" %in% data_distribution_names_for_fleet_i) {
|
| 862 | 18x |
fleet_index_distribution[[i]] <- initialize_data_distribution( |
| 863 | 18x |
module = fleet[[i]], |
| 864 |
# TODO: need to update family and match options from the distribution |
|
| 865 |
# column from the parameters tibble |
|
| 866 | 18x |
family = lognormal(link = "log"), |
| 867 | 18x |
sd = fleet_sd_input, |
| 868 | 18x |
data_type = "index" |
| 869 |
) |
|
| 870 |
} |
|
| 871 | ||
| 872 | 38x |
if ("landings" %in% fleet_types &&
|
| 873 | 38x |
"Landings" %in% data_distribution_names_for_fleet_i) {
|
| 874 | 20x |
fleet_landings_distribution[[i]] <- initialize_data_distribution( |
| 875 | 20x |
module = fleet[[i]], |
| 876 |
# TODO: need to update family and match options from the distribution |
|
| 877 |
# column from the parameters tibble |
|
| 878 | 20x |
family = lognormal(link = "log"), |
| 879 | 20x |
sd = fleet_sd_input, |
| 880 | 20x |
data_type = "landings" |
| 881 |
) |
|
| 882 |
} |
|
| 883 | ||
| 884 | 36x |
if ("age_comp" %in% fleet_types &&
|
| 885 | 36x |
"AgeComp" %in% data_distribution_names_for_fleet_i) {
|
| 886 | 32x |
fleet_agecomp_distribution[[i]] <- initialize_data_distribution( |
| 887 | 32x |
module = fleet[[i]], |
| 888 |
# TODO: need to update family and match options from the distribution |
|
| 889 |
# column from the parameters tibble |
|
| 890 | 32x |
family = multinomial(link = "logit"), |
| 891 | 32x |
data_type = "agecomp" |
| 892 |
) |
|
| 893 |
} |
|
| 894 | ||
| 895 | 36x |
if ("length_comp" %in% fleet_types &&
|
| 896 | 36x |
"LengthComp" %in% data_distribution_names_for_fleet_i) {
|
| 897 | 26x |
fleet_lengthcomp_distribution[[i]] <- initialize_data_distribution( |
| 898 | 26x |
module = fleet[[i]], |
| 899 |
# TODO: need to update family and match options from the distribution |
|
| 900 |
# column from the parameters tibble |
|
| 901 | 26x |
family = multinomial(link = "logit"), |
| 902 | 26x |
data_type = "lengthcomp" |
| 903 |
) |
|
| 904 |
} |
|
| 905 |
} |
|
| 906 | ||
| 907 |
# Recruitment |
|
| 908 |
# create new module in the recruitment class (specifically Beverton--Holt, |
|
| 909 |
# when there are other options, this would be where the option would be |
|
| 910 |
# chosen) |
|
| 911 | 18x |
recruitment <- initialize_recruitment( |
| 912 | 18x |
parameters = parameters, |
| 913 | 18x |
data = data |
| 914 |
) |
|
| 915 | ||
| 916 | 18x |
recruitment_process_input <- parameters |> |
| 917 | 18x |
dplyr::filter(module_name == "Recruitment" & distribution_type == "process") |
| 918 | ||
| 919 | 18x |
if (length(recruitment_process_input) == 0) {
|
| 920 |
# TODO: need to revisit initialize_process_structure and add R tests |
|
| 921 | ! |
recruitment_process <- initialize_process_structure( |
| 922 | ! |
module = recruitment, |
| 923 | ! |
par = "log_devs" |
| 924 |
) |
|
| 925 |
} else {
|
|
| 926 | 18x |
pars <- recruitment_process_input |> |
| 927 | 18x |
dplyr::pull(distribution_link) |> |
| 928 | 18x |
unique() |
| 929 | ||
| 930 |
# Initialize_process_distribution for each par |
|
| 931 | 18x |
recruitment_distribution <- purrr::map(pars, function(par) {
|
| 932 | 18x |
sd_input <- recruitment_process_input |> |
| 933 | 18x |
dplyr::filter(distribution_link == par & label == "log_sd") |
| 934 | 18x |
initialize_process_distribution( |
| 935 | 18x |
module = recruitment, |
| 936 | 18x |
par = par, |
| 937 |
# TODO: need to update family and match options from the distribution |
|
| 938 |
# column from the parameters tibble |
|
| 939 | 18x |
family = gaussian(), |
| 940 | 18x |
sd = sd_input, |
| 941 |
# TODO: need to remove is_random_effect and match options from the |
|
| 942 |
# estimation_type from the parameters tibble |
|
| 943 | 18x |
is_random_effect = FALSE |
| 944 |
) |
|
| 945 | ||
| 946 | 18x |
recruitment_process <- initialize_process_structure( |
| 947 | 18x |
module = recruitment, |
| 948 | 18x |
par = par |
| 949 |
) |
|
| 950 |
}) |
|
| 951 |
} |
|
| 952 | ||
| 953 |
# Growth |
|
| 954 | 18x |
growth <- initialize_growth( |
| 955 | 18x |
parameters = parameters, |
| 956 | 18x |
data = data |
| 957 |
) |
|
| 958 | ||
| 959 |
# Maturity |
|
| 960 | 18x |
maturity <- initialize_maturity( |
| 961 | 18x |
parameters = parameters, |
| 962 | 18x |
data = data |
| 963 |
) |
|
| 964 | ||
| 965 | 18x |
population_module_ids <- c( |
| 966 | 18x |
recruitment = recruitment$get_id(), |
| 967 | 18x |
growth = growth$get_id(), |
| 968 | 18x |
maturity = maturity$get_id(), |
| 969 | 18x |
fleets = purrr::map(fleet, \(x) x$get_id()) |
| 970 |
) |
|
| 971 | ||
| 972 |
# Population |
|
| 973 | 18x |
population <- initialize_population( |
| 974 | 18x |
parameters = parameters, |
| 975 | 18x |
data = data, |
| 976 |
# TODO: need to remove linked_ids from the function and add module_id to the |
|
| 977 |
# parameters tibble |
|
| 978 | 18x |
linked_ids = population_module_ids |
| 979 |
) |
|
| 980 | ||
| 981 |
# Set-up TMB |
|
| 982 |
# Hard code to be a catch-at-age model |
|
| 983 | 18x |
fims_model <- methods::new(CatchAtAge) |
| 984 | 18x |
fims_model$AddPopulation(population$get_id()) |
| 985 | ||
| 986 | 18x |
CreateTMBModel() |
| 987 |
# Create parameter list from Rcpp modules |
|
| 988 | 16x |
parameter_list <- list( |
| 989 | 16x |
parameters = list( |
| 990 | 16x |
p = get_fixed(), |
| 991 | 16x |
re = get_random() |
| 992 |
), |
|
| 993 | 16x |
model = fims_model |
| 994 |
) |
|
| 995 | ||
| 996 | 16x |
return(parameter_list) |
| 997 |
} |
|
| 998 | ||
| 999 |
#' Set parameter vector values based on module input |
|
| 1000 |
#' |
|
| 1001 |
#' @description |
|
| 1002 |
#' This function sets the parameter vector values in a module based on the |
|
| 1003 |
#' provided module input, including both initial values and estimation |
|
| 1004 |
#' information. |
|
| 1005 |
#' @param field A character string specifying the field name of the parameter |
|
| 1006 |
#' vector to be updated. |
|
| 1007 |
#' @param module A module object in which the parameter vector is to be set. |
|
| 1008 |
#' @param module_input A list containing input parameters for the module, |
|
| 1009 |
#' including value and estimation information for the parameter vector. |
|
| 1010 |
#' @return |
|
| 1011 |
#' Modified module object. |
|
| 1012 |
#' @noRd |
|
| 1013 |
set_param_vector <- function(field, module, module_input) {
|
|
| 1014 |
# Check if field_name is a non-empty character string |
|
| 1015 | 339x |
if (missing(field) || !is.character(field) || nchar(field) == 0) {
|
| 1016 | 1x |
cli::cli_abort(c( |
| 1017 | 1x |
"The {.var field} argument must be a non-empty character string."
|
| 1018 |
)) |
|
| 1019 |
} |
|
| 1020 | ||
| 1021 |
# Check if module is a reference class |
|
| 1022 | 338x |
if (!is(module, "refClass")) {
|
| 1023 | 1x |
cli::cli_abort(c( |
| 1024 | 1x |
"The {.var module} argument must be a reference class created by
|
| 1025 | 1x |
{.fn methods::new}."
|
| 1026 |
)) |
|
| 1027 |
} |
|
| 1028 | ||
| 1029 |
# Check if module_input is a list |
|
| 1030 | 337x |
if (!tibble::is_tibble(module_input)) {
|
| 1031 | 1x |
cli::cli_abort("The {.var module_input} argument must be a tibble.")
|
| 1032 |
} |
|
| 1033 | ||
| 1034 |
# Extract the value of the parameter vector |
|
| 1035 | 336x |
field_value <- module_input |> |
| 1036 | 336x |
dplyr::filter(label == field) |> |
| 1037 | 336x |
dplyr::pull(value) |
| 1038 | ||
| 1039 | 336x |
field_estimation_type <- module_input |> |
| 1040 | 336x |
dplyr::filter(label == field) |> |
| 1041 | 336x |
dplyr::pull(estimation_type) |
| 1042 | ||
| 1043 |
# Check if both value and estimation information are present |
|
| 1044 | 336x |
if (length(field_value) == 0 || length(field_estimation_type) == 0) {
|
| 1045 | ! |
cli::cli_abort(c( |
| 1046 | ! |
"Missing value or estimation_type information for {.var field}."
|
| 1047 |
)) |
|
| 1048 |
} |
|
| 1049 |
# Resize the field in the module |
|
| 1050 | 336x |
module[[field]]$resize(length(field_value)) |
| 1051 | ||
| 1052 |
# Assign each value to the corresponding position in the parameter vector |
|
| 1053 | 336x |
for (i in seq_along(field_value)) {
|
| 1054 | 10192x |
module[[field]][i][["value"]] <- field_value[i] |
| 1055 | 10192x |
module[[field]][i][["estimation_type"]]$set(field_estimation_type[i]) |
| 1056 |
} |
|
| 1057 |
} |
| 1 |
# To remove the NOTE |
|
| 2 |
# no visible binding for global variable |
|
| 3 |
utils::globalVariables(c( |
|
| 4 |
"parameter_id", "module_name", "module_id", "label", |
|
| 5 |
"estimate", "estimate.x", "estimate.y", |
|
| 6 |
"initial", "initial.x", "initial.y", |
|
| 7 |
"derived_quantity_id", |
|
| 8 |
"distribution", "gradient", |
|
| 9 |
"log_like_cv", |
|
| 10 |
"module_type", "n", "type_id", "values", |
|
| 11 |
"module_name.x", "module_name.y", |
|
| 12 |
"module_id.x", "module_id.y", |
|
| 13 |
"module_id_init", |
|
| 14 |
"module_type.x", "module_type.y", |
|
| 15 |
"unique_id" |
|
| 16 |
)) |
|
| 17 | ||
| 18 |
# Developers: ---- |
|
| 19 | ||
| 20 |
# This file defines the parent class of FIMSFit and its potential children. The |
|
| 21 |
# class is an S4 class with accessors and validators but no setters. For more |
|
| 22 |
# details on how to create an S4 class in FIMS please see R/fimsframe.R |
|
| 23 | ||
| 24 |
# TODO: ---- |
|
| 25 | ||
| 26 |
# TODO: Fix "no metadata object found to revise superClass" in sdreportOrList |
|
| 27 |
# TODO: Write more validity checks for FIMSFit |
|
| 28 |
# TODO: Better document the return of [get_estimates()], i.e., columns |
|
| 29 |
# TODO: Make a helper function to add lower and upper CI for users in estimates |
|
| 30 | ||
| 31 |
# methods::setClass: ---- |
|
| 32 | ||
| 33 |
# Need to use an S3 class for the following S4 class |
|
| 34 |
methods::setOldClass(Classes = "package_version") |
|
| 35 |
methods::setOldClass(Classes = "difftime") |
|
| 36 |
methods::setOldClass(Classes = "sdreport") |
|
| 37 |
# Join sdreport and list into a class in case the sdreport is not created |
|
| 38 |
methods::setClassUnion("sdreportOrList", members = c("sdreport", "list"))
|
|
| 39 | ||
| 40 |
methods::setClass( |
|
| 41 |
Class = "FIMSFit", |
|
| 42 |
slots = c( |
|
| 43 |
input = "list", |
|
| 44 |
obj = "list", |
|
| 45 |
opt = "list", |
|
| 46 |
max_gradient = "numeric", |
|
| 47 |
report = "list", |
|
| 48 |
sdreport = "sdreportOrList", |
|
| 49 |
number_of_parameters = "integer", |
|
| 50 |
timing = "difftime", |
|
| 51 |
version = "package_version", |
|
| 52 |
model_output = "character" |
|
| 53 |
) |
|
| 54 |
) |
|
| 55 | ||
| 56 |
# methods::setMethod: printers ---- |
|
| 57 |
# TODO: add `get_report`, `get_opt`, etc. to the list of available slots in show()? |
|
| 58 |
methods::setMethod( |
|
| 59 |
f = "show", |
|
| 60 |
signature = "FIMSFit", |
|
| 61 |
definition = function(object) {
|
|
| 62 | ! |
cli::cli_inform(c( |
| 63 | ! |
"i" = "The object is of the class FIMSFit v.{get_version(object)}",
|
| 64 | ! |
"i" = "The slots can be accessed using {.fn get_*} functions, e.g.,",
|
| 65 | ! |
"*" = "{.fn get_model_output}",
|
| 66 | ! |
"*" = "{.fn get_obj}",
|
| 67 | ! |
"*" = "{.fn get_version}",
|
| 68 | ! |
"i" = "The following slots are available: {methods::slotNames(object)}.",
|
| 69 | ! |
"i" = "Use {.fn print} to see a summary of the fit."
|
| 70 |
)) |
|
| 71 |
} |
|
| 72 |
) |
|
| 73 | ||
| 74 |
methods::setMethod( |
|
| 75 |
f = "print", |
|
| 76 |
signature = "FIMSFit", |
|
| 77 |
definition = function(x) {
|
|
| 78 | 11x |
rt <- as.numeric(x@timing[["time_total"]], units = "secs") |
| 79 | 11x |
ru <- "seconds" |
| 80 | 11x |
if (rt > 60 * 60 * 24) {
|
| 81 | 1x |
rt <- rt / (60 * 60 * 24) |
| 82 | 1x |
ru <- "days" |
| 83 | 10x |
} else if (rt > 60 * 60) {
|
| 84 | 1x |
rt <- rt / (60 * 60) |
| 85 | 1x |
ru <- "hours" |
| 86 | 9x |
} else if (rt > 60) {
|
| 87 | 5x |
rt <- rt / 60 |
| 88 | 5x |
ru <- "minutes" |
| 89 |
} |
|
| 90 | ||
| 91 | 11x |
number_of_parameters <- paste( |
| 92 | 11x |
names(x@number_of_parameters), |
| 93 | 11x |
x@number_of_parameters, |
| 94 | 11x |
sep = "=" |
| 95 |
) |
|
| 96 | 11x |
total_parameters <- sum(x@number_of_parameters) |
| 97 | 11x |
all_parameters_info <- c(number_of_parameters, paste( |
| 98 | 11x |
"total", |
| 99 | 11x |
total_parameters, |
| 100 | 11x |
sep = "=" |
| 101 |
)) |
|
| 102 | 11x |
div_digit <- cli::cli_div(theme = list(.val = list(digits = 5))) |
| 103 | 11x |
terminal_ssb <- sapply( |
| 104 | 11x |
x@report[["spawning_biomass"]], |
| 105 | 11x |
function(y) utils::tail(y, 1) |
| 106 |
) |
|
| 107 | 11x |
cli::cli_inform(c( |
| 108 | 11x |
"i" = "FIMS model version: {.val {x@version}}",
|
| 109 | 11x |
"i" = "Total run time was {.val {rt}} {ru}",
|
| 110 | 11x |
"i" = "Number of parameters: {all_parameters_info}",
|
| 111 | 11x |
"i" = "Maximum gradient= {.val {x@max_gradient}}",
|
| 112 | 11x |
"i" = "Negative log likelihood (NLL):", |
| 113 | 11x |
"*" = "Marginal NLL= {.val {x@opt$objective}}",
|
| 114 | 11x |
"*" = "Total NLL= {.val {x@report$jnll}}",
|
| 115 | 11x |
"i" = "Terminal SB= {.val {terminal_ssb}}"
|
| 116 |
)) |
|
| 117 | 11x |
cli::cli_end(div_digit) |
| 118 |
} |
|
| 119 |
) |
|
| 120 | ||
| 121 |
# methods::setMethod: accessors ---- |
|
| 122 | ||
| 123 |
# Accessor functions for a FIMSFit object |
|
| 124 |
# 1 methods::setGeneric() per slot but potentially >1 methods::setMethod() per methods::setGeneric() |
|
| 125 | ||
| 126 |
#' Get a slot in a FIMSFit object |
|
| 127 |
#' |
|
| 128 |
#' There is an accessor function for each slot in the S4 class `FIMSFit`, where |
|
| 129 |
#' the function is named `get_*()` and the star can be replaced with the slot |
|
| 130 |
#' name, e.g., [get_input()]. These accessor functions are the preferred way |
|
| 131 |
#' to access objects stored in the available slots. |
|
| 132 |
#' |
|
| 133 |
#' @param x Output returned from [fit_fims()]. |
|
| 134 |
#' @name get_FIMSFit |
|
| 135 |
#' @seealso |
|
| 136 |
#' * [fit_fims()] |
|
| 137 |
#' * [create_default_parameters()] |
|
| 138 |
NULL |
|
| 139 | ||
| 140 |
#' @return |
|
| 141 |
#' [get_input()] returns the list that was used to fit the FIMS model, which |
|
| 142 |
#' is the returned object from [create_default_parameters()]. |
|
| 143 |
#' @export |
|
| 144 |
#' @rdname get_FIMSFit |
|
| 145 |
#' @keywords fit_fims |
|
| 146 | 8x |
methods::setGeneric("get_input", function(x) standardGeneric("get_input"))
|
| 147 |
#' @rdname get_FIMSFit |
|
| 148 |
#' @keywords fit_fims |
|
| 149 | 7x |
methods::setMethod("get_input", "FIMSFit", function(x) x@input)
|
| 150 | ||
| 151 |
#' @return |
|
| 152 |
#' [get_report()] returns the TMB report, where anything that is flagged as |
|
| 153 |
#' reportable in the C++ code is returned. |
|
| 154 |
#' @export |
|
| 155 |
#' @rdname get_FIMSFit |
|
| 156 |
#' @keywords fit_fims |
|
| 157 | 9x |
methods::setGeneric("get_report", function(x) standardGeneric("get_report"))
|
| 158 |
#' @rdname get_FIMSFit |
|
| 159 |
#' @keywords fit_fims |
|
| 160 | 9x |
methods::setMethod("get_report", "FIMSFit", function(x) x@report)
|
| 161 | ||
| 162 |
#' @return |
|
| 163 |
#' [get_obj()] returns the output from [TMB::MakeADFun()]. |
|
| 164 |
#' @export |
|
| 165 |
#' @rdname get_FIMSFit |
|
| 166 |
#' @keywords fit_fims |
|
| 167 | 66x |
methods::setGeneric("get_obj", function(x) standardGeneric("get_obj"))
|
| 168 |
#' @rdname get_FIMSFit |
|
| 169 |
#' @keywords fit_fims |
|
| 170 | 65x |
methods::setMethod("get_obj", "FIMSFit", function(x) x@obj)
|
| 171 | ||
| 172 |
#' @return |
|
| 173 |
#' [get_opt()] returns the output from [nlminb()], which is the minimizer used |
|
| 174 |
#' in [fit_fims()]. |
|
| 175 |
#' @export |
|
| 176 |
#' @rdname get_FIMSFit |
|
| 177 |
#' @keywords fit_fims |
|
| 178 | 37x |
methods::setGeneric("get_opt", function(x) standardGeneric("get_opt"))
|
| 179 |
#' @rdname get_FIMSFit |
|
| 180 |
#' @keywords fit_fims |
|
| 181 | 36x |
methods::setMethod("get_opt", "FIMSFit", function(x) x@opt)
|
| 182 | ||
| 183 |
#' @return |
|
| 184 |
#' [get_max_gradient()] returns the maximum gradient found when optimizing the |
|
| 185 |
#' model. |
|
| 186 |
#' @export |
|
| 187 |
#' @rdname get_FIMSFit |
|
| 188 |
#' @keywords fit_fims |
|
| 189 | 8x |
methods::setGeneric("get_max_gradient", function(x) standardGeneric("get_max_gradient"))
|
| 190 |
#' @rdname get_FIMSFit |
|
| 191 |
#' @keywords fit_fims |
|
| 192 | 7x |
methods::setMethod("get_max_gradient", "FIMSFit", function(x) x@max_gradient)
|
| 193 | ||
| 194 |
#' @return |
|
| 195 |
#' [get_sdreport()] returns the list from [TMB::sdreport()]. |
|
| 196 |
#' @export |
|
| 197 |
#' @rdname get_FIMSFit |
|
| 198 |
#' @keywords fit_fims |
|
| 199 | 37x |
methods::setGeneric("get_sdreport", function(x) standardGeneric("get_sdreport"))
|
| 200 |
#' @rdname get_FIMSFit |
|
| 201 |
#' @keywords fit_fims |
|
| 202 | 36x |
methods::setMethod("get_sdreport", "FIMSFit", function(x) x@sdreport)
|
| 203 | ||
| 204 |
#' @return |
|
| 205 |
#' [get_estimates()] returns a tibble of parameter values and their |
|
| 206 |
#' uncertainties from a fitted model. |
|
| 207 |
#' @export |
|
| 208 |
#' @rdname get_FIMSFit |
|
| 209 |
#' @keywords fit_fims |
|
| 210 | 22x |
methods::setGeneric("get_estimates", function(x) standardGeneric("get_estimates"))
|
| 211 |
#' @rdname get_FIMSFit |
|
| 212 |
#' @keywords fit_fims |
|
| 213 |
methods::setMethod( |
|
| 214 |
"get_estimates", |
|
| 215 |
"FIMSFit", |
|
| 216 |
function(x) {
|
|
| 217 |
# Helper function |
|
| 218 | 21x |
add_unique_id <- function(data) {
|
| 219 | 42x |
dplyr::group_by(data, label) |> |
| 220 | 42x |
dplyr::mutate( |
| 221 | 42x |
unique_id = paste( |
| 222 | 42x |
label, |
| 223 | 42x |
dplyr::if_else( |
| 224 | 42x |
is.na(parameter_id), |
| 225 | 42x |
seq_len(dplyr::n()), |
| 226 | 42x |
parameter_id |
| 227 |
), |
|
| 228 | 42x |
sep = "_" |
| 229 |
) |
|
| 230 |
) |> |
|
| 231 | 42x |
dplyr::ungroup() |
| 232 |
} |
|
| 233 |
# Extract the core TMB components (object, sdreport, optimization result) |
|
| 234 |
# from the fit object. |
|
| 235 | 21x |
obj <- get_obj(x) |
| 236 | 21x |
sdreport <- get_sdreport(x) |
| 237 | 21x |
opt <- get_opt(x) |
| 238 | 21x |
parameter_names <- get_obj(x)[["par"]] |> |
| 239 | 21x |
names() |
| 240 | ||
| 241 |
# Reshape the TMB output into a standardized data frame. |
|
| 242 |
# This serves as the "expected" result to compare against. |
|
| 243 | 21x |
tmb_output <- reshape_tmb_estimates( |
| 244 | 21x |
obj = obj, |
| 245 | 21x |
sdreport = sdreport, |
| 246 | 21x |
opt = opt, |
| 247 | 21x |
parameter_names = parameter_names |
| 248 |
) |> |
|
| 249 | 21x |
add_unique_id() |
| 250 | ||
| 251 |
# Extract the model_output, which contains the JSON-like structure. |
|
| 252 | 21x |
model_output <- get_model_output(x) |
| 253 |
# Reshape the output from the JSON structure into a data frame. |
|
| 254 | 21x |
json_output <- reshape_json_estimates(model_output) |> |
| 255 | 21x |
add_unique_id() |
| 256 | ||
| 257 |
# Join the two outputs on parameter_id to compare and consolidate information. |
|
| 258 | 21x |
estimates <- dplyr::left_join( |
| 259 |
# There are more rows in json_estimates than tmb_estimates |
|
| 260 | 21x |
x = json_output, |
| 261 | 21x |
y = tmb_output |> |
| 262 | 21x |
dplyr::select(unique_id, uncertainty, log_like_cv, gradient), |
| 263 | 21x |
by = c("unique_id")
|
| 264 |
) |> |
|
| 265 | 21x |
dplyr::select(-unique_id) |> |
| 266 | 21x |
dplyr::relocate(uncertainty, .after = estimation_type) |
| 267 |
} |
|
| 268 |
) |
|
| 269 | ||
| 270 |
#' @return |
|
| 271 |
#' [get_number_of_parameters()] returns a vector of integers specifying the |
|
| 272 |
#' number of fixed-effect parameters and the number of random-effect parameters |
|
| 273 |
#' in the model. |
|
| 274 |
#' @export |
|
| 275 |
#' @rdname get_FIMSFit |
|
| 276 |
#' @keywords fit_fims |
|
| 277 |
methods::setGeneric( |
|
| 278 |
"get_number_of_parameters", |
|
| 279 | 12x |
function(x) standardGeneric("get_number_of_parameters")
|
| 280 |
) |
|
| 281 |
#' @rdname get_FIMSFit |
|
| 282 |
#' @keywords fit_fims |
|
| 283 |
methods::setMethod( |
|
| 284 |
"get_number_of_parameters", |
|
| 285 |
"FIMSFit", |
|
| 286 | 11x |
function(x) x@number_of_parameters |
| 287 |
) |
|
| 288 | ||
| 289 |
#' @return |
|
| 290 |
#' [get_timing()] returns the amount of time it took to run the model in |
|
| 291 |
#' seconds as a `difftime` object. |
|
| 292 |
#' @export |
|
| 293 |
#' @rdname get_FIMSFit |
|
| 294 |
#' @keywords fit_fims |
|
| 295 | 8x |
methods::setGeneric("get_timing", function(x) standardGeneric("get_timing"))
|
| 296 |
#' @rdname get_FIMSFit |
|
| 297 |
#' @keywords fit_fims |
|
| 298 | 7x |
methods::setMethod("get_timing", "FIMSFit", function(x) x@timing)
|
| 299 | ||
| 300 |
#' @return |
|
| 301 |
#' [get_version()] returns the `package_version` of FIMS that was used to fit |
|
| 302 |
#' the model. |
|
| 303 |
#' @export |
|
| 304 |
#' @rdname get_FIMSFit |
|
| 305 |
#' @keywords fit_fims |
|
| 306 | 8x |
methods::setGeneric("get_version", function(x) standardGeneric("get_version"))
|
| 307 |
#' @rdname get_FIMSFit |
|
| 308 |
#' @keywords fit_fims |
|
| 309 | 7x |
methods::setMethod("get_version", "FIMSFit", function(x) x@version)
|
| 310 | ||
| 311 |
#' @return |
|
| 312 |
#' [get_model_output()] returns the finalized FIMS output as a JSON list. |
|
| 313 |
#' @export |
|
| 314 |
#' @rdname get_FIMSFit |
|
| 315 |
#' @keywords fit_fims |
|
| 316 | 37x |
methods::setGeneric("get_model_output", function(x) standardGeneric("get_model_output"))
|
| 317 |
#' @rdname get_FIMSFit |
|
| 318 |
#' @keywords fit_fims |
|
| 319 | 37x |
methods::setMethod("get_model_output", "FIMSFit", function(x) x@model_output)
|
| 320 | ||
| 321 |
# methods::setValidity ---- |
|
| 322 | ||
| 323 |
methods::setValidity( |
|
| 324 |
Class = "FIMSFit", |
|
| 325 |
method = function(object) {
|
|
| 326 |
errors <- character() |
|
| 327 | ||
| 328 |
# Check that obj is from TMB::MakeADFun() |
|
| 329 |
TMB_MakeADFun_names <- c( |
|
| 330 |
"par", "fn", "gr", "he", "hessian", "method", "retape", "env", "report", |
|
| 331 |
"simulate" |
|
| 332 |
) |
|
| 333 |
if (!setequal(names(object@obj), TMB_MakeADFun_names)) {
|
|
| 334 |
errors <- c( |
|
| 335 |
errors, |
|
| 336 |
"obj must be a list returned from TMB::MakeADFun() but it does not |
|
| 337 |
appear to be so because it does not have the standard names." |
|
| 338 |
) |
|
| 339 |
} |
|
| 340 | ||
| 341 |
# Return |
|
| 342 |
if (length(errors) == 0) {
|
|
| 343 |
return(TRUE) |
|
| 344 |
} else {
|
|
| 345 |
return(errors) |
|
| 346 |
} |
|
| 347 |
} |
|
| 348 |
) |
|
| 349 | ||
| 350 |
# methods::setMethod: is.FIMSFit ---- |
|
| 351 | ||
| 352 |
#' Check if an object is of class FIMSFit |
|
| 353 |
#' |
|
| 354 |
#' @param x Returned list from [fit_fims()]. |
|
| 355 |
#' @keywords fit_fims |
|
| 356 |
#' @export |
|
| 357 |
is.FIMSFit <- function(x) {
|
|
| 358 | 2x |
inherits(x, "FIMSFit") |
| 359 |
} |
|
| 360 | ||
| 361 |
# Constructors ---- |
|
| 362 | ||
| 363 |
#' Class constructors for class `FIMSFit` and associated child classes |
|
| 364 |
#' |
|
| 365 |
#' Create an object with the class of `FIMSFit` after running a FIMS model. This |
|
| 366 |
#' is typically done within [fit_fims()] but it can be create manually by the |
|
| 367 |
#' user if they have used their own bespoke code to fit a FIMS model. |
|
| 368 |
#' |
|
| 369 |
#' @inheritParams fit_fims |
|
| 370 |
#' @param obj An object returned from [TMB::MakeADFun()]. |
|
| 371 |
#' @param opt An object returned from an optimizer, typically from |
|
| 372 |
#' [stats::nlminb()], used to fit a TMB model. |
|
| 373 |
#' @param sdreport An object of the `sdreport` class as returned from |
|
| 374 |
#' [TMB::sdreport()]. |
|
| 375 |
#' @param timing A vector of at least length one, where all entries are of the |
|
| 376 |
#' `timediff` class and at least one is named "time_total". This information |
|
| 377 |
#' is available in [fit_fims()] and added to this argument internally but if |
|
| 378 |
#' you are a power user you can calculate the time it took to run your model |
|
| 379 |
#' by subtracting two [Sys.time()] objects. |
|
| 380 |
#' @param version The version of FIMS that was used to optimize the model. If |
|
| 381 |
#' [fit_fims()] was not used to optimize the model, then the default is to |
|
| 382 |
#' use the current version of the package that is loaded. |
|
| 383 |
#' |
|
| 384 |
#' @return |
|
| 385 |
#' An object with an S4 class of `FIMSFit` is returned. The object will have the |
|
| 386 |
#' following slots: |
|
| 387 |
#' \describe{
|
|
| 388 |
#' \item{\code{input}:}{
|
|
| 389 |
#' A list containing the model setup in the same form it was passed. |
|
| 390 |
#' } |
|
| 391 |
#' \item{\code{obj}:}{
|
|
| 392 |
#' A list returned from [TMB::MakeADFun()] in the same form it was passed. |
|
| 393 |
#' } |
|
| 394 |
#' \item{\code{opt}:}{
|
|
| 395 |
#' A list containing the optimized model in the same form it was passed. |
|
| 396 |
#' } |
|
| 397 |
#' \item{\code{max_gradient}:}{
|
|
| 398 |
#' The maximum gradient found when optimizing the model. The default is |
|
| 399 |
#' `NA`, which means that the model was not optimized. |
|
| 400 |
#' } |
|
| 401 |
#' \item{\code{report}:}{
|
|
| 402 |
#' A list containing the model report from `obj[["report"]]()`. |
|
| 403 |
#' } |
|
| 404 |
#' \item{\code{sdreport}:}{
|
|
| 405 |
#' An object with the `sdreport` class containing the output from |
|
| 406 |
#' `TMB::sdreport(obj)`. |
|
| 407 |
#' } |
|
| 408 |
#' \item{\code{timing}:}{
|
|
| 409 |
#' The length of time it took to run the model if it was optimized. |
|
| 410 |
#' } |
|
| 411 |
#' \item{\code{version}:}{
|
|
| 412 |
#' The package version of FIMS used to fit the model or at least the |
|
| 413 |
#' version used to create this output, which will not always be the same |
|
| 414 |
#' if you are running this function yourself. |
|
| 415 |
#' } |
|
| 416 |
#' \item{\code{model_output}:}{
|
|
| 417 |
#' The FIMS model output as a JSON string. |
|
| 418 |
#' } |
|
| 419 |
#' } |
|
| 420 |
#' @keywords fit_fims |
|
| 421 |
#' @export |
|
| 422 |
FIMSFit <- function( |
|
| 423 |
input, |
|
| 424 |
obj, |
|
| 425 |
opt = list(), |
|
| 426 |
sdreport = list(), |
|
| 427 |
timing = c("time_total" = as.difftime(0, units = "secs")),
|
|
| 428 |
version = utils::packageVersion("FIMS")
|
|
| 429 |
) {
|
|
| 430 |
# Determine the number of parameters |
|
| 431 | 13x |
n_total <- length(obj[["env"]][["last.par.best"]]) |
| 432 | 13x |
n_fixed_effects <- length(obj[["par"]]) |
| 433 | 13x |
n_random_effects <- length(obj[["env"]]$parList()[["re"]]) |
| 434 | 13x |
number_of_parameters <- c( |
| 435 | 13x |
fixed_effects = n_fixed_effects, |
| 436 | 13x |
random_effects = n_random_effects |
| 437 |
) |
|
| 438 | 13x |
rm(n_total, n_fixed_effects, n_random_effects) |
| 439 | ||
| 440 |
# Calculate the maximum gradient |
|
| 441 | 13x |
max_gradient <- if (length(opt) > 0) {
|
| 442 | 8x |
max(abs(obj[["gr"]](opt[["par"]]))) |
| 443 |
} else {
|
|
| 444 | 13x |
NA_real_ |
| 445 |
} |
|
| 446 | ||
| 447 |
# Rename parameters instead of "p" |
|
| 448 | 13x |
parameter_names <- names(get_parameter_names(obj[["par"]])) |
| 449 | 13x |
names(obj[["par"]]) <- parameter_names |
| 450 | 13x |
random_effects_names <- names(get_random_names(obj[["env"]]$parList()[["re"]])) |
| 451 | ||
| 452 |
# Get the report |
|
| 453 | 13x |
report <- if (length(opt) == 0) {
|
| 454 | 5x |
obj[["report"]](obj[["env"]][["last.par.best"]]) |
| 455 |
} else {
|
|
| 456 | 8x |
obj[["report"]]() |
| 457 |
} |
|
| 458 | ||
| 459 | 13x |
if (length(sdreport) > 0) {
|
| 460 |
# rename the sdreport |
|
| 461 | 8x |
names(sdreport[["par.fixed"]]) <- parameter_names |
| 462 | 8x |
dimnames(sdreport[["cov.fixed"]]) <- list(parameter_names, parameter_names) |
| 463 |
} |
|
| 464 | ||
| 465 | 13x |
model_output <- input[["model"]]$get_output() |
| 466 | ||
| 467 | 13x |
fit <- methods::new( |
| 468 | 13x |
"FIMSFit", |
| 469 | 13x |
input = input, |
| 470 | 13x |
obj = obj, |
| 471 | 13x |
opt = opt, |
| 472 | 13x |
max_gradient = max_gradient, |
| 473 | 13x |
report = report, |
| 474 | 13x |
sdreport = sdreport, |
| 475 | 13x |
number_of_parameters = number_of_parameters, |
| 476 | 13x |
timing = timing, |
| 477 | 13x |
version = version, |
| 478 | 13x |
model_output = model_output |
| 479 |
) |
|
| 480 | 13x |
fit |
| 481 |
} |
|
| 482 | ||
| 483 |
#' Fit a FIMS model (BETA) |
|
| 484 |
#' |
|
| 485 |
#' @param input Input list as returned by [initialize_fims()]. |
|
| 486 |
#' @param get_sd A boolean specifying if the [TMB::sdreport()] should be |
|
| 487 |
#' calculated? |
|
| 488 |
#' @param save_sd A logical, with the default `TRUE`, indicating whether the |
|
| 489 |
#' sdreport is returned in the output. If `FALSE`, the slot for the report |
|
| 490 |
#' will be empty. |
|
| 491 |
#' @param number_of_loops A positive integer specifying the number of |
|
| 492 |
#' iterations of the optimizer that will be performed to improve the |
|
| 493 |
#' gradient. The default is three, leading to four total optimization steps. |
|
| 494 |
#' @param optimize Optimize (TRUE, default) or (FALSE) build and return |
|
| 495 |
#' a list containing the obj and report slot. |
|
| 496 |
#' @param number_of_newton_steps The number of Newton steps using the inverse |
|
| 497 |
#' Hessian to do after optimization. Not yet implemented. |
|
| 498 |
#' @param control A list of optimizer settings passed to [stats::nlminb()]. The |
|
| 499 |
#' the default is a list of length three with `eval.max = 1000`, |
|
| 500 |
#' `iter.max = 10000`, and `trace = 0`. |
|
| 501 |
#' @param filename Character string giving a file name to save the fitted |
|
| 502 |
#' object as an RDS object. Defaults to 'fit.RDS', and a value of NULL |
|
| 503 |
#' indicates not to save it. If specified, it must end in .RDS. The file is |
|
| 504 |
#' written to folder given by `input[["path"]]`. Not yet implemented. |
|
| 505 |
#' @return |
|
| 506 |
#' An object of class `FIMSFit` is returned, where the structure is the same |
|
| 507 |
#' regardless if `optimize = TRUE` or not. Uncertainty information is only |
|
| 508 |
#' included in the `estimates` slot if `get_sd = TRUE`. |
|
| 509 |
#' @seealso |
|
| 510 |
#' * [FIMSFit()] |
|
| 511 |
#' @details This function is a beta version still and subject to change |
|
| 512 |
#' without warning. |
|
| 513 |
#' @keywords fit_fims |
|
| 514 |
#' @export |
|
| 515 |
fit_fims <- function(input, |
|
| 516 |
get_sd = TRUE, |
|
| 517 |
save_sd = TRUE, |
|
| 518 |
number_of_loops = 3, |
|
| 519 |
optimize = TRUE, |
|
| 520 |
number_of_newton_steps = 0, |
|
| 521 |
control = list( |
|
| 522 |
eval.max = 10000, |
|
| 523 |
iter.max = 10000, |
|
| 524 |
trace = 0 |
|
| 525 |
), |
|
| 526 |
filename = NULL) {
|
|
| 527 |
# See issue 455 of sdmTMB to see what should be used. |
|
| 528 |
# https://github.com/pbs-assess/sdmTMB/issues/455 |
|
| 529 |
# NOTE: When we add implementation for newton step we need to |
|
| 530 |
# review the above github issue to make sure we maintain continuity |
|
| 531 |
# between outputs as last.par may not equal last.par.best due to |
|
| 532 |
# the smallest newton gradient solution not matching the smallest |
|
| 533 |
# likelihood value. This can cause sanity issues in output reporting. |
|
| 534 | 18x |
if (number_of_newton_steps > 0) {
|
| 535 | ! |
cli::cli_abort("Newton steps not implemented yet.")
|
| 536 |
} |
|
| 537 | 18x |
if (number_of_loops < 0) {
|
| 538 | ! |
cli::cli_abort("number_of_loops ({.par {number_of_loops}}) must be >= 0.")
|
| 539 |
} |
|
| 540 |
# If the estimation_type of all parameters is constant, FIMS will abort if |
|
| 541 |
# optimize is set to TRUE |
|
| 542 | 18x |
if (optimize == TRUE & all(purrr::map_vec(input[["parameters"]], length) == 0)) {
|
| 543 | 1x |
cli::cli_abort("FIMS must have at least one parameter to optimize.")
|
| 544 |
} |
|
| 545 | ||
| 546 | 13x |
obj <- TMB::MakeADFun( |
| 547 | 13x |
data = list(), |
| 548 | 13x |
parameters = input$parameters, |
| 549 | 13x |
map = input$map, |
| 550 | 13x |
random = "re", |
| 551 | 13x |
DLL = "FIMS", |
| 552 | 13x |
silent = TRUE |
| 553 |
) |
|
| 554 | 13x |
if (!optimize) {
|
| 555 | 5x |
initial_fit <- FIMSFit( |
| 556 | 5x |
input = input, |
| 557 | 5x |
obj = obj, |
| 558 | 5x |
timing = c("time_total" = as.difftime(0, units = "secs"))
|
| 559 |
) |
|
| 560 | 5x |
return(initial_fit) |
| 561 |
} |
|
| 562 | 8x |
if (!is_fims_verbose()) {
|
| 563 | 8x |
control$trace <- 0 |
| 564 |
} |
|
| 565 |
## optimize and compare |
|
| 566 | 8x |
cli::cli_inform(c("v" = "Starting optimization ..."))
|
| 567 | 8x |
t0 <- Sys.time() |
| 568 | 8x |
opt <- with( |
| 569 | 8x |
obj, |
| 570 | 8x |
nlminb( |
| 571 | 8x |
start = par, |
| 572 | 8x |
objective = fn, |
| 573 | 8x |
gradient = gr, |
| 574 | 8x |
control = control |
| 575 |
) |
|
| 576 |
) |
|
| 577 | 8x |
maxgrad0 <- maxgrad <- max(abs(obj$gr(opt$par))) |
| 578 | 8x |
if (number_of_loops > 0) {
|
| 579 | 8x |
cli::cli_inform(c( |
| 580 | 8x |
"i" = "Restarting optimizer {number_of_loops} times to improve gradient."
|
| 581 |
)) |
|
| 582 | 8x |
for (ii in 1:number_of_loops) {
|
| 583 |
# control$trace is reset to zero regardless of verbosity because the |
|
| 584 |
# differences in values printed out using control$trace will be |
|
| 585 |
# negligible between these different runs and is not worth printing |
|
| 586 | 24x |
control$trace <- 0 |
| 587 | 24x |
opt <- with( |
| 588 | 24x |
obj, |
| 589 | 24x |
nlminb( |
| 590 | 24x |
start = opt[["par"]], |
| 591 | 24x |
objective = fn, |
| 592 | 24x |
gradient = gr, |
| 593 | 24x |
control = control |
| 594 |
) |
|
| 595 |
) |
|
| 596 | 24x |
maxgrad <- max(abs(obj[["gr"]](opt[["par"]]))) |
| 597 |
} |
|
| 598 | 8x |
div_digit <- cli::cli_div(theme = list(.val = list(digits = 5))) |
| 599 | 8x |
cli::cli_inform(c( |
| 600 | 8x |
"i" = "Maximum gradient went from {.val {maxgrad0}} to
|
| 601 | 8x |
{.val {maxgrad}} after {number_of_loops} steps."
|
| 602 |
)) |
|
| 603 | 8x |
cli::cli_end(div_digit) |
| 604 |
} |
|
| 605 | 8x |
time_optimization <- Sys.time() - t0 |
| 606 | 8x |
cli::cli_inform(c("v" = "Finished optimization"))
|
| 607 | 8x |
set_fixed(opt$par) |
| 608 | ||
| 609 | 8x |
time_sdreport <- NA |
| 610 | 8x |
if (get_sd) {
|
| 611 | 8x |
t2 <- Sys.time() |
| 612 | 8x |
sdreport <- TMB::sdreport(obj) |
| 613 | 8x |
cli::cli_inform(c("v" = "Finished sdreport"))
|
| 614 | 8x |
time_sdreport <- Sys.time() - t2 |
| 615 |
} else {
|
|
| 616 | ! |
sdreport <- list() |
| 617 | ! |
time_sdreport <- as.difftime(0, units = "secs") |
| 618 |
} |
|
| 619 | ||
| 620 | 8x |
timing <- c( |
| 621 | 8x |
time_optimization = time_optimization, |
| 622 | 8x |
time_sdreport = time_sdreport, |
| 623 | 8x |
time_total = Sys.time() - t0 |
| 624 |
) |
|
| 625 | 8x |
fit <- FIMSFit( |
| 626 | 8x |
input = input, |
| 627 | 8x |
obj = obj, |
| 628 | 8x |
opt = opt, |
| 629 | 8x |
sdreport = sdreport, |
| 630 | 8x |
timing = timing |
| 631 |
) |
|
| 632 | 8x |
print(fit) |
| 633 | 8x |
if (!is.null(filename)) {
|
| 634 | ! |
cli::cli_warn(c( |
| 635 | ! |
"i" = "Saving output to file is not yet implemented." |
| 636 |
)) |
|
| 637 |
# saveRDS(fit, file=file.path(input[["path"]], filename)) |
|
| 638 |
} |
|
| 639 | 8x |
return(fit) |
| 640 |
} |
|
| 641 | ||
| 642 |
# we create an as.list method for this new FIMSFit |
|
| 643 |
methods::setMethod("as.list", signature(x = "FIMSFit"), function(x) {
|
|
| 644 | 2x |
mapply( |
| 645 | 2x |
function(y) {
|
| 646 |
# apply as.list if the slot is again an user-defined object |
|
| 647 |
# therefore, as.list gets applied recursively |
|
| 648 | 20x |
if (inherits(slot(x, y), "FIMSFit")) {
|
| 649 | ! |
as.list(slot(x, y)) |
| 650 |
} else {
|
|
| 651 |
# otherwise just return the slot |
|
| 652 | 20x |
slot(x, y) |
| 653 |
} |
|
| 654 |
}, |
|
| 655 | 2x |
slotNames(class(x)), |
| 656 | 2x |
SIMPLIFY = FALSE |
| 657 |
) |
|
| 658 |
}) |
| 1 |
# TODO: Document the names/items in each list that are returned |
|
| 2 | ||
| 3 |
# To remove the WARNING |
|
| 4 |
# no visible binding for global variable |
|
| 5 |
utils::globalVariables(c( |
|
| 6 |
"distribution.x", "distribution.y", |
|
| 7 |
"distribution_link", |
|
| 8 |
"distribution_type.x", "distribution_type.y", |
|
| 9 |
"fleet_name", |
|
| 10 |
"model_family", "model_family.x", "model_family.y" |
|
| 11 |
)) |
|
| 12 | ||
| 13 |
#' Create default parameters for a FIMS model |
|
| 14 |
#' |
|
| 15 |
#' @description |
|
| 16 |
#' This function generates a Fisheries Integrated Modeling System (FIMS) model |
|
| 17 |
#' configuration with detailed parameter specifications. This function takes a |
|
| 18 |
#' high-level configuration `tibble` and generates the corresponding parameters |
|
| 19 |
#' with default initial values and estimation settings required to build and run |
|
| 20 |
#' the model. |
|
| 21 |
#' |
|
| 22 |
#' @details |
|
| 23 |
#' The function processes the input `configurations` tibble, which defines the |
|
| 24 |
#' modules for different model components (e.g., `"Selectivity"`, `"Recruitment"`). |
|
| 25 |
#' For each module specified, it calls internal helper functions to create a |
|
| 26 |
#' default set of parameters. For example, if a fleet's selectivity is configured |
|
| 27 |
#' as `"Logistic"`, it generates initial values for `"inflection_point"` and |
|
| 28 |
#' `"slope"`. |
|
| 29 |
#' |
|
| 30 |
#' @param configurations A tibble of model configurations. Typically created |
|
| 31 |
#' by [create_default_configurations()]. Users can modify this tibble |
|
| 32 |
#' to customize the model structure before generating default parameters. |
|
| 33 |
#' @param data An S4 object. FIMS input data. |
|
| 34 |
#' @return A `tibble` with default model parameters. The tibble has a nested |
|
| 35 |
#' structure with the following top-level columns. |
|
| 36 |
#' \describe{
|
|
| 37 |
#' \item{\code{model_family}:}{The specified model family (e.g.,
|
|
| 38 |
#' "catch_at_age").} |
|
| 39 |
#' \item{\code{module_name}:}{The name of the FIMS module (e.g.,
|
|
| 40 |
#' "Data", "Selectivity", "Recruitment", "Growth", "Maturity").} |
|
| 41 |
#' \item{\code{fleet_name}:}{The name of the fleet the module applies to. This
|
|
| 42 |
#' will be `NA` for non-fleet-specific modules like "Recruitment".} |
|
| 43 |
#' \item{\code{data}:}{A list-column containing a `tibble` with detailed
|
|
| 44 |
#' parameters. Unnesting this column reveals: |
|
| 45 |
#' \describe{
|
|
| 46 |
#' \item{\code{module_type}:}{The specific type of the module (e.g.,
|
|
| 47 |
#' "Logistic" for a "Selectivity" module).} |
|
| 48 |
#' \item{\code{label}:}{The name of the parameter (e.g., "inflection_point").}
|
|
| 49 |
#' \item{\code{distribution_link}:}{The component the distribution module
|
|
| 50 |
#' links to.} |
|
| 51 |
#' \item{\code{age}:}{The age the parameter applies to.}
|
|
| 52 |
#' \item{\code{length}:}{The length bin the parameter applies to.}
|
|
| 53 |
#' \item{\code{time}:}{The time step (i.e., year) the parameter applies to.}
|
|
| 54 |
#' \item{\code{value}:}{The initial value of the parameter.}
|
|
| 55 |
#' \item{\code{estimation_type}:}{The type of estimation (e.g.,
|
|
| 56 |
#' "constant", "fixed_effects", "random_effects").} |
|
| 57 |
#' \item{\code{distribution_type}:}{The type of distribution (e.g., "Data",
|
|
| 58 |
#' "process").} |
|
| 59 |
#' \item{\code{distribution}:}{The name of distribution (e.g.,
|
|
| 60 |
#' "Dlnorm", `Dmultinom`).} |
|
| 61 |
#' } |
|
| 62 |
#' } |
|
| 63 |
#' } |
|
| 64 |
#' @export |
|
| 65 |
#' @seealso |
|
| 66 |
#' * [FIMSFrame()] |
|
| 67 |
#' * [create_default_configurations()] |
|
| 68 |
#' @examples |
|
| 69 |
#' \dontrun{
|
|
| 70 |
#' # Load the example dataset and create a FIMS data frame |
|
| 71 |
#' data("data_big")
|
|
| 72 |
#' fims_frame <- FIMSFrame(data_big) |
|
| 73 |
#' |
|
| 74 |
#' # Create default configurations |
|
| 75 |
#' default_configurations <- create_default_configurations(fims_frame) |
|
| 76 |
#' |
|
| 77 |
#' # Create default parameters |
|
| 78 |
#' default_parameters <- create_default_parameters( |
|
| 79 |
#' configurations = default_configurations, |
|
| 80 |
#' data = fims_frame |
|
| 81 |
#' ) |> |
|
| 82 |
#' tidyr::unnest(cols = data) |
|
| 83 |
#' |
|
| 84 |
#' # Update selectivity parameters for survey1 |
|
| 85 |
#' updated_parameters <- default_parameters |> |
|
| 86 |
#' dplyr::rows_update( |
|
| 87 |
#' tibble::tibble( |
|
| 88 |
#' fleet_name = "survey1", |
|
| 89 |
#' label = c("inflection_point", "slope"),
|
|
| 90 |
#' value = c(1.5, 2) |
|
| 91 |
#' ), |
|
| 92 |
#' by = c("fleet_name", "label")
|
|
| 93 |
#' ) |
|
| 94 |
#' |
|
| 95 |
#' # Do the same as above except, model fleet1 with double logistic selectivity |
|
| 96 |
#' # To see required parameters for double logistic selectivity, run |
|
| 97 |
#' # show(DoubleLogisticSelectivity) |
|
| 98 |
#' parameters_with_double_logistic <- default_configurations |> |
|
| 99 |
#' tidyr::unnest(cols = data) |> |
|
| 100 |
#' dplyr::rows_update( |
|
| 101 |
#' tibble::tibble( |
|
| 102 |
#' module_name = "Selectivity", |
|
| 103 |
#' fleet_name = "fleet1", |
|
| 104 |
#' module_type = "DoubleLogistic" |
|
| 105 |
#' ), |
|
| 106 |
#' by = c("module_name", "fleet_name")
|
|
| 107 |
#' ) |> |
|
| 108 |
#' create_default_parameters( |
|
| 109 |
#' data = fims_frame |
|
| 110 |
#' ) |
|
| 111 |
#' } |
|
| 112 |
create_default_parameters <- function( |
|
| 113 |
configurations, |
|
| 114 |
data |
|
| 115 |
) {
|
|
| 116 |
# FIXME: use default values if there are no fleets info passed into the |
|
| 117 |
# function or a fleet is not present but it has data? Maybe we don't want the |
|
| 118 |
# latter because it could be that we want to drop a fleet from a model but we |
|
| 119 |
# don't want to alter the data? |
|
| 120 | ||
| 121 |
# Check if configurations is a nested tibble. If so, unnest configurations |
|
| 122 | 5x |
if ("data" %in% names(configurations)) {
|
| 123 | 5x |
unnested_configurations <- tidyr::unnest(configurations, cols = data) |
| 124 |
} else {
|
|
| 125 | ! |
unnested_configurations <- configurations |
| 126 |
} |
|
| 127 | ||
| 128 |
# Create fleet parameters |
|
| 129 | 5x |
fleet_names <- unnested_configurations |> |
| 130 | 5x |
dplyr::pull(fleet_name) |> |
| 131 | 5x |
na.omit() |> |
| 132 | 5x |
unique() |
| 133 | 5x |
fleet_temp <- purrr::map( |
| 134 | 5x |
fleet_names, |
| 135 | 5x |
function(fleet_name_i) {
|
| 136 | 10x |
create_default_fleet( |
| 137 | 10x |
unnested_configurations = unnested_configurations, |
| 138 | 10x |
current_fleet_name = fleet_name_i, |
| 139 | 10x |
data = data |
| 140 |
) |
|
| 141 |
} |
|
| 142 |
) |> |
|
| 143 |
# bind_rows now directly takes the list of tibbles from map() |
|
| 144 | 5x |
dplyr::bind_rows() |
| 145 | ||
| 146 |
# Create recruitment parameters |
|
| 147 | 5x |
recruitment_temp <- create_default_recruitment( |
| 148 | 5x |
unnested_configurations = unnested_configurations, |
| 149 | 5x |
data = data |
| 150 |
) |
|
| 151 | ||
| 152 |
# Create maturity parameters |
|
| 153 | 5x |
maturity_temp <- create_default_maturity( |
| 154 | 5x |
unnested_configurations = unnested_configurations, |
| 155 | 5x |
data = data |
| 156 |
) |
|
| 157 | ||
| 158 |
# Create population parameters |
|
| 159 |
# Handle population parameters based on recruitment form |
|
| 160 | 5x |
log_rzero <- recruitment_temp |> |
| 161 | 5x |
dplyr::filter(label == "log_rzero") |> |
| 162 | 5x |
dplyr::pull(value) |
| 163 | ||
| 164 | 5x |
population_temp <- create_default_Population( |
| 165 | 5x |
unnested_configurations = unnested_configurations, |
| 166 | 5x |
data, |
| 167 | 5x |
log_rzero = log_rzero |
| 168 |
) |
|
| 169 | ||
| 170 |
# Compile temps |
|
| 171 | 5x |
temp <- dplyr::bind_rows( |
| 172 | 5x |
fleet_temp, |
| 173 | 5x |
recruitment_temp, |
| 174 | 5x |
maturity_temp, |
| 175 | 5x |
population_temp |
| 176 |
) |
|
| 177 |
# Merge with configuration_unnest |
|
| 178 | 5x |
expanded_configurations <- dplyr::full_join( |
| 179 | 5x |
temp, |
| 180 | 5x |
unnested_configurations, |
| 181 | 5x |
by = c("module_name", "fleet_name", "module_type", "distribution_link")
|
| 182 |
) |> |
|
| 183 | 5x |
dplyr::mutate( |
| 184 | 5x |
model_family = dplyr::coalesce(model_family.y, model_family.x), |
| 185 | 5x |
distribution_type = dplyr::coalesce(distribution_type.y, distribution_type.x), |
| 186 | 5x |
distribution = dplyr::coalesce(distribution.y, distribution.x) |
| 187 |
) |> |
|
| 188 | 5x |
dplyr::select(-dplyr::ends_with(c(".x", ".y"))) |>
|
| 189 | 5x |
tidyr::fill(model_family) |> |
| 190 | 5x |
dplyr::select( |
| 191 | 5x |
model_family, module_name, module_type, label, distribution_link, dplyr::everything() |
| 192 |
) |> |
|
| 193 | 5x |
tidyr::nest(.by = c(model_family, module_name, fleet_name)) |
| 194 |
} |
|
| 195 | ||
| 196 |
#' Create default parameters for a FIMS model |
|
| 197 |
#' @description |
|
| 198 |
#' This function creates a template for default parameters used in a Fisheries |
|
| 199 |
#' Integrated Modeling System (FIMS) model. The template includes fields for |
|
| 200 |
#' module name, module type, label, fleet name, population name, age, length, |
|
| 201 |
#' time, value, estimation type, distribution type, and distribution. |
|
| 202 |
#' @param n_parameters An integer specifying the number of parameters in the template. |
|
| 203 |
#' @return |
|
| 204 |
#' A tibble template for a FIMS model. |
|
| 205 |
#' @noRd |
|
| 206 |
#' @examples |
|
| 207 |
#' FIMS:::create_default_parameters_template(n_parameters = 3) |
|
| 208 |
create_default_parameters_template <- function(n_parameters = 1) {
|
|
| 209 | 85x |
template <- tibble::tibble( |
| 210 | 85x |
model_family = NA_character_, |
| 211 | 85x |
module_name = NA_character_, |
| 212 | 85x |
module_type = NA_character_, |
| 213 | 85x |
label = NA_character_, |
| 214 | 85x |
distribution_link = NA_character_, |
| 215 | 85x |
fleet_name = NA_character_, |
| 216 | 85x |
age = NA_real_, |
| 217 | 85x |
length = NA_real_, |
| 218 | 85x |
time = NA_integer_, |
| 219 | 85x |
value = NA_real_, |
| 220 | 85x |
estimation_type = NA_character_, |
| 221 | 85x |
distribution_type = NA_character_, |
| 222 | 85x |
distribution = NA_character_ |
| 223 |
) |> |
|
| 224 | 85x |
dplyr::slice(rep(1, each = n_parameters)) |
| 225 |
} |
|
| 226 | ||
| 227 |
#' Create default population parameters |
|
| 228 |
#' |
|
| 229 |
#' @description |
|
| 230 |
#' This function sets up default parameters for a population module. |
|
| 231 |
#' @details |
|
| 232 |
#' The natural log of the initial numbers at age (`log_init_naa.value`) is set based on |
|
| 233 |
#' unexploited recruitment and natural mortality. |
|
| 234 |
#' @param unnested_configurations A tibble of model configurations. Typically created |
|
| 235 |
#' by the `create_default_configurations()`. |
|
| 236 |
#' @param data An S4 object. FIMS input data. |
|
| 237 |
#' @param log_rzero A numeric value representing the natural log of unexploited |
|
| 238 |
#' recruitment. |
|
| 239 |
#' @return |
|
| 240 |
#' A tibble of default population parameters, including initial numbers at |
|
| 241 |
#' age and natural mortality rate. |
|
| 242 |
#' @noRd |
|
| 243 |
create_default_Population <- function( |
|
| 244 |
unnested_configurations, |
|
| 245 |
data, |
|
| 246 |
log_rzero |
|
| 247 |
) {
|
|
| 248 |
# Input checks |
|
| 249 |
# Check if log_rzero is numeric |
|
| 250 | 5x |
if (!is.numeric(log_rzero) || length(log_rzero) != 1) {
|
| 251 | ! |
local_bullets <- c( |
| 252 | ! |
"i" = "{.var log_rzero} argument must be a single numeric value.",
|
| 253 | ! |
"x" = "{.var log_rzero} has a length of {length(log_rzero)}.",
|
| 254 | ! |
"x" = "{.var log_rzero} is of the class {class(log_rzero)}."
|
| 255 |
) |
|
| 256 | ! |
names(local_bullets)[2] <- ifelse(length(log_rzero) > 1, "x", "i") |
| 257 | ! |
names(local_bullets)[3] <- ifelse(inherits(log_rzero, "numeric"), "i", "x") |
| 258 | ! |
cli::cli_abort(local_bullets) |
| 259 |
} |
|
| 260 | ||
| 261 |
# Extract necessary values from data |
|
| 262 | 5x |
n_years <- get_n_years(data) |
| 263 | 5x |
n_ages <- get_n_ages(data) |
| 264 | ||
| 265 |
# Define age and year vectors needed for the rep() calls === |
|
| 266 | 5x |
ages <- get_ages(data) |
| 267 | 5x |
years <- get_start_year(data):get_end_year(data) |
| 268 | ||
| 269 |
# Set natural mortality rate |
|
| 270 | 5x |
M_value <- 0.2 |
| 271 | ||
| 272 |
# Calculate initial numbers at age based on log_rzero and M_value |
|
| 273 | 5x |
init_naa <- exp(log_rzero) * exp(-(get_ages(data) - 1) * M_value) |
| 274 | 5x |
init_naa[n_ages] <- init_naa[n_ages] / M_value # sum of infinite series |
| 275 | ||
| 276 |
# Create a list of default parameters |
|
| 277 | 5x |
default <- create_default_parameters_template( |
| 278 | 5x |
n_parameters = n_years * n_ages |
| 279 |
) |> |
|
| 280 |
# Add the module type, label, value, and estimation type |
|
| 281 | 5x |
dplyr::mutate( |
| 282 | 5x |
label = "log_M", |
| 283 | 5x |
value = log(M_value), |
| 284 | 5x |
age = rep(ages, n_years), |
| 285 | 5x |
time = rep(years, each = n_ages), |
| 286 | 5x |
estimation_type = "constant" |
| 287 |
) |> |
|
| 288 | 5x |
dplyr::add_row( |
| 289 | 5x |
label = "log_init_naa", |
| 290 | 5x |
age = get_ages(data), |
| 291 | 5x |
value = log(init_naa), |
| 292 | 5x |
estimation_type = "fixed_effects" |
| 293 |
) |> |
|
| 294 | 5x |
dplyr::mutate( |
| 295 | 5x |
module_name = "Population" |
| 296 |
) |
|
| 297 |
} |
|
| 298 | ||
| 299 |
#' Create default logistic parameters |
|
| 300 |
#' |
|
| 301 |
#' @description |
|
| 302 |
#' This function sets up default parameters for a logistic function. There are |
|
| 303 |
#' two specified parameters, the inflection point and slope. |
|
| 304 |
#' @return |
|
| 305 |
#' A tibble containing the default logistic parameters, with inflection_point and |
|
| 306 |
#' slope values and their estimation status. |
|
| 307 |
#' @noRd |
|
| 308 |
create_default_Logistic <- function() {
|
|
| 309 |
# Create a template for default parameters |
|
| 310 | 15x |
default <- create_default_parameters_template(n_parameters = 2) |> |
| 311 |
# Add the module type, label, value, and estimation type |
|
| 312 | 15x |
dplyr::mutate( |
| 313 | 15x |
module_type = "Logistic", |
| 314 | 15x |
label = c("inflection_point", "slope"),
|
| 315 | 15x |
value = c(2, 1), |
| 316 | 15x |
estimation_type = "fixed_effects" |
| 317 |
) |
|
| 318 |
} |
|
| 319 | ||
| 320 |
#' Create default double logistic parameters |
|
| 321 |
#' |
|
| 322 |
#' @description |
|
| 323 |
#' This function sets up default parameters for a double logistic function. |
|
| 324 |
#' There four specified parameters, two for the ascending and two for the |
|
| 325 |
#' descending inflection points and slopes. |
|
| 326 |
#' @return |
|
| 327 |
#' A tibble containing the default double logistic parameters, |
|
| 328 |
#' inflection_point_asc, slope_asc, inflection_point_desc, and slope_desc |
|
| 329 |
#' values and their estimation status. |
|
| 330 |
#' @noRd |
|
| 331 |
create_default_DoubleLogistic <- function(module_name = NA_character_) {
|
|
| 332 | ! |
default <- create_default_parameters_template(n_parameters = 4) |> |
| 333 | ! |
dplyr::mutate( |
| 334 | ! |
module_name = !!module_name, |
| 335 | ! |
module_type = "DoubleLogistic", |
| 336 | ! |
label = c("inflection_point_asc", "slope_asc", "inflection_point_desc", "slope_desc"),
|
| 337 |
# TODO: Determine if inflection_point_desc should really be 4? |
|
| 338 | ! |
value = c(2, 1, 4, 1), |
| 339 | ! |
estimation_type = "fixed_effects" |
| 340 |
) |
|
| 341 |
} |
|
| 342 | ||
| 343 |
#' Create default selectivity parameters |
|
| 344 |
#' |
|
| 345 |
#' @description |
|
| 346 |
#' This function sets up default parameters for a selectivity module. |
|
| 347 |
#' @param form A string specifying the desired form of selectivity. Allowable |
|
| 348 |
#' forms include `r toString(formals(create_default_selectivity)[["form"]])` |
|
| 349 |
#' and the default is |
|
| 350 |
#' `r toString(formals(create_default_selectivity)[["form"]][1])`. |
|
| 351 |
#' @return |
|
| 352 |
#' A tibble is returned with the default parameter values for the specified form |
|
| 353 |
#' of selectivity. |
|
| 354 |
#' @noRd |
|
| 355 |
create_default_selectivity <- function( |
|
| 356 |
form = c("Logistic", "DoubleLogistic")
|
|
| 357 |
) {
|
|
| 358 |
# Input checks |
|
| 359 | 10x |
form <- rlang::arg_match(form) |
| 360 |
# NOTE: All new forms of selectivity must be placed in the vector of default |
|
| 361 |
# arguments for `form` and their methods but be placed below in the call to |
|
| 362 |
# `switch` |
|
| 363 | 10x |
default <- switch(form, |
| 364 | 10x |
"Logistic" = create_default_Logistic(), |
| 365 | 10x |
"DoubleLogistic" = create_default_DoubleLogistic() |
| 366 |
) |> |
|
| 367 | 10x |
dplyr::mutate( |
| 368 | 10x |
module_name = "Selectivity" |
| 369 |
) |
|
| 370 |
} |
|
| 371 | ||
| 372 |
#' Create default fleet parameters |
|
| 373 |
#' |
|
| 374 |
#' @description |
|
| 375 |
#' This function sets up default parameters for a fleet module. It compiles |
|
| 376 |
#' selectivity parameters along with distributions for each type of data that |
|
| 377 |
#' are present for the given fleet. |
|
| 378 |
#' |
|
| 379 |
#' @param unnested_configurations A tibble of model configurations. Typically |
|
| 380 |
#' created by the `create_default_configurations()`. |
|
| 381 |
#' @param fleet_name A character. Name of the fleet. |
|
| 382 |
#' @param data An S4 object. FIMS input data. |
|
| 383 |
#' @return |
|
| 384 |
#' A tibble with default parameters for the fleet. |
|
| 385 |
#' @noRd |
|
| 386 |
create_default_fleet <- function(unnested_configurations, |
|
| 387 |
current_fleet_name, |
|
| 388 |
data) {
|
|
| 389 |
# Input checks |
|
| 390 | 10x |
if (length(current_fleet_name) > 1) {
|
| 391 | ! |
cli::cli_abort(c( |
| 392 | ! |
"i" = "{.var current_fleet_name} should have a length of 1.",
|
| 393 | ! |
"x" = "{.var current_fleet_name} has a length of {length(current_fleet_name)}."
|
| 394 |
)) |
|
| 395 |
} |
|
| 396 | 10x |
if (!inherits(current_fleet_name, "character")) {
|
| 397 | ! |
cli::cli_abort(c( |
| 398 | ! |
"i" = "{.var current_fleet_name} should be a string.",
|
| 399 | ! |
"x" = "{.var current_fleet_name} is a {class(current_fleet_name)}."
|
| 400 |
)) |
|
| 401 |
} |
|
| 402 | ||
| 403 |
# Create default selectivity parameters |
|
| 404 | 10x |
selectivity_form <- unnested_configurations |> |
| 405 | 10x |
dplyr::filter(fleet_name == current_fleet_name & module_name == "Selectivity") |> |
| 406 | 10x |
dplyr::pull(module_type) |
| 407 | ||
| 408 | 10x |
selectivity_default <- create_default_selectivity( |
| 409 | 10x |
form = selectivity_form |
| 410 |
) |> |
|
| 411 |
# Add fleet name |
|
| 412 | 10x |
dplyr::mutate( |
| 413 | 10x |
fleet_name = current_fleet_name |
| 414 |
) |
|
| 415 | ||
| 416 |
# Get types of data for this fleet from the data object |
|
| 417 | 10x |
data_types_present <- get_data(data) |> |
| 418 | 10x |
dplyr::filter(name == current_fleet_name) |> |
| 419 | 10x |
dplyr::pull(type) |> |
| 420 | 10x |
unique() |
| 421 | ||
| 422 |
# Get data likelihood distributions assigned for this fleet |
|
| 423 | 10x |
distribution_names_for_fleet <- unnested_configurations |> |
| 424 | 10x |
dplyr::filter(fleet_name == current_fleet_name & module_name == "Data") |> |
| 425 | 10x |
dplyr::pull(module_type) |
| 426 | ||
| 427 |
# Determine default fleet parameters based on types of data present |
|
| 428 | 10x |
if ("index" %in% data_types_present &&
|
| 429 | 10x |
"Index" %in% distribution_names_for_fleet) {
|
| 430 | 5x |
fleet_index <- get_data(data) |> |
| 431 | 5x |
dplyr::filter(type == "index" & name == current_fleet_name) |> |
| 432 | 5x |
dplyr::rename(time = timing) |
| 433 | ||
| 434 | 5x |
q_default <- create_default_parameters_template(n_parameters = 1) |> |
| 435 | 5x |
dplyr::mutate( |
| 436 | 5x |
module_name = "Fleet", |
| 437 | 5x |
label = "log_q", |
| 438 | 5x |
fleet_name = current_fleet_name, |
| 439 | 5x |
value = 0, |
| 440 | 5x |
estimation_type = "fixed_effects" |
| 441 |
) |
|
| 442 | ||
| 443 | 5x |
index_distribution <- unnested_configurations |> |
| 444 | 5x |
dplyr::filter( |
| 445 | 5x |
fleet_name == current_fleet_name & module_name == "Data" & module_type == "Index" |
| 446 |
) |> |
|
| 447 | 5x |
dplyr::pull(distribution) |
| 448 | ||
| 449 | 5x |
index_uncertainty <- get_data(data) |> |
| 450 | 5x |
dplyr::filter(name == current_fleet_name, type %in% c("index")) |>
|
| 451 | 5x |
dplyr::arrange(dplyr::desc(type)) |> |
| 452 | 5x |
dplyr::pull(uncertainty) |
| 453 | ||
| 454 | 5x |
index_distribution_default <- switch(index_distribution, |
| 455 | 5x |
"Dnorm" = create_default_DnormDistribution( |
| 456 | 5x |
value = index_uncertainty, |
| 457 | 5x |
input_type = "data", |
| 458 | 5x |
data = data |
| 459 |
), |
|
| 460 | 5x |
"Dlnorm" = create_default_DlnormDistribution( |
| 461 | 5x |
value = index_uncertainty, |
| 462 | 5x |
input_type = "data", |
| 463 | 5x |
data = data |
| 464 |
) |
|
| 465 |
) |> |
|
| 466 | 5x |
dplyr::mutate( |
| 467 | 5x |
module_name = "Data", |
| 468 | 5x |
module_type = "Index", |
| 469 | 5x |
distribution_link = "Index", |
| 470 | 5x |
fleet_name = current_fleet_name, |
| 471 | 5x |
time = fleet_index[["time"]] |
| 472 |
) |
|
| 473 |
} else {
|
|
| 474 | 5x |
q_default <- create_default_parameters_template(n_parameters = 1) |> |
| 475 | 5x |
dplyr::mutate( |
| 476 | 5x |
module_name = "Fleet", |
| 477 | 5x |
label = "log_q", |
| 478 | 5x |
fleet_name = current_fleet_name, |
| 479 | 5x |
value = 0, |
| 480 | 5x |
estimation_type = "constant" |
| 481 |
) |
|
| 482 | 5x |
index_distribution_default <- NULL |
| 483 |
} |
|
| 484 | ||
| 485 | 10x |
if ("landings" %in% data_types_present &&
|
| 486 | 10x |
"Landings" %in% distribution_names_for_fleet) {
|
| 487 | 5x |
fleet_landings <- get_data(data) |> |
| 488 | 5x |
dplyr::filter(type == "landings" & name == current_fleet_name) |> |
| 489 | 5x |
dplyr::rename(time = timing) |
| 490 | ||
| 491 | 5x |
log_Fmort_default <- create_default_parameters_template( |
| 492 | 5x |
n_parameters = get_n_years(data) |
| 493 |
) |> |
|
| 494 | 5x |
dplyr::mutate( |
| 495 | 5x |
module_name = "Fleet", |
| 496 | 5x |
label = "log_Fmort", |
| 497 | 5x |
fleet_name = current_fleet_name, |
| 498 | 5x |
time = get_start_year(data):get_end_year(data), |
| 499 | 5x |
value = -3, |
| 500 | 5x |
estimation_type = "fixed_effects" |
| 501 |
) |
|
| 502 | ||
| 503 | 5x |
landings_distribution <- unnested_configurations |> |
| 504 | 5x |
dplyr::filter(fleet_name == current_fleet_name & module_name == "Data" & module_type == "Landings") |> |
| 505 | 5x |
dplyr::pull(distribution) |
| 506 | ||
| 507 | 5x |
landings_uncertainty <- get_data(data) |> |
| 508 | 5x |
dplyr::filter(name == current_fleet_name, type %in% c("landings")) |>
|
| 509 | 5x |
dplyr::arrange(dplyr::desc(type)) |> |
| 510 | 5x |
dplyr::pull(uncertainty) |
| 511 | ||
| 512 | 5x |
landings_distribution_default <- switch(landings_distribution, |
| 513 | 5x |
"Dnorm" = create_default_DnormDistribution( |
| 514 | 5x |
value = landings_uncertainty, |
| 515 | 5x |
input_type = "data", |
| 516 | 5x |
data = data |
| 517 |
), |
|
| 518 | 5x |
"Dlnorm" = create_default_DlnormDistribution( |
| 519 | 5x |
value = landings_uncertainty, |
| 520 | 5x |
input_type = "data", |
| 521 | 5x |
data = data |
| 522 |
) |
|
| 523 |
) |> |
|
| 524 | 5x |
dplyr::mutate( |
| 525 | 5x |
module_name = "Data", |
| 526 | 5x |
module_type = "Landings", |
| 527 | 5x |
distribution_link = "Landings", |
| 528 | 5x |
fleet_name = current_fleet_name, |
| 529 | 5x |
time = fleet_landings[["time"]] |
| 530 |
) |
|
| 531 |
} else {
|
|
| 532 | 5x |
fleet_index <- get_data(data) |> |
| 533 | 5x |
dplyr::filter(type == "index" & name == current_fleet_name) |
| 534 | ||
| 535 | 5x |
log_Fmort_default <- create_default_parameters_template( |
| 536 | 5x |
n_parameters = get_n_years(data) |
| 537 |
) |> |
|
| 538 | 5x |
dplyr::mutate( |
| 539 | 5x |
module_name = "Fleet", |
| 540 | 5x |
label = "log_Fmort", |
| 541 | 5x |
fleet_name = current_fleet_name, |
| 542 | 5x |
time = get_start_year(data):get_end_year(data), |
| 543 | 5x |
value = -200, |
| 544 | 5x |
estimation_type = "constant" |
| 545 |
) |
|
| 546 | ||
| 547 | 5x |
landings_distribution_default <- NULL |
| 548 |
} |
|
| 549 | ||
| 550 |
# Compile all default parameters into a single list |
|
| 551 | 10x |
default <- dplyr::bind_rows( |
| 552 | 10x |
selectivity_default, |
| 553 | 10x |
q_default, |
| 554 | 10x |
log_Fmort_default, |
| 555 | 10x |
index_distribution_default, |
| 556 | 10x |
landings_distribution_default |
| 557 |
) |
|
| 558 |
} |
|
| 559 | ||
| 560 |
#' Create default maturity parameters |
|
| 561 |
#' |
|
| 562 |
#' @description |
|
| 563 |
#' This function sets up default parameters for a maturity module. |
|
| 564 |
#' @param form A string specifying the form of maturity (e.g., |
|
| 565 |
#' `"Logistic"`). |
|
| 566 |
#' @return |
|
| 567 |
#' A tibble containing the default maturity parameters. |
|
| 568 |
#' @noRd |
|
| 569 |
create_default_maturity <- function( |
|
| 570 |
unnested_configurations, |
|
| 571 |
data |
|
| 572 |
) {
|
|
| 573 |
# Input checks |
|
| 574 | 5x |
available_forms <- c("Logistic")
|
| 575 | 5x |
form <- unnested_configurations |> |
| 576 | 5x |
dplyr::filter(module_name == "Maturity") |> |
| 577 | 5x |
dplyr::pull(module_type) |
| 578 | 5x |
if (!form %in% available_forms) {
|
| 579 | ! |
cli::cli_abort(c( |
| 580 | ! |
"Invalid `module_type`` for Maturity: {.var {form}}",
|
| 581 | ! |
"i" = "Valid options include: {.var {available_forms}}"
|
| 582 |
)) |
|
| 583 |
} |
|
| 584 | ||
| 585 |
# NOTE: All new forms of maturity must be placed in the vector of default |
|
| 586 |
# arguments for `form` and their methods but be placed below in the call to |
|
| 587 |
# `switch` |
|
| 588 | 5x |
default <- switch(form, |
| 589 | 5x |
"Logistic" = create_default_Logistic() |
| 590 |
) |> |
|
| 591 |
# We don't have an option to input maturity data into FIMS, so the maturity |
|
| 592 |
# parameters aren't really estimable. The parameters should be constant for now. |
|
| 593 |
# See more details from https://github.com/orgs/NOAA-FIMS/discussions/944. |
|
| 594 | 5x |
dplyr::mutate( |
| 595 | 5x |
estimation_type = "constant", |
| 596 | 5x |
module_name = "Maturity" |
| 597 |
) |
|
| 598 |
} |
|
| 599 | ||
| 600 |
#' Create default Beverton--Holt recruitment parameters |
|
| 601 |
#' |
|
| 602 |
#' @description |
|
| 603 |
#' This function sets up default parameters for a Beverton--Holt recruitment |
|
| 604 |
#' relationship. Parameters include the natural log of unfished recruitment, |
|
| 605 |
#' the logit transformation of the slope of the stock--recruitment curve to |
|
| 606 |
#' keep it between zero and one, and the time series of stock--recruitment |
|
| 607 |
#' deviations on the natural log scale. |
|
| 608 |
#' @param data An S4 object. FIMS input data. |
|
| 609 |
#' @return |
|
| 610 |
#' A tibble containing default recruitment parameters. |
|
| 611 |
#' @noRd |
|
| 612 |
create_default_BevertonHoltRecruitment <- function(data) {
|
|
| 613 |
# Create default parameters for Beverton--Holt recruitment |
|
| 614 | 5x |
log_rzero <- create_default_parameters_template( |
| 615 | 5x |
n_parameters = 1 |
| 616 |
) |> |
|
| 617 | 5x |
dplyr::mutate( |
| 618 | 5x |
label = "log_rzero", |
| 619 | 5x |
value = log(1e+06), |
| 620 | 5x |
estimation_type = "fixed_effects" |
| 621 |
) |
|
| 622 | 5x |
logit_steep <- create_default_parameters_template( |
| 623 | 5x |
n_parameters = 1 |
| 624 |
) |> |
|
| 625 | 5x |
dplyr::mutate( |
| 626 | 5x |
label = "logit_steep", |
| 627 | 5x |
value = -log(1.0 - 0.75) + log(0.75 - 0.2), |
| 628 | 5x |
estimation_type = "constant" |
| 629 |
) |
|
| 630 | ||
| 631 |
# TODO: Revisit the settings for log_r. Do we must set up log_r when |
|
| 632 |
# it is not random effect parameters? |
|
| 633 | 5x |
log_r <- create_default_parameters_template( |
| 634 | 5x |
n_parameters = get_n_years(data) - 1 |
| 635 |
) |> |
|
| 636 | 5x |
dplyr::mutate( |
| 637 |
# TODO: should this be LogRecDev to match output? |
|
| 638 | 5x |
label = "log_r", |
| 639 | 5x |
value = 0.0, |
| 640 | 5x |
time = (get_start_year(data) + 1):get_end_year(data), |
| 641 | 5x |
estimation_type = "constant" |
| 642 |
) |
|
| 643 | ||
| 644 | 5x |
log_devs <- create_default_parameters_template( |
| 645 | 5x |
n_parameters = get_n_years(data) - 1 |
| 646 |
) |> |
|
| 647 | 5x |
dplyr::mutate( |
| 648 |
# TODO: should this be LogRecDev to match output? |
|
| 649 | 5x |
label = "log_devs", |
| 650 | 5x |
value = 0.0, |
| 651 | 5x |
time = (get_start_year(data) + 1):get_end_year(data), |
| 652 | 5x |
estimation_type = "random_effects" |
| 653 |
) |
|
| 654 | ||
| 655 | 5x |
expected_recruitment <- create_default_parameters_template( |
| 656 | 5x |
n_parameters = get_n_years(data) + 1 |
| 657 |
) |> |
|
| 658 | 5x |
dplyr::mutate( |
| 659 | 5x |
label = "log_expected_recruitment", |
| 660 | 5x |
value = 0.0, |
| 661 | 5x |
estimation_type = "constant" |
| 662 |
) |
|
| 663 | ||
| 664 | 5x |
default <- dplyr::bind_rows( |
| 665 | 5x |
log_rzero, |
| 666 | 5x |
logit_steep, |
| 667 | 5x |
log_r, |
| 668 | 5x |
log_devs, |
| 669 | 5x |
expected_recruitment |
| 670 |
) |> |
|
| 671 | 5x |
dplyr::mutate( |
| 672 | 5x |
module_name = "Recruitment", |
| 673 | 5x |
module_type = "BevertonHolt" |
| 674 |
) |
|
| 675 |
} |
|
| 676 | ||
| 677 |
#' Create default DnormDistribution parameters |
|
| 678 |
#' |
|
| 679 |
#' @description |
|
| 680 |
#' This function sets up default parameters to calculate the density of a |
|
| 681 |
#' normal distribution, i.e., `DnormDistribution`, module. |
|
| 682 |
#' @param value A real number that is passed to `log_sd`. The default value is |
|
| 683 |
#' `0.1`. |
|
| 684 |
#' @param data An S4 object. FIMS input data. |
|
| 685 |
#' @param input_type A string specifying the input type. The available options |
|
| 686 |
#' are |
|
| 687 |
#' `r toString(formals(create_default_DnormDistribution)[["input_type"]])`. |
|
| 688 |
#' The default is |
|
| 689 |
#' `r toString(formals(create_default_DnormDistribution)[["input_type"]][1])`. |
|
| 690 |
#' @return |
|
| 691 |
#' A tibble of default parameters for Dnorm distribution. |
|
| 692 |
#' @noRd |
|
| 693 |
create_default_DnormDistribution <- function( |
|
| 694 |
value = 0.1, |
|
| 695 |
data, |
|
| 696 |
input_type = c("data", "process", "prior")
|
|
| 697 |
) {
|
|
| 698 |
# Input checks |
|
| 699 | 5x |
input_type <- rlang::arg_match(input_type) |
| 700 | ||
| 701 |
# Create default parameters |
|
| 702 | 5x |
default <- create_default_parameters_template( |
| 703 | 5x |
n_parameters = length(value) |
| 704 |
) |> |
|
| 705 |
# Add the module type and label |
|
| 706 | 5x |
dplyr::mutate( |
| 707 | 5x |
label = "log_sd", |
| 708 | 5x |
value = !!value, |
| 709 | 5x |
estimation_type = "constant", |
| 710 | 5x |
distribution_type = input_type, |
| 711 | 5x |
distribution = "Dnorm" |
| 712 |
) |
|
| 713 | ||
| 714 |
# If input_type is 'process', add additional parameters |
|
| 715 | 5x |
if (input_type == "process" | input_type == "prior") {
|
| 716 | 5x |
new_params <- create_default_parameters_template( |
| 717 | 5x |
n_parameters = length(value) |
| 718 |
) |> |
|
| 719 | 5x |
dplyr::mutate(label = "observed_values", value = 0) |> |
| 720 | 5x |
dplyr::add_row( |
| 721 | 5x |
label = "expected_values", |
| 722 | 5x |
value = rep(0, length(value)) |
| 723 |
) |> |
|
| 724 | 5x |
dplyr::mutate( |
| 725 | 5x |
estimation_type = "constant", |
| 726 | 5x |
distribution_type = input_type, |
| 727 | 5x |
distribution = "Dnorm" |
| 728 |
) |
|
| 729 | ||
| 730 | 5x |
default <- dplyr::bind_rows( |
| 731 | 5x |
default, |
| 732 | 5x |
new_params |
| 733 |
) |
|
| 734 |
} |
|
| 735 |
} |
|
| 736 | ||
| 737 |
#' Create default DlnormDistribution parameters |
|
| 738 |
#' |
|
| 739 |
#' @description |
|
| 740 |
#' This function sets up default parameters to calculate the density of a |
|
| 741 |
#' log-normal distribution, i.e., `DlnormDistribution`, module. |
|
| 742 |
#' @param value Default value for `log_sd`. |
|
| 743 |
#' @param data An S4 object. FIMS input data. |
|
| 744 |
#' @param input_type A string specifying the input type. The available options |
|
| 745 |
#' are |
|
| 746 |
#' `r toString(formals(create_default_DlnormDistribution)[["input_type"]])`. |
|
| 747 |
#' The default is |
|
| 748 |
#' `r toString(formals(create_default_DlnormDistribution)[["input_type"]][1])`. |
|
| 749 |
#' @return |
|
| 750 |
#' A tibble of default parameters for Dlnorm distribution. |
|
| 751 |
#' @noRd |
|
| 752 |
create_default_DlnormDistribution <- function( |
|
| 753 |
value = 0.1, |
|
| 754 |
data, |
|
| 755 |
input_type = c("data", "process")
|
|
| 756 |
) {
|
|
| 757 |
# Input checks |
|
| 758 |
# TODO: Determine if value can be a vector? |
|
| 759 | 10x |
if (!is.numeric(value) || any(value <= 0, na.rm = TRUE)) {
|
| 760 | ! |
cli::cli_abort(c( |
| 761 | ! |
"i" = "Inputs to {.var value} must be positive and numeric.",
|
| 762 | ! |
"x" = "{.var value} is {.var {value}}."
|
| 763 |
)) |
|
| 764 |
} |
|
| 765 | 10x |
input_type <- rlang::arg_match(input_type) |
| 766 | ||
| 767 | 10x |
log_value <- log(value) |
| 768 |
# Create the default list with log standard deviation |
|
| 769 | 10x |
default <- create_default_parameters_template( |
| 770 | 10x |
n_parameters = get_n_years(data) |
| 771 |
) |> |
|
| 772 |
# Add the module label and value |
|
| 773 | 10x |
dplyr::mutate( |
| 774 | 10x |
label = "log_sd", |
| 775 | 10x |
value = log_value |
| 776 |
) |
|
| 777 | ||
| 778 |
# Add additional parameters if input_type is "process" |
|
| 779 | 10x |
if (input_type == "process") {
|
| 780 | ! |
default <- default |> |
| 781 | ! |
dplyr::add_row( |
| 782 | ! |
label = "observed_values", |
| 783 | ! |
value = rep(0, get_n_years(data)) |
| 784 |
) |
|
| 785 |
} |
|
| 786 | ||
| 787 | 10x |
default <- default |> |
| 788 | 10x |
dplyr::mutate( |
| 789 | 10x |
estimation_type = "constant", |
| 790 | 10x |
distribution_type = input_type, |
| 791 | 10x |
distribution = "Dlnorm" |
| 792 |
) |
|
| 793 | 10x |
return(default) |
| 794 |
} |
|
| 795 | ||
| 796 |
#' Create default recruitment parameters |
|
| 797 |
#' |
|
| 798 |
#' @description |
|
| 799 |
#' This function sets up default parameters for a recruitment module. |
|
| 800 |
#' |
|
| 801 |
#' @param unnested_configurations A tibble of model configurations. Typically |
|
| 802 |
#' created by the `create_default_configurations()`. |
|
| 803 |
#' @param data An S4 object. FIMS input data. |
|
| 804 |
#' @return |
|
| 805 |
#' A tibble with the default parameters for recruitment. |
|
| 806 |
#' @noRd |
|
| 807 |
create_default_recruitment <- function( |
|
| 808 |
unnested_configurations, |
|
| 809 |
data |
|
| 810 |
) {
|
|
| 811 |
# Input checks |
|
| 812 | 5x |
available_forms <- c("BevertonHolt")
|
| 813 | 5x |
form <- unnested_configurations |> |
| 814 | 5x |
dplyr::filter(module_name == "Recruitment") |> |
| 815 | 5x |
dplyr::pull(module_type) |
| 816 | 5x |
if (!form %in% available_forms) {
|
| 817 | ! |
cli::cli_abort(c( |
| 818 | ! |
"Invalid `module_type` for Recruitment: {.var {form}}",
|
| 819 | ! |
"i" = "Valid options include: {.var {available_forms}}"
|
| 820 |
)) |
|
| 821 |
} |
|
| 822 |
# Create default parameters based on the recruitment form |
|
| 823 |
# NOTE: All new forms of recruitment must be placed in the vector of default |
|
| 824 |
# arguments for `form` and their methods but be placed below in the call to |
|
| 825 |
# `switch` |
|
| 826 | 5x |
form_default <- switch(form, |
| 827 | 5x |
"BevertonHolt" = create_default_BevertonHoltRecruitment(data) |
| 828 |
) |
|
| 829 | ||
| 830 | 5x |
distribution_input <- unnested_configurations |> |
| 831 | 5x |
dplyr::filter(module_name == "Recruitment") |
| 832 | ||
| 833 | 5x |
if (!is.null(distribution_input[["distribution"]])) {
|
| 834 | 5x |
distribution_default <- switch(distribution_input[["distribution"]], |
| 835 | 5x |
"Dnorm" = create_default_DnormDistribution( |
| 836 | 5x |
data = data, |
| 837 | 5x |
input_type = "process" |
| 838 |
) |
|
| 839 |
) |
|
| 840 | ||
| 841 | 5x |
distribution_link <- distribution_input[["distribution_link"]] |
| 842 | 5x |
if (distribution_link == "log_devs") {
|
| 843 | 5x |
distribution_default <- distribution_default |> |
| 844 | 5x |
dplyr::mutate( |
| 845 | 5x |
distribution_link = !!distribution_link |
| 846 |
) |
|
| 847 | ||
| 848 | 5x |
expanded_rows <- distribution_default |> |
| 849 | 5x |
dplyr::filter(label %in% c("observed_values", "expected_values")) |>
|
| 850 |
# Create all combinations of the original rows and years |
|
| 851 | 5x |
tidyr::expand_grid(year = (get_start_year(data) + 1):get_end_year(data)) |> |
| 852 | 5x |
dplyr::mutate( |
| 853 | 5x |
time = year |
| 854 |
) |> |
|
| 855 | 5x |
dplyr::select(-year) |
| 856 | ||
| 857 | 5x |
distribution_default <- distribution_default |> |
| 858 | 5x |
dplyr::filter(label == "log_sd") |> |
| 859 | 5x |
dplyr::bind_rows(expanded_rows) |
| 860 |
} |
|
| 861 |
} |
|
| 862 | ||
| 863 | 5x |
default <- dplyr::bind_rows(form_default, distribution_default) |> |
| 864 | 5x |
tidyr::fill(module_name, module_type) |
| 865 |
} |
| 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 | 130x |
family <- args[["family"]] |
| 27 | 130x |
sd <- args[["sd"]] |
| 28 |
# Optional argument data_type |
|
| 29 | 130x |
data_type <- args[["data_type"]] |
| 30 | 130x |
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 | 130x |
data_type_names <- c("landings", "index", "agecomp", "lengthcomp")
|
| 37 | 130x |
if (is.null(data_type)) {
|
| 38 | 25x |
available_distributions <- c("lognormal", "gaussian")
|
| 39 |
} else {
|
|
| 40 | 105x |
available_distributions <- switch( |
| 41 | 105x |
EXPR = ifelse(grepl("comp", data_type), "composition", data_type),
|
| 42 | 105x |
"landings" = c("lognormal", "gaussian"),
|
| 43 | 105x |
"index" = c("lognormal", "gaussian"),
|
| 44 | 105x |
"composition" = c("multinomial"),
|
| 45 | 105x |
"unavailable data type" |
| 46 |
) |
|
| 47 |
} |
|
| 48 | 130x |
elements_of_sd <- c("value", "estimation_type")
|
| 49 | ||
| 50 |
# Start a bulleted list of errors and add to it in each if statement |
|
| 51 | 130x |
abort_bullets <- c( |
| 52 | 130x |
" " = "The following errors were found in the input argument {.var args}."
|
| 53 |
) |
|
| 54 | 130x |
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 | 129x |
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 | 128x |
!(family[["family"]] %in% available_distributions) || |
| 76 | 128x |
"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 | 129x |
if (!is.null(data_type)) {
|
| 95 | 104x |
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 | 129x |
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 | 127x |
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 | 127x |
length(sd[["estimation_type"]]) > 1 && |
| 127 | 127x |
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 |
# Check dimensions for data distributions: sd must be either length 1 (scalar) |
|
| 143 |
# or match data length when data_type is landings or index |
|
| 144 | 129x |
if (!is.null(data_type) && !is.null(args[["module"]])) {
|
| 145 | 104x |
module <- args[["module"]] |
| 146 | 104x |
if (data_type == "landings" | data_type == "index") {
|
| 147 | 42x |
n_obs <- module$n_years$get() |
| 148 | ||
| 149 | 42x |
if (length(sd[["value"]]) > 1 && length(sd[["value"]]) != n_obs) {
|
| 150 | 2x |
abort_bullets <- c( |
| 151 | 2x |
abort_bullets, |
| 152 | 2x |
"x" = "The size of {.var log_sd} does not match the size of observed data for {data_type}.",
|
| 153 | 2x |
"i" = "The {.var log_sd} vector is of size {length(sd[['value']])}.",
|
| 154 | 2x |
"i" = "The observed {data_type} data vector is of size {n_obs}.",
|
| 155 | 2x |
"i" = "Either provide a single {.var log_sd} value (scalar) or a vector matching the data length."
|
| 156 |
) |
|
| 157 |
} |
|
| 158 |
} |
|
| 159 |
} |
|
| 160 | ||
| 161 |
# Return error messages if more than just the default is present |
|
| 162 | 129x |
if (length(abort_bullets) == 1) {
|
| 163 | 115x |
invisible(TRUE) |
| 164 |
} else {
|
|
| 165 | 14x |
cli::cli_abort(abort_bullets) |
| 166 |
} |
|
| 167 |
} |
|
| 168 | ||
| 169 |
#' Return name of expected value |
|
| 170 |
#' |
|
| 171 |
#' The combination of data type, family, and link lead to a specific name for |
|
| 172 |
#' the expected value within the code base. This function looks at the |
|
| 173 |
#' combination of these three objects and specifies the appropriate string for |
|
| 174 |
#' its name going forward. |
|
| 175 |
#' @inheritParams initialize_data_distribution |
|
| 176 |
#' @noRd |
|
| 177 |
#' @return |
|
| 178 |
#' A string specifying the name of the expected value. |
|
| 179 |
#' |
|
| 180 |
get_expected_name <- function(family, data_type) {
|
|
| 181 |
# TODO: Think about if the name of the expected value should change based on |
|
| 182 |
# the link or if it should stay the same? Keeping track of different names in |
|
| 183 |
# the code base might be too complex for the output as well |
|
| 184 | 96x |
family_string <- family[["family"]] |
| 185 | 96x |
link_string <- family[["link"]] |
| 186 | 96x |
expected_name <- dplyr::case_when( |
| 187 | 96x |
data_type == "landings" && |
| 188 | 96x |
grepl("lognormal|gaussian", family_string) &&
|
| 189 | 96x |
link_string == "log" ~ "log_landings_expected", |
| 190 | 96x |
data_type == "landings" && |
| 191 | 96x |
grepl("lognormal|gaussian", family_string) &&
|
| 192 | 96x |
link_string == "identity" ~ "landings_expected", |
| 193 | 96x |
data_type == "index" && |
| 194 | 96x |
grepl("lognormal|gaussian", family_string) &&
|
| 195 | 96x |
link_string == "log" ~ "log_index_expected", |
| 196 | 96x |
data_type == "index" && |
| 197 | 96x |
grepl("lognormal|gaussian", family_string) &&
|
| 198 | 96x |
link_string == "identity" ~ "index_expected", |
| 199 | 96x |
grepl("agecomp", data_type) ~ "agecomp_proportion",
|
| 200 | 96x |
grepl("lengthcomp", data_type) ~ "lengthcomp_proportion",
|
| 201 |
) |
|
| 202 |
# Check combination of entries was okay and led to valid name |
|
| 203 | 96x |
if (is.na(expected_name)) {
|
| 204 | ! |
cli::cli_abort(c( |
| 205 | ! |
"x" = "The combination of data type, family, and link are incompatible in |
| 206 | ! |
some way.", |
| 207 | ! |
"i" = "{.var data_type} is {.var {data_type}}.",
|
| 208 | ! |
"i" = "The family is {.var {family_string}}.",
|
| 209 | ! |
"i" = "The link is {.var {link_string}}."
|
| 210 |
)) |
|
| 211 |
} |
|
| 212 | 96x |
return(expected_name) |
| 213 |
} |
|
| 214 | ||
| 215 |
#' Set up a new distribution for a data type or a process |
|
| 216 |
#' |
|
| 217 |
#' Use [methods::new()] to set up a distribution within an existing module with |
|
| 218 |
#' the necessary linkages between the two. For example, a fleet module will need |
|
| 219 |
#' a distributional assumption for parts of the data associated with it, which |
|
| 220 |
#' requires the use of `initialize_data_distribution()`, and a recruitment |
|
| 221 |
#' module, like the Beverton--Holt stock--recruit relationship, will need a |
|
| 222 |
#' distribution associated with the recruitment deviations, which requires |
|
| 223 |
#' `initialize_process_distribution()`. |
|
| 224 |
#' @param module An identifier to a C++ fleet module that is linked to the data |
|
| 225 |
#' of interest. |
|
| 226 |
#' @param family A description of the error distribution and link function to |
|
| 227 |
#' be used in the model. The argument takes a family class, e.g., |
|
| 228 |
#' `stats::gaussian(link = "identity")`. |
|
| 229 |
#' @param sd A list of length two. The first entry is named `"value"` and it |
|
| 230 |
#' stores the initial values (scalar or vector) for the relevant standard |
|
| 231 |
#' deviations. The default is `value = 1`. The second entry is named |
|
| 232 |
#' `"estimation_type"` and it stores a vector of booleans (default = "constant") is a |
|
| 233 |
#' string indicating whether or not standard deviation is estimated as a fixed effect |
|
| 234 |
#' or held constant. If `"value"` is a vector and `"estimation_type"` is a scalar, |
|
| 235 |
#' the single value specified `"estimation_type"` value will be repeated to match the length of |
|
| 236 |
#' `value`. Otherwise, the dimensions of the two must match. |
|
| 237 |
#' @param data_type A string specifying the type of data that the |
|
| 238 |
#' distribution will be fit to. Allowable types include |
|
| 239 |
#' `r toString(formals(initialize_data_distribution)[["data_type"]])` |
|
| 240 |
#' and the default is |
|
| 241 |
#' `r toString(formals(initialize_data_distribution)[["data_type"]][1])`. |
|
| 242 |
#' @param par A string specifying the parameter name the distribution applies |
|
| 243 |
#' to. Parameters must be members of the specified module. Use |
|
| 244 |
#' `methods::show(module)` to obtain names of parameters within the module. |
|
| 245 |
#' @param is_random_effect A boolean indicating whether or not the process is |
|
| 246 |
#' estimated as a random effect. |
|
| 247 |
#' @return |
|
| 248 |
#' A reference class. is returned. Use [methods::show()] to view the various |
|
| 249 |
#' Rcpp class fields, methods, and documentation. |
|
| 250 |
#' @keywords distribution |
|
| 251 |
#' @export |
|
| 252 |
#' @examples |
|
| 253 |
#' \dontrun{
|
|
| 254 |
#' # Set up a new data distribution |
|
| 255 |
#' n_years <- 30 |
|
| 256 |
#' # Create a new fleet module |
|
| 257 |
#' fleet <- methods::new(Fleet) |
|
| 258 |
#' # Create a distribution for the fleet module |
|
| 259 |
#' fleet_distribution <- initialize_data_distribution( |
|
| 260 |
#' module = fishing_fleet, |
|
| 261 |
#' family = lognormal(link = "log"), |
|
| 262 |
#' sd = list( |
|
| 263 |
#' value = rep(sqrt(log(0.01^2 + 1)), n_years), |
|
| 264 |
#' estimation_type = rep("constant", n_years) # Could also be a single "constant"
|
|
| 265 |
#' ), |
|
| 266 |
#' data_type = "index" |
|
| 267 |
#' ) |
|
| 268 |
#' |
|
| 269 |
#' # Set up a new process distribution |
|
| 270 |
#' # Create a new recruitment module |
|
| 271 |
#' recruitment <- methods::new(BevertonHoltRecruitment) |
|
| 272 |
#' # view parameter names of the recruitment module |
|
| 273 |
#' methods::show(BevertonHoltRecruitment) |
|
| 274 |
#' # Create a distribution for the recruitment module |
|
| 275 |
#' recruitment_distribution <- initialize_process_distribution( |
|
| 276 |
#' module = recruitment, |
|
| 277 |
#' par = "log_devs", |
|
| 278 |
#' family = gaussian(), |
|
| 279 |
#' sd = list(value = 0.4, estimation_type = "constant"), |
|
| 280 |
#' is_random_effect = FALSE |
|
| 281 |
#' ) |
|
| 282 |
#' } |
|
| 283 |
initialize_data_distribution <- function( |
|
| 284 |
module, |
|
| 285 |
family = NULL, |
|
| 286 |
# Create a tibble with value and estimation_type column for sd |
|
| 287 |
sd = tibble::tibble( |
|
| 288 |
value = 1, |
|
| 289 |
estimation_type = "constant" |
|
| 290 |
), |
|
| 291 |
# FIXME: Move this argument to second to match where par is in |
|
| 292 |
# initialize_process_distribution |
|
| 293 |
data_type = c("landings", "index", "agecomp", "lengthcomp")
|
|
| 294 |
) {
|
|
| 295 | 106x |
data_type <- rlang::arg_match(data_type) |
| 296 |
# FIXME: Make the available families a data object |
|
| 297 |
# Could also make the matrix of distributions available per type as a |
|
| 298 |
# data frame where the check could use the stored object. |
|
| 299 | ||
| 300 |
# validity check on user input |
|
| 301 | 105x |
args <- list( |
| 302 | 105x |
family = family, |
| 303 | 105x |
sd = sd, |
| 304 | 105x |
data_type = data_type, |
| 305 | 105x |
module = module |
| 306 |
) |
|
| 307 | 105x |
check_distribution_validity(args) |
| 308 | ||
| 309 |
# assign name of observed data based on data_type |
|
| 310 | 96x |
obs_id_name <- glue::glue("observed_{data_type}_data_id")
|
| 311 | ||
| 312 |
# Set up distribution based on `family` argument` |
|
| 313 | 96x |
if (family[["family"]] == "lognormal") {
|
| 314 |
# create new Rcpp module |
|
| 315 | 37x |
new_module <- methods::new(DlnormDistribution) |
| 316 | ||
| 317 |
# populate logged standard deviation parameter with log of input |
|
| 318 |
# Using resize() and then assigning value to each element of log_sd directly |
|
| 319 |
# is correct, as creating a new ParameterVector for log_sd here would |
|
| 320 |
# trigger an error in integration tests with wrappers. |
|
| 321 | 37x |
new_module$log_sd$resize(length(sd[["value"]])) |
| 322 | ||
| 323 | 37x |
purrr::walk( |
| 324 | 37x |
seq_along(sd[["value"]]), |
| 325 | 37x |
\(x) new_module[["log_sd"]][x][["value"]] <- log(sd[["value"]][x]) |
| 326 |
) |
|
| 327 | ||
| 328 | 37x |
purrr::walk( |
| 329 | 37x |
seq_along(sd[["estimation_type"]]), |
| 330 | 37x |
\(x) new_module[["log_sd"]][x][["estimation_type"]]$set(sd[["estimation_type"]][x]) |
| 331 |
) |
|
| 332 |
} |
|
| 333 | ||
| 334 | 96x |
if (family[["family"]] == "gaussian") {
|
| 335 |
# create new Rcpp module |
|
| 336 | 1x |
new_module <- methods::new(DnormDistribution) |
| 337 | ||
| 338 |
# populate logged standard deviation parameter with log of input |
|
| 339 | 1x |
purrr::walk( |
| 340 | 1x |
seq_along(sd[["value"]]), |
| 341 | 1x |
\(x) new_module[["log_sd"]][x][["value"]] <- log(sd[["value"]][x]) |
| 342 |
) |
|
| 343 | ||
| 344 | 1x |
purrr::walk( |
| 345 | 1x |
seq_along(sd[["estimation_type"]]), |
| 346 | 1x |
\(x) new_module[["log_sd"]][x][["estimation_type"]]$set(sd[["estimation_type"]][x]) |
| 347 |
) |
|
| 348 |
} |
|
| 349 | ||
| 350 | 96x |
if (family[["family"]] == "multinomial") {
|
| 351 |
# create new Rcpp module |
|
| 352 | 58x |
new_module <- methods::new(DmultinomDistribution) |
| 353 |
} |
|
| 354 | ||
| 355 |
# setup link to observed data |
|
| 356 | 96x |
if (data_type == "landings") {
|
| 357 | 18x |
new_module$set_observed_data(module$GetObservedLandingsDataID()) |
| 358 |
} |
|
| 359 | 96x |
if (data_type == "index") {
|
| 360 | 20x |
new_module$set_observed_data(module$GetObservedIndexDataID()) |
| 361 |
} |
|
| 362 | 96x |
if (data_type == "agecomp") {
|
| 363 | 32x |
new_module$set_observed_data(module$GetObservedAgeCompDataID()) |
| 364 |
} |
|
| 365 | 96x |
if (data_type == "lengthcomp") {
|
| 366 | 26x |
new_module$set_observed_data(module$GetObservedLengthCompDataID()) |
| 367 |
} |
|
| 368 | ||
| 369 |
# set name of expected values |
|
| 370 | 96x |
expected <- get_expected_name(family, data_type) |
| 371 |
# setup link to expected values |
|
| 372 | 96x |
new_module$set_distribution_links("data", module$field(expected)$get_id())
|
| 373 | ||
| 374 | 96x |
return(new_module) |
| 375 |
} |
|
| 376 | ||
| 377 |
#' @rdname initialize_data_distribution |
|
| 378 |
#' @keywords distribution |
|
| 379 |
#' @export |
|
| 380 |
initialize_process_distribution <- function( |
|
| 381 |
module, |
|
| 382 |
par, |
|
| 383 |
family = NULL, |
|
| 384 |
sd = tibble::tibble( |
|
| 385 |
value = 1, |
|
| 386 |
estimation_type = "constant" |
|
| 387 |
), |
|
| 388 |
is_random_effect = FALSE |
|
| 389 |
) {
|
|
| 390 |
# validity check on user input |
|
| 391 | 25x |
args <- list(family = family, sd = sd) |
| 392 | 25x |
check_distribution_validity(args) |
| 393 | ||
| 394 | 19x |
expected <- switch(paste0(par, "_", class(module)), |
| 395 | 19x |
"log_devs_Rcpp_BevertonHoltRecruitment" = NULL, |
| 396 | 19x |
"log_r_Rcpp_BevertonHoltRecruitment" = "log_expected_recruitment" |
| 397 |
) |
|
| 398 | ||
| 399 |
# Set up distribution based on `family` argument` |
|
| 400 | 19x |
if (family[["family"]] == "lognormal") {
|
| 401 |
# create new Rcpp module |
|
| 402 | ! |
new_module <- methods::new(DlnormDistribution) |
| 403 | ||
| 404 |
# populate logged standard deviation parameter with log of input |
|
| 405 | ! |
new_module$log_sd$resize(length(sd[["value"]])) |
| 406 | ! |
purrr::walk( |
| 407 | ! |
seq_along(sd[["value"]]), |
| 408 | ! |
\(x) new_module[["log_sd"]][x][["value"]] <- log(sd[["value"]][x]) |
| 409 |
) |
|
| 410 | ||
| 411 |
# setup whether or not sd parameter is estimated |
|
| 412 | ! |
if (length(sd[["value"]]) > 1 && length(sd[["estimation_type"]]) == 1) {
|
| 413 | ! |
if (sd[["estimation_type"]] == "constant") {
|
| 414 | ! |
new_module$log_sd$set_all_estimable(FALSE) |
| 415 |
} else {
|
|
| 416 | ! |
new_module$log_sd$set_all_estimable(TRUE) |
| 417 |
} |
|
| 418 |
} else {
|
|
| 419 | ! |
for (i in seq_along(sd[["estimation_type"]])) {
|
| 420 | ! |
new_module$log_sd[i]$estimation_type$set(sd[["estimation_type"]][i]) |
| 421 |
} |
|
| 422 |
} |
|
| 423 |
} |
|
| 424 | ||
| 425 | 19x |
if (family[["family"]] == "gaussian") {
|
| 426 |
# create new Rcpp module |
|
| 427 | 19x |
new_module <- methods::new(DnormDistribution) |
| 428 | ||
| 429 |
# populate logged standard deviation parameter with log of input |
|
| 430 | 19x |
new_module$log_sd$resize(length(sd[["value"]])) |
| 431 | 19x |
for (i in seq_along(sd[["value"]])) {
|
| 432 | 19x |
new_module$log_sd[i]$value <- log(sd[["value"]][i]) |
| 433 |
} |
|
| 434 | ||
| 435 |
# setup whether or not sd parameter is estimated |
|
| 436 | 19x |
if (length(sd[["value"]]) > 1 && length(sd[["estimation_type"]]) == 1) {
|
| 437 | ! |
if (sd[["estimation_type"]] == "constant") {
|
| 438 | ! |
new_module$log_sd$set_all_estimable(FALSE) |
| 439 |
} else {
|
|
| 440 | ! |
new_module$log_sd$set_all_estimable(TRUE) |
| 441 |
} |
|
| 442 |
} else {
|
|
| 443 | 19x |
for (i in seq_along(sd[["estimation_type"]])) {
|
| 444 | 19x |
new_module$log_sd[i]$estimation_type$set(sd[["estimation_type"]][i]) |
| 445 |
} |
|
| 446 |
} |
|
| 447 |
} |
|
| 448 | ||
| 449 | ||
| 450 | 19x |
n_dim <- length(module$field(par)) |
| 451 | ||
| 452 |
# create new Rcpp modules |
|
| 453 | 19x |
new_module$observed_values$resize(n_dim) |
| 454 | 19x |
new_module$expected_values$resize(n_dim) |
| 455 | ||
| 456 |
# initialize values with 0 |
|
| 457 |
# these are overwritten in the code later by user input |
|
| 458 | 19x |
for (i in 1:n_dim) {
|
| 459 | 551x |
new_module$observed_values[i]$value <- 0 |
| 460 | 551x |
new_module$expected_values[i]$value <- 0 |
| 461 |
} |
|
| 462 | ||
| 463 |
# setup links to parameter |
|
| 464 | 19x |
if (is.null(expected)) {
|
| 465 | 19x |
new_module$set_distribution_links( |
| 466 | 19x |
"random_effects", |
| 467 | 19x |
module$field(par)$get_id() |
| 468 |
) |
|
| 469 |
} else {
|
|
| 470 | ! |
new_module$set_distribution_links( |
| 471 | ! |
"random_effects", |
| 472 | ! |
c( |
| 473 | ! |
module$field(par)$get_id(), |
| 474 | ! |
module$field(expected)$get_id() |
| 475 |
) |
|
| 476 |
) |
|
| 477 |
} |
|
| 478 | ||
| 479 | 19x |
return(new_module) |
| 480 |
} |
|
| 481 | ||
| 482 |
#' @rdname initialize_data_distribution |
|
| 483 |
#' @keywords distribution |
|
| 484 |
#' @export |
|
| 485 |
initialize_process_structure <- function(module, par) {
|
|
| 486 | 18x |
new_process_module <- switch(paste0(par, "_", class(module)), |
| 487 | 18x |
"log_devs_Rcpp_BevertonHoltRecruitment" = new(LogDevsRecruitmentProcess), |
| 488 | 18x |
"log_r_Rcpp_BevertonHoltRecruitment" = new(LogRRecruitmentProcess) |
| 489 |
) |
|
| 490 | ||
| 491 | 18x |
module$SetRecruitmentProcessID(new_process_module$get_id()) |
| 492 | ||
| 493 | 18x |
return(new_process_module) |
| 494 |
} |
|
| 495 | ||
| 496 |
#' Distributions not available in the stats package |
|
| 497 |
#' |
|
| 498 |
#' Family objects provide a convenient way to specify the details of the models |
|
| 499 |
#' used by functions such as [stats::glm()]. These functions within this |
|
| 500 |
#' package are not available within the stats package but are designed in a |
|
| 501 |
#' similar manner. |
|
| 502 |
#' |
|
| 503 |
#' @param link A string specifying the model link function. For example, |
|
| 504 |
#' `"identity"` or `"log"` are appropriate names for the [stats::gaussian()] |
|
| 505 |
#' distribution. `"log"` and `"logit"` are the defaults for the lognormal and |
|
| 506 |
#' the multinomial, respectively. |
|
| 507 |
#' @return |
|
| 508 |
#' An object of class `family` (which has a concise print method). This |
|
| 509 |
#' particular family has a truncated length compared to other distributions in |
|
| 510 |
#' [stats::family()]. |
|
| 511 |
#' \item{family}{character: the family name.}
|
|
| 512 |
#' \item{link}{character: the link name.}
|
|
| 513 |
#' |
|
| 514 |
#' @seealso |
|
| 515 |
#' * [stats::family()] |
|
| 516 |
#' * [stats::gaussian()] |
|
| 517 |
#' * [stats::glm()] |
|
| 518 |
#' * [stats::power()] |
|
| 519 |
#' * [stats::make.link()] |
|
| 520 |
#' @keywords distribution |
|
| 521 |
#' @export |
|
| 522 |
#' @examples |
|
| 523 |
#' a_family <- multinomial() |
|
| 524 |
#' a_family[["family"]] |
|
| 525 |
#' a_family[["link"]] |
|
| 526 |
lognormal <- function(link = "log") {
|
|
| 527 | 40x |
family_class <- c( |
| 528 | 40x |
list(family = "lognormal", link = link), |
| 529 | 40x |
stats::make.link(link) |
| 530 |
) |
|
| 531 | 40x |
class(family_class) <- "family" |
| 532 | 40x |
return(family_class) |
| 533 |
} |
|
| 534 | ||
| 535 |
#' @rdname lognormal |
|
| 536 |
#' @keywords distribution |
|
| 537 |
#' @export |
|
| 538 |
multinomial <- function(link = "logit") {
|
|
| 539 | 63x |
family_class <- c( |
| 540 | 63x |
list(family = "multinomial", link = link), |
| 541 | 63x |
stats::make.link(link) |
| 542 |
) |
|
| 543 | 63x |
class(family_class) <- "family" |
| 544 | 63x |
return(family_class) |
| 545 |
} |
| 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 |
"data", "data_id", "data_ids", "data_type", |
|
| 5 |
"delete_me", |
|
| 6 |
"density_component", |
|
| 7 |
"derived_quantities", "dimensionality", |
|
| 8 |
"fleet", |
|
| 9 |
"join_by", "json", |
|
| 10 |
"input_type", |
|
| 11 |
"label", "label_splits", "likelihood", "log_sd_values", |
|
| 12 |
"module_name", "module_id", "module_type", |
|
| 13 |
"observed_data_id", "observed_values", |
|
| 14 |
"parameter_min", "parameter_max", |
|
| 15 |
"parameters", |
|
| 16 |
"population" |
|
| 17 |
)) |
|
| 18 | ||
| 19 |
#' Reshape JSON estimates |
|
| 20 |
#' |
|
| 21 |
#' @description |
|
| 22 |
#' This function processes the finalized FIMS JSON output and reshapes the |
|
| 23 |
#' parameter estimates into a structured tibble for easier analysis and |
|
| 24 |
#' manipulation. |
|
| 25 |
#' |
|
| 26 |
#' @param model_output A JSON object containing the finalized FIMS output as |
|
| 27 |
#' returned from `get_output()`, which is an internal function to each model |
|
| 28 |
#' family. |
|
| 29 |
#' @return A tibble containing the reshaped parameter estimates. |
|
| 30 |
reshape_json_estimates <- function(model_output) {
|
|
| 31 | 30x |
json_list <- jsonlite::fromJSON(model_output, simplifyVector = FALSE) |
| 32 | 30x |
read_list <- purrr::map( |
| 33 | 30x |
json_list[!names(json_list) %in% c( |
| 34 | 30x |
"name", "type", "estimation_framework", "id", "objective_function_value", |
| 35 | 30x |
"max_gradient_component", "gradient", |
| 36 | 30x |
"population_ids", "fleet_ids", "log" |
| 37 |
)], |
|
| 38 | 30x |
\(x) tidyr::unnest_wider(tibble::tibble(json = x), json) |
| 39 |
) |
|
| 40 | ||
| 41 |
# Process the module parameters |
|
| 42 | 30x |
module_information <- purrr::map_df( |
| 43 | 30x |
read_list[ |
| 44 | 30x |
!names(read_list) %in% |
| 45 | 30x |
c( |
| 46 | 30x |
"name", "type", "estimation_framework", "id", |
| 47 | 30x |
"objective_function_value", "populations", "fleets", "data", |
| 48 | 30x |
"density_components", "population_ids", "fleet_ids" |
| 49 |
) |
|
| 50 |
], |
|
| 51 | 30x |
.f = \(y) dplyr::mutate( |
| 52 | 30x |
y, |
| 53 | 30x |
parameters = purrr::map( |
| 54 | 30x |
parameters, |
| 55 | 30x |
\(x) purrr::map_df(x, dimension_folded_to_tibble) |
| 56 |
) |
|
| 57 |
) |
|
| 58 |
) |> |
|
| 59 | 30x |
tidyr::unnest(parameters) |
| 60 | ||
| 61 |
# Process the fleet-level information |
|
| 62 | 30x |
fleet_density_data <- read_list[["fleets"]] |> |
| 63 | 30x |
dplyr::select(module_id, data_ids) |> |
| 64 | 30x |
dplyr::mutate( |
| 65 | 30x |
data_ids = purrr::map( |
| 66 | 30x |
data_ids, |
| 67 | 30x |
\(y) tibble::enframe(unlist(y), name = "data_type", value = "data_id") |
| 68 |
) |
|
| 69 |
) |> |
|
| 70 | 30x |
tidyr::unnest(data_ids) |> |
| 71 | 30x |
dplyr::filter(data_id != -999) |> |
| 72 | 30x |
dplyr::mutate( |
| 73 | 30x |
name = paste(data_type, "expected", sep = "_") |
| 74 |
) |> |
|
| 75 | 30x |
dplyr::left_join( |
| 76 | 30x |
y = read_list[["density_components"]] |> |
| 77 | 30x |
dplyr::filter( |
| 78 | 30x |
observed_data_id != -999 |
| 79 |
) |> |
|
| 80 | 30x |
dplyr::rename(distribution = "module_type") |> |
| 81 | 30x |
dplyr::select(-dplyr::starts_with("module")),
|
| 82 | 30x |
by = c("data_id" = "observed_data_id")
|
| 83 |
) |> |
|
| 84 | 30x |
dplyr::mutate( |
| 85 | 30x |
density_component = purrr::map(density_component, density_to_tibble) |
| 86 |
) |> |
|
| 87 | 30x |
tidyr::unnest(density_component) |> |
| 88 | 30x |
dplyr::select(-dplyr::starts_with("data_")) |>
|
| 89 | 30x |
dplyr::group_by(module_id, name) |> |
| 90 | 30x |
dplyr::mutate(join_by = dplyr::row_number()) |> |
| 91 | 30x |
dplyr::ungroup() |
| 92 | ||
| 93 | 30x |
fleet_information <- read_list[["fleets"]] |> |
| 94 | 30x |
tidyr::pivot_longer( |
| 95 | 30x |
cols = c(parameters, derived_quantities), |
| 96 | 30x |
names_to = "delete_me", |
| 97 | 30x |
values_to = "parameters" |
| 98 |
) |> |
|
| 99 | 30x |
dplyr::select(-delete_me, -data_ids) |> |
| 100 |
# Remove column ids that are not currently needed |
|
| 101 | 30x |
dplyr::select(-dplyr::matches("^n.+s$")) |>
|
| 102 | 30x |
dplyr::mutate( |
| 103 | 30x |
parameters = purrr::map( |
| 104 | 30x |
parameters, |
| 105 | 30x |
\(x) purrr::map_df(x, dimension_folded_to_tibble) |
| 106 |
) |
|
| 107 |
) |> |
|
| 108 | 30x |
tidyr::unnest(parameters) |> |
| 109 | 30x |
dplyr::group_by(module_id, name) |> |
| 110 | 30x |
dplyr::mutate(join_by = dplyr::row_number()) |> |
| 111 | 30x |
dplyr::ungroup() |> |
| 112 | 30x |
dplyr::left_join( |
| 113 | 30x |
fleet_density_data, |
| 114 | 30x |
by = c("module_id", "name", "join_by"),
|
| 115 | 30x |
suffix = c("", "_density")
|
| 116 |
) |> |
|
| 117 | 30x |
dplyr::select(-join_by) |
| 118 | ||
| 119 |
# Process the data components |
|
| 120 |
# TODO: Data component needs actual uncertainty instead of 0 |
|
| 121 | 30x |
data_information <- read_list[["data"]] |> |
| 122 | 30x |
dplyr::mutate( |
| 123 | 30x |
dimensionality = purrr::map(dimensionality, \(x) dimensions_to_tibble(x)) |
| 124 |
) |> |
|
| 125 | 30x |
tidyr::unnest(c(dimensionality, value, uncertainty)) |> |
| 126 | 30x |
dplyr::mutate(value = unlist(value), uncertainty = unlist(uncertainty)) |
| 127 | ||
| 128 |
# Process the density components |
|
| 129 |
# This is done above for fleet information but we will need to do it for |
|
| 130 |
# parameter-level information once we have a link to the parameter id |
|
| 131 | 30x |
density_information <- read_list[["density_components"]] |> |
| 132 | 30x |
dplyr::mutate( |
| 133 | 30x |
density_component = purrr::map(density_component, density_to_tibble) |
| 134 |
) |> |
|
| 135 | 30x |
tidyr::unnest(density_component) |
| 136 | ||
| 137 |
# Process the population data |
|
| 138 | 30x |
population_information <- read_list[["populations"]] |> |
| 139 | 30x |
tidyr::pivot_longer( |
| 140 | 30x |
cols = c(parameters, derived_quantities), |
| 141 | 30x |
names_to = "delete_me", |
| 142 | 30x |
values_to = "parameters" |
| 143 |
) |> |
|
| 144 |
# TODO: Think about these ids when we have more than one population |
|
| 145 | 30x |
dplyr::select(-delete_me, -dplyr::ends_with("_id"), -population) |>
|
| 146 | 30x |
dplyr::mutate( |
| 147 | 30x |
parameters = purrr::map( |
| 148 | 30x |
parameters, |
| 149 | 30x |
\(x) purrr::map_df(x, dimension_folded_to_tibble) |
| 150 |
) |
|
| 151 |
) |> |
|
| 152 | 30x |
tidyr::unnest(parameters) |
| 153 | ||
| 154 |
# TODO: Change some column names |
|
| 155 |
# Bring everything together |
|
| 156 | 30x |
out <- dplyr::bind_rows( |
| 157 |
# density_information, |
|
| 158 | 30x |
fleet_information, |
| 159 | 30x |
module_information, |
| 160 | 30x |
population_information |
| 161 |
) |> |
|
| 162 | 30x |
dplyr::select( |
| 163 | 30x |
module_name, module_id, module_type, |
| 164 | 30x |
"label" = name, |
| 165 | 30x |
type, type_id, "parameter_id" = id, |
| 166 | 30x |
fleet, dplyr::ends_with("_i"),
|
| 167 | 30x |
"input" = value, |
| 168 | 30x |
estimated = "estimated_value", |
| 169 | 30x |
"expected" = expected_values, |
| 170 | 30x |
"observed" = observed_values, |
| 171 | 30x |
estimation_type, |
| 172 | 30x |
distribution, |
| 173 | 30x |
input_type, lpdf = "lpdf_value", likelihood, |
| 174 | 30x |
"log_sd" = log_sd_values, |
| 175 | 30x |
dplyr::everything() |
| 176 |
) |
|
| 177 |
} |
|
| 178 | ||
| 179 |
#' Reshape TMB estimates |
|
| 180 |
#' |
|
| 181 |
#' @description |
|
| 182 |
#' This function processes the TMB std and reshapes them into a structured |
|
| 183 |
#' tibble for easier analysis and manipulation. |
|
| 184 |
#' |
|
| 185 |
#' @param obj An object returned from [TMB::MakeADFun()]. |
|
| 186 |
#' @param sdreport An object of the `sdreport` class as returned from |
|
| 187 |
#' [TMB::sdreport()]. |
|
| 188 |
#' @param opt An object returned from an optimizer, typically from |
|
| 189 |
#' [stats::nlminb()], used to fit a TMB model. If the model is not optimized, |
|
| 190 |
#' opt is an empty list and is not used in the function. |
|
| 191 |
#' @param parameter_names A character vector of parameter names. This is used to |
|
| 192 |
#' identify the parameters in the `std` object. |
|
| 193 |
#' @return A tibble containing the reshaped estimates (i.e., parameters and |
|
| 194 |
#' derived quantities). |
|
| 195 |
reshape_tmb_estimates <- function(obj, |
|
| 196 |
sdreport = NULL, |
|
| 197 |
opt = NULL, |
|
| 198 |
parameter_names) {
|
|
| 199 |
# Outline for the estimates table |
|
| 200 | 29x |
estimates_outline <- tibble::tibble( |
| 201 |
# The FIMS Rcpp module |
|
| 202 | 29x |
module_name = character(), |
| 203 |
# The unique ID of the module |
|
| 204 | 29x |
module_id = integer(), |
| 205 |
# The name of the parameter or derived quantity |
|
| 206 | 29x |
label = character(), |
| 207 |
# The unique ID of the parameter |
|
| 208 | 29x |
parameter_id = integer(), |
| 209 |
# The initial value use to start the optimization procedure |
|
| 210 | 29x |
initial = numeric(), |
| 211 |
# The estimated parameter value, which would be the MLE estimate or the value |
|
| 212 |
# used for a given MCMC iteration |
|
| 213 | 29x |
estimate = numeric(), |
| 214 |
# Estimated uncertainty, reported as a standard deviation |
|
| 215 | 29x |
uncertainty = numeric(), |
| 216 |
# The pointwise log-likelihood used for the test or holdout data |
|
| 217 | 29x |
log_like_cv = numeric(), |
| 218 |
# The gradient component for that parameter, NA for derived quantities |
|
| 219 | 29x |
gradient = numeric() |
| 220 |
) |
|
| 221 | ||
| 222 | 29x |
if (length(sdreport) > 0) {
|
| 223 | 23x |
std <- summary(sdreport) |
| 224 |
# Number of rows for derived quantities: based on the difference |
|
| 225 |
# between the total number of rows in std and the length of parameter_names. |
|
| 226 | 23x |
derived_quantity_nrow <- nrow(std) - length(parameter_names) |
| 227 |
# Create a tibble with the data from the std, and then apply transformations. |
|
| 228 | 23x |
estimates <- estimates_outline |> |
| 229 | 23x |
tibble::add_row( |
| 230 | 23x |
label = dimnames(std)[[1]], |
| 231 | 23x |
estimate = std[, "Estimate"], |
| 232 | 23x |
uncertainty = std[, "Std. Error"], |
| 233 |
# Use obj[["env"]][["parameters"]][["p"]] as this will return both initial |
|
| 234 |
# fixed and random effects while obj[["par"]] only returns initial fixed |
|
| 235 |
# effects |
|
| 236 | 23x |
initial = c( |
| 237 | 23x |
obj[["env"]][["parameters"]][["p"]], |
| 238 | 23x |
rep(NA_real_, derived_quantity_nrow) |
| 239 |
), |
|
| 240 | 23x |
gradient = c( |
| 241 | 23x |
obj[["gr"]](opt[["par"]]), |
| 242 | 23x |
rep(NA_real_, derived_quantity_nrow) |
| 243 |
) |
|
| 244 |
) |
|
| 245 |
} else {
|
|
| 246 | 6x |
estimates <- estimates_outline |> |
| 247 | 6x |
tibble::add_row( |
| 248 | 6x |
label = names(obj[["par"]]), |
| 249 | 6x |
initial = obj[["env"]][["parameters"]][["p"]], |
| 250 | 6x |
estimate = obj[["env"]][["parameters"]][["p"]] |
| 251 |
) |
|
| 252 |
} |
|
| 253 | ||
| 254 | 29x |
estimates <- estimates |> |
| 255 |
# Split labels and extract module, id, label, and parameter id |
|
| 256 | 29x |
dplyr::mutate(label_splits = strsplit(label, split = "\\.")) |> |
| 257 | 29x |
dplyr::rowwise() |> |
| 258 |
# TODO: the code could be simplified using tidyr::separate_wider_*(). |
|
| 259 |
# However, doing so would require avoiding pre-specification of these columns |
|
| 260 |
# in the estimates_outline tibble. Consider updating the code if we decide |
|
| 261 |
# not to create the `estimates_outline` tibble in advance. |
|
| 262 | 29x |
dplyr::mutate( |
| 263 | 29x |
module_name = ifelse(length(label_splits) > 1, label_splits[[1]], NA_character_), |
| 264 | 29x |
module_id = ifelse(length(label_splits) > 1, as.integer(label_splits[[2]]), NA_integer_), |
| 265 | 29x |
label = ifelse(length(label_splits) > 1, label_splits[[3]], label), |
| 266 | 29x |
parameter_id = ifelse(length(label_splits) > 1, as.integer(label_splits[[4]]), NA_integer_) |
| 267 |
) |> |
|
| 268 | 29x |
dplyr::select(-label_splits) |> |
| 269 | 29x |
dplyr::ungroup() |
| 270 |
} |
|
| 271 | ||
| 272 |
#' Converts a dimension-folder section into a tibble |
|
| 273 |
#' |
|
| 274 |
#' This is an internal helper function that processes a complex list |
|
| 275 |
#' structure read in from a json file containing dimensionality information, a |
|
| 276 |
#' name, and either explicit values with a type or estimated values with |
|
| 277 |
#' uncertainty. |
|
| 278 |
#' |
|
| 279 |
#' @param section A section of the json file represented as a list. |
|
| 280 |
#' @return |
|
| 281 |
#' A tibble containing the json output in a formatted structure listing the |
|
| 282 |
#' dimensionality as columns rather than just row and column lengths. |
|
| 283 |
#' @noRd |
|
| 284 |
#' |
|
| 285 |
#' @examples |
|
| 286 |
#' # A simple example for a value with uncertainty: |
|
| 287 |
#' section_derived <- list( |
|
| 288 |
#' name = "derived_quantity_name", |
|
| 289 |
#' dimensionality = list( |
|
| 290 |
#' unit = "m", symbol = "L", scale = 1.0, type = "length" |
|
| 291 |
#' ), |
|
| 292 |
#' value = 10.5, |
|
| 293 |
#' uncertainty = 0.5 |
|
| 294 |
#' ) |
|
| 295 |
#' dimension_folded_to_tibble(section_derived) |
|
| 296 |
dimension_folded_to_tibble <- function(section) {
|
|
| 297 | 2100x |
if (length(section) == 0) {
|
| 298 | ! |
return(NA) |
| 299 |
} |
|
| 300 | 2100x |
while (length(section) == 1) {
|
| 301 | ! |
section <- unlist(section, recursive = FALSE) |
| 302 |
} |
|
| 303 | 2100x |
temp <- dimensions_to_tibble(section[["dimensionality"]]) |> |
| 304 | 2100x |
dplyr::mutate(name = section[["name"]]) |
| 305 | 2100x |
if ("type" %in% names(section)) {
|
| 306 | 540x |
temp |> |
| 307 | 540x |
dplyr::mutate( |
| 308 |
# TODO: Need to rename |
|
| 309 | 540x |
type_id = section[["id"]], |
| 310 | 540x |
type = section[["type"]] |
| 311 |
) |> |
|
| 312 | 540x |
dplyr::bind_cols( |
| 313 | 540x |
tibble::tibble(data = section[["values"]]) |> |
| 314 | 540x |
tidyr::unnest_wider(data) |
| 315 |
) |
|
| 316 |
} else {
|
|
| 317 | 1560x |
temp |> |
| 318 | 1560x |
dplyr::bind_cols( |
| 319 | 1560x |
estimated_value = unlist(section[["value"]]), |
| 320 | 1560x |
estimation_type = "derived_quantity" |
| 321 |
) |
|
| 322 |
} |
|
| 323 |
} |
|
| 324 | ||
| 325 |
#' Covert the dimension information from a FIMS json output into a tibble |
|
| 326 |
#' |
|
| 327 |
#' Dimensions in the json output are stored as a list of length two, with the |
|
| 328 |
#' header information containing the name of the dimension and the dimensions |
|
| 329 |
#' containing integers specifying the length for each dimension. The result |
|
| 330 |
#' helps interpret how the FIMS output is structured given it is dimension |
|
| 331 |
#' folded into a single vector in the json output. |
|
| 332 |
#' |
|
| 333 |
#' @details |
|
| 334 |
#' The dimension index is returned not the actual year of the model. For |
|
| 335 |
#' example, if the model starts in year 1900, then year_i of 1, which is what |
|
| 336 |
#' is returned from this function will need to map to 1900 and that will need |
|
| 337 |
#' to be done externally. |
|
| 338 |
#' This function will accommodate dimensions of year-1 and year+1 where the |
|
| 339 |
#' indexing of the former will start at 2 instead of 1. |
|
| 340 |
#' @param data A list containing the header and dimensions information from a |
|
| 341 |
#' FIMS json output object. |
|
| 342 |
#' @return |
|
| 343 |
#' A tibble containing ordered rows for each combination of the dimensions. |
|
| 344 |
#' @noRd |
|
| 345 |
#' @examples |
|
| 346 |
#' dummy_dimensions <- list( |
|
| 347 |
#' header = list("n_years", "n_ages"),
|
|
| 348 |
#' dimensions = list(30L, 12L) |
|
| 349 |
#' ) |
|
| 350 |
#' dimensions_to_tibble(dummy_dimensions) |
|
| 351 |
#' # Example with n_years+1 |
|
| 352 |
#' dummy_dimensions <- list( |
|
| 353 |
#' header = list("n_years+1", "n_ages"),
|
|
| 354 |
#' dimensions = list(31L, 12L) |
|
| 355 |
#' ) |
|
| 356 |
#' dimensions_to_tibble(dummy_dimensions) |
|
| 357 |
dimensions_to_tibble <- function(data) {
|
|
| 358 |
#' Replace headers like "n_years" with "year_i". |
|
| 359 |
#' Example: "n_ages+1" with "age_i" |
|
| 360 |
#' This matches names starting with 'n' (with or without an underscore) |
|
| 361 |
#' and shortens them to a simple indexed form. |
|
| 362 | 2242x |
better_names <- unlist(data[["header"]]) |> |
| 363 | 2242x |
gsub(pattern = "^n_?(.+?)s([-\\+]\\d+)?$", replacement = "\\1_i") |
| 364 | 2242x |
names(data[["dimensions"]]) <- better_names |
| 365 | 2242x |
if (length(better_names) == 0) {
|
| 366 |
# When the header is NULL |
|
| 367 | 240x |
return(tibble::add_row(tibble::tibble())) |
| 368 |
} |
|
| 369 | 2002x |
if ("na" %in% better_names && length(better_names) == 1) {
|
| 370 |
# When the dimensions are na because there is no associated indexing |
|
| 371 | 60x |
return(tibble::add_row(tibble::tibble())) |
| 372 |
} |
|
| 373 |
# Accommodate any -1 by creating a different start value |
|
| 374 | 1942x |
test <- grepl("-\\d", data[["header"]])
|
| 375 | 1942x |
addition <- gsub(".+-(\\d)", "\\1", data[["header"]])
|
| 376 | 1942x |
addition[!test] <- 0 |
| 377 | 1942x |
start <- 1 + as.numeric(addition) |
| 378 | 1942x |
data[["dimensions"]][test] <- as.numeric(data[["dimensions"]][test]) + |
| 379 | 1942x |
as.numeric(addition) |
| 380 |
# Create the returned tibble by first sequencing from 1:n for each dimension |
|
| 381 | 1942x |
purrr::map2(start, data[["dimensions"]], seq) |> |
| 382 | 1942x |
purrr::set_names(names(data[["dimensions"]])) |> |
| 383 | 1942x |
expand.grid() |> |
| 384 | 1942x |
tibble::as_tibble() |> |
| 385 | 1942x |
dplyr::arrange(!!!rlang::syms(better_names)) |
| 386 |
} |
|
| 387 | ||
| 388 |
#' Convert the density component information into a tibble |
|
| 389 |
#' |
|
| 390 |
#' @description |
|
| 391 |
#' The log probability density function (lpdf) information is information in |
|
| 392 |
#' the json that pertains to a distribution, which is often associated with a |
|
| 393 |
#' data stream. For example, the lognormal distribution can be associated with |
|
| 394 |
#' landings for a given fleet because those landings might be uncertain. |
|
| 395 |
#' |
|
| 396 |
#' @details |
|
| 397 |
#' The raw information, i.e., `data` is a list of unknown dimensions, where the |
|
| 398 |
#' first element of the list, i.e., `lpdf_value`, is a single numeric value and |
|
| 399 |
#' the remaining list elements are lists themselves. This function converts the |
|
| 400 |
#' list to a tibble and then extracts only columns that have some derivative of |
|
| 401 |
#' "value" in their name, e.g., `lpdf_value`, `expected_values`, etc., using |
|
| 402 |
#' regular expression matching. Thus, when `data` does not have an entry for |
|
| 403 |
#' `log_sd_values` the function does not fail but will return a smaller tibble |
|
| 404 |
#' than normal. |
|
| 405 |
#' |
|
| 406 |
#' It is imperative that each list element of `data` be of length one or the |
|
| 407 |
#' exact same length as the other elements. There is an internal check in the |
|
| 408 |
#' function for this consistency. |
|
| 409 |
#' |
|
| 410 |
#' The code that writes this json information is stored in `inst/include/interface/rcpp/rcpp_objects/rcpp_distribution.hpp`. |
|
| 411 |
#' @param data A list of `density_components` from the json output that is a |
|
| 412 |
#' list of lists. The first element of the list will be `lpdf_value`, a |
|
| 413 |
#' single entry that stores the log probability density function value. The |
|
| 414 |
#' remaining list elements have "value" in their name and are formatted as |
|
| 415 |
#' lists themselves. |
|
| 416 |
#' @return |
|
| 417 |
#' A tibble is returned with the `lpdf_value` first and then other columns with |
|
| 418 |
#' value in their name following. The columns will be in the same order they |
|
| 419 |
#' are reported in the json output. |
|
| 420 |
#' @noRd |
|
| 421 |
#' |
|
| 422 |
#' @examples |
|
| 423 |
#' dummy_density <- list( |
|
| 424 |
#' name = "lpdf_vec", |
|
| 425 |
#' lpdf_value = -102.079, |
|
| 426 |
#' values = list( |
|
| 427 |
#' -1.39915, -2.44735, -2.93024, -3.21848, -2.95698, -3.51745 |
|
| 428 |
#' ), |
|
| 429 |
#' expected_values = list( |
|
| 430 |
#' 5.0854, 6.13354, 6.61636, 6.90467, 6.64311, 7.20302 |
|
| 431 |
#' ), |
|
| 432 |
#' observed_values = list( |
|
| 433 |
#' 161.646, 461.089, 747.29, 996.971, 767.548, 1343.86 |
|
| 434 |
#' ) |
|
| 435 |
#' ) |
|
| 436 |
#' density_to_tibble(dummy_density) |
|
| 437 |
#' @noRd |
|
| 438 |
density_to_tibble <- function(data) {
|
|
| 439 |
# Check that each list element is of length-one or the same length otherwise |
|
| 440 |
# the resulting tibble will not be the correct dimensions |
|
| 441 | 314x |
element_lengths <- purrr::map_int(data, length) |
| 442 | 314x |
check <- if (all(element_lengths == 1)) {
|
| 443 | ! |
TRUE |
| 444 |
} else {
|
|
| 445 | 314x |
length(unique(element_lengths[element_lengths != 1])) == 1 |
| 446 |
} |
|
| 447 | 314x |
if (!check) {
|
| 448 | ! |
cli::cli_abort( |
| 449 | ! |
"Not all elements in the density component information are equal or of |
| 450 | ! |
length 1, their lengths are as follows: {element_lengths}.
|
| 451 | ! |
The lpdf_value of this element is {data[['lpdf_value']][1]}."
|
| 452 |
) |
|
| 453 |
} |
|
| 454 | ||
| 455 |
# Return the tibble |
|
| 456 | 314x |
data |> |
| 457 | 314x |
tibble::as_tibble() |> |
| 458 | 314x |
tidyr::unnest(dplyr::contains("value")) |>
|
| 459 | 314x |
dplyr::rename(likelihood = value) |
| 460 |
} |
| 1 |
# To remove the WARNING |
|
| 2 |
# no visible binding for global variable |
|
| 3 |
utils::globalVariables(c( |
|
| 4 |
"everything", "fleet_name" |
|
| 5 |
)) |
|
| 6 | ||
| 7 |
#' Create a default FIMS configuration tibble |
|
| 8 |
#' |
|
| 9 |
#' @description |
|
| 10 |
#' This function generates a default configuration tibble for a Fisheries |
|
| 11 |
#' Integrated Modeling System (FIMS) model based on the data input. It |
|
| 12 |
#' automatically creates configuration entries for data modules (e.g., landings, |
|
| 13 |
#' index, compositions) and, depending on the model family, standard population |
|
| 14 |
#' dynamics modules (recruitment, growth, maturity) and selectivity modules for |
|
| 15 |
#' fleets. |
|
| 16 |
#' |
|
| 17 |
#' @details |
|
| 18 |
#' The function inspects the data to find unique combinations of fleet |
|
| 19 |
#' names and data types. It then maps these to the appropriate FIMS module names |
|
| 20 |
#' and joins them with a predefined template of default settings. When the |
|
| 21 |
#' `model_family` is "catch_at_age", it also adds default configurations for: |
|
| 22 |
#' \itemize{
|
|
| 23 |
#' \item **Selectivity:** A logistic selectivity module for each unique fleet. |
|
| 24 |
#' \item **Recruitment:** A Beverton--Holt recruitment module. |
|
| 25 |
#' \item **Growth:** An empirical weight-at-age (EWAA) growth module. |
|
| 26 |
#' \item **Maturity:** A logistic maturity module. |
|
| 27 |
#' } |
|
| 28 |
#' The final output is a nested tibble, which serves as a starting point for |
|
| 29 |
#' building a complete FIMS model configuration. |
|
| 30 |
#' |
|
| 31 |
#' @param data An S4 object of class `FIMSFrame`. FIMS input data. |
|
| 32 |
#' @param model_family A string specifying the model family. |
|
| 33 |
#' Defaults to `"catch_at_age"`. |
|
| 34 |
#' |
|
| 35 |
#' @return A `tibble` with default model configurations. The tibble has a nested |
|
| 36 |
#' structure with the following top-level columns. |
|
| 37 |
#' \describe{
|
|
| 38 |
#' \item{\code{model_family}:}{The specified model family (e.g.,
|
|
| 39 |
#' "catch_at_age").} |
|
| 40 |
#' \item{\code{module_name}:}{The name of the FIMS module (e.g.,
|
|
| 41 |
#' "Data", "Selectivity", "Recruitment", "Growth", "Maturity").} |
|
| 42 |
#' \item{\code{fleet_name}:}{The name of the fleet the module applies to. This
|
|
| 43 |
#' will be `NA` for non-fleet-specific modules like "Recruitment".} |
|
| 44 |
#' \item{\code{data}:}{A list-column containing a `tibble` with detailed
|
|
| 45 |
#' configurations. Unnesting this column reveals: |
|
| 46 |
#' \describe{
|
|
| 47 |
#' \item{\code{module_type}:}{The specific type of the module (e.g.,
|
|
| 48 |
#' "Logistic" for a "Selectivity" module).} |
|
| 49 |
#' \item{\code{distribution_link}:}{The component the distribution module
|
|
| 50 |
#' links to.} |
|
| 51 |
#' \item{\code{distribution_type}:}{The type of distribution (e.g., "Data",
|
|
| 52 |
#' "process").} |
|
| 53 |
#' \item{\code{distribution}:}{The name of distribution (e.g.,
|
|
| 54 |
#' "Dlnorm", `Dmultinom`).} |
|
| 55 |
#' } |
|
| 56 |
#' } |
|
| 57 |
#' } |
|
| 58 |
#' |
|
| 59 |
#' @export |
|
| 60 |
#' |
|
| 61 |
#' @examples |
|
| 62 |
#' # Load the example dataset and create a FIMS data frame |
|
| 63 |
#' data("data_big")
|
|
| 64 |
#' fims_frame <- FIMSFrame(data_big) |
|
| 65 |
#' |
|
| 66 |
#' # Create the default model configuration tibble |
|
| 67 |
#' default_configurations <- create_default_configurations(data = fims_frame) |
|
| 68 |
#' |
|
| 69 |
#' # Unnest the data column to see detailed configurations |
|
| 70 |
#' default_configurations_unnest <- default_configurations |> |
|
| 71 |
#' tidyr::unnest(cols = data) |> |
|
| 72 |
#' print() |
|
| 73 |
#' |
|
| 74 |
#' # Model fleet1 with double logistic selectivity |
|
| 75 |
#' configurations_double_logistic <- default_configurations_unnest |> |
|
| 76 |
#' dplyr::rows_update( |
|
| 77 |
#' tibble::tibble( |
|
| 78 |
#' module_name = "Selectivity", |
|
| 79 |
#' fleet_name = "fleet1", |
|
| 80 |
#' module_type = "DoubleLogistic" |
|
| 81 |
#' ), |
|
| 82 |
#' by = c("module_name", "fleet_name")
|
|
| 83 |
#' ) |> |
|
| 84 |
#' print() |
|
| 85 |
create_default_configurations <- function(data, model_family = c("catch_at_age")) {
|
|
| 86 |
# Check if the input object is a FIMSFrame, aborting if not. |
|
| 87 | 13x |
if (!inherits(data, "FIMSFrame")) {
|
| 88 | 1x |
cli::cli_abort( |
| 89 | 1x |
c( |
| 90 | 1x |
"{.var data} must be a {.cls FIMSFrame} object.",
|
| 91 | 1x |
"i" = "Please convert your data before using this function." |
| 92 |
) |
|
| 93 |
) |
|
| 94 |
} |
|
| 95 | ||
| 96 |
# Ensures the user input matches the options provided, |
|
| 97 |
# if not, then match.arg() throws an error |
|
| 98 | 12x |
model_family <- match.arg(model_family) |
| 99 | ||
| 100 |
# Extract unique combinations of fleet names and data types from the data. |
|
| 101 |
# This forms the basis for determining which modules are needed for each fleet. |
|
| 102 | 11x |
unique_fleet_types <- data |> |
| 103 | 11x |
get_data() |> |
| 104 | 11x |
dplyr::distinct(name, type) |> |
| 105 |
# Convert type from snake_case to PascalCase |
|
| 106 | 11x |
dplyr::mutate(module_type = snake_to_pascal(type)) |> |
| 107 |
# Set module_type to NA for weight-at-age and age-to-length-conversion |
|
| 108 | 11x |
dplyr::mutate(module_type = dplyr::case_when( |
| 109 | 11x |
type == "weight_at_age" ~ NA_character_, |
| 110 | 11x |
type == "age_to_length_conversion" ~ NA_character_, |
| 111 | 11x |
TRUE ~ module_type |
| 112 |
)) |> |
|
| 113 |
# Remove any combinations where the type did not match a known module. |
|
| 114 | 11x |
dplyr::filter(!is.na(module_type)) |> |
| 115 | 11x |
dplyr::rename(fleet_name = name) |> |
| 116 | 11x |
dplyr::select(-type) |
| 117 | ||
| 118 |
# Define a template for data modules (comps, landings, index). |
|
| 119 |
# This specifies the default distribution for each type of data. |
|
| 120 | 11x |
data_config_template <- dplyr::tribble( |
| 121 | 11x |
~module_name, ~module_type, ~distribution_link, ~distribution_type, ~distribution, |
| 122 | 11x |
"Data", "Landings", "Landings", "Data", "Dlnorm", |
| 123 | 11x |
"Data", "Index", "Index", "Data", "Dlnorm", |
| 124 | 11x |
"Data", "AgeComp", "AgeComp", "Data", "Dmultinom", |
| 125 | 11x |
"Data", "LengthComp", "LengthComp", "Data", "Dmultinom" |
| 126 |
) |
|
| 127 | ||
| 128 |
# Create data module configurations by joining the unique fleet types |
|
| 129 |
# with the corresponding template entries. |
|
| 130 | 11x |
fleet_data_config <- unique_fleet_types |> |
| 131 | 11x |
dplyr::left_join(data_config_template, by = "module_type") |
| 132 | ||
| 133 |
# Initialize placeholders for conditional configurations. |
|
| 134 | 11x |
selectivity_config <- tibble::tibble() |
| 135 | 11x |
other_config <- tibble::tibble() |
| 136 | ||
| 137 |
# If model_family is "catch_at_age", create selectivity configurations for |
|
| 138 |
# fleets and other configurations for population dynamics. |
|
| 139 | 11x |
if (model_family == "catch_at_age") {
|
| 140 |
# Create these rows by getting distinct fleet names and joining them |
|
| 141 |
# with the selectivity template. |
|
| 142 | 11x |
selectivity_config <- unique_fleet_types |> |
| 143 | 11x |
dplyr::distinct(fleet_name) |> |
| 144 | 11x |
dplyr::mutate( |
| 145 | 11x |
module_name = "Selectivity", |
| 146 | 11x |
module_type = "Logistic" |
| 147 |
) |
|
| 148 | ||
| 149 |
# Define a template for standard, non-fleet-specific modules. |
|
| 150 | 11x |
other_config <- dplyr::tribble( |
| 151 | 11x |
~module_name, ~module_type, ~distribution_link, ~distribution_type, ~distribution, |
| 152 | 11x |
"Recruitment", "BevertonHolt", "log_devs", "process", "Dnorm", |
| 153 | 11x |
"Growth", "EWAA", NA_character_, NA_character_, NA_character_, |
| 154 | 11x |
"Maturity", "Logistic", NA_character_, NA_character_, NA_character_ |
| 155 |
) |
|
| 156 |
} |
|
| 157 | ||
| 158 |
# Combine all configuration pieces into a single tibble. |
|
| 159 |
# The `dplyr::bind_rows` function intelligently handles differing columns |
|
| 160 |
# by filling missing values with NA. |
|
| 161 | 11x |
final_config <- dplyr::bind_rows( |
| 162 | 11x |
fleet_data_config, |
| 163 | 11x |
selectivity_config, |
| 164 | 11x |
other_config |
| 165 |
) |> |
|
| 166 |
# Add model_family column |
|
| 167 | 11x |
dplyr::mutate(model_family = model_family) |> |
| 168 |
# Arrange for readability. |
|
| 169 | 11x |
dplyr::arrange(fleet_name, module_name) |> |
| 170 |
# Reorder columns |
|
| 171 | 11x |
dplyr::select( |
| 172 | 11x |
model_family, module_name, module_type, fleet_name, everything() |
| 173 |
) |> |
|
| 174 |
# Nest the configuration details into a list-column called 'data'. |
|
| 175 |
# This creates the final, structured output format expected by FIMS. |
|
| 176 | 11x |
tidyr::nest(.by = c(model_family, module_name, fleet_name)) |
| 177 |
} |
|
| 178 | ||
| 179 |
#' Convert snake_case strings to PascalCase |
|
| 180 |
#' |
|
| 181 |
#' This function takes a vector of strings in snake_case format and converts |
|
| 182 |
#' them to PascalCase. |
|
| 183 |
#' |
|
| 184 |
#' @param snake_strings A vector of strings in snake_case format. |
|
| 185 |
#' @return A vector of strings in PascalCase format. |
|
| 186 |
#' @examples |
|
| 187 |
#' snake_to_pascal(c("age_comp", "length_comp"))
|
|
| 188 |
#' snake_to_pascal("index")
|
|
| 189 |
#' @noRd |
|
| 190 |
snake_to_pascal <- function(snake_strings) {
|
|
| 191 | 11x |
purrr::map_chr(snake_strings, \(x) {
|
| 192 | 83x |
parts <- strsplit(x, "_")[[1]] |
| 193 | 83x |
paste( |
| 194 | 83x |
toupper(substring(parts, 1, 1)), |
| 195 | 83x |
substring(parts, 2), |
| 196 | 83x |
sep = "", |
| 197 | 83x |
collapse = "" |
| 198 |
) |
|
| 199 |
}) |
|
| 200 |
} |
| 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 | 11x |
verbose_option <- getOption("rlib_message_verbosity", default = "default")
|
| 20 | 11x |
verbose_boolean <- verbose_option %in% c("default", "verbose")
|
| 21 | 11x |
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 | 248x |
DataObject(size_t imax) : dimensions(1), imax(imax) {
|
| 40 | 248x |
data.resize(imax); |
| 41 | 248x |
uncertainty.resize(imax); |
| 42 | 248x |
this->id = DataObject<Type>::id_g++; |
| 43 |
} |
|
| 44 | ||
| 45 |
/** |
|
| 46 |
* Constructs a two-dimensional data object. |
|
| 47 |
*/ |
|
| 48 | 440x |
DataObject(size_t imax, size_t jmax) : dimensions(2), imax(imax), jmax(jmax) {
|
| 49 | 440x |
data.resize(imax * jmax); |
| 50 | 440x |
uncertainty.resize(imax * jmax); |
| 51 | 440x |
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 | 1995838x |
inline Type& at(size_t i) {
|
| 88 | 1995838x |
if (i >= this->data.size()) {
|
| 89 | ! |
throw std::overflow_error("DataObject error:i index out of bounds");
|
| 90 |
} |
|
| 91 | 1995838x |
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 | 2172498x |
inline Type& at(size_t i, size_t j) {
|
| 112 | 2172498x |
if ((i * jmax + j) >= this->data.size()) {
|
| 113 | ! |
throw std::overflow_error("DataObject error: index out of bounds");
|
| 114 |
} |
|
| 115 | 2172498x |
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 | 344x |
size_t get_imax() const { return imax; }
|
| 186 | ||
| 187 |
/** |
|
| 188 |
* @brief Get the jmax object |
|
| 189 |
* |
|
| 190 |
* @return size_t |
|
| 191 |
*/ |
|
| 192 | 344x |
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 |
#define TMBAD_FIMS_TYPE TMBad::ad_aug |
|
| 87 |
#endif |
|
| 88 | ||
| 89 |
namespace fims {
|
|
| 90 | ||
| 91 |
/** |
|
| 92 |
* Log entry. |
|
| 93 |
*/ |
|
| 94 |
struct LogEntry {
|
|
| 95 |
/** The date/time that the log entry was created, e.g., "Oct 28 09:18:51 |
|
| 96 |
* 2024". You can track how long it took to work through each portion of the |
|
| 97 |
* model by analyzing the progression of the timestamp through the log file.*/ |
|
| 98 |
std::string timestamp; |
|
| 99 |
/** The description of the log entry, e.g., "Adding Selectivity object to TMB" |
|
| 100 |
* or "Mismatch dimension error", where the descriptions are predefined in the |
|
| 101 |
* C++ code. Please make a GitHub issue or contact a developer if you have |
|
| 102 |
* ideas for a more informative description.*/ |
|
| 103 |
std::string message; |
|
| 104 |
/** The logging level, which is a result of which macro was used to generate |
|
| 105 |
* the message, e.g., FIMS_INFO_LOG(), FIMS_WARNING_LOG(), or FIMS_ERROR_LOG() |
|
| 106 |
* results in "info", "warning", or "error", respectively, in the log file.*/ |
|
| 107 |
std::string level; |
|
| 108 |
/** The message id, directly corresponds to the order in which the entries |
|
| 109 |
* were created, e.g., "1", which is helpful for knowing the order of |
|
| 110 |
* operations within the code base and comparing log files across model |
|
| 111 |
* runs.*/ |
|
| 112 |
size_t rank; |
|
| 113 |
/** The user name registered to the computer where the log file was created, |
|
| 114 |
* e.g., "John.Doe".*/ |
|
| 115 |
std::string user; |
|
| 116 |
/** The working directory for the R environment that created the log file, |
|
| 117 |
* e.g., "C:/github/NOAA-FIMS/FIMS/vignettes" if you are on a Windows machine |
|
| 118 |
* or "/home/oppy/FIMS-Testing/dev/dev_logging/FIMS/vignettes" if you are on a |
|
| 119 |
* linux machine.*/ |
|
| 120 |
std::string wd; |
|
| 121 |
/** The full file path of the file that triggered the log entry, e.g., |
|
| 122 |
* "C:/github/NOAA-FIMS/FIMS/inst/include/interface/rcpp/rcpp_objects/rcpp_selectivity.hpp".*/ |
|
| 123 |
std::string file; |
|
| 124 |
/** The function or method that led to the initialization the log entry, e.g., |
|
| 125 |
* "virtual bool LogisticSelectivityInterface::add_to_fims_tmb()". If the |
|
| 126 |
* function is templated, then the function type will be reported here in |
|
| 127 |
* square brackets after the function name, e.g., "bool |
|
| 128 |
* fims_info::Information<Type>::CreateModel() [with Type = double]".*/ |
|
| 129 |
std::string routine; |
|
| 130 |
/** The line in `file` where the log entry was initiated, e.g., "219", which |
|
| 131 |
* will be a line inside of the `routine` listed above.*/ |
|
| 132 |
int line; |
|
| 133 | ||
| 134 |
/** |
|
| 135 |
* Convert this object to a string. |
|
| 136 |
*/ |
|
| 137 | 24189x |
std::string to_string() {
|
| 138 | 24189x |
std::stringstream ss; |
| 139 | 24189x |
ss << "\"timestamp\": " << "\"" << this->timestamp << "\"" << ",\n"; |
| 140 | 24189x |
ss << "\"level\": " << "\"" << this->level << "\",\n"; |
| 141 | 24189x |
ss << "\"message\": " << "\"" << this->message << "\",\n"; |
| 142 | 24189x |
ss << "\"id\": " << "\"" << this->rank << "\",\n"; |
| 143 | 24189x |
ss << "\"user\": " << "\"" << this->user << "\",\n"; |
| 144 | 24189x |
ss << "\"wd\": " << "\"" << this->wd << "\",\n"; |
| 145 | 24189x |
ss << "\"file\": " << "\"" << this->file << "\",\n"; |
| 146 | 24189x |
ss << "\"routine\": " << "\"" << this->routine << "\",\n"; |
| 147 | 24189x |
ss << "\"line\": " << "\"" << this->line << "\"\n"; |
| 148 | 48378x |
return ss.str(); |
| 149 |
} |
|
| 150 |
}; |
|
| 151 | ||
| 152 |
/** |
|
| 153 |
* FIMS logging class. |
|
| 154 |
*/ |
|
| 155 |
class FIMSLog {
|
|
| 156 |
std::vector<std::string> entries; |
|
| 157 |
std::vector<LogEntry> log_entries; |
|
| 158 |
size_t entry_number = 0; |
|
| 159 |
std::string path = "fims.log"; |
|
| 160 |
size_t warning_count = 0; |
|
| 161 |
size_t error_count = 0; |
|
| 162 | ||
| 163 |
/** |
|
| 164 |
* Get username. |
|
| 165 |
* |
|
| 166 |
* @return username. |
|
| 167 |
*/ |
|
| 168 | 31997x |
std::string get_user() {
|
| 169 |
#ifdef FIMS_WINDOWS |
|
| 170 |
char username[UNLEN + 1]; |
|
| 171 |
DWORD username_len = UNLEN + 1; |
|
| 172 |
if (GetUserNameA(username, &username_len)) {
|
|
| 173 |
return std::string(username); |
|
| 174 |
} else {
|
|
| 175 |
return "[unknown user]"; |
|
| 176 |
} |
|
| 177 | ||
| 178 |
#elif defined(FIMS_LINUX) || defined(FIMS_MACOS) || defined(FIMS_BSD) |
|
| 179 | 31997x |
const char* user_env = getenv("USER");
|
| 180 | 95991x |
if (user_env) return std::string(user_env); |
| 181 | ||
| 182 | ! |
uid_t uid = getuid(); |
| 183 | ! |
struct passwd* pw = getpwuid(uid); |
| 184 | ! |
if (pw && pw->pw_name) {
|
| 185 | ! |
return std::string(pw->pw_name); |
| 186 |
} else {
|
|
| 187 | ! |
return "[unknown user]"; |
| 188 |
} |
|
| 189 | ||
| 190 |
#else |
|
| 191 |
return "[unsupported platform]"; |
|
| 192 |
#endif |
|
| 193 |
} |
|
| 194 | ||
| 195 |
public: |
|
| 196 |
/** |
|
| 197 |
* @brief A boolean specifying if the log file is written when the session is |
|
| 198 |
* terminated. The default is TRUE. |
|
| 199 |
* |
|
| 200 |
*/ |
|
| 201 |
bool write_on_exit = true; |
|
| 202 |
/** |
|
| 203 |
* @brief A boolean specifying if the program is stopped upon the first |
|
| 204 |
* error, where the default is FALSE. This allows you go through an entire |
|
| 205 |
* program to collect all error messages. |
|
| 206 |
* |
|
| 207 |
*/ |
|
| 208 |
bool throw_on_error = false; |
|
| 209 |
/** |
|
| 210 |
* @brief A singleton instance of the log, i.e., where there is only one |
|
| 211 |
* log. The object is created when the .dll is loaded and it will never |
|
| 212 |
* be recreated while the .dll is loaded. |
|
| 213 |
* |
|
| 214 |
*/ |
|
| 215 |
static std::shared_ptr<FIMSLog> fims_log; |
|
| 216 | ||
| 217 |
/** |
|
| 218 |
* Default constructor for FIMSLog. |
|
| 219 |
*/ |
|
| 220 | 9x |
FIMSLog() {}
|
| 221 | ||
| 222 |
/** |
|
| 223 |
* Destructor. If write_on_exit is set to true, |
|
| 224 |
* the log will be written to the disk in JSON format. |
|
| 225 |
*/ |
|
| 226 | 3x |
~FIMSLog() {
|
| 227 | 3x |
if (this->write_on_exit) {
|
| 228 | 3x |
std::ofstream log(this->path); |
| 229 | 3x |
log << this->get_log(); |
| 230 | 3x |
log.close(); |
| 231 |
} |
|
| 232 |
} |
|
| 233 | ||
| 234 |
/** |
|
| 235 |
* @brief Get the Absolute Path Without Dot Dot object |
|
| 236 |
* |
|
| 237 |
* Dot dot notation is for relative paths, where this function replaces |
|
| 238 |
* all dot dots with the actual full path. |
|
| 239 |
* |
|
| 240 |
* @param relativePath A path in your file system. |
|
| 241 |
* @return std::filesystem::path |
|
| 242 |
*/ |
|
| 243 | 31997x |
std::filesystem::path getAbsolutePathWithoutDotDot( |
| 244 |
const std::filesystem::path& relativePath) {
|
|
| 245 |
std::filesystem::path absolutePath = |
|
| 246 | 31997x |
std::filesystem::absolute(relativePath); |
| 247 | ||
| 248 | 31997x |
std::filesystem::path result; |
| 249 | 486727x |
for (const auto& part : absolutePath) {
|
| 250 | 454730x |
if (part == "..") {
|
| 251 | 38961x |
if (!result.empty()) {
|
| 252 | 38961x |
result = result.parent_path(); |
| 253 |
} |
|
| 254 |
} else {
|
|
| 255 | 415769x |
result /= part; |
| 256 |
} |
|
| 257 |
} |
|
| 258 | ||
| 259 | 63994x |
return result.generic_string(); |
| 260 |
} |
|
| 261 | ||
| 262 |
/** |
|
| 263 |
* Set a path for the log file. |
|
| 264 |
* |
|
| 265 |
* @param path |
|
| 266 |
*/ |
|
| 267 | ! |
void set_path(std::string path) { this->path = path; }
|
| 268 | ||
| 269 |
/** |
|
| 270 |
* Get the path for the log file. |
|
| 271 |
* |
|
| 272 |
* @return |
|
| 273 |
*/ |
|
| 274 | ! |
std::string get_path() { return this->path; }
|
| 275 | ||
| 276 |
/** |
|
| 277 |
* Add a "info" level message to the log. |
|
| 278 |
* |
|
| 279 |
* @param str |
|
| 280 |
* @param line |
|
| 281 |
* @param file |
|
| 282 |
* @param func |
|
| 283 |
*/ |
|
| 284 | 31924x |
void info_message(std::string str, int line, const char* file, |
| 285 |
const char* func) {
|
|
| 286 | 31924x |
std::filesystem::path relativePath = file; |
| 287 |
std::filesystem::path absolutePath = |
|
| 288 | 31924x |
getAbsolutePathWithoutDotDot(relativePath); |
| 289 | 31924x |
std::filesystem::path cwd = std::filesystem::current_path(); |
| 290 | 31924x |
std::stringstream ss; |
| 291 | 31924x |
auto now = std::chrono::system_clock::now(); |
| 292 | 31924x |
std::time_t now_time = std::chrono::system_clock::to_time_t(now); |
| 293 | 31924x |
std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); |
| 294 | ||
| 295 | 31924x |
LogEntry l; |
| 296 | 31924x |
l.timestamp = ctime_no_newline; |
| 297 | 31924x |
l.message = str; |
| 298 | 31924x |
l.level = "info"; |
| 299 | 31924x |
l.rank = this->log_entries.size(); |
| 300 | 31924x |
l.user = this->get_user(); |
| 301 | 31924x |
l.wd = cwd.generic_string(); |
| 302 | 31924x |
l.file = absolutePath.string(); |
| 303 | 31924x |
l.line = line; |
| 304 | 31924x |
l.routine = func; |
| 305 | 31924x |
this->log_entries.push_back(l); |
| 306 |
} |
|
| 307 | ||
| 308 |
/** |
|
| 309 |
* Add a "error" level message to the log. |
|
| 310 |
* |
|
| 311 |
* @param str |
|
| 312 |
* @param line |
|
| 313 |
* @param file |
|
| 314 |
* @param func |
|
| 315 |
*/ |
|
| 316 | 2x |
void error_message(std::string str, int line, const char* file, |
| 317 |
const char* func) {
|
|
| 318 | 2x |
this->error_count++; |
| 319 | 2x |
std::filesystem::path relativePath = file; |
| 320 |
std::filesystem::path absolutePath = |
|
| 321 | 2x |
getAbsolutePathWithoutDotDot(relativePath); |
| 322 | 2x |
std::filesystem::path cwd = std::filesystem::current_path(); |
| 323 | ||
| 324 | 2x |
std::stringstream ss; |
| 325 | 2x |
auto now = std::chrono::system_clock::now(); |
| 326 | 2x |
std::time_t now_time = std::chrono::system_clock::to_time_t(now); |
| 327 | 2x |
std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); |
| 328 | ||
| 329 | 2x |
LogEntry l; |
| 330 | 2x |
l.timestamp = ctime_no_newline; |
| 331 | 2x |
l.message = str; |
| 332 | 2x |
l.level = "error"; |
| 333 | 2x |
l.rank = this->log_entries.size(); |
| 334 | 2x |
l.user = this->get_user(); |
| 335 | 2x |
l.wd = cwd.generic_string(); |
| 336 | 2x |
l.file = absolutePath.string(); |
| 337 | 2x |
l.line = line; |
| 338 | 2x |
l.routine = func; |
| 339 | 2x |
this->log_entries.push_back(l); |
| 340 | ||
| 341 | 2x |
if (this->throw_on_error) {
|
| 342 | ! |
std::stringstream ss; |
| 343 | ! |
ss << "\n\n" << l.to_string() << "\n\n"; |
| 344 | ! |
throw std::runtime_error(ss.str().c_str()); |
| 345 |
} |
|
| 346 |
} |
|
| 347 | ||
| 348 |
/** |
|
| 349 |
* Add a "warning" level message to the log. |
|
| 350 |
* |
|
| 351 |
* @param str |
|
| 352 |
* @param line |
|
| 353 |
* @param file |
|
| 354 |
* @param func |
|
| 355 |
*/ |
|
| 356 | 71x |
void warning_message(std::string str, int line, const char* file, |
| 357 |
const char* func) {
|
|
| 358 | 71x |
this->warning_count++; |
| 359 | 71x |
std::filesystem::path relativePath = file; |
| 360 |
std::filesystem::path absolutePath = |
|
| 361 | 71x |
getAbsolutePathWithoutDotDot(relativePath); |
| 362 | 71x |
std::filesystem::path cwd = std::filesystem::current_path(); |
| 363 | ||
| 364 | 71x |
std::stringstream ss; |
| 365 | 71x |
auto now = std::chrono::system_clock::now(); |
| 366 | 71x |
std::time_t now_time = std::chrono::system_clock::to_time_t(now); |
| 367 | 71x |
std::string ctime_no_newline = strtok(ctime(&now_time), "\n"); |
| 368 | ||
| 369 | 71x |
LogEntry l; |
| 370 | 71x |
l.timestamp = ctime_no_newline; |
| 371 | 71x |
l.message = str; |
| 372 | 71x |
l.level = "warning"; |
| 373 | 71x |
l.rank = this->log_entries.size(); |
| 374 | 71x |
l.user = this->get_user(); |
| 375 | 71x |
l.wd = cwd.generic_string(); |
| 376 | 71x |
l.file = absolutePath.string(); |
| 377 | 71x |
l.line = line; |
| 378 | 71x |
l.routine = func; |
| 379 | 71x |
this->log_entries.push_back(l); |
| 380 |
} |
|
| 381 | ||
| 382 |
/** |
|
| 383 |
* Get the log as a string object. |
|
| 384 |
* |
|
| 385 |
* @return |
|
| 386 |
*/ |
|
| 387 | 3x |
std::string get_log() {
|
| 388 | 3x |
std::stringstream ss; |
| 389 | 3x |
if (log_entries.size() == 0) {
|
| 390 | 2x |
ss << "[\n]"; |
| 391 |
} else {
|
|
| 392 | 1x |
ss << "[\n"; |
| 393 | 84x |
for (size_t i = 0; i < log_entries.size() - 1; i++) {
|
| 394 | 83x |
ss << "{\n" << this->log_entries[i].to_string() << "},\n";
|
| 395 |
} |
|
| 396 |
ss << "{\n"
|
|
| 397 | 1x |
<< this->log_entries[log_entries.size() - 1].to_string() << "}\n]"; |
| 398 |
} |
|
| 399 | 6x |
return ss.str(); |
| 400 |
} |
|
| 401 | ||
| 402 |
/** |
|
| 403 |
* Return only error entries from the log. |
|
| 404 |
* |
|
| 405 |
* @return |
|
| 406 |
*/ |
|
| 407 | 24x |
std::string get_errors() {
|
| 408 | 24x |
std::stringstream ss; |
| 409 | 24x |
std::vector<LogEntry> errors; |
| 410 | 24129x |
for (size_t i = 0; i < log_entries.size(); i++) {
|
| 411 | 24105x |
if (log_entries[i].level == "error") {
|
| 412 | ! |
errors.push_back(this->log_entries[i]); |
| 413 |
} |
|
| 414 |
} |
|
| 415 | ||
| 416 | 24x |
if (errors.size() == 0) {
|
| 417 | 24x |
ss << "[\n]"; |
| 418 |
} else {
|
|
| 419 | ! |
ss << "[\n"; |
| 420 | ! |
for (size_t i = 0; i < errors.size() - 1; i++) {
|
| 421 | ! |
ss << "{\n" << errors[i].to_string() << "},\n";
|
| 422 |
} |
|
| 423 | ||
| 424 | ! |
ss << "{\n" << errors[errors.size() - 1].to_string() << "}\n]";
|
| 425 |
} |
|
| 426 | 48x |
return ss.str(); |
| 427 |
} |
|
| 428 | ||
| 429 |
/** |
|
| 430 |
* Return only warning entries from the log. |
|
| 431 |
* |
|
| 432 |
* @return |
|
| 433 |
*/ |
|
| 434 | 24x |
std::string get_warnings() {
|
| 435 | 24x |
std::stringstream ss; |
| 436 | 24x |
std::vector<LogEntry> warnings; |
| 437 | 24129x |
for (size_t i = 0; i < log_entries.size(); i++) {
|
| 438 | 24105x |
if (log_entries[i].level == "warning") {
|
| 439 | 59x |
warnings.push_back(this->log_entries[i]); |
| 440 |
} |
|
| 441 |
} |
|
| 442 | ||
| 443 | 24x |
if (warnings.size() == 0) {
|
| 444 | ! |
ss << "[\n]"; |
| 445 |
} else {
|
|
| 446 | 24x |
ss << "[\n"; |
| 447 | 59x |
for (size_t i = 0; i < warnings.size() - 1; i++) {
|
| 448 | 35x |
ss << "{\n" << warnings[i].to_string() << "},\n";
|
| 449 |
} |
|
| 450 | ||
| 451 | 24x |
ss << "{\n" << warnings[warnings.size() - 1].to_string() << "}\n]";
|
| 452 |
} |
|
| 453 | 48x |
return ss.str(); |
| 454 |
} |
|
| 455 | ||
| 456 |
/** |
|
| 457 |
* Return only info entries from the log. |
|
| 458 |
* |
|
| 459 |
* @return |
|
| 460 |
*/ |
|
| 461 | 24x |
std::string get_info() {
|
| 462 | 24x |
std::stringstream ss; |
| 463 | 24x |
std::vector<LogEntry> info; |
| 464 | 24129x |
for (size_t i = 0; i < log_entries.size(); i++) {
|
| 465 | 24105x |
if (log_entries[i].level == "info") {
|
| 466 | 24046x |
info.push_back(this->log_entries[i]); |
| 467 |
} |
|
| 468 |
} |
|
| 469 | ||
| 470 | 24x |
if (info.size() == 0) {
|
| 471 | ! |
ss << "[\n]"; |
| 472 |
} else {
|
|
| 473 | 24x |
ss << "[\n"; |
| 474 | 24046x |
for (size_t i = 0; i < info.size() - 1; i++) {
|
| 475 | 24022x |
ss << "{\n" << info[i].to_string() << "},\n";
|
| 476 |
} |
|
| 477 | ||
| 478 | 24x |
ss << "{\n" << info[info.size() - 1].to_string() << "}\n]";
|
| 479 |
} |
|
| 480 | 48x |
return ss.str(); |
| 481 |
} |
|
| 482 | ||
| 483 |
/** |
|
| 484 |
* Query the log by module. |
|
| 485 |
* |
|
| 486 |
* @param module |
|
| 487 |
* @return |
|
| 488 |
*/ |
|
| 489 |
std::string get_module(const std::string& module) {
|
|
| 490 |
std::stringstream ss; |
|
| 491 |
std::vector<LogEntry> info; |
|
| 492 |
for (size_t i = 0; i < log_entries.size(); i++) {
|
|
| 493 |
if (log_entries[i].file.find(module) != std::string::npos) {
|
|
| 494 |
info.push_back(this->log_entries[i]); |
|
| 495 |
} |
|
| 496 |
} |
|
| 497 | ||
| 498 |
if (info.size() == 0) {
|
|
| 499 |
ss << "[\n]"; |
|
| 500 |
} else {
|
|
| 501 |
ss << "[\n"; |
|
| 502 |
for (size_t i = 0; i < info.size() - 1; i++) {
|
|
| 503 |
ss << "{\n" << info[i].to_string() << "},\n";
|
|
| 504 |
} |
|
| 505 | ||
| 506 |
ss << "{\n" << info[info.size() - 1].to_string() << "}\n]";
|
|
| 507 |
} |
|
| 508 |
return ss.str(); |
|
| 509 |
} |
|
| 510 | ||
| 511 |
/** |
|
| 512 |
* @brief Get the counts of the number of errors |
|
| 513 |
*/ |
|
| 514 |
size_t get_error_count() const { return error_count; }
|
|
| 515 | ||
| 516 |
/** |
|
| 517 |
* @brief Get the counts of the number of warnings |
|
| 518 |
*/ |
|
| 519 |
size_t get_warning_count() const { return warning_count; }
|
|
| 520 | ||
| 521 |
/** |
|
| 522 |
* @brief Clears all pointers/references of a FIMS model. |
|
| 523 |
* |
|
| 524 |
*/ |
|
| 525 | 150x |
void clear() {
|
| 526 | 150x |
this->entries.clear(); |
| 527 | 150x |
this->log_entries.clear(); |
| 528 | 150x |
this->warning_count = 0; |
| 529 | 150x |
this->entry_number = 0; |
| 530 |
} |
|
| 531 |
}; |
|
| 532 | ||
| 533 |
std::shared_ptr<FIMSLog> FIMSLog::fims_log = std::make_shared<FIMSLog>(); |
|
| 534 | ||
| 535 |
} // namespace fims |
|
| 536 | ||
| 537 |
#define FIMS_INFO_LOG(MESSAGE) \ |
|
| 538 |
fims::FIMSLog::fims_log->info_message( \ |
|
| 539 |
MESSAGE, __LINE__, __FILE__, \ |
|
| 540 |
__PRETTY_FUNCTION__); /**< Print MESSAGE to info log */ |
|
| 541 | ||
| 542 |
#define FIMS_WARNING_LOG(MESSAGE) \ |
|
| 543 |
fims::FIMSLog::fims_log->warning_message( \ |
|
| 544 |
MESSAGE, __LINE__, __FILE__, \ |
|
| 545 |
__PRETTY_FUNCTION__); /**< Print MESSAGE to warning log */ |
|
| 546 | ||
| 547 |
#define FIMS_ERROR_LOG(MESSAGE) \ |
|
| 548 |
fims::FIMSLog::fims_log->error_message( \ |
|
| 549 |
MESSAGE, __LINE__, __FILE__, \ |
|
| 550 |
__PRETTY_FUNCTION__); /**< Print MESSAGE to error log */ |
|
| 551 | ||
| 552 |
#define FIMS_STR(s) #s /**< String of s */ |
|
| 553 | ||
| 554 |
namespace fims {
|
|
| 555 | ||
| 556 |
/** |
|
| 557 |
* Signal intercept function. Writes the log to the disk before |
|
| 558 |
* a crash occurs. |
|
| 559 |
* |
|
| 560 |
* @param sig |
|
| 561 |
*/ |
|
| 562 | ! |
void WriteAtExit(int sig) {
|
| 563 | ! |
std::string signal_error = "NA"; |
| 564 | ! |
switch (sig) {
|
| 565 | ! |
case SIGSEGV: |
| 566 | ! |
signal_error = "Invalid memory access (segmentation fault)"; |
| 567 | ! |
break; |
| 568 | ! |
case SIGINT: |
| 569 | ! |
signal_error = "External interrupt, possibly initiated by the user."; |
| 570 | ! |
break; |
| 571 | ! |
case SIGABRT: |
| 572 |
signal_error = |
|
| 573 | ! |
"Abnormal termination condition, possible call to std::abort."; |
| 574 | ! |
break; |
| 575 | ! |
case SIGFPE: |
| 576 | ! |
signal_error = "Erroneous arithmetic operation."; |
| 577 | ! |
break; |
| 578 | ! |
case SIGILL: |
| 579 | ! |
signal_error = "Invalid program image or invalid instruction"; |
| 580 | ! |
break; |
| 581 | ! |
case SIGTERM: |
| 582 | ! |
signal_error = "Termination request, sent to the program."; |
| 583 | ! |
break; |
| 584 | ! |
default: |
| 585 | ! |
signal_error = "Unknown signal thrown"; |
| 586 |
} |
|
| 587 | ||
| 588 | ! |
FIMSLog::fims_log->error_message(signal_error, -999, "?", "?"); |
| 589 | ||
| 590 | ! |
if (FIMSLog::fims_log->write_on_exit) {
|
| 591 | ! |
std::ofstream log(FIMSLog::fims_log->get_path()); |
| 592 | ! |
log << FIMSLog::fims_log->get_log(); |
| 593 | ! |
log.close(); |
| 594 |
} |
|
| 595 | ! |
std::signal(sig, SIG_DFL); |
| 596 | ! |
raise(sig); |
| 597 |
} |
|
| 598 | ||
| 599 |
/** |
|
| 600 |
* Converts an object T to a string. |
|
| 601 |
* |
|
| 602 |
* @param v |
|
| 603 |
* @return |
|
| 604 |
*/ |
|
| 605 |
template <typename T> |
|
| 606 | 61806x |
std::string to_string(T v) {
|
| 607 | 61806x |
std::stringstream ss; |
| 608 | 61806x |
ss << v; |
| 609 | 123612x |
return ss.str(); |
| 610 |
} |
|
| 611 | ||
| 612 |
} // namespace fims |
|
| 613 | ||
| 614 |
#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 | 2742020x |
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 | 2742020x |
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 | 15882x |
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 | 15882x |
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 |
* @details |
|
| 194 |
* The logistic function can range from zero to one or one to zero, depending on |
|
| 195 |
* the slope parameter, but it is not normalized to force values to reach those |
|
| 196 |
* ranges. |
|
| 197 |
* |
|
| 198 |
* \f$ \frac{1.0}{ 1.0 + exp(-1.0 * slope (x - inflection_point))} \f$
|
|
| 199 |
* |
|
| 200 |
* @param inflection_point the inflection point of the logistic function |
|
| 201 |
* @param slope the slope of the logistic function. A positive slope results in |
|
| 202 |
* an ascending logistic curve (0 to 1), while a negative slope results in a |
|
| 203 |
* descending logistic curve (1 to 0). |
|
| 204 |
* @param x the index the logistic function should be evaluated at |
|
| 205 |
* @return |
|
| 206 |
*/ |
|
| 207 |
template <class Type> |
|
| 208 | 1383102x |
inline const Type logistic(const Type &inflection_point, const Type &slope, |
| 209 |
const Type &x) {
|
|
| 210 | 246408x |
return static_cast<Type>(1.0) / |
| 211 | 1383102x |
(static_cast<Type>(1.0) + |
| 212 | 1629510x |
exp(Type(-1.0) * slope * (x - inflection_point))); |
| 213 |
} |
|
| 214 | ||
| 215 |
/** |
|
| 216 |
* @brief A logit function for bounding of parameters |
|
| 217 |
* |
|
| 218 |
* \f$ -\mathrm{log}(b-x) + \mathrm{log}(x-a) \f$
|
|
| 219 |
* @param a lower bound |
|
| 220 |
* @param b upper bound |
|
| 221 |
* @param x the parameter in bounded space |
|
| 222 |
* @return the parameter in real space |
|
| 223 |
* |
|
| 224 |
*/ |
|
| 225 |
template <class Type> |
|
| 226 | 5x |
inline const Type logit(const Type &a, const Type &b, const Type &x) {
|
| 227 | 5x |
return -fims_math::log(b - x) + fims_math::log(x - a); |
| 228 |
} |
|
| 229 | ||
| 230 |
/** |
|
| 231 |
* @brief An inverse logit function for bounding of parameters |
|
| 232 |
* |
|
| 233 |
* \f$ a+\frac{b-a}{1+\mathrm{exp}(-\mathrm{logit}(x))}\f$
|
|
| 234 |
* @param a lower bound |
|
| 235 |
* @param b upper bound |
|
| 236 |
* @param logit_x the parameter in real space |
|
| 237 |
* @return the parameter in bounded space |
|
| 238 |
* |
|
| 239 |
*/ |
|
| 240 |
template <class Type> |
|
| 241 | 16404x |
inline const Type inv_logit(const Type &a, const Type &b, const Type &logit_x) {
|
| 242 | 16404x |
return a + (b - a) / (static_cast<Type>(1.0) + fims_math::exp(-logit_x)); |
| 243 |
} |
|
| 244 | ||
| 245 |
/** |
|
| 246 |
* @brief The general double logistic function |
|
| 247 |
* |
|
| 248 |
* \f$ \frac{1.0}{ 1.0 + exp(-1.0 * slope_{asc} (x - inflection_point_{asc}))}
|
|
| 249 |
* \left(1-\frac{1.0}{ 1.0 + exp(-1.0 * slope_{desc} (x -
|
|
| 250 |
* inflection_point_{desc}))} \right)\f$
|
|
| 251 |
* |
|
| 252 |
* @param inflection_point_asc the inflection point of the ascending limb of the |
|
| 253 |
* double logistic function |
|
| 254 |
* @param slope_asc the slope of the ascending limb of the double logistic |
|
| 255 |
* function |
|
| 256 |
* @param inflection_point_desc the inflection point of the descending limb of |
|
| 257 |
* the double logistic function, where inflection_point_desc > |
|
| 258 |
* inflection_point_asc |
|
| 259 |
* @param slope_desc the slope of the descending limb of the double logistic |
|
| 260 |
* function |
|
| 261 |
* @param x the index the logistic function should be evaluated at |
|
| 262 |
* @return |
|
| 263 |
*/ |
|
| 264 | ||
| 265 |
template <class Type> |
|
| 266 |
inline const Type double_logistic(const Type &inflection_point_asc, |
|
| 267 |
const Type &slope_asc, |
|
| 268 |
const Type &inflection_point_desc, |
|
| 269 |
const Type &slope_desc, const Type &x) {
|
|
| 270 |
return (static_cast<Type>(1.0)) / |
|
| 271 |
(static_cast<Type>(1.0) + |
|
| 272 |
exp(Type(-1.0) * slope_asc * (x - inflection_point_asc))) * |
|
| 273 |
(static_cast<Type>(1.0) - |
|
| 274 |
(static_cast<Type>(1.0)) / |
|
| 275 |
(static_cast<Type>(1.0) + |
|
| 276 |
exp(Type(-1.0) * slope_desc * (x - inflection_point_desc)))); |
|
| 277 |
} |
|
| 278 | ||
| 279 |
/** |
|
| 280 |
* |
|
| 281 |
* Used when x could evaluate to zero, which will result in a NaN for |
|
| 282 |
* derivative values. |
|
| 283 |
* |
|
| 284 |
* Evaluates: |
|
| 285 |
* |
|
| 286 |
* \f$ (x^2+C)^.5 \f$ |
|
| 287 |
* |
|
| 288 |
* @param x value to keep positive |
|
| 289 |
* @param C default = 1e-5 |
|
| 290 |
* @return |
|
| 291 |
*/ |
|
| 292 |
template <class Type> |
|
| 293 |
const Type ad_fabs(const Type &x, Type C = 1e-5) {
|
|
| 294 |
return sqrt((x * x) + C); |
|
| 295 |
} |
|
| 296 | ||
| 297 |
/** |
|
| 298 |
* |
|
| 299 |
* Returns the minimum between a and b in a continuous manner using: |
|
| 300 |
* |
|
| 301 |
* (a + b - fims_math::ad_fabs(a - b))*.5; |
|
| 302 |
* Reference: \ref fims_math::ad_fabs() |
|
| 303 |
* |
|
| 304 |
* This is an approximation with minimal error. |
|
| 305 |
* |
|
| 306 |
* @param a |
|
| 307 |
* @param b |
|
| 308 |
* @param C default = 1e-5 |
|
| 309 |
* @return |
|
| 310 |
*/ |
|
| 311 | ||
| 312 |
template <typename Type> |
|
| 313 |
inline const Type ad_min(const Type &a, const Type &b, Type C = 1e-5) {
|
|
| 314 |
return (a + b - fims_math::ad_fabs(a - b, C)) * static_cast<Type>(0.5); |
|
| 315 |
} |
|
| 316 | ||
| 317 |
/** |
|
| 318 |
* Returns the maximum between a and b in a continuous manner using: |
|
| 319 |
* |
|
| 320 |
* (a + b + fims_math::ad_fabs(a - b)) *.5; |
|
| 321 |
* Reference: \ref fims_math::ad_fabs() |
|
| 322 |
* This is an approximation with minimal error. |
|
| 323 |
* |
|
| 324 |
* @param a |
|
| 325 |
* @param b |
|
| 326 |
* @param C default = 1e-5 |
|
| 327 |
* @return |
|
| 328 |
*/ |
|
| 329 |
template <typename Type> |
|
| 330 |
inline const Type ad_max(const Type &a, const Type &b, Type C = 1e-5) {
|
|
| 331 |
return (a + b + fims_math::ad_fabs(a - b, C)) * static_cast<Type>(.5); |
|
| 332 |
} |
|
| 333 | ||
| 334 |
/** |
|
| 335 |
* Sum elements of a vector |
|
| 336 |
* |
|
| 337 |
* @brief |
|
| 338 |
* |
|
| 339 |
* @param v A vector of constants. |
|
| 340 |
* @return A single numeric value. |
|
| 341 |
*/ |
|
| 342 |
template <class T> |
|
| 343 |
T sum(const std::vector<T> &v) {
|
|
| 344 |
T ret = 0.0; |
|
| 345 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 346 |
ret += v[i]; |
|
| 347 |
} |
|
| 348 |
return ret; |
|
| 349 |
} |
|
| 350 | ||
| 351 |
/** |
|
| 352 |
* Sum elements of a vector |
|
| 353 |
* |
|
| 354 |
* @brief |
|
| 355 |
* |
|
| 356 |
* @param v A vector of constants. |
|
| 357 |
* @return A single numeric value. |
|
| 358 |
*/ |
|
| 359 |
template <class T> |
|
| 360 |
T sum(const fims::Vector<T> &v) {
|
|
| 361 |
T ret = 0.0; |
|
| 362 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 363 |
ret += v[i]; |
|
| 364 |
} |
|
| 365 |
return ret; |
|
| 366 |
} |
|
| 367 | ||
| 368 |
} // namespace fims_math |
|
| 369 | ||
| 370 |
#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 | 155238x |
Vector() {}
|
| 68 | ||
| 69 |
/** |
|
| 70 |
* @brief Constructs a Vector of length "size" and sets the elements with the |
|
| 71 |
* value from input "value". |
|
| 72 |
*/ |
|
| 73 | 7088x |
Vector(size_t size, const Type &value = Type()) {
|
| 74 | 7088x |
this->vec_m.resize(size, value); |
| 75 |
} |
|
| 76 | ||
| 77 |
/** |
|
| 78 |
* @brief Copy constructor. |
|
| 79 |
*/ |
|
| 80 | 45072x |
Vector(const Vector<Type> &other) {
|
| 81 | 45072x |
this->vec_m.resize(other.size()); |
| 82 | 2233802x |
for (size_t i = 0; i < this->vec_m.size(); i++) {
|
| 83 | 2188730x |
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 | 25056x |
Vector &operator=(const Vector &other) {
|
| 97 | 25056x |
if (this != &other) {
|
| 98 |
// clean up existing |
|
| 99 | 25056x |
this->~Vector(); |
| 100 |
// copy construct into *this |
|
| 101 | 25056x |
new (this) Vector(other); |
| 102 |
} |
|
| 103 | 25056x |
return *this; |
| 104 |
} |
|
| 105 | ||
| 106 |
/** |
|
| 107 |
* @brief Initialization constructor from std::vector<Type> type. |
|
| 108 |
*/ |
|
| 109 |
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 |
Vector(const tmbutils::vector<Type> &other) {
|
|
| 118 |
this->vec_m.resize(other.size()); |
|
| 119 |
for (size_t i = 0; i < this->vec_m.size(); i++) {
|
|
| 120 |
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 | 12528x |
Vector(std::initializer_list<Type> init) {
|
| 130 | 12528x |
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 | 52020600x |
inline Type &operator[](size_t pos) {
|
| 144 | 52020600x |
if (pos >= this->size()) {
|
| 145 | ! |
throw std::invalid_argument("fims::Vector out of bounds");
|
| 146 |
} |
|
| 147 | 52020600x |
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 | 2196314x |
inline const Type &operator[](size_t n) const {
|
| 155 | 2196314x |
if (n >= this->size()) {
|
| 156 | ! |
throw std::invalid_argument("fims::Vector out of bounds");
|
| 157 |
} |
|
| 158 | 2196314x |
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 | 2806092x |
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 | 2806092x |
inline Type &get_force_scalar(size_t pos) {
|
| 183 | 2806092x |
if (this->size() == 1 && pos > 0) {
|
| 184 | 2682730x |
return this->at(0); |
| 185 |
} else if (this->size() > 1 && pos >= this->size()) {
|
|
| 186 | ! |
throw std::invalid_argument( |
| 187 |
"fims::Vector index out of bounds, check parameter sizes of input."); |
|
| 188 |
} else {
|
|
| 189 | 123362x |
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 | 166542x |
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 | 58422x |
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 | 57131690x |
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 | 888x |
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 |
inline iterator insert(const_iterator pos, size_type count, |
|
| 314 |
const Type &value) {
|
|
| 315 |
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 |
void emplace_back(Args &&...args) {
|
|
| 364 |
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 | 123834x |
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 | 135954x |
tmbutils::vector<Type> to_tmb() {
|
| 440 | 135954x |
tmbutils::vector<Type> ret(this->vec_m.size()); |
| 441 | 8001520x |
for (size_t i = 0; i < this->vec_m.size(); i++) {
|
| 442 | 7865566x |
ret[i] = this->vec_m[i]; |
| 443 |
} |
|
| 444 | 135954x |
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 |
std::ostream &operator<<(std::ostream &out, const fims::Vector<Type> &v) {
|
|
| 506 |
out << std::fixed << std::setprecision(10); |
|
| 507 |
out << "["; |
|
| 508 | ||
| 509 |
if (v.size() == 0) {
|
|
| 510 |
out << "]"; |
|
| 511 |
return out; |
|
| 512 |
} |
|
| 513 |
for (size_t i = 0; i < v.size() - 1; i++) {
|
|
| 514 |
if (v[i] != v[i]) {
|
|
| 515 |
out << "-999" << ","; |
|
| 516 |
} else {
|
|
| 517 |
out << v[i] << ","; |
|
| 518 |
} |
|
| 519 |
} |
|
| 520 |
if (v[v.size() - 1] != v[v.size() - 1]) {
|
|
| 521 |
out << "-999]"; |
|
| 522 |
} else {
|
|
| 523 |
out << v[v.size() - 1] << "]"; |
|
| 524 |
} |
|
| 525 |
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 <algorithm> |
|
| 15 |
#include <map> |
|
| 16 |
#include <memory> |
|
| 17 |
#include <vector> |
|
| 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 | 768x |
void Clear() {
|
| 157 | 768x |
this->data_objects.clear(); |
| 158 | 768x |
this->populations.clear(); |
| 159 | 768x |
this->fixed_effects_parameters.clear(); |
| 160 | 768x |
this->fleets.clear(); |
| 161 | 768x |
this->growth_models.clear(); |
| 162 | 768x |
this->maturity_models.clear(); |
| 163 | 768x |
this->parameter_names.clear(); |
| 164 | 768x |
this->parameters.clear(); |
| 165 | 768x |
this->random_effects_names.clear(); |
| 166 | 768x |
this->random_effects_parameters.clear(); |
| 167 | 768x |
this->recruitment_models.clear(); |
| 168 | 768x |
this->recruitment_process_models.clear(); |
| 169 | 768x |
this->selectivity_models.clear(); |
| 170 | 768x |
this->models_map.clear(); |
| 171 | 768x |
this->n_years = 0; |
| 172 | 768x |
this->n_ages = 0; |
| 173 | ||
| 174 | 1544x |
for (density_components_iterator it = density_components.begin(); |
| 175 | 1544x |
it != density_components.end(); ++it) {
|
| 176 | 776x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 177 | 776x |
(*it).second; |
| 178 | 776x |
if ((d->priors)[0] != NULL) {
|
| 179 | 12x |
d->priors.clear(); |
| 180 |
} |
|
| 181 | 776x |
if (d->data_expected_values != NULL) {
|
| 182 | 640x |
d->data_expected_values->clear(); |
| 183 |
} |
|
| 184 | 776x |
if (d->re != NULL) {
|
| 185 | 124x |
d->re->clear(); |
| 186 |
} |
|
| 187 | 776x |
if (d->re_expected_values != NULL) {
|
| 188 | 124x |
d->re_expected_values->clear(); |
| 189 |
} |
|
| 190 |
} |
|
| 191 | 768x |
this->density_components.clear(); |
| 192 |
} |
|
| 193 | ||
| 194 |
/** |
|
| 195 |
* @brief Get a summary string of the Information object state. |
|
| 196 |
* |
|
| 197 |
* @details Returns a string containing the sizes and states of all major |
|
| 198 |
* containers and model components in the Information object. Useful for |
|
| 199 |
* debugging and diagnostics. |
|
| 200 |
* |
|
| 201 |
* @return std::string summary of the Information object state. |
|
| 202 |
*/ |
|
| 203 |
std::string State() {
|
|
| 204 |
std::stringstream ss; |
|
| 205 |
ss << "Information object State:\n"; |
|
| 206 |
ss << "data_objects: " << this->data_objects.clear(); |
|
| 207 |
ss << "populations: " << this->populations.size() << std::endl; |
|
| 208 |
ss << "fixed_effects_parameters: " << this->fixed_effects_parameters.size() |
|
| 209 |
<< std::endl; |
|
| 210 |
ss << "fleets: " << this->fleets.size() << std::endl; |
|
| 211 |
ss << "growth_models: " << this->growth_models.size() << std::endl; |
|
| 212 |
ss << "maturity_models: " << this->maturity_models.size() << std::endl; |
|
| 213 |
ss << "parameter_names: " << this->parameter_names.size() << std::endl; |
|
| 214 |
ss << "parameters: " << this->parameters.size() << std::endl; |
|
| 215 |
ss << "random_effects_names: " << this->random_effects_names.size() |
|
| 216 |
<< std::endl; |
|
| 217 |
ss << "random_effects_parameters: " |
|
| 218 |
<< this->random_effects_parameters.size() << std::endl; |
|
| 219 |
ss << "recruitment_models: " << this->recruitment_models.size() |
|
| 220 |
<< std::endl; |
|
| 221 |
ss << "recruitment_process_models: " |
|
| 222 |
<< this->recruitment_process_models.size() << std::endl; |
|
| 223 |
ss << "selectivity_models: " << this->selectivity_models.size() |
|
| 224 |
<< std::endl; |
|
| 225 |
ss << "models_map: " << this->models_map.size() << std::endl; |
|
| 226 |
ss << "n_years: " << this->n_years << std::endl; |
|
| 227 |
ss << "n_ages: " << this->n_ages << std::endl; |
|
| 228 |
ss << "density_components: " << this->density_components.size() |
|
| 229 |
<< std::endl; |
|
| 230 |
return ss.str(); |
|
| 231 |
} |
|
| 232 | ||
| 233 |
/** |
|
| 234 |
* @brief Returns a singleton Information object for type T. |
|
| 235 |
* |
|
| 236 |
* @return singleton for type T |
|
| 237 |
*/ |
|
| 238 | 5146x |
static std::shared_ptr<Information<Type>> GetInstance() {
|
| 239 | 5146x |
if (Information<Type>::fims_information == nullptr) {
|
| 240 | 4x |
Information<Type>::fims_information = |
| 241 |
std::make_shared<fims_info::Information<Type>>(); |
|
| 242 |
} |
|
| 243 | 5146x |
return Information<Type>::fims_information; |
| 244 |
} |
|
| 245 | ||
| 246 |
/** |
|
| 247 |
* @brief Register a parameter as estimable. |
|
| 248 |
* |
|
| 249 |
* @param p parameter |
|
| 250 |
*/ |
|
| 251 | 5896x |
void RegisterParameter(Type& p) {
|
| 252 | 5896x |
this->fixed_effects_parameters.push_back(&p); |
| 253 |
} |
|
| 254 | ||
| 255 |
/** |
|
| 256 |
* @brief Register a random effect as estimable. |
|
| 257 |
* |
|
| 258 |
* @param re random effect |
|
| 259 |
*/ |
|
| 260 | 1780x |
void RegisterRandomEffect(Type& re) {
|
| 261 | 1780x |
this->random_effects_parameters.push_back(&re); |
| 262 |
} |
|
| 263 | ||
| 264 |
/** |
|
| 265 |
* @brief Register a parameter name. |
|
| 266 |
* |
|
| 267 |
* @param p_name parameter name |
|
| 268 |
*/ |
|
| 269 | 5896x |
void RegisterParameterName(std::string p_name) {
|
| 270 | 5896x |
this->parameter_names.push_back(p_name); |
| 271 |
} |
|
| 272 | ||
| 273 |
/** |
|
| 274 |
* @brief Register a random effects name. |
|
| 275 |
* |
|
| 276 |
* @param re_name random effects name |
|
| 277 |
*/ |
|
| 278 | 1780x |
void RegisterRandomEffectName(std::string re_name) {
|
| 279 | 1780x |
this->random_effects_names.push_back(re_name); |
| 280 |
} |
|
| 281 | ||
| 282 |
/** |
|
| 283 |
* @brief Loop over distributions and set links to distribution x value if |
|
| 284 |
* distribution is a prior type. |
|
| 285 |
*/ |
|
| 286 | 160x |
void SetupPriors() {
|
| 287 | 936x |
for (density_components_iterator it = density_components.begin(); |
| 288 | 936x |
it != density_components.end(); ++it) {
|
| 289 | 776x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 290 | 776x |
(*it).second; |
| 291 | 776x |
if (d->input_type == "prior") {
|
| 292 | 12x |
FIMS_INFO_LOG("Setup prior for distribution " + fims::to_string(d->id));
|
| 293 | 12x |
variable_map_iterator vmit; |
| 294 | 12x |
FIMS_INFO_LOG("Link prior from distribution " + fims::to_string(d->id) +
|
| 295 |
" to parameter " + fims::to_string(d->key[0])); |
|
| 296 | 12x |
d->priors.resize(d->key.size()); |
| 297 | 32x |
for (size_t i = 0; i < d->key.size(); i++) {
|
| 298 | 20x |
FIMS_INFO_LOG("Link prior from distribution " +
|
| 299 |
fims::to_string(d->id) + " to parameter " + |
|
| 300 |
fims::to_string(d->key[0])); |
|
| 301 | 20x |
vmit = this->variable_map.find(d->key[i]); |
| 302 | 20x |
d->priors[i] = (*vmit).second; |
| 303 |
} |
|
| 304 | 12x |
FIMS_INFO_LOG("Prior size for distribution " + fims::to_string(d->id) +
|
| 305 |
"is: " + fims::to_string(d->observed_values.size())); |
|
| 306 |
} |
|
| 307 |
} |
|
| 308 |
} |
|
| 309 | ||
| 310 |
/** |
|
| 311 |
* @brief Loop over distributions and set links to distribution x value if |
|
| 312 |
* distribution is a random effects type. |
|
| 313 |
*/ |
|
| 314 | 160x |
void SetupRandomEffects() {
|
| 315 | 936x |
for (density_components_iterator it = this->density_components.begin(); |
| 316 | 936x |
it != this->density_components.end(); ++it) {
|
| 317 | 776x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 318 | 776x |
(*it).second; |
| 319 | 776x |
if (d->input_type == "random_effects") {
|
| 320 | 124x |
FIMS_INFO_LOG("Setup random effects for distribution " +
|
| 321 |
fims::to_string(d->id)); |
|
| 322 | 124x |
variable_map_iterator vmit; |
| 323 | 124x |
FIMS_INFO_LOG("Link random effects from distribution " +
|
| 324 |
fims::to_string(d->id) + " to derived value " + |
|
| 325 |
fims::to_string(d->key[0])); |
|
| 326 | 124x |
vmit = this->variable_map.find(d->key[0]); |
| 327 | 124x |
d->re = (*vmit).second; |
| 328 | 124x |
if (d->key.size() == 2) {
|
| 329 | 4x |
vmit = this->variable_map.find(d->key[1]); |
| 330 | 4x |
d->re_expected_values = (*vmit).second; |
| 331 |
} else {
|
|
| 332 | 120x |
d->re_expected_values = &d->expected_values; |
| 333 |
} |
|
| 334 | 124x |
FIMS_INFO_LOG("Random effect size for distribution " +
|
| 335 |
fims::to_string(d->id) + |
|
| 336 |
" is: " + fims::to_string(d->observed_values.size())); |
|
| 337 |
} |
|
| 338 |
} |
|
| 339 |
} |
|
| 340 | ||
| 341 |
/** |
|
| 342 |
* @brief Loop over distributions and set links to distribution expected value |
|
| 343 |
* if distribution is a data type. |
|
| 344 |
*/ |
|
| 345 | 160x |
void SetupData() {
|
| 346 | 936x |
for (density_components_iterator it = this->density_components.begin(); |
| 347 | 936x |
it != this->density_components.end(); ++it) {
|
| 348 | 776x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 349 | 776x |
(*it).second; |
| 350 | 776x |
if (d->input_type == "data") {
|
| 351 | 640x |
FIMS_INFO_LOG("Setup expected value for data distribution " +
|
| 352 |
fims::to_string(d->id)); |
|
| 353 | 640x |
variable_map_iterator vmit; |
| 354 | 640x |
FIMS_INFO_LOG("Link expected value from distribution " +
|
| 355 |
fims::to_string(d->id) + " to derived value " + |
|
| 356 |
fims::to_string(d->key[0])); |
|
| 357 | 640x |
vmit = this->variable_map.find(d->key[0]); |
| 358 | 640x |
d->data_expected_values = (*vmit).second; |
| 359 | 640x |
FIMS_INFO_LOG( |
| 360 |
"Expected value size for distribution " + fims::to_string(d->id) + |
|
| 361 |
" is: " + fims::to_string((*d->data_expected_values).size())); |
|
| 362 |
} |
|
| 363 |
} |
|
| 364 |
} |
|
| 365 | ||
| 366 |
/** |
|
| 367 |
* @brief Set pointers to landings data in the fleet module. |
|
| 368 |
* |
|
| 369 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 370 |
* model is valid. |
|
| 371 |
* @param f shared pointer to fleet module |
|
| 372 |
*/ |
|
| 373 | 240x |
void SetFleetLandingsData(bool& valid_model, |
| 374 |
std::shared_ptr<fims_popdy::Fleet<Type>> f) {
|
|
| 375 | 240x |
if (f->fleet_observed_landings_data_id_m != static_cast<Type>(-999)) {
|
| 376 | 116x |
uint32_t observed_landings_id = |
| 377 | 116x |
static_cast<uint32_t>(f->fleet_observed_landings_data_id_m); |
| 378 | 116x |
data_iterator it = this->data_objects.find(observed_landings_id); |
| 379 | 116x |
if (it != this->data_objects.end()) {
|
| 380 | 116x |
f->observed_landings_data = (*it).second; |
| 381 | 116x |
FIMS_INFO_LOG("Landings data for fleet " + fims::to_string(f->id) +
|
| 382 |
" successfully set to " + |
|
| 383 |
fims::to_string(f->observed_landings_data->at(1))); |
|
| 384 |
} else {
|
|
| 385 | ! |
valid_model = false; |
| 386 | ! |
FIMS_ERROR_LOG("Expected landings data not defined for fleet " +
|
| 387 |
fims::to_string(f->id) + ", index " + |
|
| 388 |
fims::to_string(observed_landings_id)); |
|
| 389 |
} |
|
| 390 |
} |
|
| 391 |
} |
|
| 392 | ||
| 393 |
/** |
|
| 394 |
* @brief Set pointers to index data in the fleet module. |
|
| 395 |
* |
|
| 396 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 397 |
* model is valid. |
|
| 398 |
* @param f shared pointer to fleet module |
|
| 399 |
*/ |
|
| 400 | 240x |
void SetFleetIndexData(bool& valid_model, |
| 401 |
std::shared_ptr<fims_popdy::Fleet<Type>> f) {
|
|
| 402 | 240x |
if (f->fleet_observed_index_data_id_m != static_cast<Type>(-999)) {
|
| 403 | 124x |
uint32_t observed_index_id = |
| 404 | 124x |
static_cast<uint32_t>(f->fleet_observed_index_data_id_m); |
| 405 | 124x |
data_iterator it = this->data_objects.find(observed_index_id); |
| 406 | 124x |
if (it != this->data_objects.end()) {
|
| 407 | 124x |
f->observed_index_data = (*it).second; |
| 408 | 124x |
FIMS_INFO_LOG("Index data for fleet " + fims::to_string(f->id) +
|
| 409 |
" successfully set to " + |
|
| 410 |
fims::to_string(f->observed_index_data->at(1))); |
|
| 411 |
} else {
|
|
| 412 | ! |
valid_model = false; |
| 413 | ! |
FIMS_ERROR_LOG("Expected index data not defined for fleet " +
|
| 414 |
fims::to_string(f->id) + ", index " + |
|
| 415 |
fims::to_string(observed_index_id)); |
|
| 416 |
} |
|
| 417 |
} |
|
| 418 |
} |
|
| 419 | ||
| 420 |
/** |
|
| 421 |
* @brief Set pointers to age composition data in the fleet module. |
|
| 422 |
* |
|
| 423 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 424 |
* model is valid. |
|
| 425 |
* @param f shared pointer to fleet module |
|
| 426 |
*/ |
|
| 427 | 240x |
void SetAgeCompositionData(bool& valid_model, |
| 428 |
std::shared_ptr<fims_popdy::Fleet<Type>> f) {
|
|
| 429 | 240x |
if (f->fleet_observed_agecomp_data_id_m != static_cast<Type>(-999)) {
|
| 430 | 224x |
uint32_t observed_agecomp_id = |
| 431 | 224x |
static_cast<uint32_t>(f->fleet_observed_agecomp_data_id_m); |
| 432 | 224x |
data_iterator it = this->data_objects.find(observed_agecomp_id); |
| 433 | 224x |
if (it != this->data_objects.end()) {
|
| 434 | 224x |
f->observed_agecomp_data = (*it).second; |
| 435 | 224x |
FIMS_INFO_LOG("Observed input age-composition data for fleet " +
|
| 436 |
fims::to_string(f->id) + " successfully set to " + |
|
| 437 |
fims::to_string(f->observed_agecomp_data->at(1))); |
|
| 438 |
} else {
|
|
| 439 | ! |
valid_model = false; |
| 440 | ! |
FIMS_ERROR_LOG( |
| 441 |
"Expected age-composition observations not defined for fleet " + |
|
| 442 |
fims::to_string(f->id)); |
|
| 443 |
} |
|
| 444 |
} |
|
| 445 |
} |
|
| 446 | ||
| 447 |
/** |
|
| 448 |
* @brief Set pointers to length composition data in the fleet module. |
|
| 449 |
* |
|
| 450 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 451 |
* model is valid. |
|
| 452 |
* @param f shared pointer to fleet module |
|
| 453 |
*/ |
|
| 454 | 240x |
void SetLengthCompositionData(bool& valid_model, |
| 455 |
std::shared_ptr<fims_popdy::Fleet<Type>> f) {
|
|
| 456 | 240x |
if (f->fleet_observed_lengthcomp_data_id_m != static_cast<Type>(-999)) {
|
| 457 | 200x |
uint32_t observed_lengthcomp_id = |
| 458 | 200x |
static_cast<uint32_t>(f->fleet_observed_lengthcomp_data_id_m); |
| 459 | 200x |
data_iterator it = this->data_objects.find(observed_lengthcomp_id); |
| 460 | 200x |
if (it != this->data_objects.end()) {
|
| 461 | 200x |
f->observed_lengthcomp_data = (*it).second; |
| 462 | 200x |
FIMS_INFO_LOG("Observed input length-composition data for fleet " +
|
| 463 |
fims::to_string(f->id) + " successfully set to " + |
|
| 464 |
fims::to_string(f->observed_lengthcomp_data->at(1))); |
|
| 465 |
} else {
|
|
| 466 | ! |
valid_model = false; |
| 467 | ! |
FIMS_ERROR_LOG( |
| 468 |
"Expected length-composition observations not defined for fleet " + |
|
| 469 |
fims::to_string(f->id)); |
|
| 470 |
} |
|
| 471 |
} |
|
| 472 |
} |
|
| 473 | ||
| 474 |
/** |
|
| 475 |
* @brief Set pointers to the selectivity module referenced in the fleet |
|
| 476 |
* module. |
|
| 477 |
* |
|
| 478 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 479 |
* model is valid. |
|
| 480 |
* @param f shared pointer to fleet module |
|
| 481 |
*/ |
|
| 482 | 240x |
void SetFleetSelectivityModel(bool& valid_model, |
| 483 |
std::shared_ptr<fims_popdy::Fleet<Type>> f) {
|
|
| 484 | 240x |
if (f->fleet_selectivity_id_m != static_cast<Type>(-999)) {
|
| 485 | 240x |
uint32_t sel_id = static_cast<uint32_t>( |
| 486 | 240x |
f->fleet_selectivity_id_m); // cast as unsigned integer |
| 487 | 240x |
selectivity_models_iterator it = this->selectivity_models.find( |
| 488 |
sel_id); // if find, set it, otherwise invalid |
|
| 489 | ||
| 490 | 240x |
if (it != this->selectivity_models.end()) {
|
| 491 | 240x |
f->selectivity = (*it).second; // elements in container held in pair |
| 492 | 240x |
FIMS_INFO_LOG("Selectivity model " +
|
| 493 |
fims::to_string(f->fleet_selectivity_id_m) + |
|
| 494 |
" successfully set to fleet " + fims::to_string(f->id)); |
|
| 495 |
} else {
|
|
| 496 | ! |
valid_model = false; |
| 497 | ! |
FIMS_ERROR_LOG("Expected selectivity pattern not defined for fleet " +
|
| 498 |
fims::to_string(f->id) + ", selectivity pattern " + |
|
| 499 |
fims::to_string(sel_id)); |
|
| 500 |
} |
|
| 501 |
} else {
|
|
| 502 | ! |
FIMS_WARNING_LOG("Warning: No selectivity pattern defined for fleet " +
|
| 503 |
fims::to_string(f->id) + |
|
| 504 |
". FIMS requires selectivity be defined for all fleets " |
|
| 505 |
"when running a catch at age model."); |
|
| 506 |
} |
|
| 507 |
} |
|
| 508 | ||
| 509 |
/** |
|
| 510 |
* @brief Set pointers to the recruitment module referenced in the population |
|
| 511 |
* module. |
|
| 512 |
* |
|
| 513 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 514 |
* model is valid. |
|
| 515 |
* @param p shared pointer to population module |
|
| 516 |
*/ |
|
| 517 | 120x |
void SetRecruitment(bool& valid_model, |
| 518 |
std::shared_ptr<fims_popdy::Population<Type>> p) {
|
|
| 519 | 120x |
if (p->recruitment_id != static_cast<Type>(-999)) {
|
| 520 | 120x |
uint32_t recruitment_uint = static_cast<uint32_t>(p->recruitment_id); |
| 521 | 120x |
FIMS_INFO_LOG("searching for recruitment model " +
|
| 522 |
fims::to_string(recruitment_uint)); |
|
| 523 |
recruitment_models_iterator it = |
|
| 524 | 120x |
this->recruitment_models.find(recruitment_uint); |
| 525 | ||
| 526 | 120x |
if (it != this->recruitment_models.end()) {
|
| 527 | 120x |
p->recruitment = (*it).second; // recruitment defined in population.hpp |
| 528 | 120x |
FIMS_INFO_LOG("Recruitment model " + fims::to_string(recruitment_uint) +
|
| 529 |
" successfully set to population " + |
|
| 530 |
fims::to_string(p->id)); |
|
| 531 |
} else {
|
|
| 532 | ! |
valid_model = false; |
| 533 | ! |
FIMS_ERROR_LOG( |
| 534 |
"Expected recruitment function not defined for " |
|
| 535 |
"population " + |
|
| 536 |
fims::to_string(p->id) + ", recruitment function " + |
|
| 537 |
fims::to_string(recruitment_uint)); |
|
| 538 |
} |
|
| 539 |
} else {
|
|
| 540 | ! |
FIMS_WARNING_LOG( |
| 541 |
"No recruitment function defined for population " + |
|
| 542 |
fims::to_string(p->id) + |
|
| 543 |
". FIMS requires recruitment functions be defined for all " |
|
| 544 |
"populations when running a catch at age model."); |
|
| 545 |
} |
|
| 546 |
} |
|
| 547 | ||
| 548 |
/** |
|
| 549 |
* @brief Set pointers to the recruitment process module referenced in the |
|
| 550 |
* population module. |
|
| 551 |
* |
|
| 552 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 553 |
* model is valid. |
|
| 554 |
* @param p shared pointer to population module |
|
| 555 |
*/ |
|
| 556 | 120x |
void SetRecruitmentProcess(bool& valid_model, |
| 557 |
std::shared_ptr<fims_popdy::Population<Type>> p) {
|
|
| 558 | 120x |
std::shared_ptr<fims_popdy::RecruitmentBase<Type>> r = p->recruitment; |
| 559 |
// if recruitment is defined |
|
| 560 | 120x |
if (r) {
|
| 561 | 120x |
if (r->process_id != static_cast<Type>(-999)) {
|
| 562 | 120x |
uint32_t process_uint = static_cast<uint32_t>(r->process_id); |
| 563 |
recruitment_process_iterator it = |
|
| 564 | 120x |
this->recruitment_process_models.find(process_uint); |
| 565 | ||
| 566 | 120x |
if (it != this->recruitment_process_models.end()) {
|
| 567 | 120x |
r->process = (*it).second; // recruitment process |
| 568 | 120x |
FIMS_INFO_LOG( |
| 569 |
"Recruitment Process model " + fims::to_string(process_uint) + |
|
| 570 |
" successfully set to population " + fims::to_string(p->id)); |
|
| 571 | 120x |
(*it).second->recruitment = r; |
| 572 |
} else {
|
|
| 573 | ! |
valid_model = false; |
| 574 | ! |
FIMS_ERROR_LOG( |
| 575 |
"Expected recruitment process function not defined for " |
|
| 576 |
"population " + |
|
| 577 |
fims::to_string(p->id) + ", recruitment process function " + |
|
| 578 |
fims::to_string(process_uint)); |
|
| 579 |
} |
|
| 580 |
} else {
|
|
| 581 | ! |
FIMS_WARNING_LOG( |
| 582 |
"No recruitment process function defined for population " + |
|
| 583 |
fims::to_string(p->id) + |
|
| 584 |
". FIMS requires recruitment process functions be defined for all " |
|
| 585 |
"recruitments when running a catch at age model."); |
|
| 586 |
} |
|
| 587 |
} |
|
| 588 |
} |
|
| 589 | ||
| 590 |
/** |
|
| 591 |
* @brief Set pointers to the growth module referenced in the population |
|
| 592 |
* module. |
|
| 593 |
* |
|
| 594 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 595 |
* model is valid. |
|
| 596 |
* @param p shared pointer to population module |
|
| 597 |
*/ |
|
| 598 | 120x |
void SetGrowth(bool& valid_model, |
| 599 |
std::shared_ptr<fims_popdy::Population<Type>> p) {
|
|
| 600 | 120x |
if (p->growth_id != static_cast<Type>(-999)) {
|
| 601 | 120x |
uint32_t growth_uint = static_cast<uint32_t>(p->growth_id); |
| 602 | 120x |
growth_models_iterator it = this->growth_models.find( |
| 603 |
growth_uint); // growth_models is specified in information.hpp |
|
| 604 |
// and used in rcpp |
|
| 605 |
// at the head of information.hpp; are the |
|
| 606 |
// dimensions of ages defined in rcpp or where? |
|
| 607 | 120x |
if (it != this->growth_models.end()) {
|
| 608 | 120x |
p->growth = |
| 609 | 120x |
(*it).second; // growth defined in population.hpp (the object |
| 610 |
// is called p, growth is within p) |
|
| 611 | 120x |
FIMS_INFO_LOG("Growth model " + fims::to_string(growth_uint) +
|
| 612 |
" successfully set to population " + |
|
| 613 |
fims::to_string(p->id)); |
|
| 614 |
} else {
|
|
| 615 | ! |
valid_model = false; |
| 616 | ! |
FIMS_ERROR_LOG("Expected growth function not defined for population " +
|
| 617 |
fims::to_string(p->id) + ", growth function " + |
|
| 618 |
fims::to_string(growth_uint)); |
|
| 619 |
} |
|
| 620 |
} else {
|
|
| 621 | ! |
FIMS_WARNING_LOG("No growth function defined for population " +
|
| 622 |
fims::to_string(p->id) + |
|
| 623 |
". FIMS requires growth functions be defined for all " |
|
| 624 |
"populations when running a catch at age model."); |
|
| 625 |
} |
|
| 626 |
} |
|
| 627 | ||
| 628 |
/** |
|
| 629 |
* @brief Set pointers to the maturity module referenced in the population |
|
| 630 |
* module. |
|
| 631 |
* |
|
| 632 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 633 |
* model is valid. |
|
| 634 |
* @param p shared pointer to population module |
|
| 635 |
*/ |
|
| 636 | 120x |
void SetMaturity(bool& valid_model, |
| 637 |
std::shared_ptr<fims_popdy::Population<Type>> p) {
|
|
| 638 | 120x |
if (p->maturity_id != static_cast<Type>(-999)) {
|
| 639 | 120x |
uint32_t maturity_uint = static_cast<uint32_t>(p->maturity_id); |
| 640 | 120x |
maturity_models_iterator it = this->maturity_models.find( |
| 641 |
maturity_uint); // >maturity_models is specified in |
|
| 642 |
// information.hpp and used in rcpp |
|
| 643 | 120x |
if (it != this->maturity_models.end()) {
|
| 644 | 120x |
p->maturity = (*it).second; // >maturity defined in population.hpp |
| 645 | 120x |
FIMS_INFO_LOG("Maturity model " + fims::to_string(maturity_uint) +
|
| 646 |
" successfully set to population " + |
|
| 647 |
fims::to_string(p->id)); |
|
| 648 |
} else {
|
|
| 649 | ! |
valid_model = false; |
| 650 | ! |
FIMS_ERROR_LOG( |
| 651 |
"Expected maturity function not defined for population " + |
|
| 652 |
fims::to_string(p->id) + ", maturity function " + |
|
| 653 |
fims::to_string(maturity_uint)); |
|
| 654 |
} |
|
| 655 |
} else {
|
|
| 656 | ! |
FIMS_WARNING_LOG("No maturity function defined for population " +
|
| 657 |
fims::to_string(p->id) + |
|
| 658 |
". FIMS requires maturity functions be defined for all " |
|
| 659 |
"populations when running a catch at age model."); |
|
| 660 |
} |
|
| 661 |
} |
|
| 662 | ||
| 663 |
/** |
|
| 664 |
* @brief Loop over all fleets and set pointers to fleet objects |
|
| 665 |
* |
|
| 666 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 667 |
* model is valid. |
|
| 668 |
*/ |
|
| 669 | 160x |
void CreateFleetObjects(bool& valid_model) {
|
| 670 | 400x |
for (fleet_iterator it = this->fleets.begin(); it != this->fleets.end(); |
| 671 | 240x |
++it) {
|
| 672 | 240x |
std::shared_ptr<fims_popdy::Fleet<Type>> f = (*it).second; |
| 673 | 240x |
FIMS_INFO_LOG("Initializing fleet " + fims::to_string(f->id));
|
| 674 | ||
| 675 | 240x |
SetFleetLandingsData(valid_model, f); |
| 676 | ||
| 677 | 240x |
SetFleetIndexData(valid_model, f); |
| 678 | ||
| 679 | 240x |
SetAgeCompositionData(valid_model, f); |
| 680 | ||
| 681 | 240x |
SetLengthCompositionData(valid_model, f); |
| 682 | ||
| 683 | 240x |
SetFleetSelectivityModel(valid_model, f); |
| 684 |
} |
|
| 685 |
} |
|
| 686 | ||
| 687 |
/** |
|
| 688 |
* @brief Loop over all density components and set pointers to data objects |
|
| 689 |
* |
|
| 690 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 691 |
* model is valid. |
|
| 692 |
*/ |
|
| 693 | 160x |
void SetDataObjects(bool& valid_model) {
|
| 694 | 936x |
for (density_components_iterator it = this->density_components.begin(); |
| 695 | 936x |
it != this->density_components.end(); ++it) {
|
| 696 | 776x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 697 | 776x |
(*it).second; |
| 698 | ||
| 699 |
// set data objects if distribution is a data type |
|
| 700 | 776x |
if (d->input_type == "data") {
|
| 701 | 640x |
if (d->observed_data_id_m != static_cast<Type>(-999)) {
|
| 702 | 640x |
uint32_t observed_data_id = |
| 703 | 640x |
static_cast<uint32_t>(d->observed_data_id_m); |
| 704 | 640x |
data_iterator it = this->data_objects.find(observed_data_id); |
| 705 | ||
| 706 | 640x |
if (it != this->data_objects.end()) {
|
| 707 | 640x |
d->data_observed_values = (*it).second; |
| 708 | 640x |
FIMS_INFO_LOG("Observed data " + fims::to_string(observed_data_id) +
|
| 709 |
" successfully set to density component " + |
|
| 710 |
fims::to_string(d->id)); |
|
| 711 |
} else {
|
|
| 712 | ! |
valid_model = false; |
| 713 | ! |
FIMS_ERROR_LOG( |
| 714 |
"Expected data observations not defined for density " |
|
| 715 |
"component " + |
|
| 716 |
fims::to_string(d->id) + ", observed data " + |
|
| 717 |
fims::to_string(observed_data_id)); |
|
| 718 |
} |
|
| 719 |
} else {
|
|
| 720 | ! |
valid_model = false; |
| 721 | ! |
FIMS_ERROR_LOG("No data input for density component" +
|
| 722 |
fims::to_string(d->id)); |
|
| 723 |
} |
|
| 724 |
} |
|
| 725 |
} |
|
| 726 |
} |
|
| 727 | ||
| 728 |
/** |
|
| 729 |
* @brief Loop over all populations and set pointers to population objects |
|
| 730 |
* |
|
| 731 |
* @param &valid_model reference to true/false boolean indicating whether |
|
| 732 |
* model is valid. |
|
| 733 |
*/ |
|
| 734 | 160x |
void CreatePopulationObjects(bool& valid_model) {
|
| 735 | 160x |
for (population_iterator it = this->populations.begin(); |
| 736 | 280x |
it != this->populations.end(); ++it) {
|
| 737 | 120x |
std::shared_ptr<fims_popdy::Population<Type>> p = (*it).second; |
| 738 | ||
| 739 | 120x |
FIMS_INFO_LOG("Initializing population " + fims::to_string(p->id));
|
| 740 |
// check if population has fleets |
|
| 741 | 120x |
typename std::set<uint32_t>::iterator fleet_ids_it; |
| 742 | ||
| 743 | 120x |
for (fleet_ids_it = p->fleet_ids.begin(); |
| 744 | 352x |
fleet_ids_it != p->fleet_ids.end(); ++fleet_ids_it) {
|
| 745 |
// error check and set population elements |
|
| 746 |
// check me - add another fleet iterator to push information from |
|
| 747 |
// for (fleet_iterator it = this->fleets.begin(); it != |
|
| 748 |
// this->fleets.end(); |
|
| 749 |
// ++it) {
|
|
| 750 | ||
| 751 | 232x |
fleet_iterator it = this->fleets.find(*fleet_ids_it); |
| 752 | ||
| 753 | 232x |
if (it != this->fleets.end()) {
|
| 754 |
// Initialize fleet object |
|
| 755 | 232x |
std::shared_ptr<fims_popdy::Fleet<Type>> f = (*it).second; |
| 756 |
// population to the individual fleets This is to pass catch at age |
|
| 757 |
// from population to fleets? |
|
| 758 |
// any shared member in p (population is pushed into fleets) |
|
| 759 | 232x |
p->fleets.push_back(f); |
| 760 |
} else {
|
|
| 761 | ! |
valid_model = false; |
| 762 | ! |
FIMS_ERROR_LOG("Fleet \"" + fims::to_string(*fleet_ids_it) +
|
| 763 |
"\" undefined, not found for Population \"" + |
|
| 764 |
fims::to_string(p->id) + "\". "); |
|
| 765 |
} |
|
| 766 |
// // error check and set population elements |
|
| 767 |
// // check me - add another fleet iterator to push information from |
|
| 768 |
// for (fleet_iterator it = this->fleets.begin(); it != |
|
| 769 |
// this->fleets.end(); |
|
| 770 |
// ++it) |
|
| 771 |
// {
|
|
| 772 |
// // Initialize fleet object |
|
| 773 |
// std::shared_ptr<fims_popdy::Fleet<Type>> f = (*it).second; |
|
| 774 |
// // population to the individual fleets This is to pass landings |
|
| 775 |
// at age |
|
| 776 |
// // from population to fleets? |
|
| 777 |
// // any shared member in p (population is pushed into fleets) |
|
| 778 |
// p->fleets.push_back(f); |
|
| 779 |
// } |
|
| 780 |
} |
|
| 781 | ||
| 782 |
// set information dimensions |
|
| 783 | 120x |
this->n_years = std::max(this->n_years, p->n_years); |
| 784 | 120x |
this->n_ages = std::max(this->n_ages, p->n_ages); |
| 785 | ||
| 786 | 120x |
SetRecruitment(valid_model, p); |
| 787 | ||
| 788 | 120x |
SetRecruitmentProcess(valid_model, p); |
| 789 | ||
| 790 | 120x |
SetGrowth(valid_model, p); |
| 791 | ||
| 792 | 120x |
SetMaturity(valid_model, p); |
| 793 |
} |
|
| 794 |
} |
|
| 795 | ||
| 796 |
/** |
|
| 797 |
* @brief Loop over all models and set pointers to population objects |
|
| 798 |
*/ |
|
| 799 | 160x |
void CreateModelingObjects(bool& valid_model) {
|
| 800 | 160x |
for (model_map_iterator it = this->models_map.begin(); |
| 801 | 276x |
it != this->models_map.end(); ++it) {
|
| 802 | 116x |
std::shared_ptr<fims_popdy::FisheryModelBase<Type>>& model = (*it).second; |
| 803 | 116x |
std::set<uint32_t>::iterator jt; |
| 804 | ||
| 805 | 116x |
for (jt = model->population_ids.begin(); |
| 806 | 232x |
jt != model->population_ids.end(); ++jt) {
|
| 807 | 116x |
population_iterator pt = this->populations.find((*jt)); |
| 808 | ||
| 809 | 116x |
if (pt != this->populations.end()) {
|
| 810 | 116x |
std::shared_ptr<fims_popdy::Population<Type>> p = (*pt).second; |
| 811 | 116x |
model->populations.push_back(p); |
| 812 | 348x |
for (size_t i = 0; i < p->fleets.size(); i++) {
|
| 813 | 232x |
model->fleets[p->fleets[i]->GetId()] = p->fleets[i]; |
| 814 |
} |
|
| 815 |
} else {
|
|
| 816 | ! |
valid_model = false; |
| 817 | ! |
FIMS_ERROR_LOG("No population object defined for model " +
|
| 818 |
fims::to_string(model->GetId())); |
|
| 819 |
} |
|
| 820 |
} |
|
| 821 | 116x |
model->Initialize(); |
| 822 |
} |
|
| 823 |
} |
|
| 824 | ||
| 825 |
/** |
|
| 826 |
* @brief Create the generalized stock assessment model that will evaluate the |
|
| 827 |
* objective function. Does error checking to make sure the program has |
|
| 828 |
* all necessary components for the model and that they're in the right |
|
| 829 |
* dimensions. This sets up pointers to all memory objects and initializes |
|
| 830 |
* fleet and population objects. |
|
| 831 |
* |
|
| 832 |
* @return True if valid model, False if invalid model, check fims.log for |
|
| 833 |
* errors. |
|
| 834 |
*/ |
|
| 835 | 160x |
bool CreateModel() {
|
| 836 | 160x |
bool valid_model = true; |
| 837 | ||
| 838 | 160x |
CreateFleetObjects(valid_model); |
| 839 | ||
| 840 | 160x |
SetDataObjects(valid_model); |
| 841 | ||
| 842 | 160x |
CreatePopulationObjects(valid_model); |
| 843 | ||
| 844 | 160x |
CreateModelingObjects(valid_model); |
| 845 | ||
| 846 |
// setup priors, random effect, and data density components |
|
| 847 | 160x |
SetupPriors(); |
| 848 | 160x |
SetupRandomEffects(); |
| 849 | 160x |
SetupData(); |
| 850 | ||
| 851 | 160x |
return valid_model; |
| 852 |
} |
|
| 853 | ||
| 854 |
/** |
|
| 855 |
* @brief Get the Nages object |
|
| 856 |
* |
|
| 857 |
* @return size_t |
|
| 858 |
*/ |
|
| 859 |
size_t GetNages() const { return n_ages; }
|
|
| 860 | ||
| 861 |
/** |
|
| 862 |
* @brief Set the Nages object |
|
| 863 |
* |
|
| 864 |
* @param n_ages |
|
| 865 |
*/ |
|
| 866 |
void SetNages(size_t n_ages) { this->n_ages = n_ages; }
|
|
| 867 | ||
| 868 |
/** |
|
| 869 |
* @brief Get the n_years object |
|
| 870 |
* |
|
| 871 |
* @return size_t |
|
| 872 |
*/ |
|
| 873 |
size_t GetNyears() const { return n_years; }
|
|
| 874 | ||
| 875 |
/** |
|
| 876 |
* @brief Set the n_years object |
|
| 877 |
* |
|
| 878 |
* @param n_years |
|
| 879 |
*/ |
|
| 880 |
void SetNyears(size_t n_years) { this->n_years = n_years; }
|
|
| 881 | ||
| 882 |
/** |
|
| 883 |
* @brief Get the Parameters object |
|
| 884 |
* |
|
| 885 |
* @return std::vector<Type*>& |
|
| 886 |
*/ |
|
| 887 |
std::vector<Type*>& GetParameters() { return parameters; }
|
|
| 888 | ||
| 889 |
/** |
|
| 890 |
* @brief Get the Fixed Effects Parameters object |
|
| 891 |
* |
|
| 892 |
* @return std::vector<Type*>& |
|
| 893 |
*/ |
|
| 894 |
std::vector<Type*>& GetFixedEffectsParameters() {
|
|
| 895 |
return fixed_effects_parameters; |
|
| 896 |
} |
|
| 897 | ||
| 898 |
/** |
|
| 899 |
* @brief Get the Random Effects Parameters object |
|
| 900 |
* |
|
| 901 |
* @return std::vector<Type*>& |
|
| 902 |
*/ |
|
| 903 |
std::vector<Type*>& GetRandomEffectsParameters() {
|
|
| 904 |
return random_effects_parameters; |
|
| 905 |
} |
|
| 906 | ||
| 907 |
/** |
|
| 908 |
* @brief Checks to make sure all required modules are present for specified |
|
| 909 |
* model |
|
| 910 |
* |
|
| 911 |
* @return True if valid model, False if invalid model, check fims.log for |
|
| 912 |
* errors. |
|
| 913 |
*/ |
|
| 914 | 40x |
bool CheckModel() {
|
| 915 | 40x |
bool valid_model = true; |
| 916 | 40x |
for (model_map_iterator it = this->models_map.begin(); |
| 917 | 69x |
it != this->models_map.end(); ++it) {
|
| 918 | 29x |
std::shared_ptr<fims_popdy::FisheryModelBase<Type>>& model = (*it).second; |
| 919 | 29x |
std::set<uint32_t>::iterator jt; |
| 920 | ||
| 921 | 29x |
for (jt = model->population_ids.begin(); |
| 922 | 58x |
jt != model->population_ids.end(); ++jt) {
|
| 923 | 29x |
population_iterator pt = this->populations.find((*jt)); |
| 924 | ||
| 925 | 29x |
if (pt != this->populations.end()) {
|
| 926 | 29x |
std::shared_ptr<fims_popdy::Population<Type>> p = (*pt).second; |
| 927 | ||
| 928 | 29x |
if (model->model_type_m == "caa") {
|
| 929 | 29x |
typename std::set<uint32_t>::iterator fleet_ids_it; |
| 930 | 29x |
for (fleet_ids_it = p->fleet_ids.begin(); |
| 931 | 87x |
fleet_ids_it != p->fleet_ids.end(); ++fleet_ids_it) {
|
| 932 | 58x |
fleet_iterator it = this->fleets.find(*fleet_ids_it); |
| 933 | ||
| 934 | 58x |
if (it != this->fleets.end()) {
|
| 935 |
// Initialize fleet object |
|
| 936 | 58x |
std::shared_ptr<fims_popdy::Fleet<Type>> f = (*it).second; |
| 937 | ||
| 938 | 58x |
if (f->fleet_selectivity_id_m == static_cast<Type>(-999)) {
|
| 939 | ! |
valid_model = false; |
| 940 | ! |
FIMS_ERROR_LOG( |
| 941 |
"No selectivity pattern defined for fleet " + |
|
| 942 |
fims::to_string(f->id) + |
|
| 943 |
". FIMS requires selectivity be defined for all fleets " |
|
| 944 |
"when running a catch at age model."); |
|
| 945 |
} |
|
| 946 |
} |
|
| 947 |
} |
|
| 948 | ||
| 949 | 29x |
if (p->recruitment_id == static_cast<Type>(-999)) {
|
| 950 | ! |
valid_model = false; |
| 951 | ! |
FIMS_ERROR_LOG( |
| 952 |
"No recruitment function defined for population " + |
|
| 953 |
fims::to_string(p->id) + |
|
| 954 |
". FIMS requires recruitment functions be defined for all " |
|
| 955 |
"populations when running a catch at age model."); |
|
| 956 |
} |
|
| 957 | ||
| 958 | 29x |
std::shared_ptr<fims_popdy::RecruitmentBase<Type>> r = |
| 959 | 29x |
p->recruitment; |
| 960 | 29x |
r = p->recruitment; |
| 961 | 29x |
if (r->process_id == static_cast<Type>(-999)) {
|
| 962 | ! |
valid_model = false; |
| 963 | ! |
FIMS_ERROR_LOG( |
| 964 |
"No recruitment process function defined for population " + |
|
| 965 |
fims::to_string(p->id) + |
|
| 966 |
". FIMS requires recruitment process functions be defined " |
|
| 967 |
"for all " |
|
| 968 |
"recruitments when running a catch at age model."); |
|
| 969 |
} |
|
| 970 | ||
| 971 | 29x |
if (p->growth_id == static_cast<Type>(-999)) {
|
| 972 | ! |
valid_model = false; |
| 973 | ! |
FIMS_ERROR_LOG( |
| 974 |
"No growth function defined for population " + |
|
| 975 |
fims::to_string(p->id) + |
|
| 976 |
". FIMS requires growth functions be defined for all " |
|
| 977 |
"populations when running a catch at age model."); |
|
| 978 |
} |
|
| 979 | ||
| 980 | 29x |
if (p->maturity_id == static_cast<Type>(-999)) {
|
| 981 | ! |
valid_model = false; |
| 982 | ||
| 983 | ! |
FIMS_WARNING_LOG( |
| 984 |
"No maturity function defined for population " + |
|
| 985 |
fims::to_string(p->id) + |
|
| 986 |
". FIMS requires maturity functions be defined for all " |
|
| 987 |
"populations when running a catch at age model."); |
|
| 988 |
} |
|
| 989 |
} |
|
| 990 |
} |
|
| 991 |
} |
|
| 992 |
} |
|
| 993 | 40x |
return valid_model; |
| 994 |
} |
|
| 995 |
}; |
|
| 996 | ||
| 997 |
template <typename Type> |
|
| 998 |
std::shared_ptr<Information<Type>> Information<Type>::fims_information = |
|
| 999 |
nullptr; // singleton instance |
|
| 1000 | ||
| 1001 |
} // namespace fims_info |
|
| 1002 | ||
| 1003 |
#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 | 1274x |
virtual ~FIMSObject() {}
|
| 34 | ||
| 35 |
/** |
|
| 36 |
* @brief Getter that returns the unique id for parameters in the model |
|
| 37 |
*/ |
|
| 38 | 4593974x |
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 |
} // namespace fims_model_object |
|
| 58 | ||
| 59 |
#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 | 784x |
static std::shared_ptr<Model<Type>> GetInstance() {
|
| 46 | 784x |
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 | 784x |
return Model<Type>::fims_model; |
| 52 |
} |
|
| 53 | ||
| 54 |
/** |
|
| 55 |
* @brief Evaluate. Calculates the joint negative log-likelihood function. |
|
| 56 |
*/ |
|
| 57 | 704x |
const Type Evaluate() {
|
| 58 |
// jnll = negative-log-likelihood (the objective function) |
|
| 59 | 704x |
Type jnll = static_cast<Type>(0.0); |
| 60 | 704x |
typename fims_info::Information<Type>::model_map_iterator m_it; |
| 61 |
// Check if fims_information is set |
|
| 62 | 704x |
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 | 842x |
fims::Vector<Type> nll_vec( |
| 71 | 704x |
this->fims_information->density_components.size(), 0.0); |
| 72 | ||
| 73 | 1232x |
for (m_it = this->fims_information->models_map.begin(); |
| 74 | 1232x |
m_it != this->fims_information->models_map.end(); ++m_it) {
|
| 75 |
//(*m_it).second points to the Model module |
|
| 76 | 528x |
std::shared_ptr<fims_popdy::FisheryModelBase<Type>> m = (*m_it).second; |
| 77 | 528x |
m->of = this->of; // link to TMB objective function |
| 78 | 528x |
m->Prepare(); |
| 79 | 528x |
m->Evaluate(); |
| 80 |
} |
|
| 81 | ||
| 82 |
// Loop over densities and evaluate joint negative log densities for priors |
|
| 83 | 704x |
typename fims_info::Information<Type>::density_components_iterator d_it; |
| 84 | 704x |
int nll_vec_idx = 0; |
| 85 | 704x |
size_t n_priors = 0; |
| 86 | 1408x |
FIMS_INFO_LOG("Begin evaluating prior densities.")
|
| 87 | 4160x |
for (d_it = this->fims_information->density_components.begin(); |
| 88 | 4160x |
d_it != this->fims_information->density_components.end(); ++d_it) {
|
| 89 | 3456x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 90 | 3456x |
(*d_it).second; |
| 91 |
#ifdef TMB_MODEL |
|
| 92 | 3456x |
d->of = this->of; |
| 93 |
#endif |
|
| 94 | 3456x |
if (d->input_type == "prior") {
|
| 95 | 38x |
nll_vec[nll_vec_idx] = -d->evaluate(); |
| 96 | 38x |
jnll += nll_vec[nll_vec_idx]; |
| 97 | 38x |
n_priors += 1; |
| 98 | 38x |
nll_vec_idx += 1; |
| 99 |
} |
|
| 100 |
} |
|
| 101 | 704x |
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 | 704x |
size_t n_random_effects = 0; |
| 109 | 4160x |
for (d_it = this->fims_information->density_components.begin(); |
| 110 | 4160x |
d_it != this->fims_information->density_components.end(); ++d_it) {
|
| 111 | 3456x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 112 | 3456x |
(*d_it).second; |
| 113 |
#ifdef TMB_MODEL |
|
| 114 | 3456x |
d->of = this->of; |
| 115 |
#endif |
|
| 116 | 3456x |
if (d->input_type == "random_effects") {
|
| 117 | 558x |
nll_vec[nll_vec_idx] = -d->evaluate(); |
| 118 | 558x |
jnll += nll_vec[nll_vec_idx]; |
| 119 | 558x |
n_random_effects += 1; |
| 120 | 558x |
nll_vec_idx += 1; |
| 121 |
} |
|
| 122 |
} |
|
| 123 | 704x |
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 | 704x |
int n_data = 0; |
| 131 | 4160x |
for (d_it = this->fims_information->density_components.begin(); |
| 132 | 4160x |
d_it != this->fims_information->density_components.end(); ++d_it) {
|
| 133 | 3456x |
std::shared_ptr<fims_distributions::DensityComponentBase<Type>> d = |
| 134 | 3456x |
(*d_it).second; |
| 135 |
#ifdef TMB_MODEL |
|
| 136 | 3456x |
d->of = this->of; |
| 137 |
// d->keep = this->keep; |
|
| 138 |
#endif |
|
| 139 | 3456x |
if (d->input_type == "data") {
|
| 140 | 2860x |
nll_vec[nll_vec_idx] = -d->evaluate(); |
| 141 | 2860x |
jnll += nll_vec[nll_vec_idx]; |
| 142 | 2860x |
n_data += 1; |
| 143 | 2860x |
nll_vec_idx += 1; |
| 144 |
} |
|
| 145 |
} |
|
| 146 | ||
| 147 |
// report out nll components |
|
| 148 |
#ifdef TMB_MODEL |
|
| 149 | 704x |
vector<Type> nll_components = nll_vec.to_tmb(); |
| 150 | 566x |
FIMS_REPORT_F(nll_components, this->of); |
| 151 | 566x |
FIMS_REPORT_F(jnll, this->of); |
| 152 |
#endif |
|
| 153 | ||
| 154 |
// report out model family objects |
|
| 155 | 1232x |
for (m_it = this->fims_information->models_map.begin(); |
| 156 | 1232x |
m_it != this->fims_information->models_map.end(); ++m_it) {
|
| 157 |
//(*m_it).second points to the Model module |
|
| 158 | 528x |
std::shared_ptr<fims_popdy::FisheryModelBase<Type>> m = (*m_it).second; |
| 159 | 528x |
m->Report(); |
| 160 |
} |
|
| 161 | ||
| 162 | 704x |
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 This header defines two core templates used by concrete |
|
| 7 |
* distribution functors (e.g., NormalLPDF, LogNormalLPDF, MultinomialLPMF): |
|
| 8 |
* DistributionElementObject, which stores and resolves observed/expected |
|
| 9 |
* inputs, and DensityComponentBase, which adds shared bookkeeping for |
|
| 10 |
* log-likelihood contributions and simulation/reporting behavior. |
|
| 11 |
* @copyright This file is part of the NOAA, National Marine Fisheries Service |
|
| 12 |
* Fisheries Integrated Modeling System project. See LICENSE in the source |
|
| 13 |
* folder for reuse information. |
|
| 14 |
*/ |
|
| 15 |
#ifndef DENSITY_COMPONENT_BASE_HPP |
|
| 16 |
#define DENSITY_COMPONENT_BASE_HPP |
|
| 17 | ||
| 18 |
#include "../../common/data_object.hpp" |
|
| 19 |
#include "../../common/model_object.hpp" |
|
| 20 |
#include "../../interface/interface.hpp" |
|
| 21 |
#include "../../common/fims_vector.hpp" |
|
| 22 |
#include "../../common/fims_math.hpp" |
|
| 23 | ||
| 24 |
namespace fims_distributions {
|
|
| 25 | ||
| 26 |
/** @brief Base class for all module_name functors. |
|
| 27 |
* |
|
| 28 |
* @tparam Type The type of the module_name functor. |
|
| 29 |
* |
|
| 30 |
*/ |
|
| 31 |
template <typename Type> |
|
| 32 |
struct DensityComponentBase : public fims_model_object::FIMSObject<Type> {
|
|
| 33 |
/** |
|
| 34 |
* @brief Classification of the input pathway for this distribution object. |
|
| 35 |
* Options used by accessor methods are, "prior", "random_effects", and |
|
| 36 |
*"data". |
|
| 37 |
*/ |
|
| 38 |
std::string input_type; |
|
| 39 | ||
| 40 |
/** @brief Observed data. */ |
|
| 41 |
std::shared_ptr<fims_data_object::DataObject<Type>> data_observed_values; |
|
| 42 | ||
| 43 |
/** @brief Expected value vector for prior-based pathways. */ |
|
| 44 |
fims::Vector<Type> expected_values; |
|
| 45 | ||
| 46 |
/** @brief Pointer to random effects vector. */ |
|
| 47 |
fims::Vector<Type>* re = NULL; |
|
| 48 | ||
| 49 |
/** @brief Expected value vector for random-effects pathways. */ |
|
| 50 |
fims::Vector<Type>* re_expected_values = NULL; |
|
| 51 | ||
| 52 |
/** @brief Expected value vector for data pathways. */ |
|
| 53 |
fims::Vector<Type>* data_expected_values = NULL; |
|
| 54 | ||
| 55 |
/** @brief Vector of pointers where each entry points to a prior parameter. */ |
|
| 56 |
std::vector<fims::Vector<Type>*> priors; |
|
| 57 | ||
| 58 |
/** |
|
| 59 |
* @brief Input value of distribution function for priors or random effects. |
|
| 60 |
*/ |
|
| 61 |
fims::Vector<Type> observed_values; |
|
| 62 | ||
| 63 |
/** |
|
| 64 |
* @brief The expected mean of the distribution; overrides expected values. |
|
| 65 |
*/ |
|
| 66 |
fims::Vector<Type> expected_mean; |
|
| 67 | ||
| 68 |
/** |
|
| 69 |
* @brief If "yes", `expected_mean` is used instead of `expected_values`. The |
|
| 70 |
* default is "no" leading to the use of `expected_values`. |
|
| 71 |
*/ |
|
| 72 |
std::string use_mean = fims::to_string("no");
|
|
| 73 | ||
| 74 |
// std::shared_ptr<DistributionElementObject<Type>> expected; |
|
| 75 |
// // Expected value of distribution function. |
|
| 76 | ||
| 77 |
/** |
|
| 78 |
* @brief Retrieve one observed value based on `input_type`. |
|
| 79 |
* @param i Index into the active observed source, e.g., vector or pointer. |
|
| 80 |
* @return Reference to the selected observed value. |
|
| 81 |
* @throws std::runtime_error If input_type is "prior" and priors is empty. |
|
| 82 |
*/ |
|
| 83 | 119166x |
inline Type& get_observed(size_t i) {
|
| 84 | 119166x |
if (this->input_type == "data") {
|
| 85 | 99428x |
return data_observed_values->at(i); |
| 86 |
} |
|
| 87 | 19738x |
if (this->input_type == "random_effects") {
|
| 88 | 18496x |
return (*re)[i]; |
| 89 |
} |
|
| 90 | 1242x |
if (this->input_type == "prior") {
|
| 91 | 1016x |
if (priors.size() == 0) {
|
| 92 | ! |
throw std::runtime_error("No priors defined for this distribution.");
|
| 93 | 1016x |
} else if (priors.size() == 1) {
|
| 94 | 984x |
return (*(priors[0]))[i]; |
| 95 | 32x |
} else if (priors.size() > 1) {
|
| 96 | 32x |
return (*(priors[i]))[0]; |
| 97 |
} |
|
| 98 |
} |
|
| 99 | 113x |
return observed_values[i]; |
| 100 |
} |
|
| 101 | ||
| 102 |
/** |
|
| 103 |
* @brief Retrieve one observed matrix-like value based on `input_type`. |
|
| 104 |
* @param i Row index. |
|
| 105 |
* @param j Column index. |
|
| 106 |
* @return Reference to the selected observed value. |
|
| 107 |
*/ |
|
| 108 | 1938458x |
inline Type& get_observed(size_t i, size_t j) {
|
| 109 | 1938458x |
if (this->input_type == "data") {
|
| 110 | 1938458x |
return data_observed_values->at(i, j); |
| 111 |
} |
|
| 112 | ! |
return observed_values[i * (j - 1) + j]; |
| 113 |
} |
|
| 114 | ||
| 115 |
/** |
|
| 116 |
* @brief Retrieve one expected value based on `input_type` and `use_mean`. |
|
| 117 |
* @param i Index into the active expected source, e.g., vector or pointer. |
|
| 118 |
* @return Reference to the selected expected value. |
|
| 119 |
* @details If `use_mean == "yes"`, `expected_mean` overrides other expected |
|
| 120 |
* vectors and is accessed via scalar/vector semantics. |
|
| 121 |
*/ |
|
| 122 | 1066402x |
inline Type& get_expected(size_t i) {
|
| 123 | 1066402x |
if (this->input_type == "data") {
|
| 124 | 1046720x |
return (*data_expected_values)[i]; |
| 125 | 19682x |
} else if (this->use_mean == "yes") {
|
| 126 | 960x |
return this->expected_mean.get_force_scalar(i); |
| 127 | 18722x |
} else if (this->input_type == "random_effects") {
|
| 128 | 17536x |
return (*re_expected_values)[i]; |
| 129 |
} else {
|
|
| 130 | 1186x |
return this->expected_values.get_force_scalar(i); |
| 131 |
} |
|
| 132 |
} |
|
| 133 | ||
| 134 |
/** |
|
| 135 |
* @brief Get length of the active observed input vector. |
|
| 136 |
* @return Size of the observed input under the current `input_type`. |
|
| 137 |
*/ |
|
| 138 | 1844x |
inline size_t get_n_x() {
|
| 139 | 1844x |
if (this->input_type == "data") {
|
| 140 | 1152x |
return this->data_observed_values->data.size(); |
| 141 |
} |
|
| 142 | 692x |
if (this->input_type == "random_effects") {
|
| 143 | 608x |
return (*re).size(); |
| 144 |
} |
|
| 145 | 84x |
if (this->input_type == "prior") {
|
| 146 | 40x |
return this->expected_values.size(); |
| 147 |
} |
|
| 148 | 22x |
return observed_values.size(); |
| 149 |
} |
|
| 150 | ||
| 151 |
/** |
|
| 152 |
* @brief Get length of the active expected input vector. |
|
| 153 |
* @return Size of the expected input under the current `input_type`. |
|
| 154 |
*/ |
|
| 155 | 1696x |
inline size_t get_n_expected() {
|
| 156 | 1696x |
if (this->input_type == "data") {
|
| 157 | 1056x |
return (*data_expected_values).size(); |
| 158 |
} |
|
| 159 | 640x |
if (this->input_type == "random_effects") {
|
| 160 | 558x |
return (*re_expected_values).size(); |
| 161 |
} |
|
| 162 | 82x |
if (this->input_type == "prior") {
|
| 163 | 38x |
return this->expected_values.size(); |
| 164 |
} |
|
| 165 | 22x |
return observed_values.size(); |
| 166 |
} |
|
| 167 |
// id_g is the ID of the instance of the DensityComponentBase class. |
|
| 168 |
// this is like a memory tracker. |
|
| 169 |
// Assigning each one its own ID is a way to keep track of |
|
| 170 |
// all the instances of the DensityComponentBase class. |
|
| 171 |
/** |
|
| 172 |
* @brief Global unique identifier for distribution modules. |
|
| 173 |
*/ |
|
| 174 |
static uint32_t id_g; |
|
| 175 | ||
| 176 |
/** |
|
| 177 |
* @brief Total log probability density contribution of the distribution. |
|
| 178 |
* |
|
| 179 |
*/ |
|
| 180 |
Type lpdf; |
|
| 181 | ||
| 182 |
/** |
|
| 183 |
* @brief ID of observed data component. |
|
| 184 |
*/ |
|
| 185 |
int observed_data_id_m = -999; |
|
| 186 | ||
| 187 |
/** |
|
| 188 |
* @brief Vector storing observation-level log-likelihood contributions. |
|
| 189 |
*/ |
|
| 190 |
fims::Vector<Type> lpdf_vec; |
|
| 191 | ||
| 192 |
/** |
|
| 193 |
* @brief Boolean; if true, one-step-ahead (OSA) residuals are calculated. |
|
| 194 |
*/ |
|
| 195 |
bool osa_flag = false; |
|
| 196 | ||
| 197 |
/** |
|
| 198 |
* @brief Boolean; if true, data are simulated from the distribution. |
|
| 199 |
*/ |
|
| 200 |
bool simulate_flag = false; |
|
| 201 | ||
| 202 |
/** |
|
| 203 |
* @brief Unique ID for variable map that points to a fims::Vector. |
|
| 204 |
*/ |
|
| 205 |
std::vector<uint32_t> key; |
|
| 206 | ||
| 207 |
#ifdef TMB_MODEL |
|
| 208 |
/** |
|
| 209 |
* @brief Pointer to the TMB objective function. |
|
| 210 |
*/ |
|
| 211 |
::objective_function<Type>* of; |
|
| 212 |
#endif |
|
| 213 | ||
| 214 |
/** |
|
| 215 |
* @brief Constructor, which initializes default prior pointer state and ID. |
|
| 216 |
*/ |
|
| 217 | 830x |
DensityComponentBase() {
|
| 218 |
// initialize the priors vector with a size of 1 and set the first element |
|
| 219 |
// to NULL |
|
| 220 | 830x |
this->priors.resize(1); |
| 221 | 830x |
this->priors[0] = NULL; |
| 222 | 830x |
this->id = DensityComponentBase::id_g++; |
| 223 |
} |
|
| 224 | ||
| 225 | 415x |
virtual ~DensityComponentBase() {}
|
| 226 |
/** |
|
| 227 |
* @brief Evaluate the distribution-specific log-likelihood contribution. |
|
| 228 |
* @return Total log-likelihood contribution for the active inputs. |
|
| 229 |
*/ |
|
| 230 |
virtual const Type evaluate() = 0; |
|
| 231 |
}; |
|
| 232 | ||
| 233 |
/** @brief Default id of the singleton distribution class |
|
| 234 |
*/ |
|
| 235 |
template <typename Type> |
|
| 236 |
uint32_t DensityComponentBase<Type>::id_g = 0; |
|
| 237 | ||
| 238 |
} // namespace fims_distributions |
|
| 239 | ||
| 240 |
#endif /* DENSITY_COMPONENT_BASE_HPP */ |
| 1 |
/** |
|
| 2 |
* @file lognormal_lpdf.hpp |
|
| 3 |
* @brief Implements the LogNormalLPDF distribution functor used by FIMS to |
|
| 4 |
* evaluate observation-level and total log-likelihood contributions under a |
|
| 5 |
* lognormal error model for data, priors, and random effects. |
|
| 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 |
* @copybrief lognormal_lpdf.hpp |
|
| 20 |
* |
|
| 21 |
* @details This implementation relies on [TMB's R-style `dnorm()` utility]( |
|
| 22 |
* https://kaskr.github.io/adcomp/group__R__style__distribution.html) for |
|
| 23 |
* normal log-density calculations on log-transformed values. Specifically, |
|
| 24 |
* when evaluating the lognormal likelihood, observations are transformed with |
|
| 25 |
* `log(x)` and passed to `dnorm(..., give_log = true)` to obtain log-density |
|
| 26 |
* values. For data inputs, the Jacobian adjustment `-log(x)` is applied where |
|
| 27 |
* appropriate to convert from normal density on the log scale to the lognormal |
|
| 28 |
* density on the original scale. |
|
| 29 |
* |
|
| 30 |
* For `data` input, values equal to `na_value` are skipped and contribute zero |
|
| 31 |
* to the objective. Per-observation contributions are stored in `lpdf_vec`; |
|
| 32 |
* the summed total is returned by `evaluate()` and stored in `lpdf`. |
|
| 33 |
*/ |
|
| 34 |
template <typename Type> |
|
| 35 |
struct LogNormalLPDF : public DensityComponentBase<Type> {
|
|
| 36 |
/** |
|
| 37 |
* @brief Natural log of the standard deviation of the distribution on the |
|
| 38 |
* log scale. The argument can be a vector or scalar, where the latter is |
|
| 39 |
* referenced for each instance through the use of |
|
| 40 |
* \ref fims::Vector::get_force_scalar(size_t) "get_force_scalar()". |
|
| 41 |
*/ |
|
| 42 |
fims::Vector<Type> log_sd; |
|
| 43 | ||
| 44 |
/** @brief Constructor. |
|
| 45 |
*/ |
|
| 46 | 254x |
LogNormalLPDF() : DensityComponentBase<Type>() {}
|
| 47 | ||
| 48 |
/** @brief Destructor. |
|
| 49 |
*/ |
|
| 50 | 127x |
virtual ~LogNormalLPDF() {}
|
| 51 | ||
| 52 |
/** |
|
| 53 |
* @brief Evaluates the lognormal log probability density function. |
|
| 54 |
* @details The following equation is the lognormal probability density |
|
| 55 |
* function, and thus, the log of it is evaluated: |
|
| 56 |
* \f[ |
|
| 57 |
* f(x) = \frac{1.0}{ x\sigma\sqrt{2\pi}
|
|
| 58 |
* }\mathrm{exp}\Bigg(-\frac{(\mathrm{ln}(x) - \mu)^{2}}{2\sigma^{2}}\Bigg),
|
|
| 59 |
* \f] |
|
| 60 |
* where \f$\mu\f$ is the mean of the distribution of \f$\mathrm{ln(x)}\f$
|
|
| 61 |
* and \f$\sigma^2\f$ is the variance of \f$\mathrm{ln}(x)\f$.
|
|
| 62 |
*/ |
|
| 63 | 1078x |
virtual const Type evaluate() {
|
| 64 |
// set vector size based on input type (prior, process, or data) |
|
| 65 | 1078x |
size_t n_x = this->get_n_x(); |
| 66 |
// get expected value vector size |
|
| 67 | 1078x |
size_t n_expected = this->get_n_expected(); |
| 68 |
// setup vector for recording the log probability density function values |
|
| 69 | 1078x |
this->lpdf_vec.resize(n_x); |
| 70 | 1078x |
std::fill(this->lpdf_vec.begin(), this->lpdf_vec.end(), |
| 71 | 1078x |
static_cast<Type>(0)); |
| 72 | 1078x |
this->lpdf = static_cast<Type>(0); |
| 73 | ||
| 74 |
// Dimension checks |
|
| 75 |
// TODO: fix dimension check as expected values no longer used for data |
|
| 76 | 1078x |
if (n_x != n_expected) {
|
| 77 | ! |
if (n_expected == 1) {
|
| 78 | ! |
n_expected = n_x; |
| 79 | ! |
} else if (n_x > n_expected) {
|
| 80 | ! |
n_x = n_expected; |
| 81 |
} |
|
| 82 |
} |
|
| 83 | ||
| 84 | 445x |
if (this->log_sd.size() > 1 && n_x != this->log_sd.size()) {
|
| 85 | 1x |
throw std::invalid_argument( |
| 86 |
"LognormalLPDF::Vector index out of bounds. The size of observed " |
|
| 87 |
"data does not equal the size of the log_sd vector. The observed " |
|
| 88 |
"data vector is of size " + |
|
| 89 |
fims::to_string(n_x) + " and the log_sd vector is of size " + |
|
| 90 |
fims::to_string(this->log_sd.size())); |
|
| 91 |
} |
|
| 92 | ||
| 93 | 33912x |
for (size_t i = 0; i < n_x; i++) {
|
| 94 |
#ifdef TMB_MODEL |
|
| 95 | 32836x |
if (this->input_type == "data") {
|
| 96 |
// if data, check if there are any NA values and skip lpdf calculation |
|
| 97 |
// if there are See Deroba and Miller, 2016 |
|
| 98 |
// (https://doi.org/10.1016/j.fishres.2015.12.002) for the use of |
|
| 99 |
// lognormal constant |
|
| 100 | 32780x |
if (this->get_observed(i) != this->data_observed_values->na_value) {
|
| 101 | 31834x |
this->lpdf_vec[i] = |
| 102 | 31834x |
dnorm(log(this->get_observed(i)), this->get_expected(i), |
| 103 | 37502x |
fims_math::exp(log_sd.get_force_scalar(i)), true) - |
| 104 | 37502x |
log(this->get_observed(i)); |
| 105 |
} else {
|
|
| 106 | 946x |
this->lpdf_vec[i] = 0; |
| 107 |
} |
|
| 108 |
} else {
|
|
| 109 | 28x |
if (this->input_type == "random_effects") {
|
| 110 |
// if random effects, no lognormal constant needs to be applied |
|
| 111 | ! |
this->lpdf_vec[i] = |
| 112 | ! |
dnorm(log(this->get_observed(i)), this->get_expected(i), |
| 113 | ! |
fims_math::exp(log_sd.get_force_scalar(i)), true); |
| 114 |
} else {
|
|
| 115 | 28x |
this->lpdf_vec[i] = |
| 116 | 28x |
dnorm(log(this->get_observed(i)), this->get_expected(i), |
| 117 | 28x |
fims_math::exp(log_sd.get_force_scalar(i)), true) - |
| 118 | 28x |
log(this->get_observed(i)); |
| 119 |
} |
|
| 120 |
} |
|
| 121 | ||
| 122 | 32836x |
this->lpdf += this->lpdf_vec[i]; |
| 123 | 32836x |
if (this->simulate_flag) {
|
| 124 | ! |
FIMS_SIMULATE_F(this->of) { // preprocessor definition in interface.hpp
|
| 125 |
// this simulates data that is mean biased |
|
| 126 | ! |
if (this->input_type == "data") {
|
| 127 | ! |
this->data_observed_values->at(i) = fims_math::exp( |
| 128 | ! |
rnorm(this->get_expected(i), |
| 129 | ! |
fims_math::exp(log_sd.get_force_scalar(i)))); |
| 130 |
} |
|
| 131 | ! |
if (this->input_type == "random_effects") {
|
| 132 | ! |
(*this->re)[i] = fims_math::exp( |
| 133 | ! |
rnorm(this->get_expected(i), |
| 134 | ! |
fims_math::exp(log_sd.get_force_scalar(i)))); |
| 135 |
} |
|
| 136 | ! |
if (this->input_type == "prior") {
|
| 137 | ! |
(*(this->priors[i]))[0] = fims_math::exp( |
| 138 | ! |
rnorm(this->get_expected(i), |
| 139 | ! |
fims_math::exp(log_sd.get_force_scalar(i)))); |
| 140 |
} |
|
| 141 |
} |
|
| 142 |
} |
|
| 143 |
#endif |
|
| 144 |
} |
|
| 145 |
#ifdef TMB_MODEL |
|
| 146 | 1076x |
vector<Type> lognormal_observed_values = this->observed_values.to_tmb(); |
| 147 |
// FIMS_REPORT_F(lognormal_observed_values, this->of); |
|
| 148 |
#endif |
|
| 149 | 1076x |
return (this->lpdf); |
| 150 |
} |
|
| 151 |
}; |
|
| 152 |
} // namespace fims_distributions |
|
| 153 |
#endif |
| 1 |
/** |
|
| 2 |
* @file multinomial_lpmf.hpp |
|
| 3 |
* @brief Implements the MultinomialLPMF distribution functor used by FIMS to |
|
| 4 |
* evaluate the observation-level and total log-likelihood contributions under |
|
| 5 |
* a multinomial error model for data, priors, and random effects. |
|
| 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 |
* @copybrief multinomial_lpmf.hpp |
|
| 20 |
* |
|
| 21 |
* @details This implementation relies on [TMB's R-style `dmultinom()` |
|
| 22 |
* utility]( https://kaskr.github.io/adcomp/group__R__style__distribution.html) |
|
| 23 |
* to compute row-wise multinomial log-probability mass contributions from |
|
| 24 |
* observed counts (`x_vector`) and expected proportions (`prob_vector`). |
|
| 25 |
* Specifically, when evaluating the multinomial likelihood, observations are |
|
| 26 |
* passed to `dmultinom(..., give_log = true)`. |
|
| 27 |
* |
|
| 28 |
* For `data` input, if any element in a row is equal to `na_value`, the entire |
|
| 29 |
* row is skipped and contributes zero to the objective. Contributions are |
|
| 30 |
* stored in `lpdf_vec`. The summed total is returned by `evaluate()` and |
|
| 31 |
* stored in `lpdf`. |
|
| 32 |
* |
|
| 33 |
* Row observations could be counts of each age for a given time step, where |
|
| 34 |
* additional time steps would be additional rows. Thus, columns are bins. |
|
| 35 |
*/ |
|
| 36 |
template <typename Type> |
|
| 37 |
struct MultinomialLPMF : public DensityComponentBase<Type> {
|
|
| 38 |
/** |
|
| 39 |
* @brief Dimensions of the number of rows and columns of the multivariate |
|
| 40 |
* dataset. |
|
| 41 |
*/ |
|
| 42 |
fims::Vector<size_t> dims; |
|
| 43 | ||
| 44 |
/** @brief Constructor. |
|
| 45 |
*/ |
|
| 46 | 418x |
MultinomialLPMF() : DensityComponentBase<Type>() {}
|
| 47 | ||
| 48 |
/** @brief Destructor. |
|
| 49 |
*/ |
|
| 50 | 209x |
virtual ~MultinomialLPMF() {}
|
| 51 | ||
| 52 |
/** |
|
| 53 |
* @brief Evaluates the multinomial log probability mass function. |
|
| 54 |
* @details The following equation is the multinomial probability mass |
|
| 55 |
* function, and thus, the log of it is evaluated: |
|
| 56 |
* \f[ |
|
| 57 |
* f(\underline{y}) = \frac{n!}{y_{1}!...
|
|
| 58 |
* y_{k}!}p^{y_{1}}_{1}...p^{y_{k}}_{k}, \f] where \f$k\f$ is the number of
|
|
| 59 |
* categories, \f$n\f$ is the sample size, \f$\mu_{i}\f$ is the mean of
|
|
| 60 |
* \f$y_{i}\f$ and is equal to \f$np_{i}\f$, and \f$\sigma^{2}_{i}\f$ is the
|
|
| 61 |
* variance of \f$y_{i}\f$ and is equal to \f$np_{i}(1-p_{i})\f$.
|
|
| 62 |
*/ |
|
| 63 | 907x |
virtual const Type evaluate() {
|
| 64 |
// set dims using data_observed_values if no user input |
|
| 65 | 907x |
if (dims.size() != 2) {
|
| 66 | 172x |
dims.resize(2); |
| 67 | 172x |
dims[0] = this->data_observed_values->get_imax(); |
| 68 | 172x |
dims[1] = this->data_observed_values->get_jmax(); |
| 69 |
} |
|
| 70 | ||
| 71 |
// setup vector for recording the log probability density function values |
|
| 72 | 907x |
this->lpdf = static_cast<Type>(0.0); /**< total log probability mass |
| 73 |
contribution of the distribution */ |
|
| 74 | 907x |
this->lpdf_vec.resize(dims[0] * dims[1]); |
| 75 | 907x |
std::fill(this->lpdf_vec.begin(), this->lpdf_vec.end(), 0); |
| 76 | 907x |
size_t lpdf_vec_idx = 0; /**< index for lpdf_vec vector */ |
| 77 |
// Dimension checks |
|
| 78 | 907x |
if (this->input_type == "data") {
|
| 79 | 902x |
if (this->data_expected_values) {
|
| 80 | 902x |
if (dims[0] * dims[1] != this->data_expected_values->size()) {
|
| 81 | ! |
throw std::invalid_argument( |
| 82 |
"MultinomialLPDF: Vector index out of bounds. The dimension of " |
|
| 83 |
"the " |
|
| 84 |
"number of rows times the number of columns is of size " + |
|
| 85 | ! |
fims::to_string(dims[0] * dims[1]) + |
| 86 |
" and the expected vector is of size " + |
|
| 87 | ! |
fims::to_string(this->data_expected_values->size())); |
| 88 |
} |
|
| 89 |
} |
|
| 90 |
} else {
|
|
| 91 |
if (dims[0] * dims[1] != this->observed_values.size()) {
|
|
| 92 |
throw std::invalid_argument( |
|
| 93 |
"MultinomialLPDF: Vector index out of bounds. The dimension of the " |
|
| 94 |
"number of rows times the number of columns is of size " + |
|
| 95 |
fims::to_string(dims[0] * dims[1]) + |
|
| 96 |
" and the observed vector is of size " + |
|
| 97 |
fims::to_string(this->observed_values.size())); |
|
| 98 |
} |
|
| 99 |
if (this->observed_values.size() != this->expected_values.size()) {
|
|
| 100 |
throw std::invalid_argument( |
|
| 101 |
"MultinomialLPDF: Vector index out of bounds. The dimension of the " |
|
| 102 |
"observed vector of size " + |
|
| 103 |
fims::to_string(this->observed_values.size()) + |
|
| 104 |
" and the expected vector is of size " + |
|
| 105 |
fims::to_string(this->expected_values.size())); |
|
| 106 |
} |
|
| 107 |
} |
|
| 108 | ||
| 109 | 29068x |
for (size_t i = 0; i < dims[0]; i++) {
|
| 110 |
// for each row, create new observed_values and prob vectors |
|
| 111 | 28163x |
fims::Vector<Type> observed_values_vector; |
| 112 | 28163x |
fims::Vector<Type> prob_vector; |
| 113 | 28163x |
observed_values_vector.resize(dims[1]); |
| 114 | 28163x |
prob_vector.resize(dims[1]); |
| 115 | ||
| 116 |
// Skips the entire row if any values are NA |
|
| 117 | 28163x |
bool containsNA = false; |
| 118 | ||
| 119 |
#ifdef TMB_MODEL |
|
| 120 | 490336x |
for (size_t j = 0; j < dims[1]; j++) {
|
| 121 | 463306x |
if (this->input_type == "data") {
|
| 122 |
// if data, check if there are any NA values and skip lpdf calculation |
|
| 123 |
// for entire row if there are |
|
| 124 | 627540x |
if (this->get_observed(static_cast<size_t>(i), |
| 125 | 844420x |
static_cast<size_t>(j)) == |
| 126 | 463276x |
this->data_observed_values->na_value) {
|
| 127 | 1133x |
containsNA = true; |
| 128 | 1133x |
break; |
| 129 |
} |
|
| 130 | 462143x |
if (!containsNA) {
|
| 131 | 462143x |
size_t idx = (i * dims[1]) + j; |
| 132 | 462143x |
observed_values_vector[j] = this->get_observed(i, j); |
| 133 | 462143x |
prob_vector[j] = this->get_expected(idx); |
| 134 |
} |
|
| 135 |
} else {
|
|
| 136 |
// if not data (i.e. prior or process), use observed_values vector |
|
| 137 |
// instead of data_observed_values |
|
| 138 |
size_t idx = (i * dims[1]) + j; |
|
| 139 |
observed_values_vector[j] = this->get_observed(idx); |
|
| 140 |
prob_vector[j] = this->get_expected(idx); |
|
| 141 |
} |
|
| 142 |
} |
|
| 143 | ||
| 144 | 28163x |
if (!containsNA) {
|
| 145 | 27030x |
std::fill(this->lpdf_vec.begin() + lpdf_vec_idx, |
| 146 | 27030x |
this->lpdf_vec.begin() + lpdf_vec_idx + dims[1], |
| 147 | 54060x |
dmultinom(observed_values_vector.to_tmb(), |
| 148 |
prob_vector.to_tmb(), true)); |
|
| 149 | ||
| 150 | 27030x |
this->lpdf += this->lpdf_vec[lpdf_vec_idx]; |
| 151 |
} else {
|
|
| 152 | 1133x |
this->lpdf_vec[i] = 0; |
| 153 |
} |
|
| 154 | 28163x |
lpdf_vec_idx += dims[1]; |
| 155 |
/* |
|
| 156 |
if (this->simulate_flag) |
|
| 157 |
{
|
|
| 158 |
FIMS_SIMULATE_F(this->of) |
|
| 159 |
{
|
|
| 160 |
fims::Vector<Type> sim_observed; |
|
| 161 |
sim_observed.resize(dims[1]); |
|
| 162 |
sim_observed = rmultinom(prob_vector); |
|
| 163 |
sim_observed.resize(this->observed_values.size()); |
|
| 164 |
for (size_t j = 0; j < dims[1]; j++) |
|
| 165 |
{
|
|
| 166 |
idx = (i * dims[1]) + j; |
|
| 167 |
this->observed_values[idx] = sim_observed[j]; |
|
| 168 |
} |
|
| 169 |
} |
|
| 170 |
} |
|
| 171 |
*/ |
|
| 172 |
#endif |
|
| 173 |
} |
|
| 174 | ||
| 175 |
#ifdef TMB_MODEL |
|
| 176 |
#endif |
|
| 177 | 905x |
return (this->lpdf); |
| 178 |
} |
|
| 179 |
}; |
|
| 180 |
} // namespace fims_distributions |
|
| 181 |
#endif |
| 1 |
/** |
|
| 2 |
* @file normal_lpdf.hpp |
|
| 3 |
* @brief Implements the NormalLPDF distribution functor used by FIMS to |
|
| 4 |
* evaluate observation-level and total log-likelihood contributions under a |
|
| 5 |
* normal error model for data, priors, and random effects. |
|
| 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 |
* @copybrief normal_lpdf.hpp |
|
| 21 |
* |
|
| 22 |
* @details This implementation relies on [TMB's R-style `dnorm()` utility]( |
|
| 23 |
* https://kaskr.github.io/adcomp/group__R__style__distribution.html) for |
|
| 24 |
* normal log-density calculations. Specifically, when evaluating the normal |
|
| 25 |
* likelihood, observations are passed to `dnorm(..., give_log = true)` to |
|
| 26 |
* obtain log-density values. |
|
| 27 |
* |
|
| 28 |
* For `data` input, values equal to `na_value` are skipped and contribute zero |
|
| 29 |
* to the objective. Per-observation contributions are stored in `lpdf_vec`; |
|
| 30 |
* the summed total is returned by `evaluate()` and stored in `lpdf`. |
|
| 31 |
*/ |
|
| 32 |
template <typename Type> |
|
| 33 |
struct NormalLPDF : public DensityComponentBase<Type> {
|
|
| 34 |
/** |
|
| 35 |
* @brief The natural log of the standard deviation of the distribution. The |
|
| 36 |
* argument can be a vector or scalar, where the latter is referenced for |
|
| 37 |
* each instance through the use of |
|
| 38 |
* \ref fims::Vector::get_force_scalar(size_t) "get_force_scalar()". |
|
| 39 |
*/ |
|
| 40 |
fims::Vector<Type> log_sd; |
|
| 41 | ||
| 42 |
/** @brief Constructor. |
|
| 43 |
*/ |
|
| 44 | 158x |
NormalLPDF() : DensityComponentBase<Type>() {}
|
| 45 | ||
| 46 |
/** @brief Destructor. |
|
| 47 |
*/ |
|
| 48 | 79x |
virtual ~NormalLPDF() {}
|
| 49 | ||
| 50 |
/** |
|
| 51 |
* @brief Evaluates the normal log probability density function. |
|
| 52 |
* @details The following equation is normal probability density function, |
|
| 53 |
* and thus, the log of it evaluated: |
|
| 54 |
* \f[ |
|
| 55 |
* f(x) = |
|
| 56 |
* \frac{1}{\sigma\sqrt{2\pi}}\mathrm{exp}\Bigg(-\frac{(x-\mu)^2}{2\sigma^2}
|
|
| 57 |
* \Bigg), \f] where \f$\mu\f$ is the mean of the distribution and |
|
| 58 |
* \f$\sigma^2\f$ is the variance. |
|
| 59 |
*/ |
|
| 60 | 618x |
virtual const Type evaluate() {
|
| 61 |
// set vector size based on input type (prior, process, or data) |
|
| 62 | 618x |
size_t n_x = this->get_n_x(); |
| 63 |
// get expected value vector size |
|
| 64 | 618x |
size_t n_expected = this->get_n_expected(); |
| 65 |
// setup vector for recording the log probability density function values |
|
| 66 | 618x |
this->lpdf_vec.resize(n_x); |
| 67 | 618x |
std::fill(this->lpdf_vec.begin(), this->lpdf_vec.end(), |
| 68 | 618x |
static_cast<Type>(0)); |
| 69 | 618x |
this->lpdf = static_cast<Type>(0); |
| 70 | ||
| 71 |
// Dimension checks |
|
| 72 | 618x |
if (n_x != n_expected) {
|
| 73 | 22x |
if (n_expected == 1) {
|
| 74 | ! |
n_expected = n_x; |
| 75 | 22x |
} else if (n_x > n_expected) {
|
| 76 | ! |
n_x = n_expected; |
| 77 |
} |
|
| 78 |
} |
|
| 79 | ||
| 80 | 255x |
if (this->log_sd.size() > 1 && n_x != this->log_sd.size()) {
|
| 81 | 2x |
throw std::invalid_argument( |
| 82 |
"NormalLPDF::Vector index out of bounds. The size of observed data " |
|
| 83 |
"does not equal the size of the log_sd vector. The observed data " |
|
| 84 |
"vector is of size " + |
|
| 85 |
fims::to_string(n_x) + " and the log_sd vector is of size " + |
|
| 86 |
fims::to_string(this->log_sd.size())); |
|
| 87 |
} |
|
| 88 | ||
| 89 | 18576x |
for (size_t i = 0; i < n_x; i++) {
|
| 90 |
#ifdef TMB_MODEL |
|
| 91 | 17962x |
if (this->input_type == "data") {
|
| 92 |
// if data, check if there are any NA values and skip lpdf calculation |
|
| 93 |
// if there are |
|
| 94 | ! |
if (this->get_observed(i) != this->data_observed_values->na_value) {
|
| 95 | ! |
this->lpdf_vec[i] = |
| 96 | ! |
dnorm(this->get_observed(i), this->get_expected(i), |
| 97 | ! |
fims_math::exp(log_sd.get_force_scalar(i)), true); |
| 98 |
} else {
|
|
| 99 | ! |
this->lpdf_vec[i] = 0; |
| 100 |
} |
|
| 101 |
// if not data (i.e. prior or process), use x vector instead of |
|
| 102 |
// observed_values |
|
| 103 |
} else {
|
|
| 104 | 17962x |
this->lpdf_vec[i] = |
| 105 | 17962x |
dnorm(this->get_observed(i), this->get_expected(i), |
| 106 | 17962x |
fims_math::exp(log_sd.get_force_scalar(i)), true); |
| 107 |
} |
|
| 108 | 17962x |
this->lpdf += this->lpdf_vec[i]; |
| 109 | 17962x |
if (this->simulate_flag) {
|
| 110 | ! |
FIMS_SIMULATE_F(this->of) {
|
| 111 | ! |
if (this->input_type == "data") {
|
| 112 | ! |
this->data_observed_values->at(i) = |
| 113 | ! |
rnorm(this->get_expected(i), |
| 114 | ! |
fims_math::exp(log_sd.get_force_scalar(i))); |
| 115 |
} |
|
| 116 | ! |
if (this->input_type == "random_effects") {
|
| 117 | ! |
(*this->re)[i] = rnorm(this->get_expected(i), |
| 118 | ! |
fims_math::exp(log_sd.get_force_scalar(i))); |
| 119 |
} |
|
| 120 | ! |
if (this->input_type == "prior") {
|
| 121 | ! |
(*(this->priors[i]))[0] = |
| 122 | ! |
rnorm(this->get_expected(i), |
| 123 | ! |
fims_math::exp(log_sd.get_force_scalar(i))); |
| 124 |
} |
|
| 125 |
} |
|
| 126 |
} |
|
| 127 |
#endif |
|
| 128 |
/* osa not working yet |
|
| 129 |
if(osa_flag){//data observation type implements osa residuals
|
|
| 130 |
//code for osa cdf method |
|
| 131 |
this->lpdf_vec[i] = this->keep.cdf_lower[i] * log( |
|
| 132 |
pnorm(this->observed_values[i], this->get_expected(i), sd[i]) ); |
|
| 133 |
this->lpdf_vec[i] = this->keep.cdf_upper[i] * log( 1.0 - |
|
| 134 |
pnorm(this->observed_values[i], this->get_expected(i), sd[i]) ); |
|
| 135 |
} */ |
|
| 136 |
} |
|
| 137 |
#ifdef TMB_MODEL |
|
| 138 | 614x |
vector<Type> normal_observed_values = this->observed_values.to_tmb(); |
| 139 |
#endif |
|
| 140 | 614x |
return (this->lpdf); |
| 141 |
} |
|
| 142 |
}; |
|
| 143 | ||
| 144 |
} // namespace fims_distributions |
|
| 145 |
#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 | 16320x |
vector<Type> ADREPORTvector(vector<vector<Type> > x) {
|
| 45 | 16320x |
int outer_dim = x.size(); |
| 46 | 16320x |
int dim = 0; |
| 47 | 41760x |
for (int i = 0; i < outer_dim; i++) {
|
| 48 | 25440x |
dim += x(i).size(); |
| 49 |
} |
|
| 50 | 16320x |
vector<Type> res(dim); |
| 51 | 16320x |
int idx = 0; |
| 52 | 41760x |
for (int i = 0; i < outer_dim; i++) {
|
| 53 | 25440x |
int inner_dim = x(i).size(); |
| 54 | 6019800x |
for (int j = 0; j < inner_dim; j++) {
|
| 55 | 5994360x |
res(idx) = x(i)(j); |
| 56 | 5994360x |
idx += 1; |
| 57 |
} |
|
| 58 |
} |
|
| 59 | 16320x |
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 | 42x |
void init_logging() {
|
| 28 | 42x |
std::signal(SIGSEGV, &fims::WriteAtExit); |
| 29 | 42x |
std::signal(SIGINT, &fims::WriteAtExit); |
| 30 | 42x |
std::signal(SIGABRT, &fims::WriteAtExit); |
| 31 | 42x |
std::signal(SIGFPE, &fims::WriteAtExit); |
| 32 | 42x |
std::signal(SIGILL, &fims::WriteAtExit); |
| 33 | 42x |
std::signal(SIGTERM, &fims::WriteAtExit); |
| 34 |
} |
|
| 35 | ||
| 36 |
/** |
|
| 37 |
* @brief Initialize and construct the FIMS model using TMB. |
|
| 38 |
* |
|
| 39 |
* @details |
|
| 40 |
* This function sets up the core C++ objects required for building the |
|
| 41 |
* objective function with TMB before optimizing a FIMS model. The main steps |
|
| 42 |
* of the function are as follows: |
|
| 43 |
* - The logging system is initialized and any existing model structures are |
|
| 44 |
* cleared, ensuring a clean slate for a new model. |
|
| 45 |
* - It resets and prepares the main model information objects |
|
| 46 |
* (fims_info::Information singletons), ensuring all internal data and |
|
| 47 |
* settings are cleared and ready for a new model run. This step is essential |
|
| 48 |
* for both initializing the model structure and avoiding conflicts from |
|
| 49 |
* previous runs. |
|
| 50 |
* - It iterates over all registered FIMS interface objects and adds them to |
|
| 51 |
* the TMB model context. |
|
| 52 |
* - After all of the objects are registered, it calls |
|
| 53 |
* fims_info::Information::CreateModel() and |
|
| 54 |
* fims_info::Information::CheckModel() on the base fims_info::Information |
|
| 55 |
* object. |
|
| 56 |
* - It instantiates the singleton fims_model::Model object which represents |
|
| 57 |
* the constructed TMB model. |
|
| 58 |
* |
|
| 59 |
* Typically the average user does not interact with this function because it |
|
| 60 |
* is called within <a href = |
|
| 61 |
* "https://noaa-fims.github.io/FIMS/reference/initialize_fims.html">`initialize_fims`</a>. |
|
| 62 |
* |
|
| 63 |
* @see init_logging() |
|
| 64 |
* @see fims_info::Information::Clear() |
|
| 65 |
* @see fims_info::Information::CreateModel() |
|
| 66 |
* @see fims_info::Information::CheckModel() |
|
| 67 |
* @see fims_info::Information::GetInstance() |
|
| 68 |
* @see <a href = |
|
| 69 |
* "https://noaa-fims.github.io/FIMS/reference/initialize_fims.html" |
|
| 70 |
* target="_blank">`initialize_fims()`</a> |
|
| 71 |
* @return A boolean is returned, where true indicates that the model was |
|
| 72 |
* successfully created. |
|
| 73 |
*/ |
|
| 74 | 42x |
bool CreateTMBModel() {
|
| 75 | 42x |
init_logging(); |
| 76 | ||
| 77 |
// clear first |
|
| 78 |
// base model |
|
| 79 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> info0 = |
|
| 80 | 42x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 81 | 42x |
info0->Clear(); |
| 82 | ||
| 83 |
std::shared_ptr<fims_info::Information<TMBAD_FIMS_TYPE>> info = |
|
| 84 | 42x |
fims_info::Information<TMBAD_FIMS_TYPE>::GetInstance(); |
| 85 | 42x |
info->Clear(); |
| 86 | ||
| 87 | 42x |
FIMS_INFO_LOG( |
| 88 |
"Adding FIMS objects to TMB, " + |
|
| 89 |
fims::to_string(FIMSRcppInterfaceBase::fims_interface_objects.size()) + |
|
| 90 |
" objects"); |
|
| 91 | 719x |
for (size_t i = 0; i < FIMSRcppInterfaceBase::fims_interface_objects.size(); |
| 92 |
i++) {
|
|
| 93 | 679x |
FIMSRcppInterfaceBase::fims_interface_objects[i]->add_to_fims_tmb(); |
| 94 |
} |
|
| 95 | ||
| 96 |
// base model |
|
| 97 | 40x |
info0->CreateModel(); |
| 98 | 40x |
info0->CheckModel(); |
| 99 | ||
| 100 | 40x |
info->CreateModel(); |
| 101 | ||
| 102 |
// instantiate the model? TODO: Ask Matthew what this does |
|
| 103 |
std::shared_ptr<fims_model::Model<TMB_FIMS_REAL_TYPE>> m0 = |
|
| 104 | 40x |
fims_model::Model<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 105 | ||
| 106 | 40x |
return true; |
| 107 |
} |
|
| 108 | ||
| 109 |
/* Dictionary block for shared documentation. |
|
| 110 |
[details_set_x_parameters] |
|
| 111 |
Updates the internal parameter values for the model base of type |
|
| 112 |
TMB_FIMS_REAL_TYPE. It is typically called before finalize() or |
|
| 113 |
@ref CatchAtAgeInterface::to_json "`get_output()`" to ensure the correct |
|
| 114 |
values are used because TMB doesn't always keep the updated parameters in |
|
| 115 |
the "double" version of the tape. So we need to update those first. |
|
| 116 |
\n\n |
|
| 117 |
Usage example in R: |
|
| 118 |
\code{.R}
|
|
| 119 |
set_fixed_parameters(c(1, 2, 3)) |
|
| 120 |
set_random_parameters(c(1, 2, 3)) |
|
| 121 |
catch_at_age$get_output() |
|
| 122 |
\endcode |
|
| 123 |
[details_set_x_parameters] |
|
| 124 |
*/ |
|
| 125 |
/* Dictionary block for shared documentation. |
|
| 126 |
[param_par] |
|
| 127 |
@param par A vector of parameter values. |
|
| 128 |
[param_par] |
|
| 129 |
*/ |
|
| 130 | ||
| 131 |
/** |
|
| 132 |
* @brief Update fixed parameters in the tape, so the output is correct. |
|
| 133 |
* @details @snippet{doc} this details_set_x_parameters
|
|
| 134 |
* @snippet{doc} this param_par
|
|
| 135 |
* @see set_random_parameters() |
|
| 136 |
*/ |
|
| 137 | 19x |
void set_fixed_parameters(Rcpp::NumericVector par) {
|
| 138 |
// base model |
|
| 139 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> info0 = |
|
| 140 | 19x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 141 | ||
| 142 | 939x |
for (size_t i = 0; i < info0->fixed_effects_parameters.size(); i++) {
|
| 143 | 920x |
*info0->fixed_effects_parameters[i] = par[i]; |
| 144 |
} |
|
| 145 |
} |
|
| 146 | ||
| 147 |
/** |
|
| 148 |
* @brief Gets the fixed parameters vector object. |
|
| 149 |
* |
|
| 150 |
* @return Rcpp::NumericVector |
|
| 151 |
*/ |
|
| 152 | 36x |
Rcpp::NumericVector get_fixed_parameters_vector() {
|
| 153 |
// base model |
|
| 154 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> info0 = |
|
| 155 | 36x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 156 | ||
| 157 | 36x |
Rcpp::NumericVector p; |
| 158 | ||
| 159 | 1506x |
for (size_t i = 0; i < info0->fixed_effects_parameters.size(); i++) {
|
| 160 | 1470x |
p.push_back(*info0->fixed_effects_parameters[i]); |
| 161 |
} |
|
| 162 | ||
| 163 | 72x |
return p; |
| 164 |
} |
|
| 165 | ||
| 166 |
/** |
|
| 167 |
* @brief Update random effect parameters in the tape, so the output is correct. |
|
| 168 |
* @details @snippet{doc} this details_set_x_parameters
|
|
| 169 |
* @snippet{doc} this param_par
|
|
| 170 |
* @see set_fixed_parameters() |
|
| 171 |
*/ |
|
| 172 | ! |
void set_random_parameters(Rcpp::NumericVector par) {
|
| 173 |
// base model |
|
| 174 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> info0 = |
|
| 175 | ! |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 176 | ||
| 177 | ! |
for (size_t i = 0; i < info0->random_effects_parameters.size(); i++) {
|
| 178 | ! |
*info0->random_effects_parameters[i] = par[i]; |
| 179 |
} |
|
| 180 |
} |
|
| 181 | ||
| 182 |
/** |
|
| 183 |
* @brief Gets the random parameters vector object. |
|
| 184 |
* |
|
| 185 |
* @return Rcpp::NumericVector |
|
| 186 |
*/ |
|
| 187 | 36x |
Rcpp::NumericVector get_random_parameters_vector() {
|
| 188 |
// base model |
|
| 189 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> d0 = |
|
| 190 | 36x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 191 | ||
| 192 | 36x |
Rcpp::NumericVector p; |
| 193 | ||
| 194 | 481x |
for (size_t i = 0; i < d0->random_effects_parameters.size(); i++) {
|
| 195 | 445x |
p.push_back(*d0->random_effects_parameters[i]); |
| 196 |
} |
|
| 197 | ||
| 198 | 72x |
return p; |
| 199 |
} |
|
| 200 | ||
| 201 |
/** |
|
| 202 |
* @brief Gets the parameter names object. |
|
| 203 |
* |
|
| 204 |
* @param pars |
|
| 205 |
* @return Rcpp::List |
|
| 206 |
*/ |
|
| 207 | 27x |
Rcpp::List get_parameter_names(Rcpp::List pars) {
|
| 208 |
// base model |
|
| 209 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> d0 = |
|
| 210 | 27x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 211 | ||
| 212 | 54x |
pars.attr("names") = d0->parameter_names;
|
| 213 | ||
| 214 | 54x |
return pars; |
| 215 |
} |
|
| 216 | ||
| 217 |
/** |
|
| 218 |
* @brief Gets the random effects names object. |
|
| 219 |
* |
|
| 220 |
* @param pars |
|
| 221 |
* @return Rcpp::List |
|
| 222 |
*/ |
|
| 223 | 13x |
Rcpp::List get_random_names(Rcpp::List pars) {
|
| 224 |
// base model |
|
| 225 |
std::shared_ptr<fims_info::Information<TMB_FIMS_REAL_TYPE>> d0 = |
|
| 226 | 13x |
fims_info::Information<TMB_FIMS_REAL_TYPE>::GetInstance(); |
| 227 | ||
| 228 | 26x |
pars.attr("names") = d0->random_effects_names;
|
| 229 | ||
| 230 | 26x |
return pars; |
| 231 |
} |
|
| 232 | ||
| 233 |
/** |
|
| 234 |
* @brief Clears the internal objects. |
|
| 235 |
* |
|
| 236 |
* @tparam Type |
|
| 237 |
*/ |
|
| 238 |
template <typename Type> |
|
| 239 | 600x |
void clear_internal() {
|
| 240 | 600x |
std::shared_ptr<fims_info::Information<Type>> d0 = |
| 241 |
fims_info::Information<Type>::GetInstance(); |
|
| 242 | 600x |
d0->Clear(); |
| 243 |
} |
|
| 244 | ||
| 245 |
/** |
|
| 246 |
* @brief Clears the vector of independent variables. |
|
| 247 |
*/ |
|
| 248 | 150x |
void clear() {
|
| 249 | 300x |
FIMS_INFO_LOG("Clearing FIMS objects from interface stack");
|
| 250 |
// rcpp_interface_base.hpp |
|
| 251 | 150x |
FIMSRcppInterfaceBase::fims_interface_objects.clear(); |
| 252 | ||
| 253 |
// Parameter and ParameterVector |
|
| 254 | 150x |
Parameter::id_g = 1; |
| 255 | 150x |
ParameterVector::id_g = 1; |
| 256 |
// rcpp_data.hpp |
|
| 257 | 150x |
DataInterfaceBase::id_g = 1; |
| 258 | 150x |
DataInterfaceBase::live_objects.clear(); |
| 259 | ||
| 260 | 150x |
AgeCompDataInterface::id_g = 1; |
| 261 | 150x |
AgeCompDataInterface::live_objects.clear(); |
| 262 | ||
| 263 | 150x |
LengthCompDataInterface::id_g = 1; |
| 264 | 150x |
LengthCompDataInterface::live_objects.clear(); |
| 265 | ||
| 266 | 150x |
LandingsDataInterface::id_g = 1; |
| 267 | 150x |
LandingsDataInterface::live_objects.clear(); |
| 268 | ||
| 269 | 150x |
IndexDataInterface::id_g = 1; |
| 270 | 150x |
IndexDataInterface::live_objects.clear(); |
| 271 | ||
| 272 |
// rcpp_fleets.hpp |
|
| 273 | 150x |
FleetInterfaceBase::id_g = 1; |
| 274 | 150x |
FleetInterfaceBase::live_objects.clear(); |
| 275 | ||
| 276 | 150x |
FleetInterface::id_g = 1; |
| 277 | 150x |
FleetInterface::live_objects.clear(); |
| 278 | ||
| 279 |
// rcpp_growth.hpp |
|
| 280 | 150x |
GrowthInterfaceBase::id_g = 1; |
| 281 | 150x |
GrowthInterfaceBase::live_objects.clear(); |
| 282 | ||
| 283 | 150x |
EWAAGrowthInterface::id_g = 1; |
| 284 | 150x |
EWAAGrowthInterface::live_objects.clear(); |
| 285 | ||
| 286 |
// rcpp_maturity.hpp |
|
| 287 | 150x |
MaturityInterfaceBase::id_g = 1; |
| 288 | 150x |
MaturityInterfaceBase::live_objects.clear(); |
| 289 | ||
| 290 | 150x |
LogisticMaturityInterface::id_g = 1; |
| 291 | 150x |
LogisticMaturityInterface::live_objects.clear(); |
| 292 | ||
| 293 |
// rcpp_population.hpp |
|
| 294 | 150x |
PopulationInterfaceBase::id_g = 1; |
| 295 | 150x |
PopulationInterfaceBase::live_objects.clear(); |
| 296 | ||
| 297 | 150x |
PopulationInterface::id_g = 1; |
| 298 | 150x |
PopulationInterface::live_objects.clear(); |
| 299 | ||
| 300 |
// rcpp_recruitment.hpp |
|
| 301 | 150x |
RecruitmentInterfaceBase::id_g = 1; |
| 302 | 150x |
RecruitmentInterfaceBase::live_objects.clear(); |
| 303 | ||
| 304 | 150x |
BevertonHoltRecruitmentInterface::id_g = 1; |
| 305 | 150x |
BevertonHoltRecruitmentInterface::live_objects.clear(); |
| 306 | ||
| 307 |
// rcpp_selectivity.hpp |
|
| 308 | 150x |
SelectivityInterfaceBase::id_g = 1; |
| 309 | 150x |
SelectivityInterfaceBase::live_objects.clear(); |
| 310 | ||
| 311 | 150x |
LogisticSelectivityInterface::id_g = 1; |
| 312 | 150x |
LogisticSelectivityInterface::live_objects.clear(); |
| 313 | ||
| 314 | 150x |
DoubleLogisticSelectivityInterface::id_g = 1; |
| 315 | 150x |
DoubleLogisticSelectivityInterface::live_objects.clear(); |
| 316 | ||
| 317 |
// rcpp_distribution.hpp |
|
| 318 | 150x |
DistributionsInterfaceBase::id_g = 1; |
| 319 | 150x |
DistributionsInterfaceBase::live_objects.clear(); |
| 320 | ||
| 321 | 150x |
DnormDistributionsInterface::id_g = 1; |
| 322 | 150x |
DnormDistributionsInterface::live_objects.clear(); |
| 323 | ||
| 324 | 150x |
DlnormDistributionsInterface::id_g = 1; |
| 325 | 150x |
DlnormDistributionsInterface::live_objects.clear(); |
| 326 | ||
| 327 | 150x |
DmultinomDistributionsInterface::id_g = 1; |
| 328 | 150x |
DmultinomDistributionsInterface::live_objects.clear(); |
| 329 | ||
| 330 | 150x |
FisheryModelInterfaceBase::id_g = 1; |
| 331 | 150x |
FisheryModelInterfaceBase::live_objects.clear(); |
| 332 | ||
| 333 | 150x |
clear_internal<TMB_FIMS_REAL_TYPE>(); |
| 334 | 150x |
clear_internal<TMBAD_FIMS_TYPE>(); |
| 335 | ||
| 336 | 150x |
fims::FIMSLog::fims_log->clear(); |
| 337 |
} |
|
| 338 | ||
| 339 |
/** |
|
| 340 |
* @brief Gets the log entries as a string in JSON format. |
|
| 341 |
*/ |
|
| 342 | ! |
std::string get_log() { return fims::FIMSLog::fims_log->get_log(); }
|
| 343 | ||
| 344 |
/** |
|
| 345 |
* @brief Gets the error entries from the log as a string in JSON format. |
|
| 346 |
*/ |
|
| 347 | ! |
std::string get_log_errors() { return fims::FIMSLog::fims_log->get_errors(); }
|
| 348 | ||
| 349 |
/** |
|
| 350 |
* @brief Gets the warning entries from the log as a string in JSON format. |
|
| 351 |
*/ |
|
| 352 | ! |
std::string get_log_warnings() {
|
| 353 | ! |
return fims::FIMSLog::fims_log->get_warnings(); |
| 354 |
} |
|
| 355 | ||
| 356 |
/** |
|
| 357 |
* @brief Gets the info entries from the log as a string in JSON format. |
|
| 358 |
*/ |
|
| 359 | ! |
std::string get_log_info() { return fims::FIMSLog::fims_log->get_info(); }
|
| 360 | ||
| 361 |
/** |
|
| 362 |
* @brief If true, writes the log on exit. |
|
| 363 |
*/ |
|
| 364 | ! |
void write_log(bool write) {
|
| 365 | ! |
FIMS_INFO_LOG("Setting FIMS write log: " + fims::to_string(write));
|
| 366 | ! |
fims::FIMSLog::fims_log->write_on_exit = write; |
| 367 |
} |
|
| 368 | ||
| 369 |
/** |
|
| 370 |
* @brief Sets the path for the log file to be written to. |
|
| 371 |
*/ |
|
| 372 | ! |
void set_log_path(const std::string &path) {
|
| 373 | ! |
FIMS_INFO_LOG("Setting FIMS log path: " + path);
|
| 374 | ! |
fims::FIMSLog::fims_log->set_path(path); |
| 375 |
} |
|
| 376 | ||
| 377 |
/** |
|
| 378 |
* @brief If true, throws a runtime exception when an error is logged. |
|
| 379 |
*/ |
|
| 380 | ! |
void set_log_throw_on_error(bool throw_on_error) {
|
| 381 | ! |
fims::FIMSLog::fims_log->throw_on_error = throw_on_error; |
| 382 |
} |
|
| 383 | ||
| 384 |
/** |
|
| 385 |
* @brief Adds an info entry to the log from the R environment. |
|
| 386 |
*/ |
|
| 387 | ! |
void log_info(std::string log_entry) {
|
| 388 | ! |
fims::FIMSLog::fims_log->info_message(log_entry, -1, "R_env", |
| 389 |
"R_script_entry"); |
|
| 390 |
} |
|
| 391 | ||
| 392 |
/** |
|
| 393 |
* @brief Adds a warning entry to the log from the R environment. |
|
| 394 |
*/ |
|
| 395 | ! |
void log_warning(std::string log_entry) {
|
| 396 | ! |
fims::FIMSLog::fims_log->warning_message(log_entry, -1, "R_env", |
| 397 |
"R_script_entry"); |
|
| 398 |
} |
|
| 399 | ||
| 400 |
/** |
|
| 401 |
* @brief Escapes quotations. |
|
| 402 |
* |
|
| 403 |
* @param input A string. |
|
| 404 |
* @return std::string |
|
| 405 |
*/ |
|
| 406 | ! |
std::string escapeQuotes(const std::string &input) {
|
| 407 | ! |
std::string result = input; |
| 408 | ! |
std::string search = "\""; |
| 409 | ! |
std::string replace = "\\\""; |
| 410 | ||
| 411 |
// Find each occurrence of `"` and replace it with `\"` |
|
| 412 | ! |
size_t pos = result.find(search); |
| 413 | ! |
while (pos != std::string::npos) {
|
| 414 | ! |
result.replace(pos, search.size(), replace); |
| 415 | ! |
pos = result.find(search, |
| 416 | ! |
pos + replace.size()); // Move past the replaced position |
| 417 |
} |
|
| 418 | ! |
return result; |
| 419 |
} |
|
| 420 | ||
| 421 |
/** |
|
| 422 |
* @brief Adds a error entry to the log from the R environment. |
|
| 423 |
*/ |
|
| 424 | ! |
void log_error(std::string log_entry) {
|
| 425 | ! |
std::stringstream ss; |
| 426 | ! |
ss << "capture.output(traceback(4))"; |
| 427 |
SEXP expression, result; |
|
| 428 |
ParseStatus status; |
|
| 429 | ||
| 430 | ! |
PROTECT(expression = R_ParseVector(Rf_mkString(ss.str().c_str()), 1, &status, |
| 431 |
R_NilValue)); |
|
| 432 | ! |
if (status != PARSE_OK) {
|
| 433 | ! |
Rcpp::Rcout << "Error parsing expression" << std::endl; |
| 434 | ! |
UNPROTECT(1); |
| 435 |
} |
|
| 436 | ! |
Rcpp::Rcout << "before call."; |
| 437 | ! |
PROTECT(result = Rf_eval(VECTOR_ELT(expression, 0), R_GlobalEnv)); |
| 438 | ! |
Rcpp::Rcout << "after call."; |
| 439 | ! |
UNPROTECT(2); |
| 440 | ! |
std::stringstream ss_ret; |
| 441 | ! |
ss_ret << "traceback: "; |
| 442 | ! |
for (int j = 0; j < LENGTH(result); j++) {
|
| 443 | ! |
std::string str(CHAR(STRING_ELT(result, j))); |
| 444 | ! |
ss_ret << escapeQuotes(str) << "\\n"; |
| 445 |
} |
|
| 446 | ||
| 447 |
std::string ret = |
|
| 448 | ! |
ss_ret.str(); //"find error";//Rcpp::as<std::string>(result); |
| 449 | ||
| 450 | ! |
fims::FIMSLog::fims_log->error_message(log_entry, -1, "R_env", ret.c_str()); |
| 451 |
} |
|
| 452 |
#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 | 197x |
DataInterfaceBase() {
|
| 49 | 197x |
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 | 197x |
DataInterfaceBase(const DataInterfaceBase &other) |
| 61 | 394x |
: observed_data(other.observed_data), |
| 62 | 197x |
uncertainty(other.uncertainty), |
| 63 | 394x |
id(other.id) {}
|
| 64 | ||
| 65 |
/** |
|
| 66 |
* @brief The destructor. |
|
| 67 |
*/ |
|
| 68 | 394x |
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 | 69x |
AgeCompDataInterface(int ymax = 0, int amax = 0) : DataInterfaceBase() {
|
| 117 | 69x |
this->amax = amax; |
| 118 | 69x |
this->ymax = ymax; |
| 119 | 69x |
this->age_comp_data.resize(amax * ymax); |
| 120 | 69x |
this->uncertainty.resize(amax * ymax); |
| 121 | 69x |
DataInterfaceBase::live_objects[this->id] = |
| 122 | 138x |
std::make_shared<AgeCompDataInterface>(*this); |
| 123 | 69x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 124 | 69x |
DataInterfaceBase::live_objects[this->id]); |
| 125 |
} |
|
| 126 | ||
| 127 |
/** |
|
| 128 |
* @brief Construct a new Age Comp Data Interface object |
|
| 129 |
* |
|
| 130 |
* @param other |
|
| 131 |
*/ |
|
| 132 | 69x |
AgeCompDataInterface(const AgeCompDataInterface &other) |
| 133 | 69x |
: DataInterfaceBase(other), |
| 134 | 69x |
amax(other.amax), |
| 135 | 69x |
ymax(other.ymax), |
| 136 | 69x |
age_comp_data(other.age_comp_data), |
| 137 | 138x |
uncertainty(other.uncertainty) {}
|
| 138 | ||
| 139 |
/** |
|
| 140 |
* @brief The destructor. |
|
| 141 |
*/ |
|
| 142 | 414x |
virtual ~AgeCompDataInterface() {}
|
| 143 | ||
| 144 |
/** |
|
| 145 |
* @brief Gets the ID of the interface base object. |
|
| 146 |
* @return The ID. |
|
| 147 |
*/ |
|
| 148 | 62x |
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 | 44x |
virtual std::string to_json() {
|
| 158 | 44x |
std::stringstream ss; |
| 159 | ||
| 160 | 44x |
ss << "{\n";
|
| 161 | 44x |
ss << " \"name\": \"AgeComp\",\n"; |
| 162 | 44x |
ss << " \"id\":" << this->id << ",\n"; |
| 163 | 44x |
ss << " \"type\": \"data\",\n"; |
| 164 | 44x |
ss << " \"dimensionality\": {\n";
|
| 165 | 44x |
ss << " \"header\": [" << "\"n_ages\", \"n_years\"" << "],\n"; |
| 166 | 44x |
ss << " \"dimensions\": [" << amax << ", " << ymax << "]\n},\n"; |
| 167 | 44x |
ss << " \"value\": ["; |
| 168 | 16440x |
for (size_t i = 0; i < age_comp_data.size() - 1; i++) {
|
| 169 | 16396x |
ss << age_comp_data[i] << ", "; |
| 170 |
} |
|
| 171 | 44x |
ss << age_comp_data[age_comp_data.size() - 1] << "],\n"; |
| 172 | 44x |
ss << "\"uncertainty\":[ "; |
| 173 | 16440x |
for (size_t i = 0; i < uncertainty.size() - 1; i++) {
|
| 174 | 16396x |
ss << uncertainty[i] << ", "; |
| 175 |
} |
|
| 176 | 44x |
ss << uncertainty[uncertainty.size() - 1] << "]\n"; |
| 177 | 44x |
ss << "}"; |
| 178 | 88x |
return ss.str(); |
| 179 |
} |
|
| 180 | ||
| 181 |
#ifdef TMB_MODEL |
|
| 182 | ||
| 183 |
template <typename Type> |
|
| 184 | 232x |
bool add_to_fims_tmb_internal() {
|
| 185 | 232x |
std::shared_ptr<fims_data_object::DataObject<Type>> age_comp_data = |
| 186 | 232x |
std::make_shared<fims_data_object::DataObject<Type>>(this->ymax, |
| 187 | 232x |
this->amax); |
| 188 | ||
| 189 | 232x |
age_comp_data->id = this->id; |
| 190 | 7392x |
for (int y = 0; y < ymax; y++) {
|
| 191 | 93080x |
for (int a = 0; a < amax; a++) {
|
| 192 | 85920x |
int i_age_year = y * amax + a; |
| 193 | 85920x |
age_comp_data->at(y, a) = this->age_comp_data[i_age_year]; |
| 194 | 85920x |
age_comp_data->uncertainty[i_age_year] = this->uncertainty[i_age_year]; |
| 195 |
} |
|
| 196 |
} |
|
| 197 | ||
| 198 | 232x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 199 |
fims_info::Information<Type>::GetInstance(); |
|
| 200 | ||
| 201 | 232x |
info->data_objects[this->id] = age_comp_data; |
| 202 | ||
| 203 | 232x |
return true; |
| 204 |
} |
|
| 205 | ||
| 206 |
/** |
|
| 207 |
* @brief Adds the parameters to the TMB model. |
|
| 208 |
* @return A boolean of true. |
|
| 209 |
*/ |
|
| 210 | 58x |
virtual bool add_to_fims_tmb() {
|
| 211 | 58x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 212 | 58x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 213 | ||
| 214 | 58x |
return true; |
| 215 |
} |
|
| 216 | ||
| 217 |
#endif |
|
| 218 |
}; |
|
| 219 | ||
| 220 |
/** |
|
| 221 |
* @brief The Rcpp interface for LengthComp to instantiate the object from R: |
|
| 222 |
* lcomp <- methods::new(LengthComp). |
|
| 223 |
*/ |
|
| 224 |
class LengthCompDataInterface : public DataInterfaceBase {
|
|
| 225 |
public: |
|
| 226 |
/** |
|
| 227 |
* @brief The first dimension of the data, which relates to the number of |
|
| 228 |
* length bins. |
|
| 229 |
*/ |
|
| 230 |
fims_int lmax = 0; |
|
| 231 |
/** |
|
| 232 |
* @brief The second dimension of the data, which relates to the number of |
|
| 233 |
* time steps or years. |
|
| 234 |
*/ |
|
| 235 |
fims_int ymax = 0; |
|
| 236 |
/** |
|
| 237 |
* @brief The vector of length-composition data that is being passed from R. |
|
| 238 |
*/ |
|
| 239 |
RealVector length_comp_data; |
|
| 240 |
/** |
|
| 241 |
* @brief The vector of length-composition uncertainty that is being passed |
|
| 242 |
* from R. |
|
| 243 |
*/ |
|
| 244 |
RealVector uncertainty; |
|
| 245 | ||
| 246 |
/** |
|
| 247 |
* @brief The constructor. |
|
| 248 |
*/ |
|
| 249 | 57x |
LengthCompDataInterface(int ymax = 0, int lmax = 0) : DataInterfaceBase() {
|
| 250 | 57x |
this->lmax = lmax; |
| 251 | 57x |
this->ymax = ymax; |
| 252 | 57x |
this->length_comp_data.resize(lmax * ymax); |
| 253 | 57x |
this->uncertainty.resize(lmax * ymax); |
| 254 | 57x |
DataInterfaceBase::live_objects[this->id] = |
| 255 | 114x |
std::make_shared<LengthCompDataInterface>(*this); |
| 256 | 57x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 257 | 57x |
DataInterfaceBase::live_objects[this->id]); |
| 258 |
} |
|
| 259 | ||
| 260 |
/** |
|
| 261 |
* @brief Construct a new Length Comp Data Interface object |
|
| 262 |
* |
|
| 263 |
* @param other |
|
| 264 |
*/ |
|
| 265 | 57x |
LengthCompDataInterface(const LengthCompDataInterface &other) |
| 266 | 57x |
: DataInterfaceBase(other), |
| 267 | 57x |
lmax(other.lmax), |
| 268 | 57x |
ymax(other.ymax), |
| 269 | 57x |
length_comp_data(other.length_comp_data), |
| 270 | 114x |
uncertainty(other.uncertainty) {}
|
| 271 | ||
| 272 |
/** |
|
| 273 |
* @brief The destructor. |
|
| 274 |
*/ |
|
| 275 | 342x |
virtual ~LengthCompDataInterface() {}
|
| 276 | ||
| 277 |
/** |
|
| 278 |
* @brief Gets the ID of the interface base object. |
|
| 279 |
* @return The ID. |
|
| 280 |
*/ |
|
| 281 | 56x |
virtual uint32_t get_id() { return this->id; }
|
| 282 | ||
| 283 |
/** |
|
| 284 |
* @brief Converts the data to json representation for the output. |
|
| 285 |
* @return A string is returned specifying that the module relates to the |
|
| 286 |
* data interface with length-composition data. It also returns the ID, the |
|
| 287 |
* rank of 2, the dimensions by printing ymax and lmax, followed by the data |
|
| 288 |
* values themselves. This string is formatted for a json file. |
|
| 289 |
*/ |
|
| 290 | 38x |
virtual std::string to_json() {
|
| 291 | 38x |
std::stringstream ss; |
| 292 | ||
| 293 | 38x |
ss << "{\n";
|
| 294 | 38x |
ss << " \"name\": \"LengthComp\",\n"; |
| 295 | 38x |
ss << " \"id\":" << this->id << ",\n"; |
| 296 | 38x |
ss << " \"type\": \"data\",\n"; |
| 297 | 38x |
ss << " \"dimensionality\": {\n";
|
| 298 | 38x |
ss << " \"header\": [" << "\"n_lengths\", \"n_years\"" << "],\n"; |
| 299 | 38x |
ss << " \"dimensions\": [" << lmax << ", " << ymax << "]\n},\n"; |
| 300 | 38x |
ss << " \"value\": ["; |
| 301 | 27370x |
for (size_t i = 0; i < length_comp_data.size() - 1; i++) {
|
| 302 | 27332x |
ss << length_comp_data[i] << ", "; |
| 303 |
} |
|
| 304 | 38x |
ss << length_comp_data[length_comp_data.size() - 1] << "],\n"; |
| 305 | 38x |
ss << "\"uncertainty\": [ "; |
| 306 | 27370x |
for (size_t i = 0; i < uncertainty.size() - 1; i++) {
|
| 307 | 27332x |
ss << uncertainty[i] << ", "; |
| 308 |
} |
|
| 309 | 38x |
ss << uncertainty[uncertainty.size() - 1] << "]\n"; |
| 310 | 38x |
ss << "}"; |
| 311 | 76x |
return ss.str(); |
| 312 |
} |
|
| 313 | ||
| 314 |
#ifdef TMB_MODEL |
|
| 315 |
template <typename Type> |
|
| 316 | 208x |
bool add_to_fims_tmb_internal() {
|
| 317 | 208x |
std::shared_ptr<fims_data_object::DataObject<Type>> length_comp_data = |
| 318 | 208x |
std::make_shared<fims_data_object::DataObject<Type>>(this->ymax, |
| 319 | 208x |
this->lmax); |
| 320 | 208x |
length_comp_data->id = this->id; |
| 321 | 6648x |
for (int y = 0; y < ymax; y++) {
|
| 322 | 154560x |
for (int l = 0; l < lmax; l++) {
|
| 323 | 148120x |
int i_length_year = y * lmax + l; |
| 324 | 148120x |
length_comp_data->at(y, l) = this->length_comp_data[i_length_year]; |
| 325 | 148120x |
length_comp_data->uncertainty[i_length_year] = |
| 326 |
this->uncertainty[i_length_year]; |
|
| 327 |
} |
|
| 328 |
} |
|
| 329 | 208x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 330 |
fims_info::Information<Type>::GetInstance(); |
|
| 331 | 208x |
info->data_objects[this->id] = length_comp_data; |
| 332 | 208x |
return true; |
| 333 |
} |
|
| 334 | ||
| 335 |
/** |
|
| 336 |
* @brief Adds the parameters to the TMB model. |
|
| 337 |
* @return A boolean of true. |
|
| 338 |
*/ |
|
| 339 | 52x |
virtual bool add_to_fims_tmb() {
|
| 340 | 52x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 341 | 52x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 342 | ||
| 343 | 52x |
return true; |
| 344 |
} |
|
| 345 |
#endif |
|
| 346 |
}; |
|
| 347 | ||
| 348 |
/** |
|
| 349 |
* @brief The Rcpp interface for Index to instantiate the object from R: |
|
| 350 |
* fleet <- methods::new(Index). |
|
| 351 |
*/ |
|
| 352 |
class IndexDataInterface : public DataInterfaceBase {
|
|
| 353 |
public: |
|
| 354 |
/** |
|
| 355 |
* @brief An integer that specifies the second dimension of the data. |
|
| 356 |
*/ |
|
| 357 |
fims_int ymax = 0; |
|
| 358 |
/** |
|
| 359 |
* @brief The vector of index data that is being passed from R. |
|
| 360 |
*/ |
|
| 361 |
RealVector index_data; |
|
| 362 |
/** |
|
| 363 |
* @brief The vector of index uncertainty that is being passed from |
|
| 364 |
* R. |
|
| 365 |
*/ |
|
| 366 |
RealVector uncertainty; |
|
| 367 | ||
| 368 |
/** |
|
| 369 |
* @brief The constructor. |
|
| 370 |
*/ |
|
| 371 | 37x |
IndexDataInterface(int ymax = 0) : DataInterfaceBase() {
|
| 372 | 37x |
this->ymax = ymax; |
| 373 | 37x |
this->index_data.resize(ymax); |
| 374 | 37x |
this->uncertainty.resize(ymax); |
| 375 | 37x |
DataInterfaceBase::live_objects[this->id] = |
| 376 | 74x |
std::make_shared<IndexDataInterface>(*this); |
| 377 | 37x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 378 | 37x |
DataInterfaceBase::live_objects[this->id]); |
| 379 |
} |
|
| 380 | ||
| 381 |
/** |
|
| 382 |
* @brief Construct a new Index Data Interface object |
|
| 383 |
* |
|
| 384 |
* @param other |
|
| 385 |
*/ |
|
| 386 | 37x |
IndexDataInterface(const IndexDataInterface &other) |
| 387 | 37x |
: DataInterfaceBase(other), |
| 388 | 37x |
ymax(other.ymax), |
| 389 | 37x |
index_data(other.index_data), |
| 390 | 74x |
uncertainty(other.uncertainty) {}
|
| 391 | ||
| 392 |
/** |
|
| 393 |
* @brief The destructor. |
|
| 394 |
*/ |
|
| 395 | 222x |
virtual ~IndexDataInterface() {}
|
| 396 | ||
| 397 |
/** |
|
| 398 |
* @brief Gets the ID of the interface base object. |
|
| 399 |
* @return The ID. |
|
| 400 |
*/ |
|
| 401 | 34x |
virtual uint32_t get_id() { return this->id; }
|
| 402 | ||
| 403 |
/** |
|
| 404 |
* @brief Converts the data to json representation for the output. |
|
| 405 |
* @return A string is returned specifying that the module relates to the |
|
| 406 |
* data interface with index data. It also returns the ID, the rank of 1, the |
|
| 407 |
* dimensions by printing ymax, followed by the data values themselves. This |
|
| 408 |
* string is formatted for a json file. |
|
| 409 |
*/ |
|
| 410 | 24x |
virtual std::string to_json() {
|
| 411 | 24x |
std::stringstream ss; |
| 412 | ||
| 413 | 24x |
ss << "{\n";
|
| 414 | 24x |
ss << " \"name\": \"Index\",\n"; |
| 415 | 24x |
ss << " \"id\": " << this->id << ",\n"; |
| 416 | 24x |
ss << " \"type\": \"data\",\n"; |
| 417 | 24x |
ss << " \"dimensionality\": {\n";
|
| 418 | 24x |
ss << " \"header\": [" << "\"n_years\"" << "],\n"; |
| 419 | 24x |
ss << " \"dimensions\": [" << ymax << "]\n},\n"; |
| 420 | 24x |
ss << " \"value\": ["; |
| 421 | 745x |
for (size_t i = 0; i < index_data.size() - 1; i++) {
|
| 422 | 721x |
ss << index_data[i] << ", "; |
| 423 |
} |
|
| 424 | 24x |
ss << index_data[index_data.size() - 1] << "],\n"; |
| 425 | 24x |
ss << "\"uncertainty\": [ "; |
| 426 | 745x |
for (size_t i = 0; i < uncertainty.size() - 1; i++) {
|
| 427 | 721x |
ss << uncertainty[i] << ", "; |
| 428 |
} |
|
| 429 | 24x |
ss << uncertainty[uncertainty.size() - 1] << "]\n"; |
| 430 | 24x |
ss << "}"; |
| 431 | 48x |
return ss.str(); |
| 432 |
} |
|
| 433 | ||
| 434 |
#ifdef TMB_MODEL |
|
| 435 | ||
| 436 |
template <typename Type> |
|
| 437 | 124x |
bool add_to_fims_tmb_internal() {
|
| 438 | 124x |
std::shared_ptr<fims_data_object::DataObject<Type>> data = |
| 439 | 124x |
std::make_shared<fims_data_object::DataObject<Type>>(this->ymax); |
| 440 | ||
| 441 | 124x |
data->id = this->id; |
| 442 | ||
| 443 | 3944x |
for (int y = 0; y < ymax; y++) {
|
| 444 | 3820x |
data->at(y) = this->index_data[y]; |
| 445 | 3820x |
data->uncertainty[y] = this->uncertainty[y]; |
| 446 |
} |
|
| 447 | ||
| 448 | 124x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 449 |
fims_info::Information<Type>::GetInstance(); |
|
| 450 | ||
| 451 | 124x |
info->data_objects[this->id] = data; |
| 452 | 124x |
return true; |
| 453 |
} |
|
| 454 | ||
| 455 |
/** |
|
| 456 |
* @brief Adds the parameters to the TMB model. |
|
| 457 |
* @return A boolean of true. |
|
| 458 |
*/ |
|
| 459 | 31x |
virtual bool add_to_fims_tmb() {
|
| 460 | 31x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 461 | 31x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 462 | ||
| 463 | 31x |
return true; |
| 464 |
} |
|
| 465 | ||
| 466 |
#endif |
|
| 467 |
}; |
|
| 468 | ||
| 469 |
/** |
|
| 470 |
* @brief The Rcpp interface for Landings to instantiate the object from R: |
|
| 471 |
* fleet <- methods::new(Landings). |
|
| 472 |
*/ |
|
| 473 |
class LandingsDataInterface : public DataInterfaceBase {
|
|
| 474 |
public: |
|
| 475 |
/** |
|
| 476 |
* @brief An integer that specifies the second dimension of the data. |
|
| 477 |
*/ |
|
| 478 |
fims_int ymax = 0; |
|
| 479 |
/** |
|
| 480 |
* @brief The vector of landings data that is being passed from R. |
|
| 481 |
*/ |
|
| 482 |
RealVector landings_data; |
|
| 483 |
/** |
|
| 484 |
* @brief The vector of landings uncertainty that is being passed from |
|
| 485 |
* R. |
|
| 486 |
*/ |
|
| 487 |
RealVector uncertainty; |
|
| 488 | ||
| 489 |
/** |
|
| 490 |
* @brief The constructor. |
|
| 491 |
*/ |
|
| 492 | 34x |
LandingsDataInterface(int ymax = 0) : DataInterfaceBase() {
|
| 493 | 34x |
this->ymax = ymax; |
| 494 | 34x |
this->landings_data.resize(ymax); |
| 495 | 34x |
this->uncertainty.resize(ymax); |
| 496 | 34x |
DataInterfaceBase::live_objects[this->id] = |
| 497 | 68x |
std::make_shared<LandingsDataInterface>(*this); |
| 498 | 34x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 499 | 34x |
DataInterfaceBase::live_objects[this->id]); |
| 500 |
} |
|
| 501 | ||
| 502 |
/** |
|
| 503 |
* @brief Construct a new Landings Data Interface object |
|
| 504 |
* |
|
| 505 |
* @param other |
|
| 506 |
*/ |
|
| 507 | 34x |
LandingsDataInterface(const LandingsDataInterface &other) |
| 508 | 34x |
: DataInterfaceBase(other), |
| 509 | 34x |
ymax(other.ymax), |
| 510 | 34x |
landings_data(other.landings_data), |
| 511 | 68x |
uncertainty(other.uncertainty) {}
|
| 512 | ||
| 513 |
/** |
|
| 514 |
* @brief The destructor. |
|
| 515 |
*/ |
|
| 516 | 204x |
virtual ~LandingsDataInterface() {}
|
| 517 | ||
| 518 |
/** |
|
| 519 |
* @brief Gets the ID of the interface base object. |
|
| 520 |
* @return The ID. |
|
| 521 |
*/ |
|
| 522 | 33x |
virtual uint32_t get_id() { return this->id; }
|
| 523 | ||
| 524 |
/** |
|
| 525 |
* @brief Converts the data to json representation for the output. |
|
| 526 |
* @return A string is returned specifying that the module relates to the |
|
| 527 |
* data interface with landings data. It also returns the ID, the rank of 1, |
|
| 528 |
* the dimensions by printing ymax, followed by the data values themselves. |
|
| 529 |
* This string is formatted for a json file. |
|
| 530 |
*/ |
|
| 531 | 24x |
virtual std::string to_json() {
|
| 532 | 24x |
std::stringstream ss; |
| 533 | ||
| 534 | 24x |
ss << "{\n";
|
| 535 | 24x |
ss << " \"name\": \"Landings\",\n"; |
| 536 | 24x |
ss << " \"id\": " << this->id << ",\n"; |
| 537 | 24x |
ss << " \"type\": \"data\",\n"; |
| 538 | 24x |
ss << " \"dimensionality\": {\n";
|
| 539 | 24x |
ss << " \"header\": [" << "\"n_years\"" << "],\n"; |
| 540 | 24x |
ss << " \"dimensions\": [" << ymax << "]\n},\n"; |
| 541 | 24x |
ss << " \"value\": ["; |
| 542 | 745x |
for (size_t i = 0; i < landings_data.size() - 1; i++) {
|
| 543 | 721x |
ss << landings_data[i] << ", "; |
| 544 |
} |
|
| 545 | 24x |
ss << landings_data[landings_data.size() - 1] << "],\n"; |
| 546 | 24x |
ss << "\"uncertainty\": [ "; |
| 547 | 745x |
for (size_t i = 0; i < uncertainty.size() - 1; i++) {
|
| 548 | 721x |
ss << uncertainty[i] << ", "; |
| 549 |
} |
|
| 550 | 24x |
ss << uncertainty[uncertainty.size() - 1] << "]\n"; |
| 551 | 24x |
ss << "}"; |
| 552 | 48x |
return ss.str(); |
| 553 |
} |
|
| 554 | ||
| 555 |
#ifdef TMB_MODEL |
|
| 556 | ||
| 557 |
template <typename Type> |
|
| 558 | 124x |
bool add_to_fims_tmb_internal() {
|
| 559 | 124x |
std::shared_ptr<fims_data_object::DataObject<Type>> data = |
| 560 | 124x |
std::make_shared<fims_data_object::DataObject<Type>>(this->ymax); |
| 561 | ||
| 562 | 124x |
data->id = this->id; |
| 563 | ||
| 564 | 3944x |
for (int y = 0; y < ymax; y++) {
|
| 565 | 3820x |
data->at(y) = this->landings_data[y]; |
| 566 | 3820x |
data->uncertainty[y] = this->uncertainty[y]; |
| 567 |
} |
|
| 568 | ||
| 569 | 124x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 570 |
fims_info::Information<Type>::GetInstance(); |
|
| 571 | ||
| 572 | 124x |
info->data_objects[this->id] = data; |
| 573 | 124x |
return true; |
| 574 |
} |
|
| 575 | ||
| 576 |
/** |
|
| 577 |
* @brief Adds the parameters to the TMB model. |
|
| 578 |
* @return A boolean of true. |
|
| 579 |
*/ |
|
| 580 | 31x |
virtual bool add_to_fims_tmb() {
|
| 581 | 31x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 582 | 31x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 583 | ||
| 584 | 31x |
return true; |
| 585 |
} |
|
| 586 | ||
| 587 |
#endif |
|
| 588 |
}; |
|
| 589 | ||
| 590 |
#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 Control flag indicating whether to use the expected mean in the |
|
| 40 |
* distribution calculations. |
|
| 41 |
* |
|
| 42 |
* This shared string member serves as a boolean flag (i.e., "yes" or "no") |
|
| 43 |
* that determines whether the distribution should use the `expected_mean` |
|
| 44 |
* vector or other expected values (e.g., from data or random effects) when |
|
| 45 |
* computing the expected value in the likelihood calculations. |
|
| 46 |
* |
|
| 47 |
* When set to "no" (default), the distribution uses expected values based on |
|
| 48 |
* the `input_type` setting (data expected values for "data", random effects |
|
| 49 |
* expected values for "random_effects", or standard expected values |
|
| 50 |
* otherwise). |
|
| 51 |
* |
|
| 52 |
* When set to "yes" (typically by calling `set_distribution_mean()`), the |
|
| 53 |
* distribution overrides the default expected value source and uses the |
|
| 54 |
* `expected_mean` vector instead. This is useful for setting a fixed mean |
|
| 55 |
* value for the distribution that doesn't depend on other model components. |
|
| 56 |
* |
|
| 57 |
* @see set_distribution_mean() for the method that sets this flag to "yes". |
|
| 58 |
* @see DensityComponentBase::get_expected() in density_components_base.hpp |
|
| 59 |
* for the implementation that checks this flag. |
|
| 60 |
*/ |
|
| 61 |
SharedString use_mean_m = fims::to_string("no");
|
|
| 62 |
/** |
|
| 63 |
* @brief The map associating the ID of the DistributionsInterfaceBase to the |
|
| 64 |
DistributionsInterfaceBase objects. This is a live object, which is an |
|
| 65 |
object that has been created and lives in memory. |
|
| 66 |
*/ |
|
| 67 |
static std::map<uint32_t, std::shared_ptr<DistributionsInterfaceBase>> |
|
| 68 |
live_objects; |
|
| 69 |
/** |
|
| 70 |
* @brief The ID of the observed data object, which is set to -999. |
|
| 71 |
*/ |
|
| 72 |
SharedInt interface_observed_data_id_m = -999; |
|
| 73 | ||
| 74 |
/** |
|
| 75 |
* @brief The log probability density function value. |
|
| 76 |
*/ |
|
| 77 |
double lpdf_value = 0; |
|
| 78 |
/** |
|
| 79 |
* @brief The constructor. |
|
| 80 |
*/ |
|
| 81 | 239x |
DistributionsInterfaceBase() {
|
| 82 | 239x |
this->key_m = std::make_shared<std::vector<uint32_t>>(); |
| 83 | 239x |
this->id_m = DistributionsInterfaceBase::id_g++; |
| 84 |
/* Create instance of map: key is id and value is pointer to |
|
| 85 |
DistributionsInterfaceBase */ |
|
| 86 |
// DistributionsInterfaceBase::live_objects[this->id_m] = this; |
|
| 87 |
} |
|
| 88 | ||
| 89 |
/** |
|
| 90 |
* @brief Construct a new Distributions Interface Base object |
|
| 91 |
* |
|
| 92 |
* @param other |
|
| 93 |
*/ |
|
| 94 | 239x |
DistributionsInterfaceBase(const DistributionsInterfaceBase &other) |
| 95 | 478x |
: id_m(other.id_m), |
| 96 | 239x |
key_m(other.key_m), |
| 97 | 239x |
input_type_m(other.input_type_m), |
| 98 | 239x |
use_mean_m(other.use_mean_m), |
| 99 | 478x |
interface_observed_data_id_m(other.interface_observed_data_id_m) {}
|
| 100 | ||
| 101 |
/** |
|
| 102 |
* @brief The destructor. |
|
| 103 |
*/ |
|
| 104 | 478x |
virtual ~DistributionsInterfaceBase() {}
|
| 105 | ||
| 106 |
/** |
|
| 107 |
* @brief Get the ID for the child distribution interface objects to inherit. |
|
| 108 |
*/ |
|
| 109 |
virtual uint32_t get_id() = 0; |
|
| 110 | ||
| 111 |
/** |
|
| 112 |
* @brief Sets pointers for data observations, random effects, or priors. |
|
| 113 |
* |
|
| 114 |
* @param input_type String that sets whether the distribution type is for |
|
| 115 |
* priors, random effects, or data. |
|
| 116 |
* @param ids Vector of unique ids for each linked parameter(s), derived |
|
| 117 |
* value(s), or observed data vector. |
|
| 118 |
*/ |
|
| 119 | ! |
virtual bool set_distribution_links(std::string input_type, |
| 120 |
Rcpp::IntegerVector ids) {
|
|
| 121 | ! |
return false; |
| 122 |
} |
|
| 123 | ||
| 124 |
/** |
|
| 125 |
* @brief Set the expected mean value for the distribution. |
|
| 126 |
* |
|
| 127 |
* This virtual function provides an interface for setting a fixed mean value |
|
| 128 |
* for distribution objects. When overridden in derived classes, this method |
|
| 129 |
* typically stores the provided mean value as a fixed effect parameter and |
|
| 130 |
* marks the distribution to use the mean in its calculations. |
|
| 131 |
* |
|
| 132 |
* The base class implementation returns false to indicate the operation is |
|
| 133 |
* not supported. Derived classes that support mean specification should |
|
| 134 |
* override this method to implement the actual functionality. |
|
| 135 |
* |
|
| 136 |
* @param input_value The numeric value to set as the distribution's expected |
|
| 137 |
* mean. This value will be treated as a fixed effect parameter (not |
|
| 138 |
* estimated) in derived class implementations. |
|
| 139 |
* |
|
| 140 |
* @return bool Returns true if the mean was successfully set, false |
|
| 141 |
* otherwise. The base class implementation always returns false to indicate |
|
| 142 |
* the operation is not supported by default. |
|
| 143 |
* |
|
| 144 |
* @see DnormDistributionsInterface::set_distribution_mean for an example |
|
| 145 |
* implementation that sets the mean as a fixed effect parameter. |
|
| 146 |
*/ |
|
| 147 | ! |
virtual bool set_distribution_mean(double input_value) { return false; }
|
| 148 | ||
| 149 |
/** |
|
| 150 |
* @brief Set the unique ID for the observed data object. |
|
| 151 |
* |
|
| 152 |
* @param observed_data_id Unique ID for the Observed Age Comp Data |
|
| 153 |
* object |
|
| 154 |
*/ |
|
| 155 | ! |
virtual bool set_observed_data(int observed_data_id) { return false; }
|
| 156 | ||
| 157 |
/** |
|
| 158 |
* @brief A method for each child distribution interface object to inherit so |
|
| 159 |
* each distribution can have an evaluate() function. |
|
| 160 |
*/ |
|
| 161 |
virtual double evaluate() = 0; |
|
| 162 |
}; |
|
| 163 |
// static id of the DistributionsInterfaceBase object |
|
| 164 |
uint32_t DistributionsInterfaceBase::id_g = 1; |
|
| 165 |
// local id of the DistributionsInterfaceBase object map relating the ID of the |
|
| 166 |
// DistributionsInterfaceBase to the DistributionsInterfaceBase objects |
|
| 167 |
std::map<uint32_t, std::shared_ptr<DistributionsInterfaceBase>> |
|
| 168 |
DistributionsInterfaceBase::live_objects; |
|
| 169 | ||
| 170 |
/** |
|
| 171 |
* @brief The Rcpp interface for Dnorm to instantiate from R: |
|
| 172 |
* dnorm_ <- methods::new(DnormDistribution). |
|
| 173 |
*/ |
|
| 174 |
class DnormDistributionsInterface : public DistributionsInterfaceBase {
|
|
| 175 |
public: |
|
| 176 |
/** |
|
| 177 |
* @brief Observed data. |
|
| 178 |
*/ |
|
| 179 |
ParameterVector observed_values; |
|
| 180 |
/** |
|
| 181 |
* @brief The expected values, which would be the mean of x for this |
|
| 182 |
* distribution. |
|
| 183 |
*/ |
|
| 184 |
ParameterVector expected_values; |
|
| 185 |
/** |
|
| 186 |
* @brief The expected mean, which would be the mean of x for this |
|
| 187 |
* distribution. |
|
| 188 |
*/ |
|
| 189 |
ParameterVector expected_mean; |
|
| 190 |
/** |
|
| 191 |
* @brief The uncertainty, which would be the standard deviation of x for the |
|
| 192 |
* normal distribution. |
|
| 193 |
*/ |
|
| 194 |
ParameterVector log_sd; |
|
| 195 |
/** |
|
| 196 |
* @brief Vector that records the individual log probability function for each |
|
| 197 |
* observation. |
|
| 198 |
*/ |
|
| 199 |
RealVector lpdf_vec; /**< The vector*/ |
|
| 200 | ||
| 201 |
/** |
|
| 202 |
* @brief The constructor. |
|
| 203 |
*/ |
|
| 204 | 49x |
DnormDistributionsInterface() : DistributionsInterfaceBase() {
|
| 205 | 49x |
DistributionsInterfaceBase::live_objects[this->id_m] = |
| 206 | 98x |
std::make_shared<DnormDistributionsInterface>(*this); |
| 207 | 49x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 208 | 49x |
DistributionsInterfaceBase::live_objects[this->id_m]); |
| 209 |
} |
|
| 210 | ||
| 211 |
/** |
|
| 212 |
* @brief Construct a new Dnorm Distributions Interface object |
|
| 213 |
* |
|
| 214 |
* @param other |
|
| 215 |
*/ |
|
| 216 | 49x |
DnormDistributionsInterface(const DnormDistributionsInterface &other) |
| 217 | 49x |
: DistributionsInterfaceBase(other), |
| 218 | 49x |
observed_values(other.observed_values), |
| 219 | 49x |
expected_values(other.expected_values), |
| 220 | 49x |
expected_mean(other.expected_mean), |
| 221 | 49x |
log_sd(other.log_sd), |
| 222 | 98x |
lpdf_vec(other.lpdf_vec) {}
|
| 223 | ||
| 224 |
/** |
|
| 225 |
* @brief The destructor. |
|
| 226 |
*/ |
|
| 227 | 294x |
virtual ~DnormDistributionsInterface() {}
|
| 228 | ||
| 229 |
/** |
|
| 230 |
* @brief Gets the ID of the interface base object. |
|
| 231 |
* @return The ID. |
|
| 232 |
*/ |
|
| 233 | ! |
virtual uint32_t get_id() { return this->id_m; }
|
| 234 | ||
| 235 |
/** |
|
| 236 |
* @brief Set the unique ID for the observed data object. |
|
| 237 |
* @param observed_data_id Unique ID for the observed data object. |
|
| 238 |
*/ |
|
| 239 | 1x |
virtual bool set_observed_data(int observed_data_id) {
|
| 240 | 1x |
this->interface_observed_data_id_m.set(observed_data_id); |
| 241 | 1x |
return true; |
| 242 |
} |
|
| 243 | ||
| 244 |
/** |
|
| 245 |
* @copydoc DistributionsInterfaceBase::set_distribution_mean |
|
| 246 |
*/ |
|
| 247 | 1x |
virtual bool set_distribution_mean(double input_value) {
|
| 248 | 1x |
this->expected_mean[0].initial_value_m = input_value; |
| 249 | 2x |
this->expected_mean[0].estimation_type_m.set("fixed_effects");
|
| 250 | 1x |
this->use_mean_m.set(fims::to_string("yes"));
|
| 251 | 1x |
return true; |
| 252 |
} |
|
| 253 | ||
| 254 |
/** |
|
| 255 |
* @copydoc DistributionsInterfaceBase::set_distribution_links |
|
| 256 |
*/ |
|
| 257 | 38x |
virtual bool set_distribution_links(std::string input_type, |
| 258 |
Rcpp::IntegerVector ids) {
|
|
| 259 | 38x |
this->input_type_m.set(input_type); |
| 260 | 38x |
this->key_m->resize(ids.size()); |
| 261 | 79x |
for (R_xlen_t i = 0; i < ids.size(); i++) {
|
| 262 | 41x |
this->key_m->at(i) = ids[i]; |
| 263 |
} |
|
| 264 | 38x |
return true; |
| 265 |
} |
|
| 266 | ||
| 267 |
/** |
|
| 268 |
* @brief Evaluate normal probability density function (pdf). The natural log |
|
| 269 |
* of the pdf is returned. |
|
| 270 |
* @return The natural log of the probability density function (pdf) is |
|
| 271 |
* returned. |
|
| 272 |
*/ |
|
| 273 | 11x |
virtual double evaluate() {
|
| 274 | 11x |
fims_distributions::NormalLPDF<double> dnorm; |
| 275 | 11x |
dnorm.observed_values.resize(this->observed_values.size()); |
| 276 | 11x |
dnorm.expected_values.resize(this->expected_values.size()); |
| 277 | 11x |
dnorm.log_sd.resize(this->log_sd.size()); |
| 278 | 11x |
dnorm.expected_mean.resize(this->expected_mean.size()); |
| 279 | 59x |
for (size_t i = 0; i < this->observed_values.size(); i++) {
|
| 280 | 48x |
dnorm.observed_values[i] = this->observed_values[i].initial_value_m; |
| 281 |
} |
|
| 282 | 58x |
for (size_t i = 0; i < this->expected_values.size(); i++) {
|
| 283 | 47x |
dnorm.expected_values[i] = this->expected_values[i].initial_value_m; |
| 284 |
} |
|
| 285 | 42x |
for (size_t i = 0; i < this->log_sd.size(); i++) {
|
| 286 | 31x |
dnorm.log_sd[i] = this->log_sd[i].initial_value_m; |
| 287 |
} |
|
| 288 | 22x |
for (size_t i = 0; i < this->expected_mean.size(); i++) {
|
| 289 | 11x |
dnorm.expected_mean[i] = this->expected_mean[i].initial_value_m; |
| 290 |
} |
|
| 291 | 11x |
dnorm.use_mean = this->use_mean_m; |
| 292 | 20x |
return dnorm.evaluate(); |
| 293 |
} |
|
| 294 | ||
| 295 |
/** |
|
| 296 |
* @brief Extracts the derived quantities from `Information` to the Rcpp |
|
| 297 |
* object. |
|
| 298 |
*/ |
|
| 299 | 26x |
virtual void finalize() {
|
| 300 | 26x |
if (this->finalized) {
|
| 301 |
// log warning that finalize has been called more than once. |
|
| 302 | 1x |
FIMS_WARNING_LOG("DnormDistribution " + fims::to_string(this->id_m) +
|
| 303 |
" has been finalized already."); |
|
| 304 |
} |
|
| 305 | ||
| 306 | 26x |
this->finalized = true; // indicate this has been called already |
| 307 | ||
| 308 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 309 | 26x |
fims_info::Information<double>::GetInstance(); |
| 310 | ||
| 311 | 26x |
fims_info::Information<double>::density_components_iterator it; |
| 312 | ||
| 313 |
// search for density component in Information |
|
| 314 | 26x |
it = info->density_components.find(this->id_m); |
| 315 |
// if not found, just return |
|
| 316 | 26x |
if (it == info->density_components.end()) {
|
| 317 | ! |
FIMS_WARNING_LOG("DnormDistribution " + fims::to_string(this->id_m) +
|
| 318 |
" not found in Information."); |
|
| 319 | ! |
return; |
| 320 |
} else {
|
|
| 321 |
std::shared_ptr<fims_distributions::NormalLPDF<double>> dnorm = |
|
| 322 |
std::dynamic_pointer_cast<fims_distributions::NormalLPDF<double>>( |
|
| 323 | 26x |
it->second); |
| 324 | ||
| 325 | 26x |
this->lpdf_value = dnorm->lpdf; |
| 326 | ||
| 327 | 26x |
size_t n_x = dnorm->get_n_x(); |
| 328 | ||
| 329 |
// If input log_sd is a scalar, resize to n_x and fill with the scalar |
|
| 330 |
// value |
|
| 331 | 26x |
if (this->log_sd.size() != n_x) {
|
| 332 |
// If log_sd size == 1 (scalar), repeat the entry |
|
| 333 | 23x |
if (this->log_sd.size() == 1) {
|
| 334 | 23x |
auto tmp = this->log_sd[0]; // copy the one log_sd param |
| 335 | 23x |
this->log_sd.resize(n_x); |
| 336 | 715x |
for (size_t i = 0; i < n_x; ++i) {
|
| 337 | 692x |
this->log_sd[i] = tmp; // copies all fields in Param |
| 338 |
} |
|
| 339 |
} else {
|
|
| 340 |
// Handle error |
|
| 341 | ! |
FIMS_WARNING_LOG( |
| 342 |
"log_sd size does not match number of observations and is not " |
|
| 343 |
"scalar."); |
|
| 344 |
} |
|
| 345 |
} |
|
| 346 | 828x |
for (size_t i = 0; i < n_x; i++) {
|
| 347 | 802x |
if (this->log_sd[i].estimation_type_m.get() == "constant") {
|
| 348 | 545x |
this->log_sd[i].final_value_m = this->log_sd[i].initial_value_m; |
| 349 |
} else {
|
|
| 350 | 257x |
this->log_sd[i].final_value_m = dnorm->log_sd.get_force_scalar(i); |
| 351 |
} |
|
| 352 |
} |
|
| 353 | ||
| 354 | 52x |
for (size_t i = 0; i < this->expected_mean.size(); i++) {
|
| 355 | 26x |
if (this->expected_mean[i].estimation_type_m.get() == "constant") {
|
| 356 | 25x |
this->expected_mean[i].final_value_m = |
| 357 | 25x |
this->expected_mean[i].initial_value_m; |
| 358 |
} else {
|
|
| 359 | 1x |
this->expected_mean[i].final_value_m = dnorm->expected_mean[i]; |
| 360 |
} |
|
| 361 |
} |
|
| 362 | ||
| 363 | 26x |
this->lpdf_vec = RealVector(n_x); |
| 364 | 26x |
if (this->expected_values.size() == 1) {
|
| 365 | ! |
this->expected_values.resize(n_x); |
| 366 |
} |
|
| 367 | 26x |
if (this->observed_values.size() == 1) {
|
| 368 | ! |
this->observed_values.resize(n_x); |
| 369 |
} |
|
| 370 | ||
| 371 | 828x |
for (size_t i = 0; i < this->lpdf_vec.size(); i++) {
|
| 372 | 802x |
this->lpdf_vec[i] = dnorm->lpdf_vec[i]; |
| 373 | 802x |
this->expected_values[i].final_value_m = dnorm->get_expected(i); |
| 374 | 802x |
this->observed_values[i].final_value_m = dnorm->get_observed(i); |
| 375 |
} |
|
| 376 |
} |
|
| 377 |
} |
|
| 378 | ||
| 379 |
/** |
|
| 380 |
* @brief Converts the data to json representation for the output. |
|
| 381 |
* @return A string is returned specifying that the module relates to the |
|
| 382 |
* distribution interface with a normal distribution. It also returns the ID |
|
| 383 |
* and the natural log of the probability density function values themselves. |
|
| 384 |
* This string is formatted for a json file. |
|
| 385 |
*/ |
|
| 386 | 26x |
virtual std::string to_json() {
|
| 387 | 26x |
std::stringstream ss; |
| 388 | ||
| 389 | 26x |
ss << "{\n";
|
| 390 | 26x |
ss << " \"module_name\": \"density\",\n"; |
| 391 | 26x |
ss << " \"module_id\": " << this->id_m << ",\n"; |
| 392 | 26x |
ss << " \"module_type\": \"normal\",\n"; |
| 393 | 26x |
ss << " \"observed_data_id\" : " << this->interface_observed_data_id_m |
| 394 | 26x |
<< ",\n"; |
| 395 | 26x |
ss << " \"input_type\" : \"" << this->input_type_m << "\",\n"; |
| 396 | 26x |
ss << " \"density_component\": {\n";
|
| 397 | 26x |
ss << " \"lpdf_value\": " << this->lpdf_value << ",\n"; |
| 398 | 26x |
ss << " \"value\":["; |
| 399 | 26x |
if (this->lpdf_vec.size() == 0) {
|
| 400 | ! |
ss << "],\n"; |
| 401 |
} else {
|
|
| 402 | 802x |
for (size_t i = 0; i < this->lpdf_vec.size() - 1; i++) {
|
| 403 | 776x |
ss << this->value_to_string(this->lpdf_vec[i]); |
| 404 | 776x |
ss << ", "; |
| 405 |
} |
|
| 406 | 26x |
ss << this->value_to_string(this->lpdf_vec[this->lpdf_vec.size() - 1]); |
| 407 | ||
| 408 | 26x |
ss << "],\n"; |
| 409 |
} |
|
| 410 | 26x |
ss << " \"expected_values\":["; |
| 411 | 26x |
if (this->expected_values.size() == 0) {
|
| 412 | ! |
ss << "],\n"; |
| 413 |
} else {
|
|
| 414 | 802x |
for (size_t i = 0; i < this->expected_values.size() - 1; i++) {
|
| 415 | 1552x |
ss << this->value_to_string(this->expected_values[i].final_value_m) |
| 416 |
<< ", "; |
|
| 417 |
} |
|
| 418 | 26x |
ss << this->value_to_string( |
| 419 | 26x |
this->expected_values[this->expected_values.size() - 1] |
| 420 | 26x |
.final_value_m); |
| 421 | 26x |
ss << "],\n"; |
| 422 |
} |
|
| 423 | 26x |
ss << " \"log_sd_values\":["; |
| 424 | 26x |
if (this->log_sd.size() == 0) {
|
| 425 | ! |
ss << "],\n"; |
| 426 |
} else {
|
|
| 427 | 802x |
for (R_xlen_t i = 0; i < static_cast<R_xlen_t>(this->log_sd.size()) - 1; |
| 428 |
i++) {
|
|
| 429 | 776x |
ss << this->value_to_string(this->log_sd[i].final_value_m) << ", "; |
| 430 |
} |
|
| 431 | 26x |
ss << this->value_to_string( |
| 432 | 26x |
this->log_sd[this->log_sd.size() - 1].final_value_m) |
| 433 | 26x |
<< "],\n"; |
| 434 |
} |
|
| 435 | 26x |
ss << " \"observed_values\":["; |
| 436 | 26x |
if (this->observed_values.size() == 0) {
|
| 437 | ! |
ss << "]\n"; |
| 438 |
} else {
|
|
| 439 | 802x |
for (size_t i = 0; i < this->observed_values.size() - 1; i++) {
|
| 440 | 776x |
ss << this->observed_values[i].final_value_m << ", "; |
| 441 |
} |
|
| 442 | 26x |
ss << this->observed_values[this->observed_values.size() - 1] |
| 443 | 26x |
.final_value_m |
| 444 | 26x |
<< "]\n"; |
| 445 |
} |
|
| 446 | 26x |
ss << " }}\n"; |
| 447 | 52x |
return ss.str(); |
| 448 |
} |
|
| 449 | ||
| 450 |
#ifdef TMB_MODEL |
|
| 451 | ||
| 452 |
template <typename Type> |
|
| 453 | 136x |
bool add_to_fims_tmb_internal() {
|
| 454 | 136x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 455 |
fims_info::Information<Type>::GetInstance(); |
|
| 456 | ||
| 457 | 136x |
std::shared_ptr<fims_distributions::NormalLPDF<Type>> distribution = |
| 458 |
std::make_shared<fims_distributions::NormalLPDF<Type>>(); |
|
| 459 | ||
| 460 |
// interface to data/parameter value |
|
| 461 | ||
| 462 | 136x |
distribution->observed_data_id_m = interface_observed_data_id_m; |
| 463 | 136x |
std::stringstream ss; |
| 464 | 136x |
distribution->input_type = this->input_type_m; |
| 465 | 136x |
distribution->key.resize(this->key_m->size()); |
| 466 | 284x |
for (size_t i = 0; i < this->key_m->size(); i++) {
|
| 467 | 148x |
distribution->key[i] = this->key_m->at(i); |
| 468 |
} |
|
| 469 | 136x |
distribution->id = this->id_m; |
| 470 | 136x |
distribution->observed_values.resize(this->observed_values.size()); |
| 471 | 4048x |
for (size_t i = 0; i < this->observed_values.size(); i++) {
|
| 472 | 3912x |
distribution->observed_values[i] = |
| 473 | 3912x |
this->observed_values[i].initial_value_m; |
| 474 |
} |
|
| 475 |
// set relative info |
|
| 476 | 136x |
distribution->expected_values.resize(this->expected_values.size()); |
| 477 | 4056x |
for (size_t i = 0; i < this->expected_values.size(); i++) {
|
| 478 | 3920x |
distribution->expected_values[i] = |
| 479 | 3920x |
this->expected_values[i].initial_value_m; |
| 480 |
} |
|
| 481 | 136x |
distribution->log_sd.resize(this->log_sd.size()); |
| 482 | 588x |
for (size_t i = 0; i < this->log_sd.size(); i++) {
|
| 483 | 452x |
distribution->log_sd[i] = this->log_sd[i].initial_value_m; |
| 484 | 452x |
if (this->log_sd[i].estimation_type_m.get() == "fixed_effects") {
|
| 485 | 32x |
ss.str("");
|
| 486 | 32x |
ss << "dnorm." << this->id_m << ".log_sd." << this->log_sd[i].id_m; |
| 487 | 32x |
info->RegisterParameterName(ss.str()); |
| 488 | 32x |
info->RegisterParameter(distribution->log_sd[i]); |
| 489 |
} |
|
| 490 | 452x |
if (this->log_sd[i].estimation_type_m.get() == "random_effects") {
|
| 491 | ! |
FIMS_ERROR_LOG("standard deviations cannot be set to random effects");
|
| 492 |
} |
|
| 493 |
} |
|
| 494 | 136x |
info->variable_map[this->log_sd.id_m] = &(distribution)->log_sd; |
| 495 | ||
| 496 | 136x |
distribution->use_mean = this->use_mean_m.get(); |
| 497 | 136x |
distribution->expected_mean.resize(this->expected_mean.size()); |
| 498 | 272x |
for (size_t i = 0; i < this->expected_mean.size(); i++) {
|
| 499 | 136x |
distribution->expected_mean[i] = this->expected_mean[i].initial_value_m; |
| 500 | 136x |
if (this->expected_mean[i].estimation_type_m.get() == "fixed_effects") {
|
| 501 | 4x |
ss.str("");
|
| 502 | 4x |
ss << "dnorm." << this->id_m << ".expected_mean." |
| 503 | 4x |
<< this->expected_mean[i].id_m; |
| 504 | 4x |
info->RegisterParameterName(ss.str()); |
| 505 | 4x |
info->RegisterParameter(distribution->expected_mean[i]); |
| 506 |
} |
|
| 507 | 136x |
if (this->expected_mean[i].estimation_type_m.get() == "random_effects") {
|
| 508 | ! |
FIMS_ERROR_LOG("expected_mean cannot be set to random effects");
|
| 509 |
} |
|
| 510 |
} |
|
| 511 | 136x |
info->variable_map[this->expected_mean.id_m] = |
| 512 | 136x |
&(distribution)->expected_mean; |
| 513 | ||
| 514 | 136x |
info->density_components[distribution->id] = distribution; |
| 515 | ||
| 516 | 136x |
return true; |
| 517 |
} |
|
| 518 | ||
| 519 |
/** |
|
| 520 |
* @brief Adds the parameters to the TMB model. |
|
| 521 |
* @return A boolean of true. |
|
| 522 |
*/ |
|
| 523 | 34x |
virtual bool add_to_fims_tmb() {
|
| 524 | 34x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 525 | 34x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 526 | ||
| 527 | 34x |
return true; |
| 528 |
} |
|
| 529 | ||
| 530 |
#endif |
|
| 531 |
}; |
|
| 532 | ||
| 533 |
/** |
|
| 534 |
* @brief The Rcpp interface for Dlnorm to instantiate from R: |
|
| 535 |
* dlnorm_ <- methods::new(DlnormDistribution). |
|
| 536 |
*/ |
|
| 537 |
class DlnormDistributionsInterface : public DistributionsInterfaceBase {
|
|
| 538 |
public: |
|
| 539 |
/** |
|
| 540 |
* @brief Observed data. |
|
| 541 |
*/ |
|
| 542 |
ParameterVector observed_values; |
|
| 543 |
/** |
|
| 544 |
* @brief The expected values, which would be the mean of log(x) for this |
|
| 545 |
* distribution. |
|
| 546 |
*/ |
|
| 547 |
ParameterVector expected_values; |
|
| 548 |
/** |
|
| 549 |
* @brief The uncertainty, which would be the natural logarithm of the |
|
| 550 |
standard deviation (sd) of log(x) for this distribution. The natural log |
|
| 551 |
of the standard deviation is necessary because the exponential link |
|
| 552 |
function is applied to the log transformed standard deviation to insure |
|
| 553 |
standard deviation is positive. |
|
| 554 |
*/ |
|
| 555 |
ParameterVector log_sd; |
|
| 556 |
/** |
|
| 557 |
* @brief Vector that records the individual log probability function for each |
|
| 558 |
* observation. |
|
| 559 |
*/ |
|
| 560 |
RealVector lpdf_vec; /**< The vector */ |
|
| 561 | ||
| 562 |
/** |
|
| 563 |
* @brief The constructor. |
|
| 564 |
*/ |
|
| 565 | 75x |
DlnormDistributionsInterface() : DistributionsInterfaceBase() {
|
| 566 | 75x |
DistributionsInterfaceBase::live_objects[this->id_m] = |
| 567 | 150x |
std::make_shared<DlnormDistributionsInterface>(*this); |
| 568 | 75x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 569 | 75x |
DistributionsInterfaceBase::live_objects[this->id_m]); |
| 570 |
} |
|
| 571 | ||
| 572 |
/** |
|
| 573 |
* @brief Construct a new Dlnorm Distributions Interface object |
|
| 574 |
* |
|
| 575 |
* @param other |
|
| 576 |
*/ |
|
| 577 | 75x |
DlnormDistributionsInterface(const DlnormDistributionsInterface &other) |
| 578 | 75x |
: DistributionsInterfaceBase(other), |
| 579 | 75x |
observed_values(other.observed_values), |
| 580 | 75x |
expected_values(other.expected_values), |
| 581 | 75x |
log_sd(other.log_sd), |
| 582 | 150x |
lpdf_vec(other.lpdf_vec) {}
|
| 583 | ||
| 584 |
/** |
|
| 585 |
* @brief The destructor. |
|
| 586 |
*/ |
|
| 587 | 450x |
virtual ~DlnormDistributionsInterface() {}
|
| 588 | ||
| 589 |
/** |
|
| 590 |
* @brief Gets the ID of the interface base object. |
|
| 591 |
* @return The ID. |
|
| 592 |
*/ |
|
| 593 | ! |
virtual uint32_t get_id() { return this->id_m; }
|
| 594 | ||
| 595 |
/** |
|
| 596 |
* @brief Set the unique ID for the observed data object. |
|
| 597 |
* @param observed_data_id Unique ID for the observed data object. |
|
| 598 |
*/ |
|
| 599 | 63x |
virtual bool set_observed_data(int observed_data_id) {
|
| 600 | 63x |
this->interface_observed_data_id_m.set(observed_data_id); |
| 601 | 63x |
return true; |
| 602 |
} |
|
| 603 | ||
| 604 |
/** |
|
| 605 |
* @brief Sets pointers for data observations, random effects, or priors. |
|
| 606 |
* |
|
| 607 |
* @param input_type String that sets whether the distribution type is for |
|
| 608 |
* priors, random effects, or data. |
|
| 609 |
* @param ids Vector of unique ids for each linked parameter(s), derived |
|
| 610 |
* value(s), or observed data vector. |
|
| 611 |
*/ |
|
| 612 | 63x |
virtual bool set_distribution_links(std::string input_type, |
| 613 |
Rcpp::IntegerVector ids) {
|
|
| 614 | 63x |
this->input_type_m.set(input_type); |
| 615 | 63x |
this->key_m->resize(ids.size()); |
| 616 | 126x |
for (R_xlen_t i = 0; i < ids.size(); i++) {
|
| 617 | 63x |
this->key_m->at(i) = ids[i]; |
| 618 |
} |
|
| 619 | 63x |
return true; |
| 620 |
} |
|
| 621 | ||
| 622 |
/** |
|
| 623 |
* @brief Evaluate lognormal probability density function (pdf). The natural |
|
| 624 |
* log of the pdf is returned. |
|
| 625 |
* @return The natural log of the probability density function (pdf) is |
|
| 626 |
* returned. |
|
| 627 |
*/ |
|
| 628 | 11x |
virtual double evaluate() {
|
| 629 | 11x |
fims_distributions::LogNormalLPDF<double> dlnorm; |
| 630 | 11x |
dlnorm.observed_values.resize(this->observed_values.size()); |
| 631 | 11x |
dlnorm.expected_values.resize(this->expected_values.size()); |
| 632 | 11x |
dlnorm.log_sd.resize(this->log_sd.size()); |
| 633 |
// dlnorm.input_type = "prior"; |
|
| 634 | 49x |
for (size_t i = 0; i < this->observed_values.size(); i++) {
|
| 635 | 38x |
dlnorm.observed_values[i] = this->observed_values[i].initial_value_m; |
| 636 |
} |
|
| 637 | 49x |
for (size_t i = 0; i < this->expected_values.size(); i++) {
|
| 638 | 38x |
dlnorm.expected_values[i] = this->expected_values[i].initial_value_m; |
| 639 |
} |
|
| 640 | 33x |
for (size_t i = 0; i < this->log_sd.size(); i++) {
|
| 641 | 22x |
dlnorm.log_sd[i] = this->log_sd[i].initial_value_m; |
| 642 |
} |
|
| 643 | 21x |
return dlnorm.evaluate(); |
| 644 |
} |
|
| 645 | ||
| 646 |
/** |
|
| 647 |
* @brief Extracts the derived quantities from `Information` to the Rcpp |
|
| 648 |
* object. |
|
| 649 |
*/ |
|
| 650 | 48x |
virtual void finalize() {
|
| 651 | 48x |
if (this->finalized) {
|
| 652 |
// log warning that finalize has been called more than once. |
|
| 653 | 2x |
FIMS_WARNING_LOG("LogNormalLPDF " + fims::to_string(this->id_m) +
|
| 654 |
" has been finalized already."); |
|
| 655 |
} |
|
| 656 | ||
| 657 | 48x |
this->finalized = true; // indicate this has been called already |
| 658 | ||
| 659 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 660 | 48x |
fims_info::Information<double>::GetInstance(); |
| 661 | ||
| 662 | 48x |
fims_info::Information<double>::density_components_iterator it; |
| 663 | ||
| 664 |
// search for density component in Information |
|
| 665 | 48x |
it = info->density_components.find(this->id_m); |
| 666 |
// if not found, just return |
|
| 667 | 48x |
if (it == info->density_components.end()) {
|
| 668 | ! |
FIMS_WARNING_LOG("LogNormalLPDF " + fims::to_string(this->id_m) +
|
| 669 |
" not found in Information."); |
|
| 670 | ! |
return; |
| 671 |
} else {
|
|
| 672 |
std::shared_ptr<fims_distributions::LogNormalLPDF<double>> dlnorm = |
|
| 673 |
std::dynamic_pointer_cast<fims_distributions::LogNormalLPDF<double>>( |
|
| 674 | 48x |
it->second); |
| 675 | ||
| 676 | 48x |
this->lpdf_value = dlnorm->lpdf; |
| 677 | ||
| 678 | 48x |
size_t n_x = dlnorm->get_n_x(); |
| 679 | ||
| 680 | 48x |
if (this->log_sd.size() != n_x) {
|
| 681 |
// If log_sd size == 1 (scalar), repeat the entry |
|
| 682 | 2x |
if (this->log_sd.size() == 1) {
|
| 683 | 2x |
auto tmp = this->log_sd[0]; // copy the one log_sd param |
| 684 | 2x |
this->log_sd.resize(n_x); |
| 685 | 62x |
for (size_t i = 0; i < n_x; ++i) {
|
| 686 | 60x |
this->log_sd[i] = tmp; // copies all fields in Param |
| 687 |
} |
|
| 688 |
} else {
|
|
| 689 |
// Handle error |
|
| 690 | ! |
FIMS_WARNING_LOG( |
| 691 |
"log_sd size does not match number of observations and is not " |
|
| 692 |
"scalar."); |
|
| 693 |
} |
|
| 694 |
} |
|
| 695 | ||
| 696 | 1538x |
for (size_t i = 0; i < n_x; i++) {
|
| 697 | 1490x |
if (this->log_sd[i].estimation_type_m.get() == "constant") {
|
| 698 | 1460x |
this->log_sd[i].final_value_m = this->log_sd[i].initial_value_m; |
| 699 |
} else {
|
|
| 700 | 30x |
this->log_sd[i].final_value_m = dlnorm->log_sd.get_force_scalar(i); |
| 701 |
} |
|
| 702 |
} |
|
| 703 | ||
| 704 | 48x |
this->lpdf_vec = RealVector(n_x); |
| 705 | 48x |
if (this->expected_values.size() == 1) {
|
| 706 | 46x |
this->expected_values.resize(n_x); |
| 707 |
} |
|
| 708 | 48x |
if (this->observed_values.size() == 1) {
|
| 709 | 46x |
this->observed_values.resize(n_x); |
| 710 |
} |
|
| 711 | 1538x |
for (size_t i = 0; i < this->lpdf_vec.size(); i++) {
|
| 712 | 1490x |
this->lpdf_vec[i] = dlnorm->lpdf_vec[i]; |
| 713 | 1490x |
this->expected_values[i].final_value_m = dlnorm->get_expected(i); |
| 714 | 1490x |
this->observed_values[i].final_value_m = dlnorm->get_observed(i); |
| 715 |
} |
|
| 716 |
} |
|
| 717 |
} |
|
| 718 | ||
| 719 |
/** |
|
| 720 |
* @brief Converts the data to json representation for the output. |
|
| 721 |
* @return A string is returned specifying that the module relates to the |
|
| 722 |
* distribution interface with a log_normal distribution. It also returns the |
|
| 723 |
* ID and the natural log of the probability density function values |
|
| 724 |
* themselves. This string is formatted for a json file. |
|
| 725 |
*/ |
|
| 726 | 48x |
virtual std::string to_json() {
|
| 727 | 48x |
std::stringstream ss; |
| 728 | ||
| 729 | 48x |
ss << "{\n";
|
| 730 | 48x |
ss << " \"module_name\": \"density\",\n"; |
| 731 | 48x |
ss << " \"module_id\": " << this->id_m << ",\n"; |
| 732 | 48x |
ss << " \"module_type\": \"log_normal\",\n"; |
| 733 | 48x |
ss << " \"observed_data_id\" : " << this->interface_observed_data_id_m |
| 734 | 48x |
<< ",\n"; |
| 735 | 48x |
ss << " \"input_type\" : \"" << this->input_type_m << "\",\n"; |
| 736 | 48x |
ss << " \"density_component\": {\n";
|
| 737 | 48x |
ss << " \"lpdf_value\": " << this->lpdf_value << ",\n"; |
| 738 | 48x |
ss << " \"value\":["; |
| 739 | 48x |
if (this->lpdf_vec.size() == 0) {
|
| 740 | ! |
ss << "],\n"; |
| 741 |
} else {
|
|
| 742 | 1490x |
for (size_t i = 0; i < this->lpdf_vec.size() - 1; i++) {
|
| 743 | 1442x |
ss << this->value_to_string(this->lpdf_vec[i]) << ", "; |
| 744 |
} |
|
| 745 | 48x |
ss << this->value_to_string(this->lpdf_vec[this->lpdf_vec.size() - 1]); |
| 746 | ||
| 747 | 48x |
ss << "],\n"; |
| 748 |
} |
|
| 749 | 48x |
ss << " \"expected_values\":["; |
| 750 | 48x |
if (this->expected_values.size() == 0) {
|
| 751 | ! |
ss << "],\n"; |
| 752 |
} else {
|
|
| 753 | 1490x |
for (size_t i = 0; i < this->expected_values.size() - 1; i++) {
|
| 754 | 2884x |
ss << this->value_to_string(this->expected_values[i].final_value_m) |
| 755 |
<< ", "; |
|
| 756 |
} |
|
| 757 | 48x |
ss << this->value_to_string( |
| 758 | 48x |
this->expected_values[this->expected_values.size() - 1] |
| 759 | 48x |
.final_value_m); |
| 760 | ||
| 761 | 48x |
ss << "],\n"; |
| 762 |
} |
|
| 763 | 48x |
ss << " \"log_sd_values\":["; |
| 764 | 48x |
if (this->log_sd.size() == 0) {
|
| 765 | ! |
ss << "],\n"; |
| 766 |
} else {
|
|
| 767 | 1490x |
for (R_xlen_t i = 0; i < static_cast<R_xlen_t>(this->log_sd.size()) - 1; |
| 768 |
i++) {
|
|
| 769 | 1442x |
ss << this->value_to_string(this->log_sd[i].final_value_m) << ", "; |
| 770 |
} |
|
| 771 | 48x |
ss << this->value_to_string( |
| 772 | 48x |
this->log_sd[this->log_sd.size() - 1].final_value_m) |
| 773 | 48x |
<< "],\n"; |
| 774 |
} |
|
| 775 | 48x |
ss << " \"observed_values\":["; |
| 776 | 48x |
if (this->observed_values.size() == 0) {
|
| 777 | ! |
ss << "]\n"; |
| 778 |
} else {
|
|
| 779 | 1490x |
for (size_t i = 0; i < this->observed_values.size() - 1; i++) {
|
| 780 | 1442x |
ss << this->observed_values[i].final_value_m << ", "; |
| 781 |
} |
|
| 782 | 48x |
ss << this->observed_values[this->observed_values.size() - 1] |
| 783 | 48x |
.final_value_m |
| 784 | 48x |
<< "]\n"; |
| 785 |
} |
|
| 786 | 48x |
ss << " }}\n"; |
| 787 | 96x |
return ss.str(); |
| 788 |
} |
|
| 789 | ||
| 790 |
#ifdef TMB_MODEL |
|
| 791 | ||
| 792 |
template <typename Type> |
|
| 793 | 232x |
bool add_to_fims_tmb_internal() {
|
| 794 | 232x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 795 |
fims_info::Information<Type>::GetInstance(); |
|
| 796 | ||
| 797 | 232x |
std::shared_ptr<fims_distributions::LogNormalLPDF<Type>> distribution = |
| 798 |
std::make_shared<fims_distributions::LogNormalLPDF<Type>>(); |
|
| 799 | ||
| 800 |
// set relative info |
|
| 801 | 232x |
distribution->id = this->id_m; |
| 802 | 232x |
std::stringstream ss; |
| 803 | 232x |
distribution->observed_data_id_m = interface_observed_data_id_m; |
| 804 | 232x |
distribution->input_type = this->input_type_m; |
| 805 | 232x |
distribution->key.resize(this->key_m->size()); |
| 806 | 464x |
for (size_t i = 0; i < this->key_m->size(); i++) {
|
| 807 | 232x |
distribution->key[i] = this->key_m->at(i); |
| 808 |
} |
|
| 809 | 232x |
distribution->observed_values.resize(this->observed_values.size()); |
| 810 | 464x |
for (size_t i = 0; i < this->observed_values.size(); i++) {
|
| 811 | 232x |
distribution->observed_values[i] = |
| 812 | 232x |
this->observed_values[i].initial_value_m; |
| 813 |
} |
|
| 814 |
// set relative info |
|
| 815 | 232x |
distribution->expected_values.resize(this->expected_values.size()); |
| 816 | 464x |
for (size_t i = 0; i < this->expected_values.size(); i++) {
|
| 817 | 232x |
distribution->expected_values[i] = |
| 818 | 232x |
this->expected_values[i].initial_value_m; |
| 819 |
} |
|
| 820 | 232x |
distribution->log_sd.resize(this->log_sd.size()); |
| 821 | 7160x |
for (size_t i = 0; i < this->log_sd.size(); i++) {
|
| 822 | 6928x |
distribution->log_sd[i] = this->log_sd[i].initial_value_m; |
| 823 | 6928x |
if (this->log_sd[i].estimation_type_m.get() == "fixed_effects") {
|
| 824 | 4x |
ss.str("");
|
| 825 | 4x |
ss << "dlnorm." << this->id_m << ".log_sd." << this->log_sd[i].id_m; |
| 826 | 4x |
info->RegisterParameterName(ss.str()); |
| 827 | 4x |
info->RegisterParameter(distribution->log_sd[i]); |
| 828 |
} |
|
| 829 | 6928x |
if (this->log_sd[i].estimation_type_m.get() == "random_effects") {
|
| 830 | ! |
FIMS_ERROR_LOG("standard deviations cannot be set to random effects");
|
| 831 |
} |
|
| 832 |
} |
|
| 833 | 232x |
info->variable_map[this->log_sd.id_m] = &(distribution)->log_sd; |
| 834 | ||
| 835 | 232x |
info->density_components[distribution->id] = distribution; |
| 836 | ||
| 837 | 232x |
return true; |
| 838 |
} |
|
| 839 | ||
| 840 |
/** |
|
| 841 |
* @brief Adds the parameters to the TMB model. |
|
| 842 |
* @return A boolean of true. |
|
| 843 |
*/ |
|
| 844 | 58x |
virtual bool add_to_fims_tmb() {
|
| 845 | 58x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 846 | 58x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 847 | ||
| 848 | 58x |
return true; |
| 849 |
} |
|
| 850 | ||
| 851 |
#endif |
|
| 852 |
}; |
|
| 853 | ||
| 854 |
/** |
|
| 855 |
* @brief The Rcpp interface for Dmultinom to instantiate from R: |
|
| 856 |
* dmultinom_ <- methods::new(DmultinomDistribution). |
|
| 857 |
*/ |
|
| 858 |
class DmultinomDistributionsInterface : public DistributionsInterfaceBase {
|
|
| 859 |
public: |
|
| 860 |
/** |
|
| 861 |
* @brief Observed data, which should be a vector of length K of integers. |
|
| 862 |
*/ |
|
| 863 |
ParameterVector observed_values; |
|
| 864 |
/** |
|
| 865 |
* @brief The expected values, which should be a vector of length K where |
|
| 866 |
* each value specifies the probability of class k. Note that, unlike in R, |
|
| 867 |
* these probabilities must sum to 1.0. |
|
| 868 |
*/ |
|
| 869 |
ParameterVector expected_values; |
|
| 870 |
/** |
|
| 871 |
* @brief The dimensions of the number of rows and columns of the |
|
| 872 |
* multivariate dataset. |
|
| 873 |
*/ |
|
| 874 |
RealVector dims; |
|
| 875 |
/** |
|
| 876 |
* @brief Vector that records the individual log probability function for each |
|
| 877 |
* observation. |
|
| 878 |
*/ |
|
| 879 |
RealVector lpdf_vec; /**< The vector */ |
|
| 880 | ||
| 881 |
/** |
|
| 882 |
* @brief TODO: document this. |
|
| 883 |
* |
|
| 884 |
*/ |
|
| 885 |
SharedString notes; |
|
| 886 | ||
| 887 |
/** |
|
| 888 |
* @brief The constructor. |
|
| 889 |
*/ |
|
| 890 | 115x |
DmultinomDistributionsInterface() : DistributionsInterfaceBase() {
|
| 891 | 115x |
DistributionsInterfaceBase::live_objects[this->id_m] = |
| 892 | 230x |
std::make_shared<DmultinomDistributionsInterface>(*this); |
| 893 | 115x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 894 | 115x |
DistributionsInterfaceBase::live_objects[this->id_m]); |
| 895 |
} |
|
| 896 | ||
| 897 |
/** |
|
| 898 |
* @brief Construct a new Dmultinom Distributions Interface object |
|
| 899 |
* |
|
| 900 |
* @param other |
|
| 901 |
*/ |
|
| 902 | 115x |
DmultinomDistributionsInterface(const DmultinomDistributionsInterface &other) |
| 903 | 115x |
: DistributionsInterfaceBase(other), |
| 904 | 115x |
observed_values(other.observed_values), |
| 905 | 115x |
expected_values(other.expected_values), |
| 906 | 115x |
dims(other.dims), |
| 907 | 115x |
lpdf_vec(other.lpdf_vec), |
| 908 | 230x |
notes(other.notes) {}
|
| 909 | ||
| 910 |
/** |
|
| 911 |
* @brief The destructor. |
|
| 912 |
*/ |
|
| 913 | 690x |
virtual ~DmultinomDistributionsInterface() {}
|
| 914 |
/** |
|
| 915 |
* @brief Gets the ID of the interface base object. |
|
| 916 |
* @return The ID. |
|
| 917 |
*/ |
|
| 918 | ! |
virtual uint32_t get_id() { return this->id_m; }
|
| 919 | ||
| 920 |
/** |
|
| 921 |
* @brief Set the unique ID for the observed data object. |
|
| 922 |
* @param observed_data_id Unique ID for the observed data object. |
|
| 923 |
*/ |
|
| 924 | 110x |
virtual bool set_observed_data(int observed_data_id) {
|
| 925 | 110x |
this->interface_observed_data_id_m.set(observed_data_id); |
| 926 | 110x |
return true; |
| 927 |
} |
|
| 928 | ||
| 929 |
/** |
|
| 930 |
* @brief Sets pointers for data observations, random effects, or priors. |
|
| 931 |
* |
|
| 932 |
* @param input_type String that sets whether the distribution type is for |
|
| 933 |
* priors, random effects, or data. |
|
| 934 |
* @param ids Vector of unique ids for each linked parameter(s), derived |
|
| 935 |
* value(s), or observed data vector. |
|
| 936 |
*/ |
|
| 937 | 110x |
virtual bool set_distribution_links(std::string input_type, |
| 938 |
Rcpp::IntegerVector ids) {
|
|
| 939 | 110x |
this->input_type_m.set(input_type); |
| 940 | 110x |
this->key_m->resize(ids.size()); |
| 941 | 220x |
for (R_xlen_t i = 0; i < ids.size(); i++) {
|
| 942 | 110x |
this->key_m->at(i) = ids[i]; |
| 943 |
} |
|
| 944 | 110x |
return true; |
| 945 |
} |
|
| 946 | ||
| 947 |
/** |
|
| 948 |
* @brief Set the note object |
|
| 949 |
* |
|
| 950 |
* @param note |
|
| 951 |
*/ |
|
| 952 | 13x |
void set_note(std::string note) { this->notes.set(note); }
|
| 953 | ||
| 954 |
/** |
|
| 955 |
* @brief |
|
| 956 |
* |
|
| 957 |
* @return double |
|
| 958 |
*/ |
|
| 959 | 5x |
virtual double evaluate() {
|
| 960 | 5x |
fims_distributions::MultinomialLPMF<double> dmultinom; |
| 961 |
// Declare TMBVector in this scope |
|
| 962 | 5x |
dmultinom.observed_values.resize(this->observed_values.size()); |
| 963 | 5x |
dmultinom.expected_values.resize(this->expected_values.size()); |
| 964 | 56x |
for (size_t i = 0; i < observed_values.size(); i++) {
|
| 965 | 51x |
dmultinom.observed_values[i] = this->observed_values[i].initial_value_m; |
| 966 |
} |
|
| 967 | 57x |
for (size_t i = 0; i < expected_values.size(); i++) {
|
| 968 | 52x |
dmultinom.expected_values[i] = this->expected_values[i].initial_value_m; |
| 969 |
} |
|
| 970 | 5x |
dmultinom.dims.resize(2); |
| 971 | 5x |
dmultinom.dims[0] = this->dims[0]; |
| 972 | 5x |
dmultinom.dims[1] = this->dims[1]; |
| 973 | 8x |
return dmultinom.evaluate(); |
| 974 |
} |
|
| 975 | ||
| 976 | 82x |
void finalize() {
|
| 977 | 82x |
if (this->finalized) {
|
| 978 |
// log warning that finalize has been called more than once. |
|
| 979 | 4x |
FIMS_WARNING_LOG("DmultinomDistributions " +
|
| 980 |
fims::to_string(this->id_m) + |
|
| 981 |
" has been finalized already."); |
|
| 982 |
} |
|
| 983 | ||
| 984 | 82x |
this->finalized = true; // indicate this has been called already |
| 985 | ||
| 986 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 987 | 82x |
fims_info::Information<double>::GetInstance(); |
| 988 | ||
| 989 | 82x |
fims_info::Information<double>::density_components_iterator it; |
| 990 | ||
| 991 |
// search for density component in Information |
|
| 992 | 82x |
it = info->density_components.find(this->id_m); |
| 993 |
// if not found, just return |
|
| 994 | 82x |
if (it == info->density_components.end()) {
|
| 995 | ! |
FIMS_WARNING_LOG("DmultinomDistributions " + fims::to_string(this->id_m) +
|
| 996 |
" not found in Information."); |
|
| 997 | ! |
return; |
| 998 |
} else {
|
|
| 999 |
std::shared_ptr<fims_distributions::MultinomialLPMF<double>> dmultinom = |
|
| 1000 |
std::dynamic_pointer_cast< |
|
| 1001 | 82x |
fims_distributions::MultinomialLPMF<double>>(it->second); |
| 1002 | ||
| 1003 | 82x |
this->lpdf_value = dmultinom->lpdf; |
| 1004 | ||
| 1005 | 82x |
size_t n_x = dmultinom->lpdf_vec.size(); |
| 1006 | 82x |
this->lpdf_vec = Rcpp::NumericVector(n_x); |
| 1007 | 82x |
if (this->expected_values.size() != n_x) {
|
| 1008 | 78x |
this->expected_values.resize(n_x); |
| 1009 |
} |
|
| 1010 | 82x |
if (this->observed_values.size() != n_x) {
|
| 1011 | 78x |
this->observed_values.resize(n_x); |
| 1012 |
} |
|
| 1013 | 43892x |
for (size_t i = 0; i < this->lpdf_vec.size(); i++) {
|
| 1014 | 43810x |
this->lpdf_vec[i] = dmultinom->lpdf_vec[i]; |
| 1015 | 43810x |
this->expected_values[i].final_value_m = dmultinom->get_expected(i); |
| 1016 | 43810x |
if (dmultinom->input_type != "data") {
|
| 1017 | ! |
this->observed_values[i].final_value_m = dmultinom->get_observed(i); |
| 1018 |
} |
|
| 1019 |
} |
|
| 1020 | 82x |
if (dmultinom->input_type == "data") {
|
| 1021 | 82x |
dims.resize(2); |
| 1022 | 82x |
dims[0] = dmultinom->dims[0]; |
| 1023 | 82x |
dims[1] = dmultinom->dims[1]; |
| 1024 | 2642x |
for (size_t i = 0; i < dims[0]; i++) {
|
| 1025 | 46370x |
for (size_t j = 0; j < dims[1]; j++) {
|
| 1026 | 43810x |
size_t idx = (i * dims[1]) + j; |
| 1027 | 43810x |
this->observed_values[idx].final_value_m = dmultinom->get_observed( |
| 1028 |
static_cast<size_t>(i), static_cast<size_t>(j)); |
|
| 1029 |
} |
|
| 1030 |
} |
|
| 1031 |
} |
|
| 1032 |
} |
|
| 1033 |
} |
|
| 1034 | ||
| 1035 |
/** |
|
| 1036 |
* @brief Converts the data to json representation for the output. |
|
| 1037 |
* @return A string is returned specifying that the module relates to the |
|
| 1038 |
* distribution interface with a log_normal distribution. It also returns the |
|
| 1039 |
* ID and the natural log of the probability density function values |
|
| 1040 |
* themselves. This string is formatted for a json file. |
|
| 1041 |
*/ |
|
| 1042 | 82x |
virtual std::string to_json() {
|
| 1043 | 82x |
std::stringstream ss; |
| 1044 | ||
| 1045 | 82x |
ss << "{\n";
|
| 1046 | 82x |
ss << " \"module_name\": \"density\",\n"; |
| 1047 | 82x |
ss << " \"module_id\": " << this->id_m << ",\n"; |
| 1048 | 82x |
ss << " \"module_type\": \"multinomial\",\n"; |
| 1049 | 82x |
ss << "\"observed_data_id\" : " << this->interface_observed_data_id_m |
| 1050 | 82x |
<< ",\n"; |
| 1051 | 82x |
ss << " \"input_type\" : \"" << this->input_type_m << "\",\n"; |
| 1052 | 82x |
ss << " \"density_component\": {\n";
|
| 1053 | 82x |
ss << " \"lpdf_value\": " << this->lpdf_value << ",\n"; |
| 1054 | 82x |
ss << " \"value\":["; |
| 1055 | 82x |
if (this->lpdf_vec.size() == 0) {
|
| 1056 | ! |
ss << "],\n"; |
| 1057 |
} else {
|
|
| 1058 | 43810x |
for (size_t i = 0; i < this->lpdf_vec.size() - 1; i++) {
|
| 1059 | 43728x |
ss << this->value_to_string(this->lpdf_vec[i]); |
| 1060 | 43728x |
ss << ", "; |
| 1061 |
} |
|
| 1062 | 82x |
ss << this->value_to_string(this->lpdf_vec[this->lpdf_vec.size() - 1]); |
| 1063 | ||
| 1064 | 82x |
ss << "],\n"; |
| 1065 |
} |
|
| 1066 | 82x |
ss << " \"expected_values\":["; |
| 1067 | 82x |
if (this->expected_values.size() == 0) {
|
| 1068 | ! |
ss << "],\n"; |
| 1069 |
} else {
|
|
| 1070 | 43810x |
for (size_t i = 0; i < this->expected_values.size() - 1; i++) {
|
| 1071 | 87456x |
ss << this->value_to_string(this->expected_values[i].final_value_m) |
| 1072 |
<< ", "; |
|
| 1073 |
} |
|
| 1074 | 82x |
ss << this->value_to_string( |
| 1075 | 82x |
this->expected_values[this->expected_values.size() - 1] |
| 1076 | 82x |
.final_value_m); |
| 1077 | ||
| 1078 | 82x |
ss << "],\n"; |
| 1079 |
} |
|
| 1080 |
// no log_sd_values for multinomial |
|
| 1081 | 82x |
ss << " \"observed_values\":["; |
| 1082 | 82x |
if (this->observed_values.size() == 0) {
|
| 1083 | ! |
ss << "]\n"; |
| 1084 |
} else {
|
|
| 1085 | 43810x |
for (size_t i = 0; i < this->observed_values.size() - 1; i++) {
|
| 1086 | 43728x |
ss << this->observed_values[i].final_value_m << ", "; |
| 1087 |
} |
|
| 1088 | 82x |
ss << this->observed_values[this->observed_values.size() - 1] |
| 1089 | 82x |
.final_value_m |
| 1090 | 82x |
<< "]\n"; |
| 1091 |
} |
|
| 1092 | 82x |
ss << " }}\n"; |
| 1093 | 164x |
return ss.str(); |
| 1094 |
} |
|
| 1095 | ||
| 1096 |
#ifdef TMB_MODEL |
|
| 1097 | ||
| 1098 |
template <typename Type> |
|
| 1099 | 408x |
bool add_to_fims_tmb_internal() {
|
| 1100 | 816x |
FIMS_INFO_LOG("Adding multinomial to FIMS.");
|
| 1101 | 408x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 1102 |
fims_info::Information<Type>::GetInstance(); |
|
| 1103 | ||
| 1104 | 408x |
std::shared_ptr<fims_distributions::MultinomialLPMF<Type>> distribution = |
| 1105 |
std::make_shared<fims_distributions::MultinomialLPMF<Type>>(); |
|
| 1106 | ||
| 1107 | 408x |
distribution->id = this->id_m; |
| 1108 | 408x |
distribution->observed_data_id_m = interface_observed_data_id_m; |
| 1109 | 408x |
distribution->input_type = this->input_type_m; |
| 1110 | 408x |
distribution->key.resize(this->key_m->size()); |
| 1111 | 816x |
for (size_t i = 0; i < this->key_m->size(); i++) {
|
| 1112 | 408x |
distribution->key[i] = this->key_m->at(i); |
| 1113 |
} |
|
| 1114 | 408x |
distribution->observed_values.resize(this->observed_values.size()); |
| 1115 | 816x |
for (size_t i = 0; i < this->observed_values.size(); i++) {
|
| 1116 | 408x |
distribution->observed_values[i] = |
| 1117 | 408x |
this->observed_values[i].initial_value_m; |
| 1118 |
} |
|
| 1119 |
// set relative info |
|
| 1120 | 408x |
distribution->expected_values.resize(this->expected_values.size()); |
| 1121 | 816x |
for (size_t i = 0; i < this->expected_values.size(); i++) {
|
| 1122 | 408x |
distribution->expected_values[i] = |
| 1123 | 408x |
this->expected_values[i].initial_value_m; |
| 1124 |
} |
|
| 1125 | ||
| 1126 | 408x |
info->density_components[distribution->id] = distribution; |
| 1127 | 816x |
FIMS_INFO_LOG("Done adding multinomial to FIMS.");
|
| 1128 | 408x |
return true; |
| 1129 |
} |
|
| 1130 | ||
| 1131 | 102x |
virtual bool add_to_fims_tmb() {
|
| 1132 | 102x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 1133 | 102x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 1134 | ||
| 1135 | 102x |
return true; |
| 1136 |
} |
|
| 1137 | ||
| 1138 |
#endif |
|
| 1139 |
}; |
|
| 1140 | ||
| 1141 |
#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 | 71x |
FleetInterfaceBase() {
|
| 41 | 71x |
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 | 71x |
FleetInterfaceBase(const FleetInterfaceBase &other) : id(other.id) {}
|
| 53 | ||
| 54 |
/** |
|
| 55 |
* @brief The destructor. |
|
| 56 |
*/ |
|
| 57 | 142x |
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 | 71x |
FleetInterface() : FleetInterfaceBase() {
|
| 235 |
std::shared_ptr<FleetInterface> fleet = |
|
| 236 | 71x |
std::make_shared<FleetInterface>(*this); |
| 237 | 71x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back(fleet); |
| 238 |
/* Create instance of map: key is id and value is pointer to |
|
| 239 |
FleetInterfaceBase */ |
|
| 240 | 71x |
FleetInterfaceBase::live_objects[this->id] = fleet; |
| 241 |
} |
|
| 242 | ||
| 243 |
/** |
|
| 244 |
* @brief Construct a new Fleet Interface object |
|
| 245 |
* |
|
| 246 |
* @param other |
|
| 247 |
*/ |
|
| 248 | 71x |
FleetInterface(const FleetInterface &other) |
| 249 | 71x |
: FleetInterfaceBase(other), |
| 250 | 71x |
interface_observed_agecomp_data_id_m( |
| 251 | 71x |
other.interface_observed_agecomp_data_id_m), |
| 252 | 71x |
interface_observed_lengthcomp_data_id_m( |
| 253 | 71x |
other.interface_observed_lengthcomp_data_id_m), |
| 254 | 71x |
interface_observed_index_data_id_m( |
| 255 | 71x |
other.interface_observed_index_data_id_m), |
| 256 | 71x |
interface_observed_landings_data_id_m( |
| 257 | 71x |
other.interface_observed_landings_data_id_m), |
| 258 | 71x |
interface_selectivity_id_m(other.interface_selectivity_id_m), |
| 259 | 71x |
name(other.name), |
| 260 | 71x |
n_ages(other.n_ages), |
| 261 | 71x |
n_lengths(other.n_lengths), |
| 262 | 71x |
n_years(other.n_years), |
| 263 | 71x |
observed_landings_units(other.observed_landings_units), |
| 264 | 71x |
observed_index_units(other.observed_index_units), |
| 265 | 71x |
log_q(other.log_q), |
| 266 | 71x |
log_Fmort(other.log_Fmort), |
| 267 | 71x |
log_landings_expected(other.log_landings_expected), |
| 268 | 71x |
log_index_expected(other.log_index_expected), |
| 269 | 71x |
agecomp_expected(other.agecomp_expected), |
| 270 | 71x |
lengthcomp_expected(other.lengthcomp_expected), |
| 271 | 71x |
agecomp_proportion(other.agecomp_proportion), |
| 272 | 71x |
lengthcomp_proportion(other.lengthcomp_proportion), |
| 273 | 71x |
age_to_length_conversion(other.age_to_length_conversion), |
| 274 | 71x |
derived_landings_naa(other.derived_landings_naa), |
| 275 | 71x |
derived_landings_nal(other.derived_landings_nal), |
| 276 | 71x |
derived_landings_waa(other.derived_landings_waa), |
| 277 | 71x |
derived_landings_expected(other.derived_landings_expected), |
| 278 | 71x |
derived_landings_w(other.derived_landings_w), |
| 279 | 71x |
derived_landings_n(other.derived_landings_n), |
| 280 | 71x |
derived_index_naa(other.derived_index_naa), |
| 281 | 71x |
derived_index_nal(other.derived_index_nal), |
| 282 | 71x |
derived_index_waa(other.derived_index_waa), |
| 283 | 71x |
derived_index_expected(other.derived_index_expected), |
| 284 | 71x |
derived_index_w(other.derived_index_w), |
| 285 | 71x |
derived_index_n(other.derived_index_n), |
| 286 | 71x |
derived_agecomp_proportion(other.derived_agecomp_proportion), |
| 287 | 71x |
derived_lengthcomp_proportion(other.derived_lengthcomp_proportion), |
| 288 | 71x |
derived_agecomp_expected(other.derived_agecomp_expected), |
| 289 | 142x |
derived_lengthcomp_expected(other.derived_lengthcomp_expected) {}
|
| 290 | ||
| 291 |
/** |
|
| 292 |
* @brief The destructor. |
|
| 293 |
*/ |
|
| 294 | 426x |
virtual ~FleetInterface() {}
|
| 295 | ||
| 296 |
/** |
|
| 297 |
* @brief Gets the ID of the interface base object. |
|
| 298 |
* @return The ID. |
|
| 299 |
*/ |
|
| 300 | 206x |
virtual uint32_t get_id() { return this->id; }
|
| 301 | ||
| 302 |
/** |
|
| 303 |
* @brief Sets the name of the fleet. |
|
| 304 |
* @param name The name to set. |
|
| 305 |
*/ |
|
| 306 | ! |
void SetName(const std::string &name) { this->name.set(name); }
|
| 307 | ||
| 308 |
/** |
|
| 309 |
* @brief Gets the name of the fleet. |
|
| 310 |
* @return The name. |
|
| 311 |
*/ |
|
| 312 | ! |
std::string GetName() const { return this->name.get(); }
|
| 313 | ||
| 314 |
/** |
|
| 315 |
* @brief Set the unique ID for the observed age-composition data object. |
|
| 316 |
* @param observed_agecomp_data_id Unique ID for the observed data object. |
|
| 317 |
*/ |
|
| 318 | 64x |
void SetObservedAgeCompDataID(int observed_agecomp_data_id) {
|
| 319 | 64x |
interface_observed_agecomp_data_id_m.set(observed_agecomp_data_id); |
| 320 |
} |
|
| 321 | ||
| 322 |
/** |
|
| 323 |
* @brief Set the unique ID for the observed length-composition data object. |
|
| 324 |
* @param observed_lengthcomp_data_id Unique ID for the observed data object. |
|
| 325 |
*/ |
|
| 326 | 57x |
void SetObservedLengthCompDataID(int observed_lengthcomp_data_id) {
|
| 327 | 57x |
interface_observed_lengthcomp_data_id_m.set(observed_lengthcomp_data_id); |
| 328 |
} |
|
| 329 | ||
| 330 |
/** |
|
| 331 |
* @brief Set the unique ID for the observed index data object. |
|
| 332 |
* @param observed_index_data_id Unique ID for the observed data object. |
|
| 333 |
*/ |
|
| 334 | 35x |
void SetObservedIndexDataID(int observed_index_data_id) {
|
| 335 | 35x |
interface_observed_index_data_id_m.set(observed_index_data_id); |
| 336 |
} |
|
| 337 | ||
| 338 |
/** |
|
| 339 |
* @brief Set the unique ID for the observed landings data object. |
|
| 340 |
* @param observed_landings_data_id Unique ID for the observed data object. |
|
| 341 |
*/ |
|
| 342 | 34x |
void SetObservedLandingsDataID(int observed_landings_data_id) {
|
| 343 | 34x |
interface_observed_landings_data_id_m.set(observed_landings_data_id); |
| 344 |
} |
|
| 345 |
/** |
|
| 346 |
* @brief Set the unique ID for the selectivity object. |
|
| 347 |
* @param selectivity_id Unique ID for the observed object. |
|
| 348 |
*/ |
|
| 349 | 69x |
void SetSelectivityID(int selectivity_id) {
|
| 350 | 69x |
interface_selectivity_id_m.set(selectivity_id); |
| 351 |
} |
|
| 352 | ||
| 353 |
/** |
|
| 354 |
* @brief Get the unique ID for the selectivity object. |
|
| 355 |
* |
|
| 356 |
* @return uint32_t |
|
| 357 |
*/ |
|
| 358 | 48x |
uint32_t GetSelectivityID() { return interface_selectivity_id_m.get(); }
|
| 359 | ||
| 360 |
/** |
|
| 361 |
* @brief Get the unique ID for the observed age-composition data object. |
|
| 362 |
*/ |
|
| 363 | 107x |
int GetObservedAgeCompDataID() {
|
| 364 | 107x |
return interface_observed_agecomp_data_id_m.get(); |
| 365 |
} |
|
| 366 | ||
| 367 |
/** |
|
| 368 |
* @brief Get the unique ID for the observed length-composition data |
|
| 369 |
* object. |
|
| 370 |
*/ |
|
| 371 | 100x |
int GetObservedLengthCompDataID() {
|
| 372 | 100x |
return interface_observed_lengthcomp_data_id_m.get(); |
| 373 |
} |
|
| 374 | ||
| 375 |
/** |
|
| 376 |
* @brief Get the unique id for the observed index data object. |
|
| 377 |
*/ |
|
| 378 | 82x |
int GetObservedIndexDataID() {
|
| 379 | 82x |
return interface_observed_index_data_id_m.get(); |
| 380 |
} |
|
| 381 | ||
| 382 |
/** |
|
| 383 |
* @brief Get the unique id for the observed landings data object. |
|
| 384 |
*/ |
|
| 385 | 79x |
int GetObservedLandingsDataID() {
|
| 386 | 79x |
return interface_observed_landings_data_id_m.get(); |
| 387 |
} |
|
| 388 |
/** |
|
| 389 |
* @brief Extracts the derived quantities from `Information` to the Rcpp |
|
| 390 |
* object. |
|
| 391 |
*/ |
|
| 392 | 24x |
virtual void finalize() {
|
| 393 | 24x |
if (this->finalized) {
|
| 394 |
// log warning that finalize has been called more than once. |
|
| 395 | 1x |
FIMS_WARNING_LOG("Fleet " + fims::to_string(this->id) +
|
| 396 |
" has been finalized already."); |
|
| 397 |
} |
|
| 398 | ||
| 399 | 24x |
this->finalized = true; // indicate this has been called already |
| 400 | ||
| 401 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 402 | 24x |
fims_info::Information<double>::GetInstance(); |
| 403 | ||
| 404 | 24x |
fims_info::Information<double>::fleet_iterator it; |
| 405 | ||
| 406 | 24x |
it = info->fleets.find(this->id); |
| 407 | ||
| 408 | 24x |
if (it == info->fleets.end()) {
|
| 409 | ! |
FIMS_WARNING_LOG("Fleet " + fims::to_string(this->id) +
|
| 410 |
" not found in Information."); |
|
| 411 | ! |
return; |
| 412 |
} else {
|
|
| 413 |
std::shared_ptr<fims_popdy::Fleet<double>> fleet = |
|
| 414 | 24x |
std::dynamic_pointer_cast<fims_popdy::Fleet<double>>(it->second); |
| 415 | ||
| 416 | 769x |
for (size_t i = 0; i < this->log_Fmort.size(); i++) {
|
| 417 | 745x |
if (this->log_Fmort[i].estimation_type_m.get() == "constant") {
|
| 418 | 85x |
this->log_Fmort[i].final_value_m = this->log_Fmort[i].initial_value_m; |
| 419 |
} else {
|
|
| 420 | 660x |
this->log_Fmort[i].final_value_m = fleet->log_Fmort[i]; |
| 421 |
} |
|
| 422 |
} |
|
| 423 | ||
| 424 | 48x |
for (size_t i = 0; i < this->log_q.size(); i++) {
|
| 425 | 24x |
if (this->log_q[i].estimation_type_m.get() == "constant") {
|
| 426 | 24x |
this->log_q[i].final_value_m = this->log_q[i].initial_value_m; |
| 427 |
} else {
|
|
| 428 | ! |
this->log_q[i].final_value_m = fleet->log_q[i]; |
| 429 |
} |
|
| 430 |
} |
|
| 431 | ||
| 432 | 5268x |
for (size_t i = 0; i < fleet->age_to_length_conversion.size(); i++) {
|
| 433 | 5244x |
if (this->age_to_length_conversion[i].estimation_type_m.get() == |
| 434 |
"constant") {
|
|
| 435 | 5244x |
this->age_to_length_conversion[i].final_value_m = |
| 436 | 5244x |
this->age_to_length_conversion[i].initial_value_m; |
| 437 |
} else {
|
|
| 438 | ! |
this->age_to_length_conversion[i].final_value_m = |
| 439 | ! |
fleet->age_to_length_conversion[i]; |
| 440 |
} |
|
| 441 |
} |
|
| 442 |
} |
|
| 443 |
} |
|
| 444 | ||
| 445 |
#ifdef TMB_MODEL |
|
| 446 | ||
| 447 |
template <typename Type> |
|
| 448 | 244x |
bool add_to_fims_tmb_internal() {
|
| 449 | 244x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 450 |
fims_info::Information<Type>::GetInstance(); |
|
| 451 | ||
| 452 | 244x |
std::shared_ptr<fims_popdy::Fleet<Type>> fleet = |
| 453 |
std::make_shared<fims_popdy::Fleet<Type>>(); |
|
| 454 | ||
| 455 | 244x |
std::stringstream ss; |
| 456 | ||
| 457 |
// set relative info |
|
| 458 | 244x |
fleet->id = this->id; |
| 459 | 244x |
fleet->n_ages = this->n_ages.get(); |
| 460 | 244x |
fleet->n_lengths = this->n_lengths.get(); |
| 461 | 244x |
fleet->n_years = this->n_years.get(); |
| 462 | 244x |
fleet->observed_landings_units = this->observed_landings_units; |
| 463 | 244x |
fleet->observed_index_units = this->observed_index_units; |
| 464 | ||
| 465 | 244x |
fleet->fleet_observed_agecomp_data_id_m = |
| 466 | 244x |
interface_observed_agecomp_data_id_m.get(); |
| 467 | ||
| 468 | 244x |
fleet->fleet_observed_lengthcomp_data_id_m = |
| 469 | 244x |
interface_observed_lengthcomp_data_id_m.get(); |
| 470 | ||
| 471 | 244x |
fleet->fleet_observed_index_data_id_m = |
| 472 | 244x |
interface_observed_index_data_id_m.get(); |
| 473 | 244x |
fleet->fleet_observed_landings_data_id_m = |
| 474 | 244x |
interface_observed_landings_data_id_m.get(); |
| 475 | ||
| 476 | 244x |
fleet->fleet_selectivity_id_m = interface_selectivity_id_m.get(); |
| 477 | ||
| 478 | 244x |
fleet->log_q.resize(this->log_q.size()); |
| 479 | 488x |
for (size_t i = 0; i < this->log_q.size(); i++) {
|
| 480 | 244x |
fleet->log_q[i] = this->log_q[i].initial_value_m; |
| 481 | ||
| 482 | 244x |
if (this->log_q[i].estimation_type_m.get() == "fixed_effects") {
|
| 483 | 116x |
ss.str("");
|
| 484 | 116x |
ss << "Fleet." << this->id << ".log_q." << this->log_q[i].id_m; |
| 485 | 116x |
info->RegisterParameterName(ss.str()); |
| 486 | 116x |
info->RegisterParameter(fleet->log_q[i]); |
| 487 |
} |
|
| 488 | 244x |
if (this->log_q[i].estimation_type_m.get() == "random_effects") {
|
| 489 | ! |
ss.str("");
|
| 490 | ! |
ss << "Fleet." << this->id << ".log_q." << this->log_q[i].id_m; |
| 491 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 492 | ! |
info->RegisterRandomEffect(fleet->log_q[i]); |
| 493 |
} |
|
| 494 |
} |
|
| 495 | ||
| 496 | 488x |
FIMS_INFO_LOG("adding Fleet fmort object to TMB");
|
| 497 | 244x |
if (this->log_Fmort.size() != static_cast<size_t>(this->n_years.get())) {
|
| 498 | 2x |
FIMS_ERROR_LOG("The size of `log_Fmort` does not match `n_years`: " +
|
| 499 |
fims::to_string(this->log_Fmort.size()) + |
|
| 500 |
" != " + fims::to_string(this->n_years.get())); |
|
| 501 | 2x |
throw std::invalid_argument( |
| 502 |
"Fleet log_Fmort size mismatch." |
|
| 503 |
"Fleet log_Fmort is of size " + |
|
| 504 |
fims::to_string(this->log_Fmort.size()) + |
|
| 505 |
" and the number of years is " + |
|
| 506 |
fims::to_string(this->n_years.get())); |
|
| 507 |
} |
|
| 508 | 240x |
fleet->log_Fmort.resize(static_cast<size_t>(this->log_Fmort.size())); |
| 509 | 7640x |
for (size_t i = 0; i < log_Fmort.size(); i++) {
|
| 510 | 7400x |
fleet->log_Fmort[i] = this->log_Fmort[i].initial_value_m; |
| 511 | ||
| 512 | 7400x |
if (this->log_Fmort[i].estimation_type_m.get() == "fixed_effects") {
|
| 513 | 3480x |
ss.str("");
|
| 514 | 3480x |
ss << "Fleet." << this->id << ".log_Fmort." << this->log_Fmort[i].id_m; |
| 515 | 3480x |
info->RegisterParameterName(ss.str()); |
| 516 | 3480x |
info->RegisterParameter(fleet->log_Fmort[i]); |
| 517 |
} |
|
| 518 | 7400x |
if (this->log_Fmort[i].estimation_type_m.get() == "random_effects") {
|
| 519 | ! |
ss.str("");
|
| 520 | ! |
ss << "Fleet." << this->id << ".log_Fmort." << this->log_Fmort[i].id_m; |
| 521 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 522 | ! |
info->RegisterRandomEffect(fleet->log_Fmort[i]); |
| 523 |
} |
|
| 524 |
} |
|
| 525 |
// add to variable_map |
|
| 526 | 240x |
info->variable_map[this->log_Fmort.id_m] = &(fleet)->log_Fmort; |
| 527 | ||
| 528 | 240x |
if (this->n_lengths.get() > 0) {
|
| 529 | 200x |
fleet->age_to_length_conversion.resize( |
| 530 |
this->age_to_length_conversion.size()); |
|
| 531 | ||
| 532 | 200x |
if (this->age_to_length_conversion.size() != |
| 533 | 200x |
static_cast<size_t>(this->n_ages.get() * this->n_lengths.get())) {
|
| 534 | ! |
FIMS_ERROR_LOG( |
| 535 |
"age_to_length_conversion don't match, " + |
|
| 536 |
fims::to_string(this->age_to_length_conversion.size()) + " != " + |
|
| 537 |
fims::to_string((this->n_ages.get() * this->n_lengths.get()))); |
|
| 538 |
} |
|
| 539 | ||
| 540 | 55400x |
for (size_t i = 0; i < fleet->age_to_length_conversion.size(); i++) {
|
| 541 | 55200x |
fleet->age_to_length_conversion[i] = |
| 542 | 55200x |
this->age_to_length_conversion[i].initial_value_m; |
| 543 | 55200x |
FIMS_INFO_LOG(" adding Fleet length object to TMB in loop " +
|
| 544 |
fims::to_string(i) + " of " + |
|
| 545 |
fims::to_string(fleet->age_to_length_conversion.size())); |
|
| 546 | ||
| 547 | 55200x |
if (this->age_to_length_conversion[i].estimation_type_m.get() == |
| 548 |
"fixed_effects") {
|
|
| 549 | ! |
ss.str("");
|
| 550 | ! |
ss << "Fleet." << this->id << ".age_to_length_conversion." |
| 551 | ! |
<< this->age_to_length_conversion[i].id_m; |
| 552 | ! |
info->RegisterParameterName(ss.str()); |
| 553 | ! |
info->RegisterParameter(fleet->age_to_length_conversion[i]); |
| 554 |
} |
|
| 555 | 55200x |
if (this->age_to_length_conversion[i].estimation_type_m.get() == |
| 556 |
"random_effects") {
|
|
| 557 | ! |
FIMS_ERROR_LOG( |
| 558 |
"age_to_length_conversion cannot be set to random effects"); |
|
| 559 |
} |
|
| 560 |
} |
|
| 561 | ||
| 562 | 200x |
info->variable_map[this->age_to_length_conversion.id_m] = |
| 563 | 200x |
&(fleet)->age_to_length_conversion; |
| 564 |
} |
|
| 565 | ||
| 566 |
// add to Information |
|
| 567 | 240x |
info->fleets[fleet->id] = fleet; |
| 568 | 480x |
FIMS_INFO_LOG("done adding Fleet object to TMB");
|
| 569 | 240x |
return true; |
| 570 |
} |
|
| 571 | ||
| 572 |
/** |
|
| 573 |
* @brief Adds the parameters to the TMB model. |
|
| 574 |
* @return A boolean of true. |
|
| 575 |
*/ |
|
| 576 | 62x |
virtual bool add_to_fims_tmb() {
|
| 577 | 62x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 578 | 60x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 579 | ||
| 580 | 60x |
return true; |
| 581 |
} |
|
| 582 | ||
| 583 |
#endif |
|
| 584 |
}; |
|
| 585 | ||
| 586 |
#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 | 40x |
GrowthInterfaceBase() {
|
| 40 | 40x |
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 | 80x |
GrowthInterfaceBase(const GrowthInterfaceBase &other) : id(other.id) {}
|
| 53 | ||
| 54 |
/** |
|
| 55 |
* @brief The destructor. |
|
| 56 |
*/ |
|
| 57 | 120x |
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 An integer specifying the number of years. |
|
| 94 |
* |
|
| 95 |
*/ |
|
| 96 |
SharedInt n_years; |
|
| 97 |
/** |
|
| 98 |
* @brief A map of empirical weight-at-age values allowing multiple modules to |
|
| 99 |
* access and modify the weights without copying values between modules. |
|
| 100 |
*/ |
|
| 101 |
std::shared_ptr<std::map<int, std::map<double, double>>> ewaa; |
|
| 102 |
/** |
|
| 103 |
* @brief Have weight and age vectors been set? The default is false. |
|
| 104 |
*/ |
|
| 105 |
bool initialized = false; |
|
| 106 | ||
| 107 |
/** |
|
| 108 |
* @brief The constructor. |
|
| 109 |
*/ |
|
| 110 | 40x |
EWAAGrowthInterface() : GrowthInterfaceBase() {
|
| 111 | 40x |
this->ewaa = std::make_shared<std::map<int, std::map<double, double>>>(); |
| 112 | 40x |
GrowthInterfaceBase::live_objects[this->id] = |
| 113 | 80x |
std::make_shared<EWAAGrowthInterface>(*this); |
| 114 | 40x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 115 | 80x |
std::make_shared<EWAAGrowthInterface>(*this)); |
| 116 |
} |
|
| 117 | ||
| 118 |
/** |
|
| 119 |
* @brief Construct a new EWAAGrowthInterface object |
|
| 120 |
* |
|
| 121 |
* @param other |
|
| 122 |
*/ |
|
| 123 | 80x |
EWAAGrowthInterface(const EWAAGrowthInterface &other) |
| 124 | 80x |
: GrowthInterfaceBase(other), weights(other.weights), ages(other.ages), |
| 125 | 80x |
n_years(other.n_years), ewaa(other.ewaa), |
| 126 | 80x |
initialized(other.initialized) {}
|
| 127 | ||
| 128 |
/** |
|
| 129 |
* @brief The destructor. |
|
| 130 |
*/ |
|
| 131 | 320x |
virtual ~EWAAGrowthInterface() {}
|
| 132 | ||
| 133 |
/** |
|
| 134 |
* @brief Gets the ID of the interface base object. |
|
| 135 |
* @return The ID. |
|
| 136 |
*/ |
|
| 137 | 36x |
virtual uint32_t get_id() { return this->id; }
|
| 138 | ||
| 139 |
/** |
|
| 140 |
* @brief Create a map of input numeric vectors. |
|
| 141 |
* @param weights Type vector of weights. |
|
| 142 |
* @param ages Type vector of ages. |
|
| 143 |
* @param n_years An integer specifying the number of years. |
|
| 144 |
* @return std::map<T, T>. |
|
| 145 |
*/ |
|
| 146 | 63x |
inline std::map<int, std::map<double, double>> make_map(RealVector ages, RealVector weights, |
| 147 |
SharedInt n_years) {
|
|
| 148 | 63x |
std::map<int, std::map<double, double>> mymap; |
| 149 | 63x |
const size_t n_years_plus_one = static_cast<size_t>(n_years.get() + 1); |
| 150 |
|
|
| 151 |
// Reject invalid year counts because map keys are expected to include |
|
| 152 |
// at least one model year. |
|
| 153 | 63x |
if (n_years.get() < 1) {
|
| 154 | ! |
Rcpp::stop("EWAA Error:: n_years must be at least 1");
|
| 155 |
} |
|
| 156 | ||
| 157 |
// Reject empty vectors because we need at least one age-weight pair. |
|
| 158 |
if (weights.size() == 0 || ages.size() == 0) {
|
|
| 159 | ! |
Rcpp::stop("EWAA Error:: ages and weights must have at least one value");
|
| 160 |
} |
|
| 161 | ||
| 162 |
// Accept either: |
|
| 163 |
// 1) one weight vector by age (shared across years), or |
|
| 164 |
// 2) a full year-by-age matrix flattened as (n_years + 1) * n_ages. |
|
| 165 | 77x |
if ((weights.size() != ages.size() * n_years_plus_one) && |
| 166 | 14x |
(weights.size() != ages.size())) {
|
| 167 | 2x |
Rcpp::stop("weights size does not match ages size or ages size times "
|
| 168 |
"(n_years + 1), where the plus one is for the beginning " |
|
| 169 |
"of the year after the terminal year spawning-biomass " |
|
| 170 |
"calculations."); |
|
| 171 | 61x |
} else if (weights.size() == ages.size()) {
|
| 172 |
// One age-specific vector was provided, so replicate the same |
|
| 173 |
// weight-at-age values for every year key (0 through n_years). |
|
| 174 | 434x |
for (size_t y = 0; y < n_years_plus_one; y++) {
|
| 175 | 5486x |
for (size_t i = 0; i < ages.size(); i++) {
|
| 176 | 5064x |
mymap[y][ages[i]] = weights[i]; |
| 177 |
} |
|
| 178 |
} |
|
| 179 | 49x |
} else if (weights.size() == ages.size() * n_years_plus_one) {
|
| 180 |
// A flattened year-by-age matrix was provided, so map each block of |
|
| 181 |
// n_ages values to the corresponding year key (0 through n_years). |
|
| 182 | 1568x |
for (size_t y = 0; y < n_years_plus_one; y++) {
|
| 183 | 19747x |
for (size_t i = 0; i < ages.size(); i++) {
|
| 184 | 18228x |
mymap[y][ages[i]] = weights[y * ages.size() + i]; |
| 185 |
} |
|
| 186 |
} |
|
| 187 |
} |
|
| 188 | 61x |
return mymap; |
| 189 |
} |
|
| 190 | ||
| 191 |
/** |
|
| 192 |
* @brief Evaluate the growth using empirical weight at age. |
|
| 193 |
* @param age The age at of the individual to evaluate weight. |
|
| 194 |
* @details This can be called from R using ewaagrowth.evaluate(age). |
|
| 195 |
*/ |
|
| 196 | 3x |
virtual double evaluate(double age) {
|
| 197 | 3x |
fims_popdy::EWAAGrowth<double> EWAAGrowth; |
| 198 | ||
| 199 |
// Build the EWAA map once from R inputs the first time evaluate() is |
|
| 200 |
// called. |
|
| 201 | 3x |
if (initialized == false) {
|
| 202 | 9x |
EWAAGrowth.ewaa = make_map(this->ages, this->weights, this->n_years); |
| 203 | 1x |
initialized = true; |
| 204 |
} else {
|
|
| 205 |
// Prevent re-initializing this object with a second evaluate() call. |
|
| 206 | ! |
Rcpp::stop( |
| 207 |
"this empirical weight at age object is already initialized"); |
|
| 208 |
} |
|
| 209 | 2x |
return EWAAGrowth.evaluate(0, age); |
| 210 |
} |
|
| 211 | ||
| 212 |
/** |
|
| 213 |
* @brief Converts the data to json representation for the output. |
|
| 214 |
* @return A string is returned specifying that the module relates to the |
|
| 215 |
* growth interface with empirical weight at age. It also returns the ID, |
|
| 216 |
* the rank of 1, the dimensions, age bins, and the calculated values |
|
| 217 |
* themselves. This string is formatted for a json file. |
|
| 218 |
*/ |
|
| 219 | 24x |
virtual std::string to_json() {
|
| 220 | 24x |
std::stringstream ss; |
| 221 | 24x |
ss << "{\n";
|
| 222 | 24x |
ss << " \"module_name\": \"Growth\",\n"; |
| 223 | 24x |
ss << " \"module_type\": \"EWAA\",\n"; |
| 224 | 24x |
ss << " \"module_id\":" << this->id << ",\n"; |
| 225 | 24x |
ss << " \"parameters\": [\n{\n";
|
| 226 | 24x |
ss << " \"name\": \"weight_at_age\",\n"; |
| 227 | 24x |
ss << " \"id\": null,\n"; |
| 228 | 24x |
ss << " \"type\": \"vector\",\n"; |
| 229 | 24x |
ss << " \"dimensionality\": {\n";
|
| 230 | 24x |
ss << " \"header\": [\"n_years+1\",\"n_ages\"],\n"; |
| 231 | 24x |
ss << " \"dimensions\": [" << this->n_years.get() + 1 << "," << this->ages.size() << "]\n},\n"; |
| 232 | ||
| 233 | 24x |
ss << " \"values\": [\n"; |
| 234 | 7128x |
for (size_t i = 0; i < weights.size() - 1; i++) {
|
| 235 | 7104x |
ss << "{\n";
|
| 236 | 7104x |
ss << "\"id\": null,\n"; |
| 237 | 7104x |
ss << "\"value\": " << weights[i] << ",\n"; |
| 238 | 7104x |
ss << "\"estimated_value\": " << weights[i] << ",\n"; |
| 239 | 7104x |
ss << "\"estimation_type\": \"constant\"\n"; |
| 240 | 7104x |
ss << "},\n"; |
| 241 |
} |
|
| 242 | 24x |
ss << "{\n";
|
| 243 | 24x |
ss << "\"id\": null,\n"; |
| 244 | 24x |
ss << "\"value\": " << weights[weights.size() - 1] << ",\n"; |
| 245 | 24x |
ss << "\"estimated_value\": " << weights[weights.size() - 1] << ",\n"; |
| 246 | 24x |
ss << "\"estimation_type\": \"constant\"\n"; |
| 247 | 24x |
ss << "}\n]\n"; |
| 248 | 24x |
ss << "}\n]\n}\n"; |
| 249 | 48x |
return ss.str(); |
| 250 |
} |
|
| 251 | ||
| 252 |
#ifdef TMB_MODEL |
|
| 253 | ||
| 254 | 120x |
template <typename Type> bool add_to_fims_tmb_internal() {
|
| 255 | 120x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 256 |
fims_info::Information<Type>::GetInstance(); |
|
| 257 | ||
| 258 | 120x |
std::shared_ptr<fims_popdy::EWAAGrowth<Type>> ewaa_growth = |
| 259 |
std::make_shared<fims_popdy::EWAAGrowth<Type>>(); |
|
| 260 | ||
| 261 |
// set relative info |
|
| 262 | 120x |
ewaa_growth->id = this->id; |
| 263 | 120x |
ewaa_growth->ewaa = |
| 264 | 120x |
make_map(this->ages, this->weights, this->n_years); // this->ewaa; |
| 265 |
// add to Information |
|
| 266 | 120x |
info->growth_models[ewaa_growth->id] = ewaa_growth; |
| 267 | ||
| 268 | 120x |
return true; |
| 269 |
} |
|
| 270 | ||
| 271 |
/** |
|
| 272 |
* @brief Adds the parameters to the TMB model. |
|
| 273 |
* @return A boolean of true. |
|
| 274 |
*/ |
|
| 275 | 30x |
virtual bool add_to_fims_tmb() {
|
| 276 | 30x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 277 | 30x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 278 | ||
| 279 | 30x |
return true; |
| 280 |
} |
|
| 281 | ||
| 282 |
#endif |
|
| 283 |
}; |
|
| 284 | ||
| 285 |
#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 |
* @brief A string indicating the estimation type. Options are: constant, |
|
| 51 |
* fixed_effects, or random_effects, where the default is constant. |
|
| 52 |
*/ |
|
| 53 |
SharedString estimation_type_m = SharedString("constant");
|
|
| 54 | ||
| 55 |
/** |
|
| 56 |
* @brief The constructor for initializing a parameter. |
|
| 57 |
*/ |
|
| 58 |
Parameter(double value, std::string estimation_type) |
|
| 59 |
: id_m(Parameter::id_g++), |
|
| 60 |
initial_value_m(value), |
|
| 61 |
estimation_type_m(estimation_type) {}
|
|
| 62 | ||
| 63 |
/** |
|
| 64 |
* @brief The constructor for initializing a parameter. |
|
| 65 |
*/ |
|
| 66 | 102708x |
Parameter(const Parameter& other) |
| 67 | 102708x |
: id_m(other.id_m), |
| 68 | 102708x |
initial_value_m(other.initial_value_m), |
| 69 | 102708x |
final_value_m(other.final_value_m), |
| 70 | 102708x |
estimation_type_m(other.estimation_type_m) {}
|
| 71 | ||
| 72 |
/** |
|
| 73 |
* @brief The constructor for initializing a parameter. |
|
| 74 |
*/ |
|
| 75 | 38910x |
Parameter& operator=(const Parameter& right) {
|
| 76 |
// Check for self-assignment! |
|
| 77 | 38910x |
if (this == &right) // Same object? |
| 78 | ! |
return *this; // Yes, so skip assignment, and just return *this. |
| 79 | 38910x |
this->id_m = right.id_m; |
| 80 | 38910x |
this->initial_value_m = right.initial_value_m; |
| 81 | 38910x |
this->estimation_type_m = right.estimation_type_m; |
| 82 | 38910x |
return *this; |
| 83 |
} |
|
| 84 | ||
| 85 |
/** |
|
| 86 |
* @brief The constructor for initializing a parameter. |
|
| 87 |
*/ |
|
| 88 | 3x |
Parameter(double value) {
|
| 89 | 1x |
initial_value_m = value; |
| 90 | 1x |
id_m = Parameter::id_g++; |
| 91 |
} |
|
| 92 | ||
| 93 |
/** |
|
| 94 |
* @brief The constructor for initializing a parameter. |
|
| 95 |
* @details Set value to 0 when there is no input value. |
|
| 96 |
*/ |
|
| 97 | 255422x |
Parameter() {
|
| 98 | 127711x |
initial_value_m = 0; |
| 99 | 127711x |
id_m = Parameter::id_g++; |
| 100 |
} |
|
| 101 |
}; |
|
| 102 |
/** |
|
| 103 |
* @brief The unique ID for the variable map that points to a fims::Vector. |
|
| 104 |
*/ |
|
| 105 |
uint32_t Parameter::id_g = 0; |
|
| 106 | ||
| 107 |
/** |
|
| 108 |
* @brief Sanitize a double value by replacing NaN or Inf with -999.0. |
|
| 109 |
* |
|
| 110 |
* @param x The input double value. |
|
| 111 |
* @return The sanitized double value. |
|
| 112 |
*/ |
|
| 113 | 26330x |
inline double sanitize_val(double x) {
|
| 114 |
if (std::isnan(x) || std::isinf(x)) {
|
|
| 115 | ! |
return -999.0; |
| 116 |
} |
|
| 117 | 26330x |
return x; |
| 118 |
} |
|
| 119 | ||
| 120 |
/** |
|
| 121 |
* @brief Output for std::ostream& for a parameter. |
|
| 122 |
* |
|
| 123 |
* @param out The stream. |
|
| 124 |
* @param p A parameter. |
|
| 125 |
* @return std::ostream& |
|
| 126 |
*/ |
|
| 127 | 13165x |
std::ostream& operator<<(std::ostream& out, const Parameter& p) {
|
| 128 | 13165x |
out << "{\"id\": " << p.id_m
|
| 129 | 13165x |
<< ",\n\"value\": " << sanitize_val(p.initial_value_m) |
| 130 | 13165x |
<< ",\n\"estimated_value\": " << sanitize_val(p.final_value_m); |
| 131 | 13165x |
out << ",\n\"estimation_type\": \"" << p.estimation_type_m << "\"\n}"; |
| 132 | ||
| 133 | 13165x |
return out; |
| 134 |
} |
|
| 135 | ||
| 136 |
/** |
|
| 137 |
* @brief An Rcpp interface class that defines the ParameterVector class. |
|
| 138 |
* |
|
| 139 |
* @details An Rcpp interface class that defines the interface between R and |
|
| 140 |
* C++ for a parameter vector type. |
|
| 141 |
*/ |
|
| 142 |
class ParameterVector {
|
|
| 143 |
public: |
|
| 144 |
/** |
|
| 145 |
* @brief The static ID of the Parameter object. |
|
| 146 |
*/ |
|
| 147 |
static uint32_t id_g; |
|
| 148 |
/** |
|
| 149 |
* @brief Parameter storage. |
|
| 150 |
*/ |
|
| 151 |
std::shared_ptr<std::vector<Parameter>> storage_m; |
|
| 152 |
/** |
|
| 153 |
* @brief The local ID of the Parameter object. |
|
| 154 |
*/ |
|
| 155 |
uint32_t id_m; |
|
| 156 | ||
| 157 |
/** |
|
| 158 |
* @brief The constructor. |
|
| 159 |
*/ |
|
| 160 | 1880x |
ParameterVector() {
|
| 161 | 1880x |
this->id_m = ParameterVector::id_g++; |
| 162 | 1880x |
this->storage_m = std::make_shared<std::vector<Parameter>>(); |
| 163 | 1880x |
this->storage_m->resize(1); // push_back(Rcpp::wrap(p)); |
| 164 |
} |
|
| 165 | ||
| 166 |
/** |
|
| 167 |
* @brief The constructor. |
|
| 168 |
*/ |
|
| 169 | 90624x |
ParameterVector(const ParameterVector& other) |
| 170 | 90624x |
: storage_m(other.storage_m), id_m(other.id_m) {}
|
| 171 | ||
| 172 |
/** |
|
| 173 |
* @brief The constructor. |
|
| 174 |
*/ |
|
| 175 | 27x |
ParameterVector(size_t size) {
|
| 176 | 27x |
this->id_m = ParameterVector::id_g++; |
| 177 | 27x |
this->storage_m = std::make_shared<std::vector<Parameter>>(); |
| 178 | 27x |
this->storage_m->resize(size); |
| 179 | 288x |
for (size_t i = 0; i < size; i++) {
|
| 180 | 261x |
storage_m->at(i) = Parameter(); |
| 181 |
} |
|
| 182 |
} |
|
| 183 | ||
| 184 |
/** |
|
| 185 |
* @brief The constructor for initializing a parameter vector. |
|
| 186 |
* @param x A numeric vector. |
|
| 187 |
* @param size The number of elements to copy over. |
|
| 188 |
*/ |
|
| 189 | 2x |
ParameterVector(Rcpp::NumericVector x, size_t size) {
|
| 190 | 2x |
if (static_cast<size_t>(x.size()) != size) {
|
| 191 |
throw std::invalid_argument( |
|
| 192 |
"Error in call to ParameterVector(Rcpp::NumericVector x, size_t " |
|
| 193 | 1x |
"size): x.size() != size argument."); |
| 194 |
} else {
|
|
| 195 | 1x |
this->id_m = ParameterVector::id_g++; |
| 196 | 1x |
this->storage_m = std::make_shared<std::vector<Parameter>>(); |
| 197 |
// Use std::min to avoid comparing signed and unsigned types |
|
| 198 | 1x |
size_t n = std::min(static_cast<size_t>(x.size()), size); |
| 199 | 1x |
this->storage_m->resize(n); |
| 200 | 11x |
for (size_t i = 0; i < n; i++) {
|
| 201 | 10x |
storage_m->at(i).initial_value_m = x[i]; |
| 202 |
} |
|
| 203 |
} |
|
| 204 |
} |
|
| 205 | ||
| 206 |
/** |
|
| 207 |
* @brief The constructor for initializing a parameter vector. |
|
| 208 |
* @param v A vector of doubles. |
|
| 209 |
*/ |
|
| 210 |
ParameterVector(const fims::Vector<double>& v) {
|
|
| 211 |
this->id_m = ParameterVector::id_g++; |
|
| 212 |
this->storage_m = std::make_shared<std::vector<Parameter>>(); |
|
| 213 |
this->storage_m->resize(v.size()); |
|
| 214 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 215 |
storage_m->at(i).initial_value_m = v[i]; |
|
| 216 |
} |
|
| 217 |
} |
|
| 218 | ||
| 219 |
/** |
|
| 220 |
* @brief Destroy the Parameter Vector object. |
|
| 221 |
* |
|
| 222 |
*/ |
|
| 223 | 287312x |
virtual ~ParameterVector() {}
|
| 224 | ||
| 225 |
/** |
|
| 226 |
* @brief Gets the ID of the ParameterVector object. |
|
| 227 |
*/ |
|
| 228 | 214x |
virtual uint32_t get_id() { return this->id_m; }
|
| 229 | ||
| 230 |
/** |
|
| 231 |
* @brief The accessor where the first index starts is zero. |
|
| 232 |
* @param pos The position of the ParameterVector that you want returned. |
|
| 233 |
*/ |
|
| 234 | 440689x |
inline Parameter& operator[](size_t pos) { return this->storage_m->at(pos); }
|
| 235 | ||
| 236 |
/** |
|
| 237 |
* @brief The accessor where the first index starts at one. This function is |
|
| 238 |
* for calling accessing from R. |
|
| 239 |
* @param pos The position of the ParameterVector that you want returned. |
|
| 240 |
*/ |
|
| 241 | 2x |
SEXP at(R_xlen_t pos) {
|
| 242 | 4x |
if (static_cast<size_t>(pos) == 0 || |
| 243 | 2x |
static_cast<size_t>(pos) > this->storage_m->size()) {
|
| 244 | 1x |
throw std::invalid_argument("ParameterVector: Index out of range");
|
| 245 |
FIMS_ERROR_LOG(fims::to_string(pos) + "!<" + |
|
| 246 |
fims::to_string(this->size())); |
|
| 247 |
return NULL; |
|
| 248 |
} |
|
| 249 | 1x |
return Rcpp::wrap(this->storage_m->at(pos - 1)); |
| 250 |
} |
|
| 251 | ||
| 252 |
/** |
|
| 253 |
* @brief An internal accessor for calling a position of a ParameterVector |
|
| 254 |
* from R. |
|
| 255 |
* @param pos An integer specifying the position of the ParameterVector |
|
| 256 |
* you want returned. The first position is one and the last position is |
|
| 257 |
* the same as the size of the ParameterVector. |
|
| 258 |
*/ |
|
| 259 | 50957x |
Parameter& get(size_t pos) {
|
| 260 | 50957x |
if (pos >= this->storage_m->size()) {
|
| 261 | 1x |
throw std::invalid_argument("ParameterVector: Index out of range");
|
| 262 |
} |
|
| 263 | 50956x |
return (this->storage_m->at(pos)); |
| 264 |
} |
|
| 265 | ||
| 266 |
/** |
|
| 267 |
* @brief An internal setter for setting a position of a ParameterVector |
|
| 268 |
* from R. |
|
| 269 |
* @param pos An integer specifying the position of the ParameterVector |
|
| 270 |
* you want to set. The first position is one and the last position is the |
|
| 271 |
* same as the size of the ParameterVector. |
|
| 272 |
* @param p A numeric value specifying the value to set position `pos` to |
|
| 273 |
* in the ParameterVector. |
|
| 274 |
*/ |
|
| 275 | 37897x |
void set(size_t pos, const Parameter& p) { this->storage_m->at(pos) = p; }
|
| 276 | ||
| 277 |
/** |
|
| 278 |
* @brief Returns the size of a ParameterVector. |
|
| 279 |
*/ |
|
| 280 | 146553x |
size_t size() { return this->storage_m->size(); }
|
| 281 | ||
| 282 |
/** |
|
| 283 |
* @brief Resizes a ParameterVector to the desired length. |
|
| 284 |
* @param size An integer specifying the desired length for the |
|
| 285 |
* ParameterVector to be resized to. |
|
| 286 |
*/ |
|
| 287 | 1005x |
void resize(size_t size) { this->storage_m->resize(size); }
|
| 288 | ||
| 289 |
/** |
|
| 290 |
* @brief Sets all Parameters within a ParameterVector as estimable. |
|
| 291 |
* |
|
| 292 |
* @param estimable A boolean specifying if all Parameters within the |
|
| 293 |
* ParameterVector should be estimated within the model. A value of true |
|
| 294 |
* leads to all Parameters being estimated. |
|
| 295 |
*/ |
|
| 296 | 141x |
void set_all_estimable(bool estimable) {
|
| 297 | 23135x |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 298 | 22994x |
if (estimable) {
|
| 299 | 1908x |
this->storage_m->at(i).estimation_type_m.set("fixed_effects");
|
| 300 |
} else {
|
|
| 301 | 67074x |
this->storage_m->at(i).estimation_type_m.set("constant");
|
| 302 |
} |
|
| 303 |
} |
|
| 304 |
} |
|
| 305 | ||
| 306 |
/** |
|
| 307 |
* @brief Sets all Parameters within a ParameterVector as random effects. |
|
| 308 |
* |
|
| 309 |
* @param random A boolean specifying if all Parameters within the |
|
| 310 |
* ParameterVector should be designated as random effects. A value of true |
|
| 311 |
* leads to all Parameters being random effects. |
|
| 312 |
*/ |
|
| 313 | 61x |
void set_all_random(bool random) {
|
| 314 | 15909x |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 315 | 15848x |
if (random) {
|
| 316 | 348x |
this->storage_m->at(i).estimation_type_m.set("random_effects");
|
| 317 |
} else {
|
|
| 318 | 47196x |
this->storage_m->at(i).estimation_type_m.set("constant");
|
| 319 |
} |
|
| 320 |
} |
|
| 321 |
} |
|
| 322 | ||
| 323 |
/** |
|
| 324 |
* @brief Sets the value of all Parameters in the ParameterVector to the |
|
| 325 |
* provided value. |
|
| 326 |
* |
|
| 327 |
* @param value A double specifying the value to set all Parameters to |
|
| 328 |
* within the ParameterVector. |
|
| 329 |
*/ |
|
| 330 | 1x |
void fill(double value) {
|
| 331 | 11x |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 332 | 10x |
storage_m->at(i).initial_value_m = value; |
| 333 |
} |
|
| 334 |
} |
|
| 335 | ||
| 336 |
/** |
|
| 337 |
* @brief The printing methods for a ParameterVector. |
|
| 338 |
* |
|
| 339 |
*/ |
|
| 340 | ! |
void show() {
|
| 341 | ! |
Rcpp::Rcout << this->storage_m->data() << "\n"; |
| 342 | ||
| 343 | ! |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 344 | ! |
Rcpp::Rcout << storage_m->at(i) << " "; |
| 345 |
} |
|
| 346 |
} |
|
| 347 |
}; |
|
| 348 |
uint32_t ParameterVector::id_g = 0; |
|
| 349 | ||
| 350 |
/** |
|
| 351 |
* @brief Output for std::ostream& for a ParameterVector. |
|
| 352 |
* |
|
| 353 |
* @param out The stream. |
|
| 354 |
* @param v A ParameterVector. |
|
| 355 |
* @return std::ostream& |
|
| 356 |
*/ |
|
| 357 | 408x |
std::ostream& operator<<(std::ostream& out, ParameterVector& v) {
|
| 358 | 408x |
out << "["; |
| 359 | 408x |
size_t size = v.size(); |
| 360 | 13165x |
for (size_t i = 0; i < size - 1; i++) {
|
| 361 | 12757x |
out << v[i] << ", "; |
| 362 |
} |
|
| 363 | 408x |
out << v[size - 1] << "]"; |
| 364 | 408x |
return out; |
| 365 |
} |
|
| 366 | ||
| 367 |
/** |
|
| 368 |
* @brief An Rcpp interface class that defines the RealVector class. |
|
| 369 |
* |
|
| 370 |
* @details An Rcpp interface class that defines the interface between R and |
|
| 371 |
* C++ for a real vector type. Underlying values are held in a shared pointer |
|
| 372 |
* and are carried over to any copies of this vector. |
|
| 373 |
*/ |
|
| 374 |
class RealVector {
|
|
| 375 |
public: |
|
| 376 |
/** |
|
| 377 |
* @brief The static ID of the RealVector object. |
|
| 378 |
*/ |
|
| 379 |
static uint32_t id_g; |
|
| 380 |
/** |
|
| 381 |
* @brief real storage. |
|
| 382 |
*/ |
|
| 383 |
std::shared_ptr<std::vector<double>> storage_m; |
|
| 384 |
/** |
|
| 385 |
* @brief The local ID of the RealVector object. |
|
| 386 |
*/ |
|
| 387 |
uint32_t id_m; |
|
| 388 | ||
| 389 |
/** |
|
| 390 |
* @brief The constructor. |
|
| 391 |
*/ |
|
| 392 | 902x |
RealVector() {
|
| 393 | 902x |
this->id_m = RealVector::id_g++; |
| 394 | 902x |
this->storage_m = std::make_shared<std::vector<double>>(); |
| 395 | 902x |
this->storage_m->resize(1); |
| 396 |
} |
|
| 397 | ||
| 398 |
/** |
|
| 399 |
* @brief The constructor. |
|
| 400 |
*/ |
|
| 401 | 80655x |
RealVector(const RealVector& other) |
| 402 | 80655x |
: storage_m(other.storage_m), id_m(other.id_m) {}
|
| 403 | ||
| 404 |
/** |
|
| 405 |
* @brief The constructor. |
|
| 406 |
*/ |
|
| 407 | 74x |
RealVector(size_t size) {
|
| 408 | 74x |
this->id_m = RealVector::id_g++; |
| 409 | 74x |
this->storage_m = std::make_shared<std::vector<double>>(); |
| 410 | 74x |
this->storage_m->resize(size); |
| 411 |
} |
|
| 412 | ||
| 413 |
/** |
|
| 414 |
* @brief The constructor for initializing a real vector. |
|
| 415 |
* @param x A numeric vector. |
|
| 416 |
* @param size The number of elements to copy over. |
|
| 417 |
*/ |
|
| 418 | ! |
RealVector(Rcpp::NumericVector x, size_t size) {
|
| 419 | ! |
this->id_m = RealVector::id_g++; |
| 420 | ! |
this->storage_m = std::make_shared<std::vector<double>>(); |
| 421 | ! |
this->storage_m->assign(x.begin(), x.end()); |
| 422 |
} |
|
| 423 | ||
| 424 |
/** |
|
| 425 |
* @brief The constructor for initializing a real vector. |
|
| 426 |
* @param v A vector of doubles. |
|
| 427 |
*/ |
|
| 428 |
RealVector(const fims::Vector<double>& v) {
|
|
| 429 |
this->id_m = RealVector::id_g++; |
|
| 430 |
this->storage_m = std::make_shared<std::vector<double>>(); |
|
| 431 |
this->storage_m->resize(v.size()); |
|
| 432 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 433 |
storage_m->at(i) = v[i]; |
|
| 434 |
} |
|
| 435 |
} |
|
| 436 | ||
| 437 |
/** |
|
| 438 |
* @brief Destroy the real Vector object. |
|
| 439 |
* |
|
| 440 |
*/ |
|
| 441 | 322354x |
virtual ~RealVector() {}
|
| 442 | ||
| 443 |
/** |
|
| 444 |
* @brief |
|
| 445 |
* |
|
| 446 |
* @param v |
|
| 447 |
* @return RealVector& |
|
| 448 |
*/ |
|
| 449 | 82x |
RealVector& operator=(const Rcpp::NumericVector& v) {
|
| 450 | 82x |
this->storage_m->assign(v.begin(), v.end()); |
| 451 | 82x |
return *this; |
| 452 |
} |
|
| 453 | ||
| 454 |
/** |
|
| 455 |
* @brief Gets the ID of the RealVector object. |
|
| 456 |
*/ |
|
| 457 | ! |
virtual uint32_t get_id() { return this->id_m; }
|
| 458 | ||
| 459 |
/** |
|
| 460 |
* @brief |
|
| 461 |
* |
|
| 462 |
* @param orig |
|
| 463 |
*/ |
|
| 464 | ! |
void fromRVector(const Rcpp::NumericVector& orig) {
|
| 465 | ! |
this->storage_m->resize(orig.size()); |
| 466 | ! |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 467 | ! |
this->storage_m->at(i) = orig[i]; |
| 468 |
} |
|
| 469 |
} |
|
| 470 | ||
| 471 |
/** |
|
| 472 |
* @brief |
|
| 473 |
* |
|
| 474 |
* @return Rcpp::NumericVector |
|
| 475 |
*/ |
|
| 476 | 2x |
Rcpp::NumericVector toRVector() {
|
| 477 | 2x |
Rcpp::NumericVector ret(this->storage_m->size()); |
| 478 | 1052x |
for (size_t i = 0; i < this->size(); i++) {
|
| 479 | 1050x |
ret[i] = this->storage_m->at(i); |
| 480 |
} |
|
| 481 | ||
| 482 | 2x |
return ret; |
| 483 |
} |
|
| 484 | ||
| 485 |
/** |
|
| 486 |
* @brief The accessor where the first index starts is zero. |
|
| 487 |
* @param pos The position of the RealVector that you want returned. |
|
| 488 |
*/ |
|
| 489 | 579040x |
inline double& operator[](size_t pos) { return this->storage_m->at(pos); }
|
| 490 | ||
| 491 |
/** |
|
| 492 |
* @brief The accessor where the first index starts at one. This function is |
|
| 493 |
* for calling accessing from R. |
|
| 494 |
* @param pos The position of the ParameterVector that you want returned. |
|
| 495 |
*/ |
|
| 496 | ! |
SEXP at(R_xlen_t pos) {
|
| 497 | ! |
if (static_cast<size_t>(pos) == 0 || |
| 498 | ! |
static_cast<size_t>(pos) > this->storage_m->size()) {
|
| 499 | ! |
throw std::invalid_argument("RealVector: Index out of range");
|
| 500 |
FIMS_ERROR_LOG(fims::to_string(pos) + "!<" + |
|
| 501 |
fims::to_string(this->size())); |
|
| 502 |
return NULL; |
|
| 503 |
} |
|
| 504 | ! |
return Rcpp::wrap(this->storage_m->at(pos - 1)); |
| 505 |
} |
|
| 506 | ||
| 507 |
/** |
|
| 508 |
* @brief An internal accessor for calling a position of a RealVector |
|
| 509 |
* from R. |
|
| 510 |
* @param pos An integer specifying the position of the RealVector |
|
| 511 |
* you want returned. The first position is one and the last position is |
|
| 512 |
* the same as the size of the RealVector. |
|
| 513 |
*/ |
|
| 514 | 2x |
double& get(size_t pos) {
|
| 515 | 2x |
if (pos >= this->storage_m->size()) {
|
| 516 | ! |
throw std::invalid_argument("RealVector: Index out of range");
|
| 517 |
} |
|
| 518 | 2x |
return (this->storage_m->at(pos)); |
| 519 |
} |
|
| 520 | ||
| 521 |
/** |
|
| 522 |
* @brief An internal setter for setting a position of a RealVector |
|
| 523 |
* from R. |
|
| 524 |
* @param pos An integer specifying the position of the RealVector |
|
| 525 |
* you want to set. The first position is one and the last position is the |
|
| 526 |
* same as the size of the RealVector. |
|
| 527 |
* @param p A numeric value specifying the value to set position `pos` to |
|
| 528 |
* in the RealVector. |
|
| 529 |
*/ |
|
| 530 | 79415x |
void set(size_t pos, const double& p) { this->storage_m->at(pos) = p; }
|
| 531 | ||
| 532 |
/** |
|
| 533 |
* @brief Returns the size of a RealVector. |
|
| 534 |
*/ |
|
| 535 | 236599x |
size_t size() { return this->storage_m->size(); }
|
| 536 | ||
| 537 |
/** |
|
| 538 |
* @brief Resizes a RealVector to the desired length. |
|
| 539 |
* @param size An integer specifying the desired length for the |
|
| 540 |
* RealVector to be resized to. |
|
| 541 |
*/ |
|
| 542 | 588x |
void resize(size_t size) { this->storage_m->resize(size); }
|
| 543 | ||
| 544 |
/** |
|
| 545 |
* @brief Sets the value of all elements in the RealVector to the |
|
| 546 |
* provided value. |
|
| 547 |
* |
|
| 548 |
* @param value A double specifying the value to set all elements to |
|
| 549 |
* within the RealVector. |
|
| 550 |
*/ |
|
| 551 |
void fill(double value) {
|
|
| 552 |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
|
| 553 |
storage_m->at(i) = value; |
|
| 554 |
} |
|
| 555 |
} |
|
| 556 | ||
| 557 |
/** |
|
| 558 |
* @brief The printing methods for a RealVector. |
|
| 559 |
* |
|
| 560 |
*/ |
|
| 561 | ! |
void show() {
|
| 562 | ! |
Rcpp::Rcout << this->storage_m->data() << "\n"; |
| 563 | ||
| 564 | ! |
for (size_t i = 0; i < this->storage_m->size(); i++) {
|
| 565 | ! |
Rcpp::Rcout << storage_m->at(i) << " "; |
| 566 |
} |
|
| 567 |
} |
|
| 568 |
}; |
|
| 569 |
uint32_t RealVector::id_g = 0; |
|
| 570 | ||
| 571 |
/** |
|
| 572 |
*@brief Base class for all interface objects. |
|
| 573 |
*/ |
|
| 574 |
class FIMSRcppInterfaceBase {
|
|
| 575 |
public: |
|
| 576 |
/** |
|
| 577 |
* @brief Is the object already finalized? The default is false. |
|
| 578 |
*/ |
|
| 579 |
bool finalized = false; |
|
| 580 |
/** |
|
| 581 |
* @brief FIMS interface object vectors. |
|
| 582 |
*/ |
|
| 583 |
static std::vector<std::shared_ptr<FIMSRcppInterfaceBase>> |
|
| 584 |
fims_interface_objects; |
|
| 585 | ||
| 586 |
/** |
|
| 587 |
* @brief A virtual method to inherit to add objects to the TMB model. |
|
| 588 |
*/ |
|
| 589 | ! |
virtual bool add_to_fims_tmb() {
|
| 590 |
Rcpp::Rcout << "fims_rcpp_interface_base::add_to_fims_tmb(): Not yet " |
|
| 591 | ! |
"implemented.\n"; |
| 592 | ! |
return false; |
| 593 |
} |
|
| 594 | ||
| 595 |
/** |
|
| 596 |
* @brief Extracts derived quantities back to the Rcpp interface object from |
|
| 597 |
* the Information object. |
|
| 598 |
*/ |
|
| 599 | 154x |
virtual void finalize() {}
|
| 600 | ||
| 601 |
/** |
|
| 602 |
* @brief Convert the data to json representation for the output. |
|
| 603 |
*/ |
|
| 604 | ! |
virtual std::string to_json() {
|
| 605 | ! |
FIMS_WARNING_LOG("Method not yet defined.");
|
| 606 | ! |
return "{\"name\": \"not yet implemented\"}";
|
| 607 |
} |
|
| 608 | ||
| 609 |
/** |
|
| 610 |
* @brief Report the parameter value as a string. |
|
| 611 |
* |
|
| 612 |
* @param value |
|
| 613 |
* @return std::string |
|
| 614 |
*/ |
|
| 615 | 94496x |
std::string value_to_string(double value) {
|
| 616 | 94496x |
std::stringstream ss; |
| 617 | 94496x |
if (value == std::numeric_limits<double>::infinity()) {
|
| 618 | ! |
ss << "\"Infinity\""; |
| 619 | 94496x |
} else if (value == -std::numeric_limits<double>::infinity()) {
|
| 620 | ! |
ss << "\"-Infinity\""; |
| 621 | 94496x |
} else if (value != value) {
|
| 622 | 1150x |
ss << "-999"; |
| 623 |
} else {
|
|
| 624 |
// Set precision (R default is 16) |
|
| 625 | 93346x |
ss << std::fixed << std::setprecision(16) << value; |
| 626 |
} |
|
| 627 | 188992x |
return ss.str(); |
| 628 |
} |
|
| 629 |
/** |
|
| 630 |
* @brief Make a string of dimensions for the model. |
|
| 631 |
*/ |
|
| 632 |
std::string make_dimensions(uint32_t start, uint32_t end, uint32_t rep = 1) {
|
|
| 633 |
std::stringstream ss; |
|
| 634 | ||
| 635 |
for (size_t i = 0; i < rep; i++) {
|
|
| 636 |
for (size_t j = start; j < end; j++) {
|
|
| 637 |
ss << j << ", "; |
|
| 638 |
} |
|
| 639 |
if (i < (rep - 1)) {
|
|
| 640 |
ss << end << ", "; |
|
| 641 |
} else {
|
|
| 642 |
ss << end; |
|
| 643 |
} |
|
| 644 |
} |
|
| 645 |
return ss.str(); |
|
| 646 |
} |
|
| 647 |
}; |
|
| 648 |
std::vector<std::shared_ptr<FIMSRcppInterfaceBase>> |
|
| 649 |
FIMSRcppInterfaceBase::fims_interface_objects; |
|
| 650 | ||
| 651 |
#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 | 36x |
MaturityInterfaceBase() {
|
| 41 | 36x |
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 | 36x |
MaturityInterfaceBase(const MaturityInterfaceBase& other) : id(other.id) {}
|
| 53 | ||
| 54 |
/** |
|
| 55 |
* @brief The destructor. |
|
| 56 |
*/ |
|
| 57 | 72x |
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 | 36x |
LogisticMaturityInterface() : MaturityInterfaceBase() {
|
| 96 | 36x |
MaturityInterfaceBase::live_objects[this->id] = |
| 97 | 72x |
std::make_shared<LogisticMaturityInterface>(*this); |
| 98 | 36x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 99 | 36x |
MaturityInterfaceBase::live_objects[this->id]); |
| 100 |
} |
|
| 101 | ||
| 102 |
/** |
|
| 103 |
* @brief Construct a new Logistic Maturity Interface object |
|
| 104 |
* |
|
| 105 |
* @param other |
|
| 106 |
*/ |
|
| 107 | 36x |
LogisticMaturityInterface(const LogisticMaturityInterface& other) |
| 108 | 36x |
: MaturityInterfaceBase(other), |
| 109 | 36x |
inflection_point(other.inflection_point), |
| 110 | 36x |
slope(other.slope) {}
|
| 111 | ||
| 112 |
/** |
|
| 113 |
* @brief The destructor. |
|
| 114 |
*/ |
|
| 115 | 216x |
virtual ~LogisticMaturityInterface() {}
|
| 116 | ||
| 117 |
/** |
|
| 118 |
* @brief Gets the ID of the interface base object. |
|
| 119 |
* @return The ID. |
|
| 120 |
*/ |
|
| 121 | 35x |
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 | 24x |
virtual void finalize() {
|
| 142 | 24x |
if (this->finalized) {
|
| 143 |
// log warning that finalize has been called more than once. |
|
| 144 | 1x |
FIMS_WARNING_LOG("Logistic Maturity " + fims::to_string(this->id) +
|
| 145 |
" has been finalized already."); |
|
| 146 |
} |
|
| 147 | ||
| 148 | 24x |
this->finalized = true; // indicate this has been called already |
| 149 | ||
| 150 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 151 | 24x |
fims_info::Information<double>::GetInstance(); |
| 152 | ||
| 153 | 24x |
fims_info::Information<double>::maturity_models_iterator it; |
| 154 | ||
| 155 |
// search for maturity in Information |
|
| 156 | 24x |
it = info->maturity_models.find(this->id); |
| 157 |
// if not found, just return |
|
| 158 | 24x |
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 | 24x |
it->second); |
| 166 | ||
| 167 | 48x |
for (size_t i = 0; i < inflection_point.size(); i++) {
|
| 168 | 24x |
if (this->inflection_point[i].estimation_type_m.get() == "constant") {
|
| 169 | 24x |
this->inflection_point[i].final_value_m = |
| 170 | 24x |
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 | 48x |
for (size_t i = 0; i < slope.size(); i++) {
|
| 177 | 24x |
if (this->slope[i].estimation_type_m.get() == "constant") {
|
| 178 | 24x |
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 Converts the data to json representation for the output. |
|
| 188 |
* @return A string is returned specifying that the module relates to the |
|
| 189 |
* maturity interface with logistic maturity. It also returns the ID and the |
|
| 190 |
* parameters. This string is formatted for a json file. |
|
| 191 |
*/ |
|
| 192 | 24x |
virtual std::string to_json() {
|
| 193 | 24x |
std::stringstream ss; |
| 194 | 24x |
ss << "{\n";
|
| 195 | 24x |
ss << " \"module_name\": \"Maturity\",\n"; |
| 196 | 24x |
ss << " \"module_type\": \"Logistic\",\n"; |
| 197 | 24x |
ss << " \"module_id\": " << this->id << ",\n"; |
| 198 | ||
| 199 | 24x |
ss << " \"parameters\": [\n{\n";
|
| 200 | 24x |
ss << " \"name\": \"inflection_point\",\n"; |
| 201 | 24x |
ss << " \"id\":" << this->inflection_point.id_m << ",\n"; |
| 202 | 24x |
ss << " \"type\": \"vector\",\n"; |
| 203 | 24x |
ss << " \"dimensionality\": {\n";
|
| 204 | 24x |
ss << " \"header\": [null],\n"; |
| 205 | 24x |
ss << " \"dimensions\": [1]\n},\n"; |
| 206 | 24x |
ss << " \"values\":" << this->inflection_point << "},\n "; |
| 207 | ||
| 208 | 24x |
ss << "{\n";
|
| 209 | 24x |
ss << " \"name\": \"slope\",\n"; |
| 210 | 24x |
ss << " \"id\":" << this->slope.id_m << ",\n"; |
| 211 | 24x |
ss << " \"type\": \"vector\",\n"; |
| 212 | 24x |
ss << " \"dimensionality\": {\n";
|
| 213 | 24x |
ss << " \"header\": [null],\n"; |
| 214 | 24x |
ss << " \"dimensions\": [1]\n},\n"; |
| 215 | 24x |
ss << " \"values\":" << this->slope << "}]\n"; |
| 216 | ||
| 217 | 24x |
ss << "}"; |
| 218 | ||
| 219 | 48x |
return ss.str(); |
| 220 |
} |
|
| 221 | ||
| 222 |
#ifdef TMB_MODEL |
|
| 223 | ||
| 224 |
template <typename Type> |
|
| 225 | 120x |
bool add_to_fims_tmb_internal() {
|
| 226 | 120x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 227 |
fims_info::Information<Type>::GetInstance(); |
|
| 228 | ||
| 229 | 120x |
std::shared_ptr<fims_popdy::LogisticMaturity<Type>> maturity = |
| 230 |
std::make_shared<fims_popdy::LogisticMaturity<Type>>(); |
|
| 231 | ||
| 232 |
// set relative info |
|
| 233 | 120x |
maturity->id = this->id; |
| 234 | 120x |
std::stringstream ss; |
| 235 | 120x |
maturity->inflection_point.resize(this->inflection_point.size()); |
| 236 | 240x |
for (size_t i = 0; i < this->inflection_point.size(); i++) {
|
| 237 | 120x |
maturity->inflection_point[i] = this->inflection_point[i].initial_value_m; |
| 238 | 120x |
if (this->inflection_point[i].estimation_type_m.get() == |
| 239 |
"fixed_effects") {
|
|
| 240 | ! |
ss.str("");
|
| 241 | ! |
ss << "Maturity." << this->id << ".inflection_point." |
| 242 | ! |
<< this->inflection_point[i].id_m; |
| 243 | ! |
info->RegisterParameterName(ss.str()); |
| 244 | ! |
info->RegisterParameter(maturity->inflection_point[i]); |
| 245 |
} |
|
| 246 | 120x |
if (this->inflection_point[i].estimation_type_m.get() == |
| 247 |
"random_effects") {
|
|
| 248 | ! |
ss.str("");
|
| 249 | ! |
ss << "Maturity." << this->id << ".inflection_point." |
| 250 | ! |
<< this->inflection_point[i].id_m; |
| 251 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 252 | ! |
info->RegisterRandomEffect(maturity->inflection_point[i]); |
| 253 |
} |
|
| 254 |
} |
|
| 255 | ||
| 256 | 120x |
maturity->slope.resize(this->slope.size()); |
| 257 | 240x |
for (size_t i = 0; i < this->slope.size(); i++) {
|
| 258 | 120x |
maturity->slope[i] = this->slope[i].initial_value_m; |
| 259 | 120x |
if (this->slope[i].estimation_type_m.get() == "fixed_effects") {
|
| 260 | ! |
ss.str("");
|
| 261 | ! |
ss << "Maturity." << this->id << ".slope." << this->slope[i].id_m; |
| 262 | ! |
info->RegisterParameterName(ss.str()); |
| 263 | ! |
info->RegisterParameter(maturity->slope[i]); |
| 264 |
} |
|
| 265 | 120x |
if (this->slope[i].estimation_type_m.get() == "random_effects") {
|
| 266 | ! |
ss.str("");
|
| 267 | ! |
ss << "Maturity." << this->id << ".slope." << this->slope[i].id_m; |
| 268 | ! |
info->RegisterRandomEffect(maturity->slope[i]); |
| 269 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 270 |
} |
|
| 271 |
} |
|
| 272 | ||
| 273 |
// add to Information |
|
| 274 | 120x |
info->maturity_models[maturity->id] = maturity; |
| 275 | ||
| 276 | 120x |
return true; |
| 277 |
} |
|
| 278 | ||
| 279 |
/** |
|
| 280 |
* @brief Adds the parameters to the TMB model. |
|
| 281 |
* @return A boolean of true. |
|
| 282 |
*/ |
|
| 283 | 30x |
virtual bool add_to_fims_tmb() {
|
| 284 | 30x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 285 | 30x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 286 | ||
| 287 | 30x |
return true; |
| 288 |
} |
|
| 289 | ||
| 290 |
#endif |
|
| 291 |
}; |
|
| 292 | ||
| 293 |
#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 | ||
| 17 |
#include "rcpp_interface_base.hpp" |
|
| 18 |
#include "rcpp_population.hpp" |
|
| 19 |
#include "rcpp_fleet.hpp" |
|
| 20 |
#include "rcpp_maturity.hpp" |
|
| 21 |
#include "rcpp_recruitment.hpp" |
|
| 22 |
#include "rcpp_selectivity.hpp" |
|
| 23 |
#include <valarray> |
|
| 24 |
#include <cmath> |
|
| 25 |
#include <mutex> |
|
| 26 | ||
| 27 |
/** |
|
| 28 |
* @brief The FisheryModelInterfaceBase class is the base class for all fishery |
|
| 29 |
* models in the FIMS Rcpp interface. It inherits from the |
|
| 30 |
* FIMSRcppInterfaceBase. |
|
| 31 |
* |
|
| 32 |
*/ |
|
| 33 |
class FisheryModelInterfaceBase : public FIMSRcppInterfaceBase {
|
|
| 34 |
public: |
|
| 35 |
/** |
|
| 36 |
* @brief The static id of the FleetInterfaceBase object. |
|
| 37 |
*/ |
|
| 38 |
static uint32_t id_g; |
|
| 39 |
/** |
|
| 40 |
* @brief The local id of the FleetInterfaceBase object. |
|
| 41 |
*/ |
|
| 42 |
uint32_t id; |
|
| 43 |
/** |
|
| 44 |
* @brief The map associating the IDs of FleetInterfaceBase to the objects. |
|
| 45 |
* This is a live object, which is an object that has been created and lives |
|
| 46 |
* in memory. |
|
| 47 |
*/ |
|
| 48 |
static std::map<uint32_t, std::shared_ptr<FisheryModelInterfaceBase>> |
|
| 49 |
live_objects; |
|
| 50 | ||
| 51 |
/** |
|
| 52 |
* @brief The constructor. |
|
| 53 |
*/ |
|
| 54 | 31x |
FisheryModelInterfaceBase() {
|
| 55 | 31x |
this->id = FisheryModelInterfaceBase::id_g++; |
| 56 |
/* Create instance of map: key is id and value is pointer to |
|
| 57 |
FleetInterfaceBase */ |
|
| 58 |
// FisheryModelInterfaceBase::live_objects[this->id] = this; |
|
| 59 |
} |
|
| 60 | ||
| 61 |
/** |
|
| 62 |
* @brief Construct a new Data Interface Base object |
|
| 63 |
* |
|
| 64 |
* @param other |
|
| 65 |
*/ |
|
| 66 | 31x |
FisheryModelInterfaceBase(const FisheryModelInterfaceBase &other) |
| 67 | 31x |
: id(other.id) {}
|
| 68 | ||
| 69 |
/** |
|
| 70 |
* @brief The destructor. |
|
| 71 |
*/ |
|
| 72 | 62x |
virtual ~FisheryModelInterfaceBase() {}
|
| 73 | ||
| 74 |
/** |
|
| 75 |
* @brief Serialize the fishery model to a JSON string. |
|
| 76 |
* |
|
| 77 |
* This method provides a standardized interface for converting the state of |
|
| 78 |
* a fishery model into a JSON-formatted string. The JSON output is intended |
|
| 79 |
* for use in reporting, diagnostics, or data exchange between C++ and R. |
|
| 80 |
* Derived classes should override this method to provide model-specific |
|
| 81 |
* serialization logic. |
|
| 82 |
* |
|
| 83 |
* @return A JSON string representing the current state of the model. The |
|
| 84 |
* base implementation returns a placeholder string indicating the method is |
|
| 85 |
* not yet implemented. |
|
| 86 |
*/ |
|
| 87 | ! |
virtual std::string to_json() {
|
| 88 | ! |
return "std::string to_json() not yet implemented."; |
| 89 |
} |
|
| 90 | ||
| 91 |
/** |
|
| 92 |
* @brief Get the ID for the child fleet interface objects to inherit. |
|
| 93 |
*/ |
|
| 94 |
virtual uint32_t get_id() = 0; |
|
| 95 |
}; |
|
| 96 |
// static id of the FleetInterfaceBase object |
|
| 97 |
uint32_t FisheryModelInterfaceBase::id_g = 1; |
|
| 98 | ||
| 99 |
// FleetInterfaceBase to the FleetInterfaceBase objects |
|
| 100 |
std::map<uint32_t, std::shared_ptr<FisheryModelInterfaceBase>> |
|
| 101 |
FisheryModelInterfaceBase::live_objects; |
|
| 102 | ||
| 103 |
/** |
|
| 104 |
* @brief The CatchAtAgeInterface class is used to interface with the |
|
| 105 |
* CatchAtAge model. It inherits from the FisheryModelInterfaceBase class. |
|
| 106 |
*/ |
|
| 107 |
class CatchAtAgeInterface : public FisheryModelInterfaceBase {
|
|
| 108 |
/** |
|
| 109 |
* @brief The set of population ids that this catch at age model operates on. |
|
| 110 |
*/ |
|
| 111 |
std::shared_ptr<std::set<uint32_t>> population_ids; |
|
| 112 |
/** |
|
| 113 |
* @brief Iterator for population ids. |
|
| 114 |
*/ |
|
| 115 |
typedef typename std::set<uint32_t>::iterator population_id_iterator; |
|
| 116 | ||
| 117 |
/** |
|
| 118 |
* @brief A private working map of standard error values for all |
|
| 119 |
* concatenated derived quantities. Elements are extracted in the |
|
| 120 |
* to_json method. |
|
| 121 |
*/ |
|
| 122 |
std::map<std::string, std::vector<double>> se_values; |
|
| 123 | ||
| 124 |
public: |
|
| 125 |
/** |
|
| 126 |
* @brief The constructor. |
|
| 127 |
*/ |
|
| 128 | 31x |
CatchAtAgeInterface() : FisheryModelInterfaceBase() {
|
| 129 | 31x |
this->population_ids = std::make_shared<std::set<uint32_t>>(); |
| 130 |
std::shared_ptr<CatchAtAgeInterface> caa = |
|
| 131 | 31x |
std::make_shared<CatchAtAgeInterface>(*this); |
| 132 | 31x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back(caa); |
| 133 | 31x |
FisheryModelInterfaceBase::live_objects[this->id] = caa; |
| 134 |
} |
|
| 135 | ||
| 136 |
/** |
|
| 137 |
* @brief Construct a new Catch At Age Interface object |
|
| 138 |
* |
|
| 139 |
* @param other |
|
| 140 |
*/ |
|
| 141 | 31x |
CatchAtAgeInterface(const CatchAtAgeInterface &other) |
| 142 | 31x |
: FisheryModelInterfaceBase(other), |
| 143 | 31x |
population_ids(other.population_ids) {}
|
| 144 | ||
| 145 |
/** |
|
| 146 |
* Method to add a population id to the set of population ids. |
|
| 147 |
*/ |
|
| 148 | 31x |
void AddPopulation(uint32_t id) {
|
| 149 | 31x |
this->population_ids->insert(id); |
| 150 | ||
| 151 | 31x |
std::map<uint32_t, std::shared_ptr<PopulationInterfaceBase>>::iterator pit; |
| 152 | 31x |
pit = PopulationInterfaceBase::live_objects.find(id); |
| 153 | 31x |
if (pit != PopulationInterfaceBase::live_objects.end()) {
|
| 154 | 31x |
std::shared_ptr<PopulationInterfaceBase> &pop = (*pit).second; |
| 155 | 31x |
pop->initialize_catch_at_age.set(true); |
| 156 |
} else {
|
|
| 157 | ! |
FIMS_ERROR_LOG("Population with id " + fims::to_string(id) +
|
| 158 |
" not found."); |
|
| 159 |
} |
|
| 160 |
} |
|
| 161 | ||
| 162 |
/** |
|
| 163 |
* @brief Enable or disable reporting for the CatchAtAge model. |
|
| 164 |
* |
|
| 165 |
* @details This method is used to control whether reporting is performed for |
|
| 166 |
* the CatchAtAge model. The implementation may depend on TMB_MODEL. |
|
| 167 |
* @param report Boolean flag to enable (true) or disable (false) reporting. |
|
| 168 |
*/ |
|
| 169 | ! |
void DoReporting(bool report) {
|
| 170 |
#ifdef TMB_MODEL |
|
| 171 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 172 | ! |
fims_info::Information<double>::GetInstance(); |
| 173 | ! |
typename fims_info::Information<double>::model_map_iterator model_it; |
| 174 | ! |
model_it = info->models_map.find(this->get_id()); |
| 175 | ! |
if (model_it != info->models_map.end()) {
|
| 176 |
std::shared_ptr<fims_popdy::CatchAtAge<double>> model_ptr = |
|
| 177 |
std::dynamic_pointer_cast<fims_popdy::CatchAtAge<double>>( |
|
| 178 | ! |
(*model_it).second); |
| 179 | ! |
model_ptr->do_reporting = report; |
| 180 |
} |
|
| 181 |
#endif |
|
| 182 |
} |
|
| 183 | ||
| 184 |
/** |
|
| 185 |
* @brief Check if reporting is enabled for the CatchAtAge model. |
|
| 186 |
* |
|
| 187 |
* @details Returns true if reporting is enabled, false otherwise. The |
|
| 188 |
* implementation may depend on TMB_MODEL. |
|
| 189 |
* @return Boolean indicating reporting status. |
|
| 190 |
*/ |
|
| 191 | ! |
bool IsReporting() {
|
| 192 |
#ifdef TMB_MODEL |
|
| 193 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 194 | ! |
fims_info::Information<double>::GetInstance(); |
| 195 | ! |
typename fims_info::Information<double>::model_map_iterator model_it; |
| 196 | ! |
model_it = info->models_map.find(this->get_id()); |
| 197 | ! |
if (model_it != info->models_map.end()) {
|
| 198 |
std::shared_ptr<fims_popdy::CatchAtAge<double>> model_ptr = |
|
| 199 |
std::dynamic_pointer_cast<fims_popdy::CatchAtAge<double>>( |
|
| 200 | ! |
(*model_it).second); |
| 201 | ! |
return model_ptr->do_reporting; |
| 202 |
} |
|
| 203 | ! |
return false; |
| 204 |
#else |
|
| 205 |
return false; |
|
| 206 |
#endif |
|
| 207 |
} |
|
| 208 | ||
| 209 |
/** |
|
| 210 |
* @brief Method to get this id. |
|
| 211 |
*/ |
|
| 212 | 178x |
virtual uint32_t get_id() { return this->id; }
|
| 213 | ||
| 214 |
/** |
|
| 215 |
* |
|
| 216 |
*/ |
|
| 217 | ! |
virtual void finalize() {}
|
| 218 | ||
| 219 |
/** |
|
| 220 |
* @brief Method to convert a population to a JSON string. |
|
| 221 |
*/ |
|
| 222 | 24x |
std::string population_to_json(PopulationInterface *population_interface) {
|
| 223 | 24x |
std::stringstream ss; |
| 224 | ||
| 225 |
typename std::map<uint32_t, |
|
| 226 |
std::shared_ptr<PopulationInterfaceBase>>::iterator |
|
| 227 | 24x |
pi_it; // population interface iterator |
| 228 | 24x |
pi_it = PopulationInterfaceBase::live_objects.find( |
| 229 | 24x |
population_interface->get_id()); |
| 230 | 24x |
if (pi_it == PopulationInterfaceBase::live_objects.end()) {
|
| 231 | ! |
FIMS_ERROR_LOG("Population with id " +
|
| 232 |
fims::to_string(population_interface->get_id()) + |
|
| 233 |
" not found in live objects."); |
|
| 234 | ! |
return "{}"; // Return empty JSON
|
| 235 |
} |
|
| 236 | ||
| 237 |
std::shared_ptr<PopulationInterface> population_interface_ptr = |
|
| 238 | 24x |
std::dynamic_pointer_cast<PopulationInterface>((*pi_it).second); |
| 239 | ||
| 240 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 241 | 24x |
fims_info::Information<double>::GetInstance(); |
| 242 | ||
| 243 | 24x |
typename fims_info::Information<double>::model_map_iterator model_it; |
| 244 | 24x |
model_it = info->models_map.find(this->get_id()); |
| 245 |
std::shared_ptr<fims_popdy::CatchAtAge<double>> model_ptr = |
|
| 246 |
std::dynamic_pointer_cast<fims_popdy::CatchAtAge<double>>( |
|
| 247 | 24x |
(*model_it).second); |
| 248 | ||
| 249 | 24x |
typename fims_info::Information<double>::population_iterator pit; |
| 250 | ||
| 251 | 24x |
pit = info->populations.find(population_interface->get_id()); |
| 252 | ||
| 253 | 24x |
if (pit != info->populations.end()) {
|
| 254 | 24x |
std::shared_ptr<fims_popdy::Population<double>> &pop = (*pit).second; |
| 255 | 24x |
ss << "{\n";
|
| 256 | ||
| 257 | 24x |
ss << " \"module_name\": \"Population\",\n"; |
| 258 | 24x |
ss << " \"population\": \"" << population_interface->name << "\",\n"; |
| 259 | 24x |
ss << " \"module_id\": " << population_interface->id << ",\n"; |
| 260 | 24x |
ss << " \"recruitment_id\": " << population_interface->recruitment_id |
| 261 | 24x |
<< ",\n"; |
| 262 | 24x |
ss << " \"growth_id\": " << population_interface->growth_id << ",\n"; |
| 263 | 24x |
ss << " \"maturity_id\": " << population_interface->maturity_id << ",\n"; |
| 264 | ||
| 265 | 24x |
ss << " \"parameters\": [\n"; |
| 266 | 8964x |
for (size_t i = 0; i < pop->log_M.size(); i++) {
|
| 267 | 8940x |
population_interface_ptr->log_M[i].final_value_m = pop->log_M[i]; |
| 268 |
} |
|
| 269 | ||
| 270 | 24x |
ss << "{\n \"name\": \"log_M\",\n";
|
| 271 | 24x |
ss << " \"id\":" << population_interface->log_M.id_m << ",\n"; |
| 272 | 24x |
ss << " \"type\": \"vector\",\n"; |
| 273 | 24x |
ss << " \"dimensionality\": {\n";
|
| 274 | 24x |
ss << " \"header\": [" << "\"n_years\", \"n_ages\"" << "],\n"; |
| 275 | 24x |
ss << " \"dimensions\": [" << population_interface->n_years.get() << ", " |
| 276 | 24x |
<< population_interface->n_ages.get() << "]\n},\n"; |
| 277 | 24x |
ss << " \"values\": " << population_interface->log_M << "\n\n"; |
| 278 | 24x |
ss << "},\n"; |
| 279 | ||
| 280 | 769x |
for (size_t i = 0; i < pop->log_f_multiplier.size(); i++) {
|
| 281 | 745x |
population_interface_ptr->log_f_multiplier[i].final_value_m = |
| 282 | 745x |
pop->log_f_multiplier[i]; |
| 283 |
} |
|
| 284 | ||
| 285 | 24x |
ss << "{\n \"name\": \"log_f_multiplier\",\n";
|
| 286 | 24x |
ss << " \"id\":" << population_interface->log_f_multiplier.id_m << ",\n"; |
| 287 | 24x |
ss << " \"type\": \"vector\",\n"; |
| 288 | 24x |
ss << " \"dimensionality\": {\n";
|
| 289 | 24x |
ss << " \"header\": [" << "\"n_years\"" << "],\n"; |
| 290 | 24x |
ss << " \"dimensions\": [" << population_interface->n_years.get() |
| 291 | 24x |
<< "]\n},\n"; |
| 292 | 24x |
ss << " \"values\": " << population_interface->log_f_multiplier << "\n\n"; |
| 293 | 24x |
ss << "},\n"; |
| 294 | ||
| 295 | 793x |
for (size_t i = 0; i < pop->spawning_biomass_ratio.size(); i++) {
|
| 296 | 769x |
population_interface_ptr->spawning_biomass_ratio[i].final_value_m = |
| 297 | 769x |
pop->spawning_biomass_ratio[i]; |
| 298 |
} |
|
| 299 | ||
| 300 | 24x |
ss << "{\n \"name\": \"spawning_biomass_ratio\",\n";
|
| 301 | 24x |
ss << " \"id\":" << population_interface->spawning_biomass_ratio.id_m |
| 302 | 24x |
<< ",\n"; |
| 303 | 24x |
ss << " \"type\": \"vector\",\n"; |
| 304 | 24x |
ss << " \"dimensionality\": {\n";
|
| 305 | 24x |
ss << " \"header\": [" << "\"n_years\"" << "],\n"; |
| 306 | 24x |
ss << " \"dimensions\": [" << (population_interface->n_years.get() + 1) |
| 307 | 24x |
<< "]\n},\n"; |
| 308 | 24x |
ss << " \"values\": " << population_interface->spawning_biomass_ratio |
| 309 | 24x |
<< "\n\n"; |
| 310 | 24x |
ss << "},\n"; |
| 311 | ||
| 312 | 312x |
for (size_t i = 0; i < pop->log_init_naa.size(); i++) {
|
| 313 | 288x |
population_interface_ptr->log_init_naa[i].final_value_m = |
| 314 | 288x |
pop->log_init_naa[i]; |
| 315 |
} |
|
| 316 | 24x |
ss << " {\n\"name\": \"log_init_naa\",\n";
|
| 317 | 24x |
ss << " \"id\":" << population_interface->log_init_naa.id_m << ",\n"; |
| 318 | 24x |
ss << " \"type\": \"vector\",\n"; |
| 319 | 24x |
ss << " \"dimensionality\": {\n";
|
| 320 | 24x |
ss << " \"header\": [" << "\"n_ages\"" << "],\n"; |
| 321 | 24x |
ss << " \"dimensions\": [" << population_interface->n_ages.get() |
| 322 | 24x |
<< "]\n},\n"; |
| 323 | ||
| 324 | 24x |
ss << " \"values\":" << population_interface->log_init_naa << "\n"; |
| 325 | 24x |
ss << "}],\n"; |
| 326 | ||
| 327 | 24x |
ss << " \"derived_quantities\": [\n"; |
| 328 | ||
| 329 |
std::map<std::string, fims::Vector<double>> dqs = |
|
| 330 | 48x |
model_ptr->GetPopulationDerivedQuantities( |
| 331 | 48x |
population_interface->get_id()); |
| 332 | ||
| 333 |
std::map<std::string, fims_popdy::DimensionInfo> dim_info = |
|
| 334 | 24x |
model_ptr->GetPopulationDimensionInfo(population_interface->get_id()); |
| 335 | 48x |
ss << this->derived_quantities_component_to_json(dqs, dim_info) |
| 336 | 24x |
<< " ]}\n"; |
| 337 |
} else {
|
|
| 338 | ! |
ss << "{\n";
|
| 339 | ! |
ss << " \"name\": \"Population\",\n"; |
| 340 | ||
| 341 | ! |
ss << " \"type\": \"population\",\n"; |
| 342 | ! |
ss << " \"tag\": \"" << population_interface->get_id() |
| 343 | ! |
<< " not found in Information.\",\n"; |
| 344 | ! |
ss << " \"id\": " << population_interface->get_id() << ",\n"; |
| 345 | ! |
ss << " \"recruitment_id\": " << population_interface->recruitment_id |
| 346 | ! |
<< ",\n"; |
| 347 | ! |
ss << " \"growth_id\": " << population_interface->growth_id << ",\n"; |
| 348 | ! |
ss << " \"maturity_id\": " << population_interface->maturity_id << ",\n"; |
| 349 | ! |
ss << " \"derived_quantities\": []}\n"; |
| 350 |
} |
|
| 351 | ||
| 352 | 24x |
return ss.str(); |
| 353 |
} |
|
| 354 | ||
| 355 |
/** |
|
| 356 |
* This function is used to convert the derived quantities of a population or |
|
| 357 |
* fleet to a JSON string. This function is used to create the JSON output for |
|
| 358 |
* the CatchAtAge model. |
|
| 359 |
*/ |
|
| 360 | 1248x |
std::string derived_quantity_to_json( |
| 361 |
std::map<std::string, fims::Vector<double>>::iterator it, |
|
| 362 |
const fims_popdy::DimensionInfo &dim_info) {
|
|
| 363 | 1248x |
std::stringstream ss; |
| 364 | 1248x |
fims::Vector<double> &dq = (*it).second; |
| 365 | 1248x |
std::stringstream dim_entry; |
| 366 |
// gather dimension information |
|
| 367 | 1248x |
switch (dim_info.ndims) {
|
| 368 | 600x |
case 1: |
| 369 | 600x |
dim_entry << "\"dimensionality\": {\n";
|
| 370 | 600x |
dim_entry << " \"header\": [\"" << dim_info.dim_names[0] << "\"],\n"; |
| 371 | 600x |
dim_entry << " \"dimensions\": ["; |
| 372 | 1200x |
for (size_t i = 0; i < dim_info.dims.size(); ++i) {
|
| 373 |
if (i > 0) dim_entry << ", "; |
|
| 374 | 600x |
dim_entry << dim_info.dims[i]; |
| 375 |
} |
|
| 376 | 600x |
dim_entry << "]\n"; |
| 377 | 600x |
dim_entry << "}"; |
| 378 | 600x |
break; |
| 379 | 648x |
case 2: |
| 380 | 648x |
dim_entry << "\"dimensionality\": {\n";
|
| 381 |
dim_entry << " \"header\": [\"" << dim_info.dim_names[0] << "\", \"" |
|
| 382 | 648x |
<< dim_info.dim_names[1] << "\"],\n"; |
| 383 | 648x |
dim_entry << " \"dimensions\": ["; |
| 384 | 1944x |
for (size_t i = 0; i < dim_info.dims.size(); ++i) {
|
| 385 | 1296x |
if (i > 0) dim_entry << ", "; |
| 386 | 1296x |
dim_entry << dim_info.dims[i]; |
| 387 |
} |
|
| 388 | 648x |
dim_entry << "]\n"; |
| 389 | 648x |
dim_entry << "}"; |
| 390 | 648x |
break; |
| 391 | ! |
case 3: |
| 392 | ! |
dim_entry << "\"dimensionality\": {\n";
|
| 393 |
dim_entry << " \"header\": [\"" << dim_info.dim_names[0] << "\", \"" |
|
| 394 |
<< dim_info.dim_names[1] << "\", \"" << dim_info.dim_names[2] |
|
| 395 | ! |
<< "\"],\n"; |
| 396 | ! |
dim_entry << " \"dimensions\": ["; |
| 397 | ! |
for (size_t i = 0; i < dim_info.dims.size(); ++i) {
|
| 398 | ! |
if (i > 0) dim_entry << ", "; |
| 399 | ! |
dim_entry << dim_info.dims[i]; |
| 400 |
} |
|
| 401 | ! |
dim_entry << "]\n"; |
| 402 | ! |
dim_entry << "}"; |
| 403 | ! |
break; |
| 404 | ! |
default: |
| 405 | ! |
dim_entry << "\"dimensionality\": {\n";
|
| 406 | ! |
dim_entry << " \"header\": [],\n"; |
| 407 | ! |
dim_entry << " \"dimensions\": []\n"; |
| 408 | ! |
dim_entry << "}"; |
| 409 | ! |
break; |
| 410 |
} |
|
| 411 | ||
| 412 |
// build JSON string |
|
| 413 | 1248x |
ss << "{\n";
|
| 414 | 1248x |
ss << "\"name\":\"" << (*it).first << "\",\n"; |
| 415 | 1248x |
ss << dim_entry.str() << ",\n"; |
| 416 | 1248x |
ss << "\"value\":["; |
| 417 | 1248x |
ss << std::fixed << std::setprecision(10); |
| 418 | 1248x |
if (dq.size() > 0) {
|
| 419 | 298949x |
for (size_t i = 0; i < dq.size() - 1; i++) {
|
| 420 | 297741x |
if (dq[i] != dq[i]) // check for NaN |
| 421 |
{
|
|
| 422 | 2284x |
ss << "-999" << ", "; |
| 423 |
} else {
|
|
| 424 | 295457x |
ss << dq[i] << ", "; |
| 425 |
} |
|
| 426 |
} |
|
| 427 | 1208x |
if (dq[dq.size() - 1] != dq[dq.size() - 1]) // check for NaN |
| 428 |
{
|
|
| 429 | 16x |
ss << "-999]" << "\n"; |
| 430 |
} else {
|
|
| 431 | 1192x |
ss << dq[dq.size() - 1] << "]\n"; |
| 432 |
} |
|
| 433 |
} else {
|
|
| 434 | 40x |
ss << "]\n"; |
| 435 |
} |
|
| 436 | 1248x |
ss << "}"; |
| 437 | ||
| 438 | 2496x |
return ss.str(); |
| 439 |
} |
|
| 440 | ||
| 441 |
/** |
|
| 442 |
* @brief Send the fleet-based derived quantities to the json file. |
|
| 443 |
* @return std::string |
|
| 444 |
*/ |
|
| 445 | 72x |
std::string derived_quantities_component_to_json( |
| 446 |
std::map<std::string, fims::Vector<double>> &dqs, |
|
| 447 |
std::map<std::string, fims_popdy::DimensionInfo> &dim_info) {
|
|
| 448 | 72x |
std::stringstream ss; |
| 449 | 72x |
std::map<std::string, fims_popdy::DimensionInfo>::iterator dim_info_it; |
| 450 | 72x |
std::map<std::string, fims::Vector<double>>::iterator it; |
| 451 | 72x |
std::map<std::string, fims::Vector<double>>::iterator end_it; |
| 452 | 72x |
end_it = dqs.end(); |
| 453 |
typename std::map<std::string, fims::Vector<double>>::iterator |
|
| 454 | 72x |
second_to_last; |
| 455 | 72x |
second_to_last = dqs.end(); |
| 456 | 72x |
if (it != end_it) {
|
| 457 | 72x |
second_to_last--; |
| 458 |
} |
|
| 459 | ||
| 460 | 72x |
it = dqs.begin(); |
| 461 | 1248x |
for (; it != second_to_last; ++it) {
|
| 462 | 1176x |
dim_info_it = dim_info.find(it->first); |
| 463 | 1176x |
ss << this->derived_quantity_to_json(it, dim_info_it->second) << ",\n"; |
| 464 |
} |
|
| 465 | ||
| 466 | 72x |
dim_info_it = dim_info.find(second_to_last->first); |
| 467 | 72x |
if (dim_info_it != dim_info.end()) {
|
| 468 | 144x |
ss << this->derived_quantity_to_json(second_to_last, dim_info_it->second) |
| 469 | 72x |
<< "\n"; |
| 470 |
} else {
|
|
| 471 | ! |
ss << "{}";
|
| 472 |
// Handle case where dimension info is not found |
|
| 473 |
} |
|
| 474 | 144x |
return ss.str(); |
| 475 |
} |
|
| 476 | ||
| 477 |
/** |
|
| 478 |
* @brief Method to convert a fleet to a JSON string. |
|
| 479 |
*/ |
|
| 480 | 48x |
std::string fleet_to_json(FleetInterface *fleet_interface) {
|
| 481 | 48x |
std::stringstream ss; |
| 482 | ||
| 483 | 48x |
if (!fleet_interface) {
|
| 484 | ! |
FIMS_ERROR_LOG( |
| 485 |
"Fleet pointer is null; cannot get id. Not found in live objects."); |
|
| 486 | ! |
return "{}"; // Return empty JSON
|
| 487 |
} |
|
| 488 | ||
| 489 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 490 | 48x |
fims_info::Information<double>::GetInstance(); |
| 491 | ||
| 492 | 48x |
typename fims_info::Information<double>::model_map_iterator model_it; |
| 493 | 48x |
model_it = info->models_map.find(this->get_id()); |
| 494 |
std::shared_ptr<fims_popdy::CatchAtAge<double>> model_ptr = |
|
| 495 |
std::dynamic_pointer_cast<fims_popdy::CatchAtAge<double>>( |
|
| 496 | 48x |
(*model_it).second); |
| 497 | ||
| 498 | 48x |
typename fims_info::Information<double>::fleet_iterator fit; |
| 499 | ||
| 500 | 48x |
fit = info->fleets.find(fleet_interface->get_id()); |
| 501 | ||
| 502 | 48x |
if (fit != info->fleets.end()) {
|
| 503 | 48x |
std::shared_ptr<fims_popdy::Fleet<double>> &fleet = (*fit).second; |
| 504 | ||
| 505 | 48x |
ss << "{\n";
|
| 506 | 48x |
ss << " \"module_name\": \"Fleet\",\n"; |
| 507 | 48x |
ss << " \"fleet\": \"" << fleet_interface->name << "\",\n"; |
| 508 | 48x |
ss << " \"module_id\": " << fleet_interface->id << ",\n"; |
| 509 | 48x |
ss << " \"n_ages\": " << fleet_interface->n_ages.get() << ",\n"; |
| 510 | 48x |
ss << " \"n_years\": " << fleet_interface->n_years.get() << ",\n"; |
| 511 | 48x |
ss << " \"n_lengths\": " << fleet_interface->n_lengths.get() << ",\n"; |
| 512 | 48x |
ss << "\"data_ids\" : [\n"; |
| 513 | 48x |
ss << "{\"agecomp\": " << fleet_interface->GetObservedAgeCompDataID()
|
| 514 | 48x |
<< "},\n"; |
| 515 | 48x |
ss << "{\"lengthcomp\": "
|
| 516 | 48x |
<< fleet_interface->GetObservedLengthCompDataID() << "},\n"; |
| 517 | 48x |
ss << "{\"index\": " << fleet_interface->GetObservedIndexDataID()
|
| 518 | 48x |
<< "},\n"; |
| 519 | 48x |
ss << "{\"landings\": " << fleet_interface->GetObservedLandingsDataID()
|
| 520 | 48x |
<< "}\n"; |
| 521 | 48x |
ss << "],\n"; |
| 522 | 48x |
ss << "\"parameters\": [\n"; |
| 523 | 48x |
ss << "{\n";
|
| 524 | 1538x |
for (size_t i = 0; i < fleet_interface->log_Fmort.size(); i++) {
|
| 525 | 1490x |
fleet_interface->log_Fmort[i].final_value_m = fleet->log_Fmort[i]; |
| 526 |
} |
|
| 527 | ||
| 528 | 48x |
ss << " \"name\": \"log_Fmort\",\n"; |
| 529 | 48x |
ss << " \"id\":" << fleet_interface->log_Fmort.id_m << ",\n"; |
| 530 | 48x |
ss << " \"type\": \"vector\",\n"; |
| 531 | 48x |
ss << " \"dimensionality\": {\n";
|
| 532 | 48x |
ss << " \"header\": [\"" << "n_years" << "\"],\n"; |
| 533 | 48x |
ss << " \"dimensions\": [" << fleet_interface->n_years.get() |
| 534 | 48x |
<< "]\n},\n"; |
| 535 | 48x |
ss << " \"values\": " << fleet_interface->log_Fmort << "},\n"; |
| 536 | ||
| 537 | 48x |
ss << " {\n";
|
| 538 | 96x |
for (size_t i = 0; i < fleet->log_q.size(); i++) {
|
| 539 | 48x |
fleet_interface->log_q[i].final_value_m = fleet->log_q[i]; |
| 540 |
} |
|
| 541 | 48x |
ss << " \"name\": \"log_q\",\n"; |
| 542 | 48x |
ss << " \"id\":" << fleet_interface->log_q.id_m << ",\n"; |
| 543 | 48x |
ss << " \"type\": \"vector\",\n"; |
| 544 | 48x |
ss << " \"dimensionality\": {\n";
|
| 545 | 48x |
ss << " \"header\": [\"" << "na" << "\"],\n"; |
| 546 | 48x |
ss << " \"dimensions\": [" << fleet->log_q.size() << "]\n},\n"; |
| 547 | ||
| 548 | 48x |
ss << " \"values\": " << fleet_interface->log_q << "}\n"; |
| 549 | ||
| 550 | 48x |
ss << "], \"derived_quantities\": ["; |
| 551 | ||
| 552 |
std::map<std::string, fims::Vector<double>> dqs = |
|
| 553 | 48x |
model_ptr->GetFleetDerivedQuantities(fleet_interface->get_id()); |
| 554 |
std::map<std::string, fims_popdy::DimensionInfo> dim_info = |
|
| 555 | 48x |
model_ptr->GetFleetDimensionInfo(fleet_interface->get_id()); |
| 556 | 48x |
ss << this->derived_quantities_component_to_json(dqs, dim_info) << "]}\n"; |
| 557 |
} else {
|
|
| 558 | ! |
ss << "{\n";
|
| 559 | ! |
ss << " \"name\": \"Fleet\",\n"; |
| 560 | ! |
ss << " \"type\": \"fleet\",\n"; |
| 561 | ! |
ss << " \"tag\": \"" << fleet_interface->get_id() |
| 562 | ! |
<< " not found in Information.\",\n"; |
| 563 | ! |
ss << " \"derived_quantities\": []}\n"; |
| 564 |
} |
|
| 565 | 48x |
return ss.str(); |
| 566 |
} |
|
| 567 | ||
| 568 |
/** |
|
| 569 |
* @brief Get the vector of fixed effect parameters for the CatchAtAge model. |
|
| 570 |
* |
|
| 571 |
* @details Returns a numeric vector containing the fixed effect parameters |
|
| 572 |
* used in the model. |
|
| 573 |
* @return Rcpp::NumericVector of fixed effect parameters. |
|
| 574 |
*/ |
|
| 575 |
Rcpp::NumericVector get_fixed_parameters_vector() {
|
|
| 576 |
// base model |
|
| 577 |
std::shared_ptr<fims_info::Information<double>> info0 = |
|
| 578 |
fims_info::Information<double>::GetInstance(); |
|
| 579 | ||
| 580 |
Rcpp::NumericVector p; |
|
| 581 | ||
| 582 |
for (size_t i = 0; i < info0->fixed_effects_parameters.size(); i++) {
|
|
| 583 |
p.push_back(*info0->fixed_effects_parameters[i]); |
|
| 584 |
} |
|
| 585 | ||
| 586 |
return p; |
|
| 587 |
} |
|
| 588 | ||
| 589 |
/** |
|
| 590 |
* @brief Get the vector of random effect parameters for the CatchAtAge model. |
|
| 591 |
* |
|
| 592 |
* @details Returns a numeric vector containing the random effect parameters |
|
| 593 |
* used in the model. |
|
| 594 |
* @return Rcpp::NumericVector of random effect parameters. |
|
| 595 |
*/ |
|
| 596 |
Rcpp::NumericVector get_random_parameters_vector() {
|
|
| 597 |
// base model |
|
| 598 |
std::shared_ptr<fims_info::Information<double>> d0 = |
|
| 599 |
fims_info::Information<double>::GetInstance(); |
|
| 600 | ||
| 601 |
Rcpp::NumericVector p; |
|
| 602 | ||
| 603 |
for (size_t i = 0; i < d0->random_effects_parameters.size(); i++) {
|
|
| 604 |
p.push_back(*d0->random_effects_parameters[i]); |
|
| 605 |
} |
|
| 606 | ||
| 607 |
return p; |
|
| 608 |
} |
|
| 609 | ||
| 610 |
/** |
|
| 611 |
* @copydoc FisheryModelInterfaceBase::to_json |
|
| 612 |
*/ |
|
| 613 | 24x |
virtual std::string to_json() {
|
| 614 | 24x |
std::set<uint32_t> recruitment_ids; |
| 615 | 24x |
std::set<uint32_t> growth_ids; |
| 616 | 24x |
std::set<uint32_t> maturity_ids; |
| 617 | 24x |
std::set<uint32_t> selectivity_ids; |
| 618 | 24x |
std::set<uint32_t> fleet_ids; |
| 619 |
// gather sub-module info from population and fleets |
|
| 620 | 24x |
typename std::set<uint32_t>::iterator module_id_it; // generic |
| 621 | 24x |
typename std::set<uint32_t>::iterator pit; |
| 622 | 24x |
typename std::set<uint32_t>::iterator fids; |
| 623 | 24x |
for (pit = this->population_ids->begin(); |
| 624 | 48x |
pit != this->population_ids->end(); pit++) {
|
| 625 |
std::shared_ptr<PopulationInterface> population_interface = |
|
| 626 |
std::dynamic_pointer_cast<PopulationInterface>( |
|
| 627 | 24x |
PopulationInterfaceBase::live_objects[*pit]); |
| 628 | 24x |
if (population_interface) {
|
| 629 | 24x |
recruitment_ids.insert(population_interface->recruitment_id.get()); |
| 630 | 24x |
growth_ids.insert(population_interface->growth_id.get()); |
| 631 | 24x |
maturity_ids.insert(population_interface->maturity_id.get()); |
| 632 | ||
| 633 | 24x |
for (fids = population_interface->fleet_ids->begin(); |
| 634 | 72x |
fids != population_interface->fleet_ids->end(); fids++) {
|
| 635 | 48x |
fleet_ids.insert(*fids); |
| 636 |
} |
|
| 637 |
} |
|
| 638 |
} |
|
| 639 | ||
| 640 | 72x |
for (fids = fleet_ids.begin(); fids != fleet_ids.end(); fids++) {
|
| 641 |
std::shared_ptr<FleetInterface> fleet_interface = |
|
| 642 |
std::dynamic_pointer_cast<FleetInterface>( |
|
| 643 | 48x |
FleetInterfaceBase::live_objects[*fids]); |
| 644 | 48x |
if (fleet_interface) {
|
| 645 | 48x |
selectivity_ids.insert(fleet_interface->GetSelectivityID()); |
| 646 |
} |
|
| 647 |
} |
|
| 648 | ||
| 649 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 650 | 24x |
fims_info::Information<double>::GetInstance(); |
| 651 | ||
| 652 |
std::shared_ptr<fims_popdy::CatchAtAge<double>> model = |
|
| 653 |
std::dynamic_pointer_cast<fims_popdy::CatchAtAge<double>>( |
|
| 654 | 24x |
info->models_map[this->get_id()]); |
| 655 | ||
| 656 |
std::shared_ptr<fims_model::Model<double>> model_internal = |
|
| 657 | 24x |
fims_model::Model<double>::GetInstance(); |
| 658 | ||
| 659 |
#ifdef TMB_MODEL |
|
| 660 | 24x |
model->do_reporting = false; |
| 661 |
#endif |
|
| 662 | ||
| 663 | 24x |
double value = model_internal->Evaluate(); |
| 664 | ||
| 665 | 24x |
std::stringstream ss; |
| 666 | ||
| 667 | 24x |
ss.str("");
|
| 668 | ||
| 669 | 24x |
ss << "{\n";
|
| 670 | 24x |
ss << " \"name\": \"CatchAtAge\",\n"; |
| 671 | 24x |
ss << " \"type\": \"model\",\n"; |
| 672 | 24x |
ss << " \"estimation_framework\": "; |
| 673 |
#ifdef TMB_MODEL |
|
| 674 | 24x |
ss << "\"Template_Model_Builder (TMB)\","; |
| 675 |
#else |
|
| 676 |
ss << "\"FIMS\","; |
|
| 677 |
#endif |
|
| 678 | 24x |
ss << " \"id\": " << this->get_id() << ",\n"; |
| 679 | 24x |
ss << " \"objective_function_value\": " << value << ",\n"; |
| 680 | 24x |
ss << "\"growth\":[\n"; |
| 681 | 48x |
for (module_id_it = growth_ids.begin(); module_id_it != growth_ids.end(); |
| 682 | 24x |
module_id_it++) {
|
| 683 |
std::shared_ptr<GrowthInterfaceBase> growth_interface = |
|
| 684 | 24x |
GrowthInterfaceBase::live_objects[*module_id_it]; |
| 685 | ||
| 686 | 24x |
if (growth_interface != NULL) {
|
| 687 | 24x |
growth_interface->finalize(); |
| 688 | 24x |
ss << growth_interface->to_json(); |
| 689 | 48x |
if (std::next(module_id_it) != growth_ids.end()) {
|
| 690 | ! |
ss << ", "; |
| 691 |
} |
|
| 692 |
} |
|
| 693 |
} |
|
| 694 | ||
| 695 | 24x |
ss << "],\n"; |
| 696 | ||
| 697 | 24x |
ss << "\"recruitment\": [\n"; |
| 698 | 24x |
for (module_id_it = recruitment_ids.begin(); |
| 699 | 48x |
module_id_it != recruitment_ids.end(); module_id_it++) {
|
| 700 |
std::shared_ptr<RecruitmentInterfaceBase> recruitment_interface = |
|
| 701 | 24x |
RecruitmentInterfaceBase::live_objects[*module_id_it]; |
| 702 | 24x |
if (recruitment_interface) {
|
| 703 | 24x |
recruitment_interface->finalize(); |
| 704 | 24x |
ss << recruitment_interface->to_json(); |
| 705 | 48x |
if (std::next(module_id_it) != recruitment_ids.end()) {
|
| 706 | ! |
ss << ", "; |
| 707 |
} |
|
| 708 |
} |
|
| 709 |
} |
|
| 710 | 24x |
ss << "],\n"; |
| 711 | ||
| 712 | 24x |
ss << "\"maturity\": [\n"; |
| 713 | 24x |
for (module_id_it = maturity_ids.begin(); |
| 714 | 48x |
module_id_it != maturity_ids.end(); module_id_it++) {
|
| 715 |
std::shared_ptr<MaturityInterfaceBase> maturity_interface = |
|
| 716 | 24x |
MaturityInterfaceBase::live_objects[*module_id_it]; |
| 717 | 24x |
if (maturity_interface) {
|
| 718 | 24x |
maturity_interface->finalize(); |
| 719 | 24x |
ss << maturity_interface->to_json(); |
| 720 | 48x |
if (std::next(module_id_it) != maturity_ids.end()) {
|
| 721 | ! |
ss << ", "; |
| 722 |
} |
|
| 723 |
} |
|
| 724 |
} |
|
| 725 | 24x |
ss << "],\n"; |
| 726 | ||
| 727 | 24x |
ss << "\"selectivity\": [\n"; |
| 728 | 24x |
for (module_id_it = selectivity_ids.begin(); |
| 729 | 72x |
module_id_it != selectivity_ids.end(); module_id_it++) {
|
| 730 |
std::shared_ptr<SelectivityInterfaceBase> selectivity_interface = |
|
| 731 | 48x |
SelectivityInterfaceBase::live_objects[*module_id_it]; |
| 732 | 48x |
if (selectivity_interface) {
|
| 733 | 48x |
selectivity_interface->finalize(); |
| 734 | 48x |
ss << selectivity_interface->to_json(); |
| 735 | 96x |
if (std::next(module_id_it) != selectivity_ids.end()) {
|
| 736 | 24x |
ss << ", "; |
| 737 |
} |
|
| 738 |
} |
|
| 739 |
} |
|
| 740 | 24x |
ss << "],\n"; |
| 741 | ||
| 742 | 24x |
ss << " \"population_ids\": ["; |
| 743 | 24x |
for (pit = this->population_ids->begin(); |
| 744 | 48x |
pit != this->population_ids->end(); pit++) {
|
| 745 | 24x |
ss << *pit; |
| 746 | 48x |
if (std::next(pit) != this->population_ids->end()) {
|
| 747 | ! |
ss << ", "; |
| 748 |
} |
|
| 749 |
} |
|
| 750 | 24x |
ss << "],\n"; |
| 751 | 24x |
ss << " \"fleet_ids\": ["; |
| 752 | ||
| 753 | 72x |
for (fids = fleet_ids.begin(); fids != fleet_ids.end(); fids++) {
|
| 754 | 48x |
ss << *fids; |
| 755 | 96x |
if (std::next(fids) != fleet_ids.end()) {
|
| 756 | 24x |
ss << ", "; |
| 757 |
} |
|
| 758 |
} |
|
| 759 | 24x |
ss << "],\n"; |
| 760 | 24x |
ss << "\"populations\": [\n"; |
| 761 | 24x |
typename std::set<uint32_t>::iterator pop_it; |
| 762 | 24x |
typename std::set<uint32_t>::iterator pop_end_it; |
| 763 | 24x |
pop_end_it = this->population_ids->end(); |
| 764 | 24x |
typename std::set<uint32_t>::iterator pop_second_to_last_it; |
| 765 | 24x |
if (pop_end_it != this->population_ids->begin()) {
|
| 766 | 24x |
pop_second_to_last_it = std::prev(pop_end_it); |
| 767 |
} else {
|
|
| 768 | ! |
pop_second_to_last_it = pop_end_it; |
| 769 |
} |
|
| 770 | 24x |
for (pop_it = this->population_ids->begin(); |
| 771 |
pop_it != pop_second_to_last_it; pop_it++) {
|
|
| 772 |
std::shared_ptr<PopulationInterface> population_interface = |
|
| 773 |
std::dynamic_pointer_cast<PopulationInterface>( |
|
| 774 | ! |
PopulationInterfaceBase::live_objects[*pop_it]); |
| 775 | ! |
if (population_interface) {
|
| 776 | ! |
std::set<uint32_t>::iterator fids; |
| 777 | ! |
for (fids = population_interface->fleet_ids->begin(); |
| 778 | ! |
fids != population_interface->fleet_ids->end(); fids++) {
|
| 779 | ! |
fleet_ids.insert(*fids); |
| 780 |
} |
|
| 781 | ! |
population_interface->finalize(); |
| 782 | ! |
ss << this->population_to_json(population_interface.get()) << ","; |
| 783 |
} else {
|
|
| 784 | ! |
FIMS_ERROR_LOG("Population with id " + fims::to_string(*pop_it) +
|
| 785 |
" not found in live objects."); |
|
| 786 | ! |
ss << "{}"; // Return empty JSON for this population
|
| 787 |
} |
|
| 788 |
} |
|
| 789 | ||
| 790 |
std::shared_ptr<PopulationInterface> population_interface = |
|
| 791 |
std::dynamic_pointer_cast<PopulationInterface>( |
|
| 792 | 24x |
PopulationInterfaceBase::live_objects[*pop_second_to_last_it]); |
| 793 | 24x |
if (population_interface) {
|
| 794 | 24x |
std::set<uint32_t>::iterator fids; |
| 795 | 24x |
for (fids = population_interface->fleet_ids->begin(); |
| 796 | 72x |
fids != population_interface->fleet_ids->end(); fids++) {
|
| 797 | 48x |
fleet_ids.insert(*fids); |
| 798 |
} |
|
| 799 | 24x |
ss << this->population_to_json(population_interface.get()); |
| 800 |
} else {
|
|
| 801 | ! |
FIMS_ERROR_LOG("Population with id " + fims::to_string(*pop_it) +
|
| 802 |
" not found in live objects."); |
|
| 803 | ! |
ss << "{}"; // Return empty JSON for this population
|
| 804 |
} |
|
| 805 | ||
| 806 | 24x |
ss << "]"; |
| 807 | 24x |
ss << ",\n"; |
| 808 | 24x |
ss << "\"fleets\": [\n"; |
| 809 | ||
| 810 | 24x |
typename std::set<uint32_t>::iterator fleet_it; |
| 811 | 24x |
typename std::set<uint32_t>::iterator fleet_end_it; |
| 812 | 24x |
fleet_end_it = fleet_ids.end(); |
| 813 | 24x |
typename std::set<uint32_t>::iterator fleet_second_to_last_it; |
| 814 | ||
| 815 | 24x |
if (fleet_end_it != fleet_ids.begin()) {
|
| 816 | 24x |
fleet_second_to_last_it = std::prev(fleet_end_it); |
| 817 |
} |
|
| 818 | 48x |
for (fleet_it = fleet_ids.begin(); fleet_it != fleet_second_to_last_it; |
| 819 | 24x |
fleet_it++) {
|
| 820 |
std::shared_ptr<FleetInterface> fleet_interface = |
|
| 821 |
std::dynamic_pointer_cast<FleetInterface>( |
|
| 822 | 24x |
FleetInterfaceBase::live_objects[*fleet_it]); |
| 823 | 24x |
if (fleet_interface) {
|
| 824 | 24x |
fleet_interface->finalize(); |
| 825 | 24x |
ss << this->fleet_to_json(fleet_interface.get()) << ","; |
| 826 |
} else {
|
|
| 827 | ! |
FIMS_ERROR_LOG("Fleet with id " + fims::to_string(*fleet_it) +
|
| 828 |
" not found in live objects."); |
|
| 829 | ! |
ss << "{}"; // Return empty JSON for this fleet
|
| 830 |
} |
|
| 831 |
} |
|
| 832 |
std::shared_ptr<FleetInterface> fleet_interface = |
|
| 833 |
std::dynamic_pointer_cast<FleetInterface>( |
|
| 834 | 24x |
FleetInterfaceBase::live_objects[*fleet_second_to_last_it]); |
| 835 | 24x |
if (fleet_interface) {
|
| 836 | 24x |
ss << this->fleet_to_json(fleet_interface.get()); |
| 837 |
} else {
|
|
| 838 | ! |
FIMS_ERROR_LOG("Fleet with id " + fims::to_string(*fleet_it) +
|
| 839 |
" not found in live objects."); |
|
| 840 | ! |
ss << "{}"; // Return empty JSON for this fleet
|
| 841 |
} |
|
| 842 | ||
| 843 | 24x |
ss << "],\n"; |
| 844 | ||
| 845 | 24x |
ss << "\"density_components\": [\n"; |
| 846 | ||
| 847 |
typename std::map< |
|
| 848 | 24x |
uint32_t, std::shared_ptr<DistributionsInterfaceBase>>::iterator dit; |
| 849 | 24x |
for (dit = DistributionsInterfaceBase::live_objects.begin(); |
| 850 | 180x |
dit != DistributionsInterfaceBase::live_objects.end(); ++dit) {
|
| 851 |
std::shared_ptr<DistributionsInterfaceBase> dist_interface = |
|
| 852 | 156x |
(*dit).second; |
| 853 | 156x |
if (dist_interface) {
|
| 854 | 156x |
dist_interface->finalize(); |
| 855 | 156x |
ss << dist_interface->to_json(); |
| 856 | 312x |
if (std::next(dit) != DistributionsInterfaceBase::live_objects.end()) {
|
| 857 | 132x |
ss << ",\n"; |
| 858 |
} |
|
| 859 |
} |
|
| 860 |
} |
|
| 861 | 24x |
ss << "\n],\n"; |
| 862 | 24x |
ss << "\"data\": [\n"; |
| 863 |
typename std::map<uint32_t, std::shared_ptr<DataInterfaceBase>>::iterator |
|
| 864 | 24x |
d_it; |
| 865 | 24x |
for (d_it = DataInterfaceBase::live_objects.begin(); |
| 866 | 154x |
d_it != DataInterfaceBase::live_objects.end(); ++d_it) {
|
| 867 | 130x |
std::shared_ptr<DataInterfaceBase> data_interface = (*d_it).second; |
| 868 | 130x |
if (data_interface) {
|
| 869 | 130x |
data_interface->finalize(); |
| 870 | 130x |
ss << data_interface->to_json(); |
| 871 | 260x |
if (std::next(d_it) != DataInterfaceBase::live_objects.end()) {
|
| 872 | 106x |
ss << ",\n"; |
| 873 |
} |
|
| 874 |
} |
|
| 875 |
} |
|
| 876 | 24x |
ss << "\n],\n"; |
| 877 |
// add log |
|
| 878 | 24x |
ss << " \"log\": {\n";
|
| 879 | 24x |
ss << "\"info\": " << fims::FIMSLog::fims_log->get_info() << "," |
| 880 | 48x |
<< "\"warnings\": " << fims::FIMSLog::fims_log->get_warnings() << "," |
| 881 | 72x |
<< "\"errors\": " << fims::FIMSLog::fims_log->get_errors() << "}}"; |
| 882 |
#ifdef TMB_MODEL |
|
| 883 | 24x |
model->do_reporting = true; |
| 884 |
#endif |
|
| 885 | 48x |
return fims::JsonParser::PrettyFormatJSON(ss.str()); |
| 886 |
} |
|
| 887 | ||
| 888 |
/** |
|
| 889 |
* @brief Sum method to calculate the sum of an array or vector of doubles. |
|
| 890 |
* |
|
| 891 |
* @param v |
|
| 892 |
* @return double |
|
| 893 |
*/ |
|
| 894 |
double sum(const std::valarray<double> &v) {
|
|
| 895 |
double sum = 0.0; |
|
| 896 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 897 |
sum += v[i]; |
|
| 898 |
} |
|
| 899 |
return sum; |
|
| 900 |
} |
|
| 901 | ||
| 902 |
/** |
|
| 903 |
* @brief Sum method for a vector of doubles. |
|
| 904 |
* |
|
| 905 |
* @param v |
|
| 906 |
* @return double |
|
| 907 |
*/ |
|
| 908 |
double sum(const std::vector<double> &v) {
|
|
| 909 |
double sum = 0.0; |
|
| 910 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 911 |
sum += v[i]; |
|
| 912 |
} |
|
| 913 |
return sum; |
|
| 914 |
} |
|
| 915 | ||
| 916 |
/** |
|
| 917 |
* @brief Minimum method to calculate the minimum of an array or vector |
|
| 918 |
* of doubles. |
|
| 919 |
* |
|
| 920 |
* @param v |
|
| 921 |
* @return double |
|
| 922 |
*/ |
|
| 923 |
double min(const std::valarray<double> &v) {
|
|
| 924 |
double min = v[0]; |
|
| 925 |
for (size_t i = 1; i < v.size(); i++) {
|
|
| 926 |
if (v[i] < min) {
|
|
| 927 |
min = v[i]; |
|
| 928 |
} |
|
| 929 |
} |
|
| 930 |
return min; |
|
| 931 |
} |
|
| 932 |
/** |
|
| 933 |
* @brief A function to compute the absolute value of a value array of |
|
| 934 |
* floating-point values. It is a wrapper around std::fabs. |
|
| 935 |
* |
|
| 936 |
* @param v A value array of floating-point values, where floating-point |
|
| 937 |
* values is anything with decimals. |
|
| 938 |
* @return std::valarray<double> |
|
| 939 |
*/ |
|
| 940 |
std::valarray<double> fabs(const std::valarray<double> &v) {
|
|
| 941 |
std::valarray<double> result(v.size()); |
|
| 942 |
for (size_t i = 0; i < v.size(); i++) {
|
|
| 943 |
result[i] = std::fabs(v[i]); |
|
| 944 |
} |
|
| 945 |
return result; |
|
| 946 |
} |
|
| 947 | ||
| 948 |
#ifdef TMB_MODEL |
|
| 949 | ||
| 950 |
template <typename Type> |
|
| 951 | 116x |
bool add_to_fims_tmb_internal() {
|
| 952 | 116x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 953 |
fims_info::Information<Type>::GetInstance(); |
|
| 954 | ||
| 955 | 116x |
std::shared_ptr<fims_popdy::CatchAtAge<Type>> model = |
| 956 |
std::make_shared<fims_popdy::CatchAtAge<Type>>(); |
|
| 957 | ||
| 958 | 116x |
population_id_iterator it; |
| 959 | ||
| 960 | 232x |
for (it = this->population_ids->begin(); it != this->population_ids->end(); |
| 961 | 116x |
++it) {
|
| 962 | 116x |
model->AddPopulation((*it)); |
| 963 |
} |
|
| 964 | ||
| 965 | 116x |
std::set<uint32_t> fleet_ids; // all fleets in the model |
| 966 |
typedef typename std::set<uint32_t>::iterator fleet_ids_iterator; |
|
| 967 | ||
| 968 |
// add to Information |
|
| 969 | 116x |
info->models_map[this->get_id()] = model; |
| 970 | ||
| 971 | 348x |
for (it = this->population_ids->begin(); it != this->population_ids->end(); |
| 972 | 116x |
++it) {
|
| 973 | 116x |
auto it2 = PopulationInterfaceBase::live_objects.find(*it); |
| 974 | 116x |
if (it2 == PopulationInterfaceBase::live_objects.end()) {
|
| 975 | ! |
throw std::runtime_error("Population ID " + std::to_string(*it) +
|
| 976 |
" not found in live_objects"); |
|
| 977 |
} |
|
| 978 | 116x |
auto population = |
| 979 | 116x |
std::dynamic_pointer_cast<PopulationInterface>(it2->second); |
| 980 | 116x |
model->InitializePopulationDerivedQuantities(population->id); |
| 981 |
std::map<std::string, fims::Vector<Type>> &derived_quantities = |
|
| 982 | 116x |
model->GetPopulationDerivedQuantities(population->id); |
| 983 | ||
| 984 |
std::map<std::string, fims_popdy::DimensionInfo> |
|
| 985 |
&derived_quantities_dim_info = |
|
| 986 | 116x |
model->GetPopulationDimensionInfo(population->id); |
| 987 | ||
| 988 | 116x |
std::stringstream ss; |
| 989 | ||
| 990 | 116x |
derived_quantities["total_landings_weight"] = |
| 991 | 232x |
fims::Vector<Type>(population->n_years.get()); |
| 992 | ||
| 993 | 116x |
derived_quantities_dim_info["total_landings_weight"] = |
| 994 | 464x |
fims_popdy::DimensionInfo( |
| 995 |
"total_landings_weight", |
|
| 996 | 116x |
fims::Vector<int>{(int)population->n_years.get()},
|
| 997 | 232x |
fims::Vector<std::string>{"n_years"});
|
| 998 | ||
| 999 | 116x |
derived_quantities["total_landings_numbers"] = |
| 1000 | 232x |
fims::Vector<Type>(population->n_years.get()); |
| 1001 | ||
| 1002 | 116x |
derived_quantities_dim_info["total_landings_numbers"] = |
| 1003 | 464x |
fims_popdy::DimensionInfo( |
| 1004 |
"total_landings_numbers", |
|
| 1005 | 116x |
fims::Vector<int>{population->n_years.get()},
|
| 1006 | 232x |
fims::Vector<std::string>{"n_years"});
|
| 1007 | ||
| 1008 | 232x |
derived_quantities["mortality_F"] = fims::Vector<Type>( |
| 1009 | 116x |
population->n_years.get() * population->n_ages.get()); |
| 1010 | 580x |
derived_quantities_dim_info["mortality_F"] = fims_popdy::DimensionInfo( |
| 1011 |
"mortality_F", |
|
| 1012 | 116x |
fims::Vector<int>{population->n_years.get(),
|
| 1013 | 116x |
population->n_ages.get()}, |
| 1014 | 348x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1015 | ||
| 1016 | 232x |
derived_quantities["mortality_M"] = fims::Vector<Type>( |
| 1017 | 116x |
population->n_years.get() * population->n_ages.get()); |
| 1018 | 580x |
derived_quantities_dim_info["mortality_M"] = fims_popdy::DimensionInfo( |
| 1019 |
"mortality_M", |
|
| 1020 | 116x |
fims::Vector<int>{population->n_years.get(),
|
| 1021 | 116x |
population->n_ages.get()}, |
| 1022 | 348x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1023 | ||
| 1024 | 232x |
derived_quantities["mortality_Z"] = fims::Vector<Type>( |
| 1025 | 116x |
population->n_years.get() * population->n_ages.get()); |
| 1026 | 580x |
derived_quantities_dim_info["mortality_Z"] = fims_popdy::DimensionInfo( |
| 1027 |
"mortality_Z", |
|
| 1028 | 116x |
fims::Vector<int>{population->n_years.get(),
|
| 1029 | 116x |
population->n_ages.get()}, |
| 1030 | 348x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1031 | ||
| 1032 | 232x |
derived_quantities["numbers_at_age"] = fims::Vector<Type>( |
| 1033 | 116x |
(population->n_years.get() + 1) * population->n_ages.get()); |
| 1034 | 580x |
derived_quantities_dim_info["numbers_at_age"] = fims_popdy::DimensionInfo( |
| 1035 |
"numbers_at_age", |
|
| 1036 | 116x |
fims::Vector<int>{(population->n_years.get() + 1),
|
| 1037 | 116x |
population->n_ages.get()}, |
| 1038 | 348x |
fims::Vector<std::string>{"n_years+1", "n_ages"});
|
| 1039 | ||
| 1040 | 232x |
derived_quantities["unfished_numbers_at_age"] = fims::Vector<Type>( |
| 1041 | 116x |
(population->n_years.get() + 1) * population->n_ages.get()); |
| 1042 | 116x |
derived_quantities_dim_info["unfished_numbers_at_age"] = |
| 1043 | 464x |
fims_popdy::DimensionInfo( |
| 1044 |
"unfished_numbers_at_age", |
|
| 1045 | 116x |
fims::Vector<int>{(population->n_years.get() + 1),
|
| 1046 | 116x |
population->n_ages.get()}, |
| 1047 | 348x |
fims::Vector<std::string>{"n_years+1", "n_ages"});
|
| 1048 | ||
| 1049 | 116x |
derived_quantities["biomass"] = |
| 1050 | 232x |
fims::Vector<Type>((population->n_years.get() + 1)); |
| 1051 | 464x |
derived_quantities_dim_info["biomass"] = fims_popdy::DimensionInfo( |
| 1052 | 116x |
"biomass", fims::Vector<int>{(population->n_years.get() + 1)},
|
| 1053 | 232x |
fims::Vector<std::string>{"n_years+1"});
|
| 1054 | ||
| 1055 | 116x |
derived_quantities["spawning_biomass"] = |
| 1056 | 232x |
fims::Vector<Type>((population->n_years.get() + 1)); |
| 1057 | 116x |
derived_quantities_dim_info["spawning_biomass"] = |
| 1058 | 348x |
fims_popdy::DimensionInfo( |
| 1059 |
"spawning_biomass", |
|
| 1060 | 116x |
fims::Vector<int>{(population->n_years.get() + 1)},
|
| 1061 | 232x |
fims::Vector<std::string>{"n_years+1"});
|
| 1062 | ||
| 1063 | 116x |
derived_quantities["unfished_biomass"] = |
| 1064 | 232x |
fims::Vector<Type>((population->n_years.get() + 1)); |
| 1065 | 116x |
derived_quantities_dim_info["unfished_biomass"] = |
| 1066 | 348x |
fims_popdy::DimensionInfo( |
| 1067 |
"unfished_biomass", |
|
| 1068 | 116x |
fims::Vector<int>{(population->n_years.get() + 1)},
|
| 1069 | 232x |
fims::Vector<std::string>{"n_years+1"});
|
| 1070 | ||
| 1071 | 116x |
derived_quantities["unfished_spawning_biomass"] = |
| 1072 | 232x |
fims::Vector<Type>((population->n_years.get() + 1)); |
| 1073 | 116x |
derived_quantities_dim_info["unfished_spawning_biomass"] = |
| 1074 | 348x |
fims_popdy::DimensionInfo( |
| 1075 |
"unfished_spawning_biomass", |
|
| 1076 | 116x |
fims::Vector<int>{(population->n_years.get() + 1)},
|
| 1077 | 232x |
fims::Vector<std::string>{"n_years+1"});
|
| 1078 | ||
| 1079 | 232x |
derived_quantities["proportion_mature_at_age"] = fims::Vector<Type>( |
| 1080 | 116x |
(population->n_years.get() + 1) * population->n_ages.get()); |
| 1081 | 116x |
derived_quantities_dim_info["proportion_mature_at_age"] = |
| 1082 | 464x |
fims_popdy::DimensionInfo( |
| 1083 |
"proportion_mature_at_age", |
|
| 1084 | 116x |
fims::Vector<int>{(population->n_years.get() + 1),
|
| 1085 | 116x |
population->n_ages.get()}, |
| 1086 | 348x |
fims::Vector<std::string>{"n_years+1", "n_ages"});
|
| 1087 | ||
| 1088 | 116x |
derived_quantities["expected_recruitment"] = |
| 1089 | 232x |
fims::Vector<Type>((population->n_years.get() + 1)); |
| 1090 | 116x |
derived_quantities_dim_info["expected_recruitment"] = |
| 1091 | 348x |
fims_popdy::DimensionInfo( |
| 1092 |
"expected_recruitment", |
|
| 1093 | 116x |
fims::Vector<int>{(population->n_years.get() + 1)},
|
| 1094 | 232x |
fims::Vector<std::string>{"n_years+1"});
|
| 1095 | ||
| 1096 | 232x |
derived_quantities["sum_selectivity"] = fims::Vector<Type>( |
| 1097 | 116x |
population->n_years.get() * population->n_ages.get()); |
| 1098 | 116x |
derived_quantities_dim_info["sum_selectivity"] = |
| 1099 | 464x |
fims_popdy::DimensionInfo( |
| 1100 |
"sum_selectivity", |
|
| 1101 | 116x |
fims::Vector<int>{population->n_years.get(),
|
| 1102 | 116x |
population->n_ages.get()}, |
| 1103 | 348x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1104 | ||
| 1105 |
// replace elements in the variable map |
|
| 1106 | ||
| 1107 | 116x |
for (fleet_ids_iterator fit = population->fleet_ids->begin(); |
| 1108 | 348x |
fit != population->fleet_ids->end(); ++fit) {
|
| 1109 | 232x |
fleet_ids.insert(*fit); |
| 1110 |
} |
|
| 1111 |
} |
|
| 1112 | ||
| 1113 | 348x |
for (fleet_ids_iterator it = fleet_ids.begin(); it != fleet_ids.end(); |
| 1114 | 232x |
++it) {
|
| 1115 | 232x |
std::shared_ptr<FleetInterface> fleet_interface = |
| 1116 | 232x |
std::dynamic_pointer_cast<FleetInterface>( |
| 1117 | 232x |
FleetInterfaceBase::live_objects[(*it)]); |
| 1118 | 232x |
model->InitializeFleetDerivedQuantities(fleet_interface->id); |
| 1119 |
std::map<std::string, fims::Vector<Type>> &derived_quantities = |
|
| 1120 | 232x |
model->GetFleetDerivedQuantities(fleet_interface->id); |
| 1121 | ||
| 1122 |
std::map<std::string, fims_popdy::DimensionInfo> |
|
| 1123 |
&derived_quantities_dim_info = |
|
| 1124 | 232x |
model->GetFleetDimensionInfo(fleet_interface->id); |
| 1125 | ||
| 1126 |
// initialize derive quantities |
|
| 1127 |
// landings |
|
| 1128 | 580x |
derived_quantities["landings_numbers_at_age"] = fims::Vector<Type>( |
| 1129 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1130 | 232x |
derived_quantities_dim_info["landings_numbers_at_age"] = |
| 1131 | 928x |
fims_popdy::DimensionInfo( |
| 1132 |
"landings_numbers_at_age", |
|
| 1133 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1134 | 232x |
fleet_interface->n_ages.get()}, |
| 1135 | 696x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1136 | ||
| 1137 | 464x |
derived_quantities["landings_weight_at_age"] = fims::Vector<Type>( |
| 1138 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1139 | 232x |
derived_quantities_dim_info["landings_weight_at_age"] = |
| 1140 | 928x |
fims_popdy::DimensionInfo( |
| 1141 |
"landings_weight_at_age", |
|
| 1142 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1143 | 232x |
fleet_interface->n_ages.get()}, |
| 1144 | 696x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1145 | ||
| 1146 | 464x |
derived_quantities["landings_numbers_at_length"] = fims::Vector<Type>( |
| 1147 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_lengths.get()); |
| 1148 | 232x |
derived_quantities_dim_info["landings_numbers_at_length"] = |
| 1149 | 928x |
fims_popdy::DimensionInfo( |
| 1150 |
"landings_numbers_at_length", |
|
| 1151 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1152 | 232x |
fleet_interface->n_lengths.get()}, |
| 1153 | 696x |
fims::Vector<std::string>{"n_years", "n_lengths"});
|
| 1154 | ||
| 1155 | 232x |
derived_quantities["landings_weight"] = |
| 1156 | 464x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1157 | 232x |
derived_quantities_dim_info["landings_weight"] = |
| 1158 | 928x |
fims_popdy::DimensionInfo( |
| 1159 |
"landings_weight", |
|
| 1160 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1161 | 464x |
fims::Vector<std::string>{"n_years"});
|
| 1162 | ||
| 1163 | 232x |
derived_quantities["landings_numbers"] = |
| 1164 | 464x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1165 | 232x |
derived_quantities_dim_info["landings_numbers"] = |
| 1166 | 928x |
fims_popdy::DimensionInfo( |
| 1167 |
"landings_numbers", |
|
| 1168 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1169 | 464x |
fims::Vector<std::string>{"n_years"});
|
| 1170 | ||
| 1171 | 232x |
derived_quantities["landings_expected"] = |
| 1172 | 464x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1173 | 232x |
derived_quantities_dim_info["landings_expected"] = |
| 1174 | 928x |
fims_popdy::DimensionInfo( |
| 1175 |
"landings_expected", |
|
| 1176 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1177 | 464x |
fims::Vector<std::string>{"n_years"});
|
| 1178 | ||
| 1179 | 232x |
derived_quantities["log_landings_expected"] = |
| 1180 | 464x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1181 | 232x |
derived_quantities_dim_info["log_landings_expected"] = |
| 1182 | 928x |
fims_popdy::DimensionInfo( |
| 1183 |
"log_landings_expected", |
|
| 1184 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1185 | 464x |
fims::Vector<std::string>{"n_years"});
|
| 1186 | ||
| 1187 | 464x |
derived_quantities["agecomp_proportion"] = fims::Vector<Type>( |
| 1188 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1189 | 232x |
derived_quantities_dim_info["agecomp_proportion"] = |
| 1190 | 928x |
fims_popdy::DimensionInfo( |
| 1191 |
"agecomp_proportion", |
|
| 1192 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1193 | 232x |
fleet_interface->n_ages.get()}, |
| 1194 | 696x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1195 | ||
| 1196 | 464x |
derived_quantities["lengthcomp_proportion"] = fims::Vector<Type>( |
| 1197 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_lengths.get()); |
| 1198 | 232x |
derived_quantities_dim_info["lengthcomp_proportion"] = |
| 1199 | 928x |
fims_popdy::DimensionInfo( |
| 1200 |
"lengthcomp_proportion", |
|
| 1201 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1202 | 232x |
fleet_interface->n_lengths.get()}, |
| 1203 | 696x |
fims::Vector<std::string>{"n_years", "n_lengths"});
|
| 1204 | ||
| 1205 |
// index |
|
| 1206 | 464x |
derived_quantities["index_numbers_at_age"] = fims::Vector<Type>( |
| 1207 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1208 | 232x |
derived_quantities_dim_info["index_numbers_at_age"] = |
| 1209 | 928x |
fims_popdy::DimensionInfo( |
| 1210 |
"index_numbers_at_age", |
|
| 1211 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1212 | 232x |
fleet_interface->n_ages.get()}, |
| 1213 | 696x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1214 | ||
| 1215 | 464x |
derived_quantities["index_weight_at_age"] = fims::Vector<Type>( |
| 1216 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1217 | 232x |
derived_quantities_dim_info["index_weight_at_age"] = |
| 1218 | 928x |
fims_popdy::DimensionInfo( |
| 1219 |
"index_weight_at_age", |
|
| 1220 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1221 | 232x |
fleet_interface->n_ages.get()}, |
| 1222 | 696x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1223 | ||
| 1224 | 464x |
derived_quantities["index_weight_at_age"] = fims::Vector<Type>( |
| 1225 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1226 | 232x |
derived_quantities_dim_info["index_weight_at_age"] = |
| 1227 | 928x |
fims_popdy::DimensionInfo( |
| 1228 |
"index_weight_at_age", |
|
| 1229 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1230 | 232x |
fleet_interface->n_ages.get()}, |
| 1231 | 696x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1232 | ||
| 1233 | 464x |
derived_quantities["index_numbers_at_length"] = fims::Vector<Type>( |
| 1234 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_lengths.get()); |
| 1235 | 232x |
derived_quantities_dim_info["index_numbers_at_length"] = |
| 1236 | 928x |
fims_popdy::DimensionInfo( |
| 1237 |
"index_numbers_at_length", |
|
| 1238 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1239 | 232x |
fleet_interface->n_lengths.get()}, |
| 1240 | 696x |
fims::Vector<std::string>{"n_years", "n_lengths"});
|
| 1241 | 232x |
derived_quantities["index_weight"] = |
| 1242 | 464x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1243 | 1160x |
derived_quantities_dim_info["index_weight"] = fims_popdy::DimensionInfo( |
| 1244 | 232x |
"index_weight", fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1245 | 464x |
fims::Vector<std::string>{"n_years"});
|
| 1246 | ||
| 1247 | 232x |
derived_quantities["index_numbers"] = |
| 1248 | 464x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1249 | 1160x |
derived_quantities_dim_info["index_numbers"] = fims_popdy::DimensionInfo( |
| 1250 | 232x |
"index_numbers", fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1251 | 464x |
fims::Vector<std::string>{"n_years"});
|
| 1252 | ||
| 1253 | 232x |
derived_quantities["index_expected"] = |
| 1254 | 464x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1255 | 1160x |
derived_quantities_dim_info["index_expected"] = fims_popdy::DimensionInfo( |
| 1256 | 232x |
"index_expected", fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1257 | 464x |
fims::Vector<std::string>{"n_years"});
|
| 1258 | ||
| 1259 | 232x |
derived_quantities["log_index_expected"] = |
| 1260 | 464x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1261 | 232x |
derived_quantities_dim_info["log_index_expected"] = |
| 1262 | 928x |
fims_popdy::DimensionInfo( |
| 1263 |
"log_index_expected", |
|
| 1264 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1265 | 464x |
fims::Vector<std::string>{"n_years"});
|
| 1266 | ||
| 1267 | 232x |
derived_quantities["catch_index"] = |
| 1268 | 464x |
fims::Vector<Type>(fleet_interface->n_years.get()); |
| 1269 | 1160x |
derived_quantities_dim_info["catch_index"] = fims_popdy::DimensionInfo( |
| 1270 | 232x |
"catch_index", fims::Vector<int>{(fleet_interface->n_years.get())},
|
| 1271 | 464x |
fims::Vector<std::string>{"n_years"});
|
| 1272 | ||
| 1273 | 464x |
derived_quantities["agecomp_expected"] = fims::Vector<Type>( |
| 1274 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_ages.get()); |
| 1275 | 232x |
derived_quantities_dim_info["agecomp_expected"] = |
| 1276 | 928x |
fims_popdy::DimensionInfo( |
| 1277 |
"agecomp_expected", |
|
| 1278 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1279 | 232x |
(fleet_interface->n_ages.get())}, |
| 1280 | 696x |
fims::Vector<std::string>{"n_years", "n_ages"});
|
| 1281 | ||
| 1282 | 464x |
derived_quantities["lengthcomp_expected"] = fims::Vector<Type>( |
| 1283 | 232x |
fleet_interface->n_years.get() * fleet_interface->n_lengths.get()); |
| 1284 | 232x |
derived_quantities_dim_info["lengthcomp_expected"] = |
| 1285 | 928x |
fims_popdy::DimensionInfo( |
| 1286 |
"lengthcomp_expected", |
|
| 1287 | 232x |
fims::Vector<int>{(fleet_interface->n_years.get()),
|
| 1288 | 232x |
(fleet_interface->n_lengths.get())}, |
| 1289 | 696x |
fims::Vector<std::string>{"n_years", "n_lengths"});
|
| 1290 | ||
| 1291 |
// replace elements in the variable map |
|
| 1292 | 232x |
info->variable_map[fleet_interface->log_landings_expected.id_m] = |
| 1293 | 696x |
&(derived_quantities["log_landings_expected"]); |
| 1294 | 232x |
info->variable_map[fleet_interface->log_index_expected.id_m] = |
| 1295 | 696x |
&(derived_quantities["log_index_expected"]); |
| 1296 | 232x |
info->variable_map[fleet_interface->agecomp_expected.id_m] = |
| 1297 | 696x |
&(derived_quantities["agecomp_expected"]); |
| 1298 | 232x |
info->variable_map[fleet_interface->agecomp_proportion.id_m] = |
| 1299 | 696x |
&(derived_quantities["agecomp_proportion"]); |
| 1300 | 232x |
info->variable_map[fleet_interface->lengthcomp_expected.id_m] = |
| 1301 | 696x |
&(derived_quantities["lengthcomp_expected"]); |
| 1302 | 232x |
info->variable_map[fleet_interface->lengthcomp_proportion.id_m] = |
| 1303 | 696x |
&(derived_quantities["lengthcomp_proportion"]); |
| 1304 |
} |
|
| 1305 | ||
| 1306 | 116x |
return true; |
| 1307 |
} |
|
| 1308 | ||
| 1309 | 29x |
virtual bool add_to_fims_tmb() {
|
| 1310 | 29x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 1311 | 29x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 1312 | 29x |
return true; |
| 1313 |
} |
|
| 1314 | ||
| 1315 |
#endif |
|
| 1316 |
}; |
|
| 1317 | ||
| 1318 |
#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 | 34x |
PopulationInterfaceBase() {
|
| 51 | 34x |
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 | 34x |
PopulationInterfaceBase(const PopulationInterfaceBase &other) |
| 63 | 34x |
: id(other.id) {}
|
| 64 | ||
| 65 |
/** |
|
| 66 |
* @brief The destructor. |
|
| 67 |
*/ |
|
| 68 | 67x |
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 population spawning biomass ratio for each year. |
|
| 134 |
*/ |
|
| 135 |
ParameterVector spawning_biomass_ratio; |
|
| 136 |
/** |
|
| 137 |
* @brief Log of the population annual fishing mortality multiplier. |
|
| 138 |
*/ |
|
| 139 |
ParameterVector log_f_multiplier; |
|
| 140 |
/** |
|
| 141 |
* @brief The natural log of the initial numbers at age. |
|
| 142 |
*/ |
|
| 143 |
ParameterVector log_init_naa; |
|
| 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 The name for the population. |
|
| 151 |
*/ |
|
| 152 |
SharedString name = fims::to_string("NA");
|
|
| 153 | ||
| 154 |
/** |
|
| 155 |
* @brief The constructor. |
|
| 156 |
*/ |
|
| 157 | 34x |
PopulationInterface() : PopulationInterfaceBase() {
|
| 158 | 34x |
this->fleet_ids = std::make_shared<std::set<uint32_t>>(); |
| 159 |
std::shared_ptr<PopulationInterface> population = |
|
| 160 | 34x |
std::make_shared<PopulationInterface>(*this); |
| 161 | 34x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back(population); |
| 162 | 34x |
PopulationInterfaceBase::live_objects[this->id] = population; |
| 163 |
} |
|
| 164 | ||
| 165 |
/** |
|
| 166 |
* @brief Construct a new Population Interface object |
|
| 167 |
* |
|
| 168 |
* @param other |
|
| 169 |
*/ |
|
| 170 | 34x |
PopulationInterface(const PopulationInterface &other) |
| 171 | 34x |
: PopulationInterfaceBase(other), |
| 172 | 34x |
n_ages(other.n_ages), |
| 173 | 34x |
n_fleets(other.n_fleets), |
| 174 | 34x |
fleet_ids(other.fleet_ids), |
| 175 | 34x |
n_years(other.n_years), |
| 176 | 34x |
n_lengths(other.n_lengths), |
| 177 | 34x |
maturity_id(other.maturity_id), |
| 178 | 34x |
growth_id(other.growth_id), |
| 179 | 34x |
recruitment_id(other.recruitment_id), |
| 180 | 34x |
recruitment_err_id(other.recruitment_id), |
| 181 | 34x |
log_M(other.log_M), |
| 182 | 34x |
spawning_biomass_ratio(other.spawning_biomass_ratio), |
| 183 | 34x |
log_f_multiplier(other.log_f_multiplier), |
| 184 | 34x |
log_init_naa(other.log_init_naa), |
| 185 | 34x |
ages(other.ages), |
| 186 | 68x |
name(other.name) {}
|
| 187 | ||
| 188 |
/** |
|
| 189 |
* @brief The destructor. |
|
| 190 |
*/ |
|
| 191 | 200x |
virtual ~PopulationInterface() {}
|
| 192 | ||
| 193 |
/** |
|
| 194 |
* @brief Gets the ID of the interface base object. |
|
| 195 |
* @return The ID. |
|
| 196 |
*/ |
|
| 197 | 128x |
virtual uint32_t get_id() { return this->id; }
|
| 198 | ||
| 199 |
/** |
|
| 200 |
* @brief Sets the name of the population. |
|
| 201 |
* @param name The name to set. |
|
| 202 |
*/ |
|
| 203 | ! |
void SetName(const std::string &name) { this->name.set(name); }
|
| 204 | ||
| 205 |
/** |
|
| 206 |
* @brief Gets the name of the population. |
|
| 207 |
* @return The name. |
|
| 208 |
*/ |
|
| 209 | ! |
std::string GetName() const { return this->name.get(); }
|
| 210 | ||
| 211 |
/** |
|
| 212 |
* @brief Sets the unique ID for the Maturity object. |
|
| 213 |
* @param maturity_id Unique ID for the Maturity object. |
|
| 214 |
*/ |
|
| 215 | 33x |
void SetMaturityID(uint32_t maturity_id) {
|
| 216 | 33x |
this->maturity_id.set(maturity_id); |
| 217 |
} |
|
| 218 | ||
| 219 |
/** |
|
| 220 |
* @brief Set the unique ID for the growth object. |
|
| 221 |
* @param growth_id Unique ID for the growth object. |
|
| 222 |
*/ |
|
| 223 | 33x |
void SetGrowthID(uint32_t growth_id) { this->growth_id.set(growth_id); }
|
| 224 | ||
| 225 |
/** |
|
| 226 |
* @brief Set the unique ID for the recruitment object. |
|
| 227 |
* @param recruitment_id Unique ID for the recruitment object. |
|
| 228 |
*/ |
|
| 229 | 33x |
void SetRecruitmentID(uint32_t recruitment_id) {
|
| 230 | 33x |
this->recruitment_id.set(recruitment_id); |
| 231 |
} |
|
| 232 | ||
| 233 |
/** |
|
| 234 |
* @brief Add a fleet id to the list of fleets |
|
| 235 |
* operating on this population. |
|
| 236 |
*/ |
|
| 237 | 62x |
void AddFleet(uint32_t fleet_id) { this->fleet_ids->insert(fleet_id); }
|
| 238 | ||
| 239 |
/** |
|
| 240 |
* @brief Extracts derived quantities back to the Rcpp interface object from |
|
| 241 |
* the Information object. |
|
| 242 |
*/ |
|
| 243 | ! |
virtual void finalize() {
|
| 244 | ! |
if (this->finalized) {
|
| 245 |
// log warning that finalize has been called more than once. |
|
| 246 | ! |
FIMS_WARNING_LOG("Population " + fims::to_string(this->id) +
|
| 247 |
" has been finalized already."); |
|
| 248 |
} |
|
| 249 | ||
| 250 | ! |
this->finalized = true; // indicate this has been called already |
| 251 | ||
| 252 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 253 | ! |
fims_info::Information<double>::GetInstance(); |
| 254 | ||
| 255 | ! |
fims_info::Information<double>::population_iterator it; |
| 256 | ||
| 257 | ! |
it = info->populations.find(this->id); |
| 258 | ||
| 259 |
std::shared_ptr<fims_popdy::Population<double>> pop = |
|
| 260 | ! |
info->populations[this->id]; |
| 261 | ! |
it = info->populations.find(this->id); |
| 262 | ! |
if (it == info->populations.end()) {
|
| 263 | ! |
FIMS_WARNING_LOG("Population " + fims::to_string(this->id) +
|
| 264 |
" not found in Information."); |
|
| 265 | ! |
return; |
| 266 |
} else {
|
|
| 267 | ! |
for (size_t i = 0; i < this->log_M.size(); i++) {
|
| 268 | ! |
if (this->log_M[i].estimation_type_m.get() == "constant") {
|
| 269 | ! |
this->log_M[i].final_value_m = this->log_M[i].initial_value_m; |
| 270 |
} else {
|
|
| 271 | ! |
this->log_M[i].final_value_m = pop->log_M[i]; |
| 272 |
} |
|
| 273 |
} |
|
| 274 | ||
| 275 | ! |
for (size_t i = 0; i < this->log_f_multiplier.size(); i++) {
|
| 276 | ! |
if (this->log_f_multiplier[i].estimation_type_m.get() == "constant") {
|
| 277 | ! |
this->log_f_multiplier[i].final_value_m = |
| 278 | ! |
this->log_f_multiplier[i].initial_value_m; |
| 279 |
} else {
|
|
| 280 | ! |
this->log_f_multiplier[i].final_value_m = pop->log_f_multiplier[i]; |
| 281 |
} |
|
| 282 |
} |
|
| 283 | ||
| 284 | ! |
for (size_t i = 0; i < this->log_init_naa.size(); i++) {
|
| 285 | ! |
if (this->log_init_naa[i].estimation_type_m.get() == "constant") {
|
| 286 | ! |
this->log_init_naa[i].final_value_m = |
| 287 | ! |
this->log_init_naa[i].initial_value_m; |
| 288 |
} else {
|
|
| 289 | ! |
this->log_init_naa[i].final_value_m = pop->log_init_naa[i]; |
| 290 |
} |
|
| 291 |
} |
|
| 292 |
} |
|
| 293 |
} |
|
| 294 | ||
| 295 |
#ifdef TMB_MODEL |
|
| 296 | ||
| 297 |
template <typename Type> |
|
| 298 | 120x |
bool add_to_fims_tmb_internal() {
|
| 299 | 120x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 300 |
fims_info::Information<Type>::GetInstance(); |
|
| 301 | ||
| 302 | 120x |
std::shared_ptr<fims_popdy::Population<Type>> population = |
| 303 |
std::make_shared<fims_popdy::Population<Type>>(); |
|
| 304 | ||
| 305 | 120x |
std::stringstream ss; |
| 306 | ||
| 307 |
// set relative info |
|
| 308 | 120x |
population->id = this->id; |
| 309 | 120x |
population->n_years = this->n_years.get(); |
| 310 | 120x |
population->n_fleets = this->n_fleets.get(); |
| 311 |
// only define ages if n_ages greater than 0 |
|
| 312 | 120x |
if (this->n_ages.get() > 0) {
|
| 313 | 120x |
population->n_ages = this->n_ages.get(); |
| 314 | 120x |
if (static_cast<size_t>(this->n_ages.get()) == this->ages.size()) {
|
| 315 | 120x |
population->ages.resize(this->n_ages.get()); |
| 316 |
} else {
|
|
| 317 | ! |
warning("The ages vector is not of size n_ages.");
|
| 318 |
} |
|
| 319 |
} |
|
| 320 | ||
| 321 | 120x |
fleet_ids_iterator it; |
| 322 | 352x |
for (it = this->fleet_ids->begin(); it != this->fleet_ids->end(); it++) {
|
| 323 | 232x |
population->fleet_ids.insert(*it); |
| 324 |
} |
|
| 325 | ||
| 326 | 120x |
population->growth_id = this->growth_id.get(); |
| 327 | 120x |
population->recruitment_id = this->recruitment_id.get(); |
| 328 | 120x |
population->maturity_id = this->maturity_id.get(); |
| 329 | 120x |
population->log_M.resize(this->log_M.size()); |
| 330 | ||
| 331 | 120x |
if (this->log_f_multiplier.size() == |
| 332 | 120x |
static_cast<size_t>(this->n_years.get())) {
|
| 333 | 62x |
population->log_f_multiplier.resize(this->log_f_multiplier.size()); |
| 334 |
} else {
|
|
| 335 | 58x |
FIMS_WARNING_LOG( |
| 336 |
"The log_f_multiplier vector is not of size n_years. Filling with " |
|
| 337 |
"zeros."); |
|
| 338 | 29x |
this->log_f_multiplier.resize((this->n_years.get())); |
| 339 | 914x |
for (size_t i = 0; i < log_f_multiplier.size(); i++) {
|
| 340 | 885x |
this->log_f_multiplier[i].initial_value_m = static_cast<double>(0.0); |
| 341 | 2655x |
this->log_f_multiplier[i].estimation_type_m.set("constant");
|
| 342 |
} |
|
| 343 | 29x |
population->log_f_multiplier.resize(this->log_f_multiplier.size()); |
| 344 |
} |
|
| 345 | ||
| 346 | 120x |
if (this->spawning_biomass_ratio.size() == |
| 347 | 120x |
static_cast<size_t>(this->n_years.get() + 1)) {
|
| 348 | 30x |
population->spawning_biomass_ratio.resize( |
| 349 |
this->spawning_biomass_ratio.size()); |
|
| 350 |
} else {
|
|
| 351 | 60x |
FIMS_WARNING_LOG( |
| 352 |
"Setting spawning_biomass_ratio vector to size n_years + 1."); |
|
| 353 | 30x |
this->spawning_biomass_ratio.resize((this->n_years.get() + 1)); |
| 354 | 30x |
population->spawning_biomass_ratio.resize( |
| 355 |
this->spawning_biomass_ratio.size()); |
|
| 356 |
} |
|
| 357 | 120x |
info->variable_map[this->spawning_biomass_ratio.id_m] = |
| 358 | 120x |
&(population)->spawning_biomass_ratio; |
| 359 | ||
| 360 | 120x |
population->log_init_naa.resize(this->log_init_naa.size()); |
| 361 | 44520x |
for (size_t i = 0; i < log_M.size(); i++) {
|
| 362 | 44400x |
population->log_M[i] = this->log_M[i].initial_value_m; |
| 363 | 44400x |
if (this->log_M[i].estimation_type_m.get() == "fixed_effects") {
|
| 364 | ! |
ss.str("");
|
| 365 | ! |
ss << "Population." << this->id << ".log_M." << this->log_M[i].id_m; |
| 366 | ! |
info->RegisterParameterName(ss.str()); |
| 367 | ! |
info->RegisterParameter(population->log_M[i]); |
| 368 |
} |
|
| 369 | 44400x |
if (this->log_M[i].estimation_type_m.get() == "random_effects") {
|
| 370 | ! |
ss.str("");
|
| 371 | ! |
ss << "Population." << this->id << ".log_M." << this->log_M[i].id_m; |
| 372 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 373 | ! |
info->RegisterRandomEffect(population->log_M[i]); |
| 374 |
} |
|
| 375 |
} |
|
| 376 | 120x |
info->variable_map[this->log_M.id_m] = &(population)->log_M; |
| 377 | ||
| 378 | 3820x |
for (size_t i = 0; i < log_f_multiplier.size(); i++) {
|
| 379 | 3700x |
population->log_f_multiplier[i] = |
| 380 | 3700x |
this->log_f_multiplier[i].initial_value_m; |
| 381 | 3700x |
if (this->log_f_multiplier[i].estimation_type_m.get() == |
| 382 |
"fixed_effects") {
|
|
| 383 | ! |
ss.str("");
|
| 384 | ! |
ss << "Population." << this->id << ".log_f_multiplier." |
| 385 | ! |
<< this->log_f_multiplier[i].id_m; |
| 386 | ! |
info->RegisterParameterName(ss.str()); |
| 387 | ! |
info->RegisterParameter(population->log_f_multiplier[i]); |
| 388 |
} |
|
| 389 | 3700x |
if (this->log_f_multiplier[i].estimation_type_m.get() == |
| 390 |
"random_effects") {
|
|
| 391 | 40x |
ss.str("");
|
| 392 | 40x |
ss << "Population." << this->id << ".log_f_multiplier." |
| 393 | 40x |
<< this->log_f_multiplier[i].id_m; |
| 394 | 40x |
info->RegisterRandomEffectName(ss.str()); |
| 395 | 40x |
info->RegisterRandomEffect(population->log_f_multiplier[i]); |
| 396 |
} |
|
| 397 |
} |
|
| 398 | 120x |
info->variable_map[this->log_f_multiplier.id_m] = |
| 399 | 120x |
&(population)->log_f_multiplier; |
| 400 | ||
| 401 | 1560x |
for (size_t i = 0; i < log_init_naa.size(); i++) {
|
| 402 | 1440x |
population->log_init_naa[i] = this->log_init_naa[i].initial_value_m; |
| 403 | 1440x |
if (this->log_init_naa[i].estimation_type_m.get() == "fixed_effects") {
|
| 404 | 1392x |
ss.str("");
|
| 405 | 1392x |
ss << "Population." << this->id << ".log_init_naa." |
| 406 | 1392x |
<< this->log_init_naa[i].id_m; |
| 407 | 1392x |
info->RegisterParameterName(ss.str()); |
| 408 | 1392x |
info->RegisterParameter(population->log_init_naa[i]); |
| 409 |
} |
|
| 410 | 1440x |
if (this->log_init_naa[i].estimation_type_m.get() == "random_effects") {
|
| 411 | ! |
ss.str("");
|
| 412 | ! |
ss << "Population." << this->id << ".log_init_naa." |
| 413 | ! |
<< this->log_init_naa[i].id_m; |
| 414 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 415 | ! |
info->RegisterRandomEffect(population->log_init_naa[i]); |
| 416 |
} |
|
| 417 |
} |
|
| 418 | 120x |
info->variable_map[this->log_init_naa.id_m] = &(population)->log_init_naa; |
| 419 | ||
| 420 | 1560x |
for (size_t i = 0; i < ages.size(); i++) {
|
| 421 | 1440x |
population->ages[i] = this->ages[i]; |
| 422 |
} |
|
| 423 | ||
| 424 |
// add to Information |
|
| 425 | 120x |
info->populations[population->id] = population; |
| 426 | ||
| 427 | 120x |
return true; |
| 428 |
} |
|
| 429 | ||
| 430 |
/** |
|
| 431 |
* @brief Adds the parameters to the TMB model. |
|
| 432 |
* @return A boolean of true. |
|
| 433 |
*/ |
|
| 434 | 30x |
virtual bool add_to_fims_tmb() {
|
| 435 | 30x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 436 | 30x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 437 | ||
| 438 | 30x |
return true; |
| 439 |
} |
|
| 440 | ||
| 441 |
#endif |
|
| 442 |
}; |
|
| 443 | ||
| 444 |
#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 | 73x |
RecruitmentInterfaceBase() {
|
| 46 | 73x |
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 | 73x |
RecruitmentInterfaceBase(const RecruitmentInterfaceBase &other) |
| 58 | 73x |
: id(other.id), process_id(other.process_id) {}
|
| 59 | ||
| 60 |
/** |
|
| 61 |
* @brief The destructor. |
|
| 62 |
*/ |
|
| 63 | 146x |
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 | 40x |
BevertonHoltRecruitmentInterface() : RecruitmentInterfaceBase() {
|
| 139 | 40x |
RecruitmentInterfaceBase::live_objects[this->id] = |
| 140 | 80x |
std::make_shared<BevertonHoltRecruitmentInterface>(*this); |
| 141 | 40x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 142 | 40x |
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 | 40x |
BevertonHoltRecruitmentInterface( |
| 151 |
const BevertonHoltRecruitmentInterface &other) |
|
| 152 | 40x |
: RecruitmentInterfaceBase(other), |
| 153 | 40x |
n_years(other.n_years), |
| 154 | 40x |
logit_steep(other.logit_steep), |
| 155 | 40x |
log_rzero(other.log_rzero), |
| 156 | 40x |
log_devs(other.log_devs), |
| 157 | 40x |
log_r(other.log_r), |
| 158 | 40x |
log_expected_recruitment(other.log_expected_recruitment), |
| 159 | 40x |
estimated_logit_steep(other.estimated_logit_steep), |
| 160 | 40x |
estimated_log_rzero(other.estimated_log_rzero), |
| 161 | 80x |
estimated_log_devs(other.estimated_log_devs) {}
|
| 162 | ||
| 163 |
/** |
|
| 164 |
* @brief The destructor. |
|
| 165 |
*/ |
|
| 166 | 240x |
virtual ~BevertonHoltRecruitmentInterface() {}
|
| 167 | ||
| 168 |
/** |
|
| 169 |
* @brief Gets the ID of the interface base object. |
|
| 170 |
* @return The ID. |
|
| 171 |
*/ |
|
| 172 | 35x |
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 | 32x |
void SetRecruitmentProcessID(uint32_t process_id) {
|
| 179 | 32x |
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 | 24x |
virtual void finalize() {
|
| 215 | 24x |
if (this->finalized) {
|
| 216 |
// log warning that finalize has been called more than once. |
|
| 217 | 1x |
FIMS_WARNING_LOG("Beverton-Holt Recruitment " +
|
| 218 |
fims::to_string(this->id) + |
|
| 219 |
" has been finalized already."); |
|
| 220 |
} |
|
| 221 | ||
| 222 | 24x |
this->finalized = true; // indicate this has been called already |
| 223 | ||
| 224 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 225 | 24x |
fims_info::Information<double>::GetInstance(); |
| 226 | ||
| 227 | 24x |
fims_info::Information<double>::recruitment_models_iterator it; |
| 228 | ||
| 229 | 24x |
it = info->recruitment_models.find(this->id); |
| 230 | ||
| 231 | 24x |
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 | 24x |
it->second); |
| 240 | ||
| 241 | 48x |
for (size_t i = 0; i < this->logit_steep.size(); i++) {
|
| 242 | 24x |
if (this->logit_steep[i].estimation_type_m.get() == "constant") {
|
| 243 | 24x |
this->logit_steep[i].final_value_m = |
| 244 | 24x |
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 | 48x |
for (size_t i = 0; i < log_rzero.size(); i++) {
|
| 251 | 24x |
if (log_rzero[i].estimation_type_m.get() == "constant") {
|
| 252 | 2x |
this->log_rzero[i].final_value_m = this->log_rzero[i].initial_value_m; |
| 253 |
} else {
|
|
| 254 | 22x |
this->log_rzero[i].final_value_m = recr->log_rzero[i]; |
| 255 |
} |
|
| 256 |
} |
|
| 257 | ||
| 258 | 717x |
for (size_t i = 0; i < this->log_devs.size(); i++) {
|
| 259 | 693x |
if (this->log_devs[i].estimation_type_m.get() == "constant") {
|
| 260 | 403x |
this->log_devs[i].final_value_m = this->log_devs[i].initial_value_m; |
| 261 |
} else {
|
|
| 262 | 290x |
this->log_devs[i].final_value_m = recr->log_recruit_devs[i]; |
| 263 |
} |
|
| 264 |
} |
|
| 265 | ||
| 266 | 440x |
for (size_t i = 0; i < this->log_r.size(); i++) {
|
| 267 | 416x |
if (this->log_r[i].estimation_type_m.get() == "constant") {
|
| 268 | 387x |
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 |
/** |
|
| 277 |
* @brief Converts the data to json representation for the output. |
|
| 278 |
* @return A string is returned specifying that the module relates to the |
|
| 279 |
* recruitment interface with Beverton--Holt stock--recruitment relationship. |
|
| 280 |
* It also returns the ID and the parameters. This string is formatted for a |
|
| 281 |
* json file. |
|
| 282 |
*/ |
|
| 283 | 24x |
virtual std::string to_json() {
|
| 284 | 24x |
std::stringstream ss; |
| 285 | ||
| 286 | 24x |
ss << "{\n";
|
| 287 | 24x |
ss << " \"module_name\": \"Recruitment\",\n"; |
| 288 | 24x |
ss << " \"module_type\": \"Beverton-Holt\",\n"; |
| 289 | 24x |
ss << " \"module_id\": " << this->id << ",\n"; |
| 290 | ||
| 291 | 24x |
ss << " \"parameters\": [\n{\n";
|
| 292 | 24x |
ss << " \"name\": \"logit_steep\",\n"; |
| 293 | 24x |
ss << " \"id\":" << this->logit_steep.id_m << ",\n"; |
| 294 | 24x |
ss << " \"type\": \"vector\",\n"; |
| 295 | 24x |
ss << " \"dimensionality\": {\n";
|
| 296 | 24x |
ss << " \"header\": [null],\n"; |
| 297 | 24x |
ss << " \"dimensions\": [" << this->logit_steep.size() << "]\n},\n"; |
| 298 | 24x |
ss << " \"values\":" << this->logit_steep << "},\n"; |
| 299 | ||
| 300 | 24x |
ss << "{\n";
|
| 301 | 24x |
ss << " \"name\": \"log_rzero\",\n"; |
| 302 | 24x |
ss << " \"id\":" << this->log_rzero.id_m << ",\n"; |
| 303 | 24x |
ss << " \"type\": \"vector\",\n"; |
| 304 | 24x |
ss << " \"dimensionality\": {\n";
|
| 305 | 24x |
ss << " \"header\": [null],\n"; |
| 306 | 24x |
ss << " \"dimensions\": [" << this->log_rzero.size() << "]\n},\n"; |
| 307 | 24x |
ss << " \"values\":" << this->log_rzero << "},\n"; |
| 308 | ||
| 309 | 24x |
ss << "{\n";
|
| 310 | 24x |
ss << " \"name\": \"log_devs\",\n"; |
| 311 | 24x |
ss << " \"id\":" << this->log_devs.id_m << ",\n"; |
| 312 | 24x |
ss << " \"type\": \"vector\",\n"; |
| 313 | 24x |
ss << " \"dimensionality\": {\n";
|
| 314 | 24x |
ss << " \"header\": [\"n_years-1\"],\n"; |
| 315 | 24x |
ss << " \"dimensions\": [" << this->log_devs.size() << "]\n},\n"; |
| 316 | 24x |
ss << " \"values\":" << this->log_devs << "}]\n"; |
| 317 | 24x |
ss << "}"; |
| 318 | 48x |
return ss.str(); |
| 319 |
} |
|
| 320 | ||
| 321 |
#ifdef TMB_MODEL |
|
| 322 | ||
| 323 |
template <typename Type> |
|
| 324 | 128x |
bool add_to_fims_tmb_internal() {
|
| 325 | 128x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 326 |
fims_info::Information<Type>::GetInstance(); |
|
| 327 | ||
| 328 | 128x |
std::shared_ptr<fims_popdy::SRBevertonHolt<Type>> recruitment = |
| 329 |
std::make_shared<fims_popdy::SRBevertonHolt<Type>>(); |
|
| 330 | ||
| 331 | 128x |
std::stringstream ss; |
| 332 | ||
| 333 |
// set relative info |
|
| 334 | 128x |
recruitment->id = this->id; |
| 335 | 128x |
recruitment->process_id = this->process_id.get(); |
| 336 |
// set logit_steep |
|
| 337 | 128x |
recruitment->logit_steep.resize(this->logit_steep.size()); |
| 338 | 256x |
for (size_t i = 0; i < this->logit_steep.size(); i++) {
|
| 339 | 128x |
recruitment->logit_steep[i] = this->logit_steep[i].initial_value_m; |
| 340 | ||
| 341 | 128x |
if (this->logit_steep[i].estimation_type_m.get() == "fixed_effects") {
|
| 342 | 4x |
ss.str("");
|
| 343 | 4x |
ss << "Recruitment." << this->id << ".logit_steep." |
| 344 | 4x |
<< this->logit_steep[i].id_m; |
| 345 | 4x |
info->RegisterParameterName(ss.str()); |
| 346 | 4x |
info->RegisterParameter(recruitment->logit_steep[i]); |
| 347 |
} |
|
| 348 | 128x |
if (this->logit_steep[i].estimation_type_m.get() == "random_effects") {
|
| 349 | 4x |
ss.str("");
|
| 350 | 4x |
ss << "Recruitment." << this->id << ".logit_steep." |
| 351 | 4x |
<< this->logit_steep[i].id_m; |
| 352 | 4x |
info->RegisterRandomEffectName(ss.str()); |
| 353 | 4x |
info->RegisterRandomEffect(recruitment->logit_steep[i]); |
| 354 |
} |
|
| 355 |
} |
|
| 356 | 128x |
info->variable_map[this->logit_steep.id_m] = &(recruitment)->logit_steep; |
| 357 | ||
| 358 |
// set log_rzero |
|
| 359 | 128x |
recruitment->log_rzero.resize(this->log_rzero.size()); |
| 360 | 256x |
for (size_t i = 0; i < this->log_rzero.size(); i++) {
|
| 361 | 128x |
recruitment->log_rzero[i] = this->log_rzero[i].initial_value_m; |
| 362 | ||
| 363 | 128x |
if (this->log_rzero[i].estimation_type_m.get() == "fixed_effects") {
|
| 364 | 120x |
ss.str("");
|
| 365 | 120x |
ss << "Recruitment." << this->id << ".log_rzero." |
| 366 | 120x |
<< this->log_rzero[i].id_m; |
| 367 | 120x |
info->RegisterParameterName(ss.str()); |
| 368 | 120x |
info->RegisterParameter(recruitment->log_rzero[i]); |
| 369 |
} |
|
| 370 | 128x |
if (this->log_rzero[i].estimation_type_m.get() == "random_effects") {
|
| 371 | 4x |
ss.str("");
|
| 372 | 4x |
ss << "Recruitment." << this->id << ".log_rzero." |
| 373 | 4x |
<< this->log_rzero[i].id_m; |
| 374 | 4x |
info->RegisterRandomEffectName(ss.str()); |
| 375 | 4x |
info->RegisterRandomEffect(recruitment->log_rzero[i]); |
| 376 |
} |
|
| 377 |
} |
|
| 378 | 128x |
info->variable_map[this->log_rzero.id_m] = &(recruitment)->log_rzero; |
| 379 |
// set log_recruit_devs |
|
| 380 | 128x |
recruitment->log_recruit_devs.resize(this->log_devs.size()); |
| 381 | 3604x |
for (size_t i = 0; i < this->log_devs.size(); i++) {
|
| 382 | 3476x |
recruitment->log_recruit_devs[i] = this->log_devs[i].initial_value_m; |
| 383 | ||
| 384 | 3476x |
if (this->log_devs[i].estimation_type_m.get() == "fixed_effects") {
|
| 385 | 232x |
ss.str("");
|
| 386 | 232x |
ss << "Recruitment." << this->id << ".log_devs." |
| 387 | 232x |
<< this->log_devs[i].id_m; |
| 388 | 232x |
info->RegisterParameterName(ss.str()); |
| 389 | 232x |
info->RegisterParameter(recruitment->log_recruit_devs[i]); |
| 390 |
} |
|
| 391 | 3476x |
if (this->log_devs[i].estimation_type_m.get() == "random_effects") {
|
| 392 | 1584x |
ss.str("");
|
| 393 | 1584x |
ss << "Recruitment." << this->id << ".log_devs." |
| 394 | 1584x |
<< this->log_devs[i].id_m; |
| 395 | 1584x |
info->RegisterRandomEffectName(ss.str()); |
| 396 | 1584x |
info->RegisterRandomEffect(recruitment->log_recruit_devs[i]); |
| 397 |
} |
|
| 398 |
} |
|
| 399 | ||
| 400 | 128x |
info->variable_map[this->log_devs.id_m] = &(recruitment)->log_recruit_devs; |
| 401 | ||
| 402 |
// set log_r |
|
| 403 | 128x |
recruitment->log_r.resize(this->log_r.size()); |
| 404 | 2160x |
for (size_t i = 0; i < log_r.size(); i++) {
|
| 405 | 2032x |
recruitment->log_r[i] = this->log_r[i].initial_value_m; |
| 406 | ||
| 407 | 2032x |
if (this->log_r[i].estimation_type_m.get() == "fixed_effects") {
|
| 408 | ! |
ss.str("");
|
| 409 | ! |
ss << "Recruitment." << this->id << ".log_r." << this->log_r[i].id_m; |
| 410 | ! |
info->RegisterParameterName(ss.str()); |
| 411 | ! |
info->RegisterParameter(recruitment->log_r[i]); |
| 412 |
} |
|
| 413 | 2032x |
if (this->log_r[i].estimation_type_m.get() == "random_effects") {
|
| 414 | 116x |
ss.str("");
|
| 415 | 116x |
ss << "Recruitment." << this->id << ".log_r." << this->log_r[i].id_m; |
| 416 | 116x |
info->RegisterRandomEffectName(ss.str()); |
| 417 | 116x |
info->RegisterRandomEffect(recruitment->log_r[i]); |
| 418 |
} |
|
| 419 |
} |
|
| 420 | ||
| 421 | 128x |
info->variable_map[this->log_r.id_m] = &(recruitment)->log_r; |
| 422 |
// set log_expected_recruitment |
|
| 423 | 128x |
recruitment->log_expected_recruitment.resize(this->n_years.get() + 1); |
| 424 | 3956x |
for (size_t i = 0; i < static_cast<size_t>(this->n_years.get() + 1); i++) {
|
| 425 | 3828x |
recruitment->log_expected_recruitment[i] = 0; |
| 426 |
} |
|
| 427 | 128x |
info->variable_map[this->log_expected_recruitment.id_m] = |
| 428 | 128x |
&(recruitment)->log_expected_recruitment; |
| 429 | ||
| 430 |
// add to Information |
|
| 431 | 128x |
info->recruitment_models[recruitment->id] = recruitment; |
| 432 | ||
| 433 | 128x |
return true; |
| 434 |
} |
|
| 435 | ||
| 436 |
/** |
|
| 437 |
* @brief Adds the parameters to the TMB model. |
|
| 438 |
* @return A boolean of true. |
|
| 439 |
*/ |
|
| 440 | 32x |
virtual bool add_to_fims_tmb() {
|
| 441 | 32x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 442 | 32x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 443 | ||
| 444 | 32x |
return true; |
| 445 |
} |
|
| 446 | ||
| 447 |
#endif |
|
| 448 |
}; |
|
| 449 | ||
| 450 |
/** |
|
| 451 |
* @brief Rcpp interface for Log--Devs to instantiate from R: |
|
| 452 |
* log_devs <- methods::new(log_devs). |
|
| 453 |
*/ |
|
| 454 |
class LogDevsRecruitmentInterface : public RecruitmentInterfaceBase {
|
|
| 455 |
public: |
|
| 456 |
/** |
|
| 457 |
* @brief The constructor. |
|
| 458 |
*/ |
|
| 459 | 32x |
LogDevsRecruitmentInterface() : RecruitmentInterfaceBase() {
|
| 460 | 32x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 461 | 64x |
std::make_shared<LogDevsRecruitmentInterface>(*this)); |
| 462 |
} |
|
| 463 | ||
| 464 |
/** |
|
| 465 |
* @brief The destructor. |
|
| 466 |
*/ |
|
| 467 | 192x |
virtual ~LogDevsRecruitmentInterface() {}
|
| 468 | ||
| 469 |
/** |
|
| 470 |
* @brief Gets the ID of the interface base object. |
|
| 471 |
* @return The ID. |
|
| 472 |
*/ |
|
| 473 | 31x |
virtual uint32_t get_id() { return this->id; }
|
| 474 | ||
| 475 |
/** |
|
| 476 |
* @brief Evaluate mean - returns empty function for this module. |
|
| 477 |
* @param spawners Spawning biomass per time step. |
|
| 478 |
* @param ssbzero The biomass at unfished levels. |
|
| 479 |
*/ |
|
| 480 | ! |
virtual double evaluate_mean(double spawners, double ssbzero) { return 0; }
|
| 481 | ||
| 482 |
/** |
|
| 483 |
* @brief Evaluate recruitment process using the Log--Devs approach. |
|
| 484 |
* @param pos Position index, e.g., which year. |
|
| 485 |
*/ |
|
| 486 | ! |
virtual double evaluate_process(size_t pos) {
|
| 487 | ! |
fims_popdy::LogDevs<double> LogDevs; |
| 488 | ||
| 489 | ! |
return LogDevs.evaluate_process(pos); |
| 490 |
} |
|
| 491 | ||
| 492 |
#ifdef TMB_MODEL |
|
| 493 | ||
| 494 |
template <typename Type> |
|
| 495 | 116x |
bool add_to_fims_tmb_internal() {
|
| 496 | 116x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 497 |
fims_info::Information<Type>::GetInstance(); |
|
| 498 | ||
| 499 | 116x |
std::shared_ptr<fims_popdy::LogDevs<Type>> recruitment_process = |
| 500 |
std::make_shared<fims_popdy::LogDevs<Type>>(); |
|
| 501 | ||
| 502 | 116x |
recruitment_process->id = this->id; |
| 503 | ||
| 504 |
// add to Information |
|
| 505 | 116x |
info->recruitment_process_models[recruitment_process->id] = |
| 506 |
recruitment_process; |
|
| 507 | ||
| 508 | 116x |
return true; |
| 509 |
} |
|
| 510 | ||
| 511 |
/** |
|
| 512 |
* @brief Adds the parameters to the TMB model. |
|
| 513 |
* @return A boolean of true. |
|
| 514 |
*/ |
|
| 515 | 29x |
virtual bool add_to_fims_tmb() {
|
| 516 | 29x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 517 | 29x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 518 | ||
| 519 | 29x |
return true; |
| 520 |
} |
|
| 521 | ||
| 522 |
#endif |
|
| 523 |
}; |
|
| 524 | ||
| 525 |
/** |
|
| 526 |
* @brief Rcpp interface for Log--R to instantiate from R: |
|
| 527 |
* log_r <- methods::new(log_r). |
|
| 528 |
*/ |
|
| 529 |
class LogRRecruitmentInterface : public RecruitmentInterfaceBase {
|
|
| 530 |
public: |
|
| 531 |
/** |
|
| 532 |
* @brief The constructor. |
|
| 533 |
*/ |
|
| 534 | 1x |
LogRRecruitmentInterface() : RecruitmentInterfaceBase() {
|
| 535 | 1x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 536 | 2x |
std::make_shared<LogRRecruitmentInterface>(*this)); |
| 537 |
} |
|
| 538 | ||
| 539 |
/** |
|
| 540 |
* @brief The destructor. |
|
| 541 |
*/ |
|
| 542 | 6x |
virtual ~LogRRecruitmentInterface() {}
|
| 543 | ||
| 544 |
/** |
|
| 545 |
* @brief Gets the ID of the interface base object. |
|
| 546 |
* @return The ID. |
|
| 547 |
*/ |
|
| 548 | 1x |
virtual uint32_t get_id() { return this->id; }
|
| 549 | ||
| 550 |
/** |
|
| 551 |
* @brief Evaluate mean - returns empty function for this module. |
|
| 552 |
* @param spawners Spawning biomass per time step. |
|
| 553 |
* @param ssbzero The biomass at unfished levels. |
|
| 554 |
*/ |
|
| 555 | ! |
virtual double evaluate_mean(double spawners, double ssbzero) { return 0; }
|
| 556 | ||
| 557 |
/** |
|
| 558 |
* @brief Evaluate recruitment process using the Log--R approach. |
|
| 559 |
* @param pos Position index, e.g., which year. |
|
| 560 |
*/ |
|
| 561 | ! |
virtual double evaluate_process(size_t pos) {
|
| 562 | ! |
fims_popdy::LogR<double> LogR; |
| 563 | ||
| 564 | ! |
return LogR.evaluate_process(pos); |
| 565 |
} |
|
| 566 | ||
| 567 |
#ifdef TMB_MODEL |
|
| 568 | ||
| 569 |
template <typename Type> |
|
| 570 | 4x |
bool add_to_fims_tmb_internal() {
|
| 571 | 4x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 572 |
fims_info::Information<Type>::GetInstance(); |
|
| 573 | ||
| 574 | 4x |
std::shared_ptr<fims_popdy::LogR<Type>> recruitment_process = |
| 575 |
std::make_shared<fims_popdy::LogR<Type>>(); |
|
| 576 | ||
| 577 | 4x |
recruitment_process->id = this->id; |
| 578 | ||
| 579 |
// add to Information |
|
| 580 | 4x |
info->recruitment_process_models[recruitment_process->id] = |
| 581 |
recruitment_process; |
|
| 582 | ||
| 583 | 4x |
return true; |
| 584 |
} |
|
| 585 | ||
| 586 |
/** |
|
| 587 |
* @brief Adds the parameters to the TMB model. |
|
| 588 |
* @return A boolean of true. |
|
| 589 |
*/ |
|
| 590 | 1x |
virtual bool add_to_fims_tmb() {
|
| 591 | 1x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 592 | 1x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 593 | ||
| 594 | 1x |
return true; |
| 595 |
} |
|
| 596 | ||
| 597 |
#endif |
|
| 598 |
}; |
|
| 599 | ||
| 600 |
#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 | 85x |
SelectivityInterfaceBase() {
|
| 41 | 85x |
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 | 85x |
SelectivityInterfaceBase(const SelectivityInterfaceBase &other) |
| 53 | 85x |
: id(other.id) {}
|
| 54 | ||
| 55 |
/** |
|
| 56 |
* @brief The destructor. |
|
| 57 |
*/ |
|
| 58 | 170x |
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 | 80x |
LogisticSelectivityInterface() : SelectivityInterfaceBase() {
|
| 98 | 80x |
SelectivityInterfaceBase::live_objects[this->id] = |
| 99 | 160x |
std::make_shared<LogisticSelectivityInterface>(*this); |
| 100 | 80x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 101 | 80x |
SelectivityInterfaceBase::live_objects[this->id]); |
| 102 |
} |
|
| 103 | ||
| 104 |
/** |
|
| 105 |
* @brief Construct a new Logistic Selectivity Interface object |
|
| 106 |
* |
|
| 107 |
* @param other |
|
| 108 |
*/ |
|
| 109 | 80x |
LogisticSelectivityInterface(const LogisticSelectivityInterface &other) |
| 110 | 80x |
: SelectivityInterfaceBase(other), |
| 111 | 80x |
inflection_point(other.inflection_point), |
| 112 | 80x |
slope(other.slope) {}
|
| 113 | ||
| 114 |
/** |
|
| 115 |
* @brief The destructor. |
|
| 116 |
*/ |
|
| 117 | 480x |
virtual ~LogisticSelectivityInterface() {}
|
| 118 | ||
| 119 |
/** |
|
| 120 |
* @brief Gets the ID of the interface base object. |
|
| 121 |
* @return The ID. |
|
| 122 |
*/ |
|
| 123 | 74x |
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 | 48x |
virtual void finalize() {
|
| 144 | 48x |
if (this->finalized) {
|
| 145 |
// log warning that finalize has been called more than once. |
|
| 146 | 2x |
FIMS_WARNING_LOG("Logistic Selectivity " + fims::to_string(this->id) +
|
| 147 |
" has been finalized already."); |
|
| 148 |
} |
|
| 149 | ||
| 150 | 48x |
this->finalized = true; // indicate this has been called already |
| 151 | ||
| 152 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 153 | 48x |
fims_info::Information<double>::GetInstance(); |
| 154 | ||
| 155 | 48x |
fims_info::Information<double>::selectivity_models_iterator it; |
| 156 | ||
| 157 |
// search for maturity in Information |
|
| 158 | 48x |
it = info->selectivity_models.find(this->id); |
| 159 |
// if not found, just return |
|
| 160 | 48x |
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 | 48x |
it->second); |
| 168 | ||
| 169 | 96x |
for (size_t i = 0; i < inflection_point.size(); i++) {
|
| 170 | 48x |
if (this->inflection_point[i].estimation_type_m.get() == "constant") {
|
| 171 | 4x |
this->inflection_point[i].final_value_m = |
| 172 | 4x |
this->inflection_point[i].initial_value_m; |
| 173 |
} else {
|
|
| 174 | 44x |
this->inflection_point[i].final_value_m = sel->inflection_point[i]; |
| 175 |
} |
|
| 176 |
} |
|
| 177 | ||
| 178 | 96x |
for (size_t i = 0; i < slope.size(); i++) {
|
| 179 | 48x |
if (this->slope[i].estimation_type_m.get() == "constant") {
|
| 180 | 4x |
this->slope[i].final_value_m = this->slope[i].initial_value_m; |
| 181 |
} else {
|
|
| 182 | 44x |
this->slope[i].final_value_m = sel->slope[i]; |
| 183 |
} |
|
| 184 |
} |
|
| 185 |
} |
|
| 186 |
} |
|
| 187 | ||
| 188 |
/** |
|
| 189 |
* @brief Converts the data to json representation for the output. |
|
| 190 |
* @return A string is returned specifying that the module relates to the |
|
| 191 |
* selectivity interface with logistic selectivity. It also returns the ID |
|
| 192 |
* and the parameters. This string is formatted for a json file. |
|
| 193 |
*/ |
|
| 194 | 48x |
virtual std::string to_json() {
|
| 195 | 48x |
std::stringstream ss; |
| 196 | ||
| 197 | 48x |
ss << "{\n";
|
| 198 | 48x |
ss << " \"module_name\":\"Selectivity\",\n"; |
| 199 | 48x |
ss << " \"module_type\": \"Logistic\",\n"; |
| 200 | 48x |
ss << " \"module_id\": " << this->id << ",\n"; |
| 201 | ||
| 202 | 48x |
ss << " \"parameters\": [\n{\n";
|
| 203 | 48x |
ss << " \"name\": \"inflection_point\",\n"; |
| 204 | 48x |
ss << " \"id\":" << this->inflection_point.id_m << ",\n"; |
| 205 | 48x |
ss << " \"type\": \"vector\",\n"; |
| 206 | 48x |
ss << " \"dimensionality\": {\n";
|
| 207 | 48x |
ss << " \"header\": [null],\n"; |
| 208 | 48x |
ss << " \"dimensions\": [1]\n},\n"; |
| 209 | 48x |
ss << " \"values\":" << this->inflection_point << "},\n "; |
| 210 | ||
| 211 | 48x |
ss << "{\n";
|
| 212 | 48x |
ss << " \"name\": \"slope\",\n"; |
| 213 | 48x |
ss << " \"id\":" << this->slope.id_m << ",\n"; |
| 214 | 48x |
ss << " \"type\": \"vector\",\n"; |
| 215 | 48x |
ss << " \"dimensionality\": {\n";
|
| 216 | 48x |
ss << " \"header\": [null],\n"; |
| 217 | 48x |
ss << " \"dimensions\": [1]\n},\n"; |
| 218 | 48x |
ss << " \"values\":" << this->slope << "}]\n"; |
| 219 | ||
| 220 | 48x |
ss << "}"; |
| 221 | ||
| 222 | 96x |
return ss.str(); |
| 223 |
} |
|
| 224 | ||
| 225 |
#ifdef TMB_MODEL |
|
| 226 | ||
| 227 |
template <typename Type> |
|
| 228 | 272x |
bool add_to_fims_tmb_internal() {
|
| 229 | 272x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 230 |
fims_info::Information<Type>::GetInstance(); |
|
| 231 | ||
| 232 | 272x |
std::shared_ptr<fims_popdy::LogisticSelectivity<Type>> selectivity = |
| 233 |
std::make_shared<fims_popdy::LogisticSelectivity<Type>>(); |
|
| 234 | 272x |
std::stringstream ss; |
| 235 |
// set relative info |
|
| 236 | 272x |
selectivity->id = this->id; |
| 237 | 272x |
selectivity->inflection_point.resize(this->inflection_point.size()); |
| 238 | 544x |
for (size_t i = 0; i < this->inflection_point.size(); i++) {
|
| 239 | 272x |
selectivity->inflection_point[i] = |
| 240 | 272x |
this->inflection_point[i].initial_value_m; |
| 241 | 272x |
if (this->inflection_point[i].estimation_type_m.get() == |
| 242 |
"fixed_effects") {
|
|
| 243 | 248x |
ss.str("");
|
| 244 | 248x |
ss << "Selectivity." << this->id << ".inflection_point." |
| 245 | 248x |
<< this->inflection_point[i].id_m; |
| 246 | 248x |
info->RegisterParameterName(ss.str()); |
| 247 | 248x |
info->RegisterParameter(selectivity->inflection_point[i]); |
| 248 |
} |
|
| 249 | 272x |
if (this->inflection_point[i].estimation_type_m.get() == |
| 250 |
"random_effects") {
|
|
| 251 | 8x |
ss.str("");
|
| 252 | 8x |
ss << "Selectivity." << this->id << ".inflection_point." |
| 253 | 8x |
<< this->inflection_point[i].id_m; |
| 254 | 8x |
info->RegisterRandomEffect(selectivity->inflection_point[i]); |
| 255 | 8x |
info->RegisterRandomEffectName(ss.str()); |
| 256 |
} |
|
| 257 |
} |
|
| 258 | 272x |
info->variable_map[this->inflection_point.id_m] = |
| 259 | 272x |
&(selectivity)->inflection_point; |
| 260 | ||
| 261 | 272x |
selectivity->slope.resize(this->slope.size()); |
| 262 | 544x |
for (size_t i = 0; i < this->slope.size(); i++) {
|
| 263 | 272x |
selectivity->slope[i] = this->slope[i].initial_value_m; |
| 264 | 272x |
if (this->slope[i].estimation_type_m.get() == "fixed_effects") {
|
| 265 | 252x |
ss.str("");
|
| 266 | 252x |
ss << "Selectivity." << this->id << ".slope." << this->slope[i].id_m; |
| 267 | 252x |
info->RegisterParameterName(ss.str()); |
| 268 | 252x |
info->RegisterParameter(selectivity->slope[i]); |
| 269 |
} |
|
| 270 | 272x |
if (this->slope[i].estimation_type_m.get() == "random_effects") {
|
| 271 | 12x |
ss.str("");
|
| 272 | 12x |
ss << "Selectivity." << this->id << ".slope." << this->slope[i].id_m; |
| 273 | 12x |
info->RegisterRandomEffectName(ss.str()); |
| 274 | 12x |
info->RegisterRandomEffect(selectivity->slope[i]); |
| 275 |
} |
|
| 276 |
} |
|
| 277 | 272x |
info->variable_map[this->slope.id_m] = &(selectivity)->slope; |
| 278 | ||
| 279 |
// add to Information |
|
| 280 | 272x |
info->selectivity_models[selectivity->id] = selectivity; |
| 281 | ||
| 282 | 272x |
return true; |
| 283 |
} |
|
| 284 | ||
| 285 |
/** |
|
| 286 |
* @brief Adds the parameters to the TMB model. |
|
| 287 |
* @return A boolean of true. |
|
| 288 |
*/ |
|
| 289 | 68x |
virtual bool add_to_fims_tmb() {
|
| 290 | 68x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 291 | 68x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 292 | ||
| 293 | 68x |
return true; |
| 294 |
} |
|
| 295 | ||
| 296 |
#endif |
|
| 297 |
}; |
|
| 298 | ||
| 299 |
/** |
|
| 300 |
* @brief Rcpp interface for logistic selectivity as an S4 object. To |
|
| 301 |
* instantiate from R: logistic_selectivity <- |
|
| 302 |
* methods::new(logistic_selectivity) |
|
| 303 |
*/ |
|
| 304 |
class DoubleLogisticSelectivityInterface : public SelectivityInterfaceBase {
|
|
| 305 |
public: |
|
| 306 |
ParameterVector inflection_point_asc; /**< the index value at which the |
|
| 307 |
response reaches .5 */ |
|
| 308 |
ParameterVector |
|
| 309 |
slope_asc; /**< the width of the curve at the inflection_point */ |
|
| 310 |
ParameterVector inflection_point_desc; /**< the index value at which the |
|
| 311 |
response reaches .5 */ |
|
| 312 |
ParameterVector |
|
| 313 |
slope_desc; /**< the width of the curve at the inflection_point */ |
|
| 314 | ||
| 315 | 5x |
DoubleLogisticSelectivityInterface() : SelectivityInterfaceBase() {
|
| 316 | 5x |
SelectivityInterfaceBase::live_objects[this->id] = |
| 317 | 10x |
std::make_shared<DoubleLogisticSelectivityInterface>(*this); |
| 318 | 5x |
FIMSRcppInterfaceBase::fims_interface_objects.push_back( |
| 319 | 5x |
SelectivityInterfaceBase::live_objects[this->id]); |
| 320 |
} |
|
| 321 | ||
| 322 |
/** |
|
| 323 |
* @brief Construct a new Double Logistic Selectivity Interface object |
|
| 324 |
* |
|
| 325 |
* @param other |
|
| 326 |
*/ |
|
| 327 | 5x |
DoubleLogisticSelectivityInterface( |
| 328 |
const DoubleLogisticSelectivityInterface &other) |
|
| 329 | 5x |
: SelectivityInterfaceBase(other), |
| 330 | 5x |
inflection_point_asc(other.inflection_point_asc), |
| 331 | 5x |
slope_asc(other.slope_asc), |
| 332 | 5x |
inflection_point_desc(other.inflection_point_desc), |
| 333 | 10x |
slope_desc(other.slope_desc) {}
|
| 334 | ||
| 335 | 30x |
virtual ~DoubleLogisticSelectivityInterface() {}
|
| 336 | ||
| 337 |
/** @brief returns the id for the double logistic selectivity interface */ |
|
| 338 | 2x |
virtual uint32_t get_id() { return this->id; }
|
| 339 | ||
| 340 |
/** @brief evaluate the double logistic selectivity function |
|
| 341 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 342 |
* size in selectivity). |
|
| 343 |
*/ |
|
| 344 | 3x |
virtual double evaluate(double x) {
|
| 345 | 3x |
fims_popdy::DoubleLogisticSelectivity<double> DoubleLogisticSel; |
| 346 | 3x |
DoubleLogisticSel.inflection_point_asc.resize(1); |
| 347 | 6x |
DoubleLogisticSel.inflection_point_asc[0] = |
| 348 | 3x |
this->inflection_point_asc[0].initial_value_m; |
| 349 | 3x |
DoubleLogisticSel.slope_asc.resize(1); |
| 350 | 3x |
DoubleLogisticSel.slope_asc[0] = this->slope_asc[0].initial_value_m; |
| 351 | 3x |
DoubleLogisticSel.inflection_point_desc.resize(1); |
| 352 | 6x |
DoubleLogisticSel.inflection_point_desc[0] = |
| 353 | 3x |
this->inflection_point_desc[0].initial_value_m; |
| 354 | 3x |
DoubleLogisticSel.slope_desc.resize(1); |
| 355 | 3x |
DoubleLogisticSel.slope_desc[0] = this->slope_desc[0].initial_value_m; |
| 356 | 6x |
return DoubleLogisticSel.evaluate(x); |
| 357 |
} |
|
| 358 |
/** |
|
| 359 |
* @brief finalize function. Extracts derived quantities back to |
|
| 360 |
* the Rcpp interface object from the Information object. |
|
| 361 |
*/ |
|
| 362 | ! |
virtual void finalize() {
|
| 363 | ! |
if (this->finalized) {
|
| 364 |
// log warning that finalize has been called more than once. |
|
| 365 | ! |
FIMS_WARNING_LOG("Double Logistic Selectivity " +
|
| 366 |
fims::to_string(this->id) + |
|
| 367 |
" has been finalized already."); |
|
| 368 |
} |
|
| 369 | ||
| 370 | ! |
this->finalized = true; // indicate this has been called already |
| 371 | ||
| 372 |
std::shared_ptr<fims_info::Information<double>> info = |
|
| 373 | ! |
fims_info::Information<double>::GetInstance(); |
| 374 | ||
| 375 | ! |
fims_info::Information<double>::selectivity_models_iterator it; |
| 376 | ||
| 377 |
// search for maturity in Information |
|
| 378 | ! |
it = info->selectivity_models.find(this->id); |
| 379 |
// if not found, just return |
|
| 380 | ! |
if (it == info->selectivity_models.end()) {
|
| 381 | ! |
FIMS_WARNING_LOG("Double Logistic Selectivity " +
|
| 382 |
fims::to_string(this->id) + |
|
| 383 |
" not found in Information."); |
|
| 384 | ! |
return; |
| 385 |
} else {
|
|
| 386 |
std::shared_ptr<fims_popdy::DoubleLogisticSelectivity<double>> sel = |
|
| 387 |
std::dynamic_pointer_cast< |
|
| 388 | ! |
fims_popdy::DoubleLogisticSelectivity<double>>(it->second); |
| 389 | ||
| 390 | ! |
for (size_t i = 0; i < inflection_point_asc.size(); i++) {
|
| 391 | ! |
if (this->inflection_point_asc[i].estimation_type_m.get() == |
| 392 |
"constant") {
|
|
| 393 | ! |
this->inflection_point_asc[i].final_value_m = |
| 394 | ! |
this->inflection_point_asc[i].initial_value_m; |
| 395 |
} else {
|
|
| 396 | ! |
this->inflection_point_asc[i].final_value_m = |
| 397 | ! |
sel->inflection_point_asc[i]; |
| 398 |
} |
|
| 399 |
} |
|
| 400 | ||
| 401 | ! |
for (size_t i = 0; i < slope_asc.size(); i++) {
|
| 402 | ! |
if (this->slope_asc[i].estimation_type_m.get() == "constant") {
|
| 403 | ! |
this->slope_asc[i].final_value_m = this->slope_asc[i].initial_value_m; |
| 404 |
} else {
|
|
| 405 | ! |
this->slope_asc[i].final_value_m = sel->slope_asc[i]; |
| 406 |
} |
|
| 407 |
} |
|
| 408 | ||
| 409 | ! |
for (size_t i = 0; i < inflection_point_desc.size(); i++) {
|
| 410 | ! |
if (this->inflection_point_desc[i].estimation_type_m.get() == |
| 411 |
"constant") {
|
|
| 412 | ! |
this->inflection_point_desc[i].final_value_m = |
| 413 | ! |
this->inflection_point_desc[i].initial_value_m; |
| 414 |
} else {
|
|
| 415 | ! |
this->inflection_point_desc[i].final_value_m = |
| 416 | ! |
sel->inflection_point_desc[i]; |
| 417 |
} |
|
| 418 |
} |
|
| 419 | ||
| 420 | ! |
for (size_t i = 0; i < slope_desc.size(); i++) {
|
| 421 | ! |
if (this->slope_desc[i].estimation_type_m.get() == "constant") {
|
| 422 | ! |
this->slope_desc[i].final_value_m = |
| 423 | ! |
this->slope_desc[i].initial_value_m; |
| 424 |
} else {
|
|
| 425 | ! |
this->slope_desc[i].final_value_m = sel->slope_desc[i]; |
| 426 |
} |
|
| 427 |
} |
|
| 428 |
} |
|
| 429 |
} |
|
| 430 | ||
| 431 |
/** |
|
| 432 |
* @brief Convert the data to json representation for the output. |
|
| 433 |
*/ |
|
| 434 | ! |
virtual std::string to_json() {
|
| 435 | ! |
std::stringstream ss; |
| 436 | ||
| 437 | ! |
ss << "{\n";
|
| 438 | ! |
ss << " \"module_name\": \"Selectivity\",\n"; |
| 439 | ! |
ss << " \"module_type\": \"DoubleLogistic\",\n"; |
| 440 | ! |
ss << " \"module_id\": " << this->id << ",\n"; |
| 441 | ||
| 442 | ! |
ss << " \"parameters\":[\n{\n";
|
| 443 | ! |
ss << " \"name\": \"inflection_point_asc\",\n"; |
| 444 | ! |
ss << " \"id\":" << this->inflection_point_asc.id_m << ",\n"; |
| 445 | ! |
ss << " \"type\": \"vector\",\n"; |
| 446 | ! |
ss << " \"dimensionality\": {\n";
|
| 447 | ! |
ss << " \"header\": [null],\n"; |
| 448 | ! |
ss << " \"dimensions\": [1]\n},\n"; |
| 449 | ! |
ss << " \"values\":" << this->inflection_point_asc << "},\n"; |
| 450 | ||
| 451 | ! |
ss << "{\n";
|
| 452 | ! |
ss << " \"name\": \"slope_asc\",\n"; |
| 453 | ! |
ss << " \"id\":" << this->slope_asc.id_m << ",\n"; |
| 454 | ! |
ss << " \"type\": \"vector\",\n"; |
| 455 | ! |
ss << " \"dimensionality\": {\n";
|
| 456 | ! |
ss << " \"header\": [null],\n"; |
| 457 | ! |
ss << " \"dimensions\": [1]\n},\n"; |
| 458 | ! |
ss << " \"values\":" << this->slope_asc << "},\n"; |
| 459 | ||
| 460 | ! |
ss << " {\n";
|
| 461 | ! |
ss << " \"name\": \"inflection_point_desc\",\n"; |
| 462 | ! |
ss << " \"id\":" << this->inflection_point_desc.id_m << ",\n"; |
| 463 | ! |
ss << " \"type\": \"vector\",\n"; |
| 464 | ! |
ss << " \"dimensionality\": {\n";
|
| 465 | ! |
ss << " \"header\": [null],\n"; |
| 466 | ! |
ss << " \"dimensions\": [1]\n},\n"; |
| 467 | ! |
ss << " \"values\":" << this->inflection_point_desc << "},\n"; |
| 468 | ||
| 469 | ! |
ss << "{\n";
|
| 470 | ! |
ss << " \"name\": \"slope_desc\",\n"; |
| 471 | ! |
ss << " \"id\":" << this->slope_desc.id_m << ",\n"; |
| 472 | ! |
ss << " \"type\": \"vector\",\n"; |
| 473 | ! |
ss << " \"dimensionality\": {\n";
|
| 474 | ! |
ss << " \"header\": [null],\n"; |
| 475 | ! |
ss << " \"dimensions\": [1]\n},\n"; |
| 476 | ! |
ss << " \"values\":" << this->slope_desc << "}]\n"; |
| 477 | ||
| 478 | ! |
ss << "}"; |
| 479 | ||
| 480 | ! |
return ss.str(); |
| 481 |
} |
|
| 482 | ||
| 483 |
#ifdef TMB_MODEL |
|
| 484 | ||
| 485 |
template <typename Type> |
|
| 486 | 8x |
bool add_to_fims_tmb_internal() {
|
| 487 | 8x |
std::shared_ptr<fims_info::Information<Type>> info = |
| 488 |
fims_info::Information<Type>::GetInstance(); |
|
| 489 | ||
| 490 | 8x |
std::shared_ptr<fims_popdy::DoubleLogisticSelectivity<Type>> selectivity = |
| 491 |
std::make_shared<fims_popdy::DoubleLogisticSelectivity<Type>>(); |
|
| 492 | ||
| 493 | 8x |
std::stringstream ss; |
| 494 |
// set relative info |
|
| 495 | 8x |
selectivity->id = this->id; |
| 496 | 8x |
selectivity->inflection_point_asc.resize(this->inflection_point_asc.size()); |
| 497 | 16x |
for (size_t i = 0; i < this->inflection_point_asc.size(); i++) {
|
| 498 | 8x |
selectivity->inflection_point_asc[i] = |
| 499 | 8x |
this->inflection_point_asc[i].initial_value_m; |
| 500 | 8x |
if (this->inflection_point_asc[i].estimation_type_m.get() == |
| 501 |
"fixed_effects") {
|
|
| 502 | 4x |
ss.str("");
|
| 503 | 4x |
ss << "Selectivity." << this->id << ".inflection_point_asc." |
| 504 | 4x |
<< this->inflection_point_asc[i].id_m; |
| 505 | 4x |
info->RegisterParameterName(ss.str()); |
| 506 | 4x |
info->RegisterParameter(selectivity->inflection_point_asc[i]); |
| 507 |
} |
|
| 508 | 8x |
if (this->inflection_point_asc[i].estimation_type_m.get() == |
| 509 |
"random_effects") {
|
|
| 510 | 4x |
ss.str("");
|
| 511 | 4x |
ss << "Selectivity." << this->id << ".inflection_point_asc." |
| 512 | 4x |
<< this->inflection_point_asc[i].id_m; |
| 513 | 4x |
info->RegisterRandomEffectName(ss.str()); |
| 514 | 4x |
info->RegisterRandomEffect(selectivity->inflection_point_asc[i]); |
| 515 |
} |
|
| 516 |
} |
|
| 517 | 8x |
info->variable_map[this->inflection_point_asc.id_m] = |
| 518 | 8x |
&(selectivity)->inflection_point_asc; |
| 519 | ||
| 520 | 8x |
selectivity->slope_asc.resize(this->slope_asc.size()); |
| 521 | 16x |
for (size_t i = 0; i < this->slope_asc.size(); i++) {
|
| 522 | 8x |
selectivity->slope_asc[i] = this->slope_asc[i].initial_value_m; |
| 523 | ||
| 524 | 8x |
if (this->slope_asc[i].estimation_type_m.get() == "fixed_effects") {
|
| 525 | ! |
ss.str("");
|
| 526 | ! |
ss << "Selectivity." << this->id << ".slope_asc." |
| 527 | ! |
<< this->slope_asc[i].id_m; |
| 528 | ! |
info->RegisterParameterName(ss.str()); |
| 529 | ! |
info->RegisterParameter(selectivity->slope_asc[i]); |
| 530 |
} |
|
| 531 | 8x |
if (this->slope_asc[i].estimation_type_m.get() == "random_effects") {
|
| 532 | ! |
ss.str("");
|
| 533 | ! |
ss << "Selectivity." << this->id << ".slope_asc." |
| 534 | ! |
<< this->slope_asc[i].id_m; |
| 535 | ! |
info->RegisterRandomEffectName(ss.str()); |
| 536 | ! |
info->RegisterRandomEffect(selectivity->slope_asc[i]); |
| 537 |
} |
|
| 538 |
} |
|
| 539 | 8x |
info->variable_map[this->slope_asc.id_m] = &(selectivity)->slope_asc; |
| 540 | ||
| 541 | 8x |
selectivity->inflection_point_desc.resize( |
| 542 |
this->inflection_point_desc.size()); |
|
| 543 | 16x |
for (size_t i = 0; i < this->inflection_point_desc.size(); i++) {
|
| 544 | 8x |
selectivity->inflection_point_desc[i] = |
| 545 | 8x |
this->inflection_point_desc[i].initial_value_m; |
| 546 | ||
| 547 | 8x |
if (this->inflection_point_desc[i].estimation_type_m.get() == |
| 548 |
"fixed_effects") {
|
|
| 549 | 4x |
ss.str("");
|
| 550 | 4x |
ss << "Selectivity." << this->id << ".inflection_point_desc." |
| 551 | 4x |
<< this->inflection_point_desc[i].id_m; |
| 552 | 4x |
info->RegisterParameterName(ss.str()); |
| 553 | 4x |
info->RegisterParameter(selectivity->inflection_point_desc[i]); |
| 554 |
} |
|
| 555 | 8x |
if (this->inflection_point_desc[i].estimation_type_m.get() == |
| 556 |
"random_effects") {
|
|
| 557 | 4x |
ss.str("");
|
| 558 | 4x |
ss << "Selectivity." << this->id << ".inflection_point_desc." |
| 559 | 4x |
<< this->inflection_point_desc[i].id_m; |
| 560 | 4x |
info->RegisterRandomEffectName(ss.str()); |
| 561 | 4x |
info->RegisterRandomEffect(selectivity->inflection_point_desc[i]); |
| 562 |
} |
|
| 563 |
} |
|
| 564 | 8x |
info->variable_map[this->inflection_point_desc.id_m] = |
| 565 | 8x |
&(selectivity)->inflection_point_desc; |
| 566 | ||
| 567 | 8x |
selectivity->slope_desc.resize(this->slope_desc.size()); |
| 568 | 16x |
for (size_t i = 0; i < this->slope_desc.size(); i++) {
|
| 569 | 8x |
selectivity->slope_desc[i] = this->slope_desc[i].initial_value_m; |
| 570 | ||
| 571 | 8x |
if (this->slope_desc[i].estimation_type_m.get() == "fixed_effects") {
|
| 572 | 4x |
ss.str("");
|
| 573 | 4x |
ss << "Selectivity." << this->id << ".slope_desc." |
| 574 | 4x |
<< this->slope_desc[i].id_m; |
| 575 | 4x |
info->RegisterParameterName(ss.str()); |
| 576 | 4x |
info->RegisterParameter(selectivity->slope_desc[i]); |
| 577 |
} |
|
| 578 | 8x |
if (this->slope_desc[i].estimation_type_m.get() == "random_effects") {
|
| 579 | 4x |
ss.str("");
|
| 580 | 4x |
ss << "Selectivity." << this->id << ".slope_desc." |
| 581 | 4x |
<< this->slope_desc[i].id_m; |
| 582 | 4x |
info->RegisterRandomEffectName(ss.str()); |
| 583 | 4x |
info->RegisterRandomEffect(selectivity->slope_desc[i]); |
| 584 |
} |
|
| 585 |
} |
|
| 586 | ||
| 587 | 8x |
info->variable_map[this->slope_desc.id_m] = &(selectivity)->slope_desc; |
| 588 | ||
| 589 |
// add to Information |
|
| 590 | 8x |
info->selectivity_models[selectivity->id] = selectivity; |
| 591 | ||
| 592 | 8x |
return true; |
| 593 |
} |
|
| 594 | ||
| 595 |
/** |
|
| 596 |
* @brief Adds the parameters to the TMB model. |
|
| 597 |
* @return A boolean of true. |
|
| 598 |
*/ |
|
| 599 | 2x |
virtual bool add_to_fims_tmb() {
|
| 600 | 2x |
this->add_to_fims_tmb_internal<TMB_FIMS_REAL_TYPE>(); |
| 601 | 2x |
this->add_to_fims_tmb_internal<TMBAD_FIMS_TYPE>(); |
| 602 | ||
| 603 | 2x |
return true; |
| 604 |
} |
|
| 605 | ||
| 606 |
#endif |
|
| 607 |
}; |
|
| 608 | ||
| 609 |
#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 |
/* Dictionary block for shared parameter snippet documentations. |
|
| 17 |
* Referenced in function docs via @snippet{doc} this snippet_id.
|
|
| 18 |
[param_population] |
|
| 19 |
@param population Shared pointer to the population object. |
|
| 20 |
[param_population] |
|
| 21 |
[param_i_age_year] |
|
| 22 |
@param i_age_year Dimension folded index for age and year. |
|
| 23 |
[param_i_age_year] |
|
| 24 |
[param_year] |
|
| 25 |
@param year Year index. |
|
| 26 |
[param_year] |
|
| 27 |
[param_age] |
|
| 28 |
@param age Age index. |
|
| 29 |
[param_age] |
|
| 30 |
[param_i_agem1_yearm1] |
|
| 31 |
@param i_agem1_yearm1 Dimension folded index for age-1 and year-1. |
|
| 32 |
[param_i_agem1_yearm1] |
|
| 33 |
[param_i_dev] |
|
| 34 |
@param i_dev Index to log_recruit_dev of vector length n_years-1. |
|
| 35 |
[param_i_dev] |
|
| 36 |
[param_other] |
|
| 37 |
@param other The other CatchAtAge object to copy from. |
|
| 38 |
[param_other] |
|
| 39 |
*/ |
|
| 40 | ||
| 41 |
namespace fims_popdy {
|
|
| 42 | ||
| 43 |
template <typename Type> |
|
| 44 |
/** |
|
| 45 |
* @brief CatchAtAge is a class containing a catch-at-age model, which is |
|
| 46 |
* just one of many potential fishery models that can be used in FIMS. The |
|
| 47 |
* CatchAtAge class inherits from the FisheryModelBase class and can be used |
|
| 48 |
* to fit both age and length data even though it is called CatchAtAge. |
|
| 49 |
* |
|
| 50 |
* See the @ref glossary for definitions of mathematical symbols used below. |
|
| 51 |
* |
|
| 52 |
*/ |
|
| 53 |
class CatchAtAge : public FisheryModelBase<Type> {
|
|
| 54 |
public: |
|
| 55 |
/** |
|
| 56 |
* @brief The name of the model. |
|
| 57 |
* |
|
| 58 |
*/ |
|
| 59 |
std::string name_m; |
|
| 60 | ||
| 61 |
/** |
|
| 62 |
* @brief Iterate the derived quantities. |
|
| 63 |
* |
|
| 64 |
*/ |
|
| 65 |
typedef typename std::map<std::string, fims::Vector<Type>>::iterator |
|
| 66 |
derived_quantities_iterator; |
|
| 67 | ||
| 68 |
/** |
|
| 69 |
* @brief Used to iterate through fleet-based derived quantities. |
|
| 70 |
* |
|
| 71 |
*/ |
|
| 72 |
typedef typename std::map<uint32_t, |
|
| 73 |
std::map<std::string, fims::Vector<Type>>>::iterator |
|
| 74 |
fleet_derived_quantities_iterator; |
|
| 75 | ||
| 76 |
/** |
|
| 77 |
* @brief Used to iterate through fleet-based derived quantities dimensions. |
|
| 78 |
*/ |
|
| 79 |
typedef |
|
| 80 |
typename std::map<uint32_t, |
|
| 81 |
std::map<std::string, fims::Vector<size_t>>>::iterator |
|
| 82 |
fleet_derived_quantities_dims_iterator; |
|
| 83 |
/** |
|
| 84 |
* @brief Used to iterate through population-based derived quantities. |
|
| 85 |
* |
|
| 86 |
*/ |
|
| 87 |
typedef typename std::map<uint32_t, |
|
| 88 |
std::map<std::string, fims::Vector<Type>>>::iterator |
|
| 89 |
population_derived_quantities_iterator; |
|
| 90 | ||
| 91 |
/** |
|
| 92 |
* @brief Used to iterate through population-based derived quantities |
|
| 93 |
* dimensions. |
|
| 94 |
*/ |
|
| 95 |
typedef |
|
| 96 |
typename std::map<uint32_t, |
|
| 97 |
std::map<std::string, fims::Vector<size_t>>>::iterator |
|
| 98 |
population_derived_quantities_dims_iterator; |
|
| 99 | ||
| 100 |
/** |
|
| 101 |
* @brief Iterate through fleets. |
|
| 102 |
* |
|
| 103 |
*/ |
|
| 104 |
typedef typename std::map<uint32_t, |
|
| 105 |
std::shared_ptr<fims_popdy::Fleet<Type>>>::iterator |
|
| 106 |
fleet_iterator; |
|
| 107 |
/** |
|
| 108 |
* @brief Iterate through derived quantities. |
|
| 109 |
* |
|
| 110 |
*/ |
|
| 111 |
typedef |
|
| 112 |
typename std::map<std::string, fims::Vector<Type>>::iterator dq_iterator; |
|
| 113 |
/** |
|
| 114 |
* @brief A map of report vectors for the object. |
|
| 115 |
* used to populate the report_vectors map in for submodule |
|
| 116 |
* parameters. |
|
| 117 |
*/ |
|
| 118 |
std::map<std::string, fims::Vector<fims::Vector<Type>>> report_vectors; |
|
| 119 | ||
| 120 |
public: |
|
| 121 |
std::vector<Type> ages; /*!< vector of the ages for referencing*/ |
|
| 122 |
/** |
|
| 123 |
* Constructor for the CatchAtAge class. This constructor initializes the |
|
| 124 |
* name of the model and sets the id of the model. |
|
| 125 |
*/ |
|
| 126 | 116x |
CatchAtAge() : FisheryModelBase<Type>() {
|
| 127 | 116x |
std::stringstream ss; |
| 128 | 116x |
ss << "caa_" << this->GetId() << "_"; |
| 129 | 116x |
this->name_m = ss.str(); |
| 130 | 116x |
this->model_type_m = "caa"; |
| 131 |
} |
|
| 132 | ||
| 133 |
/** |
|
| 134 |
* @brief Copy constructor for the CatchAtAge class. |
|
| 135 |
* |
|
| 136 |
* @snippet{doc} this param_other
|
|
| 137 |
*/ |
|
| 138 |
CatchAtAge(const CatchAtAge &other) |
|
| 139 |
: FisheryModelBase<Type>(other), name_m(other.name_m), ages(other.ages) {
|
|
| 140 |
this->model_type_m = "caa"; |
|
| 141 |
} |
|
| 142 | ||
| 143 |
/** |
|
| 144 |
* @brief Destroy the Catch At Age object. |
|
| 145 |
* |
|
| 146 |
*/ |
|
| 147 | 58x |
virtual ~CatchAtAge() {}
|
| 148 | ||
| 149 |
/** |
|
| 150 |
* This function is called once at the beginning of the model run. It |
|
| 151 |
* initializes the derived quantities for the populations and fleets. |
|
| 152 |
*/ |
|
| 153 | 116x |
virtual void Initialize() {
|
| 154 | 232x |
for (size_t p = 0; p < this->populations.size(); p++) {
|
| 155 | 232x |
this->populations[p]->proportion_female.resize( |
| 156 | 116x |
this->populations[p]->n_ages); |
| 157 | ||
| 158 | 116x |
this->populations[p]->M.resize(this->populations[p]->n_years * |
| 159 | 116x |
this->populations[p]->n_ages); |
| 160 | ||
| 161 | 116x |
this->populations[p]->f_multiplier.resize(this->populations[p]->n_years); |
| 162 | ||
| 163 | 116x |
this->populations[p]->spawning_biomass_ratio.resize( |
| 164 | 116x |
(this->populations[p]->n_years + 1)); |
| 165 |
} |
|
| 166 | ||
| 167 | 348x |
for (fleet_iterator fit = this->fleets.begin(); fit != this->fleets.end(); |
| 168 | 232x |
++fit) {
|
| 169 | 232x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 170 | ||
| 171 | 232x |
if (fleet->log_q.size() == 0) {
|
| 172 | ! |
fleet->log_q.resize(1); |
| 173 | ! |
fleet->log_q[0] = static_cast<Type>(0.0); |
| 174 |
} |
|
| 175 | 232x |
fleet->q.resize(fleet->log_q.size()); |
| 176 | 232x |
fleet->Fmort.resize(fleet->n_years); |
| 177 |
} |
|
| 178 |
} |
|
| 179 | ||
| 180 |
/** |
|
| 181 |
* This function is used to reset the derived quantities of a population or |
|
| 182 |
* fleet to a given value. |
|
| 183 |
*/ |
|
| 184 | 1056x |
virtual void Prepare() {
|
| 185 | 2112x |
for (size_t p = 0; p < this->populations.size(); p++) {
|
| 186 |
std::shared_ptr<fims_popdy::Population<Type>> &population = |
|
| 187 | 1056x |
this->populations[p]; |
| 188 | ||
| 189 |
auto &derived_quantities = |
|
| 190 | 1056x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 191 | ||
| 192 |
// Reset the derived quantities for the population |
|
| 193 | 15840x |
for (auto &kv : derived_quantities) {
|
| 194 | 14784x |
this->ResetVector(kv.second); |
| 195 |
} |
|
| 196 | ||
| 197 |
// Prepare proportion_female |
|
| 198 | 13728x |
for (size_t age = 0; age < population->n_ages; age++) {
|
| 199 | 12672x |
population->proportion_female[age] = 0.5; |
| 200 |
} |
|
| 201 | ||
| 202 |
// Transformation Section |
|
| 203 | 13728x |
for (size_t age = 0; age < population->n_ages; age++) {
|
| 204 | 406032x |
for (size_t year = 0; year < population->n_years; year++) {
|
| 205 | 393360x |
size_t i_age_year = age * population->n_years + year; |
| 206 | 393360x |
population->M[i_age_year] = |
| 207 | 393360x |
fims_math::exp(population->log_M[i_age_year]); |
| 208 |
} |
|
| 209 |
} |
|
| 210 | ||
| 211 | 33836x |
for (size_t year = 0; year < population->n_years; year++) {
|
| 212 | 32780x |
population->f_multiplier[year] = |
| 213 | 32780x |
fims_math::exp(population->log_f_multiplier[year]); |
| 214 |
} |
|
| 215 |
} |
|
| 216 | ||
| 217 | 3168x |
for (fleet_iterator fit = this->fleets.begin(); fit != this->fleets.end(); |
| 218 | 2112x |
++fit) {
|
| 219 | 2112x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 220 |
auto &derived_quantities = |
|
| 221 | 2112x |
this->GetFleetDerivedQuantities(fleet->GetId()); |
| 222 | ||
| 223 | 42240x |
for (auto &kv : derived_quantities) {
|
| 224 | 40128x |
this->ResetVector(kv.second); |
| 225 |
} |
|
| 226 | ||
| 227 |
// Transformation Section |
|
| 228 | 4224x |
for (size_t i = 0; i < fleet->log_q.size(); i++) {
|
| 229 | 2112x |
fleet->q[i] = fims_math::exp(fleet->log_q[i]); |
| 230 |
} |
|
| 231 | ||
| 232 | 67672x |
for (size_t year = 0; year < fleet->n_years; year++) {
|
| 233 | 65560x |
fleet->Fmort[year] = fims_math::exp(fleet->log_Fmort[year]); |
| 234 |
} |
|
| 235 |
} |
|
| 236 |
} |
|
| 237 |
/** |
|
| 238 |
* This function is used to add a population id to the set of population ids. |
|
| 239 |
*/ |
|
| 240 | 116x |
void AddPopulation(uint32_t id) { this->population_ids.insert(id); }
|
| 241 | ||
| 242 |
/** |
|
| 243 |
* @brief Get the population ids of the model. |
|
| 244 |
*/ |
|
| 245 |
std::set<uint32_t> &GetPopulationIds() { return this->population_ids; }
|
|
| 246 | ||
| 247 |
/** |
|
| 248 |
* This function is used to get the populations of the model. It returns a |
|
| 249 |
* vector of shared pointers to the populations. |
|
| 250 |
* @return std::vector<std::shared_ptr<fims_popdy::Population<Type>>>& |
|
| 251 |
*/ |
|
| 252 |
std::vector<std::shared_ptr<fims_popdy::Population<Type>>> &GetPopulations() {
|
|
| 253 |
return this->populations; |
|
| 254 |
} |
|
| 255 | ||
| 256 |
/** |
|
| 257 |
* @brief Calculates initial numbers at age for index and age. |
|
| 258 |
* |
|
| 259 |
* The formula used is: |
|
| 260 |
* \f[ |
|
| 261 |
* N_{a,0} = \exp(\log N_{a,0})
|
|
| 262 |
* \f] |
|
| 263 |
* |
|
| 264 |
* @snippet{doc} this param_population
|
|
| 265 |
* @snippet{doc} this param_i_age_year
|
|
| 266 |
* @snippet{doc} this param_age
|
|
| 267 |
*/ |
|
| 268 | 6336x |
void CalculateInitialNumbersAA( |
| 269 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 270 |
size_t i_age_year, size_t age) {
|
|
| 271 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 272 | 6336x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 273 | ||
| 274 | 6336x |
dq_["numbers_at_age"][i_age_year] = |
| 275 | 6336x |
fims_math::exp(population->log_init_naa[age]); |
| 276 |
} |
|
| 277 | ||
| 278 |
/** |
|
| 279 |
* @brief Calculates numbers at age for a population. |
|
| 280 |
* |
|
| 281 |
* This function calculates numbers at age by applying total mortality |
|
| 282 |
* \f$Z\f$ to individuals from the previous time step. It also handles |
|
| 283 |
* the accumulation of a plus group. |
|
| 284 |
* |
|
| 285 |
* Standard update: |
|
| 286 |
* \f[ |
|
| 287 |
* N_{a,y} = N_{a-1,y-1} \exp(-Z_{a-1,y-1})
|
|
| 288 |
* \f] |
|
| 289 |
* |
|
| 290 |
* Plus group update (if \f$a = A\f$): |
|
| 291 |
* \f[ |
|
| 292 |
* N_{A,y} = N_{A-1,y-1} \exp(-Z_{A-1,y-1}) + N_{A,y-1} \exp(-Z_{A,y-1})
|
|
| 293 |
* \f] |
|
| 294 |
* |
|
| 295 |
* @snippet{doc} this param_population
|
|
| 296 |
* @snippet{doc} this param_i_age_year
|
|
| 297 |
* @snippet{doc} this param_i_agem1_yearm1
|
|
| 298 |
* @snippet{doc} this param_age
|
|
| 299 |
*/ |
|
| 300 | 180290x |
void CalculateNumbersAA( |
| 301 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 302 |
size_t i_age_year, size_t i_agem1_yearm1, size_t age) {
|
|
| 303 |
// using Z from previous age/year |
|
| 304 | ||
| 305 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 306 | 180290x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 307 | ||
| 308 | 180290x |
dq_["numbers_at_age"][i_age_year] = |
| 309 | 360580x |
dq_["numbers_at_age"][i_agem1_yearm1] * |
| 310 | 508750x |
(fims_math::exp(-dq_["mortality_Z"][i_agem1_yearm1])); |
| 311 | ||
| 312 |
// Plus group calculation |
|
| 313 | 180290x |
if (age == (population->n_ages - 1)) {
|
| 314 | 16390x |
dq_["numbers_at_age"][i_age_year] = |
| 315 | 32780x |
dq_["numbers_at_age"][i_age_year] + |
| 316 | 46250x |
dq_["numbers_at_age"][i_agem1_yearm1 + 1] * |
| 317 | 49170x |
(fims_math::exp(-dq_["mortality_Z"][i_agem1_yearm1 + 1])); |
| 318 |
} |
|
| 319 |
} |
|
| 320 | ||
| 321 |
/** |
|
| 322 |
* @brief Calculates unfished numbers at age at year and age specific indices. |
|
| 323 |
* |
|
| 324 |
* This function computes unfished numbers at age by applying survival |
|
| 325 |
* through time using only natural mortality, without any fishing pressure. |
|
| 326 |
* It also accounts for accumulation of the plus group. |
|
| 327 |
* |
|
| 328 |
* Standard update: |
|
| 329 |
* \f[ |
|
| 330 |
* N^U_{a,y} = N^U_{a-1,y-1} \exp(-M_{a-1,y-1})
|
|
| 331 |
* \f] |
|
| 332 |
* |
|
| 333 |
* Plus group update (if \f$a = A\f$): |
|
| 334 |
* \f[ |
|
| 335 |
* N^U_{A,y} = N^U_{A-1,y-1} \exp(-M_{A-1,y-1}) + N^U_{A,y-1} \exp(-M_{A,y-1})
|
|
| 336 |
* \f] |
|
| 337 |
* |
|
| 338 |
* @snippet{doc} this param_population
|
|
| 339 |
* @snippet{doc} this param_i_age_year
|
|
| 340 |
* @snippet{doc} this param_i_agem1_yearm1
|
|
| 341 |
* @snippet{doc} this param_age
|
|
| 342 |
*/ |
|
| 343 | 186098x |
void CalculateUnfishedNumbersAA( |
| 344 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 345 |
size_t i_age_year, size_t i_agem1_yearm1, size_t age) {
|
|
| 346 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 347 | 186098x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 348 | ||
| 349 |
// using M from previous age/year |
|
| 350 | 186098x |
dq_["unfished_numbers_at_age"][i_age_year] = |
| 351 | 372196x |
dq_["unfished_numbers_at_age"][i_agem1_yearm1] * |
| 352 | 339042x |
(fims_math::exp(-population->M[i_agem1_yearm1])); |
| 353 | ||
| 354 |
// Plus group calculation |
|
| 355 | 186098x |
if (age == (population->n_ages - 1)) {
|
| 356 | 16918x |
dq_["unfished_numbers_at_age"][i_age_year] = |
| 357 | 33836x |
dq_["unfished_numbers_at_age"][i_age_year] + |
| 358 | 47740x |
dq_["unfished_numbers_at_age"][i_agem1_yearm1 + 1] * |
| 359 | 33836x |
(fims_math::exp(-population->M[i_agem1_yearm1 + 1])); |
| 360 |
} |
|
| 361 |
} |
|
| 362 | ||
| 363 |
/** |
|
| 364 |
* @brief Calculates total mortality for a population. |
|
| 365 |
* |
|
| 366 |
* This function calculates total mortality \f$Z\f$ for a specific age and |
|
| 367 |
* year, combining natural mortality \f$M\f$ and fishing mortality \f$F\f$ |
|
| 368 |
* from all fleets. |
|
| 369 |
* |
|
| 370 |
* The fishing mortality \f$F_{f,a,y}\f$ for each fleet \f$f\f$ is computed
|
|
| 371 |
* using age-specific selectivity \f$S_f(a)\f$, fleet-specific annual |
|
| 372 |
* fishing mortality \f$F_{f,y}\f$, and year-specific F multiplier
|
|
| 373 |
* \f$f_y\f$: |
|
| 374 |
* \f[ |
|
| 375 |
* F_{f,a,y} = F_{f,y} \times f_y \times S_f(a)
|
|
| 376 |
* \f] |
|
| 377 |
* |
|
| 378 |
* Total fishing mortality at age \f$a\f$ and year \f$y\f$ is the sum over |
|
| 379 |
* fleets: |
|
| 380 |
* \f[ |
|
| 381 |
* F_{a,y} = \sum_{f=1}^{N_{fleets}} F_{f,a,y}
|
|
| 382 |
* \f] |
|
| 383 |
* |
|
| 384 |
* Total mortality \f$Z_{a,y}\f$ is the sum of natural and fishing mortality:
|
|
| 385 |
* \f[ |
|
| 386 |
* Z_{a,y} = M_{a,y} + F_{a,y}
|
|
| 387 |
* \f] |
|
| 388 |
* |
|
| 389 |
* @snippet{doc} this param_population
|
|
| 390 |
* @snippet{doc} this param_i_age_year
|
|
| 391 |
* @snippet{doc} this param_year
|
|
| 392 |
* @snippet{doc} this param_age
|
|
| 393 |
*/ |
|
| 394 | 196680x |
void CalculateMortality( |
| 395 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 396 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 397 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 398 | 196680x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 399 | ||
| 400 | 590040x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 401 |
// evaluate is a member function of the selectivity class |
|
| 402 | 463440x |
Type s = population->fleets[fleet_]->selectivity->evaluate( |
| 403 | 393360x |
population->ages[age], year); |
| 404 | ||
| 405 | 716640x |
dq_["mortality_F"][i_age_year] += |
| 406 | 393360x |
population->fleets[fleet_]->Fmort[year] * |
| 407 | 533520x |
population->f_multiplier[year] * s; |
| 408 | ||
| 409 | 786720x |
dq_["sum_selectivity"][i_age_year] += s; |
| 410 |
} |
|
| 411 | 428400x |
dq_["mortality_M"][i_age_year] = population->M[i_age_year]; |
| 412 | ||
| 413 | 196680x |
dq_["mortality_Z"][i_age_year] = |
| 414 | 555000x |
population->M[i_age_year] + dq_["mortality_F"][i_age_year]; |
| 415 |
} |
|
| 416 | ||
| 417 |
/** |
|
| 418 |
* @brief Calculates biomass for a population. |
|
| 419 |
* |
|
| 420 |
* Adds the biomass at age to the total biomass for a given year \f$y\f$ by |
|
| 421 |
* multiplying numbers at age \f$a\f$ by weight at age \f$w_a\f$: |
|
| 422 |
* \f[ |
|
| 423 |
* B_y \mathrel{+}= N_{a,y} \times w_a
|
|
| 424 |
* \f] |
|
| 425 |
* |
|
| 426 |
* @snippet{doc} this param_population
|
|
| 427 |
* @snippet{doc} this param_i_age_year
|
|
| 428 |
* @snippet{doc} this param_year
|
|
| 429 |
* @snippet{doc} this param_age
|
|
| 430 |
*/ |
|
| 431 | 203016x |
void CalculateBiomass( |
| 432 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 433 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 434 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 435 | 203016x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 436 | ||
| 437 | 609048x |
dq_["biomass"][year] += dq_["numbers_at_age"][i_age_year] * |
| 438 | 203016x |
population->growth->evaluate(year, population->ages[age]); |
| 439 |
} |
|
| 440 | ||
| 441 |
/** |
|
| 442 |
* @brief Calculates the unfished biomass for a population. |
|
| 443 |
* |
|
| 444 |
* Updates unfished biomass \f$B^U_y\f$ by adding the biomass of age \f$a\f$ |
|
| 445 |
* in year \f$y\f$: |
|
| 446 |
* \f[ |
|
| 447 |
* B^U_y \mathrel{+}= N^U_{a,y} \times w_a
|
|
| 448 |
* \f] |
|
| 449 |
* |
|
| 450 |
* @snippet{doc} this param_population
|
|
| 451 |
* @snippet{doc} this param_i_age_year
|
|
| 452 |
* @snippet{doc} this param_year
|
|
| 453 |
* @snippet{doc} this param_age
|
|
| 454 |
*/ |
|
| 455 | 203016x |
void CalculateUnfishedBiomass( |
| 456 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 457 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 458 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 459 | 203016x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 460 | ||
| 461 | 203016x |
dq_["unfished_biomass"][year] += |
| 462 | 406032x |
dq_["unfished_numbers_at_age"][i_age_year] * |
| 463 | 203016x |
population->growth->evaluate(year,population->ages[age]); |
| 464 |
} |
|
| 465 | ||
| 466 |
/** |
|
| 467 |
* @brief Calculates spawning biomass for a population. |
|
| 468 |
* |
|
| 469 |
* This function computes yearly \f$y\f$ spawning biomass \f$SB_y\f$ by |
|
| 470 |
* summing the contributions from each age \f$a\f$, accounting for proportion |
|
| 471 |
* female, proportion mature, and weight at age \f$w_a\f$: |
|
| 472 |
* \f[ |
|
| 473 |
* SB_y \mathrel{+}= N_{a,y} \times w_a \times p_{female,a} \times
|
|
| 474 |
* p_{mature,a}
|
|
| 475 |
* \f] |
|
| 476 |
* |
|
| 477 |
* @snippet{doc} this param_population
|
|
| 478 |
* @snippet{doc} this param_i_age_year
|
|
| 479 |
* @snippet{doc} this param_year
|
|
| 480 |
* @snippet{doc} this param_age
|
|
| 481 |
*/ |
|
| 482 | 203016x |
void CalculateSpawningBiomass( |
| 483 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 484 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 485 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 486 | 203016x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 487 | ||
| 488 | 203016x |
dq_["spawning_biomass"][year] += |
| 489 | 406032x |
population->proportion_female[age] * dq_["numbers_at_age"][i_age_year] * |
| 490 | 609048x |
dq_["proportion_mature_at_age"][i_age_year] * |
| 491 | 203016x |
population->growth->evaluate(year,population->ages[age]); |
| 492 |
} |
|
| 493 | ||
| 494 |
/** |
|
| 495 |
* @brief Calculated unfished spawning biomass for a population |
|
| 496 |
* |
|
| 497 |
* Updates unfished spawning biomass \f$SB^U_y\f$ by adding the biomass of age |
|
| 498 |
* \f$a\f$ in year \f$y\f$: |
|
| 499 |
* \f[ |
|
| 500 |
* SB^U_y \mathrel{+}= N^U_{a,y} \times w_a \times p_{female,a} \times
|
|
| 501 |
* p_{mature,a}
|
|
| 502 |
* \f] |
|
| 503 |
* |
|
| 504 |
* @snippet{doc} this param_population
|
|
| 505 |
* @snippet{doc} this param_i_age_year
|
|
| 506 |
* @snippet{doc} this param_year
|
|
| 507 |
* @snippet{doc} this param_age
|
|
| 508 |
*/ |
|
| 509 | 203016x |
void CalculateUnfishedSpawningBiomass( |
| 510 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 511 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 512 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 513 | 203016x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 514 | ||
| 515 | 203016x |
dq_["unfished_spawning_biomass"][year] += |
| 516 | 203016x |
population->proportion_female[age] * |
| 517 | 275352x |
dq_["unfished_numbers_at_age"][i_age_year] * |
| 518 | 609048x |
dq_["proportion_mature_at_age"][i_age_year] * |
| 519 | 203016x |
population->growth->evaluate(year,population->ages[age]); |
| 520 |
} |
|
| 521 | ||
| 522 |
/** |
|
| 523 |
* @brief Calculate the spawning biomass ratio for a population and year. |
|
| 524 |
* |
|
| 525 |
* This method computes the ratio of spawning biomass in a given year to the |
|
| 526 |
* spawning biomass at year zero (typically unfished), for the specified |
|
| 527 |
* population: |
|
| 528 |
* \f[ |
|
| 529 |
* \text{ratio}_y = \frac{SB_y}{SB^U_0}
|
|
| 530 |
* \f] |
|
| 531 |
* |
|
| 532 |
* The result is stored in the population's spawning_biomass_ratio vector. |
|
| 533 |
* |
|
| 534 |
* @snippet{doc} this param_population
|
|
| 535 |
* @snippet{doc} this param_year
|
|
| 536 |
*/ |
|
| 537 | 16918x |
void CalculateSpawningBiomassRatio( |
| 538 |
std::shared_ptr<fims_popdy::Population<Type>> &population, size_t year) {
|
|
| 539 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 540 | 16918x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 541 | 16918x |
population->spawning_biomass_ratio[year] = |
| 542 | 67672x |
dq_["spawning_biomass"][year] / dq_["unfished_spawning_biomass"][0]; |
| 543 |
} |
|
| 544 | ||
| 545 |
/** |
|
| 546 |
* @brief Calculates equilibrium spawning biomass per recruit. |
|
| 547 |
* |
|
| 548 |
* This function calculates the spawning biomass per recruit \f$\phi_0\f$ at |
|
| 549 |
* equilibrium, assuming an unfished stock. The biomass is calculated as the |
|
| 550 |
* sum of the biomass contributions from each age \f$a\f$: |
|
| 551 |
* \f[ |
|
| 552 |
* \phi_0 = \sum_{a=0}^{A} N_a \times p_{female,a} \times p_{mature,a} \times
|
|
| 553 |
* w_a |
|
| 554 |
* \f] |
|
| 555 |
* |
|
| 556 |
* The numbers at age \f$N_a\f$ are calculated recursively with natural |
|
| 557 |
* mortality: \f[ N_a = N_{a-1} \times \exp(-M_a) \quad \text{for } a = 1,
|
|
| 558 |
* \ldots, A-1 \f] |
|
| 559 |
* |
|
| 560 |
* Plus group update: |
|
| 561 |
* \f[ |
|
| 562 |
* N_A = \frac{N_{A-1} \times \exp(-M_{A-1})}{1 - \exp(-M_A)}
|
|
| 563 |
* \f] |
|
| 564 |
* |
|
| 565 |
* @snippet{doc} this param_population
|
|
| 566 |
* @return Type |
|
| 567 |
*/ |
|
| 568 | 16390x |
Type CalculateSBPR0( |
| 569 |
std::shared_ptr<fims_popdy::Population<Type>> &population) {
|
|
| 570 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 571 | 16390x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 572 | ||
| 573 | 16390x |
std::vector<Type> numbers_spr(population->n_ages, 1.0); |
| 574 | 16390x |
Type phi_0 = 0.0; |
| 575 | 19310x |
phi_0 += numbers_spr[0] * population->proportion_female[0] * |
| 576 | 22230x |
dq_["proportion_mature_at_age"][0] * |
| 577 | 16390x |
population->growth->evaluate(0,population->ages[0]); |
| 578 | 180290x |
for (size_t a = 1; a < (population->n_ages - 1); a++) {
|
| 579 | 163900x |
numbers_spr[a] = numbers_spr[a - 1] * fims_math::exp(-population->M[a]); |
| 580 | 193100x |
phi_0 += numbers_spr[a] * population->proportion_female[a] * |
| 581 | 357000x |
dq_["proportion_mature_at_age"][a] * |
| 582 | 193100x |
population->growth->evaluate(0,population->ages[a]); |
| 583 |
} |
|
| 584 | ||
| 585 | 16390x |
numbers_spr[population->n_ages - 1] = |
| 586 | 16390x |
(numbers_spr[population->n_ages - 2] * |
| 587 | 19310x |
fims_math::exp(-population->M[population->n_ages - 2])) / |
| 588 | 16390x |
(1 - fims_math::exp(-population->M[population->n_ages - 1])); |
| 589 | 16390x |
phi_0 += |
| 590 | 16390x |
numbers_spr[population->n_ages - 1] * |
| 591 | 19310x |
population->proportion_female[population->n_ages - 1] * |
| 592 | 22230x |
dq_["proportion_mature_at_age"][population->n_ages - 1] * |
| 593 | 16390x |
population->growth->evaluate(0,population->ages[population->n_ages - 1]); |
| 594 | ||
| 595 | 16390x |
return phi_0; |
| 596 |
} |
|
| 597 | ||
| 598 |
/** |
|
| 599 |
* @brief Calculates expected recruitment for a population. |
|
| 600 |
* |
|
| 601 |
* Calculates expected recruitment as a function of spawning biomass and |
|
| 602 |
* equilibrium spawning biomass per recruit \f$\phi_0\f$. |
|
| 603 |
* |
|
| 604 |
* The expected recruitment \f$R_y\f$ in year \f$y\f$ is given by: |
|
| 605 |
* \f[ |
|
| 606 |
* R_y = |
|
| 607 |
* \begin{cases}
|
|
| 608 |
* f(SB_{y-1}, \phi_0), & \text{if } i_{dev} = n_{years} \\
|
|
| 609 |
* \exp(g(y-1)), & \text{otherwise}
|
|
| 610 |
* \end{cases}
|
|
| 611 |
* \f] |
|
| 612 |
* |
|
| 613 |
* Where \f$f()\f$ evaluates mean recruitment based on spawning biomass and |
|
| 614 |
* \f$\phi_0\f$, and \f$g(y-1)\f$ evaluates recruitment deviations. |
|
| 615 |
* |
|
| 616 |
* @snippet{doc} this param_population
|
|
| 617 |
* @snippet{doc} this param_i_age_year
|
|
| 618 |
* @snippet{doc} this param_year
|
|
| 619 |
* @snippet{doc} this param_i_dev
|
|
| 620 |
*/ |
|
| 621 | 16390x |
void CalculateRecruitment( |
| 622 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 623 |
size_t i_age_year, size_t year, size_t i_dev) {
|
|
| 624 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 625 | 16390x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 626 | ||
| 627 | 16390x |
Type phi0 = CalculateSBPR0(population); |
| 628 | ||
| 629 | 16390x |
if (i_dev == population->n_years) {
|
| 630 | 528x |
dq_["numbers_at_age"][i_age_year] = |
| 631 | 962x |
population->recruitment->evaluate_mean( |
| 632 | 1584x |
dq_["spawning_biomass"][year - 1], phi0); |
| 633 |
/*the final year of the time series has no data to inform recruitment |
|
| 634 |
devs, so this value is set to the mean recruitment.*/ |
|
| 635 |
} else {
|
|
| 636 |
// Why are we using evaluate_mean, how come a virtual function was |
|
| 637 |
// changed? AMH: there are now two virtual functions: evaluate_mean and |
|
| 638 |
// evaluate_process (see below) |
|
| 639 | 15862x |
population->recruitment->log_expected_recruitment[year - 1] = |
| 640 | 31724x |
fims_math::log(population->recruitment->evaluate_mean( |
| 641 | 31724x |
dq_["spawning_biomass"][year - 1], phi0)); |
| 642 | ||
| 643 | 18688x |
dq_["numbers_at_age"][i_age_year] = fims_math::exp( |
| 644 | 31724x |
population->recruitment->process->evaluate_process(year - 1)); |
| 645 |
} |
|
| 646 | ||
| 647 | 49170x |
dq_["expected_recruitment"][year] = dq_["numbers_at_age"][i_age_year]; |
| 648 |
} |
|
| 649 | ||
| 650 |
/** |
|
| 651 |
* @brief Calculates maturity at age, in proportion, for a population. |
|
| 652 |
* |
|
| 653 |
* This function evaluates the maturity ogive at the specified age to estimate |
|
| 654 |
* the proportion of individuals that are mature: |
|
| 655 |
* \f[ |
|
| 656 |
* p_{mature,a} = \text{maturity}(a)
|
|
| 657 |
* \f] |
|
| 658 |
* |
|
| 659 |
* @snippet{doc} this param_population
|
|
| 660 |
* @snippet{doc} this param_i_age_year
|
|
| 661 |
* @snippet{doc} this param_age
|
|
| 662 |
*/ |
|
| 663 | 203016x |
void CalculateMaturityAA( |
| 664 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 665 |
size_t i_age_year, size_t age) {
|
|
| 666 |
std::map<std::string, fims::Vector<Type>> &dq_ = |
|
| 667 | 203016x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 668 | ||
| 669 | 203016x |
dq_["proportion_mature_at_age"][i_age_year] = |
| 670 | 203016x |
population->maturity->evaluate(population->ages[age]); |
| 671 |
} |
|
| 672 | ||
| 673 |
/** |
|
| 674 |
* @brief Calculates total catch (landings) by fleet and population for a |
|
| 675 |
* given year by aggregating age-specific catch over ages. |
|
| 676 |
* |
|
| 677 |
* This function updates fleet-specific and total expected landings for a |
|
| 678 |
* given year and age by accumulating age-specific catch from each fleet: |
|
| 679 |
* \f[ |
|
| 680 |
* CW_{f,y} \mathrel{+}= CW_{f,a,y}, \quad
|
|
| 681 |
* C_{f,y} \mathrel{+}= C_{f,a,y}
|
|
| 682 |
* \f] |
|
| 683 |
* |
|
| 684 |
* @snippet{doc} this param_population
|
|
| 685 |
* @snippet{doc} this param_year
|
|
| 686 |
* @snippet{doc} this param_age
|
|
| 687 |
*/ |
|
| 688 | 196680x |
void CalculateLandings( |
| 689 |
std::shared_ptr<fims_popdy::Population<Type>> &population, size_t year, |
|
| 690 |
size_t age) {
|
|
| 691 |
std::map<std::string, fims::Vector<Type>> &pdq_ = |
|
| 692 | 196680x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 693 | ||
| 694 | 590040x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 695 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 696 | 393360x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 697 | 393360x |
size_t i_age_year = year * population->n_ages + age; |
| 698 | ||
| 699 | 393360x |
pdq_["total_landings_weight"][year] += |
| 700 | 1180080x |
fdq_["landings_weight_at_age"][i_age_year]; |
| 701 | ||
| 702 | 393360x |
fdq_["landings_weight"][year] += |
| 703 | 1180080x |
fdq_["landings_weight_at_age"][i_age_year]; |
| 704 | ||
| 705 | 393360x |
pdq_["total_landings_numbers"][year] += |
| 706 | 1180080x |
fdq_["landings_numbers_at_age"][i_age_year]; |
| 707 | ||
| 708 | 393360x |
fdq_["landings_numbers"][year] += |
| 709 | 1180080x |
fdq_["landings_numbers_at_age"][i_age_year]; |
| 710 |
} |
|
| 711 |
} |
|
| 712 | ||
| 713 |
/** |
|
| 714 |
* @brief Calculates weight at age of the landings for a given fleet from a |
|
| 715 |
* population. |
|
| 716 |
* |
|
| 717 |
* This function computes the expected landings at age in weight by |
|
| 718 |
* multiplying the expected landings numbers at age by the corresponding |
|
| 719 |
* weight at age: |
|
| 720 |
* \f[ |
|
| 721 |
* CW_{f,a,y} = C_{f,a,y} \times w_a
|
|
| 722 |
* \f] |
|
| 723 |
* |
|
| 724 |
* @snippet{doc} this param_population
|
|
| 725 |
* @snippet{doc} this param_year
|
|
| 726 |
* @snippet{doc} this param_age
|
|
| 727 |
*/ |
|
| 728 | 196680x |
void CalculateLandingsWeightAA( |
| 729 |
std::shared_ptr<fims_popdy::Population<Type>> &population, size_t year, |
|
| 730 |
size_t age) {
|
|
| 731 | 196680x |
int i_age_year = year * population->n_ages + age; |
| 732 | 590040x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 733 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 734 | 393360x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 735 | ||
| 736 | 393360x |
fdq_["landings_weight_at_age"][i_age_year] = |
| 737 | 1110000x |
fdq_["landings_numbers_at_age"][i_age_year] * |
| 738 | 463440x |
population->growth->evaluate(year,population->ages[age]); |
| 739 |
} |
|
| 740 |
} |
|
| 741 | ||
| 742 |
/** |
|
| 743 |
* @brief Calculates numbers of fish for the landings for a given fleet from a |
|
| 744 |
* population, year and age. |
|
| 745 |
* |
|
| 746 |
* This function uses the Baranov Catch Equation to calculate expected |
|
| 747 |
* landings in numbers at age for each fleet. With F multiplier \f$f_y\f$: |
|
| 748 |
* \f[ |
|
| 749 |
* C_{f,a,y} = \frac{F_{f,y} \times f_y \times S_f(a)}{Z_{a,y}} \times N_{a,y}
|
|
| 750 |
* \times |
|
| 751 |
* \left( 1 - \exp(-Z_{a,y}) \right)
|
|
| 752 |
* \f] |
|
| 753 |
* |
|
| 754 |
* @snippet{doc} this param_population
|
|
| 755 |
* @snippet{doc} this param_i_age_year
|
|
| 756 |
* @snippet{doc} this param_year
|
|
| 757 |
* @snippet{doc} this param_age
|
|
| 758 |
*/ |
|
| 759 | 196680x |
void CalculateLandingsNumbersAA( |
| 760 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 761 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 762 |
std::map<std::string, fims::Vector<Type>> &pdq_ = |
|
| 763 | 196680x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 764 | ||
| 765 | 590040x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 766 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 767 | 393360x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 768 | ||
| 769 |
// Baranov Catch Equation |
|
| 770 | 393360x |
fdq_["landings_numbers_at_age"][i_age_year] += |
| 771 | 393360x |
(population->fleets[fleet_]->Fmort[year] * |
| 772 | 463440x |
population->f_multiplier[year] * |
| 773 | 786720x |
population->fleets[fleet_]->selectivity->evaluate( |
| 774 | 463440x |
population->ages[age],year)) / |
| 775 | 1643520x |
pdq_["mortality_Z"][i_age_year] * pdq_["numbers_at_age"][i_age_year] * |
| 776 | 1180080x |
(1 - fims_math::exp(-(pdq_["mortality_Z"][i_age_year]))); |
| 777 |
} |
|
| 778 |
} |
|
| 779 | ||
| 780 |
/** |
|
| 781 |
* @brief Calculates the index for a fleet from a population. |
|
| 782 |
* |
|
| 783 |
* This function updates the population indices for each fleet by adding the |
|
| 784 |
* age- and year-specific index weights and numbers to the corresponding |
|
| 785 |
* annual totals. The updated index weight and index numbers for a given |
|
| 786 |
* fleet and year are calculated as: |
|
| 787 |
* \f[ |
|
| 788 |
* IW_{f,y} \mathrel{+}= IWAA_{a,y}, \quad
|
|
| 789 |
* IN_{f,y} \mathrel{+}= INAA_{a,y}
|
|
| 790 |
* \f] |
|
| 791 |
* |
|
| 792 |
* @snippet{doc} this param_population
|
|
| 793 |
* @snippet{doc} this param_i_age_year
|
|
| 794 |
* @snippet{doc} this param_year
|
|
| 795 |
* @snippet{doc} this param_age
|
|
| 796 |
*/ |
|
| 797 | 196680x |
void CalculateIndex(std::shared_ptr<fims_popdy::Population<Type>> &population, |
| 798 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 799 | 590040x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 800 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 801 | 393360x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 802 | ||
| 803 | 1573440x |
fdq_["index_weight"][year] += fdq_["index_weight_at_age"][i_age_year]; |
| 804 | ||
| 805 | 1573440x |
fdq_["index_numbers"][year] += fdq_["index_numbers_at_age"][i_age_year]; |
| 806 |
} |
|
| 807 |
} |
|
| 808 | ||
| 809 |
/** |
|
| 810 |
* @brief Calculates the numbers for the index for a fleet from a population. |
|
| 811 |
* |
|
| 812 |
* This function calculates the expected index in numbers at age for each |
|
| 813 |
* fleet, using catchability, selectivity, and population numbers at age: |
|
| 814 |
* \f[ |
|
| 815 |
* IN_{f,a,y} \mathrel{+}= q_{f,y} \times S_f(a) \times N_{a,y}
|
|
| 816 |
* \f] |
|
| 817 |
* |
|
| 818 |
* When timing is accounted for within FIMS the equation will include the |
|
| 819 |
* fraction of the year when the survey was conducted \f$t_y\f$: |
|
| 820 |
* \f[ IN_{f,a,y} \mathrel{+}= S_{f,y}(a) \times N_{a,y} \times
|
|
| 821 |
* e^{(-t_{y}Z_{a,y})}\f]
|
|
| 822 |
* |
|
| 823 |
* @snippet{doc} this param_population
|
|
| 824 |
* @snippet{doc} this param_i_age_year
|
|
| 825 |
* @snippet{doc} this param_year
|
|
| 826 |
* @snippet{doc} this param_age
|
|
| 827 |
*/ |
|
| 828 | 196680x |
void CalculateIndexNumbersAA( |
| 829 |
std::shared_ptr<fims_popdy::Population<Type>> &population, |
|
| 830 |
size_t i_age_year, size_t year, size_t age) {
|
|
| 831 |
std::map<std::string, fims::Vector<Type>> &pdq_ = |
|
| 832 | 196680x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 833 | ||
| 834 | 590040x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 835 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 836 | 393360x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 837 | ||
| 838 | 393360x |
fdq_["index_numbers_at_age"][i_age_year] += |
| 839 | 393360x |
(population->fleets[fleet_]->q.get_force_scalar(year) * |
| 840 | 786720x |
population->fleets[fleet_]->selectivity->evaluate( |
| 841 | 463440x |
population->ages[age],year)) * |
| 842 | 1180080x |
pdq_["numbers_at_age"][i_age_year]; |
| 843 |
} |
|
| 844 |
} |
|
| 845 | ||
| 846 |
/** |
|
| 847 |
* @brief Calculates biomass of fish for the index for a given fleet from a |
|
| 848 |
* population. |
|
| 849 |
* |
|
| 850 |
* This function computes the expected index weight at age by multiplying the |
|
| 851 |
* expected index numbers at age by the corresponding weight at age: |
|
| 852 |
* \f[ |
|
| 853 |
* IWAA_{f,a,y} = IN_{f,a,y} \times w_a
|
|
| 854 |
* \f] |
|
| 855 |
* |
|
| 856 |
* @snippet{doc} this param_population
|
|
| 857 |
* @snippet{doc} this param_year
|
|
| 858 |
* @snippet{doc} this param_age
|
|
| 859 |
*/ |
|
| 860 | 196680x |
void CalculateIndexWeightAA( |
| 861 |
std::shared_ptr<fims_popdy::Population<Type>> &population, size_t year, |
|
| 862 |
size_t age) {
|
|
| 863 | 196680x |
int i_age_year = year * population->n_ages + age; |
| 864 | 590040x |
for (size_t fleet_ = 0; fleet_ < population->n_fleets; fleet_++) {
|
| 865 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 866 | 393360x |
this->GetFleetDerivedQuantities(population->fleets[fleet_]->GetId()); |
| 867 | ||
| 868 | 393360x |
fdq_["index_weight_at_age"][i_age_year] = |
| 869 | 1110000x |
fdq_["index_numbers_at_age"][i_age_year] * |
| 870 | 463440x |
population->growth->evaluate(year,population->ages[age]); |
| 871 |
} |
|
| 872 |
} |
|
| 873 | ||
| 874 |
/** |
|
| 875 |
* Evaluate the proportion of landings numbers at age. |
|
| 876 |
*/ |
|
| 877 | 528x |
void evaluate_age_comp() {
|
| 878 | 528x |
fleet_iterator fit; |
| 879 | 1584x |
for (fit = this->fleets.begin(); fit != this->fleets.end(); ++fit) {
|
| 880 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 881 | 1056x |
this->GetFleetDerivedQuantities((*fit).second->GetId()); |
| 882 | ||
| 883 | 1056x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 884 | 33836x |
for (size_t y = 0; y < fleet->n_years; y++) {
|
| 885 | 32780x |
Type sum = static_cast<Type>(0.0); |
| 886 | 32780x |
Type sum_obs = static_cast<Type>(0.0); |
| 887 |
// robust_add is a small value to add to expected composition |
|
| 888 |
// proportions at age to stabilize likelihood calculations |
|
| 889 |
// when the expected proportions are close to zero. |
|
| 890 |
// Type robust_add = static_cast<Type>(0.0); // zeroed out before |
|
| 891 |
// testing 0.0001; sum robust is used to calculate the total sum of |
|
| 892 |
// robust additions to ensure that proportions sum to 1. Type robust_sum |
|
| 893 |
// = static_cast<Type>(1.0); |
|
| 894 | ||
| 895 | 426140x |
for (size_t a = 0; a < fleet->n_ages; a++) {
|
| 896 | 393360x |
size_t i_age_year = y * fleet->n_ages + a; |
| 897 |
// Here we have a check to determine if the age comp |
|
| 898 |
// should be calculated from the retained landings or |
|
| 899 |
// the total population. These values are slightly different. |
|
| 900 |
// In the future this will have more impact as we implement |
|
| 901 |
// timing rather than everything occurring at the start of |
|
| 902 |
// the year. |
|
| 903 | 393360x |
if (fleet->fleet_observed_landings_data_id_m == -999) {
|
| 904 | 196680x |
fdq_["agecomp_expected"][i_age_year] = |
| 905 | 590040x |
fdq_["index_numbers_at_age"][i_age_year]; |
| 906 |
} else {
|
|
| 907 | 196680x |
fdq_["agecomp_expected"][i_age_year] = |
| 908 | 590040x |
fdq_["landings_numbers_at_age"][i_age_year]; |
| 909 |
} |
|
| 910 | 393360x |
sum += fdq_["agecomp_expected"][i_age_year]; |
| 911 |
// robust_sum -= robust_add; |
|
| 912 | ||
| 913 |
// This sums over the observed age composition data so that |
|
| 914 |
// the expected age composition can be rescaled to match the |
|
| 915 |
// total number observed. The check for na values should not |
|
| 916 |
// be needed as individual years should not have missing data. |
|
| 917 |
// This is need to be re-explored if/when we modify FIMS to |
|
| 918 |
// allow for composition bins that do not match the population |
|
| 919 |
// bins. |
|
| 920 | 393360x |
if (fleet->fleet_observed_agecomp_data_id_m != -999) {
|
| 921 | 361680x |
if (fleet->observed_agecomp_data->at(i_age_year) != |
| 922 | 361680x |
fleet->observed_agecomp_data->na_value) {
|
| 923 | 347952x |
sum_obs += fleet->observed_agecomp_data->at(i_age_year); |
| 924 |
} |
|
| 925 |
} |
|
| 926 |
} |
|
| 927 | 426140x |
for (size_t a = 0; a < fleet->n_ages; a++) {
|
| 928 | 393360x |
size_t i_age_year = y * fleet->n_ages + a; |
| 929 | 393360x |
fdq_["agecomp_proportion"][i_age_year] = |
| 930 | 786720x |
fdq_["agecomp_expected"][i_age_year] / sum; |
| 931 |
// robust_add + robust_sum * this->agecomp_expected[i_age_year] / sum; |
|
| 932 | ||
| 933 | 393360x |
if (fleet->fleet_observed_agecomp_data_id_m != -999) {
|
| 934 | 361680x |
fdq_["agecomp_expected"][i_age_year] = |
| 935 | 1085040x |
fdq_["agecomp_proportion"][i_age_year] * sum_obs; |
| 936 |
} |
|
| 937 |
} |
|
| 938 |
} |
|
| 939 |
} |
|
| 940 |
} |
|
| 941 | ||
| 942 |
/** |
|
| 943 |
* Evaluate the proportion of landings numbers at length. |
|
| 944 |
*/ |
|
| 945 | 528x |
void evaluate_length_comp() {
|
| 946 | 528x |
fleet_iterator fit; |
| 947 | 1584x |
for (fit = this->fleets.begin(); fit != this->fleets.end(); ++fit) {
|
| 948 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 949 | 1056x |
this->GetFleetDerivedQuantities((*fit).second->GetId()); |
| 950 | ||
| 951 | 1056x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 952 | ||
| 953 | 1056x |
if (fleet->n_lengths > 0) {
|
| 954 | 27016x |
for (size_t y = 0; y < fleet->n_years; y++) {
|
| 955 | 26180x |
Type sum = static_cast<Type>(0.0); |
| 956 | 26180x |
Type sum_obs = static_cast<Type>(0.0); |
| 957 |
// robust_add is a small value to add to expected composition |
|
| 958 |
// proportions at age to stabilize likelihood calculations |
|
| 959 |
// when the expected proportions are close to zero. |
|
| 960 |
// Type robust_add = static_cast<Type>(0.0); // 0.0001; zeroed out |
|
| 961 |
// before testing sum robust is used to calculate the total sum of |
|
| 962 |
// robust additions to ensure that proportions sum to 1. Type |
|
| 963 |
// robust_sum = static_cast<Type>(1.0); |
|
| 964 | 628320x |
for (size_t l = 0; l < fleet->n_lengths; l++) {
|
| 965 | 602140x |
size_t i_length_year = y * fleet->n_lengths + l; |
| 966 | 7827820x |
for (size_t a = 0; a < fleet->n_ages; a++) {
|
| 967 | 7225680x |
size_t i_age_year = y * fleet->n_ages + a; |
| 968 | 7225680x |
size_t i_length_age = a * fleet->n_lengths + l; |
| 969 | 7225680x |
fdq_["lengthcomp_expected"][i_length_year] += |
| 970 | 20396400x |
fdq_["agecomp_expected"][i_age_year] * |
| 971 | 7225680x |
fleet->age_to_length_conversion[i_length_age]; |
| 972 | ||
| 973 | 7225680x |
fdq_["landings_numbers_at_length"][i_length_year] += |
| 974 | 20396400x |
fdq_["landings_numbers_at_age"][i_age_year] * |
| 975 | 7225680x |
fleet->age_to_length_conversion[i_length_age]; |
| 976 | ||
| 977 | 7225680x |
fdq_["index_numbers_at_length"][i_length_year] += |
| 978 | 21677040x |
fdq_["index_numbers_at_age"][i_age_year] * |
| 979 | 7225680x |
fleet->age_to_length_conversion[i_length_age]; |
| 980 |
} |
|
| 981 | ||
| 982 | 602140x |
sum += fdq_["lengthcomp_expected"][i_length_year]; |
| 983 |
// robust_sum -= robust_add; |
|
| 984 | ||
| 985 | 602140x |
if (fleet->fleet_observed_lengthcomp_data_id_m != -999) {
|
| 986 | 602140x |
if (fleet->observed_lengthcomp_data->at(i_length_year) != |
| 987 | 602140x |
fleet->observed_lengthcomp_data->na_value) {
|
| 988 | 576334x |
sum_obs += fleet->observed_lengthcomp_data->at(i_length_year); |
| 989 |
} |
|
| 990 |
} |
|
| 991 |
} |
|
| 992 | 628320x |
for (size_t l = 0; l < fleet->n_lengths; l++) {
|
| 993 | 602140x |
size_t i_length_year = y * fleet->n_lengths + l; |
| 994 | 602140x |
fdq_["lengthcomp_proportion"][i_length_year] = |
| 995 | 1204280x |
fdq_["lengthcomp_expected"][i_length_year] / sum; |
| 996 |
// robust_add + robust_sum * |
|
| 997 |
// this->lengthcomp_expected[i_length_year] / sum; |
|
| 998 | 602140x |
if (fleet->fleet_observed_lengthcomp_data_id_m != -999) {
|
| 999 | 602140x |
fdq_["lengthcomp_expected"][i_length_year] = |
| 1000 | 1806420x |
fdq_["lengthcomp_proportion"][i_length_year] * sum_obs; |
| 1001 |
} |
|
| 1002 |
} |
|
| 1003 |
} |
|
| 1004 |
} |
|
| 1005 |
} |
|
| 1006 |
} |
|
| 1007 | ||
| 1008 |
/** |
|
| 1009 |
* Evaluate the natural log of the expected index. |
|
| 1010 |
*/ |
|
| 1011 | 528x |
void evaluate_index() {
|
| 1012 | 528x |
fleet_iterator fit; |
| 1013 | 1584x |
for (fit = this->fleets.begin(); fit != this->fleets.end(); ++fit) {
|
| 1014 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 1015 | 1056x |
this->GetFleetDerivedQuantities((*fit).second->GetId()); |
| 1016 | 1056x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 1017 | ||
| 1018 | 68728x |
for (size_t i = 0; i < fdq_["index_numbers"].size(); i++) {
|
| 1019 | 32780x |
if (fleet->observed_index_units == "number") {
|
| 1020 | ! |
fdq_["index_expected"][i] = fdq_["index_numbers"][i]; |
| 1021 |
} else {
|
|
| 1022 | 131120x |
fdq_["index_expected"][i] = fdq_["index_weight"][i]; |
| 1023 |
} |
|
| 1024 | 131120x |
fdq_["log_index_expected"][i] = log(fdq_["index_expected"][i]); |
| 1025 |
} |
|
| 1026 |
} |
|
| 1027 |
} |
|
| 1028 | ||
| 1029 |
/** |
|
| 1030 |
* Evaluate the natural log of the expected landings. |
|
| 1031 |
*/ |
|
| 1032 | 528x |
void evaluate_landings() {
|
| 1033 | 528x |
fleet_iterator fit; |
| 1034 | 1584x |
for (fit = this->fleets.begin(); fit != this->fleets.end(); ++fit) {
|
| 1035 |
std::map<std::string, fims::Vector<Type>> &fdq_ = |
|
| 1036 | 1056x |
this->GetFleetDerivedQuantities((*fit).second->GetId()); |
| 1037 | 1056x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 1038 | ||
| 1039 | 68728x |
for (size_t i = 0; i < fdq_["landings_weight"].size(); i++) {
|
| 1040 | 32780x |
if (fleet->observed_landings_units == "number") {
|
| 1041 | ! |
fdq_["landings_expected"][i] = fdq_["landings_numbers"][i]; |
| 1042 |
} else {
|
|
| 1043 | 131120x |
fdq_["landings_expected"][i] = fdq_["landings_weight"][i]; |
| 1044 |
} |
|
| 1045 | 131120x |
fdq_["log_landings_expected"][i] = log(fdq_["landings_expected"][i]); |
| 1046 |
} |
|
| 1047 |
} |
|
| 1048 |
} |
|
| 1049 | ||
| 1050 | 528x |
virtual void Evaluate() {
|
| 1051 |
/* |
|
| 1052 |
Sets derived vectors to zero |
|
| 1053 |
Performs parameters transformations |
|
| 1054 |
Sets recruitment deviations to mean 0. |
|
| 1055 |
*/ |
|
| 1056 | 528x |
Prepare(); |
| 1057 |
/* |
|
| 1058 |
start at year=0, age=0; |
|
| 1059 |
here year 0 is the estimated initial population structure and age 0 are |
|
| 1060 |
recruits loops start at zero with if statements inside to specify unique |
|
| 1061 |
code for initial structure and recruitment 0 loops. Could also have started |
|
| 1062 |
loops at 1 with initial structure and recruitment setup outside the loops. |
|
| 1063 | ||
| 1064 |
year loop is extended to <= n_years because SSB is calculated as the start |
|
| 1065 |
of the year value and by extending one extra year we get estimates of the |
|
| 1066 |
population structure at the end of the final year. An alternative approach |
|
| 1067 |
would be to keep initial numbers at age in it's own vector and each year to |
|
| 1068 |
include the population structure at the end of the year. This is likely a |
|
| 1069 |
null point given that we are planning to modify to an event/stanza based |
|
| 1070 |
structure in later milestones which will eliminate this confusion by |
|
| 1071 |
explicitly referencing the exact date (or period of averaging) at which any |
|
| 1072 |
calculation or output is being made. |
|
| 1073 |
*/ |
|
| 1074 | 1056x |
for (size_t p = 0; p < this->populations.size(); p++) {
|
| 1075 |
std::shared_ptr<fims_popdy::Population<Type>> &population = |
|
| 1076 | 528x |
this->populations[p]; |
| 1077 |
std::map<std::string, fims::Vector<Type>> &pdq_ = |
|
| 1078 | 528x |
this->GetPopulationDerivedQuantities(population->GetId()); |
| 1079 |
// CAAPopulationProxy<Type>& population = this->populations_proxies[p]; |
|
| 1080 | ||
| 1081 | 17446x |
for (size_t y = 0; y <= population->n_years; y++) {
|
| 1082 | 219934x |
for (size_t a = 0; a < population->n_ages; a++) {
|
| 1083 |
/* |
|
| 1084 |
index naming defines the dimensional folding structure |
|
| 1085 |
i.e. i_age_year is referencing folding over years and ages. |
|
| 1086 |
*/ |
|
| 1087 | 203016x |
size_t i_age_year = y * population->n_ages + a; |
| 1088 |
/* |
|
| 1089 |
Mortality rates are not estimated in the final year which is |
|
| 1090 |
used to show expected population structure at the end of the model |
|
| 1091 |
period. This is because biomass in year i represents biomass at the |
|
| 1092 |
start of the year. Should we add complexity to track more values such |
|
| 1093 |
as start, mid, and end biomass in all years where, start biomass=end |
|
| 1094 |
biomass of the previous year? Referenced above, this is probably not |
|
| 1095 |
worth exploring as later milestone changes will eliminate this |
|
| 1096 |
confusion. |
|
| 1097 |
*/ |
|
| 1098 | 203016x |
if (y < population->n_years) {
|
| 1099 |
/* |
|
| 1100 |
First thing we need is total mortality aggregated across all fleets |
|
| 1101 |
to inform the subsequent catch and change in numbers at age |
|
| 1102 |
calculations. This is only calculated for years < n_years as these |
|
| 1103 |
are the model estimated years with data. The year loop extends to |
|
| 1104 |
y=n_years so that population numbers at age and SSB can be |
|
| 1105 |
calculated at the end of the last year of the model |
|
| 1106 |
*/ |
|
| 1107 | 196680x |
CalculateMortality(population, i_age_year, y, a); |
| 1108 |
} |
|
| 1109 | 203016x |
CalculateMaturityAA(population, i_age_year, a); |
| 1110 |
/* if statements needed because some quantities are only needed |
|
| 1111 |
for the first year and/or age, so these steps are included here. |
|
| 1112 |
*/ |
|
| 1113 | 203016x |
if (y == 0) {
|
| 1114 |
// Initial numbers at age is a user input or estimated parameter |
|
| 1115 |
// vector. |
|
| 1116 | 6336x |
CalculateInitialNumbersAA(population, i_age_year, a); |
| 1117 | ||
| 1118 | 6336x |
if (a == 0) {
|
| 1119 |
/* |
|
| 1120 |
Expected recruitment in year 0 is numbers at age 0 in year 0. |
|
| 1121 |
*/ |
|
| 1122 | 528x |
pdq_["expected_recruitment"][y] = |
| 1123 | 1056x |
pdq_["numbers_at_age"][i_age_year]; |
| 1124 | 1056x |
pdq_["unfished_numbers_at_age"][i_age_year] = |
| 1125 | 528x |
fims_math::exp(population->recruitment->log_rzero[0]); |
| 1126 |
} else {
|
|
| 1127 | 5808x |
CalculateUnfishedNumbersAA(population, i_age_year, a - 1, a); |
| 1128 |
} |
|
| 1129 | ||
| 1130 |
} else {
|
|
| 1131 | 196680x |
if (a == 0) {
|
| 1132 |
// Set the nrecruits for age a=0 year y (use pointers instead of |
|
| 1133 |
// functional returns) assuming fecundity = 1 and 50:50 sex ratio |
|
| 1134 | 16390x |
CalculateRecruitment(population, i_age_year, y, y); |
| 1135 | 32780x |
pdq_["unfished_numbers_at_age"][i_age_year] = |
| 1136 | 16390x |
fims_math::exp(population->recruitment->log_rzero[0]); |
| 1137 |
} else {
|
|
| 1138 | 180290x |
size_t i_agem1_yearm1 = (y - 1) * population->n_ages + (a - 1); |
| 1139 | 180290x |
CalculateNumbersAA(population, i_age_year, i_agem1_yearm1, a); |
| 1140 | 180290x |
CalculateUnfishedNumbersAA(population, i_age_year, i_agem1_yearm1, |
| 1141 |
a); |
|
| 1142 |
} |
|
| 1143 |
} |
|
| 1144 | ||
| 1145 |
/* |
|
| 1146 |
Fished and unfished biomass vectors are summing biomass at |
|
| 1147 |
age across ages. |
|
| 1148 |
*/ |
|
| 1149 | ||
| 1150 | 203016x |
CalculateBiomass(population, i_age_year, y, a); |
| 1151 | ||
| 1152 | 203016x |
CalculateUnfishedBiomass(population, i_age_year, y, a); |
| 1153 | ||
| 1154 |
/* |
|
| 1155 |
Fished and unfished spawning biomass vectors are summing biomass at |
|
| 1156 |
age across ages to allow calculation of recruitment in the next |
|
| 1157 |
year. |
|
| 1158 |
*/ |
|
| 1159 | ||
| 1160 | 203016x |
CalculateSpawningBiomass(population, i_age_year, y, a); |
| 1161 | ||
| 1162 | 203016x |
CalculateUnfishedSpawningBiomass(population, i_age_year, y, a); |
| 1163 | ||
| 1164 |
/* |
|
| 1165 |
Here composition, total catch, and index values are calculated for all |
|
| 1166 |
years with reference data. They are not calculated for y=n_years as |
|
| 1167 |
there is this is just to get final population structure at the end of |
|
| 1168 |
the terminal year. |
|
| 1169 |
*/ |
|
| 1170 | 203016x |
if (y < population->n_years) {
|
| 1171 | 196680x |
CalculateLandingsNumbersAA(population, i_age_year, y, a); |
| 1172 | 196680x |
CalculateLandingsWeightAA(population, y, a); |
| 1173 | 196680x |
CalculateLandings(population, y, a); |
| 1174 | ||
| 1175 | 196680x |
CalculateIndexNumbersAA(population, i_age_year, y, a); |
| 1176 | 196680x |
CalculateIndexWeightAA(population, y, a); |
| 1177 | 196680x |
CalculateIndex(population, i_age_year, y, a); |
| 1178 |
} |
|
| 1179 |
} |
|
| 1180 |
/* Calculate spawning biomass depletion ratio */ |
|
| 1181 | 16918x |
CalculateSpawningBiomassRatio(population, y); |
| 1182 |
} |
|
| 1183 |
} |
|
| 1184 | 528x |
evaluate_age_comp(); |
| 1185 | 528x |
evaluate_length_comp(); |
| 1186 | 528x |
evaluate_index(); |
| 1187 | 528x |
evaluate_landings(); |
| 1188 |
} |
|
| 1189 |
/** |
|
| 1190 |
* * This method is used to generate TMB reports from the population dynamics |
|
| 1191 |
* model. |
|
| 1192 |
*/ |
|
| 1193 | 528x |
virtual void Report() {
|
| 1194 | 528x |
int n_fleets = this->fleets.size(); |
| 1195 | 528x |
int n_pops = this->populations.size(); |
| 1196 |
#ifdef TMB_MODEL |
|
| 1197 | 528x |
if (this->do_reporting == true) {
|
| 1198 | 480x |
report_vectors.clear(); |
| 1199 |
// initialize population vectors |
|
| 1200 | 480x |
vector<vector<Type>> biomass_p(n_pops); |
| 1201 | 480x |
vector<vector<Type>> expected_recruitment_p(n_pops); |
| 1202 | 480x |
vector<vector<Type>> mortality_F_p(n_pops); |
| 1203 | 480x |
vector<vector<Type>> mortality_M_p(n_pops); |
| 1204 | 480x |
vector<vector<Type>> mortality_Z_p(n_pops); |
| 1205 | 480x |
vector<vector<Type>> numbers_at_age_p(n_pops); |
| 1206 | 480x |
vector<vector<Type>> proportion_mature_at_age_p(n_pops); |
| 1207 | 480x |
vector<vector<Type>> spawning_biomass_p(n_pops); |
| 1208 | 480x |
vector<vector<Type>> sum_selectivity_p(n_pops); |
| 1209 | 480x |
vector<vector<Type>> total_landings_numbers_p(n_pops); |
| 1210 | 480x |
vector<vector<Type>> total_landings_weight_p(n_pops); |
| 1211 | 480x |
vector<vector<Type>> unfished_biomass_p(n_pops); |
| 1212 | 480x |
vector<vector<Type>> unfished_numbers_at_age_p(n_pops); |
| 1213 | 480x |
vector<vector<Type>> unfished_spawning_biomass_p(n_pops); |
| 1214 | 480x |
vector<vector<Type>> spawning_biomass_ratio_p(n_pops); |
| 1215 | ||
| 1216 |
// initialize fleet vectors |
|
| 1217 | 480x |
vector<vector<Type>> agecomp_expected_f(n_fleets); |
| 1218 | 480x |
vector<vector<Type>> agecomp_proportion_f(n_fleets); |
| 1219 | 480x |
vector<vector<Type>> catch_index_f(n_fleets); |
| 1220 | 480x |
vector<vector<Type>> index_expected_f(n_fleets); |
| 1221 | 480x |
vector<vector<Type>> index_numbers_f(n_fleets); |
| 1222 | 480x |
vector<vector<Type>> index_numbers_at_age_f(n_fleets); |
| 1223 | 480x |
vector<vector<Type>> index_numbers_at_length_f(n_fleets); |
| 1224 | 480x |
vector<vector<Type>> index_weight_f(n_fleets); |
| 1225 | 480x |
vector<vector<Type>> index_weight_at_age_f(n_fleets); |
| 1226 | 480x |
vector<vector<Type>> landings_expected_f(n_fleets); |
| 1227 | 480x |
vector<vector<Type>> landings_numbers_f(n_fleets); |
| 1228 | 480x |
vector<vector<Type>> landings_numbers_at_age_f(n_fleets); |
| 1229 | 480x |
vector<vector<Type>> landings_numbers_at_length_f(n_fleets); |
| 1230 | 480x |
vector<vector<Type>> landings_weight_f(n_fleets); |
| 1231 | 480x |
vector<vector<Type>> landings_weight_at_age_f(n_fleets); |
| 1232 | 480x |
vector<vector<Type>> lengthcomp_expected_f(n_fleets); |
| 1233 | 480x |
vector<vector<Type>> lengthcomp_proportion_f(n_fleets); |
| 1234 | 480x |
vector<vector<Type>> log_index_expected_f(n_fleets); |
| 1235 | 480x |
vector<vector<Type>> log_landings_expected_f(n_fleets); |
| 1236 | ||
| 1237 |
// initiate population index for structuring report out objects |
|
| 1238 | 480x |
int pop_idx = 0; |
| 1239 | 960x |
for (size_t p = 0; p < this->populations.size(); p++) {
|
| 1240 |
std::map<std::string, fims::Vector<Type>> &derived_quantities = |
|
| 1241 | 480x |
this->GetPopulationDerivedQuantities(this->populations[p]->GetId()); |
| 1242 | 960x |
biomass_p(pop_idx) = derived_quantities["biomass"].to_tmb(); |
| 1243 | 480x |
expected_recruitment_p(pop_idx) = |
| 1244 | 1440x |
derived_quantities["expected_recruitment"].to_tmb(); |
| 1245 | 960x |
mortality_F_p(pop_idx) = derived_quantities["mortality_F"].to_tmb(); |
| 1246 | 960x |
mortality_M_p(pop_idx) = derived_quantities["mortality_M"].to_tmb(); |
| 1247 | 960x |
mortality_Z_p(pop_idx) = derived_quantities["mortality_Z"].to_tmb(); |
| 1248 | 480x |
numbers_at_age_p(pop_idx) = |
| 1249 | 1440x |
derived_quantities["numbers_at_age"].to_tmb(); |
| 1250 | 480x |
proportion_mature_at_age_p(pop_idx) = |
| 1251 | 1440x |
derived_quantities["proportion_mature_at_age"].to_tmb(); |
| 1252 | 480x |
spawning_biomass_p(pop_idx) = |
| 1253 | 1440x |
derived_quantities["spawning_biomass"].to_tmb(); |
| 1254 | 480x |
sum_selectivity_p(pop_idx) = |
| 1255 | 1440x |
derived_quantities["sum_selectivity"].to_tmb(); |
| 1256 | 480x |
total_landings_numbers_p(pop_idx) = |
| 1257 | 1440x |
derived_quantities["total_landings_numbers"].to_tmb(); |
| 1258 | 480x |
total_landings_weight_p(pop_idx) = |
| 1259 | 1440x |
derived_quantities["total_landings_weight"].to_tmb(); |
| 1260 | 480x |
unfished_biomass_p(pop_idx) = |
| 1261 | 1440x |
derived_quantities["unfished_biomass"].to_tmb(); |
| 1262 | 480x |
unfished_numbers_at_age_p(pop_idx) = |
| 1263 | 1440x |
derived_quantities["unfished_numbers_at_age"].to_tmb(); |
| 1264 | 480x |
unfished_spawning_biomass_p(pop_idx) = |
| 1265 | 960x |
derived_quantities["unfished_spawning_biomass"].to_tmb(); |
| 1266 | 480x |
spawning_biomass_ratio_p(pop_idx) = |
| 1267 | 480x |
this->populations[pop_idx]->spawning_biomass_ratio.to_tmb(); |
| 1268 | ||
| 1269 | 480x |
pop_idx += 1; |
| 1270 |
} |
|
| 1271 | ||
| 1272 |
// initiate fleet index for structuring report out objects |
|
| 1273 | 480x |
int fleet_idx = 0; |
| 1274 | 480x |
fleet_iterator fit; |
| 1275 | 1440x |
for (fit = this->fleets.begin(); fit != this->fleets.end(); ++fit) {
|
| 1276 | 960x |
std::shared_ptr<fims_popdy::Fleet<Type>> &fleet = (*fit).second; |
| 1277 |
std::map<std::string, fims::Vector<Type>> &derived_quantities = |
|
| 1278 | 960x |
this->GetFleetDerivedQuantities(fleet->GetId()); |
| 1279 | ||
| 1280 | 960x |
agecomp_expected_f(fleet_idx) = |
| 1281 | 2880x |
derived_quantities["agecomp_expected"].to_tmb(); |
| 1282 | 960x |
agecomp_proportion_f(fleet_idx) = |
| 1283 | 2880x |
derived_quantities["agecomp_proportion"].to_tmb(); |
| 1284 | 1920x |
catch_index_f(fleet_idx) = derived_quantities["catch_index"].to_tmb(); |
| 1285 | 960x |
index_expected_f(fleet_idx) = |
| 1286 | 2880x |
derived_quantities["index_expected"].to_tmb(); |
| 1287 | 960x |
index_numbers_f(fleet_idx) = |
| 1288 | 2880x |
derived_quantities["index_numbers"].to_tmb(); |
| 1289 | 960x |
index_numbers_at_age_f(fleet_idx) = |
| 1290 | 2880x |
derived_quantities["index_numbers_at_age"].to_tmb(); |
| 1291 | 960x |
index_numbers_at_length_f(fleet_idx) = |
| 1292 | 2880x |
derived_quantities["index_numbers_at_length"].to_tmb(); |
| 1293 | 1920x |
index_weight_f(fleet_idx) = derived_quantities["index_weight"].to_tmb(); |
| 1294 | 960x |
index_weight_at_age_f(fleet_idx) = |
| 1295 | 2880x |
derived_quantities["index_weight_at_age"].to_tmb(); |
| 1296 | 960x |
landings_expected_f(fleet_idx) = |
| 1297 | 2880x |
derived_quantities["landings_expected"].to_tmb(); |
| 1298 | 960x |
landings_numbers_f(fleet_idx) = |
| 1299 | 2880x |
derived_quantities["landings_numbers"].to_tmb(); |
| 1300 | 960x |
landings_numbers_at_age_f(fleet_idx) = |
| 1301 | 2880x |
derived_quantities["landings_numbers_at_age"].to_tmb(); |
| 1302 | 960x |
landings_numbers_at_length_f(fleet_idx) = |
| 1303 | 2880x |
derived_quantities["landings_numbers_at_length"].to_tmb(); |
| 1304 | 960x |
landings_weight_f(fleet_idx) = |
| 1305 | 2880x |
derived_quantities["landings_weight"].to_tmb(); |
| 1306 | 960x |
landings_weight_at_age_f(fleet_idx) = |
| 1307 | 2880x |
derived_quantities["landings_weight_at_age"].to_tmb(); |
| 1308 |
// length_comp_expected_f(fleet_idx) = |
|
| 1309 |
// derived_quantities["length_comp_expected"]; |
|
| 1310 |
// length_comp_proportion_f(fleet_idx) = |
|
| 1311 |
// derived_quantities["length_comp_proportion"]; |
|
| 1312 | 960x |
lengthcomp_expected_f(fleet_idx) = |
| 1313 | 2880x |
derived_quantities["lengthcomp_expected"].to_tmb(); |
| 1314 | 960x |
lengthcomp_proportion_f(fleet_idx) = |
| 1315 | 2880x |
derived_quantities["lengthcomp_proportion"].to_tmb(); |
| 1316 | 960x |
log_index_expected_f(fleet_idx) = |
| 1317 | 2880x |
derived_quantities["log_index_expected"].to_tmb(); |
| 1318 | 960x |
log_landings_expected_f(fleet_idx) = |
| 1319 | 1920x |
derived_quantities["log_landings_expected"].to_tmb(); |
| 1320 | 960x |
fleet_idx += 1; |
| 1321 |
} |
|
| 1322 | ||
| 1323 | 480x |
vector<Type> biomass = ADREPORTvector(biomass_p); |
| 1324 | 480x |
vector<Type> expected_recruitment = |
| 1325 |
ADREPORTvector(expected_recruitment_p); |
|
| 1326 | 480x |
vector<Type> mortality_F = ADREPORTvector(mortality_F_p); |
| 1327 | 480x |
vector<Type> mortality_M = ADREPORTvector(mortality_M_p); |
| 1328 | 480x |
vector<Type> mortality_Z = ADREPORTvector(mortality_Z_p); |
| 1329 | 480x |
vector<Type> numbers_at_age = ADREPORTvector(numbers_at_age_p); |
| 1330 | 480x |
vector<Type> proportion_mature_at_age = |
| 1331 |
ADREPORTvector(proportion_mature_at_age_p); |
|
| 1332 | 480x |
vector<Type> spawning_biomass = ADREPORTvector(spawning_biomass_p); |
| 1333 | 480x |
vector<Type> sum_selectivity = ADREPORTvector(sum_selectivity_p); |
| 1334 | 480x |
vector<Type> total_landings_numbers = |
| 1335 |
ADREPORTvector(total_landings_numbers_p); |
|
| 1336 | 480x |
vector<Type> total_landings_weight = |
| 1337 |
ADREPORTvector(total_landings_weight_p); |
|
| 1338 | 480x |
vector<Type> unfished_biomass = ADREPORTvector(unfished_biomass_p); |
| 1339 | 480x |
vector<Type> unfished_numbers_at_age = |
| 1340 |
ADREPORTvector(unfished_numbers_at_age_p); |
|
| 1341 | 480x |
vector<Type> unfished_spawning_biomass = |
| 1342 |
ADREPORTvector(unfished_spawning_biomass_p); |
|
| 1343 | 480x |
vector<Type> spawning_biomass_ratio = |
| 1344 |
ADREPORTvector(spawning_biomass_ratio_p); |
|
| 1345 | ||
| 1346 | 480x |
vector<Type> agecomp_expected = ADREPORTvector(agecomp_expected_f); |
| 1347 | 480x |
vector<Type> agecomp_proportion = ADREPORTvector(agecomp_proportion_f); |
| 1348 | 480x |
vector<Type> catch_index = ADREPORTvector(catch_index_f); |
| 1349 | 480x |
vector<Type> index_expected = ADREPORTvector(index_expected_f); |
| 1350 | 480x |
vector<Type> index_numbers = ADREPORTvector(index_numbers_f); |
| 1351 | 480x |
vector<Type> index_numbers_at_age = |
| 1352 |
ADREPORTvector(index_numbers_at_age_f); |
|
| 1353 | 480x |
vector<Type> index_numbers_at_length = |
| 1354 |
ADREPORTvector(index_numbers_at_length_f); |
|
| 1355 | 480x |
vector<Type> index_weight = ADREPORTvector(index_weight_f); |
| 1356 | 480x |
vector<Type> index_weight_at_age = ADREPORTvector(index_weight_at_age_f); |
| 1357 | 480x |
vector<Type> landings_expected = ADREPORTvector(landings_expected_f); |
| 1358 | 480x |
vector<Type> landings_numbers = ADREPORTvector(landings_numbers_f); |
| 1359 | 480x |
vector<Type> landings_numbers_at_age = |
| 1360 |
ADREPORTvector(landings_numbers_at_age_f); |
|
| 1361 | 480x |
vector<Type> landings_numbers_at_length = |
| 1362 |
ADREPORTvector(landings_numbers_at_length_f); |
|
| 1363 | 480x |
vector<Type> landings_weight = ADREPORTvector(landings_weight_f); |
| 1364 | 480x |
vector<Type> landings_weight_at_age = |
| 1365 |
ADREPORTvector(landings_weight_at_age_f); |
|
| 1366 |
// vector<Type> length_comp_expected = |
|
| 1367 |
// ADREPORTvector(length_comp_expected_f); vector<Type> |
|
| 1368 |
// length_comp_proportion = ADREPORTvector(length_comp_proportion_f); |
|
| 1369 | 480x |
vector<Type> lengthcomp_expected = ADREPORTvector(lengthcomp_expected_f); |
| 1370 | 480x |
vector<Type> lengthcomp_proportion = |
| 1371 |
ADREPORTvector(lengthcomp_proportion_f); |
|
| 1372 | 480x |
vector<Type> log_index_expected = ADREPORTvector(log_index_expected_f); |
| 1373 | 480x |
vector<Type> log_landings_expected = |
| 1374 |
ADREPORTvector(log_landings_expected_f); |
|
| 1375 |
// populations |
|
| 1376 |
// report |
|
| 1377 | 386x |
FIMS_REPORT_F_("biomass", biomass_p, this->of);
|
| 1378 | 386x |
FIMS_REPORT_F_("expected_recruitment", expected_recruitment_p, this->of);
|
| 1379 | 386x |
FIMS_REPORT_F_("mortality_F", mortality_F_p, this->of);
|
| 1380 | 386x |
FIMS_REPORT_F_("mortality_M", mortality_M_p, this->of);
|
| 1381 | 386x |
FIMS_REPORT_F_("mortality_Z", mortality_Z_p, this->of);
|
| 1382 | 386x |
FIMS_REPORT_F_("numbers_at_age", numbers_at_age_p, this->of);
|
| 1383 | 386x |
FIMS_REPORT_F_("proportion_mature_at_age", proportion_mature_at_age_p,
|
| 1384 |
this->of); |
|
| 1385 | 386x |
FIMS_REPORT_F_("spawning_biomass", spawning_biomass_p, this->of);
|
| 1386 | 386x |
FIMS_REPORT_F_("sum_selectivity", sum_selectivity_p, this->of);
|
| 1387 | 386x |
FIMS_REPORT_F_("total_landings_numbers", total_landings_numbers_p,
|
| 1388 |
this->of); |
|
| 1389 | 386x |
FIMS_REPORT_F_("total_landings_weight", total_landings_weight_p,
|
| 1390 |
this->of); |
|
| 1391 | 386x |
FIMS_REPORT_F_("unfished_biomass", unfished_biomass_p, this->of);
|
| 1392 | 386x |
FIMS_REPORT_F_("unfished_numbers_at_age", unfished_numbers_at_age_p,
|
| 1393 |
this->of); |
|
| 1394 | 386x |
FIMS_REPORT_F_("unfished_spawning_biomass", unfished_spawning_biomass_p,
|
| 1395 |
this->of); |
|
| 1396 | 386x |
FIMS_REPORT_F_("spawning_biomass_ratio", spawning_biomass_ratio_p,
|
| 1397 |
this->of); |
|
| 1398 | ||
| 1399 |
// adreport |
|
| 1400 | 480x |
ADREPORT_F(biomass, this->of); |
| 1401 | 480x |
ADREPORT_F(expected_recruitment, this->of); |
| 1402 | 480x |
ADREPORT_F(mortality_F, this->of); |
| 1403 | 480x |
ADREPORT_F(mortality_M, this->of); |
| 1404 | 480x |
ADREPORT_F(mortality_Z, this->of); |
| 1405 | 480x |
ADREPORT_F(numbers_at_age, this->of); |
| 1406 | 480x |
ADREPORT_F(proportion_mature_at_age, this->of); |
| 1407 | 480x |
ADREPORT_F(spawning_biomass, this->of); |
| 1408 | 480x |
ADREPORT_F(sum_selectivity, this->of); |
| 1409 | 480x |
ADREPORT_F(total_landings_numbers, this->of); |
| 1410 | 480x |
ADREPORT_F(total_landings_weight, this->of); |
| 1411 | 480x |
ADREPORT_F(unfished_biomass, this->of); |
| 1412 | 480x |
ADREPORT_F(unfished_numbers_at_age, this->of); |
| 1413 | 480x |
ADREPORT_F(unfished_spawning_biomass, this->of); |
| 1414 | 480x |
ADREPORT_F(spawning_biomass_ratio, this->of); |
| 1415 | ||
| 1416 |
// fleets |
|
| 1417 |
// report |
|
| 1418 | 386x |
FIMS_REPORT_F_("agecomp_expected", agecomp_expected_f, this->of);
|
| 1419 | 386x |
FIMS_REPORT_F_("agecomp_proportion", agecomp_proportion_f, this->of);
|
| 1420 | 386x |
FIMS_REPORT_F_("catch_index", catch_index_f, this->of);
|
| 1421 | 386x |
FIMS_REPORT_F_("index_expected", index_expected_f, this->of);
|
| 1422 | 386x |
FIMS_REPORT_F_("index_numbers", index_numbers_f, this->of);
|
| 1423 | 386x |
FIMS_REPORT_F_("index_numbers_at_age", index_numbers_at_age_f, this->of);
|
| 1424 | 386x |
FIMS_REPORT_F_("index_numbers_at_length", index_numbers_at_length_f,
|
| 1425 |
this->of); |
|
| 1426 | 386x |
FIMS_REPORT_F_("index_weight", index_weight_f, this->of);
|
| 1427 | 386x |
FIMS_REPORT_F_("index_weight_at_age", index_weight_at_age_f, this->of);
|
| 1428 | 386x |
FIMS_REPORT_F_("landings_expected", landings_expected_f, this->of);
|
| 1429 | 386x |
FIMS_REPORT_F_("landings_numbers", landings_numbers_f, this->of);
|
| 1430 | 386x |
FIMS_REPORT_F_("landings_numbers_at_age", landings_numbers_at_age_f,
|
| 1431 |
this->of); |
|
| 1432 | 386x |
FIMS_REPORT_F_("landings_numbers_at_length", landings_numbers_at_length_f,
|
| 1433 |
this->of); |
|
| 1434 | 386x |
FIMS_REPORT_F_("landings_weight", landings_weight_f, this->of);
|
| 1435 | 386x |
FIMS_REPORT_F_("landings_weight_at_age", landings_weight_at_age_f,
|
| 1436 |
this->of); |
|
| 1437 | 386x |
FIMS_REPORT_F_("lengthcomp_expected", lengthcomp_expected_f, this->of);
|
| 1438 | 386x |
FIMS_REPORT_F_("lengthcomp_proportion", lengthcomp_proportion_f,
|
| 1439 |
this->of); |
|
| 1440 | 386x |
FIMS_REPORT_F_("log_index_expected", log_index_expected_f, this->of);
|
| 1441 | 386x |
FIMS_REPORT_F_("log_landings_expected", log_landings_expected_f,
|
| 1442 |
this->of); |
|
| 1443 |
// adreport |
|
| 1444 | 480x |
ADREPORT_F(agecomp_expected, this->of); |
| 1445 | 480x |
ADREPORT_F(agecomp_proportion, this->of); |
| 1446 | 480x |
ADREPORT_F(catch_index, this->of); |
| 1447 | 480x |
ADREPORT_F(index_expected, this->of); |
| 1448 | 480x |
ADREPORT_F(index_numbers, this->of); |
| 1449 | 480x |
ADREPORT_F(index_numbers_at_age, this->of); |
| 1450 | 480x |
ADREPORT_F(index_numbers_at_length, this->of); |
| 1451 | 480x |
ADREPORT_F(index_weight, this->of); |
| 1452 | 480x |
ADREPORT_F(index_weight_at_age, this->of); |
| 1453 | 480x |
ADREPORT_F(landings_expected, this->of); |
| 1454 | 480x |
ADREPORT_F(landings_numbers, this->of); |
| 1455 | 480x |
ADREPORT_F(landings_numbers_at_age, this->of); |
| 1456 | 480x |
ADREPORT_F(landings_numbers_at_length, this->of); |
| 1457 | 480x |
ADREPORT_F(landings_weight, this->of); |
| 1458 | 480x |
ADREPORT_F(landings_weight_at_age, this->of); |
| 1459 | 480x |
ADREPORT_F(lengthcomp_expected, this->of); |
| 1460 | 480x |
ADREPORT_F(lengthcomp_proportion, this->of); |
| 1461 | 480x |
ADREPORT_F(log_index_expected, this->of); |
| 1462 | 480x |
ADREPORT_F(log_landings_expected, this->of); |
| 1463 | 480x |
std::stringstream var_name; |
| 1464 |
typename std::map<std::string, fims::Vector<fims::Vector<Type>>>::iterator |
|
| 1465 | 480x |
rvit; |
| 1466 |
for (rvit = report_vectors.begin(); rvit != report_vectors.end(); |
|
| 1467 | ! |
++rvit) {
|
| 1468 | ! |
auto &x = rvit->second; |
| 1469 | ||
| 1470 | ! |
int outer_dim = x.size(); |
| 1471 | ! |
int dim = 0; |
| 1472 | ! |
for (int i = 0; i < outer_dim; i++) {
|
| 1473 | ! |
dim += x[i].size(); |
| 1474 |
} |
|
| 1475 | ! |
vector<Type> res(dim); |
| 1476 | ! |
int idx = 0; |
| 1477 | ! |
for (int i = 0; i < outer_dim; i++) {
|
| 1478 | ! |
int inner_dim = x[i].size(); |
| 1479 | ! |
for (int j = 0; j < inner_dim; j++) {
|
| 1480 | ! |
res(idx) = x[i][j]; |
| 1481 | ! |
idx += 1; |
| 1482 |
} |
|
| 1483 |
} |
|
| 1484 | ! |
this->of->reportvector.push(res, rvit->first.c_str()); |
| 1485 |
} |
|
| 1486 |
} |
|
| 1487 |
#endif |
|
| 1488 |
} |
|
| 1489 |
}; |
|
| 1490 | ||
| 1491 |
} // namespace fims_popdy |
|
| 1492 | ||
| 1493 |
#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 | 3016x |
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 | 3132x |
DimensionInfo(const std::string &name, const fims::Vector<int> &dims, |
| 45 |
const fims::Vector<std::string> &dim_names) |
|
| 46 | 3132x |
: name(name), ndims(dims.size()), dims(dims), dim_names(dim_names) {}
|
| 47 | ||
| 48 |
/** |
|
| 49 |
* Copy constructor |
|
| 50 |
*/ |
|
| 51 | 1248x |
DimensionInfo(const DimensionInfo &other) |
| 52 | 1248x |
: name(other.name), |
| 53 | 1248x |
ndims(other.dims.size()), |
| 54 | 1248x |
dims(other.dims), |
| 55 | 1248x |
dim_names(other.dim_names) {}
|
| 56 | ||
| 57 |
/** |
|
| 58 |
* @brief Assignment operator for DimensionInfo. |
|
| 59 |
*/ |
|
| 60 | 3132x |
DimensionInfo &operator=(const DimensionInfo &other) {
|
| 61 | 3132x |
if (this != &other) {
|
| 62 | 3132x |
name = other.name; |
| 63 | 3132x |
ndims = other.ndims; |
| 64 | 3132x |
dims = other.dims; |
| 65 | 3132x |
dim_names = other.dim_names; |
| 66 | 3132x |
se_values_m = other.se_values_m; |
| 67 |
} |
|
| 68 | 3132x |
return *this; |
| 69 |
} |
|
| 70 |
}; |
|
| 71 | ||
| 72 |
/** |
|
| 73 |
* @brief FisheryModelBase is a base class for fishery models in FIMS. |
|
| 74 |
* |
|
| 75 |
*/ |
|
| 76 |
template <typename Type> |
|
| 77 |
class FisheryModelBase : public fims_model_object::FIMSObject<Type> {
|
|
| 78 |
static uint32_t id_g; /*!< global id where unique id is drawn from for fishery |
|
| 79 |
model object*/ |
|
| 80 |
uint32_t id; /*!< unique identifier assigned for fishery model object */ |
|
| 81 | ||
| 82 |
public: |
|
| 83 |
#ifdef TMB_MODEL |
|
| 84 |
bool do_reporting = |
|
| 85 |
true; /*!< flag to control reporting of derived quantities */ |
|
| 86 |
#endif |
|
| 87 |
/** |
|
| 88 |
* @brief A string specifying the model type. |
|
| 89 |
* |
|
| 90 |
*/ |
|
| 91 |
std::string model_type_m; |
|
| 92 |
/** |
|
| 93 |
* @brief Unique identifier for the fishery model. |
|
| 94 |
* |
|
| 95 |
*/ |
|
| 96 |
std::set<uint32_t> population_ids; |
|
| 97 |
/** |
|
| 98 |
* @brief A vector of populations in the fishery model. |
|
| 99 |
* |
|
| 100 |
*/ |
|
| 101 |
std::vector<std::shared_ptr<fims_popdy::Population<Type>>> populations; |
|
| 102 |
/** |
|
| 103 |
* @brief A map of fleets in the fishery model, indexed by fleet id. |
|
| 104 |
* Unique instances to eliminate duplicate initialization. |
|
| 105 |
* |
|
| 106 |
*/ |
|
| 107 |
std::map<uint32_t, std::shared_ptr<fims_popdy::Fleet<Type>>> fleets; |
|
| 108 |
/** |
|
| 109 |
* @brief Fleet-based iterator. |
|
| 110 |
* |
|
| 111 |
*/ |
|
| 112 |
typedef typename std::map<uint32_t, |
|
| 113 |
std::shared_ptr<fims_popdy::Fleet<Type>>>::iterator |
|
| 114 |
fleet_iterator; |
|
| 115 | ||
| 116 |
/** |
|
| 117 |
* @brief Type definitions for derived quantities and dimension information |
|
| 118 |
* maps. |
|
| 119 |
*/ |
|
| 120 |
typedef typename std::map<uint32_t, std::map<std::string, fims::Vector<Type>>> |
|
| 121 |
DerivedQuantitiesMap; |
|
| 122 | ||
| 123 |
/** |
|
| 124 |
* @brief Iterator for the derived quantities map. |
|
| 125 |
*/ |
|
| 126 |
typedef typename DerivedQuantitiesMap::iterator DerivedQuantitiesMapIterator; |
|
| 127 | ||
| 128 |
/** |
|
| 129 |
* @brief Shared pointer for the fleet derived quantities map. |
|
| 130 |
*/ |
|
| 131 |
std::shared_ptr<DerivedQuantitiesMap> fleet_derived_quantities; |
|
| 132 | ||
| 133 |
/** |
|
| 134 |
* @brief Shared pointer for the population derived quantities map. |
|
| 135 |
*/ |
|
| 136 |
std::shared_ptr<DerivedQuantitiesMap> population_derived_quantities; |
|
| 137 | ||
| 138 |
/** |
|
| 139 |
* @brief Type definitions for dimension information maps. |
|
| 140 |
*/ |
|
| 141 |
typedef typename std::map<uint32_t, std::map<std::string, DimensionInfo>> |
|
| 142 |
DimensionInfoMap; |
|
| 143 | ||
| 144 |
/** |
|
| 145 |
* @brief Shared pointer for the fleet dimension information map. |
|
| 146 |
*/ |
|
| 147 |
std::shared_ptr<DimensionInfoMap> fleet_dimension_info; |
|
| 148 | ||
| 149 |
/** |
|
| 150 |
* @brief Shared pointer for the population dimension information map. |
|
| 151 |
*/ |
|
| 152 |
std::shared_ptr<DimensionInfoMap> population_dimension_info; |
|
| 153 | ||
| 154 |
#ifdef TMB_MODEL |
|
| 155 |
::objective_function<Type> *of; |
|
| 156 |
#endif |
|
| 157 |
/** |
|
| 158 |
* @brief Construct a new Fishery Model Base object. |
|
| 159 |
* |
|
| 160 |
*/ |
|
| 161 | 116x |
FisheryModelBase() : id(FisheryModelBase::id_g++) {
|
| 162 | 116x |
fleet_derived_quantities = std::make_shared<DerivedQuantitiesMap>(); |
| 163 | 116x |
population_derived_quantities = std::make_shared<DerivedQuantitiesMap>(); |
| 164 | 116x |
fleet_dimension_info = std::make_shared<DimensionInfoMap>(); |
| 165 | 116x |
population_dimension_info = std::make_shared<DimensionInfoMap>(); |
| 166 |
} |
|
| 167 | ||
| 168 |
/** |
|
| 169 |
* @brief Construct a new Fishery Model Base object. |
|
| 170 |
* |
|
| 171 |
* @param other |
|
| 172 |
*/ |
|
| 173 |
FisheryModelBase(const FisheryModelBase &other) |
|
| 174 |
: id(other.id), |
|
| 175 |
population_ids(other.population_ids), |
|
| 176 |
populations(other.populations), |
|
| 177 |
fleet_derived_quantities(other.fleet_derived_quantities), |
|
| 178 |
population_derived_quantities(other.population_derived_quantities), |
|
| 179 |
fleet_dimension_info(other.fleet_dimension_info), |
|
| 180 |
population_dimension_info(other.population_dimension_info) {}
|
|
| 181 | ||
| 182 |
/** |
|
| 183 |
* @brief Destroy the Fishery Model Base object. |
|
| 184 |
* |
|
| 185 |
*/ |
|
| 186 | 58x |
virtual ~FisheryModelBase() {}
|
| 187 | ||
| 188 |
/** |
|
| 189 |
* @brief Get the fleet dimension information. |
|
| 190 |
* |
|
| 191 |
* @return std::map<uint32_t, std::map<std::string, DimensionInfo>> |
|
| 192 |
*/ |
|
| 193 |
std::map<uint32_t, std::map<std::string, DimensionInfo>> & |
|
| 194 |
GetFleetDimensionInfo() {
|
|
| 195 |
return *fleet_dimension_info; |
|
| 196 |
} |
|
| 197 | ||
| 198 |
/** |
|
| 199 |
* @brief Get the population dimension information. |
|
| 200 |
* |
|
| 201 |
* @return std::map<uint32_t, std::map<std::string, DimensionInfo>> |
|
| 202 |
*/ |
|
| 203 |
std::map<uint32_t, std::map<std::string, DimensionInfo>> & |
|
| 204 |
GetPopulationDimensionInfo() {
|
|
| 205 |
return *population_dimension_info; |
|
| 206 |
} |
|
| 207 | ||
| 208 |
/** |
|
| 209 |
* @brief Get the fleet derived quantities. |
|
| 210 |
* |
|
| 211 |
* @return DerivedQuantitiesMap |
|
| 212 |
*/ |
|
| 213 |
DerivedQuantitiesMap &GetFleetDerivedQuantities() {
|
|
| 214 |
return *fleet_derived_quantities; |
|
| 215 |
} |
|
| 216 | ||
| 217 |
/** |
|
| 218 |
* @brief Get the population derived quantities. |
|
| 219 |
* |
|
| 220 |
* @return DerivedQuantitiesMap |
|
| 221 |
*/ |
|
| 222 |
DerivedQuantitiesMap &GetPopulationDerivedQuantities() {
|
|
| 223 |
return *population_derived_quantities; |
|
| 224 |
} |
|
| 225 | ||
| 226 |
/** |
|
| 227 |
* @brief Get the fleet derived quantities for a specified fleet. |
|
| 228 |
* |
|
| 229 |
* @param fleet_id The ID of the fleet. |
|
| 230 |
* @return std::map<std::string, fims::Vector<Type>>& |
|
| 231 |
*/ |
|
| 232 | 2367784x |
std::map<std::string, fims::Vector<Type>> &GetFleetDerivedQuantities( |
| 233 |
uint32_t fleet_id) {
|
|
| 234 | 2367784x |
if (!fleet_derived_quantities) {
|
| 235 | ! |
throw std::runtime_error( |
| 236 |
"GetFleetDerivedQuantities: fleet_derived_quantities is null"); |
|
| 237 |
} |
|
| 238 | 2367784x |
auto &outer = *fleet_derived_quantities; |
| 239 | 2367784x |
auto it = outer.find(fleet_id); |
| 240 | 2367784x |
if (it == outer.end()) {
|
| 241 | ! |
std::stringstream ss; |
| 242 | ||
| 243 | ! |
ss << "GetFleetDerivedQuantities: fleet_id " << fleet_id |
| 244 | ! |
<< " not found in fleet_derived_quantities"; |
| 245 | ! |
throw std::out_of_range(ss.str()); |
| 246 |
} |
|
| 247 | 4735568x |
return it->second; |
| 248 |
} |
|
| 249 | ||
| 250 |
/** |
|
| 251 |
* @brief Initialize the derived quantities map for a fleet. |
|
| 252 |
* |
|
| 253 |
* @details Ensures the derived quantities map for the specified fleet |
|
| 254 |
* exists. If not, creates an empty map for the fleet ID. |
|
| 255 |
* |
|
| 256 |
* @param fleet_id The ID of the fleet to initialize. |
|
| 257 |
*/ |
|
| 258 | 232x |
void InitializeFleetDerivedQuantities(uint32_t fleet_id) {
|
| 259 |
// Ensure the shared_ptr exists |
|
| 260 | 232x |
if (!fleet_derived_quantities) {
|
| 261 | ! |
fleet_derived_quantities = std::make_shared< |
| 262 |
std::map<uint32_t, std::map<std::string, fims::Vector<Type>>>>(); |
|
| 263 |
} |
|
| 264 | ||
| 265 | 232x |
auto &outer = *fleet_derived_quantities; |
| 266 | ||
| 267 |
// Insert only if not already present |
|
| 268 | 232x |
if (outer.find(fleet_id) == outer.end()) {
|
| 269 | 232x |
outer.emplace(fleet_id, std::map<std::string, fims::Vector<Type>>{});
|
| 270 |
} |
|
| 271 |
} |
|
| 272 | ||
| 273 |
/** |
|
| 274 |
* @brief Initialize the derived quantities map for a population. |
|
| 275 |
* |
|
| 276 |
* @details Ensures the derived quantities map for the specified |
|
| 277 |
* population exists. If not, creates an empty map for the population ID. |
|
| 278 |
* |
|
| 279 |
* @param population_id The ID of the population to initialize. |
|
| 280 |
*/ |
|
| 281 | 116x |
void InitializePopulationDerivedQuantities(uint32_t population_id) {
|
| 282 |
// Ensure the shared_ptr exists |
|
| 283 | 116x |
if (!population_derived_quantities) {
|
| 284 | ! |
population_derived_quantities = std::make_shared< |
| 285 |
std::map<uint32_t, std::map<std::string, fims::Vector<Type>>>>(); |
|
| 286 |
} |
|
| 287 | ||
| 288 | 116x |
auto &outer = *population_derived_quantities; |
| 289 | ||
| 290 |
// Insert only if not already present |
|
| 291 | 116x |
if (outer.find(population_id) == outer.end()) {
|
| 292 | 116x |
outer.emplace(population_id, std::map<std::string, fims::Vector<Type>>{});
|
| 293 |
} |
|
| 294 |
} |
|
| 295 | ||
| 296 |
/** |
|
| 297 |
* @brief Get the population derived quantities for a specified population. |
|
| 298 |
* |
|
| 299 |
* @param population_id The ID of the population. |
|
| 300 |
* @return std::map<std::string, fims::Vector<Type>>& |
|
| 301 |
*/ |
|
| 302 | 2226450x |
std::map<std::string, fims::Vector<Type>> &GetPopulationDerivedQuantities( |
| 303 |
uint32_t population_id) {
|
|
| 304 | 2226450x |
if (!population_derived_quantities) {
|
| 305 | ! |
throw std::runtime_error( |
| 306 |
"GetPopulationDerivedQuantities: population_derived_quantities is " |
|
| 307 |
"null"); |
|
| 308 |
} |
|
| 309 | 2226450x |
auto &outer = *population_derived_quantities; |
| 310 | 2226450x |
auto it = outer.find(population_id); |
| 311 | 2226450x |
if (it == outer.end()) {
|
| 312 | ! |
std::ostringstream ss; |
| 313 | ! |
ss << "GetPopulationDerivedQuantities: population_id " << population_id |
| 314 | ! |
<< " not found in population_derived_quantities"; |
| 315 | ! |
throw std::out_of_range(ss.str()); |
| 316 |
} |
|
| 317 | 4452900x |
return it->second; |
| 318 |
} |
|
| 319 | ||
| 320 |
/** |
|
| 321 |
* @brief Get the fleet dimension information for a specified fleet. |
|
| 322 |
* |
|
| 323 |
* @param fleet_id The ID of the fleet. |
|
| 324 |
* @return std::map<std::string, DimensionInfo> |
|
| 325 |
*/ |
|
| 326 | 328x |
std::map<std::string, DimensionInfo> &GetFleetDimensionInfo( |
| 327 |
uint32_t fleet_id) {
|
|
| 328 | 328x |
return (*fleet_dimension_info)[fleet_id]; |
| 329 |
} |
|
| 330 | ||
| 331 |
/** |
|
| 332 |
* @brief Get the population dimension information for a specified population. |
|
| 333 |
* |
|
| 334 |
* @param population_id The ID of the population. |
|
| 335 |
* @return std::map<std::string, DimensionInfo> |
|
| 336 |
*/ |
|
| 337 | 164x |
std::map<std::string, DimensionInfo> &GetPopulationDimensionInfo( |
| 338 |
uint32_t population_id) {
|
|
| 339 | 164x |
return (*population_dimension_info)[population_id]; |
| 340 |
} |
|
| 341 | ||
| 342 |
/** |
|
| 343 |
* @brief Initialize a model. |
|
| 344 |
* |
|
| 345 |
*/ |
|
| 346 | ! |
virtual void Initialize() {}
|
| 347 | ||
| 348 |
/** |
|
| 349 |
* @brief Prepare the model. |
|
| 350 |
* |
|
| 351 |
*/ |
|
| 352 | ! |
virtual void Prepare() {}
|
| 353 | ||
| 354 |
/** |
|
| 355 |
* @brief Reset a vector from start to end with a value. |
|
| 356 |
* |
|
| 357 |
* @param v A vector to reset. |
|
| 358 |
* @param value The value you want to use for all elements in the |
|
| 359 |
* vector. The default is 0.0. |
|
| 360 |
*/ |
|
| 361 | 54912x |
virtual void ResetVector(fims::Vector<Type> &v, Type value = 0.0) {
|
| 362 | 54912x |
std::fill(v.begin(), v.end(), value); |
| 363 |
} |
|
| 364 | ||
| 365 |
/** |
|
| 366 |
* @brief Evaluate the model. |
|
| 367 |
* |
|
| 368 |
*/ |
|
| 369 | ! |
virtual void Evaluate() {}
|
| 370 | ||
| 371 |
/** |
|
| 372 |
* @brief Report the model results via TMB. |
|
| 373 |
* |
|
| 374 |
*/ |
|
| 375 | ! |
virtual void Report() {}
|
| 376 | ||
| 377 |
/** |
|
| 378 |
* @brief Get the Id object. |
|
| 379 |
* |
|
| 380 |
* @return uint32_t |
|
| 381 |
*/ |
|
| 382 | 116x |
uint32_t GetId() { return this->id; }
|
| 383 |
}; |
|
| 384 | ||
| 385 |
template <typename Type> |
|
| 386 |
uint32_t FisheryModelBase<Type>::id_g = 0; |
|
| 387 | ||
| 388 |
} // namespace fims_popdy |
|
| 389 |
#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 | 244x |
Fleet() { this->id = Fleet::id_g++; }
|
| 77 | ||
| 78 |
/** |
|
| 79 |
* @brief Destructor. |
|
| 80 |
*/ |
|
| 81 | 122x |
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 |
// default id of the singleton fleet class |
|
| 104 |
template <class Type> |
|
| 105 |
uint32_t Fleet<Type>::id_g = 0; |
|
| 106 | ||
| 107 |
} // end namespace fims_popdy |
|
| 108 | ||
| 109 |
#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<int, 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 | 126x |
EWAAGrowth() : GrowthBase<Type>() {}
|
| 35 | ||
| 36 | 63x |
virtual ~EWAAGrowth() {}
|
| 37 | ||
| 38 |
/** |
|
| 39 |
* @brief Returns the weight at age a (in kg) from the input vector. |
|
| 40 |
* |
|
| 41 |
* @param year year |
|
| 42 |
* @param a age of the fish, the age vector must start at zero |
|
| 43 |
*/ |
|
| 44 | 897733x |
virtual const Type evaluate(int year, const double& a) {
|
| 45 | 897733x |
return this->ewaa[year][a]; |
| 46 |
} |
|
| 47 |
}; |
|
| 48 |
} // namespace fims_popdy |
|
| 49 |
#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 | 126x |
GrowthBase() { this->id = GrowthBase::id_g++; }
|
| 35 | ||
| 36 | 63x |
virtual ~GrowthBase() {}
|
| 37 | ||
| 38 |
/** |
|
| 39 |
* @brief Calculates the growth at the independent variable value. |
|
| 40 |
* @param year The year at which to return weight of the fish (in kg). |
|
| 41 |
* @param a The age at which to return weight of the fish (in kg). |
|
| 42 |
*/ |
|
| 43 |
virtual const Type evaluate(int year, const double& a) = 0; |
|
| 44 |
}; |
|
| 45 | ||
| 46 |
template <typename Type> |
|
| 47 |
uint32_t GrowthBase<Type>::id_g = 0; |
|
| 48 | ||
| 49 |
} // namespace fims_popdy |
|
| 50 | ||
| 51 |
#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 | 122x |
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 | 203018x |
virtual const Type evaluate(const Type& x) {
|
| 44 | 203018x |
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 |
} // namespace fims_popdy |
|
| 64 | ||
| 65 |
#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 | 122x |
MaturityBase() {
|
| 34 |
// increment id of the singleton maturity class |
|
| 35 | 122x |
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 | 30x |
1, static_cast<Type>(0.5)); /*!< proportion female by age */ |
| 39 |
fims::Vector<Type> log_f_multiplier; /*!< estimated parameter: vector of |
|
| 40 |
annual fishing mortality multipliers to scale total mortality of all fleets*/ |
|
| 41 |
fims::Vector<Type> spawning_biomass_ratio; /*!< estimated parameter: vector of |
|
| 42 |
annual fishing mortality multipliers to scale total mortality of all fleets*/ |
|
| 43 | ||
| 44 |
// Transformed values |
|
| 45 |
fims::Vector<Type> M; /*!< transformed parameter: natural mortality*/ |
|
| 46 |
fims::Vector<Type> f_multiplier; /*!< transformed parameter: vector of |
|
| 47 |
annual fishing mortality multipliers to scale total mortality of all fleets*/ |
|
| 48 | ||
| 49 |
fims::Vector<double> ages; /*!< vector of the ages for referencing*/ |
|
| 50 |
fims::Vector<double> years; /*!< vector of years for referencing*/ |
|
| 51 | ||
| 52 |
/// recruitment |
|
| 53 |
int recruitment_id = -999; /*!< id of recruitment model object*/ |
|
| 54 |
std::shared_ptr<fims_popdy::RecruitmentBase<Type>> |
|
| 55 |
recruitment; /*!< shared pointer to recruitment module */ |
|
| 56 | ||
| 57 |
// growth |
|
| 58 |
int growth_id = -999; /*!< id of growth model object*/ |
|
| 59 |
std::shared_ptr<fims_popdy::GrowthBase<Type>> |
|
| 60 |
growth; /*!< shared pointer to growth module */ |
|
| 61 | ||
| 62 |
// maturity |
|
| 63 |
int maturity_id = -999; /*!< id of maturity model object*/ |
|
| 64 |
std::shared_ptr<fims_popdy::MaturityBase<Type>> |
|
| 65 |
maturity; /*!< shared pointer to maturity module */ |
|
| 66 | ||
| 67 |
// fleet |
|
| 68 |
std::set<uint32_t> fleet_ids; /*!< id of fleet model object*/ |
|
| 69 |
std::vector<std::shared_ptr<fims_popdy::Fleet<Type>>> |
|
| 70 |
fleets; /*!< shared pointer to fleet module */ |
|
| 71 | ||
| 72 |
/** |
|
| 73 |
* @brief Constructor. |
|
| 74 |
*/ |
|
| 75 | 120x |
Population() { this->id = Population::id_g++; }
|
| 76 |
}; |
|
| 77 |
template <class Type> |
|
| 78 |
uint32_t Population<Type>::id_g = 0; |
|
| 79 | ||
| 80 |
} // namespace fims_popdy |
|
| 81 | ||
| 82 |
#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 | 116x |
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 | 15224x |
virtual const Type evaluate_process(size_t pos) {
|
| 35 | 15224x |
return this->recruitment->log_expected_recruitment[pos] + |
| 36 | 17934x |
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 | ||
| 45 |
} // namespace fims_popdy |
|
| 46 | ||
| 47 |
#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 | 638x |
virtual const Type evaluate_process(size_t pos) {
|
| 35 | 638x |
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 | 252x |
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 |
* See the @ref glossary for definitions of mathematical symbols used below. |
|
| 22 |
* |
|
| 23 |
* @param logit_steep Recruitment relative to unfished recruitment at 20 |
|
| 24 |
* percent of unfished spawning biomass. Steepness is subject to a logit |
|
| 25 |
* transformation to keep it between 0.2 and 1.0. |
|
| 26 |
*/ |
|
| 27 |
template <typename Type> |
|
| 28 |
struct SRBevertonHolt : public RecruitmentBase<Type> {
|
|
| 29 |
// Here we define the members that will be used in the Beverton--Holt |
|
| 30 |
// stock--recruitment function. These members are needed by the Beverton--Holt |
|
| 31 |
// stock--recruitment function but will not be common to all recruitment |
|
| 32 |
// functions like spawners is below. |
|
| 33 |
fims::Vector<Type> logit_steep; /**< Transformed value of recruitment |
|
| 34 |
relative to unfished |
|
| 35 |
recruitment at 20 percent of unfished |
|
| 36 |
spawning biomass.*/ |
|
| 37 | ||
| 38 | 132x |
SRBevertonHolt() : RecruitmentBase<Type>() {}
|
| 39 | ||
| 40 | 6x |
virtual ~SRBevertonHolt() {}
|
| 41 | ||
| 42 |
/** @brief Beverton--Holt implementation of the stock--recruitment function. |
|
| 43 |
* |
|
| 44 |
* The Beverton--Holt stock--recruitment implementation: |
|
| 45 |
* \f$ \frac{0.8 R_{0} h S_{t-1}}{0.2 R_{0} \phi_{0} (1 - h) + S_{t-1} (h -
|
|
| 46 |
* 0.2)} \f$ |
|
| 47 |
* |
|
| 48 |
* @param spawners A measure of spawning output. |
|
| 49 |
* @param phi_0 Number of spawners per recruit of an unfished population |
|
| 50 |
*/ |
|
| 51 | 16394x |
virtual const Type evaluate_mean(const Type& spawners, const Type& phi_0) {
|
| 52 | 2920x |
Type recruits; |
| 53 | 2920x |
Type steep; |
| 54 | 16394x |
Type steep_lo = static_cast<Type>(0.2); |
| 55 | 16394x |
Type steep_hi = static_cast<Type>(1.0); |
| 56 | 2920x |
Type rzero; |
| 57 | ||
| 58 |
// Transform input parameters |
|
| 59 | 16394x |
steep = fims_math::inv_logit(steep_lo, steep_hi, this->logit_steep[0]); |
| 60 | 16394x |
rzero = fims_math::exp(this->log_rzero[0]); |
| 61 | ||
| 62 | 16394x |
recruits = (static_cast<Type>(0.8) * rzero * steep * spawners) / |
| 63 | 16394x |
(static_cast<Type>(0.2) * phi_0 * rzero * |
| 64 | 19314x |
(static_cast<Type>(1.0) - steep) + |
| 65 | 16394x |
spawners * (steep - static_cast<Type>(0.2))); |
| 66 | ||
| 67 | 16394x |
return recruits; |
| 68 |
} |
|
| 69 | ||
| 70 |
/** Empty return of base class function |
|
| 71 |
* @param pos position index |
|
| 72 |
*/ |
|
| 73 | ! |
virtual const Type evaluate_process(size_t pos) { return 0; }
|
| 74 |
}; |
|
| 75 | ||
| 76 |
} // namespace fims_popdy |
|
| 77 | ||
| 78 |
#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. If the index is out of bounds |
|
| 70 |
* then it returns the first element, which would be the case when you do not |
|
| 71 |
* have time-varying selectivity. |
|
| 72 |
*/ |
|
| 73 | ! |
virtual const Type evaluate(const Type& x, size_t pos) {
|
| 74 | ! |
return fims_math::double_logistic<Type>( |
| 75 | ! |
inflection_point_asc.get_force_scalar(pos), |
| 76 | ! |
slope_asc.get_force_scalar(pos), |
| 77 | ! |
inflection_point_desc.get_force_scalar(pos), |
| 78 | ! |
slope_desc.get_force_scalar(pos), x); |
| 79 |
} |
|
| 80 |
}; |
|
| 81 | ||
| 82 |
} // namespace fims_popdy |
|
| 83 | ||
| 84 |
#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 |
* The logistic selectivity function can produce either an ascending or |
|
| 24 |
* descending curve based on the sign of the slope parameter. A positive slope |
|
| 25 |
* creates an ascending logistic curve (selectivity increases from 0 to 1 with |
|
| 26 |
* increasing x), while a negative slope creates a descending logistic curve |
|
| 27 |
* (selectivity decreases from 1 to 0 with increasing x). |
|
| 28 |
*/ |
|
| 29 |
template <typename Type> |
|
| 30 |
struct LogisticSelectivity : public SelectivityBase<Type> {
|
|
| 31 |
fims::Vector<Type> |
|
| 32 |
inflection_point; /**< 50% quantile of the value of the quantity of |
|
| 33 |
interest (x); e.g. age at which 50% of the fish are selected */ |
|
| 34 |
fims::Vector<Type> slope; /**<scalar multiplier of difference between quantity |
|
| 35 |
of interest value (x) and inflection_point. Positive values create |
|
| 36 |
an ascending curve (0 to 1), negative values create a descending |
|
| 37 |
curve (1 to 0). */ |
|
| 38 | ||
| 39 | 276x |
LogisticSelectivity() : SelectivityBase<Type>() {}
|
| 40 | ||
| 41 | 138x |
virtual ~LogisticSelectivity() {}
|
| 42 | ||
| 43 |
/** |
|
| 44 |
* @brief Method of the logistic selectivity class that implements the |
|
| 45 |
* logistic function from FIMS math. |
|
| 46 |
* |
|
| 47 |
* \f[ \frac{1.0}{ 1.0 + exp(-1.0 * slope (x - inflection\_point))} \f]
|
|
| 48 |
* |
|
| 49 |
* The selectivity curve can be either ascending or descending depending on |
|
| 50 |
* the sign of the slope parameter: |
|
| 51 |
* - Positive slope: ascending curve (selectivity increases from 0 to 1) |
|
| 52 |
* - Negative slope: descending curve (selectivity decreases from 1 to 0) |
|
| 53 |
* |
|
| 54 |
* @param x The independent variable in the logistic function (e.g., age or |
|
| 55 |
* size in selectivity). |
|
| 56 |
*/ |
|
| 57 | 2x |
virtual const Type evaluate(const Type &x) {
|
| 58 | 2x |
return fims_math::logistic<Type>(inflection_point[0], slope[0], x); |
| 59 |
} |
|
| 60 | ||
| 61 |
/** |
|
| 62 |
* @copydoc LogisticSelectivity::evaluate(const Type &x) |
|
| 63 |
* @param pos Position index, e.g., which year. If the index is out of bounds |
|
| 64 |
* then it returns the first element, which would be the case when you do not |
|
| 65 |
* have time-varying selectivity. |
|
| 66 |
*/ |
|
| 67 | 590040x |
virtual const Type evaluate(const Type &x, size_t pos) {
|
| 68 | 590040x |
return fims_math::logistic<Type>(inflection_point.get_force_scalar(pos), |
| 69 | 1180080x |
slope.get_force_scalar(pos), x); |
| 70 |
} |
|
| 71 |
}; |
|
| 72 | ||
| 73 |
} // namespace fims_popdy |
|
| 74 | ||
| 75 |
#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 | 290x |
SelectivityBase() {
|
| 35 |
// increment id of the singleton selectivity class |
|
| 36 | 290x |
this->id = SelectivityBase::id_g++; |
| 37 |
} |
|
| 38 | ||
| 39 | 145x |
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 | 24x |
static std::string removeWhitespace(const std::string& input) {
|
| 117 | 24x |
std::string result = input; |
| 118 | 24x |
result.erase(std::remove_if(result.begin(), result.end(), ::isspace), |
| 119 | 24x |
result.end()); |
| 120 | 24x |
return result; |
| 121 |
} |
|
| 122 | ||
| 123 |
/** |
|
| 124 |
* @brief Formats a JSON string. |
|
| 125 |
* @param json |
|
| 126 |
* @return |
|
| 127 |
*/ |
|
| 128 | 24x |
static std::string PrettyFormatJSON(const std::string& json) {
|
| 129 | 24x |
std::string result; |
| 130 | 24x |
std::string input = JsonParser::removeWhitespace(json); |
| 131 | 24x |
int indentLevel = 0; |
| 132 | 24x |
bool inQuotes = false; |
| 133 | ||
| 134 | 18639993x |
for (size_t i = 0; i < input.size(); ++i) {
|
| 135 | 18639969x |
char current = input[i]; |
| 136 | ||
| 137 | 18639969x |
switch (current) {
|
| 138 | 79753x |
case '{':
|
| 139 |
case '[': |
|
| 140 | 79753x |
result += current; |
| 141 | 79753x |
if (!inQuotes) {
|
| 142 | 55488x |
result += '\n'; |
| 143 | 55488x |
indentLevel++; |
| 144 | 110976x |
result += std::string(indentLevel * 4, ' '); |
| 145 |
} |
|
| 146 | 79753x |
break; |
| 147 | ||
| 148 | 79753x |
case '}': |
| 149 |
case ']': |
|
| 150 | 79753x |
if (!inQuotes) {
|
| 151 | 55488x |
result += '\n'; |
| 152 | 55488x |
indentLevel--; |
| 153 | 110976x |
result += std::string(indentLevel * 4, ' '); |
| 154 |
} |
|
| 155 | 79753x |
result += current; |
| 156 | 79753x |
break; |
| 157 | ||
| 158 | 839172x |
case ',': |
| 159 | 839172x |
result += current; |
| 160 | 839172x |
if (!inQuotes) {
|
| 161 | 838526x |
result += '\n'; |
| 162 | 1677052x |
result += std::string(indentLevel * 4, ' '); |
| 163 |
} |
|
| 164 | 839172x |
break; |
| 165 | ||
| 166 | 463975x |
case ':': |
| 167 | 463975x |
result += current; |
| 168 | 463975x |
if (!inQuotes) result += " "; |
| 169 | 463975x |
break; |
| 170 | ||
| 171 | 1109474x |
case '"': |
| 172 | 1109474x |
result += current; |
| 173 |
// Toggle inQuotes when we encounter a double-quote |
|
| 174 |
if (i == 0 || input[i - 1] != '\\') {
|
|
| 175 | 1109474x |
inQuotes = !inQuotes; |
| 176 |
} |
|
| 177 | 1109474x |
break; |
| 178 | ||
| 179 | 16067842x |
default: |
| 180 | 16067842x |
result += current; |
| 181 | 16067842x |
break; |
| 182 |
} |
|
| 183 |
} |
|
| 184 | 48x |
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 | ! |
if (position >= data.size()) {
|
| 246 | ! |
return JsonValue(); |
| 247 |
} |
|
| 248 | ||
| 249 | ! |
char current = data[position]; |
| 250 | ! |
if (current == '{') {
|
| 251 | ! |
return ParseObject(); |
| 252 | ! |
} else if (current == '[') {
|
| 253 | ! |
return ParseArray(); |
| 254 | ! |
} else if (current == '"') {
|
| 255 | ! |
return ParseString(); |
| 256 | ! |
} else if (current == 't' || current == 'f') {
|
| 257 | ! |
return ParseBool(); |
| 258 | ! |
} else if (current == 'n') {
|
| 259 | ! |
return ParseNull(); |
| 260 | ! |
} else if (std::isdigit(current) || current == '-') {
|
| 261 | ! |
return ParseNumber(); |
| 262 |
} else {
|
|
| 263 |
// Unknown token. |
|
| 264 | ! |
position++; |
| 265 | ! |
return JsonValue(); |
| 266 |
} |
|
| 267 |
} |
|
| 268 | ||
| 269 |
/** |
|
| 270 |
* Parse a numeric JSON value. |
|
| 271 |
* @return The parsed JSON value. |
|
| 272 |
*/ |
|
| 273 | ! |
JsonValue JsonParser::ParseNumber() {
|
| 274 | ! |
size_t end_pos = position; |
| 275 | ! |
bool is_float = false; |
| 276 | ! |
while (end_pos < data.size() && |
| 277 | ! |
(std::isdigit(data[end_pos]) || data[end_pos] == '.' || |
| 278 | ! |
data[end_pos] == '-' || data[end_pos] == 'e' || |
| 279 | ! |
data[end_pos] == 'E')) {
|
| 280 | ! |
if (data[end_pos] == '.' || data[end_pos] == 'e' || data[end_pos] == 'E') {
|
| 281 | ! |
is_float = true; |
| 282 |
} |
|
| 283 | ! |
end_pos++; |
| 284 |
} |
|
| 285 | ||
| 286 | ! |
std::string num_str = data.substr(position, end_pos - position); |
| 287 | ! |
position = end_pos; |
| 288 | ||
| 289 | ! |
if (is_float) {
|
| 290 | ! |
double num = 0.0; |
| 291 | ! |
std::istringstream(num_str) >> num; |
| 292 | ! |
return JsonValue(num); |
| 293 |
} else {
|
|
| 294 | ! |
int num = 0; |
| 295 | ! |
std::istringstream(num_str) >> num; |
| 296 | ! |
return JsonValue(num); |
| 297 |
} |
|
| 298 |
} |
|
| 299 | ||
| 300 |
/** |
|
| 301 |
* Parse a string JSON value. |
|
| 302 |
* @return The parsed JSON value. |
|
| 303 |
*/ |
|
| 304 | ! |
JsonValue JsonParser::ParseString() {
|
| 305 | ! |
position++; // Skip the initial '"' |
| 306 | ! |
size_t end_pos = data.find('"', position);
|
| 307 | ! |
if (end_pos == std::string::npos) {
|
| 308 | ! |
std::string str = data.substr(position); |
| 309 | ! |
position = data.size(); |
| 310 | ! |
return JsonValue(str); |
| 311 |
} |
|
| 312 | ! |
std::string str = data.substr(position, end_pos - position); |
| 313 | ! |
position = end_pos + 1; |
| 314 | ! |
return JsonValue(str); |
| 315 |
} |
|
| 316 | ||
| 317 |
/** |
|
| 318 |
* Parse a boolean JSON value. |
|
| 319 |
* @return The parsed JSON value. |
|
| 320 |
*/ |
|
| 321 | ! |
JsonValue JsonParser::ParseBool() {
|
| 322 | ! |
if (data.compare(position, 4, "true") == 0) {
|
| 323 | ! |
position += 4; |
| 324 | ! |
return JsonValue(true); |
| 325 | ! |
} else if (data.compare(position, 5, "false") == 0) {
|
| 326 | ! |
position += 5; |
| 327 | ! |
return JsonValue(false); |
| 328 |
} else {
|
|
| 329 |
// Invalid boolean value |
|
| 330 | ! |
return JsonValue(); |
| 331 |
} |
|
| 332 |
} |
|
| 333 | ||
| 334 |
/** |
|
| 335 |
* Parse a null JSON value. |
|
| 336 |
* @return The parsed JSON value. |
|
| 337 |
*/ |
|
| 338 | ! |
JsonValue JsonParser::ParseNull() {
|
| 339 | ! |
if (data.compare(position, 4, "null") == 0) {
|
| 340 | ! |
position += 4; |
| 341 | ! |
return JsonValue(); |
| 342 |
} else {
|
|
| 343 |
// Invalid null value |
|
| 344 | ! |
return JsonValue(); |
| 345 |
} |
|
| 346 |
} |
|
| 347 | ||
| 348 |
/** |
|
| 349 |
* Parse a JSON object. |
|
| 350 |
* @return The parsed JSON value representing the object. |
|
| 351 |
*/ |
|
| 352 | ! |
JsonValue JsonParser::ParseObject() {
|
| 353 | ! |
JsonObject obj; |
| 354 | ! |
position++; // Skip the initial '{'
|
| 355 | ||
| 356 | ! |
SkipWhitespace(); |
| 357 | ! |
if (position < data.size() && data[position] == '}') {
|
| 358 | ! |
position++; // Skip empty object close brace |
| 359 | ! |
return JsonValue(obj); |
| 360 |
} |
|
| 361 | ||
| 362 | ! |
while (position < data.size() && data[position] != '}') {
|
| 363 | ! |
SkipWhitespace(); |
| 364 | ! |
if (position >= data.size() || data[position] != '"') {
|
| 365 | ! |
return JsonValue(obj); |
| 366 |
} |
|
| 367 | ! |
std::string key = ParseString().GetString(); |
| 368 | ||
| 369 | ! |
SkipWhitespace(); |
| 370 | ! |
if (position >= data.size() || data[position] != ':') {
|
| 371 | ! |
return JsonValue(obj); |
| 372 |
} |
|
| 373 | ! |
position++; // Skip the ':' |
| 374 | ! |
SkipWhitespace(); |
| 375 | ! |
JsonValue value = ParseValue(); |
| 376 | ! |
obj[key] = value; |
| 377 | ||
| 378 | ! |
SkipWhitespace(); |
| 379 | ! |
if (position < data.size() && data[position] == ',') {
|
| 380 | ! |
position++; |
| 381 |
} |
|
| 382 |
} |
|
| 383 | ||
| 384 | ! |
if (position < data.size() && data[position] == '}') {
|
| 385 | ! |
position++; // Skip the trailing '}' |
| 386 |
} |
|
| 387 | ! |
return JsonValue(obj); |
| 388 |
} |
|
| 389 | ||
| 390 |
/** |
|
| 391 |
* Parse a JSON array. |
|
| 392 |
* @return The parsed JSON value representing the array. |
|
| 393 |
*/ |
|
| 394 | ! |
JsonValue JsonParser::ParseArray() {
|
| 395 | ! |
JsonArray arr; |
| 396 | ! |
position++; // Skip the initial '[' |
| 397 | ||
| 398 | ! |
SkipWhitespace(); |
| 399 | ! |
if (position < data.size() && data[position] == ']') {
|
| 400 | ! |
position++; // Skip empty array close bracket |
| 401 | ! |
return JsonValue(arr); |
| 402 |
} |
|
| 403 | ||
| 404 | ! |
while (position < data.size() && data[position] != ']') {
|
| 405 | ! |
SkipWhitespace(); |
| 406 | ! |
JsonValue value = ParseValue(); |
| 407 | ! |
arr.push_back(value); |
| 408 | ||
| 409 | ! |
SkipWhitespace(); |
| 410 | ! |
if (position < data.size() && data[position] == ',') {
|
| 411 | ! |
position++; |
| 412 |
} |
|
| 413 |
} |
|
| 414 | ||
| 415 | ! |
if (position < data.size() && data[position] == ']') {
|
| 416 | ! |
position++; // Skip the trailing ']' |
| 417 |
} |
|
| 418 | ! |
return JsonValue(arr); |
| 419 |
} |
|
| 420 | ||
| 421 |
/** |
|
| 422 |
* Write a JSON value to an output file. |
|
| 423 |
* @param filename The name of the output file. |
|
| 424 |
* @param jsonValue The JSON value to write. |
|
| 425 |
*/ |
|
| 426 | ! |
void JsonParser::WriteToFile(const std::string& filename, JsonValue jsonValue) {
|
| 427 | ! |
std::ofstream outputFile(filename); |
| 428 | ! |
if (!outputFile) {
|
| 429 | ! |
std::cerr << "Error: Unable to open file " << filename << " for writing." |
| 430 | ! |
<< std::endl; |
| 431 | ! |
return; |
| 432 |
} |
|
| 433 | ||
| 434 |
/** Call a private helper function to write JSON values recursively */ |
|
| 435 | ! |
WriteJsonValue(outputFile, jsonValue); |
| 436 |
} |
|
| 437 | ||
| 438 |
/** |
|
| 439 |
* Write a JSON value to an output file. |
|
| 440 |
* Private helper function to write JSON values recursively |
|
| 441 |
* @param outputFile The output file stream. |
|
| 442 |
* @param jsonValue The JSON value to write. |
|
| 443 |
*/ |
|
| 444 | ! |
void JsonParser::WriteJsonValue(std::ofstream& outputFile, |
| 445 |
JsonValue jsonValue) {
|
|
| 446 | ! |
switch (jsonValue.GetType()) {
|
| 447 | ! |
case JsonValueType::Null: |
| 448 | ! |
outputFile << "null"; |
| 449 | ! |
break; |
| 450 | ! |
case JsonValueType::Number: |
| 451 | ! |
outputFile << jsonValue.GetDouble(); |
| 452 | ! |
break; |
| 453 | ! |
case JsonValueType::String: |
| 454 | ! |
outputFile << "\"" << jsonValue.GetString() << "\""; |
| 455 | ! |
break; |
| 456 | ! |
case JsonValueType::Bool: |
| 457 | ! |
outputFile << (jsonValue.GetBool() ? "true" : "false"); |
| 458 | ! |
break; |
| 459 | ! |
case JsonValueType::Object: {
|
| 460 | ! |
JsonObject& obj = jsonValue.GetObject(); |
| 461 | ! |
outputFile << "{";
|
| 462 | ! |
bool first = true; |
| 463 | ! |
for (const auto& pair : obj) {
|
| 464 | ! |
if (!first) {
|
| 465 | ! |
outputFile << ","; |
| 466 |
} |
|
| 467 | ! |
first = false; |
| 468 | ! |
outputFile << "\"" << pair.first << "\":"; |
| 469 | ! |
WriteJsonValue(outputFile, pair.second); |
| 470 |
} |
|
| 471 | ! |
outputFile << "}"; |
| 472 | ! |
} break; |
| 473 | ! |
case JsonValueType::JArray: {
|
| 474 | ! |
JsonArray& arr = jsonValue.GetArray(); |
| 475 | ! |
outputFile << "["; |
| 476 | ! |
bool first = true; |
| 477 | ! |
for (const auto& value : arr) {
|
| 478 | ! |
if (!first) {
|
| 479 | ! |
outputFile << ","; |
| 480 |
} |
|
| 481 | ! |
first = false; |
| 482 | ! |
WriteJsonValue(outputFile, value); |
| 483 |
} |
|
| 484 | ! |
outputFile << "]"; |
| 485 | ! |
} break; |
| 486 |
} |
|
| 487 |
} |
|
| 488 | ||
| 489 |
/** |
|
| 490 |
* Display a JSON value to the standard output. |
|
| 491 |
* @param jsonValue The JSON value to display. |
|
| 492 |
*/ |
|
| 493 | ! |
void JsonParser::Show(JsonValue jsonValue) {
|
| 494 | ! |
this->PrintJsonValue(std::cout, jsonValue); |
| 495 | ! |
std::cout << std::endl; |
| 496 |
} |
|
| 497 | ||
| 498 |
/** |
|
| 499 |
* Display a JSON value to an output stream. |
|
| 500 |
* @param output The output stream. |
|
| 501 |
* @param jsonValue The JSON value to display. |
|
| 502 |
*/ |
|
| 503 | ! |
void JsonParser::PrintJsonValue(std::ostream& output, JsonValue jsonValue) {
|
| 504 | ! |
switch (jsonValue.GetType()) {
|
| 505 | ! |
case JsonValueType::Null: |
| 506 | ! |
output << "null"; |
| 507 | ! |
break; |
| 508 | ! |
case JsonValueType::Number: |
| 509 | ! |
output << jsonValue.GetDouble(); |
| 510 | ! |
break; |
| 511 | ! |
case JsonValueType::String: |
| 512 | ! |
output << "\"" << jsonValue.GetString() << "\""; |
| 513 | ! |
break; |
| 514 | ! |
case JsonValueType::Bool: |
| 515 | ! |
output << (jsonValue.GetBool() ? "true" : "false"); |
| 516 | ! |
break; |
| 517 | ! |
case JsonValueType::Object: {
|
| 518 | ! |
JsonObject& obj = jsonValue.GetObject(); |
| 519 | ! |
output << "{";
|
| 520 | ! |
bool first = true; |
| 521 | ! |
for (const auto& pair : obj) {
|
| 522 | ! |
if (!first) {
|
| 523 | ! |
output << ","; |
| 524 |
} |
|
| 525 | ! |
first = false; |
| 526 | ! |
output << "\"" << pair.first << "\":"; |
| 527 | ! |
PrintJsonValue(output, pair.second); |
| 528 |
} |
|
| 529 | ! |
output << "}"; |
| 530 | ! |
} break; |
| 531 | ! |
case JsonValueType::JArray: {
|
| 532 | ! |
JsonArray& arr = jsonValue.GetArray(); |
| 533 | ! |
output << "["; |
| 534 | ! |
bool first = true; |
| 535 | ! |
for (const auto& value : arr) {
|
| 536 | ! |
if (!first) {
|
| 537 | ! |
output << ","; |
| 538 |
} |
|
| 539 | ! |
first = false; |
| 540 | ! |
PrintJsonValue(output, value); |
| 541 |
} |
|
| 542 | ! |
output << "]"; |
| 543 | ! |
} break; |
| 544 |
} |
|
| 545 |
} |
|
| 546 |
} // namespace fims |
|
| 547 |
#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 Define fims C++ functions and classes exposed in R |
|
| 35 |
* |
|
| 36 |
* @details |
|
| 37 |
* The use of `RCPP_MODULE()` allows for exporting of specific C++ code to the |
|
| 38 |
* R environment, making it callable from R, i.e., providing declarative code |
|
| 39 |
* of what the module exposes to R. |
|
| 40 |
* |
|
| 41 |
* Each element included in the module should have a name, a pointer, and a |
|
| 42 |
* description separated by commas in that order. Elements can be functions or |
|
| 43 |
* classes. Within an element, both the name and the description should be |
|
| 44 |
* wrapped in quotes. |
|
| 45 |
* |
|
| 46 |
* The description is printed to the in R when users run `methods::show()` on |
|
| 47 |
* a function or class within the RCPP_MODULE, e.g., `methods::show(Parameter)`. |
|
| 48 |
* Thus, information in the description should either link to the relevant |
|
| 49 |
* doxygen documentation for the C++ class or function or exactly duplicate |
|
| 50 |
* what is written in the doxygen. |
|
| 51 |
* |
|
| 52 |
* Each of the functions included in this module should be exported by manually |
|
| 53 |
* exporting them in R/FIMS-package.R. Typically, R packages that use C++ would |
|
| 54 |
* take care a lot of this stuff automatically using `Rcpp::export` calls in the |
|
| 55 |
* C++ documentation but we cannot do that within FIMS because of how the |
|
| 56 |
* package is compiled. |
|
| 57 |
* |
|
| 58 |
*/ |
|
| 59 | 18x |
RCPP_MODULE(fims) {
|
| 60 | 6x |
Rcpp::function( |
| 61 |
"CreateTMBModel", &CreateTMBModel, |
|
| 62 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 63 | 6x |
Rcpp::function( |
| 64 |
// TODO: fix the naming mismatch |
|
| 65 |
"set_fixed", &set_fixed_parameters, |
|
| 66 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 67 | 6x |
Rcpp::function( |
| 68 |
// TODO: fix the naming mismatch |
|
| 69 |
"get_fixed", &get_fixed_parameters_vector, |
|
| 70 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 71 | 6x |
Rcpp::function( |
| 72 |
// TODO: fix the naming mismatch |
|
| 73 |
"set_random", &set_random_parameters, |
|
| 74 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 75 | 6x |
Rcpp::function( |
| 76 |
// TODO: fix the naming mismatch |
|
| 77 |
"get_random", &get_random_parameters_vector, |
|
| 78 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 79 | 6x |
Rcpp::function( |
| 80 |
"get_parameter_names", &get_parameter_names, |
|
| 81 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 82 | 6x |
Rcpp::function( |
| 83 |
"get_random_names", &get_random_names, |
|
| 84 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 85 | 6x |
Rcpp::function( |
| 86 |
"clear", clear, |
|
| 87 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 88 | 6x |
Rcpp::function( |
| 89 |
"get_log", get_log, |
|
| 90 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 91 | 6x |
Rcpp::function( |
| 92 |
"get_log_errors", get_log_errors, |
|
| 93 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 94 | 6x |
Rcpp::function( |
| 95 |
"get_log_warnings", get_log_warnings, |
|
| 96 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 97 | 6x |
Rcpp::function( |
| 98 |
"get_log_info", get_log_info, |
|
| 99 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 100 | 6x |
Rcpp::function( |
| 101 |
"write_log", write_log, |
|
| 102 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 103 | 6x |
Rcpp::function( |
| 104 |
"set_log_path", set_log_path, |
|
| 105 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 106 | 6x |
Rcpp::function( |
| 107 |
"init_logging", init_logging, |
|
| 108 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 109 | 6x |
Rcpp::function( |
| 110 |
"set_log_throw_on_error", set_log_throw_on_error, |
|
| 111 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 112 | 6x |
Rcpp::function( |
| 113 |
"log_info", log_info, |
|
| 114 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 115 | 6x |
Rcpp::function( |
| 116 |
"log_warning", log_warning, |
|
| 117 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 118 | 6x |
Rcpp::function( |
| 119 |
"log_error", log_error, |
|
| 120 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 121 | 6x |
Rcpp::function( |
| 122 |
// TODO: fix the naming mismatch |
|
| 123 |
"logit", logit_rcpp, |
|
| 124 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 125 | 6x |
Rcpp::function( |
| 126 |
// TODO: fix the naming mismatch |
|
| 127 |
"inv_logit", inv_logit_rcpp, |
|
| 128 |
"See https://noaa-fims.github.io/FIMS/doxygen/rcpp__interface_8hpp.html."); |
|
| 129 | ||
| 130 | 12x |
Rcpp::class_<Parameter>( |
| 131 |
"Parameter", |
|
| 132 |
"See https://noaa-fims.github.io/FIMS/doxygen/classParameter.html.") |
|
| 133 | 6x |
.constructor() |
| 134 | 6x |
.constructor<double>() |
| 135 | 6x |
.constructor<Parameter>() |
| 136 | 6x |
.field("value", &Parameter::initial_value_m)
|
| 137 | 6x |
.field("estimated_value", &Parameter::final_value_m)
|
| 138 | 6x |
.field("id", &Parameter::id_m)
|
| 139 | 6x |
.field("estimation_type", &Parameter::estimation_type_m);
|
| 140 | ||
| 141 | 12x |
Rcpp::class_<ParameterVector>( |
| 142 |
"ParameterVector", |
|
| 143 |
"See https://noaa-fims.github.io/FIMS/doxygen/classParameterVector.html.") |
|
| 144 | 6x |
.constructor() |
| 145 | 6x |
.constructor<size_t>() |
| 146 | 6x |
.constructor<Rcpp::NumericVector, size_t>() |
| 147 | 6x |
.method("get", &ParameterVector::get)
|
| 148 | 6x |
.method("set", &ParameterVector::set)
|
| 149 | 6x |
.method("show", &ParameterVector::show)
|
| 150 | 6x |
.method("at", &ParameterVector::at)
|
| 151 | 6x |
.method("size", &ParameterVector::size)
|
| 152 | 6x |
.method("resize", &ParameterVector::resize)
|
| 153 | 6x |
.method("set_all_estimable", &ParameterVector::set_all_estimable)
|
| 154 | 6x |
.method("set_all_random", &ParameterVector::set_all_random)
|
| 155 | 6x |
.method("fill", &ParameterVector::fill)
|
| 156 | 6x |
.method("get_id", &ParameterVector::get_id);
|
| 157 | ||
| 158 | 12x |
Rcpp::class_<RealVector>( |
| 159 |
"RealVector", |
|
| 160 |
"See https://noaa-fims.github.io/FIMS/doxygen/classRealVector.html.") |
|
| 161 | 6x |
.constructor() |
| 162 | 6x |
.constructor<size_t>() |
| 163 | 6x |
.constructor<Rcpp::NumericVector, size_t>() |
| 164 | 6x |
.method("get", &RealVector::get)
|
| 165 | 6x |
.method("set", &RealVector::set)
|
| 166 | 6x |
.method("fromRVector", &RealVector::fromRVector)
|
| 167 | 6x |
.method("toRVector", &RealVector::toRVector)
|
| 168 | 6x |
.method("show", &RealVector::show)
|
| 169 | 6x |
.method("at", &RealVector::at)
|
| 170 | 6x |
.method("size", &RealVector::size)
|
| 171 | 6x |
.method("resize", &RealVector::resize)
|
| 172 | 6x |
.method("get_id", &RealVector::get_id);
|
| 173 | ||
| 174 | 12x |
Rcpp::class_<SharedInt>( |
| 175 |
"SharedInt", |
|
| 176 |
"See https://noaa-fims.github.io/FIMS/doxygen/classSharedInt.html.") |
|
| 177 | 6x |
.constructor() |
| 178 | 6x |
.constructor<int>() |
| 179 | 6x |
.method("get", &SharedInt::get)
|
| 180 | 6x |
.method("set", &SharedInt::set);
|
| 181 | ||
| 182 | 12x |
Rcpp::class_<SharedString>( |
| 183 |
"SharedString", |
|
| 184 |
"See https://noaa-fims.github.io/FIMS/doxygen/classSharedString.html.") |
|
| 185 | 6x |
.constructor() |
| 186 | 6x |
.constructor<std::string>() |
| 187 | 6x |
.method("get", &SharedString::get)
|
| 188 | 6x |
.method("set", &SharedString::set);
|
| 189 | ||
| 190 | 12x |
Rcpp::class_<SharedBoolean>( |
| 191 |
"SharedBoolean", |
|
| 192 |
"See https://noaa-fims.github.io/FIMS/doxygen/classSharedBoolean.html.") |
|
| 193 | 6x |
.constructor() |
| 194 | 6x |
.constructor<bool>() |
| 195 | 6x |
.method("get", &SharedBoolean::get)
|
| 196 | 6x |
.method("set", &SharedBoolean::set);
|
| 197 | ||
| 198 | 12x |
Rcpp::class_<SharedReal>( |
| 199 |
"SharedReal", |
|
| 200 |
"See https://noaa-fims.github.io/FIMS/doxygen/classSharedReal.html.") |
|
| 201 | 6x |
.constructor() |
| 202 | 6x |
.constructor<double>() |
| 203 | 6x |
.method("get", &SharedReal::get)
|
| 204 | 6x |
.method("set", &SharedReal::set);
|
| 205 | ||
| 206 | 12x |
Rcpp::class_<BevertonHoltRecruitmentInterface>( |
| 207 |
"BevertonHoltRecruitment", |
|
| 208 |
"See " |
|
| 209 |
"https://noaa-fims.github.io/FIMS/doxygen/" |
|
| 210 |
"classBevertonHoltRecruitmentInterface.html.") |
|
| 211 | 6x |
.constructor() |
| 212 | 6x |
.field("logit_steep", &BevertonHoltRecruitmentInterface::logit_steep)
|
| 213 | 6x |
.field("log_rzero", &BevertonHoltRecruitmentInterface::log_rzero)
|
| 214 | 6x |
.field("log_devs", &BevertonHoltRecruitmentInterface::log_devs)
|
| 215 | 6x |
.field("log_r", &BevertonHoltRecruitmentInterface::log_r)
|
| 216 | 6x |
.field("log_expected_recruitment",
|
| 217 |
&BevertonHoltRecruitmentInterface::log_expected_recruitment) |
|
| 218 | 6x |
.field("n_years", &BevertonHoltRecruitmentInterface::n_years)
|
| 219 | 6x |
.method("get_id", &BevertonHoltRecruitmentInterface::get_id)
|
| 220 | 6x |
.method("SetRecruitmentProcessID",
|
| 221 |
&BevertonHoltRecruitmentInterface::SetRecruitmentProcessID) |
|
| 222 | 6x |
.method("evaluate_mean",
|
| 223 |
&BevertonHoltRecruitmentInterface::evaluate_mean); |
|
| 224 | ||
| 225 | 12x |
Rcpp::class_<LogDevsRecruitmentInterface>( |
| 226 |
"LogDevsRecruitmentProcess", |
|
| 227 |
"See " |
|
| 228 |
"https://noaa-fims.github.io/FIMS/doxygen/" |
|
| 229 |
"classLogDevsRecruitmentInterface.html.") |
|
| 230 | 6x |
.constructor() |
| 231 | 6x |
.method("get_id", &LogDevsRecruitmentInterface::get_id)
|
| 232 | 6x |
.method("evaluate_process",
|
| 233 |
&LogDevsRecruitmentInterface::evaluate_process); |
|
| 234 | ||
| 235 | 12x |
Rcpp::class_<LogRRecruitmentInterface>( |
| 236 |
"LogRRecruitmentProcess", |
|
| 237 |
"See " |
|
| 238 |
"https://noaa-fims.github.io/FIMS/doxygen/classLogRRecruitmentInterface.html.") |
|
| 239 | 6x |
.constructor() |
| 240 | 6x |
.method("get_id", &LogRRecruitmentInterface::get_id)
|
| 241 | 6x |
.method("evaluate_process", &LogRRecruitmentInterface::evaluate_process);
|
| 242 | ||
| 243 | 12x |
Rcpp::class_<FleetInterface>( |
| 244 |
"Fleet", |
|
| 245 |
"See https://noaa-fims.github.io/FIMS/doxygen/classFleetInterface.html.") |
|
| 246 | 6x |
.constructor() |
| 247 | 6x |
.field("log_q", &FleetInterface::log_q)
|
| 248 | 6x |
.field("log_Fmort", &FleetInterface::log_Fmort)
|
| 249 | 6x |
.field("n_ages", &FleetInterface::n_ages)
|
| 250 | 6x |
.field("n_years", &FleetInterface::n_years)
|
| 251 | 6x |
.field("n_lengths", &FleetInterface::n_lengths)
|
| 252 | 6x |
.field("observed_landings_units",
|
| 253 |
&FleetInterface::observed_landings_units) |
|
| 254 | 6x |
.field("observed_index_units", &FleetInterface::observed_index_units)
|
| 255 | 6x |
.field("index_expected", &FleetInterface::derived_index_expected)
|
| 256 | 6x |
.field("landings_expected", &FleetInterface::derived_landings_expected)
|
| 257 | 6x |
.field("log_index_expected", &FleetInterface::log_index_expected)
|
| 258 | 6x |
.field("log_landings_expected", &FleetInterface::log_landings_expected)
|
| 259 | 6x |
.field("agecomp_expected", &FleetInterface::agecomp_expected)
|
| 260 | 6x |
.field("lengthcomp_expected", &FleetInterface::lengthcomp_expected)
|
| 261 | 6x |
.field("agecomp_proportion", &FleetInterface::agecomp_proportion)
|
| 262 | 6x |
.field("lengthcomp_proportion", &FleetInterface::lengthcomp_proportion)
|
| 263 | 6x |
.field("age_to_length_conversion",
|
| 264 |
&FleetInterface::age_to_length_conversion) |
|
| 265 | 6x |
.method("get_id", &FleetInterface::get_id)
|
| 266 | 6x |
.method("SetName", &FleetInterface::SetName)
|
| 267 | 6x |
.method("GetName", &FleetInterface::GetName)
|
| 268 | 6x |
.method("SetObservedAgeCompDataID",
|
| 269 |
&FleetInterface::SetObservedAgeCompDataID) |
|
| 270 | 6x |
.method("GetObservedAgeCompDataID",
|
| 271 |
&FleetInterface::GetObservedAgeCompDataID) |
|
| 272 | 6x |
.method("SetObservedLengthCompDataID",
|
| 273 |
&FleetInterface::SetObservedLengthCompDataID) |
|
| 274 | 6x |
.method("GetObservedLengthCompDataID",
|
| 275 |
&FleetInterface::GetObservedLengthCompDataID) |
|
| 276 | 6x |
.method("SetObservedIndexDataID", &FleetInterface::SetObservedIndexDataID)
|
| 277 | 6x |
.method("GetObservedIndexDataID", &FleetInterface::GetObservedIndexDataID)
|
| 278 | 6x |
.method("SetObservedLandingsDataID",
|
| 279 |
&FleetInterface::SetObservedLandingsDataID) |
|
| 280 | 6x |
.method("GetObservedLandingsDataID",
|
| 281 |
&FleetInterface::GetObservedLandingsDataID) |
|
| 282 | 6x |
.method("SetSelectivityID", &FleetInterface::SetSelectivityID);
|
| 283 | ||
| 284 | 12x |
Rcpp::class_<AgeCompDataInterface>( |
| 285 |
"AgeComp", |
|
| 286 |
"See https://noaa-fims.github.io/FIMS/doxygen/classAgeCompDataInterface.html.") |
|
| 287 | 6x |
.constructor<int, int>() |
| 288 | 6x |
.field("age_comp_data", &AgeCompDataInterface::age_comp_data)
|
| 289 | 6x |
.method("get_id", &AgeCompDataInterface::get_id);
|
| 290 | ||
| 291 | 12x |
Rcpp::class_<LengthCompDataInterface>( |
| 292 |
"LengthComp", |
|
| 293 |
"See " |
|
| 294 |
"https://noaa-fims.github.io/FIMS/doxygen/classLengthCompDataInterface.html.") |
|
| 295 | 6x |
.constructor<int, int>() |
| 296 | 6x |
.field("length_comp_data", &LengthCompDataInterface::length_comp_data)
|
| 297 | 6x |
.method("get_id", &LengthCompDataInterface::get_id);
|
| 298 | ||
| 299 | 12x |
Rcpp::class_<LandingsDataInterface>( |
| 300 |
"Landings", |
|
| 301 |
"See " |
|
| 302 |
"https://noaa-fims.github.io/FIMS/doxygen/classLandingsDataInterface.html.") |
|
| 303 | 6x |
.constructor<int>() |
| 304 | 6x |
.field("landings_data", &LandingsDataInterface::landings_data)
|
| 305 | 6x |
.method("get_id", &LandingsDataInterface::get_id);
|
| 306 | ||
| 307 | 12x |
Rcpp::class_<IndexDataInterface>( |
| 308 |
"Index", |
|
| 309 |
"See https://noaa-fims.github.io/FIMS/doxygen/classIndexDataInterface.html.") |
|
| 310 | 6x |
.constructor<int>() |
| 311 | 6x |
.field("index_data", &IndexDataInterface::index_data)
|
| 312 | 6x |
.method("get_id", &IndexDataInterface::get_id);
|
| 313 | ||
| 314 | 12x |
Rcpp::class_<PopulationInterface>( |
| 315 |
"Population", |
|
| 316 |
"See https://noaa-fims.github.io/FIMS/doxygen/classPopulationInterface.html.") |
|
| 317 | 6x |
.constructor() |
| 318 | 6x |
.method("get_id", &PopulationInterface::get_id)
|
| 319 | 6x |
.field("n_ages", &PopulationInterface::n_ages)
|
| 320 | 6x |
.field("n_fleets", &PopulationInterface::n_fleets)
|
| 321 | 6x |
.field("n_years", &PopulationInterface::n_years)
|
| 322 | 6x |
.field("n_lengths", &PopulationInterface::n_lengths)
|
| 323 | 6x |
.field("log_M", &PopulationInterface::log_M)
|
| 324 | 6x |
.field("log_f_multiplier", &PopulationInterface::log_f_multiplier)
|
| 325 | 6x |
.field("spawning_biomass_ratio",
|
| 326 |
&PopulationInterface::spawning_biomass_ratio) |
|
| 327 | 6x |
.field("log_init_naa", &PopulationInterface::log_init_naa)
|
| 328 | 6x |
.field("ages", &PopulationInterface::ages)
|
| 329 | 6x |
.method("SetMaturityID", &PopulationInterface::SetMaturityID)
|
| 330 | 6x |
.method("SetGrowthID", &PopulationInterface::SetGrowthID)
|
| 331 | 6x |
.method("SetRecruitmentID", &PopulationInterface::SetRecruitmentID)
|
| 332 | 6x |
.method("AddFleet", &PopulationInterface::AddFleet)
|
| 333 | 6x |
.method("SetName", &PopulationInterface::SetName)
|
| 334 | 6x |
.method("GetName", &PopulationInterface::GetName);
|
| 335 | ||
| 336 | 12x |
Rcpp::class_<LogisticMaturityInterface>( |
| 337 |
"LogisticMaturity", |
|
| 338 |
"See " |
|
| 339 |
"https://noaa-fims.github.io/FIMS/doxygen/" |
|
| 340 |
"classLogisticMaturityInterface.html.") |
|
| 341 | 6x |
.constructor() |
| 342 | 6x |
.field("inflection_point", &LogisticMaturityInterface::inflection_point)
|
| 343 | 6x |
.field("slope", &LogisticMaturityInterface::slope)
|
| 344 | 6x |
.method("get_id", &LogisticMaturityInterface::get_id)
|
| 345 | 6x |
.method("evaluate", &LogisticMaturityInterface::evaluate);
|
| 346 | ||
| 347 | 12x |
Rcpp::class_<LogisticSelectivityInterface>( |
| 348 |
"LogisticSelectivity", |
|
| 349 |
"See " |
|
| 350 |
"https://noaa-fims.github.io/FIMS/doxygen/" |
|
| 351 |
"classLogisticSelectivityInterface.html.") |
|
| 352 | 6x |
.constructor() |
| 353 | 6x |
.field("inflection_point",
|
| 354 |
&LogisticSelectivityInterface::inflection_point) |
|
| 355 | 6x |
.field("slope", &LogisticSelectivityInterface::slope)
|
| 356 | 6x |
.method("get_id", &LogisticSelectivityInterface::get_id)
|
| 357 | 6x |
.method("evaluate", &LogisticSelectivityInterface::evaluate);
|
| 358 | ||
| 359 | 12x |
Rcpp::class_<DoubleLogisticSelectivityInterface>( |
| 360 |
"DoubleLogisticSelectivity", |
|
| 361 |
"See " |
|
| 362 |
"https://noaa-fims.github.io/FIMS/doxygen/" |
|
| 363 |
"classDoubleLogisticSelectivityInterface.html.") |
|
| 364 | 6x |
.constructor() |
| 365 | 6x |
.field("inflection_point_asc",
|
| 366 |
&DoubleLogisticSelectivityInterface::inflection_point_asc) |
|
| 367 | 6x |
.field("slope_asc", &DoubleLogisticSelectivityInterface::slope_asc)
|
| 368 | 6x |
.field("inflection_point_desc",
|
| 369 |
&DoubleLogisticSelectivityInterface::inflection_point_desc) |
|
| 370 | 6x |
.field("slope_desc", &DoubleLogisticSelectivityInterface::slope_desc)
|
| 371 | 6x |
.method("get_id", &DoubleLogisticSelectivityInterface::get_id)
|
| 372 | 6x |
.method("evaluate", &DoubleLogisticSelectivityInterface::evaluate);
|
| 373 | ||
| 374 | 12x |
Rcpp::class_<EWAAGrowthInterface>( |
| 375 |
"EWAAGrowth", |
|
| 376 |
"See https://noaa-fims.github.io/FIMS/doxygen/classEWAAGrowthInterface.html.") |
|
| 377 | 6x |
.constructor() |
| 378 | 6x |
.field("ages", &EWAAGrowthInterface::ages, "Ages for each age class.")
|
| 379 | 6x |
.field("weights", &EWAAGrowthInterface::weights,
|
| 380 |
"Weights for each age class.") |
|
| 381 | 6x |
.field("n_years", &EWAAGrowthInterface::n_years, "Number of years.")
|
| 382 | 6x |
.method("get_id", &EWAAGrowthInterface::get_id)
|
| 383 | 6x |
.method("evaluate", &EWAAGrowthInterface::evaluate);
|
| 384 | ||
| 385 | 12x |
Rcpp::class_<DnormDistributionsInterface>( |
| 386 |
"DnormDistribution", |
|
| 387 |
"See " |
|
| 388 |
"https://noaa-fims.github.io/FIMS/doxygen/" |
|
| 389 |
"classDnormDistributionsInterface.html.") |
|
| 390 | 6x |
.constructor() |
| 391 | 6x |
.method("get_id", &DnormDistributionsInterface::get_id)
|
| 392 | 6x |
.method("evaluate", &DnormDistributionsInterface::evaluate)
|
| 393 | 6x |
.method("set_observed_data",
|
| 394 |
&DnormDistributionsInterface::set_observed_data) |
|
| 395 | 6x |
.method("set_distribution_mean",
|
| 396 |
&DnormDistributionsInterface::set_distribution_mean) |
|
| 397 | 6x |
.method("set_distribution_links",
|
| 398 |
&DnormDistributionsInterface::set_distribution_links) |
|
| 399 | 6x |
.field("observed_values", &DnormDistributionsInterface::observed_values)
|
| 400 | 6x |
.field("expected_values", &DnormDistributionsInterface::expected_values)
|
| 401 | 6x |
.field("expected_mean", &DnormDistributionsInterface::expected_mean)
|
| 402 | 6x |
.field("log_sd", &DnormDistributionsInterface::log_sd);
|
| 403 | ||
| 404 | 12x |
Rcpp::class_<DlnormDistributionsInterface>( |
| 405 |
"DlnormDistribution", |
|
| 406 |
"See " |
|
| 407 |
"https://noaa-fims.github.io/FIMS/doxygen/" |
|
| 408 |
"classDlnormDistributionsInterface.html.") |
|
| 409 | 6x |
.constructor() |
| 410 | 6x |
.method("get_id", &DlnormDistributionsInterface::get_id)
|
| 411 | 6x |
.method("evaluate", &DlnormDistributionsInterface::evaluate)
|
| 412 | 6x |
.method("set_observed_data",
|
| 413 |
&DlnormDistributionsInterface::set_observed_data) |
|
| 414 | 6x |
.method("set_distribution_links",
|
| 415 |
&DlnormDistributionsInterface::set_distribution_links) |
|
| 416 | 6x |
.field("observed_values", &DlnormDistributionsInterface::observed_values)
|
| 417 | 6x |
.field("expected_values", &DlnormDistributionsInterface::expected_values)
|
| 418 | 6x |
.field("log_sd", &DlnormDistributionsInterface::log_sd);
|
| 419 | ||
| 420 | 12x |
Rcpp::class_<DmultinomDistributionsInterface>( |
| 421 |
"DmultinomDistribution", |
|
| 422 |
"See " |
|
| 423 |
"https://noaa-fims.github.io/FIMS/doxygen/" |
|
| 424 |
"classDmultinomDistributionsInterface.html.") |
|
| 425 | 6x |
.constructor() |
| 426 | 6x |
.method("get_id", &DmultinomDistributionsInterface::get_id)
|
| 427 | 6x |
.method("evaluate", &DmultinomDistributionsInterface::evaluate)
|
| 428 | 6x |
.method("set_observed_data",
|
| 429 |
&DmultinomDistributionsInterface::set_observed_data) |
|
| 430 | 6x |
.method("set_distribution_links",
|
| 431 |
&DmultinomDistributionsInterface::set_distribution_links) |
|
| 432 | 6x |
.method("set_note", &DmultinomDistributionsInterface::set_note)
|
| 433 | 6x |
.field("observed_values",
|
| 434 |
&DmultinomDistributionsInterface::observed_values) |
|
| 435 | 6x |
.field("expected_values",
|
| 436 |
&DmultinomDistributionsInterface::expected_values) |
|
| 437 | 6x |
.field("dims", &DmultinomDistributionsInterface::dims);
|
| 438 | ||
| 439 | 12x |
Rcpp::class_<CatchAtAgeInterface>( |
| 440 |
"CatchAtAge", |
|
| 441 |
"See https://noaa-fims.github.io/FIMS/doxygen/classCatchAtAgeInterface.html.") |
|
| 442 | 6x |
.constructor() |
| 443 | 6x |
.method("AddPopulation", &CatchAtAgeInterface::AddPopulation)
|
| 444 | 6x |
.method("get_output", &CatchAtAgeInterface::to_json)
|
| 445 | 6x |
.method("GetId", &CatchAtAgeInterface::get_id)
|
| 446 | 6x |
.method("DoReporting", &CatchAtAgeInterface::DoReporting)
|
| 447 | 6x |
.method("IsReporting", &CatchAtAgeInterface::IsReporting);
|
| 448 |
} |
|
| 449 | ||
| 450 |
#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 | 656x |
Type objective_function<Type>::operator()() {
|
| 18 | ||
| 19 | ||
| 20 | 656x |
PARAMETER_VECTOR(p); |
| 21 | 656x |
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 | 656x |
std::shared_ptr<fims_model::Model<Type>> model = |
| 27 |
fims_model::Model<Type>::GetInstance(); |
|
| 28 |
// get the singleton instance for Information Class |
|
| 29 | 656x |
std::shared_ptr<fims_info::Information<Type>> information = |
| 30 |
fims_info::Information<Type>::GetInstance(); |
|
| 31 | ||
| 32 |
//update the fixed effects parameter values |
|
| 33 | 23700x |
for(size_t i =0; i < information->fixed_effects_parameters.size(); i++){
|
| 34 | 23044x |
*information->fixed_effects_parameters[i] = p[i]; |
| 35 |
} |
|
| 36 |
//update the random effects parameter values |
|
| 37 | 6772x |
for(size_t i =0; i < information->random_effects_parameters.size(); i++){
|
| 38 | 6116x |
*information->random_effects_parameters[i] = re[i]; |
| 39 |
} |
|
| 40 | 656x |
model -> of = this; |
| 41 | ||
| 42 | 656x |
Type nll = 0; |
| 43 |
//evaluate the model objective function value |
|
| 44 |
try{
|
|
| 45 | 656x |
nll = model->Evaluate(); |
| 46 |
} catch (const std::exception& e) {
|
|
| 47 |
Rf_error("Error during model evaluation: %s", std::string(e.what()).c_str());
|
|
| 48 |
} |
|
| 49 | ||
| 50 | 656x |
return nll; |
| 51 | ||
| 52 |
} |
|
| 53 |
/// @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 |