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,460 @@
1
+ # coding=utf-8
2
+ """Complete definition of infiltration in a simulation, including schedule and load."""
3
+ from __future__ import division
4
+
5
+ from honeybee._lockable import lockable
6
+ from honeybee.typing import float_positive, clean_and_id_ep_string
7
+
8
+ from ._base import _LoadBase
9
+ from ..schedule.ruleset import ScheduleRuleset
10
+ from ..schedule.fixedinterval import ScheduleFixedInterval
11
+ from ..reader import parse_idf_string
12
+ from ..writer import generate_idf_string
13
+ from ..properties.extension import InfiltrationProperties
14
+
15
+
16
+ @lockable
17
+ class Infiltration(_LoadBase):
18
+ """A complete definition of infiltration, including schedules and load.
19
+
20
+ Args:
21
+ identifier: Text string for a unique Infiltration ID. Must be < 100 characters
22
+ and not contain any EnergyPlus special characters. This will be used to
23
+ identify the object across a model and in the exported IDF.
24
+ flow_per_exterior_area: A numerical value for the intensity of infiltration
25
+ in m3/s per square meter of exterior surface area. Typical values for
26
+ this property are as follows (note all values are at typical building
27
+ pressures of ~4 Pa):
28
+
29
+ * 0.0001 (m3/s per m2 facade) - Tight building
30
+ * 0.0003 (m3/s per m2 facade) - Average building
31
+ * 0.0006 (m3/s per m2 facade) - Leaky building
32
+
33
+ schedule: A ScheduleRuleset or ScheduleFixedInterval for the infiltration
34
+ over the course of the year. The type of this schedule should be
35
+ Fractional and the fractional values will get multiplied by the
36
+ flow_per_exterior_area to yield a complete infiltration profile.
37
+ constant_coefficient: A number for the fraction of the infiltration that
38
+ remains constant in spite of exterior wind and the difference
39
+ between interior/exterior temperature. EnergyPlus uses 1 by default but
40
+ BLAST and DOE-2 (the EnergyPlus predecessors) used 0.606 and 0 for
41
+ this coefficient respectively. Default: 1.
42
+ temperature_coefficient: A number that will get multiplied by the difference
43
+ in interior/exterior temperature (in C) to yield a coefficient that
44
+ gets multiplied by the flow_per_exterior_area. EnergyPlus uses 0 by
45
+ default but BLAST and DOE-2 (the EnergyPlus predecessors) used 0.03636
46
+ and 0 for this coefficient respectively. Default: 0.
47
+ velocity_coefficient: A number that will get multiplied by the hourly
48
+ exterior wind velocity (in m/s) to yield a coefficient that gets
49
+ multiplied by the flow_per_exterior_area. EnergyPlus uses 0 by default
50
+ but BLAST and DOE-2 (the EnergyPlus predecessors) used 0.1177 and 0.224
51
+ for this coefficient respectively. Default: 0.
52
+
53
+ Properties:
54
+ * identifier
55
+ * display_name
56
+ * flow_per_exterior_area
57
+ * schedule
58
+ * constant_coefficient
59
+ * temperature_coefficient
60
+ * velocity_coefficient
61
+ * user_data
62
+ """
63
+ __slots__ = ('_flow_per_exterior_area', '_schedule', '_constant_coefficient',
64
+ '_temperature_coefficient', '_velocity_coefficient')
65
+
66
+ def __init__(self, identifier, flow_per_exterior_area, schedule,
67
+ constant_coefficient=1,
68
+ temperature_coefficient=0, velocity_coefficient=0):
69
+ """Initialize Infiltration."""
70
+ _LoadBase.__init__(self, identifier)
71
+ self.flow_per_exterior_area = flow_per_exterior_area
72
+ self.schedule = schedule
73
+ self.constant_coefficient = constant_coefficient
74
+ self.temperature_coefficient = temperature_coefficient
75
+ self.velocity_coefficient = velocity_coefficient
76
+ self._properties = InfiltrationProperties(self)
77
+
78
+ @property
79
+ def flow_per_exterior_area(self):
80
+ """Get or set the infiltration in m3/s per square meter of exterior surface area.
81
+
82
+ Typical values for this property are as follows:
83
+
84
+ * 0.0001 (m3/s per m2 facade) - Tight building
85
+ * 0.0003 (m3/s per m2 facade) - Average building
86
+ * 0.0006 (m3/s per m2 facade) - Leaky building
87
+ """
88
+ return self._flow_per_exterior_area
89
+
90
+ @flow_per_exterior_area.setter
91
+ def flow_per_exterior_area(self, value):
92
+ self._flow_per_exterior_area = float_positive(
93
+ value, 'infiltration flow per area')
94
+
95
+ @property
96
+ def schedule(self):
97
+ """Get or set a ScheduleRuleset or ScheduleFixedInterval for infiltration."""
98
+ return self._schedule
99
+
100
+ @schedule.setter
101
+ def schedule(self, value):
102
+ assert isinstance(value, (ScheduleRuleset, ScheduleFixedInterval)), \
103
+ 'Expected ScheduleRuleset or ScheduleFixedInterval for Infiltration ' \
104
+ 'schedule. Got {}.'.format(type(value))
105
+ self._check_fractional_schedule_type(value, 'Infiltration')
106
+ value.lock() # lock editing in case schedule has multiple references
107
+ self._schedule = value
108
+
109
+ @property
110
+ def constant_coefficient(self):
111
+ """Get or set the fraction of infiltration remaining constant despite outdoors.
112
+ """
113
+ return self._constant_coefficient
114
+
115
+ @constant_coefficient.setter
116
+ def constant_coefficient(self, value):
117
+ self._constant_coefficient = float_positive(
118
+ value, 'infiltration constant coefficient')
119
+
120
+ @property
121
+ def temperature_coefficient(self):
122
+ """Get or set the coefficient for the interior/exterior temperature difference.
123
+ """
124
+ return self._temperature_coefficient
125
+
126
+ @temperature_coefficient.setter
127
+ def temperature_coefficient(self, value):
128
+ self._temperature_coefficient = float_positive(
129
+ value, 'infiltration temperature coefficient')
130
+
131
+ @property
132
+ def velocity_coefficient(self):
133
+ """Get or set the coefficient for the exterior wind speed."""
134
+ return self._velocity_coefficient
135
+
136
+ @velocity_coefficient.setter
137
+ def velocity_coefficient(self, value):
138
+ self._velocity_coefficient = float_positive(
139
+ value, 'infiltration velocity coefficient')
140
+
141
+ def diversify(self, count, flow_stdev=20, schedule_offset=1, timestep=1,
142
+ schedule_indices=None):
143
+ """Get an array of diversified Infiltration derived from this "average" one.
144
+
145
+ Approximately 2/3 of the schedules in the output objects will be offset
146
+ from the mean by the input schedule_offset (1/3 ahead and another 1/3 behind).
147
+
148
+ Args:
149
+ count: An positive integer for the number of diversified objects to
150
+ generate from this mean object.
151
+ flow_stdev: A number between 0 and 100 for the percent of the
152
+ flow_per_exterior_area representing one standard deviation of
153
+ diversification from the mean. (Default 20 percent).
154
+ schedule_offset: A positive integer for the number of timesteps at which
155
+ the lighting schedule of the resulting objects will be shifted - roughly
156
+ 1/3 of the objects ahead and another 1/3 behind. (Default: 1).
157
+ timestep: An integer for the number of timesteps per hour at which the
158
+ shifting is occurring. This must be a value between 1 and 60, which
159
+ is evenly divisible by 60. 1 indicates that each step is an hour
160
+ while 60 indicates that each step is a minute. (Default: 1).
161
+ schedule_indices: An optional list of integers from 0 to 2 with a length
162
+ equal to the input count, which will be used to set whether a given
163
+ schedule is behind (0), ahead (2), or the same (1). This can be
164
+ used to coordinate schedules across diversified programs. If None
165
+ a random list of integers will be genrated. (Default: None).
166
+ """
167
+ # generate shifted schedules and gaussian distribution of flow_per_exterior_area
168
+ usage_schs = self._shift_schedule(self.schedule, schedule_offset, timestep)
169
+ stdev = self.flow_per_exterior_area * (flow_stdev / 100)
170
+ new_loads, sch_ints = self._gaussian_values(
171
+ count, self.flow_per_exterior_area, stdev)
172
+ sch_ints = sch_ints if schedule_indices is None else schedule_indices
173
+
174
+ # generate the new objects and return them
175
+ new_objects = []
176
+ for load_val, sch_int in zip(new_loads, sch_ints):
177
+ new_obj = self.duplicate()
178
+ new_obj.identifier = clean_and_id_ep_string(self.identifier)
179
+ new_obj.flow_per_exterior_area = load_val
180
+ new_obj.schedule = usage_schs[sch_int]
181
+ new_objects.append(new_obj)
182
+ return new_objects
183
+
184
+ @classmethod
185
+ def from_idf(cls, idf_string, schedule_dict):
186
+ """Create an Infiltration object from an EnergyPlus IDF text string.
187
+
188
+ Note that the idf_string must use the 'flow per exterior surface area'
189
+ method in order to be successfully imported.
190
+
191
+ Args:
192
+ idf_string: A text string fully describing an EnergyPlus
193
+ ZoneInfiltration:DesignFlowRate definition.
194
+ schedule_dict: A dictionary with schedule identifiers as keys and honeybee
195
+ schedule objects as values (either ScheduleRuleset or
196
+ ScheduleFixedInterval). These will be used to assign the schedules to
197
+ the Infiltration object.
198
+
199
+ Returns:
200
+ A tuple with two elements
201
+
202
+ - infiltration: An Infiltration object loaded from the idf_string.
203
+
204
+ - zone_identifier: The identifier of the zone to which the Infiltration
205
+ object should be assigned.
206
+ """
207
+ # check the inputs
208
+ ep_strs = parse_idf_string(idf_string, 'ZoneInfiltration:DesignFlowRate,')
209
+ assert ep_strs[3].lower() == 'flow/exteriorarea', \
210
+ 'ZoneInfiltration:DesignFlowRate must use Flow/ExteriorArea method ' \
211
+ 'to be loaded from IDF to honeybee.'
212
+
213
+ # extract the properties from the string
214
+ const = 1
215
+ temp = 0
216
+ vel = 0
217
+ try:
218
+ const = ep_strs[8] if ep_strs[8] != '' else 0
219
+ temp = ep_strs[9] if ep_strs[9] != '' else 0
220
+ vel = ep_strs[10] if ep_strs[10] != '' else 0
221
+ except IndexError:
222
+ pass # shorter infiltration definition lacking coefficients
223
+
224
+ # extract the schedules from the string
225
+ try:
226
+ sched = schedule_dict[ep_strs[2]]
227
+ except KeyError as e:
228
+ raise ValueError('Failed to find {} in the schedule_dict.'.format(e))
229
+
230
+ # return the object and the zone identifier for the object
231
+ obj_id = ep_strs[0].split('..')[0]
232
+ zone_id = ep_strs[1]
233
+ infiltration = cls(obj_id, ep_strs[6], sched, const, temp, vel)
234
+ return infiltration, zone_id
235
+
236
+ @classmethod
237
+ def from_dict(cls, data):
238
+ """Create a Infiltration object from a dictionary.
239
+
240
+ Note that the dictionary must be a non-abridged version for this classmethod
241
+ to work.
242
+
243
+ Args:
244
+ data: A Infiltration dictionary in following the format below.
245
+
246
+ .. code-block:: python
247
+
248
+ {
249
+ "type": 'Infiltration',
250
+ "identifier": 'Residentail_Infiltration_000030_1_0_0',
251
+ "display_name": 'Residentail Infiltration',
252
+ "flow_per_exterior_area": 0.0003, # flow per square meter of exterior area
253
+ "schedule": {}, # ScheduleRuleset/ScheduleFixedInterval dictionary
254
+ "constant_coefficient": 1, # optional constant coefficient
255
+ "temperature_coefficient": 0, # optional temperature coefficient
256
+ "velocity_coefficient": 0 # optional velocity coefficient
257
+ }
258
+ """
259
+ assert data['type'] == 'Infiltration', \
260
+ 'Expected Infiltration dictionary. Got {}.'.format(data['type'])
261
+ sched = cls._get_schedule_from_dict(data['schedule'])
262
+ const, tem, vel = cls._optional_dict_keys(data)
263
+ new_obj = cls(data['identifier'], data['flow_per_exterior_area'],
264
+ sched, const, tem, vel)
265
+ if 'display_name' in data and data['display_name'] is not None:
266
+ new_obj.display_name = data['display_name']
267
+ if 'user_data' in data and data['user_data'] is not None:
268
+ new_obj.user_data = data['user_data']
269
+ if 'properties' in data and data['properties'] is not None:
270
+ new_obj.properties._load_extension_attr_from_dict(data['properties'])
271
+ return new_obj
272
+
273
+ @classmethod
274
+ def from_dict_abridged(cls, data, schedule_dict):
275
+ """Create a Infiltration object from an abridged dictionary.
276
+
277
+ Args:
278
+ data: A InfiltrationAbridged dictionary in following the format below.
279
+ schedule_dict: A dictionary with schedule identifiers as keys and
280
+ honeybee schedule objects as values (either ScheduleRuleset or
281
+ ScheduleFixedInterval). These will be used to assign the schedules
282
+ to the Infiltration object.
283
+
284
+ .. code-block:: python
285
+
286
+ {
287
+ "type": 'InfiltrationAbridged',
288
+ "identifier": 'Residentail_Infiltration_000030_1_0_0',
289
+ "display_name": 'Residentail Infiltration',
290
+ "flow_per_exterior_area": 0.0003, # flow per square meter of exterior area
291
+ "schedule": "Residentail Infiltration Schedule", # Schedule identifier
292
+ "constant_coefficient": 1, # optional constant coefficient
293
+ "temperature_coefficient": 0, # optional temperature coefficient
294
+ "velocity_coefficient": 0 # optional velocity coefficient
295
+ }
296
+ """
297
+ assert data['type'] == 'InfiltrationAbridged', \
298
+ 'Expected InfiltrationAbridged dictionary. Got {}.'.format(data['type'])
299
+ try:
300
+ sched = schedule_dict[data['schedule']]
301
+ except KeyError as e:
302
+ raise ValueError('Failed to find {} in the schedule_dict.'.format(e))
303
+ const, tem, vel = cls._optional_dict_keys(data)
304
+ new_obj = cls(data['identifier'], data['flow_per_exterior_area'],
305
+ sched, const, tem, vel)
306
+ if 'display_name' in data and data['display_name'] is not None:
307
+ new_obj.display_name = data['display_name']
308
+ if 'user_data' in data and data['user_data'] is not None:
309
+ new_obj.user_data = data['user_data']
310
+ if 'properties' in data and data['properties'] is not None:
311
+ new_obj.properties._load_extension_attr_from_dict(data['properties'])
312
+ return new_obj
313
+
314
+ def to_idf(self, zone_identifier):
315
+ """IDF string representation of Infiltration object.
316
+
317
+ Note that this method only outputs a single string for the ZoneInfiltration:
318
+ DesignFlowRate object and, to write everything needed to describe the
319
+ object into an IDF, this object's schedule must also be written.
320
+
321
+ Args:
322
+ zone_identifier: Text for the zone identifier that the ZoneInfiltration:
323
+ DesignFlowRate object is assigned to.
324
+
325
+ .. code-block:: shell
326
+
327
+ ZoneInfiltration:DesignFlowRate,
328
+ Infiltration 1, !- Name
329
+ DORM ROOMS AND COMMON AREAS, !- Zone Name
330
+ Infiltration Sch, !- Schedule Name
331
+ Flow/Zone, !- Design Flow Rate Calculation Method
332
+ , !- Design Flow Rate {m3/s}
333
+ , !- Flow Rate per Floor Area {m3/s/m2}
334
+ 0.0003, !- Flow Rate per Exterior Surface Area {m3/s/m2}
335
+ , !- Air Changes per Hour
336
+ 0.6060000 , !- Constant Term Coefficient
337
+ 3.6359996E-02, !- Temperature Term Coefficient
338
+ 0.1177165 , !- Velocity Term Coefficient
339
+ 0.0000000E+00; !- Velocity Squared Term Coefficient
340
+ """
341
+ values = ('{}..{}'.format(self.identifier, zone_identifier), zone_identifier,
342
+ self.schedule.identifier, 'Flow/ExteriorArea', '', '',
343
+ self.flow_per_exterior_area, '', self.constant_coefficient,
344
+ self.temperature_coefficient, self.velocity_coefficient, '')
345
+ comments = ('name', 'zone name', 'schedule name', 'flow rate method',
346
+ 'flow rate {m3/s}', 'flow per floor area {m3/s-m2}',
347
+ 'flow per exterior area {m3/s-m2}', 'air changes per hour {1/hr}',
348
+ 'constant term coefficient', 'temperature term coefficient',
349
+ 'velocity term coefficient', 'velocity squared term coefficient')
350
+ return generate_idf_string('ZoneInfiltration:DesignFlowRate', values, comments)
351
+
352
+ def to_dict(self, abridged=False):
353
+ """Infiltration dictionary representation.
354
+
355
+ Args:
356
+ abridged: Boolean to note whether the full dictionary describing the
357
+ object should be returned (False) or just an abridged version (True),
358
+ which only specifies the identifiers of schedules. Default: False.
359
+ """
360
+ base = {'type': 'Infiltration'} if not abridged \
361
+ else {'type': 'InfiltrationAbridged'}
362
+ base['identifier'] = self.identifier
363
+ base['flow_per_exterior_area'] = self.flow_per_exterior_area
364
+ base['schedule'] = self.schedule.to_dict() if not \
365
+ abridged else self.schedule.identifier
366
+ if self.constant_coefficient != 1:
367
+ base['constant_coefficient'] = self.constant_coefficient
368
+ if self.temperature_coefficient != 0:
369
+ base['temperature_coefficient'] = self.temperature_coefficient
370
+ if self.velocity_coefficient != 0:
371
+ base['velocity_coefficient'] = self.velocity_coefficient
372
+ if self._display_name is not None:
373
+ base['display_name'] = self.display_name
374
+ if self._user_data is not None:
375
+ base['user_data'] = self._user_data
376
+ prop_dict = self.properties.to_dict()
377
+ if prop_dict is not None:
378
+ base['properties'] = prop_dict
379
+ return base
380
+
381
+ @staticmethod
382
+ def average(identifier, infiltrations, weights=None, timestep_resolution=1):
383
+ """Get an Infiltration object that's an average between other Infiltrations.
384
+
385
+ Args:
386
+ identifier: Text string for a unique ID for the new averaged Infiltration.
387
+ Must be < 100 characters and not contain any EnergyPlus special
388
+ characters. This will be used to identify the object across a model
389
+ and in the exported IDF.
390
+ infiltrations: A list of Infiltration objects that will be averaged
391
+ together to make a new Infiltration.
392
+ weights: An optional list of fractional numbers with the same length
393
+ as the input infiltrations. These will be used to weight each of the
394
+ Infiltration objects in the resulting average. Note that these weights
395
+ can sum to less than 1 in which case the average flow_per_exterior_area
396
+ will assume 0 for the unaccounted fraction of the weights.
397
+ If None, the objects will be weighted equally. Default: None.
398
+ timestep_resolution: An optional integer for the timestep resolution
399
+ at which the schedules will be averaged. Any schedule details
400
+ smaller than this timestep will be lost in the averaging process.
401
+ Default: 1.
402
+ """
403
+ weights, u_weights = \
404
+ Infiltration._check_avg_weights(infiltrations, weights, 'Infiltration')
405
+
406
+ # calculate the average values
407
+ fd = sum([inf.flow_per_exterior_area * w
408
+ for inf, w in zip(infiltrations, weights)])
409
+ const = sum([inf.constant_coefficient * w
410
+ for inf, w in zip(infiltrations, u_weights)])
411
+ temp = sum([inf.temperature_coefficient * w
412
+ for inf, w in zip(infiltrations, u_weights)])
413
+ vel = sum([inf.velocity_coefficient * w
414
+ for inf, w in zip(infiltrations, u_weights)])
415
+
416
+ # calculate the average schedules
417
+ sched = Infiltration._average_schedule(
418
+ '{} Schedule'.format(identifier), [inf.schedule for inf in infiltrations],
419
+ u_weights, timestep_resolution)
420
+
421
+ # return the averaged infiltration object
422
+ return Infiltration(identifier, fd, sched, const, temp, vel)
423
+
424
+ @staticmethod
425
+ def _optional_dict_keys(data):
426
+ """Get the optional keys from an Infiltration dictionary."""
427
+ const = data['constant_coefficient'] if 'constant_coefficient' in data else 1
428
+ tem = data['temperature_coefficient'] if 'temperature_coefficient' in data else 0
429
+ vel = data['velocity_coefficient'] if 'velocity_coefficient' in data else 0
430
+ return const, tem, vel
431
+
432
+ def __key(self):
433
+ """A tuple based on the object properties, useful for hashing."""
434
+ return (self.identifier, self.flow_per_exterior_area, hash(self.schedule),
435
+ self.constant_coefficient, self.temperature_coefficient,
436
+ self.velocity_coefficient)
437
+
438
+ def __hash__(self):
439
+ return hash(self.__key())
440
+
441
+ def __eq__(self, other):
442
+ return isinstance(other, Infiltration) and self.__key() == other.__key()
443
+
444
+ def __ne__(self, other):
445
+ return not self.__eq__(other)
446
+
447
+ def __copy__(self):
448
+ new_obj = Infiltration(
449
+ self.identifier, self.flow_per_exterior_area, self.schedule,
450
+ self.constant_coefficient, self.temperature_coefficient,
451
+ self.velocity_coefficient)
452
+ new_obj._display_name = self._display_name
453
+ new_obj._user_data = None if self._user_data is None else self._user_data.copy()
454
+ new_obj._properties._duplicate_extension_attr(self._properties)
455
+ return new_obj
456
+
457
+ def __repr__(self):
458
+ return 'Infiltration: {} [{} m3/s-m2] [schedule: {}]'.format(
459
+ self.display_name, round(self.flow_per_exterior_area, 6),
460
+ self.schedule.display_name)