Skip to content

feat(china): use official 2023 MEE/NBS provincial emission factors - #1448

Merged
benoit-cty merged 2 commits into
mlco2:masterfrom
Zhaohh0706:china-provincial-factors
Oct 17, 2026
Merged

benoit-cty merged 2 commits into
mlco2:masterfrom
Zhaohh0706:china-provincial-factors

Conversation

@Zhaohh0706

Copy link
Copy Markdown
Contributor

Description

Adds the official 2023 provincial electricity CO2 emission factors for China (MEE/NBS Announcement 2025 No. 47, Table 3) and uses them for private-infrastructure emissions when the geolocation service reports a Chinese province.

  • New data file codecarbon/data/private_infra/2023/china_provincial_emissions.json: 30 provinces keyed by ISO 3166-2 code, emission_factor in gCO2/kWh, with metadata (source URL, announcement number, publication date, year, unit, convention, note that Tibet is not published) and, per province, the lower-case names accepted from geolocation (names).
  • codecarbon/input.py: loads the file with the other static data (same cache pattern as the Nordic file) and exposes DataSource.get_china_provincial_emissions_data().
  • codecarbon/core/emissions.py: new CHN branch in get_region_emissions next to USA/CAN, via _try_get_china_province_emissions. Matching is case-insensitive and ignores a trailing "province", "municipality" or "autonomous region". The CHN branch is only entered when the country code is CHN, so Hong Kong, Macao and Taiwan (their own country codes) never get a mainland value.
  • Fallback: an unknown region, no region, or a province missing from the table (Tibet) uses the existing national value for China (get_country_emissions), as today, with no warning logged.
  • pyproject.toml: adds the JSON to the package data.

Convention: the values are exactly as published, CO2 only (not CO2eq, no lifecycle), average over all generation in the province, location-based. This is stated in the JSON metadata.

Related Issue

Resolves #1444

Motivation and Context

Grid carbon intensity in China differs by a factor of about five between provinces (for example Yunnan 133.3 g/kWh, Tianjin 679.6 g/kWh), but codecarbon applies a single national value to every Chinese IP. The ipinfo.io fallback returns the province for Chinese IPs (geojs returns no region for them), so the information is already available; only the factors and the name mapping were missing. The structure follows the one described in the discussion on the issue: JSON data file with the source URL, a name-to-key mapping, and a branch in emissions.py with tests.

How Has This Been Tested?

  • New tests in tests/test_emissions.py: province hit with an exact expected value, all 30 provinces resolve to their own factor, name variants (case, whitespace, "Inner Mongolia", "Nei Mongol", "Ningxia Hui", "Xinjiang Uygur", "Guangxi Zhuang", "... Autonomous Region", "... Province"), Shaanxi and Shanxi kept distinct, alias uniqueness, Tibet / Xizang / Hong Kong / Macao / Taiwan / unknown / no region fall back to the national value without warnings, a province name under another country code (HKG, TWN, MAC, FRA) is not used, a data loading error falls back to the national value, forced carbon intensity still takes precedence.
  • Values were re-extracted from the official attachment PDF and compared with the JSON: 30 of 30 match.
  • Checked the province strings that ipinfo.io returns for public Chinese DNS server IPs (e.g. "Inner Mongolia", "Ningxia", "Xinjiang", "Guangxi", "Tibet", "Shaanxi") and ran them through GeoMetadata and Emissions.
  • pre-commit run --all-files passes; full suite (test-package task) 681 passed, 20 skipped; the built wheel contains the JSON file.

Screenshots (if appropriate):

Types of changes

What types of changes does your code introduce? Put an x in all the boxes that apply:

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

AI Usage Disclosure

Please refer to docs/how-to/ai-policy.md for detailed guidelines on how to disclose AI usage in your PR. Accurately completing this section is mandatory.

The AI tool read the codebase, drafted the data file, the name mapping, the emissions branch and the tests, and ran the tests and linters. I reviewed the diff line by line, re-checked all 30 values against the official PDF, and re-ran the tests locally.

  • 🟥 AI-vibecoded: You cannot explain the logic. Car analogy : the car drive by itself, you are outside it and just tell it where to go.
  • 🟠 AI-generated: Car analogy : the car drive by itself, you are inside and give instructions.
  • ⭐ AI-assisted. Car analogy : you drive the car, AI help you find your way.
  • ♻️ No AI used. Car analogy : you drive the car.

Checklist:

Go over all the following points, and put an x in all the boxes that apply.

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the docs/how-to/contributing.md document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

Add the 30 provincial electricity CO2 factors published in Announcement
2025 No. 47, a province name lookup, and a CHN branch next to USA/CAN in
get_region_emissions. Tibet, Hong Kong, Macao, Taiwan and unknown
regions keep using the national value.
@Zhaohh0706
Zhaohh0706 requested a review from a team as a code owner October 14, 2026 18:40
@benoit-cty

Copy link
Copy Markdown
Contributor

Thanks for this great improvement.

@codecov

codecov Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 92.15%. Comparing base (8a8776a) to head (4b1f847).

Files with missing lines Patch % Lines
codecarbon/core/emissions.py 94.73% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1448      +/-   ##
==========================================
+ Coverage   92.07%   92.15%   +0.07%     
==========================================
  Files          49       49              
  Lines        5202     5227      +25     
==========================================
+ Hits         4790     4817      +27     
+ Misses        412      410       -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.

Add a 'Regional data' section to the methodology page listing the
sub-national sources (USA, Canada, Nordic bidding zones, China
provinces) and the CO2 vs CO2eq convention of the MEE/NBS factors.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions github-actions Bot added size/XL and removed size/L labels Oct 17, 2026
@benoit-cty
benoit-cty merged commit 3095efc into mlco2:master Oct 17, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provincial carbon intensity for China (official 2023 MEE/NBS factors)

2 participants