diff --git a/AUTHORS.rst b/AUTHORS.rst index 761a1d08..9fd7ba93 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -15,3 +15,4 @@ Authors * Julian Endres * Felix Maurer * Pierre-Francois Duc +* Sabine Haas diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ceebef4f..bd12790c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,7 @@ Unreleased Features * Improve the function to infer package metadata `#173 `_ +* Add optional emission buses to conversion and extraction turbine facades `#170 `_ Fixes diff --git a/src/oemof/tabular/facades/conversion.py b/src/oemof/tabular/facades/conversion.py index 133e5560..1ee8cb7e 100644 --- a/src/oemof/tabular/facades/conversion.py +++ b/src/oemof/tabular/facades/conversion.py @@ -44,6 +44,8 @@ class Conversion(Converter, Facade): ouput_parameters: dict (optional) Set parameters on the output edge of the conversion unit (see oemof.solph for more information on possible parameters) + emissions: dict (optional) + Add emission bus(es) as output flow(s). ({solph.Bus: float}) .. math:: @@ -105,6 +107,8 @@ class Conversion(Converter, Facade): output_parameters: dict = field(default_factory=dict) + emissions: dict = field(default_factory=dict) + def build_solph_components(self): """ """ self.conversion_factors.update( @@ -132,3 +136,12 @@ def build_solph_components(self): ) } ) + + if self.emissions: + self.outputs.update({bus: Flow() for bus in self.emissions.keys()}) + self.conversion_factors.update( + { + bus: sequence(emission_factor) + for bus, emission_factor in self.emissions.items() + } + ) diff --git a/src/oemof/tabular/facades/extraction_turbine.py b/src/oemof/tabular/facades/extraction_turbine.py index 45a31576..49b69229 100644 --- a/src/oemof/tabular/facades/extraction_turbine.py +++ b/src/oemof/tabular/facades/extraction_turbine.py @@ -58,6 +58,8 @@ class ExtractionTurbine(ExtractionTurbineCHP, Facade): fixed_costs : numeric (iterable or scalar) (optional) The fixed costs associated with a flow. Note: Only applicable for a multi-period model. Default: None. + emissions: dict (optional) + Add emission bus(es) as output flow(s). ({solph.Bus: float}) The mathematical description is derived from the oemof base class @@ -149,6 +151,8 @@ class ExtractionTurbine(ExtractionTurbineCHP, Facade): conversion_factor_full_condensation: dict = field(default_factory=dict) + emissions: dict = field(default_factory=dict) + def build_solph_components(self): """ """ self.conversion_factors.update( @@ -181,3 +185,12 @@ def build_solph_components(self): self.conversion_factor_full_condensation.update( {self.electricity_bus: sequence(self.condensing_efficiency)} ) + + if self.emissions: + self.outputs.update({bus: Flow() for bus in self.emissions.keys()}) + self.conversion_factors.update( + { + bus: sequence(emission_factor) + for bus, emission_factor in self.emissions.items() + } + ) diff --git a/tests/_files/lp_files/conversion_em_buses.lp b/tests/_files/lp_files/conversion_em_buses.lp new file mode 100644 index 00000000..fd29553c --- /dev/null +++ b/tests/_files/lp_files/conversion_em_buses.lp @@ -0,0 +1,92 @@ +\* Source Pyomo model name=Model *\ + +min +objective: ++0 ONE_VAR_CONSTANT + +s.t. + +c_e_BusBlock_balance(biomass_0_0)_: ++1 flow(biomass_biomass_plant_0_0) += 0 + +c_e_BusBlock_balance(biomass_0_1)_: ++1 flow(biomass_biomass_plant_0_1) += 0 + +c_e_BusBlock_balance(biomass_0_2)_: ++1 flow(biomass_biomass_plant_0_2) += 0 + +c_e_BusBlock_balance(heat_0_0)_: ++1 flow(biomass_plant_heat_0_0) += 0 + +c_e_BusBlock_balance(heat_0_1)_: ++1 flow(biomass_plant_heat_0_1) += 0 + +c_e_BusBlock_balance(heat_0_2)_: ++1 flow(biomass_plant_heat_0_2) += 0 + +c_e_ConverterBlock_relation(biomass_plant_biomass_heat_0_0)_: ++0.4 flow(biomass_biomass_plant_0_0) +-1 flow(biomass_plant_heat_0_0) += 0 + +c_e_ConverterBlock_relation(biomass_plant_biomass_co2_em_0_0)_: ++0.5 flow(biomass_biomass_plant_0_0) +-1 flow(biomass_plant_co2_em_0_0) += 0 + +c_e_ConverterBlock_relation(biomass_plant_biomass_ch4_em_0_0)_: ++10 flow(biomass_biomass_plant_0_0) +-1 flow(biomass_plant_ch4_em_0_0) += 0 + +c_e_ConverterBlock_relation(biomass_plant_biomass_heat_0_1)_: ++0.4 flow(biomass_biomass_plant_0_1) +-1 flow(biomass_plant_heat_0_1) += 0 + +c_e_ConverterBlock_relation(biomass_plant_biomass_co2_em_0_1)_: ++0.5 flow(biomass_biomass_plant_0_1) +-1 flow(biomass_plant_co2_em_0_1) += 0 + +c_e_ConverterBlock_relation(biomass_plant_biomass_ch4_em_0_1)_: ++10 flow(biomass_biomass_plant_0_1) +-1 flow(biomass_plant_ch4_em_0_1) += 0 + +c_e_ConverterBlock_relation(biomass_plant_biomass_heat_0_2)_: ++0.4 flow(biomass_biomass_plant_0_2) +-1 flow(biomass_plant_heat_0_2) += 0 + +c_e_ConverterBlock_relation(biomass_plant_biomass_co2_em_0_2)_: ++0.5 flow(biomass_biomass_plant_0_2) +-1 flow(biomass_plant_co2_em_0_2) += 0 + +c_e_ConverterBlock_relation(biomass_plant_biomass_ch4_em_0_2)_: ++10 flow(biomass_biomass_plant_0_2) +-1 flow(biomass_plant_ch4_em_0_2) += 0 + +bounds + 1 <= ONE_VAR_CONSTANT <= 1 + 0 <= flow(biomass_biomass_plant_0_0) <= +inf + 0 <= flow(biomass_biomass_plant_0_1) <= +inf + 0 <= flow(biomass_biomass_plant_0_2) <= +inf + 0 <= flow(biomass_plant_heat_0_0) <= 100 + 0 <= flow(biomass_plant_heat_0_1) <= 100 + 0 <= flow(biomass_plant_heat_0_2) <= 100 + 0 <= flow(biomass_plant_co2_em_0_0) <= +inf + 0 <= flow(biomass_plant_co2_em_0_1) <= +inf + 0 <= flow(biomass_plant_co2_em_0_2) <= +inf + 0 <= flow(biomass_plant_ch4_em_0_0) <= +inf + 0 <= flow(biomass_plant_ch4_em_0_1) <= +inf + 0 <= flow(biomass_plant_ch4_em_0_2) <= +inf +end diff --git a/tests/_files/lp_files/extraction_em_buses.lp b/tests/_files/lp_files/extraction_em_buses.lp new file mode 100644 index 00000000..53934763 --- /dev/null +++ b/tests/_files/lp_files/extraction_em_buses.lp @@ -0,0 +1,90 @@ +\* Source Pyomo model name=Model *\ + +min +objective: ++0.6 flow(gas_extraction_0_0) ++0.6 flow(gas_extraction_0_1) ++0.6 flow(gas_extraction_0_2) + +s.t. + +c_e_BusBlock_balance(electricity_0_0)_: ++1 flow(extraction_electricity_0_0) += 0 + +c_e_BusBlock_balance(electricity_0_1)_: ++1 flow(extraction_electricity_0_1) += 0 + +c_e_BusBlock_balance(electricity_0_2)_: ++1 flow(extraction_electricity_0_2) += 0 + +c_e_BusBlock_balance(gas_0_0)_: ++1 flow(gas_extraction_0_0) += 0 + +c_e_BusBlock_balance(gas_0_1)_: ++1 flow(gas_extraction_0_1) += 0 + +c_e_BusBlock_balance(gas_0_2)_: ++1 flow(gas_extraction_0_2) += 0 + +c_e_BusBlock_balance(heat_0_0)_: ++1 flow(extraction_heat_0_0) += 0 + +c_e_BusBlock_balance(heat_0_1)_: ++1 flow(extraction_heat_0_1) += 0 + +c_e_BusBlock_balance(heat_0_2)_: ++1 flow(extraction_heat_0_2) += 0 + +c_e_ExtractionTurbineCHPBlock_input_output_relation(extraction_0_0)_: ++1 flow(gas_extraction_0_0) +-2.0 flow(extraction_electricity_0_0) +-0.5714285714285713 flow(extraction_heat_0_0) += 0 + +c_e_ExtractionTurbineCHPBlock_input_output_relation(extraction_0_1)_: ++1 flow(gas_extraction_0_1) +-2.0 flow(extraction_electricity_0_1) +-0.5714285714285713 flow(extraction_heat_0_1) += 0 + +c_e_ExtractionTurbineCHPBlock_input_output_relation(extraction_0_2)_: ++1 flow(gas_extraction_0_2) +-2.0 flow(extraction_electricity_0_2) +-0.5714285714285713 flow(extraction_heat_0_2) += 0 + +c_u_ExtractionTurbineCHPBlock_out_flow_relation(extraction_0_0)_: +-1 flow(extraction_electricity_0_0) ++1.142857142857143 flow(extraction_heat_0_0) +<= 0 + +c_u_ExtractionTurbineCHPBlock_out_flow_relation(extraction_0_1)_: +-1 flow(extraction_electricity_0_1) ++1.142857142857143 flow(extraction_heat_0_1) +<= 0 + +c_u_ExtractionTurbineCHPBlock_out_flow_relation(extraction_0_2)_: +-1 flow(extraction_electricity_0_2) ++1.142857142857143 flow(extraction_heat_0_2) +<= 0 + +bounds + 0 <= flow(gas_extraction_0_0) <= +inf + 0 <= flow(gas_extraction_0_1) <= +inf + 0 <= flow(gas_extraction_0_2) <= +inf + 0 <= flow(extraction_electricity_0_0) <= 1000 + 0 <= flow(extraction_electricity_0_1) <= 1000 + 0 <= flow(extraction_electricity_0_2) <= 1000 + 0 <= flow(extraction_heat_0_0) <= +inf + 0 <= flow(extraction_heat_0_1) <= +inf + 0 <= flow(extraction_heat_0_2) <= +inf +end diff --git a/tests/test_constraints.py b/tests/test_constraints.py index 6111e93d..acd5f0e5 100644 --- a/tests/test_constraints.py +++ b/tests/test_constraints.py @@ -303,6 +303,34 @@ def test_extraction_investment_brown_field(self): self.compare_to_reference_lp("extraction_investment_brown_field.lp") + def test_extraction_with_emission_buses(self): + r""" + ExtractionTurbine investment with emission busses. + """ + bus_fuel = solph.Bus(label="gas") + bus_el = solph.Bus(label="electricity") + bus_heat = solph.Bus(label="heat") + bus_co2_em = solph.Bus("co2_em") + bus_ch4_em = solph.Bus("ch4_em") + + extchp = ExtractionTurbine( + label="extraction", + carrier="gas", + tech="extraction", + fuel_bus=bus_fuel, + heat_bus=bus_heat, + electricity_bus=bus_el, + emissions={bus_co2_em: 0.5, bus_ch4_em: 10}, + capacity=1000, + carrier_cost=0.6, + condensing_efficiency=0.5, + electric_efficiency=0.4, + thermal_efficiency=0.35, + ) + self.energysystem.add(bus_el, bus_fuel, bus_heat, extchp) + + self.compare_to_reference_lp("extraction_em_buses.lp") + def test_commodity(self): r""" """ bus_biomass = solph.Bus("biomass") @@ -337,6 +365,27 @@ def test_conversion(self): self.compare_to_reference_lp("conversion.lp") + def test_conversion_with_emission_buses(self): + r""" """ + bus_biomass = solph.Bus("biomass") + bus_heat = solph.Bus("heat") + bus_co2_em = solph.Bus("co2_em") + bus_ch4_em = solph.Bus("ch4_em") + + conversion = Conversion( + label="biomass_plant", + carrier="biomass", + tech="st", + from_bus=bus_biomass, + to_bus=bus_heat, + emissions={bus_co2_em: 0.5, bus_ch4_em: 10}, + capacity=100, + efficiency=0.4, + ) + self.energysystem.add(bus_heat, bus_biomass, conversion) + + self.compare_to_reference_lp("conversion_em_buses.lp") + def test_dispatchable(self): bus = solph.Bus("electricity")