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,1186 @@
|
|
|
1
|
+
"""honeybee radiance daylight postprocessing commands."""
|
|
2
|
+
import click
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
6
|
+
import shutil
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
from ladybug.wea import Wea
|
|
10
|
+
from ladybug.legend import LegendParameters
|
|
11
|
+
from ladybug.color import Colorset, Color
|
|
12
|
+
from ladybug.datatype.generic import GenericType
|
|
13
|
+
from ladybug.datatype.fraction import Fraction
|
|
14
|
+
from ladybug.datatype.illuminance import Illuminance
|
|
15
|
+
from ladybug.datatype.luminance import Luminance
|
|
16
|
+
from ladybug.datatype.time import Time
|
|
17
|
+
|
|
18
|
+
from honeybee_radiance.postprocess.annualdaylight import metrics_to_folder
|
|
19
|
+
from honeybee_radiance.postprocess.en17037 import en17037_to_folder
|
|
20
|
+
from honeybee_radiance.postprocess.annualglare import glare_autonomy_to_folder
|
|
21
|
+
from honeybee_radiance.postprocess.annualirradiance import annual_irradiance_to_folder, \
|
|
22
|
+
_annual_irradiance_config, _annual_irradiance_vis_metadata
|
|
23
|
+
from honeybee_radiance.postprocess.electriclight import daylight_control_schedules
|
|
24
|
+
from honeybee_radiance.postprocess.leed import leed_illuminance_to_folder
|
|
25
|
+
from honeybee_radiance.postprocess.solartracking import post_process_solar_tracking
|
|
26
|
+
from honeybee_radiance.cli.util import get_compare_func, remove_header
|
|
27
|
+
|
|
28
|
+
_logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@click.group(help='Commands to post-process Radiance results.')
|
|
32
|
+
def post_process():
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@post_process.command('convert-to-binary')
|
|
37
|
+
@click.argument(
|
|
38
|
+
'input-matrix', type=click.Path(exists=True, file_okay=True, resolve_path=True)
|
|
39
|
+
)
|
|
40
|
+
@click.option(
|
|
41
|
+
'--output', '-o', help='Optional path to output file to output the name of the newly'
|
|
42
|
+
' created matrix. By default the list will be printed out to stdout',
|
|
43
|
+
type=click.File('w'), default='-')
|
|
44
|
+
@click.option(
|
|
45
|
+
'--minimum', type=float, default='-inf', help='Minimum range for values to be '
|
|
46
|
+
'converted to 1.'
|
|
47
|
+
)
|
|
48
|
+
@click.option(
|
|
49
|
+
'--maximum', type=float, default='+inf', help='Maximum range for values to be '
|
|
50
|
+
'converted to 1.'
|
|
51
|
+
)
|
|
52
|
+
@click.option(
|
|
53
|
+
'--include-max/--exclude-max', is_flag=True, help='A flag to include the maximum '
|
|
54
|
+
'threshold itself. By default the threshold value will be included.', default=True
|
|
55
|
+
)
|
|
56
|
+
@click.option(
|
|
57
|
+
'--include-min/--exclude-min', is_flag=True, help='A flag to include the minimum '
|
|
58
|
+
'threshold itself. By default the threshold value will be included.', default=True
|
|
59
|
+
)
|
|
60
|
+
@click.option(
|
|
61
|
+
'--comply/--reverse', is_flag=True, help='A flag to reverse the selection logic. '
|
|
62
|
+
'This is useful for cases that you want to all the values outside a certain range '
|
|
63
|
+
'to be converted to 1. By default the input logic will be used as is.', default=True
|
|
64
|
+
)
|
|
65
|
+
def convert_matrix_to_binary(
|
|
66
|
+
input_matrix, output, minimum, maximum, include_max, include_min, comply
|
|
67
|
+
):
|
|
68
|
+
"""Postprocess a Radiance matrix and convert it to 0-1 values.
|
|
69
|
+
|
|
70
|
+
\b
|
|
71
|
+
This command is useful for translating Radiance results to outputs like sunlight
|
|
72
|
+
hours. Input matrix must be in ASCII format. The header in the input file will be
|
|
73
|
+
ignored.
|
|
74
|
+
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
compare = get_compare_func(include_min, include_max, comply)
|
|
78
|
+
minimum = float(minimum)
|
|
79
|
+
maximum = float(maximum)
|
|
80
|
+
try:
|
|
81
|
+
first_line, input_file = remove_header(input_matrix)
|
|
82
|
+
values = [
|
|
83
|
+
'1' if compare(float(v), minimum, maximum) else '0'
|
|
84
|
+
for v in first_line.split()
|
|
85
|
+
]
|
|
86
|
+
output.write('\t'.join(values) + '\n')
|
|
87
|
+
for line in input_file:
|
|
88
|
+
# write binary values to new file
|
|
89
|
+
values = [
|
|
90
|
+
'1' if compare(float(v), minimum, maximum) else '0'
|
|
91
|
+
for v in line.split()
|
|
92
|
+
]
|
|
93
|
+
output.write('\t'.join(values) + '\n')
|
|
94
|
+
except Exception:
|
|
95
|
+
_logger.exception('Failed to convert the input file to binary format.')
|
|
96
|
+
sys.exit(1)
|
|
97
|
+
else:
|
|
98
|
+
sys.exit(0)
|
|
99
|
+
finally:
|
|
100
|
+
input_file.close()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@post_process.command('count')
|
|
104
|
+
@click.argument(
|
|
105
|
+
'input-matrix', type=click.Path(exists=True, file_okay=True, resolve_path=True)
|
|
106
|
+
)
|
|
107
|
+
@click.option(
|
|
108
|
+
'--output', '-o', help='Optional path to output file to output the name of the newly'
|
|
109
|
+
' created matrix. By default the list will be printed out to stdout',
|
|
110
|
+
type=click.File('w'), default='-')
|
|
111
|
+
@click.option(
|
|
112
|
+
'--minimum', type=float, default='-inf', help='Minimum range for values to be '
|
|
113
|
+
'converted to 1.'
|
|
114
|
+
)
|
|
115
|
+
@click.option(
|
|
116
|
+
'--maximum', type=float, default='+inf', help='Maximum range for values to be '
|
|
117
|
+
'converted to 1.'
|
|
118
|
+
)
|
|
119
|
+
@click.option(
|
|
120
|
+
'--include-max/--exclude-max', is_flag=True, help='A flag to include the maximum '
|
|
121
|
+
'threshold itself. By default the threshold value will be included.', default=True
|
|
122
|
+
)
|
|
123
|
+
@click.option(
|
|
124
|
+
'--include-min/--exclude-min', is_flag=True, help='A flag to include the minimum '
|
|
125
|
+
'threshold itself. By default the threshold value will be included.', default=True
|
|
126
|
+
)
|
|
127
|
+
@click.option(
|
|
128
|
+
'--comply/--reverse', is_flag=True, help='A flag to reverse the selection logic. '
|
|
129
|
+
'This is useful for cases that you want to all the values outside a certain range '
|
|
130
|
+
'to be converted to 1. By default the input logic will be used as is.', default=True
|
|
131
|
+
)
|
|
132
|
+
def count_values(
|
|
133
|
+
input_matrix, output, minimum, maximum, include_max, include_min, comply
|
|
134
|
+
):
|
|
135
|
+
"""Count values in a row that meet a certain criteria.
|
|
136
|
+
|
|
137
|
+
\b
|
|
138
|
+
This command is useful for post processing results like the number of sensors
|
|
139
|
+
which receive more than X lux at any timestep.
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
compare = get_compare_func(include_min, include_max, comply)
|
|
143
|
+
minimum = float(minimum)
|
|
144
|
+
maximum = float(maximum)
|
|
145
|
+
try:
|
|
146
|
+
first_line, input_file = remove_header(input_matrix)
|
|
147
|
+
value = sum(
|
|
148
|
+
1 if compare(float(v), minimum, maximum) else 0
|
|
149
|
+
for v in first_line.split()
|
|
150
|
+
)
|
|
151
|
+
output.write('%d\n' % value)
|
|
152
|
+
for line in input_file:
|
|
153
|
+
# write binary values to new file
|
|
154
|
+
value = sum(
|
|
155
|
+
1 if compare(float(v), minimum, maximum) else 0
|
|
156
|
+
for v in line.split()
|
|
157
|
+
)
|
|
158
|
+
output.write('%d\n' % value)
|
|
159
|
+
except Exception:
|
|
160
|
+
_logger.exception('Failed to convert the input file to binary format.')
|
|
161
|
+
sys.exit(1)
|
|
162
|
+
else:
|
|
163
|
+
sys.exit(0)
|
|
164
|
+
finally:
|
|
165
|
+
input_file.close()
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@post_process.command('sum-row')
|
|
169
|
+
@click.argument(
|
|
170
|
+
'input-matrix', type=click.Path(exists=True, file_okay=True, resolve_path=True)
|
|
171
|
+
)
|
|
172
|
+
@click.option(
|
|
173
|
+
'--divisor', type=float, default=1, help='An optional number, that the summed '
|
|
174
|
+
'row will be divided by. For example, this can be a timestep, which can be used '
|
|
175
|
+
'to ensure that a summed row of irradiance yields cumulative radiation over '
|
|
176
|
+
'the entire time period of the matrix.'
|
|
177
|
+
)
|
|
178
|
+
@click.option(
|
|
179
|
+
'--output', '-o', help='Optional path to output file to output the name of the newly'
|
|
180
|
+
' created matrix. By default the list will be printed out to stdout',
|
|
181
|
+
type=click.File('w'), default='-')
|
|
182
|
+
def sum_matrix_rows(input_matrix, divisor, output):
|
|
183
|
+
"""Postprocess a Radiance matrix and add all the numbers in each row.
|
|
184
|
+
|
|
185
|
+
\b
|
|
186
|
+
This command is useful for translating Radiance results to outputs like radiation
|
|
187
|
+
to total radiation. Input matrix must be in ASCII format. The header in the input
|
|
188
|
+
file will be ignored.
|
|
189
|
+
"""
|
|
190
|
+
try:
|
|
191
|
+
first_line, input_file = remove_header(input_matrix)
|
|
192
|
+
value = sum(float(v) for v in first_line.split()) / divisor
|
|
193
|
+
output.write('%s\n' % value)
|
|
194
|
+
for line in input_file:
|
|
195
|
+
# write sum to a new file
|
|
196
|
+
value = sum(float(v) for v in line.split()) / divisor
|
|
197
|
+
output.write('%s\n' % value)
|
|
198
|
+
except Exception:
|
|
199
|
+
_logger.exception('Failed to sum numbers in each row.')
|
|
200
|
+
sys.exit(1)
|
|
201
|
+
else:
|
|
202
|
+
sys.exit(0)
|
|
203
|
+
finally:
|
|
204
|
+
input_file.close()
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@post_process.command('average-row')
|
|
208
|
+
@click.argument(
|
|
209
|
+
'input-matrix', type=click.Path(exists=True, file_okay=True, resolve_path=True)
|
|
210
|
+
)
|
|
211
|
+
@click.option(
|
|
212
|
+
'--output', '-o', help='Optional path to output file to output the name of the newly'
|
|
213
|
+
' created matrix. By default the list will be printed out to stdout',
|
|
214
|
+
type=click.File('w'), default='-')
|
|
215
|
+
def average_matrix_rows(input_matrix, output):
|
|
216
|
+
"""Postprocess a Radiance matrix and average the numbers in each row.
|
|
217
|
+
|
|
218
|
+
\b
|
|
219
|
+
This command is useful for translating Radiance results to outputs like radiation
|
|
220
|
+
to average radiation. Input matrix must be in ASCII format. The header in the input
|
|
221
|
+
file will be ignored.
|
|
222
|
+
"""
|
|
223
|
+
try:
|
|
224
|
+
first_line, input_file = remove_header(input_matrix)
|
|
225
|
+
|
|
226
|
+
# calculate the values for the first line
|
|
227
|
+
values = [float(v) for v in first_line.split()]
|
|
228
|
+
count = len(values)
|
|
229
|
+
output.write('%s\n' % sum(values) / count)
|
|
230
|
+
|
|
231
|
+
# write rest of the lines
|
|
232
|
+
for line in input_file:
|
|
233
|
+
# write sum to a new file
|
|
234
|
+
value = sum(float(v) for v in line.split())
|
|
235
|
+
output.write('%s\n' % value / count)
|
|
236
|
+
|
|
237
|
+
except Exception:
|
|
238
|
+
_logger.exception('Failed to average the numbers in each row.')
|
|
239
|
+
sys.exit(1)
|
|
240
|
+
else:
|
|
241
|
+
sys.exit(0)
|
|
242
|
+
finally:
|
|
243
|
+
input_file.close()
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@post_process.command('cumulative-radiation')
|
|
247
|
+
@click.argument(
|
|
248
|
+
'average-irradiance', type=click.Path(exists=True, file_okay=True, resolve_path=True)
|
|
249
|
+
)
|
|
250
|
+
@click.argument(
|
|
251
|
+
'wea', type=click.Path(exists=True, file_okay=True, resolve_path=True)
|
|
252
|
+
)
|
|
253
|
+
@click.option(
|
|
254
|
+
'--timestep', type=int, default=1, help='The timestep of the Wea file, which '
|
|
255
|
+
'is used to to compute cumulative radiation over the time period of the Wea.'
|
|
256
|
+
)
|
|
257
|
+
@click.option(
|
|
258
|
+
'--output', '-o', help='Optional path to output file to output the name of the newly'
|
|
259
|
+
' created matrix. By default the list will be printed out to stdout',
|
|
260
|
+
type=click.File('w'), default='-')
|
|
261
|
+
def cumulative_radiation(average_irradiance, wea, timestep, output):
|
|
262
|
+
"""Postprocess average irradiance (W/m2) into cumulative radiation (kWh/m2).
|
|
263
|
+
|
|
264
|
+
\b
|
|
265
|
+
Args:
|
|
266
|
+
average_irradiance: A single-column matrix of average irradiance values.
|
|
267
|
+
This input matrix must be in ASCII format.
|
|
268
|
+
wea: The .wea file that was used in the irradiance simulation. This
|
|
269
|
+
will be used to determine the duration of the analysis for computing
|
|
270
|
+
cumulative radiation. This can also be an .epw file.
|
|
271
|
+
"""
|
|
272
|
+
try:
|
|
273
|
+
with open(wea) as inf:
|
|
274
|
+
first_word = inf.read(5)
|
|
275
|
+
is_wea = True if first_word == 'place' else False
|
|
276
|
+
if not is_wea:
|
|
277
|
+
_wea_file = os.path.join(os.path.dirname(wea), 'epw_to_wea.wea')
|
|
278
|
+
wea = Wea.from_epw_file(wea, timestep).write(_wea_file)
|
|
279
|
+
# parse the Wea and the average_irradiance matrix
|
|
280
|
+
conversion = Wea.count_timesteps(wea) / (timestep * 1000)
|
|
281
|
+
first_line, input_file = remove_header(average_irradiance)
|
|
282
|
+
# calculate the value for the first line
|
|
283
|
+
output.write('%s\n' % (float(first_line) * conversion))
|
|
284
|
+
# write rest of the lines
|
|
285
|
+
for line in input_file:
|
|
286
|
+
output.write('%s\n' % (float(line) * conversion))
|
|
287
|
+
except Exception:
|
|
288
|
+
_logger.exception('Failed to compute cumulative radiation.')
|
|
289
|
+
sys.exit(1)
|
|
290
|
+
else:
|
|
291
|
+
sys.exit(0)
|
|
292
|
+
finally:
|
|
293
|
+
input_file.close()
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
@post_process.command('annual-irradiance')
|
|
297
|
+
@click.argument(
|
|
298
|
+
'folder',
|
|
299
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True)
|
|
300
|
+
)
|
|
301
|
+
@click.argument(
|
|
302
|
+
'wea', type=click.Path(exists=True, file_okay=True, resolve_path=True)
|
|
303
|
+
)
|
|
304
|
+
@click.option(
|
|
305
|
+
'--timestep', type=int, default=1, help='The timestep of the Wea file, which '
|
|
306
|
+
'is used to ensure the summed row of irradiance yields cumulative radiation over '
|
|
307
|
+
'the time period of the Wea.'
|
|
308
|
+
)
|
|
309
|
+
@click.option(
|
|
310
|
+
'--sub-folder', '-sf', help='Optional relative path for subfolder to write output '
|
|
311
|
+
'metric files.', default='metrics'
|
|
312
|
+
)
|
|
313
|
+
def annual_irradiance(folder, wea, timestep, sub_folder):
|
|
314
|
+
"""Compute irradiance metrics in a folder and write them in a subfolder.
|
|
315
|
+
|
|
316
|
+
\b
|
|
317
|
+
This command generates 3 files for each input grid.
|
|
318
|
+
average_irradiance/{grid-name}.res -> Average Irradiance (W/m2)
|
|
319
|
+
peak_irradiance/{grid-name}.res -> Peak Irradiance (W/m2)
|
|
320
|
+
cumulative_radiation/{grid-name}.res -> Cumulative Radiation (kWh/m2)
|
|
321
|
+
|
|
322
|
+
\b
|
|
323
|
+
Args:
|
|
324
|
+
folder: Results folder from an annual irradiance recipe.
|
|
325
|
+
wea: The .wea file that was used in the annual irradiance simulation. This
|
|
326
|
+
will be used to determine the duration of the analysis for computing
|
|
327
|
+
cumulative radiation. This can also be an .epw file.
|
|
328
|
+
"""
|
|
329
|
+
try:
|
|
330
|
+
with open(wea) as inf:
|
|
331
|
+
first_word = inf.read(5)
|
|
332
|
+
is_wea = True if first_word == 'place' else False
|
|
333
|
+
if not is_wea:
|
|
334
|
+
_wea_file = os.path.join(os.path.dirname(wea), 'epw_to_wea.wea')
|
|
335
|
+
wea = Wea.from_epw_file(wea, timestep).write(_wea_file)
|
|
336
|
+
annual_irradiance_to_folder(folder, wea, timestep, sub_folder)
|
|
337
|
+
except Exception:
|
|
338
|
+
_logger.exception('Failed to compute irradiance metrics.')
|
|
339
|
+
sys.exit(1)
|
|
340
|
+
else:
|
|
341
|
+
sys.exit(0)
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
@post_process.command('annual-daylight')
|
|
345
|
+
@click.argument(
|
|
346
|
+
'folder',
|
|
347
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True)
|
|
348
|
+
)
|
|
349
|
+
@click.option(
|
|
350
|
+
'--schedule', '-sch', help='Path to an annual schedule file. Values should be 0-1 '
|
|
351
|
+
'separated by new line. If not provided an 8-5 annual schedule will be created.',
|
|
352
|
+
type=click.Path(exists=False, file_okay=True, dir_okay=False, resolve_path=True)
|
|
353
|
+
)
|
|
354
|
+
@click.option(
|
|
355
|
+
'--threshold', '-t', help='Threshold illuminance level for daylight autonomy.',
|
|
356
|
+
default=300, type=int, show_default=True
|
|
357
|
+
)
|
|
358
|
+
@click.option(
|
|
359
|
+
'--lower-threshold', '-lt',
|
|
360
|
+
help='Minimum threshold for useful daylight illuminance.', default=100, type=int,
|
|
361
|
+
show_default=True
|
|
362
|
+
)
|
|
363
|
+
@click.option(
|
|
364
|
+
'--upper-threshold', '-ut',
|
|
365
|
+
help='Maximum threshold for useful daylight illuminance.', default=3000, type=int,
|
|
366
|
+
show_default=True
|
|
367
|
+
)
|
|
368
|
+
@click.option(
|
|
369
|
+
'--grids-filter', '-gf', help='A pattern to filter the grids.', default='*',
|
|
370
|
+
show_default=True
|
|
371
|
+
)
|
|
372
|
+
@click.option(
|
|
373
|
+
'--sub_folder', '-sf', help='Optional relative path for subfolder to write output '
|
|
374
|
+
'metric files.', default='metrics'
|
|
375
|
+
)
|
|
376
|
+
def annual_metrics(
|
|
377
|
+
folder, schedule, threshold, lower_threshold, upper_threshold, grids_filter,
|
|
378
|
+
sub_folder
|
|
379
|
+
):
|
|
380
|
+
"""Compute annual metrics in a folder and write them in a subfolder.
|
|
381
|
+
|
|
382
|
+
\b
|
|
383
|
+
This command generates 5 files for each input grid.
|
|
384
|
+
da/{grid-name}.da -> Daylight Autonomy
|
|
385
|
+
cda/{grid-name}.cda -> Continuos Daylight Autonomy
|
|
386
|
+
udi/{grid-name}.udi -> Useful Daylight Illuminance
|
|
387
|
+
udi_lower/{grid-name}_upper.udi -> Upper Useful Daylight Illuminance
|
|
388
|
+
udi_upper/{grid-name}_lower.udi -> Lower Useful Daylight Illuminance
|
|
389
|
+
|
|
390
|
+
\b
|
|
391
|
+
Args:
|
|
392
|
+
folder: Results folder. This folder is an output folder of annual
|
|
393
|
+
daylight recipe. Folder should include grids_info.json and sun-up-hours.txt.
|
|
394
|
+
The command uses the list in grids_info.json to find the result files for each
|
|
395
|
+
sensor grid.
|
|
396
|
+
"""
|
|
397
|
+
# optional input - only check if the file exist otherwise ignore
|
|
398
|
+
if schedule and os.path.isfile(schedule):
|
|
399
|
+
with open(schedule) as hourly_schedule:
|
|
400
|
+
schedule = [int(float(v)) for v in hourly_schedule]
|
|
401
|
+
else:
|
|
402
|
+
schedule = None
|
|
403
|
+
|
|
404
|
+
try:
|
|
405
|
+
metrics_to_folder(
|
|
406
|
+
folder, schedule, threshold, lower_threshold, upper_threshold,
|
|
407
|
+
grids_filter, sub_folder
|
|
408
|
+
)
|
|
409
|
+
except Exception:
|
|
410
|
+
_logger.exception('Failed to calculate annual metrics.')
|
|
411
|
+
sys.exit(1)
|
|
412
|
+
else:
|
|
413
|
+
sys.exit(0)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
@post_process.command('annual-daylight-en17037')
|
|
417
|
+
@click.argument(
|
|
418
|
+
'folder',
|
|
419
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True)
|
|
420
|
+
)
|
|
421
|
+
@click.argument(
|
|
422
|
+
'schedule',
|
|
423
|
+
type=click.Path(exists=True, file_okay=True, dir_okay=False, resolve_path=True)
|
|
424
|
+
)
|
|
425
|
+
@click.option(
|
|
426
|
+
'--grids-filter', '-gf', help='A pattern to filter the grids.', default='*',
|
|
427
|
+
show_default=True
|
|
428
|
+
)
|
|
429
|
+
@click.option(
|
|
430
|
+
'--sub_folder', '-sf', help='Optional relative path for subfolder to write output '
|
|
431
|
+
'metric files.', default='metrics'
|
|
432
|
+
)
|
|
433
|
+
def annual_en17037_metrics(
|
|
434
|
+
folder, schedule, grids_filter, sub_folder
|
|
435
|
+
):
|
|
436
|
+
"""Compute annual EN 17037 metrics in a folder and write them in a subfolder.
|
|
437
|
+
|
|
438
|
+
\b
|
|
439
|
+
This command generates multiple files for each input grid. Files for target
|
|
440
|
+
illuminance and minimum illuminance will be calculated for three levels of
|
|
441
|
+
recommendation: minimum, medium, high.
|
|
442
|
+
|
|
443
|
+
\b
|
|
444
|
+
Args:
|
|
445
|
+
folder: Results folder. This folder is an output folder of annual
|
|
446
|
+
daylight recipe. Folder should include grids_info.json and sun-up-hours.txt.
|
|
447
|
+
The command uses the list in grids_info.json to find the result files for
|
|
448
|
+
each sensor grid.
|
|
449
|
+
schedule: Path to an annual schedule file. Values should be 0-1 separated by new
|
|
450
|
+
line. This should be a daylight hours schedule.
|
|
451
|
+
"""
|
|
452
|
+
with open(schedule) as hourly_schedule:
|
|
453
|
+
schedule = [int(float(v)) for v in hourly_schedule]
|
|
454
|
+
try:
|
|
455
|
+
en17037_to_folder(folder, schedule, grids_filter, sub_folder)
|
|
456
|
+
except Exception:
|
|
457
|
+
_logger.exception('Failed to calculate annual EN 17037 metrics.')
|
|
458
|
+
sys.exit(1)
|
|
459
|
+
else:
|
|
460
|
+
sys.exit(0)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
@post_process.command('annual-glare')
|
|
464
|
+
@click.argument(
|
|
465
|
+
'folder',
|
|
466
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True)
|
|
467
|
+
)
|
|
468
|
+
@click.option(
|
|
469
|
+
'--schedule', '-sch', help='Path to an annual schedule file. Values should be 0-1 '
|
|
470
|
+
'separated by new line. If not provided an 8-5 annual schedule will be created.',
|
|
471
|
+
type=click.Path(exists=False, file_okay=True, dir_okay=False, resolve_path=True)
|
|
472
|
+
)
|
|
473
|
+
@click.option(
|
|
474
|
+
'--glare-threshold', '-gt', help='A fractional number for the threshold of DGP '
|
|
475
|
+
'above which conditions are considered to induce glare.',
|
|
476
|
+
default=0.4, type=float, show_default=True
|
|
477
|
+
)
|
|
478
|
+
@click.option(
|
|
479
|
+
'--grids-filter', '-gf', help='A pattern to filter the grids.', default='*',
|
|
480
|
+
show_default=True
|
|
481
|
+
)
|
|
482
|
+
@click.option(
|
|
483
|
+
'--sub_folder', '-sf', help='Optional relative path for subfolder to write output '
|
|
484
|
+
'metric files.', default='metrics'
|
|
485
|
+
)
|
|
486
|
+
def annual_glare(
|
|
487
|
+
folder, schedule, glare_threshold, grids_filter, sub_folder
|
|
488
|
+
):
|
|
489
|
+
"""Compute annual glare autonomy in a folder and write them in a subfolder.
|
|
490
|
+
|
|
491
|
+
\b
|
|
492
|
+
This command generates 1 file for each input grid.
|
|
493
|
+
ga/{grid-name}.ga -> Glare Autonomy
|
|
494
|
+
|
|
495
|
+
\b
|
|
496
|
+
Args:
|
|
497
|
+
folder: Results folder. This folder is an output folder of imageless annual
|
|
498
|
+
glare recipe. Folder should include grids_info.json and sun-up-hours.txt.
|
|
499
|
+
The command uses the list in grids_info.json to find the result files for each
|
|
500
|
+
sensor grid.
|
|
501
|
+
"""
|
|
502
|
+
# optional input - only check if the file exist otherwise ignore
|
|
503
|
+
if schedule and os.path.isfile(schedule):
|
|
504
|
+
with open(schedule) as hourly_schedule:
|
|
505
|
+
schedule = [int(float(v)) for v in hourly_schedule]
|
|
506
|
+
else:
|
|
507
|
+
schedule = None
|
|
508
|
+
|
|
509
|
+
try:
|
|
510
|
+
glare_autonomy_to_folder(
|
|
511
|
+
folder, schedule, glare_threshold, grids_filter, sub_folder
|
|
512
|
+
)
|
|
513
|
+
except Exception:
|
|
514
|
+
_logger.exception('Failed to calculate annual glare autonomy.')
|
|
515
|
+
sys.exit(1)
|
|
516
|
+
else:
|
|
517
|
+
sys.exit(0)
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
@post_process.command('electric-lighting')
|
|
521
|
+
@click.argument(
|
|
522
|
+
'folder',
|
|
523
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True)
|
|
524
|
+
)
|
|
525
|
+
@click.option(
|
|
526
|
+
'--base-schedule', '-s', help='Path to a CSV file for the lighting schedule '
|
|
527
|
+
'without any daylight controls. The values of this schedule will be multiplied '
|
|
528
|
+
'by the hourly dimming fraction to yield the output lighting schedules. If '
|
|
529
|
+
'unspecified, a schedule from 9AM to 5PM on weekdays will be used.',
|
|
530
|
+
type=click.Path(exists=False, file_okay=True, dir_okay=False, resolve_path=True)
|
|
531
|
+
)
|
|
532
|
+
@click.option(
|
|
533
|
+
'--ill-setpoint', '-i', help='A number for the illuminance setpoint in lux beyond '
|
|
534
|
+
'which electric lights are dimmed if there is sufficient daylight.',
|
|
535
|
+
default=300, type=int, show_default=True
|
|
536
|
+
)
|
|
537
|
+
@click.option(
|
|
538
|
+
'--min-power-in', '-p',
|
|
539
|
+
help='A number between 0 and 1 for the the lowest power the lighting system can '
|
|
540
|
+
'dim down to, expressed as a fraction of maximum input power.', default=0.3,
|
|
541
|
+
type=float, show_default=True
|
|
542
|
+
)
|
|
543
|
+
@click.option(
|
|
544
|
+
'--min-light-out', '-l',
|
|
545
|
+
help='A number between 0 and 1 the lowest lighting output the lighting system can '
|
|
546
|
+
'dim down to, expressed as a fraction of maximum light output. Note that setting '
|
|
547
|
+
'this to 1 means lights are not dimmed at all until the illuminance setpoint is '
|
|
548
|
+
'reached. This can be used to approximate manual light-switching behavior when '
|
|
549
|
+
'used in conjunction with the off_at_min_ output below.', default=0.2,
|
|
550
|
+
type=float, show_default=True
|
|
551
|
+
)
|
|
552
|
+
@click.option(
|
|
553
|
+
'--on-at-min/--off-at-min', ' /-oam', help='Flag to note whether lights should '
|
|
554
|
+
'switch off completely when they get to the minimum power input.',
|
|
555
|
+
default=True, show_default=True
|
|
556
|
+
)
|
|
557
|
+
@click.option(
|
|
558
|
+
'--output-file', '-f', help='Optional JSON file to output a summary of the number '
|
|
559
|
+
'of LEED credits and the percentage of sensor area that meets the criteria. '
|
|
560
|
+
'By default this will be printed out to stdout',
|
|
561
|
+
type=click.File('w'), default='-', show_default=True
|
|
562
|
+
)
|
|
563
|
+
def electric_lighting(
|
|
564
|
+
folder, base_schedule, ill_setpoint, min_power_in, min_light_out, on_at_min,
|
|
565
|
+
output_file
|
|
566
|
+
):
|
|
567
|
+
"""Generate electric lighting schedules from annual daylight results.
|
|
568
|
+
|
|
569
|
+
Such controls will dim the lights according to whether the illuminance values
|
|
570
|
+
at the sensor locations are at a target illuminance setpoint. The results can be
|
|
571
|
+
used to account for daylight controls in energy simulations.
|
|
572
|
+
|
|
573
|
+
This function will generate one schedule per sensor grid in the simulation. Each
|
|
574
|
+
grid should have sensors at the locations in space where daylight dimming sensors
|
|
575
|
+
are located. Grids with one, two, or more sensors can be used to model setups
|
|
576
|
+
where fractions of each room are controlled by different sensors. If the sensor
|
|
577
|
+
grids are distributed over the entire floor of the rooms, the resulting schedules
|
|
578
|
+
will be idealized, where light dimming has been optimized to supply the minimum
|
|
579
|
+
illuminance setpoint everywhere in the room.
|
|
580
|
+
|
|
581
|
+
\b
|
|
582
|
+
Args:
|
|
583
|
+
folder: Results folder. This folder is an output folder of the annual
|
|
584
|
+
daylight recipe. Folder should include grids_info.json and
|
|
585
|
+
sun-up-hours.txt. The command uses the list in grids_info.json to
|
|
586
|
+
find the result files for each sensor grid.
|
|
587
|
+
"""
|
|
588
|
+
try:
|
|
589
|
+
# optional input - only check if the file exist otherwise ignore
|
|
590
|
+
if base_schedule and os.path.isfile(base_schedule):
|
|
591
|
+
with open(base_schedule) as hourly_schedule:
|
|
592
|
+
schedule = [float(v) for v in hourly_schedule]
|
|
593
|
+
else:
|
|
594
|
+
schedule = None
|
|
595
|
+
|
|
596
|
+
off_at_min = not on_at_min
|
|
597
|
+
schedules, _ = daylight_control_schedules(
|
|
598
|
+
folder, schedule, ill_setpoint, min_power_in, min_light_out, off_at_min
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
for line in zip(*schedules):
|
|
602
|
+
output_file.write(','.join([str(v) for v in line]) + '\n')
|
|
603
|
+
except Exception:
|
|
604
|
+
_logger.exception('Failed to calculate electric lighting.')
|
|
605
|
+
sys.exit(1)
|
|
606
|
+
else:
|
|
607
|
+
sys.exit(0)
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
@post_process.command('leed-illuminance')
|
|
611
|
+
@click.argument(
|
|
612
|
+
'folder',
|
|
613
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True)
|
|
614
|
+
)
|
|
615
|
+
@click.option(
|
|
616
|
+
'--glare-control/--no-glare-control', ' /-ngc', help='Flag to note whether '
|
|
617
|
+
'the model has "view-preserving automatic (with manual override) glare-control '
|
|
618
|
+
'devices," which means that illuminance only needs to be above 300 lux and not '
|
|
619
|
+
'between 300 and 3000 lux.', default=True, show_default=True
|
|
620
|
+
)
|
|
621
|
+
@click.option(
|
|
622
|
+
'--grids-filter', '-gf', help='A pattern to filter the grids for just the '
|
|
623
|
+
'regularly occupied spaces.', default='*', show_default=True
|
|
624
|
+
)
|
|
625
|
+
@click.option(
|
|
626
|
+
'--sub-folder', '-sf', help='Optional relative path for a subfolder to write the '
|
|
627
|
+
'pass/fail files for each sensor grid.', default=None
|
|
628
|
+
)
|
|
629
|
+
@click.option(
|
|
630
|
+
'--output-file', help='Optional JSON file to output a summary of the number '
|
|
631
|
+
'of LEED credits and the percentage of sensor area that meets the criteria. '
|
|
632
|
+
'By default this will be printed out to stdout',
|
|
633
|
+
type=click.File('w'), default='-', show_default=True
|
|
634
|
+
)
|
|
635
|
+
def leed_illuminance(folder, glare_control, grids_filter, sub_folder, output_file):
|
|
636
|
+
"""Estimate LEED daylight credits from two point-in-time illuminance folders.
|
|
637
|
+
|
|
638
|
+
\b
|
|
639
|
+
Args:
|
|
640
|
+
folder: Project folder for a LEED illuminance simulation. It should contain
|
|
641
|
+
a HBJSON model and two sub-folders of complete point-in-time illuminance
|
|
642
|
+
simulations labeled "9AM" and "3PM". These two sub-folders should each
|
|
643
|
+
have results folders that include a grids_info.json and .res files with
|
|
644
|
+
illuminance values for each sensor. If Meshes are found for the sensor
|
|
645
|
+
grids in the HBJSON file, they will be used to compute percentages
|
|
646
|
+
of occupied floor area that pass vs. fail. Otherwise, all sensors will
|
|
647
|
+
be assumed to represent an equal amount of floor area.
|
|
648
|
+
"""
|
|
649
|
+
try:
|
|
650
|
+
credit_summary = leed_illuminance_to_folder(
|
|
651
|
+
folder, glare_control, grids_filter, sub_folder)
|
|
652
|
+
output_file.write(json.dumps(credit_summary, indent=4))
|
|
653
|
+
except Exception:
|
|
654
|
+
_logger.exception('Failed to calculate LEED daylight metrics.')
|
|
655
|
+
sys.exit(1)
|
|
656
|
+
else:
|
|
657
|
+
sys.exit(0)
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
@post_process.command('solar-tracking')
|
|
661
|
+
@click.argument(
|
|
662
|
+
'folder',
|
|
663
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True)
|
|
664
|
+
)
|
|
665
|
+
@click.argument(
|
|
666
|
+
'sun-up-hours', type=click.Path(exists=True, file_okay=True, resolve_path=True)
|
|
667
|
+
)
|
|
668
|
+
@click.argument(
|
|
669
|
+
'wea', type=click.Path(exists=True, file_okay=True, resolve_path=True)
|
|
670
|
+
)
|
|
671
|
+
@click.option(
|
|
672
|
+
'--north', default=0, type=float, show_default=True,
|
|
673
|
+
help='Angle to north (0-360). 90 is west and 270 is east'
|
|
674
|
+
)
|
|
675
|
+
@click.option(
|
|
676
|
+
'--tracking-increment', '-t', type=int, default=5, help='An integer for the '
|
|
677
|
+
'increment angle of each state in degrees. (Default: 5).'
|
|
678
|
+
)
|
|
679
|
+
@click.option(
|
|
680
|
+
'--sub-folder', '-sf', help='Optional relative path for subfolder to write output '
|
|
681
|
+
'.ill files of the dynamic tracking system.', default='final'
|
|
682
|
+
)
|
|
683
|
+
def solar_tracking(folder, sun_up_hours, wea, north, tracking_increment, sub_folder):
|
|
684
|
+
"""Postprocess a list of result folders to account for dynamic solar tracking.
|
|
685
|
+
|
|
686
|
+
\b
|
|
687
|
+
This function essentially takes .ill files for each state of a dynamic tracking
|
|
688
|
+
system and produces a single .ill file that models the tracking behavior.
|
|
689
|
+
|
|
690
|
+
\b
|
|
691
|
+
Args:
|
|
692
|
+
folder: Results folder containing sub-folders that each represent a state
|
|
693
|
+
of the dynamic solar tracking system. Each sub-folder should contain .ill
|
|
694
|
+
files for that state and the names of these .ill files should be the
|
|
695
|
+
same across all sub-folders.
|
|
696
|
+
sun_up_hours: The .txt file containing the sun-up hours that were simulated.
|
|
697
|
+
wea: The .wea file that was used in the simulation. This will be used to
|
|
698
|
+
determine the solar positions.
|
|
699
|
+
"""
|
|
700
|
+
try:
|
|
701
|
+
# load all of the result sub-folders in the folder and sort them
|
|
702
|
+
models = [f for f in os.listdir(folder)
|
|
703
|
+
if os.path.isdir(os.path.join(folder, f)) and
|
|
704
|
+
os.path.isfile(os.path.join(folder, f, 'grids_info.json'))]
|
|
705
|
+
model_num = [int(''.join([i for i in f if i.isdigit()])) for f in models]
|
|
706
|
+
sorted_models = [x for _, x in sorted(zip(model_num, models))]
|
|
707
|
+
models = [os.path.join(folder, f) for f in sorted_models]
|
|
708
|
+
|
|
709
|
+
dest_folder = os.path.join(folder, sub_folder)
|
|
710
|
+
if len(models) == 1: # not a dynamic system; just copy the files
|
|
711
|
+
if not os.path.isdir(dest_folder):
|
|
712
|
+
os.mkdir(dest_folder)
|
|
713
|
+
for f in os.listdir(models[0]):
|
|
714
|
+
shutil.copyfile(
|
|
715
|
+
os.path.join(models[0], f),
|
|
716
|
+
os.path.join(dest_folder, f))
|
|
717
|
+
else:
|
|
718
|
+
wea_obj = Wea.from_file(wea)
|
|
719
|
+
post_process_solar_tracking(
|
|
720
|
+
models, sun_up_hours, wea_obj.location, north,
|
|
721
|
+
tracking_increment, dest_folder)
|
|
722
|
+
except Exception:
|
|
723
|
+
_logger.exception('Failed to compute irradiance metrics.')
|
|
724
|
+
sys.exit(1)
|
|
725
|
+
else:
|
|
726
|
+
sys.exit(0)
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
@post_process.command('daylight-factor-vis-metadata')
|
|
730
|
+
@click.option(
|
|
731
|
+
'--output-file', '-o', help='Optional JSON file to output the metadata file.',
|
|
732
|
+
type=click.File('w'), default='-', show_default=True
|
|
733
|
+
)
|
|
734
|
+
def daylight_factor_vis(output_file):
|
|
735
|
+
"""Write a visualization metadata file for daylight factor."""
|
|
736
|
+
vm_data = {
|
|
737
|
+
'type': 'VisualizationMetaData',
|
|
738
|
+
'data_type': Fraction('Daylight Factor').to_dict(),
|
|
739
|
+
'unit': '%',
|
|
740
|
+
'legend_parameters': LegendParameters(colors=Colorset.ecotect()).to_dict()
|
|
741
|
+
}
|
|
742
|
+
try:
|
|
743
|
+
output_file.write(json.dumps(vm_data, indent=4))
|
|
744
|
+
except Exception:
|
|
745
|
+
_logger.exception('Failed to write the visualization metadata file.')
|
|
746
|
+
sys.exit(1)
|
|
747
|
+
else:
|
|
748
|
+
sys.exit(0)
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
@post_process.command('daylight-factor-config')
|
|
752
|
+
@click.option(
|
|
753
|
+
'--folder', '-f', help='Optional relative path for results folder. This value will '
|
|
754
|
+
'be set as path inside the config file', default='daylight-factor'
|
|
755
|
+
)
|
|
756
|
+
@click.option(
|
|
757
|
+
'--output-file', '-o', help='Optional JSON file to output the config file.',
|
|
758
|
+
type=click.File('w'), default='-', show_default=True
|
|
759
|
+
)
|
|
760
|
+
def daylight_fatcor_config(folder, output_file):
|
|
761
|
+
"""Write a vtk-config file for daylight factor."""
|
|
762
|
+
cfg = {
|
|
763
|
+
'data': [
|
|
764
|
+
{
|
|
765
|
+
'identifier': 'Daylight Factor',
|
|
766
|
+
'object_type': 'grid',
|
|
767
|
+
'unit': 'Percentage',
|
|
768
|
+
'path': folder,
|
|
769
|
+
'hide': False,
|
|
770
|
+
'legend_parameters': {
|
|
771
|
+
'hide_legend': False,
|
|
772
|
+
'min': 0,
|
|
773
|
+
'max': 2,
|
|
774
|
+
'color_set': 'original'
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
]
|
|
778
|
+
}
|
|
779
|
+
try:
|
|
780
|
+
output_file.write(json.dumps(cfg, indent=4))
|
|
781
|
+
except Exception:
|
|
782
|
+
_logger.exception('Failed to write the config file.')
|
|
783
|
+
sys.exit(1)
|
|
784
|
+
else:
|
|
785
|
+
sys.exit(0)
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
@post_process.command('point-in-time-vis-metadata')
|
|
789
|
+
@click.option(
|
|
790
|
+
'--metric', '-m', default='illuminance', show_default=True,
|
|
791
|
+
help='Text for the type of metric to be output from the calculation. Choose from: '
|
|
792
|
+
'illuminance, irradiance, luminance, radiance.'
|
|
793
|
+
)
|
|
794
|
+
@click.option(
|
|
795
|
+
'--output-file', '-o', help='Optional JSON file to output the config file.',
|
|
796
|
+
type=click.File('w'), default='-', show_default=True
|
|
797
|
+
)
|
|
798
|
+
def point_in_time_vis(metric, output_file):
|
|
799
|
+
"""Write a visualization metadata file for point-in-time."""
|
|
800
|
+
unit_map = {
|
|
801
|
+
'illuminance': ['lux', 0, 3000, Illuminance('Illuminance')],
|
|
802
|
+
'irradiance': ['W/m2', 0, 300, GenericType('Irradiance', unit='W/m2')],
|
|
803
|
+
'luminance': ['cd/m2', 0, 3000, Luminance('Luminance')],
|
|
804
|
+
'radiance': ['W/m2-sr', 0, 300, GenericType('Radiance', unit='W/m2-sr')]
|
|
805
|
+
}
|
|
806
|
+
unit_props = unit_map[metric.lower()]
|
|
807
|
+
|
|
808
|
+
vm_data = {
|
|
809
|
+
'type': 'VisualizationMetaData',
|
|
810
|
+
'data_type': unit_props[-1].to_dict(),
|
|
811
|
+
'unit': unit_props[0],
|
|
812
|
+
'legend_parameters': LegendParameters(
|
|
813
|
+
colors=Colorset.ecotect(), min=unit_props[1], max=unit_props[2]
|
|
814
|
+
).to_dict()
|
|
815
|
+
}
|
|
816
|
+
try:
|
|
817
|
+
output_file.write(json.dumps(vm_data, indent=4))
|
|
818
|
+
except Exception:
|
|
819
|
+
_logger.exception('Failed to write the visualization metadata file.')
|
|
820
|
+
sys.exit(1)
|
|
821
|
+
else:
|
|
822
|
+
sys.exit(0)
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
@post_process.command('point-in-time-config')
|
|
826
|
+
@click.option(
|
|
827
|
+
'--metric', '-m', default='illuminance', show_default=True,
|
|
828
|
+
help='Text for the type of metric to be output from the calculation. Choose from: '
|
|
829
|
+
'illuminance, irradiance, luminance, radiance.'
|
|
830
|
+
)
|
|
831
|
+
@click.option(
|
|
832
|
+
'--folder', '-f', help='Optional relative path for results folder. This value will '
|
|
833
|
+
'be set as path inside the config file', default='point-in-time'
|
|
834
|
+
)
|
|
835
|
+
@click.option(
|
|
836
|
+
'--output-file', '-o', help='Optional JSON file to output the config file.',
|
|
837
|
+
type=click.File('w'), default='-', show_default=True
|
|
838
|
+
)
|
|
839
|
+
def point_in_time_config(metric, folder, output_file):
|
|
840
|
+
"""Write a vtk-config file for a point-in-time study."""
|
|
841
|
+
unit_map = {
|
|
842
|
+
'illuminance': ['Lux', 0, 3000],
|
|
843
|
+
'irradiance': ['W/m2', 0, 300],
|
|
844
|
+
'luminance': ['cd/m2', 0, 3000],
|
|
845
|
+
'radiance': ['W/m2-sr', 0, 300]
|
|
846
|
+
}
|
|
847
|
+
unit_props = unit_map[metric.lower()]
|
|
848
|
+
cfg = {
|
|
849
|
+
'data': [
|
|
850
|
+
{
|
|
851
|
+
'identifier': 'Point-in-time {}'.format(metric.title()),
|
|
852
|
+
'object_type': 'grid',
|
|
853
|
+
'unit': unit_props[0],
|
|
854
|
+
'path': folder,
|
|
855
|
+
'hide': False,
|
|
856
|
+
'legend_parameters': {
|
|
857
|
+
'hide_legend': False,
|
|
858
|
+
'min': unit_props[1],
|
|
859
|
+
'max': unit_props[2],
|
|
860
|
+
'color_set': 'ecotect'
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
]
|
|
864
|
+
}
|
|
865
|
+
try:
|
|
866
|
+
output_file.write(json.dumps(cfg, indent=4))
|
|
867
|
+
except Exception:
|
|
868
|
+
_logger.exception('Failed to write the config file.')
|
|
869
|
+
sys.exit(1)
|
|
870
|
+
else:
|
|
871
|
+
sys.exit(0)
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
@post_process.command('cumulative-radiation-vis-metadata')
|
|
875
|
+
@click.option(
|
|
876
|
+
'--output-file', '-o', help='Optional JSON file to output the config file.',
|
|
877
|
+
type=click.File('w'), default='-', show_default=True
|
|
878
|
+
)
|
|
879
|
+
def cumulative_radiation_vis(output_file):
|
|
880
|
+
"""Write a visualization metadata file for cumulative radiation."""
|
|
881
|
+
rad_vis_metadata = _annual_irradiance_vis_metadata()
|
|
882
|
+
vm_data = rad_vis_metadata['cumulative_radiation']
|
|
883
|
+
|
|
884
|
+
try:
|
|
885
|
+
output_file.write(json.dumps(vm_data, indent=4))
|
|
886
|
+
except Exception:
|
|
887
|
+
_logger.exception('Failed to write the visualization metadata file.')
|
|
888
|
+
sys.exit(1)
|
|
889
|
+
else:
|
|
890
|
+
sys.exit(0)
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
@post_process.command('cumulative-radiation-config')
|
|
894
|
+
@click.option(
|
|
895
|
+
'--output-file', '-o', help='Optional JSON file to output the config file.',
|
|
896
|
+
type=click.File('w'), default='-', show_default=True
|
|
897
|
+
)
|
|
898
|
+
def cumulative_radiation_config(output_file):
|
|
899
|
+
"""Write a vtk-config file for cumulative radiation."""
|
|
900
|
+
rad_config_dict = _annual_irradiance_config()
|
|
901
|
+
cfg = {
|
|
902
|
+
'data': [
|
|
903
|
+
rad_config_dict['data'][0],
|
|
904
|
+
rad_config_dict['data'][2]
|
|
905
|
+
]
|
|
906
|
+
}
|
|
907
|
+
try:
|
|
908
|
+
output_file.write(json.dumps(cfg, indent=4))
|
|
909
|
+
except Exception:
|
|
910
|
+
_logger.exception('Failed to write the config file.')
|
|
911
|
+
sys.exit(1)
|
|
912
|
+
else:
|
|
913
|
+
sys.exit(0)
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
@post_process.command('average-irradiance-vis-metadata')
|
|
917
|
+
@click.option(
|
|
918
|
+
'--output-file', '-o', help='Optional JSON file to output the config file.',
|
|
919
|
+
type=click.File('w'), default='-', show_default=True
|
|
920
|
+
)
|
|
921
|
+
def average_irradiance_vis(output_file):
|
|
922
|
+
"""Write a visualization metadata file for cumulative radiation."""
|
|
923
|
+
rad_vis_metadata = _annual_irradiance_vis_metadata()
|
|
924
|
+
vm_data = rad_vis_metadata['average_irradiance']
|
|
925
|
+
try:
|
|
926
|
+
output_file.write(json.dumps(vm_data, indent=4))
|
|
927
|
+
except Exception:
|
|
928
|
+
_logger.exception('Failed to write the visualization metadata file.')
|
|
929
|
+
sys.exit(1)
|
|
930
|
+
else:
|
|
931
|
+
sys.exit(0)
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
@post_process.command('direct-sun-hours-vis-metadata')
|
|
935
|
+
@click.option(
|
|
936
|
+
'--output-file', '-o', help='Optional JSON file to output the metadata file.',
|
|
937
|
+
type=click.File('w'), default='-', show_default=True
|
|
938
|
+
)
|
|
939
|
+
def direct_sun_hours_vis(output_file):
|
|
940
|
+
"""Write a visualization metadata file for direct sun hours."""
|
|
941
|
+
vm_data = {
|
|
942
|
+
'type': 'VisualizationMetaData',
|
|
943
|
+
'data_type': Time('Direct Sun Hours').to_dict(),
|
|
944
|
+
'unit': 'hr',
|
|
945
|
+
'legend_parameters': LegendParameters(colors=Colorset.ecotect()).to_dict()
|
|
946
|
+
}
|
|
947
|
+
try:
|
|
948
|
+
output_file.write(json.dumps(vm_data, indent=4))
|
|
949
|
+
except Exception:
|
|
950
|
+
_logger.exception('Failed to write the visualization metadata file.')
|
|
951
|
+
sys.exit(1)
|
|
952
|
+
else:
|
|
953
|
+
sys.exit(0)
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
@post_process.command('direct-sun-hours-config')
|
|
957
|
+
@click.option(
|
|
958
|
+
'--folder', '-f', help='Optional relative path for results folder. This value will '
|
|
959
|
+
'be set as path inside the config file', default='direct-sun-hours'
|
|
960
|
+
)
|
|
961
|
+
@click.option(
|
|
962
|
+
'--output-file', '-o', help='Optional JSON file to output the config file.',
|
|
963
|
+
type=click.File('w'), default='-', show_default=True
|
|
964
|
+
)
|
|
965
|
+
def direct_sun_hours_config(folder, output_file):
|
|
966
|
+
"""Write a vtk-config file for direct sun hours."""
|
|
967
|
+
cfg = {
|
|
968
|
+
'data': [
|
|
969
|
+
{
|
|
970
|
+
'identifier': 'Direct Sun Hours',
|
|
971
|
+
'object_type': 'grid',
|
|
972
|
+
'unit': 'Hours',
|
|
973
|
+
'path': folder,
|
|
974
|
+
'hide': False,
|
|
975
|
+
'legend_parameters': {
|
|
976
|
+
'hide_legend': False,
|
|
977
|
+
'color_set': 'ecotect'
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
]
|
|
981
|
+
}
|
|
982
|
+
try:
|
|
983
|
+
output_file.write(json.dumps(cfg, indent=4))
|
|
984
|
+
except Exception:
|
|
985
|
+
_logger.exception('Failed to write the config file.')
|
|
986
|
+
sys.exit(1)
|
|
987
|
+
else:
|
|
988
|
+
sys.exit(0)
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
@post_process.command('sky-view-vis-metadata')
|
|
992
|
+
@click.option(
|
|
993
|
+
'--output-file', '-o', help='Optional JSON file to output the metadata file.',
|
|
994
|
+
type=click.File('w'), default='-', show_default=True
|
|
995
|
+
)
|
|
996
|
+
def sky_view_vis(output_file):
|
|
997
|
+
"""Write a visualization metadata file for sky view."""
|
|
998
|
+
sky_view_lpar = LegendParameters(min=0, max=100, colors=Colorset.view_study())
|
|
999
|
+
vm_data = {
|
|
1000
|
+
'type': 'VisualizationMetaData',
|
|
1001
|
+
'data_type': Fraction('Sky View').to_dict(),
|
|
1002
|
+
'unit': '%',
|
|
1003
|
+
'legend_parameters': sky_view_lpar.to_dict()
|
|
1004
|
+
}
|
|
1005
|
+
try:
|
|
1006
|
+
output_file.write(json.dumps(vm_data, indent=4))
|
|
1007
|
+
except Exception:
|
|
1008
|
+
_logger.exception('Failed to write the visualization metadata file.')
|
|
1009
|
+
sys.exit(1)
|
|
1010
|
+
else:
|
|
1011
|
+
sys.exit(0)
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
@post_process.command('sky-view-config')
|
|
1015
|
+
@click.option(
|
|
1016
|
+
'--folder', '-f', help='Optional relative path for results folder. This value will '
|
|
1017
|
+
'be set as path inside the config file', default='sky-view'
|
|
1018
|
+
)
|
|
1019
|
+
@click.option(
|
|
1020
|
+
'--output-file', '-o', help='Optional JSON file to output the config file.',
|
|
1021
|
+
type=click.File('w'), default='-', show_default=True
|
|
1022
|
+
)
|
|
1023
|
+
def sky_view_config(folder, output_file):
|
|
1024
|
+
"""Write a vtk-config file for daylight factor. """
|
|
1025
|
+
cfg = {
|
|
1026
|
+
'data': [
|
|
1027
|
+
{
|
|
1028
|
+
'identifier': 'Sky View',
|
|
1029
|
+
'object_type': 'grid',
|
|
1030
|
+
'unit': 'Percentage',
|
|
1031
|
+
'path': folder,
|
|
1032
|
+
'hide': False,
|
|
1033
|
+
'legend_parameters': {
|
|
1034
|
+
'hide_legend': False,
|
|
1035
|
+
'min': 0,
|
|
1036
|
+
'max': 100,
|
|
1037
|
+
'color_set': 'view_study'
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
]
|
|
1041
|
+
}
|
|
1042
|
+
try:
|
|
1043
|
+
output_file.write(json.dumps(cfg, indent=4))
|
|
1044
|
+
except Exception:
|
|
1045
|
+
_logger.exception('Failed to write the config file.')
|
|
1046
|
+
sys.exit(1)
|
|
1047
|
+
else:
|
|
1048
|
+
sys.exit(0)
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
@post_process.command('imageless-annual-glare-vis-metadata')
|
|
1052
|
+
@click.option(
|
|
1053
|
+
'--output-file', '-o', help='Optional JSON file to output the metadata file.',
|
|
1054
|
+
type=click.File('w'), default='-', show_default=True
|
|
1055
|
+
)
|
|
1056
|
+
def imageless_annual_glare_vis(output_file):
|
|
1057
|
+
"""Write a visualization metadata file for imageless annual glare."""
|
|
1058
|
+
ga_lpar = LegendParameters(min=0, max=100, colors=reversed(Colorset.glare_study()))
|
|
1059
|
+
vm_data = {
|
|
1060
|
+
'type': 'VisualizationMetaData',
|
|
1061
|
+
'data_type': Fraction('Glare Autonomy').to_dict(),
|
|
1062
|
+
'unit': '%',
|
|
1063
|
+
'legend_parameters': ga_lpar.to_dict()
|
|
1064
|
+
}
|
|
1065
|
+
try:
|
|
1066
|
+
output_file.write(json.dumps(vm_data, indent=4))
|
|
1067
|
+
except Exception:
|
|
1068
|
+
_logger.exception('Failed to write the visualization metadata file.')
|
|
1069
|
+
sys.exit(1)
|
|
1070
|
+
else:
|
|
1071
|
+
sys.exit(0)
|
|
1072
|
+
|
|
1073
|
+
|
|
1074
|
+
@post_process.command('leed-daylight-option-two-vis-metadata')
|
|
1075
|
+
@click.option(
|
|
1076
|
+
'--output-folder', '-o', help='Output folder for vis metadata files.',
|
|
1077
|
+
type=click.Path(exists=False, file_okay=False, dir_okay=True, resolve_path=True),
|
|
1078
|
+
default='visualization', show_default=True
|
|
1079
|
+
)
|
|
1080
|
+
def leed_daylight_option_two_vis(output_folder):
|
|
1081
|
+
"""Write five visualization metadata files for LEED Daylight Option Two."""
|
|
1082
|
+
ill_lpar = LegendParameters(min=300, max=3000, colors=Colorset.ecotect())
|
|
1083
|
+
colors = [Color(220, 0, 0), Color(0, 220, 0)]
|
|
1084
|
+
pass_fail_lpar = \
|
|
1085
|
+
LegendParameters(min=0, max=1, colors=colors, segment_count=2, title='Pass/Fail')
|
|
1086
|
+
pass_fail_lpar.ordinal_dictionary = {0: "Fail", 1: "Pass"}
|
|
1087
|
+
|
|
1088
|
+
metric_info_dict = {
|
|
1089
|
+
'illuminance-9am': {
|
|
1090
|
+
'type': 'VisualizationMetaData',
|
|
1091
|
+
'data_type': Illuminance('Illuminance 9am').to_dict(),
|
|
1092
|
+
'unit': 'lux',
|
|
1093
|
+
'legend_parameters': ill_lpar.to_dict()
|
|
1094
|
+
},
|
|
1095
|
+
'illuminance-3pm': {
|
|
1096
|
+
'type': 'VisualizationMetaData',
|
|
1097
|
+
'data_type': Illuminance('Illuminance 3pm').to_dict(),
|
|
1098
|
+
'unit': 'lux',
|
|
1099
|
+
'legend_parameters': ill_lpar.to_dict()
|
|
1100
|
+
},
|
|
1101
|
+
'pass-fail-9am': {
|
|
1102
|
+
'type': 'VisualizationMetaData',
|
|
1103
|
+
'data_type': GenericType('Pass/Fail 9am', '').to_dict(),
|
|
1104
|
+
'unit': '',
|
|
1105
|
+
'legend_parameters': pass_fail_lpar.to_dict()
|
|
1106
|
+
},
|
|
1107
|
+
'pass-fail-3pm': {
|
|
1108
|
+
'type': 'VisualizationMetaData',
|
|
1109
|
+
'data_type': GenericType('Pass/Fail 3pm', '').to_dict(),
|
|
1110
|
+
'unit': '',
|
|
1111
|
+
'legend_parameters': pass_fail_lpar.to_dict()
|
|
1112
|
+
},
|
|
1113
|
+
'pass-fail-combined': {
|
|
1114
|
+
'type': 'VisualizationMetaData',
|
|
1115
|
+
'data_type': GenericType('Pass/Fail', '').to_dict(),
|
|
1116
|
+
'unit': '',
|
|
1117
|
+
'legend_parameters': pass_fail_lpar.to_dict()
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
try:
|
|
1121
|
+
if not os.path.exists(output_folder):
|
|
1122
|
+
os.mkdir(output_folder)
|
|
1123
|
+
for metric, data in metric_info_dict.items():
|
|
1124
|
+
if not os.path.exists(os.path.join(output_folder, metric)):
|
|
1125
|
+
os.mkdir(os.path.join(output_folder, metric))
|
|
1126
|
+
file_path = os.path.join(output_folder, metric, 'vis_metadata.json')
|
|
1127
|
+
with open(file_path, 'w') as fp:
|
|
1128
|
+
json.dump(data, fp, indent=4)
|
|
1129
|
+
except Exception:
|
|
1130
|
+
_logger.exception('Failed to write the visualization metadata files.')
|
|
1131
|
+
sys.exit(1)
|
|
1132
|
+
else:
|
|
1133
|
+
sys.exit(0)
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
@post_process.command('abnt-nbr-15575-daylight-vis-metadata')
|
|
1137
|
+
@click.option(
|
|
1138
|
+
'--output-folder', '-o', help='Output folder for vis metadata files.',
|
|
1139
|
+
type=click.Path(exists=False, file_okay=False, dir_okay=True, resolve_path=True),
|
|
1140
|
+
default='visualization', show_default=True
|
|
1141
|
+
)
|
|
1142
|
+
def abnt_nbr_15575_daylight_vis(output_folder):
|
|
1143
|
+
"""Write four visualization metadata files for ABNT NBR 15575."""
|
|
1144
|
+
ill_lpar = LegendParameters(min=48, max=1000, colors=Colorset.ecotect(),
|
|
1145
|
+
title='Iluminancia')
|
|
1146
|
+
|
|
1147
|
+
metric_info_dict = {
|
|
1148
|
+
'4_930AM': {
|
|
1149
|
+
'type': 'VisualizationMetaData',
|
|
1150
|
+
'data_type': Illuminance('23 de abril 9:30h').to_dict(),
|
|
1151
|
+
'unit': 'lux',
|
|
1152
|
+
'legend_parameters': ill_lpar.to_dict()
|
|
1153
|
+
},
|
|
1154
|
+
'4_330PM': {
|
|
1155
|
+
'type': 'VisualizationMetaData',
|
|
1156
|
+
'data_type': Illuminance('23 de abril 15:30h').to_dict(),
|
|
1157
|
+
'unit': 'lux',
|
|
1158
|
+
'legend_parameters': ill_lpar.to_dict()
|
|
1159
|
+
},
|
|
1160
|
+
'10_930AM': {
|
|
1161
|
+
'type': 'VisualizationMetaData',
|
|
1162
|
+
'data_type': Illuminance('23 de outubro 9:30h').to_dict(),
|
|
1163
|
+
'unit': 'lux',
|
|
1164
|
+
'legend_parameters': ill_lpar.to_dict()
|
|
1165
|
+
},
|
|
1166
|
+
'10_330PM': {
|
|
1167
|
+
'type': 'VisualizationMetaData',
|
|
1168
|
+
'data_type': Illuminance('23 de outubro 15:30h').to_dict(),
|
|
1169
|
+
'unit': 'lux',
|
|
1170
|
+
'legend_parameters': ill_lpar.to_dict()
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
try:
|
|
1174
|
+
if not os.path.exists(output_folder):
|
|
1175
|
+
os.mkdir(output_folder)
|
|
1176
|
+
for metric, data in metric_info_dict.items():
|
|
1177
|
+
if not os.path.exists(os.path.join(output_folder, metric)):
|
|
1178
|
+
os.mkdir(os.path.join(output_folder, metric))
|
|
1179
|
+
file_path = os.path.join(output_folder, metric, 'vis_metadata.json')
|
|
1180
|
+
with open(file_path, 'w') as fp:
|
|
1181
|
+
json.dump(data, fp, indent=4)
|
|
1182
|
+
except Exception:
|
|
1183
|
+
_logger.exception('Failed to write the visualization metadata files.')
|
|
1184
|
+
sys.exit(1)
|
|
1185
|
+
else:
|
|
1186
|
+
sys.exit(0)
|