|
| 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