Skip to content

data(nordic): per-zone carbon intensity for Swedish bidding zones SE1–SE4#1262

Open
avalyset wants to merge 1 commit into
mlco2:masterfrom
avalyset:khepri-se-per-zone-ci
Open

data(nordic): per-zone carbon intensity for Swedish bidding zones SE1–SE4#1262
avalyset wants to merge 1 commit into
mlco2:masterfrom
avalyset:khepri-se-per-zone-ci

Conversation

@avalyset

Copy link
Copy Markdown

Hi! This proposes replacing the uniform 18.0 gCO2eq/kWh placeholder currently shared by all four Swedish bidding zones in codecarbon/data/private_infra/nordic_emissions.json with per-zone, derived values. Data-only change — happy to adjust anything based on your review.

This is a companion to #1260, which does the equivalent for Norwegian zones NO1–NO5. The two PRs are independent and can be merged in either order.

What

Zone before after (gCO2eq/kWh)
SE1 (Northern Sweden) 18.0 20.6
SE2 (North-central Sweden) 18.0 20.1
SE3 (South-central Sweden, incl. Stockholm) 18.0 14.5
SE4 (Southern Sweden) 18.0 17.4

NO1–NO5 and FI are unchanged (byte-for-byte; only SE blocks + file metadata touched).

Why the placeholder is worth improving

The current 18.0 is identical across SE1–SE4 and is systematically wrong in both directions: it undervalues SE1 and SE2 (true CI ~20 gCO2eq/kWh, ~+12–15% error relative to 18.0) and overvalues SE3 (true CI ~14.5, ~−19% error). A single uniform constant cannot represent structurally different zones.

The clearest case for per-zone values

SE3 is Sweden's nuclear-dominant zone. Nuclear generation carries a lifecycle factor of ~12 gCO2eq/kWh (IPCC AR5), well below any fossil source. As a result, SE3's true CI sits at 14.5 gCO2eq/kWh — the 18.0 placeholder is roughly 19% too high. This error is structurally absent in the Norwegian zones, which are predominantly hydropower and have no nuclear-dominant zone; Norwegian CIs cluster near or above 18.0 rather than well below it.

SE1 and SE2, by contrast, give the undervaluation counterpart: their hydro-and-wind mix yields CIs of ~20 gCO2eq/kWh, making the placeholder ~12–15% too low. Together, SE3's overvaluation and SE1/SE2's undervaluation make the two-way error explicit and large — a single uniform value is wrong in opposite directions across the four Swedish zones.

Source & method

  • Source: ENTSO-E Transparency Actual Generation per Production Type (A75), per bidding zone, full year 2025.
  • Method: production-based generation-mix weighted average (ENTSO-E A75 + IPCC AR5 Annex III lifecycle factors) — each generation source weighted by its share in the annual mix and multiplied by its IPCC AR5 Annex III lifecycle emission factor.
  • This PR updates the static nordic emission factors only; it does not modify the Electricity Maps API integration (electricitymaps_api.py) or any other data path.

A point we'd like your steer on: the factor basis

We derived these with IPCC AR5 Annex III (Table A.III.2) lifecycle medians (coal 820, gas 490, hydro 24, wind 11, nuclear 12, …) rather than CodeCarbon's carbon_intensity_per_source.json. Our reasoning:

  • IPCC AR5 is a single, peer-reviewed, consistent-lifecycle basis, and it keeps these numbers identical to the upstream derivation's DOI-frozen record (so there's one citable value per zone, not two).
  • The main table difference is gas (AR5 490 vs your 743, carbon_intensity_per_source.json:9), but fossil gas is a negligible share of the Swedish mix, so the choice has minimal effect on these values — we flag it only for transparency.

That said — this is a recommendation, not a correction of your table. If you'd prefer internal consistency with carbon_intensity_per_source.json, re-deriving with your own per-source factors is a one-line change on our side; just say the word.

Honest characterization (per-zone drift notes added)

A multi-year analysis (2022–2025) is carried in the per-zone note fields:

Zone Drift Recommendation
SE1 Mix drifting (hydro→wind shift, −3.8% CI) More frequent than annual updates recommended
SE2 Stable: CI −2.4%, mix shifts <5pp Annual update sufficient
SE3 Nuclear share eroding −6.4pp; CI +7.8% (below 15% threshold) More frequent than annual updates recommended
SE4 Material drift: CI +15.2% (solar growth) More frequent than annual updates required

SE4 shows the most active drift (monotonically rising CI driven by solar growth, Solar=48 gCO2eq/kWh vs wind=11). SE2 is the only SE zone below both materiality thresholds.

Reproducibility

Every value is traceable. Derivation method, pre-registered before computation, is in the ADR chain (esp. ADR-0001 CI method); the per-zone results and multi-year drift analysis are in the repo's docs/. Frozen and citable:

Tests

The existing Nordic test (test_get_emissions_PRIVATE_INFRA_NORDIC_REGION) previously hardcoded the placeholder 0.018 for SE2; updated to 0.0201 to match the new derived value. All 9 Nordic tests pass; 8 package integrity tests pass. No other code changes.

Thanks for maintaining CodeCarbon — glad to iterate on any of this.

Replace the uniform 18.0 gCO2eq/kWh placeholder for SE1-SE4 with per-zone
production-based values (SE1 20.6, SE2 20.1, SE3 14.5, SE4 17.4) derived
from ENTSO-E generation-per-type x IPCC AR5 lifecycle factors (2025 annual
means). Adds per-zone method/source/drift notes + updated file metadata.
NO1-NO5 and FI unchanged.

Update test_get_emissions_PRIVATE_INFRA_NORDIC_REGION to reflect SE2's
new derived value (20.1 gCO2eq/kWh = 0.0201 kg/kWh). Test previously
hardcoded the placeholder 0.018; now uses the derived 2025 figure. All
9 nordic tests pass; 8 package integrity tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@avalyset avalyset requested a review from a team as a code owner June 29, 2026 21:09
@benoit-cty

Copy link
Copy Markdown
Contributor

Thanks for your contribution.
Can you give us the exact link to review the source of the value ?

@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.68%. Comparing base (3161c53) to head (20de124).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1262      +/-   ##
==========================================
+ Coverage   89.64%   89.68%   +0.04%     
==========================================
  Files          48       48              
  Lines        4771     4771              
==========================================
+ Hits         4277     4279       +2     
+ Misses        494      492       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@avalyset

Copy link
Copy Markdown
Author

Hi Benoît, thanks for taking a look.

The values are derived rather than taken from a single source, so the "source" is a short chain:

Generation data: ENTSO-E Transparency, Actual Generation per Production Type (A75), per bidding zone, full year 2025. The raw series isn't committed (fetched reproducibly from the ENTSO-E API), but the exact EIC codes per zone are in ADR-0006.

Emission factors: IPCC AR5 Annex III, Table A.III.2 lifecycle medians (hydro 24, wind 11, nuclear 12, solar 48, gas 490 gCO2eq/kWh).

Method: production-based generation-mix weighted average — each source weighted by its annual share, multiplied by its factor.

The four SE values, the drift analysis, and the nine-zone table are in the README, and the whole thing is frozen and citable at https://doi.org/10.5281/zenodo.21042581.

So there's no single CSV that says "20.6" — the value is traceable through method + the two sources above. Glad to add a worked example for one zone (e.g. SE3) showing the mix × factors arithmetic explicitly if that helps.

@avalyset

avalyset commented Jul 1, 2026

Copy link
Copy Markdown
Author

Quick follow-up, @benoit-cty — I've since published a corrected version (same concept DOI, now resolves to v1.2):

https://doi.org/10.5281/zenodo.21042581

Two things this fixes for your review: the SE per-zone drift results are now included in full (docs/se-drift-results-2022-2025.md), and one correction to my earlier note — the factor source is IPCC WG III AR5 Annex III lifecycle medians (I referenced "Table A.III.2" above; the manuscript and repo now cite "Annex III" without that sub-ID). Factor values are unchanged (hydro 24, wind 11, nuclear 12, solar 48, gas 490 gCO2eq/kWh). Method in ADR-0006 (SE CI) and ADR-0007 (SE drift).

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.

2 participants