diff --git a/CHANGELOG.md b/CHANGELOG.md index c693e5c2e..26af174ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - xxx ## Fixed -- xxx +- Removing the use of the electricity price profile for heat assets that have an ElectricityPort connecting to an electricity network. # [0.1.19] - 2026-06-08 diff --git a/examples/heating_and_cooling/src/run_case.py b/examples/heating_and_cooling/src/run_case.py index 30eb042dd..8c3ced4c1 100644 --- a/examples/heating_and_cooling/src/run_case.py +++ b/examples/heating_and_cooling/src/run_case.py @@ -87,6 +87,11 @@ def heating_cooling_case(self): np.testing.assert_array_less(1e3, results[f"{a_1_id}__fixed_operational_cost"]) np.testing.assert_array_less(1e3, results[f"{hp_1_id}__investment_cost"]) np.testing.assert_array_less(1e3, results[f"{hp_1_id}__installation_cost"]) + # TODO: The heat pump __variable_operational_cost check below will fail due the heat pump + # variable cost not including the electricty profile. The intend of this example case + # is to include a elect cost profile which still has to be + # accounted for via the "Import" asset. Once this asset is catered for in MESIDO it has to + # replace the elect producer in this example. np.testing.assert_array_less(1e3, results[f"{hp_1_id}__variable_operational_cost"]) np.testing.assert_array_less(1e3, results[f"{hp_1_id}__fixed_operational_cost"]) np.testing.assert_array_less(1e3, results[f"{ac_1_id}__investment_cost"]) diff --git a/src/mesido/esdl/esdl_heat_model.py b/src/mesido/esdl/esdl_heat_model.py index b16c2bf49..33d02e760 100644 --- a/src/mesido/esdl/esdl_heat_model.py +++ b/src/mesido/esdl/esdl_heat_model.py @@ -1384,11 +1384,11 @@ def convert_heat_pump(self, asset: Asset) -> Tuple[ # TODO: the power filled in at the heatpmp should always be the electric power, thus, # the max heat supply should be power*cop _, modifiers = self.convert_heat_source(asset) + modifiers.update(elec_power_nominal=modifiers["Heat_source"]["max"]) return AirWaterHeatPump, modifiers # In this case we only have the secondary side ports, here we assume a air-water HP elec if len(asset.in_ports) == 2 and len(asset.out_ports) == 1: - _, modifiers = self.convert_air_water_heat_pump_elec(asset) - return AirWaterHeatPumpElec, modifiers + return self.convert_air_water_heat_pump_elec(asset) if not asset.attributes["COP"]: raise _ESDLInputException( diff --git a/src/mesido/financial_mixin.py b/src/mesido/financial_mixin.py index 83480406c..14f1cfdb2 100644 --- a/src/mesido/financial_mixin.py +++ b/src/mesido/financial_mixin.py @@ -1055,10 +1055,11 @@ def __variable_operational_cost_constraints(self, ensemble_member): if (len(self.get_electricity_carriers().keys()) > 0) and s in [ *self.energy_system_components.get("heat_source_elec", []), - *self.energy_system_components.get("elec_heat_source_elec", []), - *self.energy_system_components.get("air_water_heat_pump_elec", []), - *self.energy_system_components.get("heat_pump_elec", []), + *self.energy_system_components.get("air_water_heat_pump", []), ]: + # Electricity priceprofile calculations on heat produced should only be performed + # if there is no electricity port at the asset, e.g. the asset is not connected + # to an electricity network in the model. sum_ += ( ca.sum1(price_profile[1:] * nominator_vector[1:] * timesteps_hr) / denominator ) diff --git a/src/mesido/pycml/component_library/milp/heat/air_water_heat_pump.py b/src/mesido/pycml/component_library/milp/heat/air_water_heat_pump.py index 88ee3e0d6..0d75ca4db 100644 --- a/src/mesido/pycml/component_library/milp/heat/air_water_heat_pump.py +++ b/src/mesido/pycml/component_library/milp/heat/air_water_heat_pump.py @@ -1,5 +1,8 @@ +from mesido.pycml import Variable from mesido.pycml.pycml_mixin import add_variables_documentation_automatically +from numpy import nan + from .heat_source import HeatSource @@ -21,3 +24,9 @@ def __init__(self, name, **modifiers): super().__init__(name, **modifiers) self.cop = modifiers["cop"] self.component_subtype = "air_water_heat_pump" + + self.elec_power_nominal = nan + + self.add_variable(Variable, "Power_elec", min=0.0, nominal=self.elec_power_nominal) + + self.add_equation(((self.Power_elec * self.cop - self.Heat_source) / self.Heat_nominal)) diff --git a/src/mesido/pycml/component_library/milp/multicommodity/airwater_heat_pump_elec.py b/src/mesido/pycml/component_library/milp/multicommodity/airwater_heat_pump_elec.py index bcf352b91..eee10b0df 100644 --- a/src/mesido/pycml/component_library/milp/multicommodity/airwater_heat_pump_elec.py +++ b/src/mesido/pycml/component_library/milp/multicommodity/airwater_heat_pump_elec.py @@ -1,4 +1,3 @@ -from mesido.pycml import Variable from mesido.pycml.component_library.milp.electricity.electricity_base import ElectricityPort from mesido.pycml.component_library.milp.heat.air_water_heat_pump import AirWaterHeatPump from mesido.pycml.pycml_mixin import add_variables_documentation_automatically @@ -37,13 +36,9 @@ def __init__(self, name, **modifiers): self.id_mapping_carrier = -1 self.min_voltage = nan - self.elec_power_nominal = nan # Assumption: heat in/out and added is nonnegative # Heat in the return (i.e. cold) line is zero self.add_variable(ElectricityPort, "ElectricityIn") - self.add_variable(Variable, "Power_elec", min=0.0, nominal=self.elec_power_nominal) self.add_equation(((self.ElectricityIn.Power - self.Power_elec) / self.elec_power_nominal)) - - self.add_equation(((self.Power_elec * self.cop - self.Heat_source) / self.Heat_nominal)) diff --git a/tests/utils_tests.py b/tests/utils_tests.py index 136f3b729..e9eb501b1 100644 --- a/tests/utils_tests.py +++ b/tests/utils_tests.py @@ -961,9 +961,8 @@ def cost_calculation_test(solution, results, check_objective_function=False, ato if (len(solution.get_electricity_carriers().keys()) > 0) and asset in [ *solution.energy_system_components.get("heat_source_elec", []), - *solution.energy_system_components.get("elec_heat_source_elec", []), - *solution.energy_system_components.get("air_water_heat_pump_elec", []), - *solution.energy_system_components.get("heat_pump_elec", []), + *solution.energy_system_components.get("air_water_heat_pump", []), + *solution.energy_system_components.get("heat_pump", []), ]: variable_operational_cost += sum( price_profile.values[1:] * nominator_vector[1:] * timesteps_hr / denominator