honeybee-energy 1.116.106__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- honeybee_energy/__init__.py +24 -0
- honeybee_energy/__main__.py +4 -0
- honeybee_energy/_extend_honeybee.py +145 -0
- honeybee_energy/altnumber.py +21 -0
- honeybee_energy/baseline/__init__.py +2 -0
- honeybee_energy/baseline/create.py +608 -0
- honeybee_energy/baseline/data/__init__.py +1 -0
- honeybee_energy/baseline/data/constructions.csv +64 -0
- honeybee_energy/baseline/data/fen_ratios.csv +15 -0
- honeybee_energy/baseline/data/lpd_building.csv +21 -0
- honeybee_energy/baseline/data/pci_2016.csv +22 -0
- honeybee_energy/baseline/data/pci_2019.csv +22 -0
- honeybee_energy/baseline/data/pci_2022.csv +22 -0
- honeybee_energy/baseline/data/shw.csv +21 -0
- honeybee_energy/baseline/pci.py +512 -0
- honeybee_energy/baseline/result.py +371 -0
- honeybee_energy/boundarycondition.py +128 -0
- honeybee_energy/cli/__init__.py +69 -0
- honeybee_energy/cli/baseline.py +475 -0
- honeybee_energy/cli/edit.py +327 -0
- honeybee_energy/cli/lib.py +1154 -0
- honeybee_energy/cli/result.py +810 -0
- honeybee_energy/cli/setconfig.py +124 -0
- honeybee_energy/cli/settings.py +569 -0
- honeybee_energy/cli/simulate.py +380 -0
- honeybee_energy/cli/translate.py +1714 -0
- honeybee_energy/cli/validate.py +224 -0
- honeybee_energy/config.json +11 -0
- honeybee_energy/config.py +842 -0
- honeybee_energy/construction/__init__.py +1 -0
- honeybee_energy/construction/_base.py +374 -0
- honeybee_energy/construction/air.py +325 -0
- honeybee_energy/construction/dictutil.py +89 -0
- honeybee_energy/construction/dynamic.py +607 -0
- honeybee_energy/construction/opaque.py +460 -0
- honeybee_energy/construction/shade.py +319 -0
- honeybee_energy/construction/window.py +1096 -0
- honeybee_energy/construction/windowshade.py +847 -0
- honeybee_energy/constructionset.py +1655 -0
- honeybee_energy/dictutil.py +56 -0
- honeybee_energy/generator/__init__.py +5 -0
- honeybee_energy/generator/loadcenter.py +204 -0
- honeybee_energy/generator/pv.py +535 -0
- honeybee_energy/hvac/__init__.py +21 -0
- honeybee_energy/hvac/_base.py +124 -0
- honeybee_energy/hvac/_template.py +270 -0
- honeybee_energy/hvac/allair/__init__.py +22 -0
- honeybee_energy/hvac/allair/_base.py +349 -0
- honeybee_energy/hvac/allair/furnace.py +168 -0
- honeybee_energy/hvac/allair/psz.py +131 -0
- honeybee_energy/hvac/allair/ptac.py +163 -0
- honeybee_energy/hvac/allair/pvav.py +109 -0
- honeybee_energy/hvac/allair/vav.py +128 -0
- honeybee_energy/hvac/detailed.py +337 -0
- honeybee_energy/hvac/doas/__init__.py +28 -0
- honeybee_energy/hvac/doas/_base.py +345 -0
- honeybee_energy/hvac/doas/fcu.py +127 -0
- honeybee_energy/hvac/doas/radiant.py +329 -0
- honeybee_energy/hvac/doas/vrf.py +81 -0
- honeybee_energy/hvac/doas/wshp.py +91 -0
- honeybee_energy/hvac/heatcool/__init__.py +23 -0
- honeybee_energy/hvac/heatcool/_base.py +177 -0
- honeybee_energy/hvac/heatcool/baseboard.py +61 -0
- honeybee_energy/hvac/heatcool/evapcool.py +72 -0
- honeybee_energy/hvac/heatcool/fcu.py +92 -0
- honeybee_energy/hvac/heatcool/gasunit.py +53 -0
- honeybee_energy/hvac/heatcool/radiant.py +269 -0
- honeybee_energy/hvac/heatcool/residential.py +77 -0
- honeybee_energy/hvac/heatcool/vrf.py +54 -0
- honeybee_energy/hvac/heatcool/windowac.py +70 -0
- honeybee_energy/hvac/heatcool/wshp.py +62 -0
- honeybee_energy/hvac/idealair.py +699 -0
- honeybee_energy/internalmass.py +310 -0
- honeybee_energy/lib/__init__.py +1 -0
- honeybee_energy/lib/_loadconstructions.py +194 -0
- honeybee_energy/lib/_loadconstructionsets.py +117 -0
- honeybee_energy/lib/_loadmaterials.py +83 -0
- honeybee_energy/lib/_loadprogramtypes.py +125 -0
- honeybee_energy/lib/_loadschedules.py +87 -0
- honeybee_energy/lib/_loadtypelimits.py +64 -0
- honeybee_energy/lib/constructions.py +207 -0
- honeybee_energy/lib/constructionsets.py +95 -0
- honeybee_energy/lib/materials.py +67 -0
- honeybee_energy/lib/programtypes.py +125 -0
- honeybee_energy/lib/schedules.py +61 -0
- honeybee_energy/lib/scheduletypelimits.py +31 -0
- honeybee_energy/load/__init__.py +1 -0
- honeybee_energy/load/_base.py +190 -0
- honeybee_energy/load/daylight.py +397 -0
- honeybee_energy/load/dictutil.py +47 -0
- honeybee_energy/load/equipment.py +771 -0
- honeybee_energy/load/hotwater.py +543 -0
- honeybee_energy/load/infiltration.py +460 -0
- honeybee_energy/load/lighting.py +480 -0
- honeybee_energy/load/people.py +497 -0
- honeybee_energy/load/process.py +472 -0
- honeybee_energy/load/setpoint.py +816 -0
- honeybee_energy/load/ventilation.py +550 -0
- honeybee_energy/material/__init__.py +1 -0
- honeybee_energy/material/_base.py +166 -0
- honeybee_energy/material/dictutil.py +59 -0
- honeybee_energy/material/frame.py +367 -0
- honeybee_energy/material/gas.py +1087 -0
- honeybee_energy/material/glazing.py +854 -0
- honeybee_energy/material/opaque.py +1351 -0
- honeybee_energy/material/shade.py +1360 -0
- honeybee_energy/measure.py +472 -0
- honeybee_energy/programtype.py +723 -0
- honeybee_energy/properties/__init__.py +1 -0
- honeybee_energy/properties/aperture.py +333 -0
- honeybee_energy/properties/door.py +342 -0
- honeybee_energy/properties/extension.py +244 -0
- honeybee_energy/properties/face.py +274 -0
- honeybee_energy/properties/model.py +2640 -0
- honeybee_energy/properties/room.py +1747 -0
- honeybee_energy/properties/shade.py +314 -0
- honeybee_energy/properties/shademesh.py +262 -0
- honeybee_energy/reader.py +48 -0
- honeybee_energy/result/__init__.py +1 -0
- honeybee_energy/result/colorobj.py +648 -0
- honeybee_energy/result/emissions.py +290 -0
- honeybee_energy/result/err.py +101 -0
- honeybee_energy/result/eui.py +100 -0
- honeybee_energy/result/generation.py +160 -0
- honeybee_energy/result/loadbalance.py +890 -0
- honeybee_energy/result/match.py +202 -0
- honeybee_energy/result/osw.py +90 -0
- honeybee_energy/result/rdd.py +59 -0
- honeybee_energy/result/zsz.py +190 -0
- honeybee_energy/run.py +1577 -0
- honeybee_energy/schedule/__init__.py +1 -0
- honeybee_energy/schedule/day.py +626 -0
- honeybee_energy/schedule/dictutil.py +59 -0
- honeybee_energy/schedule/fixedinterval.py +1012 -0
- honeybee_energy/schedule/rule.py +619 -0
- honeybee_energy/schedule/ruleset.py +1867 -0
- honeybee_energy/schedule/typelimit.py +310 -0
- honeybee_energy/shw.py +315 -0
- honeybee_energy/simulation/__init__.py +1 -0
- honeybee_energy/simulation/control.py +214 -0
- honeybee_energy/simulation/daylightsaving.py +185 -0
- honeybee_energy/simulation/dictutil.py +51 -0
- honeybee_energy/simulation/output.py +646 -0
- honeybee_energy/simulation/parameter.py +606 -0
- honeybee_energy/simulation/runperiod.py +443 -0
- honeybee_energy/simulation/shadowcalculation.py +295 -0
- honeybee_energy/simulation/sizing.py +546 -0
- honeybee_energy/ventcool/__init__.py +5 -0
- honeybee_energy/ventcool/_crack_data.py +91 -0
- honeybee_energy/ventcool/afn.py +289 -0
- honeybee_energy/ventcool/control.py +269 -0
- honeybee_energy/ventcool/crack.py +126 -0
- honeybee_energy/ventcool/fan.py +493 -0
- honeybee_energy/ventcool/opening.py +365 -0
- honeybee_energy/ventcool/simulation.py +314 -0
- honeybee_energy/writer.py +1078 -0
- honeybee_energy-1.116.106.dist-info/METADATA +113 -0
- honeybee_energy-1.116.106.dist-info/RECORD +162 -0
- honeybee_energy-1.116.106.dist-info/WHEEL +5 -0
- honeybee_energy-1.116.106.dist-info/entry_points.txt +2 -0
- honeybee_energy-1.116.106.dist-info/licenses/LICENSE +661 -0
- honeybee_energy-1.116.106.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Base class for HVAC systems following a template from the OpenStudio standards gem."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
from ._base import _HVACSystem
|
|
6
|
+
|
|
7
|
+
from honeybee._lockable import lockable
|
|
8
|
+
from honeybee.typing import valid_ep_string
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import importlib
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@lockable
|
|
15
|
+
class _TemplateSystem(_HVACSystem):
|
|
16
|
+
"""Base class for HVAC systems following a standards template.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
identifier: Text string for system identifier. Must be < 100 characters
|
|
20
|
+
and not contain any EnergyPlus special characters. This will be used to
|
|
21
|
+
identify the object across a model and in the exported IDF.
|
|
22
|
+
vintage: Text for the vintage of the template system. This will be used
|
|
23
|
+
to set efficiencies for various pieces of equipment within the system.
|
|
24
|
+
Choose from the following.
|
|
25
|
+
|
|
26
|
+
* DOE_Ref_Pre_1980
|
|
27
|
+
* DOE_Ref_1980_2004
|
|
28
|
+
* ASHRAE_2004
|
|
29
|
+
* ASHRAE_2007
|
|
30
|
+
* ASHRAE_2010
|
|
31
|
+
* ASHRAE_2013
|
|
32
|
+
* ASHRAE_2016
|
|
33
|
+
* ASHRAE_2019
|
|
34
|
+
|
|
35
|
+
equipment_type: Text for the specific type of the system and equipment.
|
|
36
|
+
For example, 'VAV chiller with gas boiler reheat'.
|
|
37
|
+
|
|
38
|
+
Properties:
|
|
39
|
+
* identifier
|
|
40
|
+
* display_name
|
|
41
|
+
* vintage
|
|
42
|
+
* equipment_type
|
|
43
|
+
* schedules
|
|
44
|
+
* has_district_heating
|
|
45
|
+
* has_district_cooling
|
|
46
|
+
* user_data
|
|
47
|
+
"""
|
|
48
|
+
__slots__ = ('_vintage', '_equipment_type')
|
|
49
|
+
|
|
50
|
+
VINTAGES = ('DOE_Ref_Pre_1980', 'DOE_Ref_1980_2004', 'ASHRAE_2004', 'ASHRAE_2007',
|
|
51
|
+
'ASHRAE_2010', 'ASHRAE_2013', 'ASHRAE_2016', 'ASHRAE_2019')
|
|
52
|
+
EQUIPMENT_TYPES = ('Inferred',)
|
|
53
|
+
|
|
54
|
+
def __init__(self, identifier, vintage='ASHRAE_2019', equipment_type=None):
|
|
55
|
+
"""Initialize HVACSystem."""
|
|
56
|
+
# initialize base HVAC system properties
|
|
57
|
+
_HVACSystem.__init__(self, identifier)
|
|
58
|
+
self.vintage = vintage
|
|
59
|
+
self.equipment_type = equipment_type
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def vintage(self):
|
|
63
|
+
"""Get or set text to indicate the vintage of the template system.
|
|
64
|
+
|
|
65
|
+
Choose from the following options:
|
|
66
|
+
|
|
67
|
+
* DOE_Ref_Pre_1980
|
|
68
|
+
* DOE_Ref_1980_2004
|
|
69
|
+
* ASHRAE_2004
|
|
70
|
+
* ASHRAE_2007
|
|
71
|
+
* ASHRAE_2010
|
|
72
|
+
* ASHRAE_2013
|
|
73
|
+
* ASHRAE_2016
|
|
74
|
+
* ASHRAE_2019
|
|
75
|
+
"""
|
|
76
|
+
return self._vintage
|
|
77
|
+
|
|
78
|
+
@vintage.setter
|
|
79
|
+
def vintage(self, value):
|
|
80
|
+
clean_input = valid_ep_string(value).lower()
|
|
81
|
+
for key in self.VINTAGES:
|
|
82
|
+
if key.lower() == clean_input:
|
|
83
|
+
value = key
|
|
84
|
+
break
|
|
85
|
+
else:
|
|
86
|
+
raise ValueError(
|
|
87
|
+
'Template HVAC vintage "{}" is not recognized.\nChoose from the '
|
|
88
|
+
'following:\n{}'.format(value, self.VINTAGES))
|
|
89
|
+
self._vintage = value
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def equipment_type(self):
|
|
93
|
+
"""Get or set text for the system's equipment specification.
|
|
94
|
+
|
|
95
|
+
For example, 'VAV chiller with gas boiler reheat'.
|
|
96
|
+
"""
|
|
97
|
+
return self._equipment_type
|
|
98
|
+
|
|
99
|
+
@equipment_type.setter
|
|
100
|
+
def equipment_type(self, value):
|
|
101
|
+
if value is not None:
|
|
102
|
+
clean_input = valid_ep_string(value).lower()
|
|
103
|
+
for key in self.EQUIPMENT_TYPES:
|
|
104
|
+
if key.lower() == clean_input:
|
|
105
|
+
value = key
|
|
106
|
+
break
|
|
107
|
+
else:
|
|
108
|
+
raise ValueError(
|
|
109
|
+
'HVAC equipment_type "{}" is not supported for {}.\n'
|
|
110
|
+
'Choose from the following:\n{}'.format(
|
|
111
|
+
value, self.__class__.__name__, '\n'.join(self.EQUIPMENT_TYPES)))
|
|
112
|
+
self._equipment_type = value
|
|
113
|
+
else:
|
|
114
|
+
self._equipment_type = self.EQUIPMENT_TYPES[0]
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def has_district_heating(self):
|
|
118
|
+
"""Get a boolean for whether the HVAC system has district heating."""
|
|
119
|
+
return self._equipment_type is not None and 'DHW' in self._equipment_type
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def has_district_cooling(self):
|
|
123
|
+
"""Get a boolean for whether the HVAC system has district cooling."""
|
|
124
|
+
return self._equipment_type is not None and 'DCW' in self._equipment_type
|
|
125
|
+
|
|
126
|
+
@classmethod
|
|
127
|
+
def from_dict(cls, data):
|
|
128
|
+
"""Create a HVAC object from a dictionary.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
data: A HVAC dictionary in following the format below.
|
|
132
|
+
|
|
133
|
+
.. code-block:: python
|
|
134
|
+
|
|
135
|
+
{
|
|
136
|
+
"type": "", # text for the class name of the HVAC
|
|
137
|
+
"identifier": "Classroom1_System", # identifier for the HVAC
|
|
138
|
+
"display_name": "Standard System", # name for the HVAC
|
|
139
|
+
"vintage": "ASHRAE_2019", # text for the vintage of the template
|
|
140
|
+
"equipment_type": "" # text for the HVAC equipment type
|
|
141
|
+
}
|
|
142
|
+
"""
|
|
143
|
+
assert data['type'] == cls.__name__, \
|
|
144
|
+
'Expected {} dictionary. Got {}.'.format(cls.__name__, data['type'])
|
|
145
|
+
new_obj = cls(data['identifier'], data['vintage'], data['equipment_type'])
|
|
146
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
147
|
+
new_obj.display_name = data['display_name']
|
|
148
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
149
|
+
new_obj.user_data = data['user_data']
|
|
150
|
+
return new_obj
|
|
151
|
+
|
|
152
|
+
@classmethod
|
|
153
|
+
def from_dict_abridged(cls, data, schedule_dict):
|
|
154
|
+
"""Create a HVAC object from an abridged dictionary.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
data: An abridged dictionary in following the format below.
|
|
158
|
+
schedule_dict: A dictionary with schedule identifiers as keys and honeybee
|
|
159
|
+
schedule objects as values (either ScheduleRuleset or
|
|
160
|
+
ScheduleFixedInterval). These will be used to assign the schedules
|
|
161
|
+
to the Setpoint object.
|
|
162
|
+
|
|
163
|
+
.. code-block:: python
|
|
164
|
+
|
|
165
|
+
{
|
|
166
|
+
"type": "", # text for the class name of the HVAC
|
|
167
|
+
"identifier": "Classroom1_System", # identifier for the HVAC
|
|
168
|
+
"display_name": "Standard System", # name for the HVAC
|
|
169
|
+
"vintage": "ASHRAE_2019", # text for the vintage of the template
|
|
170
|
+
"equipment_type": "" # text for the HVAC equipment type
|
|
171
|
+
}
|
|
172
|
+
"""
|
|
173
|
+
# this is the same as the from_dict method for as long as there are not schedules
|
|
174
|
+
return cls.from_dict(data)
|
|
175
|
+
|
|
176
|
+
def to_dict(self, abridged=False):
|
|
177
|
+
"""All air system dictionary representation.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
abridged: Boolean to note whether the full dictionary describing the
|
|
181
|
+
object should be returned (False) or just an abridged version (True).
|
|
182
|
+
This input currently has no effect but may eventually have one if
|
|
183
|
+
schedule-type properties are exposed on this template.
|
|
184
|
+
"""
|
|
185
|
+
base = {'type': self.__class__.__name__}
|
|
186
|
+
base['identifier'] = self.identifier
|
|
187
|
+
if self._display_name is not None:
|
|
188
|
+
base['display_name'] = self.display_name
|
|
189
|
+
base['vintage'] = self.vintage
|
|
190
|
+
base['equipment_type'] = self.equipment_type
|
|
191
|
+
if self._user_data is not None:
|
|
192
|
+
base['user_data'] = self.user_data
|
|
193
|
+
return base
|
|
194
|
+
|
|
195
|
+
def __copy__(self):
|
|
196
|
+
new_obj = self.__class__(self.identifier, self.vintage, self.equipment_type)
|
|
197
|
+
new_obj._display_name = self._display_name
|
|
198
|
+
new_obj._user_data = None if self._user_data is None else self._user_data.copy()
|
|
199
|
+
return new_obj
|
|
200
|
+
|
|
201
|
+
def __key(self):
|
|
202
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
203
|
+
return (self._identifier, self._vintage, self._equipment_type)
|
|
204
|
+
|
|
205
|
+
def __hash__(self):
|
|
206
|
+
return hash(self.__key())
|
|
207
|
+
|
|
208
|
+
def __eq__(self, other):
|
|
209
|
+
return isinstance(other, self.__class__) and self.__key() == other.__key()
|
|
210
|
+
|
|
211
|
+
def __ne__(self, other):
|
|
212
|
+
return not self.__eq__(other)
|
|
213
|
+
|
|
214
|
+
def __repr__(self):
|
|
215
|
+
return '{}: {} [type: {}] [vintage: {}]'.format(
|
|
216
|
+
self.__class__.__name__, self.display_name,
|
|
217
|
+
self.equipment_type, self.vintage)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class _EnumerationBase(object):
|
|
221
|
+
"""Enumerates the systems that inherit from a given template class."""
|
|
222
|
+
|
|
223
|
+
def __init__(self):
|
|
224
|
+
pass # this class is only intended to be used in child objects
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def types(self):
|
|
228
|
+
"""A tuple indicating the currently supported HVAC types."""
|
|
229
|
+
return tuple(sorted(self._HVAC_TYPES.keys()))
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def equipment_types(self):
|
|
233
|
+
"""A tuple indicating the supported equipment types."""
|
|
234
|
+
return tuple(sorted(self._EQUIPMENT_TYPES.keys()))
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def types_dict(self):
|
|
238
|
+
"""A dictionary containing pointers to the classes of each HVAC type.
|
|
239
|
+
|
|
240
|
+
The keys of this dictionary are the names of the HVAC classes (eg. 'FCU').
|
|
241
|
+
"""
|
|
242
|
+
return self._HVAC_TYPES
|
|
243
|
+
|
|
244
|
+
@property
|
|
245
|
+
def equipment_types_dict(self):
|
|
246
|
+
"""A dictionary containing pointers to the classes of each equipment type.
|
|
247
|
+
|
|
248
|
+
The keys of this dictionary are the names of the HVAC systems as they
|
|
249
|
+
appear in the OpenStudio standards gem and include the specific equipment
|
|
250
|
+
in the system (eg. 'DOAS with fan coil chiller with boiler').
|
|
251
|
+
"""
|
|
252
|
+
return self._EQUIPMENT_TYPES
|
|
253
|
+
|
|
254
|
+
@staticmethod
|
|
255
|
+
def _import_modules(root_dir, base_package):
|
|
256
|
+
"""Import all of the modules in the root_dir.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
root_dir: The directory from which modules will be imported.
|
|
260
|
+
base_package: Text for the start of the import statement
|
|
261
|
+
(eg. 'honeybee_energy.hvac.heatcool').
|
|
262
|
+
"""
|
|
263
|
+
exclude = ('__init__.py', '_base.py')
|
|
264
|
+
modules = [mod for mod in os.listdir(root_dir)
|
|
265
|
+
if mod not in exclude]
|
|
266
|
+
modules = [os.path.join(root_dir, mod) for mod in modules]
|
|
267
|
+
importable = ['.{}'.format(os.path.basename(f)[:-3]) for f in modules
|
|
268
|
+
if os.path.isfile(f) and f.endswith('.py')]
|
|
269
|
+
for mod in importable:
|
|
270
|
+
importlib.import_module(mod, base_package)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Template All-air HVAC definitions.
|
|
2
|
+
|
|
3
|
+
All-air systems provide both ventilation and heating + cooling demand with
|
|
4
|
+
the same stream of warm/cool air. As such, they often grant tight control
|
|
5
|
+
over zone humidity. However, because such systems often involve the
|
|
6
|
+
cooling of air only to reheat it again, they are often more energy intensive
|
|
7
|
+
than systems that separate ventilation from the meeting of thermal loads.
|
|
8
|
+
|
|
9
|
+
Properties:
|
|
10
|
+
* HVAC_TYPES_DICT: A dictionary containing pointers to the classes of each
|
|
11
|
+
HVAC system. The keys of this dictionary are the names of the HVAC
|
|
12
|
+
classes (eg. 'VAV').
|
|
13
|
+
* EQUIPMENT_TYPES_DICT: A dictionary containing pointers to the classes of
|
|
14
|
+
the HVAC systems. The keys of this dictionary are the names of the HVAC
|
|
15
|
+
systems as they appear in the OpenStudio standards gem and include the
|
|
16
|
+
specific equipment in the system (eg. 'VAV chiller with gas boiler reheat').
|
|
17
|
+
"""
|
|
18
|
+
from ._base import _AllAirEnumeration
|
|
19
|
+
|
|
20
|
+
_all_air_types = _AllAirEnumeration(import_modules=True)
|
|
21
|
+
HVAC_TYPES_DICT = _all_air_types.types_dict
|
|
22
|
+
EQUIPMENT_TYPES_DICT = _all_air_types.equipment_types_dict
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Base class for All-Air HVAC systems."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from honeybee._lockable import lockable
|
|
7
|
+
from honeybee.typing import valid_string, float_in_range
|
|
8
|
+
from honeybee.altnumber import autosize
|
|
9
|
+
|
|
10
|
+
from .._template import _TemplateSystem, _EnumerationBase
|
|
11
|
+
from ..idealair import IdealAirSystem
|
|
12
|
+
from ...properties.extension import AllAirSystemProperties
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@lockable
|
|
16
|
+
class _AllAirBase(_TemplateSystem):
|
|
17
|
+
"""Base class for All-Air HVAC systems.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
identifier: Text string for system identifier. Must be < 100 characters
|
|
21
|
+
and not contain any EnergyPlus special characters. This will be used to
|
|
22
|
+
identify the object across a model and in the exported IDF.
|
|
23
|
+
vintage: Text for the vintage of the template system. This will be used
|
|
24
|
+
to set efficiencies for various pieces of equipment within the system.
|
|
25
|
+
Choose from the following.
|
|
26
|
+
|
|
27
|
+
* DOE_Ref_Pre_1980
|
|
28
|
+
* DOE_Ref_1980_2004
|
|
29
|
+
* ASHRAE_2004
|
|
30
|
+
* ASHRAE_2007
|
|
31
|
+
* ASHRAE_2010
|
|
32
|
+
* ASHRAE_2013
|
|
33
|
+
* ASHRAE_2016
|
|
34
|
+
* ASHRAE_2019
|
|
35
|
+
|
|
36
|
+
equipment_type: Text for the specific type of the system and equipment.
|
|
37
|
+
For example, 'VAV chiller with gas boiler reheat'.
|
|
38
|
+
economizer_type: Text to indicate the type of air-side economizer used on
|
|
39
|
+
the system. (Default: NoEconomizer). Choose from the following.
|
|
40
|
+
|
|
41
|
+
* NoEconomizer
|
|
42
|
+
* DifferentialDryBulb
|
|
43
|
+
* DifferentialEnthalpy
|
|
44
|
+
* DifferentialDryBulbAndEnthalpy
|
|
45
|
+
* FixedDryBulb
|
|
46
|
+
* FixedEnthalpy
|
|
47
|
+
* ElectronicEnthalpy
|
|
48
|
+
|
|
49
|
+
sensible_heat_recovery: A number between 0 and 1 for the effectiveness
|
|
50
|
+
of sensible heat recovery within the system. (Default: 0).
|
|
51
|
+
latent_heat_recovery: A number between 0 and 1 for the effectiveness
|
|
52
|
+
of latent heat recovery within the system. (Default: 0).
|
|
53
|
+
demand_controlled_ventilation: Boolean to note whether demand controlled
|
|
54
|
+
ventilation should be used on the system, which will vary the amount
|
|
55
|
+
of ventilation air according to the occupancy schedule of the
|
|
56
|
+
Rooms. (Default: False).
|
|
57
|
+
|
|
58
|
+
Properties:
|
|
59
|
+
* identifier
|
|
60
|
+
* display_name
|
|
61
|
+
* vintage
|
|
62
|
+
* equipment_type
|
|
63
|
+
* economizer_type
|
|
64
|
+
* sensible_heat_recovery
|
|
65
|
+
* latent_heat_recovery
|
|
66
|
+
* demand_controlled_ventilation
|
|
67
|
+
* schedules
|
|
68
|
+
* has_district_heating
|
|
69
|
+
* has_district_cooling
|
|
70
|
+
* user_data
|
|
71
|
+
* properties
|
|
72
|
+
"""
|
|
73
|
+
__slots__ = ('_economizer_type', '_sensible_heat_recovery', '_latent_heat_recovery',
|
|
74
|
+
'_demand_controlled_ventilation', '_properties')
|
|
75
|
+
ECONOMIZER_TYPES = ('NoEconomizer', 'DifferentialDryBulb', 'DifferentialEnthalpy',
|
|
76
|
+
'DifferentialDryBulbAndEnthalpy', 'FixedDryBulb',
|
|
77
|
+
'FixedEnthalpy', 'ElectronicEnthalpy')
|
|
78
|
+
COOL_ONLY_TYPES = ('PSZAC', 'PSZAC_DCW', 'PTAC')
|
|
79
|
+
HEAT_ONLY_TYPES = ('Furnace',)
|
|
80
|
+
_has_air_loop = True
|
|
81
|
+
|
|
82
|
+
def __init__(self, identifier, vintage='ASHRAE_2019', equipment_type=None,
|
|
83
|
+
economizer_type='NoEconomizer',
|
|
84
|
+
sensible_heat_recovery=0, latent_heat_recovery=0,
|
|
85
|
+
demand_controlled_ventilation=False):
|
|
86
|
+
"""Initialize HVACSystem."""
|
|
87
|
+
# initialize base HVAC system properties
|
|
88
|
+
_TemplateSystem.__init__(self, identifier, vintage, equipment_type)
|
|
89
|
+
|
|
90
|
+
# set the main features of the HVAC system
|
|
91
|
+
self.economizer_type = economizer_type
|
|
92
|
+
self.sensible_heat_recovery = sensible_heat_recovery
|
|
93
|
+
self.latent_heat_recovery = latent_heat_recovery
|
|
94
|
+
self.demand_controlled_ventilation = demand_controlled_ventilation
|
|
95
|
+
self._properties = AllAirSystemProperties(self)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def economizer_type(self):
|
|
99
|
+
"""Get or set text to indicate the type of air-side economizer.
|
|
100
|
+
|
|
101
|
+
Choose from the following options.
|
|
102
|
+
|
|
103
|
+
* NoEconomizer
|
|
104
|
+
* DifferentialDryBulb
|
|
105
|
+
* DifferentialEnthalpy
|
|
106
|
+
* DifferentialDryBulbAndEnthalpy
|
|
107
|
+
* FixedDryBulb
|
|
108
|
+
* FixedEnthalpy
|
|
109
|
+
* ElectronicEnthalpy
|
|
110
|
+
"""
|
|
111
|
+
return self._economizer_type
|
|
112
|
+
|
|
113
|
+
@economizer_type.setter
|
|
114
|
+
def economizer_type(self, value):
|
|
115
|
+
clean_input = valid_string(value).lower()
|
|
116
|
+
for key in self.ECONOMIZER_TYPES:
|
|
117
|
+
if key.lower() == clean_input:
|
|
118
|
+
value = key
|
|
119
|
+
break
|
|
120
|
+
else:
|
|
121
|
+
raise ValueError(
|
|
122
|
+
'economizer_type {} is not recognized.\nChoose from the '
|
|
123
|
+
'following:\n{}'.format(value, self.ECONOMIZER_TYPES))
|
|
124
|
+
if value != 'NoEconomizer':
|
|
125
|
+
self._air_loop_check('economizer')
|
|
126
|
+
self._economizer_type = value
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def sensible_heat_recovery(self):
|
|
130
|
+
"""Get or set a number for the effectiveness of sensible heat recovery."""
|
|
131
|
+
return self._sensible_heat_recovery
|
|
132
|
+
|
|
133
|
+
@sensible_heat_recovery.setter
|
|
134
|
+
def sensible_heat_recovery(self, value):
|
|
135
|
+
if value is None or value == 0:
|
|
136
|
+
self._sensible_heat_recovery = 0
|
|
137
|
+
else:
|
|
138
|
+
self._air_loop_check('sensible_heat_recovery')
|
|
139
|
+
self._sensible_heat_recovery = \
|
|
140
|
+
float_in_range(value, 0.0, 1.0, 'hvac sensible heat recovery')
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def latent_heat_recovery(self):
|
|
144
|
+
"""Get or set a number for the effectiveness of latent heat recovery."""
|
|
145
|
+
return self._latent_heat_recovery
|
|
146
|
+
|
|
147
|
+
@latent_heat_recovery.setter
|
|
148
|
+
def latent_heat_recovery(self, value):
|
|
149
|
+
if value is None or value == 0:
|
|
150
|
+
self._latent_heat_recovery = 0
|
|
151
|
+
else:
|
|
152
|
+
self._air_loop_check('latent_heat_recovery')
|
|
153
|
+
self._latent_heat_recovery = \
|
|
154
|
+
float_in_range(value, 0.0, 1.0, 'hvac latent heat recovery')
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def demand_controlled_ventilation(self):
|
|
158
|
+
"""Get or set a boolean for whether demand controlled ventilation is present."""
|
|
159
|
+
return self._demand_controlled_ventilation
|
|
160
|
+
|
|
161
|
+
@demand_controlled_ventilation.setter
|
|
162
|
+
def demand_controlled_ventilation(self, value):
|
|
163
|
+
self._demand_controlled_ventilation = bool(value)
|
|
164
|
+
if self._demand_controlled_ventilation:
|
|
165
|
+
self._air_loop_check('demand_controlled_ventilation')
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def properties(self):
|
|
169
|
+
"""Get properties for extensions."""
|
|
170
|
+
return self._properties
|
|
171
|
+
|
|
172
|
+
@classmethod
|
|
173
|
+
def from_dict(cls, data):
|
|
174
|
+
"""Create a HVAC object from a dictionary.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
data: An all-air dictionary in following the format below.
|
|
178
|
+
|
|
179
|
+
.. code-block:: python
|
|
180
|
+
|
|
181
|
+
{
|
|
182
|
+
"type": "", # text for the class name of the HVAC
|
|
183
|
+
"identifier": "Classroom1_System", # identifier for the HVAC
|
|
184
|
+
"display_name": "Standard System", # name for the HVAC
|
|
185
|
+
"vintage": "ASHRAE_2019", # text for the vintage of the template
|
|
186
|
+
"equipment_type": "", # text for the HVAC equipment type
|
|
187
|
+
"economizer_type": 'DifferentialDryBulb', # Economizer type
|
|
188
|
+
"sensible_heat_recovery": 0.75, # Sensible heat recovery effectiveness
|
|
189
|
+
"latent_heat_recovery": 0.7, # Latent heat recovery effectiveness
|
|
190
|
+
"demand_controlled_ventilation": False # Boolean for DCV
|
|
191
|
+
"properties": { ... } # AllAirSystemProperties as a dict
|
|
192
|
+
}
|
|
193
|
+
"""
|
|
194
|
+
assert cls.__name__ in data['type'], \
|
|
195
|
+
'Expected {} dictionary. Got {}.'.format(cls.__name__, data['type'])
|
|
196
|
+
# extract the key features and properties of the HVAC
|
|
197
|
+
econ, sensible, latent, dcv = cls._properties_from_dict(data)
|
|
198
|
+
new_obj = cls(data['identifier'], data['vintage'], data['equipment_type'],
|
|
199
|
+
econ, sensible, latent, dcv)
|
|
200
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
201
|
+
new_obj.display_name = data['display_name']
|
|
202
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
203
|
+
new_obj.user_data = data['user_data']
|
|
204
|
+
if 'properties' in data and data['properties'] is not None:
|
|
205
|
+
new_obj.properties._load_extension_attr_from_dict(data['properties'])
|
|
206
|
+
return new_obj
|
|
207
|
+
|
|
208
|
+
@classmethod
|
|
209
|
+
def from_dict_abridged(cls, data, schedule_dict):
|
|
210
|
+
"""Create a HVAC object from an abridged dictionary.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
data: An all-air abridged dictionary in following the format below.
|
|
214
|
+
schedule_dict: A dictionary with schedule identifiers as keys and honeybee
|
|
215
|
+
schedule objects as values (either ScheduleRuleset or
|
|
216
|
+
ScheduleFixedInterval). These will be used to assign the schedules
|
|
217
|
+
to the Setpoint object.
|
|
218
|
+
|
|
219
|
+
.. code-block:: python
|
|
220
|
+
|
|
221
|
+
{
|
|
222
|
+
"type": "", # text for the class name of the HVAC
|
|
223
|
+
"identifier": "Classroom1_System", # identifier for the HVAC
|
|
224
|
+
"display_name": "Standard System", # name for the HVAC
|
|
225
|
+
"vintage": "ASHRAE_2013", # text for the vintage of the template
|
|
226
|
+
"equipment_type": "", # text for the HVAC equipment type
|
|
227
|
+
"economizer_type": 'DifferentialDryBulb', # Economizer type
|
|
228
|
+
"sensible_heat_recovery": 0.75, # Sensible heat recovery effectiveness
|
|
229
|
+
"latent_heat_recovery": 0.7, # Latent heat recovery effectiveness
|
|
230
|
+
"demand_controlled_ventilation": False # Boolean for DCV
|
|
231
|
+
"properties": { ... } # dict of the AllAirSystemProperties
|
|
232
|
+
}
|
|
233
|
+
"""
|
|
234
|
+
# this is the same as the from_dict method for as long as there are not schedules
|
|
235
|
+
return cls.from_dict(data)
|
|
236
|
+
|
|
237
|
+
def to_dict(self, abridged=False):
|
|
238
|
+
"""All air system dictionary representation.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
abridged: Boolean to note whether the full dictionary describing the
|
|
242
|
+
object should be returned (False) or just an abridged version (True).
|
|
243
|
+
This input currently has no effect but may eventually have one if
|
|
244
|
+
schedule-type properties are exposed on this template.
|
|
245
|
+
"""
|
|
246
|
+
base = {'type': self.__class__.__name__}
|
|
247
|
+
base['identifier'] = self.identifier
|
|
248
|
+
if self._display_name is not None:
|
|
249
|
+
base['display_name'] = self.display_name
|
|
250
|
+
base['vintage'] = self.vintage
|
|
251
|
+
base['equipment_type'] = self.equipment_type
|
|
252
|
+
if self.economizer_type != 'NoEconomizer':
|
|
253
|
+
base['economizer_type'] = self.economizer_type
|
|
254
|
+
if self.sensible_heat_recovery != 0:
|
|
255
|
+
base['sensible_heat_recovery'] = self.sensible_heat_recovery
|
|
256
|
+
if self.latent_heat_recovery != 0:
|
|
257
|
+
base['latent_heat_recovery'] = self.latent_heat_recovery
|
|
258
|
+
base['demand_controlled_ventilation'] = self.demand_controlled_ventilation
|
|
259
|
+
if self._user_data is not None:
|
|
260
|
+
base['user_data'] = self.user_data
|
|
261
|
+
prop_dict = self.properties.to_dict()
|
|
262
|
+
if prop_dict is not None:
|
|
263
|
+
base['properties'] = prop_dict
|
|
264
|
+
return base
|
|
265
|
+
|
|
266
|
+
def to_ideal_air_equivalent(self):
|
|
267
|
+
"""Get a version of this HVAC as an IdealAirSystem.
|
|
268
|
+
|
|
269
|
+
Relevant properties will be transferred to the resulting ideal air such as
|
|
270
|
+
economizer_type, sensible_heat_recovery, latent_heat_recovery, and
|
|
271
|
+
demand_controlled_ventilation.
|
|
272
|
+
"""
|
|
273
|
+
econ_typ = self.economizer_type
|
|
274
|
+
if econ_typ not in self.ECONOMIZER_TYPES[:3]:
|
|
275
|
+
enth_types = ('FixedEnthalpy', 'ElectronicEnthalpy')
|
|
276
|
+
econ_typ = 'DifferentialEnthalpy' if econ_typ in enth_types \
|
|
277
|
+
else 'DifferentialDryBulb'
|
|
278
|
+
i_sys = IdealAirSystem(
|
|
279
|
+
self.identifier, economizer_type=econ_typ,
|
|
280
|
+
sensible_heat_recovery=self.sensible_heat_recovery,
|
|
281
|
+
latent_heat_recovery=self.latent_heat_recovery,
|
|
282
|
+
demand_controlled_ventilation=self.demand_controlled_ventilation)
|
|
283
|
+
if self.equipment_type in self.COOL_ONLY_TYPES:
|
|
284
|
+
i_sys.heating_limit = 0
|
|
285
|
+
if self.equipment_type in self.HEAT_ONLY_TYPES:
|
|
286
|
+
i_sys.cooling_limit = 0
|
|
287
|
+
i_sys._display_name = self._display_name
|
|
288
|
+
return i_sys
|
|
289
|
+
|
|
290
|
+
def _air_loop_check(self, prop_name):
|
|
291
|
+
"""Check whether the system has an air loop and rase an error if not."""
|
|
292
|
+
assert self._has_air_loop, \
|
|
293
|
+
'HVAC system must have an air loop to assign {}.'.format(prop_name)
|
|
294
|
+
|
|
295
|
+
@staticmethod
|
|
296
|
+
def _properties_from_dict(data):
|
|
297
|
+
"""Extract basic properties from a dictionary and assign defaults."""
|
|
298
|
+
econ = data['economizer_type'] if 'economizer_type' in data and \
|
|
299
|
+
data['economizer_type'] is not None else 'NoEconomizer'
|
|
300
|
+
sensible = data['sensible_heat_recovery'] if \
|
|
301
|
+
'sensible_heat_recovery' in data else 0
|
|
302
|
+
sensible = sensible if sensible != autosize.to_dict() else 0
|
|
303
|
+
latent = data['latent_heat_recovery'] if \
|
|
304
|
+
'latent_heat_recovery' in data else 0
|
|
305
|
+
latent = latent if latent != autosize.to_dict() else 0
|
|
306
|
+
dcv = data['demand_controlled_ventilation'] \
|
|
307
|
+
if 'demand_controlled_ventilation' in data else False
|
|
308
|
+
return econ, sensible, latent, dcv
|
|
309
|
+
|
|
310
|
+
def __copy__(self):
|
|
311
|
+
new_obj = self.__class__(
|
|
312
|
+
self._identifier, self._vintage, self._equipment_type, self._economizer_type,
|
|
313
|
+
self._sensible_heat_recovery, self._latent_heat_recovery,
|
|
314
|
+
self._demand_controlled_ventilation)
|
|
315
|
+
new_obj._display_name = self._display_name
|
|
316
|
+
new_obj._user_data = None if self._user_data is None else self._user_data.copy()
|
|
317
|
+
new_obj._properties._duplicate_extension_attr(self._properties)
|
|
318
|
+
return new_obj
|
|
319
|
+
|
|
320
|
+
def __key(self):
|
|
321
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
322
|
+
return (self._identifier, self._vintage, self._equipment_type,
|
|
323
|
+
self._economizer_type, self._sensible_heat_recovery,
|
|
324
|
+
self._latent_heat_recovery, self._demand_controlled_ventilation)
|
|
325
|
+
|
|
326
|
+
def __hash__(self):
|
|
327
|
+
return hash(self.__key())
|
|
328
|
+
|
|
329
|
+
def __eq__(self, other):
|
|
330
|
+
return isinstance(other, self.__class__) and self.__key() == other.__key()
|
|
331
|
+
|
|
332
|
+
def __ne__(self, other):
|
|
333
|
+
return not self.__eq__(other)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
class _AllAirEnumeration(_EnumerationBase):
|
|
337
|
+
"""Enumerates the systems that inherit from _AllAirBase."""
|
|
338
|
+
|
|
339
|
+
def __init__(self, import_modules=True):
|
|
340
|
+
if import_modules:
|
|
341
|
+
self._import_modules(
|
|
342
|
+
os.path.dirname(__file__), 'honeybee_energy.hvac.allair')
|
|
343
|
+
|
|
344
|
+
self._HVAC_TYPES = {}
|
|
345
|
+
self._EQUIPMENT_TYPES = {}
|
|
346
|
+
for clss in _AllAirBase.__subclasses__():
|
|
347
|
+
self._HVAC_TYPES[clss.__name__] = clss
|
|
348
|
+
for equip_type in clss.EQUIPMENT_TYPES:
|
|
349
|
+
self._EQUIPMENT_TYPES[equip_type] = clss
|