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,847 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Window Construction with shades/blinds or a dynamically-controlled glass pane."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
from .window import WindowConstruction
|
|
6
|
+
from ..material.dictutil import dict_to_material
|
|
7
|
+
from ..material.glazing import EnergyWindowMaterialGlazing, \
|
|
8
|
+
EnergyWindowMaterialSimpleGlazSys
|
|
9
|
+
from ..material.shade import _EnergyWindowMaterialShadeBase, EnergyWindowMaterialBlind
|
|
10
|
+
from ..schedule.dictutil import dict_to_schedule
|
|
11
|
+
from ..schedule.ruleset import ScheduleRuleset
|
|
12
|
+
from ..schedule.fixedinterval import ScheduleFixedInterval
|
|
13
|
+
from ..writer import generate_idf_string
|
|
14
|
+
from ..properties.extension import WindowConstructionShadeProperties
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
from honeybee._lockable import lockable
|
|
18
|
+
from honeybee.typing import valid_ep_string
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@lockable
|
|
22
|
+
class WindowConstructionShade(object):
|
|
23
|
+
"""Window Construction with shades/blinds or a dynamically-controlled glass pane.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
identifier: Text string for a unique Construction ID. Must be < 100 characters
|
|
27
|
+
and not contain any EnergyPlus special characters. This will be used to
|
|
28
|
+
identify the object across a model and in the exported IDF.
|
|
29
|
+
window_construction: A WindowConstruction object that serves as the
|
|
30
|
+
"switched off" version of the construction (aka. the "bare construction").
|
|
31
|
+
The shade_material and shade_location will be used to modify this
|
|
32
|
+
starting construction.
|
|
33
|
+
shade_material: An EnergyWindowMaterialShade or an EnergyWindowMaterialBlind
|
|
34
|
+
that serves as the shading layer for this construction. This can also
|
|
35
|
+
be an EnergyWindowMaterialGlazing, which will indicate that the
|
|
36
|
+
WindowConstruction has a dynamically-controlled glass pane like an
|
|
37
|
+
electrochromic window assembly.
|
|
38
|
+
shade_location: Text to indicate where in the window assembly the shade_material
|
|
39
|
+
is located. (Default: "Interior"). Choose from the following 3 options:
|
|
40
|
+
|
|
41
|
+
* Interior
|
|
42
|
+
* Between
|
|
43
|
+
* Exterior
|
|
44
|
+
|
|
45
|
+
Note that the WindowConstruction must have at least one gas gap to use
|
|
46
|
+
the "Between" option. Also note that, for a WindowConstruction with more
|
|
47
|
+
than one gas gap, the "Between" option defaults to using the inner gap
|
|
48
|
+
as this is the only option that EnergyPlus supports.
|
|
49
|
+
control_type: Text to indicate how the shading device is controlled, which
|
|
50
|
+
determines when the shading is “on” or “off.” (Default: "AlwaysOn").
|
|
51
|
+
Choose from the options below (units for the values of the corresponding
|
|
52
|
+
setpoint are noted in parentheses next to each option):
|
|
53
|
+
|
|
54
|
+
* AlwaysOn
|
|
55
|
+
* OnIfHighSolarOnWindow (W/m2)
|
|
56
|
+
* OnIfHighHorizontalSolar (W/m2)
|
|
57
|
+
* OnIfHighOutdoorAirTemperature (C)
|
|
58
|
+
* OnIfHighZoneAirTemperature (C)
|
|
59
|
+
* OnIfHighZoneCooling (W)
|
|
60
|
+
* OnNightIfLowOutdoorTempAndOffDay (C)
|
|
61
|
+
* OnNightIfLowInsideTempAndOffDay (C)
|
|
62
|
+
* OnNightIfHeatingAndOffDay (W)
|
|
63
|
+
|
|
64
|
+
setpoint: A number that corresponds to the specified control_type. This can
|
|
65
|
+
be a value in (W/m2), (C) or (W) depending upon the control type.
|
|
66
|
+
schedule: An optional ScheduleRuleset or ScheduleFixedInterval to be applied
|
|
67
|
+
on top of the control_type. If None, the control_type will govern all
|
|
68
|
+
behavior of the construction. (Default: None).
|
|
69
|
+
|
|
70
|
+
Properties:
|
|
71
|
+
* identifier
|
|
72
|
+
* display_name
|
|
73
|
+
* window_construction
|
|
74
|
+
* shade_material
|
|
75
|
+
* shade_location
|
|
76
|
+
* control_type
|
|
77
|
+
* setpoint
|
|
78
|
+
* schedule
|
|
79
|
+
* materials
|
|
80
|
+
* layers
|
|
81
|
+
* unique_materials
|
|
82
|
+
* frame
|
|
83
|
+
* r_value
|
|
84
|
+
* u_value
|
|
85
|
+
* u_factor
|
|
86
|
+
* r_factor
|
|
87
|
+
* is_symmetric
|
|
88
|
+
* is_switchable_glazing
|
|
89
|
+
* has_frame
|
|
90
|
+
* has_shade
|
|
91
|
+
* is_dynamic
|
|
92
|
+
* inside_emissivity
|
|
93
|
+
* outside_emissivity
|
|
94
|
+
* solar_transmittance
|
|
95
|
+
* visible_transmittance
|
|
96
|
+
* shgc
|
|
97
|
+
* thickness
|
|
98
|
+
* glazing_count
|
|
99
|
+
* gap_count
|
|
100
|
+
* is_groupable
|
|
101
|
+
* is_zone_groupable
|
|
102
|
+
* inside_material
|
|
103
|
+
* outside_material
|
|
104
|
+
* user_data
|
|
105
|
+
* properties
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
__slots__ = ('_identifier', '_display_name', '_window_construction',
|
|
109
|
+
'_shade_material', '_shade_location', '_control_type',
|
|
110
|
+
'_setpoint', '_schedule', '_between_gap', '_locked', '_user_data',
|
|
111
|
+
"_properties", )
|
|
112
|
+
SHADE_LOCATIONS = ('Interior', 'Between', 'Exterior')
|
|
113
|
+
CONTROL_TYPES = (
|
|
114
|
+
'AlwaysOn', 'OnIfHighSolarOnWindow', 'OnIfHighHorizontalSolar',
|
|
115
|
+
'OnIfHighOutdoorAirTemperature', 'OnIfHighZoneAirTemperature',
|
|
116
|
+
'OnIfHighZoneCooling', 'OnNightIfLowOutdoorTempAndOffDay',
|
|
117
|
+
'OnNightIfLowInsideTempAndOffDay', 'OnNightIfHeatingAndOffDay')
|
|
118
|
+
GROUPABLE_TYPES = (
|
|
119
|
+
'AlwaysOn', 'OnIfHighHorizontalSolar', 'OnIfHighOutdoorAirTemperature',
|
|
120
|
+
'OnNightIfLowOutdoorTempAndOffDay')
|
|
121
|
+
ROOM_GROUPABLE_TYPES = (
|
|
122
|
+
'OnIfHighZoneAirTemperature', 'OnIfHighZoneCooling',
|
|
123
|
+
'OnNightIfLowInsideTempAndOffDay', 'OnNightIfHeatingAndOffDay')
|
|
124
|
+
|
|
125
|
+
def __init__(self, identifier, window_construction, shade_material,
|
|
126
|
+
shade_location='Interior', control_type='AlwaysOn',
|
|
127
|
+
setpoint=None, schedule=None):
|
|
128
|
+
"""Initialize shaded window construction."""
|
|
129
|
+
self._locked = False # unlocked by default
|
|
130
|
+
self.identifier = identifier
|
|
131
|
+
self._display_name = None
|
|
132
|
+
self._between_gap = None # will be used if 'Between' option is used
|
|
133
|
+
self._user_data = None
|
|
134
|
+
# check that the window construction, shade, and shade location are compatible
|
|
135
|
+
assert isinstance(window_construction, WindowConstruction), \
|
|
136
|
+
'Expected WindowConstruction for WindowConstructionShade. ' \
|
|
137
|
+
'Got {}.'.format(type(window_construction))
|
|
138
|
+
shade_types = (_EnergyWindowMaterialShadeBase, EnergyWindowMaterialGlazing)
|
|
139
|
+
assert isinstance(shade_material, shade_types), \
|
|
140
|
+
'Expected Shade/Blind or Glazing material for WindowConstructionShade. ' \
|
|
141
|
+
'Got {}.'.format(type(shade_material))
|
|
142
|
+
assert shade_location in self.SHADE_LOCATIONS, \
|
|
143
|
+
'Invalid input "{}" for shade location. Must be one ' \
|
|
144
|
+
'of the following:\n{}'.format(shade_location, self.SHADE_LOCATIONS)
|
|
145
|
+
if isinstance(shade_material, EnergyWindowMaterialGlazing):
|
|
146
|
+
ext_pane = window_construction[0]
|
|
147
|
+
assert not isinstance(ext_pane, EnergyWindowMaterialSimpleGlazSys), \
|
|
148
|
+
'WindowConstruction cannot be a SimpleGlazSys when shading material ' \
|
|
149
|
+
'is a glass pane.'
|
|
150
|
+
elif shade_location == 'Between': # it's a shade/blind between glass panes
|
|
151
|
+
assert window_construction.gap_count >= 1, 'WindowConstruction must have ' \
|
|
152
|
+
'at least one gap in order to use "Between" shade_location.'
|
|
153
|
+
# calculate the thickness of the gaps on either side of the shade
|
|
154
|
+
int_gap = window_construction[-2]
|
|
155
|
+
if isinstance(shade_material, EnergyWindowMaterialBlind):
|
|
156
|
+
assert shade_material.slat_width < int_gap.thickness, \
|
|
157
|
+
'Blind slat_width must be less than the width of the gap in which ' \
|
|
158
|
+
'it sits. {} > {}.'.format(
|
|
159
|
+
shade_material.slat_width, int_gap.thickness)
|
|
160
|
+
shd_thick = 0 if isinstance(shade_material, EnergyWindowMaterialBlind) \
|
|
161
|
+
else shade_material.thickness
|
|
162
|
+
gap_thick = (int_gap.thickness - shd_thick) / 2
|
|
163
|
+
assert gap_thick > 0, \
|
|
164
|
+
'Shade thickness is greater than the gap in which it sits.'
|
|
165
|
+
# create the split gap material to be used on either side of the shade
|
|
166
|
+
between_int_gap = int_gap.duplicate()
|
|
167
|
+
between_int_gap.identifier = \
|
|
168
|
+
'{}_Split{}'.format(int_gap.identifier, round(gap_thick, 3))
|
|
169
|
+
between_int_gap.thickness = gap_thick
|
|
170
|
+
self._between_gap = between_int_gap
|
|
171
|
+
window_construction.lock() # lock to avoid illegal shade/material combinations
|
|
172
|
+
self._window_construction = window_construction
|
|
173
|
+
self._shade_material = shade_material
|
|
174
|
+
self._shade_location = shade_location
|
|
175
|
+
|
|
176
|
+
# assign the control type, setpoint and schedule
|
|
177
|
+
assert control_type in self.CONTROL_TYPES, \
|
|
178
|
+
'Invalid input "{}" for shading control type.' \
|
|
179
|
+
' Must be one of the following:\n{}'.format(control_type, self.CONTROL_TYPES)
|
|
180
|
+
self._control_type = control_type
|
|
181
|
+
self.setpoint = setpoint
|
|
182
|
+
self.schedule = schedule
|
|
183
|
+
self._properties = WindowConstructionShadeProperties(self)
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def identifier(self):
|
|
187
|
+
"""Get or set the text string for construction identifier."""
|
|
188
|
+
return self._identifier
|
|
189
|
+
|
|
190
|
+
@identifier.setter
|
|
191
|
+
def identifier(self, identifier):
|
|
192
|
+
self._identifier = valid_ep_string(identifier, 'construction identifier')
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def display_name(self):
|
|
196
|
+
"""Get or set a string for the object name without any character restrictions.
|
|
197
|
+
|
|
198
|
+
If not set, this will be equal to the identifier.
|
|
199
|
+
"""
|
|
200
|
+
if self._display_name is None:
|
|
201
|
+
return self._identifier
|
|
202
|
+
return self._display_name
|
|
203
|
+
|
|
204
|
+
@display_name.setter
|
|
205
|
+
def display_name(self, value):
|
|
206
|
+
if value is not None:
|
|
207
|
+
try:
|
|
208
|
+
value = str(value)
|
|
209
|
+
except UnicodeEncodeError: # Python 2 machine lacking the character set
|
|
210
|
+
pass # keep it as unicode
|
|
211
|
+
self._display_name = value
|
|
212
|
+
|
|
213
|
+
@property
|
|
214
|
+
def window_construction(self):
|
|
215
|
+
"""Get the WindowConstruction serving as the "switched off" version."""
|
|
216
|
+
return self._window_construction
|
|
217
|
+
|
|
218
|
+
@property
|
|
219
|
+
def shade_material(self):
|
|
220
|
+
"""Get the material that serves as the shading layer for this construction."""
|
|
221
|
+
return self._shade_material
|
|
222
|
+
|
|
223
|
+
@property
|
|
224
|
+
def shade_location(self):
|
|
225
|
+
"""Get text to indicate where in the construction the shade_material is located.
|
|
226
|
+
|
|
227
|
+
This will be either "Interior", "Between" or "Exterior". Note that, for a
|
|
228
|
+
WindowConstruction with more than one gas gap, the "Between" option defaults
|
|
229
|
+
to using the inner gap as this is the only option that EnergyPlus supports.
|
|
230
|
+
"""
|
|
231
|
+
return self._shade_location
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def control_type(self):
|
|
235
|
+
"""Get or set the text indicating how the shading device is controlled.
|
|
236
|
+
|
|
237
|
+
Choose from the options below:
|
|
238
|
+
|
|
239
|
+
* AlwaysOn
|
|
240
|
+
* OnIfHighSolarOnWindow
|
|
241
|
+
* OnIfHighHorizontalSolar
|
|
242
|
+
* OnIfHighOutdoorAirTemperature
|
|
243
|
+
* OnIfHighZoneAirTemperature
|
|
244
|
+
* OnIfHighZoneCooling
|
|
245
|
+
* OnNightIfLowOutdoorTempAndOffDay
|
|
246
|
+
* OnNightIfLowInsideTempAndOffDay
|
|
247
|
+
* OnNightIfHeatingAndOffDay
|
|
248
|
+
"""
|
|
249
|
+
return self._control_type
|
|
250
|
+
|
|
251
|
+
@control_type.setter
|
|
252
|
+
def control_type(self, value):
|
|
253
|
+
assert value in self.CONTROL_TYPES, \
|
|
254
|
+
'Invalid input "{}" for shading control type.' \
|
|
255
|
+
' Must be one of the following:\n{}'.format(value, self.CONTROL_TYPES)
|
|
256
|
+
if value != 'AlwaysOn':
|
|
257
|
+
assert self._setpoint is not None, 'Control setpoint must not ' \
|
|
258
|
+
'be None to use "{}" control type.'.format(value)
|
|
259
|
+
self._control_type = value
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def setpoint(self):
|
|
263
|
+
"""A number for the setpoint that corresponds to the specified control_type.
|
|
264
|
+
|
|
265
|
+
This can be a value in (W/m2), (C) or (W) depending upon the control type.
|
|
266
|
+
"""
|
|
267
|
+
return self._setpoint
|
|
268
|
+
|
|
269
|
+
@setpoint.setter
|
|
270
|
+
def setpoint(self, value):
|
|
271
|
+
if value is not None:
|
|
272
|
+
try:
|
|
273
|
+
value = float(value)
|
|
274
|
+
except (ValueError, TypeError):
|
|
275
|
+
raise TypeError('Input setpoint must be a number. Got '
|
|
276
|
+
'{}: {}.'.format(type(value), value))
|
|
277
|
+
else:
|
|
278
|
+
assert self._control_type == 'AlwaysOn', 'Control setpoint cannot ' \
|
|
279
|
+
'be None for control type "{}"'.format(self._control_type)
|
|
280
|
+
self._setpoint = value
|
|
281
|
+
|
|
282
|
+
@property
|
|
283
|
+
def schedule(self):
|
|
284
|
+
"""Get or set a fractional schedule to be applied on top of the control_type.
|
|
285
|
+
|
|
286
|
+
If None, the control_type will govern all behavior of the construction.
|
|
287
|
+
"""
|
|
288
|
+
return self._schedule
|
|
289
|
+
|
|
290
|
+
@schedule.setter
|
|
291
|
+
def schedule(self, value):
|
|
292
|
+
if value is not None:
|
|
293
|
+
assert isinstance(value, (ScheduleRuleset, ScheduleFixedInterval)), \
|
|
294
|
+
'Expected schedule for window construction shaded schedule. ' \
|
|
295
|
+
'Got {}.'.format(type(value))
|
|
296
|
+
if value.schedule_type_limit is not None:
|
|
297
|
+
assert value.schedule_type_limit.unit == 'fraction', 'Window ' \
|
|
298
|
+
'construction schedule should be fractional. Got a schedule ' \
|
|
299
|
+
'of unit_type [{}].'.format(value.schedule_type_limit.unit_type)
|
|
300
|
+
value.lock() # lock editing in case schedule has multiple references
|
|
301
|
+
self._schedule = value
|
|
302
|
+
|
|
303
|
+
@property
|
|
304
|
+
def materials(self):
|
|
305
|
+
"""Get the list of materials in the construction (outside to inside).
|
|
306
|
+
|
|
307
|
+
This will include the shade material layer in its correct position.
|
|
308
|
+
"""
|
|
309
|
+
base_mats = list(self._window_construction.materials)
|
|
310
|
+
if self.is_switchable_glazing:
|
|
311
|
+
if self._shade_location == 'Interior':
|
|
312
|
+
base_mats[-1] = self._shade_material
|
|
313
|
+
elif self._shade_location == 'Exterior' or \
|
|
314
|
+
self._window_construction.gap_count == 0:
|
|
315
|
+
base_mats[0] = self._shade_material
|
|
316
|
+
else: # middle glass pane
|
|
317
|
+
base_mats[-3] = self._shade_material
|
|
318
|
+
else:
|
|
319
|
+
if self._shade_location == 'Interior':
|
|
320
|
+
base_mats.append(self._shade_material)
|
|
321
|
+
elif self._shade_location == 'Exterior':
|
|
322
|
+
base_mats.insert(0, self._shade_material)
|
|
323
|
+
else: # between glass shade/blind
|
|
324
|
+
base_mats[-2] = self._between_gap
|
|
325
|
+
base_mats.insert(-1, self._shade_material)
|
|
326
|
+
base_mats.insert(-1, self._between_gap)
|
|
327
|
+
return base_mats
|
|
328
|
+
|
|
329
|
+
@property
|
|
330
|
+
def layers(self):
|
|
331
|
+
"""Get a list of material identifiers in the construction (outside to inside).
|
|
332
|
+
|
|
333
|
+
This will include the shade material layer in its correct position.
|
|
334
|
+
"""
|
|
335
|
+
return [mat.identifier for mat in self.materials]
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
def unique_materials(self):
|
|
339
|
+
"""Get a list of only unique material objects in the construction.
|
|
340
|
+
|
|
341
|
+
This will include the shade material layer. It will include both types of glass
|
|
342
|
+
layers if the construction is a switchable glazing.
|
|
343
|
+
"""
|
|
344
|
+
if self.is_switchable_glazing:
|
|
345
|
+
return list(set(
|
|
346
|
+
self._window_construction.materials + (self.shade_material,)))
|
|
347
|
+
return list(set(self.materials))
|
|
348
|
+
|
|
349
|
+
@property
|
|
350
|
+
def frame(self):
|
|
351
|
+
"""Get a window frame for the frame material surrounding the construction."""
|
|
352
|
+
return self._window_construction.frame
|
|
353
|
+
|
|
354
|
+
@property
|
|
355
|
+
def r_value(self):
|
|
356
|
+
"""R-value of the bare window construction [m2-K/W] (excluding air films).
|
|
357
|
+
|
|
358
|
+
Note that this excludes all effects of the shade layer.
|
|
359
|
+
"""
|
|
360
|
+
return self._window_construction.r_value
|
|
361
|
+
|
|
362
|
+
@property
|
|
363
|
+
def u_value(self):
|
|
364
|
+
"""U-value of the bare window construction [W/m2-K] (excluding air films).
|
|
365
|
+
|
|
366
|
+
Note that this excludes all effects of the shade layer.
|
|
367
|
+
"""
|
|
368
|
+
return self._window_construction.u_value
|
|
369
|
+
|
|
370
|
+
@property
|
|
371
|
+
def r_factor(self):
|
|
372
|
+
"""Bare window construction R-factor [m2-K/W] (with standard air resistances).
|
|
373
|
+
|
|
374
|
+
Note that this excludes all effects of the shade layer.
|
|
375
|
+
Formulas for film coefficients come from EN673 / ISO10292.
|
|
376
|
+
"""
|
|
377
|
+
return self._window_construction.r_factor
|
|
378
|
+
|
|
379
|
+
@property
|
|
380
|
+
def u_factor(self):
|
|
381
|
+
"""Bare window construction U-factor [W/m2-K] (with standard air resistances).
|
|
382
|
+
|
|
383
|
+
Note that this excludes all effects of the shade layer.
|
|
384
|
+
Formulas for film coefficients come from EN673 / ISO10292.
|
|
385
|
+
"""
|
|
386
|
+
return self._window_construction.u_factor
|
|
387
|
+
|
|
388
|
+
@property
|
|
389
|
+
def solar_transmittance(self):
|
|
390
|
+
"""The solar transmittance of the bare window construction at normal incidence.
|
|
391
|
+
|
|
392
|
+
Note that this excludes all effects of the shade layer.
|
|
393
|
+
"""
|
|
394
|
+
return self._window_construction.solar_transmittance
|
|
395
|
+
|
|
396
|
+
@property
|
|
397
|
+
def visible_transmittance(self):
|
|
398
|
+
"""The visible transmittance of the bare window construction at normal incidence.
|
|
399
|
+
|
|
400
|
+
Note that this excludes all effects of the shade layer.
|
|
401
|
+
"""
|
|
402
|
+
return self._window_construction.visible_transmittance
|
|
403
|
+
|
|
404
|
+
@property
|
|
405
|
+
def shgc(self):
|
|
406
|
+
"""The solar heat gain coefficient (SHGC) of the bare window construction.
|
|
407
|
+
|
|
408
|
+
Note that this excludes all effects of the shade layer.
|
|
409
|
+
"""
|
|
410
|
+
return self._window_construction.shgc
|
|
411
|
+
|
|
412
|
+
@property
|
|
413
|
+
def is_symmetric(self):
|
|
414
|
+
"""Get a boolean for whether the construction layers are symmetric.
|
|
415
|
+
|
|
416
|
+
Symmetric means that the materials in reversed order are equal to those
|
|
417
|
+
in the current order (eg. 'Glass', 'Air Gap', 'Glass'). This is particularly
|
|
418
|
+
helpful for interior constructions, which need to have matching materials
|
|
419
|
+
in reversed order between adjacent Faces.
|
|
420
|
+
"""
|
|
421
|
+
mats = self.materials
|
|
422
|
+
half_mat = int(len(mats) / 2)
|
|
423
|
+
for i in range(half_mat):
|
|
424
|
+
if mats[i] != mats[-(i + 1)]:
|
|
425
|
+
return False
|
|
426
|
+
return True
|
|
427
|
+
|
|
428
|
+
@property
|
|
429
|
+
def has_frame(self):
|
|
430
|
+
"""Get a boolean noting whether the construction has a frame assigned to it."""
|
|
431
|
+
return self._window_construction.has_frame
|
|
432
|
+
|
|
433
|
+
@property
|
|
434
|
+
def has_shade(self):
|
|
435
|
+
"""Get a boolean noting whether dynamic materials are in the construction.
|
|
436
|
+
|
|
437
|
+
This should always be True for this class.
|
|
438
|
+
"""
|
|
439
|
+
return True
|
|
440
|
+
|
|
441
|
+
@property
|
|
442
|
+
def is_dynamic(self):
|
|
443
|
+
"""Get a boolean noting whether the construction is dynamic.
|
|
444
|
+
|
|
445
|
+
This will always be True for this class.
|
|
446
|
+
"""
|
|
447
|
+
return True
|
|
448
|
+
|
|
449
|
+
@property
|
|
450
|
+
def is_switchable_glazing(self):
|
|
451
|
+
"""Get a boolean to note whether the construction is switchable glazing.
|
|
452
|
+
|
|
453
|
+
The construction is a switchable glazing if the shade material is a
|
|
454
|
+
glass material.
|
|
455
|
+
"""
|
|
456
|
+
return isinstance(self.shade_material, EnergyWindowMaterialGlazing)
|
|
457
|
+
|
|
458
|
+
@property
|
|
459
|
+
def switched_glass_material(self):
|
|
460
|
+
"""Get material replaced by shade glass when construction is switchable glazing.
|
|
461
|
+
|
|
462
|
+
This can be used to compare the properties of the glass layer replaced by
|
|
463
|
+
the shade glass. Will be None if the construction is not a switchable glazing.
|
|
464
|
+
"""
|
|
465
|
+
if not self.is_switchable_glazing:
|
|
466
|
+
return None
|
|
467
|
+
base_mats = self._window_construction.materials
|
|
468
|
+
if self._shade_location == 'Interior':
|
|
469
|
+
return self.base_mats[-1]
|
|
470
|
+
elif self._shade_location == 'Exterior' or \
|
|
471
|
+
self._window_construction.gap_count == 0:
|
|
472
|
+
return base_mats[0]
|
|
473
|
+
else: # middle glass pane
|
|
474
|
+
return base_mats[-3]
|
|
475
|
+
|
|
476
|
+
@property
|
|
477
|
+
def inside_emissivity(self):
|
|
478
|
+
""""The emissivity of the inside face of the construction.
|
|
479
|
+
|
|
480
|
+
This will use the emissivity of the shade layer if it is interior.
|
|
481
|
+
"""
|
|
482
|
+
mats = self.materials
|
|
483
|
+
if isinstance(mats[-1], EnergyWindowMaterialSimpleGlazSys):
|
|
484
|
+
return 0.84
|
|
485
|
+
try:
|
|
486
|
+
return mats[-1].emissivity_back
|
|
487
|
+
except AttributeError:
|
|
488
|
+
return mats[-1].emissivity
|
|
489
|
+
|
|
490
|
+
@property
|
|
491
|
+
def outside_emissivity(self):
|
|
492
|
+
""""The emissivity of the outside face of the construction.
|
|
493
|
+
|
|
494
|
+
This will use the emissivity of the shade layer if it is interior.
|
|
495
|
+
"""
|
|
496
|
+
mats = self.materials
|
|
497
|
+
if isinstance(mats[0], EnergyWindowMaterialSimpleGlazSys):
|
|
498
|
+
return 0.84
|
|
499
|
+
return mats[0].emissivity
|
|
500
|
+
|
|
501
|
+
@property
|
|
502
|
+
def thickness(self):
|
|
503
|
+
"""Thickness of the construction [m], excluding the shade layer.
|
|
504
|
+
|
|
505
|
+
This is effectively the thickness that EnergyPlus assumes.
|
|
506
|
+
"""
|
|
507
|
+
return self._window_construction.thickness
|
|
508
|
+
|
|
509
|
+
@property
|
|
510
|
+
def glazing_count(self):
|
|
511
|
+
"""The number of glazing materials contained within the construction.
|
|
512
|
+
|
|
513
|
+
Note that Simple Glazing System materials do not count.
|
|
514
|
+
"""
|
|
515
|
+
return self._window_construction.glazing_count
|
|
516
|
+
|
|
517
|
+
@property
|
|
518
|
+
def gap_count(self):
|
|
519
|
+
"""Get the number of gas gaps contained within the construction."""
|
|
520
|
+
count = self._window_construction.gap_count
|
|
521
|
+
if self.shade_location == 'Between' and not self.is_switchable_glazing:
|
|
522
|
+
count += 1
|
|
523
|
+
return count
|
|
524
|
+
|
|
525
|
+
@property
|
|
526
|
+
def is_groupable(self):
|
|
527
|
+
"""Get a boolean for whether controls allow the construction to be grouped."""
|
|
528
|
+
return self.control_type in self.GROUPABLE_TYPES
|
|
529
|
+
|
|
530
|
+
@property
|
|
531
|
+
def is_room_groupable(self):
|
|
532
|
+
"""Get a boolean for whether controls allow grouping by room."""
|
|
533
|
+
return self.control_type in self.ROOM_GROUPABLE_TYPES
|
|
534
|
+
|
|
535
|
+
@property
|
|
536
|
+
def inside_material(self):
|
|
537
|
+
"""The the inside material layer of the construction.
|
|
538
|
+
|
|
539
|
+
Useful for checking that an asymmetric construction is correctly assigned.
|
|
540
|
+
"""
|
|
541
|
+
return self.materials[-1]
|
|
542
|
+
|
|
543
|
+
@property
|
|
544
|
+
def outside_material(self):
|
|
545
|
+
"""The the outside material layer of the construction.
|
|
546
|
+
|
|
547
|
+
Useful for checking that an asymmetric construction is correctly assigned.
|
|
548
|
+
"""
|
|
549
|
+
return self.materials[0]
|
|
550
|
+
|
|
551
|
+
@property
|
|
552
|
+
def _ep_shading_type(self):
|
|
553
|
+
"""Text for the Shading Type field that EnergyPlus wants in the IDF."""
|
|
554
|
+
if self.is_switchable_glazing:
|
|
555
|
+
return 'SwitchableGlazing'
|
|
556
|
+
elif isinstance(self.shade_material, EnergyWindowMaterialBlind):
|
|
557
|
+
return 'BetweenGlassBlind' if self.shade_location == 'Between' \
|
|
558
|
+
else '{}Blind'.format(self.shade_location)
|
|
559
|
+
else:
|
|
560
|
+
return 'BetweenGlassShade' if self.shade_location == 'Between' \
|
|
561
|
+
else '{}Shade'.format(self.shade_location)
|
|
562
|
+
|
|
563
|
+
@property
|
|
564
|
+
def user_data(self):
|
|
565
|
+
"""Get or set an optional dictionary for additional meta data for this object.
|
|
566
|
+
|
|
567
|
+
This will be None until it has been set. All keys and values of this
|
|
568
|
+
dictionary should be of a standard Python type to ensure correct
|
|
569
|
+
serialization of the object to/from JSON (eg. str, float, int, list, dict)
|
|
570
|
+
"""
|
|
571
|
+
if self._user_data is not None:
|
|
572
|
+
return self._user_data
|
|
573
|
+
|
|
574
|
+
@user_data.setter
|
|
575
|
+
def user_data(self, value):
|
|
576
|
+
if value is not None:
|
|
577
|
+
assert isinstance(value, dict), 'Expected dictionary for honeybee_energy' \
|
|
578
|
+
'object user_data. Got {}.'.format(type(value))
|
|
579
|
+
self._user_data = value
|
|
580
|
+
|
|
581
|
+
@property
|
|
582
|
+
def properties(self):
|
|
583
|
+
"""Get properties for extensions."""
|
|
584
|
+
return self._properties
|
|
585
|
+
|
|
586
|
+
@classmethod
|
|
587
|
+
def from_dict(cls, data):
|
|
588
|
+
"""Create a WindowConstructionShade from a dictionary.
|
|
589
|
+
|
|
590
|
+
Note that the dictionary must be a non-abridged version for this
|
|
591
|
+
classmethod to work.
|
|
592
|
+
|
|
593
|
+
Args:
|
|
594
|
+
data: A python dictionary in the following format
|
|
595
|
+
|
|
596
|
+
.. code-block:: python
|
|
597
|
+
|
|
598
|
+
{
|
|
599
|
+
"type": 'WindowConstructionShade',
|
|
600
|
+
"identifier": 'Double Pane U-250 IntBlind-0025',
|
|
601
|
+
"display_name": 'Double Pane with Interior Blind',
|
|
602
|
+
"window_construction": {} # a WindowConstruction dictionary representation
|
|
603
|
+
"shade_material": {} # a shade/blind/glass dictionary representation
|
|
604
|
+
"shade_location": 'Interior', # text for shade layer location
|
|
605
|
+
"control_type": 'OnIfHighSolarOnWindow', # text for shade control type
|
|
606
|
+
"setpoint": 200, # number for control setpoint
|
|
607
|
+
"schedule": {} # optional ScheduleRuleset or ScheduleFixedInterval dict
|
|
608
|
+
}
|
|
609
|
+
"""
|
|
610
|
+
# check the type
|
|
611
|
+
assert data['type'] == 'WindowConstructionShade', \
|
|
612
|
+
'Expected WindowConstructionShade. Got {}.'.format(data['type'])
|
|
613
|
+
|
|
614
|
+
# re-serialize required inputs
|
|
615
|
+
window_constr = WindowConstruction.from_dict(data['window_construction'])
|
|
616
|
+
shade_material = dict_to_material(data['shade_material'])
|
|
617
|
+
|
|
618
|
+
# re-serialize optional inputs
|
|
619
|
+
shade_location, control_type, setpoint = cls._from_dict_defaults(data)
|
|
620
|
+
schedule = dict_to_schedule(data['schedule']) if 'schedule' in data and \
|
|
621
|
+
data['schedule'] is not None else None
|
|
622
|
+
|
|
623
|
+
new_obj = cls(data['identifier'], window_constr, shade_material, shade_location,
|
|
624
|
+
control_type, setpoint, schedule)
|
|
625
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
626
|
+
new_obj.display_name = data['display_name']
|
|
627
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
628
|
+
new_obj.user_data = data['user_data']
|
|
629
|
+
if 'properties' in data and data['properties'] is not None:
|
|
630
|
+
new_obj.properties._load_extension_attr_from_dict(data['properties'])
|
|
631
|
+
return new_obj
|
|
632
|
+
|
|
633
|
+
@classmethod
|
|
634
|
+
def from_dict_abridged(cls, data, materials, schedules):
|
|
635
|
+
"""Create a WindowConstructionShade from an abridged dictionary.
|
|
636
|
+
|
|
637
|
+
Args:
|
|
638
|
+
data: An WindowConstructionShade dictionary with the format below.
|
|
639
|
+
materials: A dictionary with identifiers of materials as keys and
|
|
640
|
+
Python material objects as values.
|
|
641
|
+
schedules: A dictionary with schedule identifiers as keys and
|
|
642
|
+
honeybee schedule objects as values.
|
|
643
|
+
|
|
644
|
+
.. code-block:: python
|
|
645
|
+
|
|
646
|
+
{
|
|
647
|
+
"type": 'WindowConstructionShadeAbridged',
|
|
648
|
+
"identifier": 'Double Pane U-250 IntBlind-0025',
|
|
649
|
+
"display_name": 'Double Pane with Interior Blind',
|
|
650
|
+
"window_construction": {} # a WindowConstructionAbridged dictionary
|
|
651
|
+
"shade_material": 'Blind-0025' # a shade/blind/glass identifier
|
|
652
|
+
"shade_location": 'Interior', # text for shade layer location
|
|
653
|
+
"control_type": 'OnIfHighSolarOnWindow', # text for shade control type
|
|
654
|
+
"setpoint": 200, # number for control setpoint
|
|
655
|
+
"schedule": 'DayNight_Schedule' # optional schedule identifier
|
|
656
|
+
}
|
|
657
|
+
"""
|
|
658
|
+
# check the type
|
|
659
|
+
assert data['type'] == 'WindowConstructionShadeAbridged', \
|
|
660
|
+
'Expected WindowConstructionShadeAbridged. Got {}.'.format(data['type'])
|
|
661
|
+
|
|
662
|
+
# re-serialize required inputs
|
|
663
|
+
window_constr = WindowConstruction.from_dict_abridged(
|
|
664
|
+
data['window_construction'], materials)
|
|
665
|
+
shade_material = materials[data['shade_material']]
|
|
666
|
+
|
|
667
|
+
# re-serialize optional inputs
|
|
668
|
+
shade_location, control_type, setpoint = cls._from_dict_defaults(data)
|
|
669
|
+
schedule = schedules[data['schedule']] if 'schedule' in data and \
|
|
670
|
+
data['schedule'] is not None else None
|
|
671
|
+
|
|
672
|
+
new_obj = cls(data['identifier'], window_constr, shade_material, shade_location,
|
|
673
|
+
control_type, setpoint, schedule)
|
|
674
|
+
if 'display_name' in data and data['display_name'] is not None:
|
|
675
|
+
new_obj.display_name = data['display_name']
|
|
676
|
+
if 'user_data' in data and data['user_data'] is not None:
|
|
677
|
+
new_obj.user_data = data['user_data']
|
|
678
|
+
if 'properties' in data and data['properties'] is not None:
|
|
679
|
+
new_obj.properties._load_extension_attr_from_dict(data['properties'])
|
|
680
|
+
return new_obj
|
|
681
|
+
|
|
682
|
+
def to_idf(self):
|
|
683
|
+
"""IDF string representation of construction object.
|
|
684
|
+
|
|
685
|
+
Note that this method only outputs a single string for the bare window
|
|
686
|
+
construction and, to write the full construction into an IDF, the
|
|
687
|
+
construction's unique_materials must also be written along with the
|
|
688
|
+
output of to_shaded_idf, which contains the shaded construction.
|
|
689
|
+
Also, for each Aperture to which this construction is assigned, a
|
|
690
|
+
ShadingControl object must also be written, which can be obtained from
|
|
691
|
+
the to_shading_control_idf. If the construction has a frame, the frame
|
|
692
|
+
definition must also be written.
|
|
693
|
+
|
|
694
|
+
Returns:
|
|
695
|
+
Text string representation of the bare (unshaded) construction.
|
|
696
|
+
|
|
697
|
+
.. code-block:: shell
|
|
698
|
+
|
|
699
|
+
Construction,
|
|
700
|
+
Generic Double Pane, !- name
|
|
701
|
+
Generic Low-e Glass, !- layer 1
|
|
702
|
+
Generic Window Air Gap, !- layer 2
|
|
703
|
+
Generic Clear Glass; !- layer 3
|
|
704
|
+
"""
|
|
705
|
+
return self._window_construction.to_idf()
|
|
706
|
+
|
|
707
|
+
def to_shaded_idf(self):
|
|
708
|
+
"""IDF string representation of construction in its shaded state.
|
|
709
|
+
|
|
710
|
+
Returns:
|
|
711
|
+
Text string representation of the shaded construction.
|
|
712
|
+
"""
|
|
713
|
+
materials = self.materials
|
|
714
|
+
values = (self.identifier,) + tuple(mat.identifier for mat in materials)
|
|
715
|
+
comments = ('name',) + tuple('layer %s' % (i + 1) for i in range(len(materials)))
|
|
716
|
+
return generate_idf_string('Construction', values, comments)
|
|
717
|
+
|
|
718
|
+
def to_shading_control_idf(self, aperture_identifier, room_identifier):
|
|
719
|
+
"""IDF string representation of a WindowShadingControl object.
|
|
720
|
+
|
|
721
|
+
This has to be written for every Aperture to which this construction is
|
|
722
|
+
assigned in order for EnergyPlus to simulate it correctly.
|
|
723
|
+
|
|
724
|
+
Args:
|
|
725
|
+
aperture_identifier: The identifier of the honeybee Aperture to
|
|
726
|
+
which this construction is assigned.
|
|
727
|
+
room_identifier: The identifier of the honeybee Room to which the
|
|
728
|
+
aperture belongs.
|
|
729
|
+
|
|
730
|
+
Returns:
|
|
731
|
+
Text string representation of the WindowShadingControl.
|
|
732
|
+
"""
|
|
733
|
+
control_name = '{}_ShdControl'.format(aperture_identifier)
|
|
734
|
+
control_type = 'OnIfScheduleAllows' if self.schedule is not None and \
|
|
735
|
+
self.control_type == 'AlwaysOn' else self.control_type
|
|
736
|
+
sch = self.schedule.identifier if self.schedule is not None else ''
|
|
737
|
+
sch_bool = 'Yes' if self.schedule is not None else 'No'
|
|
738
|
+
setpt = self.setpoint if self.setpoint is not None else ''
|
|
739
|
+
values = (control_name, room_identifier, 1, self._ep_shading_type,
|
|
740
|
+
self.identifier, control_type, sch, setpt, sch_bool,
|
|
741
|
+
'', '', '', '', '', '', '', aperture_identifier)
|
|
742
|
+
comments = \
|
|
743
|
+
('name', 'zone name', 'sequence number', 'shading type',
|
|
744
|
+
'construction with shade', 'control type', 'schedule', 'setpoint',
|
|
745
|
+
'is scheduled', 'is glare controlled', 'shade material', 'slat control',
|
|
746
|
+
'slat schedule', 'setpoint 2', 'daylight object', 'multiple control type',
|
|
747
|
+
'fenestration surface')
|
|
748
|
+
return generate_idf_string('WindowShadingControl', values, comments)
|
|
749
|
+
|
|
750
|
+
def to_radiance_solar(self):
|
|
751
|
+
"""Honeybee Radiance material for the bare (unshaded) construction."""
|
|
752
|
+
# TODO: add method that represents blinds with BSDF + shades with Trans
|
|
753
|
+
return self._window_construction.to_radiance_solar()
|
|
754
|
+
|
|
755
|
+
def to_radiance_visible(self):
|
|
756
|
+
"""Honeybee Radiance material for the bare (unshaded) construction."""
|
|
757
|
+
# TODO: add method that represents blinds with BSDF + shades with Trans
|
|
758
|
+
return self._window_construction.to_radiance_visible()
|
|
759
|
+
|
|
760
|
+
def to_dict(self, abridged=False):
|
|
761
|
+
"""Window construction dictionary representation.
|
|
762
|
+
|
|
763
|
+
Args:
|
|
764
|
+
abridged: Boolean to note whether the full dictionary describing the
|
|
765
|
+
object should be returned (False) or just an abridged version (True),
|
|
766
|
+
which only specifies the identifiers of material layers and
|
|
767
|
+
schedules. (Default: False).
|
|
768
|
+
"""
|
|
769
|
+
base = {'type': 'WindowConstructionShade'} if not \
|
|
770
|
+
abridged else {'type': 'WindowConstructionShadeAbridged'}
|
|
771
|
+
base['identifier'] = self.identifier
|
|
772
|
+
base['window_construction'] = self.window_construction.to_dict(abridged)
|
|
773
|
+
base['shade_material'] = self.shade_material.identifier if abridged \
|
|
774
|
+
else self.shade_material.to_dict()
|
|
775
|
+
base['shade_location'] = self.shade_location
|
|
776
|
+
base['control_type'] = self.control_type
|
|
777
|
+
if self.control_type != 'AlwaysOn':
|
|
778
|
+
base['setpoint'] = self.setpoint
|
|
779
|
+
if self.schedule is not None:
|
|
780
|
+
base['schedule'] = self.schedule.identifier if abridged \
|
|
781
|
+
else self.schedule.to_dict()
|
|
782
|
+
if self._display_name is not None:
|
|
783
|
+
base['display_name'] = self.display_name
|
|
784
|
+
if self._user_data is not None:
|
|
785
|
+
base['user_data'] = self.user_data
|
|
786
|
+
base['properties'] = self.properties.to_dict() if self._properties else None
|
|
787
|
+
return base
|
|
788
|
+
|
|
789
|
+
def lock(self):
|
|
790
|
+
"""The lock() method will also lock the shade_material."""
|
|
791
|
+
self._locked = True
|
|
792
|
+
self.shade_material.lock()
|
|
793
|
+
|
|
794
|
+
def unlock(self):
|
|
795
|
+
"""The unlock() method will also unlock the shade_material."""
|
|
796
|
+
self._locked = False
|
|
797
|
+
self.shade_material.unlock()
|
|
798
|
+
|
|
799
|
+
def duplicate(self):
|
|
800
|
+
"""Get a copy of this construction."""
|
|
801
|
+
return self.__copy__()
|
|
802
|
+
|
|
803
|
+
@staticmethod
|
|
804
|
+
def _from_dict_defaults(data):
|
|
805
|
+
"Re-serialize default values from a dictionary."
|
|
806
|
+
shade_location = data['shade_location'] if 'shade_location' in data and \
|
|
807
|
+
data['shade_location'] is not None else 'Interior'
|
|
808
|
+
control_type = data['control_type'] if 'control_type' in data and \
|
|
809
|
+
data['control_type'] is not None else 'AlwaysOn'
|
|
810
|
+
setpoint = data['setpoint'] if 'setpoint' in data \
|
|
811
|
+
else None
|
|
812
|
+
return shade_location, control_type, setpoint
|
|
813
|
+
|
|
814
|
+
def __copy__(self):
|
|
815
|
+
new_con = WindowConstructionShade(
|
|
816
|
+
self.identifier, self.window_construction, self.shade_material,
|
|
817
|
+
self.shade_location, self.control_type, self.setpoint,
|
|
818
|
+
self.schedule)
|
|
819
|
+
new_con._between_gap = self._between_gap
|
|
820
|
+
new_con._display_name = self._display_name
|
|
821
|
+
new_con._user_data = None if self._user_data is None else self._user_data.copy()
|
|
822
|
+
new_con._properties._duplicate_extension_attr(self._properties)
|
|
823
|
+
return new_con
|
|
824
|
+
|
|
825
|
+
def __key(self):
|
|
826
|
+
"""A tuple based on the object properties, useful for hashing."""
|
|
827
|
+
sch = hash(self.schedule) if self.schedule is not None else None
|
|
828
|
+
return (self._identifier, hash(self.window_construction),
|
|
829
|
+
hash(self.shade_material), self.shade_location, self.control_type,
|
|
830
|
+
self.setpoint, sch)
|
|
831
|
+
|
|
832
|
+
def __hash__(self):
|
|
833
|
+
return hash(self.__key())
|
|
834
|
+
|
|
835
|
+
def __eq__(self, other):
|
|
836
|
+
return isinstance(other, WindowConstructionShade) and \
|
|
837
|
+
self.__key() == other.__key()
|
|
838
|
+
|
|
839
|
+
def __ne__(self, other):
|
|
840
|
+
return not self.__eq__(other)
|
|
841
|
+
|
|
842
|
+
def ToString(self):
|
|
843
|
+
"""Overwrite .NET ToString."""
|
|
844
|
+
return self.__repr__()
|
|
845
|
+
|
|
846
|
+
def __repr__(self):
|
|
847
|
+
return self.to_shaded_idf()
|