""" HeatPumpExport exports heatpump coefficient into several formats SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com """ import subprocess from typing import List, Tuple, Union import yaml from string import Template class HeatPumpExport: """ Exports heat pump values as coefficients of some defined function """ def __init__(self, base_path, city): self._template_path = (base_path / 'heat_pumps/template.txt') self._constants_path = (base_path / 'heat_pumps/constants.yaml') # needed to compute max demand. self._demand_path = (base_path / 'heat_pumps/demand.txt') self._city = city self._input_data = None self._base_path = base_path def run_insel(self, user_input, hp_model, data_type) -> None: """ Runs insel and write the necessary files :param user_input: a dictionary containing the user values necessary to run insel :param hp_model: a string that indicates the heat pump model to be used e.g. 012, 015 :param data_type: a string that indicates whether insel should run for heat or cooling performance :return: """ self._input_data = user_input # update input data with other data necessary to run insel capacity_coff, comp_power_coff = self._extract_model_coff(hp_model, data_type) self._update_input_data_with_coff(capacity_coff, comp_power_coff) # update input data with constants self._update_input_data_with_constants() # update input data with input and output files for insel self._update_input_data_with_files() insel_file_handler = None insel_template_handler = None try: # run insel insel_template_handler = open(self._template_path, "r") insel_template_handler = insel_template_handler.read() insel_template = Template(insel_template_handler).substitute(self._input_data) # create the insel file and write the template with substituted values into it insel_file = (self._base_path / 'heat_pumps/dompark_heat_pump.insel') insel_file_handler = open(insel_file, "w") insel_file_handler.write(insel_template) # Now run insel subprocess.call('insel', insel_file) except IOError as err: print("I/O exception: {}".format(err)) except subprocess.CalledProcessError as err: print("Insel command error {}".format(err)) else: print("Insel executed successfully") finally: insel_file_handler.close() insel_template_handler.close() def _update_input_data_with_files(self): """ Updates input data for insel with some files that will be written to after insel runs. Also specifies and input file which is the Heating Demand (demand.txt) file :return: """ self._input_data["HeatingDemand"] = self._demand_path self._input_data["fileOut1"] = (self._base_path / 'heat_pumps/technical_performance.csv') self._input_data["fileOut2"] = (self._base_path / 'heat_pumps/system_daily_emissions.cs') self._input_data["fileOut3"] = (self._base_path / 'heat_pumps/monthly_operational_costs.csv') self._input_data["fileOut4"] = (self._base_path / 'heat_pumps/monthly_fossil_fuel_consumptions.csv') self._input_data["fileOut5"] = (self._base_path / 'heat_pumps/system_monthly_emissions.csv') self._input_data["fileOut6"] = (self._base_path / 'heat_pumps/daily_hp_electricity_demand.csv') self._input_data["fileOut7"] = (self._base_path / 'heat_pumps/daily_operational_costs.csv') self._input_data["fileOut8"] = (self._base_path / 'heat_pumps/monthly_hp_electricity_demand.csv') self._input_data["fileOut9"] = (self._base_path / 'heat_pumps/daily_fossil_fuel_consumption.csv') self._input_data["fileOut10"] = (self._base_path / 'heat_pumps/hp_hourly_electricity_demand.csv') def _compute_max_demand(self): """ Retrieves the maximum demand value from the demands text file :return: float """ max_demand = -1 with open(self._demand_path) as file_handler: for demand in file_handler.readlines(): if float(demand) > max_demand: max_demand = float(demand) return max_demand def _update_input_data_with_constants(self): with open(self._constants_path) as file: constants_dict = yaml.load(file, Loader=yaml.FullLoader) for key, value in constants_dict.items(): self._input_data[key] = value # compute maximum demand. TODO: This should come from catalog in the future max_demand = self._compute_max_demand() # compute TESCapacity self._input_data["TESCapacity"] = self._input_data["HoursOfStorageAtMaxDemand"] * (max_demand * 3.6) / ( (self._input_data["Cp"] / 1000) * self._input_data["TemperatureDifference"]) def _update_input_data_with_coff(self, capacity_coff, comp_power_coff): """ Updates the user data with coefficients derived from imports :param capacity_coff: heat or cooling capacity coefficients :param comp_power_coff: heat or cooling comppressor power coefficients :return: """ self._input_data["a1"] = capacity_coff[0] self._input_data["a2"] = capacity_coff[1] self._input_data["a3"] = capacity_coff[2] self._input_data["a4"] = capacity_coff[3] self._input_data["a5"] = capacity_coff[4] self._input_data["a6"] = capacity_coff[5] self._input_data["b1"] = comp_power_coff[0] self._input_data["b2"] = comp_power_coff[1] self._input_data["b3"] = comp_power_coff[2] self._input_data["b4"] = comp_power_coff[3] self._input_data["b5"] = comp_power_coff[4] self._input_data["b6"] = comp_power_coff[5] def _extract_model_coff(self, hp_model, data_type='heat') -> Union[Tuple[List, List], None]: """ Extracts heat pump coefficient data for a specific model. e.g 012, 140 :param hp_model: the model type :param data_type: indicates whether we're extracting cooling or heating perfarmcn coefficients :return: """ for energy_system in self._city.energy_systems: if energy_system.heat_pump.model == hp_model: if data_type == 'heat': return energy_system.heat_pump.heating_capacity_coff, energy_system.heat_pump.heating_comp_power_coff return energy_system.heat_pump.cooling_capacity_coff, energy_system.heat_pump.cooling_comp_power_coff return None