Added heatpump export module
This commit is contained in:
parent
ce2e46a236
commit
45f682767d
|
@ -3,10 +3,10 @@ HeatPumpExport exports heatpump coefficient into several formats
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com
|
Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com
|
||||||
"""
|
"""
|
||||||
import numpy as np
|
import subprocess
|
||||||
from scipy.optimize import curve_fit
|
from typing import List, Tuple, Union
|
||||||
from typing import Dict, Tuple
|
import yaml
|
||||||
import pandas as pd
|
from string import Template
|
||||||
|
|
||||||
|
|
||||||
class HeatPumpExport:
|
class HeatPumpExport:
|
||||||
|
@ -16,70 +16,131 @@ class HeatPumpExport:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, base_path, city):
|
def __init__(self, base_path, city):
|
||||||
self._base_path = (base_path / 'heat_pumps/coefficients.xlsx')
|
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._city = city
|
||||||
|
self._input_data = None
|
||||||
|
self._base_path = base_path
|
||||||
|
|
||||||
def export_xlsx(self):
|
def run_insel(self, user_input, hp_model, data_type) -> None:
|
||||||
"""
|
"""
|
||||||
Writes the coefficients computed from heat performance
|
Runs insel and write the necessary files
|
||||||
and cooling performance data to excel sheet
|
:param user_input: a dictionary containing the user
|
||||||
:return: None
|
values necessary to run insel
|
||||||
"""
|
:param hp_model: a string that indicates the heat
|
||||||
writer = pd.ExcelWriter(self._base_path)
|
pump model to be used e.g. 012, 015
|
||||||
heat_column_names = ["a1", "a2", "a3", "a4", "a5", "a6"]
|
:param data_type: a string that indicates whether
|
||||||
cool_column_names = ["b1", "b2", "b3", "b4", "b5", "b6"]
|
insel should run for heat or cooling performance
|
||||||
heat_coff, cool_coff = self._compute_coefficients()
|
|
||||||
for (k_cool, v_cool), (k_heat, v_heat) in \
|
|
||||||
zip(heat_coff.items(), cool_coff.items()):
|
|
||||||
heat_df = pd.DataFrame([v_heat["heat_cap"], v_heat["comp_power"]], columns=heat_column_names,
|
|
||||||
index=["Heat Capacity", "Compressor Power"])
|
|
||||||
heat_df.to_excel(writer, sheet_name=k_heat)
|
|
||||||
cool_df = pd.DataFrame([v_heat["cool_cap"], v_heat["comp_power"]], columns=cool_column_names,
|
|
||||||
index=["Cooling Capacity", "Compressor Power"])
|
|
||||||
cool_df.to_excel(writer, sheet_name=k_cool, startrow=10)
|
|
||||||
|
|
||||||
writer.save()
|
|
||||||
|
|
||||||
def _compute_coefficients(self) -> Tuple[Dict, Dict]:
|
|
||||||
"""
|
|
||||||
Compute heat output and electrical demand coefficients
|
|
||||||
from heating and cooling performance data
|
|
||||||
:return: Tuple[Dict, Dict]
|
|
||||||
"""
|
|
||||||
out_temp = [25, 30, 32, 35, 40, 45] * 6
|
|
||||||
heat_x_values = np.repeat([-5, 0, 7, 10, 15], 6)
|
|
||||||
cool_x_values = np.repeat([6, 7, 8, 9, 10, 11], 6)
|
|
||||||
cooling_coff = {}
|
|
||||||
heating_coff = {}
|
|
||||||
for energy_system in self._city.energy_systems:
|
|
||||||
# Compute heat output coefficients
|
|
||||||
heating_cap_popt, _ = curve_fit(self._objective_function, [heat_x_values, out_temp],
|
|
||||||
energy_system.heat_pump.heating_capacity)
|
|
||||||
heating_comp_power_popt, _ = curve_fit(self._objective_function, [heat_x_values, out_temp],
|
|
||||||
energy_system.heat_pump.heating_comp_power)
|
|
||||||
# Compute electricity demand coefficients
|
|
||||||
cooling_cap_popt, _ = curve_fit(self._objective_function, [cool_x_values, out_temp],
|
|
||||||
energy_system.heat_pump.cooling_capacity)
|
|
||||||
cooling_comp_power_popt, _ = curve_fit(self._objective_function, [cool_x_values, out_temp],
|
|
||||||
energy_system.heat_pump.cooling_comp_power)
|
|
||||||
|
|
||||||
heating_coff[energy_system.heat_pump.model] = {"heat_cap": heating_cap_popt.tolist(),
|
|
||||||
"comp_power": heating_comp_power_popt.tolist()}
|
|
||||||
cooling_coff[energy_system.heat_pump.model] = {"cool_cap": cooling_cap_popt.tolist(),
|
|
||||||
"comp_power": cooling_comp_power_popt.tolist()}
|
|
||||||
return heating_coff, cooling_coff
|
|
||||||
|
|
||||||
def _objective_function(self, xdata, a1, a2, a3, a4, a5, a6):
|
|
||||||
"""
|
|
||||||
Objective function for computing coefficients
|
|
||||||
:param xdata:
|
|
||||||
:param a1: float
|
|
||||||
:param a2: float
|
|
||||||
:param a3: float
|
|
||||||
:param a4: float
|
|
||||||
:param a5: float
|
|
||||||
:param a6: float
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
x, y = xdata
|
self._input_data = user_input
|
||||||
return (a1 * x ** 2) + (a2 * x) + (a3 * x * y) + (a4 * y) + (a5 * y ** 2) + a6
|
# 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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user