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,400 @@
|
|
|
1
|
+
"""honeybee radiance translation commands."""
|
|
2
|
+
import click
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
import logging
|
|
6
|
+
import json
|
|
7
|
+
import zipfile
|
|
8
|
+
import shutil
|
|
9
|
+
|
|
10
|
+
from ladybug.commandutil import process_content_to_output
|
|
11
|
+
from honeybee_radiance.reader import string_to_dicts
|
|
12
|
+
from honeybee_radiance.mutil import dict_to_modifier, modifier_class_from_type_string
|
|
13
|
+
|
|
14
|
+
from honeybee.model import Model
|
|
15
|
+
from ladybug.futil import preparedir, unzip_file
|
|
16
|
+
|
|
17
|
+
_logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@click.group(help='Commands for translating Honeybee JSON files to/from RAD.')
|
|
21
|
+
def translate():
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@translate.command('model-to-rad-folder')
|
|
26
|
+
@click.argument('model-file', type=click.Path(
|
|
27
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
28
|
+
@click.option(
|
|
29
|
+
'--folder', help='Folder into which the model Radiance '
|
|
30
|
+
'folders will be written. If None, the files will be output in the '
|
|
31
|
+
'same location as the model_file.', default=None, show_default=True
|
|
32
|
+
)
|
|
33
|
+
@click.option(
|
|
34
|
+
'--grid', '-g', multiple=True, help='List of grids to be included in folder. By '
|
|
35
|
+
'default all the sensor grids will be exported. You can also use wildcards here. '
|
|
36
|
+
'For instance first_floor_* will select all the sensor grids that has an identifier '
|
|
37
|
+
'that starts with first_floor. To filter based on group_identifier use /. For '
|
|
38
|
+
'example daylight/* will select all the grids that belong to daylight group.')
|
|
39
|
+
@click.option(
|
|
40
|
+
'--view', '-v', multiple=True, help='List of views to be included in folder. By '
|
|
41
|
+
'default all the views will be exported. You can also use wildcards to filter '
|
|
42
|
+
'multiple views. For instance first_floor_* will select all the views that has an '
|
|
43
|
+
'identifier that starts with first_floor. To filter based on group_identifier use '
|
|
44
|
+
'/. For example daylight/* will select all the views that belong to daylight group.')
|
|
45
|
+
@click.option(
|
|
46
|
+
'--full-match/--no-full-match', help='Flag to note whether the grids and'
|
|
47
|
+
'views should be filtered by their identifiers as full matches. Setting '
|
|
48
|
+
'this to True indicates that wildcard symbols will not be used in the '
|
|
49
|
+
'filtering of grids and views.', default=False, show_default=True)
|
|
50
|
+
@click.option(
|
|
51
|
+
'--config-file', '-c', help='An optional config file path to modify the '
|
|
52
|
+
'default folder names. If None, folder.cfg in honeybee-radiance-folder '
|
|
53
|
+
'will be used.', default=None, show_default=True)
|
|
54
|
+
@click.option(
|
|
55
|
+
'--minimal/--maximal', '-min/-max', help='Flag to note whether the radiance strings '
|
|
56
|
+
'should be written in a minimal format (with spaces instead of line '
|
|
57
|
+
'breaks).', default=False, show_default=True)
|
|
58
|
+
@click.option(
|
|
59
|
+
'--no-grid-check/--grid-check', ' /-gc', help='Flag to note whether the '
|
|
60
|
+
'model should be checked for the presence of sensor grids. If the check '
|
|
61
|
+
'is set and the model has no grids, an explicit error will be raised.',
|
|
62
|
+
default=True, show_default=True)
|
|
63
|
+
@click.option(
|
|
64
|
+
'--no-view-check/--view-check', ' /-vc', help='Flag to note whether the '
|
|
65
|
+
'model should be checked for the presence of views. If the check '
|
|
66
|
+
'is set and the model has no views, an explicit error will be raised.',
|
|
67
|
+
default=True, show_default=True)
|
|
68
|
+
@click.option(
|
|
69
|
+
'--create-grids', '-cg', default=False, show_default=True, is_flag=True,
|
|
70
|
+
help='Flag to note whether sensor grids should be created if none exists. '
|
|
71
|
+
'This will only create sensor grids for rooms if there are no sensor grids '
|
|
72
|
+
'in the model.'
|
|
73
|
+
)
|
|
74
|
+
@click.option(
|
|
75
|
+
'--log-file', help='Optional log file to output the path of the radiance '
|
|
76
|
+
'folder generated from the model. By default this will be printed '
|
|
77
|
+
'to stdout', type=click.File('w'), default='-')
|
|
78
|
+
def model_to_rad_folder_cli(
|
|
79
|
+
model_file, folder, view, grid, full_match, config_file, minimal,
|
|
80
|
+
no_grid_check, no_view_check, create_grids, log_file):
|
|
81
|
+
"""Translate a Model file into a Radiance Folder.
|
|
82
|
+
|
|
83
|
+
\b
|
|
84
|
+
Args:
|
|
85
|
+
model_file: Full path to a Model JSON file (HBJSON) or a Model
|
|
86
|
+
pkl (HBpkl) file. This can also be a zipped version of a Radiance
|
|
87
|
+
folder, in which case this command will simply unzip the file
|
|
88
|
+
into the --folder and no other operations will be performed on it.
|
|
89
|
+
"""
|
|
90
|
+
try:
|
|
91
|
+
grid_check = not no_grid_check
|
|
92
|
+
view_check = not no_view_check
|
|
93
|
+
model_to_rad_folder(
|
|
94
|
+
model_file, folder, view, grid, full_match, config_file,
|
|
95
|
+
minimal, grid_check, view_check, log_file, create_grids=create_grids)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
_logger.exception('Model translation failed.\n{}'.format(e))
|
|
98
|
+
sys.exit(1)
|
|
99
|
+
else:
|
|
100
|
+
sys.exit(0)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def model_to_rad_folder(
|
|
104
|
+
model_file, folder=None, view=None, grid=None, full_match=False, config_file=None,
|
|
105
|
+
minimal=False, grid_check=False, view_check=False, log_file=None,
|
|
106
|
+
no_full_match=True, maximal=True, no_grid_check=False, no_view_check=False,
|
|
107
|
+
create_grids=False):
|
|
108
|
+
"""Translate a Model file into a Radiance Folder.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
model_file: Full path to a Model JSON file (HBJSON) or a Model
|
|
112
|
+
pkl (HBpkl) file. This can also be a zipped version of a Radiance
|
|
113
|
+
folder, in which case this command will simply unzip the file
|
|
114
|
+
into the --folder and no other operations will be performed on it.
|
|
115
|
+
folder: Folder into which the model Radiance folders will be written.
|
|
116
|
+
If None, the files will be output in the same location as the model_file.
|
|
117
|
+
view: List of grids to be included in folder. By default all the sensor
|
|
118
|
+
grids will be exported. You can also use wildcards here. For instance
|
|
119
|
+
first_floor_* will select all the sensor grids that has an identifier
|
|
120
|
+
that starts with first_floor. To filter based on group_identifier
|
|
121
|
+
use /. For example daylight/* will select all the grids that belong
|
|
122
|
+
to daylight group. (Default: None).
|
|
123
|
+
grid: List of views to be included in folder. By default all the views
|
|
124
|
+
will be exported. You can also use wildcards to filter multiple views.
|
|
125
|
+
For instance first_floor_* will select all the views that has an
|
|
126
|
+
identifier that starts with first_floor. To filter based on
|
|
127
|
+
group_identifier use /. For example daylight/* will select all the
|
|
128
|
+
views that belong to daylight group. (Default: None).
|
|
129
|
+
full_match: Boolean to note whether the grids and views should be
|
|
130
|
+
filtered by their identifiers as full matches. Setting this to
|
|
131
|
+
True indicates that wildcard symbols will not be used in the
|
|
132
|
+
filtering of grids and views. (Default: False).
|
|
133
|
+
config_file: An optional config file path to modify the default folder
|
|
134
|
+
names. If None, folder.cfg in honeybee-radiance-folder will be used.
|
|
135
|
+
minimal: Boolean to note whether the radiance strings should be written
|
|
136
|
+
in a minimal format (with spaces instead of line breaks). (Default: False).
|
|
137
|
+
grid_check: Boolean to note whether the model should be checked for the
|
|
138
|
+
presence of sensor grids. If the check is set and the model has no
|
|
139
|
+
grids, an explicit error will be raised. (Default: False).
|
|
140
|
+
view_check: Boolean to note whether the model should be checked for the
|
|
141
|
+
presence of views. If the check is set and the model has no views,
|
|
142
|
+
an explicit error will be raised. (Default: False).
|
|
143
|
+
log_file: Optional log file to output the path of the radiance folder
|
|
144
|
+
generated from the model. If None, it will be returned from this method.
|
|
145
|
+
"""
|
|
146
|
+
# set the default folder if it's not specified
|
|
147
|
+
if folder is None:
|
|
148
|
+
folder = os.path.dirname(os.path.abspath(model_file))
|
|
149
|
+
|
|
150
|
+
# first check to see if the model_file is a zipped radiance folder
|
|
151
|
+
if zipfile.is_zipfile(model_file):
|
|
152
|
+
unzip_file(model_file, folder)
|
|
153
|
+
if log_file is None:
|
|
154
|
+
return folder
|
|
155
|
+
else:
|
|
156
|
+
log_file.write(folder)
|
|
157
|
+
else:
|
|
158
|
+
# re-serialize the Model and perform any checks
|
|
159
|
+
model = Model.from_file(model_file)
|
|
160
|
+
|
|
161
|
+
if create_grids:
|
|
162
|
+
if not model.properties.radiance.has_sensor_grids:
|
|
163
|
+
sensor_grids = []
|
|
164
|
+
|
|
165
|
+
unit_conversion = {
|
|
166
|
+
'Meters': 1,
|
|
167
|
+
'Millimeters': 0.001,
|
|
168
|
+
'Centimeters': 0.01,
|
|
169
|
+
'Feet': 0.3048,
|
|
170
|
+
'Inches': 0.0254
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if model.units in ['Meters', 'Millimeters', 'Centimeters']:
|
|
174
|
+
grid_size = 0.5 / unit_conversion[model.units]
|
|
175
|
+
offset = 0.76 / unit_conversion[model.units]
|
|
176
|
+
wall_offset = 0.3 / unit_conversion[model.units]
|
|
177
|
+
else: # assume IP units
|
|
178
|
+
grid_size = 2 * 0.3048 / unit_conversion[model.units]
|
|
179
|
+
offset = 2.5 * 0.3048 / unit_conversion[model.units]
|
|
180
|
+
wall_offset = 1 * 0.3048 / unit_conversion[model.units]
|
|
181
|
+
|
|
182
|
+
for room in model.rooms:
|
|
183
|
+
sensor_grids.append(room.properties.radiance.generate_sensor_grid(
|
|
184
|
+
grid_size, offset=offset, wall_offset=wall_offset))
|
|
185
|
+
model.properties.radiance.sensor_grids = sensor_grids
|
|
186
|
+
model.to_hbjson('output_model', '.')
|
|
187
|
+
else:
|
|
188
|
+
file_extension = os.path.splitext(model_file)[1]
|
|
189
|
+
shutil.copy(model_file, 'output_model' + file_extension)
|
|
190
|
+
|
|
191
|
+
if grid_check and len(model.properties.radiance.sensor_grids) == 0:
|
|
192
|
+
raise ValueError('Model contains no sensor grids. These are required.')
|
|
193
|
+
if view_check and len(model.properties.radiance.views) == 0:
|
|
194
|
+
raise ValueError('Model contains no views These are required.')
|
|
195
|
+
|
|
196
|
+
# translate the model to a radiance folder
|
|
197
|
+
rad_fold = model.to.rad_folder(
|
|
198
|
+
model, folder, config_file, minimal, views=view, grids=grid,
|
|
199
|
+
full_match=full_match
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if log_file is None:
|
|
203
|
+
return rad_fold
|
|
204
|
+
else:
|
|
205
|
+
log_file.write(rad_fold)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@translate.command('model-to-rad')
|
|
209
|
+
@click.argument('model-file', type=click.Path(
|
|
210
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
211
|
+
@click.option('--blk', help='Flag to note whether the "blacked out" version '
|
|
212
|
+
'of the geometry should be output, which is useful for direct studies '
|
|
213
|
+
'and isolation studies of individual apertures.',
|
|
214
|
+
default=False, show_default=True)
|
|
215
|
+
@click.option('--minimal/--maximal', help='Flag to note whether the radiance strings '
|
|
216
|
+
'should be written in a minimal format (with spaces instead of line '
|
|
217
|
+
'breaks).', default=False, show_default=True)
|
|
218
|
+
@click.option('--output-file', help='Optional RAD file to output the RAD string of the '
|
|
219
|
+
'translation. By default this will be printed out to stdout',
|
|
220
|
+
type=click.File('w'), default='-', show_default=True)
|
|
221
|
+
def model_to_rad_cli(model_file, blk, minimal, output_file):
|
|
222
|
+
"""Translate a Model file to a Radiance string.
|
|
223
|
+
|
|
224
|
+
The resulting strings will include all geometry (Rooms, Faces, Shades, Apertures,
|
|
225
|
+
Doors) and all modifiers. However, it does not include any states for dynamic
|
|
226
|
+
geometry and will only write the default state for each dynamic object. To
|
|
227
|
+
correctly account for dynamic objects, model-to-rad-folder should be used.
|
|
228
|
+
|
|
229
|
+
\b
|
|
230
|
+
Args:
|
|
231
|
+
model_file: Full path to a Model JSON file (HBJSON) or a Model pkl (HBpkl) file.
|
|
232
|
+
"""
|
|
233
|
+
try:
|
|
234
|
+
model_to_rad(model_file, blk, minimal, output_file)
|
|
235
|
+
except Exception as e:
|
|
236
|
+
_logger.exception('Model translation failed.\n{}'.format(e))
|
|
237
|
+
sys.exit(1)
|
|
238
|
+
else:
|
|
239
|
+
sys.exit(0)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def model_to_rad(model_file, blk=False, minimal=False, output_file=None, maximal=True):
|
|
243
|
+
"""Translate a Model file to a Radiance string.
|
|
244
|
+
|
|
245
|
+
The resulting strings will include all geometry (Rooms, Faces, Shades, Apertures,
|
|
246
|
+
Doors) and all modifiers. However, it does not include any states for dynamic
|
|
247
|
+
geometry and will only write the default state for each dynamic object. To
|
|
248
|
+
correctly account for dynamic objects, model-to-rad-folder should be used.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
model_file: Full path to a Model JSON file (HBJSON) or a Model pkl (HBpkl) file.
|
|
252
|
+
blk: Boolean to note whether the "blacked out" version of the geometry
|
|
253
|
+
should be output, which is useful for direct studies and isolation
|
|
254
|
+
studies of individual apertures.
|
|
255
|
+
minimal: Boolean to note whether the radiance strings should be written
|
|
256
|
+
in a minimal format (with spaces instead of line breaks).
|
|
257
|
+
output_file: Optional RAD file to output the RAD string of the translation.
|
|
258
|
+
If None, the string will be returned from this method. (Default: None).
|
|
259
|
+
"""
|
|
260
|
+
# re-serialize the Model and translate the model to a rad string
|
|
261
|
+
model = Model.from_file(model_file)
|
|
262
|
+
model_str, modifier_str = model.to.rad(model, blk, minimal)
|
|
263
|
+
rad_str_list = ['# ======== MODEL MODIFIERS ========', modifier_str,
|
|
264
|
+
'# ======== MODEL GEOMETRY ========', model_str]
|
|
265
|
+
rad_str = '\n\n'.join(rad_str_list)
|
|
266
|
+
|
|
267
|
+
# write out the rad string
|
|
268
|
+
return process_content_to_output(rad_str, output_file)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@translate.command('model-radiant-enclosure-info')
|
|
272
|
+
@click.argument('model-file', type=click.Path(
|
|
273
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
274
|
+
@click.option('--folder', help='Folder into which the radiant enclosure info JSONs '
|
|
275
|
+
'will be written. If None, the files will be output in the'
|
|
276
|
+
'same location as the model_file in an enclosure subfolder.',
|
|
277
|
+
default=None, show_default=True)
|
|
278
|
+
@click.option('--log-file', help='Optional log file to output the list of generated '
|
|
279
|
+
'radiant enclosure JSONs. By default this will be printed '
|
|
280
|
+
'to stdout', type=click.File('w'), default='-')
|
|
281
|
+
def model_radiant_enclosure_info(model_file, folder, log_file):
|
|
282
|
+
"""Translate a Model file to a list of JSONs with radiant enclosure information.
|
|
283
|
+
|
|
284
|
+
There will be one radiant enclosure JSON for each Model SensorGrid written to
|
|
285
|
+
the output folder and each JSON will contain a list of values about which room
|
|
286
|
+
(or radiant enclosure) each sensor is located. JSONs will also include a mapper
|
|
287
|
+
that links the integers of each sensor with the identifier(s) of a room.
|
|
288
|
+
|
|
289
|
+
\b
|
|
290
|
+
Args:
|
|
291
|
+
model_file: Full path to a Model JSON file (HBJSON) or a Model pkl (HBpkl) file.
|
|
292
|
+
"""
|
|
293
|
+
try:
|
|
294
|
+
# re-serialize the Model
|
|
295
|
+
model = Model.from_file(model_file)
|
|
296
|
+
|
|
297
|
+
# set the default folder if it's not specified
|
|
298
|
+
if folder is None:
|
|
299
|
+
folder = os.path.dirname(os.path.abspath(model_file))
|
|
300
|
+
folder = os.path.join(folder, 'enclosure')
|
|
301
|
+
if not os.path.isdir(folder):
|
|
302
|
+
preparedir(folder) # create the directory if it's not there
|
|
303
|
+
|
|
304
|
+
# loop through sensor grids and build up the radiant enclosure dicts
|
|
305
|
+
grids_info = []
|
|
306
|
+
for grid in model.properties.radiance.sensor_grids:
|
|
307
|
+
# write an enclosure JSON for each grid
|
|
308
|
+
enc_dict = grid.enclosure_info_dict(model)
|
|
309
|
+
enclosure_file = os.path.join(folder, '{}.json'.format(grid.identifier))
|
|
310
|
+
with open(enclosure_file, 'w') as fp:
|
|
311
|
+
json.dump(enc_dict, fp)
|
|
312
|
+
g_info = {
|
|
313
|
+
'id': grid.identifier,
|
|
314
|
+
'enclosure_path': enclosure_file,
|
|
315
|
+
'enclosure_full_path': os.path.abspath(enclosure_file),
|
|
316
|
+
'count': grid.count
|
|
317
|
+
}
|
|
318
|
+
grids_info.append(g_info)
|
|
319
|
+
|
|
320
|
+
# write out the list of radiant enclosure JSON info
|
|
321
|
+
log_file.write(json.dumps(grids_info, indent=4))
|
|
322
|
+
except Exception as e:
|
|
323
|
+
_logger.exception('Model translation to radiant enclosure failed.\n{}'.format(e))
|
|
324
|
+
sys.exit(1)
|
|
325
|
+
else:
|
|
326
|
+
sys.exit(0)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
@translate.command('modifiers-to-rad')
|
|
330
|
+
@click.argument('modifier-json', type=click.Path(
|
|
331
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
332
|
+
@click.option('--minimal/--maximal', help='Flag to note whether the radiance strings '
|
|
333
|
+
'should be written in a minimal format (with spaces instead of line '
|
|
334
|
+
'breaks).', default=False, show_default=True)
|
|
335
|
+
@click.option('--output-file', help='Optional RAD file to output the RAD string of the '
|
|
336
|
+
'translation. By default this will be printed out to stdout',
|
|
337
|
+
type=click.File('w'), default='-', show_default=True)
|
|
338
|
+
def modifier_to_rad(modifier_json, minimal, output_file):
|
|
339
|
+
"""Translate a Modifier JSON file to an RAD using direct-to-rad translators.
|
|
340
|
+
\n
|
|
341
|
+
Args:
|
|
342
|
+
modifier_json: Full path to a Modifier JSON file. This file should
|
|
343
|
+
either be an array of non-abridged Modifiers or a dictionary where
|
|
344
|
+
the values are non-abridged Modifiers.
|
|
345
|
+
"""
|
|
346
|
+
try:
|
|
347
|
+
# re-serialize the Modifiers to Python
|
|
348
|
+
with open(modifier_json) as json_file:
|
|
349
|
+
data = json.load(json_file)
|
|
350
|
+
mod_list = data.values() if isinstance(data, dict) else data
|
|
351
|
+
mod_objs = []
|
|
352
|
+
for mod_dict in mod_list:
|
|
353
|
+
m_class = modifier_class_from_type_string(mod_dict['type'].lower())
|
|
354
|
+
mod_objs.append(m_class.from_dict(mod_dict))
|
|
355
|
+
|
|
356
|
+
# create the RAD strings
|
|
357
|
+
rad_str_list = []
|
|
358
|
+
rad_str_list.extend([mod.to_radiance(minimal) for mod in mod_objs])
|
|
359
|
+
rad_str = '\n\n'.join(rad_str_list)
|
|
360
|
+
|
|
361
|
+
# write out the RAD file
|
|
362
|
+
output_file.write(rad_str)
|
|
363
|
+
except Exception as e:
|
|
364
|
+
_logger.exception('Modifier translation failed.\n{}'.format(e))
|
|
365
|
+
sys.exit(1)
|
|
366
|
+
else:
|
|
367
|
+
sys.exit(0)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@translate.command('modifiers-from-rad')
|
|
371
|
+
@click.argument('modifier-rad', type=click.Path(
|
|
372
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
373
|
+
@click.option('--output-file', help='Optional JSON file to output the JSON string of the'
|
|
374
|
+
'translation. By default this will be printed out to stdout',
|
|
375
|
+
type=click.File('w'), default='-', show_default=True)
|
|
376
|
+
def modifier_from_rad(modifier_rad, output_file):
|
|
377
|
+
"""Translate a Modifier JSON file to a honeybee JSON as an array of modifiers.
|
|
378
|
+
\n
|
|
379
|
+
Args:
|
|
380
|
+
modifier_rad: Full path to a Modifier .rad or .mat file. Only the modifiers
|
|
381
|
+
and materials in this file will be extracted.
|
|
382
|
+
"""
|
|
383
|
+
try:
|
|
384
|
+
# re-serialize the Modifiers to Python
|
|
385
|
+
mod_objs = []
|
|
386
|
+
with open(modifier_rad) as f:
|
|
387
|
+
rad_dicts = string_to_dicts(f.read())
|
|
388
|
+
for mod_dict in rad_dicts:
|
|
389
|
+
mod_objs.append(dict_to_modifier(mod_dict))
|
|
390
|
+
|
|
391
|
+
# create the honeybee dictionaries
|
|
392
|
+
json_dicts = [mod.to_dict() for mod in mod_objs]
|
|
393
|
+
|
|
394
|
+
# write out the JSON file
|
|
395
|
+
output_file.write(json.dumps(json_dicts))
|
|
396
|
+
except Exception as e:
|
|
397
|
+
_logger.exception('Modifier translation failed.\n{}'.format(e))
|
|
398
|
+
sys.exit(1)
|
|
399
|
+
else:
|
|
400
|
+
sys.exit(0)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from ladybug.analysisperiod import AnalysisPeriod
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
import copy
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_hoys(start_date, start_time, end_date, end_time, timestep, leap_year):
|
|
7
|
+
"""Return list of hours from start date, star hour, end date and end hour.
|
|
8
|
+
|
|
9
|
+
Date should be formatted as MMM-DD (e.g JUL-21) and hours must be formatted
|
|
10
|
+
as HH:MM (e.g 18:30).
|
|
11
|
+
"""
|
|
12
|
+
# convert datetimes
|
|
13
|
+
try:
|
|
14
|
+
start_date = datetime.strptime(start_date, '%b-%d')
|
|
15
|
+
except ValueError as e:
|
|
16
|
+
raise ValueError('Wrong input for start date:\n\t{}'.format(e))
|
|
17
|
+
try:
|
|
18
|
+
start_time = datetime.strptime(start_time, '%H:%M')
|
|
19
|
+
except ValueError as e:
|
|
20
|
+
raise ValueError('Wrong input for start time:\n\t{}'.format(e))
|
|
21
|
+
try:
|
|
22
|
+
end_date = datetime.strptime(end_date, '%b-%d')
|
|
23
|
+
except ValueError as e:
|
|
24
|
+
raise ValueError('Wrong input for end date:\n\t{}'.format(e))
|
|
25
|
+
try:
|
|
26
|
+
end_time = datetime.strptime(end_time, '%H:%M')
|
|
27
|
+
except ValueError as e:
|
|
28
|
+
raise ValueError('Wrong input for end time:\n\t{}'.format(e))
|
|
29
|
+
|
|
30
|
+
org_end_time = copy.copy(end_time)
|
|
31
|
+
if end_time.minute != 0:
|
|
32
|
+
if end_time.hour != 23:
|
|
33
|
+
end_time = datetime(
|
|
34
|
+
end_time.year, end_time.month, end_time.day, end_time.hour + 1, 0
|
|
35
|
+
)
|
|
36
|
+
else:
|
|
37
|
+
end_time = datetime(
|
|
38
|
+
end_time.year, end_time.month, end_time.day + 1, 0, 0
|
|
39
|
+
)
|
|
40
|
+
ap = AnalysisPeriod(
|
|
41
|
+
start_date.month, start_date.day, start_time.hour,
|
|
42
|
+
end_date.month, end_date.day, end_time.hour,
|
|
43
|
+
timestep, leap_year
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
hoys = ap.hoys
|
|
47
|
+
|
|
48
|
+
# filter start and end hours if needed
|
|
49
|
+
start_index = 0
|
|
50
|
+
end_index = None
|
|
51
|
+
if start_time.minute != 0:
|
|
52
|
+
# remove the hours that are smaller than this hour
|
|
53
|
+
for start_index, h in enumerate(hoys):
|
|
54
|
+
if round(60 * h) % 60 >= start_time.minute:
|
|
55
|
+
break
|
|
56
|
+
|
|
57
|
+
if org_end_time.minute != 0:
|
|
58
|
+
for end_index, h in enumerate(reversed(hoys)):
|
|
59
|
+
if (60 * h) % 60 <= org_end_time.minute:
|
|
60
|
+
break
|
|
61
|
+
|
|
62
|
+
if start_index == 0 and end_index is None:
|
|
63
|
+
return hoys
|
|
64
|
+
elif end_index is None:
|
|
65
|
+
return hoys[start_index:]
|
|
66
|
+
else:
|
|
67
|
+
return hoys[start_index: -1 * (end_index + 1)]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def handle_operator(operator):
|
|
71
|
+
"""Handle operator for rmtxop command."""
|
|
72
|
+
if operator == '+':
|
|
73
|
+
return '+'
|
|
74
|
+
elif operator == '-':
|
|
75
|
+
return '+ -s -1.0'
|
|
76
|
+
elif operator == '/':
|
|
77
|
+
return '/'
|
|
78
|
+
elif operator == '*':
|
|
79
|
+
return '"*"'
|
|
80
|
+
else:
|
|
81
|
+
raise ValueError('Invalid operator: %s' % operator)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def remove_header(input_file):
|
|
85
|
+
"""Remove the header text from a Radiance matrix file."""
|
|
86
|
+
inf = open(input_file)
|
|
87
|
+
first_line = next(inf)
|
|
88
|
+
if first_line[:10] == '#?RADIANCE':
|
|
89
|
+
for line in inf:
|
|
90
|
+
if line[:7] == 'FORMAT=':
|
|
91
|
+
# pass next empty line
|
|
92
|
+
next(inf)
|
|
93
|
+
first_line = next(inf)
|
|
94
|
+
break
|
|
95
|
+
continue
|
|
96
|
+
return first_line, inf
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def get_compare_func(include_min, include_max, comply):
|
|
100
|
+
if include_max and include_min:
|
|
101
|
+
if comply:
|
|
102
|
+
compare = lambda value, minimum, maximum: minimum <= value <= maximum
|
|
103
|
+
else:
|
|
104
|
+
compare = lambda value, minimum, maximum: not (minimum <= value <= maximum)
|
|
105
|
+
elif not include_max and not include_min:
|
|
106
|
+
if comply:
|
|
107
|
+
compare = lambda value, minimum, maximum: minimum < value < maximum
|
|
108
|
+
else:
|
|
109
|
+
compare = lambda value, minimum, maximum: not (minimum < value < maximum)
|
|
110
|
+
elif include_max and not include_min:
|
|
111
|
+
if comply:
|
|
112
|
+
compare = lambda value, minimum, maximum: minimum < value <= maximum
|
|
113
|
+
else:
|
|
114
|
+
compare = lambda value, minimum, maximum: not (minimum < value <= maximum)
|
|
115
|
+
elif not include_max and include_min:
|
|
116
|
+
if comply:
|
|
117
|
+
compare = lambda value, minimum, maximum: minimum <= value < maximum
|
|
118
|
+
else:
|
|
119
|
+
compare = lambda value, minimum, maximum: not (minimum <= value < maximum)
|
|
120
|
+
|
|
121
|
+
return compare
|