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.
- honeybee_radiance/__init__.py +11 -0
- honeybee_radiance/__main__.py +4 -0
- honeybee_radiance/_extend_honeybee.py +93 -0
- honeybee_radiance/cli/__init__.py +88 -0
- honeybee_radiance/cli/dc.py +400 -0
- honeybee_radiance/cli/edit.py +529 -0
- honeybee_radiance/cli/glare.py +118 -0
- honeybee_radiance/cli/grid.py +859 -0
- honeybee_radiance/cli/lib.py +458 -0
- honeybee_radiance/cli/modifier.py +133 -0
- honeybee_radiance/cli/mtx.py +226 -0
- honeybee_radiance/cli/multiphase.py +1034 -0
- honeybee_radiance/cli/octree.py +640 -0
- honeybee_radiance/cli/postprocess.py +1186 -0
- honeybee_radiance/cli/raytrace.py +219 -0
- honeybee_radiance/cli/rpict.py +125 -0
- honeybee_radiance/cli/schedule.py +56 -0
- honeybee_radiance/cli/setconfig.py +63 -0
- honeybee_radiance/cli/sky.py +545 -0
- honeybee_radiance/cli/study.py +66 -0
- honeybee_radiance/cli/sunpath.py +331 -0
- honeybee_radiance/cli/threephase.py +255 -0
- honeybee_radiance/cli/translate.py +400 -0
- honeybee_radiance/cli/util.py +121 -0
- honeybee_radiance/cli/view.py +261 -0
- honeybee_radiance/cli/viewfactor.py +347 -0
- honeybee_radiance/config.json +6 -0
- honeybee_radiance/config.py +427 -0
- honeybee_radiance/dictutil.py +50 -0
- honeybee_radiance/dynamic/__init__.py +5 -0
- honeybee_radiance/dynamic/group.py +479 -0
- honeybee_radiance/dynamic/multiphase.py +557 -0
- honeybee_radiance/dynamic/state.py +718 -0
- honeybee_radiance/dynamic/stategeo.py +352 -0
- honeybee_radiance/geometry/__init__.py +13 -0
- honeybee_radiance/geometry/bubble.py +42 -0
- honeybee_radiance/geometry/cone.py +215 -0
- honeybee_radiance/geometry/cup.py +54 -0
- honeybee_radiance/geometry/cylinder.py +197 -0
- honeybee_radiance/geometry/geometrybase.py +37 -0
- honeybee_radiance/geometry/instance.py +40 -0
- honeybee_radiance/geometry/mesh.py +38 -0
- honeybee_radiance/geometry/polygon.py +174 -0
- honeybee_radiance/geometry/ring.py +214 -0
- honeybee_radiance/geometry/source.py +182 -0
- honeybee_radiance/geometry/sphere.py +178 -0
- honeybee_radiance/geometry/tube.py +46 -0
- honeybee_radiance/lib/__init__.py +1 -0
- honeybee_radiance/lib/_loadmodifiers.py +72 -0
- honeybee_radiance/lib/_loadmodifiersets.py +69 -0
- honeybee_radiance/lib/modifiers.py +58 -0
- honeybee_radiance/lib/modifiersets.py +63 -0
- honeybee_radiance/lightpath.py +204 -0
- honeybee_radiance/lightsource/__init__.py +1 -0
- honeybee_radiance/lightsource/_gendaylit.py +479 -0
- honeybee_radiance/lightsource/dictutil.py +49 -0
- honeybee_radiance/lightsource/ground.py +160 -0
- honeybee_radiance/lightsource/sky/__init__.py +7 -0
- honeybee_radiance/lightsource/sky/_skybase.py +177 -0
- honeybee_radiance/lightsource/sky/certainirradiance.py +232 -0
- honeybee_radiance/lightsource/sky/cie.py +378 -0
- honeybee_radiance/lightsource/sky/climatebased.py +501 -0
- honeybee_radiance/lightsource/sky/hemisphere.py +160 -0
- honeybee_radiance/lightsource/sky/skydome.py +113 -0
- honeybee_radiance/lightsource/sky/skymatrix.py +163 -0
- honeybee_radiance/lightsource/sky/strutil.py +34 -0
- honeybee_radiance/lightsource/sky/sunmatrix.py +212 -0
- honeybee_radiance/lightsource/sunpath.py +247 -0
- honeybee_radiance/modifier/__init__.py +3 -0
- honeybee_radiance/modifier/material/__init__.py +30 -0
- honeybee_radiance/modifier/material/absdf.py +477 -0
- honeybee_radiance/modifier/material/antimatter.py +54 -0
- honeybee_radiance/modifier/material/ashik2.py +51 -0
- honeybee_radiance/modifier/material/brtdfunc.py +81 -0
- honeybee_radiance/modifier/material/bsdf.py +292 -0
- honeybee_radiance/modifier/material/dielectric.py +53 -0
- honeybee_radiance/modifier/material/glass.py +431 -0
- honeybee_radiance/modifier/material/glow.py +246 -0
- honeybee_radiance/modifier/material/illum.py +51 -0
- honeybee_radiance/modifier/material/interface.py +49 -0
- honeybee_radiance/modifier/material/light.py +206 -0
- honeybee_radiance/modifier/material/materialbase.py +36 -0
- honeybee_radiance/modifier/material/metal.py +167 -0
- honeybee_radiance/modifier/material/metal2.py +41 -0
- honeybee_radiance/modifier/material/metdata.py +41 -0
- honeybee_radiance/modifier/material/metfunc.py +41 -0
- honeybee_radiance/modifier/material/mirror.py +340 -0
- honeybee_radiance/modifier/material/mist.py +86 -0
- honeybee_radiance/modifier/material/plasdata.py +58 -0
- honeybee_radiance/modifier/material/plasfunc.py +59 -0
- honeybee_radiance/modifier/material/plastic.py +354 -0
- honeybee_radiance/modifier/material/plastic2.py +58 -0
- honeybee_radiance/modifier/material/prism1.py +57 -0
- honeybee_radiance/modifier/material/prism2.py +48 -0
- honeybee_radiance/modifier/material/spotlight.py +50 -0
- honeybee_radiance/modifier/material/trans.py +518 -0
- honeybee_radiance/modifier/material/trans2.py +49 -0
- honeybee_radiance/modifier/material/transdata.py +50 -0
- honeybee_radiance/modifier/material/transfunc.py +53 -0
- honeybee_radiance/modifier/mixture/__init__.py +6 -0
- honeybee_radiance/modifier/mixture/mixdata.py +49 -0
- honeybee_radiance/modifier/mixture/mixfunc.py +54 -0
- honeybee_radiance/modifier/mixture/mixpict.py +52 -0
- honeybee_radiance/modifier/mixture/mixtext.py +66 -0
- honeybee_radiance/modifier/mixture/mixturebase.py +28 -0
- honeybee_radiance/modifier/modifierbase.py +40 -0
- honeybee_radiance/modifier/pattern/__init__.py +9 -0
- honeybee_radiance/modifier/pattern/brightdata.py +49 -0
- honeybee_radiance/modifier/pattern/brightfunc.py +47 -0
- honeybee_radiance/modifier/pattern/brighttext.py +81 -0
- honeybee_radiance/modifier/pattern/colordata.py +56 -0
- honeybee_radiance/modifier/pattern/colorfunc.py +47 -0
- honeybee_radiance/modifier/pattern/colorpict.py +54 -0
- honeybee_radiance/modifier/pattern/colortext.py +73 -0
- honeybee_radiance/modifier/pattern/patternbase.py +34 -0
- honeybee_radiance/modifier/texture/__init__.py +4 -0
- honeybee_radiance/modifier/texture/texdata.py +29 -0
- honeybee_radiance/modifier/texture/texfunc.py +26 -0
- honeybee_radiance/modifier/texture/texturebase.py +27 -0
- honeybee_radiance/modifierset.py +1091 -0
- honeybee_radiance/mutil.py +60 -0
- honeybee_radiance/postprocess/__init__.py +1 -0
- honeybee_radiance/postprocess/annual.py +108 -0
- honeybee_radiance/postprocess/annualdaylight.py +425 -0
- honeybee_radiance/postprocess/annualglare.py +201 -0
- honeybee_radiance/postprocess/annualirradiance.py +187 -0
- honeybee_radiance/postprocess/electriclight.py +119 -0
- honeybee_radiance/postprocess/en17037.py +261 -0
- honeybee_radiance/postprocess/leed.py +304 -0
- honeybee_radiance/postprocess/solartracking.py +90 -0
- honeybee_radiance/primitive.py +554 -0
- honeybee_radiance/properties/__init__.py +1 -0
- honeybee_radiance/properties/_base.py +390 -0
- honeybee_radiance/properties/aperture.py +197 -0
- honeybee_radiance/properties/door.py +198 -0
- honeybee_radiance/properties/face.py +123 -0
- honeybee_radiance/properties/model.py +1291 -0
- honeybee_radiance/properties/room.py +490 -0
- honeybee_radiance/properties/shade.py +186 -0
- honeybee_radiance/properties/shademesh.py +116 -0
- honeybee_radiance/putil.py +44 -0
- honeybee_radiance/reader.py +214 -0
- honeybee_radiance/sensor.py +166 -0
- honeybee_radiance/sensorgrid.py +1008 -0
- honeybee_radiance/view.py +1101 -0
- honeybee_radiance/writer.py +951 -0
- honeybee_radiance-1.66.190.dist-info/METADATA +89 -0
- honeybee_radiance-1.66.190.dist-info/RECORD +152 -0
- honeybee_radiance-1.66.190.dist-info/WHEEL +5 -0
- honeybee_radiance-1.66.190.dist-info/entry_points.txt +2 -0
- honeybee_radiance-1.66.190.dist-info/licenses/LICENSE +661 -0
- honeybee_radiance-1.66.190.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
"""Object representing a group of sub-faces or shades that change states in unison."""
|
|
3
|
+
from __future__ import division
|
|
4
|
+
|
|
5
|
+
from .state import RadianceShadeState, RadianceSubFaceState
|
|
6
|
+
from ..geometry import Polygon
|
|
7
|
+
from ..modifier.material import BSDF
|
|
8
|
+
from ..lib.modifiers import white_glow
|
|
9
|
+
|
|
10
|
+
from honeybee.typing import valid_rad_string
|
|
11
|
+
from honeybee.shade import Shade
|
|
12
|
+
from honeybee.aperture import Aperture
|
|
13
|
+
from honeybee.door import Door
|
|
14
|
+
from honeybee.boundarycondition import Surface
|
|
15
|
+
|
|
16
|
+
from honeybee_radiance_command.options.rfluxmtx import RfluxmtxControlParameters
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DynamicShadeGroup(object):
|
|
22
|
+
"""Object representing a group of dynamic shades that change states in unison.
|
|
23
|
+
|
|
24
|
+
Note that this object is not intended to set any Model properties. It is only
|
|
25
|
+
used by the Model to collect objects with the same dynamic_group_identifier
|
|
26
|
+
and export a common set of radiance files from them.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
identifier: Text string for a unique Group ID. Must not contain spaces
|
|
30
|
+
or special characters. This will be used to identify the object across
|
|
31
|
+
a model and in the exported Radiance files.
|
|
32
|
+
dynamic_objects: An array of Shades that are contained within the group.
|
|
33
|
+
|
|
34
|
+
Properties:
|
|
35
|
+
* identifier
|
|
36
|
+
* dynamic_objects
|
|
37
|
+
* state_count
|
|
38
|
+
* is_opaque
|
|
39
|
+
* is_indoor
|
|
40
|
+
* states_json_list
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
__slots__ = ('_identifier', '_dynamic_objects', '_state_count')
|
|
44
|
+
|
|
45
|
+
def __init__(self, identifier, dynamic_objects):
|
|
46
|
+
"""Initialize DynamicShadeGroup."""
|
|
47
|
+
# set identifier
|
|
48
|
+
self._identifier = valid_rad_string(identifier)
|
|
49
|
+
|
|
50
|
+
# set the dynamic_objects
|
|
51
|
+
if not isinstance(dynamic_objects, tuple):
|
|
52
|
+
dynamic_objects = tuple(dynamic_objects)
|
|
53
|
+
self._check_dynamic_objects(dynamic_objects)
|
|
54
|
+
self._dynamic_objects = dynamic_objects
|
|
55
|
+
|
|
56
|
+
# compute the state_count
|
|
57
|
+
count = 1
|
|
58
|
+
for obj in self.dynamic_objects:
|
|
59
|
+
s_cnt = len(obj.properties.radiance._states)
|
|
60
|
+
if s_cnt > count:
|
|
61
|
+
count = s_cnt
|
|
62
|
+
self._state_count = count
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def identifier(self):
|
|
66
|
+
"""Get a text string for the unique group identifier."""
|
|
67
|
+
return self._identifier
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def dynamic_objects(self):
|
|
71
|
+
"""Get a tuple of objects contained within the group."""
|
|
72
|
+
return self._dynamic_objects
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def state_count(self):
|
|
76
|
+
"""Gat an integer for the total number of states of the dynamic group.
|
|
77
|
+
|
|
78
|
+
This is equal to the number of states in the dynamic_object with the
|
|
79
|
+
highest number of states. After a dynamic_object with fewer states than that
|
|
80
|
+
of it's dynamic group has hit its highest state, it just remains in that
|
|
81
|
+
state as the other dynamic_objects continue to change.
|
|
82
|
+
"""
|
|
83
|
+
return self._state_count
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def is_opaque(self):
|
|
87
|
+
"""Get a boolean for whether all states of all shades in the group are opaque.
|
|
88
|
+
"""
|
|
89
|
+
for obj in self._dynamic_objects:
|
|
90
|
+
for state in obj.properties.radiance._states:
|
|
91
|
+
if not state.modifier.is_opaque:
|
|
92
|
+
return False
|
|
93
|
+
return True
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def is_indoor(self):
|
|
97
|
+
"""Get a boolean for whether all shades in the group are indoor."""
|
|
98
|
+
for obj in self._dynamic_objects:
|
|
99
|
+
if not obj.is_indoor:
|
|
100
|
+
return False
|
|
101
|
+
return True
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def states_json_list(self):
|
|
105
|
+
"""A list for the states.json file that notes the files for each state.
|
|
106
|
+
|
|
107
|
+
The files will follow a standard naming convention as follows.
|
|
108
|
+
<dynamic group identifier>..<field name>..<state count>.rad.
|
|
109
|
+
For instance skylight..direct..000.rad
|
|
110
|
+
"""
|
|
111
|
+
ident = self.identifier
|
|
112
|
+
states_list = []
|
|
113
|
+
for st_i in range(self.state_count):
|
|
114
|
+
states_list.append({
|
|
115
|
+
'identifier': '{}_{}'.format(st_i, ident),
|
|
116
|
+
'default': './{}..default..{}.rad'.format(ident, str(st_i)),
|
|
117
|
+
'direct': './{}..direct..{}.rad'.format(ident, str(st_i))
|
|
118
|
+
})
|
|
119
|
+
return states_list
|
|
120
|
+
|
|
121
|
+
def states_by_index(self, state_index):
|
|
122
|
+
"""Get an array of state objects representing a single state for this group.
|
|
123
|
+
|
|
124
|
+
The resulting array will parallel the dynamic_objects of this group, with
|
|
125
|
+
one state object per dynamic object.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
state_index: An integer from 0 up to the state_count - 1 , which notes
|
|
129
|
+
the state of the group for which a rad string will be produced.
|
|
130
|
+
"""
|
|
131
|
+
# make sure that the state_index is valid
|
|
132
|
+
assert 0 <= state_index < self.state_count, '"{}" is not a valid state index ' \
|
|
133
|
+
'for dynamic group "{}".'.format(state_index, self.identifier)
|
|
134
|
+
|
|
135
|
+
# gather the state objects that correspond to the state_index
|
|
136
|
+
states = []
|
|
137
|
+
for obj in self._dynamic_objects:
|
|
138
|
+
try: # try to get the state at the correct index
|
|
139
|
+
states.append(obj.properties.radiance._states[state_index])
|
|
140
|
+
except IndexError: # use the last state that is available
|
|
141
|
+
try:
|
|
142
|
+
states.append(obj.properties.radiance._states[-1])
|
|
143
|
+
except IndexError: # no states assigned; create default a dummy state
|
|
144
|
+
st = RadianceShadeState()
|
|
145
|
+
st._parent = obj
|
|
146
|
+
states.append(st)
|
|
147
|
+
return states
|
|
148
|
+
|
|
149
|
+
def to_radiance(self, state_index, direct=False, minimal=False):
|
|
150
|
+
"""Generate a RAD string representation of a state for this group.
|
|
151
|
+
|
|
152
|
+
The resulting string includes everything going into a single .rad file
|
|
153
|
+
to simulate the state, including all geometry and modifiers.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
state_index: An integer from 0 up to the state_count - 1 , which notes
|
|
157
|
+
the state of the group for which a rad string will be produced.
|
|
158
|
+
direct: Boolean to note whether to write the "direct" version of the
|
|
159
|
+
state. (Default: False)
|
|
160
|
+
minimal: Boolean to note whether the radiance string should be written
|
|
161
|
+
in a minimal format (with spaces instead of line breaks). Default: False.
|
|
162
|
+
"""
|
|
163
|
+
states = self.states_by_index(state_index)
|
|
164
|
+
|
|
165
|
+
# gather all unique modifiers across the geometry of the state
|
|
166
|
+
modifiers = []
|
|
167
|
+
if not direct:
|
|
168
|
+
for state in states:
|
|
169
|
+
mod = state.modifier
|
|
170
|
+
if not self._instance_in_array(mod, modifiers):
|
|
171
|
+
modifiers.append(mod)
|
|
172
|
+
for shd in state._shades:
|
|
173
|
+
mod = shd.modifier
|
|
174
|
+
if not self._instance_in_array(mod, modifiers):
|
|
175
|
+
modifiers.append(mod)
|
|
176
|
+
else: # use modifier_direct
|
|
177
|
+
for state in states:
|
|
178
|
+
mod = state.modifier_direct
|
|
179
|
+
if not self._instance_in_array(mod, modifiers):
|
|
180
|
+
modifiers.append(mod)
|
|
181
|
+
for shd in state._shades:
|
|
182
|
+
mod = shd.modifier_direct
|
|
183
|
+
if not self._instance_in_array(mod, modifiers):
|
|
184
|
+
modifiers.append(mod)
|
|
185
|
+
modifiers = list(set(modifiers))
|
|
186
|
+
|
|
187
|
+
# get rad strings for all modifier and geometry.
|
|
188
|
+
state_str = ['# STATE {} for "{}"'.format(state_index, self.identifier)]
|
|
189
|
+
for mod in modifiers:
|
|
190
|
+
if isinstance(mod, BSDF):
|
|
191
|
+
self._process_bsdf_modifier(mod, state_str, minimal)
|
|
192
|
+
else:
|
|
193
|
+
state_str.append(mod.to_radiance(minimal))
|
|
194
|
+
for state in states:
|
|
195
|
+
state_str.append(state.to_radiance(direct, minimal))
|
|
196
|
+
return '\n\n'.join(state_str)
|
|
197
|
+
|
|
198
|
+
@staticmethod
|
|
199
|
+
def _check_dynamic_objects(dynamic_objects):
|
|
200
|
+
for obj in dynamic_objects:
|
|
201
|
+
assert isinstance(obj, Shade), \
|
|
202
|
+
'Expected Shade for DynamicShadeGroup. Got {}.'.format(type(obj))
|
|
203
|
+
|
|
204
|
+
@staticmethod
|
|
205
|
+
def _process_bsdf_modifier(modifier, mod_strs, minimal):
|
|
206
|
+
"""Process a BSDF modifier for a radiance model folder."""
|
|
207
|
+
bsdf_name = os.path.split(modifier.bsdf_file)[-1]
|
|
208
|
+
mod_dup = modifier.duplicate() # duplicate to avoid editing the original
|
|
209
|
+
# the hidden _bsdf_file property is edited since the file has not yet been copied
|
|
210
|
+
mod_dup._bsdf_file = os.path.join('model', 'bsdf', bsdf_name)
|
|
211
|
+
mod_strs.insert(1, mod_dup.to_radiance(minimal))
|
|
212
|
+
|
|
213
|
+
@staticmethod
|
|
214
|
+
def _instance_in_array(object_instance, object_array):
|
|
215
|
+
"""Check if a specific object instance is already in an array.
|
|
216
|
+
|
|
217
|
+
This can be much faster than `if object_instance in object_array`
|
|
218
|
+
when you expect to be testing a lot of the same instance of an object for
|
|
219
|
+
inclusion in an array since the builtin method uses an == operator to
|
|
220
|
+
test inclusion.
|
|
221
|
+
"""
|
|
222
|
+
for val in object_array:
|
|
223
|
+
if val is object_instance:
|
|
224
|
+
return True
|
|
225
|
+
return False
|
|
226
|
+
|
|
227
|
+
def __repr__(self):
|
|
228
|
+
return 'Dynamic Shade Group: {}'.format(self.identifier)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class DynamicSubFaceGroup(DynamicShadeGroup):
|
|
232
|
+
"""A group of dynamic Apertures and Doors that change states in unison.
|
|
233
|
+
|
|
234
|
+
Note that this object is not intended to set any Model properties. It is only
|
|
235
|
+
used by the Model to collect objects with the same dynamic_group_identifier
|
|
236
|
+
and export a common set of radiance files from them.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
identifier: Text string for a unique Group ID. Must not contain spaces
|
|
240
|
+
or special characters. This will be used to identify the object across
|
|
241
|
+
a model and in the exported Radiance files.
|
|
242
|
+
dynamic_objects: An array of Shades that are contained within the group.
|
|
243
|
+
|
|
244
|
+
Properties:
|
|
245
|
+
* identifier
|
|
246
|
+
* dynamic_objects
|
|
247
|
+
* state_count
|
|
248
|
+
* is_opaque
|
|
249
|
+
* is_indoor
|
|
250
|
+
* states_json_list
|
|
251
|
+
|
|
252
|
+
"""
|
|
253
|
+
__slots__ = ()
|
|
254
|
+
|
|
255
|
+
def __init__(self, modifier, dynamic_objects):
|
|
256
|
+
"""Initialize DynamicSubFaceGroup."""
|
|
257
|
+
DynamicShadeGroup.__init__(self, modifier, dynamic_objects)
|
|
258
|
+
|
|
259
|
+
@property
|
|
260
|
+
def is_opaque(self):
|
|
261
|
+
"""Always False for dynamic sub-faces."""
|
|
262
|
+
return False
|
|
263
|
+
|
|
264
|
+
@property
|
|
265
|
+
def is_indoor(self):
|
|
266
|
+
"""Get a boolean for whether all sub-faces in the group have a Surface BC."""
|
|
267
|
+
for obj in self._dynamic_objects:
|
|
268
|
+
if not isinstance(obj.boundary_condition, Surface):
|
|
269
|
+
return False
|
|
270
|
+
return True
|
|
271
|
+
|
|
272
|
+
@property
|
|
273
|
+
def states_json_list(self):
|
|
274
|
+
"""A list for the states.json file that notes the files for each state.
|
|
275
|
+
|
|
276
|
+
The files will follow a standard naming convention as follows.
|
|
277
|
+
<dynamic group identifier>..<field name>..<state count>.rad.
|
|
278
|
+
For instance skylight..direct..000.rad
|
|
279
|
+
|
|
280
|
+
Note that this list does not contain the tmtx, vmtx, or dmtx keys
|
|
281
|
+
and these should be added separately if this states.json is to be used for
|
|
282
|
+
3-phase studies.
|
|
283
|
+
"""
|
|
284
|
+
ident = self.identifier
|
|
285
|
+
states_list = []
|
|
286
|
+
for st_i in range(self.state_count):
|
|
287
|
+
states_list.append({
|
|
288
|
+
'identifier': '{}_{}'.format(st_i, ident),
|
|
289
|
+
'default': './{}..default..{}.rad'.format(ident, str(st_i)),
|
|
290
|
+
'direct': './{}..direct..{}.rad'.format(ident, str(st_i)),
|
|
291
|
+
'black': './{}..black.rad'.format(ident)
|
|
292
|
+
})
|
|
293
|
+
return states_list
|
|
294
|
+
|
|
295
|
+
def rfluxmtx_control_params(self, state_index=0, sampling=None, up_direction=None):
|
|
296
|
+
"""Create a formatted Rfluxmtx control parameters string.
|
|
297
|
+
|
|
298
|
+
The optional values are sampling and up_direction. If these values are not
|
|
299
|
+
provided they will be assigned based on the first State of the dynamic object.
|
|
300
|
+
|
|
301
|
+
The control params are only meaningful for BSDF modifiers with one of the
|
|
302
|
+
sampling types listed below.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
sampling: Set hemisphere sampling type. Acceptable inputs for hemisphere
|
|
306
|
+
sampling type are:
|
|
307
|
+
|
|
308
|
+
* u for uniform.(Usually applicable for ground).
|
|
309
|
+
* kf for klems full.
|
|
310
|
+
* kh for klems half.
|
|
311
|
+
* kq for klems quarter.
|
|
312
|
+
* rN for Reinhart - Tregenza type skies. N stands for subdivisions
|
|
313
|
+
and defaults to 1.
|
|
314
|
+
* scN for shirley-chiu subdivisions.
|
|
315
|
+
|
|
316
|
+
Add a ``-`` in front of the input for left-handed coordinates. For more
|
|
317
|
+
information see rfluxmtx docs.
|
|
318
|
+
https://www.radiance-online.org/learning/documentation/manual-pages/pdfs/rfluxmtx.pdf/at_download/file
|
|
319
|
+
up_direction: Orient the "up" direction for the hemisphere using the
|
|
320
|
+
indicated axis or a direction vector. Valid inputs include the
|
|
321
|
+
following. [-]{X|Y|Z|ux,uy,uz}. (Default: Y).
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
RfluxmtxControlParameters
|
|
325
|
+
|
|
326
|
+
"""
|
|
327
|
+
state = self.states_by_index(state_index)[0]
|
|
328
|
+
if up_direction is None:
|
|
329
|
+
up_direction = state.vmtx_geometry.plane.y
|
|
330
|
+
if sampling is None:
|
|
331
|
+
sampling = state.modifier.sampling_type
|
|
332
|
+
if sampling is None:
|
|
333
|
+
raise ValueError(
|
|
334
|
+
'Rfluxmtx control parameters can only be generated for states '
|
|
335
|
+
'with BSDF modifier. Current modifier: %s is a %s.' % (
|
|
336
|
+
state.modifier, self.modifier.__class__.__name__)
|
|
337
|
+
)
|
|
338
|
+
up_direction = tuple(up_direction)
|
|
339
|
+
return RfluxmtxControlParameters(sampling, up_direction)
|
|
340
|
+
|
|
341
|
+
def states_by_index(self, state_index):
|
|
342
|
+
"""Get an array of state objects representing a single state for this group.
|
|
343
|
+
|
|
344
|
+
The resulting array will parallel the dynamic_objects of this group, with
|
|
345
|
+
one state object per dynamic object.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
state_index: An integer from 0 up to the state_count - 1 , which notes
|
|
349
|
+
the state of the group for which a rad string will be produced.
|
|
350
|
+
"""
|
|
351
|
+
# make sure that the state_index is valid
|
|
352
|
+
assert 0 <= state_index < self.state_count, '"{}" is not a valid state index ' \
|
|
353
|
+
'for dynamic group "{}".'.format(state_index, self.identifier)
|
|
354
|
+
|
|
355
|
+
# gather the state objects that correspond to the state_index
|
|
356
|
+
states = []
|
|
357
|
+
for obj in self._dynamic_objects:
|
|
358
|
+
try: # try to get the state at the correct index
|
|
359
|
+
states.append(obj.properties.radiance._states[state_index])
|
|
360
|
+
except IndexError: # use the last state that is available
|
|
361
|
+
try:
|
|
362
|
+
states.append(obj.properties.radiance._states[-1])
|
|
363
|
+
except IndexError: # no states assigned; create default a dummy state
|
|
364
|
+
st = RadianceSubFaceState()
|
|
365
|
+
st._parent = obj
|
|
366
|
+
states.append(st)
|
|
367
|
+
return states
|
|
368
|
+
|
|
369
|
+
def blk_to_radiance(self, minimal=False):
|
|
370
|
+
"""Generate a RAD string for the black representation of this group.
|
|
371
|
+
|
|
372
|
+
The resulting string includes everything going into the black .rad file,
|
|
373
|
+
including all geometry and modifiers.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
minimal: Boolean to note whether the radiance string should be written
|
|
377
|
+
in a minimal format (with spaces instead of line breaks). Default: False.
|
|
378
|
+
"""
|
|
379
|
+
# gather all unique modifier_blk and write geometry rad strings
|
|
380
|
+
blk_str = ['# BLACK representation for "{}"'.format(self.identifier)]
|
|
381
|
+
modifiers = []
|
|
382
|
+
for obj in self._dynamic_objects:
|
|
383
|
+
mod = obj.properties.radiance.modifier_blk
|
|
384
|
+
base_poly = Polygon(obj.identifier, obj.vertices, mod)
|
|
385
|
+
blk_str.append(base_poly.to_radiance(minimal, False, False))
|
|
386
|
+
if not self._instance_in_array(mod, modifiers):
|
|
387
|
+
modifiers.append(mod)
|
|
388
|
+
modifiers = list(set(modifiers))
|
|
389
|
+
|
|
390
|
+
# get rad strings for all modifiers.
|
|
391
|
+
for mod in modifiers:
|
|
392
|
+
if isinstance(mod, BSDF):
|
|
393
|
+
self._process_bsdf_modifier(mod, blk_str, minimal)
|
|
394
|
+
else:
|
|
395
|
+
blk_str.insert(1, mod.to_radiance(minimal))
|
|
396
|
+
return '\n\n'.join(blk_str)
|
|
397
|
+
|
|
398
|
+
def tmxt_bsdf(self, state_index):
|
|
399
|
+
"""A BSDF modifier representing the tranmission matrix of a state if it exists.
|
|
400
|
+
|
|
401
|
+
This will be None unless all of the objects in the group have the same
|
|
402
|
+
BSDF modifier for the state. Note that having a single tmxt_bsdf
|
|
403
|
+
is a requirement in order to be compatible with 3-phase and 5-phase
|
|
404
|
+
simulation.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
state_index: An integer from 0 up to the state_count - 1 , which notes
|
|
408
|
+
the state of the group for which a rad string will be produced.
|
|
409
|
+
"""
|
|
410
|
+
bsdf_mods = []
|
|
411
|
+
for state in self.states_by_index(state_index):
|
|
412
|
+
mod = state.modifier
|
|
413
|
+
if not isinstance(mod, BSDF):
|
|
414
|
+
return None # not a BSDF; not valid for 3-phase
|
|
415
|
+
elif not self._instance_in_array(mod, bsdf_mods):
|
|
416
|
+
bsdf_mods.append(mod)
|
|
417
|
+
if len(set(bsdf_mods)) != 1:
|
|
418
|
+
return None # more than one type of BSDF; not valid for 3-phase
|
|
419
|
+
return bsdf_mods[0] # just one BSDF for the t_mtx; it's valid!
|
|
420
|
+
|
|
421
|
+
def vmtx_to_radiance(self, state_index, minimal=False):
|
|
422
|
+
"""Generate a vmtx RAD string representation of a state.
|
|
423
|
+
|
|
424
|
+
The resulting string has all geometry geometry and the white_glow modifier.
|
|
425
|
+
|
|
426
|
+
Args:
|
|
427
|
+
state_index: An integer from 0 up to the state_count - 1 , which notes
|
|
428
|
+
the state of the group for which a rad string will be produced.
|
|
429
|
+
minimal: Boolean to note whether the radiance string should be written
|
|
430
|
+
in a minimal format (with spaces instead of line breaks). Default: False.
|
|
431
|
+
"""
|
|
432
|
+
states = self.states_by_index(state_index)
|
|
433
|
+
# create unique glow modifier for aperture group
|
|
434
|
+
unique_glow = white_glow.duplicate()
|
|
435
|
+
unique_glow.identifier = 'white_glow_{}'.format(self.identifier)
|
|
436
|
+
# get rad strings for the white_glow modifier and geometry.
|
|
437
|
+
state_str = ['# VMTX representation for "{}"'.format(self.identifier),
|
|
438
|
+
unique_glow.to_radiance(minimal)]
|
|
439
|
+
|
|
440
|
+
# use first state to add the header
|
|
441
|
+
header = self.rfluxmtx_control_params(state_index=state_index)
|
|
442
|
+
state_str.append(header.to_radiance())
|
|
443
|
+
|
|
444
|
+
for state in states:
|
|
445
|
+
state_str.append(state.vmtx_to_radiance(unique_glow, minimal))
|
|
446
|
+
return '\n\n'.join(state_str)
|
|
447
|
+
|
|
448
|
+
def dmtx_to_radiance(self, state_index, minimal=False):
|
|
449
|
+
"""Generate a dmtx RAD string representation of a state.
|
|
450
|
+
|
|
451
|
+
The resulting string has all geometry geometry and the white_glow modifier.
|
|
452
|
+
|
|
453
|
+
Args:
|
|
454
|
+
state_index: An integer from 0 up to the state_count - 1 , which notes
|
|
455
|
+
the state of the group for which a rad string will be produced.
|
|
456
|
+
minimal: Boolean to note whether the radiance string should be written
|
|
457
|
+
in a minimal format (with spaces instead of line breaks). Default: False.
|
|
458
|
+
"""
|
|
459
|
+
states = self.states_by_index(state_index)
|
|
460
|
+
# get rad strings for the white_glow modifier and geometry.
|
|
461
|
+
state_str = ['# DMTX representation for "{}"'.format(self.identifier),
|
|
462
|
+
white_glow.to_radiance(minimal)]
|
|
463
|
+
|
|
464
|
+
# use first state to add the header
|
|
465
|
+
header = self.rfluxmtx_control_params()
|
|
466
|
+
state_str.append(header.to_radiance())
|
|
467
|
+
|
|
468
|
+
for state in states:
|
|
469
|
+
state_str.append(state.dmtx_to_radiance(minimal))
|
|
470
|
+
return '\n\n'.join(state_str)
|
|
471
|
+
|
|
472
|
+
@staticmethod
|
|
473
|
+
def _check_dynamic_objects(dynamic_objects):
|
|
474
|
+
for obj in dynamic_objects:
|
|
475
|
+
assert isinstance(obj, (Aperture, Door)), 'Expected Aperture or Door ' \
|
|
476
|
+
'for DynamicSubFaceGroup. Got {}.'.format(type(obj))
|
|
477
|
+
|
|
478
|
+
def __repr__(self):
|
|
479
|
+
return 'Dynamic SubFace Group: {}'.format(self.identifier)
|