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,493 @@
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 ..reader import parse_idf_string
7
+ from ..writer import generate_idf_string
8
+
9
+ from honeybee._lockable import lockable
10
+ from honeybee.typing import float_in_range, float_positive, valid_string, valid_ep_string
11
+
12
+
13
+ @lockable
14
+ class VentilationFan(object):
15
+ """Definition of a fan for ventilative cooling.
16
+
17
+ This fan is not connected to any heating or cooling system and is meant to
18
+ represent the intentional circulation of unconditioned outdoor air for the
19
+ purposes of keeping a space cooler, drier or free of indoor pollutants (as in
20
+ the case of kitchen or bathroom exhaust fans).
21
+
22
+ Args:
23
+ identifier: Text string for a unique VentilationFan ID. Must be < 100 characters
24
+ and not contain any EnergyPlus special characters. This will be used to
25
+ identify the object across a model and in the exported IDF.
26
+ flow_rate: A positive number for the flow rate of the fan in m3/s.
27
+ ventilation_type: Text to indicate the type of type of ventilation. Choose
28
+ from the options below. For either Exhaust or Intake, values for
29
+ fan pressure and efficiency define the fan electric consumption. For Exhaust
30
+ ventilation, the conditions of the air entering the space are assumed
31
+ to be equivalent to outside air conditions. For Intake and Balanced
32
+ ventilation, an appropriate amount of fan heat is added to the
33
+ entering air stream. For Balanced ventilation, both an intake fan
34
+ and an exhaust fan are assumed to co-exist, both having the same
35
+ flow rate and power consumption (using the entered values for fan
36
+ pressure rise and fan total efficiency). Thus, the fan electric
37
+ consumption for Balanced ventilation is twice that for the Exhaust or
38
+ Intake ventilation types which employ only a single fan. (Default: Balanced).
39
+
40
+ * Exhaust
41
+ * Intake
42
+ * Balanced
43
+
44
+ pressure_rise: A number for the the pressure rise across the fan in Pascals
45
+ (N/m2). This is often a function of the fan speed and the conditions in
46
+ which the fan is operating since having the fan blow air through filters
47
+ or narrow ducts will increase the pressure rise that is needed to
48
+ deliver the input flow rate. The pressure rise plays an important role in
49
+ determining the amount of energy consumed by the fan. Smaller fans like
50
+ a 0.05 m3/s desk fan tend to have lower pressure rises around 60 Pa.
51
+ Larger fans, such as a 6 m3/s fan used for ventilating a large room tend
52
+ to have higher pressure rises around 400 Pa. The highest pressure rises
53
+ are typically for large fans blowing air through ducts and filters, which
54
+ can have pressure rises as high as 1000 Pa. If this input is None,
55
+ the pressure rise will be estimated from the flow_rate, with higher
56
+ flow rates corresponding to larger pressure rises (up to 400 Pa). These
57
+ estimated pressure rises are generally assumed to have minimal obstructions
58
+ between the fan and the room and they should be increased if the fan is
59
+ blowing air through ducts or filters. (Default: None).
60
+ efficiency: A number between 0 and 1 for the overall efficiency of the fan.
61
+ Specifically, this is the ratio of the power delivered to the fluid
62
+ to the electrical input power. It is the product of the fan motor
63
+ efficiency and the fan impeller efficiency. Fans that have a higher blade
64
+ diameter and operate at lower speeds with smaller pressure rises for
65
+ their size tend to have higher efficiencies. Because motor efficiencies
66
+ are typically between 0.8 and 0.9, the best overall fan efficiencies
67
+ tend to be around 0.7 with most typical fan efficiencies between 0.5 and
68
+ 0.7. The lowest efficiencies often happen for small fans in situations
69
+ with high pressure rises for their size, which can result in efficiencies
70
+ as low as 0.15. If None, this input will be estimated from the fan
71
+ flow rate and pressure rise with large fans operating at low pressure
72
+ rises for their size having up to 0.7 efficiency and small fans
73
+ operating at high pressure rises for their size having as low as
74
+ 0.15 efficiency. (Default: None).
75
+ control: A VentilationControl object that dictates the conditions under
76
+ which the fan is turned on. If None, a default VentilationControl will
77
+ be generated, which will keep the fan on all of the time. (Default: None).
78
+
79
+ Properties:
80
+ * identifier
81
+ * display_name
82
+ * flow_rate
83
+ * ventilation_type
84
+ * pressure_rise
85
+ * efficiency
86
+ * control
87
+ """
88
+ __slots__ = (
89
+ '_identifier', '_display_name', '_flow_rate', '_ventilation_type',
90
+ '_pressure_rise', '_efficiency', '_control', '_locked')
91
+ # types of ventilation
92
+ VENTILATION_TYPES = ('Exhaust', 'Intake', 'Balanced')
93
+ # values relating flow rates to pressure rises
94
+ PRESSURE_RISES = (
95
+ (0.01, 10),
96
+ (0.05, 60),
97
+ (0.25, 120),
98
+ (0.5, 200),
99
+ (2, 300),
100
+ (6, 400)
101
+ )
102
+
103
+ def __init__(self, identifier, flow_rate, ventilation_type='Balanced',
104
+ pressure_rise=None, efficiency=None, control=None):
105
+ """Initialize VentilationControl."""
106
+ self._locked = False # unlocked by default
107
+ self.identifier = identifier
108
+ self._display_name = None
109
+ self.flow_rate = flow_rate
110
+ self.ventilation_type = ventilation_type
111
+ self.pressure_rise = pressure_rise
112
+ self.efficiency = efficiency
113
+ self.control = control
114
+
115
+ @property
116
+ def identifier(self):
117
+ """Get or set the text string for object identifier."""
118
+ return self._identifier
119
+
120
+ @identifier.setter
121
+ def identifier(self, identifier):
122
+ self._identifier = valid_ep_string(identifier)
123
+
124
+ @property
125
+ def display_name(self):
126
+ """Get or set a string for the object name without any character restrictions.
127
+
128
+ If not set, this will be equal to the identifier.
129
+ """
130
+ if self._display_name is None:
131
+ return self._identifier
132
+ return self._display_name
133
+
134
+ @display_name.setter
135
+ def display_name(self, value):
136
+ if value is not None:
137
+ try:
138
+ value = str(value)
139
+ except UnicodeEncodeError: # Python 2 machine lacking the character set
140
+ pass # keep it as unicode
141
+ self._display_name = value
142
+
143
+ @property
144
+ def flow_rate(self):
145
+ """Get or set a number for the fan flow rate in m3/s."""
146
+ return self._flow_rate
147
+
148
+ @flow_rate.setter
149
+ def flow_rate(self, value):
150
+ self._flow_rate = float_positive(value, 'fan flow rate')
151
+
152
+ @property
153
+ def ventilation_type(self):
154
+ """Get or set text to indicate the type of ventilation.
155
+
156
+ Choose from the following options:
157
+
158
+ * Exhaust
159
+ * Intake
160
+ * Balanced
161
+ """
162
+ return self._ventilation_type
163
+
164
+ @ventilation_type.setter
165
+ def ventilation_type(self, value):
166
+ clean_input = valid_string(value).lower()
167
+ for key in self.VENTILATION_TYPES:
168
+ if key.lower() == clean_input:
169
+ value = key
170
+ break
171
+ else:
172
+ raise ValueError(
173
+ 'ventilation_type {} is not recognized.\nChoose from the '
174
+ 'following:\n{}'.format(value, self.VENTILATION_TYPES))
175
+ self._ventilation_type = value
176
+
177
+ @property
178
+ def pressure_rise(self):
179
+ """Get or set a number for the fan flow rate in m3/s."""
180
+ if self._pressure_rise is not None:
181
+ return self._pressure_rise
182
+ return self._default_pressure_rise()
183
+
184
+ @pressure_rise.setter
185
+ def pressure_rise(self, value):
186
+ if value is not None:
187
+ value = float_positive(value, 'fan pressure rise')
188
+ self._pressure_rise = value
189
+
190
+ @property
191
+ def efficiency(self):
192
+ """Get or set a number between 0 and 1 for the fan efficiency."""
193
+ if self._efficiency is not None:
194
+ return self._efficiency
195
+ return self._default_efficiency()
196
+
197
+ @efficiency.setter
198
+ def efficiency(self, value):
199
+ if value is not None:
200
+ value = float_in_range(value, 0, 1, 'fan efficiency')
201
+ self._efficiency = value
202
+
203
+ @property
204
+ def control(self):
205
+ """Get or set a VentilationControl object to dictate when the fan comes on."""
206
+ return self._control
207
+
208
+ @control.setter
209
+ def control(self, value):
210
+ if value is not None:
211
+ assert isinstance(value, VentilationControl), 'Expected VentilationControl' \
212
+ ' object for Fan control. Got {}'.format(type(value))
213
+ else:
214
+ value = VentilationControl()
215
+ self._control = value
216
+
217
+ @classmethod
218
+ def from_idf(cls, idf_string, schedule_dict):
219
+ """Create a VentilationFan object from an EnergyPlus IDF text string.
220
+
221
+ Note that the ZoneVentilation:DesignFlowRate idf_string must use
222
+ the 'Flow/Zone' method in order to be successfully imported.
223
+
224
+ Args:
225
+ idf_string: A text string fully describing an EnergyPlus
226
+ ZoneVentilation:DesignFlowRate definition.
227
+ schedule_dict: A dictionary with schedule identifiers as keys and honeybee
228
+ schedule objects as values (either ScheduleRuleset or
229
+ ScheduleFixedInterval). These will be used to assign the schedules to
230
+ the VentilationControl object that governs the control of the fan.
231
+
232
+ Returns:
233
+ A tuple with two elements
234
+
235
+ - fan: An VentilationFan object loaded from the idf_string.
236
+
237
+ - zone_id: The identifier of the zone to which the
238
+ VentilationFan object should be assigned.
239
+ """
240
+ # check the inputs
241
+ ep_strs = parse_idf_string(idf_string, 'ZoneVentilation:DesignFlowRate,')
242
+ # check the inputs
243
+ assert len(ep_strs) >= 9, 'ZoneVentilation:DesignFlowRate does not contain ' \
244
+ 'enough information to be loaded to a VentilationFan.'
245
+ assert ep_strs[3].lower() == 'flow/zone', 'ZoneVentilation:DesignFlowRate ' \
246
+ 'must use Flow/Zone method to be loaded to a VentilationFan.'
247
+ assert ep_strs[8] != '' and ep_strs[8].lower() != 'natural', \
248
+ 'ZoneVentilation:DesignFlowRate cannot use Natural ventilation ' \
249
+ 'to be loaded to a VentilationFan.'
250
+ # extract the properties from the string
251
+ sched = None
252
+ flow = 0
253
+ vt = 'Balanced'
254
+ pressure = 0
255
+ eff = 1
256
+ min_in_t = -100
257
+ max_in_t = 100
258
+ delta_t = -100
259
+ min_out_t = -100
260
+ max_out_t = 100
261
+ try:
262
+ sched = ep_strs[2] if ep_strs[2] != '' else None
263
+ flow = ep_strs[4] if ep_strs[4] != '' else 0
264
+ vt = ep_strs[8] if ep_strs[8] != '' else 'Balanced'
265
+ pressure = ep_strs[9] if ep_strs[9] != '' else 0
266
+ eff = ep_strs[10] if ep_strs[10] != '' else 1
267
+ min_in_t = ep_strs[15] if ep_strs[15] != '' else -100
268
+ max_in_t = ep_strs[17] if ep_strs[17] != '' else 100
269
+ delta_t = ep_strs[19] if ep_strs[19] != '' else -100
270
+ min_out_t = ep_strs[21] if ep_strs[21] != '' else -100
271
+ max_out_t = ep_strs[23] if ep_strs[23] != '' else 100
272
+ except IndexError:
273
+ pass # shorter IDF definition lacking specifications
274
+ # extract the schedules from the string
275
+ try:
276
+ if sched is not None:
277
+ sched = schedule_dict[sched]
278
+ except KeyError as e:
279
+ raise ValueError('Failed to find {} in the schedule_dict.'.format(e))
280
+ control = VentilationControl(
281
+ min_in_t, max_in_t, min_out_t, max_out_t, delta_t, sched)
282
+
283
+ # return the fan object and the zone identifier for the fan object
284
+ obj_id = ep_strs[0].split('..')[0]
285
+ zone_id = ep_strs[2]
286
+ fan = cls(obj_id, flow, vt, pressure, eff, control)
287
+ return fan, zone_id
288
+
289
+ @classmethod
290
+ def from_dict(cls, data):
291
+ """Create a VentilationFan from a dictionary.
292
+
293
+ Args:
294
+ data: A python dictionary in the following format
295
+
296
+ .. code-block:: python
297
+
298
+ {
299
+ "type": 'VentilationFan',
300
+ "flow_rate": 1.0,
301
+ "ventilation_type": "Exhaust",
302
+ "pressure_rise": 200,
303
+ "efficiency": 0.7,
304
+ "control": {} # dictionary of a VentilationControl
305
+ }
306
+ """
307
+ assert data['type'] == 'VentilationFan', \
308
+ 'Expected VentilationFan. Got {}.'.format(data['type'])
309
+ vt, pr, eff = cls._default_dict_values(data)
310
+ ctrl = VentilationControl.from_dict(data['control']) \
311
+ if 'control' in data and data['control'] is not None else None
312
+ new_obj = cls(data['identifier'], data['flow_rate'], vt, pr, eff, ctrl)
313
+ if 'display_name' in data and data['display_name'] is not None:
314
+ new_obj.display_name = data['display_name']
315
+ return new_obj
316
+
317
+ @classmethod
318
+ def from_dict_abridged(cls, data, schedule_dict):
319
+ """Create a VentilationFan from an abridged dictionary.
320
+
321
+ Args:
322
+ data: A VentilationFanAbridged dictionary with the format below.
323
+ schedule_dict: A dictionary with schedule identifiers as keys and
324
+ honeybee schedule objects as values. These will be used to
325
+ assign the schedule to the VentilationControl object.
326
+
327
+ .. code-block:: python
328
+
329
+ {
330
+ "type": 'VentilationFanAbridged',
331
+ "flow_rate": 1.0,
332
+ "ventilation_type": "Exhaust",
333
+ "pressure_rise": 200,
334
+ "efficiency": 0.7,
335
+ "control": {} # dictionary of a VentilationControlAbridged
336
+ }
337
+ """
338
+ assert data['type'] == 'VentilationFanAbridged', \
339
+ 'Expected VentilationFanAbridged. Got {}.'.format(data['type'])
340
+ vt, pr, eff = cls._default_dict_values(data)
341
+ ctrl = VentilationControl.from_dict_abridged(data['control'], schedule_dict) \
342
+ if 'control' in data and data['control'] is not None else None
343
+ new_obj = cls(data['identifier'], data['flow_rate'], vt, pr, eff, ctrl)
344
+ if 'display_name' in data and data['display_name'] is not None:
345
+ new_obj.display_name = data['display_name']
346
+ return new_obj
347
+
348
+ def to_idf(self, zone_identifier):
349
+ """IDF string representation of VentilationFan object.
350
+
351
+ Note that this method does not return full definitions of the VentilationControl
352
+ schedules and so this objects's schedules must also be translated into
353
+ the final IDF file.
354
+
355
+ Args:
356
+ zone_identifier: Text for the zone identifier that the VentilationFan
357
+ object is assigned to.
358
+
359
+ .. code-block::
360
+
361
+ ZoneVentilation:DesignFlowRate,
362
+ Ventilation 1, !- Name
363
+ ZONE 2, !- Zone Name
364
+ Simple Vent, !- Schedule Name
365
+ Flow/Zone, !- Design Volume Flow Rate calculation method
366
+ 6.131944, !- Design Volume Flow Rate {m3/s}
367
+ , !- Flow Rate per Floor Area {m3/s-m2}
368
+ , !- Flow Rate per Person {m3/s-person}
369
+ , !- Air Changes per Hour
370
+ INTAKE, !- Ventilation Type
371
+ 400.0, !- Fan Pressure Rise{Pa}
372
+ 0.9, !- Fan Total Efficiency
373
+ 0.6060000 , !- Constant Term Coefficient
374
+ 2.0199999E-02, !- Temperature Term Coefficient
375
+ 5.9800001E-04, !- Velocity Term Coefficient
376
+ 0.0000000E+00!- Velocity Squared Term Coefficient
377
+ 18.0, !- Minimum Indoor Temperature {C}
378
+ , !- Minimum Indoor Temperature Schedule Name
379
+ , !- Maximum Indoor Temperature {C}
380
+ , !- Maximum Indoor Temperature Schedule Name
381
+ 1.0; !- Delta temperature {C}
382
+ """
383
+
384
+ # process the properties on this object into IDF format
385
+ cntrl = self.control
386
+ values = (
387
+ '{}..{}'.format(self.identifier, zone_identifier), zone_identifier,
388
+ cntrl.schedule.identifier, 'Flow/Zone', self.flow_rate, '', '', '',
389
+ self.ventilation_type, self.pressure_rise, self.efficiency, '1', '', '', '',
390
+ cntrl.min_indoor_temperature, '', cntrl.max_indoor_temperature, '',
391
+ cntrl.delta_temperature, '',
392
+ cntrl.min_outdoor_temperature, '', cntrl.max_outdoor_temperature, '', 40)
393
+ comments = (
394
+ 'name', 'zone name', 'schedule', 'flow calculation method',
395
+ 'flow rate {m3/s}', 'flow per floor {m3/s-m2}',
396
+ 'flow per person {m3/s-person}' 'flow ach', 'ventilation type',
397
+ 'fan pressure rise', 'fan total efficiency', 'constant term',
398
+ 'temperature term', 'velocity term', 'velocity squared term',
399
+ 'min indoor temperature {C}', 'min in temp schedule',
400
+ 'max indoor temperature {C}', 'max in temp schedule',
401
+ 'delta temperature {C}', 'delta temp schedule',
402
+ 'min outdoor temperature {C}', 'min out temp schedule',
403
+ 'max outdoor temperature {C}', 'max out temp schedule', 'max wind speed')
404
+ return generate_idf_string(
405
+ 'ZoneVentilation:DesignFlowRate', values, comments)
406
+
407
+ def to_dict(self, abridged=False):
408
+ """Ventilation Fan dictionary representation."""
409
+ base = {'type': 'VentilationFan'} if not \
410
+ abridged else {'type': 'VentilationFanAbridged'}
411
+ base['identifier'] = self.identifier
412
+ base['flow_rate'] = self.flow_rate
413
+ base['ventilation_type'] = self.ventilation_type
414
+ base['pressure_rise'] = self.pressure_rise
415
+ base['efficiency'] = self.efficiency
416
+ base['control'] = self.control.to_dict(abridged)
417
+ if self._display_name is not None:
418
+ base['display_name'] = self.display_name
419
+ return base
420
+
421
+ def lock(self):
422
+ """The lock() method will also lock the control."""
423
+ self._locked = True
424
+ self._control.lock()
425
+
426
+ def unlock(self):
427
+ """The unlock() method will also unlock the control."""
428
+ self._locked = False
429
+ self._control.unlock()
430
+
431
+ def duplicate(self):
432
+ """Get a copy of this object."""
433
+ return self.__copy__()
434
+
435
+ def _default_pressure_rise(self):
436
+ """Calculate the pressure rise from the assigned flow rate."""
437
+ if self._flow_rate < self.PRESSURE_RISES[0][0]:
438
+ return self.PRESSURE_RISES[0][1]
439
+ if self._flow_rate > self.PRESSURE_RISES[-1][0]:
440
+ return self.PRESSURE_RISES[-1][1]
441
+ for i, (flow, pr) in enumerate(self.PRESSURE_RISES):
442
+ if flow <= self._flow_rate <= self.PRESSURE_RISES[i + 1][0]:
443
+ f_num = self._flow_rate - flow
444
+ f_denom = self.PRESSURE_RISES[i + 1][0] - flow
445
+ f_dist = f_num / f_denom
446
+ return pr + (f_dist * (self.PRESSURE_RISES[i + 1][1] - pr))
447
+
448
+ def _default_efficiency(self):
449
+ """Calculate the efficiency from the assigned flow rate and pressure rise."""
450
+ pr_rise_ratio = self.pressure_rise / self._default_pressure_rise()
451
+ eff_est = 0.8 - (pr_rise_ratio * 0.1)
452
+ if eff_est > 0.7:
453
+ return 0.7
454
+ if eff_est < 0.15:
455
+ return 0.15
456
+ return eff_est
457
+
458
+ @staticmethod
459
+ def _default_dict_values(data):
460
+ """Process dictionary values and include defaults for missing values."""
461
+ vt = data['ventilation_type'] if 'ventilation_type' in data \
462
+ and data['ventilation_type'] is not None else 'Balanced'
463
+ pr = data['pressure_rise'] if 'pressure_rise' in data else None
464
+ eff = data['efficiency'] if 'efficiency' in data else None
465
+ return vt, pr, eff
466
+
467
+ def __copy__(self):
468
+ new_obj = VentilationFan(
469
+ self._identifier, self._flow_rate, self._ventilation_type,
470
+ self._pressure_rise, self._efficiency, self._control.duplicate())
471
+ new_obj._display_name = self._display_name
472
+ return new_obj
473
+
474
+ def __key(self):
475
+ """A tuple based on the object properties, useful for hashing."""
476
+ return (self.identifier, self.flow_rate, self.ventilation_type,
477
+ self.pressure_rise, self.efficiency, hash(self.control))
478
+
479
+ def __hash__(self):
480
+ return hash(self.__key())
481
+
482
+ def __eq__(self, other):
483
+ return isinstance(other, VentilationFan) and self.__key() == other.__key()
484
+
485
+ def __ne__(self, other):
486
+ return not self.__eq__(other)
487
+
488
+ def ToString(self):
489
+ """Overwrite .NET ToString."""
490
+ return self.__repr__()
491
+
492
+ def __repr__(self):
493
+ return 'VentilationFan: {}'.format(self.display_name)