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,1351 @@
1
+ # coding=utf-8
2
+ """Opaque energy materials.
3
+
4
+ The materials here are the only ones that can be used in opaque constructions.
5
+ """
6
+ from __future__ import division
7
+
8
+ from ._base import _EnergyMaterialOpaqueBase
9
+ from ..reader import parse_idf_string
10
+ from ..writer import generate_idf_string
11
+
12
+ from honeybee._lockable import lockable
13
+ from honeybee.typing import float_in_range, float_positive, clean_rad_string
14
+ from ..properties.extension import EnergyMaterialProperties, \
15
+ EnergyMaterialNoMassProperties, EnergyMaterialVegetationProperties
16
+
17
+
18
+ @lockable
19
+ class EnergyMaterial(_EnergyMaterialOpaqueBase):
20
+ """Typical opaque energy material.
21
+
22
+ Args:
23
+ identifier: Text string for a unique Material 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
+ thickness: Number for the thickness of the material layer [m].
27
+ conductivity: Number for the thermal conductivity of the material [W/m-K].
28
+ density: Number for the density of the material [kg/m3].
29
+ specific_heat: Number for the specific heat of the material [J/kg-K].
30
+ roughness: Text describing the relative roughness of the material. (Default:
31
+ MediumRough). Must be one of the following:
32
+
33
+ * VeryRough
34
+ * Rough
35
+ * MediumRough
36
+ * MediumSmooth
37
+ * Smooth
38
+ * VerySmooth
39
+
40
+ thermal_absorptance: A number between 0 and 1 for the fraction of incident long
41
+ wavelength radiation that is absorbed by the material. (Default: 0.9).
42
+ solar_absorptance: A number between 0 and 1 for the fraction of incident
43
+ solar radiation absorbed by the material. (Default: 0.7).
44
+ visible_absorptance: A number between 0 and 1 for the fraction of incident
45
+ visible wavelength radiation absorbed by the material.
46
+ Default is None, which will yield the same value as solar_absorptance.
47
+
48
+ Properties:
49
+ * identifier
50
+ * display_name
51
+ * roughness
52
+ * thickness
53
+ * conductivity
54
+ * density
55
+ * specific_heat
56
+ * thermal_absorptance
57
+ * solar_absorptance
58
+ * visible_absorptance
59
+ * solar_reflectance
60
+ * visible_reflectance
61
+ * resistivity
62
+ * u_value
63
+ * r_value
64
+ * mass_area_density
65
+ * area_heat_capacity
66
+ * user_data
67
+ * properties
68
+ """
69
+ __slots__ = ('_roughness', '_thickness', '_conductivity',
70
+ '_density', '_specific_heat', '_thermal_absorptance',
71
+ '_solar_absorptance', '_visible_absorptance')
72
+
73
+ def __init__(self, identifier, thickness, conductivity, density, specific_heat,
74
+ roughness='MediumRough', thermal_absorptance=0.9,
75
+ solar_absorptance=0.7, visible_absorptance=None):
76
+ """Initialize energy material."""
77
+ _EnergyMaterialOpaqueBase.__init__(self, identifier)
78
+ self.thickness = thickness
79
+ self.conductivity = conductivity
80
+ self.density = density
81
+ self.specific_heat = specific_heat
82
+ self.roughness = roughness
83
+ self.thermal_absorptance = thermal_absorptance
84
+ self.solar_absorptance = solar_absorptance
85
+ self.visible_absorptance = visible_absorptance
86
+ self._locked = False
87
+ self._properties = EnergyMaterialProperties(self)
88
+
89
+ @property
90
+ def roughness(self):
91
+ """Get or set the text describing the roughness of the material layer."""
92
+ return self._roughness
93
+
94
+ @roughness.setter
95
+ def roughness(self, rough):
96
+ assert rough in self.ROUGHTYPES, 'Invalid input "{}" for material roughness.' \
97
+ ' Roughness must be one of the following:\n{}'.format(
98
+ rough, self.ROUGHTYPES)
99
+ self._roughness = rough
100
+
101
+ @property
102
+ def thickness(self):
103
+ """Get or set the thickness of the material layer [m]."""
104
+ return self._thickness
105
+
106
+ @thickness.setter
107
+ def thickness(self, thick):
108
+ self._thickness = float_positive(thick, 'material thickness')
109
+ assert self._thickness != 0, 'Material thickness must be greater than zero.'
110
+
111
+ @property
112
+ def conductivity(self):
113
+ """Get or set the conductivity of the material layer [W/m-K]."""
114
+ return self._conductivity
115
+
116
+ @conductivity.setter
117
+ def conductivity(self, cond):
118
+ self._conductivity = float_positive(cond, 'material conductivity')
119
+
120
+ @property
121
+ def density(self):
122
+ """Get or set the density of the material layer [kg/m3]."""
123
+ return self._density
124
+
125
+ @density.setter
126
+ def density(self, dens):
127
+ self._density = float_positive(dens, 'material density')
128
+
129
+ @property
130
+ def specific_heat(self):
131
+ """Get or set the specific heat of the material layer [J/kg-K]."""
132
+ return self._specific_heat
133
+
134
+ @specific_heat.setter
135
+ def specific_heat(self, sp_ht):
136
+ self._specific_heat = float_in_range(
137
+ sp_ht, 100.0, input_name='material specific heat')
138
+
139
+ @property
140
+ def thermal_absorptance(self):
141
+ """Get or set the thermal absorptance of the material layer."""
142
+ return self._thermal_absorptance
143
+
144
+ @thermal_absorptance.setter
145
+ def thermal_absorptance(self, t_abs):
146
+ self._thermal_absorptance = float_in_range(
147
+ t_abs, 0.0, 1.0, 'material thermal absorptance')
148
+
149
+ @property
150
+ def solar_absorptance(self):
151
+ """Get or set the solar absorptance of the material layer."""
152
+ return self._solar_absorptance
153
+
154
+ @solar_absorptance.setter
155
+ def solar_absorptance(self, s_abs):
156
+ self._solar_absorptance = float_in_range(
157
+ s_abs, 0.0, 1.0, 'material solar absorptance')
158
+
159
+ @property
160
+ def visible_absorptance(self):
161
+ """Get or set the visible absorptance of the material layer."""
162
+ return self._visible_absorptance if self._visible_absorptance is not None \
163
+ else self._solar_absorptance
164
+
165
+ @visible_absorptance.setter
166
+ def visible_absorptance(self, v_abs):
167
+ self._visible_absorptance = float_in_range(
168
+ v_abs, 0.0, 1.0, 'material visible absorptance') if v_abs is not None \
169
+ else None
170
+
171
+ @property
172
+ def solar_reflectance(self):
173
+ """Get or set the front solar reflectance of the material layer."""
174
+ return 1 - self.solar_absorptance
175
+
176
+ @solar_reflectance.setter
177
+ def solar_reflectance(self, v_ref):
178
+ v_ref = float_in_range(v_ref, 0.0, 1.0, 'material solar reflectance')
179
+ self.solar_absorptance = 1 - v_ref
180
+
181
+ @property
182
+ def visible_reflectance(self):
183
+ """Get or set the front visible reflectance of the material layer."""
184
+ return 1 - self.visible_absorptance
185
+
186
+ @visible_reflectance.setter
187
+ def visible_reflectance(self, v_ref):
188
+ v_ref = float_in_range(v_ref, 0.0, 1.0, 'material visible reflectance')
189
+ self.visible_absorptance = 1 - v_ref
190
+
191
+ @property
192
+ def resistivity(self):
193
+ """Get or set the resistivity of the material layer [m-K/W]."""
194
+ return 1 / self._conductivity
195
+
196
+ @resistivity.setter
197
+ def resistivity(self, resis):
198
+ self._conductivity = 1 / float_positive(resis, 'material resistivity')
199
+
200
+ @property
201
+ def r_value(self):
202
+ """Get or set the R-value of the material in [m2-K/W] (excluding air films).
203
+
204
+ Note that, when setting the R-value, the thickness of the material will
205
+ remain fixed and only the conductivity will be adjusted.
206
+ """
207
+ return self.thickness / self.conductivity
208
+
209
+ @r_value.setter
210
+ def r_value(self, r_val):
211
+ _new_conductivity = self.thickness / \
212
+ float_positive(r_val, 'material r-value')
213
+ self._conductivity = _new_conductivity
214
+
215
+ @property
216
+ def u_value(self):
217
+ """Get or set the U-value of the material [W/m2-K] (excluding air films).
218
+
219
+ Note that, when setting the R-value, the thickness of the material will
220
+ remain fixed and only the conductivity will be adjusted.
221
+ """
222
+ return self.conductivity / self.thickness
223
+
224
+ @u_value.setter
225
+ def u_value(self, u_val):
226
+ self.r_value = 1 / float_positive(u_val, 'material u-value')
227
+
228
+ @property
229
+ def mass_area_density(self):
230
+ """The area density of the material [kg/m2]."""
231
+ return self.thickness * self.density
232
+
233
+ @property
234
+ def area_heat_capacity(self):
235
+ """The heat capacity per unit area of the material [J/K-m2]."""
236
+ return self.mass_area_density * self.specific_heat
237
+
238
+ @classmethod
239
+ def from_idf(cls, idf_string):
240
+ """Create an EnergyMaterial from an EnergyPlus text string.
241
+
242
+ Args:
243
+ idf_string: A text string fully describing an EnergyPlus material.
244
+ """
245
+ ep_strs = parse_idf_string(idf_string, 'Material,')
246
+ idf_defaults = {6: 0.9, 7: 0.7, 8: 0.7}
247
+ for i, ep_str in enumerate(ep_strs): # fill in any default values
248
+ if ep_str == '' and i in idf_defaults:
249
+ ep_strs[i] = idf_defaults[i]
250
+ ep_strs.insert(5, ep_strs.pop(1)) # move roughness to correct place
251
+ return cls(*ep_strs)
252
+
253
+ @classmethod
254
+ def from_dict(cls, data):
255
+ """Create a EnergyMaterial from a dictionary.
256
+
257
+ Args:
258
+ data: A python dictionary in the following format
259
+
260
+ .. code-block:: python
261
+
262
+ {
263
+ "type": 'EnergyMaterial',
264
+ "identifier": 'Concrete_020_231_2322_832',
265
+ "display_name": 'Concrete Slab',
266
+ "roughness": 'MediumRough',
267
+ "thickness": 0.2,
268
+ "conductivity": 2.31,
269
+ "density": 2322,
270
+ "specific_heat": 832,
271
+ "thermal_absorptance": 0.9,
272
+ "solar_absorptance": 0.7,
273
+ "visible_absorptance": 0.7
274
+ }
275
+ """
276
+ assert data['type'] == 'EnergyMaterial', \
277
+ 'Expected EnergyMaterial. Got {}.'.format(data['type'])
278
+
279
+ rough = data['roughness'] if 'roughness' in data and \
280
+ data['roughness'] is not None else 'MediumRough'
281
+ t_abs = data['thermal_absorptance'] if 'thermal_absorptance' in data and \
282
+ data['thermal_absorptance'] is not None else 0.9
283
+ s_abs = data['solar_absorptance'] if 'solar_absorptance' in data and \
284
+ data['solar_absorptance'] is not None else 0.7
285
+ v_abs = data['visible_absorptance'] if 'visible_absorptance' in data else None
286
+
287
+ new_mat = cls(data['identifier'], data['thickness'], data['conductivity'],
288
+ data['density'], data['specific_heat'], rough, t_abs, s_abs, v_abs)
289
+ if 'display_name' in data and data['display_name'] is not None:
290
+ new_mat.display_name = data['display_name']
291
+ if 'user_data' in data and data['user_data'] is not None:
292
+ new_mat.user_data = data['user_data']
293
+ if 'properties' in data and data['properties'] is not None:
294
+ new_mat.properties._load_extension_attr_from_dict(data['properties'])
295
+
296
+ return new_mat
297
+
298
+ def to_idf(self):
299
+ """Get an EnergyPlus string representation of the material.
300
+
301
+ .. code-block:: shell
302
+
303
+ Material,A2 - 4 IN DENSE FACE BRICK, ! Material Name
304
+ Rough, ! Roughness
305
+ 0.1014984, ! Thickness {m}
306
+ 1.245296, ! Conductivity {W/M*K}
307
+ 2082.400, ! Density {Kg/M**3}
308
+ 920.4800, ! Specific Heat {J/Kg*K}
309
+ 0.9000000, ! Thermal Absorptance
310
+ 0.9300000, ! Solar Absorptance
311
+ 0.9300000; ! Visible Absorptance
312
+ """
313
+ values = (self.identifier, self.roughness, self.thickness, self.conductivity,
314
+ self.density, self.specific_heat, self.thermal_absorptance,
315
+ self.solar_absorptance, self.visible_absorptance)
316
+ comments = ('name', 'roughness', 'thickness {m}', 'conductivity {W/m-K}',
317
+ 'density {kg/m3}', 'specific heat {J/kg-K}', 'thermal absorptance',
318
+ 'solar absorptance', 'visible absorptance')
319
+ return generate_idf_string('Material', values, comments)
320
+
321
+ def to_radiance_solar(self, specularity=0.0):
322
+ """Honeybee Radiance material from the solar reflectance of this material."""
323
+ try:
324
+ from honeybee_radiance.modifier.material import Plastic
325
+ except ImportError as e:
326
+ raise ImportError('honeybee_radiance library must be installed to use '
327
+ 'to_radiance_solar() method. {}'.format(e))
328
+ return Plastic.from_single_reflectance(
329
+ clean_rad_string(self.identifier), 1 - self.solar_absorptance, specularity,
330
+ self.RADIANCEROUGHTYPES[self.roughness])
331
+
332
+ def to_radiance_visible(self, specularity=0.0):
333
+ """Honeybee Radiance material from the visible reflectance of this material."""
334
+ try:
335
+ from honeybee_radiance.modifier.material import Plastic
336
+ except ImportError as e:
337
+ raise ImportError('honeybee_radiance library must be installed to use '
338
+ 'to_radiance_solar() method. {}'.format(e))
339
+ return Plastic.from_single_reflectance(
340
+ clean_rad_string(self.identifier), 1 - self.visible_absorptance, specularity,
341
+ self.RADIANCEROUGHTYPES[self.roughness])
342
+
343
+ def to_dict(self):
344
+ """Energy Material dictionary representation."""
345
+ base = {
346
+ 'type': 'EnergyMaterial',
347
+ 'identifier': self.identifier,
348
+ 'roughness': self.roughness,
349
+ 'thickness': self.thickness,
350
+ 'conductivity': self.conductivity,
351
+ 'density': self.density,
352
+ 'specific_heat': self.specific_heat,
353
+ 'thermal_absorptance': self.thermal_absorptance,
354
+ 'solar_absorptance': self.solar_absorptance,
355
+ 'visible_absorptance': self.visible_absorptance
356
+ }
357
+ if self._display_name is not None:
358
+ base['display_name'] = self.display_name
359
+ if self._user_data is not None:
360
+ base['user_data'] = self.user_data
361
+ prop_dict = self.properties.to_dict()
362
+ if prop_dict is not None:
363
+ base['properties'] = prop_dict
364
+ return base
365
+
366
+ def __key(self):
367
+ """A tuple based on the object properties, useful for hashing."""
368
+ return (self.identifier, self.roughness, self.thickness, self.conductivity,
369
+ self.density, self.specific_heat, self.thermal_absorptance,
370
+ self.solar_absorptance, self.visible_absorptance)
371
+
372
+ def __hash__(self):
373
+ return hash(self.__key())
374
+
375
+ def __eq__(self, other):
376
+ return isinstance(other, EnergyMaterial) and self.__key() == other.__key()
377
+
378
+ def __ne__(self, other):
379
+ return not self.__eq__(other)
380
+
381
+ def __repr__(self):
382
+ return self.to_idf()
383
+
384
+ def __copy__(self):
385
+ new_material = self.__class__(
386
+ self.identifier, self.thickness, self.conductivity, self.density,
387
+ self.specific_heat, self.roughness, self.thermal_absorptance,
388
+ self.solar_absorptance, self._visible_absorptance)
389
+ new_material._display_name = self._display_name
390
+ new_material._user_data = None if self._user_data is None \
391
+ else self._user_data.copy()
392
+ new_material._properties._duplicate_extension_attr(self._properties)
393
+ return new_material
394
+
395
+
396
+ @lockable
397
+ class EnergyMaterialNoMass(_EnergyMaterialOpaqueBase):
398
+ """Typical no mass opaque energy material.
399
+
400
+ Args:
401
+ identifier: Text string for a unique Material ID. Must be < 100 characters
402
+ and not contain any EnergyPlus special characters. This will be used to
403
+ identify the object across a model and in the exported IDF.
404
+ r_value: Number for the R-value of the material [m2-K/W].
405
+ roughness: Text describing the relative roughness of the material.
406
+ Must be one of the following: 'VeryRough', 'Rough', 'MediumRough',
407
+ 'MediumSmooth', 'Smooth', 'VerySmooth'. Default: 'MediumRough'.
408
+ thermal_absorptance: A number between 0 and 1 for the fraction of
409
+ incident long wavelength radiation that is absorbed by the material.
410
+ Default: 0.9.
411
+ solar_absorptance: A number between 0 and 1 for the fraction of incident
412
+ solar radiation absorbed by the material. Default: 0.7.
413
+ visible_absorptance: A number between 0 and 1 for the fraction of incident
414
+ visible wavelength radiation absorbed by the material.
415
+ Default value is None, which will use the same value as the
416
+ solar_absorptance.
417
+
418
+ Properties:
419
+ * identifier
420
+ * display_name
421
+ * r_value
422
+ * u_value
423
+ * roughness
424
+ * thermal_absorptance
425
+ * solar_absorptance
426
+ * visible_absorptance
427
+ * solar_reflectance
428
+ * visible_reflectance
429
+ * mass_area_density
430
+ * area_heat_capacity
431
+ * user_data
432
+ * properties
433
+ """
434
+ __slots__ = ('_r_value', '_roughness', '_thermal_absorptance',
435
+ '_solar_absorptance', '_visible_absorptance')
436
+
437
+ def __init__(self, identifier, r_value, roughness='MediumRough',
438
+ thermal_absorptance=0.9, solar_absorptance=0.7,
439
+ visible_absorptance=None):
440
+ """Initialize energy material."""
441
+ _EnergyMaterialOpaqueBase.__init__(self, identifier)
442
+ self.r_value = r_value
443
+ self.roughness = roughness
444
+ self.thermal_absorptance = thermal_absorptance
445
+ self.solar_absorptance = solar_absorptance
446
+ self.visible_absorptance = visible_absorptance
447
+ self._properties = EnergyMaterialNoMassProperties(self)
448
+
449
+ @property
450
+ def r_value(self):
451
+ """Get or set the r_value of the material layer [m2-K/W] (excluding air films).
452
+ """
453
+ return self._r_value
454
+
455
+ @r_value.setter
456
+ def r_value(self, r_val):
457
+ self._r_value = float_positive(r_val, 'material r-value')
458
+
459
+ @property
460
+ def u_value(self):
461
+ """U-value of the material layer [W/m2-K] (excluding air films)."""
462
+ return 1 / self.r_value
463
+
464
+ @u_value.setter
465
+ def u_value(self, u_val):
466
+ self._r_value = 1 / float_positive(u_val, 'material u-value')
467
+
468
+ @property
469
+ def roughness(self):
470
+ """Get or set the text describing the roughness of the material layer."""
471
+ return self._roughness
472
+
473
+ @roughness.setter
474
+ def roughness(self, rough):
475
+ assert rough in self.ROUGHTYPES, 'Invalid input "{}" for material roughness.' \
476
+ ' Roughness must be one of the following:\n{}'.format(
477
+ rough, self.ROUGHTYPES)
478
+ self._roughness = rough
479
+
480
+ @property
481
+ def thermal_absorptance(self):
482
+ """Get or set the thermal absorptance of the material layer."""
483
+ return self._thermal_absorptance
484
+
485
+ @thermal_absorptance.setter
486
+ def thermal_absorptance(self, t_abs):
487
+ self._thermal_absorptance = float_in_range(
488
+ t_abs, 0.0, 1.0, 'material thermal absorptance')
489
+
490
+ @property
491
+ def solar_absorptance(self):
492
+ """Get or set the solar absorptance of the material layer."""
493
+ return self._solar_absorptance
494
+
495
+ @solar_absorptance.setter
496
+ def solar_absorptance(self, s_abs):
497
+ self._solar_absorptance = float_in_range(
498
+ s_abs, 0.0, 1.0, 'material solar absorptance')
499
+
500
+ @property
501
+ def visible_absorptance(self):
502
+ """Get or set the visible absorptance of the material layer."""
503
+ return self._visible_absorptance if self._visible_absorptance is not None \
504
+ else self._solar_absorptance
505
+
506
+ @visible_absorptance.setter
507
+ def visible_absorptance(self, v_abs):
508
+ self._visible_absorptance = float_in_range(
509
+ v_abs, 0.0, 1.0, 'material visible absorptance') if v_abs is not None \
510
+ else None
511
+
512
+ @property
513
+ def solar_reflectance(self):
514
+ """Get or set the front solar reflectance of the material layer."""
515
+ return 1 - self.solar_absorptance
516
+
517
+ @solar_reflectance.setter
518
+ def solar_reflectance(self, v_ref):
519
+ v_ref = float_in_range(v_ref, 0.0, 1.0, 'material solar reflectance')
520
+ self.solar_absorptance = 1 - v_ref
521
+
522
+ @property
523
+ def visible_reflectance(self):
524
+ """Get or set the front visible reflectance of the material layer."""
525
+ return 1 - self.visible_absorptance
526
+
527
+ @visible_reflectance.setter
528
+ def visible_reflectance(self, v_ref):
529
+ v_ref = float_in_range(v_ref, 0.0, 1.0, 'material visible reflectance')
530
+ self.visible_absorptance = 1 - v_ref
531
+
532
+ @property
533
+ def thickness(self):
534
+ """Returns 0 for the thickness of a no mass material."""
535
+ return 0
536
+
537
+ @property
538
+ def mass_area_density(self):
539
+ """Returns 0 for the area density of a no mass material."""
540
+ return 0
541
+
542
+ @property
543
+ def area_heat_capacity(self):
544
+ """Returns 0 for the heat capacity of a no mass material."""
545
+ return 0
546
+
547
+ @classmethod
548
+ def from_idf(cls, idf_string):
549
+ """Create an EnergyMaterialNoMass from an EnergyPlus text string.
550
+
551
+ Args:
552
+ idf_string: A text string fully describing an EnergyPlus material.
553
+ """
554
+ ep_strs = parse_idf_string(idf_string, 'Material:NoMass,')
555
+ idf_defaults = {3: 0.9, 4: 0.7, 5: 0.7}
556
+ for i, ep_str in enumerate(ep_strs): # fill in any default values
557
+ if ep_str == '' and i in idf_defaults:
558
+ ep_strs[i] = idf_defaults[i]
559
+ ep_strs.insert(2, ep_strs.pop(1)) # move roughness to correct place
560
+ return cls(*ep_strs)
561
+
562
+ @classmethod
563
+ def from_idf_air_gap(cls, idf_string):
564
+ """Create an EnergyMaterialNoMass from an EnergyPlus string of an AirGap.
565
+
566
+ Args:
567
+ idf_string: A text string fully describing an EnergyPlus Material:AirGap.
568
+ """
569
+ ep_strs = parse_idf_string(idf_string, 'Material:AirGap,')
570
+ return cls(*ep_strs)
571
+
572
+ @classmethod
573
+ def from_dict(cls, data):
574
+ """Create a EnergyMaterialNoMass from a dictionary.
575
+
576
+ Args:
577
+ data: A python dictionary in the following format
578
+
579
+ .. code-block:: python
580
+
581
+ {
582
+ "type": 'EnergyMaterialNoMass',
583
+ "identifier": 'Insulation_R20_MediumRough_090_070_070',
584
+ "display_name": 'Insulation R2',
585
+ "r_value": 2.0,
586
+ "roughness": 'MediumRough',
587
+ "thermal_absorptance": 0.9,
588
+ "solar_absorptance": 0.7,
589
+ "visible_absorptance": 0.7
590
+ }
591
+ """
592
+ assert data['type'] == 'EnergyMaterialNoMass', \
593
+ 'Expected EnergyMaterialNoMass. Got {}.'.format(data['type'])
594
+
595
+ rough = data['roughness'] if 'roughness' in data and \
596
+ data['roughness'] is not None else 'MediumRough'
597
+ t_abs = data['thermal_absorptance'] if 'thermal_absorptance' in data and \
598
+ data['thermal_absorptance'] is not None else 0.9
599
+ s_abs = data['solar_absorptance'] if 'solar_absorptance' in data and \
600
+ data['solar_absorptance'] is not None else 0.7
601
+ v_abs = data['visible_absorptance'] if 'visible_absorptance' in data else None
602
+
603
+ new_mat = cls(data['identifier'], data['r_value'],
604
+ rough, t_abs, s_abs, v_abs)
605
+ if 'display_name' in data and data['display_name'] is not None:
606
+ new_mat.display_name = data['display_name']
607
+ if 'user_data' in data and data['user_data'] is not None:
608
+ new_mat.user_data = data['user_data']
609
+ if 'properties' in data and data['properties'] is not None:
610
+ new_mat.properties._load_extension_attr_from_dict(data['properties'])
611
+ return new_mat
612
+
613
+ def to_idf(self):
614
+ """Get an EnergyPlus string representation of the material.
615
+
616
+ ..code-block:: shell
617
+
618
+ Material:NoMass,
619
+ R13LAYER, ! Material Name
620
+ Rough, ! Roughness
621
+ 2.290965, ! Resistance {M**2K/W}
622
+ 0.9000000, ! Thermal Absorptance
623
+ 0.7500000, ! Solar Absorptance
624
+ 0.7500000; ! Visible Absorptance
625
+ """
626
+ values = (
627
+ self.identifier, self.roughness, self.r_value, self.thermal_absorptance,
628
+ self.solar_absorptance, self.visible_absorptance
629
+ )
630
+ comments = ('name', 'roughness', 'r-value {m2-K/W}', 'thermal absorptance',
631
+ 'solar absorptance', 'visible absorptance')
632
+ return generate_idf_string('Material:NoMass', values, comments)
633
+
634
+ def to_radiance_solar(self, specularity=0.0):
635
+ """Honeybee Radiance material from the solar reflectance of this material."""
636
+ try:
637
+ from honeybee_radiance.modifier.material import Plastic
638
+ except ImportError as e:
639
+ raise ImportError('honeybee_radiance library must be installed to use '
640
+ 'to_radiance_solar() method. {}'.format(e))
641
+ return Plastic.from_single_reflectance(
642
+ clean_rad_string(self.identifier), 1 - self.solar_absorptance, specularity,
643
+ self.RADIANCEROUGHTYPES[self.roughness])
644
+
645
+ def to_radiance_visible(self, specularity=0.0):
646
+ """Honeybee Radiance material from the visible reflectance of this material."""
647
+ try:
648
+ from honeybee_radiance.modifier.material import Plastic
649
+ except ImportError as e:
650
+ raise ImportError('honeybee_radiance library must be installed to use '
651
+ 'to_radiance_solar() method. {}'.format(e))
652
+ return Plastic.from_single_reflectance(
653
+ clean_rad_string(self.identifier), 1 - self.visible_absorptance, specularity,
654
+ self.RADIANCEROUGHTYPES[self.roughness])
655
+
656
+ def to_dict(self):
657
+ """Energy Material No Mass dictionary representation."""
658
+ base = {
659
+ 'type': 'EnergyMaterialNoMass',
660
+ 'identifier': self.identifier,
661
+ 'r_value': self.r_value,
662
+ 'roughness': self.roughness,
663
+ 'thermal_absorptance': self.thermal_absorptance,
664
+ 'solar_absorptance': self.solar_absorptance,
665
+ 'visible_absorptance': self.visible_absorptance
666
+ }
667
+ if self._display_name is not None:
668
+ base['display_name'] = self.display_name
669
+ if self._user_data is not None:
670
+ base['user_data'] = self.user_data
671
+ prop_dict = self.properties.to_dict()
672
+ if prop_dict is not None:
673
+ base['properties'] = prop_dict
674
+ return base
675
+
676
+ def __key(self):
677
+ return (self.identifier, self.r_value, self.roughness, self.thermal_absorptance,
678
+ self.solar_absorptance, self.visible_absorptance)
679
+
680
+ def __hash__(self):
681
+ """A small tuple based on the object properties, useful for hashing."""
682
+ return hash(self.__key())
683
+
684
+ def __eq__(self, other):
685
+ return isinstance(other, EnergyMaterialNoMass) and self.__key() == other.__key()
686
+
687
+ def __ne__(self, other):
688
+ return not self.__eq__(other)
689
+
690
+ def __repr__(self):
691
+ return self.to_idf()
692
+
693
+ def __copy__(self):
694
+ new_material = self.__class__(
695
+ self.identifier, self.r_value, self.roughness, self.thermal_absorptance,
696
+ self.solar_absorptance, self._visible_absorptance)
697
+ new_material._display_name = self._display_name
698
+ new_material._user_data = None if self._user_data is None \
699
+ else self._user_data.copy()
700
+ new_material._properties._duplicate_extension_attr(self._properties)
701
+ return new_material
702
+
703
+
704
+ @lockable
705
+ class EnergyMaterialVegetation(_EnergyMaterialOpaqueBase):
706
+ """EnergyPlus Material:RoofVegetation
707
+
708
+ Args:
709
+ identifier: Text string for a unique Material ID. Must be < 100 characters
710
+ and not contain any EnergyPlus special characters. This will be used to
711
+ identify the object across a model and in the exported IDF.
712
+ thickness: Number for the thickness of the soil layer [m]. (Default: 0.1).
713
+ conductivity: Number for the thermal conductivity of the dry soil
714
+ [W/m-K]. (Default: 0.35).
715
+ density: Number for the density of the dry soil [kg/m3]. (Default: 1100).
716
+ specific_heat: Number for the specific heat of the soil [J/kg-K]. (Default: 1200)
717
+ roughness: Text describing the relative roughness of the soil material. (Default:
718
+ MediumRough). Must be one of the following:
719
+
720
+ * VeryRough
721
+ * Rough
722
+ * MediumRough
723
+ * MediumSmooth
724
+ * Smooth
725
+ * VerySmooth
726
+
727
+ soil_thermal_absorptance: A number between 0 and 1 for the fraction of
728
+ incident long wavelength radiation that is absorbed by the soil
729
+ material. (Default: 0.9).
730
+ soil_solar_absorptance: A number between 0 and 1 for the fraction of incident
731
+ solar radiation absorbed by the soil material. (Default: 0.7).
732
+ soil_visible_absorptance: A number between 0 and 1 for the fraction of incident
733
+ visible wavelength radiation absorbed by the soil material.
734
+ Default is None, which will yield the same value as soil_solar_absorptance.
735
+ plant_height: A number between 0.005 and 1.0 for the height of plants in the
736
+ vegetation layer [m]. (Default: 0.2 m).
737
+ leaf_area_index: A number between 0.001 and 5.0 for the projected leaf area
738
+ per unit area of soil surface (aka. Leaf Area Index or LAI). Note that
739
+ the fraction of vegetation cover is calculated directly from LAI
740
+ using an empirical relation. (Default: 1.0).
741
+ leaf_reflectivity: A number between 0.05 and 0.5 for the fraction of incident
742
+ solar radiation that is reflected by the leaf surfaces. Solar radiation
743
+ includes the visible spectrum as well as infrared and ultraviolet
744
+ wavelengths. Typical values are 0.18 to 0.25. (Default: 0.22).
745
+ leaf_emissivity: A number between 0.8 and 1.0 for the ratio of thermal
746
+ radiation emitted from leaf surfaces to that emitted by an ideal black
747
+ body at the same temperature. (Default: 0.95).
748
+ min_stomatal_resist: A number between 50 and 300 for the resistance of the plants
749
+ to moisture transport [s/m]. Plants with low values of stomatal resistance
750
+ will result in higher evapotranspiration rates than plants with high
751
+ resistance. (Default: 180).
752
+
753
+ Properties:
754
+ * identifier
755
+ * display_name
756
+ * roughness
757
+ * thickness
758
+ * conductivity
759
+ * density
760
+ * specific_heat
761
+ * soil_thermal_absorptance
762
+ * soil_solar_absorptance
763
+ * soil_visible_absorptance
764
+ * plant_height
765
+ * leaf_area_index
766
+ * leaf_reflectivity
767
+ * leaf_emissivity
768
+ * min_stomatal_resist
769
+ * sat_vol_moist_cont
770
+ * residual_vol_moist_cont
771
+ * init_vol_moist_cont
772
+ * moist_diff_model
773
+ * soil_layer
774
+ * thermal_absorptance
775
+ * solar_absorptance
776
+ * visible_absorptance
777
+ * solar_reflectance
778
+ * visible_reflectance
779
+ * resistivity
780
+ * u_value
781
+ * r_value
782
+ * mass_area_density
783
+ * area_heat_capacity
784
+ * user_data
785
+ * properties
786
+ """
787
+ __slots__ = (
788
+ '_thickness', '_conductivity', '_density', '_specific_heat', '_roughness',
789
+ '_soil_thermal_absorptance', '_soil_solar_absorptance',
790
+ '_soil_visible_absorptance', '_plant_height', '_leaf_area_index',
791
+ '_leaf_reflectivity', '_leaf_emissivity', '_min_stomatal_resist',
792
+ '_sat_vol_moist_cont', '_residual_vol_moist_cont', '_init_vol_moist_cont',
793
+ '_moist_diff_model'
794
+ )
795
+ DIFFTYPES = ('Simple', 'Advanced')
796
+
797
+ def __init__(
798
+ self, identifier, thickness=0.1, conductivity=0.35, density=1100,
799
+ specific_heat=1200, roughness='MediumRough', soil_thermal_absorptance=0.9,
800
+ soil_solar_absorptance=0.7, soil_visible_absorptance=None, plant_height=0.2,
801
+ leaf_area_index=1.0, leaf_reflectivity=0.22, leaf_emissivity=0.95,
802
+ min_stomatal_resist=180
803
+ ):
804
+ # set the properties from the init arguments
805
+ _EnergyMaterialOpaqueBase.__init__(self, identifier)
806
+ self.thickness = thickness
807
+ self.conductivity = conductivity
808
+ self.density = density
809
+ self.specific_heat = specific_heat
810
+ self.roughness = roughness
811
+ self.soil_thermal_absorptance = soil_thermal_absorptance
812
+ self.soil_solar_absorptance = soil_solar_absorptance
813
+ self.soil_visible_absorptance = soil_visible_absorptance
814
+ self.plant_height = plant_height
815
+ self.leaf_area_index = leaf_area_index
816
+ self.leaf_reflectivity = leaf_reflectivity
817
+ self.leaf_emissivity = leaf_emissivity
818
+ self.min_stomatal_resist = min_stomatal_resist
819
+
820
+ # set some basic defaults for everything else
821
+ self._sat_vol_moist_cont = 0.3
822
+ self._residual_vol_moist_cont = 0.01
823
+ self._init_vol_moist_cont = 0.1
824
+ self._moist_diff_model = 'Simple'
825
+ self._locked = False
826
+ self._properties = EnergyMaterialVegetationProperties(self)
827
+
828
+ @property
829
+ def roughness(self):
830
+ """Get or set the text describing the roughness of the soil material layer."""
831
+ return self._roughness
832
+
833
+ @roughness.setter
834
+ def roughness(self, rough):
835
+ assert rough in self.ROUGHTYPES, 'Invalid input "{}" for material roughness.' \
836
+ ' Roughness must be one of the following:\n{}'.format(rough, self.ROUGHTYPES)
837
+ self._roughness = rough
838
+
839
+ @property
840
+ def thickness(self):
841
+ """Get or set the thickness of the soil material layer [m]."""
842
+ return self._thickness
843
+
844
+ @thickness.setter
845
+ def thickness(self, thick):
846
+ self._thickness = float_positive(thick, 'material thickness')
847
+ assert self._thickness != 0, 'Material thickness must be greater than zero.'
848
+
849
+ @property
850
+ def conductivity(self):
851
+ """Get or set the conductivity of the soil material layer [W/m-K]."""
852
+ return self._conductivity
853
+
854
+ @conductivity.setter
855
+ def conductivity(self, cond):
856
+ self._conductivity = float_positive(cond, 'material conductivity')
857
+
858
+ @property
859
+ def density(self):
860
+ """Get or set the density of the soil material layer [kg/m3]."""
861
+ return self._density
862
+
863
+ @density.setter
864
+ def density(self, dens):
865
+ self._density = float_positive(dens, 'material density')
866
+
867
+ @property
868
+ def specific_heat(self):
869
+ """Get or set the specific heat of the soil material layer [J/kg-K]."""
870
+ return self._specific_heat
871
+
872
+ @specific_heat.setter
873
+ def specific_heat(self, sp_ht):
874
+ self._specific_heat = float_in_range(
875
+ sp_ht, 100.0, input_name='material specific heat')
876
+
877
+ @property
878
+ def soil_thermal_absorptance(self):
879
+ """Get or set the thermal absorptance of the soil material layer."""
880
+ return self._soil_thermal_absorptance
881
+
882
+ @soil_thermal_absorptance.setter
883
+ def soil_thermal_absorptance(self, t_abs):
884
+ self._soil_thermal_absorptance = float_in_range(
885
+ t_abs, 0.0, 1.0, 'material thermal absorptance')
886
+
887
+ @property
888
+ def soil_solar_absorptance(self):
889
+ """Get or set the solar absorptance of the soil material layer."""
890
+ return self._soil_solar_absorptance
891
+
892
+ @soil_solar_absorptance.setter
893
+ def soil_solar_absorptance(self, s_abs):
894
+ self._soil_solar_absorptance = float_in_range(
895
+ s_abs, 0.0, 1.0, 'material solar absorptance')
896
+
897
+ @property
898
+ def soil_visible_absorptance(self):
899
+ """Get or set the visible absorptance of the soil material layer."""
900
+ return self._soil_visible_absorptance if self._soil_visible_absorptance \
901
+ is not None else self._soil_solar_absorptance
902
+
903
+ @soil_visible_absorptance.setter
904
+ def soil_visible_absorptance(self, v_abs):
905
+ self._soil_visible_absorptance = float_in_range(
906
+ v_abs, 0.0, 1.0, 'material visible absorptance') \
907
+ if v_abs is not None else None
908
+
909
+ @property
910
+ def plant_height(self):
911
+ """Get or set a number for the height of plants in the vegetation layer [m]."""
912
+ return self._plant_height
913
+
914
+ @plant_height.setter
915
+ def plant_height(self, p_h):
916
+ self._plant_height = float_in_range(p_h, 0.005, 1.000, 'plant height')
917
+
918
+ @property
919
+ def leaf_area_index(self):
920
+ """Get or set a number for the leaf area per unit area of soil surface."""
921
+ return self._leaf_area_index
922
+
923
+ @leaf_area_index.setter
924
+ def leaf_area_index(self, lai):
925
+ self._leaf_area_index = float_in_range(lai, 0.001, 5.00, 'leaf area index')
926
+
927
+ @property
928
+ def leaf_reflectivity(self):
929
+ """Get or set a number for the solar reflectivity of the leaf surfaces."""
930
+ return self._leaf_reflectivity
931
+
932
+ @leaf_reflectivity.setter
933
+ def leaf_reflectivity(self, l_r):
934
+ self._leaf_reflectivity = float_in_range(l_r, 0.05, 0.50, 'leaf reflectivity')
935
+
936
+ @property
937
+ def leaf_emissivity(self):
938
+ """Get or set a number for the emissivity of the leaf surfaces."""
939
+ return self._leaf_emissivity
940
+
941
+ @leaf_emissivity.setter
942
+ def leaf_emissivity(self, l_e):
943
+ self._leaf_emissivity = float_in_range(l_e, 0.8, 1.0)
944
+
945
+ @property
946
+ def min_stomatal_resist(self):
947
+ """Get or set a number for the resistance of the plants to moisture [s/m]."""
948
+ return self._min_stomatal_resist
949
+
950
+ @min_stomatal_resist.setter
951
+ def min_stomatal_resist(self, msr):
952
+ self._min_stomatal_resist = float_in_range(
953
+ msr, 50.0, 300.0, 'minimum stomatal resistance')
954
+
955
+ @property
956
+ def sat_vol_moist_cont(self):
957
+ """Get or set a number for the for the saturation moisture content of the soil.
958
+
959
+ The number must be between 0.1 and 0.5. (Default: 0.3).
960
+ """
961
+ return self._sat_vol_moist_cont
962
+
963
+ @sat_vol_moist_cont.setter
964
+ def sat_vol_moist_cont(self, s_vmc):
965
+ self._sat_vol_moist_cont = float_in_range(
966
+ s_vmc, 0.1, 0.5, 'saturation moisture content of soil layer')
967
+
968
+ @property
969
+ def residual_vol_moist_cont(self):
970
+ """Get or set a number for the for the residual moisture content of the soil.
971
+
972
+ The number must be between 0.01 and 0.1. (Default: .01).
973
+ """
974
+ return self._residual_vol_moist_cont
975
+
976
+ @residual_vol_moist_cont.setter
977
+ def residual_vol_moist_cont(self, r_vmc):
978
+ self._residual_vol_moist_cont = float_in_range(
979
+ r_vmc, 0.01, 0.1, 'residual moisture content of soil layer')
980
+
981
+ @property
982
+ def init_vol_moist_cont(self):
983
+ """Get or set a number for the for the initial moisture content of the soil.
984
+
985
+ The number must be between 0.05 and 0.5. (Default: .01).
986
+ """
987
+ return self._init_vol_moist_cont
988
+
989
+ @init_vol_moist_cont.setter
990
+ def init_vol_moist_cont(self, i_vmc):
991
+ self._init_vol_moist_cont = float_in_range(
992
+ i_vmc, 0.05, 0.50, 'initial moisture content of soil layer')
993
+
994
+ @property
995
+ def moist_diff_model(self):
996
+ """Get or set text for the moisture diffusion model to use.
997
+
998
+ Note that the Advanced model should be run with simulation parameters of 20
999
+ timesteps per hour. (Default: Simple). Choose from the following:
1000
+
1001
+ * Simple
1002
+ * Advanced
1003
+ """
1004
+ return self._moist_diff_model
1005
+
1006
+ @moist_diff_model.setter
1007
+ def moist_diff_model(self, mdc):
1008
+ assert mdc in self.DIFFTYPES, 'Invalid input "{}" for moisture diffusion ' \
1009
+ 'model. Must be one of the following:\n{}'.format(mdc, self.DIFFTYPES)
1010
+ self._moist_diff_model = mdc
1011
+
1012
+ @property
1013
+ def soil_layer(self):
1014
+ """Get an EnergyMaterial representing only the soil."""
1015
+ return EnergyMaterial(
1016
+ '{}_Soil'.format(self.identifier), self.thickness, self.conductivity,
1017
+ self.density, self.specific_heat, self.roughness,
1018
+ self.soil_thermal_absorptance,
1019
+ self.soil_solar_absorptance, self.soil_visible_absorptance)
1020
+
1021
+ @property
1022
+ def thermal_absorptance(self):
1023
+ """Get the thermal absorptance including soil and vegetation."""
1024
+ return self._leaf_emissivity if self._leaf_area_index >= 1 else \
1025
+ (self._leaf_emissivity * self._leaf_area_index) + \
1026
+ (self._soil_thermal_absorptance * (1 - self._leaf_area_index))
1027
+
1028
+ @property
1029
+ def solar_absorptance(self):
1030
+ """Get the solar absorptance including soil and vegetation."""
1031
+ return 1 - self._leaf_reflectivity if self._leaf_area_index >= 1 else \
1032
+ ((1 - self._leaf_reflectivity) * self._leaf_area_index) + \
1033
+ (self._soil_solar_absorptance * (1 - self._leaf_area_index))
1034
+
1035
+ @property
1036
+ def visible_absorptance(self):
1037
+ """Get the visible absorptance including soil and vegetation."""
1038
+ s_vis = self._soil_visible_absorptance if self._soil_visible_absorptance \
1039
+ is not None else self._soil_solar_absorptance
1040
+ return 1 - self._leaf_reflectivity if self._leaf_area_index >= 1 else \
1041
+ ((1 - self._leaf_reflectivity) * self._leaf_area_index) + \
1042
+ (s_vis * (1 - self._leaf_area_index))
1043
+
1044
+ @property
1045
+ def solar_reflectance(self):
1046
+ """Get the solar reflectance including soil and vegetation."""
1047
+ return 1 - self.solar_absorptance
1048
+
1049
+ @property
1050
+ def visible_reflectance(self):
1051
+ """Get the visible reflectance including soil and vegetation."""
1052
+ return 1 - self.visible_absorptance
1053
+
1054
+ @property
1055
+ def resistivity(self):
1056
+ """Get or set the resistivity of the material layer [m-K/W]."""
1057
+ return 1 / self._conductivity
1058
+
1059
+ @resistivity.setter
1060
+ def resistivity(self, resis):
1061
+ self._conductivity = 1 / float_positive(resis, 'material resistivity')
1062
+
1063
+ @property
1064
+ def r_value(self):
1065
+ """Get or set the R-value of the material in [m2-K/W] (excluding air films).
1066
+
1067
+ Note that, when setting the R-value, the thickness of the material will
1068
+ remain fixed and only the conductivity will be adjusted.
1069
+ """
1070
+ return self.thickness / self.conductivity
1071
+
1072
+ @r_value.setter
1073
+ def r_value(self, r_val):
1074
+ _new_conductivity = self.thickness / float_positive(r_val, 'material r-value')
1075
+ self._conductivity = _new_conductivity
1076
+
1077
+ @property
1078
+ def u_value(self):
1079
+ """Get or set the U-value of the material [W/m2-K] (excluding air films).
1080
+
1081
+ Note that, when setting the R-value, the thickness of the material will
1082
+ remain fixed and only the conductivity will be adjusted.
1083
+ """
1084
+ return self.conductivity / self.thickness
1085
+
1086
+ @u_value.setter
1087
+ def u_value(self, u_val):
1088
+ self.r_value = 1 / float_positive(u_val, 'material u-value')
1089
+
1090
+ @property
1091
+ def mass_area_density(self):
1092
+ """The area density of the material [kg/m2]."""
1093
+ return self.thickness * self.density
1094
+
1095
+ @property
1096
+ def area_heat_capacity(self):
1097
+ """The heat capacity per unit area of the material [J/K-m2]."""
1098
+ return self.mass_area_density * self.specific_heat
1099
+
1100
+ @classmethod
1101
+ def from_idf(cls, idf_string):
1102
+ """Create an EnergyMaterial from an EnergyPlus text string.
1103
+
1104
+ Args:
1105
+ idf_string: A text string fully describing an EnergyPlus roof
1106
+ vegetation material.
1107
+ """
1108
+ ep_strs = parse_idf_string(idf_string, 'Material:RoofVegetation')
1109
+ vals = [None, 0.2, 1, 0.22, 0.95, 180, None, 'MediumRough', 0.1, 0.35,
1110
+ 1100, 1200, 0.9, 0.7, 0.75, 0.3, 0.01, 0.1, 'Advanced']
1111
+ for i, ep_str in enumerate(ep_strs): # fill in any default values
1112
+ if ep_str != '':
1113
+ vals[i] = ep_str
1114
+ mat = cls(vals[0], vals[8], vals[9], vals[10], vals[11],
1115
+ vals[7], vals[12], vals[13], vals[14],
1116
+ vals[1], vals[2], vals[3], vals[4], vals[5])
1117
+ mat.sat_vol_moist_cont = vals[15]
1118
+ mat.residual_vol_moist_cont = vals[16]
1119
+ mat.init_vol_moist_cont = vals[17]
1120
+ mat.moist_diff_model = vals[18]
1121
+ return mat
1122
+
1123
+ @classmethod
1124
+ def from_dict(cls, data):
1125
+ """Create an EnergyMaterialVegetation from a dictionary.
1126
+
1127
+ Args:
1128
+ data: A python dictionary in the following format
1129
+
1130
+ .. code-block:: python
1131
+
1132
+ {
1133
+ 'type': 'EnergyMaterialVegetation',
1134
+ 'identifier': 'Green_Roof_040_110_7868_987',
1135
+ 'plant_height': 0.9,
1136
+ 'leaf_area_index': 1.0,
1137
+ 'leaf_reflectivity': 0.22,
1138
+ 'leaf_emissivity': 0.95,
1139
+ 'min_stomatal_resist': 180,
1140
+ 'soil_layer_name': 'GreenRoofSoil,
1141
+ 'roughness': 'MediumRough,
1142
+ 'thickness':0.1,
1143
+ 'conductivity': 0.35,
1144
+ 'density': 1100,
1145
+ 'specific_heat': 800,
1146
+ 'soil_thermal_absorptance': 0.9,
1147
+ 'soil_solar_absorptance': 0.7,
1148
+ 'soil_visible_absorptance':0.7,
1149
+ 'sat_vol_moist_cont': 0.3,
1150
+ 'residual_vol_moist_cont': 0.01,
1151
+ 'init_vol_moist_cont': 0.1,
1152
+ 'moist_diff_model': 'Simple'
1153
+ }
1154
+
1155
+ """
1156
+ assert data['type'] == 'EnergyMaterialVegetation', \
1157
+ 'Expected EnergyMaterialVegetation. Got {}'.format(data['type'])
1158
+
1159
+ rough = data['roughness'] if 'roughness' in data and \
1160
+ data['roughness'] is not None else 'MediumRough'
1161
+ thick = data['thickness'] if 'thickness' in data and \
1162
+ data['thickness'] is not None else 0.1
1163
+ t_abs = data['soil_thermal_absorptance'] if 'soil_thermal_absorptance' in data \
1164
+ and data['soil_thermal_absorptance'] is not None else 0.9
1165
+ s_abs = data['soil_solar_absorptance'] if 'soil_solar_absorptance' in data \
1166
+ and data['soil_solar_absorptance'] is not None else 0.7
1167
+ v_abs = data['soil_visible_absorptance'] \
1168
+ if 'soil_visible_absorptance' in data else None
1169
+ cond = data['conductivity'] if 'conductivity' in data and \
1170
+ data['conductivity'] is not None else 0.35
1171
+ dens = data['density'] if 'density' in data and \
1172
+ data['density'] is not None else 1100
1173
+ sp_ht = data['specific_heat'] if 'specific_heat' in data and \
1174
+ data['specific_heat'] is not None else 1200
1175
+ p_h = data['plant_height'] if 'plant_height' in data and \
1176
+ data['plant_height'] is not None else 0.2
1177
+ lai = data['leaf_area_index'] if 'leaf_area_index' in data and \
1178
+ data['leaf_area_index'] is not None else 1.0
1179
+ l_r = data['leaf_reflectivity'] if 'leaf_reflectivity' in data and \
1180
+ data['leaf_reflectivity'] is not None else 0.22
1181
+ l_e = data['leaf_emissivity'] if 'leaf_emissivity' in data and \
1182
+ data['leaf_emissivity'] is not None else 0.95
1183
+ msr = data['min_stomatal_resist'] if 'min_stomatal_resist' in data and \
1184
+ data['min_stomatal_resist'] is not None else 180
1185
+
1186
+ s_vmc = data['sat_vol_moist_cont'] if 'sat_vol_moist_cont' \
1187
+ in data and data['sat_vol_moist_cont'] is not None else 0.3
1188
+ r_vmc = data['residual_vol_moist_cont'] if 'residual_vol_moist_cont' \
1189
+ in data and data['residual_vol_moist_cont'] is not None else 0.01
1190
+ i_vmc = data['init_vol_moist_cont'] if 'init_vol_moist_cont' \
1191
+ in data and data['init_vol_moist_cont'] is not None else 0.1
1192
+ mdc = data['moist_diff_model'] if 'moist_diff_model' in data and \
1193
+ data['moist_diff_model'] is not None else 'Simple'
1194
+
1195
+ new_mat = cls(
1196
+ data['identifier'], thick, cond, dens, sp_ht, rough, t_abs, s_abs, v_abs,
1197
+ p_h, lai, l_r, l_e, msr)
1198
+ new_mat.sat_vol_moist_cont = s_vmc
1199
+ new_mat.residual_vol_moist_cont = r_vmc
1200
+ new_mat.init_vol_moist_cont = i_vmc
1201
+ new_mat.moist_diff_model = mdc
1202
+ if 'display_name' in data and data['display_name'] is not None:
1203
+ new_mat.display_name = data['display_name']
1204
+ if 'user_data' in data and data['user_data'] is not None:
1205
+ new_mat.user_data = data['user_data']
1206
+ if 'properties' in data and data['properties'] is not None:
1207
+ new_mat.properties._load_extension_attr_from_dict(data['properties'])
1208
+
1209
+ return new_mat
1210
+
1211
+ def to_radiance_solar(self, specularity=0.0):
1212
+ """Honeybee Radiance material from the solar reflectance of this material."""
1213
+ try:
1214
+ from honeybee_radiance.modifier.material import Plastic
1215
+ except ImportError as e:
1216
+ raise ImportError('honeybee_radiance library must be installed to use '
1217
+ 'to_radiance_solar() method. {}'.format(e))
1218
+ return Plastic.from_single_reflectance(
1219
+ clean_rad_string(self.identifier), self.solar_reflectance, specularity,
1220
+ self.RADIANCEROUGHTYPES[self.roughness])
1221
+
1222
+ def to_radiance_visible(self, specularity=0.0):
1223
+ """Honeybee Radiance material from the visible reflectance of this material."""
1224
+ try:
1225
+ from honeybee_radiance.modifier.material import Plastic
1226
+ except ImportError as e:
1227
+ raise ImportError('honeybee_radiance library must be installed to use '
1228
+ 'to_radiance_solar() method. {}'.format(e))
1229
+ return Plastic.from_single_reflectance(
1230
+ clean_rad_string(self.identifier), self.visible_reflectance, specularity,
1231
+ self.RADIANCEROUGHTYPES[self.roughness])
1232
+
1233
+ def to_idf(self):
1234
+ """Get an EnergyPlus string representation of the material.
1235
+
1236
+ .. code-block:: shell
1237
+
1238
+ Material:RoofVegetation,
1239
+ BaseEco, !- Name
1240
+ 0.5, !- Height of Plants {m}
1241
+ 5, !- Leaf Area Index {dimensionless}
1242
+ 0.2, !- Leaf Reflectivity {dimensionless}
1243
+ 0.95, !- Leaf Emissivity
1244
+ 180, !- Minimum Stomatal Resistance {s/m}
1245
+ EcoRoofSoil, !- Soil Layer Name
1246
+ MediumSmooth, !- Roughness
1247
+ 0.18, !- Thickness {m}
1248
+ 0.4, !- Conductivity of Dry Soil {W/m-K}
1249
+ 641, !- Density of Dry Soil {kg/m3}
1250
+ 1100, !- Specific Heat of Dry Soil {J/kg-K}
1251
+ 0.95, !- Thermal Absorptance
1252
+ 0.8, !- Solar Absorptance
1253
+ 0.7, !- Visible Absorptance
1254
+ 0.4, !- Saturation Volumetric Moisture Content of the Soil Layer
1255
+ 0.01, !- Residual Volumetric Moisture Content of the Soil Layer
1256
+ 0.2, !- Initial Volumetric Moisture Content of the Soil Layer
1257
+ Simple; !- Moisture Diffusion Calculation Method
1258
+ """
1259
+ soil_name = '{}_SoilLayer'.format(self.identifier)
1260
+ values = (
1261
+ self.identifier, self.plant_height, self.leaf_area_index,
1262
+ self.leaf_reflectivity, self.leaf_emissivity, self.min_stomatal_resist,
1263
+ soil_name, self.roughness, self.thickness, self.conductivity,
1264
+ self.density, self.specific_heat, self.soil_thermal_absorptance,
1265
+ self.soil_solar_absorptance, self.soil_visible_absorptance,
1266
+ self.sat_vol_moist_cont, self.residual_vol_moist_cont,
1267
+ self.init_vol_moist_cont, self.moist_diff_model
1268
+ )
1269
+ comments = (
1270
+ 'name', 'height of plants', 'leaf area index', 'leaf reflectivity',
1271
+ 'leaf emissivity', 'minimum stomatal resistance', 'soil layer name',
1272
+ 'roughness', 'thickness', 'conductivity of dry soil', 'density of dry soil',
1273
+ 'specific heat of dry soil', 'soil thermal absorptance',
1274
+ 'soil solar absorptance', 'soil visible absorptance',
1275
+ 'saturation volumetric moisture content of soil',
1276
+ 'residual volumetric moisture content of soil',
1277
+ 'initial volumetric moisture content of soil',
1278
+ 'moisture diffusion calculation method'
1279
+ )
1280
+ return generate_idf_string('Material:RoofVegetation', values, comments)
1281
+
1282
+ def to_dict(self):
1283
+ base = {
1284
+ 'type': 'EnergyMaterialVegetation',
1285
+ 'identifier': self.identifier,
1286
+ 'plant_height': self.plant_height,
1287
+ 'leaf_area_index': self.leaf_area_index,
1288
+ 'leaf_reflectivity': self.leaf_reflectivity,
1289
+ 'leaf_emissivity': self.leaf_emissivity,
1290
+ 'min_stomatal_resist': self.min_stomatal_resist,
1291
+ 'roughness': self.roughness,
1292
+ 'thickness': self.thickness,
1293
+ 'conductivity': self.conductivity,
1294
+ 'density': self.density,
1295
+ 'specific_heat': self.specific_heat,
1296
+ 'soil_thermal_absorptance': self.soil_thermal_absorptance,
1297
+ 'soil_solar_absorptance': self.soil_solar_absorptance,
1298
+ 'soil_visible_absorptance': self.soil_visible_absorptance,
1299
+ 'sat_vol_moist_cont': self.sat_vol_moist_cont,
1300
+ 'residual_vol_moist_cont': self.residual_vol_moist_cont,
1301
+ 'init_vol_moist_cont': self.init_vol_moist_cont,
1302
+ 'moist_diff_model': self.moist_diff_model
1303
+ }
1304
+ if self._display_name is not None:
1305
+ base['display_name'] = self.display_name
1306
+ if self._user_data is not None:
1307
+ base['user_data'] = self.user_data
1308
+ prop_dict = self.properties.to_dict()
1309
+ if prop_dict is not None:
1310
+ base['properties'] = prop_dict
1311
+ return base
1312
+
1313
+ def __key(self):
1314
+ """A tuple based on the object properties, useful for hashing."""
1315
+ return (self.identifier, self.plant_height, self.leaf_area_index,
1316
+ self.leaf_reflectivity, self.leaf_emissivity, self.min_stomatal_resist,
1317
+ self.roughness, self.thickness, self.conductivity,
1318
+ self.density, self.specific_heat, self.soil_thermal_absorptance,
1319
+ self.soil_solar_absorptance, self.soil_visible_absorptance,
1320
+ self.sat_vol_moist_cont, self.residual_vol_moist_cont,
1321
+ self.init_vol_moist_cont, self.moist_diff_model)
1322
+
1323
+ def __hash__(self):
1324
+ return hash(self.__key())
1325
+
1326
+ def __eq__(self, other):
1327
+ return isinstance(other, EnergyMaterialVegetation) \
1328
+ and self.__key() == other.__key()
1329
+
1330
+ def __ne__(self, other):
1331
+ return not self.__eq__(other)
1332
+
1333
+ def __repr__(self):
1334
+ return self.to_idf()
1335
+
1336
+ def __copy__(self):
1337
+ new_material = EnergyMaterialVegetation(
1338
+ self.identifier, self.thickness, self.conductivity, self.density,
1339
+ self.specific_heat, self.roughness, self.soil_thermal_absorptance,
1340
+ self.soil_solar_absorptance, self.soil_visible_absorptance,
1341
+ self.plant_height, self.leaf_area_index, self.leaf_reflectivity,
1342
+ self.leaf_emissivity, self.min_stomatal_resist)
1343
+ new_material._sat_vol_moist_cont = self._sat_vol_moist_cont
1344
+ new_material._residual_vol_moist_cont = self._residual_vol_moist_cont
1345
+ new_material._init_vol_moist_cont = self._init_vol_moist_cont
1346
+ new_material._moist_diff_model = self._moist_diff_model
1347
+ new_material._display_name = self._display_name
1348
+ new_material._user_data = None if self._user_data is None \
1349
+ else self._user_data.copy()
1350
+ new_material._properties._duplicate_extension_attr(self._properties)
1351
+ return new_material