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.
- honeybee_energy/__init__.py +24 -0
- honeybee_energy/__main__.py +4 -0
- honeybee_energy/_extend_honeybee.py +145 -0
- honeybee_energy/altnumber.py +21 -0
- honeybee_energy/baseline/__init__.py +2 -0
- honeybee_energy/baseline/create.py +608 -0
- honeybee_energy/baseline/data/__init__.py +1 -0
- honeybee_energy/baseline/data/constructions.csv +64 -0
- honeybee_energy/baseline/data/fen_ratios.csv +15 -0
- honeybee_energy/baseline/data/lpd_building.csv +21 -0
- honeybee_energy/baseline/data/pci_2016.csv +22 -0
- honeybee_energy/baseline/data/pci_2019.csv +22 -0
- honeybee_energy/baseline/data/pci_2022.csv +22 -0
- honeybee_energy/baseline/data/shw.csv +21 -0
- honeybee_energy/baseline/pci.py +512 -0
- honeybee_energy/baseline/result.py +371 -0
- honeybee_energy/boundarycondition.py +128 -0
- honeybee_energy/cli/__init__.py +69 -0
- honeybee_energy/cli/baseline.py +475 -0
- honeybee_energy/cli/edit.py +327 -0
- honeybee_energy/cli/lib.py +1154 -0
- honeybee_energy/cli/result.py +810 -0
- honeybee_energy/cli/setconfig.py +124 -0
- honeybee_energy/cli/settings.py +569 -0
- honeybee_energy/cli/simulate.py +380 -0
- honeybee_energy/cli/translate.py +1714 -0
- honeybee_energy/cli/validate.py +224 -0
- honeybee_energy/config.json +11 -0
- honeybee_energy/config.py +842 -0
- honeybee_energy/construction/__init__.py +1 -0
- honeybee_energy/construction/_base.py +374 -0
- honeybee_energy/construction/air.py +325 -0
- honeybee_energy/construction/dictutil.py +89 -0
- honeybee_energy/construction/dynamic.py +607 -0
- honeybee_energy/construction/opaque.py +460 -0
- honeybee_energy/construction/shade.py +319 -0
- honeybee_energy/construction/window.py +1096 -0
- honeybee_energy/construction/windowshade.py +847 -0
- honeybee_energy/constructionset.py +1655 -0
- honeybee_energy/dictutil.py +56 -0
- honeybee_energy/generator/__init__.py +5 -0
- honeybee_energy/generator/loadcenter.py +204 -0
- honeybee_energy/generator/pv.py +535 -0
- honeybee_energy/hvac/__init__.py +21 -0
- honeybee_energy/hvac/_base.py +124 -0
- honeybee_energy/hvac/_template.py +270 -0
- honeybee_energy/hvac/allair/__init__.py +22 -0
- honeybee_energy/hvac/allair/_base.py +349 -0
- honeybee_energy/hvac/allair/furnace.py +168 -0
- honeybee_energy/hvac/allair/psz.py +131 -0
- honeybee_energy/hvac/allair/ptac.py +163 -0
- honeybee_energy/hvac/allair/pvav.py +109 -0
- honeybee_energy/hvac/allair/vav.py +128 -0
- honeybee_energy/hvac/detailed.py +337 -0
- honeybee_energy/hvac/doas/__init__.py +28 -0
- honeybee_energy/hvac/doas/_base.py +345 -0
- honeybee_energy/hvac/doas/fcu.py +127 -0
- honeybee_energy/hvac/doas/radiant.py +329 -0
- honeybee_energy/hvac/doas/vrf.py +81 -0
- honeybee_energy/hvac/doas/wshp.py +91 -0
- honeybee_energy/hvac/heatcool/__init__.py +23 -0
- honeybee_energy/hvac/heatcool/_base.py +177 -0
- honeybee_energy/hvac/heatcool/baseboard.py +61 -0
- honeybee_energy/hvac/heatcool/evapcool.py +72 -0
- honeybee_energy/hvac/heatcool/fcu.py +92 -0
- honeybee_energy/hvac/heatcool/gasunit.py +53 -0
- honeybee_energy/hvac/heatcool/radiant.py +269 -0
- honeybee_energy/hvac/heatcool/residential.py +77 -0
- honeybee_energy/hvac/heatcool/vrf.py +54 -0
- honeybee_energy/hvac/heatcool/windowac.py +70 -0
- honeybee_energy/hvac/heatcool/wshp.py +62 -0
- honeybee_energy/hvac/idealair.py +699 -0
- honeybee_energy/internalmass.py +310 -0
- honeybee_energy/lib/__init__.py +1 -0
- honeybee_energy/lib/_loadconstructions.py +194 -0
- honeybee_energy/lib/_loadconstructionsets.py +117 -0
- honeybee_energy/lib/_loadmaterials.py +83 -0
- honeybee_energy/lib/_loadprogramtypes.py +125 -0
- honeybee_energy/lib/_loadschedules.py +87 -0
- honeybee_energy/lib/_loadtypelimits.py +64 -0
- honeybee_energy/lib/constructions.py +207 -0
- honeybee_energy/lib/constructionsets.py +95 -0
- honeybee_energy/lib/materials.py +67 -0
- honeybee_energy/lib/programtypes.py +125 -0
- honeybee_energy/lib/schedules.py +61 -0
- honeybee_energy/lib/scheduletypelimits.py +31 -0
- honeybee_energy/load/__init__.py +1 -0
- honeybee_energy/load/_base.py +190 -0
- honeybee_energy/load/daylight.py +397 -0
- honeybee_energy/load/dictutil.py +47 -0
- honeybee_energy/load/equipment.py +771 -0
- honeybee_energy/load/hotwater.py +543 -0
- honeybee_energy/load/infiltration.py +460 -0
- honeybee_energy/load/lighting.py +480 -0
- honeybee_energy/load/people.py +497 -0
- honeybee_energy/load/process.py +472 -0
- honeybee_energy/load/setpoint.py +816 -0
- honeybee_energy/load/ventilation.py +550 -0
- honeybee_energy/material/__init__.py +1 -0
- honeybee_energy/material/_base.py +166 -0
- honeybee_energy/material/dictutil.py +59 -0
- honeybee_energy/material/frame.py +367 -0
- honeybee_energy/material/gas.py +1087 -0
- honeybee_energy/material/glazing.py +854 -0
- honeybee_energy/material/opaque.py +1351 -0
- honeybee_energy/material/shade.py +1360 -0
- honeybee_energy/measure.py +472 -0
- honeybee_energy/programtype.py +723 -0
- honeybee_energy/properties/__init__.py +1 -0
- honeybee_energy/properties/aperture.py +333 -0
- honeybee_energy/properties/door.py +342 -0
- honeybee_energy/properties/extension.py +244 -0
- honeybee_energy/properties/face.py +274 -0
- honeybee_energy/properties/model.py +2640 -0
- honeybee_energy/properties/room.py +1747 -0
- honeybee_energy/properties/shade.py +314 -0
- honeybee_energy/properties/shademesh.py +262 -0
- honeybee_energy/reader.py +48 -0
- honeybee_energy/result/__init__.py +1 -0
- honeybee_energy/result/colorobj.py +648 -0
- honeybee_energy/result/emissions.py +290 -0
- honeybee_energy/result/err.py +101 -0
- honeybee_energy/result/eui.py +100 -0
- honeybee_energy/result/generation.py +160 -0
- honeybee_energy/result/loadbalance.py +890 -0
- honeybee_energy/result/match.py +202 -0
- honeybee_energy/result/osw.py +90 -0
- honeybee_energy/result/rdd.py +59 -0
- honeybee_energy/result/zsz.py +190 -0
- honeybee_energy/run.py +1577 -0
- honeybee_energy/schedule/__init__.py +1 -0
- honeybee_energy/schedule/day.py +626 -0
- honeybee_energy/schedule/dictutil.py +59 -0
- honeybee_energy/schedule/fixedinterval.py +1012 -0
- honeybee_energy/schedule/rule.py +619 -0
- honeybee_energy/schedule/ruleset.py +1867 -0
- honeybee_energy/schedule/typelimit.py +310 -0
- honeybee_energy/shw.py +315 -0
- honeybee_energy/simulation/__init__.py +1 -0
- honeybee_energy/simulation/control.py +214 -0
- honeybee_energy/simulation/daylightsaving.py +185 -0
- honeybee_energy/simulation/dictutil.py +51 -0
- honeybee_energy/simulation/output.py +646 -0
- honeybee_energy/simulation/parameter.py +606 -0
- honeybee_energy/simulation/runperiod.py +443 -0
- honeybee_energy/simulation/shadowcalculation.py +295 -0
- honeybee_energy/simulation/sizing.py +546 -0
- honeybee_energy/ventcool/__init__.py +5 -0
- honeybee_energy/ventcool/_crack_data.py +91 -0
- honeybee_energy/ventcool/afn.py +289 -0
- honeybee_energy/ventcool/control.py +269 -0
- honeybee_energy/ventcool/crack.py +126 -0
- honeybee_energy/ventcool/fan.py +493 -0
- honeybee_energy/ventcool/opening.py +365 -0
- honeybee_energy/ventcool/simulation.py +314 -0
- honeybee_energy/writer.py +1078 -0
- honeybee_energy-1.116.106.dist-info/METADATA +113 -0
- honeybee_energy-1.116.106.dist-info/RECORD +162 -0
- honeybee_energy-1.116.106.dist-info/WHEEL +5 -0
- honeybee_energy-1.116.106.dist-info/entry_points.txt +2 -0
- honeybee_energy-1.116.106.dist-info/licenses/LICENSE +661 -0
- 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
|