diff --git a/codecarbon/data/private_infra/carbon_intensity_per_source.json b/codecarbon/data/private_infra/carbon_intensity_per_source.json index 8ce6e8b89..239061499 100644 --- a/codecarbon/data/private_infra/carbon_intensity_per_source.json +++ b/codecarbon/data/private_infra/carbon_intensity_per_source.json @@ -19,5 +19,11 @@ "solar": 48, "solar_source": "http://www.world-nuclear.org/uploadedFiles/org/WNA/Publications/Working_Group_Reports/comparison_of_lifecycle.pdf", "wind": 26, - "wind_source": "http://www.world-nuclear.org/uploadedFiles/org/WNA/Publications/Working_Group_Reports/comparison_of_lifecycle.pdf" + "wind_source": "http://www.world-nuclear.org/uploadedFiles/org/WNA/Publications/Working_Group_Reports/comparison_of_lifecycle.pdf", + "biomass": 230, + "biomass_source": "IPCC AR5 WG3 Annex III, Table A.III.2, 'Biomass - dedicated', median lifecycle emissions (min 130, max 420): https://www.ipcc.ch/site/assets/uploads/2018/02/ipcc_wg3_ar5_annex-iii.pdf", + "biofuel": 230, + "biofuel_source": "Same factor as biomass. global_energy_mix.json names bioenergy generation biofuel_TWh, so the factor is reachable under that name.", + "waste": 230, + "waste_source": "One value for mixed renewable and non-renewable waste: the biomass factor, following Electricity Maps, which groups ENTSO-E B17 Waste with biomass (https://github.com/electricitymaps/electricitymaps-contrib/blob/b7469384a7/electricitymap/contrib/parsers/ENTSOE.py#L123). The non-renewable fraction varies by country and year and is not modelled." } \ No newline at end of file diff --git a/docs/explanation/methodology.md b/docs/explanation/methodology.md index ec3fbdb7d..ef6a09c1f 100644 --- a/docs/explanation/methodology.md +++ b/docs/explanation/methodology.md @@ -70,10 +70,13 @@ intensity of electricity using this table: | Coal | 995 | | Petroleum | 816 | | Natural Gas | 743 | +| Biofuel | 230 | +| Biomass | 230 | | Geothermal | 38 | | Hydroelectricity | 26 | | Nuclear | 29 | | Solar | 48 | +| Waste | 230 | | Wind | 26 | *Carbon Intensity Across Energy Sources* @@ -82,6 +85,8 @@ Sources: - [for fossil energies](https://github.com/responsibleproblemsolving/energy-usage#conversion-to-co2) - [for renewables energies](http://www.world-nuclear.org/uploadedFiles/org/WNA/Publications/Working_Group_Reports/comparison_of_lifecycle.pdf) +- [for biomass and biofuel](https://www.ipcc.ch/site/assets/uploads/2018/02/ipcc_wg3_ar5_annex-iii.pdf) (IPCC AR5 WG3 Annex III, Table A.III.2, median for "Biomass — dedicated") +- [for waste](https://github.com/electricitymaps/electricitymaps-contrib/blob/b7469384a7/electricitymap/contrib/parsers/ENTSOE.py#L123) (the biomass factor, following Electricity Maps, which groups waste with biomass) Then, for example, if the Energy Mix of the Grid Electricity is 25% Coal, 35% Petroleum, 26% Natural Gas and 14% Nuclear: diff --git a/tests/test_emissions.py b/tests/test_emissions.py index 3361f2d1d..2e067d306 100644 --- a/tests/test_emissions.py +++ b/tests/test_emissions.py @@ -50,10 +50,63 @@ def test_emissions_CLOUD_GCP(self): def test_get_carbon_intensity_per_source_data(self): # pytest tests/test_emissions.py::TestEmissions::test_get_carbon_intensity_per_source_data carbon_intensity = DataSource().get_carbon_intensity_per_source_data() - self.assertEqual(len(carbon_intensity.keys()), 21) + self.assertEqual(len(carbon_intensity.keys()), 27) self.assertGreater(carbon_intensity["coal"], 800) self.assertLess(carbon_intensity["wind"], 80) + def test_energy_mix_with_biomass_and_waste_is_not_dropped(self): + """ + A mix carrying biomass and waste must be priced from the factor table. + Without a factor for them, the two types are left out of the computed + sum, the sanity check fails and the world average is returned (#1415). + """ + # GIVEN + factors = DataSource().get_carbon_intensity_per_source_data() + energy_mix = { + "total_TWh": 10.0, + "hydroelectricity_TWh": 6.0, + "biomass_TWh": 3.0, + "waste_TWh": 1.0, + } + + # WHEN + rate = Emissions._global_energy_mix_to_emissions_rate(energy_mix) + + # THEN + self.assertNotAlmostEqual( + rate.kgs_per_kWh * 1000, factors["world_average"], places=6 + ) + expected = ( + 6.0 * factors["hydroelectricity"] + + 3.0 * factors["biomass"] + + 1.0 * factors["waste"] + ) / 10.0 + self.assertAlmostEqual(rate.kgs_per_kWh * 1000, expected, places=6) + + def test_energy_mix_with_biofuel_key_from_global_energy_mix(self): + """ + global_energy_mix.json names bioenergy generation ``biofuel_TWh``, so + the factor has to be reachable under that name as well. + """ + # GIVEN + factors = DataSource().get_carbon_intensity_per_source_data() + energy_mix = { + "total_TWh": 10.0, + "hydroelectricity_TWh": 6.0, + "biofuel_TWh": 4.0, + } + + # WHEN + rate = Emissions._global_energy_mix_to_emissions_rate(energy_mix) + + # THEN + self.assertNotAlmostEqual( + rate.kgs_per_kWh * 1000, factors["world_average"], places=6 + ) + expected = (6.0 * factors["hydroelectricity"] + 4.0 * factors["biomass"]) / 10.0 + self.assertEqual(factors["biofuel"], factors["biomass"]) + self.assertAlmostEqual(rate.kgs_per_kWh * 1000, expected, places=6) + def test_get_emissions_PRIVATE_INFRA_FRA(self): """ European country is a specific case as we have there carbon intensity to