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 @@
|
|
|
1
|
+
"""honeybee-energy properties."""
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Aperture Energy Properties."""
|
|
3
|
+
from honeybee.units import conversion_factor_to_meters
|
|
4
|
+
from honeybee.checkdup import is_equivalent
|
|
5
|
+
|
|
6
|
+
from ..construction.dictutil import dict_to_construction
|
|
7
|
+
from ..material.glazing import EnergyWindowMaterialSimpleGlazSys
|
|
8
|
+
from ..construction.window import WindowConstruction
|
|
9
|
+
from ..construction.windowshade import WindowConstructionShade
|
|
10
|
+
from ..construction.dynamic import WindowConstructionDynamic
|
|
11
|
+
from ..ventcool.opening import VentilationOpening
|
|
12
|
+
from ..lib.constructionsets import generic_construction_set
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ApertureEnergyProperties(object):
|
|
16
|
+
"""Energy Properties for Honeybee Aperture.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
host: A honeybee_core Aperture object that hosts these properties.
|
|
20
|
+
construction: An optional Honeybee WindowConstruction, WindowConstructionShade
|
|
21
|
+
or WindowConstructionDynamic object for the aperture. If None, it will
|
|
22
|
+
be set by the parent Room ConstructionSet or the the Honeybee default
|
|
23
|
+
generic ConstructionSet.
|
|
24
|
+
vent_opening: An optional VentilationOpening to specify the operable
|
|
25
|
+
portion of the Aperture. (Default: None).
|
|
26
|
+
|
|
27
|
+
Properties:
|
|
28
|
+
* host
|
|
29
|
+
* construction
|
|
30
|
+
* vent_opening
|
|
31
|
+
* is_construction_set_on_object
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
__slots__ = ('_host', '_construction', '_vent_opening')
|
|
35
|
+
|
|
36
|
+
def __init__(self, host, construction=None, vent_opening=None):
|
|
37
|
+
"""Initialize Aperture energy properties."""
|
|
38
|
+
self._host = host
|
|
39
|
+
self.construction = construction
|
|
40
|
+
self.vent_opening = vent_opening
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def host(self):
|
|
44
|
+
"""Get the Aperture object hosting these properties."""
|
|
45
|
+
return self._host
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def construction(self):
|
|
49
|
+
"""Get or set Aperture Construction.
|
|
50
|
+
|
|
51
|
+
If the Construction is not set on the aperture-level, then it will be assigned
|
|
52
|
+
based on the ConstructionSet assigned to the parent Room. If there is no
|
|
53
|
+
parent Room or the parent Room's ConstructionSet has no construction for
|
|
54
|
+
the aperture, it will be assigned using the honeybee default generic
|
|
55
|
+
construction set.
|
|
56
|
+
"""
|
|
57
|
+
if self._construction: # set by user
|
|
58
|
+
return self._construction
|
|
59
|
+
elif self._host.has_parent and self._host.parent.has_parent: # set by zone
|
|
60
|
+
constr_set = self._host.parent.parent.properties.energy.construction_set
|
|
61
|
+
return constr_set.get_aperture_construction(
|
|
62
|
+
self._host.boundary_condition.name, self._host.is_operable,
|
|
63
|
+
self._host.parent.type.name)
|
|
64
|
+
elif self._host.has_parent: # generic but influenced by parent face
|
|
65
|
+
return generic_construction_set.get_aperture_construction(
|
|
66
|
+
self._host.boundary_condition.name, self._host.is_operable,
|
|
67
|
+
self._host.parent.type.name)
|
|
68
|
+
else:
|
|
69
|
+
return generic_construction_set.get_aperture_construction(
|
|
70
|
+
self._host.boundary_condition.name, self._host.is_operable, 'Wall')
|
|
71
|
+
|
|
72
|
+
@construction.setter
|
|
73
|
+
def construction(self, value):
|
|
74
|
+
if value is not None:
|
|
75
|
+
vw = (WindowConstruction, WindowConstructionShade, WindowConstructionDynamic)
|
|
76
|
+
assert isinstance(value, vw), 'Expected WindowConstruction, ' \
|
|
77
|
+
'WindowConstructionShade or WindowConstructionDynamic for aperture.' \
|
|
78
|
+
' Got {}'.format(type(value))
|
|
79
|
+
value.lock() # lock editing in case construction has multiple references
|
|
80
|
+
self._construction = value
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def vent_opening(self):
|
|
84
|
+
"""Get or set a VentilationOpening object to specify the operable portion."""
|
|
85
|
+
return self._vent_opening
|
|
86
|
+
|
|
87
|
+
@vent_opening.setter
|
|
88
|
+
def vent_opening(self, value):
|
|
89
|
+
if value is not None:
|
|
90
|
+
assert isinstance(value, VentilationOpening), 'Expected Ventilation' \
|
|
91
|
+
'Opening for Aperture vent_opening. Got {}'.format(type(value))
|
|
92
|
+
assert self.host.is_operable, 'Aperture must have a "True" is_operable ' \
|
|
93
|
+
'property in order to assign vent_opening energy properties.'
|
|
94
|
+
if value._parent is None:
|
|
95
|
+
value._parent = self.host
|
|
96
|
+
elif value._parent.identifier != self.host.identifier:
|
|
97
|
+
raise ValueError(
|
|
98
|
+
'{0} objects can be assigned to only one parent.\n{0} cannot be '
|
|
99
|
+
'assigned to Aperture "{1}" since it is already assigned to "{2}".\n'
|
|
100
|
+
'Try duplicating the object and then assign it.'.format(
|
|
101
|
+
'VentilationOpening', self.host.identifier,
|
|
102
|
+
value._parent.identifier))
|
|
103
|
+
self._vent_opening = value
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def is_construction_set_on_object(self):
|
|
107
|
+
"""Boolean noting if construction is assigned on the level of this Aperture.
|
|
108
|
+
|
|
109
|
+
This is opposed to having the construction assigned by a ConstructionSet.
|
|
110
|
+
"""
|
|
111
|
+
return self._construction is not None
|
|
112
|
+
|
|
113
|
+
def r_factor(self, units='Meters'):
|
|
114
|
+
"""Get the Aperture R-factor [m2-K/W] (including resistances for air films).
|
|
115
|
+
|
|
116
|
+
The air film resistances are computed using the orientation and height
|
|
117
|
+
of the Aperture geometry. If the window construction has a frame, the
|
|
118
|
+
geometry of the frame will also be accounted for.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
units: Text for the units in which the Aperture geometry exists. These
|
|
122
|
+
will be used to correctly interpret the dimensions of the
|
|
123
|
+
geometry for heat flow calculation. (Default: Meters).
|
|
124
|
+
"""
|
|
125
|
+
# compute the center-of-glass R-value
|
|
126
|
+
u_conv = conversion_factor_to_meters(units)
|
|
127
|
+
win_con = self._window_construction()
|
|
128
|
+
height = (self.host.max.z - self.host.min.z) * u_conv
|
|
129
|
+
height = 1 if height < 1 else height
|
|
130
|
+
_, r_vals = win_con.temperature_profile(
|
|
131
|
+
height=height, angle=abs(self.host.altitude - 90))
|
|
132
|
+
if not win_con.has_frame:
|
|
133
|
+
return sum(r_vals)
|
|
134
|
+
# if there is a frame, account for it in the final R-value
|
|
135
|
+
glass_u = (1 / sum(r_vals))
|
|
136
|
+
glass_area = (self.host.area * (u_conv ** 2))
|
|
137
|
+
if win_con.frame.edge_to_center_ratio != 1 and not \
|
|
138
|
+
isinstance(win_con.materials[0], EnergyWindowMaterialSimpleGlazSys):
|
|
139
|
+
edge_u = win_con.frame.edge_to_center_ratio * glass_u
|
|
140
|
+
edge_area = self.host.perimeter * u_conv * 0.06
|
|
141
|
+
cog_area = glass_area - edge_area
|
|
142
|
+
cog_area = 0 if cog_area < 0 else cog_area
|
|
143
|
+
total_area = cog_area + edge_area
|
|
144
|
+
glass_u = ((glass_u * cog_area) + (edge_u * edge_area)) / total_area
|
|
145
|
+
_, fr_r_vals = win_con.temperature_profile_frame(
|
|
146
|
+
angle=abs(self.host.altitude - 90))
|
|
147
|
+
frame_u = 1 / sum(fr_r_vals)
|
|
148
|
+
frame_area = (self.host.perimeter * u_conv * win_con.frame.width) + \
|
|
149
|
+
((win_con.frame.width * u_conv) ** 2) * len(self.host.geometry)
|
|
150
|
+
assembly_area = glass_area + frame_area
|
|
151
|
+
total_u = ((glass_u * glass_area) + (frame_u * frame_area)) / assembly_area
|
|
152
|
+
return 1 / total_u
|
|
153
|
+
|
|
154
|
+
def u_factor(self, units='Meters'):
|
|
155
|
+
"""Get the Aperture U-factor [W/m2-K] (including resistances for air films).
|
|
156
|
+
|
|
157
|
+
The air film resistances are computed using the orientation and height
|
|
158
|
+
of the Aperture geometry. If the window construction has a frame, the
|
|
159
|
+
geometry of the frame will also be accounted for.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
units: Text for the units in which the Aperture geometry exists. These
|
|
163
|
+
will be used to correctly interpret the dimensions of the
|
|
164
|
+
geometry for heat flow calculation. (Default: Meters).
|
|
165
|
+
"""
|
|
166
|
+
return 1 / self.r_factor(units)
|
|
167
|
+
|
|
168
|
+
def shgc(self, units='Meters'):
|
|
169
|
+
"""Get the Aperture solar heat gain coefficient (SHGC).
|
|
170
|
+
|
|
171
|
+
If this construction is not a simple glazing system, this value is computed
|
|
172
|
+
by summing the transmitted and conducted portions of solar irradiance under
|
|
173
|
+
the NFRC summer conditions. The air film resistances are computed using
|
|
174
|
+
the orientation and height of the Aperture geometry. If the window
|
|
175
|
+
construction has a frame, the geometry of the frame will also be accounted for.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
units: Text for the units in which the Aperture geometry exists. These
|
|
179
|
+
will be used to correctly interpret the dimensions of the
|
|
180
|
+
geometry for heat flow calculation. (Default: Meters).
|
|
181
|
+
"""
|
|
182
|
+
win_con = self._window_construction()
|
|
183
|
+
if isinstance(win_con.materials[0], EnergyWindowMaterialSimpleGlazSys):
|
|
184
|
+
if not win_con.has_frame:
|
|
185
|
+
return win_con.materials[0].shgc
|
|
186
|
+
# compute the temperature profile
|
|
187
|
+
t_out, t_in, sol_irr = 32, 24, 783 # NFRC 2010 summer conditions
|
|
188
|
+
u_conv = conversion_factor_to_meters(units)
|
|
189
|
+
height = (self.host.max.z - self.host.min.z) * u_conv
|
|
190
|
+
height = 1 if height < 1 else height
|
|
191
|
+
_, r_vals = win_con.temperature_profile(
|
|
192
|
+
t_out, t_in, height=height, angle=abs(self.host.altitude - 90),
|
|
193
|
+
solar_irradiance=sol_irr)
|
|
194
|
+
heat_gen, transmitted = win_con._heat_gen_from_solar(sol_irr)
|
|
195
|
+
conducted = 0
|
|
196
|
+
r_factor = sum(r_vals)
|
|
197
|
+
for i, heat_g in enumerate(heat_gen):
|
|
198
|
+
if heat_g != 0:
|
|
199
|
+
conducted += heat_g * (1 - (sum(r_vals[i + 1:]) / r_factor))
|
|
200
|
+
if not win_con.has_frame:
|
|
201
|
+
return (transmitted + conducted) / sol_irr
|
|
202
|
+
else: # account for the frame conduction
|
|
203
|
+
_, r_values = win_con.temperature_profile_frame(
|
|
204
|
+
t_out, t_in, height=height, angle=abs(self.host.altitude - 90),
|
|
205
|
+
solar_irradiance=sol_irr)
|
|
206
|
+
heat_gen = [0, sol_irr * win_con.frame.solar_absorptance, 0]
|
|
207
|
+
frame_conducted = 0
|
|
208
|
+
r_factor = sum(r_values)
|
|
209
|
+
for i, heat_g in enumerate(heat_gen):
|
|
210
|
+
if heat_g != 0:
|
|
211
|
+
frame_conducted += heat_g * (1 - (sum(r_values[i + 1:]) / r_factor))
|
|
212
|
+
glass_area = (self.host.area * (u_conv ** 2))
|
|
213
|
+
frame_area = (self.host.perimeter * u_conv * win_con.frame.width) + \
|
|
214
|
+
((win_con.frame.width * u_conv) ** 2) * len(self.host.geometry)
|
|
215
|
+
glass_trans = transmitted * glass_area
|
|
216
|
+
glass_conduct = conducted * glass_area
|
|
217
|
+
frame_conduct = frame_conducted * frame_area
|
|
218
|
+
total_irr = sol_irr * (glass_area + frame_area)
|
|
219
|
+
return (glass_trans + glass_conduct + frame_conduct) / total_irr
|
|
220
|
+
|
|
221
|
+
def reset_construction_to_set(self):
|
|
222
|
+
"""Reset a construction assigned at the level of this Aperture to the default.
|
|
223
|
+
|
|
224
|
+
This means the Aperture's construction will be assigned by a ConstructionSet.
|
|
225
|
+
"""
|
|
226
|
+
self._construction = None
|
|
227
|
+
for shade in self.host.shades:
|
|
228
|
+
shade.properties.energy.reset_construction_to_set()
|
|
229
|
+
|
|
230
|
+
@classmethod
|
|
231
|
+
def from_dict(cls, data, host):
|
|
232
|
+
"""Create ApertureEnergyProperties from a dictionary.
|
|
233
|
+
|
|
234
|
+
Note that the dictionary must be a non-abridged version for this
|
|
235
|
+
classmethod to work.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
data: A dictionary representation of ApertureEnergyProperties in the
|
|
239
|
+
format below.
|
|
240
|
+
host: A Aperture object that hosts these properties.
|
|
241
|
+
|
|
242
|
+
.. code-block:: python
|
|
243
|
+
|
|
244
|
+
{
|
|
245
|
+
"type": 'ApertureEnergyProperties',
|
|
246
|
+
"construction": {}, # Window Construction dictionary
|
|
247
|
+
"vent_opening": {} # VentilationOpening dict
|
|
248
|
+
}
|
|
249
|
+
"""
|
|
250
|
+
assert data['type'] == 'ApertureEnergyProperties', \
|
|
251
|
+
'Expected ApertureEnergyProperties. Got {}.'.format(data['type'])
|
|
252
|
+
|
|
253
|
+
new_prop = cls(host)
|
|
254
|
+
if 'construction' in data and data['construction'] is not None:
|
|
255
|
+
new_prop.construction = dict_to_construction(data['construction'])
|
|
256
|
+
if 'vent_opening' in data and data['vent_opening'] is not None:
|
|
257
|
+
new_prop.vent_opening = VentilationOpening.from_dict(data['vent_opening'])
|
|
258
|
+
return new_prop
|
|
259
|
+
|
|
260
|
+
def apply_properties_from_dict(self, abridged_data, constructions):
|
|
261
|
+
"""Apply properties from a ApertureEnergyPropertiesAbridged dictionary.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
abridged_data: A ApertureEnergyPropertiesAbridged dictionary (typically
|
|
265
|
+
coming from a Model).
|
|
266
|
+
constructions: A dictionary of constructions with constructions identifiers
|
|
267
|
+
as keys, which will be used to re-assign constructions.
|
|
268
|
+
"""
|
|
269
|
+
if 'construction' in abridged_data and abridged_data['construction'] is not None:
|
|
270
|
+
try:
|
|
271
|
+
self.construction = constructions[abridged_data['construction']]
|
|
272
|
+
except KeyError:
|
|
273
|
+
raise ValueError('Aperture construction "{}" was not found in '
|
|
274
|
+
'constructions.'.format(abridged_data['construction']))
|
|
275
|
+
if 'vent_opening' in abridged_data and abridged_data['vent_opening'] is not None:
|
|
276
|
+
self.vent_opening = \
|
|
277
|
+
VentilationOpening.from_dict(abridged_data['vent_opening'])
|
|
278
|
+
|
|
279
|
+
def to_dict(self, abridged=False):
|
|
280
|
+
"""Return energy properties as a dictionary.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
abridged: Boolean to note whether the full dictionary describing the
|
|
284
|
+
object should be returned (False) or just an abridged version (True).
|
|
285
|
+
Default: False.
|
|
286
|
+
"""
|
|
287
|
+
base = {'energy': {}}
|
|
288
|
+
base['energy']['type'] = 'ApertureEnergyProperties' if not \
|
|
289
|
+
abridged else 'ApertureEnergyPropertiesAbridged'
|
|
290
|
+
if self._construction is not None:
|
|
291
|
+
base['energy']['construction'] = \
|
|
292
|
+
self._construction.identifier if abridged else \
|
|
293
|
+
self._construction.to_dict()
|
|
294
|
+
if self._vent_opening is not None:
|
|
295
|
+
base['energy']['vent_opening'] = self._vent_opening.to_dict()
|
|
296
|
+
return base
|
|
297
|
+
|
|
298
|
+
def duplicate(self, new_host=None):
|
|
299
|
+
"""Get a copy of this object.
|
|
300
|
+
|
|
301
|
+
new_host: A new Aperture object that hosts these properties.
|
|
302
|
+
If None, the properties will be duplicated with the same host.
|
|
303
|
+
"""
|
|
304
|
+
_host = new_host or self._host
|
|
305
|
+
vo = self._vent_opening.duplicate() if self._vent_opening is not None else None
|
|
306
|
+
return ApertureEnergyProperties(_host, self._construction, vo)
|
|
307
|
+
|
|
308
|
+
def is_equivalent(self, other):
|
|
309
|
+
"""Check to see if these energy properties are equivalent to another object.
|
|
310
|
+
|
|
311
|
+
This will only be True if all properties match (except for the host) and
|
|
312
|
+
will otherwise be False.
|
|
313
|
+
"""
|
|
314
|
+
if not is_equivalent(self._construction, other._construction):
|
|
315
|
+
return False
|
|
316
|
+
if not is_equivalent(self._vent_opening, other._vent_opening):
|
|
317
|
+
return False
|
|
318
|
+
return True
|
|
319
|
+
|
|
320
|
+
def _window_construction(self):
|
|
321
|
+
"""Get the base window construction assigned to the aperture."""
|
|
322
|
+
win_con = self.construction
|
|
323
|
+
if isinstance(win_con, WindowConstructionShade):
|
|
324
|
+
win_con = win_con.window_construction
|
|
325
|
+
elif isinstance(win_con, WindowConstructionDynamic):
|
|
326
|
+
win_con = win_con.constructions[0]
|
|
327
|
+
return win_con
|
|
328
|
+
|
|
329
|
+
def ToString(self):
|
|
330
|
+
return self.__repr__()
|
|
331
|
+
|
|
332
|
+
def __repr__(self):
|
|
333
|
+
return 'Aperture Energy Properties: [host: {}]'.format(self.host.display_name)
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Door Energy Properties."""
|
|
3
|
+
from honeybee.units import conversion_factor_to_meters
|
|
4
|
+
from honeybee.checkdup import is_equivalent
|
|
5
|
+
|
|
6
|
+
from ..construction.dictutil import dict_to_construction
|
|
7
|
+
from ..material.glazing import EnergyWindowMaterialSimpleGlazSys
|
|
8
|
+
from ..construction.opaque import OpaqueConstruction
|
|
9
|
+
from ..construction.window import WindowConstruction
|
|
10
|
+
from ..construction.windowshade import WindowConstructionShade
|
|
11
|
+
from ..construction.dynamic import WindowConstructionDynamic
|
|
12
|
+
from ..ventcool.opening import VentilationOpening
|
|
13
|
+
from ..lib.constructionsets import generic_construction_set
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DoorEnergyProperties(object):
|
|
17
|
+
"""Energy Properties for Honeybee Door.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
host_door: A honeybee_core Door object that hosts these properties.
|
|
21
|
+
construction: An optional Honeybee OpaqueConstruction or WindowConstruction
|
|
22
|
+
object for the door. Note that the host Door must have the is_glass
|
|
23
|
+
property set to True to assign a WindowConstruction,
|
|
24
|
+
WindowConstructionShade or WindowConstructionDynamic. If None, it
|
|
25
|
+
will be set by the parent Room ConstructionSet or the the Honeybee
|
|
26
|
+
default generic ConstructionSet.
|
|
27
|
+
vent_opening: An optional VentilationOpening to specify the operable
|
|
28
|
+
portion of the Door. (Default: None).
|
|
29
|
+
|
|
30
|
+
Properties:
|
|
31
|
+
* host
|
|
32
|
+
* construction
|
|
33
|
+
* vent_opening
|
|
34
|
+
* is_construction_set_on_object
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
__slots__ = ('_host', '_construction', '_vent_opening')
|
|
38
|
+
|
|
39
|
+
def __init__(self, host, construction=None, vent_opening=None):
|
|
40
|
+
"""Initialize Door energy properties."""
|
|
41
|
+
self._host = host
|
|
42
|
+
self.construction = construction
|
|
43
|
+
self.vent_opening = vent_opening
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def host(self):
|
|
47
|
+
"""Get the Door object hosting these properties."""
|
|
48
|
+
return self._host
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def construction(self):
|
|
52
|
+
"""Get or set Door Construction.
|
|
53
|
+
|
|
54
|
+
If the Construction is not set on the door-level, then it will be assigned
|
|
55
|
+
based on the ConstructionSet assigned to the parent Room. If there is no
|
|
56
|
+
parent Room or the parent Room's ConstructionSet has no construction for
|
|
57
|
+
this type of door, it will be assigned using the honeybee default
|
|
58
|
+
generic construction set.
|
|
59
|
+
"""
|
|
60
|
+
if self._construction: # set by user
|
|
61
|
+
return self._construction
|
|
62
|
+
elif self._host.has_parent and self._host.parent.has_parent: # set by room
|
|
63
|
+
constr_set = self._host.parent.parent.properties.energy.construction_set
|
|
64
|
+
return constr_set.get_door_construction(
|
|
65
|
+
self._host.boundary_condition.name, self._host.is_glass,
|
|
66
|
+
self._host.parent.type.name)
|
|
67
|
+
elif self._host.has_parent: # generic but influenced by parent face
|
|
68
|
+
return generic_construction_set.get_door_construction(
|
|
69
|
+
self._host.boundary_condition.name, self._host.is_glass,
|
|
70
|
+
self._host.parent.type.name)
|
|
71
|
+
else:
|
|
72
|
+
return generic_construction_set.get_door_construction(
|
|
73
|
+
self._host.boundary_condition.name, self._host.is_glass, 'Wall')
|
|
74
|
+
|
|
75
|
+
@construction.setter
|
|
76
|
+
def construction(self, value):
|
|
77
|
+
if value is not None:
|
|
78
|
+
if not self.host.is_glass:
|
|
79
|
+
assert isinstance(value, OpaqueConstruction), 'Expected ' \
|
|
80
|
+
'OpaqueConstruction for door. Got {}'.format(type(value))
|
|
81
|
+
else:
|
|
82
|
+
vw = (WindowConstruction, WindowConstructionShade,
|
|
83
|
+
WindowConstructionDynamic)
|
|
84
|
+
assert isinstance(value, vw), 'Expected WindowConstruction, ' \
|
|
85
|
+
'WindowConstructionShade or WindowConstructionDynamic for ' \
|
|
86
|
+
'glass door. Got {}'.format(type(value))
|
|
87
|
+
value.lock() # lock editing in case construction has multiple references
|
|
88
|
+
self._construction = value
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def vent_opening(self):
|
|
92
|
+
"""Get or set a VentilationOpening object to specify the operable portion."""
|
|
93
|
+
return self._vent_opening
|
|
94
|
+
|
|
95
|
+
@vent_opening.setter
|
|
96
|
+
def vent_opening(self, value):
|
|
97
|
+
if value is not None:
|
|
98
|
+
assert isinstance(value, VentilationOpening), 'Expected Ventilation' \
|
|
99
|
+
'Opening for Door vent_opening. Got {}'.format(type(value))
|
|
100
|
+
if value._parent is None:
|
|
101
|
+
value._parent = self.host
|
|
102
|
+
elif value._parent.identifier != self.host.identifier:
|
|
103
|
+
raise ValueError(
|
|
104
|
+
'{0} objects can be assigned to only one parent.\n{0} cannot be '
|
|
105
|
+
'assigned to Door "{1}" since it is already assigned to "{2}".\n'
|
|
106
|
+
'Try duplicating the object and then assign it.'.format(
|
|
107
|
+
'VentilationOpening', self.host.identifier,
|
|
108
|
+
value._parent.identifier))
|
|
109
|
+
self._vent_opening = value
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def is_construction_set_on_object(self):
|
|
113
|
+
"""Boolean noting if construction is assigned on the level of this Door.
|
|
114
|
+
|
|
115
|
+
This is opposed to having the construction assigned by a ConstructionSet.
|
|
116
|
+
"""
|
|
117
|
+
return self._construction is not None
|
|
118
|
+
|
|
119
|
+
def r_factor(self, units='Meters'):
|
|
120
|
+
"""Get the Door R-factor [m2-K/W] (including air film resistance).
|
|
121
|
+
|
|
122
|
+
The air film resistances are computed using the orientation and height
|
|
123
|
+
of the Door geometry.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
units: Text for the units in which the Door geometry exists. These
|
|
127
|
+
will be used to correctly interpret the dimensions of the
|
|
128
|
+
geometry for heat flow calculation. (Default: Meters).
|
|
129
|
+
"""
|
|
130
|
+
u_conv = conversion_factor_to_meters(units)
|
|
131
|
+
win_con = self._window_construction()
|
|
132
|
+
height = (self.host.max.z - self.host.min.z) * u_conv
|
|
133
|
+
height = 1 if height < 1 else height
|
|
134
|
+
_, r_vals = win_con.temperature_profile(
|
|
135
|
+
height=height, angle=abs(self.host.altitude - 90))
|
|
136
|
+
if not win_con.has_frame:
|
|
137
|
+
return sum(r_vals)
|
|
138
|
+
# if there is a frame, account for it in the final R-value
|
|
139
|
+
glass_u = (1 / sum(r_vals))
|
|
140
|
+
glass_area = (self.host.area * (u_conv ** 2))
|
|
141
|
+
if win_con.frame.edge_to_center_ratio != 1 and not \
|
|
142
|
+
isinstance(win_con.materials[0], EnergyWindowMaterialSimpleGlazSys):
|
|
143
|
+
edge_u = win_con.frame.edge_to_center_ratio * glass_u
|
|
144
|
+
edge_area = self.host.perimeter * u_conv * 0.06
|
|
145
|
+
cog_area = glass_area - edge_area
|
|
146
|
+
cog_area = 0 if cog_area < 0 else cog_area
|
|
147
|
+
total_area = cog_area + edge_area
|
|
148
|
+
glass_u = ((glass_u * cog_area) + (edge_u * edge_area)) / total_area
|
|
149
|
+
_, fr_r_vals = win_con.temperature_profile_frame(
|
|
150
|
+
angle=abs(self.host.altitude - 90))
|
|
151
|
+
frame_u = 1 / sum(fr_r_vals)
|
|
152
|
+
frame_area = (self.host.perimeter * u_conv * win_con.frame.width) + \
|
|
153
|
+
((win_con.frame.width * u_conv) ** 2) * len(self.host.geometry)
|
|
154
|
+
assembly_area = glass_area + frame_area
|
|
155
|
+
total_u = ((glass_u * glass_area) + (frame_u * frame_area)) / assembly_area
|
|
156
|
+
return 1 / total_u
|
|
157
|
+
|
|
158
|
+
def u_factor(self, units='Meters'):
|
|
159
|
+
"""Get the Door U-factor [W/m2-K] (including resistances for air films).
|
|
160
|
+
|
|
161
|
+
The air film resistances are computed using the orientation and height
|
|
162
|
+
of the Door geometry.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
units: Text for the units in which the Door geometry exists. These
|
|
166
|
+
will be used to correctly interpret the dimensions of the
|
|
167
|
+
geometry for heat flow calculation. (Default: Meters).
|
|
168
|
+
"""
|
|
169
|
+
return 1 / self.r_factor(units)
|
|
170
|
+
|
|
171
|
+
def shgc(self, units='Meters'):
|
|
172
|
+
"""Get the Door solar heat gain coefficient (SHGC).
|
|
173
|
+
|
|
174
|
+
If this construction is not a simple glazing system, this value is computed
|
|
175
|
+
by summing the transmitted and conducted portions of solar irradiance under
|
|
176
|
+
the NFRC summer conditions. The air film resistances are computed using
|
|
177
|
+
the orientation and height of the Door geometry. If the window construction
|
|
178
|
+
has a frame, the geometry of the frame will also be accounted for.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
units: Text for the units in which the Door geometry exists. These
|
|
182
|
+
will be used to correctly interpret the dimensions of the
|
|
183
|
+
geometry for heat flow calculation. (Default: Meters).
|
|
184
|
+
"""
|
|
185
|
+
win_con = self._window_construction()
|
|
186
|
+
if isinstance(win_con.materials[0], EnergyWindowMaterialSimpleGlazSys):
|
|
187
|
+
if not win_con.has_frame:
|
|
188
|
+
return win_con.materials[0].shgc
|
|
189
|
+
# compute the temperature profile
|
|
190
|
+
t_out, t_in, sol_irr = 32, 24, 783 # NFRC 2010 summer conditions
|
|
191
|
+
u_conv = conversion_factor_to_meters(units)
|
|
192
|
+
height = (self.host.max.z - self.host.min.z) * u_conv
|
|
193
|
+
height = 1 if height < 1 else height
|
|
194
|
+
_, r_vals = win_con.temperature_profile(
|
|
195
|
+
t_out, t_in, height=height, angle=abs(self.host.altitude - 90),
|
|
196
|
+
solar_irradiance=sol_irr)
|
|
197
|
+
if isinstance(win_con, OpaqueConstruction):
|
|
198
|
+
heat_gen = sol_irr * (1 - win_con.outside_solar_reflectance)
|
|
199
|
+
r_factor = sum(r_vals)
|
|
200
|
+
conducted = heat_gen * (1 - (sum(r_vals[1:]) / r_factor))
|
|
201
|
+
return conducted / sol_irr
|
|
202
|
+
heat_gen, transmitted = win_con._heat_gen_from_solar(sol_irr)
|
|
203
|
+
conducted = 0
|
|
204
|
+
r_factor = sum(r_vals)
|
|
205
|
+
for i, heat_g in enumerate(heat_gen):
|
|
206
|
+
if heat_g != 0:
|
|
207
|
+
conducted += heat_g * (1 - (sum(r_vals[i + 1:]) / r_factor))
|
|
208
|
+
if not win_con.has_frame:
|
|
209
|
+
return (transmitted + conducted) / sol_irr
|
|
210
|
+
else: # account for the frame conduction
|
|
211
|
+
_, r_values = win_con.temperature_profile_frame(
|
|
212
|
+
t_out, t_in, height=height, angle=abs(self.host.altitude - 90),
|
|
213
|
+
solar_irradiance=sol_irr)
|
|
214
|
+
heat_gen = [0, sol_irr * win_con.frame.solar_absorptance, 0]
|
|
215
|
+
frame_conducted = 0
|
|
216
|
+
r_factor = sum(r_values)
|
|
217
|
+
for i, heat_g in enumerate(heat_gen):
|
|
218
|
+
if heat_g != 0:
|
|
219
|
+
frame_conducted += heat_g * (1 - (sum(r_values[i + 1:]) / r_factor))
|
|
220
|
+
glass_area = (self.host.area * (u_conv ** 2))
|
|
221
|
+
frame_area = (self.host.perimeter * u_conv * win_con.frame.width) + \
|
|
222
|
+
((win_con.frame.width * u_conv) ** 2) * len(self.host.geometry)
|
|
223
|
+
glass_trans = transmitted * glass_area
|
|
224
|
+
glass_conduct = conducted * glass_area
|
|
225
|
+
frame_conduct = frame_conducted * frame_area
|
|
226
|
+
total_irr = sol_irr * (glass_area + frame_area)
|
|
227
|
+
return (glass_trans + glass_conduct + frame_conduct) / total_irr
|
|
228
|
+
|
|
229
|
+
def reset_construction_to_set(self):
|
|
230
|
+
"""Reset a construction assigned at the level of this Door to the default.
|
|
231
|
+
|
|
232
|
+
This means that the Door's construction will be assigned by a ConstructionSet.
|
|
233
|
+
"""
|
|
234
|
+
self._construction = None
|
|
235
|
+
for shade in self.host.shades:
|
|
236
|
+
shade.properties.energy.reset_construction_to_set()
|
|
237
|
+
|
|
238
|
+
@classmethod
|
|
239
|
+
def from_dict(cls, data, host):
|
|
240
|
+
"""Create DoorEnergyProperties from a dictionary.
|
|
241
|
+
|
|
242
|
+
Note that the dictionary must be a non-abridged version for this
|
|
243
|
+
classmethod to work.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
data: A dictionary representation of DoorEnergyProperties in the
|
|
247
|
+
format below.
|
|
248
|
+
host: A Door object that hosts these properties.
|
|
249
|
+
|
|
250
|
+
.. code-block:: python
|
|
251
|
+
|
|
252
|
+
{
|
|
253
|
+
"type": 'DoorEnergyProperties',
|
|
254
|
+
"construction": {}, # OpaqueConstruction or WindowConstruction dict
|
|
255
|
+
"vent_opening": {} # VentilationOpening dict
|
|
256
|
+
}
|
|
257
|
+
"""
|
|
258
|
+
assert data['type'] == 'DoorEnergyProperties', \
|
|
259
|
+
'Expected DoorEnergyProperties. Got {}.'.format(data['type'])
|
|
260
|
+
|
|
261
|
+
new_prop = cls(host)
|
|
262
|
+
if 'construction' in data and data['construction'] is not None:
|
|
263
|
+
new_prop.construction = dict_to_construction(data['construction'])
|
|
264
|
+
if 'vent_opening' in data and data['vent_opening'] is not None:
|
|
265
|
+
new_prop.vent_opening = VentilationOpening.from_dict(data['vent_opening'])
|
|
266
|
+
return new_prop
|
|
267
|
+
|
|
268
|
+
def apply_properties_from_dict(self, abridged_data, constructions):
|
|
269
|
+
"""Apply properties from a DoorEnergyPropertiesAbridged dictionary.
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
abridged_data: A DoorEnergyPropertiesAbridged dictionary (typically
|
|
273
|
+
coming from a Model).
|
|
274
|
+
constructions: A dictionary of constructions with constructions identifiers
|
|
275
|
+
as keys, which will be used to re-assign constructions.
|
|
276
|
+
"""
|
|
277
|
+
if 'construction' in abridged_data and abridged_data['construction'] is not None:
|
|
278
|
+
try:
|
|
279
|
+
self.construction = constructions[abridged_data['construction']]
|
|
280
|
+
except KeyError:
|
|
281
|
+
raise ValueError('Door construction "{}" was not found in '
|
|
282
|
+
'constructions.'.format(abridged_data['construction']))
|
|
283
|
+
if 'vent_opening' in abridged_data and abridged_data['vent_opening'] is not None:
|
|
284
|
+
self.vent_opening = \
|
|
285
|
+
VentilationOpening.from_dict(abridged_data['vent_opening'])
|
|
286
|
+
|
|
287
|
+
def to_dict(self, abridged=False):
|
|
288
|
+
"""Return energy properties as a dictionary.
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
abridged: Boolean to note whether the full dictionary describing the
|
|
292
|
+
object should be returned (False) or just an abridged version (True).
|
|
293
|
+
Default: False.
|
|
294
|
+
"""
|
|
295
|
+
base = {'energy': {}}
|
|
296
|
+
base['energy']['type'] = 'DoorEnergyProperties' if not \
|
|
297
|
+
abridged else 'DoorEnergyPropertiesAbridged'
|
|
298
|
+
if self._construction is not None:
|
|
299
|
+
base['energy']['construction'] = \
|
|
300
|
+
self._construction.identifier if abridged else \
|
|
301
|
+
self._construction.to_dict()
|
|
302
|
+
if self._vent_opening is not None:
|
|
303
|
+
base['energy']['vent_opening'] = self._vent_opening.to_dict()
|
|
304
|
+
return base
|
|
305
|
+
|
|
306
|
+
def duplicate(self, new_host=None):
|
|
307
|
+
"""Get a copy of this object.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
new_host: A new Door object that hosts these properties.
|
|
311
|
+
If None, the properties will be duplicated with the same host.
|
|
312
|
+
"""
|
|
313
|
+
_host = new_host or self._host
|
|
314
|
+
vo = self._vent_opening.duplicate() if self._vent_opening is not None else None
|
|
315
|
+
return DoorEnergyProperties(_host, self._construction, vo)
|
|
316
|
+
|
|
317
|
+
def is_equivalent(self, other):
|
|
318
|
+
"""Check to see if these energy properties are equivalent to another object.
|
|
319
|
+
|
|
320
|
+
This will only be True if all properties match (except for the host) and
|
|
321
|
+
will otherwise be False.
|
|
322
|
+
"""
|
|
323
|
+
if not is_equivalent(self._construction, other._construction):
|
|
324
|
+
return False
|
|
325
|
+
if not is_equivalent(self._vent_opening, other._vent_opening):
|
|
326
|
+
return False
|
|
327
|
+
return True
|
|
328
|
+
|
|
329
|
+
def _window_construction(self):
|
|
330
|
+
"""Get the base window or opaque construction assigned to the door."""
|
|
331
|
+
win_con = self.construction
|
|
332
|
+
if isinstance(win_con, WindowConstructionShade):
|
|
333
|
+
win_con = win_con.window_construction
|
|
334
|
+
elif isinstance(win_con, WindowConstructionDynamic):
|
|
335
|
+
win_con = win_con.constructions[0]
|
|
336
|
+
return win_con
|
|
337
|
+
|
|
338
|
+
def ToString(self):
|
|
339
|
+
return self.__repr__()
|
|
340
|
+
|
|
341
|
+
def __repr__(self):
|
|
342
|
+
return 'Door Energy Properties: [host: {}]'.format(self.host.display_name)
|