Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
35c62b4808
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,3 +2,5 @@
|
||||||
/venv/
|
/venv/
|
||||||
.idea/
|
.idea/
|
||||||
/development_tests/
|
/development_tests/
|
||||||
|
/data/energy_systems/heat_pumps/*.csv
|
||||||
|
/data/energy_systems/heat_pumps/*.insel
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,240 +14,240 @@ from helpers.configuration_helper import ConfigurationHelper
|
||||||
|
|
||||||
|
|
||||||
class Polyhedron:
|
class Polyhedron:
|
||||||
"""
|
"""
|
||||||
Polyhedron class
|
Polyhedron class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, polygons):
|
def __init__(self, polygons):
|
||||||
self._polygons = polygons
|
self._polygons = polygons
|
||||||
self._polyhedron = None
|
self._polyhedron = None
|
||||||
self._triangulated_polyhedron = None
|
self._triangulated_polyhedron = None
|
||||||
self._volume = None
|
self._volume = None
|
||||||
self._faces = None
|
self._faces = None
|
||||||
self._vertices = None
|
self._vertices = None
|
||||||
self._trimesh = None
|
self._trimesh = None
|
||||||
self._centroid = None
|
self._centroid = None
|
||||||
self._max_z = None
|
self._max_z = None
|
||||||
self._max_y = None
|
self._max_y = None
|
||||||
self._max_x = None
|
self._max_x = None
|
||||||
self._min_z = None
|
self._min_z = None
|
||||||
self._min_y = None
|
self._min_y = None
|
||||||
self._min_x = None
|
self._min_x = None
|
||||||
|
|
||||||
def _position_of(self, point, face):
|
def _position_of(self, point, face):
|
||||||
"""
|
"""
|
||||||
position of a specific point in the list of points that define a face
|
position of a specific point in the list of points that define a face
|
||||||
:return: int
|
:return: int
|
||||||
"""
|
"""
|
||||||
vertices = self.vertices
|
vertices = self.vertices
|
||||||
for i in range(len(vertices)):
|
for i in range(len(vertices)):
|
||||||
# ensure not duplicated vertex
|
# ensure not duplicated vertex
|
||||||
power = 0
|
power = 0
|
||||||
vertex2 = vertices[i]
|
vertex2 = vertices[i]
|
||||||
for dimension in range(0, 3):
|
for dimension in range(0, 3):
|
||||||
power += math.pow(vertex2[dimension] - point[dimension], 2)
|
power += math.pow(vertex2[dimension] - point[dimension], 2)
|
||||||
distance = math.sqrt(power)
|
distance = math.sqrt(power)
|
||||||
if i not in face and distance == 0:
|
if i not in face and distance == 0:
|
||||||
return i
|
return i
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def vertices(self) -> np.ndarray:
|
def vertices(self) -> np.ndarray:
|
||||||
"""
|
"""
|
||||||
Get polyhedron vertices
|
Get polyhedron vertices
|
||||||
:return: np.ndarray(int)
|
:return: np.ndarray(int)
|
||||||
"""
|
"""
|
||||||
if self._vertices is None:
|
if self._vertices is None:
|
||||||
vertices, self._vertices = [], []
|
vertices, self._vertices = [], []
|
||||||
_ = [vertices.extend(s.coordinates) for s in self._polygons]
|
_ = [vertices.extend(s.coordinates) for s in self._polygons]
|
||||||
for vertex_1 in vertices:
|
for vertex_1 in vertices:
|
||||||
found = False
|
found = False
|
||||||
for vertex_2 in self._vertices:
|
for vertex_2 in self._vertices:
|
||||||
found = False
|
found = False
|
||||||
power = 0
|
power = 0
|
||||||
for dimension in range(0, 3):
|
for dimension in range(0, 3):
|
||||||
power += math.pow(vertex_2[dimension] - vertex_1[dimension], 2)
|
power += math.pow(vertex_2[dimension] - vertex_1[dimension], 2)
|
||||||
distance = math.sqrt(power)
|
distance = math.sqrt(power)
|
||||||
if distance == 0:
|
if distance == 0:
|
||||||
found = True
|
found = True
|
||||||
break
|
break
|
||||||
if not found:
|
if not found:
|
||||||
self._vertices.append(vertex_1)
|
self._vertices.append(vertex_1)
|
||||||
self._vertices = np.asarray(self._vertices)
|
self._vertices = np.asarray(self._vertices)
|
||||||
return self._vertices
|
return self._vertices
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def faces(self) -> List[List[int]]:
|
def faces(self) -> List[List[int]]:
|
||||||
"""
|
"""
|
||||||
Get polyhedron triangular faces
|
Get polyhedron triangular faces
|
||||||
:return: [face]
|
:return: [face]
|
||||||
"""
|
"""
|
||||||
if self._faces is None:
|
if self._faces is None:
|
||||||
self._faces = []
|
self._faces = []
|
||||||
|
|
||||||
for polygon in self._polygons:
|
for polygon in self._polygons:
|
||||||
|
|
||||||
face = []
|
face = []
|
||||||
points = polygon.coordinates
|
points = polygon.coordinates
|
||||||
if len(points) != 3:
|
if len(points) != 3:
|
||||||
sub_polygons = polygon.triangulate()
|
sub_polygons = polygon.triangulate()
|
||||||
# todo: I modified this! To be checked @Guille
|
# todo: I modified this! To be checked @Guille
|
||||||
if len(sub_polygons) >= 1:
|
if len(sub_polygons) >= 1:
|
||||||
for sub_polygon in sub_polygons:
|
for sub_polygon in sub_polygons:
|
||||||
face = []
|
face = []
|
||||||
points = sub_polygon.coordinates
|
points = sub_polygon.coordinates
|
||||||
for point in points:
|
for point in points:
|
||||||
face.append(self._position_of(point, face))
|
face.append(self._position_of(point, face))
|
||||||
self._faces.append(face)
|
self._faces.append(face)
|
||||||
else:
|
else:
|
||||||
for point in points:
|
for point in points:
|
||||||
face.append(self._position_of(point, face))
|
face.append(self._position_of(point, face))
|
||||||
self._faces.append(face)
|
self._faces.append(face)
|
||||||
return self._faces
|
return self._faces
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def trimesh(self) -> Union[Trimesh, None]:
|
def trimesh(self) -> Union[Trimesh, None]:
|
||||||
"""
|
"""
|
||||||
Get polyhedron trimesh
|
Get polyhedron trimesh
|
||||||
:return: Trimesh
|
:return: Trimesh
|
||||||
"""
|
"""
|
||||||
if self._trimesh is None:
|
if self._trimesh is None:
|
||||||
for face in self.faces:
|
for face in self.faces:
|
||||||
if len(face) != 3:
|
if len(face) != 3:
|
||||||
sys.stderr.write('Not able to generate trimesh\n')
|
sys.stderr.write('Not able to generate trimesh\n')
|
||||||
return None
|
return None
|
||||||
self._trimesh = Trimesh(vertices=self.vertices, faces=self.faces)
|
self._trimesh = Trimesh(vertices=self.vertices, faces=self.faces)
|
||||||
return self._trimesh
|
return self._trimesh
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volume(self):
|
def volume(self):
|
||||||
"""
|
"""
|
||||||
Get polyhedron volume in cubic meters
|
Get polyhedron volume in cubic meters
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
if self._volume is None:
|
if self._volume is None:
|
||||||
if self.trimesh is None:
|
if self.trimesh is None:
|
||||||
self._volume = np.inf
|
self._volume = np.inf
|
||||||
elif not self.trimesh.is_volume:
|
elif not self.trimesh.is_volume:
|
||||||
self._volume = np.inf
|
self._volume = np.inf
|
||||||
else:
|
else:
|
||||||
self._volume = self.trimesh.volume
|
self._volume = self.trimesh.volume
|
||||||
return self._volume
|
return self._volume
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_z(self):
|
def max_z(self):
|
||||||
"""
|
"""
|
||||||
Get polyhedron maximal z value in meters
|
Get polyhedron maximal z value in meters
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
if self._max_z is None:
|
if self._max_z is None:
|
||||||
self._max_z = ConfigurationHelper().min_coordinate
|
self._max_z = ConfigurationHelper().min_coordinate
|
||||||
for polygon in self._polygons:
|
for polygon in self._polygons:
|
||||||
for point in polygon.coordinates:
|
for point in polygon.coordinates:
|
||||||
self._max_z = max(self._max_z, point[2])
|
self._max_z = max(self._max_z, point[2])
|
||||||
return self._max_z
|
return self._max_z
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_y(self):
|
def max_y(self):
|
||||||
"""
|
"""
|
||||||
Get polyhedron maximal y value in meters
|
Get polyhedron maximal y value in meters
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
if self._max_y is None:
|
if self._max_y is None:
|
||||||
self._max_y = ConfigurationHelper().min_coordinate
|
self._max_y = ConfigurationHelper().min_coordinate
|
||||||
for polygon in self._polygons:
|
for polygon in self._polygons:
|
||||||
for point in polygon.coordinates:
|
for point in polygon.coordinates:
|
||||||
if self._max_y < point[1]:
|
if self._max_y < point[1]:
|
||||||
self._max_y = point[1]
|
self._max_y = point[1]
|
||||||
return self._max_y
|
return self._max_y
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_x(self):
|
def max_x(self):
|
||||||
"""
|
"""
|
||||||
Get polyhedron maximal x value in meters
|
Get polyhedron maximal x value in meters
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
if self._max_x is None:
|
if self._max_x is None:
|
||||||
self._max_x = ConfigurationHelper().min_coordinate
|
self._max_x = ConfigurationHelper().min_coordinate
|
||||||
for polygon in self._polygons:
|
for polygon in self._polygons:
|
||||||
for point in polygon.coordinates:
|
for point in polygon.coordinates:
|
||||||
self._max_x = max(self._max_x, point[0])
|
self._max_x = max(self._max_x, point[0])
|
||||||
return self._max_x
|
return self._max_x
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_z(self):
|
def min_z(self):
|
||||||
"""
|
"""
|
||||||
Get polyhedron minimal z value in meters
|
Get polyhedron minimal z value in meters
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
if self._min_z is None:
|
if self._min_z is None:
|
||||||
self._min_z = self.max_z
|
self._min_z = self.max_z
|
||||||
for polygon in self._polygons:
|
for polygon in self._polygons:
|
||||||
for point in polygon.coordinates:
|
for point in polygon.coordinates:
|
||||||
if self._min_z > point[2]:
|
if self._min_z > point[2]:
|
||||||
self._min_z = point[2]
|
self._min_z = point[2]
|
||||||
return self._min_z
|
return self._min_z
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_y(self):
|
def min_y(self):
|
||||||
"""
|
"""
|
||||||
Get polyhedron minimal y value in meters
|
Get polyhedron minimal y value in meters
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
if self._min_y is None:
|
if self._min_y is None:
|
||||||
self._min_y = self.max_y
|
self._min_y = self.max_y
|
||||||
for polygon in self._polygons:
|
for polygon in self._polygons:
|
||||||
for point in polygon.coordinates:
|
for point in polygon.coordinates:
|
||||||
if self._min_y > point[1]:
|
if self._min_y > point[1]:
|
||||||
self._min_y = point[1]
|
self._min_y = point[1]
|
||||||
return self._min_y
|
return self._min_y
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_x(self):
|
def min_x(self):
|
||||||
"""
|
"""
|
||||||
Get polyhedron minimal x value in meters
|
Get polyhedron minimal x value in meters
|
||||||
:return: float
|
:return: float
|
||||||
"""
|
"""
|
||||||
if self._min_x is None:
|
if self._min_x is None:
|
||||||
self._min_x = self.max_x
|
self._min_x = self.max_x
|
||||||
for polygon in self._polygons:
|
for polygon in self._polygons:
|
||||||
for point in polygon.coordinates:
|
for point in polygon.coordinates:
|
||||||
if self._min_x > point[0]:
|
if self._min_x > point[0]:
|
||||||
self._min_x = point[0]
|
self._min_x = point[0]
|
||||||
return self._min_x
|
return self._min_x
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def centroid(self) -> Union[None, List[float]]:
|
def centroid(self) -> Union[None, List[float]]:
|
||||||
"""
|
"""
|
||||||
Get polyhedron centroid
|
Get polyhedron centroid
|
||||||
:return: [x,y,z]
|
:return: [x,y,z]
|
||||||
"""
|
"""
|
||||||
if self._centroid is None:
|
if self._centroid is None:
|
||||||
trimesh = self.trimesh
|
trimesh = self.trimesh
|
||||||
if trimesh is None:
|
if trimesh is None:
|
||||||
return None
|
return None
|
||||||
self._centroid = self.trimesh.centroid
|
self._centroid = self.trimesh.centroid
|
||||||
return self._centroid
|
return self._centroid
|
||||||
|
|
||||||
def stl_export(self, full_path):
|
def stl_export(self, full_path):
|
||||||
"""
|
"""
|
||||||
Export the polyhedron to stl given file
|
Export the polyhedron to stl given file
|
||||||
:param full_path: str
|
:param full_path: str
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
self.trimesh.export(full_path, 'stl_ascii')
|
self.trimesh.export(full_path, 'stl_ascii')
|
||||||
|
|
||||||
def obj_export(self, full_path):
|
def obj_export(self, full_path):
|
||||||
"""
|
"""
|
||||||
Export the polyhedron to obj given file
|
Export the polyhedron to obj given file
|
||||||
:param full_path: str
|
:param full_path: str
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
self.trimesh.export(full_path, 'obj')
|
self.trimesh.export(full_path, 'obj')
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
"""
|
"""
|
||||||
Auxiliary function to render the polyhedron
|
Auxiliary function to render the polyhedron
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
self.trimesh.show()
|
self.trimesh.show()
|
||||||
|
|
|
@ -9,130 +9,131 @@ from typing import Union, List
|
||||||
|
|
||||||
|
|
||||||
class Schedule:
|
class Schedule:
|
||||||
"""
|
"""
|
||||||
Schedule class
|
Schedule class
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
|
||||||
self._id = None
|
|
||||||
self._type = None
|
|
||||||
self._values = None
|
|
||||||
self._data_type = None
|
|
||||||
self._time_step = None
|
|
||||||
self._time_range = None
|
|
||||||
self._day_types = None
|
|
||||||
|
|
||||||
@property
|
def __init__(self):
|
||||||
def id(self):
|
self._id = None
|
||||||
"""
|
self._type = None
|
||||||
|
self._values = None
|
||||||
|
self._data_type = None
|
||||||
|
self._time_step = None
|
||||||
|
self._time_range = None
|
||||||
|
self._day_types = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self):
|
||||||
|
"""
|
||||||
Get schedule id, an universally unique identifier randomly generated
|
Get schedule id, an universally unique identifier randomly generated
|
||||||
:return: str
|
:return: str
|
||||||
"""
|
"""
|
||||||
if self._id is None:
|
if self._id is None:
|
||||||
self._id = uuid.uuid4()
|
self._id = uuid.uuid4()
|
||||||
return self._id
|
return self._id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self) -> Union[None, str]:
|
def type(self) -> Union[None, str]:
|
||||||
"""
|
"""
|
||||||
Get schedule type
|
Get schedule type
|
||||||
:return: None or str
|
:return: None or str
|
||||||
"""
|
"""
|
||||||
return self._type
|
return self._type
|
||||||
|
|
||||||
@type.setter
|
@type.setter
|
||||||
def type(self, value):
|
def type(self, value):
|
||||||
"""
|
"""
|
||||||
Set schedule type
|
Set schedule type
|
||||||
:param: str
|
:param: str
|
||||||
"""
|
"""
|
||||||
if value is not None:
|
if value is not None:
|
||||||
self._type = str(value)
|
self._type = str(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def values(self):
|
def values(self):
|
||||||
"""
|
"""
|
||||||
Get schedule values
|
Get schedule values
|
||||||
:return: [Any]
|
:return: [Any]
|
||||||
"""
|
"""
|
||||||
return self._values
|
return self._values
|
||||||
|
|
||||||
@values.setter
|
@values.setter
|
||||||
def values(self, value):
|
def values(self, value):
|
||||||
"""
|
"""
|
||||||
Set schedule values
|
Set schedule values
|
||||||
:param: [Any]
|
:param: [Any]
|
||||||
"""
|
"""
|
||||||
self._values = value
|
self._values = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def data_type(self) -> Union[None, str]:
|
def data_type(self) -> Union[None, str]:
|
||||||
"""
|
"""
|
||||||
Get schedule data type from:
|
Get schedule data type from:
|
||||||
['any_number', 'fraction', 'on_off', 'temperature', 'humidity', 'control_type']
|
['any_number', 'fraction', 'on_off', 'temperature', 'humidity', 'control_type']
|
||||||
:return: None or str
|
:return: None or str
|
||||||
"""
|
"""
|
||||||
return self._data_type
|
return self._data_type
|
||||||
|
|
||||||
@data_type.setter
|
@data_type.setter
|
||||||
def data_type(self, value):
|
def data_type(self, value):
|
||||||
"""
|
"""
|
||||||
Set schedule data type
|
Set schedule data type
|
||||||
:param: str
|
:param: str
|
||||||
"""
|
"""
|
||||||
if value is not None:
|
if value is not None:
|
||||||
self._data_type = str(value)
|
self._data_type = str(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def time_step(self) -> Union[None, str]:
|
def time_step(self) -> Union[None, str]:
|
||||||
"""
|
"""
|
||||||
Get schedule time step from:
|
Get schedule time step from:
|
||||||
['second', 'minute', 'hour', 'day', 'week', 'month']
|
['second', 'minute', 'hour', 'day', 'week', 'month']
|
||||||
:return: None or str
|
:return: None or str
|
||||||
"""
|
"""
|
||||||
return self._time_step
|
return self._time_step
|
||||||
|
|
||||||
@time_step.setter
|
@time_step.setter
|
||||||
def time_step(self, value):
|
def time_step(self, value):
|
||||||
"""
|
"""
|
||||||
Set schedule time step
|
Set schedule time step
|
||||||
:param: str
|
:param: str
|
||||||
"""
|
"""
|
||||||
if value is not None:
|
if value is not None:
|
||||||
self._time_step = str(value)
|
self._time_step = str(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def time_range(self) -> Union[None, str]:
|
def time_range(self) -> Union[None, str]:
|
||||||
"""
|
"""
|
||||||
Get schedule time range from:
|
Get schedule time range from:
|
||||||
['minute', 'hour', 'day', 'week', 'month', 'year']
|
['minute', 'hour', 'day', 'week', 'month', 'year']
|
||||||
:return: None or str
|
:return: None or str
|
||||||
"""
|
"""
|
||||||
return self._time_range
|
return self._time_range
|
||||||
|
|
||||||
@time_range.setter
|
@time_range.setter
|
||||||
def time_range(self, value):
|
def time_range(self, value):
|
||||||
"""
|
"""
|
||||||
Set schedule time range
|
Set schedule time range
|
||||||
:param: str
|
:param: str
|
||||||
"""
|
"""
|
||||||
if value is not None:
|
if value is not None:
|
||||||
self._time_range = str(value)
|
self._time_range = str(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def day_types(self) -> Union[None, List[str]]:
|
def day_types(self) -> Union[None, List[str]]:
|
||||||
"""
|
"""
|
||||||
Get schedule day types, as many as needed from:
|
Get schedule day types, as many as needed from:
|
||||||
['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'holiday', 'winter_design_day',
|
['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'holiday', 'winter_design_day',
|
||||||
'summer_design_day']
|
'summer_design_day']
|
||||||
:return: None or [str]
|
:return: None or [str]
|
||||||
"""
|
"""
|
||||||
return self._day_types
|
return self._day_types
|
||||||
|
|
||||||
@day_types.setter
|
@day_types.setter
|
||||||
def day_types(self, value):
|
def day_types(self, value):
|
||||||
"""
|
"""
|
||||||
Set schedule day types
|
Set schedule day types
|
||||||
:param: [str]
|
:param: [str]
|
||||||
"""
|
"""
|
||||||
if value is not None:
|
if value is not None:
|
||||||
self._day_types = [str(i) for i in value]
|
self._day_types = [str(i) for i in value]
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
City module
|
City module
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
Copyright © 2020 Project Author Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||||
|
Contributor Peter Yefi peteryefi@gmail.com
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import sys
|
import sys
|
||||||
|
@ -21,6 +22,7 @@ from city_model_structure.subway_entrance import SubwayEntrance
|
||||||
from city_model_structure.fuel import Fuel
|
from city_model_structure.fuel import Fuel
|
||||||
from helpers.geometry_helper import GeometryHelper
|
from helpers.geometry_helper import GeometryHelper
|
||||||
from helpers.location import Location
|
from helpers.location import Location
|
||||||
|
from city_model_structure.energy_system import EnergySystem
|
||||||
|
|
||||||
|
|
||||||
class City:
|
class City:
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
"""
|
"""
|
||||||
EnergySystem module
|
EnergySystem module
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
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
|
from city_model_structure.city_object import CityObject
|
||||||
|
@ -12,11 +13,33 @@ class EnergySystem(CityObject):
|
||||||
"""
|
"""
|
||||||
EnergySystem(CityObject) class
|
EnergySystem(CityObject) class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, lod, surfaces, city_lower_corner):
|
def __init__(self, name, lod, surfaces, city_lower_corner):
|
||||||
super().__init__(name, lod, surfaces, city_lower_corner)
|
super().__init__(name, lod, surfaces, city_lower_corner)
|
||||||
self._heat_pump = None
|
self._heat_pump = None
|
||||||
|
self._type = 'energy_system'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def heat_pump(self) -> HeatPump:
|
def heat_pump(self) -> HeatPump:
|
||||||
|
"""
|
||||||
|
Heat pump energy system
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
return self._heat_pump
|
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
|
heat_pump module defines a heat pump
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||||
Copyright © 2020 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 typing import Union
|
from typing import List
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
|
||||||
class HeatPump:
|
class HeatPump:
|
||||||
"""
|
"""
|
||||||
HeatPump class
|
HeatPump class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._model = None
|
self._model = None
|
||||||
self._cooling_pf = None
|
self._cooling_capacity = None
|
||||||
self._cooling_pa = None
|
self._cooling_comp_power = None
|
||||||
self._cooling_qw = None
|
self._cooling_capacity_coff = None
|
||||||
self._heating_pf = None
|
self._cooling_comp_power_coff = None
|
||||||
self._heating_pa = None
|
self._heating_capacity = None
|
||||||
self._heating_qw = None
|
self._heating_comp_power = None
|
||||||
|
self._heating_capacity_coff = None
|
||||||
|
self._heating_comp_power_coff = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def model(self):
|
def model(self) -> str:
|
||||||
"""
|
"""
|
||||||
Get model name
|
Get model name
|
||||||
:return: str
|
:return: str
|
||||||
"""
|
"""
|
||||||
return self._model
|
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
|
@property
|
||||||
def cooling_pf(self):
|
def cooling_capacity(self) -> List[float]:
|
||||||
"""
|
"""
|
||||||
Get cooling capacity in kW
|
Get cooling capacity in kW
|
||||||
:return: [[float]]
|
:return: [[float]]
|
||||||
"""
|
"""
|
||||||
return self._cooling_pf
|
return self._cooling_capacity
|
||||||
|
|
||||||
@cooling_pf.setter
|
@cooling_capacity.setter
|
||||||
def cooling_pf(self, value):
|
def cooling_capacity(self, value):
|
||||||
"""
|
"""
|
||||||
Set cooling capacity in kW
|
Set cooling capacity in kW
|
||||||
:param value: [[float]]
|
:param value: [[float]]
|
||||||
"""
|
"""
|
||||||
if self._cooling_pf is None:
|
if self._cooling_capacity is None:
|
||||||
self._cooling_pf = value
|
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
|
XlsxHeatPumpParameters import the heat pump information
|
||||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
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
|
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:
|
class XlsxHeatPumpParameters:
|
||||||
"""
|
"""
|
||||||
XlsxHeatPumpParameters class
|
XlsxHeatPumpParameters class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, city, base_path):
|
def __init__(self, city, base_path):
|
||||||
self._city = city
|
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
|
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):
|
def enrich_city(self):
|
||||||
"""
|
"""
|
||||||
Enriches the city with information from file
|
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
|
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
|
EnergySystemsFactory class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, handler, city, base_path=None):
|
def __init__(self, handler, city, base_path=None):
|
||||||
if base_path is None:
|
if base_path is None:
|
||||||
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
|
base_path = Path(Path(__file__).parent.parent / 'data/energy_systems')
|
||||||
|
@ -18,7 +19,7 @@ class EnergySystemsFactory:
|
||||||
self._city = city
|
self._city = city
|
||||||
self._base_path = base_path
|
self._base_path = base_path
|
||||||
|
|
||||||
def _xlsxheatpump(self):
|
def _xlsx_heat_pump(self):
|
||||||
"""
|
"""
|
||||||
Enrich the city by using xlsx heat pump information
|
Enrich the city by using xlsx heat pump information
|
||||||
"""
|
"""
|
||||||
|
@ -30,4 +31,3 @@ class EnergySystemsFactory:
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
getattr(self, self._handler, lambda: None)()
|
getattr(self, self._handler, lambda: None)()
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,10 @@ geomeppy~=0.11.8
|
||||||
pathlib~=1.0.1
|
pathlib~=1.0.1
|
||||||
PyWavefront~=1.3.3
|
PyWavefront~=1.3.3
|
||||||
xlrd~=2.0.1
|
xlrd~=2.0.1
|
||||||
|
openpyxl~=3.0.7
|
||||||
networkx~=2.5.1
|
networkx~=2.5.1
|
||||||
parseidf~=1.0.0
|
parseidf~=1.0.0
|
||||||
ply~=3.11
|
ply~=3.11
|
||||||
rhino3dm~=7.7.0
|
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