Integrate Peter's head pump branch into master

This commit is contained in:
Guille Gutierrez 2021-11-15 09:47:09 -05:00
commit eeff2eec18
17 changed files with 107328 additions and 756 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@
/venv/ /venv/
.idea/ .idea/
/development_tests/ /development_tests/
/data/energy_systems/heat_pumps/*.csv
/data/energy_systems/heat_pumps/*.insel

View File

@ -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 Copyright © 2020 Project Author Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
""" """
from __future__ import annotations from __future__ import annotations
import math import math
import sys import sys
@ -242,25 +241,30 @@ class Polygon:
if self._is_ear(ear, rest_points): if self._is_ear(ear, rest_points):
ears.append(ear) ears.append(ear)
point_to_remove = concave_points[i] 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) total_points_list.remove(point_to_remove)
concave_points.remove(point_to_remove) concave_points.remove(point_to_remove)
# Was any of the adjacent points convex? -> check if changed status to concave # Was any of the adjacent points convex? -> check if changed status to concave
for convex_point in convex_points: for convex_point in convex_points:
if convex_point == previous_point_in_list: 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, convex_point,
total_points_list, total_points_list,
concave_points, convex_points, concave_points,
convex_points,
previous_point_in_list) previous_point_in_list)
if end_loop: if end_loop:
break break
continue continue
if convex_point == next_point_in_list: 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, convex_point,
total_points_list, total_points_list,
concave_points, convex_points, concave_points,
convex_points,
next_point_in_list) next_point_in_list)
if end_loop: if end_loop:
break break
@ -547,7 +551,8 @@ class Polygon:
def _edge_in_edges_list(edge, edges_list): def _edge_in_edges_list(edge, edges_list):
for edge_element in 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 \ 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): (edge_element[1].distance_to_point(edge[0]) == 0 and edge_element[0].distance_to_point(
edge[1]) == 0):
return True return True
return False return False
@ -571,8 +576,10 @@ class Polygon:
def _remove_from_list(edge, edges_list): def _remove_from_list(edge, edges_list):
new_list = [] new_list = []
for edge_element in edges_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 if not ((edge_element[0].distance_to_point(edge[0]) == 0 and edge_element[1].distance_to_point(
(edge_element[1].distance_to_point(edge[0]) == 0 and edge_element[0].distance_to_point(edge[1]) == 0)): 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) new_list.append(edge_element)
return new_list return new_list

View File

@ -12,6 +12,7 @@ class Schedule:
""" """
Schedule class Schedule class
""" """
def __init__(self): def __init__(self):
self._id = None self._id = None
self._type = None self._type = None

View File

@ -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:

View File

@ -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

View File

@ -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

View 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

File diff suppressed because it is too large Load Diff

View 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

View File

View 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)

View 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)()

View File

@ -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

View File

@ -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)()

View File

@ -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

View 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