From a06a757ae44df491c32dc5e2757298dd439513ee Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Wed, 6 Dec 2023 16:37:53 +0100 Subject: [PATCH 01/27] more advanced heat pump model, example and tester --- .../more_advanced_heat_pump_hplib.py | 1567 +++++++++++++++++ ...ehold_with_more_advanced_hp_hws_dhw_hds.py | 264 +++ ...ehold_with_more_advanced_hp_hws_dhw_hds.py | 23 + 3 files changed, 1854 insertions(+) create mode 100644 hisim/components/more_advanced_heat_pump_hplib.py create mode 100644 system_setups/household_with_more_advanced_hp_hws_dhw_hds.py create mode 100644 tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py diff --git a/hisim/components/more_advanced_heat_pump_hplib.py b/hisim/components/more_advanced_heat_pump_hplib.py new file mode 100644 index 000000000..fd5de71a7 --- /dev/null +++ b/hisim/components/more_advanced_heat_pump_hplib.py @@ -0,0 +1,1567 @@ +"""Advanced heat pump module. + +See library on https://github.com/FZJ-IEK3-VSA/hplib/tree/main/hplib + +two controller: one dhw controller and one building heating controller + +priority on dhw, if there is a demand from both in one timestep + +preparation on district heating for water/water heatpumps + +""" +from typing import Any, List, Optional, Tuple, Dict +import hashlib +from dataclasses import dataclass +from dataclasses_json import dataclass_json +from dataclass_wizard import JSONWizard + +import pandas as pd + +from hplib import hplib as hpl + +# Import modules from HiSim +from hisim.component import ( + Component, + ComponentInput, + ComponentOutput, + SingleTimeStepValues, + ConfigBase, + ComponentConnection, + OpexCostDataClass, +) +from hisim.components import weather, simple_hot_water_storage, heat_distribution_system +from hisim.loadtypes import LoadTypes, Units, InandOutputType +from hisim.simulationparameters import SimulationParameters +from hisim.sim_repository_singleton import SingletonSimRepository, SingletonDictKeyEnum +from hisim.components.heat_distribution_system import HeatingSystemType +from hisim.components.configuration import EmissionFactorsAndCostsForFuelsConfig +from hisim import log +from hisim.components import generic_hot_water_storage_modular +from hisim.components.configuration import PhysicsConfig + +__authors__ = "Jonas Hoppe" +__copyright__ = "" +__credits__ = ["Jonas Hoppe"] +__license__ = "-" +__version__ = "" +__maintainer__ = "" +__status__ = "" + + +@dataclass_json +@dataclass +class HeatPumpHplibConfig(ConfigBase): + + """HeatPumpHPLibConfig.""" + + @classmethod + def get_main_classname(cls): + """Returns the full class name of the base class.""" + return HeatPumpHplib.get_full_classname() + + name: str + model: str + heat_source: str + group_id: int + heating_reference_temperature_in_celsius: float # before t_in + flow_temperature_in_celsius: float # before t_out_val + set_thermal_output_power_in_watt: float # before p_th_set + cycling_mode: bool + minimum_running_time_in_seconds: Optional[int] + minimum_idle_time_in_seconds: Optional[int] + hx_building_temp_diff: Optional[float] #to be used, if water/water or brine/water heatpump + #: CO2 footprint of investment in kg + co2_footprint: float + #: cost for investment in Euro + cost: float + #: lifetime in years + lifetime: float + # maintenance cost as share of investment [0..1] + maintenance_cost_as_percentage_of_investment: float + #: consumption of the heatpump in kWh + consumption: float + + @classmethod + def get_default_generic_advanced_hp_lib(cls) -> "HeatPumpHplibConfig": + """Gets a default HPLib Heat Pump. + + see default values for air/water hp on: + https://github.com/FZJ-IEK3-VSA/hplib/blob/main/hplib/hplib.py l.135 "fit_p_th_ref. + """ + set_thermal_output_power_in_watt: float = 8000 + return HeatPumpHplibConfig( + name="AdvancedHeatPumpHPLib", + model="Generic", + heat_source="air", + group_id=4, + heating_reference_temperature_in_celsius=-7, + flow_temperature_in_celsius=52, + set_thermal_output_power_in_watt=set_thermal_output_power_in_watt, + cycling_mode=True, + minimum_running_time_in_seconds=600, + minimum_idle_time_in_seconds=600, + hx_building_temp_diff=2, + co2_footprint=set_thermal_output_power_in_watt + * 1e-3 + * 165.84, # value from emission_factros_and_costs_devices.csv + cost=set_thermal_output_power_in_watt + * 1e-3 + * 1513.74, # value from emission_factros_and_costs_devices.csv + lifetime=10, # value from emission_factros_and_costs_devices.csv + maintenance_cost_as_percentage_of_investment=0.025, # source: VDI2067-1 + consumption=0, + ) + + @classmethod + def get_scaled_advanced_hp_lib( + cls, heating_load_of_building_in_watt: float + ) -> "HeatPumpHplibConfig": + """Gets a default heat pump with scaling according to heating load of the building.""" + + set_thermal_output_power_in_watt = heating_load_of_building_in_watt + + return HeatPumpHplibConfig( + name="AdvancedHeatPumpHPLib", + model="Generic", + group_id=4, + heating_reference_temperature_in_celsius=-7, + flow_temperature_in_celsius=52, + set_thermal_output_power_in_watt=set_thermal_output_power_in_watt, + cycling_mode=True, + minimum_running_time_in_seconds=600, + minimum_idle_time_in_seconds=600, + co2_footprint=set_thermal_output_power_in_watt + * 1e-3 + * 165.84, # value from emission_factros_and_costs_devices.csv + cost=set_thermal_output_power_in_watt + * 1e-3 + * 1513.74, # value from emission_factros_and_costs_devices.csv + lifetime=10, # value from emission_factros_and_costs_devices.csv + maintenance_cost_as_percentage_of_investment=0.025, # source: VDI2067-1 + consumption=0, + ) + + +class HeatPumpHplib(Component): + + # Inputs + OnOffSwitchHotWater = "OnOffSwitchHotWater" # 1 = on hot Water, 0 = 0ff + OnOffSwitchDHW = "OnOffSwitchDHW" #2 = on DHW , 0 = 0ff + ThermalPowerIsConstantforDHW = "ThermalPowerisConstantforDHW" # true/false + MaxThermalPowerforDHW = "MaxThermalPowerforDHW" # max. Leistungswert + TemperatureInputPrimary = "TemperatureInputPrimary" # °C + TemperatureInputSecondary_HotWater = "TemperatureInputSecondaryHotWater" # °C + TemperatureInputSecondary_DHW = "TemperatureInputSecondaryDWH" # °C + TemperatureAmbient = "TemperatureAmbient" # °C + + + # Outputs + ThermalOutputPowerHotWater = "ThermalOutputPowerHotWater" # W + ThermalOutputPowerDHW = "ThermalOutputPowerDHW" # W + ThermalOutputPowerGesamt = "ThermalOutputPowerWholeHeatpump" #W + ElectricalInputPowerHotWater = "ElectricalInputPowerHotWater" # W + ElectricalInputPowerDHW = "ElectricalInputPowerDHW" # W + ElectricalInputPowerGesamt = "ElectricalInputPowerWholeHeatpump" + COP = "COP" # - + EER = "EER" # - + heatpumpOnOffState = "OnOffStateHeatpump" + TemperatureOutputHotWater = "TemperatureOutputHotWater" # °C + TemperatureOutputDHW = "TemperatureOutputDHW" # °C + MassFlowOutputHotWater = "MassFlowOutputHotWater" # kg/s + MassFlowOutputDHW = "MassFlowOutputDHW" # kg/s + TimeOn = "TimeOn" # s + TimeOff = "TimeOff" # s + ThermalPowerFromEnvironment = "ThermalPowerInputFromEnvironment" #W + mdotWaterPrimaryDHNet = "MassflowHXBuildingDHNnet" # kg/s + WaterTemperatureHXIn = "TemperatureFromDHWNetInHX" # °C + WaterTemperatureHXOut = "TemperatureToDHWNetOutHX" # °C + + + + def __init__( + self, + my_simulation_parameters: SimulationParameters, + config: HeatPumpHplibConfig, + ): + + super().__init__( + name=config.name, + my_simulation_parameters=my_simulation_parameters, + my_config=config, + ) + + self.model = config.model + + self.group_id = config.group_id + + self.t_in = config.heating_reference_temperature_in_celsius + + self.t_out_val = config.flow_temperature_in_celsius + + self.p_th_set = config.set_thermal_output_power_in_watt + + self.cycling_mode = config.cycling_mode + + self.minimum_running_time_in_seconds = config.minimum_running_time_in_seconds + + self.minimum_idle_time_in_seconds = config.minimum_idle_time_in_seconds + + self.hx_building_temp_diff = config.hx_building_temp_diff + + self.heat_source = config.heat_source + + #self.on_off: int = 0 + + postprocessing_flag = [InandOutputType.ELECTRICITY_CONSUMPTION_UNCONTROLLED] + + # Component has states + self.state = HeatPumpState( + time_on=0, time_off=0, time_on_cooling=0, on_off_previous=0 + ) + self.previous_state = self.state.self_copy() + + # Load parameters from heat pump database + self.parameters = hpl.get_parameters( + self.model, self.group_id, self.t_in, self.t_out_val, self.p_th_set + ) + + self.specific_heat_capacity_of_water_in_joule_per_kilogram_per_celsius = ( + PhysicsConfig.water_specific_heat_capacity_in_joule_per_kilogram_per_kelvin + ) + + #protect erros for Water/Water Heatpumps + if self.parameters['Group'].iloc[0] == 1.0 or self.parameters['Group'].iloc[0] == 4.0: + if self.heat_source != "air": + raise KeyError("WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!") + if self.parameters['Group'].iloc[0] == 2.0 or self.parameters['Group'].iloc[0] == 5.0: + if self.heat_source != "brine": + raise KeyError("WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!") + if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: + if self.heat_source != "water": + raise KeyError("WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!") + + + + + # Define component inputs + self.on_off_switch_hotWater: ComponentInput = self.add_input( + object_name=self.component_name, + field_name=self.OnOffSwitchHotWater, + load_type=LoadTypes.ANY, + unit=Units.ANY, + mandatory=True, + ) + + # Define component inputs + self.on_off_switch_DHW: ComponentInput = self.add_input( + object_name=self.component_name, + field_name=self.OnOffSwitchDHW, + load_type=LoadTypes.ANY, + unit=Units.ANY, + mandatory=True, + ) + + self.const_thermal_power_truefalse_DHW: ComponentInput = self.add_input( + object_name=self.component_name, + field_name=self.ThermalPowerIsConstantforDHW, + load_type=LoadTypes.ANY, + unit=Units.ANY, + mandatory=True, + ) + + self.const_thermal_power_value_DHW: ComponentInput = self.add_input( + object_name=self.component_name, + field_name=self.MaxThermalPowerforDHW, + load_type=LoadTypes.ANY, + unit=Units.ANY, + mandatory=True, + ) + + + self.t_in_primary: ComponentInput = self.add_input( + object_name=self.component_name, + field_name=self.TemperatureInputPrimary, + load_type=LoadTypes.TEMPERATURE, + unit=Units.CELSIUS, + mandatory=True, + ) + + self.t_in_secondary_hot_water: ComponentInput = self.add_input( + object_name=self.component_name, + field_name=self.TemperatureInputSecondary_HotWater, + load_type=LoadTypes.TEMPERATURE, + unit=Units.CELSIUS, + mandatory=True, + ) + + self.t_in_secondary_dhw: ComponentInput = self.add_input( + object_name=self.component_name, + field_name=self.TemperatureInputSecondary_DHW, + load_type=LoadTypes.TEMPERATURE, + unit=Units.CELSIUS, + mandatory=True, + ) + + self.t_amb: ComponentInput = self.add_input( + object_name=self.component_name, + field_name=self.TemperatureAmbient, + load_type=LoadTypes.TEMPERATURE, + unit=Units.CELSIUS, + mandatory=True, + ) + + # Define component outputs + self.p_th_hot_water: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.ThermalOutputPowerHotWater, + load_type=LoadTypes.HEATING, + unit=Units.WATT, + output_description=("Thermal output power hot Water Storage in Watt"), + ) + + self.p_th_dhw: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.ThermalOutputPowerDHW, + load_type=LoadTypes.HEATING, + unit=Units.WATT, + output_description=("Thermal output power dhw Storage in Watt"), + ) + + self.p_th_ges: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.ThermalOutputPowerGesamt, + load_type=LoadTypes.HEATING, + unit=Units.WATT, + postprocessing_flag=postprocessing_flag, + output_description="Thermal output power for whole HP in Watt", + ) + + self.p_el_hot_water: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.ElectricalInputPowerHotWater, + load_type=LoadTypes.ELECTRICITY, + unit=Units.WATT, + postprocessing_flag=postprocessing_flag, + output_description="Electricity input power for Hot Water in Watt", + ) + + self.p_el_dhw: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.ElectricalInputPowerDHW, + load_type=LoadTypes.ELECTRICITY, + unit=Units.WATT, + postprocessing_flag=postprocessing_flag, + output_description="Electricity input power for DHW in Watt", + ) + + self.p_el_ges: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.ElectricalInputPowerGesamt, + load_type=LoadTypes.ELECTRICITY, + unit=Units.WATT, + postprocessing_flag=postprocessing_flag, + output_description="Electricity input power for whole HP in Watt", + ) + + self.cop: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.COP, + load_type=LoadTypes.ANY, + unit=Units.ANY, + output_description="COP", + ) + self.eer: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.EER, + load_type=LoadTypes.ANY, + unit=Units.ANY, + output_description="EER", + ) + + self.heatpump_state: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.heatpumpOnOffState, + load_type=LoadTypes.ANY, + unit=Units.ANY, + output_description="OnOffState", + ) + + self.t_out_hot_water: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.TemperatureOutputHotWater, + load_type=LoadTypes.HEATING, + unit=Units.CELSIUS, + output_description="Temperature Output hot Water in °C", + ) + self.t_out_dhw: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.TemperatureOutputDHW, + load_type=LoadTypes.HEATING, + unit=Units.CELSIUS, + output_description="Temperature Output DHW Water in °C", + ) + + self.m_dot_hot_water: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.MassFlowOutputHotWater, + load_type=LoadTypes.VOLUME, + unit=Units.KG_PER_SEC, + output_description="Mass flow output", + ) + self.m_dot_dhw: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.MassFlowOutputDHW, + load_type=LoadTypes.VOLUME, + unit=Units.KG_PER_SEC, + output_description="Mass flow output", + ) + + self.time_on: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.TimeOn, + load_type=LoadTypes.TIME, + unit=Units.SECONDS, + output_description="Time turned on", + ) + + self.time_off: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.TimeOff, + load_type=LoadTypes.TIME, + unit=Units.SECONDS, + output_description="Time turned off", + ) + + self.thermal_power_from_environment: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.ThermalPowerFromEnvironment, + load_type=LoadTypes.HEATING, + unit=Units.WATT, + output_description="Thermal Input Power from Environment", + ) + + if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: + self.m_dot_water_primary_dhnet: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.mdotWaterPrimaryDHNet, + load_type=LoadTypes.VOLUME, + unit=Units.KG_PER_SEC, + output_description="Massflow of Water from District Heating Net", + ) + self.temp_water_primary_hx_in: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.WaterTemperatureHXIn, + load_type=LoadTypes.TEMPERATURE, + unit=Units.CELSIUS, + output_description="Temperature of Water from District Heating Net In HX", + ) + self.temp_water_primary_hx_out: ComponentOutput = self.add_output( + object_name=self.component_name, + field_name=self.WaterTemperatureHXOut, + load_type=LoadTypes.TEMPERATURE, + unit=Units.CELSIUS, + output_description="Temperature of Water to District Heating Net Out HX", + ) + + + self.add_default_connections( + self.get_default_connections_from_heat_pump_controller_hot_water() + ) + self.add_default_connections( + self.get_default_connections_from_heat_pump_controller_dhw() + ) + self.add_default_connections(self.get_default_connections_from_weather()) + self.add_default_connections(self.get_default_connections_from_simple_hot_water_storage()) + self.add_default_connections(self.get_default_connections_from_dhw_storage()) + + def get_default_connections_from_heat_pump_controller_hot_water(self,): + """Get default connections.""" + log.information("setting heat pump controller default connections") + connections = [] + hpc_classname = HeatPumpHplibControllerHotWaterStorage.get_classname() + connections.append( + ComponentConnection( + HeatPumpHplib.OnOffSwitchHotWater, hpc_classname, HeatPumpHplibControllerHotWaterStorage.State_HotWater, + ) + ) + return connections + + def get_default_connections_from_heat_pump_controller_dhw(self,): + """Get default connections.""" + log.information("setting heat pump controller default connections") + connections = [] + hpc_dhw_classname = HeatPumpHplibControllerDHW.get_classname() + connections.append( + ComponentConnection( + HeatPumpHplib.OnOffSwitchDHW, hpc_dhw_classname, HeatPumpHplibControllerDHW.State_dhw, + ) + ) + connections.append( + ComponentConnection( + HeatPumpHplib.ThermalPowerIsConstantforDHW, hpc_dhw_classname, HeatPumpHplibControllerDHW.ThermalPower_Bedingung_for_konst_dhw, + ) + ) + connections.append( + ComponentConnection( + HeatPumpHplib.MaxThermalPowerforDHW, hpc_dhw_classname, HeatPumpHplibControllerDHW.Value_Max_Thermal_Power_for_dhw, + ) + ) + return connections + + def get_default_connections_from_weather(self,): + """Get default connections.""" + log.information("setting weather default connections") + connections = [] + weather_classname = weather.Weather.get_classname() + connections.append( + ComponentConnection( + HeatPumpHplib.TemperatureAmbient, + weather_classname, + weather.Weather.DailyAverageOutsideTemperatures, + ) + ) + return connections + + def get_default_connections_from_simple_hot_water_storage(self,): + """Get simple hot water storage default connections.""" + log.information("setting simple hot water storage default connections") + connections = [] + hws_classname = simple_hot_water_storage.SimpleHotWaterStorage.get_classname() + connections.append( + ComponentConnection( + HeatPumpHplib.TemperatureInputSecondary_HotWater, + hws_classname, + simple_hot_water_storage.SimpleHotWaterStorage.WaterTemperatureToHeatGenerator, + ) + ) + return connections + + def get_default_connections_from_dhw_storage(self,): + """Get simple hot water storage default connections.""" + log.information("setting simple hot water storage default connections") + connections = [] + dhw_classname = generic_hot_water_storage_modular.HotWaterStorage.get_classname() + connections.append( + ComponentConnection( + HeatPumpHplib.TemperatureInputSecondary_DHW, + dhw_classname, + generic_hot_water_storage_modular.HotWaterStorage.TemperatureMean, + ) + ) + return connections + + def write_to_report(self): + """Write configuration to the report.""" + return self.config.get_string_dict() + + def i_save_state(self) -> None: + """Save state.""" + self.previous_state = self.state.self_copy() + # pass + + def i_restore_state(self) -> None: + """Restore state.""" + self.state = self.previous_state.self_copy() + # pass + + def i_doublecheck(self, timestep: int, stsv: SingleTimeStepValues) -> None: + """Doubelcheck.""" + pass + + def i_prepare_simulation(self) -> None: + """Prepare simulation.""" + pass + + def i_simulate( + self, timestep: int, stsv: SingleTimeStepValues, force_convergence: bool + ) -> None: + """Simulate the component.""" + + # Load input values + on_off: float + on_off_HotWater: float = stsv.get_input_value(self.on_off_switch_hotWater) + on_off_DHW: float = stsv.get_input_value(self.on_off_switch_DHW) + const_thermal_power_truefalse_DHW: bool = stsv.get_input_value(self.const_thermal_power_truefalse_DHW) + const_thermal_power_value_DHW: float = stsv.get_input_value(self.const_thermal_power_value_DHW) + t_in_primary = stsv.get_input_value(self.t_in_primary) + t_in_secondary_hot_water = stsv.get_input_value(self.t_in_secondary_hot_water) + t_in_secondary_dhw = stsv.get_input_value(self.t_in_secondary_dhw) + t_amb = stsv.get_input_value(self.t_amb) + time_on_heating = self.state.time_on + time_on_cooling = self.state.time_on_cooling + time_off = self.state.time_off + + + if on_off_DHW != 0: + on_off = on_off_DHW + else: + on_off = on_off_HotWater + + # cycling means periodic turning on and off of the heat pump + if self.cycling_mode is True: + + # Parameter + time_on_min = self.minimum_running_time_in_seconds # [s] + time_off_min = self.minimum_idle_time_in_seconds + on_off_previous = self.state.on_off_previous + + if time_on_min is None or time_off_min is None: + raise ValueError( + "When the cycling mode is true, the minimum running time and minimum idle time of the heat pump must be given an integer value." + ) + + # Overwrite on_off to realize minimum time of or time off + if on_off_previous == 1 and time_on_heating < time_on_min: + on_off = 1 + elif on_off_previous == 2 and time_on_heating < time_on_min: + on_off = 2 + elif on_off_previous == -1 and time_on_cooling < time_on_min: + on_off = -1 + elif on_off_previous == 0 and time_off < time_off_min: + on_off = 0 + + # heat pump is turned on and off only according to heat pump controller + elif self.cycling_mode is False: + pass + else: + raise ValueError("Cycling mode of the advanced hplib unknown.") + + + if on_off_DHW != 0: + on_off = on_off_DHW + + + # OnOffSwitch + if on_off == 1: + # Calulate outputs for heating mode + results = hpl.simulate( + t_in_primary=t_in_primary, + t_in_secondary=t_in_secondary_hot_water, + parameters=self.parameters, + t_amb=t_amb, + mode=1, + ) + p_th_hot_water = results["P_th"].values[0] + p_th_dhw = 0 + p_el_hot_water = results["P_el"].values[0] + p_el_dhw = 0 + cop = results["COP"].values[0] + eer = results["EER"].values[0] + t_out_hot_water = results["T_out"].values[0] + t_out_dhw = t_in_secondary_dhw + m_dot_hot_water = results["m_dot"].values[0] + m_dot_dhw = 0 + time_on_heating = time_on_heating + self.my_simulation_parameters.seconds_per_timestep + time_on_cooling = 0 + time_off = 0 + + elif on_off == 2: # Calculate outputs for dhw mode + if const_thermal_power_truefalse_DHW == False: # False=modulation + results = hpl.simulate( + t_in_primary=t_in_primary, + t_in_secondary=t_in_secondary_dhw, + parameters=self.parameters, + t_amb=t_amb, + mode=1, + ) + p_th_dhw = results["P_th"].values[0] + p_th_hot_water = 0 + p_el_dhw = results["P_el"].values[0] + p_el_hot_water = 0 + cop = results["COP"].values[0] + eer = results["EER"].values[0] + t_out_hot_water = t_in_secondary_hot_water + t_out_dhw = results["T_out"].values[0] + m_dot_hot_water = 0 + m_dot_dhw = results["m_dot"].values[0] + time_on_heating = time_on_heating + self.my_simulation_parameters.seconds_per_timestep + time_on_cooling = 0 + time_off = 0 + # print("t_out_WP_dhw " + str(t_out_dhw)) + + elif const_thermal_power_truefalse_DHW == True: # True = constante thermische Leistung + results = hpl.simulate( + t_in_primary=t_in_primary, + t_in_secondary=t_in_secondary_dhw, + parameters=self.parameters, + t_amb=t_amb, + mode=1, + ) + p_th_dhw = const_thermal_power_value_DHW + p_th_hot_water = 0 + cop = results["COP"].values[0] + p_el_dhw = p_th_dhw/cop + p_el_hot_water = 0 + eer = results["EER"].values[0] + t_out_hot_water = t_in_secondary_hot_water + t_out_dhw = results["T_out"].values[0] + m_dot_hot_water = 0 + m_dot_dhw = results["m_dot"].values[0] + time_on_heating = time_on_heating + self.my_simulation_parameters.seconds_per_timestep + time_on_cooling = 0 + time_off = 0 + + + elif on_off == -1: + # Calulate outputs for cooling mode + results = hpl.simulate( + t_in_primary=t_in_primary, + t_in_secondary=t_in_secondary_hot_water, + parameters=self.parameters, + t_amb=t_amb, + mode=2, + ) + p_th_hot_water = results["P_th"].values[0] + p_th_dhw = 0 + p_el_hot_water = results["P_el"].values[0] + p_el_dhw = 0 + cop = results["COP"].values[0] + eer = results["EER"].values[0] + t_out_hot_water = results["T_out"].values[0] + t_out_dhw = t_out_hot_water + m_dot_hot_water = results["m_dot"].values[0] + m_dot_dhw = 0 + time_on_cooling = ( + time_on_cooling + self.my_simulation_parameters.seconds_per_timestep + ) + time_on_heating = 0 + time_off = 0 + + elif on_off == 0: + # Calulate outputs for off mode + p_th_hot_water = 0 + p_th_dhw = 0 + p_el_hot_water = 0 + p_el_dhw = 0 + # None values or nans will cause troubles in post processing, that is why there are not used here + # cop = None + # t_out = None + cop = 0 + eer = 0 + t_out_hot_water = t_in_secondary_hot_water + t_out_dhw = t_in_secondary_dhw + m_dot_hot_water = 0 + m_dot_dhw = 0 + time_off = time_off + self.my_simulation_parameters.seconds_per_timestep + time_on_heating = 0 + time_on_cooling = 0 + + else: + raise ValueError("Unknown mode for Advanced HPLib On_Off.") + + + + if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: + #todo: variability of massflow. now there is a fix temperaturdiffernz between inlet and outlet which calculate the massflow + + q_dot_entzugsleistung = ((p_th_dhw + p_th_hot_water) - (p_el_dhw + p_el_hot_water)) + m_dot_water_primary = q_dot_entzugsleistung/(self.specific_heat_capacity_of_water_in_joule_per_kilogram_per_celsius*self.hx_building_temp_diff) + t_out_primary = t_in_primary-self.hx_building_temp_diff + stsv.set_output_value(self.m_dot_water_primary_dhnet, m_dot_water_primary) + stsv.set_output_value(self.temp_water_primary_hx_in, t_in_primary) + stsv.set_output_value(self.temp_water_primary_hx_out, t_out_primary) + + + + # write values for output time series + stsv.set_output_value(self.p_th_hot_water, p_th_hot_water) + stsv.set_output_value(self.p_th_dhw, p_th_dhw) + stsv.set_output_value(self.p_th_ges, p_th_dhw+p_th_hot_water) + stsv.set_output_value(self.p_el_hot_water, p_el_hot_water) + stsv.set_output_value(self.p_el_dhw, p_el_dhw) + stsv.set_output_value(self.p_el_ges, p_el_dhw+p_el_hot_water) + stsv.set_output_value(self.cop, cop) + stsv.set_output_value(self.eer, eer) + stsv.set_output_value(self.heatpump_state, on_off) + stsv.set_output_value(self.t_out_hot_water, t_out_hot_water) + stsv.set_output_value(self.t_out_dhw, t_out_dhw) + stsv.set_output_value(self.m_dot_hot_water, m_dot_hot_water) + stsv.set_output_value(self.m_dot_dhw, m_dot_dhw) + stsv.set_output_value(self.time_on, time_on_heating) + stsv.set_output_value(self.time_off, time_off) + stsv.set_output_value(self.thermal_power_from_environment, (p_th_dhw+p_th_hot_water)-(p_el_dhw+p_el_hot_water)) + + + + # write values to state + self.state.time_on = time_on_heating + self.state.time_on_cooling = time_on_cooling + self.state.time_off = time_off + self.state.on_off_previous = on_off + + @staticmethod + def get_cost_capex(config: HeatPumpHplibConfig) -> Tuple[float, float, float]: + """Returns investment cost, CO2 emissions and lifetime.""" + return config.cost, config.co2_footprint, config.lifetime + + def get_cost_opex( + self, + all_outputs: List, + postprocessing_results: pd.DataFrame, + ) -> Tuple[float, float]: + """Calculate OPEX costs, consisting of maintenance costs. + + No electricity costs for components except for Electricity Meter, + because part of electricity consumption is feed by PV + """ + for index, output in enumerate(all_outputs): + if ( + output.component_name == "HeatPumpHPLib" + and output.load_type == LoadTypes.ELECTRICITY + ): # Todo: check component name from examples: find another way of using only heatpump-outputs + self.config.consumption = round( + sum(postprocessing_results.iloc[:, index]) + * self.my_simulation_parameters.seconds_per_timestep + / 3.6e6, + 1, + ) + + return self.calc_maintenance_cost(), 0.0 + + +@dataclass +class HeatPumpState: # anpassen, dass automatisch dhw priorisiert wird + """HeatPumpState class.""" + + time_on: int = 0 + time_off: int = 0 + time_on_cooling: int = 0 + on_off_previous: float = 0 + + def self_copy(self,): + """Copy the Heat Pump State.""" + return HeatPumpState( + self.time_on, self.time_off, self.time_on_cooling, self.on_off_previous + ) + + +# =========================================================================== +# try to implement a hplib controller l1 +@dataclass_json +@dataclass +class HeatPumpHplibControllerHotWaterStorageL1Config(ConfigBase): + + """HeatPump Controller Config Class for building heating.""" + + @classmethod + def get_main_classname(cls): + """Returns the full class name of the base class.""" + return HeatPumpHplibControllerHotWaterStorage.get_full_classname() + + name: str + mode: int + set_heating_threshold_outside_temperature_in_celsius: Optional[float] + set_cooling_threshold_outside_temperature_in_celsius: Optional[float] + temperature_offset_for_state_conditions_in_celsius: float + + @classmethod + def get_default_generic_heat_pump_controller_config(cls): + """Gets a default Generic Heat Pump Controller.""" + return HeatPumpHplibControllerHotWaterStorageL1Config( + name="HeatPumpControllerHotWaterStorage", + mode=1, + set_heating_threshold_outside_temperature_in_celsius=None, + set_cooling_threshold_outside_temperature_in_celsius=20.0, + temperature_offset_for_state_conditions_in_celsius=5.0, + ) + + +class HeatPumpHplibControllerHotWaterStorage(Component): + + """Heat Pump Controller. + + It takes data from other + components and sends signal to the heat pump for + activation or deactivation. + On/off Switch with respect to water temperature from storage. + + Parameters + ---------- + t_air_heating: float + Minimum comfortable temperature for residents + t_air_cooling: float + Maximum comfortable temperature for residents + offset: float + Temperature offset to compensate the hysteresis + correction for the building temperature change + mode : int + Mode index for operation type for this heat pump + + """ + + # Inputs + WaterTemperatureInputFromHeatWaterStorage = ( + "WaterTemperatureInputFromHeatWaterStorage" + ) + HeatingFlowTemperatureFromHeatDistributionSystem = ( + "HeatingFlowTemperatureFromHeatDistributionSystem" + ) + + DailyAverageOutsideTemperature = "DailyAverageOutsideTemperature" + + SimpleHotWaterStorageTemperatureModifier = ( + "SimpleHotWaterStorageTemperatureModifier" + ) + + # Outputs + State_HotWater = "State_HotWater" + + def __init__( + self, + my_simulation_parameters: SimulationParameters, + config: HeatPumpHplibControllerHotWaterStorageL1Config, + ) -> None: + """Construct all the neccessary attributes.""" + self.heatpump_controller_config = config + super().__init__( + self.heatpump_controller_config.name, + my_simulation_parameters=my_simulation_parameters, + my_config=config, + ) + + if SingletonSimRepository().exist_entry(key=SingletonDictKeyEnum.HEATINGSYSTEM): + self.heating_system = SingletonSimRepository().get_entry( + key=SingletonDictKeyEnum.HEATINGSYSTEM + ) + else: + raise KeyError( + "Keys for heating system was not found in the singleton sim repository." + + "This might be because the heat distribution system was not initialized before the advanced hplib controller." + + "Please check the order of the initialization of the components in your example." + ) + self.build( + mode=self.heatpump_controller_config.mode, + temperature_offset_for_state_conditions_in_celsius=self.heatpump_controller_config.temperature_offset_for_state_conditions_in_celsius, + ) + + self.water_temperature_input_channel: ComponentInput = self.add_input( + self.component_name, + self.WaterTemperatureInputFromHeatWaterStorage, + LoadTypes.TEMPERATURE, + Units.CELSIUS, + True, + ) + + self.heating_flow_temperature_from_heat_distribution_system_channel: ComponentInput = self.add_input( + self.component_name, + self.HeatingFlowTemperatureFromHeatDistributionSystem, + LoadTypes.TEMPERATURE, + Units.CELSIUS, + True, + ) + self.daily_avg_outside_temperature_input_channel: ComponentInput = ( + self.add_input( + self.component_name, + self.DailyAverageOutsideTemperature, + LoadTypes.TEMPERATURE, + Units.CELSIUS, + True, + ) + ) + + self.simple_hot_water_storage_temperature_modifier_channel: ComponentInput = ( + self.add_input( + self.component_name, + self.SimpleHotWaterStorageTemperatureModifier, + LoadTypes.TEMPERATURE, + Units.CELSIUS, + mandatory=False, + ) + ) + + self.state_channel: ComponentOutput = self.add_output( + self.component_name, + self.State_HotWater, + LoadTypes.ANY, + Units.ANY, + output_description=f"here a description for {self.State_HotWater} will follow.", + ) + + self.controller_heatpumpmode: Any + self.previous_heatpump_mode: Any + + self.add_default_connections( + self.get_default_connections_from_heat_distribution_controller() + ) + self.add_default_connections(self.get_default_connections_from_weather()) + self.add_default_connections( + self.get_default_connections_from_simple_hot_water_storage() + ) + + def get_default_connections_from_heat_distribution_controller(self,): + """Get default connections.""" + log.information("setting heat distribution controller default connections") + connections = [] + hdsc_classname = ( + heat_distribution_system.HeatDistributionController.get_classname() + ) + connections.append( + ComponentConnection( + HeatPumpHplibControllerHotWaterStorage.HeatingFlowTemperatureFromHeatDistributionSystem, + hdsc_classname, + heat_distribution_system.HeatDistributionController.HeatingFlowTemperature, + ) + ) + return connections + + def get_default_connections_from_weather(self,): + """Get default connections.""" + log.information("setting weather default connections") + connections = [] + weather_classname = weather.Weather.get_classname() + connections.append( + ComponentConnection( + HeatPumpHplibControllerHotWaterStorage.DailyAverageOutsideTemperature, + weather_classname, + weather.Weather.DailyAverageOutsideTemperatures, + ) + ) + return connections + + def get_default_connections_from_simple_hot_water_storage(self,): + """Get simple hot water storage default connections.""" + log.information("setting simple hot water storage default connections") + connections = [] + hws_classname = simple_hot_water_storage.SimpleHotWaterStorage.get_classname() + connections.append( + ComponentConnection( + HeatPumpHplibControllerHotWaterStorage.WaterTemperatureInputFromHeatWaterStorage, + hws_classname, + simple_hot_water_storage.SimpleHotWaterStorage.WaterTemperatureToHeatGenerator, + ) + ) + return connections + + def build( + self, mode: float, temperature_offset_for_state_conditions_in_celsius: float, + ) -> None: + """Build function. + + The function sets important constants and parameters for the calculations. + """ + # Sth + self.controller_heatpumpmode = "off" + self.previous_heatpump_mode = self.controller_heatpumpmode + + # Configuration + self.mode = mode + self.temperature_offset_for_state_conditions_in_celsius = ( + temperature_offset_for_state_conditions_in_celsius + ) + + def i_prepare_simulation(self) -> None: + """Prepare the simulation.""" + pass + + def i_save_state(self) -> None: + """Save the current state.""" + self.previous_heatpump_mode = self.controller_heatpumpmode + + def i_restore_state(self) -> None: + """Restore the previous state.""" + self.controller_heatpumpmode = self.previous_heatpump_mode + + def i_doublecheck(self, timestep: int, stsv: SingleTimeStepValues) -> None: + """Doublecheck.""" + pass + + def write_to_report(self) -> List[str]: + """Write important variables to report.""" + return self.heatpump_controller_config.get_string_dict() + + def i_simulate( + self, timestep: int, stsv: SingleTimeStepValues, force_convergence: bool + ) -> None: + """Simulate the heat pump comtroller.""" + + if force_convergence: + pass + else: + # Retrieves inputs + + water_temperature_input_from_heat_water_storage_in_celsius = ( + stsv.get_input_value(self.water_temperature_input_channel) + ) + + heating_flow_temperature_from_heat_distribution_system = ( + stsv.get_input_value( + self.heating_flow_temperature_from_heat_distribution_system_channel + ) + ) + + daily_avg_outside_temperature_in_celsius = stsv.get_input_value( + self.daily_avg_outside_temperature_input_channel + ) + + storage_temperature_modifier = stsv.get_input_value( + self.simple_hot_water_storage_temperature_modifier_channel + ) + + # turning heat pump off when the average daily outside temperature is above a certain threshold (if threshold is set in the config) + summer_heating_mode = self.summer_heating_condition( + daily_average_outside_temperature_in_celsius=daily_avg_outside_temperature_in_celsius, + set_heating_threshold_temperature_in_celsius=self.heatpump_controller_config.set_heating_threshold_outside_temperature_in_celsius, + ) + + # mode 1 is on/off controller + if self.mode == 1: + self.conditions_on_off( + water_temperature_input_in_celsius=water_temperature_input_from_heat_water_storage_in_celsius, + set_heating_flow_temperature_in_celsius=heating_flow_temperature_from_heat_distribution_system, + summer_heating_mode=summer_heating_mode, + storage_temperature_modifier=storage_temperature_modifier, + temperature_offset_for_state_conditions_in_celsius=self.temperature_offset_for_state_conditions_in_celsius, + ) + + # mode 2 is regulated controller (meaning heating, cooling, off). this is only possible if heating system is floor heating + elif ( + self.mode == 2 and self.heating_system == HeatingSystemType.FLOORHEATING + ): + # turning heat pump cooling mode off when the average daily outside temperature is below a certain threshold + summer_cooling_mode = self.summer_cooling_condition( + daily_average_outside_temperature_in_celsius=daily_avg_outside_temperature_in_celsius, + set_cooling_threshold_temperature_in_celsius=self.heatpump_controller_config.set_cooling_threshold_outside_temperature_in_celsius, + ) + self.conditions_heating_cooling_off( + water_temperature_input_in_celsius=water_temperature_input_from_heat_water_storage_in_celsius, + set_heating_flow_temperature_in_celsius=heating_flow_temperature_from_heat_distribution_system, + summer_heating_mode=summer_heating_mode, + summer_cooling_mode=summer_cooling_mode, + storage_temperature_modifier=storage_temperature_modifier, + temperature_offset_for_state_conditions_in_celsius=self.temperature_offset_for_state_conditions_in_celsius, + ) + + else: + raise ValueError( + "Either the Advanced HP Lib Controller Mode is neither 1 nor 2," + "or the heating system is not floor heating which is the condition for cooling (mode 2)." + ) + + if self.controller_heatpumpmode == "heating": + state = 1 + elif self.controller_heatpumpmode == "cooling": + state = -1 + elif self.controller_heatpumpmode == "off": + state = 0 + else: + raise ValueError("Advanced HP Lib Controller State unknown.") + + stsv.set_output_value(self.state_channel, state) + + def conditions_on_off( + self, + water_temperature_input_in_celsius: float, + set_heating_flow_temperature_in_celsius: float, + summer_heating_mode: str, + storage_temperature_modifier: float, + temperature_offset_for_state_conditions_in_celsius: float, + ) -> None: + """Set conditions for the heat pump controller mode.""" + + if self.controller_heatpumpmode == "heating": + if ( + water_temperature_input_in_celsius + > ( + set_heating_flow_temperature_in_celsius + # + 0.5 + + temperature_offset_for_state_conditions_in_celsius + + storage_temperature_modifier + ) + or summer_heating_mode == "off" + ): # + 1: + self.controller_heatpumpmode = "off" + return + + elif self.controller_heatpumpmode == "off": + + # heat pump is only turned on if the water temperature is below the flow temperature + # and if the avg daily outside temperature is cold enough (summer mode on) + if ( + water_temperature_input_in_celsius + < ( + set_heating_flow_temperature_in_celsius + # - 1.0 + - temperature_offset_for_state_conditions_in_celsius + + storage_temperature_modifier + ) + and summer_heating_mode == "on" + ): # - 1: + self.controller_heatpumpmode = "heating" + return + + else: + raise ValueError("unknown mode") + + def conditions_heating_cooling_off( + self, + water_temperature_input_in_celsius: float, + set_heating_flow_temperature_in_celsius: float, + summer_heating_mode: str, + summer_cooling_mode: str, + storage_temperature_modifier: float, + temperature_offset_for_state_conditions_in_celsius: float, + ) -> None: + """Set conditions for the heat pump controller mode according to the flow temperature.""" + # Todo: storage temperature modifier is only working for heating so far. Implement for cooling similar + heating_set_temperature = set_heating_flow_temperature_in_celsius + cooling_set_temperature = set_heating_flow_temperature_in_celsius + + if self.controller_heatpumpmode == "heating": + if ( + water_temperature_input_in_celsius + >= heating_set_temperature + + storage_temperature_modifier # Todo: Check if storage_temperature_modifier is neccessary here + or summer_heating_mode == "off" + ): + self.controller_heatpumpmode = "off" + return + elif self.controller_heatpumpmode == "cooling": + if ( + water_temperature_input_in_celsius <= cooling_set_temperature + or summer_cooling_mode == "off" + ): + self.controller_heatpumpmode = "off" + return + + elif self.controller_heatpumpmode == "off": + + # heat pump is only turned on if the water temperature is below the flow temperature + # and if the avg daily outside temperature is cold enough (summer heating mode on) + if ( + water_temperature_input_in_celsius + < ( + heating_set_temperature + - temperature_offset_for_state_conditions_in_celsius + + storage_temperature_modifier + ) + and summer_heating_mode == "on" + ): + self.controller_heatpumpmode = "heating" + return + + # heat pump is only turned on for cooling if the water temperature is above a certain flow temperature + # and if the avg daily outside temperature is warm enough (summer cooling mode on) + if ( + water_temperature_input_in_celsius + > ( + cooling_set_temperature + + temperature_offset_for_state_conditions_in_celsius + ) + and summer_cooling_mode == "on" + ): + self.controller_heatpumpmode = "cooling" + return + + else: + raise ValueError("unknown mode") + + def summer_heating_condition( + self, + daily_average_outside_temperature_in_celsius: float, + set_heating_threshold_temperature_in_celsius: Optional[float], + ) -> str: + """Set conditions for the heat pump.""" + + # if no heating threshold is set, the heat pump is always on + if set_heating_threshold_temperature_in_celsius is None: + heating_mode = "on" + + # it is too hot for heating + elif ( + daily_average_outside_temperature_in_celsius + > set_heating_threshold_temperature_in_celsius + ): + heating_mode = "off" + + # it is cold enough for heating + elif ( + daily_average_outside_temperature_in_celsius + < set_heating_threshold_temperature_in_celsius + ): + heating_mode = "on" + + else: + raise ValueError( + f"daily average temperature {daily_average_outside_temperature_in_celsius}°C" + f"or heating threshold temperature {set_heating_threshold_temperature_in_celsius}°C is not acceptable." + ) + return heating_mode + + def summer_cooling_condition( + self, + daily_average_outside_temperature_in_celsius: float, + set_cooling_threshold_temperature_in_celsius: Optional[float], + ) -> str: + """Set conditions for the heat pump.""" + + # if no cooling threshold is set, cooling is always possible no matter what daily outside temperature + if set_cooling_threshold_temperature_in_celsius is None: + cooling_mode = "on" + + # it is hot enough for cooling + elif ( + daily_average_outside_temperature_in_celsius + > set_cooling_threshold_temperature_in_celsius + ): + cooling_mode = "on" + + # it is too cold for cooling + elif ( + daily_average_outside_temperature_in_celsius + < set_cooling_threshold_temperature_in_celsius + ): + cooling_mode = "off" + + else: + raise ValueError( + f"daily average temperature {daily_average_outside_temperature_in_celsius}°C" + f"or cooling threshold temperature {set_cooling_threshold_temperature_in_celsius}°C is not acceptable." + ) + + return cooling_mode + + +@dataclass +class CalculationRequest(JSONWizard): + + """Class for caching hplib parameters so that hplib.simulate does not need to run so often.""" + + t_in_primary: float + t_in_secondary: float + t_amb: float + mode: int + + def get_key(self): + """Get key of class with important parameters.""" + + return ( + str(self.t_in_primary) + + " " + + str(self.t_in_secondary) + + " " + + str(self.t_amb) + + " " + + str(self.mode) + ) + +# =========================================================================== +# implement a hplib controller l1 for dhw storage (tww) +@dataclass_json +@dataclass +class HeatPumpHplibControllerDHWL1Config(ConfigBase): + + """HeatPump Controller Config Class for dhw .""" + + @classmethod + def get_main_classname(cls): + """Returns the full class name of the base class.""" + return HeatPumpHplibControllerDHW.get_full_classname() + + name: str + #: lower set temperature of DHW Storage, given in °C + t_min_dhw_storage_in_celsius: float + #: upper set temperature of DHW Storage, given in °C + t_max_dhw_storage_in_celsius: float + #: set thermal power delivered for dhw on constant value --> max. Value of heatpump + thermalPower_is_constant_for_dhw: bool + #: max. Power of Heatpump for not modulation dhw production + p_th_max_dhw_in_W: float + + + @classmethod + def get_default_generic_heat_pump_controller_config(cls): + """Gets a default Generic Heat Pump Controller.""" + return HeatPumpHplibControllerDHWL1Config( + name="HeatPumpControllerDHW", + t_min_dhw_storage_in_celsius=40.0, + t_max_dhw_storage_in_celsius=60.0, + thermalPower_is_constant_for_dhw = False, #false: modulation, true: constant power for dhw + p_th_max_dhw_in_W = 5000, # only if true + ) + + +class HeatPumpHplibControllerDHW(Component): + + """Heat Pump Controller for DHW. + + It takes data from DHW Storage --> generic hot water stoprage modular + sends signal to the heat pump for activation or deactivation. + + """ + + + # in state mit aufnehmen das hier priorisiert wird + + # Inputs + WaterTemperatureInputFromDHWStorage ="WaterTemperatureInputFromDHWStorage" + DWHStorageTemperatureModifier = "StorageTemperatureModifier" + + # Outputs + State_dhw = "State DHW" + ThermalPower_Bedingung_for_konst_dhw = "BedingungfuerKonstDHW" #if heatpump has fix power for dhw + Value_Max_Thermal_Power_for_dhw = "ThermalPowerHPForDHWConst" #if heatpump has fix power for dhw + + + + + def __init__( + self, + my_simulation_parameters: SimulationParameters, + config: HeatPumpHplibControllerDHWL1Config, + ) -> None: + """Construct all the neccessary attributes.""" + self.heatpump_controller_dhw_config = config + super().__init__( + self.heatpump_controller_dhw_config.name, + my_simulation_parameters=my_simulation_parameters, + my_config=config, + ) + self.config: HeatPumpHplibControllerDHWL1Config = config + + self.build() + + self.water_temperature_input_channel: ComponentInput = self.add_input( + self.component_name, + self.WaterTemperatureInputFromDHWStorage, + LoadTypes.TEMPERATURE, + Units.CELSIUS, + True, + ) + + self.storage_temperature_modifier_channel: ComponentInput = self.add_input( + self.component_name, + self.DWHStorageTemperatureModifier, + LoadTypes.TEMPERATURE, + Units.CELSIUS, + mandatory=False, + ) + + self.state_dhw_channel: ComponentOutput = self.add_output( + self.component_name, + self.State_dhw, + LoadTypes.ANY, + Units.ANY, + output_description=f"here a description for {self.State_dhw} will follow.", + ) + + self.thermalPower_const_bedingung_channel: ComponentOutput = self.add_output( + self.component_name, + self.ThermalPower_Bedingung_for_konst_dhw, + LoadTypes.ANY, + Units.ANY, + output_description=f"here a description for {self.ThermalPower_Bedingung_for_konst_dhw} will follow.", + ) + + self.thermalPower_max_value_channel: ComponentOutput = self.add_output( + self.component_name, + self.Value_Max_Thermal_Power_for_dhw, + LoadTypes.ANY, + Units.ANY, + output_description=f"here a description for {self.Value_Max_Thermal_Power_for_dhw} will follow.", + ) + + self.controller_heatpumpmode_dhw: Any + self.previous_heatpump_mode_dhw: Any + self.controller_signal: int + self.thermalPower_constant_for_dhw: bool + self.p_th_max_dhw: float + + + self.add_default_connections(self.get_default_connections_from_dhw_storage()) + + def get_default_connections_from_dhw_storage(self, ): + """Get simple hot water storage default connections.""" + log.information("setting dhw storage default connections") + connections = [] + dhw_classname = generic_hot_water_storage_modular.HotWaterStorage.get_classname() + connections.append( + ComponentConnection( + HeatPumpHplibControllerDHW.WaterTemperatureInputFromDHWStorage, + dhw_classname, + generic_hot_water_storage_modular.HotWaterStorage.TemperatureMean, + ) + ) + return connections + + def build(self, ) -> None: + """Build function. + + The function sets important constants and parameters for the calculations. + """ + # Sth + self.controller_heatpumpmode_dhw = "off_dhw_heating" + self.previous_heatpump_mode_dhw = self.controller_heatpumpmode_dhw + self.controller_signal = 1 + self.thermalPower_constant_for_dhw = self.config.thermalPower_is_constant_for_dhw + self.p_th_max_dhw = self.config.p_th_max_dhw_in_W + + if self.thermalPower_constant_for_dhw == True: + print("INFO: DHW Power ist constant with " + str(self.p_th_max_dhw) + "W") + elif self.thermalPower_constant_for_dhw == False: + print("INFO: DHW Power is modulating") + self.p_th_max_dhw=0 + + + def i_prepare_simulation(self) -> None: + """Prepare the simulation.""" + pass + + def i_save_state(self) -> None: + """Save the current state.""" + self.previous_heatpump_mode_dhw = self.controller_heatpumpmode_dhw + + def i_restore_state(self) -> None: + """Restore the previous state.""" + self.controller_heatpumpmode_dhw = self.previous_heatpump_mode_dhw + + def i_doublecheck(self, timestep: int, stsv: SingleTimeStepValues) -> None: + """Doublecheck.""" + pass + + def write_to_report(self) -> List[str]: + """Write important variables to report.""" + return self.heatpump_controller_dhw_config.get_string_dict() + + def i_simulate( + self, timestep: int, stsv: SingleTimeStepValues, force_convergence: bool + ) -> None: + """Simulate the heat pump comtroller.""" + + #if force_convergence: + # pass + #else: + # Retrieves inputs + + water_temperature_input_from_dhw_storage_in_celsius = stsv.get_input_value(self.water_temperature_input_channel) + temperature_modifier = stsv.get_input_value(self.storage_temperature_modifier_channel) + + t_min_dhw_storage_in_celsius = self.config.t_min_dhw_storage_in_celsius + t_max_dhw_storage_in_celsius = self.config.t_max_dhw_storage_in_celsius + + + if water_temperature_input_from_dhw_storage_in_celsius < t_min_dhw_storage_in_celsius: #an + self.controller_signal = 1 + elif water_temperature_input_from_dhw_storage_in_celsius > t_max_dhw_storage_in_celsius + temperature_modifier: #aus + self.controller_signal = 0 + elif temperature_modifier > 0 and water_temperature_input_from_dhw_storage_in_celsius < t_max_dhw_storage_in_celsius: + self.controller_signal = 1 + else: + + pass + + + if self.controller_signal == 1: + state_dhw = 2 + elif self.controller_signal == 0: + state_dhw = 0 + else: + raise ValueError("Advanced HP Lib DHW Controller State unknown.") + + stsv.set_output_value(self.state_dhw_channel, state_dhw) + stsv.set_output_value(self.thermalPower_const_bedingung_channel, self.thermalPower_constant_for_dhw) + if self.thermalPower_constant_for_dhw == True: + stsv.set_output_value(self.thermalPower_max_value_channel, self.p_th_max_dhw) + elif self.thermalPower_constant_for_dhw == False: + stsv.set_output_value(self.thermalPower_max_value_channel, 0) + + diff --git a/system_setups/household_with_more_advanced_hp_hws_dhw_hds.py b/system_setups/household_with_more_advanced_hp_hws_dhw_hds.py new file mode 100644 index 000000000..6da02a1d9 --- /dev/null +++ b/system_setups/household_with_more_advanced_hp_hws_dhw_hds.py @@ -0,0 +1,264 @@ +""" Basic household new system setup. """ + +# clean + +from typing import Optional, Any +from hisim.simulator import SimulationParameters +from hisim.components import loadprofilegenerator_connector +from hisim.components import weather +from hisim.components import building +from hisim.components import more_advanced_heat_pump_hplib +from hisim.components import electricity_meter +from hisim.components import simple_hot_water_storage +from hisim.components import generic_hot_water_storage_modular +from hisim.components import heat_distribution_system +from hisim import loadtypes as lt + +__authors__ = "Jonas Hoppe" +__copyright__ = "" +__credits__ = ["Jonas Hoppe"] +__license__ = "-" +__version__ = "" +__maintainer__ = "" +__status__ = "" + + + +def setup_function( + my_sim: Any, my_simulation_parameters: Optional[SimulationParameters] = None +) -> None: # noqa: too-many-statements + """Basic household system setup. + + This setup function emulates an household including the basic components. Here the residents have their + electricity and heating needs covered by the photovoltaic system and the heat pump. + + - Simulation Parameters + - Components + - Occupancy (Residents' Demands) + - Weather + - Building + - Heat Pump + - Heat Pump Controller for dhw + - Heat Pump Controller for building heating + - Heat Distribution System + - Heat Distribution Controller + - Hot Water Storage + - DHW Water Storage + """ + + # ================================================================================================================================= + # Set System Parameters + + # Set Simulation Parameters + year = 2021 + seconds_per_timestep = 60 + + # ================================================================================================================================= + # Build Components + + # Build Simulation Parameters + if my_simulation_parameters is None: + my_simulation_parameters = SimulationParameters.three_months_with_plots_only( + year=year, seconds_per_timestep=seconds_per_timestep + ) + + my_sim.set_simulation_parameters(my_simulation_parameters) + + # Build Heat Distribution Controller + my_heat_distribution_controller_config = heat_distribution_system.HeatDistributionControllerConfig.get_default_heat_distribution_controller_config() + + my_heat_distribution_controller = heat_distribution_system.HeatDistributionController( + my_simulation_parameters=my_simulation_parameters, + config=my_heat_distribution_controller_config + ) + # Build Building + my_building_config = building.BuildingConfig.get_default_german_single_family_home() + + my_building = building.Building( + config=my_building_config, + my_simulation_parameters=my_simulation_parameters + ) + + # Build Occupancy + my_occupancy_config = loadprofilegenerator_connector.OccupancyConfig.get_default_chr01_couple_both_at_work() + + my_occupancy = loadprofilegenerator_connector.Occupancy( + config=my_occupancy_config, my_simulation_parameters=my_simulation_parameters + ) + + # Build Weather + my_weather_config = weather.WeatherConfig.get_default( location_entry=weather.LocationEnum.AACHEN) + + my_weather = weather.Weather( + config=my_weather_config, + my_simulation_parameters=my_simulation_parameters + ) + + # Build Electricity Meter + my_electricity_meter = electricity_meter.ElectricityMeter( + my_simulation_parameters=my_simulation_parameters, + config=electricity_meter.ElectricityMeterConfig.get_electricity_meter_default_config(), + ) + + # Build Heat Pump Controller for hot water (heating building) + my_heatpump_controller_hotwater_config = more_advanced_heat_pump_hplib.HeatPumpHplibControllerHotWaterStorageL1Config.get_default_generic_heat_pump_controller_config() + + my_heatpump_controller_hotWater = more_advanced_heat_pump_hplib.HeatPumpHplibControllerHotWaterStorage( + config=my_heatpump_controller_hotwater_config, + my_simulation_parameters=my_simulation_parameters + ) + + my_heatpump_controller_dhw_config = more_advanced_heat_pump_hplib.HeatPumpHplibControllerDHWL1Config.get_default_generic_heat_pump_controller_config() + + # Build Heat Pump Controller for dhw + my_heatpump_controller_dhw = more_advanced_heat_pump_hplib.HeatPumpHplibControllerDHW( + config=my_heatpump_controller_dhw_config, + my_simulation_parameters=my_simulation_parameters + ) + + # Build Heat Pump + my_heatpump_config = more_advanced_heat_pump_hplib.HeatPumpHplibConfig.get_default_generic_advanced_hp_lib() + + my_heatpump = more_advanced_heat_pump_hplib.HeatPumpHplib( + config=my_heatpump_config, + my_simulation_parameters=my_simulation_parameters, + ) + + # Build Heat Distribution System + my_heat_distribution_config = heat_distribution_system.HeatDistributionConfig.get_default_heatdistributionsystem_config( + heating_load_of_building_in_watt=my_building.my_building_information.max_thermal_building_demand_in_watt + ) + + my_heat_distribution = heat_distribution_system.HeatDistribution( + config=my_heat_distribution_config, + my_simulation_parameters=my_simulation_parameters, + ) + + # Build Heat Water Storage + my_hot_water_storage_config = simple_hot_water_storage.SimpleHotWaterStorageConfig.get_default_simplehotwaterstorage_config() + + my_hot_water_storage = simple_hot_water_storage.SimpleHotWaterStorage( + config=my_hot_water_storage_config, + my_simulation_parameters=my_simulation_parameters, + ) + + # Build DHW Storage + my_dhw_storage_config = generic_hot_water_storage_modular.StorageConfig.get_default_config_for_boiler() + + my_dhw_storage = generic_hot_water_storage_modular.HotWaterStorage( + config=my_dhw_storage_config, + my_simulation_parameters=my_simulation_parameters, + ) + + # ================================================================================================================================= + # Connect Components + my_building.connect_only_predefined_connections(my_weather) + my_building.connect_only_predefined_connections(my_occupancy) + + my_building.connect_input( + my_building.ThermalPowerDelivered, + my_heat_distribution.component_name, + my_heat_distribution.ThermalPowerDelivered, + ) + + ################################# + my_heat_distribution_controller.connect_only_predefined_connections( + my_weather, my_building, my_hot_water_storage + ) + + my_heat_distribution.connect_only_predefined_connections( + my_building, my_heat_distribution_controller, my_hot_water_storage) + + ################################# + my_heatpump.connect_only_predefined_connections( + my_heatpump_controller_hotWater, my_heatpump_controller_dhw, my_weather, my_hot_water_storage, + my_dhw_storage) + + + # Verknüpfung mit Luft als Umgebungswärmeqzuelle + if my_heatpump.parameters['Group'].iloc[0] == 1.0 or my_heatpump.parameters['Group'].iloc[ + 0] == 4.0: + my_heatpump.connect_input( + my_heatpump.TemperatureInputPrimary, + my_weather.component_name, + my_weather.DailyAverageOutsideTemperatures, + ) + else: + raise KeyError("Wasser oder Sole als primäres Wärmeträgermedium muss über extra Wärmenetz-Modell noch bereitgestellt werden") + + #todo: Water and Brine Connection + + + + + my_heatpump_controller_hotWater.connect_only_predefined_connections(my_heat_distribution_controller, + my_weather, + my_hot_water_storage) + + my_heatpump_controller_dhw.connect_only_predefined_connections(my_dhw_storage) + + ################################# + my_hot_water_storage.connect_input( + my_hot_water_storage.WaterTemperatureFromHeatDistribution, + my_heat_distribution.component_name, + my_heat_distribution.WaterTemperatureOutput, + ) + + my_hot_water_storage.connect_input( + my_hot_water_storage.WaterTemperatureFromHeatGenerator, + my_heatpump.component_name, + my_heatpump.TemperatureOutputHotWater, + ) + + my_hot_water_storage.connect_input( + my_hot_water_storage.WaterMassFlowRateFromHeatGenerator, + my_heatpump.component_name, + my_heatpump.MassFlowOutputHotWater, + ) + + ################################# + + my_dhw_storage.connect_only_predefined_connections(my_occupancy) + my_dhw_storage.connect_input( + my_dhw_storage.ThermalPowerDelivered, + my_heatpump.component_name, + my_heatpump.ThermalOutputPowerDHW, + ) + + ################################ + + my_electricity_meter.add_component_input_and_connect( + source_object_name=my_occupancy.component_name, + source_component_output=my_occupancy.ElectricityOutput, + source_load_type=lt.LoadTypes.ELECTRICITY, + source_unit=lt.Units.WATT, + source_tags=[lt.InandOutputType.ELECTRICITY_CONSUMPTION_UNCONTROLLED], + source_weight=999, + ) + + my_electricity_meter.add_component_input_and_connect( + source_object_name=my_heatpump.component_name, + source_component_output=my_heatpump.ElectricalInputPowerGesamt, + source_load_type=lt.LoadTypes.ELECTRICITY, + source_unit=lt.Units.WATT, + source_tags=[ + lt.InandOutputType.ELECTRICITY_CONSUMPTION_UNCONTROLLED, + ], + source_weight=999, + ) + + # ================================================================================================================================= + # Add Components to Simulation Parameters + + my_sim.add_component(my_occupancy) + my_sim.add_component(my_weather) + my_sim.add_component(my_electricity_meter) + my_sim.add_component(my_building) + my_sim.add_component(my_heat_distribution_controller) + my_sim.add_component(my_heat_distribution) + my_sim.add_component(my_hot_water_storage) + my_sim.add_component(my_dhw_storage) + my_sim.add_component(my_heatpump_controller_hotWater) + my_sim.add_component(my_heatpump_controller_dhw) + my_sim.add_component(my_heatpump) + diff --git a/tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py b/tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py new file mode 100644 index 000000000..850cb58a9 --- /dev/null +++ b/tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py @@ -0,0 +1,23 @@ +""" Tests for the basic household system setup. """ +# clean +import os +import pytest + +from hisim import hisim_main +from hisim.simulationparameters import SimulationParameters +from hisim import log +from hisim import utils + + +@pytest.mark.system_setups +@utils.measure_execution_time +def test_household_with_more_advanced_hp_hws_dhw_hds(): + """Single day.""" + path = "../system_setups/household_with_more_advanced_hp_hws_dhw_hds.py" + + mysimpar = SimulationParameters.one_day_only( + year=2021, seconds_per_timestep=60 + ) + + hisim_main.main(path, mysimpar) + log.information(os.getcwd()) From 5a13bdaaea2a4058a272ff2c9b7f2e963d7e865e Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Wed, 6 Dec 2023 17:14:09 +0100 Subject: [PATCH 02/27] tester for more advanced heatpump --- ...em_setups_household_with_more_advanced_hp_hws_dhw_hds.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py b/tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py index 850cb58a9..07ae74215 100644 --- a/tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py +++ b/tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py @@ -1,5 +1,5 @@ """ Tests for the basic household system setup. """ -# clean + import os import pytest @@ -9,15 +9,15 @@ from hisim import utils + @pytest.mark.system_setups @utils.measure_execution_time -def test_household_with_more_advanced_hp_hws_dhw_hds(): +def test_household_with_advanced_hp_hws_hds_pv(): """Single day.""" path = "../system_setups/household_with_more_advanced_hp_hws_dhw_hds.py" mysimpar = SimulationParameters.one_day_only( year=2021, seconds_per_timestep=60 ) - hisim_main.main(path, mysimpar) log.information(os.getcwd()) From 4dad0453bb9a1194f516fb5794a27fb7fc6580e4 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Fri, 8 Dec 2023 16:20:54 +0100 Subject: [PATCH 03/27] =?UTF-8?q?units=20for=20pressure=20todo:=20automati?= =?UTF-8?q?sche=20=C3=A4nderung=20bei=20plots=20von=20hPa=20in=20bar=20etc?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hisim/loadtypes.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hisim/loadtypes.py b/hisim/loadtypes.py index cb8252f4c..7bf9f1992 100644 --- a/hisim/loadtypes.py +++ b/hisim/loadtypes.py @@ -86,6 +86,7 @@ class LoadTypes(str, enum.Enum): # Substance GAS = "Gas" + AIR = "Air" HYDROGEN = "Hydrogen" OXYGEN = "Oxygen" WATER = "Water" @@ -147,6 +148,11 @@ class Units(str, enum.Enum): # Degrees DEGREES = "Degrees" + # Pressure + BAR = "bar" + PA = "Pa" + HEKTOPASCAL ="hPa" + # Time SECONDS = "s" HOURS = "h" From 40db1761e88aa03b1570a2e79295f604dbd0dc86 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Fri, 8 Dec 2023 16:22:04 +0100 Subject: [PATCH 04/27] =?UTF-8?q?weather=20model=20erg=C3=A4nzt=20um=20dru?= =?UTF-8?q?ck=20aus-/=C3=BCbergabe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hisim/components/weather.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/hisim/components/weather.py b/hisim/components/weather.py index 3291a9b03..30ff602d5 100644 --- a/hisim/components/weather.py +++ b/hisim/components/weather.py @@ -420,6 +420,7 @@ class Weather(Component): Azimuth = "Azimuth" ApparentZenith = "ApparentZenith" WindSpeed = "WindSpeed" + Pressure = "Pressure" Weather_Temperature_Forecast_24h = "Weather_Temperature_Forecast_24h" DailyAverageOutsideTemperatures = "DailyAverageOutsideTemperatures" @@ -523,6 +524,14 @@ def __init__( output_description=f"here a description for {self.WindSpeed} will follow.", ) + self.pressure_output: ComponentOutput = self.add_output( + self.component_name, + self.Pressure, + lt.LoadTypes.ANY, + lt.Units.HEKTOPASCAL, + output_description=f"here a description for {self.WindSpeed} will follow.", + ) + self.daily_average_outside_temperature_output: ComponentOutput = self.add_output( self.component_name, self.DailyAverageOutsideTemperatures, @@ -537,6 +546,7 @@ def __init__( self.altitude_list: List[float] self.azimuth_list: List[float] self.wind_speed_list: List[float] + self.pressure_list: List[float] self.ghi_list: List[float] self.apparent_zenith_list: List[float] self.dhi_list: List[float] @@ -578,6 +588,7 @@ def i_simulate( stsv.set_output_value(self.altitude_output, self.altitude_list[timestep]) stsv.set_output_value(self.azimuth_output, self.azimuth_list[timestep]) stsv.set_output_value(self.wind_speed_output, self.wind_speed_list[timestep]) + stsv.set_output_value(self.pressure_output, self.pressure_list[timestep]) stsv.set_output_value( self.apparent_zenith_output, self.apparent_zenith_list[timestep] ) @@ -634,6 +645,7 @@ def i_prepare_simulation(self) -> None: self.azimuth_list = my_weather["azimuth"].tolist() self.apparent_zenith_list = my_weather["apparent_zenith"].tolist() self.wind_speed_list = my_weather["Wspd"].tolist() + self.pressure_list = my_weather["Pressure"].tolist() else: tmy_data = read_test_reference_year_data( weatherconfig=self.weather_config, @@ -658,6 +670,8 @@ def i_prepare_simulation(self) -> None: .asfreq() .interpolate(method="linear") ) + pressure = (tmy_data["Pressure"].resample("1T").asfreq() .interpolate(method="linear") + ) else: dni = self.interpolate( tmy_data["DNI"], self.my_simulation_parameters.year @@ -674,6 +688,9 @@ def i_prepare_simulation(self) -> None: wind_speed = self.interpolate( tmy_data["Wspd"], self.my_simulation_parameters.year ) + pressure = self.interpolate( + tmy_data["Pressure"], self.my_simulation_parameters.year + ) # calculate extra terrestrial radiation- n eeded for perez array diffuse irradiance models dni_extra = pd.Series(pvlib.irradiance.get_extra_radiation(dni.index), index=dni.index) # type: ignore @@ -725,6 +742,9 @@ def i_prepare_simulation(self) -> None: self.wind_speed_list = ( wind_speed.resample(str(seconds_per_timestep) + "S").mean().tolist() ) + self.pressure_list = ( + pressure.resample(str(seconds_per_timestep) + "S").mean().tolist() + ) else: self.temperature_list = temperature.tolist() self.dry_bulb_list = temperature.to_list() @@ -742,6 +762,7 @@ def i_prepare_simulation(self) -> None: self.wind_speed_list = ( wind_speed.resample(str(seconds_per_timestep) + "S").mean().tolist() ) + self.pressure_list = pressure.tolist() solardata = [ self.dni_list, @@ -753,6 +774,7 @@ def i_prepare_simulation(self) -> None: self.apparent_zenith_list, self.dry_bulb_list, self.wind_speed_list, + self.pressure_list, self.dniextra_list, self.daily_average_outside_temperature_list_in_celsius, ] @@ -769,6 +791,7 @@ def i_prepare_simulation(self) -> None: "apparent_zenith", "DryBulb", "Wspd", + "Pressure", "DNIextra", "t_out_daily_average", ], @@ -809,6 +832,10 @@ def i_prepare_simulation(self) -> None: key=SingletonDictKeyEnum.WEATHERWINDSPEEDYEARLYFORECAST, entry=self.wind_speed_list, ) + SingletonSimRepository().set_entry( + key=SingletonDictKeyEnum.WEATHERPRESSUREYEARLYFORECAST, + entry=self.pressure_list, + ) SingletonSimRepository().set_entry( key=SingletonDictKeyEnum.WEATHERALTITUDEYEARLYFORECAST, entry=self.altitude_list, From 69722321dafabe7b923e3eb21677a10dd3d43386 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Fri, 8 Dec 2023 16:22:56 +0100 Subject: [PATCH 05/27] =?UTF-8?q?model=20erg=C3=A4nzt=20um=20druck=20f?= =?UTF-8?q?=C3=BCr=20ggf=20zuk=C3=BCnftige=20erweiterung=20von=20windkraft?= =?UTF-8?q?anlage=20modell?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hisim/sim_repository_singleton.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hisim/sim_repository_singleton.py b/hisim/sim_repository_singleton.py index 9472b29d7..be10fb2d7 100644 --- a/hisim/sim_repository_singleton.py +++ b/hisim/sim_repository_singleton.py @@ -152,3 +152,4 @@ class SingletonDictKeyEnum(enum.Enum): WEATHERAPPARENTZENITHYEARLYFORECAST = 46 HEATINGBYRESIDENTSYEARLYFORECAST = 47 WEATHERWINDSPEEDYEARLYFORECAST = 48 + WEATHERPRESSUREYEARLYFORECAST = 49 From ea6b14752b501f271594369b2901fb2d68d69ca2 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Fri, 8 Dec 2023 16:46:53 +0100 Subject: [PATCH 06/27] pressure output angepasst --- hisim/components/weather.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hisim/components/weather.py b/hisim/components/weather.py index 30ff602d5..614cfbfb9 100644 --- a/hisim/components/weather.py +++ b/hisim/components/weather.py @@ -527,9 +527,9 @@ def __init__( self.pressure_output: ComponentOutput = self.add_output( self.component_name, self.Pressure, - lt.LoadTypes.ANY, - lt.Units.HEKTOPASCAL, - output_description=f"here a description for {self.WindSpeed} will follow.", + lt.LoadTypes.PRESSURE, + lt.Units.HEKTOPASCAL, # in try(dwd) unit: hPa, in nsrdb unit: mbar = hPa + output_description=f"here a description for {self.Pressure} will follow.", ) self.daily_average_outside_temperature_output: ComponentOutput = self.add_output( From ed75731f9dc05c99cd541780232fd2f9327c1c7c Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Fri, 8 Dec 2023 16:47:15 +0100 Subject: [PATCH 07/27] =?UTF-8?q?pressure=20erg=C3=A4nzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hisim/loadtypes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hisim/loadtypes.py b/hisim/loadtypes.py index 7bf9f1992..687b44e2e 100644 --- a/hisim/loadtypes.py +++ b/hisim/loadtypes.py @@ -82,6 +82,7 @@ class LoadTypes(str, enum.Enum): VOLUME = "Volume" TEMPERATURE = "Temperature" + PRESSURE = "Pressure" TIME = "Time" # Substance @@ -150,7 +151,7 @@ class Units(str, enum.Enum): # Pressure BAR = "bar" - PA = "Pa" + PASCAL = "Pa" HEKTOPASCAL ="hPa" # Time @@ -173,6 +174,7 @@ class ComponentType(str, enum.Enum): """Component types for use in dynamic controllers.""" PV = "PV" + WINDTURBINE = "Windturbine" SMART_DEVICE = "SmartDevice" SURPLUS_CONTROLLER = "SurplusController" PREDICTIVE_CONTROLLER = "PredictiveControllerforSmartDevices" From 4bda79810d9b1700e5104048e22396dd3c2b4d02 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Mon, 11 Dec 2023 09:57:06 +0100 Subject: [PATCH 08/27] =?UTF-8?q?anpassen=20auf=20SI-Einheit=20f=C3=BCr=20?= =?UTF-8?q?Druck?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hisim/loadtypes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hisim/loadtypes.py b/hisim/loadtypes.py index 687b44e2e..e562590a1 100644 --- a/hisim/loadtypes.py +++ b/hisim/loadtypes.py @@ -152,7 +152,6 @@ class Units(str, enum.Enum): # Pressure BAR = "bar" PASCAL = "Pa" - HEKTOPASCAL ="hPa" # Time SECONDS = "s" From 193f6f147ac0de1d22980f0be8f5646b817e8517 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Mon, 11 Dec 2023 09:57:20 +0100 Subject: [PATCH 09/27] =?UTF-8?q?anpassen=20auf=20SI-Einheit=20f=C3=BCr=20?= =?UTF-8?q?Druck?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hisim/components/weather.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hisim/components/weather.py b/hisim/components/weather.py index 614cfbfb9..1735023b6 100644 --- a/hisim/components/weather.py +++ b/hisim/components/weather.py @@ -588,7 +588,7 @@ def i_simulate( stsv.set_output_value(self.altitude_output, self.altitude_list[timestep]) stsv.set_output_value(self.azimuth_output, self.azimuth_list[timestep]) stsv.set_output_value(self.wind_speed_output, self.wind_speed_list[timestep]) - stsv.set_output_value(self.pressure_output, self.pressure_list[timestep]) + stsv.set_output_value(self.pressure_output, self.pressure_list[timestep]*100) #*100 umrechnung von hPA bzw mbar in PA stsv.set_output_value( self.apparent_zenith_output, self.apparent_zenith_list[timestep] ) From a3d959876f7dc930952744d60ee9528f30c2e373 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Mon, 11 Dec 2023 09:57:36 +0100 Subject: [PATCH 10/27] =?UTF-8?q?anpassen=20auf=20SI-Einheit=20f=C3=BCr=20?= =?UTF-8?q?Druck?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hisim/components/weather.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hisim/components/weather.py b/hisim/components/weather.py index 1735023b6..b9cf6b339 100644 --- a/hisim/components/weather.py +++ b/hisim/components/weather.py @@ -528,7 +528,7 @@ def __init__( self.component_name, self.Pressure, lt.LoadTypes.PRESSURE, - lt.Units.HEKTOPASCAL, # in try(dwd) unit: hPa, in nsrdb unit: mbar = hPa + lt.Units.PASCAL, output_description=f"here a description for {self.Pressure} will follow.", ) From 569b9bf964de8346a7bcf91a0a27c99ac07ce1a5 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Wed, 20 Dec 2023 12:42:48 +0100 Subject: [PATCH 11/27] =?UTF-8?q?modell=20erg=C3=A4nzt=20um=20pressure=20o?= =?UTF-8?q?utput=20f=C3=BCr=20windkraftanlage,=20vorbereitung=20funktion?= =?UTF-8?q?=20zum=20beziehen=20von=20wetterdaten=20vom=20dwd=20(10min=20af?= =?UTF-8?q?l=C3=B6sung)=20durch=20extra=20modell=20-->=20aktuelle=20reale?= =?UTF-8?q?=20wetterdaten=20f=C3=BCr=20ein=20jahr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hisim/components/weather.py | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/hisim/components/weather.py b/hisim/components/weather.py index b9cf6b339..b2caf2f22 100644 --- a/hisim/components/weather.py +++ b/hisim/components/weather.py @@ -45,6 +45,7 @@ class WeatherDataSourceEnum(Enum): DWD = 1 NSRDB = 2 NSRDB_15MIN = 3 + OWN_DWD_10MIN = 4 class LocationEnum(Enum): @@ -672,6 +673,28 @@ def i_prepare_simulation(self) -> None: ) pressure = (tmy_data["Pressure"].resample("1T").asfreq() .interpolate(method="linear") ) + + elif self.weather_config.data_source == WeatherDataSourceEnum.OWN_DWD_10MIN: + dni = ( + tmy_data["DNI"].resample("1T").asfreq().interpolate(method="linear") + ) + temperature = ( + tmy_data["T"].resample("1T").asfreq().interpolate(method="linear") + ) + dhi = ( + tmy_data["DHI"].resample("1T").asfreq().interpolate(method="linear") + ) + ghi = ( + tmy_data["GHI"].resample("1T").asfreq().interpolate(method="linear") + ) + wind_speed = ( + tmy_data["Wspd"] + .resample("1T") + .asfreq() + .interpolate(method="linear") + ) + pressure = (tmy_data["Pressure"].resample("1T").asfreq().interpolate(method="linear") + ) else: dni = self.interpolate( tmy_data["DNI"], self.my_simulation_parameters.year @@ -983,6 +1006,17 @@ def get_coordinates(filepath: str, source_enum: WeatherDataSourceEnum) -> Any: lon = float(row[6]) elif i > 1: break + + elif source_enum == WeatherDataSourceEnum.OWN_DWD_10MIN: + with open(filepath, encoding="utf-8") as csvfile: + spamreader = csv.reader(csvfile) + for i, row in enumerate(spamreader): + if i == 1: + location_name = row[0] + lat = float(row[1]) + lon = float(row[2]) + elif i > 1: + break else: # get the geoposition with open(filepath + ".dat", encoding="utf-8") as file_stream: @@ -1007,6 +1041,8 @@ def read_test_reference_year_data(weatherconfig: WeatherConfig, year: int) -> An data = read_dwd_data(filepath, year) elif weatherconfig.data_source == WeatherDataSourceEnum.NSRDB_15MIN: data = read_nsrdb_15min_data(filepath, year) + elif weatherconfig.data_source == WeatherDataSourceEnum.OWN_DWD_10MIN: + data = read_dwd_simulation_data_10min(filepath, year) return data @@ -1047,6 +1083,7 @@ def read_dwd_data(filepath: str, year: int) -> pd.DataFrame: # calculate direct normal data["DNI"] = calculate_direct_normal_radiation(data["B"], lon, lat) + print(data) return data @@ -1090,6 +1127,29 @@ def read_nsrdb_15min_data(filepath: str, year: int) -> pd.DataFrame: ) return data +def read_dwd_simulation_data_10min(filepath: str, year: int) -> pd.DataFrame: + """Reads a set of OWN DWD data in 10 min resolution.""" + data = pd.read_csv(filepath, encoding="utf-8", skiprows=[0,1]) + # get data + data.index = pd.date_range( + f"{year}-01-01 00:00:00", periods=24 * 6 * 365, freq="600S", tz="UTC" + ) + data = data.rename( + columns={ + "diffuse_irradiation": "DHI", + "temperature": "T", + "wind_speed": "Wspd", + "month": "Month", + "day": "Day", + "hour": "Hour", + "minute": "Minutes", + "pressure": "Pressure", + "wind_direction": "Wdir", + "global_irradiation": "GHI" + } + ) + data["DNI"] = data["GHI"] - data["DHI"] + return data def calculate_direct_normal_radiation( direct_horizontal_irradation: pd.Series, From d5c91a667809478957a8ffe185af11607fde48db Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Wed, 20 Dec 2023 13:07:34 +0100 Subject: [PATCH 12/27] new:Outputparameter Name for primary side if water/water HP comment: model actual doesn't work with regulated generic model --> maybe problem with hpLib todo: implement caching --- hisim/components/more_advanced_heat_pump_hplib.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hisim/components/more_advanced_heat_pump_hplib.py b/hisim/components/more_advanced_heat_pump_hplib.py index fd5de71a7..3772072b3 100644 --- a/hisim/components/more_advanced_heat_pump_hplib.py +++ b/hisim/components/more_advanced_heat_pump_hplib.py @@ -8,6 +8,8 @@ preparation on district heating for water/water heatpumps +don't work with regulated generic hp group --> todo + """ from typing import Any, List, Optional, Tuple, Dict import hashlib @@ -172,9 +174,9 @@ class HeatPumpHplib(Component): TimeOn = "TimeOn" # s TimeOff = "TimeOff" # s ThermalPowerFromEnvironment = "ThermalPowerInputFromEnvironment" #W - mdotWaterPrimaryDHNet = "MassflowHXBuildingDHNnet" # kg/s - WaterTemperatureHXIn = "TemperatureFromDHWNetInHX" # °C - WaterTemperatureHXOut = "TemperatureToDHWNetOutHX" # °C + mdotWaterPrimaryDHNet = "MassflowPrimary" # kg/s + WaterTemperatureHXIn = "TemperaturePrimaryIn" # °C + WaterTemperatureHXOut = "TemperaturePrimaryOut" # °C From da87a629795d9960a1d58ad2757f3937517573cc Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Wed, 20 Dec 2023 20:46:31 +0100 Subject: [PATCH 13/27] hisim uodate --- hisim/components/weather.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/hisim/components/weather.py b/hisim/components/weather.py index b2caf2f22..6040d16bc 100644 --- a/hisim/components/weather.py +++ b/hisim/components/weather.py @@ -1080,10 +1080,8 @@ def read_dwd_data(filepath: str, year: int) -> pd.DataFrame: "WR": "Wdir", } ) - # calculate direct normal data["DNI"] = calculate_direct_normal_radiation(data["B"], lon, lat) - print(data) return data From 6ca5a895e1e08251d5dfc6a662a6e1cfde483def Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Thu, 21 Dec 2023 09:15:46 +0100 Subject: [PATCH 14/27] erst zu mein branche, wenn komplett fertig und abgenommen --- .../more_advanced_heat_pump_hplib.py | 1567 ----------------- 1 file changed, 1567 deletions(-) delete mode 100644 hisim/components/more_advanced_heat_pump_hplib.py diff --git a/hisim/components/more_advanced_heat_pump_hplib.py b/hisim/components/more_advanced_heat_pump_hplib.py deleted file mode 100644 index fd5de71a7..000000000 --- a/hisim/components/more_advanced_heat_pump_hplib.py +++ /dev/null @@ -1,1567 +0,0 @@ -"""Advanced heat pump module. - -See library on https://github.com/FZJ-IEK3-VSA/hplib/tree/main/hplib - -two controller: one dhw controller and one building heating controller - -priority on dhw, if there is a demand from both in one timestep - -preparation on district heating for water/water heatpumps - -""" -from typing import Any, List, Optional, Tuple, Dict -import hashlib -from dataclasses import dataclass -from dataclasses_json import dataclass_json -from dataclass_wizard import JSONWizard - -import pandas as pd - -from hplib import hplib as hpl - -# Import modules from HiSim -from hisim.component import ( - Component, - ComponentInput, - ComponentOutput, - SingleTimeStepValues, - ConfigBase, - ComponentConnection, - OpexCostDataClass, -) -from hisim.components import weather, simple_hot_water_storage, heat_distribution_system -from hisim.loadtypes import LoadTypes, Units, InandOutputType -from hisim.simulationparameters import SimulationParameters -from hisim.sim_repository_singleton import SingletonSimRepository, SingletonDictKeyEnum -from hisim.components.heat_distribution_system import HeatingSystemType -from hisim.components.configuration import EmissionFactorsAndCostsForFuelsConfig -from hisim import log -from hisim.components import generic_hot_water_storage_modular -from hisim.components.configuration import PhysicsConfig - -__authors__ = "Jonas Hoppe" -__copyright__ = "" -__credits__ = ["Jonas Hoppe"] -__license__ = "-" -__version__ = "" -__maintainer__ = "" -__status__ = "" - - -@dataclass_json -@dataclass -class HeatPumpHplibConfig(ConfigBase): - - """HeatPumpHPLibConfig.""" - - @classmethod - def get_main_classname(cls): - """Returns the full class name of the base class.""" - return HeatPumpHplib.get_full_classname() - - name: str - model: str - heat_source: str - group_id: int - heating_reference_temperature_in_celsius: float # before t_in - flow_temperature_in_celsius: float # before t_out_val - set_thermal_output_power_in_watt: float # before p_th_set - cycling_mode: bool - minimum_running_time_in_seconds: Optional[int] - minimum_idle_time_in_seconds: Optional[int] - hx_building_temp_diff: Optional[float] #to be used, if water/water or brine/water heatpump - #: CO2 footprint of investment in kg - co2_footprint: float - #: cost for investment in Euro - cost: float - #: lifetime in years - lifetime: float - # maintenance cost as share of investment [0..1] - maintenance_cost_as_percentage_of_investment: float - #: consumption of the heatpump in kWh - consumption: float - - @classmethod - def get_default_generic_advanced_hp_lib(cls) -> "HeatPumpHplibConfig": - """Gets a default HPLib Heat Pump. - - see default values for air/water hp on: - https://github.com/FZJ-IEK3-VSA/hplib/blob/main/hplib/hplib.py l.135 "fit_p_th_ref. - """ - set_thermal_output_power_in_watt: float = 8000 - return HeatPumpHplibConfig( - name="AdvancedHeatPumpHPLib", - model="Generic", - heat_source="air", - group_id=4, - heating_reference_temperature_in_celsius=-7, - flow_temperature_in_celsius=52, - set_thermal_output_power_in_watt=set_thermal_output_power_in_watt, - cycling_mode=True, - minimum_running_time_in_seconds=600, - minimum_idle_time_in_seconds=600, - hx_building_temp_diff=2, - co2_footprint=set_thermal_output_power_in_watt - * 1e-3 - * 165.84, # value from emission_factros_and_costs_devices.csv - cost=set_thermal_output_power_in_watt - * 1e-3 - * 1513.74, # value from emission_factros_and_costs_devices.csv - lifetime=10, # value from emission_factros_and_costs_devices.csv - maintenance_cost_as_percentage_of_investment=0.025, # source: VDI2067-1 - consumption=0, - ) - - @classmethod - def get_scaled_advanced_hp_lib( - cls, heating_load_of_building_in_watt: float - ) -> "HeatPumpHplibConfig": - """Gets a default heat pump with scaling according to heating load of the building.""" - - set_thermal_output_power_in_watt = heating_load_of_building_in_watt - - return HeatPumpHplibConfig( - name="AdvancedHeatPumpHPLib", - model="Generic", - group_id=4, - heating_reference_temperature_in_celsius=-7, - flow_temperature_in_celsius=52, - set_thermal_output_power_in_watt=set_thermal_output_power_in_watt, - cycling_mode=True, - minimum_running_time_in_seconds=600, - minimum_idle_time_in_seconds=600, - co2_footprint=set_thermal_output_power_in_watt - * 1e-3 - * 165.84, # value from emission_factros_and_costs_devices.csv - cost=set_thermal_output_power_in_watt - * 1e-3 - * 1513.74, # value from emission_factros_and_costs_devices.csv - lifetime=10, # value from emission_factros_and_costs_devices.csv - maintenance_cost_as_percentage_of_investment=0.025, # source: VDI2067-1 - consumption=0, - ) - - -class HeatPumpHplib(Component): - - # Inputs - OnOffSwitchHotWater = "OnOffSwitchHotWater" # 1 = on hot Water, 0 = 0ff - OnOffSwitchDHW = "OnOffSwitchDHW" #2 = on DHW , 0 = 0ff - ThermalPowerIsConstantforDHW = "ThermalPowerisConstantforDHW" # true/false - MaxThermalPowerforDHW = "MaxThermalPowerforDHW" # max. Leistungswert - TemperatureInputPrimary = "TemperatureInputPrimary" # °C - TemperatureInputSecondary_HotWater = "TemperatureInputSecondaryHotWater" # °C - TemperatureInputSecondary_DHW = "TemperatureInputSecondaryDWH" # °C - TemperatureAmbient = "TemperatureAmbient" # °C - - - # Outputs - ThermalOutputPowerHotWater = "ThermalOutputPowerHotWater" # W - ThermalOutputPowerDHW = "ThermalOutputPowerDHW" # W - ThermalOutputPowerGesamt = "ThermalOutputPowerWholeHeatpump" #W - ElectricalInputPowerHotWater = "ElectricalInputPowerHotWater" # W - ElectricalInputPowerDHW = "ElectricalInputPowerDHW" # W - ElectricalInputPowerGesamt = "ElectricalInputPowerWholeHeatpump" - COP = "COP" # - - EER = "EER" # - - heatpumpOnOffState = "OnOffStateHeatpump" - TemperatureOutputHotWater = "TemperatureOutputHotWater" # °C - TemperatureOutputDHW = "TemperatureOutputDHW" # °C - MassFlowOutputHotWater = "MassFlowOutputHotWater" # kg/s - MassFlowOutputDHW = "MassFlowOutputDHW" # kg/s - TimeOn = "TimeOn" # s - TimeOff = "TimeOff" # s - ThermalPowerFromEnvironment = "ThermalPowerInputFromEnvironment" #W - mdotWaterPrimaryDHNet = "MassflowHXBuildingDHNnet" # kg/s - WaterTemperatureHXIn = "TemperatureFromDHWNetInHX" # °C - WaterTemperatureHXOut = "TemperatureToDHWNetOutHX" # °C - - - - def __init__( - self, - my_simulation_parameters: SimulationParameters, - config: HeatPumpHplibConfig, - ): - - super().__init__( - name=config.name, - my_simulation_parameters=my_simulation_parameters, - my_config=config, - ) - - self.model = config.model - - self.group_id = config.group_id - - self.t_in = config.heating_reference_temperature_in_celsius - - self.t_out_val = config.flow_temperature_in_celsius - - self.p_th_set = config.set_thermal_output_power_in_watt - - self.cycling_mode = config.cycling_mode - - self.minimum_running_time_in_seconds = config.minimum_running_time_in_seconds - - self.minimum_idle_time_in_seconds = config.minimum_idle_time_in_seconds - - self.hx_building_temp_diff = config.hx_building_temp_diff - - self.heat_source = config.heat_source - - #self.on_off: int = 0 - - postprocessing_flag = [InandOutputType.ELECTRICITY_CONSUMPTION_UNCONTROLLED] - - # Component has states - self.state = HeatPumpState( - time_on=0, time_off=0, time_on_cooling=0, on_off_previous=0 - ) - self.previous_state = self.state.self_copy() - - # Load parameters from heat pump database - self.parameters = hpl.get_parameters( - self.model, self.group_id, self.t_in, self.t_out_val, self.p_th_set - ) - - self.specific_heat_capacity_of_water_in_joule_per_kilogram_per_celsius = ( - PhysicsConfig.water_specific_heat_capacity_in_joule_per_kilogram_per_kelvin - ) - - #protect erros for Water/Water Heatpumps - if self.parameters['Group'].iloc[0] == 1.0 or self.parameters['Group'].iloc[0] == 4.0: - if self.heat_source != "air": - raise KeyError("WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!") - if self.parameters['Group'].iloc[0] == 2.0 or self.parameters['Group'].iloc[0] == 5.0: - if self.heat_source != "brine": - raise KeyError("WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!") - if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: - if self.heat_source != "water": - raise KeyError("WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!") - - - - - # Define component inputs - self.on_off_switch_hotWater: ComponentInput = self.add_input( - object_name=self.component_name, - field_name=self.OnOffSwitchHotWater, - load_type=LoadTypes.ANY, - unit=Units.ANY, - mandatory=True, - ) - - # Define component inputs - self.on_off_switch_DHW: ComponentInput = self.add_input( - object_name=self.component_name, - field_name=self.OnOffSwitchDHW, - load_type=LoadTypes.ANY, - unit=Units.ANY, - mandatory=True, - ) - - self.const_thermal_power_truefalse_DHW: ComponentInput = self.add_input( - object_name=self.component_name, - field_name=self.ThermalPowerIsConstantforDHW, - load_type=LoadTypes.ANY, - unit=Units.ANY, - mandatory=True, - ) - - self.const_thermal_power_value_DHW: ComponentInput = self.add_input( - object_name=self.component_name, - field_name=self.MaxThermalPowerforDHW, - load_type=LoadTypes.ANY, - unit=Units.ANY, - mandatory=True, - ) - - - self.t_in_primary: ComponentInput = self.add_input( - object_name=self.component_name, - field_name=self.TemperatureInputPrimary, - load_type=LoadTypes.TEMPERATURE, - unit=Units.CELSIUS, - mandatory=True, - ) - - self.t_in_secondary_hot_water: ComponentInput = self.add_input( - object_name=self.component_name, - field_name=self.TemperatureInputSecondary_HotWater, - load_type=LoadTypes.TEMPERATURE, - unit=Units.CELSIUS, - mandatory=True, - ) - - self.t_in_secondary_dhw: ComponentInput = self.add_input( - object_name=self.component_name, - field_name=self.TemperatureInputSecondary_DHW, - load_type=LoadTypes.TEMPERATURE, - unit=Units.CELSIUS, - mandatory=True, - ) - - self.t_amb: ComponentInput = self.add_input( - object_name=self.component_name, - field_name=self.TemperatureAmbient, - load_type=LoadTypes.TEMPERATURE, - unit=Units.CELSIUS, - mandatory=True, - ) - - # Define component outputs - self.p_th_hot_water: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.ThermalOutputPowerHotWater, - load_type=LoadTypes.HEATING, - unit=Units.WATT, - output_description=("Thermal output power hot Water Storage in Watt"), - ) - - self.p_th_dhw: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.ThermalOutputPowerDHW, - load_type=LoadTypes.HEATING, - unit=Units.WATT, - output_description=("Thermal output power dhw Storage in Watt"), - ) - - self.p_th_ges: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.ThermalOutputPowerGesamt, - load_type=LoadTypes.HEATING, - unit=Units.WATT, - postprocessing_flag=postprocessing_flag, - output_description="Thermal output power for whole HP in Watt", - ) - - self.p_el_hot_water: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.ElectricalInputPowerHotWater, - load_type=LoadTypes.ELECTRICITY, - unit=Units.WATT, - postprocessing_flag=postprocessing_flag, - output_description="Electricity input power for Hot Water in Watt", - ) - - self.p_el_dhw: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.ElectricalInputPowerDHW, - load_type=LoadTypes.ELECTRICITY, - unit=Units.WATT, - postprocessing_flag=postprocessing_flag, - output_description="Electricity input power for DHW in Watt", - ) - - self.p_el_ges: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.ElectricalInputPowerGesamt, - load_type=LoadTypes.ELECTRICITY, - unit=Units.WATT, - postprocessing_flag=postprocessing_flag, - output_description="Electricity input power for whole HP in Watt", - ) - - self.cop: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.COP, - load_type=LoadTypes.ANY, - unit=Units.ANY, - output_description="COP", - ) - self.eer: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.EER, - load_type=LoadTypes.ANY, - unit=Units.ANY, - output_description="EER", - ) - - self.heatpump_state: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.heatpumpOnOffState, - load_type=LoadTypes.ANY, - unit=Units.ANY, - output_description="OnOffState", - ) - - self.t_out_hot_water: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.TemperatureOutputHotWater, - load_type=LoadTypes.HEATING, - unit=Units.CELSIUS, - output_description="Temperature Output hot Water in °C", - ) - self.t_out_dhw: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.TemperatureOutputDHW, - load_type=LoadTypes.HEATING, - unit=Units.CELSIUS, - output_description="Temperature Output DHW Water in °C", - ) - - self.m_dot_hot_water: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.MassFlowOutputHotWater, - load_type=LoadTypes.VOLUME, - unit=Units.KG_PER_SEC, - output_description="Mass flow output", - ) - self.m_dot_dhw: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.MassFlowOutputDHW, - load_type=LoadTypes.VOLUME, - unit=Units.KG_PER_SEC, - output_description="Mass flow output", - ) - - self.time_on: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.TimeOn, - load_type=LoadTypes.TIME, - unit=Units.SECONDS, - output_description="Time turned on", - ) - - self.time_off: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.TimeOff, - load_type=LoadTypes.TIME, - unit=Units.SECONDS, - output_description="Time turned off", - ) - - self.thermal_power_from_environment: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.ThermalPowerFromEnvironment, - load_type=LoadTypes.HEATING, - unit=Units.WATT, - output_description="Thermal Input Power from Environment", - ) - - if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: - self.m_dot_water_primary_dhnet: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.mdotWaterPrimaryDHNet, - load_type=LoadTypes.VOLUME, - unit=Units.KG_PER_SEC, - output_description="Massflow of Water from District Heating Net", - ) - self.temp_water_primary_hx_in: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.WaterTemperatureHXIn, - load_type=LoadTypes.TEMPERATURE, - unit=Units.CELSIUS, - output_description="Temperature of Water from District Heating Net In HX", - ) - self.temp_water_primary_hx_out: ComponentOutput = self.add_output( - object_name=self.component_name, - field_name=self.WaterTemperatureHXOut, - load_type=LoadTypes.TEMPERATURE, - unit=Units.CELSIUS, - output_description="Temperature of Water to District Heating Net Out HX", - ) - - - self.add_default_connections( - self.get_default_connections_from_heat_pump_controller_hot_water() - ) - self.add_default_connections( - self.get_default_connections_from_heat_pump_controller_dhw() - ) - self.add_default_connections(self.get_default_connections_from_weather()) - self.add_default_connections(self.get_default_connections_from_simple_hot_water_storage()) - self.add_default_connections(self.get_default_connections_from_dhw_storage()) - - def get_default_connections_from_heat_pump_controller_hot_water(self,): - """Get default connections.""" - log.information("setting heat pump controller default connections") - connections = [] - hpc_classname = HeatPumpHplibControllerHotWaterStorage.get_classname() - connections.append( - ComponentConnection( - HeatPumpHplib.OnOffSwitchHotWater, hpc_classname, HeatPumpHplibControllerHotWaterStorage.State_HotWater, - ) - ) - return connections - - def get_default_connections_from_heat_pump_controller_dhw(self,): - """Get default connections.""" - log.information("setting heat pump controller default connections") - connections = [] - hpc_dhw_classname = HeatPumpHplibControllerDHW.get_classname() - connections.append( - ComponentConnection( - HeatPumpHplib.OnOffSwitchDHW, hpc_dhw_classname, HeatPumpHplibControllerDHW.State_dhw, - ) - ) - connections.append( - ComponentConnection( - HeatPumpHplib.ThermalPowerIsConstantforDHW, hpc_dhw_classname, HeatPumpHplibControllerDHW.ThermalPower_Bedingung_for_konst_dhw, - ) - ) - connections.append( - ComponentConnection( - HeatPumpHplib.MaxThermalPowerforDHW, hpc_dhw_classname, HeatPumpHplibControllerDHW.Value_Max_Thermal_Power_for_dhw, - ) - ) - return connections - - def get_default_connections_from_weather(self,): - """Get default connections.""" - log.information("setting weather default connections") - connections = [] - weather_classname = weather.Weather.get_classname() - connections.append( - ComponentConnection( - HeatPumpHplib.TemperatureAmbient, - weather_classname, - weather.Weather.DailyAverageOutsideTemperatures, - ) - ) - return connections - - def get_default_connections_from_simple_hot_water_storage(self,): - """Get simple hot water storage default connections.""" - log.information("setting simple hot water storage default connections") - connections = [] - hws_classname = simple_hot_water_storage.SimpleHotWaterStorage.get_classname() - connections.append( - ComponentConnection( - HeatPumpHplib.TemperatureInputSecondary_HotWater, - hws_classname, - simple_hot_water_storage.SimpleHotWaterStorage.WaterTemperatureToHeatGenerator, - ) - ) - return connections - - def get_default_connections_from_dhw_storage(self,): - """Get simple hot water storage default connections.""" - log.information("setting simple hot water storage default connections") - connections = [] - dhw_classname = generic_hot_water_storage_modular.HotWaterStorage.get_classname() - connections.append( - ComponentConnection( - HeatPumpHplib.TemperatureInputSecondary_DHW, - dhw_classname, - generic_hot_water_storage_modular.HotWaterStorage.TemperatureMean, - ) - ) - return connections - - def write_to_report(self): - """Write configuration to the report.""" - return self.config.get_string_dict() - - def i_save_state(self) -> None: - """Save state.""" - self.previous_state = self.state.self_copy() - # pass - - def i_restore_state(self) -> None: - """Restore state.""" - self.state = self.previous_state.self_copy() - # pass - - def i_doublecheck(self, timestep: int, stsv: SingleTimeStepValues) -> None: - """Doubelcheck.""" - pass - - def i_prepare_simulation(self) -> None: - """Prepare simulation.""" - pass - - def i_simulate( - self, timestep: int, stsv: SingleTimeStepValues, force_convergence: bool - ) -> None: - """Simulate the component.""" - - # Load input values - on_off: float - on_off_HotWater: float = stsv.get_input_value(self.on_off_switch_hotWater) - on_off_DHW: float = stsv.get_input_value(self.on_off_switch_DHW) - const_thermal_power_truefalse_DHW: bool = stsv.get_input_value(self.const_thermal_power_truefalse_DHW) - const_thermal_power_value_DHW: float = stsv.get_input_value(self.const_thermal_power_value_DHW) - t_in_primary = stsv.get_input_value(self.t_in_primary) - t_in_secondary_hot_water = stsv.get_input_value(self.t_in_secondary_hot_water) - t_in_secondary_dhw = stsv.get_input_value(self.t_in_secondary_dhw) - t_amb = stsv.get_input_value(self.t_amb) - time_on_heating = self.state.time_on - time_on_cooling = self.state.time_on_cooling - time_off = self.state.time_off - - - if on_off_DHW != 0: - on_off = on_off_DHW - else: - on_off = on_off_HotWater - - # cycling means periodic turning on and off of the heat pump - if self.cycling_mode is True: - - # Parameter - time_on_min = self.minimum_running_time_in_seconds # [s] - time_off_min = self.minimum_idle_time_in_seconds - on_off_previous = self.state.on_off_previous - - if time_on_min is None or time_off_min is None: - raise ValueError( - "When the cycling mode is true, the minimum running time and minimum idle time of the heat pump must be given an integer value." - ) - - # Overwrite on_off to realize minimum time of or time off - if on_off_previous == 1 and time_on_heating < time_on_min: - on_off = 1 - elif on_off_previous == 2 and time_on_heating < time_on_min: - on_off = 2 - elif on_off_previous == -1 and time_on_cooling < time_on_min: - on_off = -1 - elif on_off_previous == 0 and time_off < time_off_min: - on_off = 0 - - # heat pump is turned on and off only according to heat pump controller - elif self.cycling_mode is False: - pass - else: - raise ValueError("Cycling mode of the advanced hplib unknown.") - - - if on_off_DHW != 0: - on_off = on_off_DHW - - - # OnOffSwitch - if on_off == 1: - # Calulate outputs for heating mode - results = hpl.simulate( - t_in_primary=t_in_primary, - t_in_secondary=t_in_secondary_hot_water, - parameters=self.parameters, - t_amb=t_amb, - mode=1, - ) - p_th_hot_water = results["P_th"].values[0] - p_th_dhw = 0 - p_el_hot_water = results["P_el"].values[0] - p_el_dhw = 0 - cop = results["COP"].values[0] - eer = results["EER"].values[0] - t_out_hot_water = results["T_out"].values[0] - t_out_dhw = t_in_secondary_dhw - m_dot_hot_water = results["m_dot"].values[0] - m_dot_dhw = 0 - time_on_heating = time_on_heating + self.my_simulation_parameters.seconds_per_timestep - time_on_cooling = 0 - time_off = 0 - - elif on_off == 2: # Calculate outputs for dhw mode - if const_thermal_power_truefalse_DHW == False: # False=modulation - results = hpl.simulate( - t_in_primary=t_in_primary, - t_in_secondary=t_in_secondary_dhw, - parameters=self.parameters, - t_amb=t_amb, - mode=1, - ) - p_th_dhw = results["P_th"].values[0] - p_th_hot_water = 0 - p_el_dhw = results["P_el"].values[0] - p_el_hot_water = 0 - cop = results["COP"].values[0] - eer = results["EER"].values[0] - t_out_hot_water = t_in_secondary_hot_water - t_out_dhw = results["T_out"].values[0] - m_dot_hot_water = 0 - m_dot_dhw = results["m_dot"].values[0] - time_on_heating = time_on_heating + self.my_simulation_parameters.seconds_per_timestep - time_on_cooling = 0 - time_off = 0 - # print("t_out_WP_dhw " + str(t_out_dhw)) - - elif const_thermal_power_truefalse_DHW == True: # True = constante thermische Leistung - results = hpl.simulate( - t_in_primary=t_in_primary, - t_in_secondary=t_in_secondary_dhw, - parameters=self.parameters, - t_amb=t_amb, - mode=1, - ) - p_th_dhw = const_thermal_power_value_DHW - p_th_hot_water = 0 - cop = results["COP"].values[0] - p_el_dhw = p_th_dhw/cop - p_el_hot_water = 0 - eer = results["EER"].values[0] - t_out_hot_water = t_in_secondary_hot_water - t_out_dhw = results["T_out"].values[0] - m_dot_hot_water = 0 - m_dot_dhw = results["m_dot"].values[0] - time_on_heating = time_on_heating + self.my_simulation_parameters.seconds_per_timestep - time_on_cooling = 0 - time_off = 0 - - - elif on_off == -1: - # Calulate outputs for cooling mode - results = hpl.simulate( - t_in_primary=t_in_primary, - t_in_secondary=t_in_secondary_hot_water, - parameters=self.parameters, - t_amb=t_amb, - mode=2, - ) - p_th_hot_water = results["P_th"].values[0] - p_th_dhw = 0 - p_el_hot_water = results["P_el"].values[0] - p_el_dhw = 0 - cop = results["COP"].values[0] - eer = results["EER"].values[0] - t_out_hot_water = results["T_out"].values[0] - t_out_dhw = t_out_hot_water - m_dot_hot_water = results["m_dot"].values[0] - m_dot_dhw = 0 - time_on_cooling = ( - time_on_cooling + self.my_simulation_parameters.seconds_per_timestep - ) - time_on_heating = 0 - time_off = 0 - - elif on_off == 0: - # Calulate outputs for off mode - p_th_hot_water = 0 - p_th_dhw = 0 - p_el_hot_water = 0 - p_el_dhw = 0 - # None values or nans will cause troubles in post processing, that is why there are not used here - # cop = None - # t_out = None - cop = 0 - eer = 0 - t_out_hot_water = t_in_secondary_hot_water - t_out_dhw = t_in_secondary_dhw - m_dot_hot_water = 0 - m_dot_dhw = 0 - time_off = time_off + self.my_simulation_parameters.seconds_per_timestep - time_on_heating = 0 - time_on_cooling = 0 - - else: - raise ValueError("Unknown mode for Advanced HPLib On_Off.") - - - - if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: - #todo: variability of massflow. now there is a fix temperaturdiffernz between inlet and outlet which calculate the massflow - - q_dot_entzugsleistung = ((p_th_dhw + p_th_hot_water) - (p_el_dhw + p_el_hot_water)) - m_dot_water_primary = q_dot_entzugsleistung/(self.specific_heat_capacity_of_water_in_joule_per_kilogram_per_celsius*self.hx_building_temp_diff) - t_out_primary = t_in_primary-self.hx_building_temp_diff - stsv.set_output_value(self.m_dot_water_primary_dhnet, m_dot_water_primary) - stsv.set_output_value(self.temp_water_primary_hx_in, t_in_primary) - stsv.set_output_value(self.temp_water_primary_hx_out, t_out_primary) - - - - # write values for output time series - stsv.set_output_value(self.p_th_hot_water, p_th_hot_water) - stsv.set_output_value(self.p_th_dhw, p_th_dhw) - stsv.set_output_value(self.p_th_ges, p_th_dhw+p_th_hot_water) - stsv.set_output_value(self.p_el_hot_water, p_el_hot_water) - stsv.set_output_value(self.p_el_dhw, p_el_dhw) - stsv.set_output_value(self.p_el_ges, p_el_dhw+p_el_hot_water) - stsv.set_output_value(self.cop, cop) - stsv.set_output_value(self.eer, eer) - stsv.set_output_value(self.heatpump_state, on_off) - stsv.set_output_value(self.t_out_hot_water, t_out_hot_water) - stsv.set_output_value(self.t_out_dhw, t_out_dhw) - stsv.set_output_value(self.m_dot_hot_water, m_dot_hot_water) - stsv.set_output_value(self.m_dot_dhw, m_dot_dhw) - stsv.set_output_value(self.time_on, time_on_heating) - stsv.set_output_value(self.time_off, time_off) - stsv.set_output_value(self.thermal_power_from_environment, (p_th_dhw+p_th_hot_water)-(p_el_dhw+p_el_hot_water)) - - - - # write values to state - self.state.time_on = time_on_heating - self.state.time_on_cooling = time_on_cooling - self.state.time_off = time_off - self.state.on_off_previous = on_off - - @staticmethod - def get_cost_capex(config: HeatPumpHplibConfig) -> Tuple[float, float, float]: - """Returns investment cost, CO2 emissions and lifetime.""" - return config.cost, config.co2_footprint, config.lifetime - - def get_cost_opex( - self, - all_outputs: List, - postprocessing_results: pd.DataFrame, - ) -> Tuple[float, float]: - """Calculate OPEX costs, consisting of maintenance costs. - - No electricity costs for components except for Electricity Meter, - because part of electricity consumption is feed by PV - """ - for index, output in enumerate(all_outputs): - if ( - output.component_name == "HeatPumpHPLib" - and output.load_type == LoadTypes.ELECTRICITY - ): # Todo: check component name from examples: find another way of using only heatpump-outputs - self.config.consumption = round( - sum(postprocessing_results.iloc[:, index]) - * self.my_simulation_parameters.seconds_per_timestep - / 3.6e6, - 1, - ) - - return self.calc_maintenance_cost(), 0.0 - - -@dataclass -class HeatPumpState: # anpassen, dass automatisch dhw priorisiert wird - """HeatPumpState class.""" - - time_on: int = 0 - time_off: int = 0 - time_on_cooling: int = 0 - on_off_previous: float = 0 - - def self_copy(self,): - """Copy the Heat Pump State.""" - return HeatPumpState( - self.time_on, self.time_off, self.time_on_cooling, self.on_off_previous - ) - - -# =========================================================================== -# try to implement a hplib controller l1 -@dataclass_json -@dataclass -class HeatPumpHplibControllerHotWaterStorageL1Config(ConfigBase): - - """HeatPump Controller Config Class for building heating.""" - - @classmethod - def get_main_classname(cls): - """Returns the full class name of the base class.""" - return HeatPumpHplibControllerHotWaterStorage.get_full_classname() - - name: str - mode: int - set_heating_threshold_outside_temperature_in_celsius: Optional[float] - set_cooling_threshold_outside_temperature_in_celsius: Optional[float] - temperature_offset_for_state_conditions_in_celsius: float - - @classmethod - def get_default_generic_heat_pump_controller_config(cls): - """Gets a default Generic Heat Pump Controller.""" - return HeatPumpHplibControllerHotWaterStorageL1Config( - name="HeatPumpControllerHotWaterStorage", - mode=1, - set_heating_threshold_outside_temperature_in_celsius=None, - set_cooling_threshold_outside_temperature_in_celsius=20.0, - temperature_offset_for_state_conditions_in_celsius=5.0, - ) - - -class HeatPumpHplibControllerHotWaterStorage(Component): - - """Heat Pump Controller. - - It takes data from other - components and sends signal to the heat pump for - activation or deactivation. - On/off Switch with respect to water temperature from storage. - - Parameters - ---------- - t_air_heating: float - Minimum comfortable temperature for residents - t_air_cooling: float - Maximum comfortable temperature for residents - offset: float - Temperature offset to compensate the hysteresis - correction for the building temperature change - mode : int - Mode index for operation type for this heat pump - - """ - - # Inputs - WaterTemperatureInputFromHeatWaterStorage = ( - "WaterTemperatureInputFromHeatWaterStorage" - ) - HeatingFlowTemperatureFromHeatDistributionSystem = ( - "HeatingFlowTemperatureFromHeatDistributionSystem" - ) - - DailyAverageOutsideTemperature = "DailyAverageOutsideTemperature" - - SimpleHotWaterStorageTemperatureModifier = ( - "SimpleHotWaterStorageTemperatureModifier" - ) - - # Outputs - State_HotWater = "State_HotWater" - - def __init__( - self, - my_simulation_parameters: SimulationParameters, - config: HeatPumpHplibControllerHotWaterStorageL1Config, - ) -> None: - """Construct all the neccessary attributes.""" - self.heatpump_controller_config = config - super().__init__( - self.heatpump_controller_config.name, - my_simulation_parameters=my_simulation_parameters, - my_config=config, - ) - - if SingletonSimRepository().exist_entry(key=SingletonDictKeyEnum.HEATINGSYSTEM): - self.heating_system = SingletonSimRepository().get_entry( - key=SingletonDictKeyEnum.HEATINGSYSTEM - ) - else: - raise KeyError( - "Keys for heating system was not found in the singleton sim repository." - + "This might be because the heat distribution system was not initialized before the advanced hplib controller." - + "Please check the order of the initialization of the components in your example." - ) - self.build( - mode=self.heatpump_controller_config.mode, - temperature_offset_for_state_conditions_in_celsius=self.heatpump_controller_config.temperature_offset_for_state_conditions_in_celsius, - ) - - self.water_temperature_input_channel: ComponentInput = self.add_input( - self.component_name, - self.WaterTemperatureInputFromHeatWaterStorage, - LoadTypes.TEMPERATURE, - Units.CELSIUS, - True, - ) - - self.heating_flow_temperature_from_heat_distribution_system_channel: ComponentInput = self.add_input( - self.component_name, - self.HeatingFlowTemperatureFromHeatDistributionSystem, - LoadTypes.TEMPERATURE, - Units.CELSIUS, - True, - ) - self.daily_avg_outside_temperature_input_channel: ComponentInput = ( - self.add_input( - self.component_name, - self.DailyAverageOutsideTemperature, - LoadTypes.TEMPERATURE, - Units.CELSIUS, - True, - ) - ) - - self.simple_hot_water_storage_temperature_modifier_channel: ComponentInput = ( - self.add_input( - self.component_name, - self.SimpleHotWaterStorageTemperatureModifier, - LoadTypes.TEMPERATURE, - Units.CELSIUS, - mandatory=False, - ) - ) - - self.state_channel: ComponentOutput = self.add_output( - self.component_name, - self.State_HotWater, - LoadTypes.ANY, - Units.ANY, - output_description=f"here a description for {self.State_HotWater} will follow.", - ) - - self.controller_heatpumpmode: Any - self.previous_heatpump_mode: Any - - self.add_default_connections( - self.get_default_connections_from_heat_distribution_controller() - ) - self.add_default_connections(self.get_default_connections_from_weather()) - self.add_default_connections( - self.get_default_connections_from_simple_hot_water_storage() - ) - - def get_default_connections_from_heat_distribution_controller(self,): - """Get default connections.""" - log.information("setting heat distribution controller default connections") - connections = [] - hdsc_classname = ( - heat_distribution_system.HeatDistributionController.get_classname() - ) - connections.append( - ComponentConnection( - HeatPumpHplibControllerHotWaterStorage.HeatingFlowTemperatureFromHeatDistributionSystem, - hdsc_classname, - heat_distribution_system.HeatDistributionController.HeatingFlowTemperature, - ) - ) - return connections - - def get_default_connections_from_weather(self,): - """Get default connections.""" - log.information("setting weather default connections") - connections = [] - weather_classname = weather.Weather.get_classname() - connections.append( - ComponentConnection( - HeatPumpHplibControllerHotWaterStorage.DailyAverageOutsideTemperature, - weather_classname, - weather.Weather.DailyAverageOutsideTemperatures, - ) - ) - return connections - - def get_default_connections_from_simple_hot_water_storage(self,): - """Get simple hot water storage default connections.""" - log.information("setting simple hot water storage default connections") - connections = [] - hws_classname = simple_hot_water_storage.SimpleHotWaterStorage.get_classname() - connections.append( - ComponentConnection( - HeatPumpHplibControllerHotWaterStorage.WaterTemperatureInputFromHeatWaterStorage, - hws_classname, - simple_hot_water_storage.SimpleHotWaterStorage.WaterTemperatureToHeatGenerator, - ) - ) - return connections - - def build( - self, mode: float, temperature_offset_for_state_conditions_in_celsius: float, - ) -> None: - """Build function. - - The function sets important constants and parameters for the calculations. - """ - # Sth - self.controller_heatpumpmode = "off" - self.previous_heatpump_mode = self.controller_heatpumpmode - - # Configuration - self.mode = mode - self.temperature_offset_for_state_conditions_in_celsius = ( - temperature_offset_for_state_conditions_in_celsius - ) - - def i_prepare_simulation(self) -> None: - """Prepare the simulation.""" - pass - - def i_save_state(self) -> None: - """Save the current state.""" - self.previous_heatpump_mode = self.controller_heatpumpmode - - def i_restore_state(self) -> None: - """Restore the previous state.""" - self.controller_heatpumpmode = self.previous_heatpump_mode - - def i_doublecheck(self, timestep: int, stsv: SingleTimeStepValues) -> None: - """Doublecheck.""" - pass - - def write_to_report(self) -> List[str]: - """Write important variables to report.""" - return self.heatpump_controller_config.get_string_dict() - - def i_simulate( - self, timestep: int, stsv: SingleTimeStepValues, force_convergence: bool - ) -> None: - """Simulate the heat pump comtroller.""" - - if force_convergence: - pass - else: - # Retrieves inputs - - water_temperature_input_from_heat_water_storage_in_celsius = ( - stsv.get_input_value(self.water_temperature_input_channel) - ) - - heating_flow_temperature_from_heat_distribution_system = ( - stsv.get_input_value( - self.heating_flow_temperature_from_heat_distribution_system_channel - ) - ) - - daily_avg_outside_temperature_in_celsius = stsv.get_input_value( - self.daily_avg_outside_temperature_input_channel - ) - - storage_temperature_modifier = stsv.get_input_value( - self.simple_hot_water_storage_temperature_modifier_channel - ) - - # turning heat pump off when the average daily outside temperature is above a certain threshold (if threshold is set in the config) - summer_heating_mode = self.summer_heating_condition( - daily_average_outside_temperature_in_celsius=daily_avg_outside_temperature_in_celsius, - set_heating_threshold_temperature_in_celsius=self.heatpump_controller_config.set_heating_threshold_outside_temperature_in_celsius, - ) - - # mode 1 is on/off controller - if self.mode == 1: - self.conditions_on_off( - water_temperature_input_in_celsius=water_temperature_input_from_heat_water_storage_in_celsius, - set_heating_flow_temperature_in_celsius=heating_flow_temperature_from_heat_distribution_system, - summer_heating_mode=summer_heating_mode, - storage_temperature_modifier=storage_temperature_modifier, - temperature_offset_for_state_conditions_in_celsius=self.temperature_offset_for_state_conditions_in_celsius, - ) - - # mode 2 is regulated controller (meaning heating, cooling, off). this is only possible if heating system is floor heating - elif ( - self.mode == 2 and self.heating_system == HeatingSystemType.FLOORHEATING - ): - # turning heat pump cooling mode off when the average daily outside temperature is below a certain threshold - summer_cooling_mode = self.summer_cooling_condition( - daily_average_outside_temperature_in_celsius=daily_avg_outside_temperature_in_celsius, - set_cooling_threshold_temperature_in_celsius=self.heatpump_controller_config.set_cooling_threshold_outside_temperature_in_celsius, - ) - self.conditions_heating_cooling_off( - water_temperature_input_in_celsius=water_temperature_input_from_heat_water_storage_in_celsius, - set_heating_flow_temperature_in_celsius=heating_flow_temperature_from_heat_distribution_system, - summer_heating_mode=summer_heating_mode, - summer_cooling_mode=summer_cooling_mode, - storage_temperature_modifier=storage_temperature_modifier, - temperature_offset_for_state_conditions_in_celsius=self.temperature_offset_for_state_conditions_in_celsius, - ) - - else: - raise ValueError( - "Either the Advanced HP Lib Controller Mode is neither 1 nor 2," - "or the heating system is not floor heating which is the condition for cooling (mode 2)." - ) - - if self.controller_heatpumpmode == "heating": - state = 1 - elif self.controller_heatpumpmode == "cooling": - state = -1 - elif self.controller_heatpumpmode == "off": - state = 0 - else: - raise ValueError("Advanced HP Lib Controller State unknown.") - - stsv.set_output_value(self.state_channel, state) - - def conditions_on_off( - self, - water_temperature_input_in_celsius: float, - set_heating_flow_temperature_in_celsius: float, - summer_heating_mode: str, - storage_temperature_modifier: float, - temperature_offset_for_state_conditions_in_celsius: float, - ) -> None: - """Set conditions for the heat pump controller mode.""" - - if self.controller_heatpumpmode == "heating": - if ( - water_temperature_input_in_celsius - > ( - set_heating_flow_temperature_in_celsius - # + 0.5 - + temperature_offset_for_state_conditions_in_celsius - + storage_temperature_modifier - ) - or summer_heating_mode == "off" - ): # + 1: - self.controller_heatpumpmode = "off" - return - - elif self.controller_heatpumpmode == "off": - - # heat pump is only turned on if the water temperature is below the flow temperature - # and if the avg daily outside temperature is cold enough (summer mode on) - if ( - water_temperature_input_in_celsius - < ( - set_heating_flow_temperature_in_celsius - # - 1.0 - - temperature_offset_for_state_conditions_in_celsius - + storage_temperature_modifier - ) - and summer_heating_mode == "on" - ): # - 1: - self.controller_heatpumpmode = "heating" - return - - else: - raise ValueError("unknown mode") - - def conditions_heating_cooling_off( - self, - water_temperature_input_in_celsius: float, - set_heating_flow_temperature_in_celsius: float, - summer_heating_mode: str, - summer_cooling_mode: str, - storage_temperature_modifier: float, - temperature_offset_for_state_conditions_in_celsius: float, - ) -> None: - """Set conditions for the heat pump controller mode according to the flow temperature.""" - # Todo: storage temperature modifier is only working for heating so far. Implement for cooling similar - heating_set_temperature = set_heating_flow_temperature_in_celsius - cooling_set_temperature = set_heating_flow_temperature_in_celsius - - if self.controller_heatpumpmode == "heating": - if ( - water_temperature_input_in_celsius - >= heating_set_temperature - + storage_temperature_modifier # Todo: Check if storage_temperature_modifier is neccessary here - or summer_heating_mode == "off" - ): - self.controller_heatpumpmode = "off" - return - elif self.controller_heatpumpmode == "cooling": - if ( - water_temperature_input_in_celsius <= cooling_set_temperature - or summer_cooling_mode == "off" - ): - self.controller_heatpumpmode = "off" - return - - elif self.controller_heatpumpmode == "off": - - # heat pump is only turned on if the water temperature is below the flow temperature - # and if the avg daily outside temperature is cold enough (summer heating mode on) - if ( - water_temperature_input_in_celsius - < ( - heating_set_temperature - - temperature_offset_for_state_conditions_in_celsius - + storage_temperature_modifier - ) - and summer_heating_mode == "on" - ): - self.controller_heatpumpmode = "heating" - return - - # heat pump is only turned on for cooling if the water temperature is above a certain flow temperature - # and if the avg daily outside temperature is warm enough (summer cooling mode on) - if ( - water_temperature_input_in_celsius - > ( - cooling_set_temperature - + temperature_offset_for_state_conditions_in_celsius - ) - and summer_cooling_mode == "on" - ): - self.controller_heatpumpmode = "cooling" - return - - else: - raise ValueError("unknown mode") - - def summer_heating_condition( - self, - daily_average_outside_temperature_in_celsius: float, - set_heating_threshold_temperature_in_celsius: Optional[float], - ) -> str: - """Set conditions for the heat pump.""" - - # if no heating threshold is set, the heat pump is always on - if set_heating_threshold_temperature_in_celsius is None: - heating_mode = "on" - - # it is too hot for heating - elif ( - daily_average_outside_temperature_in_celsius - > set_heating_threshold_temperature_in_celsius - ): - heating_mode = "off" - - # it is cold enough for heating - elif ( - daily_average_outside_temperature_in_celsius - < set_heating_threshold_temperature_in_celsius - ): - heating_mode = "on" - - else: - raise ValueError( - f"daily average temperature {daily_average_outside_temperature_in_celsius}°C" - f"or heating threshold temperature {set_heating_threshold_temperature_in_celsius}°C is not acceptable." - ) - return heating_mode - - def summer_cooling_condition( - self, - daily_average_outside_temperature_in_celsius: float, - set_cooling_threshold_temperature_in_celsius: Optional[float], - ) -> str: - """Set conditions for the heat pump.""" - - # if no cooling threshold is set, cooling is always possible no matter what daily outside temperature - if set_cooling_threshold_temperature_in_celsius is None: - cooling_mode = "on" - - # it is hot enough for cooling - elif ( - daily_average_outside_temperature_in_celsius - > set_cooling_threshold_temperature_in_celsius - ): - cooling_mode = "on" - - # it is too cold for cooling - elif ( - daily_average_outside_temperature_in_celsius - < set_cooling_threshold_temperature_in_celsius - ): - cooling_mode = "off" - - else: - raise ValueError( - f"daily average temperature {daily_average_outside_temperature_in_celsius}°C" - f"or cooling threshold temperature {set_cooling_threshold_temperature_in_celsius}°C is not acceptable." - ) - - return cooling_mode - - -@dataclass -class CalculationRequest(JSONWizard): - - """Class for caching hplib parameters so that hplib.simulate does not need to run so often.""" - - t_in_primary: float - t_in_secondary: float - t_amb: float - mode: int - - def get_key(self): - """Get key of class with important parameters.""" - - return ( - str(self.t_in_primary) - + " " - + str(self.t_in_secondary) - + " " - + str(self.t_amb) - + " " - + str(self.mode) - ) - -# =========================================================================== -# implement a hplib controller l1 for dhw storage (tww) -@dataclass_json -@dataclass -class HeatPumpHplibControllerDHWL1Config(ConfigBase): - - """HeatPump Controller Config Class for dhw .""" - - @classmethod - def get_main_classname(cls): - """Returns the full class name of the base class.""" - return HeatPumpHplibControllerDHW.get_full_classname() - - name: str - #: lower set temperature of DHW Storage, given in °C - t_min_dhw_storage_in_celsius: float - #: upper set temperature of DHW Storage, given in °C - t_max_dhw_storage_in_celsius: float - #: set thermal power delivered for dhw on constant value --> max. Value of heatpump - thermalPower_is_constant_for_dhw: bool - #: max. Power of Heatpump for not modulation dhw production - p_th_max_dhw_in_W: float - - - @classmethod - def get_default_generic_heat_pump_controller_config(cls): - """Gets a default Generic Heat Pump Controller.""" - return HeatPumpHplibControllerDHWL1Config( - name="HeatPumpControllerDHW", - t_min_dhw_storage_in_celsius=40.0, - t_max_dhw_storage_in_celsius=60.0, - thermalPower_is_constant_for_dhw = False, #false: modulation, true: constant power for dhw - p_th_max_dhw_in_W = 5000, # only if true - ) - - -class HeatPumpHplibControllerDHW(Component): - - """Heat Pump Controller for DHW. - - It takes data from DHW Storage --> generic hot water stoprage modular - sends signal to the heat pump for activation or deactivation. - - """ - - - # in state mit aufnehmen das hier priorisiert wird - - # Inputs - WaterTemperatureInputFromDHWStorage ="WaterTemperatureInputFromDHWStorage" - DWHStorageTemperatureModifier = "StorageTemperatureModifier" - - # Outputs - State_dhw = "State DHW" - ThermalPower_Bedingung_for_konst_dhw = "BedingungfuerKonstDHW" #if heatpump has fix power for dhw - Value_Max_Thermal_Power_for_dhw = "ThermalPowerHPForDHWConst" #if heatpump has fix power for dhw - - - - - def __init__( - self, - my_simulation_parameters: SimulationParameters, - config: HeatPumpHplibControllerDHWL1Config, - ) -> None: - """Construct all the neccessary attributes.""" - self.heatpump_controller_dhw_config = config - super().__init__( - self.heatpump_controller_dhw_config.name, - my_simulation_parameters=my_simulation_parameters, - my_config=config, - ) - self.config: HeatPumpHplibControllerDHWL1Config = config - - self.build() - - self.water_temperature_input_channel: ComponentInput = self.add_input( - self.component_name, - self.WaterTemperatureInputFromDHWStorage, - LoadTypes.TEMPERATURE, - Units.CELSIUS, - True, - ) - - self.storage_temperature_modifier_channel: ComponentInput = self.add_input( - self.component_name, - self.DWHStorageTemperatureModifier, - LoadTypes.TEMPERATURE, - Units.CELSIUS, - mandatory=False, - ) - - self.state_dhw_channel: ComponentOutput = self.add_output( - self.component_name, - self.State_dhw, - LoadTypes.ANY, - Units.ANY, - output_description=f"here a description for {self.State_dhw} will follow.", - ) - - self.thermalPower_const_bedingung_channel: ComponentOutput = self.add_output( - self.component_name, - self.ThermalPower_Bedingung_for_konst_dhw, - LoadTypes.ANY, - Units.ANY, - output_description=f"here a description for {self.ThermalPower_Bedingung_for_konst_dhw} will follow.", - ) - - self.thermalPower_max_value_channel: ComponentOutput = self.add_output( - self.component_name, - self.Value_Max_Thermal_Power_for_dhw, - LoadTypes.ANY, - Units.ANY, - output_description=f"here a description for {self.Value_Max_Thermal_Power_for_dhw} will follow.", - ) - - self.controller_heatpumpmode_dhw: Any - self.previous_heatpump_mode_dhw: Any - self.controller_signal: int - self.thermalPower_constant_for_dhw: bool - self.p_th_max_dhw: float - - - self.add_default_connections(self.get_default_connections_from_dhw_storage()) - - def get_default_connections_from_dhw_storage(self, ): - """Get simple hot water storage default connections.""" - log.information("setting dhw storage default connections") - connections = [] - dhw_classname = generic_hot_water_storage_modular.HotWaterStorage.get_classname() - connections.append( - ComponentConnection( - HeatPumpHplibControllerDHW.WaterTemperatureInputFromDHWStorage, - dhw_classname, - generic_hot_water_storage_modular.HotWaterStorage.TemperatureMean, - ) - ) - return connections - - def build(self, ) -> None: - """Build function. - - The function sets important constants and parameters for the calculations. - """ - # Sth - self.controller_heatpumpmode_dhw = "off_dhw_heating" - self.previous_heatpump_mode_dhw = self.controller_heatpumpmode_dhw - self.controller_signal = 1 - self.thermalPower_constant_for_dhw = self.config.thermalPower_is_constant_for_dhw - self.p_th_max_dhw = self.config.p_th_max_dhw_in_W - - if self.thermalPower_constant_for_dhw == True: - print("INFO: DHW Power ist constant with " + str(self.p_th_max_dhw) + "W") - elif self.thermalPower_constant_for_dhw == False: - print("INFO: DHW Power is modulating") - self.p_th_max_dhw=0 - - - def i_prepare_simulation(self) -> None: - """Prepare the simulation.""" - pass - - def i_save_state(self) -> None: - """Save the current state.""" - self.previous_heatpump_mode_dhw = self.controller_heatpumpmode_dhw - - def i_restore_state(self) -> None: - """Restore the previous state.""" - self.controller_heatpumpmode_dhw = self.previous_heatpump_mode_dhw - - def i_doublecheck(self, timestep: int, stsv: SingleTimeStepValues) -> None: - """Doublecheck.""" - pass - - def write_to_report(self) -> List[str]: - """Write important variables to report.""" - return self.heatpump_controller_dhw_config.get_string_dict() - - def i_simulate( - self, timestep: int, stsv: SingleTimeStepValues, force_convergence: bool - ) -> None: - """Simulate the heat pump comtroller.""" - - #if force_convergence: - # pass - #else: - # Retrieves inputs - - water_temperature_input_from_dhw_storage_in_celsius = stsv.get_input_value(self.water_temperature_input_channel) - temperature_modifier = stsv.get_input_value(self.storage_temperature_modifier_channel) - - t_min_dhw_storage_in_celsius = self.config.t_min_dhw_storage_in_celsius - t_max_dhw_storage_in_celsius = self.config.t_max_dhw_storage_in_celsius - - - if water_temperature_input_from_dhw_storage_in_celsius < t_min_dhw_storage_in_celsius: #an - self.controller_signal = 1 - elif water_temperature_input_from_dhw_storage_in_celsius > t_max_dhw_storage_in_celsius + temperature_modifier: #aus - self.controller_signal = 0 - elif temperature_modifier > 0 and water_temperature_input_from_dhw_storage_in_celsius < t_max_dhw_storage_in_celsius: - self.controller_signal = 1 - else: - - pass - - - if self.controller_signal == 1: - state_dhw = 2 - elif self.controller_signal == 0: - state_dhw = 0 - else: - raise ValueError("Advanced HP Lib DHW Controller State unknown.") - - stsv.set_output_value(self.state_dhw_channel, state_dhw) - stsv.set_output_value(self.thermalPower_const_bedingung_channel, self.thermalPower_constant_for_dhw) - if self.thermalPower_constant_for_dhw == True: - stsv.set_output_value(self.thermalPower_max_value_channel, self.p_th_max_dhw) - elif self.thermalPower_constant_for_dhw == False: - stsv.set_output_value(self.thermalPower_max_value_channel, 0) - - From bba251550a1793d6d37d21672bcf9da0c9581a9e Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Thu, 21 Dec 2023 09:38:34 +0100 Subject: [PATCH 15/27] update to newsest HiSim Version, with caching results for heatpump calculation --- .../more_advanced_heat_pump_hplib.py | 184 +++++++++++------- 1 file changed, 112 insertions(+), 72 deletions(-) diff --git a/hisim/components/more_advanced_heat_pump_hplib.py b/hisim/components/more_advanced_heat_pump_hplib.py index 3772072b3..e8f2b4e55 100644 --- a/hisim/components/more_advanced_heat_pump_hplib.py +++ b/hisim/components/more_advanced_heat_pump_hplib.py @@ -16,12 +16,8 @@ from dataclasses import dataclass from dataclasses_json import dataclass_json from dataclass_wizard import JSONWizard - import pandas as pd - from hplib import hplib as hpl - -# Import modules from HiSim from hisim.component import ( Component, ComponentInput, @@ -31,12 +27,10 @@ ComponentConnection, OpexCostDataClass, ) -from hisim.components import weather, simple_hot_water_storage, heat_distribution_system +from hisim.components import weather, simple_hot_water_storage,generic_hot_water_storage_modular, heat_distribution_system from hisim.loadtypes import LoadTypes, Units, InandOutputType from hisim.simulationparameters import SimulationParameters -from hisim.sim_repository_singleton import SingletonSimRepository, SingletonDictKeyEnum -from hisim.components.heat_distribution_system import HeatingSystemType -from hisim.components.configuration import EmissionFactorsAndCostsForFuelsConfig +from hisim.components.heat_distribution_system import HeatDistributionSystemType from hisim import log from hisim.components import generic_hot_water_storage_modular from hisim.components.configuration import PhysicsConfig @@ -174,11 +168,9 @@ class HeatPumpHplib(Component): TimeOn = "TimeOn" # s TimeOff = "TimeOff" # s ThermalPowerFromEnvironment = "ThermalPowerInputFromEnvironment" #W - mdotWaterPrimaryDHNet = "MassflowPrimary" # kg/s - WaterTemperatureHXIn = "TemperaturePrimaryIn" # °C - WaterTemperatureHXOut = "TemperaturePrimaryOut" # °C - - + mdotWaterPrimary = "MassflowPrimary" # kg/s + WaterTemperaturePrimaryIn = "TemperaturePrimaryIn" # °C + WaterTemperaturePrimaryOut = "TemperaturePrimaryOut" # °C def __init__( self, @@ -191,6 +183,8 @@ def __init__( my_simulation_parameters=my_simulation_parameters, my_config=config, ) + # caching for hplib simulation + self.calculation_cache: Dict = {} self.model = config.model @@ -445,21 +439,21 @@ def __init__( if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: self.m_dot_water_primary_dhnet: ComponentOutput = self.add_output( object_name=self.component_name, - field_name=self.mdotWaterPrimaryDHNet, + field_name=self.mdotWaterPrimary, load_type=LoadTypes.VOLUME, unit=Units.KG_PER_SEC, output_description="Massflow of Water from District Heating Net", ) self.temp_water_primary_hx_in: ComponentOutput = self.add_output( object_name=self.component_name, - field_name=self.WaterTemperatureHXIn, + field_name=self.WaterTemperaturePrimaryIn, load_type=LoadTypes.TEMPERATURE, unit=Units.CELSIUS, output_description="Temperature of Water from District Heating Net In HX", ) self.temp_water_primary_hx_out: ComponentOutput = self.add_output( object_name=self.component_name, - field_name=self.WaterTemperatureHXOut, + field_name=self.WaterTemperaturePrimaryOut, load_type=LoadTypes.TEMPERATURE, unit=Units.CELSIUS, output_description="Temperature of Water to District Heating Net Out HX", @@ -490,7 +484,7 @@ def get_default_connections_from_heat_pump_controller_hot_water(self,): def get_default_connections_from_heat_pump_controller_dhw(self,): """Get default connections.""" - log.information("setting heat pump controller default connections") + connections = [] hpc_dhw_classname = HeatPumpHplibControllerDHW.get_classname() connections.append( @@ -512,7 +506,7 @@ def get_default_connections_from_heat_pump_controller_dhw(self,): def get_default_connections_from_weather(self,): """Get default connections.""" - log.information("setting weather default connections") + connections = [] weather_classname = weather.Weather.get_classname() connections.append( @@ -636,7 +630,7 @@ def i_simulate( # OnOffSwitch if on_off == 1: # Calulate outputs for heating mode - results = hpl.simulate( + results = self.get_cached_results_or_run_hplib_simulation( #hpl.simulate( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_hot_water, parameters=self.parameters, @@ -659,7 +653,7 @@ def i_simulate( elif on_off == 2: # Calculate outputs for dhw mode if const_thermal_power_truefalse_DHW == False: # False=modulation - results = hpl.simulate( + results = self.get_cached_results_or_run_hplib_simulation( #hpl.simulate( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_dhw, parameters=self.parameters, @@ -682,7 +676,7 @@ def i_simulate( # print("t_out_WP_dhw " + str(t_out_dhw)) elif const_thermal_power_truefalse_DHW == True: # True = constante thermische Leistung - results = hpl.simulate( + results = self.get_cached_results_or_run_hplib_simulation( #hpl.simulate( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_dhw, parameters=self.parameters, @@ -706,7 +700,7 @@ def i_simulate( elif on_off == -1: # Calulate outputs for cooling mode - results = hpl.simulate( + results = self.get_cached_results_or_run_hplib_simulation( #hpl.simulate( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_hot_water, parameters=self.parameters, @@ -800,7 +794,7 @@ def get_cost_opex( self, all_outputs: List, postprocessing_results: pd.DataFrame, - ) -> Tuple[float, float]: + ) -> OpexCostDataClass: """Calculate OPEX costs, consisting of maintenance costs. No electricity costs for components except for Electricity Meter, @@ -810,15 +804,56 @@ def get_cost_opex( if ( output.component_name == "HeatPumpHPLib" and output.load_type == LoadTypes.ELECTRICITY - ): # Todo: check component name from examples: find another way of using only heatpump-outputs + ): # Todo: check component name from system_setups: find another way of using only heatpump-outputs self.config.consumption = round( sum(postprocessing_results.iloc[:, index]) * self.my_simulation_parameters.seconds_per_timestep / 3.6e6, 1, ) + opex_cost_data_class = OpexCostDataClass( + opex_cost=self.calc_maintenance_cost(), + co2_footprint=0, + consumption=self.config.consumption, + ) + + return opex_cost_data_class + + def get_cached_results_or_run_hplib_simulation( + self, + t_in_primary: float, + t_in_secondary: float, + parameters: pd.DataFrame, + t_amb: float, + mode: int, + ) -> Any: + """Use caching of results of hplib simulation.""" + + # rounding of variable values + t_in_primary = round(t_in_primary, 1) + t_in_secondary = round(t_in_secondary, 1) + t_amb = round(t_amb, 1) + + my_data_class = CalculationRequest( + t_in_primary=t_in_primary, + t_in_secondary=t_in_secondary, + t_amb=t_amb, + mode=mode, + ) + my_json_key = my_data_class.get_key() + my_hash_key = hashlib.sha256(my_json_key.encode("utf-8")).hexdigest() + + if my_hash_key in self.calculation_cache: + results = self.calculation_cache[my_hash_key] + + else: + results = hpl.simulate( + t_in_primary, t_in_secondary, parameters, t_amb, mode=mode + ) - return self.calc_maintenance_cost(), 0.0 + self.calculation_cache[my_hash_key] = results + + return results @dataclass @@ -830,7 +865,9 @@ class HeatPumpState: # an time_on_cooling: int = 0 on_off_previous: float = 0 - def self_copy(self,): + def self_copy( + self, + ): """Copy the Heat Pump State.""" return HeatPumpState( self.time_on, self.time_off, self.time_on_cooling, self.on_off_previous @@ -855,9 +892,12 @@ def get_main_classname(cls): set_heating_threshold_outside_temperature_in_celsius: Optional[float] set_cooling_threshold_outside_temperature_in_celsius: Optional[float] temperature_offset_for_state_conditions_in_celsius: float + heat_distribution_system_type: Any @classmethod - def get_default_generic_heat_pump_controller_config(cls): + def get_default_generic_heat_pump_controller_config( + cls, heat_distribution_system_type: Any + )-> "HeatPumpHplibControllerHotWaterStorageL1Config" : """Gets a default Generic Heat Pump Controller.""" return HeatPumpHplibControllerHotWaterStorageL1Config( name="HeatPumpControllerHotWaterStorage", @@ -865,6 +905,7 @@ def get_default_generic_heat_pump_controller_config(cls): set_heating_threshold_outside_temperature_in_celsius=None, set_cooling_threshold_outside_temperature_in_celsius=20.0, temperature_offset_for_state_conditions_in_celsius=5.0, + heat_distribution_system_type=heat_distribution_system_type, ) @@ -921,16 +962,9 @@ def __init__( my_config=config, ) - if SingletonSimRepository().exist_entry(key=SingletonDictKeyEnum.HEATINGSYSTEM): - self.heating_system = SingletonSimRepository().get_entry( - key=SingletonDictKeyEnum.HEATINGSYSTEM - ) - else: - raise KeyError( - "Keys for heating system was not found in the singleton sim repository." - + "This might be because the heat distribution system was not initialized before the advanced hplib controller." - + "Please check the order of the initialization of the components in your example." - ) + self.heat_distribution_system_type = ( + self.heatpump_controller_config.heat_distribution_system_type + ) self.build( mode=self.heatpump_controller_config.mode, temperature_offset_for_state_conditions_in_celsius=self.heatpump_controller_config.temperature_offset_for_state_conditions_in_celsius, @@ -992,7 +1026,6 @@ def __init__( def get_default_connections_from_heat_distribution_controller(self,): """Get default connections.""" - log.information("setting heat distribution controller default connections") connections = [] hdsc_classname = ( heat_distribution_system.HeatDistributionController.get_classname() @@ -1008,7 +1041,6 @@ def get_default_connections_from_heat_distribution_controller(self,): def get_default_connections_from_weather(self,): """Get default connections.""" - log.information("setting weather default connections") connections = [] weather_classname = weather.Weather.get_classname() connections.append( @@ -1022,7 +1054,6 @@ def get_default_connections_from_weather(self,): def get_default_connections_from_simple_hot_water_storage(self,): """Get simple hot water storage default connections.""" - log.information("setting simple hot water storage default connections") connections = [] hws_classname = simple_hot_water_storage.SimpleHotWaterStorage.get_classname() connections.append( @@ -1035,7 +1066,9 @@ def get_default_connections_from_simple_hot_water_storage(self,): return connections def build( - self, mode: float, temperature_offset_for_state_conditions_in_celsius: float, + self, + mode: float, + temperature_offset_for_state_conditions_in_celsius: float, ) -> None: """Build function. @@ -1117,7 +1150,9 @@ def i_simulate( # mode 2 is regulated controller (meaning heating, cooling, off). this is only possible if heating system is floor heating elif ( - self.mode == 2 and self.heating_system == HeatingSystemType.FLOORHEATING + self.mode == 2 + and self.heat_distribution_system_type + == HeatDistributionSystemType.FLOORHEATING ): # turning heat pump cooling mode off when the average daily outside temperature is below a certain threshold summer_cooling_mode = self.summer_cooling_condition( @@ -1352,7 +1387,7 @@ def get_key(self): @dataclass class HeatPumpHplibControllerDHWL1Config(ConfigBase): - """HeatPump Controller Config Class for dhw .""" + """HeatPump Controller Config Class.""" @classmethod def get_main_classname(cls): @@ -1386,7 +1421,7 @@ class HeatPumpHplibControllerDHW(Component): """Heat Pump Controller for DHW. - It takes data from DHW Storage --> generic hot water stoprage modular + It takes data from DHW Storage --> generic hot water storage modular sends signal to the heat pump for activation or deactivation. """ @@ -1529,41 +1564,46 @@ def i_simulate( ) -> None: """Simulate the heat pump comtroller.""" - #if force_convergence: - # pass - #else: - # Retrieves inputs + if force_convergence: + pass + else: - water_temperature_input_from_dhw_storage_in_celsius = stsv.get_input_value(self.water_temperature_input_channel) - temperature_modifier = stsv.get_input_value(self.storage_temperature_modifier_channel) + water_temperature_input_from_dhw_storage_in_celsius = stsv.get_input_value(self.water_temperature_input_channel) + temperature_modifier = stsv.get_input_value(self.storage_temperature_modifier_channel) - t_min_dhw_storage_in_celsius = self.config.t_min_dhw_storage_in_celsius - t_max_dhw_storage_in_celsius = self.config.t_max_dhw_storage_in_celsius + t_min_dhw_storage_in_celsius = self.config.t_min_dhw_storage_in_celsius + t_max_dhw_storage_in_celsius = self.config.t_max_dhw_storage_in_celsius - if water_temperature_input_from_dhw_storage_in_celsius < t_min_dhw_storage_in_celsius: #an - self.controller_signal = 1 - elif water_temperature_input_from_dhw_storage_in_celsius > t_max_dhw_storage_in_celsius + temperature_modifier: #aus - self.controller_signal = 0 - elif temperature_modifier > 0 and water_temperature_input_from_dhw_storage_in_celsius < t_max_dhw_storage_in_celsius: - self.controller_signal = 1 - else: + if water_temperature_input_from_dhw_storage_in_celsius < t_min_dhw_storage_in_celsius: #an + #self.controller_heatpumpmode_dhw = "heating_dhw" + self.controller_signal = 1 + elif water_temperature_input_from_dhw_storage_in_celsius > t_max_dhw_storage_in_celsius + temperature_modifier: #aus + # self.controller_heatpumpmode_dhw = "off_dhw_heating" + self.controller_signal = 0 + elif temperature_modifier > 0 and water_temperature_input_from_dhw_storage_in_celsius < t_max_dhw_storage_in_celsius: #aktiviren wenn strom überschuss + self.controller_signal = 1 + else: + # self.controller_signal=630 + pass - pass + if self.controller_signal == 1: + state_dhw = 2 + # print("heating dhw on") + elif self.controller_signal == 0: + state_dhw = 0 + # print("heating dhw off") + else: + raise ValueError("Advanced HP Lib DHW Controller State unknown.") - if self.controller_signal == 1: - state_dhw = 2 - elif self.controller_signal == 0: - state_dhw = 0 - else: - raise ValueError("Advanced HP Lib DHW Controller State unknown.") - stsv.set_output_value(self.state_dhw_channel, state_dhw) - stsv.set_output_value(self.thermalPower_const_bedingung_channel, self.thermalPower_constant_for_dhw) - if self.thermalPower_constant_for_dhw == True: - stsv.set_output_value(self.thermalPower_max_value_channel, self.p_th_max_dhw) - elif self.thermalPower_constant_for_dhw == False: - stsv.set_output_value(self.thermalPower_max_value_channel, 0) + # print("state controller neu " + str(state_dhw)) + stsv.set_output_value(self.state_dhw_channel, state_dhw) + stsv.set_output_value(self.thermalPower_const_bedingung_channel, self.thermalPower_constant_for_dhw) + if self.thermalPower_constant_for_dhw == True: + stsv.set_output_value(self.thermalPower_max_value_channel, self.p_th_max_dhw) + elif self.thermalPower_constant_for_dhw == False: + stsv.set_output_value(self.thermalPower_max_value_channel, 0) From 9f796398d836fb3a610e8e8d4627044508a2eda4 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Thu, 21 Dec 2023 10:39:16 +0100 Subject: [PATCH 16/27] new example for more_advanced_heat_pump_hplib model for comparison with example "household_1" --- ...ousehold_1b_more_advanced_hp_diesel_car.py | 395 ++++++++++++++++++ 1 file changed, 395 insertions(+) create mode 100644 system_setups/household_1b_more_advanced_hp_diesel_car.py diff --git a/system_setups/household_1b_more_advanced_hp_diesel_car.py b/system_setups/household_1b_more_advanced_hp_diesel_car.py new file mode 100644 index 000000000..56dbe9f6e --- /dev/null +++ b/system_setups/household_1b_more_advanced_hp_diesel_car.py @@ -0,0 +1,395 @@ +""" Household system setup with advanced heat pump and diesel car. """ + +# clean + +from typing import List, Optional, Any +from pathlib import Path +from dataclasses import dataclass +from os import getenv, listdir +from utspclient.helpers.lpgdata import ( + ChargingStationSets, + Households, + TransportationDeviceSets, + TravelRouteSets, + EnergyIntensityType, +) + +from hisim.simulator import SimulationParameters +from hisim.components import loadprofilegenerator_utsp_connector +from hisim.components import weather +from hisim.components import more_advanced_heat_pump_hplib +from hisim.components import heat_distribution_system +from hisim.components import building +from hisim.components import simple_hot_water_storage +from hisim.components import generic_car +from hisim.components import generic_hot_water_storage_modular +from hisim.components import electricity_meter +from hisim.components.configuration import HouseholdWarmWaterDemandConfig +from hisim.system_setup_configuration import SystemSetupConfigBase +from hisim import utils + +from system_setups.modular_example import cleanup_old_lpg_requests + +__authors__ = ["Markus Blasberg", "Kevin Knosala"] +__copyright__ = "Copyright 2023, FZJ-IEK-3" +__credits__ = ["Noah Pflugradt"] +__license__ = "MIT" +__version__ = "1.0" +__maintainer__ = "Markus Blasberg" +__status__ = "development" + + +@dataclass +class HouseholdAdvancedHPDieselCarConfig(SystemSetupConfigBase): + + """Configuration for with advanced heat pump and diesel car.""" + + building_type: str + number_of_apartments: int + occupancy_config: loadprofilegenerator_utsp_connector.UtspLpgConnectorConfig + building_config: building.BuildingConfig + hds_controller_config: heat_distribution_system.HeatDistributionControllerConfig + hds_config: heat_distribution_system.HeatDistributionConfig + hp_controller_config: more_advanced_heat_pump_hplib.HeatPumpHplibControllerHotWaterStorageL1Config + hp_config: more_advanced_heat_pump_hplib.HeatPumpHplibConfig + simple_hot_water_storage_config: simple_hot_water_storage.SimpleHotWaterStorageConfig + dhw_heatpump_controller_config: more_advanced_heat_pump_hplib.HeatPumpHplibControllerDHWL1Config + dhw_storage_config: generic_hot_water_storage_modular.StorageConfig + car_config: generic_car.CarConfig + electricity_meter_config: electricity_meter.ElectricityMeterConfig + + @classmethod + def get_default(cls) -> "HouseholdAdvancedHPDieselCarConfig": + """Get default HouseholdAdvancedHPDieselCarConfig.""" + + heating_reference_temperature_in_celsius: float = -7 + + building_config = ( + building.BuildingConfig.get_default_german_single_family_home(heating_reference_temperature_in_celsius=heating_reference_temperature_in_celsius) + ) + + household_config = cls.get_scaled_default(building_config) + + household_config.hp_config.set_thermal_output_power_in_watt = ( + 6000 # default value leads to switching on-off very often + ) + household_config.dhw_storage_config.volume = ( + 250 # default(volume = 230) leads to an error + ) + + return household_config + + @classmethod + def get_scaled_default( + cls, + building_config: building.BuildingConfig, + ) -> "HouseholdAdvancedHPDieselCarConfig": + """Get scaled default HouseholdAdvancedHPDieselCarConfig.""" + + set_heating_threshold_outside_temperature_in_celsius: float = 16.0 + + my_building_information = building.BuildingInformation(config=building_config) + + hds_controller_config = heat_distribution_system.HeatDistributionControllerConfig.get_default_heat_distribution_controller_config( + set_heating_temperature_for_building_in_celsius=my_building_information.set_heating_temperature_for_building_in_celsius, + set_cooling_temperature_for_building_in_celsius=my_building_information.set_cooling_temperature_for_building_in_celsius, + heating_load_of_building_in_watt=my_building_information.max_thermal_building_demand_in_watt, + heating_reference_temperature_in_celsius=my_building_information.heating_reference_temperature_in_celsius + ) + my_hds_controller_information = ( + heat_distribution_system.HeatDistributionControllerInformation( + config=hds_controller_config + ) + ) + household_config = HouseholdAdvancedHPDieselCarConfig( + building_type="blub", + number_of_apartments=int(my_building_information.number_of_apartments), + occupancy_config=loadprofilegenerator_utsp_connector.UtspLpgConnectorConfig( + url="http://134.94.131.167:443/api/v1/profilerequest", + api_key="OrjpZY93BcNWw8lKaMp0BEchbCc", + household=Households.CHR01_Couple_both_at_Work, + energy_intensity=EnergyIntensityType.EnergySaving, + result_dir_path=utils.HISIMPATH["results"], + travel_route_set=TravelRouteSets.Travel_Route_Set_for_10km_Commuting_Distance, + transportation_device_set=TransportationDeviceSets.Bus_and_one_30_km_h_Car, + charging_station_set=ChargingStationSets.Charging_At_Home_with_11_kW, + name="UTSPConnector", + consumption=0.0, + profile_with_washing_machine_and_dishwasher=True, + predictive_control=False, + ), + building_config=building_config, + hds_controller_config=hds_controller_config, + hds_config=( + heat_distribution_system.HeatDistributionConfig.get_default_heatdistributionsystem_config( + temperature_difference_between_flow_and_return_in_celsius=my_hds_controller_information.temperature_difference_between_flow_and_return_in_celsius, + water_mass_flow_rate_in_kg_per_second=my_hds_controller_information.water_mass_flow_rate_in_kp_per_second, + ) + ), + hp_controller_config=more_advanced_heat_pump_hplib.HeatPumpHplibControllerHotWaterStorageL1Config.get_default_generic_heat_pump_controller_config( + heat_distribution_system_type=my_hds_controller_information.heat_distribution_system_type + ), + hp_config=more_advanced_heat_pump_hplib.HeatPumpHplibConfig.get_scaled_advanced_hp_lib( + heating_load_of_building_in_watt=my_building_information.max_thermal_building_demand_in_watt, + heating_reference_temperature_in_celsius=my_building_information.heating_reference_temperature_in_celsius + ), + simple_hot_water_storage_config=simple_hot_water_storage.SimpleHotWaterStorageConfig.get_scaled_hot_water_storage( + max_thermal_power_in_watt_of_heating_system=my_building_information.max_thermal_building_demand_in_watt, + temperature_difference_between_flow_and_return_in_celsius=my_hds_controller_information.temperature_difference_between_flow_and_return_in_celsius, + heating_system_name="AdvancedHeatPumpHPLib", + water_mass_flow_rate_from_hds_in_kg_per_second=my_hds_controller_information.water_mass_flow_rate_in_kp_per_second, + ), + dhw_heatpump_controller_config=more_advanced_heat_pump_hplib.HeatPumpHplibControllerDHWL1Config.get_default_generic_heat_pump_controller_config(), + dhw_storage_config=generic_hot_water_storage_modular.StorageConfig.get_scaled_config_for_boiler_to_number_of_apartments( + number_of_apartments=int(my_building_information.number_of_apartments) + ), + car_config=generic_car.CarConfig.get_default_diesel_config(), + electricity_meter_config=electricity_meter.ElectricityMeterConfig.get_electricity_meter_default_config(), + ) + + # adjust HeatPump + household_config.hp_config.group_id = 1 # use modulating heatpump as default + household_config.hp_controller_config.mode = ( + 2 # use heating and cooling as default + ) + household_config.hp_config.minimum_idle_time_in_seconds = ( + 900 # default value leads to switching on-off very often + ) + household_config.hp_config.minimum_running_time_in_seconds = ( + 900 # default value leads to switching on-off very often + ) + + # set same heating threshold + household_config.hds_controller_config.set_heating_threshold_outside_temperature_in_celsius = ( + set_heating_threshold_outside_temperature_in_celsius + ) + household_config.hp_controller_config.set_heating_threshold_outside_temperature_in_celsius = ( + set_heating_threshold_outside_temperature_in_celsius + ) + + household_config.hp_config.flow_temperature_in_celsius = 21 # Todo: check value + + return household_config + + +def setup_function( + my_sim: Any, + my_simulation_parameters: Optional[SimulationParameters] = None, +) -> None: # noqa: too-many-statements + """System setup with advanced hp and diesel car. + + This setup function emulates a household with some basic components. Here the residents have their + electricity and heating needs covered by a the advanced heat pump. + + - Simulation Parameters + - Components + - Occupancy (Residents' Demands) + - Weather + - Building + - Electricity Meter + - Advanced Heat Pump HPlib + - Advanced Heat Pump HPlib Controller + - Heat Distribution System + - Heat Distribution System Controller + - Simple Hot Water Storage + + - DHW (Heatpump, Heatpumpcontroller, Storage; copied from modular_example) + - Car (Diesel) + """ + + # cleanup old lpg requests, mandatory to change number of cars + # Todo: change cleanup-function if result_path from occupancy is not utils.HISIMPATH["results"] + if Path(utils.HISIMPATH["utsp_results"]).exists(): + cleanup_old_lpg_requests() + + if my_sim.my_module_config_path: + my_config = HouseholdAdvancedHPDieselCarConfig.load_from_json( + my_sim.my_module_config_path + ) + else: + my_config = HouseholdAdvancedHPDieselCarConfig.get_default() + + # Todo: save file leads to use of file in next run. File was just produced to check how it looks like + # my_config_json = my_config.to_json() + # with open(config_filename, "w", encoding="utf8") as system_config_file: + # system_config_file.write(my_config_json) + + # ================================================================================================================================= + # Set System Parameters + + # Set Simulation Parameters + year = 2021 + seconds_per_timestep = 60 + + # ================================================================================================================================= + # Build Components + + # Build Simulation Parameters + if my_simulation_parameters is None: + my_simulation_parameters = SimulationParameters.full_year_all_options( + year=year, seconds_per_timestep=seconds_per_timestep + ) + my_sim.set_simulation_parameters(my_simulation_parameters) + + # Build heat Distribution System Controller + my_heat_distribution_controller = ( + heat_distribution_system.HeatDistributionController( + config=my_config.hds_controller_config, + my_simulation_parameters=my_simulation_parameters, + ) + ) + + # Build Occupancy + my_occupancy_config = my_config.occupancy_config + my_occupancy = loadprofilegenerator_utsp_connector.UtspLpgConnector( + config=my_occupancy_config, my_simulation_parameters=my_simulation_parameters + ) + + # Build Weather + my_weather = weather.Weather( + config=weather.WeatherConfig.get_default(weather.LocationEnum.AACHEN), + my_simulation_parameters=my_simulation_parameters, + ) + + # Build Building + my_building = building.Building( + config=my_config.building_config, + my_simulation_parameters=my_simulation_parameters, + ) + + # Build Heat Distribution System + my_heat_distribution = heat_distribution_system.HeatDistribution( + my_simulation_parameters=my_simulation_parameters, config=my_config.hds_config + ) + # Build Heat Pump Controller for hot water + my_heatpump_controller_hotwater_config = my_config.hp_controller_config + my_heatpump_controller_hotwater_config.name = "HPHotWaterController" + + my_heatpump_controller_hotWater = more_advanced_heat_pump_hplib.HeatPumpHplibControllerHotWaterStorage( + config=my_heatpump_controller_hotwater_config, + my_simulation_parameters=my_simulation_parameters + ) + + # Build Heat Pump Controller for dhw + my_heatpump_controller_dhw_config = my_config.dhw_heatpump_controller_config + + my_heatpump_controller_dhw = more_advanced_heat_pump_hplib.HeatPumpHplibControllerDHW( + config=my_heatpump_controller_dhw_config, + my_simulation_parameters=my_simulation_parameters + ) + + # Build Heat Pump + my_heatpump_config = my_config.hp_config + my_heatpump_config.name = "HeatPumpHPLib" + + my_heatpump = more_advanced_heat_pump_hplib.HeatPumpHplib( + config=my_heatpump_config, + my_simulation_parameters=my_simulation_parameters, + ) + + # Build Heat Water Storage + my_hot_water_storage = simple_hot_water_storage.SimpleHotWaterStorage( + config=my_config.simple_hot_water_storage_config, + my_simulation_parameters=my_simulation_parameters, + ) + + my_dhw_storage_config = my_config.dhw_storage_config + my_dhw_storage_config.name = "DHWStorage" + my_dhw_storage_config.compute_default_cycle( + temperature_difference_in_kelvin=60-40 #default values + ) + + my_dhw_storage = generic_hot_water_storage_modular.HotWaterStorage( + my_simulation_parameters=my_simulation_parameters, config=my_dhw_storage_config + ) + + # Build Diesel-Car(s) + # get names of all available cars + filepaths = listdir(utils.HISIMPATH["utsp_results"]) + filepaths_location = [elem for elem in filepaths if "CarLocation." in elem] + names = [elem.partition(",")[0].partition(".")[2] for elem in filepaths_location] + + my_car_config = my_config.car_config + my_car_config.name = "DieselCar" + + # create all cars + my_cars: List[generic_car.Car] = [] + for car in names: + my_car_config.name = car + my_cars.append( + generic_car.Car( + my_simulation_parameters=my_simulation_parameters, + config=my_car_config, + occupancy_config=my_occupancy_config, + ) + ) + + # Build Electricity Meter + my_electricity_meter = electricity_meter.ElectricityMeter( + my_simulation_parameters=my_simulation_parameters, + config=my_config.electricity_meter_config, + ) + + # ================================================================================================================================= + # Connect Components + + my_heatpump.connect_only_predefined_connections( + my_heatpump_controller_hotWater, my_heatpump_controller_dhw, my_weather, my_hot_water_storage, + my_dhw_storage) + + # Verknüpfung mit Luft als Umgebungswärmeqzuelle + if my_heatpump.parameters['Group'].iloc[0] == 1.0 or my_heatpump.parameters['Group'].iloc[ + 0] == 4.0: + my_heatpump.connect_input( + my_heatpump.TemperatureInputPrimary, + my_weather.component_name, + my_weather.DailyAverageOutsideTemperatures, + ) + else: + raise KeyError( + "Wasser oder Sole als primäres Wärmeträgermedium muss über extra Wärmenetz-Modell noch bereitgestellt werden") + + my_dhw_storage.connect_input( + my_dhw_storage.ThermalPowerDelivered, + my_heatpump.component_name, + my_heatpump.ThermalOutputPowerDHW, + ) + my_hot_water_storage.connect_input( + my_hot_water_storage.WaterMassFlowRateFromHeatGenerator, + my_heatpump.component_name, + my_heatpump.MassFlowOutputHotWater, + ) + my_hot_water_storage.connect_input( + my_hot_water_storage.WaterTemperatureFromHeatGenerator, + my_heatpump.component_name, + my_heatpump.TemperatureOutputHotWater, + ) + my_heatpump_controller_hotWater.connect_only_predefined_connections(my_heat_distribution_controller, + my_weather, + my_hot_water_storage) + + my_heatpump_controller_dhw.connect_only_predefined_connections(my_dhw_storage) + # ================================================================================================================================= + # Add Components to Simulation Parameters + my_sim.add_component(my_occupancy) + my_sim.add_component(my_weather) + my_sim.add_component(my_building, connect_automatically=True) + my_sim.add_component(my_heatpump) + my_sim.add_component(my_heatpump_controller_hotWater) + my_sim.add_component(my_heatpump_controller_dhw) + my_sim.add_component(my_heat_distribution, connect_automatically=True) + my_sim.add_component(my_heat_distribution_controller, connect_automatically=True) + my_sim.add_component(my_hot_water_storage, connect_automatically=True) + my_sim.add_component(my_dhw_storage, connect_automatically=True) + my_sim.add_component(my_electricity_meter, connect_automatically=True) + for my_car in my_cars: + my_sim.add_component(my_car) + + +import hisim.hisim_main + +def sim(): + hisim.hisim_main.main("household_1b_more_advanced_hp_diesel_car.py") + + +sim() \ No newline at end of file From d8e87947cf17849b99f4aa2b9744cb7749068737 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Thu, 21 Dec 2023 10:39:48 +0100 Subject: [PATCH 17/27] update new hisim version --- .../more_advanced_heat_pump_hplib.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/hisim/components/more_advanced_heat_pump_hplib.py b/hisim/components/more_advanced_heat_pump_hplib.py index e8f2b4e55..feb63abe8 100644 --- a/hisim/components/more_advanced_heat_pump_hplib.py +++ b/hisim/components/more_advanced_heat_pump_hplib.py @@ -32,7 +32,6 @@ from hisim.simulationparameters import SimulationParameters from hisim.components.heat_distribution_system import HeatDistributionSystemType from hisim import log -from hisim.components import generic_hot_water_storage_modular from hisim.components.configuration import PhysicsConfig __authors__ = "Jonas Hoppe" @@ -78,19 +77,22 @@ def get_main_classname(cls): consumption: float @classmethod - def get_default_generic_advanced_hp_lib(cls) -> "HeatPumpHplibConfig": + def get_default_generic_advanced_hp_lib( + cls, + set_thermal_output_power_in_watt: float = 8000, + heating_reference_temperature_in_celsius: float = -7.0, + ) -> "HeatPumpHplibConfig": """Gets a default HPLib Heat Pump. see default values for air/water hp on: https://github.com/FZJ-IEK3-VSA/hplib/blob/main/hplib/hplib.py l.135 "fit_p_th_ref. """ - set_thermal_output_power_in_watt: float = 8000 return HeatPumpHplibConfig( name="AdvancedHeatPumpHPLib", model="Generic", heat_source="air", group_id=4, - heating_reference_temperature_in_celsius=-7, + heating_reference_temperature_in_celsius=heating_reference_temperature_in_celsius, flow_temperature_in_celsius=52, set_thermal_output_power_in_watt=set_thermal_output_power_in_watt, cycling_mode=True, @@ -110,7 +112,9 @@ def get_default_generic_advanced_hp_lib(cls) -> "HeatPumpHplibConfig": @classmethod def get_scaled_advanced_hp_lib( - cls, heating_load_of_building_in_watt: float + cls, + heating_load_of_building_in_watt: float, + heating_reference_temperature_in_celsius: float = -7.0, ) -> "HeatPumpHplibConfig": """Gets a default heat pump with scaling according to heating load of the building.""" @@ -119,13 +123,15 @@ def get_scaled_advanced_hp_lib( return HeatPumpHplibConfig( name="AdvancedHeatPumpHPLib", model="Generic", + heat_source="air", group_id=4, - heating_reference_temperature_in_celsius=-7, + heating_reference_temperature_in_celsius=heating_reference_temperature_in_celsius, flow_temperature_in_celsius=52, set_thermal_output_power_in_watt=set_thermal_output_power_in_watt, cycling_mode=True, minimum_running_time_in_seconds=600, minimum_idle_time_in_seconds=600, + hx_building_temp_diff=2, co2_footprint=set_thermal_output_power_in_watt * 1e-3 * 165.84, # value from emission_factros_and_costs_devices.csv From f0d3e34beb969e7404ae62b24ce680d4a29d85cc Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Thu, 21 Dec 2023 11:03:41 +0100 Subject: [PATCH 18/27] set connections of components --- ...ousehold_1b_more_advanced_hp_diesel_car.py | 91 +++++++++++++++---- 1 file changed, 74 insertions(+), 17 deletions(-) diff --git a/system_setups/household_1b_more_advanced_hp_diesel_car.py b/system_setups/household_1b_more_advanced_hp_diesel_car.py index 56dbe9f6e..f27706d51 100644 --- a/system_setups/household_1b_more_advanced_hp_diesel_car.py +++ b/system_setups/household_1b_more_advanced_hp_diesel_car.py @@ -27,6 +27,7 @@ from hisim.components.configuration import HouseholdWarmWaterDemandConfig from hisim.system_setup_configuration import SystemSetupConfigBase from hisim import utils +from hisim import loadtypes as lt from system_setups.modular_example import cleanup_old_lpg_requests @@ -330,14 +331,32 @@ def setup_function( config=my_config.electricity_meter_config, ) + # ================================================================================================================================= # ================================================================================================================================= # Connect Components + my_building.connect_only_predefined_connections(my_weather) + my_building.connect_only_predefined_connections(my_occupancy) + + my_building.connect_input( + my_building.ThermalPowerDelivered, + my_heat_distribution.component_name, + my_heat_distribution.ThermalPowerDelivered, + ) + + ################################# + my_heat_distribution_controller.connect_only_predefined_connections( + my_weather, my_building, my_hot_water_storage + ) + my_heat_distribution.connect_only_predefined_connections( + my_building, my_heat_distribution_controller, my_hot_water_storage) + + ################################# my_heatpump.connect_only_predefined_connections( my_heatpump_controller_hotWater, my_heatpump_controller_dhw, my_weather, my_hot_water_storage, my_dhw_storage) - # Verknüpfung mit Luft als Umgebungswärmeqzuelle + # Verknüpfung mit Luft als Umgebungswärmequelle if my_heatpump.parameters['Group'].iloc[0] == 1.0 or my_heatpump.parameters['Group'].iloc[ 0] == 4.0: my_heatpump.connect_input( @@ -349,39 +368,77 @@ def setup_function( raise KeyError( "Wasser oder Sole als primäres Wärmeträgermedium muss über extra Wärmenetz-Modell noch bereitgestellt werden") - my_dhw_storage.connect_input( - my_dhw_storage.ThermalPowerDelivered, + # todo: Water and Brine Connection + + my_heatpump_controller_hotWater.connect_only_predefined_connections(my_heat_distribution_controller, + my_weather, + my_hot_water_storage) + + my_heatpump_controller_dhw.connect_only_predefined_connections(my_dhw_storage) + + ################################# + my_hot_water_storage.connect_input( + my_hot_water_storage.WaterTemperatureFromHeatDistribution, + my_heat_distribution.component_name, + my_heat_distribution.WaterTemperatureOutput, + ) + + my_hot_water_storage.connect_input( + my_hot_water_storage.WaterTemperatureFromHeatGenerator, my_heatpump.component_name, - my_heatpump.ThermalOutputPowerDHW, + my_heatpump.TemperatureOutputHotWater, ) + my_hot_water_storage.connect_input( my_hot_water_storage.WaterMassFlowRateFromHeatGenerator, my_heatpump.component_name, my_heatpump.MassFlowOutputHotWater, ) - my_hot_water_storage.connect_input( - my_hot_water_storage.WaterTemperatureFromHeatGenerator, + + ################################# + + my_dhw_storage.connect_only_predefined_connections(my_occupancy) + my_dhw_storage.connect_input( + my_dhw_storage.ThermalPowerDelivered, my_heatpump.component_name, - my_heatpump.TemperatureOutputHotWater, + my_heatpump.ThermalOutputPowerDHW, + ) + + ################################ + + my_electricity_meter.add_component_input_and_connect( + source_object_name=my_occupancy.component_name, + source_component_output=my_occupancy.ElectricityOutput, + source_load_type=lt.LoadTypes.ELECTRICITY, + source_unit=lt.Units.WATT, + source_tags=[lt.InandOutputType.ELECTRICITY_CONSUMPTION_UNCONTROLLED], + source_weight=999, + ) + + my_electricity_meter.add_component_input_and_connect( + source_object_name=my_heatpump.component_name, + source_component_output=my_heatpump.ElectricalInputPowerGesamt, + source_load_type=lt.LoadTypes.ELECTRICITY, + source_unit=lt.Units.WATT, + source_tags=[ + lt.InandOutputType.ELECTRICITY_CONSUMPTION_UNCONTROLLED, + ], + source_weight=999, ) - my_heatpump_controller_hotWater.connect_only_predefined_connections(my_heat_distribution_controller, - my_weather, - my_hot_water_storage) - my_heatpump_controller_dhw.connect_only_predefined_connections(my_dhw_storage) # ================================================================================================================================= # Add Components to Simulation Parameters my_sim.add_component(my_occupancy) my_sim.add_component(my_weather) - my_sim.add_component(my_building, connect_automatically=True) + my_sim.add_component(my_building) my_sim.add_component(my_heatpump) my_sim.add_component(my_heatpump_controller_hotWater) my_sim.add_component(my_heatpump_controller_dhw) - my_sim.add_component(my_heat_distribution, connect_automatically=True) - my_sim.add_component(my_heat_distribution_controller, connect_automatically=True) - my_sim.add_component(my_hot_water_storage, connect_automatically=True) - my_sim.add_component(my_dhw_storage, connect_automatically=True) - my_sim.add_component(my_electricity_meter, connect_automatically=True) + my_sim.add_component(my_heat_distribution) + my_sim.add_component(my_heat_distribution_controller) + my_sim.add_component(my_hot_water_storage) + my_sim.add_component(my_dhw_storage) + my_sim.add_component(my_electricity_meter) for my_car in my_cars: my_sim.add_component(my_car) From 26a06bced157a98cffa67e8e36aad7d7a7edcc6a Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Thu, 21 Dec 2023 11:05:10 +0100 Subject: [PATCH 19/27] calculate hp results in every timestep (like version before caching function) --> caching leads to convergence errors??? --- hisim/components/more_advanced_heat_pump_hplib.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hisim/components/more_advanced_heat_pump_hplib.py b/hisim/components/more_advanced_heat_pump_hplib.py index feb63abe8..12c91931c 100644 --- a/hisim/components/more_advanced_heat_pump_hplib.py +++ b/hisim/components/more_advanced_heat_pump_hplib.py @@ -636,7 +636,7 @@ def i_simulate( # OnOffSwitch if on_off == 1: # Calulate outputs for heating mode - results = self.get_cached_results_or_run_hplib_simulation( #hpl.simulate( + results = hpl.simulate( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_hot_water, parameters=self.parameters, @@ -659,7 +659,7 @@ def i_simulate( elif on_off == 2: # Calculate outputs for dhw mode if const_thermal_power_truefalse_DHW == False: # False=modulation - results = self.get_cached_results_or_run_hplib_simulation( #hpl.simulate( + results = hpl.simulate( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_dhw, parameters=self.parameters, @@ -682,7 +682,7 @@ def i_simulate( # print("t_out_WP_dhw " + str(t_out_dhw)) elif const_thermal_power_truefalse_DHW == True: # True = constante thermische Leistung - results = self.get_cached_results_or_run_hplib_simulation( #hpl.simulate( + results = hpl.simulate( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_dhw, parameters=self.parameters, @@ -706,7 +706,7 @@ def i_simulate( elif on_off == -1: # Calulate outputs for cooling mode - results = self.get_cached_results_or_run_hplib_simulation( #hpl.simulate( + results = hpl.simulate( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_hot_water, parameters=self.parameters, From 5545e997b04ffb7260684115b58817b2ea173953 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Thu, 21 Dec 2023 21:30:18 +0100 Subject: [PATCH 20/27] -new example household (household_1b) for new heatpump -set hp parameters (model/manufacture) in both example to stiebel wpl25 for comparison - tester for new hp - but doesn't work?? --- .../household_1_advanced_hp_diesel_car.py | 17 +++++-- ...ousehold_1b_more_advanced_hp_diesel_car.py | 48 ++++++++----------- ...ousehold_1b_more_advanced_hp_diesel_car.py | 28 +++++++++++ 3 files changed, 61 insertions(+), 32 deletions(-) create mode 100644 tests/test_system_setups_household_1b_more_advanced_hp_diesel_car.py diff --git a/system_setups/household_1_advanced_hp_diesel_car.py b/system_setups/household_1_advanced_hp_diesel_car.py index 4a60e9b4f..264169485 100644 --- a/system_setups/household_1_advanced_hp_diesel_car.py +++ b/system_setups/household_1_advanced_hp_diesel_car.py @@ -31,6 +31,7 @@ from hisim import utils from system_setups.modular_example import cleanup_old_lpg_requests +import datetime __authors__ = ["Markus Blasberg", "Kevin Knosala"] __copyright__ = "Copyright 2023, FZJ-IEK-3" @@ -108,8 +109,8 @@ def get_scaled_default( building_type="blub", number_of_apartments=int(my_building_information.number_of_apartments), occupancy_config=loadprofilegenerator_utsp_connector.UtspLpgConnectorConfig( - url=getenv("UTSP_URL", ""), - api_key=getenv("UTSP_API_KEY", ""), + url="http://134.94.131.167:443/api/v1/profilerequest", + api_key="OrjpZY93BcNWw8lKaMp0BEchbCc", household=Households.CHR01_Couple_both_at_Work, energy_intensity=EnergyIntensityType.EnergySaving, result_dir_path=utils.HISIMPATH["results"], @@ -156,7 +157,12 @@ def get_scaled_default( ) # adjust HeatPump - household_config.hp_config.group_id = 1 # use modulating heatpump as default + # household_config.hp_config.group_id = 1 # use modulating heatpump as default + household_config.hp_config.model = "WPL 25 A" #Stiebel WP --> hplib_database_ALL + + household_config.dhw_heatpump_config.manufacturer = "Stiebel Eltron" + household_config.dhw_heatpump_config.device_name = "WPL 25" + household_config.hp_controller_config.mode = ( 2 # use heating and cooling as default ) @@ -235,8 +241,8 @@ def setup_function( # Build Simulation Parameters if my_simulation_parameters is None: my_simulation_parameters = SimulationParameters.full_year_all_options( - year=year, seconds_per_timestep=seconds_per_timestep - ) + year=year, seconds_per_timestep=seconds_per_timestep) + my_sim.set_simulation_parameters(my_simulation_parameters) # Build heat Distribution System Controller @@ -376,3 +382,4 @@ def setup_function( my_sim.add_component(my_electricity_meter, connect_automatically=True) for my_car in my_cars: my_sim.add_component(my_car) + diff --git a/system_setups/household_1b_more_advanced_hp_diesel_car.py b/system_setups/household_1b_more_advanced_hp_diesel_car.py index f27706d51..8070db0dc 100644 --- a/system_setups/household_1b_more_advanced_hp_diesel_car.py +++ b/system_setups/household_1b_more_advanced_hp_diesel_car.py @@ -31,19 +31,19 @@ from system_setups.modular_example import cleanup_old_lpg_requests -__authors__ = ["Markus Blasberg", "Kevin Knosala"] -__copyright__ = "Copyright 2023, FZJ-IEK-3" -__credits__ = ["Noah Pflugradt"] -__license__ = "MIT" -__version__ = "1.0" -__maintainer__ = "Markus Blasberg" -__status__ = "development" +__authors__ = ["Jonas Hoppe"] +__copyright__ = "" +__credits__ = [""] +__license__ = "" +__version__ = "" +__maintainer__ = "" +__status__ = "" @dataclass -class HouseholdAdvancedHPDieselCarConfig(SystemSetupConfigBase): +class HouseholdMoreAdvancedHPDieselCarConfig(SystemSetupConfigBase): - """Configuration for with advanced heat pump and diesel car.""" + """Configuration for with more advanced heat pump and diesel car.""" building_type: str number_of_apartments: int @@ -60,8 +60,8 @@ class HouseholdAdvancedHPDieselCarConfig(SystemSetupConfigBase): electricity_meter_config: electricity_meter.ElectricityMeterConfig @classmethod - def get_default(cls) -> "HouseholdAdvancedHPDieselCarConfig": - """Get default HouseholdAdvancedHPDieselCarConfig.""" + def get_default(cls) -> "HouseholdMoreAdvancedHPDieselCarConfig": + """Get default HouseholdMoreAdvancedHPDieselCarConfig.""" heating_reference_temperature_in_celsius: float = -7 @@ -84,8 +84,8 @@ def get_default(cls) -> "HouseholdAdvancedHPDieselCarConfig": def get_scaled_default( cls, building_config: building.BuildingConfig, - ) -> "HouseholdAdvancedHPDieselCarConfig": - """Get scaled default HouseholdAdvancedHPDieselCarConfig.""" + ) -> "HouseholdMoreAdvancedHPDieselCarConfig": + """Get scaled default HouseholdMoreAdvancedHPDieselCarConfig.""" set_heating_threshold_outside_temperature_in_celsius: float = 16.0 @@ -102,7 +102,7 @@ def get_scaled_default( config=hds_controller_config ) ) - household_config = HouseholdAdvancedHPDieselCarConfig( + household_config = HouseholdMoreAdvancedHPDieselCarConfig( building_type="blub", number_of_apartments=int(my_building_information.number_of_apartments), occupancy_config=loadprofilegenerator_utsp_connector.UtspLpgConnectorConfig( @@ -149,7 +149,8 @@ def get_scaled_default( ) # adjust HeatPump - household_config.hp_config.group_id = 1 # use modulating heatpump as default + # household_config.hp_config.group_id = 1 # use modulating heatpump as default + household_config.hp_config.model = "WPL 25 A" # Stiebel WP --> hplib_database_ALL household_config.hp_controller_config.mode = ( 2 # use heating and cooling as default ) @@ -177,7 +178,7 @@ def setup_function( my_sim: Any, my_simulation_parameters: Optional[SimulationParameters] = None, ) -> None: # noqa: too-many-statements - """System setup with advanced hp and diesel car. + """System setup with more advanced hp and diesel car. This setup function emulates a household with some basic components. Here the residents have their electricity and heating needs covered by a the advanced heat pump. @@ -204,11 +205,11 @@ def setup_function( cleanup_old_lpg_requests() if my_sim.my_module_config_path: - my_config = HouseholdAdvancedHPDieselCarConfig.load_from_json( + my_config = HouseholdMoreAdvancedHPDieselCarConfig.load_from_json( my_sim.my_module_config_path ) else: - my_config = HouseholdAdvancedHPDieselCarConfig.get_default() + my_config = HouseholdMoreAdvancedHPDieselCarConfig.get_default() # Todo: save file leads to use of file in next run. File was just produced to check how it looks like # my_config_json = my_config.to_json() @@ -228,8 +229,8 @@ def setup_function( # Build Simulation Parameters if my_simulation_parameters is None: my_simulation_parameters = SimulationParameters.full_year_all_options( - year=year, seconds_per_timestep=seconds_per_timestep - ) + year=year, seconds_per_timestep=seconds_per_timestep) + my_sim.set_simulation_parameters(my_simulation_parameters) # Build heat Distribution System Controller @@ -443,10 +444,3 @@ def setup_function( my_sim.add_component(my_car) -import hisim.hisim_main - -def sim(): - hisim.hisim_main.main("household_1b_more_advanced_hp_diesel_car.py") - - -sim() \ No newline at end of file diff --git a/tests/test_system_setups_household_1b_more_advanced_hp_diesel_car.py b/tests/test_system_setups_household_1b_more_advanced_hp_diesel_car.py new file mode 100644 index 000000000..85cd3de83 --- /dev/null +++ b/tests/test_system_setups_household_1b_more_advanced_hp_diesel_car.py @@ -0,0 +1,28 @@ +""" Tests for the basic household system setup. """ +# clean +import os +from pathlib import Path +import pytest + +from hisim import hisim_main +from hisim.simulationparameters import SimulationParameters +from hisim import log +from hisim import utils +from hisim.postprocessingoptions import PostProcessingOptions + + +# @pytest.mark.system_setups +@pytest.mark.utsp +@utils.measure_execution_time +def test_basic_household(): + """Single day.""" + + config_filename = "household_1b_more_advanced_hp_diesel_car_config.json" + if Path(config_filename).is_file(): + os.remove(config_filename) + + path = "../system_setups/household_1b_more_advanced_hp_diesel_car.py" + mysimpar = SimulationParameters.one_day_only(year=2019, seconds_per_timestep=60) + mysimpar.post_processing_options.append(PostProcessingOptions.MAKE_NETWORK_CHARTS) + hisim_main.main(path, mysimpar) + log.information(os.getcwd()) From 6ba9a432dac53adc4f45ca0ec59cef709a4da214 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Thu, 21 Dec 2023 21:31:22 +0100 Subject: [PATCH 21/27] prepared for new cache function now cache function leads to convergence errors --- .../more_advanced_heat_pump_hplib.py | 70 +++++++++---------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/hisim/components/more_advanced_heat_pump_hplib.py b/hisim/components/more_advanced_heat_pump_hplib.py index 12c91931c..4a80f5bd6 100644 --- a/hisim/components/more_advanced_heat_pump_hplib.py +++ b/hisim/components/more_advanced_heat_pump_hplib.py @@ -478,7 +478,6 @@ def __init__( def get_default_connections_from_heat_pump_controller_hot_water(self,): """Get default connections.""" - log.information("setting heat pump controller default connections") connections = [] hpc_classname = HeatPumpHplibControllerHotWaterStorage.get_classname() connections.append( @@ -490,7 +489,6 @@ def get_default_connections_from_heat_pump_controller_hot_water(self,): def get_default_connections_from_heat_pump_controller_dhw(self,): """Get default connections.""" - connections = [] hpc_dhw_classname = HeatPumpHplibControllerDHW.get_classname() connections.append( @@ -512,7 +510,6 @@ def get_default_connections_from_heat_pump_controller_dhw(self,): def get_default_connections_from_weather(self,): """Get default connections.""" - connections = [] weather_classname = weather.Weather.get_classname() connections.append( @@ -526,7 +523,6 @@ def get_default_connections_from_weather(self,): def get_default_connections_from_simple_hot_water_storage(self,): """Get simple hot water storage default connections.""" - log.information("setting simple hot water storage default connections") connections = [] hws_classname = simple_hot_water_storage.SimpleHotWaterStorage.get_classname() connections.append( @@ -540,7 +536,6 @@ def get_default_connections_from_simple_hot_water_storage(self,): def get_default_connections_from_dhw_storage(self,): """Get simple hot water storage default connections.""" - log.information("setting simple hot water storage default connections") connections = [] dhw_classname = generic_hot_water_storage_modular.HotWaterStorage.get_classname() connections.append( @@ -636,7 +631,7 @@ def i_simulate( # OnOffSwitch if on_off == 1: # Calulate outputs for heating mode - results = hpl.simulate( + results = hpl.simulate( #self.get_cached_results_or_run_hplib_simulation( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_hot_water, parameters=self.parameters, @@ -659,7 +654,7 @@ def i_simulate( elif on_off == 2: # Calculate outputs for dhw mode if const_thermal_power_truefalse_DHW == False: # False=modulation - results = hpl.simulate( + results = hpl.simulate( #self.get_cached_results_or_run_hplib_simulation( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_dhw, parameters=self.parameters, @@ -682,7 +677,7 @@ def i_simulate( # print("t_out_WP_dhw " + str(t_out_dhw)) elif const_thermal_power_truefalse_DHW == True: # True = constante thermische Leistung - results = hpl.simulate( + results = hpl.simulate( #self.get_cached_results_or_run_hplib_simulation( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_dhw, parameters=self.parameters, @@ -706,7 +701,7 @@ def i_simulate( elif on_off == -1: # Calulate outputs for cooling mode - results = hpl.simulate( + results = hpl.simulate( #self.get_cached_results_or_run_hplib_simulation( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_hot_water, parameters=self.parameters, @@ -752,7 +747,6 @@ def i_simulate( raise ValueError("Unknown mode for Advanced HPLib On_Off.") - if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: #todo: variability of massflow. now there is a fix temperaturdiffernz between inlet and outlet which calculate the massflow @@ -764,7 +758,6 @@ def i_simulate( stsv.set_output_value(self.temp_water_primary_hx_out, t_out_primary) - # write values for output time series stsv.set_output_value(self.p_th_hot_water, p_th_hot_water) stsv.set_output_value(self.p_th_dhw, p_th_dhw) @@ -784,7 +777,6 @@ def i_simulate( stsv.set_output_value(self.thermal_power_from_environment, (p_th_dhw+p_th_hot_water)-(p_el_dhw+p_el_hot_water)) - # write values to state self.state.time_on = time_on_heating self.state.time_on_cooling = time_on_cooling @@ -880,6 +872,31 @@ def self_copy( ) + +@dataclass +class CalculationRequest(JSONWizard): + + """Class for caching hplib parameters so that hplib.simulate does not need to run so often.""" + + t_in_primary: float + t_in_secondary: float + t_amb: float + mode: int + + def get_key(self): + """Get key of class with important parameters.""" + + return ( + str(self.t_in_primary) + + " " + + str(self.t_in_secondary) + + " " + + str(self.t_amb) + + " " + + str(self.mode) + ) + + # =========================================================================== # try to implement a hplib controller l1 @dataclass_json @@ -1364,29 +1381,6 @@ def summer_cooling_condition( return cooling_mode -@dataclass -class CalculationRequest(JSONWizard): - - """Class for caching hplib parameters so that hplib.simulate does not need to run so often.""" - - t_in_primary: float - t_in_secondary: float - t_amb: float - mode: int - - def get_key(self): - """Get key of class with important parameters.""" - - return ( - str(self.t_in_primary) - + " " - + str(self.t_in_secondary) - + " " - + str(self.t_amb) - + " " - + str(self.mode) - ) - # =========================================================================== # implement a hplib controller l1 for dhw storage (tww) @dataclass_json @@ -1506,6 +1500,7 @@ def __init__( self.controller_heatpumpmode_dhw: Any self.previous_heatpump_mode_dhw: Any self.controller_signal: int + self.previous_controller_signal: int self.thermalPower_constant_for_dhw: bool self.p_th_max_dhw: float @@ -1534,7 +1529,8 @@ def build(self, ) -> None: # Sth self.controller_heatpumpmode_dhw = "off_dhw_heating" self.previous_heatpump_mode_dhw = self.controller_heatpumpmode_dhw - self.controller_signal = 1 + self.controller_signal = 0 + self.previous_controller_signal = self.controller_signal self.thermalPower_constant_for_dhw = self.config.thermalPower_is_constant_for_dhw self.p_th_max_dhw = self.config.p_th_max_dhw_in_W @@ -1552,10 +1548,12 @@ def i_prepare_simulation(self) -> None: def i_save_state(self) -> None: """Save the current state.""" self.previous_heatpump_mode_dhw = self.controller_heatpumpmode_dhw + self.previous_controller_signal = self.controller_signal def i_restore_state(self) -> None: """Restore the previous state.""" self.controller_heatpumpmode_dhw = self.previous_heatpump_mode_dhw + self.controller_signal = self.previous_controller_signal def i_doublecheck(self, timestep: int, stsv: SingleTimeStepValues) -> None: """Doublecheck.""" From 02435659ea5c280aa62c39da9dc1f43bd1b7110a Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Fri, 22 Dec 2023 11:21:09 +0100 Subject: [PATCH 22/27] delete "old" system setup tester, add new tester on basis "test_system_setup_household_1" --> now it works --- ...ousehold_1b_more_advanced_hp_diesel_car.py | 1 + ...ehold_with_more_advanced_hp_hws_dhw_hds.py | 23 ------------------- 2 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py diff --git a/tests/test_system_setups_household_1b_more_advanced_hp_diesel_car.py b/tests/test_system_setups_household_1b_more_advanced_hp_diesel_car.py index 85cd3de83..f9643a456 100644 --- a/tests/test_system_setups_household_1b_more_advanced_hp_diesel_car.py +++ b/tests/test_system_setups_household_1b_more_advanced_hp_diesel_car.py @@ -26,3 +26,4 @@ def test_basic_household(): mysimpar.post_processing_options.append(PostProcessingOptions.MAKE_NETWORK_CHARTS) hisim_main.main(path, mysimpar) log.information(os.getcwd()) + diff --git a/tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py b/tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py deleted file mode 100644 index 07ae74215..000000000 --- a/tests/test_system_setups_household_with_more_advanced_hp_hws_dhw_hds.py +++ /dev/null @@ -1,23 +0,0 @@ -""" Tests for the basic household system setup. """ - -import os -import pytest - -from hisim import hisim_main -from hisim.simulationparameters import SimulationParameters -from hisim import log -from hisim import utils - - - -@pytest.mark.system_setups -@utils.measure_execution_time -def test_household_with_advanced_hp_hws_hds_pv(): - """Single day.""" - path = "../system_setups/household_with_more_advanced_hp_hws_dhw_hds.py" - - mysimpar = SimulationParameters.one_day_only( - year=2021, seconds_per_timestep=60 - ) - hisim_main.main(path, mysimpar) - log.information(os.getcwd()) From 8da54fd5a079ea3ce249d06848b0d30742f2aa54 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Fri, 22 Dec 2023 14:10:11 +0100 Subject: [PATCH 23/27] postprocessing_flag only for "p_el_ges", so kpi calculation should be right (before electrical power of hp was too high) --- hisim/components/more_advanced_heat_pump_hplib.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/hisim/components/more_advanced_heat_pump_hplib.py b/hisim/components/more_advanced_heat_pump_hplib.py index 4a80f5bd6..862cd7ce1 100644 --- a/hisim/components/more_advanced_heat_pump_hplib.py +++ b/hisim/components/more_advanced_heat_pump_hplib.py @@ -334,7 +334,6 @@ def __init__( field_name=self.ThermalOutputPowerGesamt, load_type=LoadTypes.HEATING, unit=Units.WATT, - postprocessing_flag=postprocessing_flag, output_description="Thermal output power for whole HP in Watt", ) @@ -343,7 +342,6 @@ def __init__( field_name=self.ElectricalInputPowerHotWater, load_type=LoadTypes.ELECTRICITY, unit=Units.WATT, - postprocessing_flag=postprocessing_flag, output_description="Electricity input power for Hot Water in Watt", ) @@ -352,7 +350,6 @@ def __init__( field_name=self.ElectricalInputPowerDHW, load_type=LoadTypes.ELECTRICITY, unit=Units.WATT, - postprocessing_flag=postprocessing_flag, output_description="Electricity input power for DHW in Watt", ) From faae2715bd2c6118162d9fb048f8ae5546a010b2 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Fri, 22 Dec 2023 14:10:46 +0100 Subject: [PATCH 24/27] tester for only new hp model --- tests/test_more_advanced_heat_pump_hplib.py | 121 ++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 tests/test_more_advanced_heat_pump_hplib.py diff --git a/tests/test_more_advanced_heat_pump_hplib.py b/tests/test_more_advanced_heat_pump_hplib.py new file mode 100644 index 000000000..7425cc456 --- /dev/null +++ b/tests/test_more_advanced_heat_pump_hplib.py @@ -0,0 +1,121 @@ +"""Test for advanced heat pump hplib.""" + +import pytest +from tests import functions_for_testing as fft +from hisim import component as cp +from hisim.components.more_advanced_heat_pump_hplib import ( + HeatPumpHplib, + HeatPumpHplibConfig, + HeatPumpState, +) +from hisim import loadtypes as lt +from hisim.simulationparameters import SimulationParameters +from hisim import log + +@pytest.mark.base +def test_heat_pump_hplib_new(): + """Test heat pump hplib.""" + + # Definitions for HeatPump init + model: str = "Generic" + group_id: int = 1 + t_in: float = -7 + t_out: float = 52 + p_th_set: float = 10000 + simpars = SimulationParameters.one_day_only(2017, 60) + # Definitions for i_simulate + timestep = 1 + force_convergence = False + + # Create fake component outputs as inputs for simulation + on_off_switch_hotWater = cp.ComponentOutput( + "Fake_on_off_switch", "Fake_on_off_switch", lt.LoadTypes.ANY, lt.Units.ANY + ) + on_off_switch_DHW = cp.ComponentOutput( + "Fake_on_off_switch", "Fake_on_off_switch", lt.LoadTypes.ANY, lt.Units.ANY + ) + const_thermal_power_truefalse_DHW = cp.ComponentOutput( + "Fake_const_thermal_power_truefalse_DHW", "Fake_const_thermal_power_truefalse_DHW", lt.LoadTypes.ANY, lt.Units.ANY + ) + const_thermal_power_value_DHW = cp.ComponentOutput( + "Fake_const_thermal_power_value_DHW", "Fake_const_thermal_power_value_DHW", lt.LoadTypes.ANY, lt.Units.ANY + ) + t_in_primary = cp.ComponentOutput( + "Fake_t_in_primary", "Fake_t_in_primary", lt.LoadTypes.ANY, lt.Units.ANY + ) + t_in_secondary_hot_water = cp.ComponentOutput( + "Fake_t_in_secondary_hot_water", "Fake_t_in_secondary_hot_water", lt.LoadTypes.ANY, lt.Units.ANY + ) + t_in_secondary_dhw = cp.ComponentOutput( + "Fake_t_in_secondary_dhw", "Fake_t_in_secondary_dhw", lt.LoadTypes.ANY, lt.Units.ANY + ) + t_amb = cp.ComponentOutput( + "Fake_t_amb", "Fake_t_amb", lt.LoadTypes.ANY, lt.Units.ANY + ) + + const_thermal_power_truefalse_DHW=False + + # Initialize component + heatpump_config = HeatPumpHplibConfig( + name="Heat Pump", + model=model, + heat_source="air", + group_id=group_id, + heating_reference_temperature_in_celsius=t_in, + flow_temperature_in_celsius=t_out, + set_thermal_output_power_in_watt=p_th_set, + cycling_mode=True, + hx_building_temp_diff=2, + minimum_idle_time_in_seconds=600, + minimum_running_time_in_seconds=600, + co2_footprint=p_th_set * 1e-3 * 165.84, + cost=p_th_set * 1e-3 * 1513.74, + lifetime=10, + maintenance_cost_as_percentage_of_investment=0.025, + consumption=0, + ) + heatpump = HeatPumpHplib(config=heatpump_config, my_simulation_parameters=simpars) + heatpump.state = HeatPumpState( + time_on=0, time_off=0, time_on_cooling=0, on_off_previous=1 + ) + + number_of_outputs = fft.get_number_of_outputs( + [on_off_switch_hotWater,on_off_switch_DHW, const_thermal_power_value_DHW,t_in_primary, t_in_secondary_hot_water,t_in_secondary_dhw, t_amb, heatpump] + ) + stsv: cp.SingleTimeStepValues = cp.SingleTimeStepValues(number_of_outputs) + + heatpump.on_off_switch_hotWater.source_output = on_off_switch_hotWater + heatpump.on_off_switch_DHW.source_output=on_off_switch_DHW + heatpump.const_thermal_power_value_DHW.source_output=const_thermal_power_value_DHW + heatpump.t_in_primary.source_output = t_in_primary + heatpump.t_in_secondary_hot_water.source_output = t_in_secondary_hot_water + heatpump.t_in_secondary_dhw.source_output = t_in_secondary_dhw + heatpump.t_amb.source_output = t_amb + + # Add Global Index and set values for fake Inputs + fft.add_global_index_of_components( + [on_off_switch_hotWater, on_off_switch_DHW, const_thermal_power_value_DHW, + t_in_primary, t_in_secondary_hot_water, t_in_secondary_dhw, t_amb, heatpump] + ) + stsv.values[on_off_switch_hotWater.global_index] = 1 + stsv.values[on_off_switch_DHW.global_index] = 0 + stsv.values[const_thermal_power_value_DHW.global_index] = 0 + stsv.values[const_thermal_power_truefalse_DHW] = False + stsv.values[t_in_primary.global_index] = -7 + stsv.values[t_in_secondary_hot_water.global_index] = 47.0 + stsv.values[t_in_secondary_dhw.global_index] = 55.0 + stsv.values[t_amb.global_index] = -7 + + # Simulation + heatpump.i_simulate( + timestep=timestep, stsv=stsv, force_convergence=force_convergence + ) + log.information(str(stsv.values)) + # Check + assert p_th_set == stsv.values[heatpump.p_th_hot_water.global_index] + assert 7074.033573088874 == stsv.values[heatpump.p_el_hot_water.global_index] + assert 1.4136206588052005 == stsv.values[heatpump.cop.global_index] + assert t_out == stsv.values[heatpump.t_out_hot_water.global_index] + assert 0.47619047619047616 == stsv.values[heatpump.m_dot_hot_water.global_index] + assert 60 == stsv.values[heatpump.time_on.global_index] + assert 0 == stsv.values[heatpump.time_off.global_index] From 2eff9b0bcb216af71fa39919fda86f7431128095 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Wed, 10 Jan 2024 12:44:42 +0100 Subject: [PATCH 25/27] update to new HiSim utsp_connector --> url and api_key --- system_setups/household_1b_more_advanced_hp_diesel_car.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system_setups/household_1b_more_advanced_hp_diesel_car.py b/system_setups/household_1b_more_advanced_hp_diesel_car.py index 8070db0dc..1519870d2 100644 --- a/system_setups/household_1b_more_advanced_hp_diesel_car.py +++ b/system_setups/household_1b_more_advanced_hp_diesel_car.py @@ -106,8 +106,8 @@ def get_scaled_default( building_type="blub", number_of_apartments=int(my_building_information.number_of_apartments), occupancy_config=loadprofilegenerator_utsp_connector.UtspLpgConnectorConfig( - url="http://134.94.131.167:443/api/v1/profilerequest", - api_key="OrjpZY93BcNWw8lKaMp0BEchbCc", + url=utils.get_environment_variable("UTSP_URL"), + api_key=utils.get_environment_variable("UTSP_API_KEY"), household=Households.CHR01_Couple_both_at_Work, energy_intensity=EnergyIntensityType.EnergySaving, result_dir_path=utils.HISIMPATH["results"], From 1551cdc23377a73766aab7440f328e2dee187122 Mon Sep 17 00:00:00 2001 From: Jonas Hoppe Date: Sat, 13 Jan 2024 23:31:34 +0100 Subject: [PATCH 26/27] system setup with "generic" hp modell --> easier to compare with "household_1" --- system_setups/household_1b_more_advanced_hp_diesel_car.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/system_setups/household_1b_more_advanced_hp_diesel_car.py b/system_setups/household_1b_more_advanced_hp_diesel_car.py index 1519870d2..c712eca43 100644 --- a/system_setups/household_1b_more_advanced_hp_diesel_car.py +++ b/system_setups/household_1b_more_advanced_hp_diesel_car.py @@ -149,8 +149,7 @@ def get_scaled_default( ) # adjust HeatPump - # household_config.hp_config.group_id = 1 # use modulating heatpump as default - household_config.hp_config.model = "WPL 25 A" # Stiebel WP --> hplib_database_ALL + household_config.hp_config.group_id = 1 # use modulating heatpump as default household_config.hp_controller_config.mode = ( 2 # use heating and cooling as default ) From 16fcf220b44df96f866e4ca69a1eb505b27fe664 Mon Sep 17 00:00:00 2001 From: Hoppe-J Date: Fri, 19 Jan 2024 10:03:48 +0100 Subject: [PATCH 27/27] =?UTF-8?q?implementing=20caching=20f=C3=BCr=20dhw,?= =?UTF-8?q?=20code=20style=20and=20test=20issues=20will=20follow=20in=20ne?= =?UTF-8?q?xt=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../more_advanced_heat_pump_hplib.py | 406 +++++++++++------- 1 file changed, 241 insertions(+), 165 deletions(-) diff --git a/hisim/components/more_advanced_heat_pump_hplib.py b/hisim/components/more_advanced_heat_pump_hplib.py index 862cd7ce1..1975b4e28 100644 --- a/hisim/components/more_advanced_heat_pump_hplib.py +++ b/hisim/components/more_advanced_heat_pump_hplib.py @@ -27,7 +27,12 @@ ComponentConnection, OpexCostDataClass, ) -from hisim.components import weather, simple_hot_water_storage,generic_hot_water_storage_modular, heat_distribution_system +from hisim.components import ( + weather, + simple_hot_water_storage, + generic_hot_water_storage_modular, + heat_distribution_system, +) from hisim.loadtypes import LoadTypes, Units, InandOutputType from hisim.simulationparameters import SimulationParameters from hisim.components.heat_distribution_system import HeatDistributionSystemType @@ -64,7 +69,9 @@ def get_main_classname(cls): cycling_mode: bool minimum_running_time_in_seconds: Optional[int] minimum_idle_time_in_seconds: Optional[int] - hx_building_temp_diff: Optional[float] #to be used, if water/water or brine/water heatpump + hx_building_temp_diff: Optional[ + float + ] # to be used, if water/water or brine/water heatpump #: CO2 footprint of investment in kg co2_footprint: float #: cost for investment in Euro @@ -145,10 +152,9 @@ def get_scaled_advanced_hp_lib( class HeatPumpHplib(Component): - # Inputs OnOffSwitchHotWater = "OnOffSwitchHotWater" # 1 = on hot Water, 0 = 0ff - OnOffSwitchDHW = "OnOffSwitchDHW" #2 = on DHW , 0 = 0ff + OnOffSwitchDHW = "OnOffSwitchDHW" # 2 = on DHW , 0 = 0ff ThermalPowerIsConstantforDHW = "ThermalPowerisConstantforDHW" # true/false MaxThermalPowerforDHW = "MaxThermalPowerforDHW" # max. Leistungswert TemperatureInputPrimary = "TemperatureInputPrimary" # °C @@ -156,11 +162,10 @@ class HeatPumpHplib(Component): TemperatureInputSecondary_DHW = "TemperatureInputSecondaryDWH" # °C TemperatureAmbient = "TemperatureAmbient" # °C - # Outputs ThermalOutputPowerHotWater = "ThermalOutputPowerHotWater" # W ThermalOutputPowerDHW = "ThermalOutputPowerDHW" # W - ThermalOutputPowerGesamt = "ThermalOutputPowerWholeHeatpump" #W + ThermalOutputPowerGesamt = "ThermalOutputPowerWholeHeatpump" # W ElectricalInputPowerHotWater = "ElectricalInputPowerHotWater" # W ElectricalInputPowerDHW = "ElectricalInputPowerDHW" # W ElectricalInputPowerGesamt = "ElectricalInputPowerWholeHeatpump" @@ -173,17 +178,16 @@ class HeatPumpHplib(Component): MassFlowOutputDHW = "MassFlowOutputDHW" # kg/s TimeOn = "TimeOn" # s TimeOff = "TimeOff" # s - ThermalPowerFromEnvironment = "ThermalPowerInputFromEnvironment" #W - mdotWaterPrimary = "MassflowPrimary" # kg/s - WaterTemperaturePrimaryIn = "TemperaturePrimaryIn" # °C - WaterTemperaturePrimaryOut = "TemperaturePrimaryOut" # °C + ThermalPowerFromEnvironment = "ThermalPowerInputFromEnvironment" # W + mdotWaterPrimary = "MassflowPrimary" # kg/s + WaterTemperaturePrimaryIn = "TemperaturePrimaryIn" # °C + WaterTemperaturePrimaryOut = "TemperaturePrimaryOut" # °C def __init__( self, my_simulation_parameters: SimulationParameters, config: HeatPumpHplibConfig, ): - super().__init__( name=config.name, my_simulation_parameters=my_simulation_parameters, @@ -212,7 +216,7 @@ def __init__( self.heat_source = config.heat_source - #self.on_off: int = 0 + # self.on_off: int = 0 postprocessing_flag = [InandOutputType.ELECTRICITY_CONSUMPTION_UNCONTROLLED] @@ -231,19 +235,31 @@ def __init__( PhysicsConfig.water_specific_heat_capacity_in_joule_per_kilogram_per_kelvin ) - #protect erros for Water/Water Heatpumps - if self.parameters['Group'].iloc[0] == 1.0 or self.parameters['Group'].iloc[0] == 4.0: + # protect erros for Water/Water Heatpumps + if ( + self.parameters["Group"].iloc[0] == 1.0 + or self.parameters["Group"].iloc[0] == 4.0 + ): if self.heat_source != "air": - raise KeyError("WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!") - if self.parameters['Group'].iloc[0] == 2.0 or self.parameters['Group'].iloc[0] == 5.0: + raise KeyError( + "WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!" + ) + if ( + self.parameters["Group"].iloc[0] == 2.0 + or self.parameters["Group"].iloc[0] == 5.0 + ): if self.heat_source != "brine": - raise KeyError("WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!") - if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: + raise KeyError( + "WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!" + ) + if ( + self.parameters["Group"].iloc[0] == 3.0 + or self.parameters["Group"].iloc[0] == 6.0 + ): if self.heat_source != "water": - raise KeyError("WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!") - - - + raise KeyError( + "WP Modell passt nicht zu in Eingangsparameter angegebenen HeatSource!" + ) # Define component inputs self.on_off_switch_hotWater: ComponentInput = self.add_input( @@ -279,7 +295,6 @@ def __init__( mandatory=True, ) - self.t_in_primary: ComponentInput = self.add_input( object_name=self.component_name, field_name=self.TemperatureInputPrimary, @@ -439,7 +454,10 @@ def __init__( output_description="Thermal Input Power from Environment", ) - if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: + if ( + self.parameters["Group"].iloc[0] == 3.0 + or self.parameters["Group"].iloc[0] == 6.0 + ): self.m_dot_water_primary_dhnet: ComponentOutput = self.add_output( object_name=self.component_name, field_name=self.mdotWaterPrimary, @@ -462,7 +480,6 @@ def __init__( output_description="Temperature of Water to District Heating Net Out HX", ) - self.add_default_connections( self.get_default_connections_from_heat_pump_controller_hot_water() ) @@ -470,42 +487,58 @@ def __init__( self.get_default_connections_from_heat_pump_controller_dhw() ) self.add_default_connections(self.get_default_connections_from_weather()) - self.add_default_connections(self.get_default_connections_from_simple_hot_water_storage()) + self.add_default_connections( + self.get_default_connections_from_simple_hot_water_storage() + ) self.add_default_connections(self.get_default_connections_from_dhw_storage()) - def get_default_connections_from_heat_pump_controller_hot_water(self,): + def get_default_connections_from_heat_pump_controller_hot_water( + self, + ): """Get default connections.""" connections = [] hpc_classname = HeatPumpHplibControllerHotWaterStorage.get_classname() connections.append( ComponentConnection( - HeatPumpHplib.OnOffSwitchHotWater, hpc_classname, HeatPumpHplibControllerHotWaterStorage.State_HotWater, + HeatPumpHplib.OnOffSwitchHotWater, + hpc_classname, + HeatPumpHplibControllerHotWaterStorage.State_HotWater, ) ) return connections - def get_default_connections_from_heat_pump_controller_dhw(self,): + def get_default_connections_from_heat_pump_controller_dhw( + self, + ): """Get default connections.""" connections = [] hpc_dhw_classname = HeatPumpHplibControllerDHW.get_classname() connections.append( ComponentConnection( - HeatPumpHplib.OnOffSwitchDHW, hpc_dhw_classname, HeatPumpHplibControllerDHW.State_dhw, + HeatPumpHplib.OnOffSwitchDHW, + hpc_dhw_classname, + HeatPumpHplibControllerDHW.State_dhw, ) ) connections.append( ComponentConnection( - HeatPumpHplib.ThermalPowerIsConstantforDHW, hpc_dhw_classname, HeatPumpHplibControllerDHW.ThermalPower_Bedingung_for_konst_dhw, + HeatPumpHplib.ThermalPowerIsConstantforDHW, + hpc_dhw_classname, + HeatPumpHplibControllerDHW.ThermalPower_Bedingung_for_konst_dhw, ) ) connections.append( ComponentConnection( - HeatPumpHplib.MaxThermalPowerforDHW, hpc_dhw_classname, HeatPumpHplibControllerDHW.Value_Max_Thermal_Power_for_dhw, + HeatPumpHplib.MaxThermalPowerforDHW, + hpc_dhw_classname, + HeatPumpHplibControllerDHW.Value_Max_Thermal_Power_for_dhw, ) ) return connections - def get_default_connections_from_weather(self,): + def get_default_connections_from_weather( + self, + ): """Get default connections.""" connections = [] weather_classname = weather.Weather.get_classname() @@ -518,7 +551,9 @@ def get_default_connections_from_weather(self,): ) return connections - def get_default_connections_from_simple_hot_water_storage(self,): + def get_default_connections_from_simple_hot_water_storage( + self, + ): """Get simple hot water storage default connections.""" connections = [] hws_classname = simple_hot_water_storage.SimpleHotWaterStorage.get_classname() @@ -531,10 +566,14 @@ def get_default_connections_from_simple_hot_water_storage(self,): ) return connections - def get_default_connections_from_dhw_storage(self,): + def get_default_connections_from_dhw_storage( + self, + ): """Get simple hot water storage default connections.""" connections = [] - dhw_classname = generic_hot_water_storage_modular.HotWaterStorage.get_classname() + dhw_classname = ( + generic_hot_water_storage_modular.HotWaterStorage.get_classname() + ) connections.append( ComponentConnection( HeatPumpHplib.TemperatureInputSecondary_DHW, @@ -551,7 +590,8 @@ def write_to_report(self): def i_save_state(self) -> None: """Save state.""" self.previous_state = self.state.self_copy() - # pass + + # pass def i_restore_state(self) -> None: """Restore state.""" @@ -572,11 +612,15 @@ def i_simulate( """Simulate the component.""" # Load input values - on_off: float + # on_off: float on_off_HotWater: float = stsv.get_input_value(self.on_off_switch_hotWater) on_off_DHW: float = stsv.get_input_value(self.on_off_switch_DHW) - const_thermal_power_truefalse_DHW: bool = stsv.get_input_value(self.const_thermal_power_truefalse_DHW) - const_thermal_power_value_DHW: float = stsv.get_input_value(self.const_thermal_power_value_DHW) + const_thermal_power_truefalse_DHW: bool = stsv.get_input_value( + self.const_thermal_power_truefalse_DHW + ) + const_thermal_power_value_DHW: float = stsv.get_input_value( + self.const_thermal_power_value_DHW + ) t_in_primary = stsv.get_input_value(self.t_in_primary) t_in_secondary_hot_water = stsv.get_input_value(self.t_in_secondary_hot_water) t_in_secondary_dhw = stsv.get_input_value(self.t_in_secondary_dhw) @@ -585,15 +629,14 @@ def i_simulate( time_on_cooling = self.state.time_on_cooling time_off = self.state.time_off - if on_off_DHW != 0: on_off = on_off_DHW else: on_off = on_off_HotWater + # on_off=self.state.on_off_previous # cycling means periodic turning on and off of the heat pump if self.cycling_mode is True: - # Parameter time_on_min = self.minimum_running_time_in_seconds # [s] time_off_min = self.minimum_idle_time_in_seconds @@ -620,21 +663,29 @@ def i_simulate( else: raise ValueError("Cycling mode of the advanced hplib unknown.") - - if on_off_DHW != 0: + if ( + on_off_DHW != 0 + ): # priority on dhw if there is a demand, independently if the actual state and time_on_heating on_off = on_off_DHW + if on_off == 1: # Calculation for building heating + if force_convergence: + results = hpl.simulate( + t_in_primary=t_in_primary, + t_in_secondary=t_in_secondary_hot_water, + parameters=self.parameters, + t_amb=t_amb, + mode=1, + ) + else: + results = self.get_cached_results_or_run_hplib_simulation( + t_in_primary=t_in_primary, + t_in_secondary=t_in_secondary_hot_water, + parameters=self.parameters, + t_amb=t_amb, + mode=1, + ) - # OnOffSwitch - if on_off == 1: - # Calulate outputs for heating mode - results = hpl.simulate( #self.get_cached_results_or_run_hplib_simulation( - t_in_primary=t_in_primary, - t_in_secondary=t_in_secondary_hot_water, - parameters=self.parameters, - t_amb=t_amb, - mode=1, - ) p_th_hot_water = results["P_th"].values[0] p_th_dhw = 0 p_el_hot_water = results["P_el"].values[0] @@ -645,60 +696,55 @@ def i_simulate( t_out_dhw = t_in_secondary_dhw m_dot_hot_water = results["m_dot"].values[0] m_dot_dhw = 0 - time_on_heating = time_on_heating + self.my_simulation_parameters.seconds_per_timestep + time_on_heating = ( + time_on_heating + self.my_simulation_parameters.seconds_per_timestep + ) time_on_cooling = 0 time_off = 0 - elif on_off == 2: # Calculate outputs for dhw mode - if const_thermal_power_truefalse_DHW == False: # False=modulation - results = hpl.simulate( #self.get_cached_results_or_run_hplib_simulation( + elif on_off == 2: # Calculate outputs for dhw mode + if force_convergence: + results = hpl.simulate( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_dhw, parameters=self.parameters, t_amb=t_amb, mode=1, ) - p_th_dhw = results["P_th"].values[0] - p_th_hot_water = 0 - p_el_dhw = results["P_el"].values[0] - p_el_hot_water = 0 - cop = results["COP"].values[0] - eer = results["EER"].values[0] - t_out_hot_water = t_in_secondary_hot_water - t_out_dhw = results["T_out"].values[0] - m_dot_hot_water = 0 - m_dot_dhw = results["m_dot"].values[0] - time_on_heating = time_on_heating + self.my_simulation_parameters.seconds_per_timestep - time_on_cooling = 0 - time_off = 0 - # print("t_out_WP_dhw " + str(t_out_dhw)) - - elif const_thermal_power_truefalse_DHW == True: # True = constante thermische Leistung - results = hpl.simulate( #self.get_cached_results_or_run_hplib_simulation( + else: + results = self.get_cached_results_or_run_hplib_simulation( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_dhw, parameters=self.parameters, t_amb=t_amb, mode=1, ) - p_th_dhw = const_thermal_power_value_DHW - p_th_hot_water = 0 - cop = results["COP"].values[0] - p_el_dhw = p_th_dhw/cop - p_el_hot_water = 0 - eer = results["EER"].values[0] - t_out_hot_water = t_in_secondary_hot_water - t_out_dhw = results["T_out"].values[0] - m_dot_hot_water = 0 - m_dot_dhw = results["m_dot"].values[0] - time_on_heating = time_on_heating + self.my_simulation_parameters.seconds_per_timestep - time_on_cooling = 0 - time_off = 0 + p_th_hot_water = 0 + p_el_hot_water = 0 + cop = results["COP"].values[0] + eer = results["EER"].values[0] + t_out_hot_water = t_in_secondary_hot_water + t_out_dhw = results["T_out"].values[0] + m_dot_hot_water = 0 + m_dot_dhw = results["m_dot"].values[0] + if const_thermal_power_truefalse_DHW == False: # False=modulation + p_th_dhw = results["P_th"].values[0] + p_el_dhw = results["P_el"].values[0] + if ( + const_thermal_power_truefalse_DHW == True + ): # True = constant thermal power output + p_th_dhw = const_thermal_power_value_DHW + p_el_dhw = p_th_dhw / cop + time_on_heating = ( + time_on_heating + self.my_simulation_parameters.seconds_per_timestep + ) + time_on_cooling = 0 + time_off = 0 elif on_off == -1: # Calulate outputs for cooling mode - results = hpl.simulate( #self.get_cached_results_or_run_hplib_simulation( + results = self.get_cached_results_or_run_hplib_simulation( t_in_primary=t_in_primary, t_in_secondary=t_in_secondary_hot_water, parameters=self.parameters, @@ -708,7 +754,7 @@ def i_simulate( p_th_hot_water = results["P_th"].values[0] p_th_dhw = 0 p_el_hot_water = results["P_el"].values[0] - p_el_dhw = 0 + p_el_dhw = 0 cop = results["COP"].values[0] eer = results["EER"].values[0] t_out_hot_water = results["T_out"].values[0] @@ -743,25 +789,31 @@ def i_simulate( else: raise ValueError("Unknown mode for Advanced HPLib On_Off.") + if ( + self.parameters["Group"].iloc[0] == 3.0 + or self.parameters["Group"].iloc[0] == 6.0 + ): + # todo: variability of massflow. now there is a fix temperaturdiffernz between inlet and outlet which calculate the massflow - if self.parameters['Group'].iloc[0] == 3.0 or self.parameters['Group'].iloc[0] == 6.0: - #todo: variability of massflow. now there is a fix temperaturdiffernz between inlet and outlet which calculate the massflow - - q_dot_entzugsleistung = ((p_th_dhw + p_th_hot_water) - (p_el_dhw + p_el_hot_water)) - m_dot_water_primary = q_dot_entzugsleistung/(self.specific_heat_capacity_of_water_in_joule_per_kilogram_per_celsius*self.hx_building_temp_diff) - t_out_primary = t_in_primary-self.hx_building_temp_diff + q_dot_entzugsleistung = (p_th_dhw + p_th_hot_water) - ( + p_el_dhw + p_el_hot_water + ) + m_dot_water_primary = q_dot_entzugsleistung / ( + self.specific_heat_capacity_of_water_in_joule_per_kilogram_per_celsius + * self.hx_building_temp_diff + ) + t_out_primary = t_in_primary - self.hx_building_temp_diff stsv.set_output_value(self.m_dot_water_primary_dhnet, m_dot_water_primary) stsv.set_output_value(self.temp_water_primary_hx_in, t_in_primary) stsv.set_output_value(self.temp_water_primary_hx_out, t_out_primary) - # write values for output time series stsv.set_output_value(self.p_th_hot_water, p_th_hot_water) stsv.set_output_value(self.p_th_dhw, p_th_dhw) - stsv.set_output_value(self.p_th_ges, p_th_dhw+p_th_hot_water) + stsv.set_output_value(self.p_th_ges, p_th_dhw + p_th_hot_water) stsv.set_output_value(self.p_el_hot_water, p_el_hot_water) stsv.set_output_value(self.p_el_dhw, p_el_dhw) - stsv.set_output_value(self.p_el_ges, p_el_dhw+p_el_hot_water) + stsv.set_output_value(self.p_el_ges, p_el_dhw + p_el_hot_water) stsv.set_output_value(self.cop, cop) stsv.set_output_value(self.eer, eer) stsv.set_output_value(self.heatpump_state, on_off) @@ -771,8 +823,10 @@ def i_simulate( stsv.set_output_value(self.m_dot_dhw, m_dot_dhw) stsv.set_output_value(self.time_on, time_on_heating) stsv.set_output_value(self.time_off, time_off) - stsv.set_output_value(self.thermal_power_from_environment, (p_th_dhw+p_th_hot_water)-(p_el_dhw+p_el_hot_water)) - + stsv.set_output_value( + self.thermal_power_from_environment, + (p_th_dhw + p_th_hot_water) - (p_el_dhw + p_el_hot_water), + ) # write values to state self.state.time_on = time_on_heating @@ -823,7 +877,6 @@ def get_cached_results_or_run_hplib_simulation( mode: int, ) -> Any: """Use caching of results of hplib simulation.""" - # rounding of variable values t_in_primary = round(t_in_primary, 1) t_in_secondary = round(t_in_secondary, 1) @@ -845,14 +898,13 @@ def get_cached_results_or_run_hplib_simulation( results = hpl.simulate( t_in_primary, t_in_secondary, parameters, t_amb, mode=mode ) - self.calculation_cache[my_hash_key] = results return results @dataclass -class HeatPumpState: # anpassen, dass automatisch dhw priorisiert wird +class HeatPumpState: """HeatPumpState class.""" time_on: int = 0 @@ -869,7 +921,6 @@ def self_copy( ) - @dataclass class CalculationRequest(JSONWizard): @@ -895,7 +946,6 @@ def get_key(self): # =========================================================================== -# try to implement a hplib controller l1 @dataclass_json @dataclass class HeatPumpHplibControllerHotWaterStorageL1Config(ConfigBase): @@ -916,8 +966,8 @@ def get_main_classname(cls): @classmethod def get_default_generic_heat_pump_controller_config( - cls, heat_distribution_system_type: Any - )-> "HeatPumpHplibControllerHotWaterStorageL1Config" : + cls, heat_distribution_system_type: Any + ) -> "HeatPumpHplibControllerHotWaterStorageL1Config": """Gets a default Generic Heat Pump Controller.""" return HeatPumpHplibControllerHotWaterStorageL1Config( name="HeatPumpControllerHotWaterStorage", @@ -1044,7 +1094,9 @@ def __init__( self.get_default_connections_from_simple_hot_water_storage() ) - def get_default_connections_from_heat_distribution_controller(self,): + def get_default_connections_from_heat_distribution_controller( + self, + ): """Get default connections.""" connections = [] hdsc_classname = ( @@ -1059,7 +1111,9 @@ def get_default_connections_from_heat_distribution_controller(self,): ) return connections - def get_default_connections_from_weather(self,): + def get_default_connections_from_weather( + self, + ): """Get default connections.""" connections = [] weather_classname = weather.Weather.get_classname() @@ -1072,7 +1126,9 @@ def get_default_connections_from_weather(self,): ) return connections - def get_default_connections_from_simple_hot_water_storage(self,): + def get_default_connections_from_simple_hot_water_storage( + self, + ): """Get simple hot water storage default connections.""" connections = [] hws_classname = simple_hot_water_storage.SimpleHotWaterStorage.get_classname() @@ -1230,7 +1286,6 @@ def conditions_on_off( return elif self.controller_heatpumpmode == "off": - # heat pump is only turned on if the water temperature is below the flow temperature # and if the avg daily outside temperature is cold enough (summer mode on) if ( @@ -1281,7 +1336,6 @@ def conditions_heating_cooling_off( return elif self.controller_heatpumpmode == "off": - # heat pump is only turned on if the water temperature is below the flow temperature # and if the avg daily outside temperature is cold enough (summer heating mode on) if ( @@ -1401,7 +1455,6 @@ def get_main_classname(cls): #: max. Power of Heatpump for not modulation dhw production p_th_max_dhw_in_W: float - @classmethod def get_default_generic_heat_pump_controller_config(cls): """Gets a default Generic Heat Pump Controller.""" @@ -1409,8 +1462,8 @@ def get_default_generic_heat_pump_controller_config(cls): name="HeatPumpControllerDHW", t_min_dhw_storage_in_celsius=40.0, t_max_dhw_storage_in_celsius=60.0, - thermalPower_is_constant_for_dhw = False, #false: modulation, true: constant power for dhw - p_th_max_dhw_in_W = 5000, # only if true + thermalPower_is_constant_for_dhw=False, # false: modulation, true: constant power for dhw + p_th_max_dhw_in_W=5000, # only if true ) @@ -1423,25 +1476,25 @@ class HeatPumpHplibControllerDHW(Component): """ - # in state mit aufnehmen das hier priorisiert wird # Inputs - WaterTemperatureInputFromDHWStorage ="WaterTemperatureInputFromDHWStorage" + WaterTemperatureInputFromDHWStorage = "WaterTemperatureInputFromDHWStorage" DWHStorageTemperatureModifier = "StorageTemperatureModifier" # Outputs State_dhw = "State DHW" - ThermalPower_Bedingung_for_konst_dhw = "BedingungfuerKonstDHW" #if heatpump has fix power for dhw - Value_Max_Thermal_Power_for_dhw = "ThermalPowerHPForDHWConst" #if heatpump has fix power for dhw - - - + ThermalPower_Bedingung_for_konst_dhw = ( + "BedingungfuerKonstDHW" # if heatpump has fix power for dhw + ) + Value_Max_Thermal_Power_for_dhw = ( + "ThermalPowerHPForDHWConst" # if heatpump has fix power for dhw + ) def __init__( - self, - my_simulation_parameters: SimulationParameters, - config: HeatPumpHplibControllerDHWL1Config, + self, + my_simulation_parameters: SimulationParameters, + config: HeatPumpHplibControllerDHWL1Config, ) -> None: """Construct all the neccessary attributes.""" self.heatpump_controller_dhw_config = config @@ -1494,21 +1547,23 @@ def __init__( output_description=f"here a description for {self.Value_Max_Thermal_Power_for_dhw} will follow.", ) - self.controller_heatpumpmode_dhw: Any - self.previous_heatpump_mode_dhw: Any + self.state_dhw: int + self.previous_state_dhw: int self.controller_signal: int self.previous_controller_signal: int self.thermalPower_constant_for_dhw: bool self.p_th_max_dhw: float - self.add_default_connections(self.get_default_connections_from_dhw_storage()) - def get_default_connections_from_dhw_storage(self, ): + def get_default_connections_from_dhw_storage( + self, + ): """Get simple hot water storage default connections.""" - log.information("setting dhw storage default connections") connections = [] - dhw_classname = generic_hot_water_storage_modular.HotWaterStorage.get_classname() + dhw_classname = ( + generic_hot_water_storage_modular.HotWaterStorage.get_classname() + ) connections.append( ComponentConnection( HeatPumpHplibControllerDHW.WaterTemperatureInputFromDHWStorage, @@ -1518,25 +1573,28 @@ def get_default_connections_from_dhw_storage(self, ): ) return connections - def build(self, ) -> None: + def build( + self, + ) -> None: """Build function. The function sets important constants and parameters for the calculations. """ # Sth - self.controller_heatpumpmode_dhw = "off_dhw_heating" - self.previous_heatpump_mode_dhw = self.controller_heatpumpmode_dhw + self.controller_signal = 0 + self.state_dhw = 0 self.previous_controller_signal = self.controller_signal - self.thermalPower_constant_for_dhw = self.config.thermalPower_is_constant_for_dhw + self.thermalPower_constant_for_dhw = ( + self.config.thermalPower_is_constant_for_dhw + ) self.p_th_max_dhw = self.config.p_th_max_dhw_in_W if self.thermalPower_constant_for_dhw == True: print("INFO: DHW Power ist constant with " + str(self.p_th_max_dhw) + "W") elif self.thermalPower_constant_for_dhw == False: print("INFO: DHW Power is modulating") - self.p_th_max_dhw=0 - + self.p_th_max_dhw = 0 def i_prepare_simulation(self) -> None: """Prepare the simulation.""" @@ -1544,13 +1602,13 @@ def i_prepare_simulation(self) -> None: def i_save_state(self) -> None: """Save the current state.""" - self.previous_heatpump_mode_dhw = self.controller_heatpumpmode_dhw self.previous_controller_signal = self.controller_signal + self.previous_state_dhw = self.state_dhw def i_restore_state(self) -> None: """Restore the previous state.""" - self.controller_heatpumpmode_dhw = self.previous_heatpump_mode_dhw self.controller_signal = self.previous_controller_signal + self.state_dhw = self.previous_state_dhw def i_doublecheck(self, timestep: int, stsv: SingleTimeStepValues) -> None: """Doublecheck.""" @@ -1561,50 +1619,68 @@ def write_to_report(self) -> List[str]: return self.heatpump_controller_dhw_config.get_string_dict() def i_simulate( - self, timestep: int, stsv: SingleTimeStepValues, force_convergence: bool + self, timestep: int, stsv: SingleTimeStepValues, force_convergence: bool ) -> None: - """Simulate the heat pump comtroller.""" + """Simulate the heat pump controller for dhw.""" if force_convergence: + # self.controller_signal = self.previous_controller_signal + # self.state_dhw = self.previous_state_dhw pass else: - - water_temperature_input_from_dhw_storage_in_celsius = stsv.get_input_value(self.water_temperature_input_channel) - temperature_modifier = stsv.get_input_value(self.storage_temperature_modifier_channel) + water_temperature_input_from_dhw_storage_in_celsius = stsv.get_input_value( + self.water_temperature_input_channel + ) + temperature_modifier = stsv.get_input_value( + self.storage_temperature_modifier_channel + ) t_min_dhw_storage_in_celsius = self.config.t_min_dhw_storage_in_celsius t_max_dhw_storage_in_celsius = self.config.t_max_dhw_storage_in_celsius - - if water_temperature_input_from_dhw_storage_in_celsius < t_min_dhw_storage_in_celsius: #an - #self.controller_heatpumpmode_dhw = "heating_dhw" + if ( + water_temperature_input_from_dhw_storage_in_celsius + < t_min_dhw_storage_in_celsius + ): # an self.controller_signal = 1 - elif water_temperature_input_from_dhw_storage_in_celsius > t_max_dhw_storage_in_celsius + temperature_modifier: #aus - # self.controller_heatpumpmode_dhw = "off_dhw_heating" + + elif ( + water_temperature_input_from_dhw_storage_in_celsius + > t_max_dhw_storage_in_celsius + temperature_modifier + ): # aus self.controller_signal = 0 - elif temperature_modifier > 0 and water_temperature_input_from_dhw_storage_in_celsius < t_max_dhw_storage_in_celsius: #aktiviren wenn strom überschuss + + elif ( + temperature_modifier > 0 + and water_temperature_input_from_dhw_storage_in_celsius + < t_max_dhw_storage_in_celsius + ): # aktiviren wenn strom überschuss self.controller_signal = 1 + else: - # self.controller_signal=630 pass - if self.controller_signal == 1: - state_dhw = 2 - # print("heating dhw on") + self.state_dhw = 2 + # print("heating dhw on") elif self.controller_signal == 0: - state_dhw = 0 - # print("heating dhw off") + self.state_dhw = 0 + # print("heating dhw off") else: raise ValueError("Advanced HP Lib DHW Controller State unknown.") + self.previous_controller_signal = self.controller_signal + self.previous_state_dhw = self.state_dhw - # print("state controller neu " + str(state_dhw)) - stsv.set_output_value(self.state_dhw_channel, state_dhw) - stsv.set_output_value(self.thermalPower_const_bedingung_channel, self.thermalPower_constant_for_dhw) - if self.thermalPower_constant_for_dhw == True: - stsv.set_output_value(self.thermalPower_max_value_channel, self.p_th_max_dhw) - elif self.thermalPower_constant_for_dhw == False: - stsv.set_output_value(self.thermalPower_max_value_channel, 0) - + stsv.set_output_value(self.state_dhw_channel, self.state_dhw) + stsv.set_output_value( + self.thermalPower_const_bedingung_channel, + self.thermalPower_constant_for_dhw, + ) + if self.thermalPower_constant_for_dhw == True: + stsv.set_output_value( + self.thermalPower_max_value_channel, self.p_th_max_dhw + ) + elif self.thermalPower_constant_for_dhw == False: + stsv.set_output_value(self.thermalPower_max_value_channel, 0)