---
title: "Growth estimation with linkages and priors"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteIndexEntry{Growth estimation with linkages and priors}
  %\VignetteEncoding{UTF-8}
---
  
```{r, include = FALSE}
  knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 5,
  eval = FALSE
  )
```
  
## Overview
  
This vignette demonstrates how to fit growth using Rceattle's built-in
von Bertalanffy and Richards growth functions, and how to use the
formula-driven `linkage_spec()` API to attach priors to growth
linkages.

We use the internal `whamGrowthData` dataset, which includes conditional
age-at-length data (`caal_data`) and the stock assessment data needed to
estimate growth parameters.

## Load data and inspect the growth dataset
  
```{r}
library(Rceattle)

data(whamGrowthData)
plot_data(whamGrowthData)

# The dataset includes CAAL data for the survey.
head(whamGrowthData$caal_data)

# Use logistic selectivity for all fleets in this example.
whamGrowthData$fleet_control$Selectivity <- "Logistic"
whamGrowthData$fleet_control$Selectivity_dimension <- "Length"
```
  
## Build a growth model with linkages
  
Rceattle supports growth linkages through `build_growth()` and
`linkage_spec()`. The linkage table can alter any von Bertalanffy growth
parameter such as `K`, `Linf`, or `L1` (natural-scale names; the default
`link = "log"` keeps the underlying TMB parameter on the log scale), and
it can also carry priors on the linked coefficients.
  
```{r}
# Create a simple environmental covariate for the example data.
set.seed(123)
yrs <- whamGrowthData$styr:whamGrowthData$endyr
whamGrowthData$env_data <- data.frame(
  Year = yrs,
  temp = rnorm(length(yrs), 0, 0.5)
)


growth_spec <- build_growth(
  fun = "vonBertalanffy",
  linkages = list(
    Linf = linkage_spec(
      formula = ~ temp,             # 2 columns: (Intercept) and `temp`
      by      = ~ species,          # one beta per (species, column)
      priors  = list(
        # Intercept prior is on natural-scale Linf (log link back-transforms).
        # Use lognormal() if you want a Normal on log(Linf) instead.
        "(Intercept)" = normal(85, 5),
        temp = normal(0, 0.1)) # Tight prior on the slope
    )
  )
)

```

### What this linkage does

- `formula = ~ temp` fits an intercept and a temperature slope.
- `by = ~ species + sex` gives each species/sex combination its own
intercept and slope.
- `link = "log"` (the default) keeps the underlying TMB parameter on the
log scale, so the slope rows act multiplicatively on natural `Linf`.
- `priors` attaches a Normal prior to both the intercept and the
temperature slope.

The prior on `(Intercept)` is effectively a prior on the base
`Linf` value (natural scale, because the default log link is back-transformed
inside the prior block), and intercept-bearing linkages replace the base
parameter and carry its level.

## Fit the model

```{r}
vbgf_prior_fit <- fit_mod(
  data_list   = whamGrowthData,
  growthFun   = growth_spec,
  estimateMode = 0,
  msmMode     = 0,
  fit_control = fit_control(verbose = 0, phase = FALSE)
)
summary(vbgf_prior_fit)
```

## Inspect the linkage table and prior contributions

```{r}
# The linkage table is stored on the fitted model.
vbgf_prior_fit$data_list$linkage_table

# The design matrix used by the linkages.
head(vbgf_prior_fit$data_list$linkage_X)

# Prior contribution appears in the joint NLL components.
vbgf_prior_fit$quantities$jnll_comp["Linkage-table priors", ]
```

## Compare with an unlinked baseline model and Richards model

```{r}
baseline_fit <- Rceattle::fit_mod(
  data_list = whamGrowthData,
  inits = NULL,       # Initial parameters at default
  estimateMode = 0,   # Estimate
  growthFun = build_growth(fun = "vonBertalanffy"), # Von Bert
  random_rec = FALSE, # No random recruitment
  msmMode = 0,        # Single species mode
  initMode = "NonEquilibrium",       # Unfished disequilibrium
  fit_control = fit_control(phase = FALSE, verbose = 1))


richards_model <- Rceattle::fit_mod(
  data_list = whamGrowthData,
  inits = NULL, # Initial parameters from above
  estimateMode = 0,   # Estimate
  growthFun = build_growth(fun = "Richards"), # Richards
  random_rec = FALSE, # No random recruitment
  msmMode = 0,        # Single species mode
  initMode = "NonEquilibrium",       # Unfished disequilibrium
  fit_control = fit_control(phase = FALSE, verbose = 1))



plot_biomass(
  list(baseline_fit, richards_model, vbgf_prior_fit),
  species = 1,
  model_names = c("Baseline VBGF", "Richards", "VBGF with K linkage and priors"),
  incl_proj = TRUE
)

baseline_fit$opt$AIC
vbgf_prior_fit$opt$AIC
```

## Notes on priors through linkages

- A prior on `"(Intercept)"` in a growth linkage is a prior on the
base growth parameter value itself.
- A prior on a covariate column such as `temp` constrains the effect of
that driver on the parameter.
- The linkage table API supports all R-style formulas and per-species
or per-sex stratification.
- The SD endpoints `sd_L1` and `sd_Linf` (the length-at-age SDs anchored
at `L1` and `Linf`, stored internally on the log scale via `growth_log_sd`)
are linkage targets too -- they thread `init` / `bounds` / `priors` onto
`growth_log_sd`. Only intercept-bearing formulas (typically `~ 1`) are
honored; the SDs do not vary by year in `growth.hpp`, so slope rows have
no effect and slope-only formulas error. See the "Growth SD endpoints"
section of `vignette("environmental-linkages-and-priors")` for an example.
