From 6b1006018134c1dd1e2ea4808616943f05fecf64 Mon Sep 17 00:00:00 2001 From: Eirik Botten Nicolaysen Date: Mon, 29 Jun 2026 22:36:17 +0200 Subject: [PATCH 1/4] data(nordic): per-zone CI for Swedish bidding zones SE1-SE4 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 --- .../data/private_infra/nordic_emissions.json | 151 ++++++++++-------- tests/test_emissions.py | 5 +- 2 files changed, 85 insertions(+), 71 deletions(-) diff --git a/codecarbon/data/private_infra/nordic_emissions.json b/codecarbon/data/private_infra/nordic_emissions.json index e420a5a9e..d70e47742 100644 --- a/codecarbon/data/private_infra/nordic_emissions.json +++ b/codecarbon/data/private_infra/nordic_emissions.json @@ -1,69 +1,82 @@ -{ - "data": { - "SE1": { - "emission_factor": 18.0, - "unit": "gCO2eq/kWh", - "description": "Sweden Bidding Zone 1 (Northern Sweden)", - "year": 2024 - }, - "SE2": { - "emission_factor": 18.0, - "unit": "gCO2eq/kWh", - "description": "Sweden Bidding Zone 2 (Central Sweden)", - "year": 2024 - }, - "SE3": { - "emission_factor": 18.0, - "unit": "gCO2eq/kWh", - "description": "Sweden Bidding Zone 3 (Southern Sweden)", - "year": 2024 - }, - "SE4": { - "emission_factor": 18.0, - "unit": "gCO2eq/kWh", - "description": "Sweden Bidding Zone 4 (Stockholm region)", - "year": 2024 - }, - "NO1": { - "emission_factor": 18.0, - "unit": "gCO2eq/kWh", - "description": "Norway Bidding Zone 1 (Oslo)", - "year": 2024 - }, - "NO2": { - "emission_factor": 18.0, - "unit": "gCO2eq/kWh", - "description": "Norway Bidding Zone 2 (Southern Norway)", - "year": 2024 - }, - "NO3": { - "emission_factor": 18.0, - "unit": "gCO2eq/kWh", - "description": "Norway Bidding Zone 3 (Central Norway)", - "year": 2024 - }, - "NO4": { - "emission_factor": 18.0, - "unit": "gCO2eq/kWh", - "description": "Norway Bidding Zone 4 (Northern Norway)", - "year": 2024 - }, - "NO5": { - "emission_factor": 18.0, - "unit": "gCO2eq/kWh", - "description": "Norway Bidding Zone 5 (Western Norway)", - "year": 2024 - }, - "FI": { - "emission_factor": 72.0, - "unit": "gCO2eq/kWh", - "description": "Finland", - "year": 2025 - } - }, - "metadata": { - "source": "Based on historical averages from ENTSO-E data", - "last_updated": "2026-01-24", - "notes": "Static emission factors for Nordic regions. Sweden and Norway have very low carbon intensity due to high renewable energy (primarily hydro and nuclear). Finland has higher emissions due to greater fossil fuel dependency." - } -} +{ + "data": { + "SE1": { + "emission_factor": 20.6, + "unit": "gCO2eq/kWh", + "description": "Sweden Bidding Zone 1 (Northern Sweden)", + "year": 2025, + "method": "production-based generation-mix (ENTSO-E A75 x IPCC AR5 lifecycle factors)", + "source": "ENTSO-E Transparency generation-per-type + IPCC AR5 Annex III; derived by Khepri (avalyset/khepri)", + "note": "Mix drifting (hydro-to-wind shift, 2022-2025: hydro -6.2pp, wind +6.4pp); CI stable (-3.8% 2022-2025) because hydro and wind share similar lifecycle factors. More frequent than annual updates recommended." + }, + "SE2": { + "emission_factor": 20.1, + "unit": "gCO2eq/kWh", + "description": "Sweden Bidding Zone 2 (North-central Sweden)", + "year": 2025, + "method": "production-based generation-mix (ENTSO-E A75 x IPCC AR5 lifecycle factors)", + "source": "ENTSO-E Transparency generation-per-type + IPCC AR5 Annex III; derived by Khepri (avalyset/khepri)", + "note": "Stable: CI -2.4% and mix shifts <5pp 2022-2025. Annual update sufficient. Only SE zone below both materiality thresholds." + }, + "SE3": { + "emission_factor": 14.5, + "unit": "gCO2eq/kWh", + "description": "Sweden Bidding Zone 3 (South-central Sweden, includes Stockholm)", + "year": 2025, + "method": "production-based generation-mix (ENTSO-E A75 x IPCC AR5 lifecycle factors)", + "source": "ENTSO-E Transparency generation-per-type + IPCC AR5 Annex III; derived by Khepri (avalyset/khepri)", + "note": "Nuclear-dominant zone (SE3 only; IPCC AR5 factor 12 gCO2eq/kWh). Nuclear share eroding (-6.4pp 2022-2025); CI +7.8% but below 15% threshold. Mix-drift warrants more frequent than annual updates." + }, + "SE4": { + "emission_factor": 17.4, + "unit": "gCO2eq/kWh", + "description": "Sweden Bidding Zone 4 (Southern Sweden)", + "year": 2025, + "method": "production-based generation-mix (ENTSO-E A75 x IPCC AR5 lifecycle factors)", + "source": "ENTSO-E Transparency generation-per-type + IPCC AR5 Annex III; derived by Khepri (avalyset/khepri)", + "note": "Material drift: CI +15.2% 2022-2025 (solar growth, Solar=48 gCO2eq/kWh vs wind=11). Monotonically rising. More frequent than annual updates required." + }, + "NO1": { + "emission_factor": 18.0, + "unit": "gCO2eq/kWh", + "description": "Norway Bidding Zone 1 (Oslo)", + "year": 2024 + }, + "NO2": { + "emission_factor": 18.0, + "unit": "gCO2eq/kWh", + "description": "Norway Bidding Zone 2 (Southern Norway)", + "year": 2024 + }, + "NO3": { + "emission_factor": 18.0, + "unit": "gCO2eq/kWh", + "description": "Norway Bidding Zone 3 (Central Norway)", + "year": 2024 + }, + "NO4": { + "emission_factor": 18.0, + "unit": "gCO2eq/kWh", + "description": "Norway Bidding Zone 4 (Northern Norway)", + "year": 2024 + }, + "NO5": { + "emission_factor": 18.0, + "unit": "gCO2eq/kWh", + "description": "Norway Bidding Zone 5 (Western Norway)", + "year": 2024 + }, + "FI": { + "emission_factor": 72.0, + "unit": "gCO2eq/kWh", + "description": "Finland", + "year": 2025 + } + }, + "metadata": { + "source": "SE1-SE4: ENTSO-E Transparency actual generation per production type, weighted by IPCC AR5 Annex III lifecycle emission factors (production-based generation-mix), derived reproducibly by Khepri (avalyset/khepri). NO1-NO5 and FI: prior values, unchanged.", + "method": "production-based: weighted average of generation-mix per source x lifecycle factor (same approach as CodeCarbon's static fallback methodology). NOT consumption-based; the Electricity Maps API path remains the consumption-based source.", + "last_updated": "2026-06-29", + "notes": "SE1-SE4 replace the prior uniform 18.0 placeholder with per-zone derived values (2025 annual means). The 18.0 placeholder is systematically wrong in both directions: it undervalues SE1/SE2 (true CI ~20 gCO2eq/kWh, ~+12-15% error) and overvalues SE3 (true CI ~14.5, ~-19% error) and SE4 (true CI ~17.4, ~-3% error). A single uniform constant cannot represent structurally different zones. Drift characterization: SE2 stable (annual update sufficient); SE1/SE3/SE4 show mix or CI drift (more frequent updates recommended, especially SE4). NO1-NO5 and FI retained from prior data pending equivalent per-zone derivation (see companion PR for Norwegian zones)." + } +} diff --git a/tests/test_emissions.py b/tests/test_emissions.py index 9084ef3ea..e953de141 100644 --- a/tests/test_emissions.py +++ b/tests/test_emissions.py @@ -220,9 +220,10 @@ def test_get_emissions_PRIVATE_INFRA_NORDIC_REGION(self): # THEN # Nordic regions use static emission factors from the JSON file - # SE2 has an emission factor specified in nordic_country_energy_mix.json + # SE2 has an emission factor specified in nordic_emissions.json + # Updated to 20.1 gCO2eq/kWh (2025 per-zone derived value, Khepri) assert isinstance(emissions, float) - self.assertAlmostEqual(emissions, 0.018, places=6) + self.assertAlmostEqual(emissions, 0.0201, places=6) def test_get_emissions_PRIVATE_INFRA_NORDIC_FINLAND(self): # WHEN From fab6ae978cbfb5168c87986e9c1bd9287b6ef441 Mon Sep 17 00:00:00 2001 From: Eirik Botten Nicolaysen Date: Tue, 18 Aug 2026 16:48:07 +0200 Subject: [PATCH 2/4] data(nordic): state AR5 factor basis, drop "true CI", cite v1.2 DOI Addresses the three points from @benoit-cty's review. Factor basis: the metadata said the method was "the same approach as CodeCarbon's static fallback methodology". It is not the same factor basis - carbon_intensity_per_source.json carries 743 for natural gas where IPCC AR5 Annex III carries 490. The metadata now names AR5 as the basis and records the difference without ranking either one. Overclaim: "true CI" in the notes is replaced with "production-based CI". The method weights generation physically produced in a zone; it does not flow-trace imports, so it is not the consumption-based intensity that phrasing implies. Provenance: adds the versioned DOI 10.5281/zenodo.21097430 (Khepri v1.2), which is the frozen record the values come from, rather than the concept DOI. Emission factors are unchanged. --- codecarbon/data/private_infra/nordic_emissions.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/codecarbon/data/private_infra/nordic_emissions.json b/codecarbon/data/private_infra/nordic_emissions.json index d70e47742..70bb20e5c 100644 --- a/codecarbon/data/private_infra/nordic_emissions.json +++ b/codecarbon/data/private_infra/nordic_emissions.json @@ -75,8 +75,9 @@ }, "metadata": { "source": "SE1-SE4: ENTSO-E Transparency actual generation per production type, weighted by IPCC AR5 Annex III lifecycle emission factors (production-based generation-mix), derived reproducibly by Khepri (avalyset/khepri). NO1-NO5 and FI: prior values, unchanged.", - "method": "production-based: weighted average of generation-mix per source x lifecycle factor (same approach as CodeCarbon's static fallback methodology). NOT consumption-based; the Electricity Maps API path remains the consumption-based source.", + "method": "production-based: weighted average of generation-mix per source x lifecycle emission factor. The emission factors are IPCC AR5 Annex III lifecycle medians. This is a different factor basis from CodeCarbon's static carbon_intensity_per_source.json, which carries different values for some sources (natural gas: 743 there, 490 in AR5). NOT consumption-based; the Electricity Maps API path remains the consumption-based source.", + "provenance": "SE1-SE4 values are taken from Khepri v1.2, archived at https://doi.org/10.5281/zenodo.21097430 (versioned record).", "last_updated": "2026-06-29", - "notes": "SE1-SE4 replace the prior uniform 18.0 placeholder with per-zone derived values (2025 annual means). The 18.0 placeholder is systematically wrong in both directions: it undervalues SE1/SE2 (true CI ~20 gCO2eq/kWh, ~+12-15% error) and overvalues SE3 (true CI ~14.5, ~-19% error) and SE4 (true CI ~17.4, ~-3% error). A single uniform constant cannot represent structurally different zones. Drift characterization: SE2 stable (annual update sufficient); SE1/SE3/SE4 show mix or CI drift (more frequent updates recommended, especially SE4). NO1-NO5 and FI retained from prior data pending equivalent per-zone derivation (see companion PR for Norwegian zones)." + "notes": "SE1-SE4 replace the prior uniform 18.0 placeholder with per-zone derived values (2025 annual means). The 18.0 placeholder is systematically wrong in both directions: it undervalues SE1/SE2 (production-based CI ~20 gCO2eq/kWh, ~+12-15% error) and overvalues SE3 (production-based CI ~14.5, ~-19% error) and SE4 (production-based CI ~17.4, ~-3% error). A single uniform constant cannot represent structurally different zones. Drift characterization: SE2 stable (annual update sufficient); SE1/SE3/SE4 show mix or CI drift (more frequent updates recommended, especially SE4). NO1-NO5 and FI retained from prior data pending equivalent per-zone derivation (see companion PR for Norwegian zones)." } } From 5d63756027bbb912a8346298be3a464a1ae48ecc Mon Sep 17 00:00:00 2001 From: Eirik Botten Nicolaysen Date: Sun, 30 Aug 2026 13:43:27 +0200 Subject: [PATCH 3/4] data(nordic): re-derive SE1-SE4 on carbon_intensity_per_source.json Per review on #1262: re-derived on CodeCarbon's own factor table instead of IPCC AR5, so the shipped values are internally consistent with the rest of the package. SE1 20.6 -> 25.9, SE2 20.1 -> 25.7, SE3 14.5 -> 27.0, SE4 17.4 -> 24.7. The review was right that the previous text's 'the main table difference is gas' was wrong: for Sweden the differences that matter are nuclear (29 vs 12) and wind (26 vs 11). SE3 moves 1.86x. Production types with no entry in carbon_intensity_per_source.json (Other B20, Other renewable, Waste, Biomass) are now kept in the denominator at factor 0 rather than dropped from both numerator and denominator, so the stored value is a complete gCO2eq/kWh factor over all zone generation, as CodeCarbon applies it. No factor was invented for them. Each zone block carries an explicit coverage field; SE4 is the weak case at 85.05%. Metadata now names both factor bases with all four differing sources, and keeps the versioned DOI 10.5281/zenodo.21097430 while stating that the archived record publishes AR5 values, which are not what this file ships. test_get_emissions_PRIVATE_INFRA_NORDIC_REGION asserts SE2 directly: 0.0201 -> 0.0257. 9 Nordic tests (+3 subtests), 25 test_emissions, 8 package-integrity all pass. --- .../data/private_infra/nordic_emissions.json | 49 +++++++++++-------- tests/test_emissions.py | 5 +- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/codecarbon/data/private_infra/nordic_emissions.json b/codecarbon/data/private_infra/nordic_emissions.json index 70bb20e5c..c5c8c5870 100644 --- a/codecarbon/data/private_infra/nordic_emissions.json +++ b/codecarbon/data/private_infra/nordic_emissions.json @@ -1,40 +1,44 @@ { "data": { "SE1": { - "emission_factor": 20.6, + "emission_factor": 25.9, "unit": "gCO2eq/kWh", "description": "Sweden Bidding Zone 1 (Northern Sweden)", "year": 2025, - "method": "production-based generation-mix (ENTSO-E A75 x IPCC AR5 lifecycle factors)", - "source": "ENTSO-E Transparency generation-per-type + IPCC AR5 Annex III; derived by Khepri (avalyset/khepri)", - "note": "Mix drifting (hydro-to-wind shift, 2022-2025: hydro -6.2pp, wind +6.4pp); CI stable (-3.8% 2022-2025) because hydro and wind share similar lifecycle factors. More frequent than annual updates recommended." + "method": "production-based generation-mix (ENTSO-E A75 2025 x CodeCarbon carbon_intensity_per_source.json)", + "source": "ENTSO-E Transparency generation-per-type (A75) 2025 x CodeCarbon carbon_intensity_per_source.json; derived reproducibly by Khepri (avalyset/khepri)", + "coverage": "99.59% of 2025 generation has a factor in carbon_intensity_per_source.json; remainder carried in the denominator at 0 (Other 0.41 %)", + "note": "Hydro-and-wind. Mix drifting (hydro -6.2pp, wind +6.4pp 2022-2025), but hydro and wind carry the same 26 gCO2eq/kWh factor in this table, so the mix shift barely moves the value." }, "SE2": { - "emission_factor": 20.1, + "emission_factor": 25.7, "unit": "gCO2eq/kWh", "description": "Sweden Bidding Zone 2 (North-central Sweden)", "year": 2025, - "method": "production-based generation-mix (ENTSO-E A75 x IPCC AR5 lifecycle factors)", - "source": "ENTSO-E Transparency generation-per-type + IPCC AR5 Annex III; derived by Khepri (avalyset/khepri)", - "note": "Stable: CI -2.4% and mix shifts <5pp 2022-2025. Annual update sufficient. Only SE zone below both materiality thresholds." + "method": "production-based generation-mix (ENTSO-E A75 2025 x CodeCarbon carbon_intensity_per_source.json)", + "source": "ENTSO-E Transparency generation-per-type (A75) 2025 x CodeCarbon carbon_intensity_per_source.json; derived reproducibly by Khepri (avalyset/khepri)", + "coverage": "98.92% of 2025 generation has a factor in carbon_intensity_per_source.json; remainder carried in the denominator at 0 (Other 1.08 %)", + "note": "Hydro-and-wind. Most stable SE zone; mix shifts <5pp 2022-2025." }, "SE3": { - "emission_factor": 14.5, + "emission_factor": 27.0, "unit": "gCO2eq/kWh", "description": "Sweden Bidding Zone 3 (South-central Sweden, includes Stockholm)", "year": 2025, - "method": "production-based generation-mix (ENTSO-E A75 x IPCC AR5 lifecycle factors)", - "source": "ENTSO-E Transparency generation-per-type + IPCC AR5 Annex III; derived by Khepri (avalyset/khepri)", - "note": "Nuclear-dominant zone (SE3 only; IPCC AR5 factor 12 gCO2eq/kWh). Nuclear share eroding (-6.4pp 2022-2025); CI +7.8% but below 15% threshold. Mix-drift warrants more frequent than annual updates." + "method": "production-based generation-mix (ENTSO-E A75 2025 x CodeCarbon carbon_intensity_per_source.json)", + "source": "ENTSO-E Transparency generation-per-type (A75) 2025 x CodeCarbon carbon_intensity_per_source.json; derived reproducibly by Khepri (avalyset/khepri)", + "coverage": "94.58% of 2025 generation has a factor in carbon_intensity_per_source.json; remainder carried in the denominator at 0 (Other 5.42 %)", + "note": "Sweden's only nuclear zone (nuclear 63.1% of all 2025 generation at 29 gCO2eq/kWh). Nuclear share eroding -6.4pp 2022-2025." }, "SE4": { - "emission_factor": 17.4, + "emission_factor": 24.7, "unit": "gCO2eq/kWh", "description": "Sweden Bidding Zone 4 (Southern Sweden)", "year": 2025, - "method": "production-based generation-mix (ENTSO-E A75 x IPCC AR5 lifecycle factors)", - "source": "ENTSO-E Transparency generation-per-type + IPCC AR5 Annex III; derived by Khepri (avalyset/khepri)", - "note": "Material drift: CI +15.2% 2022-2025 (solar growth, Solar=48 gCO2eq/kWh vs wind=11). Monotonically rising. More frequent than annual updates required." + "method": "production-based generation-mix (ENTSO-E A75 2025 x CodeCarbon carbon_intensity_per_source.json)", + "source": "ENTSO-E Transparency generation-per-type (A75) 2025 x CodeCarbon carbon_intensity_per_source.json; derived reproducibly by Khepri (avalyset/khepri)", + "coverage": "85.05% of 2025 generation has a factor in carbon_intensity_per_source.json; remainder carried in the denominator at 0 (Other 14.95 %)", + "note": "Lowest coverage in this set: 14.95% of SE4 generation is ENTSO-E 'Other' (B20), which has no entry in carbon_intensity_per_source.json and is therefore carried in the denominator at 0. The value is correspondingly a lower bound - see the coverage field. Solar growing (Solar=48 vs wind=26)." }, "NO1": { "emission_factor": 18.0, @@ -74,10 +78,13 @@ } }, "metadata": { - "source": "SE1-SE4: ENTSO-E Transparency actual generation per production type, weighted by IPCC AR5 Annex III lifecycle emission factors (production-based generation-mix), derived reproducibly by Khepri (avalyset/khepri). NO1-NO5 and FI: prior values, unchanged.", - "method": "production-based: weighted average of generation-mix per source x lifecycle emission factor. The emission factors are IPCC AR5 Annex III lifecycle medians. This is a different factor basis from CodeCarbon's static carbon_intensity_per_source.json, which carries different values for some sources (natural gas: 743 there, 490 in AR5). NOT consumption-based; the Electricity Maps API path remains the consumption-based source.", - "provenance": "SE1-SE4 values are taken from Khepri v1.2, archived at https://doi.org/10.5281/zenodo.21097430 (versioned record).", - "last_updated": "2026-06-29", - "notes": "SE1-SE4 replace the prior uniform 18.0 placeholder with per-zone derived values (2025 annual means). The 18.0 placeholder is systematically wrong in both directions: it undervalues SE1/SE2 (production-based CI ~20 gCO2eq/kWh, ~+12-15% error) and overvalues SE3 (production-based CI ~14.5, ~-19% error) and SE4 (production-based CI ~17.4, ~-3% error). A single uniform constant cannot represent structurally different zones. Drift characterization: SE2 stable (annual update sufficient); SE1/SE3/SE4 show mix or CI drift (more frequent updates recommended, especially SE4). NO1-NO5 and FI retained from prior data pending equivalent per-zone derivation (see companion PR for Norwegian zones)." + "source": "SE1-SE4: ENTSO-E Transparency actual generation per production type (A75), full year 2025, weighted by CodeCarbon's own carbon_intensity_per_source.json emission factors (production-based generation-mix), derived reproducibly by Khepri (avalyset/khepri). NO1-NO5 and FI: prior values, unchanged.", + "method": "production-based generation-mix: energy-weighted average over ENTSO-E Actual Generation per Production Type (A75), full year 2025, using CodeCarbon's own carbon_intensity_per_source.json factors. NOT consumption-based; the Electricity Maps API path remains the consumption-based source.", + "factor_basis": "CodeCarbon's own carbon_intensity_per_source.json - NOT IPCC AR5. These values were re-derived on this project's table so they are internally consistent with the rest of CodeCarbon. The two bases differ materially for the sources that dominate the Nordic mix, not only for gas: nuclear 29 here vs 12 in AR5; wind 26 vs 11; hydroelectricity 26 vs 24; natural gas 743 vs 490. Because hydro and wind carry the same 26 in this table, per-zone spread is much narrower here than on an AR5 basis.", + "coverage": "Each zone carries a 'coverage' field: the share of that zone's 2025 generation that has an entry in carbon_intensity_per_source.json. Production types with no entry (ENTSO-E 'Other' B20, 'Other renewable', 'Waste', 'Biomass') are kept in the denominator with factor 0 and contribute nothing to the numerator, so the stored number is a complete gCO2eq/kWh factor applicable to all consumed energy, as CodeCarbon uses it. Where coverage is well below 100% the value is a lower bound; SE4 (85.05%) is the weakest case in this set. No factor was invented for the uncovered types.", + "alternative_basis": "The upstream derivation also publishes these zones on IPCC AR5 Annex III lifecycle medians (nuclear 12, wind 11, hydro 24, gas 490), which excludes factor-less types from both numerator and denominator instead of carrying them at 0. That is a different factor basis and a different treatment of uncovered generation, and it yields lower values (e.g. SE3 14.5 and NO4 39.6 on AR5, vs 27.0 and 51.7 here). Published and archived at https://doi.org/10.5281/zenodo.21097430 (Khepri v1.2). The AR5 figures are NOT what this file ships.", + "provenance": "SE1-SE4 values are derived by Khepri v1.2, archived at https://doi.org/10.5281/zenodo.21097430 (versioned record), re-derived on CodeCarbon's factor table for this file.", + "last_updated": "2026-08-30", + "notes": "SE1-SE4 replace the prior uniform 18.0 placeholder with per-zone derived values (2025 annual, energy-weighted). On this factor table the placeholder is too LOW for every zone in this set. Per-zone spread on CodeCarbon's factors is narrow for the Swedish zones (24.7-27.0) because hydro and wind share the same 26 gCO2eq/kWh factor; the Norwegian spread is wider (25.8-51.7) and driven almost entirely by NO4's fossil-gas share. NO1-NO5 and FI retained from prior data pending equivalent per-zone derivation." } } diff --git a/tests/test_emissions.py b/tests/test_emissions.py index e953de141..3d6893b16 100644 --- a/tests/test_emissions.py +++ b/tests/test_emissions.py @@ -221,9 +221,10 @@ def test_get_emissions_PRIVATE_INFRA_NORDIC_REGION(self): # THEN # Nordic regions use static emission factors from the JSON file # SE2 has an emission factor specified in nordic_emissions.json - # Updated to 20.1 gCO2eq/kWh (2025 per-zone derived value, Khepri) + # Updated to 25.7 gCO2eq/kWh (2025 per-zone value, derived on + # carbon_intensity_per_source.json) assert isinstance(emissions, float) - self.assertAlmostEqual(emissions, 0.0201, places=6) + self.assertAlmostEqual(emissions, 0.0257, places=6) def test_get_emissions_PRIVATE_INFRA_NORDIC_FINLAND(self): # WHEN From 954da9d649ea3cbcf0cfa86808f21fb6b27239b0 Mon Sep 17 00:00:00 2001 From: Eirik Botten Nicolaysen Date: Thu, 3 Sep 2026 19:34:35 +0200 Subject: [PATCH 4/4] data(nordic): point provenance at the Khepri v1.3 record v1.3 documents the basis these values are derived on: the ENTSO-E to codecarbon category mapping, and the named parameter that carries unfactored generation in the denominator at zero. On v1.2 that treatment existed only as an undocumented parameter combination, so the provenance link did not lead to something a reader could check. No value changes. Co-Authored-By: Claude Opus 5 --- codecarbon/data/private_infra/nordic_emissions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecarbon/data/private_infra/nordic_emissions.json b/codecarbon/data/private_infra/nordic_emissions.json index c5c8c5870..a359a7615 100644 --- a/codecarbon/data/private_infra/nordic_emissions.json +++ b/codecarbon/data/private_infra/nordic_emissions.json @@ -83,7 +83,7 @@ "factor_basis": "CodeCarbon's own carbon_intensity_per_source.json - NOT IPCC AR5. These values were re-derived on this project's table so they are internally consistent with the rest of CodeCarbon. The two bases differ materially for the sources that dominate the Nordic mix, not only for gas: nuclear 29 here vs 12 in AR5; wind 26 vs 11; hydroelectricity 26 vs 24; natural gas 743 vs 490. Because hydro and wind carry the same 26 in this table, per-zone spread is much narrower here than on an AR5 basis.", "coverage": "Each zone carries a 'coverage' field: the share of that zone's 2025 generation that has an entry in carbon_intensity_per_source.json. Production types with no entry (ENTSO-E 'Other' B20, 'Other renewable', 'Waste', 'Biomass') are kept in the denominator with factor 0 and contribute nothing to the numerator, so the stored number is a complete gCO2eq/kWh factor applicable to all consumed energy, as CodeCarbon uses it. Where coverage is well below 100% the value is a lower bound; SE4 (85.05%) is the weakest case in this set. No factor was invented for the uncovered types.", "alternative_basis": "The upstream derivation also publishes these zones on IPCC AR5 Annex III lifecycle medians (nuclear 12, wind 11, hydro 24, gas 490), which excludes factor-less types from both numerator and denominator instead of carrying them at 0. That is a different factor basis and a different treatment of uncovered generation, and it yields lower values (e.g. SE3 14.5 and NO4 39.6 on AR5, vs 27.0 and 51.7 here). Published and archived at https://doi.org/10.5281/zenodo.21097430 (Khepri v1.2). The AR5 figures are NOT what this file ships.", - "provenance": "SE1-SE4 values are derived by Khepri v1.2, archived at https://doi.org/10.5281/zenodo.21097430 (versioned record), re-derived on CodeCarbon's factor table for this file.", + "provenance": "SE1-SE4 values are derived by Khepri v1.3, archived at https://doi.org/10.5281/zenodo.22285397 (versioned record), re-derived on CodeCarbon's factor table for this file.", "last_updated": "2026-08-30", "notes": "SE1-SE4 replace the prior uniform 18.0 placeholder with per-zone derived values (2025 annual, energy-weighted). On this factor table the placeholder is too LOW for every zone in this set. Per-zone spread on CodeCarbon's factors is narrow for the Swedish zones (24.7-27.0) because hydro and wind share the same 26 gCO2eq/kWh factor; the Norwegian spread is wider (25.8-51.7) and driven almost entirely by NO4's fossil-gas share. NO1-NO5 and FI retained from prior data pending equivalent per-zone derivation." }