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
+ """Opaque Construction."""
3
+ from __future__ import division
4
+
5
+ import re
6
+
7
+ from honeybee._lockable import lockable
8
+
9
+ from ._base import _ConstructionBase
10
+ from ..material.dictutil import dict_to_material
11
+ from ..material._base import _EnergyMaterialOpaqueBase
12
+ from ..material.opaque import EnergyMaterial, EnergyMaterialNoMass, \
13
+ EnergyMaterialVegetation
14
+ from ..reader import parse_idf_string, clean_idf_file_contents
15
+ from ..properties.extension import OpaqueConstructionProperties
16
+
17
+
18
+ @lockable
19
+ class OpaqueConstruction(_ConstructionBase):
20
+ """Opaque energy construction.
21
+
22
+ Args:
23
+ identifier: Text string for a unique Construction 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
+ materials: List of materials in the construction (from outside to inside).
27
+ All materials must be opaque and a maximum of 10 materials are allowed.
28
+
29
+ Properties:
30
+ * identifier
31
+ * display_name
32
+ * materials
33
+ * layers
34
+ * unique_materials
35
+ * r_value
36
+ * u_value
37
+ * u_factor
38
+ * r_factor
39
+ * is_symmetric
40
+ * has_frame
41
+ * has_shade
42
+ * is_dynamic
43
+ * inside_emissivity
44
+ * inside_solar_reflectance
45
+ * inside_visible_reflectance
46
+ * outside_emissivity
47
+ * outside_solar_reflectance
48
+ * outside_visible_reflectance
49
+ * mass_area_density
50
+ * area_heat_capacity
51
+ * thickness
52
+ * inside_material
53
+ * outside_material
54
+ * user_data
55
+ * properties
56
+ """
57
+ __slots__ = ()
58
+
59
+ def __init__(self, identifier, materials):
60
+ """Initialize opaque construction."""
61
+ _ConstructionBase.__init__(self, identifier, materials)
62
+ self._properties = OpaqueConstructionProperties(self)
63
+
64
+ @classmethod
65
+ def from_simple_parameters(
66
+ cls, identifier, r_value, roughness='MediumRough',
67
+ thermal_absorptance=0.9, solar_absorptance=0.7, visible_absorptance=None
68
+ ):
69
+ """Create a no-mass OpaqueConstruction from a specification of simple parameters.
70
+
71
+ The result will have a single EnergyMaterialNoMass layer that is derived
72
+ from the input parameters.
73
+
74
+ Args:
75
+ identifier: Text string for a unique construction ID.
76
+ Must be <90 characters and not contain any EnergyPlus special
77
+ characters. This will be used to identify the object across a model
78
+ and in the exported IDF.
79
+ r_value: Number for the R-value of the construction [m2-K/W].
80
+ roughness: Text describing the relative roughness of the construction.
81
+ Must be one of the following: 'VeryRough', 'Rough', 'MediumRough',
82
+ 'MediumSmooth', 'Smooth', 'VerySmooth'. Default: 'MediumRough'.
83
+ thermal_absorptance: A number between 0 and 1 for the fraction of
84
+ incident long wavelength radiation that is absorbed by the construction.
85
+ Default: 0.9.
86
+ solar_absorptance: A number between 0 and 1 for the fraction of incident
87
+ solar radiation absorbed by the construction. Default: 0.7.
88
+ visible_absorptance: A number between 0 and 1 for the fraction of incident
89
+ visible wavelength radiation absorbed by the construction.
90
+ Default value is None, which will use the same value as the
91
+ solar_absorptance.
92
+ """
93
+ mat_layer = EnergyMaterialNoMass(
94
+ '{} Material'.format(identifier), r_value, roughness,
95
+ thermal_absorptance, solar_absorptance, visible_absorptance
96
+ )
97
+ return cls(identifier, (mat_layer,))
98
+
99
+ @property
100
+ def materials(self):
101
+ """Get or set the list of materials in the construction (outside to inside).
102
+
103
+ All materials must be opaque and a maximum of 10 materials are allowed.
104
+ """
105
+ return self._materials
106
+
107
+ @materials.setter
108
+ def materials(self, mats):
109
+ try:
110
+ if not isinstance(mats, tuple):
111
+ mats = tuple(mats)
112
+ except TypeError:
113
+ raise TypeError('Expected list or tuple for construction materials. '
114
+ 'Got {}'.format(type(mats)))
115
+ for i, mat in enumerate(mats):
116
+ assert isinstance(mat, _EnergyMaterialOpaqueBase), 'Expected opaque energy' \
117
+ ' material for construction. Got {}.'.format(type(mat))
118
+ if isinstance(mat, EnergyMaterialVegetation):
119
+ assert i == 0, 'Vegetation material layer must bet the first ' \
120
+ '(exterior) layer in the construction.'
121
+ assert len(mats) > 0, 'Construction must possess at least one material.'
122
+ assert len(mats) <= 10, 'Opaque Construction cannot have more than 10 materials.'
123
+ self._materials = mats
124
+
125
+ @property
126
+ def inside_solar_reflectance(self):
127
+ """The solar reflectance of the inside face of the construction."""
128
+ return 1 - self.materials[-1].solar_absorptance
129
+
130
+ @property
131
+ def inside_visible_reflectance(self):
132
+ """The visible reflectance of the inside face of the construction."""
133
+ return 1 - self.materials[-1].visible_absorptance
134
+
135
+ @property
136
+ def outside_solar_reflectance(self):
137
+ """The solar reflectance of the outside face of the construction."""
138
+ return 1 - self.materials[0].solar_absorptance
139
+
140
+ @property
141
+ def outside_visible_reflectance(self):
142
+ """The visible reflectance of the outside face of the construction."""
143
+ return 1 - self.materials[0].visible_absorptance
144
+
145
+ @property
146
+ def mass_area_density(self):
147
+ """The area density of the construction [kg/m2]."""
148
+ return sum(tuple(mat.mass_area_density for mat in self.materials))
149
+
150
+ @property
151
+ def area_heat_capacity(self):
152
+ """The heat capacity per unit area of the construction [J/K-m2]."""
153
+ return sum(tuple(mat.area_heat_capacity for mat in self.materials))
154
+
155
+ @property
156
+ def thickness(self):
157
+ """Thickness of the construction [m]."""
158
+ thickness = 0
159
+ for mat in self.materials:
160
+ thickness += mat.thickness
161
+ return thickness
162
+
163
+ @property
164
+ def inside_material(self):
165
+ """The the inside material layer of the construction.
166
+
167
+ Useful for checking that an asymmetric construction is correctly assigned.
168
+ """
169
+ return self.materials[-1]
170
+
171
+ @property
172
+ def outside_material(self):
173
+ """The the outside material layer of the construction.
174
+
175
+ Useful for checking that an asymmetric construction is correctly assigned.
176
+ """
177
+ return self.materials[0]
178
+
179
+ def temperature_profile(self, outside_temperature=-18, inside_temperature=21,
180
+ outside_wind_speed=6.7, solar_irradiance=0,
181
+ height=1.0, angle=90.0, pressure=101325):
182
+ """Get a list of temperatures at each material boundary across the construction.
183
+
184
+ Args:
185
+ outside_temperature: The temperature on the outside of the
186
+ construction [C]. (Default: -18, consistent with NFRC 100-2010).
187
+ inside_temperature: The temperature on the inside of the
188
+ construction [C]. (Default: 21, consistent with NFRC 100-2010).
189
+ wind_speed: The average outdoor wind speed [m/s]. This affects outdoor
190
+ convective heat transfer coefficient. (Default: 6.7 m/s).
191
+ solar_irradiance: An optional value for solar irradiance that is incident
192
+ on the front (exterior) of the construction [W/m2]. (Default: 0 W/m2).
193
+ height: An optional height for the surface in meters. (Default: 1.0 m).
194
+ angle: An angle in degrees between 0 and 180.
195
+
196
+ * 0 = A horizontal surface with the outside boundary on the top.
197
+ * 90 = A vertical surface
198
+ * 180 = A horizontal surface with the outside boundary on the bottom.
199
+
200
+ pressure: The average pressure of in Pa. (Default: 101325 Pa for
201
+ standard pressure at sea level).
202
+
203
+ Returns:
204
+ A tuple with two elements
205
+
206
+ - temperatures: A list of temperature values [C].
207
+ The first value will always be the outside temperature and the
208
+ second will be the exterior surface temperature.
209
+ The last value will always be the inside temperature and the second
210
+ to last will be the interior surface temperature.
211
+
212
+ - r_values: A list of R-values for each of the material layers [m2-K/W].
213
+ The first value will always be the resistance of the exterior air
214
+ and the last value is the resistance of the interior air.
215
+ The sum of this list is the R-factor for this construction given
216
+ the input parameters.
217
+ """
218
+ # reverse the angle if the outside temperature is greater than the inside one
219
+ if angle != 90 and outside_temperature > inside_temperature:
220
+ angle = abs(180 - angle)
221
+
222
+ # compute delta temperature from solar irradiance if applicable
223
+ heat_gen = None
224
+ if solar_irradiance != 0:
225
+ heat_gen = self.materials[0].solar_absorptance * solar_irradiance
226
+
227
+ # use the r-values to get the temperature profile
228
+ in_r_init = 1 / self.in_h_simple()
229
+ r_values = [1 / self.out_h(outside_wind_speed, outside_temperature + 273.15)] + \
230
+ [mat.r_value for mat in self.materials] + [in_r_init]
231
+ in_delta_t = (in_r_init / sum(r_values)) * \
232
+ (outside_temperature - inside_temperature)
233
+ r_values[-1] = 1 / self.in_h(inside_temperature - (in_delta_t / 2) + 273.15,
234
+ in_delta_t, height, angle, pressure)
235
+ temperatures = self._temperature_profile_from_r_values(
236
+ r_values, outside_temperature, inside_temperature, heat_gen)
237
+ return temperatures, r_values
238
+
239
+ @classmethod
240
+ def from_idf(cls, idf_string, ep_mat_strings):
241
+ """Create an OpaqueConstruction from an EnergyPlus IDF text string.
242
+
243
+ Args:
244
+ idf_string: A text string fully describing an EnergyPlus construction.
245
+ ep_mat_strings: A list of text strings for each of the materials in
246
+ the construction.
247
+ """
248
+ materials_dict = cls._idf_materials_dictionary(ep_mat_strings)
249
+ ep_strs = parse_idf_string(idf_string)
250
+ try:
251
+ materials = [materials_dict[mat.upper()] for mat in ep_strs[1:]]
252
+ except KeyError as e:
253
+ raise ValueError('Failed to find {} in the input ep_mat_strings.'.format(e))
254
+ return cls(ep_strs[0], materials)
255
+
256
+ @classmethod
257
+ def from_dict(cls, data):
258
+ """Create a OpaqueConstruction from a dictionary.
259
+
260
+ Note that the dictionary must be a non-abridged version for this
261
+ classmethod to work.
262
+
263
+ Args:
264
+ data: A python dictionary in the following format
265
+
266
+ .. code-block:: python
267
+
268
+ {
269
+ "type": 'OpaqueConstruction',
270
+ "identifier": 'Generic Brick Wall R-10',
271
+ "display_name": 'Brick Wall',
272
+ "materials": [] # list of unique material objects (from outside to inside)
273
+ }
274
+ """
275
+ assert data['type'] == 'OpaqueConstruction', \
276
+ 'Expected OpaqueConstruction. Got {}.'.format(data['type'])
277
+ mat_layers = cls._old_schema_materials(data) if 'layers' in data else \
278
+ [dict_to_material(mat) for mat in data['materials']]
279
+ new_obj = cls(data['identifier'], mat_layers)
280
+ if 'display_name' in data and data['display_name'] is not None:
281
+ new_obj.display_name = data['display_name']
282
+ if 'user_data' in data and data['user_data'] is not None:
283
+ new_obj.user_data = data['user_data']
284
+ if 'properties' in data and data['properties'] is not None:
285
+ new_obj.properties._load_extension_attr_from_dict(data['properties'])
286
+ return new_obj
287
+
288
+ @classmethod
289
+ def from_dict_abridged(cls, data, materials):
290
+ """Create a OpaqueConstruction from an abridged dictionary.
291
+
292
+ Args:
293
+ data: An OpaqueConstructionAbridged dictionary.
294
+ materials: A dictionary with identifiers of materials as keys and Python
295
+ material objects as values.
296
+
297
+ .. code-block:: python
298
+
299
+ {
300
+ "type": 'OpaqueConstructionAbridged',
301
+ "identifier": 'Generic Brick Wall R-10',
302
+ "display_name": 'Brick Wall',
303
+ "materials": [], # list of material identifiers (from outside to inside)
304
+ }
305
+ """
306
+ assert data['type'] == 'OpaqueConstructionAbridged', \
307
+ 'Expected OpaqueConstructionAbridged. Got {}.'.format(data['type'])
308
+ # handle old schema definition before May 2021 (used layers instead of materials)
309
+ mat_key = 'layers' if 'layers' in data else 'materials'
310
+ try:
311
+ mat_layers = [materials[mat_id] for mat_id in data[mat_key]]
312
+ except KeyError as e:
313
+ raise ValueError('Failed to find {} in materials.'.format(e))
314
+ new_obj = cls(data['identifier'], mat_layers)
315
+ if 'display_name' in data and data['display_name'] is not None:
316
+ new_obj.display_name = data['display_name']
317
+ if 'user_data' in data and data['user_data'] is not None:
318
+ new_obj.user_data = data['user_data']
319
+ if 'properties' in data and data['properties'] is not None:
320
+ new_obj.properties._load_extension_attr_from_dict(data['properties'])
321
+ return new_obj
322
+
323
+ def to_idf(self):
324
+ """IDF string representation of construction object.
325
+
326
+ Note that this method only outputs a single string for the construction and,
327
+ to write the full construction into an IDF, the construction's unique_materials
328
+ must also be written.
329
+
330
+ Returns:
331
+ construction_idf -- Text string representation of the construction.
332
+
333
+ .. code-block:: shell
334
+
335
+ Construction, FLOOR38, ! Material layer names follow:
336
+ E5 - ACOUSTIC TILE,
337
+ E4 - CEILING AIRSPACE,
338
+ C12 - 2 IN HW CONCRETE;
339
+ """
340
+ return self._generate_idf_string('opaque', self.identifier, self.materials)
341
+
342
+ def to_radiance_solar_interior(self, specularity=0.0):
343
+ """Honeybee Radiance modifier with the interior solar reflectance."""
344
+ return self.materials[-1].to_radiance_solar(specularity)
345
+
346
+ def to_radiance_visible_interior(self, specularity=0.0):
347
+ """Honeybee Radiance modifier with the interior visible reflectance."""
348
+ return self.materials[-1].to_radiance_visible(specularity)
349
+
350
+ def to_radiance_solar_exterior(self, specularity=0.0):
351
+ """Honeybee Radiance modifier with the exterior solar reflectance."""
352
+ return self.materials[0].to_radiance_solar(specularity)
353
+
354
+ def to_radiance_visible_exterior(self, specularity=0.0):
355
+ """Honeybee Radiance modifier with the exterior visible reflectance."""
356
+ return self.materials[0].to_radiance_visible(specularity)
357
+
358
+ def to_dict(self, abridged=False):
359
+ """Opaque construction dictionary representation.
360
+
361
+ Args:
362
+ abridged: Boolean to note whether the full dictionary describing the
363
+ object should be returned (False) or just an abridged version (True),
364
+ which only specifies the identifiers of material layers. Default: False.
365
+ """
366
+ base = {'type': 'OpaqueConstruction'} if not \
367
+ abridged else {'type': 'OpaqueConstructionAbridged'}
368
+ base['identifier'] = self.identifier
369
+ base['materials'] = self.layers if abridged else \
370
+ [m.to_dict() for m in self.materials]
371
+ if self._display_name is not None:
372
+ base['display_name'] = self.display_name
373
+ if self._user_data is not None:
374
+ base['user_data'] = self.user_data
375
+ prop_dict = self.properties.to_dict()
376
+ if prop_dict is not None:
377
+ base['properties'] = prop_dict
378
+ return base
379
+
380
+ @staticmethod
381
+ def extract_all_from_idf_file(idf_file):
382
+ """Extract all OpaqueConstruction objects from an EnergyPlus IDF file.
383
+
384
+ Args:
385
+ idf_file: A path to an IDF file containing objects for opaque
386
+ constructions and corresponding materials.
387
+
388
+ Returns:
389
+ A tuple with two elements
390
+
391
+ - constructions: A list of all OpaqueConstruction objects in the IDF
392
+ file as honeybee_energy OpaqueConstruction objects.
393
+
394
+ - materials: A list of all opaque materials in the IDF file as
395
+ honeybee_energy EnergyMaterial objects.
396
+ """
397
+ # read the file and remove lines of comments
398
+ file_contents = clean_idf_file_contents(idf_file)
399
+ # extract all of the opaque material objects
400
+ mat_pattern1 = re.compile(r"(?i)(Material,[\s\S]*?;)")
401
+ mat_pattern2 = re.compile(r"(?i)(Material:NoMass,[\s\S]*?;)")
402
+ mat_pattern3 = re.compile(r"(?i)(Material:AirGap,[\s\S]*?;)")
403
+ mat_pattern4 = re.compile(r"(?i)(Material:RoofVegetation,[\s\S]*?;)")
404
+ material_str = mat_pattern1.findall(file_contents) + \
405
+ mat_pattern2.findall(file_contents) + mat_pattern3.findall(file_contents) + \
406
+ mat_pattern4.findall(file_contents)
407
+ materials_dict = OpaqueConstruction._idf_materials_dictionary(material_str)
408
+ materials = list(materials_dict.values())
409
+ # extract all of the construction objects
410
+ constr_pattern = re.compile(r"(?i)(Construction,[\s\S]*?;)")
411
+ constr_props = tuple(parse_idf_string(idf_string) for
412
+ idf_string in constr_pattern.findall(file_contents))
413
+ constructions = []
414
+ for constr in constr_props:
415
+ try:
416
+ constr_mats = [materials_dict[mat.upper()] for mat in constr[1:]]
417
+ constructions.append(OpaqueConstruction(constr[0], constr_mats))
418
+ except (KeyError, AssertionError):
419
+ pass # the construction is probably a window construction
420
+ return constructions, materials
421
+
422
+ @staticmethod
423
+ def _idf_materials_dictionary(ep_mat_strings):
424
+ """Get a dictionary of opaque EnergyMaterial objects from an IDF string list."""
425
+ materials_dict = {}
426
+ for mat_str in ep_mat_strings:
427
+ mat_str = mat_str.strip()
428
+ if mat_str.startswith('Material,'):
429
+ mat_obj = EnergyMaterial.from_idf(mat_str)
430
+ materials_dict[mat_obj.identifier.upper()] = mat_obj
431
+ elif mat_str.startswith('Material:NoMass,'):
432
+ mat_obj = EnergyMaterialNoMass.from_idf(mat_str)
433
+ materials_dict[mat_obj.identifier.upper()] = mat_obj
434
+ elif mat_str.startswith('Material:AirGap,'):
435
+ mat_obj = EnergyMaterialNoMass.from_idf_air_gap(mat_str)
436
+ materials_dict[mat_obj.identifier.upper()] = mat_obj
437
+ elif mat_str.startswith('Material:RoofVegetation,'):
438
+ mat_obj = EnergyMaterialVegetation.from_idf(mat_str)
439
+ materials_dict[mat_obj.identifier.upper()] = mat_obj
440
+ return materials_dict
441
+
442
+ @staticmethod
443
+ def _old_schema_materials(data):
444
+ """Get material objects from an old schema definition of OpaqueConstruction.
445
+
446
+ The schema is from before May 2021 and this method should eventually be removed.
447
+ """
448
+ materials = {}
449
+ for mat in data['materials']:
450
+ materials[mat['identifier']] = dict_to_material(mat)
451
+ try:
452
+ mat_layers = [materials[mat_id] for mat_id in data['layers']]
453
+ except KeyError as e:
454
+ raise ValueError(
455
+ 'Failed to find {} in opaque construction materials.'.format(e))
456
+ return mat_layers
457
+
458
+ def __repr__(self):
459
+ """Represent opaque energy construction."""
460
+ return self._generate_idf_string('opaque', self.identifier, self.materials)