honeybee-radiance 1.66.190__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.

Potentially problematic release.


This version of honeybee-radiance might be problematic. Click here for more details.

Files changed (152) hide show
  1. honeybee_radiance/__init__.py +11 -0
  2. honeybee_radiance/__main__.py +4 -0
  3. honeybee_radiance/_extend_honeybee.py +93 -0
  4. honeybee_radiance/cli/__init__.py +88 -0
  5. honeybee_radiance/cli/dc.py +400 -0
  6. honeybee_radiance/cli/edit.py +529 -0
  7. honeybee_radiance/cli/glare.py +118 -0
  8. honeybee_radiance/cli/grid.py +859 -0
  9. honeybee_radiance/cli/lib.py +458 -0
  10. honeybee_radiance/cli/modifier.py +133 -0
  11. honeybee_radiance/cli/mtx.py +226 -0
  12. honeybee_radiance/cli/multiphase.py +1034 -0
  13. honeybee_radiance/cli/octree.py +640 -0
  14. honeybee_radiance/cli/postprocess.py +1186 -0
  15. honeybee_radiance/cli/raytrace.py +219 -0
  16. honeybee_radiance/cli/rpict.py +125 -0
  17. honeybee_radiance/cli/schedule.py +56 -0
  18. honeybee_radiance/cli/setconfig.py +63 -0
  19. honeybee_radiance/cli/sky.py +545 -0
  20. honeybee_radiance/cli/study.py +66 -0
  21. honeybee_radiance/cli/sunpath.py +331 -0
  22. honeybee_radiance/cli/threephase.py +255 -0
  23. honeybee_radiance/cli/translate.py +400 -0
  24. honeybee_radiance/cli/util.py +121 -0
  25. honeybee_radiance/cli/view.py +261 -0
  26. honeybee_radiance/cli/viewfactor.py +347 -0
  27. honeybee_radiance/config.json +6 -0
  28. honeybee_radiance/config.py +427 -0
  29. honeybee_radiance/dictutil.py +50 -0
  30. honeybee_radiance/dynamic/__init__.py +5 -0
  31. honeybee_radiance/dynamic/group.py +479 -0
  32. honeybee_radiance/dynamic/multiphase.py +557 -0
  33. honeybee_radiance/dynamic/state.py +718 -0
  34. honeybee_radiance/dynamic/stategeo.py +352 -0
  35. honeybee_radiance/geometry/__init__.py +13 -0
  36. honeybee_radiance/geometry/bubble.py +42 -0
  37. honeybee_radiance/geometry/cone.py +215 -0
  38. honeybee_radiance/geometry/cup.py +54 -0
  39. honeybee_radiance/geometry/cylinder.py +197 -0
  40. honeybee_radiance/geometry/geometrybase.py +37 -0
  41. honeybee_radiance/geometry/instance.py +40 -0
  42. honeybee_radiance/geometry/mesh.py +38 -0
  43. honeybee_radiance/geometry/polygon.py +174 -0
  44. honeybee_radiance/geometry/ring.py +214 -0
  45. honeybee_radiance/geometry/source.py +182 -0
  46. honeybee_radiance/geometry/sphere.py +178 -0
  47. honeybee_radiance/geometry/tube.py +46 -0
  48. honeybee_radiance/lib/__init__.py +1 -0
  49. honeybee_radiance/lib/_loadmodifiers.py +72 -0
  50. honeybee_radiance/lib/_loadmodifiersets.py +69 -0
  51. honeybee_radiance/lib/modifiers.py +58 -0
  52. honeybee_radiance/lib/modifiersets.py +63 -0
  53. honeybee_radiance/lightpath.py +204 -0
  54. honeybee_radiance/lightsource/__init__.py +1 -0
  55. honeybee_radiance/lightsource/_gendaylit.py +479 -0
  56. honeybee_radiance/lightsource/dictutil.py +49 -0
  57. honeybee_radiance/lightsource/ground.py +160 -0
  58. honeybee_radiance/lightsource/sky/__init__.py +7 -0
  59. honeybee_radiance/lightsource/sky/_skybase.py +177 -0
  60. honeybee_radiance/lightsource/sky/certainirradiance.py +232 -0
  61. honeybee_radiance/lightsource/sky/cie.py +378 -0
  62. honeybee_radiance/lightsource/sky/climatebased.py +501 -0
  63. honeybee_radiance/lightsource/sky/hemisphere.py +160 -0
  64. honeybee_radiance/lightsource/sky/skydome.py +113 -0
  65. honeybee_radiance/lightsource/sky/skymatrix.py +163 -0
  66. honeybee_radiance/lightsource/sky/strutil.py +34 -0
  67. honeybee_radiance/lightsource/sky/sunmatrix.py +212 -0
  68. honeybee_radiance/lightsource/sunpath.py +247 -0
  69. honeybee_radiance/modifier/__init__.py +3 -0
  70. honeybee_radiance/modifier/material/__init__.py +30 -0
  71. honeybee_radiance/modifier/material/absdf.py +477 -0
  72. honeybee_radiance/modifier/material/antimatter.py +54 -0
  73. honeybee_radiance/modifier/material/ashik2.py +51 -0
  74. honeybee_radiance/modifier/material/brtdfunc.py +81 -0
  75. honeybee_radiance/modifier/material/bsdf.py +292 -0
  76. honeybee_radiance/modifier/material/dielectric.py +53 -0
  77. honeybee_radiance/modifier/material/glass.py +431 -0
  78. honeybee_radiance/modifier/material/glow.py +246 -0
  79. honeybee_radiance/modifier/material/illum.py +51 -0
  80. honeybee_radiance/modifier/material/interface.py +49 -0
  81. honeybee_radiance/modifier/material/light.py +206 -0
  82. honeybee_radiance/modifier/material/materialbase.py +36 -0
  83. honeybee_radiance/modifier/material/metal.py +167 -0
  84. honeybee_radiance/modifier/material/metal2.py +41 -0
  85. honeybee_radiance/modifier/material/metdata.py +41 -0
  86. honeybee_radiance/modifier/material/metfunc.py +41 -0
  87. honeybee_radiance/modifier/material/mirror.py +340 -0
  88. honeybee_radiance/modifier/material/mist.py +86 -0
  89. honeybee_radiance/modifier/material/plasdata.py +58 -0
  90. honeybee_radiance/modifier/material/plasfunc.py +59 -0
  91. honeybee_radiance/modifier/material/plastic.py +354 -0
  92. honeybee_radiance/modifier/material/plastic2.py +58 -0
  93. honeybee_radiance/modifier/material/prism1.py +57 -0
  94. honeybee_radiance/modifier/material/prism2.py +48 -0
  95. honeybee_radiance/modifier/material/spotlight.py +50 -0
  96. honeybee_radiance/modifier/material/trans.py +518 -0
  97. honeybee_radiance/modifier/material/trans2.py +49 -0
  98. honeybee_radiance/modifier/material/transdata.py +50 -0
  99. honeybee_radiance/modifier/material/transfunc.py +53 -0
  100. honeybee_radiance/modifier/mixture/__init__.py +6 -0
  101. honeybee_radiance/modifier/mixture/mixdata.py +49 -0
  102. honeybee_radiance/modifier/mixture/mixfunc.py +54 -0
  103. honeybee_radiance/modifier/mixture/mixpict.py +52 -0
  104. honeybee_radiance/modifier/mixture/mixtext.py +66 -0
  105. honeybee_radiance/modifier/mixture/mixturebase.py +28 -0
  106. honeybee_radiance/modifier/modifierbase.py +40 -0
  107. honeybee_radiance/modifier/pattern/__init__.py +9 -0
  108. honeybee_radiance/modifier/pattern/brightdata.py +49 -0
  109. honeybee_radiance/modifier/pattern/brightfunc.py +47 -0
  110. honeybee_radiance/modifier/pattern/brighttext.py +81 -0
  111. honeybee_radiance/modifier/pattern/colordata.py +56 -0
  112. honeybee_radiance/modifier/pattern/colorfunc.py +47 -0
  113. honeybee_radiance/modifier/pattern/colorpict.py +54 -0
  114. honeybee_radiance/modifier/pattern/colortext.py +73 -0
  115. honeybee_radiance/modifier/pattern/patternbase.py +34 -0
  116. honeybee_radiance/modifier/texture/__init__.py +4 -0
  117. honeybee_radiance/modifier/texture/texdata.py +29 -0
  118. honeybee_radiance/modifier/texture/texfunc.py +26 -0
  119. honeybee_radiance/modifier/texture/texturebase.py +27 -0
  120. honeybee_radiance/modifierset.py +1091 -0
  121. honeybee_radiance/mutil.py +60 -0
  122. honeybee_radiance/postprocess/__init__.py +1 -0
  123. honeybee_radiance/postprocess/annual.py +108 -0
  124. honeybee_radiance/postprocess/annualdaylight.py +425 -0
  125. honeybee_radiance/postprocess/annualglare.py +201 -0
  126. honeybee_radiance/postprocess/annualirradiance.py +187 -0
  127. honeybee_radiance/postprocess/electriclight.py +119 -0
  128. honeybee_radiance/postprocess/en17037.py +261 -0
  129. honeybee_radiance/postprocess/leed.py +304 -0
  130. honeybee_radiance/postprocess/solartracking.py +90 -0
  131. honeybee_radiance/primitive.py +554 -0
  132. honeybee_radiance/properties/__init__.py +1 -0
  133. honeybee_radiance/properties/_base.py +390 -0
  134. honeybee_radiance/properties/aperture.py +197 -0
  135. honeybee_radiance/properties/door.py +198 -0
  136. honeybee_radiance/properties/face.py +123 -0
  137. honeybee_radiance/properties/model.py +1291 -0
  138. honeybee_radiance/properties/room.py +490 -0
  139. honeybee_radiance/properties/shade.py +186 -0
  140. honeybee_radiance/properties/shademesh.py +116 -0
  141. honeybee_radiance/putil.py +44 -0
  142. honeybee_radiance/reader.py +214 -0
  143. honeybee_radiance/sensor.py +166 -0
  144. honeybee_radiance/sensorgrid.py +1008 -0
  145. honeybee_radiance/view.py +1101 -0
  146. honeybee_radiance/writer.py +951 -0
  147. honeybee_radiance-1.66.190.dist-info/METADATA +89 -0
  148. honeybee_radiance-1.66.190.dist-info/RECORD +152 -0
  149. honeybee_radiance-1.66.190.dist-info/WHEEL +5 -0
  150. honeybee_radiance-1.66.190.dist-info/entry_points.txt +2 -0
  151. honeybee_radiance-1.66.190.dist-info/licenses/LICENSE +661 -0
  152. honeybee_radiance-1.66.190.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1091 @@
1
+ """Radiance modifier set."""
2
+ from __future__ import division
3
+
4
+ from honeybee_radiance.modifier import Modifier
5
+ from honeybee_radiance.mutil import dict_to_modifier # imports all modifiers classes
6
+ from honeybee_radiance.lib.modifiers import generic_floor, generic_wall, \
7
+ generic_ceiling, generic_door, generic_exterior_window, generic_interior_window, \
8
+ generic_exterior_shade, generic_interior_shade, air_boundary
9
+
10
+ from honeybee._lockable import lockable
11
+ from honeybee.typing import valid_rad_string
12
+
13
+
14
+ _default_modifiers = {
15
+ '_BaseSet': {'exterior': None, 'interior': None},
16
+ 'WallModifierSet': {
17
+ 'exterior': generic_wall,
18
+ 'interior': generic_wall
19
+ },
20
+ 'FloorModifierSet': {
21
+ 'exterior': generic_floor,
22
+ 'interior': generic_floor
23
+ },
24
+ 'RoofCeilingModifierSet': {
25
+ 'exterior': generic_ceiling,
26
+ 'interior': generic_ceiling
27
+ },
28
+ 'ApertureModifierSet': {
29
+ 'exterior': generic_exterior_window,
30
+ 'interior': generic_interior_window,
31
+ 'operable': generic_exterior_window,
32
+ 'skylight': generic_exterior_window
33
+ },
34
+ 'DoorModifierSet': {
35
+ 'exterior': generic_door,
36
+ 'interior': generic_door,
37
+ 'exterior_glass': generic_exterior_window,
38
+ 'interior_glass': generic_interior_window,
39
+ 'overhead': generic_door
40
+ },
41
+ 'ShadeModifierSet': {
42
+ 'exterior': generic_exterior_shade,
43
+ 'interior': generic_interior_shade
44
+ }
45
+ }
46
+
47
+
48
+ @lockable
49
+ class ModifierSet(object):
50
+ """Set containing all radiance modifiers needed to create a radiance model.
51
+
52
+ ModifierSets can be used to establish templates that are applied broadly
53
+ across a Model, like a color scheme used consistently throughout a building.
54
+
55
+ Args:
56
+ identifier: Text string for a unique ModifierSet ID. Must not contain
57
+ spaces or special characters. This will be used to identify the
58
+ object across a model and in the exported Radiance files.
59
+ wall_set: An optional WallModifierSet object for this ModifierSet.
60
+ If None, it will be the honeybee generic default WallModifierSet.
61
+ floor_set: An optional FloorModifierSet object for this ModifierSet.
62
+ If None, it will be the honeybee generic default FloorModifierSet.
63
+ roof_ceiling_set: An optional RoofCeilingModifierSet object for this ModifierSet.
64
+ If None, it will be the honeybee generic default RoofCeilingModifierSet.
65
+ aperture_set: An optional ApertureModifierSet object for this ModifierSet.
66
+ If None, it will be the honeybee generic default ApertureModifierSet.
67
+ door_set: An optional DoorModifierSet object for this ModifierSet.
68
+ If None, it will be the honeybee generic default DoorModifierSet.
69
+ shade_set: An optional ShadeModifierSet object for this ModifierSet.
70
+ If None, it will be the honeybee generic default ShadeModifierSet.
71
+ air_boundary_modifier: An optional Modifier to be used for all Faces with
72
+ an AirBoundary face type. If None, it will be the honeybee generic
73
+ air wall modifier.
74
+
75
+ Properties:
76
+ * identifier
77
+ * display_name
78
+ * wall_set
79
+ * floor_set
80
+ * roof_ceiling_set
81
+ * aperture_set
82
+ * door_set
83
+ * shade_set
84
+ * air_boundary_modifier
85
+ * modifiers
86
+ * modified_modifiers
87
+ * modifiers_unique
88
+ * modified_modifiers_unique
89
+ """
90
+
91
+ __slots__ = ('_identifier', '_display_name', '_wall_set', '_floor_set',
92
+ '_roof_ceiling_set', '_aperture_set', '_door_set', '_shade_set',
93
+ '_air_boundary_modifier', '_locked')
94
+
95
+ def __init__(self, identifier, wall_set=None, floor_set=None, roof_ceiling_set=None,
96
+ aperture_set=None, door_set=None, shade_set=None,
97
+ air_boundary_modifier=None):
98
+ """Initialize radiance modifier set."""
99
+ self._locked = False # unlocked by default
100
+ self.identifier = identifier
101
+ self._display_name = None
102
+ self.wall_set = wall_set
103
+ self.floor_set = floor_set
104
+ self.roof_ceiling_set = roof_ceiling_set
105
+ self.aperture_set = aperture_set
106
+ self.door_set = door_set
107
+ self.shade_set = shade_set
108
+ self.air_boundary_modifier = air_boundary_modifier
109
+
110
+ @property
111
+ def identifier(self):
112
+ """Get or set a text string for the unique modifier set identifier."""
113
+ return self._identifier
114
+
115
+ @identifier.setter
116
+ def identifier(self, identifier):
117
+ self._identifier = valid_rad_string(identifier, 'ModifierSet identifier')
118
+
119
+ @property
120
+ def display_name(self):
121
+ """Get or set a string for the object name without any character restrictions.
122
+
123
+ If not set, this will be equal to the identifier.
124
+ """
125
+ if self._display_name is None:
126
+ return self._identifier
127
+ return self._display_name
128
+
129
+ @display_name.setter
130
+ def display_name(self, value):
131
+ try:
132
+ self._display_name = str(value)
133
+ except UnicodeEncodeError: # Python 2 machine lacking the character set
134
+ self._display_name = value # keep it as unicode
135
+
136
+ @property
137
+ def wall_set(self):
138
+ """Get or set the WallModifierSet assigned to this ModifierSet."""
139
+ return self._wall_set
140
+
141
+ @wall_set.setter
142
+ def wall_set(self, value):
143
+ if value is not None:
144
+ assert isinstance(value, WallModifierSet), \
145
+ 'Expected WallModifierSet. Got {}'.format(type(value))
146
+ self._wall_set = value
147
+ else:
148
+ self._wall_set = WallModifierSet()
149
+
150
+ @property
151
+ def floor_set(self):
152
+ """Get or set the FloorModifierSet assigned to this ModifierSet."""
153
+ return self._floor_set
154
+
155
+ @floor_set.setter
156
+ def floor_set(self, value):
157
+ if value is not None:
158
+ assert isinstance(value, FloorModifierSet), \
159
+ 'Expected FloorModifierSet. Got {}'.format(type(value))
160
+ self._floor_set = value
161
+ else:
162
+ self._floor_set = FloorModifierSet()
163
+
164
+ @property
165
+ def roof_ceiling_set(self):
166
+ """Get or set the RoofCeilingModifierSet assigned to this ModifierSet."""
167
+ return self._roof_ceiling_set
168
+
169
+ @roof_ceiling_set.setter
170
+ def roof_ceiling_set(self, value):
171
+ if value is not None:
172
+ assert isinstance(value, RoofCeilingModifierSet), \
173
+ 'Expected RoofCeilingModifierSet. Got {}'.format(type(value))
174
+ self._roof_ceiling_set = value
175
+ else:
176
+ self._roof_ceiling_set = RoofCeilingModifierSet()
177
+
178
+ @property
179
+ def aperture_set(self):
180
+ """Get or set the ApertureModifierSet assigned to this ModifierSet."""
181
+ return self._aperture_set
182
+
183
+ @aperture_set.setter
184
+ def aperture_set(self, value):
185
+ if value is not None:
186
+ assert isinstance(value, ApertureModifierSet), \
187
+ 'Expected ApertureModifierSet. Got {}'.format(type(value))
188
+ self._aperture_set = value
189
+ else:
190
+ self._aperture_set = ApertureModifierSet()
191
+
192
+ @property
193
+ def door_set(self):
194
+ """Get or set the DoorModifierSet assigned to this ModifierSet."""
195
+ return self._door_set
196
+
197
+ @door_set.setter
198
+ def door_set(self, value):
199
+ if value is not None:
200
+ assert isinstance(value, DoorModifierSet), \
201
+ 'Expected DoorModifierSet. Got {}'.format(type(value))
202
+ self._door_set = value
203
+ else:
204
+ self._door_set = DoorModifierSet()
205
+
206
+ @property
207
+ def shade_set(self):
208
+ """Get or set the ShadeModifierSet assigned to this ModifierSet."""
209
+ return self._shade_set
210
+
211
+ @shade_set.setter
212
+ def shade_set(self, value):
213
+ if value is not None:
214
+ assert isinstance(value, ShadeModifierSet), \
215
+ 'Expected ShadeModifierSet. Got {}'.format(type(value))
216
+ self._shade_set = value
217
+ else:
218
+ self._shade_set = ShadeModifierSet()
219
+
220
+ @property
221
+ def air_boundary_modifier(self):
222
+ """Get or set a Modifier to be used for all Faces with an AirBoundary face type.
223
+ """
224
+ if self._air_boundary_modifier is None:
225
+ return air_boundary
226
+ return self._air_boundary_modifier
227
+
228
+ @air_boundary_modifier.setter
229
+ def air_boundary_modifier(self, value):
230
+ if value is not None:
231
+ assert isinstance(value, Modifier), \
232
+ 'Expected Modifier. Got {}'.format(type(value))
233
+ value.lock() # lock editing in case modifier has multiple references
234
+ self._air_boundary_modifier = value
235
+
236
+ @property
237
+ def modifiers(self):
238
+ """List of all modifiers contained within the set."""
239
+ return self.wall_set.modifiers + \
240
+ self.floor_set.modifiers + \
241
+ self.roof_ceiling_set.modifiers + \
242
+ self.aperture_set.modifiers + \
243
+ self.door_set.modifiers + \
244
+ self.shade_set.modifiers + \
245
+ [self.air_boundary_modifier]
246
+
247
+ @property
248
+ def modified_modifiers(self):
249
+ """List of all modifiers that are not defaulted within the set."""
250
+ modified_modifiers = self.wall_set.modified_modifiers + \
251
+ self.floor_set.modified_modifiers + \
252
+ self.roof_ceiling_set.modified_modifiers + \
253
+ self.aperture_set.modified_modifiers + \
254
+ self.door_set.modified_modifiers + \
255
+ self.shade_set.modified_modifiers
256
+ if self._air_boundary_modifier is not None:
257
+ modified_modifiers.append(self._air_boundary_modifier)
258
+ return modified_modifiers
259
+
260
+ @property
261
+ def modifiers_unique(self):
262
+ """List of all unique modifiers contained within the set."""
263
+ return list(set(self.modifiers))
264
+
265
+ @property
266
+ def modified_modifiers_unique(self):
267
+ """List of all unique modifiers that are not defaulted within the set."""
268
+ return list(set(self.modified_modifiers))
269
+
270
+ def get_face_modifier(self, face_type, boundary_condition):
271
+ """Get a modifier object that will be assigned to a given type of face.
272
+
273
+ Args:
274
+ face_type: Text string for the type of face (eg. 'Wall', 'Floor',
275
+ 'Roof', 'AirBoundary').
276
+ boundary_condition: Text string for the boundary condition
277
+ (eg. 'Outdoors', 'Surface', 'Ground')
278
+ """
279
+ if face_type == 'Wall':
280
+ return self._get_modifier_from_set(self.wall_set, boundary_condition)
281
+ elif face_type == 'Floor':
282
+ return self._get_modifier_from_set(self.floor_set, boundary_condition)
283
+ elif face_type == 'RoofCeiling':
284
+ return self._get_modifier_from_set(self.roof_ceiling_set, boundary_condition)
285
+ elif face_type == 'AirBoundary':
286
+ return self.air_boundary_modifier
287
+ else:
288
+ raise NotImplementedError(
289
+ 'Face type {} is not recognized for ModifierSet'.format(face_type))
290
+
291
+ def get_aperture_modifier(self, boundary_condition, is_operable, parent_face_type):
292
+ """Get a modifier object that will be assigned to a given type of aperture.
293
+
294
+ Args:
295
+ boundary_condition: Text string for the boundary condition
296
+ (eg. 'Outdoors', 'Surface')
297
+ is_operable: Boolean to note whether the aperture is operable.
298
+ parent_face_type: Text string for the type of face to which the aperture
299
+ is a child (eg. 'Wall', 'Floor', 'Roof').
300
+ """
301
+ if boundary_condition == 'Outdoors':
302
+ if not is_operable:
303
+ if parent_face_type == 'Wall':
304
+ return self.aperture_set.window_modifier
305
+ else:
306
+ return self.aperture_set.skylight_modifier
307
+ else:
308
+ return self.aperture_set.operable_modifier
309
+ elif boundary_condition == 'Surface':
310
+ return self.aperture_set.interior_modifier
311
+ else:
312
+ raise NotImplementedError(
313
+ 'Boundary condition {} is not recognized for apertures in '
314
+ 'ModifierSet'.format(boundary_condition))
315
+
316
+ def get_door_modifier(self, boundary_condition, is_glass, parent_face_type):
317
+ """Get a modifier object that will be assigned to a given type of door.
318
+
319
+ Args:
320
+ boundary_condition: Text string for the boundary condition
321
+ (eg. 'Outdoors', 'Surface').
322
+ is_glass: Boolean to note whether the door is glass (instead of opaque).
323
+ parent_face_type: Text string for the type of face to which the door
324
+ is a child (eg. 'Wall', 'Floor', 'Roof').
325
+ """
326
+ if boundary_condition == 'Outdoors':
327
+ if not is_glass:
328
+ if parent_face_type == 'Wall':
329
+ return self.door_set.exterior_modifier
330
+ else:
331
+ return self.door_set.overhead_modifier
332
+ else:
333
+ return self.door_set.exterior_glass_modifier
334
+ elif boundary_condition == 'Surface':
335
+ if not is_glass:
336
+ return self.door_set.interior_modifier
337
+ else:
338
+ return self.door_set.interior_glass_modifier
339
+ else:
340
+ raise NotImplementedError(
341
+ 'Boundary condition {} is not recognized for doors in '
342
+ 'ModifierSet'.format(boundary_condition)
343
+ )
344
+
345
+ def get_shade_modifier(self, is_indoor=False):
346
+ """Get a modifier object that will be assigned to a shade.
347
+
348
+ Args:
349
+ is_indoor: A boolean to indicate if the shade is on the indoors or
350
+ the outdoors of its parent. Default: False.
351
+ """
352
+ if is_indoor:
353
+ return self.shade_set.interior_modifier
354
+ else:
355
+ return self.shade_set.exterior_modifier
356
+
357
+ @classmethod
358
+ def from_dict(cls, data):
359
+ """Create a ModifierSet from a dictionary.
360
+
361
+ Note that the dictionary must be a non-abridged version for this
362
+ classmethod to work.
363
+
364
+ Args:
365
+ data: Dictionary describing the ModifierSet in the following format.
366
+
367
+ .. code-block:: python
368
+
369
+ {
370
+ 'type': 'ModifierSet',
371
+ 'identifier': str, # ModifierSet identifier
372
+ "display_name": str, # ModifierSet display name
373
+ 'wall_set': {}, # WallModifierSet dictionary
374
+ 'floor_set': {}, # FloorSet dictionary
375
+ 'roof_ceiling_set': {}, # RoofCeilingModifierSet dictionary
376
+ 'aperture_set': {}, # ApertureModifierSet dictionary
377
+ 'door_set': {}, # DoorModifierSet dictionary
378
+ 'shade_set': {}, # ShadeModifierSet dictionary
379
+ 'air_boundary_modifier': {}, # AirBoundary dictionary
380
+ }
381
+ """
382
+ assert data['type'] == 'ModifierSet', \
383
+ 'Expected ModifierSet. Got {}.'.format(data['type'])
384
+
385
+ # build each of the sub-modifier sets
386
+ wall_set = WallModifierSet.from_dict(data['wall_set']) if 'wall_set' \
387
+ in data and data['wall_set'] is not None else None
388
+ floor_set = FloorModifierSet.from_dict(data['floor_set']) if 'floor_set' \
389
+ in data and data['floor_set'] is not None else None
390
+ roof_ceiling_set = RoofCeilingModifierSet.from_dict(data['roof_ceiling_set']) \
391
+ if 'roof_ceiling_set' in data and \
392
+ data['roof_ceiling_set'] is not None else None
393
+ aperture_set = ApertureModifierSet.from_dict(data['aperture_set']) if \
394
+ 'aperture_set' in data and data['aperture_set'] is not None else None
395
+ door_set = DoorModifierSet.from_dict(data['door_set']) if \
396
+ 'door_set' in data and data['door_set'] is not None else None
397
+ shade_set = ShadeModifierSet.from_dict(data['shade_set']) if \
398
+ 'shade_set' in data and data['shade_set'] is not None else None
399
+ air_mod = dict_to_modifier(data['air_boundary_modifier']) \
400
+ if 'air_boundary_modifier' in data and \
401
+ data['air_boundary_modifier'] is not None else None
402
+
403
+ new_obj = cls(data['identifier'], wall_set, floor_set, roof_ceiling_set,
404
+ aperture_set, door_set, shade_set, air_mod)
405
+ if 'display_name' in data and data['display_name'] is not None:
406
+ new_obj.display_name = data['display_name']
407
+ return new_obj
408
+
409
+ @classmethod
410
+ def from_dict_abridged(cls, data, modifier_dict):
411
+ """Create a ModifierSet from an abridged dictionary.
412
+
413
+ Args:
414
+ data: A ModifierSetAbridged dictionary with the format below.
415
+ modifier_dict: A dictionary with modifier identifiers as keys and
416
+ honeybee modifier objects as values. These will be used to
417
+ assign the 4 to the ModifierSet object.
418
+
419
+ .. code-block:: python
420
+
421
+ {
422
+ 'type': 'ModifierSetAbridged',
423
+ 'identifier': str, # ModifierSet identifier
424
+ "display_name": str, # ModifierSet display name
425
+ 'wall_set': {}, # WallModifierSetAbridged dictionary
426
+ 'floor_set': {}, # FloorSetAbridged dictionary
427
+ 'roof_ceiling_set': {}, # RoofCeilingModifierSetAbridged dictionary
428
+ 'aperture_set': {}, # ApertureModifierSetAbridged dictionary
429
+ 'door_set': {}, # DoorModifierSetAbridged dictionary
430
+ 'shade_set': {}, # ShadeModifierSetAbridged dictionary
431
+ 'air_boundary_modifier': {}, # AirBoundary dictionary
432
+ }
433
+ """
434
+ assert data['type'] == 'ModifierSetAbridged', \
435
+ 'Expected ModifierSetAbridged. Got {}.'.format(data['type'])
436
+ wall_set, floor_set, roof_ceiling_set, aperture_set, door_set, shade_set, \
437
+ air_boundary_mod = cls._get_subsets_from_abridged(data, modifier_dict)
438
+ new_obj = cls(data['identifier'], wall_set, floor_set, roof_ceiling_set,
439
+ aperture_set, door_set, shade_set, air_boundary_mod)
440
+ if 'display_name' in data and data['display_name'] is not None:
441
+ new_obj.display_name = data['display_name']
442
+ return new_obj
443
+
444
+ def to_dict(self, abridged=False, none_for_defaults=True):
445
+ """Get ModifierSet as a dictionary.
446
+
447
+ Args:
448
+ abridged: Boolean noting whether detailed modifier objects should be
449
+ written into the ModifierSet (False) or just an abridged
450
+ version (True). Default: False.
451
+ none_for_defaults: Boolean to note whether default modifiers in the
452
+ set should be included in detail (False) or should be None (True).
453
+ Default: True.
454
+ """
455
+ base = {'type': 'ModifierSet'} if not abridged \
456
+ else {'type': 'ModifierSetAbridged'}
457
+
458
+ base['identifier'] = self.identifier
459
+ base['wall_set'] = self.wall_set.to_dict(abridged, none_for_defaults)
460
+ base['floor_set'] = self.floor_set.to_dict(abridged, none_for_defaults)
461
+ base['roof_ceiling_set'] = \
462
+ self.roof_ceiling_set.to_dict(abridged, none_for_defaults)
463
+ base['aperture_set'] = self.aperture_set.to_dict(abridged, none_for_defaults)
464
+ base['door_set'] = self.door_set.to_dict(abridged, none_for_defaults)
465
+ base['shade_set'] = self.shade_set.to_dict(abridged, none_for_defaults)
466
+ if none_for_defaults:
467
+ if abridged:
468
+ base['air_boundary_modifier'] = self._air_boundary_modifier.identifier \
469
+ if self._air_boundary_modifier is not None else None
470
+ else:
471
+ base['air_boundary_modifier'] = self._air_boundary_modifier.to_dict() \
472
+ if self._air_boundary_modifier is not None else None
473
+ else:
474
+ base['air_boundary_modifier'] = self.air_boundary_modifier.identifier \
475
+ if abridged else self.air_boundary_modifier.to_dict()
476
+
477
+ if self._display_name is not None:
478
+ base['display_name'] = self.display_name
479
+ return base
480
+
481
+ def duplicate(self):
482
+ """Get a copy of this ModifierSet."""
483
+ return self.__copy__()
484
+
485
+ def lock(self):
486
+ """The lock() method to will also lock the WallModifierSet, etc."""
487
+ self._locked = True
488
+ self._wall_set.lock()
489
+ self._floor_set.lock()
490
+ self._roof_ceiling_set.lock()
491
+ self._aperture_set.lock()
492
+ self._door_set.lock()
493
+ self._shade_set.lock()
494
+
495
+ def unlock(self):
496
+ """The unlock() method will also unlock the WallModifierSet, etc."""
497
+ self._locked = False
498
+ self._wall_set.unlock()
499
+ self._floor_set.unlock()
500
+ self._roof_ceiling_set.unlock()
501
+ self._aperture_set.unlock()
502
+ self._door_set.unlock()
503
+ self._shade_set.unlock()
504
+
505
+ def _get_modifier_from_set(self, face_type_set, boundary_condition):
506
+ """Get a specific modifier from a face_type_set."""
507
+ if boundary_condition == 'Outdoors':
508
+ return face_type_set.exterior_modifier
509
+ else:
510
+ return face_type_set.interior_modifier
511
+
512
+ @staticmethod
513
+ def _get_subsets_from_abridged(data, modifiers):
514
+ """Get subset objects from and abridged dictionary."""
515
+ wall_set = ModifierSet._make_modifier_subset(
516
+ data, WallModifierSet(), 'wall_set', modifiers)
517
+ floor_set = ModifierSet._make_modifier_subset(
518
+ data, FloorModifierSet(), 'floor_set', modifiers)
519
+ roof_ceiling_set = ModifierSet._make_modifier_subset(
520
+ data, RoofCeilingModifierSet(), 'roof_ceiling_set', modifiers)
521
+ shade_set = ModifierSet._make_modifier_subset(
522
+ data, ShadeModifierSet(), 'shade_set', modifiers)
523
+ aperture_set = ModifierSet._make_aperture_subset(
524
+ data, ApertureModifierSet(), modifiers)
525
+ door_set = ModifierSet._make_door_subset(data, DoorModifierSet(), modifiers)
526
+ if 'air_boundary_modifier' in data and data['air_boundary_modifier'] is not None:
527
+ air_boundary_mod = modifiers[data['air_boundary_modifier']]
528
+ else:
529
+ air_boundary_mod = None
530
+
531
+ return wall_set, floor_set, roof_ceiling_set, aperture_set, door_set, \
532
+ shade_set, air_boundary_mod
533
+
534
+ @staticmethod
535
+ def _make_modifier_subset(data, sub_set, sub_set_name, modifiers):
536
+ """Make a wall set, floor set, roof ceiling set, or shade set from dictionary."""
537
+ if sub_set_name in data:
538
+ if 'exterior_modifier' in data[sub_set_name] and \
539
+ data[sub_set_name]['exterior_modifier'] is not None:
540
+ sub_set.exterior_modifier = \
541
+ modifiers[data[sub_set_name]['exterior_modifier']]
542
+ if 'interior_modifier' in data[sub_set_name] and \
543
+ data[sub_set_name]['interior_modifier'] is not None:
544
+ sub_set.interior_modifier = \
545
+ modifiers[data[sub_set_name]['interior_modifier']]
546
+ return sub_set
547
+
548
+ @staticmethod
549
+ def _make_aperture_subset(data, sub_set, modifiers):
550
+ """Make an ApertureModifierSet from a dictionary."""
551
+ if 'aperture_set' in data:
552
+ if 'window_modifier' in data['aperture_set'] and \
553
+ data['aperture_set']['window_modifier'] is not None:
554
+ sub_set.window_modifier = \
555
+ modifiers[data['aperture_set']['window_modifier']]
556
+ if 'interior_modifier' in data['aperture_set'] and \
557
+ data['aperture_set']['interior_modifier'] is not None:
558
+ sub_set.interior_modifier = \
559
+ modifiers[data['aperture_set']['interior_modifier']]
560
+ if 'skylight_modifier' in data['aperture_set'] and \
561
+ data['aperture_set']['skylight_modifier'] is not None:
562
+ sub_set.skylight_modifier = \
563
+ modifiers[data['aperture_set']['skylight_modifier']]
564
+ if 'operable_modifier' in data['aperture_set'] and \
565
+ data['aperture_set']['operable_modifier'] is not None:
566
+ sub_set.operable_modifier = \
567
+ modifiers[data['aperture_set']['operable_modifier']]
568
+ return sub_set
569
+
570
+ @staticmethod
571
+ def _make_door_subset(data, sub_set, modifiers):
572
+ """Make a DoorModifierSet from dictionary."""
573
+ if 'door_set' in data:
574
+ if 'exterior_modifier' in data['door_set'] and \
575
+ data['door_set']['exterior_modifier'] is not None:
576
+ sub_set.exterior_modifier = \
577
+ modifiers[data['door_set']['exterior_modifier']]
578
+ if 'interior_modifier' in data['door_set'] and \
579
+ data['door_set']['interior_modifier'] is not None:
580
+ sub_set.interior_modifier = \
581
+ modifiers[data['door_set']['interior_modifier']]
582
+ if 'exterior_glass_modifier' in data['door_set'] and \
583
+ data['door_set']['exterior_glass_modifier'] is not None:
584
+ sub_set.exterior_glass_modifier = \
585
+ modifiers[data['door_set']['exterior_glass_modifier']]
586
+ if 'interior_glass_modifier' in data['door_set'] and \
587
+ data['door_set']['interior_glass_modifier'] is not None:
588
+ sub_set.interior_glass_modifier = \
589
+ modifiers[data['door_set']['interior_glass_modifier']]
590
+ if 'overhead_modifier' in data['door_set'] and \
591
+ data['door_set']['overhead_modifier'] is not None:
592
+ sub_set.overhead_modifier = \
593
+ modifiers[data['door_set']['overhead_modifier']]
594
+ return sub_set
595
+
596
+ def ToString(self):
597
+ """Overwrite .NET ToString."""
598
+ return self.__repr__()
599
+
600
+ def __copy__(self):
601
+ new_obj = ModifierSet(
602
+ self.identifier,
603
+ self.wall_set.duplicate(),
604
+ self.floor_set.duplicate(),
605
+ self.roof_ceiling_set.duplicate(),
606
+ self.aperture_set.duplicate(),
607
+ self.door_set.duplicate(),
608
+ self.shade_set.duplicate(),
609
+ self._air_boundary_modifier
610
+ )
611
+ new_obj._display_name = self._display_name
612
+ return new_obj
613
+
614
+ def __key(self):
615
+ """A tuple based on the object properties, useful for hashing."""
616
+ return (self.identifier,) + tuple(hash(mod) for mod in self.modifiers)
617
+
618
+ def __hash__(self):
619
+ return hash(self.__key())
620
+
621
+ def __eq__(self, other):
622
+ return isinstance(other, ModifierSet) and self.__key() == other.__key()
623
+
624
+ def __ne__(self, other):
625
+ return not self.__eq__(other)
626
+
627
+ def __repr__(self):
628
+ return 'Radiance Modifier Set: {}'.format(self.display_name)
629
+
630
+
631
+ @lockable
632
+ class _BaseSet(object):
633
+ """Base class for the sets assigned to Faces.
634
+
635
+ This includes WallModifierSet, FloorModifierSet, RoofCeilingModifierSet and
636
+ ShadeModifierSet.
637
+
638
+ Args:
639
+ exterior_modifier: A radiance modifier object for faces with an
640
+ Outdoors boundary condition.
641
+ interior_modifier: A radiance modifier object for faces with a boundary
642
+ condition other than Outdoors.
643
+ """
644
+
645
+ __slots__ = ('_exterior_modifier', '_interior_modifier', '_locked')
646
+
647
+ def __init__(self, exterior_modifier=None, interior_modifier=None):
648
+ """Initialize set."""
649
+ self._locked = False # unlocked by default
650
+ self.exterior_modifier = exterior_modifier
651
+ self.interior_modifier = interior_modifier
652
+
653
+ @property
654
+ def exterior_modifier(self):
655
+ """Get or set the modifier for exterior objects."""
656
+ if self._exterior_modifier is None:
657
+ return _default_modifiers[self.__class__.__name__]['exterior']
658
+ return self._exterior_modifier
659
+
660
+ @exterior_modifier.setter
661
+ def exterior_modifier(self, value):
662
+ self._exterior_modifier = self._validate_modifier(value)
663
+
664
+ @property
665
+ def interior_modifier(self):
666
+ """Get or set the modifier for interior objects."""
667
+ if self._interior_modifier is None:
668
+ return _default_modifiers[self.__class__.__name__]['interior']
669
+ return self._interior_modifier
670
+
671
+ @interior_modifier.setter
672
+ def interior_modifier(self, value):
673
+ self._interior_modifier = self._validate_modifier(value)
674
+
675
+ @property
676
+ def modifiers(self):
677
+ """List of all modifiers contained within the set."""
678
+ return [getattr(self, attr[1:]) for attr in self._slots]
679
+
680
+ @property
681
+ def modified_modifiers(self):
682
+ """List of all modifiers that are not defaulted within the set."""
683
+ _modifiers = [getattr(self, attr) for attr in self._slots]
684
+ modifiers = [
685
+ modifier for modifier in _modifiers
686
+ if modifier is not None
687
+ ]
688
+ return modifiers
689
+
690
+ @property
691
+ def is_modified(self):
692
+ """Boolean noting whether any modifiers are modified from the default."""
693
+ return len(self.modified_modifiers) != 0
694
+
695
+ @classmethod
696
+ def from_dict(cls, data):
697
+ """Create a SubSet from a dictionary.
698
+
699
+ Note that the dictionary must be a non-abridged version for this
700
+ classmethod to work.
701
+
702
+ Args:
703
+ data: Dictionary describing the Set of the object.
704
+ """
705
+ assert data['type'] == cls.__name__, \
706
+ 'Expected {}. Got {}.'.format(cls.__name__, data['type'])
707
+ extc = dict_to_modifier(data['exterior_modifier']) \
708
+ if 'exterior_modifier' in data and data['exterior_modifier'] \
709
+ is not None else None
710
+ intc = dict_to_modifier(data['interior_modifier']) \
711
+ if 'interior_modifier' in data and data['interior_modifier'] \
712
+ is not None else None
713
+ return cls(extc, intc)
714
+
715
+ def to_dict(self, abridged=False, none_for_defaults=True):
716
+ """Get the ModifierSet as a dictionary.
717
+
718
+ Args:
719
+ abridged: Boolean noting whether detailed modifiers objects should
720
+ be written into the ModifierSet (False) or just an abridged
721
+ version (True). Default: False.
722
+ none_for_defaults: Boolean to note whether default modifiers in the
723
+ set should be included in detail (False) or should be None (True).
724
+ Default: True.
725
+ """
726
+ attributes = self._slots
727
+ if none_for_defaults:
728
+ if abridged:
729
+ base = {attr[1:]: getattr(self, attr[1:]).identifier
730
+ if getattr(self, attr) is not None else None
731
+ for attr in attributes}
732
+ else:
733
+ base = {attr[1:]: getattr(self, attr[1:]).to_dict()
734
+ if getattr(self, attr) is not None else None
735
+ for attr in attributes}
736
+ else:
737
+ if abridged:
738
+ base = {attr[1:]: getattr(self, attr[1:]).identifier
739
+ for attr in attributes}
740
+ else:
741
+ base = {attr[1:]: getattr(self, attr[1:]).to_dict()
742
+ for attr in attributes}
743
+
744
+ base['type'] = self.__class__.__name__ + 'Abridged' if abridged else \
745
+ self.__class__.__name__
746
+ return base
747
+
748
+ def duplicate(self):
749
+ """Get a copy of this set."""
750
+ return self.__copy__()
751
+
752
+ def _validate_modifier(self, value):
753
+ """Check a modifier before assigning it."""
754
+ if value is not None:
755
+ assert isinstance(value, Modifier), \
756
+ 'Expected modifier. Got {}'.format(type(value))
757
+ value.lock() # lock editing in case modifier has multiple references
758
+ return value
759
+
760
+ @property
761
+ def _slots(self):
762
+ """Return slots including the ones from the baseclass if any."""
763
+ slots = set(self.__slots__)
764
+ for cls in self.__class__.__mro__[:-1]:
765
+ for s in getattr(cls, '__slots__', tuple()):
766
+ if s in slots:
767
+ continue
768
+ slots.add(s)
769
+ slots.remove('_locked')
770
+ return slots
771
+
772
+ def ToString(self):
773
+ """Overwrite .NET ToString."""
774
+ return self.__repr__()
775
+
776
+ def __len__(self):
777
+ return 2
778
+
779
+ def __iter__(self):
780
+ return iter(self.modifiers)
781
+
782
+ def __copy__(self):
783
+ return self.__class__(self._exterior_modifier, self._interior_modifier)
784
+
785
+ def __repr__(self):
786
+ name = self.__class__.__name__.split('Set')[0]
787
+ return '{} Modifier Set: [Exterior: {}] [Interior: {}]'.format(
788
+ name, self.exterior_modifier.display_name,
789
+ self.interior_modifier.display_name)
790
+
791
+
792
+ @lockable
793
+ class WallModifierSet(_BaseSet):
794
+ """Set containing all radiance modifiers needed to for an radiance model's Walls.
795
+
796
+ Properties:
797
+ * exterior_modifier
798
+ * interior_modifier
799
+ * modifiers
800
+ * modified_modifiers
801
+ * is_modified
802
+ """
803
+ __slots__ = ()
804
+
805
+
806
+ @lockable
807
+ class FloorModifierSet(_BaseSet):
808
+ """Set containing all radiance modifiers needed to for an radiance model's floors.
809
+
810
+ Properties:
811
+ * exterior_modifier
812
+ * interior_modifier
813
+ * modifiers
814
+ * modified_modifiers
815
+ * is_modified
816
+ """
817
+ __slots__ = ()
818
+
819
+
820
+ @lockable
821
+ class RoofCeilingModifierSet(_BaseSet):
822
+ """Set containing all radiance modifiers needed to for an radiance model's roofs.
823
+
824
+ Properties:
825
+ * exterior_modifier
826
+ * interior_modifier
827
+ * modifiers
828
+ * modified_modifiers
829
+ * is_modified
830
+ """
831
+ __slots__ = ()
832
+
833
+
834
+ @lockable
835
+ class ShadeModifierSet(_BaseSet):
836
+ """Set containing all radiance modifiers needed to for an radiance model's Shade.
837
+
838
+ Properties:
839
+ * exterior_modifier
840
+ * interior_modifier
841
+ * modifiers
842
+ * modified_modifiers
843
+ * is_modified
844
+ """
845
+ __slots__ = ()
846
+
847
+
848
+ @lockable
849
+ class ApertureModifierSet(_BaseSet):
850
+ """Set containing all radiance modifiers needed to for a radiance model's Apertures.
851
+
852
+ Args:
853
+ window_modifier: A modifier object for apertures with an Outdoors
854
+ boundary condition, False is_operable property, and Wall parent Face.
855
+ interior_modifier: A modifier object for apertures with a Surface
856
+ boundary condition.
857
+ skylight_modifier: : A modifier object for apertures with an Outdoors
858
+ boundary condition, False is_operable property, and a RoofCeiling
859
+ or Floor face type for their parent face.
860
+ operable_modifier: A modifier object for apertures with an Outdoors
861
+ boundary condition and a True is_operable property.
862
+
863
+ Properties:
864
+ * window_modifier
865
+ * interior_modifier
866
+ * skylight_modifier
867
+ * operable_modifier
868
+ * modifiers
869
+ * modified_modifiers
870
+ * is_modified
871
+ """
872
+ __slots__ = ('_skylight_modifier', '_operable_modifier')
873
+
874
+ def __init__(self, window_modifier=None, interior_modifier=None,
875
+ skylight_modifier=None, operable_modifier=None):
876
+ """Initialize aperture set."""
877
+ _BaseSet.__init__(self, window_modifier, interior_modifier)
878
+ self.skylight_modifier = skylight_modifier
879
+ self.operable_modifier = operable_modifier
880
+
881
+ @property
882
+ def window_modifier(self):
883
+ """Get or set the modifier for exterior fixed apertures in walls."""
884
+ if self._exterior_modifier is None:
885
+ return _default_modifiers[self.__class__.__name__]['exterior']
886
+ return self._exterior_modifier
887
+
888
+ @window_modifier.setter
889
+ def window_modifier(self, value):
890
+ self._exterior_modifier = self._validate_modifier(value)
891
+
892
+ @property
893
+ def skylight_modifier(self):
894
+ """Get or set the modifier for apertures in roofs."""
895
+ if self._skylight_modifier is None:
896
+ return _default_modifiers[self.__class__.__name__]['skylight']
897
+ return self._skylight_modifier
898
+
899
+ @skylight_modifier.setter
900
+ def skylight_modifier(self, value):
901
+ self._skylight_modifier = self._validate_modifier(value)
902
+
903
+ @property
904
+ def operable_modifier(self):
905
+ """Get or set the modifier for operable apertures."""
906
+ if self._operable_modifier is None:
907
+ return _default_modifiers[self.__class__.__name__]['operable']
908
+ return self._operable_modifier
909
+
910
+ @operable_modifier.setter
911
+ def operable_modifier(self, value):
912
+ self._operable_modifier = self._validate_modifier(value)
913
+
914
+ @classmethod
915
+ def from_dict(cls, data):
916
+ """Create a ApertureModifierSet from a dictionary.
917
+
918
+ Note that the dictionary must be a non-abridged version for this
919
+ classmethod to work.
920
+
921
+ Args:
922
+ data: Dictionary describing the ApertureModifierSet.
923
+ """
924
+ assert data['type'] == cls.__name__, \
925
+ 'Expected {}. Got {}.'.format(cls.__name__, data['type'])
926
+ extc = dict_to_modifier(data['window_modifier']) \
927
+ if 'window_modifier' in data and data['window_modifier'] \
928
+ is not None else None
929
+ intc = dict_to_modifier(data['interior_modifier']) \
930
+ if 'interior_modifier' in data and data['interior_modifier'] \
931
+ is not None else None
932
+ skyc = dict_to_modifier(data['skylight_modifier']) \
933
+ if 'skylight_modifier' in data and data['skylight_modifier'] \
934
+ is not None else None
935
+ opc = dict_to_modifier(data['operable_modifier']) \
936
+ if 'operable_modifier' in data and data['operable_modifier'] \
937
+ is not None else None
938
+ return cls(extc, intc, skyc, opc)
939
+
940
+ def to_dict(self, abridged=False, none_for_defaults=True):
941
+ """Get the ModifierSet as a dictionary.
942
+
943
+ Args:
944
+ abridged: Boolean noting whether detailed modifier objects should
945
+ be written into the ModifierSet (False) or just an abridged
946
+ version (True). Default: False.
947
+ none_for_defaults: Boolean to note whether default modifiers in the
948
+ set should be included in detail (False) or should be None (True).
949
+ Default: True.
950
+ """
951
+ base = _BaseSet.to_dict(self, abridged, none_for_defaults)
952
+ if 'exterior_modifier' in base:
953
+ base['window_modifier'] = base['exterior_modifier']
954
+ del base['exterior_modifier']
955
+ return base
956
+
957
+ def __len__(self):
958
+ return 4
959
+
960
+ def __copy__(self):
961
+ return self.__class__(
962
+ self._exterior_modifier,
963
+ self._interior_modifier,
964
+ self._skylight_modifier,
965
+ self._operable_modifier
966
+ )
967
+
968
+ def __repr__(self):
969
+ return 'Aperture Modifier Set: [Exterior: {}] [Interior: {}]' \
970
+ ' [Skylight: {}] [Operable: {}]'.format(
971
+ self.window_modifier.display_name,
972
+ self.interior_modifier.display_name,
973
+ self.skylight_modifier.display_name,
974
+ self.operable_modifier.display_name)
975
+
976
+
977
+ @lockable
978
+ class DoorModifierSet(_BaseSet):
979
+ """Set containing all radiance modifiers needed to for an radiance model's Doors.
980
+
981
+ Args:
982
+ exterior_modifier: A modifier object for doors in walls with an Outdoors
983
+ boundary condition.
984
+ interior_modifier: A modifier object for doors with a Surface (or other)
985
+ boundary condition.
986
+ exterior_glass_modifier: A modifier object for all glass doors with an
987
+ Outdoors boundary condition.
988
+ interior_glass_modifier: A modifier object for all glass doors with a
989
+ Surface boundary condition.
990
+ overhead_modifier: : A modifier object for doors with an Outdoors boundary
991
+ condition and a RoofCeiling or Floor face type for their parent face.
992
+
993
+ Properties:
994
+ * exterior_modifier
995
+ * interior_modifier
996
+ * exterior_glass_modifier
997
+ * interior_glass_modifier
998
+ * overhead_modifier
999
+ * modifiers
1000
+ * modified_modifiers
1001
+ * is_modified
1002
+ """
1003
+ __slots__ = ('_overhead_modifier', '_exterior_glass_modifier',
1004
+ '_interior_glass_modifier')
1005
+
1006
+ def __init__(self, exterior_modifier=None, interior_modifier=None,
1007
+ exterior_glass_modifier=None, interior_glass_modifier=None,
1008
+ overhead_modifier=None):
1009
+ """Initialize door set."""
1010
+ _BaseSet.__init__(self, exterior_modifier, interior_modifier)
1011
+ self.exterior_glass_modifier = exterior_glass_modifier
1012
+ self.interior_glass_modifier = interior_glass_modifier
1013
+ self.overhead_modifier = overhead_modifier
1014
+
1015
+ @property
1016
+ def exterior_glass_modifier(self):
1017
+ """Get or set the modifier for exterior glass doors."""
1018
+ if self._exterior_glass_modifier is None:
1019
+ return _default_modifiers[self.__class__.__name__]['exterior_glass']
1020
+ return self._exterior_glass_modifier
1021
+
1022
+ @exterior_glass_modifier.setter
1023
+ def exterior_glass_modifier(self, value):
1024
+ self._exterior_glass_modifier = self._validate_modifier(value)
1025
+
1026
+ @property
1027
+ def interior_glass_modifier(self):
1028
+ """Get or set the modifier for interior glass doors."""
1029
+ if self._interior_glass_modifier is None:
1030
+ return _default_modifiers[self.__class__.__name__]['interior_glass']
1031
+ return self._interior_glass_modifier
1032
+
1033
+ @interior_glass_modifier.setter
1034
+ def interior_glass_modifier(self, value):
1035
+ self._interior_glass_modifier = self._validate_modifier(value)
1036
+
1037
+ @property
1038
+ def overhead_modifier(self):
1039
+ """Get or set the modifier for skylights."""
1040
+ if self._overhead_modifier is None:
1041
+ return _default_modifiers[self.__class__.__name__]['overhead']
1042
+ return self._overhead_modifier
1043
+
1044
+ @overhead_modifier.setter
1045
+ def overhead_modifier(self, value):
1046
+ self._overhead_modifier = self._validate_modifier(value)
1047
+
1048
+ @classmethod
1049
+ def from_dict(cls, data):
1050
+ """Create a ApertureModifierSet from a dictionary.
1051
+
1052
+ Note that the dictionary must be a non-abridged version for this
1053
+ classmethod to work.
1054
+
1055
+ Args:
1056
+ data: Dictionary describing the ApertureModifierSet.
1057
+ """
1058
+ assert data['type'] == cls.__name__, \
1059
+ 'Expected {}. Got {}.'.format(cls.__name__, data['type'])
1060
+ extc = dict_to_modifier(data['exterior_modifier']) \
1061
+ if 'exterior_modifier' in data and data['exterior_modifier'] \
1062
+ is not None else None
1063
+ intc = dict_to_modifier(data['interior_modifier']) \
1064
+ if 'interior_modifier' in data and data['interior_modifier'] \
1065
+ is not None else None
1066
+ egc = dict_to_modifier(data['exterior_glass_modifier']) \
1067
+ if 'exterior_glass_modifier' in data and data['exterior_glass_modifier'] \
1068
+ is not None else None
1069
+ igc = dict_to_modifier(data['interior_glass_modifier']) \
1070
+ if 'interior_glass_modifier' in data and data['interior_glass_modifier'] \
1071
+ is not None else None
1072
+ ohc = dict_to_modifier(data['overhead_modifier']) \
1073
+ if 'overhead_modifier' in data and data['overhead_modifier'] \
1074
+ is not None else None
1075
+ return cls(extc, intc, egc, igc, ohc)
1076
+
1077
+ def __len__(self):
1078
+ return 3
1079
+
1080
+ def __copy__(self):
1081
+ return self.__class__(
1082
+ self._exterior_modifier,
1083
+ self._interior_modifier,
1084
+ self._exterior_glass_modifier,
1085
+ self._interior_glass_modifier,
1086
+ self._overhead_modifier
1087
+ )
1088
+
1089
+ def __repr__(self):
1090
+ return 'Door Modifier Set: [Exterior: {}] [Interior: {}]'.format(
1091
+ self.exterior_modifier.display_name, self.interior_modifier.display_name)