From d2e3d4c6506d01c5c86d306afb8c03c0b2371e00 Mon Sep 17 00:00:00 2001 From: Femke Janssen <137757789+FJanssen-TNO@users.noreply.github.com> Date: Tue, 12 Mar 2024 14:18:58 +0100 Subject: [PATCH] 112 utilize carrier cost in esdl for price profile in electricity (#131) Included costs of electricity for heat pumps. Refactor to update the component type of the electric heatpump to reamin heat_pump and the subcomponent type to be heat_pump_elec. This prevents forgetting to add heat_pump_elec to specific loops Added function to be used in future when extracting multiple assettypes, to prevent overlapping and thus duplicating constraints or assets in the objective function --- src/rtctools_heat_network/asset_sizing_mixin.py | 2 -- src/rtctools_heat_network/base_component_type_mixin.py | 7 +++++++ src/rtctools_heat_network/esdl/asset_to_component_base.py | 1 - .../esdl/esdl_additional_vars_mixin.py | 1 - src/rtctools_heat_network/financial_mixin.py | 6 ++++-- src/rtctools_heat_network/heat_physics_mixin.py | 3 --- .../component_library/milp/electricity/heat_pump_elec.py | 8 +++----- .../workflows/goals/minimize_tco_goal.py | 1 - tests/utils_tests.py | 4 ---- 9 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/rtctools_heat_network/asset_sizing_mixin.py b/src/rtctools_heat_network/asset_sizing_mixin.py index 099ab133..2176cc30 100644 --- a/src/rtctools_heat_network/asset_sizing_mixin.py +++ b/src/rtctools_heat_network/asset_sizing_mixin.py @@ -800,7 +800,6 @@ def _make_max_size_var(name, lb, ub, nominal): for asset_name in [ *self.energy_system_components.get("heat_exchanger", []), *self.energy_system_components.get("heat_pump", []), - *self.energy_system_components.get("heat_pump_elec", []), ]: ub = bounds[f"{asset_name}.Secondary_heat"][1] lb = 0.0 if parameters[f"{asset_name}.state"] != 1 else ub @@ -1802,7 +1801,6 @@ def __max_size_constraints(self, ensemble_member): for hx in [ *self.energy_system_components.get("heat_exchanger", []), *self.energy_system_components.get("heat_pump", []), - *self.energy_system_components.get("heat_pump_elec", []), ]: max_var = self._asset_max_size_map[hx] max_heat = self.extra_variable(max_var, ensemble_member) diff --git a/src/rtctools_heat_network/base_component_type_mixin.py b/src/rtctools_heat_network/base_component_type_mixin.py index d140314e..c9a04ff5 100644 --- a/src/rtctools_heat_network/base_component_type_mixin.py +++ b/src/rtctools_heat_network/base_component_type_mixin.py @@ -20,6 +20,13 @@ def energy_system_components(self) -> Dict[str, str]: """ raise NotImplementedError + def energy_system_components_get(self, list_types: list) -> list: + components = [] + for component_type in list_types: + components.extend(self.energy_system_components.get(component_type)) + components = list(set(components)) + return components + @property @abstractmethod def energy_system_topology(self) -> Topology: diff --git a/src/rtctools_heat_network/esdl/asset_to_component_base.py b/src/rtctools_heat_network/esdl/asset_to_component_base.py index 9f59059f..9b037717 100644 --- a/src/rtctools_heat_network/esdl/asset_to_component_base.py +++ b/src/rtctools_heat_network/esdl/asset_to_component_base.py @@ -256,7 +256,6 @@ def _is_disconnectable_pipe(self, asset: Asset) -> bool: "ates", "heat_exchanger", "heat_pump", - "heat_pump_elec", } } diff --git a/src/rtctools_heat_network/esdl/esdl_additional_vars_mixin.py b/src/rtctools_heat_network/esdl/esdl_additional_vars_mixin.py index e8b03c45..f8784595 100644 --- a/src/rtctools_heat_network/esdl/esdl_additional_vars_mixin.py +++ b/src/rtctools_heat_network/esdl/esdl_additional_vars_mixin.py @@ -24,7 +24,6 @@ def read(self): *self.energy_system_components.get("ates", []), *self.energy_system_components.get("heat_buffer", []), *self.energy_system_components.get("heat_pump", []), - *self.energy_system_components.get("heat_pump_elec", []), ]: esdl_asset = self.esdl_assets[self.esdl_asset_name_to_id_map[asset]] for constraint in esdl_asset.attributes.get("constraint", []): diff --git a/src/rtctools_heat_network/financial_mixin.py b/src/rtctools_heat_network/financial_mixin.py index 653893f9..cab10716 100644 --- a/src/rtctools_heat_network/financial_mixin.py +++ b/src/rtctools_heat_network/financial_mixin.py @@ -140,7 +140,6 @@ def pre(self): elif asset_name in [ *self.energy_system_components.get("heat_exchanger", []), *self.energy_system_components.get("heat_pump", []), - *self.energy_system_components.get("heat_pump_elec", []), ]: nominal_fixed_operational = self.variable_nominal(f"{asset_name}.Secondary_heat") nominal_variable_operational = nominal_fixed_operational @@ -802,7 +801,6 @@ def __variable_operational_cost_constraints(self, ensemble_member): for hp in [ *self.energy_system_components.get("heat_pump", []), - *self.energy_system_components.get("heat_pump_elec", []), ]: elec_consumption = self.__state_vector_scaled(f"{hp}.Power_elec", ensemble_member) variable_operational_cost_var = self._asset_variable_operational_cost_map[hp] @@ -835,6 +833,10 @@ def __variable_operational_cost_constraints(self, ensemble_member): variable_operational_cost_coefficient * elec_consumption[i] * timesteps[i - 1] ) sum += price_profile.values[i] * pump_power[i] * timesteps[i - 1] / eff + if hp not in self.energy_system_components.get("heat_pump_elec", []): + # assuming that if heatpump has electricity port, the cost for the electricity + # are already made by the electricity producer and transport + sum += price_profile.values[i] * elec_consumption[i] * timesteps[i - 1] constraints.append(((variable_operational_cost - sum) / nominal, 0.0, 0.0)) diff --git a/src/rtctools_heat_network/heat_physics_mixin.py b/src/rtctools_heat_network/heat_physics_mixin.py index 913f33ef..8acf6508 100644 --- a/src/rtctools_heat_network/heat_physics_mixin.py +++ b/src/rtctools_heat_network/heat_physics_mixin.py @@ -295,7 +295,6 @@ def _get_min_bound(bound): for hex in [ *self.energy_system_components.get("heat_exchanger", []), *self.energy_system_components.get("heat_pump", []), - *self.energy_system_components.get("heat_pump_elec", []), ]: disabeld_hex_var = f"{hex}__disabled" self.__disabled_hex_map[hex] = disabeld_hex_var @@ -1791,7 +1790,6 @@ def __heat_exchanger_heat_to_discharge_path_constraints(self, ensemble_member): for heat_exchanger in [ *self.energy_system_components.get("heat_exchanger", []), *self.energy_system_components.get("heat_pump", []), - *self.energy_system_components.get("heat_pump_elec", []), ]: cp_prim = parameters[f"{heat_exchanger}.Primary.cp"] rho_prim = parameters[f"{heat_exchanger}.Primary.rho"] @@ -2505,7 +2503,6 @@ def __heat_pump_cop_constraints(self, ensemble_member): for hp in [ *self.energy_system_components.get("heat_pump", []), - *self.energy_system_components.get("heat_pump_elec", []), ]: sec_sup_carrier = parameters[f"{hp}.Secondary.T_supply_id"] sec_ret_carrier = parameters[f"{hp}.Secondary.T_return_id"] diff --git a/src/rtctools_heat_network/pycml/component_library/milp/electricity/heat_pump_elec.py b/src/rtctools_heat_network/pycml/component_library/milp/electricity/heat_pump_elec.py index 3649718d..dfc1faa0 100644 --- a/src/rtctools_heat_network/pycml/component_library/milp/electricity/heat_pump_elec.py +++ b/src/rtctools_heat_network/pycml/component_library/milp/electricity/heat_pump_elec.py @@ -8,9 +8,9 @@ # where this is then placed. class HeatPumpElec(HeatPump): """ - The milp pump elec is to model a water-water heatpump where we explicitly model its connection + The heat pump elec is to model a water-water heatpump where we explicitly model its connection to the electricity grid. This allows to potentially optimize for electricity network constraints - in the optimization of the milp network and vice-versa. + in the optimization of the heat network and vice-versa. """ def __init__(self, name, **modifiers): @@ -22,9 +22,7 @@ def __init__(self, name, **modifiers): ), ) - # TODO: potentially we can keep the component type as heat_pump and set subcomponent to - # heat_pump_elec, first need to check if there wouldn't be anything conflicting then. - self.component_type = "heat_pump_elec" + self.component_subtype = "heat_pump_elec" self.min_voltage = 1.0e4 self.add_variable(ElectricityPort, "ElectricityIn") diff --git a/src/rtctools_heat_network/workflows/goals/minimize_tco_goal.py b/src/rtctools_heat_network/workflows/goals/minimize_tco_goal.py index cd636754..f08944fb 100644 --- a/src/rtctools_heat_network/workflows/goals/minimize_tco_goal.py +++ b/src/rtctools_heat_network/workflows/goals/minimize_tco_goal.py @@ -40,7 +40,6 @@ def __init__( "heat_source", "ates", "heat_pump", - "heat_pump_elec", "pump", "heat_exchanger", "heat_buffer", diff --git a/tests/utils_tests.py b/tests/utils_tests.py index c21c153b..5d51c444 100644 --- a/tests/utils_tests.py +++ b/tests/utils_tests.py @@ -199,7 +199,6 @@ def heat_to_discharge_test(solution, results): for d in [ *solution.energy_system_components.get("heat_exchanger", []), *solution.energy_system_components.get("heat_pump", []), - *solution.energy_system_components.get("heat_pump_elec", []), ]: for p in ["Primary", "Secondary"]: cp = solution.parameters(0)[f"{d}.{p}.cp"] @@ -308,9 +307,6 @@ def energy_conservation_test(solution, results): for d in solution.energy_system_components.get("heat_pump", []): energy_sum += results[f"{d}.Power_elec"] - for d in solution.energy_system_components.get("heat_pump_elec", []): - energy_sum += results[f"{d}.Power_elec"] - for p in solution.energy_system_components.get("heat_pipe", []): energy_sum -= abs(results[f"{p}.HeatIn.Heat"] - results[f"{p}.HeatOut.Heat"]) if f"{p}__is_disconnected" in results.keys():