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,545 @@
|
|
|
1
|
+
"""honeybee radiance sky commands."""
|
|
2
|
+
import click
|
|
3
|
+
import sys
|
|
4
|
+
import os
|
|
5
|
+
import logging
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
from ladybug.dt import DateTime
|
|
9
|
+
from ladybug.futil import write_to_file_by_name
|
|
10
|
+
from ladybug.wea import Wea
|
|
11
|
+
from honeybee_radiance_command.gendaymtx import Gendaymtx, GendaymtxOptions
|
|
12
|
+
from honeybee_radiance_command._command_util import run_command
|
|
13
|
+
|
|
14
|
+
import honeybee_radiance.lightsource.sky as hbsky
|
|
15
|
+
from honeybee_radiance.config import folders
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
_logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@click.group(help='Commands to generate Radiance skies.')
|
|
22
|
+
def sky():
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@sky.command('cie')
|
|
27
|
+
@click.argument('day', type=int, default=21)
|
|
28
|
+
@click.argument('month', type=str, default='Jun')
|
|
29
|
+
@click.argument('time', type=str, default='12:00')
|
|
30
|
+
@click.option('--latitude', '-lat', type=float, default=0, show_default=True,
|
|
31
|
+
help='Location latitude between -90 (south) and 90 (north).')
|
|
32
|
+
@click.option('--longitude', '-lon', type=float, default=0, show_default=True,
|
|
33
|
+
help='Location longitude between -180 (west) and 180 (east).')
|
|
34
|
+
@click.option('--time-zone', '-tz', type=int, default=None,
|
|
35
|
+
help='Time zone between -12 hours (west) and +14 hours (east). If '
|
|
36
|
+
'unspecified, the time will be interpreted as solar time at the '
|
|
37
|
+
'given longitude.')
|
|
38
|
+
@click.option('--sky-type', '-type', type=int, default=0, show_default=True, help='An '
|
|
39
|
+
'integer from 0-5 to indicate CIE Sky Type. 0 = Sunny with sun, 1 = Sunny'
|
|
40
|
+
' without sun, 2 = Intermediate with sun, 3 = Intermediate without sun, '
|
|
41
|
+
'4 = Cloudy sky, 5 = Uniform cloudy sky.')
|
|
42
|
+
@click.option('--north', '-n', type=float, default=0, show_default=True, help='A '
|
|
43
|
+
'number between -360 and 360 for the counterclockwise difference between '
|
|
44
|
+
'the North and the positive Y-axis in degrees. 90 is West; 270 is East')
|
|
45
|
+
@click.option('--ground', '-g', type=float, default=0.2, show_default=True,
|
|
46
|
+
help='Fractional value for ground reflectance.')
|
|
47
|
+
@click.option('--altitude', '-alt', type=float, default=None,
|
|
48
|
+
help='Solar altitude measured in degrees above the horizon.')
|
|
49
|
+
@click.option('--azimuth', '-az', type=float, default=None,
|
|
50
|
+
help='Solar azimuth measured in degrees east of North. East is 90, South '
|
|
51
|
+
'is 180 and West is 270. Note that this is different from Radiance '
|
|
52
|
+
'convention where the azimuth degrees are measured in west of South.')
|
|
53
|
+
@click.option('--folder', help='Output folder.', default='.', show_default=True)
|
|
54
|
+
@click.option('--name', help='Sky file name.', default=None, show_default=True)
|
|
55
|
+
def sky_cie(day, month, time, latitude, longitude, time_zone, sky_type,
|
|
56
|
+
north, ground, altitude, azimuth, folder, name):
|
|
57
|
+
"""Get a CIE sky file from parameters.
|
|
58
|
+
|
|
59
|
+
These can be a minimal representation of the sky through altitude and azimuth (eg.
|
|
60
|
+
"cie -alt 71.6 -az 185.2 -type 0"). Or it can be a detailed specification of
|
|
61
|
+
time and location (eg. "cie 21 Jun 12:00 -lat 41.78 -lon -87.75 -type 0").
|
|
62
|
+
Both the altitude and azimuth must be specified for the minimal representation
|
|
63
|
+
to be used. Otherwise, this command defaults to the detailed specification
|
|
64
|
+
of time and location.
|
|
65
|
+
|
|
66
|
+
\b
|
|
67
|
+
Args:
|
|
68
|
+
day: An intger for the day of the month (between 1 and 28-31).
|
|
69
|
+
month: Text for the 3-letter abbreviation of the month of the year (eg. "Mar").
|
|
70
|
+
time: Text for the time of day (from 0:00 to 23:59).
|
|
71
|
+
"""
|
|
72
|
+
try:
|
|
73
|
+
if altitude is not None and azimuth is not None:
|
|
74
|
+
sky_obj = hbsky.CIE(altitude, azimuth, sky_type, ground)
|
|
75
|
+
else:
|
|
76
|
+
dtime = DateTime.from_date_time_string('{} {} {}'.format(day, month, time))
|
|
77
|
+
sky_obj = hbsky.CIE.from_lat_long(
|
|
78
|
+
latitude, longitude, time_zone, dtime.month, dtime.day, dtime.float_hour,
|
|
79
|
+
sky_type, north, ground)
|
|
80
|
+
sky_obj.to_file(folder, name, True)
|
|
81
|
+
except Exception:
|
|
82
|
+
_logger.exception('Failed to generate sky.')
|
|
83
|
+
sys.exit(1)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@sky.command('climate-based')
|
|
87
|
+
@click.argument('day', type=int, default=21)
|
|
88
|
+
@click.argument('month', type=str, default='Jun')
|
|
89
|
+
@click.argument('time', type=str, default='12:00')
|
|
90
|
+
@click.option('--latitude', '-lat', type=float, default=0, show_default=True,
|
|
91
|
+
help='Location latitude between -90 (south) and 90 (north).')
|
|
92
|
+
@click.option('--longitude', '-lon', type=float, default=0, show_default=True,
|
|
93
|
+
help='Location longitude between -180 (west) and 180 (east).')
|
|
94
|
+
@click.option('--time-zone', '-tz', type=int, default=None,
|
|
95
|
+
help='Time zone between -12 hours (west) and +14 hours (east). If '
|
|
96
|
+
'unspecified, the time will be interpreted as solar time at the '
|
|
97
|
+
'given longitude.')
|
|
98
|
+
@click.option('--direct-normal-irradiance', '-dni', type=float, default=0,
|
|
99
|
+
show_default=True, help='Direct normal irradiance (W/m2).')
|
|
100
|
+
@click.option('--diffuse_horizontal_irradiance', '-dhi', type=float, default=0,
|
|
101
|
+
show_default=True, help='Diffuse horizontal irradiance (W/m2).')
|
|
102
|
+
@click.option('--north', '-n', type=float, default=0, show_default=True, help='A '
|
|
103
|
+
'number between -360 and 360 for the counterclockwise difference between '
|
|
104
|
+
'the North and the positive Y-axis in degrees. 90 is West; 270 is East')
|
|
105
|
+
@click.option('--ground', '-g', type=float, default=0.2, show_default=True,
|
|
106
|
+
help='Fractional value for ground reflectance.')
|
|
107
|
+
@click.option('--altitude', '-alt', type=float, default=None,
|
|
108
|
+
help='Solar altitude measured in degrees above the horizon.')
|
|
109
|
+
@click.option('--azimuth', '-az', type=float, default=None,
|
|
110
|
+
help='Solar azimuth measured in degrees east of North. East is 90, South '
|
|
111
|
+
'is 180 and West is 270. Note that this is different from Radiance '
|
|
112
|
+
'convention where the azimuth degrees are measured in west of South.')
|
|
113
|
+
@click.option('--folder', help='Output folder.', default='.', show_default=True)
|
|
114
|
+
@click.option('--name', help='Sky file name.', default=None, show_default=True)
|
|
115
|
+
def sky_climate_based(
|
|
116
|
+
day, month, time, latitude, longitude, time_zone, direct_normal_irradiance,
|
|
117
|
+
diffuse_horizontal_irradiance, north, ground, altitude, azimuth, folder, name):
|
|
118
|
+
"""Get a ClimateBased sky file from parameters.
|
|
119
|
+
|
|
120
|
+
These can be a minimal representation of the sky through altitude and azimuth (eg.
|
|
121
|
+
"climate-based -alt 71.6 -az 185.2 -dni 800 -dhi 120"). Or it can be a detailed
|
|
122
|
+
specification of time and location (eg. "climate-based 21 Jun 12:00 -lat 41.78
|
|
123
|
+
-lon -87.75 -dni 800 -dhi 120"). Both the altitude and azimuth must be specified
|
|
124
|
+
for the minimal representation to be used. Otherwise, this command defaults
|
|
125
|
+
to the detailed specification of time and location.
|
|
126
|
+
|
|
127
|
+
\b
|
|
128
|
+
Args:
|
|
129
|
+
day: An intger for the day of the month (between 1 and 28-31).
|
|
130
|
+
month: Text for the 3-letter abbreviation of the month of the year (eg. "Mar").
|
|
131
|
+
time: Text for the time of day (from 0:00 to 23:59).
|
|
132
|
+
"""
|
|
133
|
+
try:
|
|
134
|
+
if altitude is not None and azimuth is not None:
|
|
135
|
+
sky_obj = hbsky.ClimateBased(
|
|
136
|
+
altitude, azimuth, direct_normal_irradiance,
|
|
137
|
+
diffuse_horizontal_irradiance, ground)
|
|
138
|
+
else:
|
|
139
|
+
dtime = DateTime.from_date_time_string('{} {} {}'.format(day, month, time))
|
|
140
|
+
sky_obj = hbsky.ClimateBased.from_lat_long(
|
|
141
|
+
latitude, longitude, time_zone, dtime.month, dtime.day, dtime.float_hour,
|
|
142
|
+
direct_normal_irradiance, diffuse_horizontal_irradiance,
|
|
143
|
+
north, ground)
|
|
144
|
+
sky_obj.to_file(folder, name, True)
|
|
145
|
+
except Exception:
|
|
146
|
+
_logger.exception('Failed to generate sky.')
|
|
147
|
+
sys.exit(1)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@sky.command('irradiance')
|
|
151
|
+
@click.argument('irrad', default=558.659, type=float)
|
|
152
|
+
@click.option('--ground', '-g', type=float, default=0.2, show_default=True,
|
|
153
|
+
help='Fractional value for ground reflectance.')
|
|
154
|
+
@click.option('--cloudy/--uniform', '-u', default=True,
|
|
155
|
+
help='Flag to note whether the sky is uniform instead of cloudy.')
|
|
156
|
+
@click.option('--folder', help='Output folder.', default='.', show_default=True)
|
|
157
|
+
@click.option('--name', help='Sky file name.', default=None, show_default=True)
|
|
158
|
+
def sky_with_certain_irrad(irrad, ground, cloudy, folder, name):
|
|
159
|
+
"""Generate an overcast / cloudy sky with certain irradiance value.
|
|
160
|
+
|
|
161
|
+
\b
|
|
162
|
+
Args:
|
|
163
|
+
irrad: Desired irradiance value in W/m2. (Default: 558.659).
|
|
164
|
+
"""
|
|
165
|
+
try:
|
|
166
|
+
uniform = not cloudy
|
|
167
|
+
c_sky = hbsky.CertainIrradiance(irrad, ground, uniform)
|
|
168
|
+
c_sky.to_file(folder, name, True)
|
|
169
|
+
except Exception:
|
|
170
|
+
_logger.exception('Failed to generate sky.')
|
|
171
|
+
sys.exit(1)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@sky.command('illuminance')
|
|
175
|
+
@click.argument('illum', default=100000, type=float)
|
|
176
|
+
@click.option('--ground', '-g', type=float, default=0.2, show_default=True,
|
|
177
|
+
help='Fractional value for ground reflectance.')
|
|
178
|
+
@click.option('--cloudy/--uniform', '-u', default=True,
|
|
179
|
+
help='Flag to note whether the sky is uniform instead of cloudy.')
|
|
180
|
+
@click.option('--folder', help='Output folder.', default='.', show_default=True)
|
|
181
|
+
@click.option('--name', help='Sky file name.', default=None, show_default=True)
|
|
182
|
+
def sky_with_certain_illum(illum, ground, cloudy, folder, name):
|
|
183
|
+
"""Generate an overcast / cloudy sky with certain illuminance value.
|
|
184
|
+
|
|
185
|
+
\b
|
|
186
|
+
Args:
|
|
187
|
+
illum: Desired illuminance value in lux. (Default: 100000).
|
|
188
|
+
"""
|
|
189
|
+
try:
|
|
190
|
+
uniform = not cloudy
|
|
191
|
+
c_sky = hbsky.CertainIrradiance.from_illuminance(illum, ground, uniform)
|
|
192
|
+
c_sky.to_file(folder, name, True)
|
|
193
|
+
except Exception:
|
|
194
|
+
_logger.exception('Failed to generate sky.')
|
|
195
|
+
sys.exit(1)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@sky.command('skydome')
|
|
199
|
+
@click.option(
|
|
200
|
+
'--sky-density', type=int, help='Sky patch subdivision density. This values is '
|
|
201
|
+
'similar to -m option in gendaymtx command. Default is 1 which means 145 sky '
|
|
202
|
+
'patches and 1 patch for the ground. One can add to the resolution typically by '
|
|
203
|
+
'factors of two (2, 4, 8, ...) which yields a higher resolution sky using the '
|
|
204
|
+
'Reinhart patch subdivision', default=1, show_default=True)
|
|
205
|
+
@click.option('--folder', help='Output folder.', default='.', show_default=True)
|
|
206
|
+
@click.option('--name', help='Sky file name.', default=None, show_default=True)
|
|
207
|
+
def sky_dome(sky_density, folder, name):
|
|
208
|
+
"""Virtual skydome for daylight coefficient studies with constant radiance.
|
|
209
|
+
|
|
210
|
+
Use this sky to calculate daylight matrix.
|
|
211
|
+
"""
|
|
212
|
+
try:
|
|
213
|
+
c_sky = hbsky.SkyDome(sky_density=sky_density)
|
|
214
|
+
c_sky.to_file(folder, name, True)
|
|
215
|
+
except Exception:
|
|
216
|
+
_logger.exception('Failed to generate sky.')
|
|
217
|
+
sys.exit(1)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@sky.command('uniform-sky')
|
|
221
|
+
@click.option('--ground-emittance', '-g', type=float, help='Ground emittance value.',
|
|
222
|
+
default=0.2, show_default=True)
|
|
223
|
+
@click.option('--folder', help='Output folder.', default='.', show_default=True)
|
|
224
|
+
@click.option('--name', help='Sky file name.', default='uniform_sky', show_default=True)
|
|
225
|
+
def uniform_sky(ground_emittance, folder, name):
|
|
226
|
+
"""Virtual skydome with uniform characteristics.
|
|
227
|
+
|
|
228
|
+
This sky is usually used to create an octree that is sent to rcontrib command.
|
|
229
|
+
"""
|
|
230
|
+
try:
|
|
231
|
+
c_sky = hbsky.UniformSky(ground_emittance=ground_emittance)
|
|
232
|
+
c_sky.to_file(folder, name, True)
|
|
233
|
+
except Exception:
|
|
234
|
+
_logger.exception('Failed to generate sky.')
|
|
235
|
+
sys.exit(1)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@sky.command('mtx')
|
|
239
|
+
@click.argument('wea', type=click.Path(
|
|
240
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
241
|
+
@click.option(
|
|
242
|
+
'--north', default=0, type=float, show_default=True,
|
|
243
|
+
help='Angle to north (0-360). 90 is west and 270 is east')
|
|
244
|
+
@click.option(
|
|
245
|
+
'--sky-type', type=click.Choice(['sun-only', 'no-sun', 'total']),
|
|
246
|
+
default='total'
|
|
247
|
+
)
|
|
248
|
+
@click.option(
|
|
249
|
+
'--sky-density', type=int, default=1, help='The density of generated sky. This '
|
|
250
|
+
'input corresponds to gendaymtx -m option. -m 1 generates 146 patch starting with '
|
|
251
|
+
'0 for the ground and continuing to 145 for the zenith. Increasing the -m parameter '
|
|
252
|
+
'yields a higher resolution sky using the Reinhart patch subdivision. For example, '
|
|
253
|
+
'setting -m 4 yields a sky with 2305 patches plus one patch for the ground.'
|
|
254
|
+
)
|
|
255
|
+
@click.option(
|
|
256
|
+
'--output-format', type=click.Choice(['float', 'double', 'ASCII']),
|
|
257
|
+
default='ASCII'
|
|
258
|
+
)
|
|
259
|
+
@click.option(
|
|
260
|
+
'--hourly/--cumulative', is_flag=True, default=True, help='Flag to generate a '
|
|
261
|
+
'cumulative or hourly sky.'
|
|
262
|
+
)
|
|
263
|
+
@click.option(
|
|
264
|
+
'--visible/--solar', is_flag=True, default=True, help='A flag to indicate the '
|
|
265
|
+
'output type. Visible is equal to -O0 and solar is -O1 in gendaymtx options. '
|
|
266
|
+
'Default: visible.'
|
|
267
|
+
)
|
|
268
|
+
@click.option(
|
|
269
|
+
'--all-hours/--sun-up-hours', is_flag=True, default=True, help='A flag to indicate '
|
|
270
|
+
'if only sun up hours should be included in the sky. By default all the hours from '
|
|
271
|
+
'the input wea file will be included.'
|
|
272
|
+
)
|
|
273
|
+
@click.option('--folder', type=click.Path(
|
|
274
|
+
exists=False, file_okay=False, dir_okay=True, resolve_path=True), default='.',
|
|
275
|
+
help='Output folder.')
|
|
276
|
+
@click.option('--name', default='sky', help='File name.')
|
|
277
|
+
@click.option(
|
|
278
|
+
'--log-file', help='Optional log file to output the name of the newly'
|
|
279
|
+
' created modifier files. By default the list will be printed out to stdout',
|
|
280
|
+
type=click.File('w'), default='-')
|
|
281
|
+
@click.option(
|
|
282
|
+
'--dry-run', is_flag=True, default=False, show_default=True,
|
|
283
|
+
help='A flag to show the command without running it.'
|
|
284
|
+
)
|
|
285
|
+
def sunpath_from_wea_rad(
|
|
286
|
+
wea, north, sky_type, sky_density, output_format, hourly, visible, all_hours,
|
|
287
|
+
folder, name, log_file, dry_run
|
|
288
|
+
):
|
|
289
|
+
"""Generate a climate-based sky matrix from a Wea file using radiance's gendaymtx.
|
|
290
|
+
|
|
291
|
+
\b
|
|
292
|
+
Args:
|
|
293
|
+
wea: Path to a wea file. This can also be an epw file.
|
|
294
|
+
"""
|
|
295
|
+
try:
|
|
296
|
+
if not os.path.exists(folder):
|
|
297
|
+
os.makedirs(folder)
|
|
298
|
+
with open(wea) as inf:
|
|
299
|
+
first_word = inf.read(5)
|
|
300
|
+
is_wea = True if first_word == 'place' else False
|
|
301
|
+
if not is_wea:
|
|
302
|
+
_wea_file = os.path.join(os.path.dirname(wea), 'epw_to_wea.wea')
|
|
303
|
+
wea = Wea.from_epw_file(wea).write(_wea_file)
|
|
304
|
+
output = os.path.join(folder, '%s.mtx' % name)
|
|
305
|
+
opt = GendaymtxOptions()
|
|
306
|
+
opt.r = north
|
|
307
|
+
opt.O = '0' if visible else '1'
|
|
308
|
+
if sky_type == 'total':
|
|
309
|
+
pass
|
|
310
|
+
elif sky_type == 'sun-only':
|
|
311
|
+
opt.d = True
|
|
312
|
+
elif sky_type == 'no-sun':
|
|
313
|
+
opt.s = True
|
|
314
|
+
|
|
315
|
+
if output_format == 'ASCII':
|
|
316
|
+
pass
|
|
317
|
+
elif output_format == 'float':
|
|
318
|
+
opt.o = 'f'
|
|
319
|
+
elif output_format == 'double':
|
|
320
|
+
opt.o = 'd'
|
|
321
|
+
|
|
322
|
+
if not hourly:
|
|
323
|
+
opt.A = True
|
|
324
|
+
|
|
325
|
+
if not all_hours:
|
|
326
|
+
opt.u = True
|
|
327
|
+
if sky_density > 1:
|
|
328
|
+
opt.m = sky_density
|
|
329
|
+
|
|
330
|
+
cmd = Gendaymtx(wea=wea, options=opt, output=output)
|
|
331
|
+
if dry_run:
|
|
332
|
+
print(cmd.to_radiance())
|
|
333
|
+
sys.exit(0)
|
|
334
|
+
|
|
335
|
+
try:
|
|
336
|
+
run_command(cmd.to_radiance(), env=folders.env)
|
|
337
|
+
except RuntimeError as e: # likely a nighttime Wea; write blank .mtx file
|
|
338
|
+
with open(output, 'w') as wf:
|
|
339
|
+
wf.write('')
|
|
340
|
+
files = [{'path': os.path.relpath(output, folder), 'full_path': output}]
|
|
341
|
+
log_file.write(json.dumps(files))
|
|
342
|
+
|
|
343
|
+
except Exception:
|
|
344
|
+
_logger.exception('Failed to generate sunpath.')
|
|
345
|
+
sys.exit(1)
|
|
346
|
+
else:
|
|
347
|
+
sys.exit(0)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
@sky.command('adjust-for-metric')
|
|
351
|
+
@click.argument('sky', type=click.Path(
|
|
352
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
353
|
+
@click.option(
|
|
354
|
+
'--metric', '-m', default='illuminance', show_default=True,
|
|
355
|
+
help='Text for the type of metric to be output from the calculation. Choose from: '
|
|
356
|
+
'illuminance, irradiance, luminance, radiance.'
|
|
357
|
+
)
|
|
358
|
+
@click.option('--folder', help='Output folder.', default='.', show_default=True)
|
|
359
|
+
@click.option('--name', help='Sky file name.', default=None, show_default=True)
|
|
360
|
+
def adjust_sky_for_metric(sky, metric, folder, name):
|
|
361
|
+
"""Adjust a sky file to ensure it is suitable for a given metric.
|
|
362
|
+
|
|
363
|
+
Specifically, this ensures that skies being created with gendaylit have a -O
|
|
364
|
+
option that aligns with visible vs. solar energy.
|
|
365
|
+
|
|
366
|
+
\b
|
|
367
|
+
Args:
|
|
368
|
+
sky: Path to a .sky file to be adjusted based on the metric.
|
|
369
|
+
"""
|
|
370
|
+
try:
|
|
371
|
+
with open(sky) as inf:
|
|
372
|
+
content = inf.read()
|
|
373
|
+
if content.startswith('!gendaylit'):
|
|
374
|
+
split_content = content.split('\n')
|
|
375
|
+
first_line = split_content[0].replace('-O 0', '-O 1') if metric in \
|
|
376
|
+
('irradiance', 'radiance') else split_content[0].replace('-O 1', '-O 0')
|
|
377
|
+
split_content[0] = first_line
|
|
378
|
+
content = '\n'.join(split_content)
|
|
379
|
+
name = '{}.sky'.format(metric) if name is None else name
|
|
380
|
+
write_to_file_by_name(folder, name, content, True)
|
|
381
|
+
except Exception:
|
|
382
|
+
_logger.exception('Failed to adjust sky.')
|
|
383
|
+
sys.exit(1)
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
@sky.command('leed-illuminance')
|
|
387
|
+
@click.argument('wea', type=click.Path(
|
|
388
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
389
|
+
@click.option(
|
|
390
|
+
'--north', '-n', type=float, default=0, show_default=True, help='A '
|
|
391
|
+
'number between -360 and 360 for the counterclockwise difference between '
|
|
392
|
+
'the North and the positive Y-axis in degrees. 90 is West; 270 is East')
|
|
393
|
+
@click.option('--folder', type=click.Path(
|
|
394
|
+
exists=False, file_okay=False, dir_okay=True, resolve_path=True), default='.',
|
|
395
|
+
help='Output folder for the two generated .sky files.')
|
|
396
|
+
@click.option(
|
|
397
|
+
'--name', help='Sky file base name. Each of the two output skies will have this '
|
|
398
|
+
'base name concatenated with 9AM or 3PM', default='', show_default=True)
|
|
399
|
+
@click.option(
|
|
400
|
+
'--log-file', help='Optional log file to output the information about the two '
|
|
401
|
+
'generated sky files. By default the list will be printed out to stdout',
|
|
402
|
+
type=click.File('w'), default='-')
|
|
403
|
+
def leed_illuminance(wea, north, folder, name, log_file):
|
|
404
|
+
"""Generate two climate-based lear skies for LEED v4.1 Daylight Option 2.
|
|
405
|
+
|
|
406
|
+
This involves evaluating the input TMY Wea, finding the clearest day within
|
|
407
|
+
15 days of September and March, and using that to generate skies at 9AM and 3PM.
|
|
408
|
+
|
|
409
|
+
\b
|
|
410
|
+
Args:
|
|
411
|
+
wea: Path to a Typical Meteorological Year (TMY) .wea file. The file must
|
|
412
|
+
be annual with a timestep of 1 for a non-leap year. This can also be
|
|
413
|
+
an .epw
|
|
414
|
+
"""
|
|
415
|
+
try:
|
|
416
|
+
with open(wea) as inf:
|
|
417
|
+
first_word = inf.read(5)
|
|
418
|
+
is_wea = True if first_word == 'place' else False
|
|
419
|
+
if not is_wea:
|
|
420
|
+
_wea_file = os.path.join(os.path.dirname(wea), 'epw_to_wea.wea')
|
|
421
|
+
wea = Wea.from_epw_file(wea).write(_wea_file)
|
|
422
|
+
# get HOYs for the time around the equinoxes
|
|
423
|
+
mar_9, sep_9 = DateTime(3, 21, 9).hoy, DateTime(9, 21, 9).hoy
|
|
424
|
+
mar_3, sep_3 = DateTime(3, 21, 15).hoy, DateTime(9, 21, 15).hoy
|
|
425
|
+
hoys_mar9 = list(range(int(mar_9 - (15 * 24)), int(mar_9 + (15 * 24)), 24))
|
|
426
|
+
hoys_sep9 = list(range(int(sep_9 - (15 * 24)), int(sep_9 + (15 * 24)), 24))
|
|
427
|
+
hoys_mar3 = list(range(int(mar_3 - (15 * 24)), int(mar_3 + (15 * 24)), 24))
|
|
428
|
+
hoys_sep3 = list(range(int(sep_3 - (15 * 24)), int(sep_3 + (15 * 24)), 24))
|
|
429
|
+
|
|
430
|
+
# analyze the Wea file to get the sunniest days around the equinoxes
|
|
431
|
+
wea_obj = Wea.from_file(wea)
|
|
432
|
+
dni = wea_obj.direct_normal_irradiance
|
|
433
|
+
dhi = wea_obj.diffuse_horizontal_irradiance
|
|
434
|
+
irr_mar9 = [x for _, x in sorted(zip([dni[h] for h in hoys_mar9], hoys_mar9))]
|
|
435
|
+
irr_sep9 = [x for _, x in sorted(zip([dni[h] for h in hoys_sep9], hoys_sep9))]
|
|
436
|
+
irr_mar3 = [x for _, x in sorted(zip([dni[h] for h in hoys_mar3], hoys_mar3))]
|
|
437
|
+
irr_sep3 = [x for _, x in sorted(zip([dni[h] for h in hoys_sep3], hoys_sep3))]
|
|
438
|
+
|
|
439
|
+
# create the clear sky objects from the averaged irradiance
|
|
440
|
+
dni_9 = (dni[irr_mar9[-1]] + dni[irr_sep9[-1]]) / 2
|
|
441
|
+
dhi_9 = (dhi[irr_mar9[-1]] + dhi[irr_sep9[-1]]) / 2
|
|
442
|
+
dni_3 = (dni[irr_mar3[-1]] + dni[irr_sep3[-1]]) / 2
|
|
443
|
+
dhi_3 = (dhi[irr_mar3[-1]] + dhi[irr_sep3[-1]]) / 2
|
|
444
|
+
sky_obj_9 = hbsky.ClimateBased.from_location(
|
|
445
|
+
wea_obj.location, 3, 21, 9, dni_9, dhi_9, north)
|
|
446
|
+
sky_obj_3 = hbsky.ClimateBased.from_location(
|
|
447
|
+
wea_obj.location, 3, 21, 15, dni_3, dhi_3, north)
|
|
448
|
+
|
|
449
|
+
# write out the sky files and the log file
|
|
450
|
+
output_9 = sky_obj_9.to_file(folder, '{}9AM.sky'.format(name), True)
|
|
451
|
+
output_3 = sky_obj_3.to_file(folder, '{}3PM.sky'.format(name), True)
|
|
452
|
+
files = [
|
|
453
|
+
{
|
|
454
|
+
'id': '{}9AM'.format(name),
|
|
455
|
+
'path': os.path.relpath(output_9, folder),
|
|
456
|
+
'full_path': output_9
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
'id': '{}3PM'.format(name),
|
|
460
|
+
'path': os.path.relpath(output_3, folder),
|
|
461
|
+
'full_path': output_3
|
|
462
|
+
}
|
|
463
|
+
]
|
|
464
|
+
log_file.write(json.dumps(files))
|
|
465
|
+
except Exception:
|
|
466
|
+
_logger.exception('Failed to create LEED skies.')
|
|
467
|
+
sys.exit(1)
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
@sky.command('abnt-nbr-15575')
|
|
471
|
+
@click.argument('wea', type=click.Path(
|
|
472
|
+
exists=True, file_okay=True, dir_okay=False, resolve_path=True))
|
|
473
|
+
@click.option(
|
|
474
|
+
'--north', '-n', type=float, default=0, show_default=True, help='A '
|
|
475
|
+
'number between -360 and 360 for the counterclockwise difference between '
|
|
476
|
+
'the North and the positive Y-axis in degrees. 90 is West; 270 is East.')
|
|
477
|
+
@click.option('--folder', type=click.Path(
|
|
478
|
+
exists=False, file_okay=False, dir_okay=True, resolve_path=True), default='.',
|
|
479
|
+
help='Output folder for the four generated .sky files.')
|
|
480
|
+
@click.option(
|
|
481
|
+
'--log-file', help='Optional log file to output the information about the '
|
|
482
|
+
'four generated sky files. By default the list will be printed out to stdout.',
|
|
483
|
+
type=click.File('w'), default='-')
|
|
484
|
+
def abnt_nbr_15575(wea, north, folder, log_file):
|
|
485
|
+
"""Generate four CIE skies for ABNT NBR 15575.
|
|
486
|
+
|
|
487
|
+
The four skies are:
|
|
488
|
+
- April 23rd at 9:30AM and 3:30PM.
|
|
489
|
+
- October 23rd at 9:30AM and 3:30PM.
|
|
490
|
+
|
|
491
|
+
\b
|
|
492
|
+
Args:
|
|
493
|
+
wea: Path to a Typical Meteorological Year (TMY) .wea file. This can
|
|
494
|
+
also be an .epw. The file is only used to extract the location.
|
|
495
|
+
"""
|
|
496
|
+
try:
|
|
497
|
+
with open(wea, errors='ignore') as inf:
|
|
498
|
+
first_word = inf.read(5)
|
|
499
|
+
is_wea = True if first_word == 'place' else False
|
|
500
|
+
if not is_wea:
|
|
501
|
+
wea = Wea.from_epw_file(wea)
|
|
502
|
+
else:
|
|
503
|
+
wea = Wea.from_file(wea)
|
|
504
|
+
|
|
505
|
+
sky_type = 3
|
|
506
|
+
sky_obj_4_930am = hbsky.CIE.from_location(
|
|
507
|
+
wea.location, 4, 23, 9.5, sky_type=sky_type, north_angle=north)
|
|
508
|
+
sky_obj_4_330pm = hbsky.CIE.from_location(
|
|
509
|
+
wea.location, 4, 23, 15.5, sky_type=sky_type, north_angle=north)
|
|
510
|
+
sky_obj_10_930am = hbsky.CIE.from_location(
|
|
511
|
+
wea.location, 10, 23, 9.5, sky_type=sky_type, north_angle=north)
|
|
512
|
+
sky_obj_10_330pm = hbsky.CIE.from_location(
|
|
513
|
+
wea.location, 10, 23, 15.5, sky_type=sky_type, north_angle=north)
|
|
514
|
+
|
|
515
|
+
# write out the sky files and the log file
|
|
516
|
+
output_4_930am = sky_obj_4_930am.to_file(folder, '4_930AM.sky', True)
|
|
517
|
+
output_4_330pm = sky_obj_4_330pm.to_file(folder, '4_330PM.sky', True)
|
|
518
|
+
output_10_930am = sky_obj_10_930am.to_file(folder, '10_930AM.sky', True)
|
|
519
|
+
output_10_330pm = sky_obj_10_330pm.to_file(folder, '10_330PM.sky', True)
|
|
520
|
+
files = [
|
|
521
|
+
{
|
|
522
|
+
'id': '4_930AM',
|
|
523
|
+
'path': os.path.relpath(output_4_930am, folder),
|
|
524
|
+
'full_path': output_4_930am
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
'id': '4_330PM',
|
|
528
|
+
'path': os.path.relpath(output_4_330pm, folder),
|
|
529
|
+
'full_path': output_4_330pm
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
'id': '10_930AM',
|
|
533
|
+
'path': os.path.relpath(output_10_930am, folder),
|
|
534
|
+
'full_path': output_10_930am
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
'id': '10_330PM',
|
|
538
|
+
'path': os.path.relpath(output_10_330pm, folder),
|
|
539
|
+
'full_path': output_10_330pm
|
|
540
|
+
}
|
|
541
|
+
]
|
|
542
|
+
log_file.write(json.dumps(files))
|
|
543
|
+
except Exception:
|
|
544
|
+
_logger.exception('Failed to create ABNT NBR 15575 skies.')
|
|
545
|
+
sys.exit(1)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""honeybee radiance study command."""
|
|
2
|
+
import click
|
|
3
|
+
import sys
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import shutil
|
|
7
|
+
import json
|
|
8
|
+
|
|
9
|
+
from ladybug.wea import Wea
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
_logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@click.group(help='Commands to create info files for studies.')
|
|
16
|
+
def study():
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@study.command('study-info')
|
|
21
|
+
@click.argument(
|
|
22
|
+
'wea', type=click.Path(exists=True, dir_okay=False, resolve_path=True))
|
|
23
|
+
@click.argument('timestep', type=click.INT)
|
|
24
|
+
@click.option('--folder', '-f', help='Output folder.', default='.', show_default=True)
|
|
25
|
+
@click.option(
|
|
26
|
+
'--name', '-n', help='Output file name study info.',
|
|
27
|
+
type=click.STRING, default='study_info', show_default=True
|
|
28
|
+
)
|
|
29
|
+
def study_info(wea, timestep, folder, name):
|
|
30
|
+
"""Create a study info file.
|
|
31
|
+
|
|
32
|
+
This command generates a study info file with the timestep and the hoys of
|
|
33
|
+
the wea.
|
|
34
|
+
|
|
35
|
+
\b
|
|
36
|
+
Args:
|
|
37
|
+
wea: Path to wea file.
|
|
38
|
+
timestep: Timestep of the study.
|
|
39
|
+
"""
|
|
40
|
+
try:
|
|
41
|
+
study_info = {}
|
|
42
|
+
with open(wea) as inf:
|
|
43
|
+
first_word = inf.read(5)
|
|
44
|
+
is_wea = True if first_word == 'place' else False
|
|
45
|
+
if not is_wea:
|
|
46
|
+
_wea_file = os.path.join(os.path.dirname(wea), 'epw_to_wea.wea')
|
|
47
|
+
if os.path.splitext(wea)[-1] != '.epw':
|
|
48
|
+
wea = shutil.copyfile(wea, os.path.splitext(wea)[0] + '.epw')
|
|
49
|
+
wea = Wea.from_epw_file(wea).write(_wea_file)
|
|
50
|
+
wea = Wea.from_file(wea, timestep=timestep)
|
|
51
|
+
study_info['timestep'] = timestep
|
|
52
|
+
study_info['study_hours'] = wea.hoys
|
|
53
|
+
|
|
54
|
+
if not os.path.isdir(folder):
|
|
55
|
+
os.makedirs(folder)
|
|
56
|
+
|
|
57
|
+
# write JSON
|
|
58
|
+
file_path = os.path.join(folder, '%s.json' % name)
|
|
59
|
+
with open(file_path, 'w') as fp:
|
|
60
|
+
json.dump(study_info, fp)
|
|
61
|
+
|
|
62
|
+
except Exception:
|
|
63
|
+
_logger.exception('Failed to generate study info file.')
|
|
64
|
+
sys.exit(1)
|
|
65
|
+
else:
|
|
66
|
+
sys.exit(0)
|