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,365 @@
1
+ # coding=utf-8
2
+ """Definition of window opening for ventilative cooling."""
3
+ from __future__ import division
4
+
5
+ from .control import VentilationControl
6
+ from ..writer import generate_idf_string
7
+
8
+ from honeybee.typing import float_in_range, float_positive
9
+
10
+
11
+ class VentilationOpening(object):
12
+ """Definition of window opening for ventilative cooling.
13
+
14
+ Args:
15
+ fraction_area_operable: A number between 0.0 and 1.0 for the fraction of the
16
+ window area that is operable. (Default: 0.5, typical of sliding windows).
17
+ fraction_height_operable: A number between 0.0 and 1.0 for the fraction
18
+ of the distance from the bottom of the window to the top that is
19
+ operable. (Default: 1.0, typical of windows that slide horizontally).
20
+ discharge_coefficient: A number between 0.0 and 1.0 that will be multiplied
21
+ by the area of the window in the stack (buoyancy-driven) part of the
22
+ equation to account for additional friction from window geometry,
23
+ insect screens, etc. (Default: 0.45, for unobstructed windows with
24
+ insect screens). This value should be lowered if windows are of an
25
+ awning or casement type and not allowed to fully open. Some common
26
+ values for this coefficient include the following.
27
+
28
+ * 0.0 - Completely discount stack ventilation from the calculation.
29
+ * 0.45 - For unobstructed windows with an insect screen.
30
+ * 0.65 - For unobstructed windows with NO insect screen.
31
+
32
+ wind_cross_vent: Boolean to indicate if there is an opening of roughly
33
+ equal area on the opposite side of the Room such that wind-driven
34
+ cross ventilation will be induced. If False, the assumption is that
35
+ the operable area is primarily on one side of the Room and there is
36
+ no wind-driven ventilation. (Default: False)
37
+ flow_coefficient_closed: A number in kg/s-m, at 1 Pa per meter of crack
38
+ length, used to calculate the mass flow rate when the opening is closed;
39
+ only used in an AirflowNetwork simulation. Some common values for this
40
+ coefficient (from the DesignBuilder Cracks template) include the following:
41
+
42
+ * 0.00001 - Tight, low-leakage closed external window
43
+ * 0.003 - Very poor, high-leakage closed external window
44
+
45
+ (Default: 0, indicates the VentilationOpening object will not participate
46
+ in the AirflowNetwork simulation).
47
+ flow_exponent_closed: An optional dimensionless number between 0.5 and
48
+ 1 used to calculate the mass flow rate when the opening is closed; required
49
+ to run an AirflowNetwork simulation. This value represents the leak geometry
50
+ impact on airflow, with 0.5 generally corresponding to turbulent orifice flow
51
+ and 1 generally corresponding to laminar flow. (Default: 0.65,
52
+ representative of many cases of wall and window leakage, used when the
53
+ exponent cannot be measured).
54
+ two_way_threshold: A number in kg/m3 indicating the minimum density difference
55
+ above which two-way flow may occur due to stack effect, required to run an
56
+ AirflowNetwork simulation. This value is required because the air density
57
+ difference between two zones (which drives two-way air flow) will tend
58
+ towards division by zero errors as the air density difference approaches
59
+ zero. (Default: 0.0001, typical default value used for AirflowNetwork
60
+ openings).
61
+
62
+ Properties:
63
+ * fraction_area_operable
64
+ * fraction_height_operable
65
+ * discharge_coefficient
66
+ * wind_cross_vent
67
+ * flow_coefficient_closed
68
+ * flow_exponent_closed
69
+ * two_way_threshold
70
+ * parent
71
+ * has_parent
72
+ """
73
+ __slots__ = ('_fraction_area_operable', '_fraction_height_operable',
74
+ '_discharge_coefficient', '_wind_cross_vent',
75
+ '_flow_coefficient_closed', '_flow_exponent_closed',
76
+ '_two_way_threshold', '_parent')
77
+
78
+ def __init__(self, fraction_area_operable=0.5, fraction_height_operable=1.0,
79
+ discharge_coefficient=0.45, wind_cross_vent=False,
80
+ flow_coefficient_closed=0, flow_exponent_closed=0.65,
81
+ two_way_threshold=0.0001):
82
+ """Initialize VentilationOpening."""
83
+ self.fraction_area_operable = fraction_area_operable
84
+ self.fraction_height_operable = fraction_height_operable
85
+ self.discharge_coefficient = discharge_coefficient
86
+ self.wind_cross_vent = wind_cross_vent
87
+ self.flow_coefficient_closed = flow_coefficient_closed
88
+ self.flow_exponent_closed = flow_exponent_closed
89
+ self.two_way_threshold = two_way_threshold
90
+ self._parent = None # this will be set when assigned to an aperture
91
+
92
+ @property
93
+ def fraction_area_operable(self):
94
+ """Get or set a number for the fraction of the window area that is operable."""
95
+ return self._fraction_area_operable
96
+
97
+ @fraction_area_operable.setter
98
+ def fraction_area_operable(self, value):
99
+ self._fraction_area_operable = \
100
+ float_in_range(value, 0.0, 1.0, 'fraction area operable')
101
+
102
+ @property
103
+ def fraction_height_operable(self):
104
+ """Get or set a number for the fraction of the window height that is operable."""
105
+ return self._fraction_height_operable
106
+
107
+ @fraction_height_operable.setter
108
+ def fraction_height_operable(self, value):
109
+ self._fraction_height_operable = \
110
+ float_in_range(value, 0.0, 1.0, 'fraction height operable')
111
+
112
+ @property
113
+ def discharge_coefficient(self):
114
+ """Get or set a number for the discharge coefficient."""
115
+ return self._discharge_coefficient
116
+
117
+ @discharge_coefficient.setter
118
+ def discharge_coefficient(self, value):
119
+ self._discharge_coefficient = \
120
+ float_in_range(value, 0.0, 1.0, 'discharge coefficient')
121
+
122
+ @property
123
+ def wind_cross_vent(self):
124
+ """Get or set a boolean for whether there is cross ventilation from the window.
125
+
126
+ Note that this property only has significance for simulations using SingleZone
127
+ ventilation_simulation_control and has no bearing on multizone simulations
128
+ with the Airflow Network.
129
+
130
+ This should be True if there is an opening of roughly equal area on the
131
+ opposite side of the Room such that wind-driven cross ventilation will
132
+ be induced. If False, the assumption is that the operable area is primarily
133
+ on one side of the Room and there is no wind-driven ventilation.
134
+ """
135
+ return self._wind_cross_vent
136
+
137
+ @wind_cross_vent.setter
138
+ def wind_cross_vent(self, value):
139
+ self._wind_cross_vent = bool(value)
140
+
141
+ @property
142
+ def flow_coefficient_closed(self):
143
+ """Get or set a number for the mass flow coefficient when opening is closed [kg/s-m].
144
+
145
+ Note that anything assigned here has no bearing on the simulation unless
146
+ the Model that this object is a part of has its ventilation_simulation_control
147
+ set for MultiZone air flow, thereby triggering the use of the AirflowNetwork.
148
+ """
149
+ return self._flow_coefficient_closed
150
+
151
+ @flow_coefficient_closed.setter
152
+ def flow_coefficient_closed(self, value):
153
+ self._flow_coefficient_closed = float_positive(value, 'flow_coefficient_closed')
154
+
155
+ @property
156
+ def flow_exponent_closed(self):
157
+ """Get or set the exponent for deriving the mass flow rate when opening is closed.
158
+
159
+ Note that anything assigned here has no bearing on the simulation unless
160
+ the Model that this object is a part of has its ventilation_simulation_control
161
+ set for MultiZone air flow, thereby triggering the use of the AirflowNetwork.
162
+ """
163
+ return self._flow_exponent_closed
164
+
165
+ @flow_exponent_closed.setter
166
+ def flow_exponent_closed(self, value):
167
+ self._flow_exponent_closed = \
168
+ float_in_range(value, 0.5, 1.0, 'flow_exponent_closed')
169
+
170
+ @property
171
+ def two_way_threshold(self):
172
+ """Get or set minimum density difference above which two-way flow occurs [kg/m3].
173
+
174
+ Note that anything assigned here has no bearing on the simulation unless
175
+ the Model that this object is a part of has its ventilation_simulation_control
176
+ set for MultiZone air flow, thereby triggering the use of the AirflowNetwork.
177
+ """
178
+ return self._two_way_threshold
179
+
180
+ @two_way_threshold.setter
181
+ def two_way_threshold(self, value):
182
+ self._two_way_threshold = float_positive(value, 'two_way_threshold')
183
+
184
+ @property
185
+ def parent(self):
186
+ """Get the parent of this object if it exists."""
187
+ return self._parent
188
+
189
+ @property
190
+ def has_parent(self):
191
+ """Get a boolean noting whether this VentilationOpening has a parent object."""
192
+ return self._parent is not None
193
+
194
+ @classmethod
195
+ def from_dict(cls, data):
196
+ """Create a VentilationOpening object from a dictionary.
197
+
198
+ Args:
199
+ data: A VentilationOpening dictionary in following the format below.
200
+
201
+ .. code-block:: python
202
+
203
+ {
204
+ "type": "VentilationOpening",
205
+ "fraction_area_operable": 0.5, # Fractional number for area operable
206
+ "fraction_height_operable": 0.5, # Fractional number for height operable
207
+ "discharge_coefficient": 0.45, # Fractional number for discharge coefficient
208
+ "wind_cross_vent": True # Wind-driven cross ventilation
209
+ "flow_coefficient_closed": 0.001 # Coefficient for mass flow rate
210
+ "flow_exponent_closed": 0.667 # Exponent for mass flow rate
211
+ "two_way_threshold": 1e-3 # Minimum density for two-way flow
212
+ }
213
+ """
214
+ assert data['type'] == 'VentilationOpening', \
215
+ 'Expected VentilationOpening dictionary. Got {}.'.format(data['type'])
216
+
217
+ area_op = data['fraction_area_operable'] if 'fraction_area_operable' in data \
218
+ and data['fraction_area_operable'] is not None else 0.5
219
+ height_op = data['fraction_height_operable'] if 'fraction_height_operable' in \
220
+ data and data['fraction_height_operable'] is not None else 1.0
221
+ discharge = data['discharge_coefficient'] if 'discharge_coefficient' in data \
222
+ and data['discharge_coefficient'] is not None else 0.45
223
+ cross_vent = data['wind_cross_vent'] if 'wind_cross_vent' in data \
224
+ and data['wind_cross_vent'] is not None else False
225
+
226
+ # Add AFN parameters
227
+ air_flow_coeff = data['flow_coefficient_closed'] if \
228
+ 'flow_coefficient_closed' in data and \
229
+ data['flow_coefficient_closed'] is not None else 0
230
+ air_flow_exp = data['flow_exponent_closed'] if \
231
+ 'flow_exponent_closed' in data and \
232
+ data['flow_exponent_closed'] is not None else 0.65
233
+ min_diff = data['two_way_threshold'] if \
234
+ 'two_way_threshold' in data and \
235
+ data['two_way_threshold'] is not None else 0.0001
236
+
237
+ return cls(area_op, height_op, discharge, cross_vent, air_flow_coeff,
238
+ air_flow_exp, min_diff)
239
+
240
+ def to_idf(self):
241
+ """IDF string representation of VentilationOpening object.
242
+
243
+ Note that this ventilation opening must be assigned to a honeybee Aperture
244
+ or Door for this method to run. This parent Aperture or Door must also have
245
+ a parent Room. It is also recommended that this Room have a VentilationControl
246
+ object under its energy properties. Otherwise, the default control sequence
247
+ will be used, which will likely result in the window never opening.
248
+
249
+ Also note that the parent's geometry should be in meters whenever calling
250
+ this method and that this method does not return full definitions of
251
+ ventilation control schedules. So these schedules must also be translated
252
+ into the final IDF file.
253
+
254
+ .. code-block shell
255
+
256
+ ZoneVentilation:WindandStackOpenArea,
257
+ ZONE 3 Ventl 1, !- Name
258
+ ZONE 3, !- Zone Name
259
+ 0.5, !- Opening Area {m2}
260
+ Constant, !- Opening Area Fraction Schedule Name
261
+ AutoCalculate, !- Opening Effectiveness
262
+ 0.0, !- Effective Angle {deg}
263
+ 1.0, !- Height Difference {m}
264
+ AutoCalculate, !- Discharge Coefficient for Opening
265
+ 18.0, !- Minimum Indoor Temperature {C}
266
+ , !- Minimum Indoor Temperature Schedule Name
267
+ , !- Maximum Indoor Temperature {C}
268
+ , !- Maximum Indoor Temperature Schedule Name
269
+ 1.0; !- Delta Temperature {deltaC}
270
+ """
271
+ # check that a parent is assigned
272
+ assert self.parent is not None, \
273
+ 'VentilationOpening must be assigned to an Aperture or Door to use to_idf().'
274
+
275
+ # get the VentilationControl object from the room
276
+ cntrl = None
277
+ room = None
278
+ if self.parent.has_parent:
279
+ if self.parent.parent.has_parent:
280
+ room = self.parent.parent.parent
281
+ if room.properties.energy.window_vent_control is not None:
282
+ cntrl = room.properties.energy.window_vent_control
283
+ if cntrl is None: # use default ventilation control
284
+ cntrl = VentilationControl()
285
+ assert room is not None, \
286
+ 'VentilationOpening must have a parent Room to use to_idf().'
287
+
288
+ # process the properties on this object into IDF format
289
+ sch = '' if cntrl.schedule is None else cntrl.schedule.identifier
290
+ wind = 'autocalculate' if self.wind_cross_vent else 0
291
+ angle = self.parent.horizontal_orientation() if self.parent.normal.z != 1 else 0
292
+ angle = angle % 360
293
+ height = (self.parent.geometry.max.z - self.parent.geometry.min.z) * \
294
+ self.fraction_height_operable
295
+
296
+ # create the final IDF string
297
+ values = (
298
+ '{}_Opening'.format(self.parent.identifier), room.identifier,
299
+ self.parent.area * self.fraction_area_operable, sch, wind, angle,
300
+ height, self.discharge_coefficient, cntrl.min_indoor_temperature, '',
301
+ cntrl.max_indoor_temperature, '', cntrl.delta_temperature, '',
302
+ cntrl.min_outdoor_temperature, '', cntrl.max_outdoor_temperature, '', 40)
303
+ comments = (
304
+ 'name', 'zone name', 'opening area', 'opening schedule',
305
+ 'opening effectiveness {m2}', 'horizontal orientation angle',
306
+ 'height difference {m}', 'discharge coefficient',
307
+ 'min indoor temperature {C}', 'min in temp schedule',
308
+ 'max indoor temperature {C}', 'max in temp schedule',
309
+ 'delta temperature {C}', 'delta temp schedule',
310
+ 'min outdoor temperature {C}', 'min out temp schedule',
311
+ 'max outdoor temperature {C}', 'max out temp schedule', 'max wind speed')
312
+ return generate_idf_string(
313
+ 'ZoneVentilation:WindandStackOpenArea', values, comments)
314
+
315
+ def to_dict(self):
316
+ """Ventilation Opening dictionary representation."""
317
+ base = {'type': 'VentilationOpening'}
318
+ base['fraction_area_operable'] = self.fraction_area_operable
319
+ base['fraction_height_operable'] = self.fraction_height_operable
320
+ base['discharge_coefficient'] = self.discharge_coefficient
321
+ base['wind_cross_vent'] = self.wind_cross_vent
322
+
323
+ base['flow_coefficient_closed'] = self.flow_coefficient_closed
324
+ base['flow_exponent_closed'] = self.flow_exponent_closed
325
+ base['two_way_threshold'] = self.two_way_threshold
326
+
327
+ return base
328
+
329
+ def duplicate(self):
330
+ """Get a copy of this object."""
331
+ return self.__copy__()
332
+
333
+ def __copy__(self):
334
+ return VentilationOpening(
335
+ self.fraction_area_operable, self.fraction_height_operable,
336
+ self.discharge_coefficient, self.wind_cross_vent,
337
+ self.flow_coefficient_closed, self.flow_exponent_closed,
338
+ self.two_way_threshold)
339
+
340
+ def __key(self):
341
+ """A tuple based on the object properties, useful for hashing."""
342
+ return (self.fraction_area_operable, self.fraction_height_operable,
343
+ self.discharge_coefficient, self.wind_cross_vent,
344
+ self.flow_coefficient_closed,
345
+ self.flow_exponent_closed,
346
+ self.two_way_threshold)
347
+
348
+ def __hash__(self):
349
+ return hash(self.__key())
350
+
351
+ def __eq__(self, other):
352
+ return isinstance(other, VentilationOpening) and self.__key() == other.__key()
353
+
354
+ def __ne__(self, other):
355
+ return not self.__eq__(other)
356
+
357
+ def ToString(self):
358
+ """Overwrite .NET ToString."""
359
+ return self.__repr__()
360
+
361
+ def __repr__(self):
362
+ return 'VentilationOpening: [fraction area: {}] ' \
363
+ '[fraction height: {}] [discharge: {}]'.format(
364
+ self.fraction_area_operable, self.fraction_height_operable,
365
+ self.discharge_coefficient)
@@ -0,0 +1,314 @@
1
+ # coding=utf-8
2
+ """Definitions for global parameters used in the ventilation simulation."""
3
+ from __future__ import division
4
+ import math
5
+
6
+ from ladybug_geometry.bounding import bounding_box_extents
7
+
8
+ from honeybee._lockable import lockable
9
+ from honeybee.typing import float_in_range, float_positive, float_in_range_excl_incl
10
+
11
+
12
+ @lockable
13
+ class VentilationSimulationControl(object):
14
+ """Global parameters used to specify the simulation of air flow.
15
+
16
+ Args:
17
+ vent_control_type: Text indicating type of ventilation control.
18
+ Choose from the following:
19
+
20
+ * SingleZone
21
+ * MultiZoneWithDistribution
22
+ * MultiZoneWithoutDistribution
23
+
24
+ The MultiZone options will model air flow with the AirflowNetwork model,
25
+ which is generally more accurate then the SingleZone option, but will take
26
+ considerably longer to simulate, and requires defining more ventilation
27
+ parameters to explicitly account for weather and building-induced pressure
28
+ differences, and the leakage geometry corresponding to specific windows,
29
+ doors, and surface cracks (Default: 'SingleZone').
30
+ reference_temperature: Reference temperature measurement in Celsius under which
31
+ the surface crack data were obtained. This is only used for AFN simulations,
32
+ when vent_control_type is NOT SingleZone. (Default: 20).
33
+ reference_pressure: Reference barometric pressure measurement in Pascals
34
+ under which the surface crack data were obtained. This is only used for AFN
35
+ simulations, when vent_control_type is NOT SingleZone.(Default: 101325).
36
+ reference_humidity_ratio: Reference humidity ratio measurement in
37
+ kgWater/kgDryAir under which the surface crack data were obtained.
38
+ This is only used for AFN simulations, when vent_control_type is
39
+ NOT SingleZone. (Default: 0).
40
+ building_type: Text indicating relationship between building footprint and
41
+ height. Choose from the following:
42
+
43
+ * LowRise
44
+ * HighRise
45
+
46
+ LowRise corresponds to a building where the height is less then three
47
+ times the width AND length of the footprint. HighRise corresponds to a
48
+ building where height is more than three times the width OR length of
49
+ the footprint. This parameter is used to estimate building-wide wind
50
+ pressure coefficients for the AFN by approximating the building geometry
51
+ as an extruded rectangle. This property can be auto-calculated from
52
+ Honeybee Room geometry with the geometry_properties_from_rooms
53
+ method. (Default: 'LowRise').
54
+ long_axis_angle: A number between 0 and 180 for the clockwise angle difference
55
+ in degrees that the long axis of the building is from true North. This
56
+ parameter is used to estimate building-wide wind pressure coefficients
57
+ for the AFN by approximating the building geometry as an extruded
58
+ rectangle. 0 indicates a North-South long axis while 90 indicates an
59
+ East-West long axis. (Default: 0).
60
+ aspect_ratio: A number between 0 and 1 for the aspect ratio of the building's
61
+ footprint, defined as the ratio of length of the short axis divided
62
+ by the length of the long axis. This parameter is used to estimate
63
+ building-wide wind pressure coefficients for the AFN by approximating
64
+ the building geometry as an extruded rectangle (Default: 1).
65
+
66
+ Properties:
67
+ * vent_control_type
68
+ * reference_temperature
69
+ * reference_pressure
70
+ * reference_humidity_ratio
71
+ * building_type
72
+ * long_axis_angle
73
+ * aspect_ratio
74
+ """
75
+ __slots__ = ('_vent_control_type', '_reference_temperature',
76
+ '_reference_pressure', '_reference_humidity_ratio',
77
+ '_building_type', '_long_axis_angle', '_aspect_ratio', '_locked')
78
+ VENT_CONTROL_TYPES = ('SingleZone', 'MultiZoneWithDistribution',
79
+ 'MultiZoneWithoutDistribution')
80
+ BUILDING_TYPES = ('LowRise', 'HighRise')
81
+
82
+ def __init__(self, vent_control_type='SingleZone', reference_temperature=20,
83
+ reference_pressure=101325, reference_humidity_ratio=0,
84
+ building_type='LowRise', long_axis_angle=0, aspect_ratio=1):
85
+ """Initialize VentilationSimulationControl."""
86
+ self.vent_control_type = vent_control_type
87
+ self.reference_temperature = reference_temperature
88
+ self.reference_pressure = reference_pressure
89
+ self.reference_humidity_ratio = reference_humidity_ratio
90
+ self.building_type = building_type
91
+ self.long_axis_angle = long_axis_angle
92
+ self.aspect_ratio = aspect_ratio
93
+
94
+ @property
95
+ def vent_control_type(self):
96
+ """Get or set text indicating type of ventilation control type."""
97
+ return self._vent_control_type
98
+
99
+ @vent_control_type.setter
100
+ def vent_control_type(self, value):
101
+ assert value in self.VENT_CONTROL_TYPES, 'vent_control_type {} is not '\
102
+ 'recognized.\nChoose from the following:\n{}'.format(
103
+ value, self.VENT_CONTROL_TYPES)
104
+ self._vent_control_type = value
105
+
106
+ @property
107
+ def reference_temperature(self):
108
+ """Get or set the temperature for the reference crack."""
109
+ return self._reference_temperature
110
+
111
+ @reference_temperature.setter
112
+ def reference_temperature(self, value):
113
+ self._reference_temperature = \
114
+ float_in_range(value, mi=-273.15, input_name='reference_temperature')
115
+
116
+ @property
117
+ def reference_pressure(self):
118
+ """Get or set the barometric pressure for the reference crack."""
119
+ return self._reference_pressure
120
+
121
+ @reference_pressure.setter
122
+ def reference_pressure(self, value):
123
+ self._reference_pressure = \
124
+ float_in_range(value, 31000, 120000, 'reference_pressure')
125
+
126
+ @property
127
+ def reference_humidity_ratio(self):
128
+ """Get or set the humidity ratio for the reference crack."""
129
+ return self._reference_humidity_ratio
130
+
131
+ @reference_humidity_ratio.setter
132
+ def reference_humidity_ratio(self, value):
133
+ self._reference_humidity_ratio = \
134
+ float_positive(value, 'reference_humidity_ratio')
135
+
136
+ @property
137
+ def building_type(self):
138
+ """Get or set text indicating whether the building is high or low rise."""
139
+ return self._building_type
140
+
141
+ @building_type.setter
142
+ def building_type(self, value):
143
+ assert value in self.BUILDING_TYPES, 'building_type {} is not '\
144
+ 'recognized.\nChoose from the following:\n{}'.format(
145
+ value, self.BUILDING_TYPES)
146
+ self._building_type = value
147
+
148
+ @property
149
+ def long_axis_angle(self):
150
+ """Get or set a number between 0 and 180 for the building long axis angle.
151
+
152
+ The value represents the clockwise difference between the long axis and
153
+ true North. 0 indicates a North-South long axis while 90 indicates an
154
+ East-West long axis.
155
+ """
156
+ return self._long_axis_angle
157
+
158
+ @long_axis_angle.setter
159
+ def long_axis_angle(self, value):
160
+ self._long_axis_angle = float_in_range(value, 0, 180, 'long_axis_angle')
161
+
162
+ @property
163
+ def aspect_ratio(self):
164
+ """Get or set a number between 0 and 1 for the building footprint aspect ratio.
165
+ """
166
+ return self._aspect_ratio
167
+
168
+ @aspect_ratio.setter
169
+ def aspect_ratio(self, value):
170
+ self._aspect_ratio = float_in_range_excl_incl(value, 0, 1, 'aspect_ratio')
171
+
172
+ def assign_geometry_properties_from_rooms(self, rooms):
173
+ """Assign the geometry properties of this object using an array of Honeybee Rooms.
174
+
175
+ The building_type (HighRise or LowRise) will be determined by analyzing
176
+ the bounding box around the Rooms (assessing whether the box is taller than
177
+ it is wide + long).
178
+
179
+ This object's long_axis_angle will be used to orient the bounding box and
180
+ compute the aspect ratio of the footprint. If the length of what should
181
+ be the short axis ends up being longer than the other axis, this object's
182
+ long_axis_angle will be rotated 90 degrees in order to keep the aspect
183
+ ratio from being greater than 1.
184
+
185
+ Args:
186
+ rooms: An array of Honeybee Rooms, which will have their geometry
187
+ collectively analyzed in order to set the geometry properties
188
+ of this object. Typically, this should be all of the Rooms of
189
+ a Honeybee Model.
190
+ """
191
+ l_axis = self.long_axis_angle
192
+ bldg_type, aspect_r = self.geometry_properties_from_rooms(rooms, l_axis)
193
+ self.building_type = bldg_type
194
+ if aspect_r > 1: # rotate the long axis 90 degrees
195
+ aspect_r = 1 / aspect_r
196
+ self.long_axis_angle = l_axis + 90 if l_axis < 90 else l_axis - 90
197
+ self.aspect_ratio = aspect_r
198
+
199
+ @classmethod
200
+ def from_dict(cls, data):
201
+ """Create a VentilationSimulationControl object from a dictionary.
202
+
203
+ Args:
204
+ data: A VentilationSimulationControl dictionary following the format below.
205
+
206
+ .. code-block:: python
207
+
208
+ {
209
+ "type": "VentilationSimulationControl"
210
+ "vent_control_type": SingleZone # type of ventilation control
211
+ "reference_temperature": 20 # reference crack temperature
212
+ "reference_pressure": 101320 # reference crack barometric pressure
213
+ "reference_humidity_ratio": 0.5 # reference crack humidity ratio
214
+ "building_type": 'LowRise' # building type text
215
+ "long_axis_angle": 0 # angle of building low axis
216
+ "aspect_ratio": 1 # aspect ratio of building footprint
217
+ }
218
+ """
219
+ assert data['type'] == 'VentilationSimulationControl', 'Expected ' \
220
+ 'VentilationSimulationControl dictionary. Got {}.'.format(data['type'])
221
+
222
+ vent_control_type = data['vent_control_type'] if 'vent_control_type' in data \
223
+ and data['vent_control_type'] is not None else 'SingleZone'
224
+ ref_temp = data['reference_temperature'] if 'reference_temperature' in data \
225
+ and data['reference_temperature'] is not None else 20
226
+ ref_pres = data['reference_pressure'] if \
227
+ 'reference_pressure' in data and \
228
+ data['reference_pressure'] is not None else 101320
229
+ ref_hum = data['reference_humidity_ratio'] if 'reference_humidity_ratio' in \
230
+ data and data['reference_humidity_ratio'] is not None else 0
231
+ bld_type = data['building_type'] if 'building_type' in data and \
232
+ data['building_type'] is not None else 'LowRise'
233
+ axis = data['long_axis_angle'] if 'long_axis_angle' in data and \
234
+ data['long_axis_angle'] is not None else 0
235
+ ratio = data['aspect_ratio'] if 'aspect_ratio' in data and data['aspect_ratio'] \
236
+ is not None else 1
237
+ return cls(vent_control_type, ref_temp, ref_pres, ref_hum, bld_type, axis, ratio)
238
+
239
+ def to_dict(self):
240
+ """VentilationSimulationControl dictionary representation."""
241
+ base = {'type': 'VentilationSimulationControl'}
242
+ base['vent_control_type'] = self.vent_control_type
243
+ base['reference_temperature'] = self.reference_temperature
244
+ base['reference_pressure'] = self.reference_pressure
245
+ base['reference_humidity_ratio'] = self.reference_humidity_ratio
246
+ base['building_type'] = self.building_type
247
+ base['long_axis_angle'] = self.long_axis_angle
248
+ base['aspect_ratio'] = self.aspect_ratio
249
+ return base
250
+
251
+ def duplicate(self):
252
+ """Get a copy of this object."""
253
+ return self.__copy__()
254
+
255
+ @staticmethod
256
+ def geometry_properties_from_rooms(rooms, axis_angle=0):
257
+ """Get AFN building geometry properties from an array of Honeybee Rooms.
258
+
259
+ Args:
260
+ rooms: An array of Honeybee Rooms, which will have their geometry
261
+ collectively analyzed.
262
+ axis_angle: The clockwise rotation angle in degrees in the XY plane
263
+ to represent the orientation of the bounding box. (Default: 0).
264
+
265
+ Returns:
266
+ A tuple with 2 values for geometry properties.
267
+
268
+ 1) Text indicating the building_type (either Highrise or LowRise)
269
+ 2) A number for the aspect ratio of the axis_angle-oriented bounding box.
270
+
271
+ Note that the aspect ratio may be greater than 1 if the axis_angle
272
+ isn't aligned to the long axis of the geometry.
273
+ """
274
+ # process the inputs to be suitable for ladybug_geometry
275
+ if axis_angle != 0: # convert to counter-clockwise radians for ladybug_geometry
276
+ axis_angle = -math.radians(axis_angle)
277
+ geo = [room.geometry for room in rooms] # get ladybug_geometry polyfaces
278
+
279
+ # get the bounding box and return the properties
280
+ xx, yy, zz = bounding_box_extents(geo)
281
+ bldg_type = 'LowRise' if zz <= 3 * max(xx, yy) else 'HighRise'
282
+ return bldg_type, xx / yy
283
+
284
+ def __copy__(self):
285
+ return VentilationSimulationControl(
286
+ self.vent_control_type, self.reference_temperature,
287
+ self.reference_pressure, self.reference_humidity_ratio,
288
+ self.building_type, self.long_axis_angle, self.aspect_ratio)
289
+
290
+ def __key(self):
291
+ """A tuple based on the object properties, useful for hashing."""
292
+ return (self.vent_control_type, self.reference_temperature,
293
+ self.reference_pressure, self.reference_humidity_ratio,
294
+ self.building_type, self.long_axis_angle, self.aspect_ratio)
295
+
296
+ def __hash__(self):
297
+ return hash(self.__key())
298
+
299
+ def __eq__(self, other):
300
+ return isinstance(other, VentilationSimulationControl) and \
301
+ self.__key() == other.__key()
302
+
303
+ def __ne__(self, other):
304
+ return not self.__eq__(other)
305
+
306
+ def ToString(self):
307
+ """Overwrite .NET ToString."""
308
+ return self.__repr__()
309
+
310
+ def __repr__(self):
311
+ return 'VentilationSimulationControl: [control type: {}] ' \
312
+ '[building_type: {}] [long axis: {}] [aspect_ratio: {}]' .format(
313
+ self.vent_control_type, self.building_type,
314
+ round(self.long_axis_angle), round(self.aspect_ratio, 2))