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.
Files changed (162) hide show
  1. honeybee_energy/__init__.py +24 -0
  2. honeybee_energy/__main__.py +4 -0
  3. honeybee_energy/_extend_honeybee.py +145 -0
  4. honeybee_energy/altnumber.py +21 -0
  5. honeybee_energy/baseline/__init__.py +2 -0
  6. honeybee_energy/baseline/create.py +608 -0
  7. honeybee_energy/baseline/data/__init__.py +1 -0
  8. honeybee_energy/baseline/data/constructions.csv +64 -0
  9. honeybee_energy/baseline/data/fen_ratios.csv +15 -0
  10. honeybee_energy/baseline/data/lpd_building.csv +21 -0
  11. honeybee_energy/baseline/data/pci_2016.csv +22 -0
  12. honeybee_energy/baseline/data/pci_2019.csv +22 -0
  13. honeybee_energy/baseline/data/pci_2022.csv +22 -0
  14. honeybee_energy/baseline/data/shw.csv +21 -0
  15. honeybee_energy/baseline/pci.py +512 -0
  16. honeybee_energy/baseline/result.py +371 -0
  17. honeybee_energy/boundarycondition.py +128 -0
  18. honeybee_energy/cli/__init__.py +69 -0
  19. honeybee_energy/cli/baseline.py +475 -0
  20. honeybee_energy/cli/edit.py +327 -0
  21. honeybee_energy/cli/lib.py +1154 -0
  22. honeybee_energy/cli/result.py +810 -0
  23. honeybee_energy/cli/setconfig.py +124 -0
  24. honeybee_energy/cli/settings.py +569 -0
  25. honeybee_energy/cli/simulate.py +380 -0
  26. honeybee_energy/cli/translate.py +1714 -0
  27. honeybee_energy/cli/validate.py +224 -0
  28. honeybee_energy/config.json +11 -0
  29. honeybee_energy/config.py +842 -0
  30. honeybee_energy/construction/__init__.py +1 -0
  31. honeybee_energy/construction/_base.py +374 -0
  32. honeybee_energy/construction/air.py +325 -0
  33. honeybee_energy/construction/dictutil.py +89 -0
  34. honeybee_energy/construction/dynamic.py +607 -0
  35. honeybee_energy/construction/opaque.py +460 -0
  36. honeybee_energy/construction/shade.py +319 -0
  37. honeybee_energy/construction/window.py +1096 -0
  38. honeybee_energy/construction/windowshade.py +847 -0
  39. honeybee_energy/constructionset.py +1655 -0
  40. honeybee_energy/dictutil.py +56 -0
  41. honeybee_energy/generator/__init__.py +5 -0
  42. honeybee_energy/generator/loadcenter.py +204 -0
  43. honeybee_energy/generator/pv.py +535 -0
  44. honeybee_energy/hvac/__init__.py +21 -0
  45. honeybee_energy/hvac/_base.py +124 -0
  46. honeybee_energy/hvac/_template.py +270 -0
  47. honeybee_energy/hvac/allair/__init__.py +22 -0
  48. honeybee_energy/hvac/allair/_base.py +349 -0
  49. honeybee_energy/hvac/allair/furnace.py +168 -0
  50. honeybee_energy/hvac/allair/psz.py +131 -0
  51. honeybee_energy/hvac/allair/ptac.py +163 -0
  52. honeybee_energy/hvac/allair/pvav.py +109 -0
  53. honeybee_energy/hvac/allair/vav.py +128 -0
  54. honeybee_energy/hvac/detailed.py +337 -0
  55. honeybee_energy/hvac/doas/__init__.py +28 -0
  56. honeybee_energy/hvac/doas/_base.py +345 -0
  57. honeybee_energy/hvac/doas/fcu.py +127 -0
  58. honeybee_energy/hvac/doas/radiant.py +329 -0
  59. honeybee_energy/hvac/doas/vrf.py +81 -0
  60. honeybee_energy/hvac/doas/wshp.py +91 -0
  61. honeybee_energy/hvac/heatcool/__init__.py +23 -0
  62. honeybee_energy/hvac/heatcool/_base.py +177 -0
  63. honeybee_energy/hvac/heatcool/baseboard.py +61 -0
  64. honeybee_energy/hvac/heatcool/evapcool.py +72 -0
  65. honeybee_energy/hvac/heatcool/fcu.py +92 -0
  66. honeybee_energy/hvac/heatcool/gasunit.py +53 -0
  67. honeybee_energy/hvac/heatcool/radiant.py +269 -0
  68. honeybee_energy/hvac/heatcool/residential.py +77 -0
  69. honeybee_energy/hvac/heatcool/vrf.py +54 -0
  70. honeybee_energy/hvac/heatcool/windowac.py +70 -0
  71. honeybee_energy/hvac/heatcool/wshp.py +62 -0
  72. honeybee_energy/hvac/idealair.py +699 -0
  73. honeybee_energy/internalmass.py +310 -0
  74. honeybee_energy/lib/__init__.py +1 -0
  75. honeybee_energy/lib/_loadconstructions.py +194 -0
  76. honeybee_energy/lib/_loadconstructionsets.py +117 -0
  77. honeybee_energy/lib/_loadmaterials.py +83 -0
  78. honeybee_energy/lib/_loadprogramtypes.py +125 -0
  79. honeybee_energy/lib/_loadschedules.py +87 -0
  80. honeybee_energy/lib/_loadtypelimits.py +64 -0
  81. honeybee_energy/lib/constructions.py +207 -0
  82. honeybee_energy/lib/constructionsets.py +95 -0
  83. honeybee_energy/lib/materials.py +67 -0
  84. honeybee_energy/lib/programtypes.py +125 -0
  85. honeybee_energy/lib/schedules.py +61 -0
  86. honeybee_energy/lib/scheduletypelimits.py +31 -0
  87. honeybee_energy/load/__init__.py +1 -0
  88. honeybee_energy/load/_base.py +190 -0
  89. honeybee_energy/load/daylight.py +397 -0
  90. honeybee_energy/load/dictutil.py +47 -0
  91. honeybee_energy/load/equipment.py +771 -0
  92. honeybee_energy/load/hotwater.py +543 -0
  93. honeybee_energy/load/infiltration.py +460 -0
  94. honeybee_energy/load/lighting.py +480 -0
  95. honeybee_energy/load/people.py +497 -0
  96. honeybee_energy/load/process.py +472 -0
  97. honeybee_energy/load/setpoint.py +816 -0
  98. honeybee_energy/load/ventilation.py +550 -0
  99. honeybee_energy/material/__init__.py +1 -0
  100. honeybee_energy/material/_base.py +166 -0
  101. honeybee_energy/material/dictutil.py +59 -0
  102. honeybee_energy/material/frame.py +367 -0
  103. honeybee_energy/material/gas.py +1087 -0
  104. honeybee_energy/material/glazing.py +854 -0
  105. honeybee_energy/material/opaque.py +1351 -0
  106. honeybee_energy/material/shade.py +1360 -0
  107. honeybee_energy/measure.py +472 -0
  108. honeybee_energy/programtype.py +723 -0
  109. honeybee_energy/properties/__init__.py +1 -0
  110. honeybee_energy/properties/aperture.py +333 -0
  111. honeybee_energy/properties/door.py +342 -0
  112. honeybee_energy/properties/extension.py +244 -0
  113. honeybee_energy/properties/face.py +274 -0
  114. honeybee_energy/properties/model.py +2640 -0
  115. honeybee_energy/properties/room.py +1747 -0
  116. honeybee_energy/properties/shade.py +314 -0
  117. honeybee_energy/properties/shademesh.py +262 -0
  118. honeybee_energy/reader.py +48 -0
  119. honeybee_energy/result/__init__.py +1 -0
  120. honeybee_energy/result/colorobj.py +648 -0
  121. honeybee_energy/result/emissions.py +290 -0
  122. honeybee_energy/result/err.py +101 -0
  123. honeybee_energy/result/eui.py +100 -0
  124. honeybee_energy/result/generation.py +160 -0
  125. honeybee_energy/result/loadbalance.py +890 -0
  126. honeybee_energy/result/match.py +202 -0
  127. honeybee_energy/result/osw.py +90 -0
  128. honeybee_energy/result/rdd.py +59 -0
  129. honeybee_energy/result/zsz.py +190 -0
  130. honeybee_energy/run.py +1577 -0
  131. honeybee_energy/schedule/__init__.py +1 -0
  132. honeybee_energy/schedule/day.py +626 -0
  133. honeybee_energy/schedule/dictutil.py +59 -0
  134. honeybee_energy/schedule/fixedinterval.py +1012 -0
  135. honeybee_energy/schedule/rule.py +619 -0
  136. honeybee_energy/schedule/ruleset.py +1867 -0
  137. honeybee_energy/schedule/typelimit.py +310 -0
  138. honeybee_energy/shw.py +315 -0
  139. honeybee_energy/simulation/__init__.py +1 -0
  140. honeybee_energy/simulation/control.py +214 -0
  141. honeybee_energy/simulation/daylightsaving.py +185 -0
  142. honeybee_energy/simulation/dictutil.py +51 -0
  143. honeybee_energy/simulation/output.py +646 -0
  144. honeybee_energy/simulation/parameter.py +606 -0
  145. honeybee_energy/simulation/runperiod.py +443 -0
  146. honeybee_energy/simulation/shadowcalculation.py +295 -0
  147. honeybee_energy/simulation/sizing.py +546 -0
  148. honeybee_energy/ventcool/__init__.py +5 -0
  149. honeybee_energy/ventcool/_crack_data.py +91 -0
  150. honeybee_energy/ventcool/afn.py +289 -0
  151. honeybee_energy/ventcool/control.py +269 -0
  152. honeybee_energy/ventcool/crack.py +126 -0
  153. honeybee_energy/ventcool/fan.py +493 -0
  154. honeybee_energy/ventcool/opening.py +365 -0
  155. honeybee_energy/ventcool/simulation.py +314 -0
  156. honeybee_energy/writer.py +1078 -0
  157. honeybee_energy-1.116.106.dist-info/METADATA +113 -0
  158. honeybee_energy-1.116.106.dist-info/RECORD +162 -0
  159. honeybee_energy-1.116.106.dist-info/WHEEL +5 -0
  160. honeybee_energy-1.116.106.dist-info/entry_points.txt +2 -0
  161. honeybee_energy-1.116.106.dist-info/licenses/LICENSE +661 -0
  162. honeybee_energy-1.116.106.dist-info/top_level.txt +1 -0
@@ -0,0 +1,699 @@
1
+ # coding=utf-8
2
+ """Simple ideal air system object used to condition zones."""
3
+ from __future__ import division
4
+
5
+ from honeybee._lockable import lockable
6
+ from honeybee.typing import valid_string, float_positive, float_in_range
7
+ from honeybee.altnumber import autosize, no_limit
8
+
9
+ from ._base import _HVACSystem
10
+ from ..reader import parse_idf_string
11
+ from ..writer import generate_idf_string
12
+ from ..properties.extension import IdealAirSystemProperties
13
+
14
+
15
+ @lockable
16
+ class IdealAirSystem(_HVACSystem):
17
+ """Simple ideal air system object used to condition zones.
18
+
19
+ Args:
20
+ identifier: Text string for ideal air 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
+ economizer_type: Text to indicate the type of air-side economizer used on
24
+ the ideal air system. Economizers will mix in a greater amount of
25
+ outdoor air to cool the zone (rather than running the cooling system)
26
+ when the zone needs cooling and the outdoor air is cooler than the zone.
27
+ Choose from the options below. (Default: DifferentialDryBulb).
28
+
29
+ * NoEconomizer
30
+ * DifferentialDryBulb
31
+ * DifferentialEnthalpy
32
+
33
+ demand_controlled_ventilation: Boolean to note whether demand controlled
34
+ ventilation should be used on the system, which will vary the amount
35
+ of ventilation air according to the occupancy schedule of the
36
+ Room. (Default: False).
37
+ sensible_heat_recovery: A number between 0 and 1 for the effectiveness
38
+ of sensible heat recovery within the system. (Default: 0).
39
+ latent_heat_recovery: A number between 0 and 1 for the effectiveness
40
+ of latent heat recovery within the system. (Default: 0).
41
+ heating_air_temperature: A number for the maximum heating supply air
42
+ temperature [C]. (Default: 50, which is typical for many air-based
43
+ HVAC systems).
44
+ cooling_air_temperature: A number for the minimum cooling supply air
45
+ temperature [C]. (Default: 13, which is typical for many air-based
46
+ HVAC systems).
47
+ heating_limit: A number for the maximum heating capacity in Watts. This
48
+ can also be an Autosize object to indicate that the capacity should
49
+ be determined during the EnergyPlus sizing calculation. This can also
50
+ be a NoLimit object to indicate no upper limit to the heating
51
+ capacity. (Default: autosize).
52
+ cooling_limit: A number for the maximum cooling capacity in Watts. This
53
+ can also be an Autosize object to indicate that the capacity should
54
+ be determined during the EnergyPlus sizing calculation. This can also
55
+ be a NoLimit object to indicate no upper limit to the cooling
56
+ capacity. (Default: autosize).
57
+ heating_availability: An optional on/off schedule to set the availability of
58
+ heating over the course of the simulation. (Default: None).
59
+ cooling_availability: An optional on/off schedule to set the availability of
60
+ cooling over the course of the simulation. (Default: None).
61
+
62
+ Properties:
63
+ * identifier
64
+ * display_name
65
+ * economizer_type
66
+ * demand_controlled_ventilation
67
+ * sensible_heat_recovery
68
+ * latent_heat_recovery
69
+ * heating_air_temperature
70
+ * cooling_air_temperature
71
+ * heating_limit
72
+ * cooling_limit
73
+ * heating_availability
74
+ * cooling_availability
75
+ * schedules
76
+ * properties
77
+ """
78
+ __slots__ = ('_economizer_type', '_demand_controlled_ventilation',
79
+ '_sensible_heat_recovery', '_latent_heat_recovery',
80
+ '_heating_air_temperature', '_cooling_air_temperature',
81
+ '_heating_limit', '_cooling_limit', '_heating_availability',
82
+ '_cooling_availability', '_properties')
83
+ ECONOMIZER_TYPES = ('NoEconomizer', 'DifferentialDryBulb', 'DifferentialEnthalpy')
84
+
85
+ def __init__(self, identifier, economizer_type='DifferentialDryBulb',
86
+ demand_controlled_ventilation=False,
87
+ sensible_heat_recovery=0, latent_heat_recovery=0,
88
+ heating_air_temperature=50, cooling_air_temperature=13,
89
+ heating_limit=autosize, cooling_limit=autosize,
90
+ heating_availability=None, cooling_availability=None):
91
+ """Initialize IdealAirSystem."""
92
+ # initialize base HVAC system properties
93
+ _HVACSystem.__init__(self, identifier)
94
+
95
+ # set the main features of the HVAC system
96
+ self.economizer_type = economizer_type
97
+ self.demand_controlled_ventilation = demand_controlled_ventilation
98
+ self.sensible_heat_recovery = sensible_heat_recovery
99
+ self.latent_heat_recovery = latent_heat_recovery
100
+
101
+ # set the options affecting heating and cooling
102
+ # set heating_air_temperature without the setter to ensure > cooling check works
103
+ self._heating_air_temperature = \
104
+ float_positive(heating_air_temperature, 'ideal air heating air temperature')
105
+ self.cooling_air_temperature = cooling_air_temperature
106
+ self.heating_limit = heating_limit
107
+ self.cooling_limit = cooling_limit
108
+ self.heating_availability = heating_availability
109
+ self.cooling_availability = cooling_availability
110
+
111
+ # initialize properties for extensions
112
+ self._properties = IdealAirSystemProperties(self)
113
+
114
+ @property
115
+ def economizer_type(self):
116
+ """Get or set text to indicate the type of air-side economizer.
117
+
118
+ Choose from the following options:
119
+
120
+ * NoEconomizer
121
+ * DifferentialDryBulb
122
+ * DifferentialEnthalpy
123
+ """
124
+ return self._economizer_type
125
+
126
+ @economizer_type.setter
127
+ def economizer_type(self, value):
128
+ clean_input = valid_string(value).lower()
129
+ for key in self.ECONOMIZER_TYPES:
130
+ if key.lower() == clean_input:
131
+ value = key
132
+ break
133
+ else:
134
+ raise ValueError(
135
+ 'economizer_type {} is not recognized.\nChoose from the '
136
+ 'following:\n{}'.format(value, self.ECONOMIZER_TYPES))
137
+ self._economizer_type = value
138
+
139
+ @property
140
+ def demand_controlled_ventilation(self):
141
+ """Get or set a boolean for whether demand controlled ventilation is present."""
142
+ return self._demand_controlled_ventilation
143
+
144
+ @demand_controlled_ventilation.setter
145
+ def demand_controlled_ventilation(self, value):
146
+ self._demand_controlled_ventilation = bool(value)
147
+
148
+ @property
149
+ def sensible_heat_recovery(self):
150
+ """Get or set a number for the effectiveness of sensible heat recovery."""
151
+ return self._sensible_heat_recovery
152
+
153
+ @sensible_heat_recovery.setter
154
+ def sensible_heat_recovery(self, value):
155
+ self._sensible_heat_recovery = float_in_range(
156
+ value, 0.0, 1.0, 'ideal air sensible heat recovery')
157
+
158
+ @property
159
+ def latent_heat_recovery(self):
160
+ """Get or set a number for the effectiveness of latent heat recovery."""
161
+ return self._latent_heat_recovery
162
+
163
+ @latent_heat_recovery.setter
164
+ def latent_heat_recovery(self, value):
165
+ self._latent_heat_recovery = float_in_range(
166
+ value, 0.0, 1.0, 'ideal air latent heat recovery')
167
+
168
+ @property
169
+ def heating_air_temperature(self):
170
+ """Get or set a number for the maximum heating supply air temperature."""
171
+ return self._heating_air_temperature
172
+
173
+ @heating_air_temperature.setter
174
+ def heating_air_temperature(self, value):
175
+ self._heating_air_temperature = float_in_range(
176
+ value, 0, 100, 'ideal air heating air temperature')
177
+ self._air_temperature_check()
178
+
179
+ @property
180
+ def cooling_air_temperature(self):
181
+ """Get or set a number for the minimum cooling supply air temperature."""
182
+ return self._cooling_air_temperature
183
+
184
+ @cooling_air_temperature.setter
185
+ def cooling_air_temperature(self, value):
186
+ self._cooling_air_temperature = float_in_range(
187
+ value, -100, 50, 'ideal air cooling air temperature')
188
+ self._air_temperature_check()
189
+
190
+ @property
191
+ def heating_limit(self):
192
+ """Get or set a number for the maximum heating capacity in Watts."""
193
+ return self._heating_limit
194
+
195
+ @heating_limit.setter
196
+ def heating_limit(self, value):
197
+ if value == autosize or value is None:
198
+ self._heating_limit = autosize
199
+ elif value == no_limit:
200
+ self._heating_limit = no_limit
201
+ else:
202
+ self._heating_limit = float_positive(value, 'ideal air heating limit')
203
+
204
+ @property
205
+ def cooling_limit(self):
206
+ """Get or set a number for the maximum cooling capacity in Watts."""
207
+ return self._cooling_limit
208
+
209
+ @cooling_limit.setter
210
+ def cooling_limit(self, value):
211
+ if value == autosize or value is None:
212
+ self._cooling_limit = autosize
213
+ elif value == no_limit:
214
+ assert self.economizer_type == 'NoEconomizer', 'Ideal air system ' \
215
+ 'economizer_type must be "NoEconomizer" to have no cooling limit.'
216
+ self._cooling_limit = no_limit
217
+ else:
218
+ self._cooling_limit = float_positive(value, 'ideal air cooling limit')
219
+
220
+ @property
221
+ def heating_availability(self):
222
+ """Get or set a ScheduleRuleset/ScheduleFixedInterval for heating availability.
223
+ """
224
+ return self._heating_availability
225
+
226
+ @heating_availability.setter
227
+ def heating_availability(self, value):
228
+ if value is not None:
229
+ self._check_schedule(value, 'heating_availability')
230
+ value.lock() # lock editing in case schedule has multiple references
231
+ self._heating_availability = value
232
+
233
+ @property
234
+ def cooling_availability(self):
235
+ """Get or set a ScheduleRuleset/ScheduleFixedInterval for cooling availability.
236
+ """
237
+ return self._cooling_availability
238
+
239
+ @cooling_availability.setter
240
+ def cooling_availability(self, value):
241
+ if value is not None:
242
+ self._check_schedule(value, 'cooling_availability')
243
+ value.lock() # lock editing in case schedule has multiple references
244
+ self._cooling_availability = value
245
+
246
+ @property
247
+ def schedules(self):
248
+ """Get an array of all the schedules associated with the HVAC system."""
249
+ schedules = []
250
+ if self._heating_availability is not None:
251
+ schedules.append(self._heating_availability)
252
+ if self._cooling_availability is not None:
253
+ schedules.append(self._cooling_availability)
254
+ return schedules
255
+
256
+ @classmethod
257
+ def from_idf(cls, idf_string, schedule_dict):
258
+ """Create an IdealAirSystem object from an EnergyPlus IDF text string.
259
+
260
+ Args:
261
+ idf_string: A text string fully describing an EnergyPlus
262
+ HVACTemplate:Zone:IdealLoadsAirSystem definition.
263
+ schedule_dict: A dictionary with schedule identifiers as keys and honeybee
264
+ schedule objects as values (either ScheduleRuleset or
265
+ ScheduleFixedInterval). These will be used to assign the schedules to
266
+ the IdealAirSystem object.
267
+
268
+ Returns:
269
+ A tuple with two elements
270
+
271
+ - ideal_air_system: An IdealAirSystem object loaded from the idf_string.
272
+
273
+ - zone_identifier: The identifier of the zone to which the IdealAirSystem
274
+ object should be assigned.
275
+ """
276
+ # check the inputs
277
+ ep_strs = parse_idf_string(idf_string, 'HVACTemplate:Zone:IdealLoadsAirSystem,')
278
+
279
+ # set defaults for anything not included
280
+ identifier = '{} Ideal Loads Air System'.format(ep_strs[0])
281
+ econ = 'DifferentialDryBulb'
282
+ dcv = False
283
+ sensible = 0
284
+ latent = 0
285
+ heat_temp = 50
286
+ cool_temp = 13
287
+ heat_limit = autosize
288
+ cool_limit = autosize
289
+ heat_sch = None
290
+ cool_sch = None
291
+
292
+ # extract the properties from the string
293
+ try:
294
+ heat_temp = ep_strs[3] if ep_strs[3] != '' else heat_temp
295
+ cool_temp = ep_strs[4] if ep_strs[4] != '' else cool_temp
296
+ if ep_strs[7].lower() == 'limitcapacity' or \
297
+ ep_strs[7].lower() == 'limitflowrateandcapacity':
298
+ heat_limit = autosize if ep_strs[9] == '' or \
299
+ ep_strs[9].lower() == 'autosize' else ep_strs[9]
300
+ else:
301
+ heat_limit = no_limit
302
+ if ep_strs[10].lower() == 'limitcapacity' or \
303
+ ep_strs[10].lower() == 'limitflowrateandcapacity':
304
+ cool_limit = autosize if ep_strs[12] == '' or \
305
+ ep_strs[12].lower() == 'autosize' else ep_strs[12]
306
+ else:
307
+ cool_limit = no_limit
308
+ if ep_strs[13] != '':
309
+ heat_sch = schedule_dict[ep_strs[13]]
310
+ if ep_strs[14] != '':
311
+ cool_sch = schedule_dict[ep_strs[14]]
312
+ if ep_strs[25].lower() == 'occupancyschedule':
313
+ dcv = True
314
+ if ep_strs[26].lower() != 'differentialdrybulb':
315
+ econ = ep_strs[26]
316
+ if ep_strs[27].lower() == 'sensible':
317
+ sensible = ep_strs[28] if ep_strs[28] != '' else 0.7
318
+ elif ep_strs[27].lower() == 'enthalpy':
319
+ sensible = ep_strs[28] if ep_strs[28] != '' else 0.7
320
+ latent = ep_strs[29] if ep_strs[29] != '' else 0.65
321
+ except IndexError:
322
+ pass # shorter Ideal air loads definition
323
+
324
+ # return the object and the zone identifier for the object
325
+ ideal_air_system = cls(
326
+ identifier, econ, dcv, sensible, latent, heat_temp, cool_temp,
327
+ heat_limit, cool_limit, heat_sch, cool_sch)
328
+ zone_identifier = ep_strs[0]
329
+ return ideal_air_system, zone_identifier
330
+
331
+ @classmethod
332
+ def from_dict(cls, data):
333
+ """Create a IdealAirSystem object from a dictionary.
334
+
335
+ Args:
336
+ data: A IdealAirSystem dictionary in following the format below.
337
+
338
+ .. code-block:: python
339
+
340
+ {
341
+ "type": "IdealAirSystem",
342
+ "identifier": "Classroom1 Ideal Loads Air System", # identifier for the HVAC
343
+ "display_name": "Standard IdealAir", # name for the HVAC
344
+ "economizer_type": 'DifferentialDryBulb', # Economizer type
345
+ "demand_controlled_ventilation": True, # Demand controlled ventilation
346
+ "sensible_heat_recovery": 0.75, # Sensible heat recovery effectiveness
347
+ "latent_heat_recovery": 0.7, # Latent heat recovery effectiveness
348
+ "heating_air_temperature": 50, # Heating supply air temperature
349
+ "cooling_air_temperature": 13, # Cooling supply air temperature
350
+ "heating_limit": {'type': 'Autosize'}, # Max size of the heating system
351
+ "cooling_limit": {'type': 'Autosize'}, # Max size of the cooling system
352
+ "heating_availability": {}, # Schedule for availability of heat or None
353
+ "cooling_availability": {} # Schedule for availability of cooling or None
354
+ }
355
+ """
356
+ assert data['type'] == 'IdealAirSystem', \
357
+ 'Expected IdealAirSystem dictionary. Got {}.'.format(data['type'])
358
+
359
+ # extract the key features and properties of the HVAC
360
+ econ, dcv, sensible, latent, heat_temp, cool_temp, heat_limit, cool_limit = \
361
+ cls._properties_from_dict(data)
362
+
363
+ # extract the schedules
364
+ heat_avail = cls._get_schedule_from_dict(data['heating_availability']) if \
365
+ 'heating_availability' in data and data['heating_availability'] is not None \
366
+ else None
367
+ cool_avail = cls._get_schedule_from_dict(data['cooling_availability']) if \
368
+ 'cooling_availability' in data and data['cooling_availability'] is not None \
369
+ else None
370
+
371
+ new_obj = cls(data['identifier'], econ, dcv, sensible, latent, heat_temp,
372
+ cool_temp, heat_limit, cool_limit, heat_avail, cool_avail)
373
+ if 'display_name' in data and data['display_name'] is not None:
374
+ new_obj.display_name = data['display_name']
375
+ if 'user_data' in data and data['user_data'] is not None:
376
+ new_obj.user_data = data['user_data']
377
+ if 'properties' in data and data['properties'] is not None:
378
+ new_obj.properties._load_extension_attr_from_dict(data['properties'])
379
+ return new_obj
380
+
381
+ @classmethod
382
+ def from_dict_abridged(cls, data, schedule_dict):
383
+ """Create a IdealAirSystem object from an abridged dictionary.
384
+
385
+ Args:
386
+ data: A IdealAirSystemAbridged dictionary in following the format below.
387
+ schedule_dict: A dictionary with schedule identifiers as keys and honeybee
388
+ schedule objects as values (either ScheduleRuleset or
389
+ ScheduleFixedInterval). These will be used to assign the schedules
390
+ to the Setpoint object.
391
+
392
+ .. code-block:: python
393
+
394
+ {
395
+ "type": 'IdealAirSystemAbridged',
396
+ "identifier": 'Warehouse1 Ideal Loads Air System', # identifier for the HVAC
397
+ "economizer_type": 'DifferentialDryBulb', # Economizer type
398
+ "demand_controlled_ventilation": True, # Demand controlled ventilation
399
+ "sensible_heat_recovery": 0.75, # Sensible heat recovery effectiveness
400
+ "latent_heat_recovery": 0.7, # Latent heat recovery effectiveness
401
+ "heating_air_temperature": 40, # Heating supply air temperature
402
+ "cooling_air_temperature": 15, # Cooling supply air temperature
403
+ "heating_limit": 'autosize', # Max size of the heating system in Watts
404
+ "cooling_limit": 'autosize', # Max size of the cooling system in Watts
405
+ "heating_availability": "Warehouse Heating Control", # schedule identifier
406
+ "cooling_availability": "Warehouse Cooling Control", # schedule identifier
407
+ }
408
+ """
409
+ assert data['type'] == 'IdealAirSystemAbridged', \
410
+ 'Expected IdealAirSystemAbridged dictionary. Got {}.'.format(data['type'])
411
+
412
+ # extract the key features and properties of the HVAC
413
+ econ, dcv, sensible, latent, heat_temp, cool_temp, heat_limit, cool_limit = \
414
+ cls._properties_from_dict(data)
415
+
416
+ # extract the schedules
417
+ heat_avail = None
418
+ cool_avail = None
419
+ if 'heating_availability' in data and data['heating_availability'] is not None:
420
+ try:
421
+ heat_avail = schedule_dict[data['heating_availability']]
422
+ except KeyError as e:
423
+ raise ValueError('Failed to find {} in the schedule_dict.'.format(e))
424
+ if 'cooling_availability' in data and data['cooling_availability'] is not None:
425
+ try:
426
+ cool_avail = schedule_dict[data['cooling_availability']]
427
+ except KeyError as e:
428
+ raise ValueError('Failed to find {} in the schedule_dict.'.format(e))
429
+
430
+ new_obj = cls(data['identifier'], econ, dcv, sensible, latent, heat_temp,
431
+ cool_temp, heat_limit, cool_limit, heat_avail, cool_avail)
432
+ if 'display_name' in data and data['display_name'] is not None:
433
+ new_obj.display_name = data['display_name']
434
+ if 'user_data' in data and data['user_data'] is not None:
435
+ new_obj.user_data = data['user_data']
436
+ if 'properties' in data and data['properties'] is not None:
437
+ new_obj.properties._load_extension_attr_from_dict(data['properties'])
438
+ return new_obj
439
+
440
+ def to_idf(self, room):
441
+ """IDF string representation of IdealAirSystem object.
442
+
443
+ Note that this method does not return full definitions of heating/cooling
444
+ availability schedules and so this objects's schedules must also be translated
445
+ into the final IDF file.
446
+
447
+ Args:
448
+ room: A Honeybee Room for which the specific IDF string will be generated.
449
+ This Room must have a Setpoint object for this method to work
450
+ correctly since all setpoints (and any ventilation requirements)
451
+ are pulled from this Room.
452
+
453
+ .. code-block:: shell
454
+
455
+ HVACTemplate:Zone:IdealLoadsAirSystem,
456
+ Zone 1, !- Zone Name
457
+ All Zones, !- Thermostat Name
458
+ FanAvailSched, !- System Availability Schedule Name
459
+ 50, !- Maximum Heating Supply Air Temperature {C}
460
+ 13, !- Minimum Cooling Supply Air Temperature {C}
461
+ 0.0156, !- Maximum Heating Supply Air Humidity Ratio {kgWater/kgDryAir}
462
+ 0.0077, !- Minimum Cooling Supply Air Humidity Ratio {kgWater/kgDryAir}
463
+ NoLimit, !- Heating Limit
464
+ , !- Maximum Heating Air Flow Rate {m3/s}
465
+ , !- Maximum Sensible Heating Capacity {W}
466
+ NoLimit, !- Cooling Limit
467
+ , !- Maximum Cooling Air Flow Rate {m3/s}
468
+ , !- Maximum Total Cooling Capacity {W}
469
+ , !- Heating Availability Schedule Name
470
+ , !- Cooling Availability Schedule Name
471
+ ConstantSensibleHeatRatio, !- Dehumidification Control Type
472
+ 0.7, !- Cooling Sensible Heat Ratio
473
+ 60, !- Dehumidification Setpoint {percent}
474
+ None, !- Humidification Control Type
475
+ 30, !- Humidification Setpoint {percent}
476
+ flow/person, !- Outdoor Air Method
477
+ 0.00944, !- Outdoor Air Flow Rate per Person {m3/s}
478
+ 0.0, !- Outdoor Air Flow Rate per Zone Floor Area {m3/s-m2}
479
+ 0.0, !- Outdoor Air Flow Rate per Zone {m3/s}
480
+ , !- Design Specification Outdoor Air Object Name
481
+ None, !- Demand Controlled Ventilation Type
482
+ NoEconomizer, !- Outdoor Air Economizer Type
483
+ None, !- Heat Recovery Type
484
+ 0.70, !- Sensible Heat Recovery Effectiveness
485
+ 0.65; !- Latent Heat Recovery Effectiveness
486
+ """
487
+ # check that a setpoint object is assigned
488
+ r_set_p = room.properties.energy.setpoint
489
+ r_vent = room.properties.energy.ventilation
490
+ assert r_set_p is not None, 'IdealAirSystem must be assigned to a Room ' \
491
+ 'with a setpoint object to use IdealAirSystem.to_idf.'
492
+ return self.to_idf_zone(room.identifier, r_set_p, r_vent)
493
+
494
+ def to_idf_zone(self, zone_identifier, setpoint, ventilation=None):
495
+ """IDF string representation of IdealAirSystem using custom zone inputs.
496
+
497
+ This method is identical to the to_idf() method but it is intended to work
498
+ with the case that the ideal air system is assigned to multiple Rooms that
499
+ together form a single thermal Zone. As such, there are custom inputs for
500
+ the name of the zone as well as the setpoint and ventilation.
501
+
502
+ Args:
503
+ zone_identifier: Text for the identifier of the zone to which the
504
+ ideal air system is assigned.
505
+ setpoint: A Setpoint object representing the thermostat setpoints
506
+ of the Zone.
507
+ ventilation: An optional Ventilation object that represents the minimum
508
+ outdoor air requirements of the Zone. (Default: None).
509
+ """
510
+ # extract all of the fields from this object and its room
511
+ # heating limit
512
+ if self.heating_limit != no_limit:
513
+ h_lim_type = 'LimitCapacity'
514
+ heat_limit = str(self.heating_limit) # stringify Autosize
515
+ else:
516
+ h_lim_type = 'NoLimit'
517
+ heat_limit = ''
518
+ # cooling limit
519
+ if self.cooling_limit != no_limit:
520
+ c_lim_type = 'LimitFlowRateAndCapacity'
521
+ air_limit = 'Autosize'
522
+ cool_limit = str(self.cooling_limit) # stringify Autosize
523
+ else:
524
+ c_lim_type = 'NoLimit'
525
+ air_limit = cool_limit = ''
526
+ # availability schedules
527
+ heat_avail = self.heating_availability.identifier if \
528
+ self.heating_availability is not None else ''
529
+ cool_avail = self.cooling_availability.identifier if \
530
+ self.cooling_availability is not None else ''
531
+ # humidifying setpoint
532
+ if setpoint.humidifying_setpoint is not None:
533
+ humid_type = 'Humidistat'
534
+ humid_setpt = setpoint.humidifying_setpoint
535
+ else:
536
+ humid_type = 'None'
537
+ humid_setpt = ''
538
+ # dehumidifying setpoint
539
+ if setpoint.dehumidifying_setpoint is not None:
540
+ dehumid_type = 'Humidistat'
541
+ dehumid_setpt = setpoint.dehumidifying_setpoint
542
+ else:
543
+ dehumid_type = 'None'
544
+ dehumid_setpt = ''
545
+ # ventilation requirements
546
+ if ventilation is not None:
547
+ oa_method = 'DetailedSpecification'
548
+ oa_id = '{}..{}'.format(ventilation.identifier, zone_identifier)
549
+ else:
550
+ oa_method = 'None'
551
+ oa_id = ''
552
+ # demand controlled ventilation
553
+ dcv = 'OccupancySchedule' if self.demand_controlled_ventilation else 'None'
554
+ # heat recovery
555
+ if self.sensible_heat_recovery == 0 and self.latent_heat_recovery == 0:
556
+ heat_recovery = 'None'
557
+ elif self.latent_heat_recovery != 0:
558
+ heat_recovery = 'Enthalpy'
559
+ else:
560
+ heat_recovery = 'Sensible'
561
+
562
+ # return a full IDF string
563
+ thermostat = '{}..{}'.format(setpoint.identifier, zone_identifier) \
564
+ if setpoint.setpoint_cutout_difference == 0 else ''
565
+ values = (zone_identifier, thermostat,
566
+ '', self.heating_air_temperature, self.cooling_air_temperature,
567
+ '', '', h_lim_type, '', heat_limit, c_lim_type, air_limit, cool_limit,
568
+ heat_avail, cool_avail, dehumid_type, '', dehumid_setpt,
569
+ humid_type, humid_setpt, oa_method, '', '', '', oa_id, dcv,
570
+ self.economizer_type, heat_recovery, self.sensible_heat_recovery,
571
+ self.latent_heat_recovery)
572
+ comments = (
573
+ 'zone name', 'template thermostat name', 'availability schedule',
574
+ 'heating supply air temp {C}', 'cooling supply air temp {C}',
575
+ 'max heating supply air hr {kg-H2O/kg-air}',
576
+ 'min cooling supply air hr {kg-H2O/kg-air}',
577
+ 'heating limit', 'max heating fow rate {m3/s}', 'max sensible heat capacity',
578
+ 'cooling limit', 'max cooling fow rate {m3/s}', 'max total cooling capacity',
579
+ 'heating availability schedule', 'cooling availability schedule',
580
+ 'dehumidification type', 'cooling shr', 'dehumidification setpoint',
581
+ 'humidification type', 'humidification setpoint', 'outdoor air method',
582
+ 'oa per person', 'oa per area', 'oa per zone', 'outdoor air object name',
583
+ 'demand controlled vent type', 'economizer type', 'heat recovery type',
584
+ 'sensible heat recovery effectiveness', 'latent heat recovery effectiveness')
585
+ return generate_idf_string(
586
+ 'HVACTemplate:Zone:IdealLoadsAirSystem', values, comments)
587
+
588
+ def to_dict(self, abridged=False):
589
+ """IdealAirSystem dictionary representation.
590
+
591
+ Args:
592
+ abridged: Boolean to note whether the full dictionary describing the
593
+ object should be returned (False) or just an abridged version (True),
594
+ which only specifies the identifiers of schedules. Default: False.
595
+ """
596
+ base = {'type': 'IdealAirSystem'} if not \
597
+ abridged else {'type': 'IdealAirSystemAbridged'}
598
+ base['identifier'] = self.identifier
599
+ base['economizer_type'] = self.economizer_type
600
+ base['demand_controlled_ventilation'] = self.demand_controlled_ventilation
601
+ base['sensible_heat_recovery'] = self.sensible_heat_recovery
602
+ base['latent_heat_recovery'] = self.latent_heat_recovery
603
+ base['heating_air_temperature'] = self.heating_air_temperature
604
+ base['cooling_air_temperature'] = self.cooling_air_temperature
605
+ base['heating_limit'] = self.heating_limit if \
606
+ isinstance(self.heating_limit, float) else self.heating_limit.to_dict()
607
+ base['cooling_limit'] = self.cooling_limit if \
608
+ isinstance(self.cooling_limit, float) else self.cooling_limit.to_dict()
609
+ if self.heating_availability is not None:
610
+ base['heating_availability'] = self.heating_availability.identifier if \
611
+ abridged else self.heating_availability.to_dict()
612
+ if self.cooling_availability is not None:
613
+ base['cooling_availability'] = self.cooling_availability.identifier if \
614
+ abridged else self.cooling_availability.to_dict()
615
+ if self._display_name is not None:
616
+ base['display_name'] = self.display_name
617
+ if self._user_data is not None:
618
+ base['user_data'] = self.user_data
619
+ prop_dict = self.properties.to_dict()
620
+ if prop_dict is not None:
621
+ base['properties'] = prop_dict
622
+ return base
623
+
624
+ def _air_temperature_check(self):
625
+ """Check that heating_air_temperature is greater than cooling_air_temperature."""
626
+ assert self._heating_air_temperature > self._cooling_air_temperature, \
627
+ 'Ideal air heating_air_temperature must be greater than ' \
628
+ 'cooling_air_temperature.'
629
+
630
+ @staticmethod
631
+ def _properties_from_dict(data):
632
+ """Extract basic properties from a dictionary and assign defaults."""
633
+ # extract the key features of the HVAC
634
+ econ = data['economizer_type'] if 'economizer_type' in data and \
635
+ data['economizer_type'] is not None else 'DifferentialDryBulb'
636
+ dcv = data['demand_controlled_ventilation'] if \
637
+ 'demand_controlled_ventilation' in data else False
638
+ sensible = data['sensible_heat_recovery'] if \
639
+ 'sensible_heat_recovery' in data else 0
640
+ latent = data['latent_heat_recovery'] if \
641
+ 'latent_heat_recovery' in data else 0
642
+
643
+ # extract the heating and cooling temperature
644
+ heat_temp = data['heating_air_temperature'] if \
645
+ 'heating_air_temperature' in data else 50
646
+ cool_temp = data['cooling_air_temperature'] if \
647
+ 'cooling_air_temperature' in data else 13
648
+
649
+ # extract the heating and cooling limits
650
+ if 'heating_limit' not in data or data['heating_limit'] == autosize.to_dict():
651
+ heat_limit = autosize
652
+ else:
653
+ heat_limit = no_limit if data['heating_limit'] == no_limit.to_dict() \
654
+ else data['heating_limit']
655
+ if 'cooling_limit' not in data or data['cooling_limit'] == autosize.to_dict():
656
+ cool_limit = autosize
657
+ else:
658
+ cool_limit = no_limit if data['cooling_limit'] == no_limit.to_dict() \
659
+ else data['cooling_limit']
660
+
661
+ return econ, dcv, sensible, latent, heat_temp, cool_temp, heat_limit, cool_limit
662
+
663
+ @property
664
+ def properties(self):
665
+ """Get properties for extensions."""
666
+ return self._properties
667
+
668
+ def __copy__(self):
669
+ new_obj = IdealAirSystem(
670
+ self._identifier, self._economizer_type, self._demand_controlled_ventilation,
671
+ self._sensible_heat_recovery, self._latent_heat_recovery,
672
+ self._heating_air_temperature, self._cooling_air_temperature,
673
+ self._heating_limit, self._cooling_limit, self._heating_availability,
674
+ self._cooling_availability)
675
+ new_obj._display_name = self._display_name
676
+ new_obj._user_data = None if self._user_data is None else self._user_data.copy()
677
+ new_obj._properties._duplicate_extension_attr(self._properties)
678
+ return new_obj
679
+
680
+ def __key(self):
681
+ """A tuple based on the object properties, useful for hashing."""
682
+ return (
683
+ self._identifier, self._economizer_type, self._demand_controlled_ventilation,
684
+ self._sensible_heat_recovery, self._latent_heat_recovery,
685
+ self._heating_air_temperature, self._cooling_air_temperature,
686
+ str(self._heating_limit), str(self._cooling_limit),
687
+ hash(self._heating_availability), hash(self._cooling_availability))
688
+
689
+ def __hash__(self):
690
+ return hash(self.__key())
691
+
692
+ def __eq__(self, other):
693
+ return isinstance(other, IdealAirSystem) and self.__key() == other.__key()
694
+
695
+ def __ne__(self, other):
696
+ return not self.__eq__(other)
697
+
698
+ def __repr__(self):
699
+ return 'IdealAirSystem: {}'.format(self.display_name)