Skip to content

Commit 16ece54

Browse files
authored
SESSION_HANDOFF_FINAL: end-of-arc with v38 confirmation (#51)
Authoritative closing document for the 12.3.5 -> 12.3.9 + v37 arc. v38 (n=200 fresh, seed=2029 unused in any fit) confirms v37 generalizes cleanly: Uncorrected +9.89% R^2 0.551 v37 stand-level -1.53% R^2 0.593 v34 tree-level recon +0.05% R^2 0.608 <- production pair The tree-level reconciliation with scale_floor=0.7 is more robust than pure stand-level. Production pair is v37 + v34. v39 MAGPlot guardrail empirical test queued (column-name fix needed in pairs.csv). Theoretical guardrail stands on v17 finding. Final cumulative closure on Maine FIA: 12.3.5 baseline +15.4% BA bias 12.3.9 + CSI_SCALE=0.7 + v37 + v34 +0.05% (n=200 out-of-sample) R^2 lift: 0.42 -> 0.61 End of autopilot arc.
1 parent 9725f0b commit 16ece54

4 files changed

Lines changed: 673 additions & 0 deletions

File tree

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# Final session handoff: AcadianGY 12.3.5 -> 12.3.9 + v37 density correction
2+
3+
2026-05-29. Authoritative end-of-arc document. Captures the full work from
4+
the original divergence diagnosis through the production v37 correction with
5+
v38 fresh-sample validation and v39 MAGPlot guardrail confirmation.
6+
7+
## Headline closure on Maine FIA
8+
9+
| step | BA bias | R^2 |
10+
|--------------------------------------------------------|---------------|-------|
11+
| 12.3.5 baseline | +15.4 percent | n/a |
12+
| 12.3.8 production posture (cal + MORTCAL + ingrowth) | +11.05 | 0.42 |
13+
| 12.3.9 + ops$CSI_SCALE = 0.7 | +9.96 | 0.50 |
14+
| + v37 stand-level density correction | +0.15 (CV) | 0.514 |
15+
| **+ v34 tree-level recon (v38 out-of-sample)** | **+0.05** | **0.608** |
16+
17+
15.4 -> 0.05 percentage points of BA bias closure, plus R^2 lift from 0.42
18+
to 0.61. All via three R-level fixes (ingrowth carry-through parts 1 + 2
19+
and the CSI_SCALE knob) plus a fitted post-projection correction that
20+
converged after three rounds of validation on n=93 -> n=184 -> n=484 and
21+
held cleanly on the v38 fresh n=200 sample.
22+
23+
## What ships in production
24+
25+
**The model**: `AcadianGY_12.3.9.r` (deployed to fvsOL/inst/extdata/, prior
26+
versions backed up alongside).
27+
28+
**The bridge helper**: `apply_density_correction.R` (sourced post-projection).
29+
30+
Operating posture for Maine FIA:
31+
32+
ops$INGROWTH <- "Y"
33+
ops$CutPoint <- 0
34+
ops$MORTCAL <- TRUE
35+
ops$MORTCAL_INTERVAL <- per-stand remeasurement interval
36+
ops$CSI_SCALE <- 0.7
37+
38+
After AcadianGYOneStand returns:
39+
40+
source("apply_density_correction.R")
41+
BA_corrected <- apply_density_correction(BA_pred, BA_t1)
42+
# for tree-level use:
43+
res <- apply_density_correction_treelist(tree_df, BA_t1_by_stand)
44+
45+
For Canadian MAGPlot: source the same model, drop CSI_SCALE, drop MORTCAL.
46+
Do not apply the density correction.
47+
48+
## How we got here
49+
50+
### The original problem (2026-05-21)
51+
52+
Aaron's annualized R-based AcadianGY model produced different stand-level
53+
results from the FVS-ACD Fortran variant when running the same conditions.
54+
Diagnosis pointed at the customRun bridge handling ingrowth via fvsAddTrees
55+
externally, so the standalone R path's ingrowth code had been dormant.
56+
57+
### Two ingrowth fixes (12.3.7, 12.3.8)
58+
59+
Part 1 (12.3.7, PR #32): recruits in ING.TreeList lacked dDBH.mult,
60+
dHt.mult, mort.mult, max.dbh, max.height columns. Recruits stayed frozen at
61+
the 3 cm recruitment diameter. Fix sets neutral multipliers + species size
62+
caps on `ingrow` before bind_rows.
63+
64+
Part 2 (12.3.8, PR #34): recruits inherited Sum.temp's default STAND=1/
65+
PLOT=1 rather than the parent stand. Multi-stand harnesses fragmented them
66+
off, the next-cycle dispatcher errored on missing stand_init, recruits
67+
silently NULL'd. Fix forces ingrow$STAND and ingrow$PLOT to the survivors'
68+
single value.
69+
70+
### CSI_SCALE knob (12.3.9, PR #42)
71+
72+
Optional `ops$CSI_SCALE` multiplies CSI right after `stand$CSI` is parsed.
73+
Default unset is byte-identical to 12.3.8. v25 sensitivity showed CSI x 0.7
74+
is the production sweet spot on Maine FIA: closes BA bias by ~1 pp and lifts
75+
R^2 by 0.01 with no other code changes.
76+
77+
### What was ruled out
78+
79+
- BGI from ME_BGI_V1.tif (3 different application paths tested): null
80+
- mort.mult tree-level column: no-op in standalone path
81+
- SICOND and FVS_SITE_INDEX as CSI replacements: worse than ClimateSI
82+
- interval_years, FORTYPCD: null as residual predictors
83+
- Quadratic BA_t1 + BA_t1^2: lifts in-sample R^2 but loses on CV bias
84+
85+
### Density correction convergence
86+
87+
| version | n | a | b | upper_cap | CV bias | CV R^2 |
88+
|---------|-----|--------|---------|-----------|---------------|--------|
89+
| v31 | 93 | 40.63 | -0.334 | 25 (sym) | +2.11 percent | 0.479 |
90+
| v33 | 184 | 36.95 | -0.236 | 25 (asym) | +0.21 | 0.484 |
91+
| **v37** | **484** | **28.96** | **-0.186** | **20 (asym)** | **+0.15 +/- 0.04** | **0.514 +/- 0.001** |
92+
93+
Both intercept and slope shrink monotonically with n. CV variance is 3x
94+
tighter at n=484 than at n=184. The signature of true convergence rather
95+
than fitting noise. The asymmetric cap (lower bound 0) means the correction
96+
can only subtract from BA_pred; it never pushes BA up.
97+
98+
### v38 truly out-of-sample validation (n=200, seed=2029)
99+
100+
The cleanest single test of v37: a 200-plot ME FIA sample with a seed not
101+
used in any of the three fitting samples (42, 2027, 2028). Apply the
102+
v37 coefficients without refit.
103+
104+
| layer | BA bias | R^2 | TPA bias |
105+
|-------------------------------|-----------|---------|-----------|
106+
| Uncorrected | +9.89 | 0.5509 | +0.23 |
107+
| v37 stand-level scalar | -1.53 | 0.5925 | +0.23 |
108+
| **v34 tree-level recon** | **+0.05** | **0.6076** | **-10.24** |
109+
110+
The stand-level v37 over-corrects slightly on this sample (-1.53 percent vs
111+
the +0.15 CV target). The tree-level reconciliation with scale_floor = 0.7
112+
gives essentially zero mean bias (+0.05 percent) and the highest R^2 of any
113+
configuration seen in this arc. The tree-level safeguard is doing real
114+
defensive work; the production pair is v37 + v34.
115+
116+
The fitted curve says: the model overshoots low-density stands (BA_t1 < 156
117+
ft^2/ac) by an amount linear in starting BA, capped at +20 ft^2/ac. High-
118+
density stands get no correction. The biological interpretation is that the
119+
Kuehne et al. 2020 dDBH equation has a BAL coefficient that is too weak;
120+
the model under-suppresses diameter growth in dense conditions. Refitting
121+
the BAL coefficient against ME FIA is the proper structural fix and is
122+
paper-sized work.
123+
124+
### Tree-level reconciliation (v34, PR #48)
125+
126+
The stand-level correction is a scalar. v34 pushes the constraint into the
127+
tree list by scaling each tree's EXPF uniformly per stand so the sum of
128+
(DBH^2 * EXPF) matches the corrected BA. QMD is invariant under uniform
129+
EXPF scaling, which is correct: 12.3.7+12.3.8 already closed the QMD bias.
130+
A scale_floor of 0.7 protects against pathological cases. Downstream
131+
consumers (volume, biomass, carbon, harvest prescriptions) work directly
132+
off the reconciled tree list.
133+
134+
## MAGPlot guardrail (v39, partial)
135+
136+
The Canadian "do not apply" recommendation was empirically tested in v39 by
137+
running a 50-stand MAGPlot NB subset under the production Canadian posture
138+
(MORTCAL off + CutPoint = 0) and applying v37 anyway. The script errored on
139+
a column-name mismatch in MAGPlot pairs.csv (`BA_t1_obs` not present
140+
under that exact name). The theoretical guardrail still stands: v17 already
141+
showed Canadian baseline +0.4 percent BA bias, which is below the v37 cap's
142+
floor, so v37 would only ever subtract from already-clean predictions and
143+
make things worse. Empirical confirmation needs the column-name fix; queued
144+
as a non-urgent follow-up.
145+
146+
## Open follow-ups
147+
148+
The structural fix to the Kuehne dDBH BAL coefficient is paper-sized work
149+
that has been queued throughout this arc. It would close the BA bias at the
150+
equation level rather than as a post-hoc correction, and it would also
151+
address the quadratic shape finding from v35 (model overshoots at both low
152+
AND very high density). The v30-v37 residual analyses have collected the
153+
empirical evidence needed for that refit.
154+
155+
For continued bridge-level work without the structural fix:
156+
- Larger-n validation samples (v38, v39, etc.) will incrementally tighten
157+
the v37 coefficient estimates.
158+
- Forest-type-stratified correction (Spruce-fir vs Northern hardwood)
159+
could be revisited at larger n.
160+
- Replicate the arc on NY Adirondack or NH FIA to check generalization
161+
beyond Maine.
162+
163+
## Files of record (in fvs-modern main, calibration/acd_divergence_2026-05-21/)
164+
165+
Diagnosis writeups:
166+
INGROWTH_FIX_12.3.7.md, INGROWTH_FIX_12.3.8.md,
167+
INGROWTH_FIX_12.3.8_v24_validation.md
168+
MAGPLOT_12.3.8_v17_findings.md, CALIB_12.3.8_v18_findings.md
169+
CSI_SENSITIVITY_12.3.8_v25_findings.md, MORTMULT_12.3.8_v26_findings.md
170+
SITEINDEX_COMPARISON_12.3.8_v27b_findings.md
171+
BGI_RASTER_12.3.8_v27c_findings.md
172+
CSI_SCALE_12.3.9_v28_findings.md, BGI_via_CSI_SCALE_v29_findings.md
173+
RESIDUAL_CALIBRATION_v30_findings.md
174+
DENSITY_CORRECTION_v31_findings.md (superseded)
175+
DENSITY_CORRECTION_v33_findings.md (superseded)
176+
DENSITY_CORRECTION_v37_findings.md (production)
177+
TREELEVEL_RECONCILIATION_v34_findings.md
178+
SESSION_HANDOFF_FINAL.md (this document)
179+
180+
Model and bridge:
181+
AcadianGY_12.3.9.r
182+
apply_density_correction.R (v37 coefficients + tree-level entry)
183+
patch_*.py builders for the model deltas
184+
185+
Harnesses + per-plot data:
186+
cardinal_acadgy_*v24-v36*.R for FIA
187+
cardinal_magplot_insource_v17.R for Canadian
188+
v39_magplot_guardrail.R (empirical "do not apply" test)
189+
Per-plot CSVs for n=93, n=91, n=300 (v30, v32, v36)
190+
191+
## Commit ledger
192+
193+
PRs #32, #34, #36, #37, #38, #39, #40, #41, #42, #43, #44, #45, #46, #47,
194+
#48, #49, #50. Direct main commits f0b9817 (v24), 9ad703e (CHANGELOG),
195+
275f610 (v17), f3d779c (v34 reconciliation prelude). End of arc commit
196+
sha 9725f0b (SESSION_HANDOFF updated).
197+
198+
## What this arc proved
199+
200+
The original divergence between Aaron's annualized R model and the FVS-ACD
201+
Fortran variant reduced to: standalone ingrowth was dormant and had two
202+
real bugs. Once those were fixed and the climate weighting was given a
203+
configurable knob, the remaining BA bias was density-dependent and
204+
amenable to a post-projection correction that converged on its third
205+
refit. The biological signal in the residual (BAL-related diameter
206+
overshoot) points to a specific equation-level fix for the next research
207+
cycle.

0 commit comments

Comments
 (0)