Integrate Peter's head pump branch into master
This commit is contained in:
commit
eeff2eec18
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,3 +2,5 @@
|
|||
/venv/
|
||||
.idea/
|
||||
/development_tests/
|
||||
/data/energy_systems/heat_pumps/*.csv
|
||||
/data/energy_systems/heat_pumps/*.insel
|
||||
|
|
|
@ -4,7 +4,6 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|||
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
|
||||
from __future__ import annotations
|
||||
import math
|
||||
import sys
|
||||
|
@ -72,11 +71,11 @@ class Polygon:
|
|||
"""
|
||||
if self._edges is None:
|
||||
self._edges = []
|
||||
for i in range(0, len(self.points)-1):
|
||||
for i in range(0, len(self.points) - 1):
|
||||
point_1 = self.points[i]
|
||||
point_2 = self.points[i+1]
|
||||
point_2 = self.points[i + 1]
|
||||
self._edges.append([point_1, point_2])
|
||||
self._edges.append([self.points[len(self.points)-1], self.points[0]])
|
||||
self._edges.append([self.points[len(self.points) - 1], self.points[0]])
|
||||
return self._edges
|
||||
|
||||
@property
|
||||
|
@ -100,12 +99,12 @@ class Polygon:
|
|||
return 0
|
||||
horizontal_points = self._points_rotated_to_horizontal
|
||||
area = 0
|
||||
for i in range(0, len(horizontal_points)-1):
|
||||
for i in range(0, len(horizontal_points) - 1):
|
||||
point = horizontal_points[i]
|
||||
next_point = horizontal_points[i+1]
|
||||
next_point = horizontal_points[i + 1]
|
||||
area += (next_point[1] + point[1]) / 2 * (next_point[0] - point[0])
|
||||
next_point = horizontal_points[0]
|
||||
point = horizontal_points[len(horizontal_points)-1]
|
||||
point = horizontal_points[len(horizontal_points) - 1]
|
||||
area += (next_point[1] + point[1]) / 2 * (next_point[0] - point[0])
|
||||
self._area = abs(area)
|
||||
return self._area
|
||||
|
@ -157,8 +156,8 @@ class Polygon:
|
|||
if self._normal is None:
|
||||
points = self.coordinates
|
||||
# todo: IF THE FIRST ONE IS 0, START WITH THE NEXT
|
||||
point_origin = points[len(points)-2]
|
||||
vector_1 = points[len(points)-1] - point_origin
|
||||
point_origin = points[len(points) - 2]
|
||||
vector_1 = points[len(points) - 1] - point_origin
|
||||
vector_2 = points[0] - point_origin
|
||||
vector_3 = points[1] - point_origin
|
||||
cross_product = np.cross(vector_1, vector_2)
|
||||
|
@ -173,9 +172,9 @@ class Polygon:
|
|||
if np.linalg.norm(cross_product) == 0:
|
||||
return cross_product
|
||||
alpha += self._angle(vector_2, vector_3, cross_product)
|
||||
for i in range(0, len(points)-4):
|
||||
vector_1 = points[i+1] - point_origin
|
||||
vector_2 = points[i+2] - point_origin
|
||||
for i in range(0, len(points) - 4):
|
||||
vector_1 = points[i + 1] - point_origin
|
||||
vector_2 = points[i + 2] - point_origin
|
||||
alpha += self._angle(vector_1, vector_2, cross_product)
|
||||
vector_1 = points[len(points) - 1] - point_origin
|
||||
vector_2 = points[0] - point_origin
|
||||
|
@ -242,25 +241,30 @@ class Polygon:
|
|||
if self._is_ear(ear, rest_points):
|
||||
ears.append(ear)
|
||||
point_to_remove = concave_points[i]
|
||||
previous_point_in_list, next_point_in_list = self._enveloping_points(point_to_remove, total_points_list)
|
||||
previous_point_in_list, next_point_in_list = self._enveloping_points(point_to_remove,
|
||||
total_points_list)
|
||||
total_points_list.remove(point_to_remove)
|
||||
concave_points.remove(point_to_remove)
|
||||
# Was any of the adjacent points convex? -> check if changed status to concave
|
||||
for convex_point in convex_points:
|
||||
if convex_point == previous_point_in_list:
|
||||
concave_points, convex_points, end_loop = self._if_concave_change_status(normal, points_list,
|
||||
concave_points, convex_points, end_loop = self._if_concave_change_status(normal,
|
||||
points_list,
|
||||
convex_point,
|
||||
total_points_list,
|
||||
concave_points, convex_points,
|
||||
concave_points,
|
||||
convex_points,
|
||||
previous_point_in_list)
|
||||
if end_loop:
|
||||
break
|
||||
continue
|
||||
if convex_point == next_point_in_list:
|
||||
concave_points, convex_points, end_loop = self._if_concave_change_status(normal, points_list,
|
||||
concave_points, convex_points, end_loop = self._if_concave_change_status(normal,
|
||||
points_list,
|
||||
convex_point,
|
||||
total_points_list,
|
||||
concave_points, convex_points,
|
||||
concave_points,
|
||||
convex_points,
|
||||
next_point_in_list)
|
||||
if end_loop:
|
||||
break
|
||||
|
@ -300,11 +304,11 @@ class Polygon:
|
|||
else:
|
||||
convex_points.append(index)
|
||||
# case 2: all points except first and last
|
||||
for i in range(0, int((len(points_list)-6)/3)):
|
||||
point = points_list[(i+1)*3:(i+2)*3]
|
||||
previous_point = points_list[i*3:(i+1)*3]
|
||||
next_point = points_list[(i+2)*3:(i+3)*3]
|
||||
index = i+1
|
||||
for i in range(0, int((len(points_list) - 6) / 3)):
|
||||
point = points_list[(i + 1) * 3:(i + 2) * 3]
|
||||
previous_point = points_list[i * 3:(i + 1) * 3]
|
||||
next_point = points_list[(i + 2) * 3:(i + 3) * 3]
|
||||
index = i + 1
|
||||
total_points_list.append(index)
|
||||
if Polygon._point_is_concave(normal, point, previous_point, next_point):
|
||||
concave_points.append(index)
|
||||
|
@ -314,7 +318,7 @@ class Polygon:
|
|||
point = points_list[len(points_list) - 3:]
|
||||
previous_point = points_list[len(points_list) - 6:len(points_list) - 3]
|
||||
next_point = points_list[0:3]
|
||||
index = int(len(points_list)/3) - 1
|
||||
index = int(len(points_list) / 3) - 1
|
||||
total_points_list.append(index)
|
||||
if Polygon._point_is_concave(normal, point, previous_point, next_point):
|
||||
concave_points.append(index)
|
||||
|
@ -358,7 +362,7 @@ class Polygon:
|
|||
if point_position == total_points_list[len(total_points_list) - 1]:
|
||||
previous_point_index = total_points_list[len(total_points_list) - 2] * 3
|
||||
next_point_index = total_points_list[0] * 3
|
||||
for i in range(1, len(total_points_list)-1):
|
||||
for i in range(1, len(total_points_list) - 1):
|
||||
if point_position == total_points_list[i]:
|
||||
previous_point_index = total_points_list[i - 1] * 3
|
||||
next_point_index = total_points_list[i + 1] * 3
|
||||
|
@ -495,9 +499,9 @@ class Polygon:
|
|||
sys.stderr.write("Warning: impossible to calculate angle between planes' normal. Return 0\n")
|
||||
return 0
|
||||
cosine = np.dot(vec_1, vec_2) / np.linalg.norm(vec_1) / np.linalg.norm(vec_2)
|
||||
if cosine > 1 and cosine-1 < 1e-5:
|
||||
if cosine > 1 and cosine - 1 < 1e-5:
|
||||
cosine = 1
|
||||
elif cosine < -1 and cosine+1 > -1e-5:
|
||||
elif cosine < -1 and cosine + 1 > -1e-5:
|
||||
cosine = -1
|
||||
alpha = math.acos(cosine)
|
||||
return alpha
|
||||
|
@ -546,8 +550,9 @@ class Polygon:
|
|||
@staticmethod
|
||||
def _edge_in_edges_list(edge, edges_list):
|
||||
for edge_element in edges_list:
|
||||
if (edge_element[0].distance_to_point(edge[0]) == 0 and edge_element[1].distance_to_point(edge[1]) == 0) or\
|
||||
(edge_element[1].distance_to_point(edge[0]) == 0 and edge_element[0].distance_to_point(edge[1]) == 0):
|
||||
if (edge_element[0].distance_to_point(edge[0]) == 0 and edge_element[1].distance_to_point(edge[1]) == 0) or \
|
||||
(edge_element[1].distance_to_point(edge[0]) == 0 and edge_element[0].distance_to_point(
|
||||
edge[1]) == 0):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -558,10 +563,10 @@ class Polygon:
|
|||
for _ in range(0, len(points)):
|
||||
for i in range(1, len(edges_list)):
|
||||
point_1 = edges_list[i][0]
|
||||
point_2 = points[len(points)-1]
|
||||
point_2 = points[len(points) - 1]
|
||||
if point_1.distance_to_point(point_2) == 0:
|
||||
points.append(edges_list[i][1])
|
||||
points.remove(points[len(points)-1])
|
||||
points.remove(points[len(points) - 1])
|
||||
array_points = []
|
||||
for point in points:
|
||||
array_points.append(point.coordinates)
|
||||
|
@ -571,8 +576,10 @@ class Polygon:
|
|||
def _remove_from_list(edge, edges_list):
|
||||
new_list = []
|
||||
for edge_element in edges_list:
|
||||
if not((edge_element[0].distance_to_point(edge[0]) == 0 and edge_element[1].distance_to_point(edge[1]) == 0) or
|
||||
(edge_element[1].distance_to_point(edge[0]) == 0 and edge_element[0].distance_to_point(edge[1]) == 0)):
|
||||
if not ((edge_element[0].distance_to_point(edge[0]) == 0 and edge_element[1].distance_to_point(
|
||||
edge[1]) == 0) or
|
||||
(edge_element[1].distance_to_point(edge[0]) == 0 and edge_element[0].distance_to_point(
|
||||
edge[1]) == 0)):
|
||||
new_list.append(edge_element)
|
||||
return new_list
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ class Schedule:
|
|||
"""
|
||||
Schedule class
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._id = None
|
||||
self._type = None
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
City module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
Contributor Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import sys
|
||||
|
@ -21,6 +22,7 @@ from city_model_structure.subway_entrance import SubwayEntrance
|
|||
from city_model_structure.fuel import Fuel
|
||||
from helpers.geometry_helper import GeometryHelper
|
||||
from helpers.location import Location
|
||||
from city_model_structure.energy_system import EnergySystem
|
||||
|
||||
|
||||
class City:
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
"""
|
||||
EnergySystem module
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2021 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
Contributor Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
|
||||
from city_model_structure.city_object import CityObject
|
||||
|
@ -12,11 +13,33 @@ class EnergySystem(CityObject):
|
|||
"""
|
||||
EnergySystem(CityObject) class
|
||||
"""
|
||||
|
||||
def __init__(self, name, lod, surfaces, city_lower_corner):
|
||||
super().__init__(name, lod, surfaces, city_lower_corner)
|
||||
self._heat_pump = None
|
||||
self._type = 'energy_system'
|
||||
|
||||
@property
|
||||
def heat_pump(self) -> HeatPump:
|
||||
"""
|
||||
Heat pump energy system
|
||||
:return:
|
||||
"""
|
||||
return self._heat_pump
|
||||
|
||||
@heat_pump.setter
|
||||
def heat_pump(self, value):
|
||||
"""
|
||||
Set heat pumm for energy system
|
||||
:param value: HeatPump
|
||||
"""
|
||||
if self._heat_pump is None:
|
||||
self._heat_pump = value
|
||||
|
||||
@property
|
||||
def type(self) -> str:
|
||||
"""
|
||||
Type of city object
|
||||
:return: str
|
||||
"""
|
||||
return self._type
|
||||
|
|
|
@ -2,45 +2,189 @@
|
|||
heat_pump module defines a heat pump
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
Contributor Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
|
||||
from typing import Union
|
||||
from typing import List
|
||||
from typing import Dict
|
||||
|
||||
|
||||
class HeatPump:
|
||||
"""
|
||||
HeatPump class
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._model = None
|
||||
self._cooling_pf = None
|
||||
self._cooling_pa = None
|
||||
self._cooling_qw = None
|
||||
self._heating_pf = None
|
||||
self._heating_pa = None
|
||||
self._heating_qw = None
|
||||
self._cooling_capacity = None
|
||||
self._cooling_comp_power = None
|
||||
self._cooling_capacity_coff = None
|
||||
self._cooling_comp_power_coff = None
|
||||
self._heating_capacity = None
|
||||
self._heating_comp_power = None
|
||||
self._heating_capacity_coff = None
|
||||
self._heating_comp_power_coff = None
|
||||
|
||||
@property
|
||||
def model(self):
|
||||
def model(self) -> str:
|
||||
"""
|
||||
Get model name
|
||||
:return: str
|
||||
"""
|
||||
return self._model
|
||||
|
||||
@model.setter
|
||||
def model(self, value):
|
||||
"""
|
||||
Set model (name, indicated in capacity)
|
||||
:param value: str
|
||||
"""
|
||||
if self._model is None:
|
||||
self._model = value
|
||||
|
||||
@property
|
||||
def cooling_pf(self):
|
||||
def cooling_capacity(self) -> List[float]:
|
||||
"""
|
||||
Get cooling capacity in kW
|
||||
:return: [[float]]
|
||||
"""
|
||||
return self._cooling_pf
|
||||
return self._cooling_capacity
|
||||
|
||||
@cooling_pf.setter
|
||||
def cooling_pf(self, value):
|
||||
@cooling_capacity.setter
|
||||
def cooling_capacity(self, value):
|
||||
"""
|
||||
Set cooling capacity in kW
|
||||
:param value: [[float]]
|
||||
"""
|
||||
if self._cooling_pf is None:
|
||||
self._cooling_pf = value
|
||||
if self._cooling_capacity is None:
|
||||
self._cooling_capacity = value
|
||||
|
||||
@property
|
||||
def cooling_comp_power(self) -> List[float]:
|
||||
"""
|
||||
Get cooling compressor power input in kW
|
||||
:return: [[float]]
|
||||
"""
|
||||
return self._cooling_comp_power
|
||||
|
||||
@cooling_comp_power.setter
|
||||
def cooling_comp_power(self, value):
|
||||
"""
|
||||
Set the cooling compressor in kW
|
||||
:param value: [[float]]
|
||||
:return:
|
||||
"""
|
||||
if self._cooling_comp_power is None:
|
||||
self._cooling_comp_power = value
|
||||
|
||||
@property
|
||||
def cooling_capacity_coff(self) -> List[float]:
|
||||
"""
|
||||
Get cooling capacity coefficients
|
||||
:return: [float]
|
||||
"""
|
||||
return self._cooling_capacity_coff
|
||||
|
||||
@cooling_capacity_coff.setter
|
||||
def cooling_capacity_coff(self, value):
|
||||
"""
|
||||
Set the value for cooling capacity coefficients
|
||||
:param value: [float]
|
||||
:return:
|
||||
"""
|
||||
if self._cooling_capacity_coff is None:
|
||||
self._cooling_capacity_coff = value
|
||||
|
||||
@property
|
||||
def cooling_comp_power_coff(self) -> List[float]:
|
||||
"""
|
||||
Get cooling compressor power coefficients
|
||||
:return: [float]
|
||||
"""
|
||||
return self._cooling_comp_power_coff
|
||||
|
||||
@cooling_comp_power_coff.setter
|
||||
def cooling_comp_power_coff(self, value):
|
||||
"""
|
||||
Set the value for cooling compressor power coefficients
|
||||
:param value: [float]
|
||||
:return:
|
||||
"""
|
||||
if self._cooling_comp_power_coff is None:
|
||||
self._cooling_comp_power_coff = value
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def heating_capacity(self) -> List[float]:
|
||||
"""
|
||||
Get heating capacity kW
|
||||
:return: [[float]]
|
||||
"""
|
||||
return self._heating_capacity
|
||||
|
||||
@heating_capacity.setter
|
||||
def heating_capacity(self, value):
|
||||
"""
|
||||
Set the heating capacity in kW
|
||||
:param value: [[float]]
|
||||
:return:
|
||||
"""
|
||||
if self._heating_capacity is None:
|
||||
self._heating_capacity = value
|
||||
|
||||
@property
|
||||
def heating_comp_power(self) -> List[float]:
|
||||
"""
|
||||
Get heating compressor power kW
|
||||
:return: [[float]]
|
||||
"""
|
||||
return self._heating_comp_power
|
||||
|
||||
@heating_comp_power.setter
|
||||
def heating_comp_power(self, value):
|
||||
"""
|
||||
Set the heating compressor power in kW
|
||||
:param value: [[float]]
|
||||
:return:
|
||||
"""
|
||||
if self._heating_comp_power is None:
|
||||
self._heating_comp_power = value
|
||||
|
||||
@property
|
||||
def heating_comp_power_coff(self) -> List[float]:
|
||||
"""
|
||||
Get heating compressor power coefficients
|
||||
:return: [float]
|
||||
"""
|
||||
return self._heating_comp_power_coff
|
||||
|
||||
@heating_comp_power_coff.setter
|
||||
def heating_comp_power_coff(self, value):
|
||||
"""
|
||||
Set the value for heating compressor power coefficients
|
||||
:param value: [float]
|
||||
:return:
|
||||
"""
|
||||
if self._heating_comp_power_coff is None:
|
||||
self._heating_comp_power_coff = value
|
||||
|
||||
@property
|
||||
def heating_capacity_coff(self) -> List[float]:
|
||||
"""
|
||||
Get heating capacity coefficients
|
||||
:return: [float]
|
||||
"""
|
||||
return self._heating_capacity_coff
|
||||
|
||||
@heating_capacity_coff.setter
|
||||
def heating_capacity_coff(self, value):
|
||||
"""
|
||||
Set the value for heating capacity coefficients
|
||||
:param value: [float]
|
||||
:return:
|
||||
"""
|
||||
if self._heating_capacity_coff is None:
|
||||
self._heating_capacity_coff = value
|
||||
|
||||
|
||||
|
|
20
data/energy_systems/heat_pumps/constants.yaml
Normal file
20
data/energy_systems/heat_pumps/constants.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Heat pump performance constants
|
||||
StartMonth: 1
|
||||
StartDay: 1
|
||||
StartHour: 0
|
||||
StartMinute: 0
|
||||
StartSecond: 0
|
||||
EndMonth: 1
|
||||
EndDay: 1
|
||||
EndHour: 0
|
||||
EndMinute: 0
|
||||
EndSecond: 0
|
||||
Cp: 4190
|
||||
Rhow: 1000
|
||||
TESDiameter: 5
|
||||
AuxHeaterEfficiency: 0.9
|
||||
|
||||
# These come from the data model according to other student's work
|
||||
ElecGridEF: 0.5
|
||||
ElectricityPrice: 0.073
|
||||
|
105120
data/energy_systems/heat_pumps/demand.txt
Normal file
105120
data/energy_systems/heat_pumps/demand.txt
Normal file
File diff suppressed because it is too large
Load Diff
816
data/energy_systems/heat_pumps/template.txt
Normal file
816
data/energy_systems/heat_pumps/template.txt
Normal file
|
@ -0,0 +1,816 @@
|
|||
|
||||
B 10 MUL
|
||||
64.1
|
||||
183.1
|
||||
|
||||
B 11 MUL
|
||||
198.1
|
||||
167.1
|
||||
163.1
|
||||
162.1
|
||||
|
||||
B 12 MUL
|
||||
201.1
|
||||
24.1
|
||||
|
||||
B 13 MUL
|
||||
70.1
|
||||
180.1
|
||||
|
||||
B 14 MUL
|
||||
184.1
|
||||
34.1
|
||||
|
||||
B 15 MUL
|
||||
198.1
|
||||
165.1
|
||||
163.1
|
||||
162.1
|
||||
|
||||
B 16 MUL
|
||||
186.1
|
||||
40.1
|
||||
|
||||
B 17 MUL
|
||||
79.1
|
||||
56.1
|
||||
69.1
|
||||
|
||||
B 18 MUL
|
||||
188.1
|
||||
49.1
|
||||
|
||||
B 19 MUL
|
||||
46.1
|
||||
158.1
|
||||
|
||||
B 20 MUL
|
||||
72.1
|
||||
66.1
|
||||
|
||||
B 21 MUL
|
||||
57.1
|
||||
182.1
|
||||
|
||||
B 22 MUL
|
||||
203.2
|
||||
43.1
|
||||
|
||||
B 23 MUL
|
||||
78.1
|
||||
50.1
|
||||
47.1
|
||||
|
||||
B 24 MUL
|
||||
201.1
|
||||
193.1
|
||||
196.1
|
||||
|
||||
B 25 MUL
|
||||
203.2
|
||||
76.1
|
||||
|
||||
B 26 MUL
|
||||
58.1
|
||||
68.1
|
||||
|
||||
B 27 MUL
|
||||
160.1
|
||||
63.1
|
||||
168.1
|
||||
136.1
|
||||
|
||||
B 28 MUL
|
||||
58.1
|
||||
60.1
|
||||
|
||||
B 29 MUL
|
||||
65.1
|
||||
181.1
|
||||
|
||||
B 30 MUL
|
||||
203.2
|
||||
58.1
|
||||
36.1
|
||||
|
||||
B 31 MUL
|
||||
159.1
|
||||
195.1
|
||||
|
||||
B 32 MUL
|
||||
203.2
|
||||
58.1
|
||||
77.1
|
||||
|
||||
B 33 MUL
|
||||
202.1
|
||||
74.1
|
||||
|
||||
B 34 CONST
|
||||
P 34
|
||||
$ElecGridEF % Constant value
|
||||
|
||||
B 35 CONST
|
||||
P 35
|
||||
5 % Constant value
|
||||
|
||||
B 36 CONST
|
||||
P 36
|
||||
$a3 % Constant value
|
||||
|
||||
B 37 CONST
|
||||
P 37
|
||||
$TemperatureDifference % Constant value
|
||||
|
||||
B 38 CONST
|
||||
P 38
|
||||
42 % Constant value
|
||||
|
||||
B 39 CONST
|
||||
P 39
|
||||
40 % Constant value
|
||||
|
||||
B 40 CONST
|
||||
P 40
|
||||
$ElectricityPrice % Constant value
|
||||
|
||||
B 41 CONST
|
||||
P 41
|
||||
9 % Constant value
|
||||
|
||||
B 42 CONST
|
||||
P 42
|
||||
12 % Constant value
|
||||
|
||||
B 43 CONST
|
||||
P 43
|
||||
$b2 % Constant value
|
||||
|
||||
B 44 CONST
|
||||
P 44
|
||||
$a6 % Constant value
|
||||
|
||||
B 45 CONST
|
||||
P 45
|
||||
55 % Constant value
|
||||
|
||||
B 46 CONST
|
||||
P 46
|
||||
$Cp % Constant value
|
||||
|
||||
B 47 CONST
|
||||
P 47
|
||||
$FuelEF % Constant value
|
||||
|
||||
B 48 CONST
|
||||
P 48
|
||||
2 % Constant value
|
||||
|
||||
B 49 CONST
|
||||
P 49
|
||||
1 % Constant value
|
||||
|
||||
B 50 CONST
|
||||
P 50
|
||||
300 % Constant value
|
||||
|
||||
B 51 CONST
|
||||
P 51
|
||||
10 % Constant value
|
||||
|
||||
B 52 CONST
|
||||
P 52
|
||||
0 % Constant value
|
||||
|
||||
B 53 CONST
|
||||
P 53
|
||||
12 % Constant value
|
||||
|
||||
B 54 CONST
|
||||
P 54
|
||||
$FuelLHV % Constant value
|
||||
|
||||
B 55 CONST
|
||||
P 55
|
||||
2 % Constant value
|
||||
|
||||
B 56 CONST
|
||||
P 56
|
||||
300 % Constant value
|
||||
|
||||
B 57 CONST
|
||||
P 57
|
||||
$b5 % Constant value
|
||||
|
||||
B 58 CONST
|
||||
P 58
|
||||
$HPSupTemp % Constant value
|
||||
|
||||
B 59 CONST
|
||||
P 59
|
||||
40 % Constant value
|
||||
|
||||
B 60 CONST
|
||||
P 60
|
||||
$a4 % Constant value
|
||||
|
||||
B 61 CONST
|
||||
P 61
|
||||
$b6 % Constant value
|
||||
|
||||
B 62 CONST
|
||||
P 62
|
||||
2 % Constant value
|
||||
|
||||
B 63 CONST
|
||||
P 63
|
||||
$Cp % Constant value
|
||||
|
||||
B 64 CONST
|
||||
P 64
|
||||
$b1 % Constant value
|
||||
|
||||
B 65 CONST
|
||||
P 65
|
||||
$a1 % Constant value
|
||||
|
||||
B 66 CONST
|
||||
P 66
|
||||
$TemperatureDifference % Constant value
|
||||
|
||||
B 67 CONST
|
||||
P 67
|
||||
$MaximumHPEnergyInput % Constant value
|
||||
|
||||
B 68 CONST
|
||||
P 68
|
||||
$b4 % Constant value
|
||||
|
||||
B 69 CONST
|
||||
P 69
|
||||
$FuelPrice % Constant value
|
||||
|
||||
B 70 CONST
|
||||
P 70
|
||||
$a5 % Constant value
|
||||
|
||||
B 71 CONST
|
||||
P 71
|
||||
2 % Constant value
|
||||
|
||||
B 72 CONST
|
||||
P 72
|
||||
$Cp % Constant value
|
||||
|
||||
B 73 CONST
|
||||
P 73
|
||||
$BuildingSuppTemp % Constant value
|
||||
|
||||
B 74 CONST
|
||||
P 74
|
||||
25 % Constant value
|
||||
|
||||
B 75 CONST
|
||||
P 75
|
||||
0 % Constant value
|
||||
|
||||
B 76 CONST
|
||||
P 76
|
||||
$a2 % Constant value
|
||||
|
||||
B 77 CONST
|
||||
P 77
|
||||
$b3 % Constant value
|
||||
|
||||
B 78 ATT
|
||||
191.1
|
||||
P 78
|
||||
$FuelDensity % Attenuation factor a
|
||||
|
||||
B 79 ATT
|
||||
191.1
|
||||
P 79
|
||||
$FuelDensity % Attenuation factor a
|
||||
|
||||
B 80 ATT
|
||||
27.1
|
||||
P 80
|
||||
$AuxHeaterEfficiency % Attenuation factor a
|
||||
|
||||
B 81 ATT
|
||||
191.1
|
||||
P 81
|
||||
$FuelDensity % Attenuation factor a
|
||||
|
||||
B 82 ATT
|
||||
11.1
|
||||
P 82
|
||||
12 % Attenuation factor a
|
||||
|
||||
B 83 ATT
|
||||
210.5
|
||||
P 83
|
||||
3600000 % Attenuation factor a
|
||||
|
||||
B 84 ATT
|
||||
161.1
|
||||
P 84
|
||||
3600000 % Attenuation factor a
|
||||
|
||||
B 85 ATT
|
||||
27.1
|
||||
P 85
|
||||
1000 % Attenuation factor a
|
||||
|
||||
|
||||
B 125 WRITE
|
||||
156.1
|
||||
156.2
|
||||
156.3
|
||||
P 125
|
||||
2 % Mode
|
||||
0 % Suppress FNQ inputs
|
||||
$fileOut7 % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 126 WRITE
|
||||
151.1
|
||||
151.2
|
||||
151.3
|
||||
P 126
|
||||
2 % Mode
|
||||
0 % Suppress FNQ inputs
|
||||
$fileOut2 % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 127 WRITE
|
||||
154.1
|
||||
154.2
|
||||
154.3
|
||||
P 127
|
||||
2 % Mode
|
||||
0 % Suppress FNQ inputs
|
||||
$fileOut3 % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 128 WRITE
|
||||
153.1
|
||||
153.2
|
||||
153.3
|
||||
P 128
|
||||
2 % Mode
|
||||
0 % Suppress FNQ inputs
|
||||
$fileOut5 % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 129 WRITE
|
||||
204.1
|
||||
204.2
|
||||
204.3
|
||||
204.4
|
||||
204.5
|
||||
15.1
|
||||
11.1
|
||||
190.1
|
||||
187.1
|
||||
160.1
|
||||
210.1
|
||||
210.2
|
||||
210.3
|
||||
210.4
|
||||
210.5
|
||||
83.1
|
||||
84.1
|
||||
191.1
|
||||
85.1
|
||||
16.1
|
||||
17.1
|
||||
14.1
|
||||
23.1
|
||||
164.1
|
||||
145.1
|
||||
P 129
|
||||
2 % Mode
|
||||
0 % Suppress FNQ inputs
|
||||
$fileOut1 % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 130 WRITE
|
||||
204.1
|
||||
204.2
|
||||
204.3
|
||||
152.1
|
||||
152.2
|
||||
P 130
|
||||
2 % Mode
|
||||
0 % Suppress FNQ inputs
|
||||
$fileOut10 % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 131 WRITE
|
||||
149.1
|
||||
149.2
|
||||
P 131
|
||||
2 % Mode
|
||||
0 % Suppress FNQ inputs
|
||||
$fileOut9 % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 132 WRITE
|
||||
157.1
|
||||
157.2
|
||||
P 132
|
||||
2 % Mode
|
||||
0 % Suppress FNQ inputs
|
||||
$fileOut8 % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 133 WRITE
|
||||
150.1
|
||||
150.2
|
||||
P 133
|
||||
2 % Mode
|
||||
0 % Suppress FNQ inputs
|
||||
$fileOut4 % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 134 WRITE
|
||||
155.1
|
||||
155.2
|
||||
P 134
|
||||
2 % Mode
|
||||
0 % Suppress FNQ inputs
|
||||
$fileOut6 % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 135 LT
|
||||
204.2
|
||||
35.1
|
||||
|
||||
B 136 LT
|
||||
210.1
|
||||
39.1
|
||||
|
||||
%B 137 SCREEN
|
||||
%176.1
|
||||
%P 137
|
||||
%'*' % Format
|
||||
%'Total CO2 Emissions from Electricity Grid (g)' % Headline
|
||||
|
||||
%B 138 SCREEN
|
||||
%178.1
|
||||
%P 138
|
||||
%'*' % Format
|
||||
%'Total Electricity Cost in a Year (CAD)' % Headline
|
||||
|
||||
%B 139 SCREEN
|
||||
%173.1
|
||||
%P 139
|
||||
%'*' % Format
|
||||
%'Total Cost of the Auxiliary Heater Fuel in a Year (CAD)' % Headline
|
||||
|
||||
%B 140 SCREEN
|
||||
%177.1
|
||||
%P 140
|
||||
%'*' % Format
|
||||
%'Total CO2 Emissions from Auxiliary Heater (g)' % Headline
|
||||
|
||||
%B 141 SCREEN
|
||||
%189.1
|
||||
%P 141
|
||||
%'*' % Format
|
||||
%'HP Seasonal COP' % Headline
|
||||
|
||||
%B 142 SCREEN
|
||||
%148.1
|
||||
%P 142
|
||||
%'*' % Format
|
||||
%'Maximum Number of HPs in Operation' % Headline
|
||||
|
||||
%B 143 SCREEN
|
||||
%174.1
|
||||
%P 143
|
||||
%'*' % Format
|
||||
%'Total Electricuty Demand of Heat Pumps in a year (kWh)' % Headline
|
||||
|
||||
%B 144 SCREEN
|
||||
%179.1
|
||||
%P 144
|
||||
%'*' % Format
|
||||
%'Total Fossil Fuel consumption in a Year (m3)' % Headline
|
||||
|
||||
B 145 READ
|
||||
P 145
|
||||
1 % Number of values to be read per record
|
||||
0 % Number of records to be skipped on the first call
|
||||
$HeatingDemand % File name
|
||||
'*' % Fortran format
|
||||
|
||||
B 146 DELAY
|
||||
15.1
|
||||
P 146
|
||||
0 % Initial value
|
||||
|
||||
B 147 DELAY
|
||||
210.5
|
||||
P 147
|
||||
0 % Initial value
|
||||
|
||||
B 148 MAXX
|
||||
198.1
|
||||
|
||||
B 149 CUMC
|
||||
204.3
|
||||
205.1
|
||||
|
||||
B 150 CUMC
|
||||
204.2
|
||||
205.1
|
||||
|
||||
B 151 CUMC
|
||||
204.3
|
||||
14.1
|
||||
23.1
|
||||
|
||||
B 152 CUMC
|
||||
204.4
|
||||
82.1
|
||||
|
||||
B 153 CUMC
|
||||
204.2
|
||||
14.1
|
||||
23.1
|
||||
|
||||
B 154 CUMC
|
||||
204.2
|
||||
16.1
|
||||
17.1
|
||||
|
||||
B 155 CUMC
|
||||
204.3
|
||||
82.1
|
||||
|
||||
B 156 CUMC
|
||||
204.3
|
||||
16.1
|
||||
17.1
|
||||
|
||||
B 157 CUMC
|
||||
204.2
|
||||
82.1
|
||||
|
||||
B 158 SUM
|
||||
58.1
|
||||
169.1
|
||||
|
||||
B 159 SUM
|
||||
170.1
|
||||
210.1
|
||||
|
||||
B 160 SUM
|
||||
18.1
|
||||
75.1
|
||||
|
||||
B 161 SUM
|
||||
210.5
|
||||
172.1
|
||||
|
||||
B 162 SUM
|
||||
12.1
|
||||
200.1
|
||||
|
||||
B 163 SUM
|
||||
135.1
|
||||
197.1
|
||||
|
||||
B 164 SUM
|
||||
31.1
|
||||
33.1
|
||||
|
||||
B 165 SUM
|
||||
29.1
|
||||
25.1
|
||||
30.1
|
||||
28.1
|
||||
13.1
|
||||
44.1
|
||||
|
||||
B 166 SUM
|
||||
51.1
|
||||
203.2
|
||||
|
||||
B 167 SUM
|
||||
10.1
|
||||
22.1
|
||||
32.1
|
||||
26.1
|
||||
21.1
|
||||
61.1
|
||||
|
||||
B 168 SUM
|
||||
73.1
|
||||
171.1
|
||||
|
||||
B 169 CHS
|
||||
210.4
|
||||
|
||||
B 170 CHS
|
||||
37.1
|
||||
|
||||
B 171 CHS
|
||||
210.1
|
||||
|
||||
B 172 CHS
|
||||
147.1
|
||||
|
||||
B 173 CUM
|
||||
17.1
|
||||
|
||||
B 174 CUM
|
||||
82.1
|
||||
|
||||
B 175 CUM
|
||||
15.1
|
||||
11.1
|
||||
|
||||
B 176 CUM
|
||||
14.1
|
||||
|
||||
B 177 CUM
|
||||
23.1
|
||||
|
||||
B 178 CUM
|
||||
16.1
|
||||
|
||||
B 179 CUM
|
||||
205.1
|
||||
|
||||
B 180 EXPG
|
||||
58.1
|
||||
55.1
|
||||
|
||||
B 181 EXPG
|
||||
203.2
|
||||
71.1
|
||||
|
||||
B 182 EXPG
|
||||
58.1
|
||||
48.1
|
||||
|
||||
B 183 EXPG
|
||||
203.2
|
||||
62.1
|
||||
|
||||
B 184 DIV
|
||||
11.1
|
||||
53.1
|
||||
|
||||
B 185 DIV
|
||||
67.1
|
||||
165.1
|
||||
|
||||
B 186 DIV
|
||||
11.1
|
||||
42.1
|
||||
|
||||
B 187 DIV
|
||||
206.1
|
||||
19.1
|
||||
|
||||
B 188 DIV
|
||||
207.1
|
||||
20.1
|
||||
|
||||
B 189 DIV
|
||||
175.1
|
||||
175.2
|
||||
|
||||
B 190 DIV
|
||||
15.1
|
||||
11.1
|
||||
|
||||
B 191 DIV
|
||||
80.1
|
||||
54.1
|
||||
|
||||
B 192 GE
|
||||
210.1
|
||||
45.1
|
||||
P 192
|
||||
0 % Error tolerance
|
||||
|
||||
B 193 GE
|
||||
210.1
|
||||
38.1
|
||||
P 193
|
||||
0 % Error tolerance
|
||||
|
||||
B 194 SOY
|
||||
204.1
|
||||
204.2
|
||||
204.3
|
||||
204.4
|
||||
204.5
|
||||
204.6
|
||||
|
||||
B 195 GT
|
||||
210.1
|
||||
59.1
|
||||
|
||||
B 196 GT
|
||||
146.1
|
||||
52.1
|
||||
|
||||
B 197 GT
|
||||
204.2
|
||||
41.1
|
||||
|
||||
B 198 INT
|
||||
185.1
|
||||
|
||||
B 199 MTM
|
||||
204.2
|
||||
P 199
|
||||
'Montreal' % Location
|
||||
|
||||
B 200 INV
|
||||
193.1
|
||||
|
||||
B 201 INV
|
||||
192.1
|
||||
|
||||
B 202 INV
|
||||
195.1
|
||||
|
||||
B 203 GENGT
|
||||
199.1
|
||||
199.3
|
||||
199.4
|
||||
199.5
|
||||
199.7
|
||||
199.8
|
||||
204.1
|
||||
204.2
|
||||
204.3
|
||||
204.4
|
||||
P 203
|
||||
45.5 % Latitude
|
||||
73.62 % Longitude
|
||||
5 % Time zone
|
||||
1 % Variance factor of the Gordon Reddy correlation
|
||||
0 % Year-to-year variability
|
||||
0.3 % Autocorrelation coefficient lag one
|
||||
0.171 % Autocorrelation coefficient lag two
|
||||
4711 % Initialisation of random number generator
|
||||
2 % Maximum allowed mean temperature deviation
|
||||
100 % Maximum number of iterations
|
||||
|
||||
B 204 CLOCK
|
||||
P 204
|
||||
$StartYear % Start year
|
||||
$StartMonth % Start month
|
||||
$StartDay % Start day
|
||||
$StartHour % Start hour
|
||||
$StartMinute % Start minute
|
||||
$StartSecond % Start second
|
||||
$EndYear % End year
|
||||
$EndMonth % End month
|
||||
$EndDay % End day
|
||||
$EndHour % End hour
|
||||
$EndMinute % End minute
|
||||
$EndSecond % End second
|
||||
5 % Increment
|
||||
'm' % Unit
|
||||
|
||||
B 205 GAIN
|
||||
81.1
|
||||
P 205
|
||||
300 % Gain factor g
|
||||
|
||||
B 206 GAIN
|
||||
15.1
|
||||
P 206
|
||||
1000 % Gain factor g
|
||||
|
||||
B 207 GAIN
|
||||
145.1
|
||||
P 207
|
||||
1000 % Gain factor g
|
||||
|
||||
B 210 TANKST
|
||||
58.1
|
||||
187.1
|
||||
164.1
|
||||
160.1
|
||||
166.1
|
||||
194.1
|
||||
P 210
|
||||
$TESCapacity % Tank volume
|
||||
4 % Number of temperature nodes
|
||||
$TESDiameter % Tank diameter
|
||||
$Cp % Specfic heat of fluid
|
||||
$Rhow % Fluid density
|
||||
0 % Overall heat-loss coefficient
|
||||
1 % Effective heat conductivity
|
||||
30 % Initial tank temperature
|
||||
|
0
exports/energy_systems/__init__.py
Normal file
0
exports/energy_systems/__init__.py
Normal file
216
exports/energy_systems/heat_pump_export.py
Normal file
216
exports/energy_systems/heat_pump_export.py
Normal file
|
@ -0,0 +1,216 @@
|
|||
"""
|
||||
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 os
|
||||
from typing import List, Tuple, Union, Dict
|
||||
import yaml
|
||||
from string import Template
|
||||
import pandas as pd
|
||||
|
||||
|
||||
class HeatPumpExport:
|
||||
"""
|
||||
Exports heat pump values as coefficients
|
||||
of some defined function
|
||||
"""
|
||||
|
||||
def __init__(self, base_path, city, output_path):
|
||||
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
|
||||
self._output_path = output_path
|
||||
|
||||
def run_insel(self, user_input: Dict, hp_model: str, data_type: str) -> 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_content = insel_template_handler.read()
|
||||
insel_template = Template(insel_template_content).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
|
||||
self._delete_existing_output_files()
|
||||
os.system('insel {}'.format(insel_file))
|
||||
# Writer headers to csv output files generated by insel
|
||||
self._write_insel_output_headers()
|
||||
# User output
|
||||
self._get_user_out_put()
|
||||
except IOError as err:
|
||||
print("I/O exception: {}".format(err))
|
||||
finally:
|
||||
insel_file_handler.close()
|
||||
insel_template_handler.close()
|
||||
|
||||
def _write_insel_output_headers(self):
|
||||
"""
|
||||
Write headers to the various csv file generated by insel
|
||||
:return:
|
||||
"""
|
||||
header_data = {
|
||||
self._input_data['fileOut1']: ['Year', ' Month', ' Day', 'Hour', 'Minute', 'HP Heat Output (kW)',
|
||||
'HP Electricity Consumption (kW)', 'HP COP', 'TES Charging Rate (kg/s)',
|
||||
'TES Discharging Rate (kg/s)', 'TES Node 1 Temperature', 'TES Node 2 Temperature',
|
||||
'TES Node 3 Temperature', 'TES Node 4 Temperature', 'TES Energy Content (J)',
|
||||
'TES Energy Content (kWh)', 'TES Energy Content Variation (kWh)',
|
||||
'Auxiliary Heater Fuel Flow Rate (kg/s)', 'Auxiliary Heater Energy Input (kW)',
|
||||
'HP Operational Cost (CAD)', 'Auxiliary Heater Operational Cost (CAD)',
|
||||
'Operational CO2 Emissions of HP (g)',
|
||||
'Operational CO2 Emissions of Auxiliary Heater (g)',
|
||||
'Return Temperature', 'Demand (kW)'],
|
||||
self._input_data['fileOut2']: ['Day', 'Operational Daily Emissions from Heat Pumps (g)',
|
||||
'Operational Daily Emissions from Auxiliary Heater (g)'],
|
||||
self._input_data['fileOut3']: ['Month', 'Monthly Operational Costs of Heat Pumps (CAD)',
|
||||
'Monthly Operational Costs of Auxiliary Heater (CAD)'],
|
||||
self._input_data['fileOut4']: ['Month', 'Monthly Fuel Consumption of Auxiliary Heater (m3)'],
|
||||
self._input_data['fileOut5']: ['Month', 'Operational Monthly Emissions from Heat Pumps (g)',
|
||||
'Operational Monthly Emissions from Auxiliary Heater (g)'],
|
||||
self._input_data['fileOut6']: ['Day', 'Daily HP Electricity Demand (kWh)'],
|
||||
self._input_data['fileOut7']: ['Day', 'Daily Operational Costs of Heat Pumps (CAD)',
|
||||
'Daily Operational Costs of Auxiliary Heater (CAD)'],
|
||||
self._input_data['fileOut8']: ['Month', 'Monthly HP Electricity Demand (kWh)'],
|
||||
self._input_data['fileOut9']: ['Day', 'Daily Fuel Consumption of Auxiliary Heater (m3)'],
|
||||
self._input_data['fileOut10']: ['Year', 'Month', 'Day', 'Hour', 'HP Electricity Demand (kWh)']
|
||||
}
|
||||
for file_path, header in header_data.items():
|
||||
file_path = file_path.strip("'")
|
||||
df = pd.read_csv(file_path, header=None, sep='\s+')
|
||||
df.to_csv(file_path, header=header)
|
||||
|
||||
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"] = f"'{str(self._demand_path)}'"
|
||||
self._input_data["fileOut1"] = f"'{str((self._base_path / 'heat_pumps/technical_performance.csv'))}'"
|
||||
self._input_data["fileOut2"] = f"'{str((self._base_path / 'heat_pumps/system_daily_emissions.csv'))}'"
|
||||
self._input_data["fileOut3"] = f"'{str((self._base_path / 'heat_pumps/monthly_operational_costs.csv'))}'"
|
||||
self._input_data["fileOut4"] = f"'{str((self._base_path / 'heat_pumps/monthly_fossil_fuel_consumptions.csv'))}'"
|
||||
self._input_data["fileOut5"] = f"'{str((self._base_path / 'heat_pumps/system_monthly_emissions.csv'))}'"
|
||||
self._input_data["fileOut6"] = f"'{str((self._base_path / 'heat_pumps/daily_hp_electricity_demand.csv'))}'"
|
||||
self._input_data["fileOut7"] = f"'{str((self._base_path / 'heat_pumps/daily_operational_costs.csv'))}'"
|
||||
self._input_data["fileOut8"] = f"'{str((self._base_path / 'heat_pumps/monthly_hp_electricity_demand.csv'))}'"
|
||||
self._input_data["fileOut9"] = f"'{str((self._base_path / 'heat_pumps/daily_fossil_fuel_consumption.csv'))}'"
|
||||
self._input_data["fileOut10"] = f"'{str((self._base_path / 'heat_pumps/hp_hourly_electricity_demand.csv'))}'"
|
||||
|
||||
def _delete_existing_output_files(self):
|
||||
"""
|
||||
Remove existing out files generated by insel before
|
||||
running insel
|
||||
:return:
|
||||
"""
|
||||
for key, file_path in self._input_data.items():
|
||||
if 'fileOut' in key:
|
||||
file_path = file_path.strip("'")
|
||||
try:
|
||||
os.remove(file_path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
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: List, comp_power_coff: List):
|
||||
"""
|
||||
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: str, 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
|
||||
|
||||
def _get_user_out_put(self):
|
||||
"""
|
||||
Extracts monthly electricity demand and fossil fuel consumption
|
||||
from output files generated by insel
|
||||
:return:
|
||||
"""
|
||||
|
||||
electricity_df = pd.read_csv(self._input_data['fileOut8'].strip("'")).iloc[:, 2]
|
||||
fossil_df = pd.read_csv(self._input_data['fileOut4'].strip("'")).iloc[:, 2]
|
||||
|
||||
data = [electricity_df, fossil_df]
|
||||
df = pd.concat(data, axis=1)
|
||||
df = df.append(df.agg(['sum']))
|
||||
s = pd.Series(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec", "Total"])
|
||||
df = df.set_index([s])
|
||||
df.to_csv(self._output_path)
|
||||
|
40
exports/energy_systems_factory.py
Normal file
40
exports/energy_systems_factory.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
"""
|
||||
EnergySystemsFactory exports energy systems into several formats
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from exports.energy_systems.heat_pump_export import HeatPumpExport
|
||||
|
||||
|
||||
class EnergySystemsExportFactory:
|
||||
"""
|
||||
Exports factory class for energy systems
|
||||
"""
|
||||
|
||||
def __init__(self, city, user_input, hp_model, output_path, data_type='heat', base_path=None):
|
||||
self._city = city
|
||||
if base_path is None:
|
||||
base_path = base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
|
||||
self._base_path = base_path
|
||||
self._user_input = user_input
|
||||
self._hp_model = hp_model
|
||||
self._data_type = data_type
|
||||
self._output_path = output_path
|
||||
|
||||
def _export_heat_pump(self):
|
||||
"""
|
||||
Exports heat pump performance data as coefficients
|
||||
of some objective function
|
||||
:return: None
|
||||
"""
|
||||
HeatPumpExport(self._base_path, self._city, self._output_path)\
|
||||
.run_insel(self._user_input, self._hp_model, self._data_type)
|
||||
|
||||
def export(self):
|
||||
"""
|
||||
Export the city given to the class using the given export type handler
|
||||
:return: None
|
||||
"""
|
||||
return getattr(self, '_export_heat_pump', lambda: None)()
|
|
@ -1,26 +1,143 @@
|
|||
"""
|
||||
XlsxHeatPumpParameters import the heat pump information
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2020 Project Author
|
||||
Copyright © 2020 Project Author Peter Yefi peteryefi@gmail.com
|
||||
Contributor Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
from typing import Dict
|
||||
from city_model_structure.energy_systems.heat_pump import HeatPump
|
||||
from city_model_structure.energy_system import EnergySystem
|
||||
from scipy.optimize import curve_fit
|
||||
import numpy as np
|
||||
from typing import List
|
||||
import itertools
|
||||
|
||||
|
||||
class XlsxHeatPumpParameters:
|
||||
"""
|
||||
XlsxHeatPumpParameters class
|
||||
"""
|
||||
|
||||
def __init__(self, city, base_path):
|
||||
self._city = city
|
||||
self._base_path = (base_path / 'heat_pumps/Air source.xlsx')
|
||||
self._base_path = (base_path / 'heat_pumps/Air Source.xlsx')
|
||||
|
||||
def _read_file(self):
|
||||
def _read_file(self) -> Dict:
|
||||
"""
|
||||
reads xlsx file containing the heat pump information
|
||||
into a dictionary
|
||||
:return : Dict
|
||||
"""
|
||||
xl_file = pd.ExcelFile(self._base_path)
|
||||
heat_pump_dfs = {sheet_name: xl_file.parse(sheet_name)
|
||||
for sheet_name in xl_file.sheet_names}
|
||||
|
||||
cooling_data = {}
|
||||
heating_data = {}
|
||||
|
||||
for sheet, dataframe in heat_pump_dfs.items():
|
||||
if sheet == "Summary":
|
||||
continue
|
||||
# Remove nan rows and columns and extract cooling and heating data
|
||||
# for each sheet
|
||||
df = heat_pump_dfs[sheet].dropna(axis=1, how='all')
|
||||
cooling_df = df.iloc[4:34, 0:8]
|
||||
heating_df = df.iloc[4:29, 8:20]
|
||||
|
||||
# extract the data into dictionaries each sheet is a key entry in the
|
||||
# dictionary
|
||||
cooling_data[sheet] = {}
|
||||
heating_data[sheet] = {}
|
||||
i = 0
|
||||
# for each sheet extract data for twout/Ta.RU temperatures. Thus, the twout
|
||||
# temp is the key for the values of pf,pa,qw data
|
||||
while i < 25:
|
||||
cooling_data[sheet][cooling_df.iloc[i][0]] = cooling_df.iloc[i + 1:i + 4, 2:8].values.tolist()
|
||||
heating_data[sheet][heating_df.iloc[i][0]] = heating_df.iloc[i + 1:i + 4, 2:8].values.tolist()
|
||||
i = i + 5
|
||||
# extract the last cooling data
|
||||
cooling_data[sheet][cooling_df.iloc[i][0]] = cooling_df.iloc[i + 1:i + 4, 2:8].values.tolist()
|
||||
return {"cooling": cooling_data, "heating": heating_data}
|
||||
|
||||
def enrich_city(self):
|
||||
"""
|
||||
Enriches the city with information from file
|
||||
"""
|
||||
heap_pump_data = self._read_file()
|
||||
for (k_cool, v_cool), (k_heat, v_heat) in \
|
||||
zip(heap_pump_data["cooling"].items(), heap_pump_data["heating"].items()):
|
||||
heat_pump = HeatPump()
|
||||
heat_pump.model = k_cool
|
||||
h_data = self._extract_heat_pump_data(v_heat)
|
||||
c_data = self._extract_heat_pump_data(v_cool)
|
||||
heat_pump.cooling_capacity = c_data[0]
|
||||
heat_pump.cooling_comp_power = c_data[1]
|
||||
heat_pump.cooling_capacity_coff = self._compute_coefficients(c_data[0], "cool")
|
||||
heat_pump.cooling_comp_power_coff = self._compute_coefficients(c_data[1], "cool")
|
||||
heat_pump.heating_capacity = h_data[0]
|
||||
heat_pump.heating_comp_power = h_data[1]
|
||||
heat_pump.heating_capacity_coff = self._compute_coefficients(h_data[0])
|
||||
heat_pump.heating_comp_power_coff = self._compute_coefficients(h_data[1])
|
||||
|
||||
energy_system = EnergySystem('{} capacity heat pump'.format(heat_pump.model), 0, [], None)
|
||||
energy_system.heat_pump = heat_pump
|
||||
self._city.add_city_object(energy_system)
|
||||
return self._city
|
||||
|
||||
def _extract_heat_pump_data(self, heat_pump_capacity_data: Dict) -> [List, List]:
|
||||
"""
|
||||
Fetches a list of metric based data for heat pump for various temperature,
|
||||
eg. cooling capacity data for 12 capacity heat pump
|
||||
for 6,7,8,9,10 and 11 degree celsius
|
||||
:param heat_pump_capacity_data: the heat pump capacity data from the
|
||||
which the metric specific data is fetched: {List}
|
||||
:return: List
|
||||
"""
|
||||
cooling_heating_capacity_data = []
|
||||
compressor_power_data = []
|
||||
for _, metric_data in heat_pump_capacity_data.items():
|
||||
cooling_heating_capacity_data.append(metric_data[0])
|
||||
compressor_power_data.append(metric_data[1])
|
||||
return [cooling_heating_capacity_data, compressor_power_data]
|
||||
|
||||
def _compute_coefficients(self, heat_pump_data: List, data_type="heat") -> List[float]:
|
||||
"""
|
||||
Compute heat output and electrical demand coefficients
|
||||
from heating and cooling performance data
|
||||
:param heat_pump_data: a list of heat pump data. eg. cooling capacity
|
||||
:param data_type: string to indicate if data is cooling performance data
|
||||
or heating performance data
|
||||
:return: Tuple[Dict, Dict]
|
||||
"""
|
||||
# Determine the recurrence of temperature values. 6 repetitions for
|
||||
# cooling performance and 5 repetition for heating performance
|
||||
temp_multiplier = 5 if data_type == "heat" else 6
|
||||
out_temp = [25, 30, 32, 35, 40, 45] * temp_multiplier
|
||||
|
||||
heat_x_values = np.repeat([-5, 0, 7, 10, 15], 6)
|
||||
cool_x_values = np.repeat([6, 7, 8, 9, 10, 11], 6)
|
||||
x_values = heat_x_values if data_type == "heat" else cool_x_values
|
||||
x_values = x_values.tolist()
|
||||
# convert list of lists to one list
|
||||
heat_pump_data = list(itertools.chain.from_iterable(heat_pump_data))
|
||||
|
||||
# Compute heat output coefficients
|
||||
popt, _ = curve_fit(self._objective_function, [x_values, out_temp], heat_pump_data)
|
||||
return popt.tolist()
|
||||
|
||||
def _objective_function(self, xdata: List, a1: float, a2: float, a3: float, a4: float, a5: float, a6: float) -> float:
|
||||
"""
|
||||
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:
|
||||
"""
|
||||
x, y = xdata
|
||||
return (a1 * x ** 2) + (a2 * x) + (a3 * x * y) + (a4 * y) + (a5 * y ** 2) + a6
|
||||
|
|
|
@ -11,6 +11,7 @@ class EnergySystemsFactory:
|
|||
"""
|
||||
EnergySystemsFactory class
|
||||
"""
|
||||
|
||||
def __init__(self, handler, city, base_path=None):
|
||||
if base_path is None:
|
||||
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
|
||||
|
@ -18,7 +19,7 @@ class EnergySystemsFactory:
|
|||
self._city = city
|
||||
self._base_path = base_path
|
||||
|
||||
def _xlsxheatpump(self):
|
||||
def _xlsx_heat_pump(self):
|
||||
"""
|
||||
Enrich the city by using xlsx heat pump information
|
||||
"""
|
||||
|
@ -30,4 +31,3 @@ class EnergySystemsFactory:
|
|||
:return: None
|
||||
"""
|
||||
getattr(self, self._handler, lambda: None)()
|
||||
|
||||
|
|
|
@ -9,7 +9,10 @@ geomeppy~=0.11.8
|
|||
pathlib~=1.0.1
|
||||
PyWavefront~=1.3.3
|
||||
xlrd~=2.0.1
|
||||
openpyxl~=3.0.7
|
||||
networkx~=2.5.1
|
||||
parseidf~=1.0.0
|
||||
ply~=3.11
|
||||
rhino3dm~=7.7.0
|
||||
scipy==1.7.1
|
||||
PyYAML==6.0
|
61
unittests/test_energy_systems_factory.py
Normal file
61
unittests/test_energy_systems_factory.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
"""
|
||||
Test EnergySystemsFactory and various heatpump models
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2021 Project Author Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
import pandas as pd
|
||||
from unittest import TestCase
|
||||
from imports.geometry_factory import GeometryFactory
|
||||
from imports.energy_systems_factory import EnergySystemsFactory
|
||||
from city_model_structure.energy_systems.heat_pump import HeatPump
|
||||
from exports.energy_systems_factory import EnergySystemsExportFactory
|
||||
import os
|
||||
|
||||
|
||||
class TestEnergySystemsFactory(TestCase):
|
||||
"""
|
||||
TestBuilding TestCase 1
|
||||
"""
|
||||
|
||||
def setUp(self) -> None:
|
||||
"""
|
||||
Test setup
|
||||
:return: None
|
||||
"""
|
||||
city_file = "../unittests/tests_data/C40_Final.gml"
|
||||
self._output_path = "../unittests/tests_data/user_output.csv"
|
||||
self._city = GeometryFactory('citygml', city_file).city
|
||||
EnergySystemsFactory('xlsx heat pump', self._city).enrich()
|
||||
|
||||
def test_heat_pump_import(self):
|
||||
self.assertIsNotNone(self._city.energy_systems, 'City has energy systems')
|
||||
self.assertIsInstance(self._city.energy_systems[0].heat_pump, HeatPump)
|
||||
self.assertEqual(self._city.energy_systems[0].heat_pump.model, '012')
|
||||
self.assertEqual(self._city.energy_systems[len(self._city.energy_systems) - 1].heat_pump.model, '140')
|
||||
|
||||
def test_heat_pump_export(self):
|
||||
# User defined paramenters
|
||||
user_input = {
|
||||
'StartYear': 2020,
|
||||
'EndYear': 2021,
|
||||
'MaximumHPEnergyInput': 8000,
|
||||
'HoursOfStorageAtMaxDemand': 1,
|
||||
'BuildingSuppTemp': 40,
|
||||
'TemperatureDifference': 15,
|
||||
'FuelLHV': 47100,
|
||||
'FuelPrice': 0.12,
|
||||
'FuelEF': 1887,
|
||||
'FuelDensity': 0.717,
|
||||
'HPSupTemp': 60
|
||||
}
|
||||
|
||||
EnergySystemsExportFactory(self._city, user_input, '012', self._output_path).export()
|
||||
df = pd.read_csv(self._output_path)
|
||||
self.assertEqual(df.shape, (13, 3))
|
||||
self.assertEqual(df.iloc[0, 1], 3045398.0)
|
||||
|
||||
def tearDown(self) -> None:
|
||||
try:
|
||||
os.remove(self._output_path)
|
||||
except OSError:
|
||||
pass
|
Loading…
Reference in New Issue
Block a user