Skip to content

Forest carbon growth-curve update, other-planted forest pool, and satellite forest ages - #917

Draft
flohump wants to merge 10 commits into
magpiemodel:developfrom
flohump:f_regrowth_refit
Draft

Forest carbon growth-curve update, other-planted forest pool, and satellite forest ages#917
flohump wants to merge 10 commits into
magpiemodel:developfrom
flohump:f_regrowth_refit

Conversation

@flohump

@flohump flohump commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

🐦 Description of this PR 🐦

This PR replaces MAgPIE's modelled forest growth curves with observation-based ones, adds an "other planted" forest pool matching the FRA 2025 taxonomy, and adds a satellite forest-age dataset — together with the mechanism change that lets a realistic carbon curve coexist with the FRA wood calibration.

1. Observation-based forest growth curves

MAgPIE's forest carbon growth curves are currently a process-model output (Braakhekke et al. 2019). This PR replaces them with observation-based curves, one per forest type — naturally regrowing forest (Robinson et al. 2025, global regrowth data), timber plantations (Bukoski et al. 2022, global plantation-plot database), and other planted forest (new curve, derived from the naturally-regrowing one). They grow faster and more realistically in the early decades, especially plantations and boreal forest; the mature-carbon level (asymptote) is unchanged — only the growth shape. (central figure below) The legacy Braakhekke curves remain selectable via c52_growth_par_source = braakhekke (other-planted forest, which those curves predate, then falls back to naturally regenerating forest). Note this applies the old curve shape inside the new framework — a sensitivity option, not a full revert to develop's behaviour.

2. Other-planted forest as its own pool

The FRA 2025 taxonomy distinguishes naturally regenerating → other planted → plantation forest. This other-planted forest — the planted forest present at model initialisation that is not an intensive plantation — already existed in MAgPIE, but it was not harvestable and was wrongly assigned to the NPI/NDC afforestation category (a policy-afforestation label, not an observed forest type). This PR promotes it to its own harvestable pool with its own growth curve, correctly separated from policy-driven afforestation. Planted forest is now split into Timber (plantations) and Other Planted across the land pools, reporting, and validation.

3. Satellite forest ages (GAMI)

The forest age-class distribution sets how much young vs. mature forest the model starts with — and therefore how much regrowth carbon it can credit. It currently comes from GFAD (Poulter et al. 2019). This PR adds the GAMI global forest-age dataset (Besnard et al. 2024, satellite-derived) as the new default age-class source (c28_ageclass_source); GFAD remains selectable (c28_ageclass_source = gfad). Globally the two carry the same total forest area but a different age shape: GFAD is strongly bimodal (most forest in the youngest 0–10 yr class or the >140 yr old-growth pool), while GAMI shifts area toward the middle age classes. (comparison figure below) Shipped via pik-piam/mrmagpie#66.

4. Separating the wood calibration from the carbon curve

One growth curve currently sets both a forest's carbon and its harvestable wood, and its rate was tuned (k-bisection) so the wood matched the FRA growing-stock (timber) target — bending the carbon curve to fit a wood target. This PR keeps one realistic carbon curve for all forest and meets the FRA wood target separately, with a per-region wood-only multiplier on the harvestable growing stock; carbon is never touched. Across the 12 regions this multiplier stays order-one — 0.5–3.3 for naturally regrowing forest and 0.3–1.6 for plantations — with a single arid outlier (MEA, which has almost no forest: 8.3 and 3.6). It reconciles the realistic-curve growing stock with the regional FRA timber target, not a large or arbitrary rescaling. That makes the old work-arounds obsolete — the k-bisection calibration, the "natural-origin" secondary-forest blend and harvest floor, and the young-secondary-forest harvest loophole.

5. Plantation rotation from an external table

Plantation harvest rotation used to be derived from the growth curve itself, via the current-annual-increment (CAI) criterion — cut at the age where the curve's annual increment peaks. That only worked while a single curve stood in for both a stand's carbon and its merchantable wood. Two reasons it no longer does: (i) the optimal age to cut a plantation is set by the growth of its merchantable wood volume, and total biomass carbon accumulates on a different shape and timescale than merchantable stem volume, so the carbon-increment peak is not the wood-increment peak; and (ii) once wood is calibrated separately from carbon (point 4), the carbon curve carries no wood signal left to optimise a rotation against. Rotation is therefore now an explicit input — a per-Köppen table of plantation rotation lengths (f32_plant_rotation.cs4; ~15 yr tropical, ~30 temperate, ~60 boreal) that sets both the cellular and regional rotation directly, consistent with the FAO-validated ranges reported by Mishra et al. 2021.

6. Removed the minimum carbon-price floor

MAgPIE applied a small floor to the carbon price in every timestep (s56_minimum_cprice, 3.67 USD/tC) to dampen sudden year-to-year jumps in carbon-stock change. As a side effect, that floor suppressed historical deforestation. This PR sets it to 0, giving more realistic historical land-use change. The jump-damping the floor provided is now handled in reporting instead, by the legacy land-clearing reframe in magpie4 (which spreads land-clearing emissions over a decay tail — see the companion PR below). ⚠ This changes calibrated historical land-use change — flagged for review.

Input data: ships as preprocessing rev4.133 (FRA2025 forest data + the new growth curves via additional_data; GAMI ages via mrmagpie).

Validation: compiles clean (codeCheck); 4 test runs (develop vs. this PR × NPi + PkBudg650) solve to 2100. The realistic curves roughly triple the mid-century land-carbon sink under mitigation (PkBudg650, 2050: −5.4 vs −1.7 GtCO2/yr).

Companion PRs:

Suggested label: High risk (changes a model default and a core mechanic).

Figures

growth_curves_old_vs_new gami_vs_gfad

Comparison, develop vs. this PR:

01_Emissions-CO2-Land-Land-use-Change_global 02_Resources-Land-Cover-Cropland_global 03_Resources-Land-Cover-Pastures-and-Rangelands_global 04_Resources-Land-Cover-Forest_global 05_Resources-Land-Cover-Other-Land_global 06_Productivity-Landuse-Intensity-Indicator-Tau_global 11_Resources-Land-Cover-Forest-Planted-Forest_global

🔧 Checklist for PR creator 🔧

If a point is not applicable, check the checkbox anyway and write "non-applicable" next to the checkbox.

  • Label pull request from the label list.

    • Low risk: Simple bugfixes (missing files, updated documentation, typos) or changes in start or output scripts
    • Medium risk: Uncritical changes in the model core (e.g. moderate modifications in non-default realizations)
    • High risk: Critical changes in model core or default settings (e.g. changing a model default or adjusting a core mechanic in the model)
  • Self-review own code

    • No hard coded numbers and cluster/country/region names.
    • The new code doesn't contain declared but unused parameters or variables.
    • magpie4 R library has been updated accordingly and backwards compatible where necessary.
    • scenario_config.csv has been updated accordingly (important if default.cfg has been updated)
  • Document changes

    • Add changes to CHANGELOG.md
    • Where relevant, put In-code documentation comments
    • Properly address updates in interfaces in the module documentations
    • run goxygen::goxygen() and verify the modified code is properly documented
  • Perform test runs

    • Low risk:
      • Run a compilation check via Rscript start.R --> "compilation check"
    • Medium risk:
      • Run default run via Rscript start.R --> "default"
      • Check logs for errors/warnings
      • Fill in performance section below
    • High risk:
      • Run test runs via Rscript start.R --> "test runs"
      • Check logs for errors/warnings
      • Default run from the PR target branch for comparison
      • Provide relevant comparison plots (land-use, emissions, food prices, land-use intensity,...)
      • Fill in performance section below
  • Reporting produces no errors and no new warnings
    3 warnings regarding the piaminterfaces mapping will be fixed after approval and before merging the PR

  • Get two approving reviews (at least one from RSE)

📉 Performance 📈

  • This PR's default : ~33 mins (NPi / PkBudg650 test runs, coup2100)
  • For comparison: runtimes of weekly test

🚨 Checklist for reviewer 🚨

  • PR is labeled correctly
  • Code changes look reasonable
    • No hard coded numbers and cluster/country/region names.
    • No unnecessary increase in module interfaces
    • model behavior/performance is satisfactory.
  • Changes are properly documented
    • CHANGELOG is updated correctly
    • Updates in interfaces have been properly addressed in the module documentations
    • In-code documentation looks appropriate

flohump added 9 commits July 28, 2026 12:31
MAgPIE derived a forest's carbon stock and its harvestable wood from a
single growth curve, so the FRA growing-stock (wood) calibration bent the
carbon curve. This keeps one realistic carbon curve for all forest and meets
the FRA wood target with a per-region, wood-only multiplier (lambda); carbon
is never bent.

- 52_carbon: replace the k-bisection calibration with an analytic wood-only
  lambda (natural forest weighted by the GFAD age distribution, plantations
  sampled at the cellular rotation age). Carbon densities keep the realistic
  three-curve growth parameters for naturally regenerating / other planted /
  plantation forest (f52_growth_par_3curve.csv). Add a wood-only niche floor
  for arid divide-by-near-zero cells (s52_gs_niche_floor).
- 14_yields: scale the growing stock by lambda before the harvest floors;
  carbon is untouched.
- 35_natveg: remove the natural-origin carbon blend and the natural-origin
  harvest floor (collapse to the single realistic curve); keep the WDPA
  conservation floor. Keep the ac35 young-secondary proxy.
- 32_forestry: other-planted forest becomes its own harvestable pool; the
  plantation rotation comes from an external per-Koeppen table
  (f32_plant_rotation.cs4) and the curve-derived rotation machinery
  (CAI/MAI/Faustmann) is retired.
- 28_ageclass: add GAMI v2.1 (Besnard et al. 2024) as an age-class source
  option (c28_ageclass_source, default gami); the GFAD path is unchanged.
- 56_ghg_policy: remove the minimum C-price floor (s56_minimum_cprice = 0),
  which had suppressed historical deforestation.

Input data ship via additional_data (f52_growth_par_3curve.csv,
f32_plant_rotation.cs4) and the preprocessing pipeline (forestageclasses_gami.cs3).
…s realization

Merging develop brought in the new dynRegPastrTau_apr26 realization of module 14,
which was branched from the pre-decouple managementcalib_aug19 and so still built
the harvestable growing stock the old (coupled) way: it computed im_growing_stock_ysf
from the uncalibrated secondary-forest curve and applied no wood-only lambda.

Mirror the decoupled wood block from managementcalib_aug19 into it so both
realizations of module 14 provide the same wood interface: scale the harvestable
growing stock by the module-52 multipliers (pm_lambda_pla / pm_lambda_nrf) and the
niche floor (pm_gs_niche_fac), and compute im_growing_stock_oplant for the
other-planted pool. Carbon densities are untouched. Without this, running
yields = dynRegPastrTau_apr26 would leave wood coupled to carbon and reference
im_growing_stock_oplant (consumed in module 32) without computing it.
The decouple's forestry inputs ship through the input-data pipeline: rev4.133
(regional/cellular/validation) carries the FRA2025 forest data and the GAMI
age-class dataset; additional_data rev4.68 carries the three-curve growth
parameters (f52_growth_par_3curve.csv) and the plantation rotation lengths
(f32_plant_rotation.cs4).

Note: rev4.133FH is an interim personal preprocessing build; re-point to the
official published revision before merge.
setScenario reads config/scenario_config.csv to set the per-rcp cellular
input tarball, overriding cfg$input in default.cfg. Bump its cellular row
from rev4.131 to rev4.133FH so it is consistent with the input-data revision
already committed to default.cfg (the config-hash is invariant across
revisions, only the prefix changes).

Note: rev4.133FH is an interim personal preprocessing build; re-point to the
official published revision before merge (same as default.cfg).
… selectable

The observation-based 3-curve refit is the default (refit). Setting
c52_growth_par_source = braakhekke selects the legacy Braakhekke et al. 2019
curves; since those predate the other-planted forest type, other_planted
falls back to the naturally regenerating (natveg) curve. This uses the old
curve shape within the new (decoupled) framework, not a full revert.
The rev4.133 input data (mrland R36M414 coupled REMIND-MAgPIE runs) adds new
GHG-price and 2nd-gen bioenergy-demand scenarios. Regenerate the ghgscen56 (56)
and bioenergy-demand (60) scenario sets from the distributed input so they list
the new R36M414-* scenarios; existing R34M410-* scenarios are unchanged.
@flohump flohump added enhancement New feature or request Major Substantial modifications High risk Higher risk data update AI An AI model was used for this modification labels Jul 29, 2026
The forestry land-split mapping only covered {aff, ndc, plant}. With the new
other_planted forestry pool, landForestry() returns a fourth pool that was not in
the mapping, so toolAggregate aborted the forestry disaggregation and cell.land_split
was never written (breaking the gridded reportPBland/reportPBbiosphere/reportBII).
Fold other_planted into the NPiNDC grid category, consistent with the develop-branch
land split (where it was part of the ndc pool).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI An AI model was used for this modification data update enhancement New feature or request High risk Higher risk Major Substantial modifications

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant