Skip to content

Add water consumption from electricity mix - #1407

Draft
benoit-cty wants to merge 6 commits into
masterfrom
feat/water-consumption
Draft

Add water consumption from electricity mix#1407
benoit-cty wants to merge 6 commits into
masterfrom
feat/water-consumption

Conversation

@benoit-cty

Copy link
Copy Markdown
Contributor

Description

Adds an estimation of the water consumed by your compute, reported in the existing water_consumed field (litres), across the whole stack:

  • Core package: water_consumed is now the sum of
    • direct water: data center cooling water, computed from the user-provided wue parameter (unchanged, defaults to 0), and
    • indirect water (new): water consumed by power plants to generate the electricity used, estimated from the energy mix of the country (or Canadian region) where the machine runs — mirroring how carbon intensity is computed. Per-source factors live in codecarbon/data/private_infra/water_consumption_per_source.json (Meldrum et al. 2013, Macknick et al. 2012). When sources with known water intensity cover less than 90% of a country's mix (e.g. geothermal-heavy Kenya/Iceland), a world average of ~3.75 L/kWh is used (computed from the same per-source table weighted by the world mix, so the fallback is consistent with computed country values). Cloud providers publish no per-region water data, so cloud runs fall back to the water intensity of the host country.
  • API: new water_consumed column on emissions (alembic migration included), accepted on emission creation and summed in run/experiment/project/organization reports.
  • Webapp: a water radial chart next to the energy one on the organization, project and public project dashboards; water_consumed added to CSV exports.
  • Docs: new Water Consumption section in the methodology page, CSV field documented, examples/water_consumption.py added.

This is a rework of the student branches feat/water_consumption and feat/water_consumption_S (the latter is a superset; both can be deleted once this merges). The branches were 481 commits behind master, so the feature was ported onto master rather than rebased, keeping the students as co-authors. Beyond the rebase, the main fixes over the original branch:

  • The source keys of the water data file did not match global_energy_mix.json (natural_gas vs gas, missing oil/hydroelectricity/biofuel), so the energy-mix computation always fell back to the world average — and one fallback path called a method that did not exist (WaterPerKWh.from_g_per_kWh). Keys now match, hydro/oil/biofuel factors were added, and coverage is ≥90% for 207 of 213 countries.
  • Fixed a 1000× unit error (gal/kWh vs gal/MWh) in the cloud fallback path.
  • The exact-sum sanity check (which always failed) was replaced by a 90% coverage threshold with normalization over the covered share.
  • Water now accumulates incrementally in _update_emissions() alongside emissions instead of being recomputed from the total at report time; wue water is added rather than replacing the estimate (direct + indirect, as in Li et al. 2023, "Making AI Less Thirsty").
  • Removed methods duplicated from the Emissions class, the noisy per-measurement warnings, an unrelated alembic/env.py change, and a migration that carried unrelated auto-generated schema changes with a wrong down_revision.
  • The webapp part was re-implemented from scratch: the original branch targeted the old Next.js webapp, which has since been replaced by the Vite + React Router app.

An adversarial multi-angle review was then run on the branch and its accepted findings applied: the water intensity is cached per location (it is constant for a run, and its fallback warnings now log once instead of every measurement cycle), the water estimation is wrapped so a failure can never break the carbon tracking, the new data file was added to [tool.setuptools.package-data] (verified present in a built wheel), the dead USA regional branch was dropped (only Canada ships a regional energy mix), a null water_consumed is coalesced to 0 before insert (the column is NOT NULL), and the duplicated webapp RadialChartData type/skeleton markup were consolidated.

Behavior change to be aware of (not an API break): water_consumed was previously wue × energy and therefore 0 unless wue was set. It is now non-zero for every run, since the indirect water of electricity generation is always estimated. Orders of magnitude: France ≈ 3.8 L/kWh (nuclear+hydro), Poland ≈ 1.8 L/kWh (coal), Norway ≈ 15 L/kWh (hydro reservoir evaporation — high but consistent with the literature; flagged as uncertain in the docs). If maintainers prefer the estimate to stay opt-in, gating it behind a parameter is a small follow-up.

Related Issue

Extends #894 (water usage estimation), which was partially addressed by the wue parameter in #941. Supersedes the branches feat/water_consumption and feat/water_consumption_S.

Motivation and Context

Computing does not only emit CO₂: generating the electricity it uses also consumes fresh water (thermal/nuclear plant cooling, reservoir evaporation). Reporting only the datacenter WUE misses this — usually dominant — indirect part, and required the user to know their WUE. With this change every run gets a water estimate out of the box, computed from the same energy-mix data already used for carbon intensity.

How Has This Been Tested?

  • New unit tests in tests/test_water_consumption.py (14 tests): unit conversions, per-country values (FRA/POL), scaling with energy, world-average fallbacks (unknown country, low-coverage country, cloud without geo), CAN regional mix, USA regional fallback, and a data-file consistency test that fails if the JSON keys ever drift from global_energy_mix.json.
  • Full core suite: uv run task test-package — passes except test_task_energy_with_live_update_interference, which fails identically on master (pre-existing, unrelated: energy sum mismatch).
  • API unit tests: uv run task test-api-unit — 119 passed (fixtures extended with water_consumed; the existing wue default/custom tests now also assert the new field).
  • Webapp: tsc --noEmit clean, vitest run — same 3 pre-existing interaction-test failures as master, everything else passes; prettier clean.
  • Manual: end-to-end tracker run writes water_consumed to emissions.csv with the expected 3.83 L/kWh ratio for France; examples/water_consumption.py runs.

Screenshots (if appropriate):

Types of changes

  • 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

  • 🟥 AI-vibecoded: You cannot explain the logic.
  • 🟠 AI-generated: the port to master, fixes, tests and docs were written by Claude under maintainer direction, on top of the students' original design and data.
  • ⭐ AI-assisted.
  • ♻️ No AI used.

Checklist:

  • 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.

benoit-cty and others added 6 commits August 28, 2026 16:34
Report in water_consumed the water used to generate the electricity
consumed, on top of the direct cooling water given by the wue
parameter. The water intensity (L/kWh) is computed as a weighted
average of per-source water consumption factors over the energy mix
of the country (or Canadian region) where the machine runs, with a
world-average fallback when coverage of the mix is below 90%. The
intensity is cached per location and a failure of the water
estimation can never break the emissions tracking.

Ported and reworked from feat/water_consumption_S, started by students:
- fix the source keys of water_consumption_per_source.json so they
  match global_energy_mix.json (the original computation always fell
  back to the world average), and add oil/hydro/biofuel factors
- fix a gal/kWh vs gal/MWh unit error in the cloud fallback path
- make the world-average fallback consistent with the computed
  country values (weighted by the world energy mix) to avoid a 5x
  discontinuity at the coverage threshold
- accumulate water incrementally in _update_emissions alongside
  emissions, instead of recomputing from the total at report time
- drop code duplicated from the Emissions class and the dead USA
  regional branch (only Canada has regional energy mix data)

Co-authored-by: Sifflet_blanc <flo.crahay@gmail.com>
Co-authored-by: Simon Decostanzi <gbsny8zh@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add the water_consumed column to the emissions table (alembic
migration included), accept it on emission creation, and sum it in
the run, experiment, project and organization reports.

Co-authored-by: Simon Decostanzi <gbsny8zh@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Show a water radial chart next to the energy one on the organization,
project and public project dashboards, and add water_consumed to the
CSV exports.

Co-authored-by: Simon Decostanzi <gbsny8zh@gmail.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.52542% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.58%. Comparing base (d1fb78a) to head (5d66024).

Files with missing lines Patch % Lines
codecarbon/core/water_consumption.py 94.11% 4 Missing ⚠️
codecarbon/emissions_tracker.py 76.92% 3 Missing ⚠️
codecarbon/cli/main.py 87.50% 2 Missing ⚠️
codecarbon/input.py 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1407      +/-   ##
==========================================
- Coverage   91.58%   91.58%   -0.01%     
==========================================
  Files          49       50       +1     
  Lines        5100     5216     +116     
==========================================
+ Hits         4671     4777     +106     
- Misses        429      439      +10     

☔ 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.

@SaboniAmine

Copy link
Copy Markdown
Member

Thanks for this integration Benoît!
I know that Benoît petit is working on the water consumption modelling, do you think we could make him review / discuss with us before we merge this one ?

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.

2 participants