Skip to contents

Builds tidy, stacked tables from one or more fitted TAM models. For each model it collects:

  • observation diagnostics from the model's $obs_pred component (falling back to tidy_obs_pred() when absent),

  • population summaries from $pop (falling back to tidy_pop() when absent), and

  • parameter summaries from $fixed_par/$random_par (falling back to tidy_par() when absent),

then stacks per component across models (e.g., all "catch" tables together; all "N" tables together; all fixed parameters together; each random-effect block together).

Usage

tidy_tam(
  ...,
  model_list = NULL,
  interval = 0.95,
  label = "model",
  label_type = "auto",
  process_residuals = TRUE,
  process_seed = 123456L
)

Arguments

...

One or more fitted TAM objects (as returned by fit_tam()). Supply these or model_list, not both.

model_list

A named list of fitted TAM objects. Required to be named; the names are used as label values.

interval

Confidence level passed to tidy_pop() and tidy_par() for interval construction. Default 0.95.

label

Character scalar giving the label column name to add when stacking across multiple/named models. Default "model".

label_type

Controls how the label column is coerced. One of:

  • "auto" (default): numeric when possible, else character.

  • "numeric": force numeric conversion (with NA for non-numeric).

  • "character": keep as character.

  • "factor": convert to factor.

process_residuals

Calculate joint-sample process diagnostics? Use FALSE for lightweight consumers that need only existing fitted summaries.

process_seed

Non-negative integer seed for a reproducible local Gaussian joint sample. Default 123456L; the caller's RNG state is restored.

Value

A named list of stacked tables, with formula_effects when present:

  • obs_pred — a named list of stacked data frames (e.g., catch, index);

  • pop — a named list of stacked data frames (e.g., ssb, N, M, mu_M, F, mu_F, Z, …);

  • deviations — signed N/F/M process tables, using annual increments for RW processes and mean deviations for IID/AR1. M rows represent unique state blocks. These point estimates exclude unpenalized RW boundary rows.

  • process_residuals — standardized joint-sample recruitment, N, F and M tables when available. est contains the diagnostic draw and fitted the standardized innovation at the fitted mode. A status table records each model's calculation status, explanation, seed and method. Disabled processes, projections and unpenalized boundaries have no rows. M coordinates represent unique state blocks, with state_block giving their order. Missing or invalid joint precision produces a warning and an unavailable status, retaining fitted deviations without fabricating draws.

  • patterns — population and mortality age-year tables for plot_matrix(). Compatible units follow the first fitted model's displayed metric units, including explicit reference conversions. Unspecified fitted units remain unspecified; reference tables with unknown units remain missing;

  • recruitment — predictions, residuals and optional stock-recruit curves; see tidy_recruitment();

  • fixed_par — a single stacked data frame of fixed-effect parameters with columns like par, est, se, lwr, upr, plus indices (e.g., coef, year, age) and the label column when applicable;

  • random_par — a named list of stacked data frames, one per random-effect block, each with the same schema as fixed_par plus block-appropriate indices.

  • formula_effects — signed Gaussian q, F/M mean and log observation-SD effect levels, RW increments and numeric-by contributions, grouped by term. Intervals use their joint fitted uncertainty; the zero RW anchor is explicitly marked as fixed. smooths contains complete centered smooth functions, including their unpenalized directions, with joint uncertainty on the log F/q-link scale. Log-q and logit-q functions are kept in separate entries. Basis coefficient tables identify basis indices, which are not biological ages or years.

Details

Inputs: Pass models through ... or via model_list =. Precomputed assessment reference objects of class tam_ref are also accepted. Their existing tables and uncertainty are retained without constructing a tinyAM optimizer. A tam_ref may contain a named comparison_scales vector; those factors are applied to the matching tinyAM population estimates and uncertainty so the combined tables use the reference's units.

  • If ... supplies one model, no label column is added.

  • If ... supplies >1 model, a label column is added using the object/expression names from ....

  • If model_list is used, it must be a named list; its names are always used as labels (even when length 1).

Names (from ... or model_list) are passed through utils::type.convert() with as.is = TRUE, so numeric-like labels (e.g. "2010", "2011") become numeric.

Components present in any model are stacked; columns missing from particular models are filled with NA values so diagnostics like one-step-ahead residuals survive stacking. Parameter summaries are stacked separately for fixed and random effects: fixed effects in a single data frame; random effects as a named list of data frames (one per random-effect block, e.g. "log_f", "log_r", …).

Process diagnostics

Innovations are whitened using the fitted IID, RW, age-correlated RW or separable AR1 distribution, including stationary boundaries and age-specific SDs. All predictions are recomputed through the fitted population code. One Gaussian parameter perturbation from the stored joint precision is propagated through the automatic-differentiation Jacobian of those innovations. This SAM-style local Gaussian approximation retains covariance across components without constructing a dense residual covariance matrix. Results for a model do not depend on which other models are supplied or their order. See plot_process_deviations() and plot_process_residuals() for reusable viewers of the same tables.

Examples

fit <- fit_tam(
  cod_obs,
  years = 1983:2024,
  ages = 2:14,
  N_settings = list(process = "iid", init = "exp"),
  F_settings = list(process = "rw", mu_form = NULL),
  M_settings = list(process = "off", mu_supplied = ~ I(0.3)),
  catch_settings = list(sd_form = ~ 1),
  index_settings = list(sd_form = ~ 1, q_form = ~ q_block),
  silent = TRUE
)
# Single model: no label column added
fit1 <- fit
tabs1 <- tidy_tam(fit1)
names(tabs1)
#> [1] "obs_pred"          "osa"               "pop"              
#> [4] "patterns"          "fixed_par"         "random_par"       
#> [7] "recruitment"       "deviations"        "process_residuals"
head(tabs1$fixed_par)
#>        par        coef year age          unit          est          lwr
#> 1       r0        <NA> 1983   2 thousand fish 4.859111e+05 3.909536e+05
#> 2     sd_r        <NA>   NA  NA          <NA> 4.972649e-01 3.668274e-01
#> 3     sd_f        <NA>   NA  NA          <NA> 4.932985e-01 4.298799e-01
#> 4     sd_n        <NA>   NA  NA          <NA> 5.951395e-01 5.306665e-01
#> 5 sd_catch (Intercept)   NA  NA          <NA> 3.814101e-01 3.007537e-01
#> 6 sd_index (Intercept)   NA  NA          <NA> 4.282125e-01 3.722307e-01
#>            upr         se se_scale is_proj
#> 1 6.039325e+05 0.11093916      log   FALSE
#> 2 6.740836e-01 0.15522297      log      NA
#> 3 5.660731e-01 0.07020984      log      NA
#> 4 6.674457e-01 0.05850218      log      NA
#> 5 4.836969e-01 0.12121827      log      NA
#> 6 4.926138e-01 0.07148390      log      NA

# Two models via ...: label uses object names
fit2 <- update(fit1, years = 1983:2023)
tabs2 <- tidy_tam(fit1, fit2)
head(tabs2$obs_pred$catch)      # contains column "model"
#>   model year age obs          unit F_y_block F_a_block is_proj      pred
#> 1  fit1 1983   2  18 thousand fish 1954-1991       2-3   FALSE 13.281992
#> 2  fit1 1984   2   3 thousand fish 1954-1991       2-3   FALSE  4.438363
#> 3  fit1 1985   2   0 thousand fish 1954-1991       2-3   FALSE  2.539587
#> 4  fit1 1986   2   1 thousand fish 1954-1991       2-3   FALSE  2.211582
#> 5  fit1 1987   2  42 thousand fish 1954-1991       2-3   FALSE 18.146481
#> 6  fit1 1988   2  25 thousand fish 1954-1991       2-3   FALSE 21.066685
#>          sd    std_res
#> 1 0.3814101  0.7969445
#> 2 0.3814101 -1.0269088
#> 3 0.3814101         NA
#> 4 0.3814101 -2.0809837
#> 5 0.3814101  2.2002381
#> 6 0.3814101  0.4488161
head(tabs2$fixed_par)           # fixed effects stacked with "model"
#>   model      par        coef year age          unit          est          lwr
#> 1  fit1       r0        <NA> 1983   2 thousand fish 4.859111e+05 3.909536e+05
#> 2  fit1     sd_r        <NA>   NA  NA          <NA> 4.972649e-01 3.668274e-01
#> 3  fit1     sd_f        <NA>   NA  NA          <NA> 4.932985e-01 4.298799e-01
#> 4  fit1     sd_n        <NA>   NA  NA          <NA> 5.951395e-01 5.306665e-01
#> 5  fit1 sd_catch (Intercept)   NA  NA          <NA> 3.814101e-01 3.007537e-01
#> 6  fit1 sd_index (Intercept)   NA  NA          <NA> 4.282125e-01 3.722307e-01
#>            upr         se se_scale is_proj
#> 1 6.039325e+05 0.11093916      log   FALSE
#> 2 6.740836e-01 0.15522297      log      NA
#> 3 5.660731e-01 0.07020984      log      NA
#> 4 6.674457e-01 0.05850218      log      NA
#> 5 4.836969e-01 0.12121827      log      NA
#> 6 4.926138e-01 0.07148390      log      NA
names(tabs2$random_par)         # e.g. "log_f", "log_r", ...
#> [1] "log_f" "log_r" "log_n"
head(tabs2$random_par$log_f)    # random block stacked with "model"
#>   model par year age unit          est          lwr          upr        se
#> 1  fit1   f 1983   2 <NA> 3.163951e-05 1.619098e-05 6.182817e-05 0.3418188
#> 2  fit1   f 1984   2 <NA> 1.902865e-05 9.263852e-06 3.908629e-05 0.3672649
#> 3  fit1   f 1985   2 <NA> 2.203581e-05 8.746427e-06 5.551718e-05 0.4714493
#> 4  fit1   f 1986   2 <NA> 2.551802e-05 1.171828e-05 5.556869e-05 0.3970659
#> 5  fit1   f 1987   2 <NA> 1.114730e-04 5.373377e-05 2.312556e-04 0.3723237
#> 6  fit1   f 1988   2 <NA> 1.196298e-04 5.844459e-05 2.448693e-04 0.3654775
#>   se_scale is_proj
#> 1      log   FALSE
#> 2      log   FALSE
#> 3      log   FALSE
#> 4      log   FALSE
#> 5      log   FALSE
#> 6      log   FALSE

# Named list: must be named; names used as labels (even length 1)
fits <- list(`2023` = fit2, `2024` = fit1)
tabs3 <- tidy_tam(model_list = fits, label = "retro_year")
head(tabs3$pop$N) # column "retro_year" has 2023/2024
#>   retro_year year age       est is_proj          unit
#> 1       2023 1983   2 488245.84   FALSE thousand fish
#> 2       2023 1984   2 265588.98   FALSE thousand fish
#> 3       2023 1985   2 130309.17   FALSE thousand fish
#> 4       2023 1986   2  97455.09   FALSE thousand fish
#> 5       2023 1987   2 187506.91   FALSE thousand fish
#> 6       2023 1988   2 201021.13   FALSE thousand fish