Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@ patch_*.sh
repair_*.sh
inspect_*.sh
remove_*.sh
#logs
examples/NMFS/*/outputs/*.log
# Editors
Binary file added a.out
Binary file not shown.
20 changes: 20 additions & 0 deletions a.out.dSYM/Contents/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleIdentifier</key>
<string>com.apple.xcode.dsym.a.out</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>dSYM</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
Binary file added a.out.dSYM/Contents/Resources/DWARF/a.out
Binary file not shown.
5 changes: 5 additions & 0 deletions a.out.dSYM/Contents/Resources/Relocations/aarch64/a.out.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
triple: 'arm64-apple-darwin'
binary-path: a.out
relocations: []
...
63 changes: 63 additions & 0 deletions add_laplace_result_component_fields.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env bash
set -euo pipefail

FILE="core/laplace.hpp"

if [[ ! -f "$FILE" ]]; then
echo "ERROR: $FILE not found. Run this from the Quadra repo root."
exit 1
fi

STAMP="$(date +%Y%m%d_%H%M%S)"
BACKUP="${FILE}.before_laplace_result_component_fields.${STAMP}"
cp "$FILE" "$BACKUP"
echo "Backed up $FILE to:"
echo " $BACKUP"

python3 - <<'PY'
from pathlib import Path
import re

path = Path("core/laplace.hpp")
text = path.read_text()

if "joint_objective" in text and "laplace_logdet" in text and "laplace_constant" in text:
print("LaplaceResult component fields already appear to exist. No patch needed.")
raise SystemExit(0)

m = re.search(
r'(template\s*<\s*typename\s+Model\s*>\s*\n\s*struct\s+LaplaceResult\s*\{)',
text
)
if not m:
m = re.search(r'(struct\s+LaplaceResult\s*\{)', text)

if not m:
raise RuntimeError("Could not find struct LaplaceResult in core/laplace.hpp")

insert_at = m.end()

fields = """\n
// Component breakdown of the Laplace objective:
//
// value = joint_objective + 0.5 * laplace_logdet - laplace_constant
//
// These are intentionally stored for diagnostics/reporting and for
// optimizer-side bookkeeping. They do not change the objective math.
double joint_objective = 0.0;
double laplace_logdet = 0.0;
double laplace_constant = 0.0;
"""

text = text[:insert_at] + fields + text[insert_at:]
path.write_text(text)
print("Inserted joint_objective, laplace_logdet, and laplace_constant into LaplaceResult.")
PY

echo
echo "Relevant LaplaceResult region:"
grep -n "struct LaplaceResult\|joint_objective\|laplace_logdet\|laplace_constant" "$FILE" | head -40

echo
echo "Done. Rebuild now:"
echo 'clang++ -std=c++17 -g -I"external/eigen/" examples/NMFS/sefsc_red_snapper/quadra/red_snapper_quadra_fit.cpp examples/NMFS/sefsc_red_snapper/quadra/red_snapper_age_structured.cpp'
191 changes: 191 additions & 0 deletions add_science_center_validation_roadmap_v1.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
#!/usr/bin/env bash
set -euo pipefail

echo "== Add science-center validation roadmap and SEFSC red-snapper scaffold =="

mkdir -p docs/validation
mkdir -p examples/NMFS/sefsc_red_snapper/{data,quadra,tmb,outputs,validation}

cat > docs/validation/science-center-example-roadmap.md <<'MD'
# Science Center Example Validation Roadmap

This document tracks a proposed validation suite with one representative assessment-style example from each NOAA Fisheries Science Center.

The goal is to build examples that are:
- public-data-safe or synthetic,
- reproducible,
- paired with TMB reference implementations where practical,
- documented with expected outputs,
- capable of reporting uncertainty, derived quantities, and projections.

## Proposed example set

| Science Center | Example | Status | Main validation target |
|---|---|---:|---|
| PIFSC | Opakapaka projection example | In progress | Projection validation and Level-1 uncertainty reporting |
| SEFSC | Red-snapper-style age-structured model | Scaffolded | Age structure, selectivity, recruitment deviations, projections |
| NEFSC | Groundfish/index-heavy assessment | Planned | Multiple indices, survey likelihoods, retrospective-style diagnostics |
| NWFSC | West Coast age-structured model | Planned | Age composition, selectivity, biological reference points |
| AFSC | Pollock/sablefish-style model | Planned | Recruitment deviations, state-space/random-effect scalability |
| SWFSC | CPS/tuna-style model | Planned | Time-varying dynamics, index scaling, projection scenarios |

## Shared validation requirements

Each example should eventually include:

1. Quadra implementation
2. TMB comparison implementation
3. synthetic or public-data-safe input data
4. reproducible runner
5. fit diagnostics
6. standard errors and confidence intervals
7. random-effect conditional uncertainty
8. derived quantity uncertainty
9. projection envelopes
10. comparison summary against TMB

## Recommended directory layout

```text
examples/<example_name>/
README.md
data/
quadra/
tmb/
outputs/
validation/
```

## Development order

1. Finish Opakapaka Level-1 uncertainty reporting.
2. Scaffold SEFSC red-snapper-style age-structured model.
3. Add minimal Quadra implementation.
4. Add TMB reference implementation.
5. Add validation summary and uncertainty outputs.
6. Repeat for the remaining science centers.
MD

cat > examples/NMFS/sefsc_red_snapper/README.md <<'MD'
# SEFSC Red-Snapper-Style Assessment Example

This directory is a placeholder for a synthetic, public-data-safe red-snapper-style assessment example.

The goal is not to reproduce an official assessment. The goal is to provide a representative SEFSC-style validation case for Quadra with age structure, selectivity, recruitment deviations, uncertainty reporting, and projections.

## Planned model features

- age-structured population dynamics
- catch likelihood
- survey/index likelihood
- age-composition likelihood
- recruitment deviations as random effects
- age-based selectivity
- derived quantities:
- biomass
- spawning biomass proxy
- depletion
- fishing mortality proxy
- MSY-like reference metrics
- projection scenarios
- uncertainty outputs:
- inverse Hessian / covariance
- standard errors
- confidence intervals
- random-effect conditional uncertainty
- derived quantity uncertainty
- projection envelopes

## Directory layout

```text
data/ synthetic or public-data-safe inputs
quadra/ Quadra implementation
tmb/ TMB reference implementation
outputs/ generated outputs, ignored by git
validation/ comparison summaries and validation notes
```

## Initial validation target

The first milestone is a minimal working model with:

1. deterministic age-structured dynamics,
2. one abundance index,
3. synthetic catch observations,
4. recruitment deviations,
5. TMB side-by-side comparison,
6. Level-1 uncertainty outputs.
MD

cat > examples/NMFS/sefsc_red_snapper/validation/validation_plan.md <<'MD'
# SEFSC Red-Snapper-Style Validation Plan

## Level 0: deterministic fit

- Build a minimal deterministic age-structured model.
- Fit fixed effects only.
- Confirm objective value and parameter estimates are stable.

## Level 1: random effects and uncertainty

- Add recruitment deviations as random effects.
- Extract conditional random-effect uncertainty.
- Add fixed-effect covariance and confidence intervals.
- Add derived quantity uncertainty.

## Level 2: TMB comparison

- Implement matching TMB reference model.
- Compare:
- objective value
- fixed-effect estimates
- random-effect modes
- standard errors
- derived quantities
- projection summaries

## Level 3: projections

- Add projection scenarios.
- Report projection envelopes.
- Compare Quadra and TMB projection outputs where feasible.

## Notes

This example should remain synthetic or public-data-safe. It should not be presented as an official red snapper assessment.
MD

cat > examples/NMFS/sefsc_red_snapper/data/README.md <<'MD'
# Data

Synthetic or public-data-safe input files will live here.

Do not commit generated outputs or confidential assessment data.
MD

cat > examples/NMFS/sefsc_red_snapper/quadra/README.md <<'MD'
# Quadra Implementation

Quadra model source files for the SEFSC red-snapper-style example will live here.
MD

cat > examples/NMFS/sefsc_red_snapper/tmb/README.md <<'MD'
# TMB Reference Implementation

TMB comparison files for the SEFSC red-snapper-style example will live here.
MD

cat > examples/NMFS/sefsc_red_snapper/outputs/.gitignore <<'EOF'
*
!.gitignore
EOF

echo
echo "Created:"
echo " docs/validation/science-center-example-roadmap.md"
echo " examples/NMFS/sefsc_red_snapper/"
echo
echo "Next:"
echo " git add docs/validation/science-center-example-roadmap.md examples/NMFS/sefsc_red_snapper"
echo " git commit -m \"Add science center validation roadmap and SEFSC scaffold\""
88 changes: 88 additions & 0 deletions add_sefsc_red_snapper_age_comp_likelihood_v1.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

p = Path("examples/NMFS/sefsc_red_snapper/quadra/red_snapper_quadra_fit.cpp")
s = p.read_text()

s = s.replace(
"""template <class T>
T logistic_selectivity_t""",
"""template <class T>
T age_comp_nll(const std::array<double, kAges>& observed,
const std::array<T, kAges>& predicted,
double effective_n,
double floor = 1.0e-12) {
T nll = T(0.0);
for (int a = 0; a < kAges; ++a) {
const auto i = static_cast<std::size_t>(a);
const double obs = std::max(observed[i], 0.0);
if (obs > 0.0) {
nll = nll - T(effective_n * obs) * log_t(max_t(predicted[i], floor));
}
}
return nll;
}

template <class T>
T logistic_selectivity_t""",
1)

s = s.replace(
""" const T sigma_log_catch = T(0.15);
const double min_positive = 1.0e-12;""",
""" const T sigma_log_catch = T(0.15);
const double age_comp_effective_n = 50.0;
const double min_positive = 1.0e-12;""",
1)

s = s.replace(
""" if (obs.catch_mt > 0.0) {
const T z = (log_t(T(obs.catch_mt)) -
log_t(max_t(catch_hat, min_positive))) /
sigma_log_catch;
nll = nll + T(0.5) * square_t(z);
}

std::array<T, kAges> next{};""",
""" if (obs.catch_mt > 0.0) {
const T z = (log_t(T(obs.catch_mt)) -
log_t(max_t(catch_hat, min_positive))) /
sigma_log_catch;
nll = nll + T(0.5) * square_t(z);
}

std::array<T, kAges> pred_age_comp{};
T selected_numbers_sum = T(0.0);
for (int a = 0; a < kAges; ++a) {
const auto i = static_cast<std::size_t>(a);
pred_age_comp[i] = n[i] * selectivity[i];
selected_numbers_sum = selected_numbers_sum + pred_age_comp[i];
}
for (int a = 0; a < kAges; ++a) {
const auto i = static_cast<std::size_t>(a);
pred_age_comp[i] =
pred_age_comp[i] / max_t(selected_numbers_sum, min_positive);
}

nll = nll + age_comp_nll(obs.age_comp, pred_age_comp,
age_comp_effective_n, min_positive);

std::array<T, kAges> next{};""",
1)

p.write_text(s)
PY

cat > examples/NMFS/sefsc_red_snapper/validation/age_composition_likelihood_checklist.md <<'MD'
# Age-Composition Likelihood Checklist

- [x] predicted selected age composition added
- [x] multinomial-style negative log likelihood added
- [x] fixed effective sample size added
- [ ] selectivity parameters estimated
- [ ] age-composition residuals written
- [ ] Dirichlet-multinomial alternative
MD
Loading
Loading