dragonfly-radiance 0.4.121__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 dragonfly-radiance might be problematic. Click here for more details.
- dragonfly_radiance/__init__.py +9 -0
- dragonfly_radiance/__main__.py +4 -0
- dragonfly_radiance/_extend_dragonfly.py +56 -0
- dragonfly_radiance/cli/__init__.py +18 -0
- dragonfly_radiance/cli/translate.py +394 -0
- dragonfly_radiance/gridpar.py +653 -0
- dragonfly_radiance/properties/__init__.py +1 -0
- dragonfly_radiance/properties/building.py +163 -0
- dragonfly_radiance/properties/context.py +139 -0
- dragonfly_radiance/properties/model.py +443 -0
- dragonfly_radiance/properties/room2d.py +230 -0
- dragonfly_radiance/properties/story.py +122 -0
- dragonfly_radiance-0.4.121.dist-info/METADATA +85 -0
- dragonfly_radiance-0.4.121.dist-info/RECORD +18 -0
- dragonfly_radiance-0.4.121.dist-info/WHEEL +5 -0
- dragonfly_radiance-0.4.121.dist-info/entry_points.txt +2 -0
- dragonfly_radiance-0.4.121.dist-info/licenses/LICENSE +661 -0
- dragonfly_radiance-0.4.121.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Model Radiance Properties."""
|
|
3
|
+
try:
|
|
4
|
+
from itertools import izip as zip # python 2
|
|
5
|
+
except ImportError:
|
|
6
|
+
pass # python 3
|
|
7
|
+
|
|
8
|
+
from honeybee.checkdup import check_duplicate_identifiers
|
|
9
|
+
from honeybee.extensionutil import room_extension_dicts
|
|
10
|
+
import honeybee_radiance.properties.model as hb_model_properties
|
|
11
|
+
from honeybee_radiance.lib.modifiersets import generic_modifier_set_visible
|
|
12
|
+
from honeybee_radiance.lib.modifiers import generic_context
|
|
13
|
+
|
|
14
|
+
from dragonfly.extensionutil import model_extension_dicts
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ModelRadianceProperties(object):
|
|
18
|
+
"""Radiance Properties for Dragonfly Model.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
host: A dragonfly_core Model object that hosts these properties.
|
|
22
|
+
|
|
23
|
+
Properties:
|
|
24
|
+
* host
|
|
25
|
+
* modifiers
|
|
26
|
+
* shade_modifiers
|
|
27
|
+
* modifier_sets
|
|
28
|
+
* global_modifier_set
|
|
29
|
+
"""
|
|
30
|
+
# dictionary mapping validation error codes to a corresponding check function
|
|
31
|
+
ERROR_MAP = {
|
|
32
|
+
'010001': 'check_duplicate_modifier_identifiers',
|
|
33
|
+
'010002': 'check_duplicate_modifier_set_identifiers'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
def __init__(self, host):
|
|
37
|
+
"""Initialize Model Radiance properties."""
|
|
38
|
+
self._host = host
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def host(self):
|
|
42
|
+
"""Get the Model object hosting these properties."""
|
|
43
|
+
return self._host
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def modifiers(self):
|
|
47
|
+
"""List of all unique modifiers contained within the model.
|
|
48
|
+
|
|
49
|
+
This includes modifiers across all Room2Ds, Stories, and Building
|
|
50
|
+
ModifierSets but it does NOT include the Honeybee generic default
|
|
51
|
+
modifier set.
|
|
52
|
+
"""
|
|
53
|
+
bldg_mods = []
|
|
54
|
+
for mod_set in self.modifier_sets:
|
|
55
|
+
bldg_mods.extend(mod_set.modified_modifiers_unique)
|
|
56
|
+
all_mods = bldg_mods + self.face_modifiers + self.shade_modifiers
|
|
57
|
+
return list(set(all_mods))
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def face_modifiers(self):
|
|
61
|
+
"""Get a list of all unique modifiers assigned to Faces, Apertures and Doors.
|
|
62
|
+
|
|
63
|
+
These objects only exist under the Building.room_3ds property.
|
|
64
|
+
"""
|
|
65
|
+
modifiers = []
|
|
66
|
+
for bldg in self.host.buildings:
|
|
67
|
+
for face in bldg.room_3d_faces:
|
|
68
|
+
self._check_and_add_obj_modifier(face, modifiers)
|
|
69
|
+
for ap in face.apertures:
|
|
70
|
+
self._check_and_add_obj_modifier(ap, modifiers)
|
|
71
|
+
for dr in face.doors:
|
|
72
|
+
self._check_and_add_obj_modifier(dr, modifiers)
|
|
73
|
+
return list(set(modifiers))
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def shade_modifiers(self):
|
|
77
|
+
"""A list of all unique modifiers assigned to ContextShades in the model."""
|
|
78
|
+
modifiers = []
|
|
79
|
+
for shade in self.host.context_shades:
|
|
80
|
+
self._check_and_add_obj_modifier(shade, modifiers)
|
|
81
|
+
for bldg in self.host.buildings:
|
|
82
|
+
for shd in bldg.room_3d_shades:
|
|
83
|
+
self._check_and_add_obj_modifier(shd, modifiers)
|
|
84
|
+
return list(set(modifiers))
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def modifier_sets(self):
|
|
88
|
+
"""A list of all unique Building-Assigned ModifierSets in the Model.
|
|
89
|
+
|
|
90
|
+
Note that this includes ModifierSets assigned to individual Stories and
|
|
91
|
+
Room2Ds in the Building.
|
|
92
|
+
"""
|
|
93
|
+
modifier_sets = []
|
|
94
|
+
for bldg in self.host.buildings:
|
|
95
|
+
self._check_and_add_obj_mod_set(bldg, modifier_sets)
|
|
96
|
+
for story in bldg.unique_stories:
|
|
97
|
+
self._check_and_add_obj_mod_set(story, modifier_sets)
|
|
98
|
+
for room in story.room_2ds:
|
|
99
|
+
self._check_and_add_obj_mod_set(room, modifier_sets)
|
|
100
|
+
for room in bldg.room_3ds:
|
|
101
|
+
self._check_and_add_obj_mod_set(room, modifier_sets)
|
|
102
|
+
return list(set(modifier_sets)) # catch equivalent modifier sets
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def global_modifier_set(self):
|
|
106
|
+
"""The global radiance modifier set.
|
|
107
|
+
|
|
108
|
+
This is what is used whenever there is no modifier_set assigned to a
|
|
109
|
+
Room2D, a parent Story, or a parent Building.
|
|
110
|
+
"""
|
|
111
|
+
return generic_modifier_set_visible
|
|
112
|
+
|
|
113
|
+
def check_for_extension(self, raise_exception=True, detailed=False):
|
|
114
|
+
"""Check that the Model is valid for Radiance simulation.
|
|
115
|
+
|
|
116
|
+
This process includes all relevant dragonfly-core checks as well as checks
|
|
117
|
+
that apply only for Radiance.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
raise_exception: Boolean to note whether a ValueError should be raised
|
|
121
|
+
if any errors are found. If False, this method will simply
|
|
122
|
+
return a text string with all errors that were found. (Default: True).
|
|
123
|
+
detailed: Boolean for whether the returned object is a detailed list of
|
|
124
|
+
dicts with error info or a string with a message. (Default: False).
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
A text string with all errors that were found or a list if detailed is True.
|
|
128
|
+
This string (or list) will be empty if no errors were found.
|
|
129
|
+
"""
|
|
130
|
+
# set up defaults to ensure the method runs correctly
|
|
131
|
+
detailed = False if raise_exception else detailed
|
|
132
|
+
msgs = []
|
|
133
|
+
tol = self.host.tolerance
|
|
134
|
+
ang_tol = self.host.angle_tolerance
|
|
135
|
+
|
|
136
|
+
# perform checks for duplicate identifiers, which might mess with other checks
|
|
137
|
+
msgs.append(self.host.check_all_duplicate_identifiers(False, detailed))
|
|
138
|
+
|
|
139
|
+
# perform checks for key dragonfly model schema rules
|
|
140
|
+
msgs.append(self.host.check_degenerate_room_2ds(tol, False, detailed))
|
|
141
|
+
msgs.append(self.host.check_self_intersecting_room_2ds(tol, False, detailed))
|
|
142
|
+
msgs.append(self.host.check_plenum_depths(tol, False, detailed))
|
|
143
|
+
msgs.append(self.host.check_window_parameters_valid(tol, False, detailed))
|
|
144
|
+
msgs.append(self.host.check_no_room2d_overlaps(tol, False, detailed))
|
|
145
|
+
msgs.append(self.host.check_collisions_between_stories(tol, False, detailed))
|
|
146
|
+
msgs.append(self.host.check_roofs_above_rooms(tol, False, detailed))
|
|
147
|
+
msgs.append(self.host.check_room2d_floor_heights_valid(False, detailed))
|
|
148
|
+
msgs.append(self.host.check_all_room3d(tol, ang_tol, False, detailed))
|
|
149
|
+
|
|
150
|
+
# output a final report of errors or raise an exception
|
|
151
|
+
full_msgs = [msg for msg in msgs if msg]
|
|
152
|
+
if detailed:
|
|
153
|
+
return [m for msg in full_msgs for m in msg]
|
|
154
|
+
full_msg = '\n'.join(full_msgs)
|
|
155
|
+
if raise_exception and len(full_msgs) != 0:
|
|
156
|
+
raise ValueError(full_msg)
|
|
157
|
+
return full_msg
|
|
158
|
+
|
|
159
|
+
def check_generic(self, raise_exception=True, detailed=False):
|
|
160
|
+
"""Check generic of the aspects of the Model radiance properties.
|
|
161
|
+
|
|
162
|
+
This includes checks for everything except duplicate identifiers for
|
|
163
|
+
modifiers and modifier sets. Typically, these checks just add to the
|
|
164
|
+
validation time without providing useful information since extension
|
|
165
|
+
objects with duplicate IDs are lost during HBJSON serialization.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
raise_exception: Boolean to note whether a ValueError should be raised
|
|
169
|
+
if any errors are found. If False, this method will simply
|
|
170
|
+
return a text string with all errors that were found.
|
|
171
|
+
detailed: Boolean for whether the returned object is a detailed list of
|
|
172
|
+
dicts with error info or a string with a message. (Default: False).
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
A text string with all errors that were found or a list if detailed is True.
|
|
176
|
+
This string (or list) will be empty if no errors were found.
|
|
177
|
+
"""
|
|
178
|
+
# set up defaults to ensure the method runs correctly
|
|
179
|
+
detailed = False if raise_exception else detailed
|
|
180
|
+
msgs = []
|
|
181
|
+
# perform checks for specific radiance simulation rules
|
|
182
|
+
# output a final report of errors or raise an exception
|
|
183
|
+
full_msgs = [msg for msg in msgs if msg]
|
|
184
|
+
if detailed:
|
|
185
|
+
return [m for msg in full_msgs for m in msg]
|
|
186
|
+
full_msg = '\n'.join(full_msgs)
|
|
187
|
+
if raise_exception and len(full_msgs) != 0:
|
|
188
|
+
raise ValueError(full_msg)
|
|
189
|
+
return full_msg
|
|
190
|
+
|
|
191
|
+
def check_all(self, raise_exception=True, detailed=False):
|
|
192
|
+
"""Check all of the aspects of the Model radiance properties.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
raise_exception: Boolean to note whether a ValueError should be raised
|
|
196
|
+
if any errors are found. If False, this method will simply
|
|
197
|
+
return a text string with all errors that were found.
|
|
198
|
+
detailed: Boolean for whether the returned object is a detailed list of
|
|
199
|
+
dicts with error info or a string with a message. (Default: False).
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
A text string with all errors that were found or a list if detailed is True.
|
|
203
|
+
This string (or list) will be empty if no errors were found.
|
|
204
|
+
"""
|
|
205
|
+
# set up defaults to ensure the method runs correctly
|
|
206
|
+
detailed = False if raise_exception else detailed
|
|
207
|
+
msgs = []
|
|
208
|
+
# perform checks for duplicate identifiers
|
|
209
|
+
msgs.append(self.check_all_duplicate_identifiers(False, detailed))
|
|
210
|
+
# perform checks for specific radiance simulation rules
|
|
211
|
+
# output a final report of errors or raise an exception
|
|
212
|
+
full_msgs = [msg for msg in msgs if msg]
|
|
213
|
+
if detailed:
|
|
214
|
+
return [m for msg in full_msgs for m in msg]
|
|
215
|
+
full_msg = '\n'.join(full_msgs)
|
|
216
|
+
if raise_exception and len(full_msgs) != 0:
|
|
217
|
+
raise ValueError(full_msg)
|
|
218
|
+
return full_msg
|
|
219
|
+
|
|
220
|
+
def check_all_duplicate_identifiers(self, raise_exception=True, detailed=False):
|
|
221
|
+
"""Check that there are no duplicate identifiers for any geometry objects.
|
|
222
|
+
|
|
223
|
+
This includes Rooms, Faces, Apertures, Doors, Shades, and ShadeMeshes.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
raise_exception: Boolean to note whether a ValueError should be raised
|
|
227
|
+
if any Model errors are found. If False, this method will simply
|
|
228
|
+
return a text string with all errors that were found. (Default: True).
|
|
229
|
+
detailed: Boolean for whether the returned object is a detailed list of
|
|
230
|
+
dicts with error info or a string with a message. (Default: False).
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
A text string with all errors that were found or a list if detailed is True.
|
|
234
|
+
This string (or list) will be empty if no errors were found.
|
|
235
|
+
"""
|
|
236
|
+
# set up defaults to ensure the method runs correctly
|
|
237
|
+
detailed = False if raise_exception else detailed
|
|
238
|
+
msgs = []
|
|
239
|
+
# perform checks for duplicate identifiers
|
|
240
|
+
msgs.append(self.check_duplicate_modifier_identifiers(False, detailed))
|
|
241
|
+
msgs.append(self.check_duplicate_modifier_set_identifiers(False, detailed))
|
|
242
|
+
# output a final report of errors or raise an exception
|
|
243
|
+
full_msgs = [msg for msg in msgs if msg]
|
|
244
|
+
if detailed:
|
|
245
|
+
return [m for msg in full_msgs for m in msg]
|
|
246
|
+
full_msg = '\n'.join(full_msgs)
|
|
247
|
+
if raise_exception and len(full_msgs) != 0:
|
|
248
|
+
raise ValueError(full_msg)
|
|
249
|
+
return full_msg
|
|
250
|
+
|
|
251
|
+
def check_duplicate_modifier_identifiers(self, raise_exception=True, detailed=False):
|
|
252
|
+
"""Check that there are no duplicate Modifier identifiers in the model.
|
|
253
|
+
|
|
254
|
+
Args:
|
|
255
|
+
raise_exception: Boolean to note whether a ValueError should be raised
|
|
256
|
+
if duplicate identifiers are found. (Default: True).
|
|
257
|
+
detailed: Boolean for whether the returned object is a detailed list of
|
|
258
|
+
dicts with error info or a string with a message. (Default: False).
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
A string with the message or a list with a dictionary if detailed is True.
|
|
262
|
+
"""
|
|
263
|
+
return check_duplicate_identifiers(
|
|
264
|
+
self.modifiers, raise_exception, 'Radiance Modifier',
|
|
265
|
+
detailed, '010001', 'Radiance', error_type='Duplicate Modifier Identifier')
|
|
266
|
+
|
|
267
|
+
def check_duplicate_modifier_set_identifiers(
|
|
268
|
+
self, raise_exception=True, detailed=False):
|
|
269
|
+
"""Check that there are no duplicate ModifierSet identifiers in the model.
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
raise_exception: Boolean to note whether a ValueError should be raised
|
|
273
|
+
if duplicate identifiers are found. (Default: True).
|
|
274
|
+
detailed: Boolean for whether the returned object is a detailed list of
|
|
275
|
+
dicts with error info or a string with a message. (Default: False).
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
A string with the message or a list with a dictionary if detailed is True.
|
|
279
|
+
"""
|
|
280
|
+
return check_duplicate_identifiers(
|
|
281
|
+
self.modifier_sets, raise_exception, 'ModifierSet',
|
|
282
|
+
detailed, '010002', 'Radiance',
|
|
283
|
+
error_type='Duplicate ModifierSet Identifier')
|
|
284
|
+
|
|
285
|
+
def apply_properties_from_dict(self, data):
|
|
286
|
+
"""Apply the radiance properties of a dictionary to the host Model of this object.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
data: A dictionary representation of an entire dragonfly-core Model.
|
|
290
|
+
Note that this dictionary must have ModelRadianceProperties in order
|
|
291
|
+
for this method to successfully apply the radiance properties.
|
|
292
|
+
"""
|
|
293
|
+
assert 'radiance' in data['properties'], \
|
|
294
|
+
'Dictionary possesses no ModelRadianceProperties.'
|
|
295
|
+
modifiers, modifier_sets = \
|
|
296
|
+
hb_model_properties.ModelRadianceProperties.load_properties_from_dict(data)
|
|
297
|
+
|
|
298
|
+
# collect lists of radiance property dictionaries
|
|
299
|
+
building_e_dicts, story_e_dicts, room2d_e_dicts, context_e_dicts = \
|
|
300
|
+
model_extension_dicts(data, 'radiance', [], [], [], [])
|
|
301
|
+
|
|
302
|
+
# apply radiance properties to objects using the radiance property dictionaries
|
|
303
|
+
for bldg, b_dict in zip(self.host.buildings, building_e_dicts):
|
|
304
|
+
if b_dict is not None:
|
|
305
|
+
bldg.properties.radiance.apply_properties_from_dict(
|
|
306
|
+
b_dict, modifier_sets)
|
|
307
|
+
if bldg.has_room_3ds and b_dict is not None and 'room_3ds' in b_dict and \
|
|
308
|
+
b_dict['room_3ds'] is not None:
|
|
309
|
+
room_e_dicts, face_e_dicts, shd_e_dicts, ap_e_dicts, dr_e_dicts = \
|
|
310
|
+
room_extension_dicts(b_dict['room_3ds'], 'radiance', [], [], [], [], [])
|
|
311
|
+
for room, r_dict in zip(bldg.room_3ds, room_e_dicts):
|
|
312
|
+
if r_dict is not None:
|
|
313
|
+
room.properties.radiance.apply_properties_from_dict(
|
|
314
|
+
r_dict, modifier_sets)
|
|
315
|
+
for face, f_dict in zip(bldg.room_3d_faces, face_e_dicts):
|
|
316
|
+
if f_dict is not None:
|
|
317
|
+
face.properties.radiance.apply_properties_from_dict(
|
|
318
|
+
f_dict, modifiers)
|
|
319
|
+
for aperture, a_dict in zip(bldg.room_3d_apertures, ap_e_dicts):
|
|
320
|
+
if a_dict is not None:
|
|
321
|
+
aperture.properties.radiance.apply_properties_from_dict(
|
|
322
|
+
a_dict, modifiers)
|
|
323
|
+
for door, d_dict in zip(bldg.room_3d_doors, dr_e_dicts):
|
|
324
|
+
if d_dict is not None:
|
|
325
|
+
door.properties.radiance.apply_properties_from_dict(
|
|
326
|
+
d_dict, modifiers)
|
|
327
|
+
for shade, s_dict in zip(bldg.room_3d_shades, shd_e_dicts):
|
|
328
|
+
if s_dict is not None:
|
|
329
|
+
shade.properties.radiance.apply_properties_from_dict(
|
|
330
|
+
s_dict, modifiers)
|
|
331
|
+
for story, s_dict in zip(self.host.stories, story_e_dicts):
|
|
332
|
+
if s_dict is not None:
|
|
333
|
+
story.properties.radiance.apply_properties_from_dict(
|
|
334
|
+
s_dict, modifier_sets)
|
|
335
|
+
for room, r_dict in zip(self.host.room_2ds, room2d_e_dicts):
|
|
336
|
+
if r_dict is not None:
|
|
337
|
+
room.properties.radiance.apply_properties_from_dict(
|
|
338
|
+
r_dict, modifier_sets)
|
|
339
|
+
for shade, s_dict in zip(self.host.context_shades, context_e_dicts):
|
|
340
|
+
if s_dict is not None:
|
|
341
|
+
shade.properties.radiance.apply_properties_from_dict(s_dict, modifiers)
|
|
342
|
+
|
|
343
|
+
def to_dict(self):
|
|
344
|
+
"""Return Model radiance properties as a dictionary."""
|
|
345
|
+
base = {'radiance': {'type': 'ModelRadianceProperties'}}
|
|
346
|
+
|
|
347
|
+
# add the global modifier set to the dictionary
|
|
348
|
+
gs = self.global_modifier_set.to_dict(abridged=True, none_for_defaults=False)
|
|
349
|
+
gs['type'] = 'GlobalModifierSet'
|
|
350
|
+
del gs['identifier']
|
|
351
|
+
g_mods = self.global_modifier_set.modifiers_unique
|
|
352
|
+
gs['modifiers'] = [mod.to_dict() for mod in g_mods]
|
|
353
|
+
gs['context_modifier'] = generic_context.identifier
|
|
354
|
+
gs['modifiers'].append(generic_context.to_dict())
|
|
355
|
+
base['radiance']['global_modifier_set'] = gs
|
|
356
|
+
|
|
357
|
+
# add all ModifierSets to the dictionary
|
|
358
|
+
base['radiance']['modifier_sets'] = []
|
|
359
|
+
modifier_sets = self.modifier_sets
|
|
360
|
+
for mod_set in modifier_sets:
|
|
361
|
+
base['radiance']['modifier_sets'].append(mod_set.to_dict(abridged=True))
|
|
362
|
+
|
|
363
|
+
# add all unique Modifiers to the dictionary
|
|
364
|
+
room_mods = []
|
|
365
|
+
for mod_set in modifier_sets:
|
|
366
|
+
room_mods.extend(mod_set.modified_modifiers_unique)
|
|
367
|
+
all_mods = room_mods + self.face_modifiers + self.shade_modifiers
|
|
368
|
+
modifiers = tuple(set(all_mods))
|
|
369
|
+
base['radiance']['modifiers'] = []
|
|
370
|
+
for mod in modifiers:
|
|
371
|
+
base['radiance']['modifiers'].append(mod.to_dict())
|
|
372
|
+
|
|
373
|
+
return base
|
|
374
|
+
|
|
375
|
+
def to_honeybee(self, new_host):
|
|
376
|
+
"""Get a honeybee version of this object.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
new_host: A honeybee-core Model object that will host these properties.
|
|
380
|
+
"""
|
|
381
|
+
hb_rad_props = hb_model_properties.ModelRadianceProperties(new_host)
|
|
382
|
+
# gather all of the sensor grid parameters across the model
|
|
383
|
+
sg_dict = {}
|
|
384
|
+
for rm_2d in self.host.room_2ds:
|
|
385
|
+
if len(rm_2d.properties.radiance._grid_parameters) != 0:
|
|
386
|
+
sg_dict[rm_2d.identifier] = rm_2d.properties.radiance._grid_parameters
|
|
387
|
+
# generate and assign sensor grids to the rooms of the new_host
|
|
388
|
+
if len(sg_dict) != 0:
|
|
389
|
+
sensor_grids = []
|
|
390
|
+
for rm_id, g_par in sg_dict.items():
|
|
391
|
+
for room in new_host.rooms:
|
|
392
|
+
if room.identifier == rm_id:
|
|
393
|
+
for gp in g_par:
|
|
394
|
+
sg = gp.generate_grid_from_room(room)
|
|
395
|
+
if sg is not None:
|
|
396
|
+
sensor_grids.append(sg)
|
|
397
|
+
break
|
|
398
|
+
hb_rad_props.sensor_grids = sensor_grids
|
|
399
|
+
return hb_rad_props
|
|
400
|
+
|
|
401
|
+
def duplicate(self, new_host=None):
|
|
402
|
+
"""Get a copy of this Model.
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
new_host: A new Model object that hosts these properties.
|
|
406
|
+
If None, the properties will be duplicated with the same host.
|
|
407
|
+
"""
|
|
408
|
+
_host = new_host or self._host
|
|
409
|
+
return ModelRadianceProperties(_host)
|
|
410
|
+
|
|
411
|
+
def _check_and_add_obj_modifier(self, obj, modifiers):
|
|
412
|
+
"""Check if a modifier is assigned to an object and add it to a list."""
|
|
413
|
+
mod = obj.properties.radiance._modifier
|
|
414
|
+
if mod is not None:
|
|
415
|
+
if not self._instance_in_array(mod, modifiers):
|
|
416
|
+
modifiers.append(mod)
|
|
417
|
+
|
|
418
|
+
def _check_and_add_obj_mod_set(self, obj, modifier_sets):
|
|
419
|
+
"""Check if a modifier set is assigned to an object and add it to a list."""
|
|
420
|
+
m_set = obj.properties.radiance._modifier_set
|
|
421
|
+
if m_set is not None:
|
|
422
|
+
if not self._instance_in_array(m_set, modifier_sets):
|
|
423
|
+
modifier_sets.append(m_set)
|
|
424
|
+
|
|
425
|
+
@staticmethod
|
|
426
|
+
def _instance_in_array(object_instance, object_array):
|
|
427
|
+
"""Check if a specific object instance is already in an array.
|
|
428
|
+
|
|
429
|
+
This can be much faster than `if object_instance in object_array`
|
|
430
|
+
when you expect to be testing a lot of the same instance of an object for
|
|
431
|
+
inclusion in an array since the builtin method uses an == operator to
|
|
432
|
+
test inclusion.
|
|
433
|
+
"""
|
|
434
|
+
for val in object_array:
|
|
435
|
+
if val is object_instance:
|
|
436
|
+
return True
|
|
437
|
+
return False
|
|
438
|
+
|
|
439
|
+
def ToString(self):
|
|
440
|
+
return self.__repr__()
|
|
441
|
+
|
|
442
|
+
def __repr__(self):
|
|
443
|
+
return 'Model Radiance Properties: {}'.format(self.host.identifier)
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Room2D Radiance Properties."""
|
|
3
|
+
from honeybee_radiance.properties.room import RoomRadianceProperties
|
|
4
|
+
from honeybee_radiance.modifierset import ModifierSet
|
|
5
|
+
from honeybee_radiance.lib.modifiersets import generic_modifier_set_visible
|
|
6
|
+
|
|
7
|
+
import dragonfly_radiance.gridpar as sg_par
|
|
8
|
+
from ..gridpar import _GridParameterBase, RoomGridParameter, RoomRadialGridParameter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Room2DRadianceProperties(object):
|
|
12
|
+
"""Radiance Properties for Dragonfly Room2D.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
host: A dragonfly_core Room2D object that hosts these properties.
|
|
16
|
+
modifier_set: A honeybee ModifierSet object to specify all default
|
|
17
|
+
modifiers for the Faces of the Room2D. If None, the Room2D will use
|
|
18
|
+
the honeybee default modifier set, which is only representative
|
|
19
|
+
of typical indoor conditions in the visible spectrum. (Default: None).
|
|
20
|
+
grid_parameters: An optional list of GridParameter objects to describe
|
|
21
|
+
how sensor grids should be generated for the Room2D. (Default: None).
|
|
22
|
+
|
|
23
|
+
Properties:
|
|
24
|
+
* host
|
|
25
|
+
* modifier_set
|
|
26
|
+
* grid_parameters
|
|
27
|
+
"""
|
|
28
|
+
__slots__ = ('_host', '_modifier_set', '_grid_parameters')
|
|
29
|
+
|
|
30
|
+
def __init__(self, host, modifier_set=None, grid_parameters=None):
|
|
31
|
+
"""Initialize Room2D Radiance properties."""
|
|
32
|
+
self._host = host
|
|
33
|
+
self.modifier_set = modifier_set
|
|
34
|
+
self.grid_parameters = grid_parameters
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def host(self):
|
|
38
|
+
"""Get the Room2D object hosting these properties."""
|
|
39
|
+
return self._host
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def modifier_set(self):
|
|
43
|
+
"""Get or set the Room2D ModifierSet object.
|
|
44
|
+
|
|
45
|
+
If not set, it will be set by the parent Story or will be the Honeybee
|
|
46
|
+
default generic ModifierSet.
|
|
47
|
+
"""
|
|
48
|
+
if self._modifier_set is not None: # set by the user
|
|
49
|
+
return self._modifier_set
|
|
50
|
+
elif self._host.has_parent: # set by parent story
|
|
51
|
+
return self._host.parent.properties.radiance.modifier_set
|
|
52
|
+
else:
|
|
53
|
+
return generic_modifier_set_visible
|
|
54
|
+
|
|
55
|
+
@modifier_set.setter
|
|
56
|
+
def modifier_set(self, value):
|
|
57
|
+
if value is not None:
|
|
58
|
+
assert isinstance(value, ModifierSet), \
|
|
59
|
+
'Expected ModifierSet. Got {}'.format(type(value))
|
|
60
|
+
value.lock() # lock in case modifier set has multiple references
|
|
61
|
+
self._modifier_set = value
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def grid_parameters(self):
|
|
65
|
+
"""Get or set a list of GridParameters to generate sensor grids for the room.
|
|
66
|
+
"""
|
|
67
|
+
return tuple(self._grid_parameters)
|
|
68
|
+
|
|
69
|
+
@grid_parameters.setter
|
|
70
|
+
def grid_parameters(self, value):
|
|
71
|
+
if value is not None:
|
|
72
|
+
if not isinstance(value, list):
|
|
73
|
+
value = list(value)
|
|
74
|
+
for sg in value:
|
|
75
|
+
assert isinstance(sg, _GridParameterBase), \
|
|
76
|
+
'Expected GridParameter. Got {}'.format(type(sg))
|
|
77
|
+
else:
|
|
78
|
+
value = []
|
|
79
|
+
self._grid_parameters = value
|
|
80
|
+
|
|
81
|
+
def remove_grid_parameters(self):
|
|
82
|
+
"""Remove all grid_parameters from the Room2D."""
|
|
83
|
+
self._grid_parameters = []
|
|
84
|
+
|
|
85
|
+
def add_grid_parameter(self, grid_parameter):
|
|
86
|
+
"""Add a GridParameter to this Room2D.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
grid_parameter: An GridParameter objects to describe how sensor grids
|
|
90
|
+
should be generated for the Room2D.
|
|
91
|
+
"""
|
|
92
|
+
assert isinstance(grid_parameter, _GridParameterBase), \
|
|
93
|
+
'Expected GridParameter. Got {}.'.format(type(grid_parameter))
|
|
94
|
+
self._grid_parameters.append(grid_parameter)
|
|
95
|
+
|
|
96
|
+
def make_plenum(self):
|
|
97
|
+
"""Turn the host Room2D into a plenum with no grid parameters inside the room.
|
|
98
|
+
|
|
99
|
+
Grid parameters for exterior facades will be kept. This is useful to
|
|
100
|
+
appropriately assign properties for closets, underfloor spaces, and
|
|
101
|
+
drop ceilings.
|
|
102
|
+
"""
|
|
103
|
+
plenum_g_par = []
|
|
104
|
+
for g_par in self._grid_parameters:
|
|
105
|
+
if not isinstance(g_par, (RoomGridParameter, RoomRadialGridParameter)):
|
|
106
|
+
plenum_g_par.append(g_par)
|
|
107
|
+
self._grid_parameters = plenum_g_par
|
|
108
|
+
|
|
109
|
+
@classmethod
|
|
110
|
+
def from_dict(cls, data, host):
|
|
111
|
+
"""Create Room2DRadianceProperties from a dictionary.
|
|
112
|
+
|
|
113
|
+
Note that the dictionary must be a non-abridged version for this
|
|
114
|
+
classmethod to work.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
data: A dictionary representation of Room2DRadianceProperties in the
|
|
118
|
+
format below.
|
|
119
|
+
host: A Room2D object that hosts these properties.
|
|
120
|
+
|
|
121
|
+
.. code-block:: python
|
|
122
|
+
|
|
123
|
+
{
|
|
124
|
+
"type": 'Room2DRadianceProperties',
|
|
125
|
+
"modifier_set": {}, # A ModifierSet dictionary
|
|
126
|
+
"grid_parameters": [] # A list of GridParameter dictionaries
|
|
127
|
+
}
|
|
128
|
+
"""
|
|
129
|
+
assert data['type'] == 'Room2DRadianceProperties', \
|
|
130
|
+
'Expected Room2DRadianceProperties. Got {}.'.format(data['type'])
|
|
131
|
+
|
|
132
|
+
new_prop = cls(host)
|
|
133
|
+
if 'modifier_set' in data and data['modifier_set'] is not None:
|
|
134
|
+
new_prop.modifier_set = ModifierSet.from_dict(data['modifier_set'])
|
|
135
|
+
if 'grid_parameters' in data and data['grid_parameters'] is not None:
|
|
136
|
+
grd_par = []
|
|
137
|
+
for gp in data['grid_parameters']:
|
|
138
|
+
try:
|
|
139
|
+
g_class = getattr(sg_par, gp['type'])
|
|
140
|
+
except AttributeError:
|
|
141
|
+
raise ValueError(
|
|
142
|
+
'GridParameter "{}" is not recognized.'.format(gp['type']))
|
|
143
|
+
grd_par.append(g_class.from_dict(gp))
|
|
144
|
+
new_prop.grid_parameters = grd_par
|
|
145
|
+
|
|
146
|
+
return new_prop
|
|
147
|
+
|
|
148
|
+
def apply_properties_from_dict(self, abridged_data, modifier_sets):
|
|
149
|
+
"""Apply properties from a Room2DRadiancePropertiesAbridged dictionary.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
abridged_data: A Room2DRadiancePropertiesAbridged dictionary (typically
|
|
153
|
+
coming from a Model).
|
|
154
|
+
modifier_sets: A dictionary of ModifierSets with identifiers
|
|
155
|
+
of the sets as keys, which will be used to re-assign modifier_sets.
|
|
156
|
+
"""
|
|
157
|
+
if 'modifier_set' in abridged_data and abridged_data['modifier_set'] is not None:
|
|
158
|
+
self.modifier_set = modifier_sets[abridged_data['modifier_set']]
|
|
159
|
+
if 'grid_parameters' in abridged_data and \
|
|
160
|
+
abridged_data['grid_parameters'] is not None:
|
|
161
|
+
grd_par = []
|
|
162
|
+
for gp in abridged_data['grid_parameters']:
|
|
163
|
+
try:
|
|
164
|
+
g_class = getattr(sg_par, gp['type'])
|
|
165
|
+
except AttributeError:
|
|
166
|
+
raise ValueError(
|
|
167
|
+
'GridParameter "{}" is not recognized.'.format(gp['type']))
|
|
168
|
+
grd_par.append(g_class.from_dict(gp))
|
|
169
|
+
self.grid_parameters = grd_par
|
|
170
|
+
|
|
171
|
+
def to_dict(self, abridged=False):
|
|
172
|
+
"""Return Room2D radiance properties as a dictionary.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
abridged: Boolean for whether the full dictionary of the Room2D should
|
|
176
|
+
be written (False) or just the identifier of the the individual
|
|
177
|
+
properties (True). Default: False.
|
|
178
|
+
"""
|
|
179
|
+
base = {'radiance': {}}
|
|
180
|
+
base['radiance']['type'] = 'Room2DRadianceProperties' if not \
|
|
181
|
+
abridged else 'Room2DRadiancePropertiesAbridged'
|
|
182
|
+
|
|
183
|
+
# write the ModifierSet into the dictionary
|
|
184
|
+
if self._modifier_set is not None:
|
|
185
|
+
base['radiance']['modifier_set'] = \
|
|
186
|
+
self._modifier_set.identifier if abridged else \
|
|
187
|
+
self._modifier_set.to_dict()
|
|
188
|
+
|
|
189
|
+
# write the GridParameters into the dictionary
|
|
190
|
+
if len(self._grid_parameters) != 0:
|
|
191
|
+
base['radiance']['grid_parameters'] = \
|
|
192
|
+
[gdp.to_dict() for gdp in self._grid_parameters]
|
|
193
|
+
return base
|
|
194
|
+
|
|
195
|
+
def to_honeybee(self, new_host):
|
|
196
|
+
"""Get a honeybee version of this object.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
new_host: A honeybee-core Room object that will host these properties.
|
|
200
|
+
"""
|
|
201
|
+
mod_set = self.modifier_set # includes story and building-assigned sets
|
|
202
|
+
hb_mods = mod_set if mod_set is not generic_modifier_set_visible else None
|
|
203
|
+
hb_prop = RoomRadianceProperties(new_host, hb_mods)
|
|
204
|
+
return hb_prop
|
|
205
|
+
|
|
206
|
+
def from_honeybee(self, hb_properties):
|
|
207
|
+
"""Transfer radiance attributes from a Honeybee Room to Dragonfly Room2D.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
hb_properties: The RoomRadianceProperties of the honeybee Room that is being
|
|
211
|
+
translated to a Dragonfly Room2D.
|
|
212
|
+
"""
|
|
213
|
+
self._modifier_set = hb_properties._modifier_set
|
|
214
|
+
|
|
215
|
+
def duplicate(self, new_host=None):
|
|
216
|
+
"""Get a copy of this object.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
new_host: A new Room2D object that hosts these properties.
|
|
220
|
+
If None, the properties will be duplicated with the same host.
|
|
221
|
+
"""
|
|
222
|
+
_host = new_host or self._host
|
|
223
|
+
return Room2DRadianceProperties(
|
|
224
|
+
_host, self._modifier_set, self._grid_parameters[:])
|
|
225
|
+
|
|
226
|
+
def ToString(self):
|
|
227
|
+
return self.__repr__()
|
|
228
|
+
|
|
229
|
+
def __repr__(self):
|
|
230
|
+
return 'Room2D Radiance Properties: {}'.format(self.host.identifier)
|