diff --git a/co2calculator/calculate.py b/co2calculator/calculate.py index d240d3d..53e78c1 100644 --- a/co2calculator/calculate.py +++ b/co2calculator/calculate.py @@ -46,75 +46,6 @@ conversion_factors = ConversionFactors() -def calc_co2_electricity( - consumption: float, fuel_type: ElectricityFuel = None, energy_share: float = 1 -) -> Kilogram: - """Function to compute electricity emissions - - :param consumption: energy consumption - :param fuel_type: energy (mix) used for electricity [german_energy_mix, solar] - :param energy_share: the research group's approximate share of the total electricity energy consumption - :type consumption: float - :type fuel_type: str - :type energy_share: float - :return: total emissions of electricity energy consumption - :rtype: Kilogram - """ - - # Validate parameters - params_extracted = {k: v for k, v in locals().items() if v is not None} - params = ElectricityEmissionParameters(**params_extracted) - - # Get the co2 factor - co2e = emission_factors.get(params.dict()) - - # co2 equivalents for heating and electricity refer to a consumption of 1 TJ - # so consumption needs to be converted to TJ - return consumption * energy_share / KWH_TO_TJ * co2e - - -def calc_co2_heating( - consumption: float, - fuel_type: HeatingFuel, - unit: Unit = None, - area_share: float = 1.0, -) -> Kilogram: - """Function to compute heating emissions - - :param consumption: energy consumption - :param fuel_type: fuel type used for heating - [coal, district_heating, electricity, gas, heat_pump_air, - heat_pump_ground, liquid_gas, oil, pellet, solar, woodchips] - :param unit: unit of energy consumption [kwh, kg, l, m^3] - :param area_share: share of building area used by research group - :type consumption: float - :type fuel_type: str - :type unit: str - :type area_share: float - :return: total emissions of heating energy consumption - :rtype: Kilogram - """ - # Validate parameters - assert 0 < area_share <= 1 - params_extracted = {k: v for k, v in locals().items() if v is not None} - params = HeatingEmissionParameters(**params_extracted) - - # Get the co2 factor - co2e = emission_factors.get(params.dict()) - - if unit is not Unit.KWH: - # Get the conversion factor - conversion_factor = conversion_factors.get(fuel_type=fuel_type, unit=unit) - - consumption_kwh = consumption * conversion_factor - else: - consumption_kwh = consumption - - # co2 equivalents for heating and electricity refer to a consumption of 1 TJ - # so consumption needs to be converted to TJ - return consumption_kwh * area_share / KWH_TO_TJ * co2e - - def calc_co2_businesstrip( transportation_mode: TransportationMode, start=None, diff --git a/co2calculator/energy/__init__.py b/co2calculator/energy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/co2calculator/energy/calculate_energy.py b/co2calculator/energy/calculate_energy.py new file mode 100644 index 0000000..a473674 --- /dev/null +++ b/co2calculator/energy/calculate_energy.py @@ -0,0 +1,81 @@ +"""Function colleciton to calculate energy type co2 emissions""" + +from ctypes import Union +from co2calculator.constants import KWH_TO_TJ, Unit +from co2calculator.data_handlers import ConversionFactors, EmissionFactors +from co2calculator.parameters import ( + ElectricityEmissionParameters, + ElectricityParameters, + HeatingEmissionParameters, + HeatingParameters, +) +from co2calculator._types import Kilogram + +emission_factors = EmissionFactors() +conversion_factors = ConversionFactors() + + +def calc_co2_heating( + consumption: float, + options: Union[HeatingParameters, dict] = None, +) -> Kilogram: + """Function to compute heating emissions + + :param consumption: energy consumption + :param options: parameters for heating emissions calculation + :type consumption: float + :type options: HeatingParameters | dict + :return: total emissions of heating energy consumption + :rtype: Kilogram + """ + # Validate parameters + if options is None: + options = {} + params = HeatingParameters(**options) + emission_params = HeatingEmissionParameters(**params.heating_emission_parameters) + + # Get the co2 factor + co2e = emission_factors.get(params.dict()) + + if params.unit is not Unit.KWH: + # Get the conversion factor + conversion_factor = ConversionFactors.get( + fuel_type=emission_params.fuel_type, unit=params.unit + ) + + consumption_kwh = consumption * conversion_factor + else: + consumption_kwh = consumption + + # co2 equivalents for heating and electricity refer to a consumption of 1 TJ + # so consumption needs to be converted to TJ + return consumption_kwh * params.area_share / KWH_TO_TJ * co2e + + +def calc_co2_electricity( + consumption: float, options: Union[ElectricityParameters, dict] = None +) -> Kilogram: + """Function to compute electricity emissions + + :param consumption: energy consumption + :param fuel_type: energy (mix) used for electricity [german_energy_mix, solar] + :param energy_share: the research group's approximate share of the total electricity energy consumption + :type consumption: float + :type fuel_type: str + :type energy_share: float + :return: total emissions of electricity energy consumption + :rtype: Kilogram + """ + + # Validate parameters + if options is None: + options = {} + params = ElectricityParameters(**options) + emission_params = ElectricityEmissionParameters(**params) + + # Get the co2 factor + co2e = emission_factors.get(params.dict()) + + # co2 equivalents for heating and electricity refer to a consumption of 1 TJ + # so consumption needs to be converted to TJ + return consumption * emission_params.energy_share / KWH_TO_TJ * co2e diff --git a/co2calculator/parameters.py b/co2calculator/parameters.py index 9582a1b..312848e 100644 --- a/co2calculator/parameters.py +++ b/co2calculator/parameters.py @@ -174,6 +174,16 @@ def check_fueltype(cls, v): return ElectricityFuel(v) +class ElectricityParameters(BaseModel): + electricity_emission_parameters: ElectricityEmissionParameters + energy_share: float + + @validator("energy_share", allow_reuse=True) + def check_energy_share(cls, v): + assert 0 <= v <= 1 + return v + + class HeatingEmissionParameters(BaseModel): fuel_type: Union[Size, str] = HeatingFuel.GAS @@ -184,3 +194,21 @@ def check_fueltype(cls, v): assert v.lower() in (item.value for item in HeatingFuel) v = v.lower() return HeatingFuel(v) + + +class HeatingParameters(BaseModel): + heating_emission_parameters: HeatingEmissionParameters + unit: Unit + area_share: float + + @validator("unit", allow_reuse=True) + def check_unit(cls, v): + if isinstance(v, str): + assert v.lower() in (item.value for item in Unit) + v = v.lower() + return Unit(v) + + @validator("area_share", allow_reuse=True) + def check_area_share(cls, v): + assert 0 <= v <= 1 + return v diff --git a/tests/unit/test_calculate.py b/tests/unit/test_calculate.py index 1e9dd9e..85714d7 100644 --- a/tests/unit/test_calculate.py +++ b/tests/unit/test_calculate.py @@ -14,38 +14,6 @@ # @pytest.mark.skip( # reason="Failing right now, but units will change anyways. let's check after the co2factors are updated" # ) -def test_heating_woodchips(): - """Test co2e calculation for heating: woodchips""" - # Given parameters - fuel_type = "woodchips" # emission factor: 9322 kg/TJ - consumption = 250 - unit = "kg" # conversion factor to kWh = 5.4 - # divide by 277777.77777778 to convert from TJ to kWh - co2e_kg_expected = 43.63 - - # Calculate co2e - co2e = candidate.calc_co2_heating( - consumption=consumption, unit=unit, fuel_type=fuel_type - ) - - # Check if expected result matches calculated result - assert co2e == pytest.approx(co2e_kg_expected, rel=0.01) - - -def test_electricity(): - """Test co2e calculation for electricity""" - # Given parameters - fuel_type = "german_energy_mix" - consumption_kwh = 10000 - co2e_kg_expected = 3942.65 # emission factor: 109518 kg/TJ - - # Calculate co2e - co2e = candidate.calc_co2_electricity( - consumption=consumption_kwh, fuel_type=fuel_type - ) - - # Check if expected result matches calculated result - assert co2e == pytest.approx(co2e_kg_expected, rel=0.01) @pytest.mark.parametrize( diff --git a/tests/unit/test_calculate_energy.py b/tests/unit/test_calculate_energy.py new file mode 100644 index 0000000..d99a461 --- /dev/null +++ b/tests/unit/test_calculate_energy.py @@ -0,0 +1,46 @@ +"""tests for energy calculation""" +import co2calculator.energy.calculate_energy as energy +import pytest + + +def test_heating_woodchips(): + """Test co2e calculation for heating: woodchips""" + # Given parameters + consumption = 250 + co2e_kg_expected = 43.63 + + func_options = { + # Given parameters + "heating_emission_parameters": { + "fuel_type": "woodchips" # emission factor: 9322 kg/TJ + }, + "unit": "kg", # conversion factor to kWh = 5.4 + } + + # Calculate co2e + co2e = energy.calc_co2_heating(consumption=consumption, options=func_options) + + # Check if expected result matches calculated result + assert co2e == pytest.approx(co2e_kg_expected, rel=0.01) + + +def test_electricity(): + """Test co2e calculation for electricity""" + # Given parameters + fuel_type = "german_energy_mix" + consumption_kwh = 10000 + co2e_kg_expected = 3942.65 # emission factor: 109518 kg/TJ + + func_options = { + "electricity_emission_parameters": { + "fuel_type": "german_energy_mix" # emission factor: 109518 kg/TJ + } + } + + # Calculate co2e + co2e = energy.calc_co2_electricity( + consumption=consumption_kwh, options=func_options + ) + + # Check if expected result matches calculated result + assert co2e == pytest.approx(co2e_kg_expected, rel=0.01)