Skip to content

Improvements to the Slope-Based Carbon Price Rescale Algorithm (module 47)#2363

Draft
Renato-Rodrigues wants to merge 11 commits into
remindmodel:developfrom
Renato-Rodrigues:47_algorithm
Draft

Improvements to the Slope-Based Carbon Price Rescale Algorithm (module 47)#2363
Renato-Rodrigues wants to merge 11 commits into
remindmodel:developfrom
Renato-Rodrigues:47_algorithm

Conversation

@Renato-Rodrigues
Copy link
Copy Markdown
Member

@Renato-Rodrigues Renato-Rodrigues commented Jun 5, 2026

Purpose of this PR

This pull request introduces enhancements to the slope-based carbon price rescaling algorithm within the 47_regipol module. The changes aim to prevent convergence stalls, handle degenerate/noisy slopes in near-net-zero scenarios, and keep the price scaling process focused on the local abatement cost curve.

Changes

  1. Local Abatement Slope Window

    • Problem: Using a reference iteration that is too old doesn't accurately represent the local abatement cost curve due to shifts in the model state.
    • Solution: Introduced a max-history parameter s47_slopeMaxWindow (default 5 iterations). If the current iteration exceeds the reference iteration by more than this window, it falls back to SquareDev (squareDev_outsideWindow) to force a reset and keep the slope calculation local.
  2. Adaptive Upper Clamp Bound

    • Before: The code had a static maximum (least-negative) permitted value of -0.3 for clamping the Rescale Slope when the raw slope was too flat or positive.
    • Problem: A static clamp can cause convergence to stall indefinitely when the raw abatement slope is persistently flat or noisy.
    • Solution: Introduced an adaptive upper clamp bound that dynamically relaxes (halves) if the clamp is triggered in consecutive outer iterations at the same level:
      • 2× triggers at -0.3 → relax bound to -0.15 (next iteration)
      • 2× triggers at -0.15 → relax bound to -0.075 (next iteration)
      • 2× triggers at -0.075 → immediately override to SquareDev fallback (squareDev_adaptiveClamp), reset bound to -0.3, and reset the slope reference iteration.
      • Resets: The upper clamp bound resets to -0.3 if the upper clamp does not fire or when the reference iteration changes.
  3. Slope Degeneration Detection

    • Problem: If the change in emissions ($\Delta\text{Emi} = \text{Emi}{\text{current}} - \text{Emi}{\text{reference}}$) was extremely close to zero, then the calculated $\text{Slope}$ became a very small number (approaching $0$). In the next step, dividing by this near-zero slope blew up the $\text{RescaleFactor}$ to an extremely large value. This caused the carbon tax to make explosive, unrealistic jumps in a single iteration. Before this PR, the code only guarded against a zero price difference (division-by-zero in the slope step itself), but did not guard against a close to zero emissions difference. This could be happen in near-net-zero scenarios (e.g., when the target is net-zero and the current iteration is already very close to it), or if we have highly inelastic abatement zones (e.g. if a region is temporarily constrained by technology capacity limits like wind/solar expansion limits).
    • Solution: I introduced a degeneracy check based on a threshold parameter s47_slopeDegenerateThreshold (default 1% of the region's 2005 reference emissions). If the absolute change in emissions between the current iteration and the reference iteration is smaller than this threshold we:
      • Reject the slope and fallback the scaling type to the squared target deviation method for this iteration (squareDev_degenerateSlope). The reference iteration is also set to the current iteration so that subsequent iterations can try to calculate a fresh, non-degenerate slope.
  4. Code Robustness & Bug Fixes

    • Resolved index bugs in convergence iteration tracking.
    • Avoided potential division-by-zero errors when total net emissions are close to zero.

Type of change

Indicate the items relevant for your PR by replacing ◻️ with ☑️.
Do not delete any lines. This makes it easier to understand which areas are affected by your changes and which are not.

Parts concerned

  • ☑️ GAMS Code
  • ◻️ R-scripts
  • ☑️ Documentation (GAMS incode documentation, comments, tutorials)
  • ◻️ Input data / CES parameters
  • ◻️ Tests, CI/CD (continuous integration/deployment)
  • ◻️ Configuration (switches in main.gms, default.cfg, and scenario_config*.csv files)
  • ◻️ Other (please give a description)

Impact

  • ☑️ Bug fix
  • ◻️ Refactoring
  • ☑️ New feature
  • ◻️ Change of parameter values or input data (including CES parameters)
  • ☑️ Minor change (default scenarios show only small differences)
  • ◻️ Fundamental change of results of default scenarios

Checklist

Do not delete any line. Leave unfinished elements unchecked so others know how far along you are.
In the end all checkboxes must be ticked before you can merge
.

  • I executed the automated model tests (make test) after my final commit and all tests pass (FAIL 0)
  • I adjusted the reporting in remind2 if and where it was needed
  • I adjusted the madrat packages (mrremind and other packages involved) for input data generation if and where it was needed
  • My code follows the coding etiquette
  • I explained my changes within the PR, particularly in hard-to-understand areas
  • I checked that the in-code documentation is up-to-date
  • I adjusted forbiddenColumnNames in readCheckScenarioConfig.R in case the PR leads to deprecated switches
  • I updated the CHANGELOG.md correctly (added, changed, fixed, removed, input data/calibration)

Further information (optional)

  • Runs with these changes are here:
    /p/projects/ecemf/REMIND/debug/remind_47_algorithm/output/SSP2-EU21-PkBudg1000_2026-06-05_20.20.32

Check the report nashConvergence-regiTarget.html for more information.

  • Comparison of results (what changes by this PR?):

Not Aplicable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant