honeybee-grasshopper-radiance 1.35.1__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.
- honeybee_grasshopper_radiance/__init__.py +7 -0
- honeybee_grasshopper_radiance/src/HB Adjust HDR.py +107 -0
- honeybee_grasshopper_radiance/src/HB Ambient Resolution.py +63 -0
- honeybee_grasshopper_radiance/src/HB Annual Average Values.py +205 -0
- honeybee_grasshopper_radiance/src/HB Annual Cumulative Values.py +191 -0
- honeybee_grasshopper_radiance/src/HB Annual Daylight Metrics.py +209 -0
- honeybee_grasshopper_radiance/src/HB Annual Daylight.py +153 -0
- honeybee_grasshopper_radiance/src/HB Annual Glare Metrics.py +137 -0
- honeybee_grasshopper_radiance/src/HB Annual Irradiance.py +112 -0
- honeybee_grasshopper_radiance/src/HB Annual Peak Values.py +224 -0
- honeybee_grasshopper_radiance/src/HB Annual Results to Data.py +246 -0
- honeybee_grasshopper_radiance/src/HB Annual Sunlight Exposure.py +147 -0
- honeybee_grasshopper_radiance/src/HB Aperture Group Schedule.py +69 -0
- honeybee_grasshopper_radiance/src/HB Apply Face Modifier.py +107 -0
- honeybee_grasshopper_radiance/src/HB Apply ModifierSet.py +71 -0
- honeybee_grasshopper_radiance/src/HB Apply Shade Modifier.py +110 -0
- honeybee_grasshopper_radiance/src/HB Apply Window Modifier.py +120 -0
- honeybee_grasshopper_radiance/src/HB Assign Grids and Views.py +58 -0
- honeybee_grasshopper_radiance/src/HB Automatic Aperture Group.py +100 -0
- honeybee_grasshopper_radiance/src/HB BSDF Modifier.py +78 -0
- honeybee_grasshopper_radiance/src/HB CIE Standard Sky.py +75 -0
- honeybee_grasshopper_radiance/src/HB Certain Illuminance.py +41 -0
- honeybee_grasshopper_radiance/src/HB Check Scene.py +208 -0
- honeybee_grasshopper_radiance/src/HB Climatebased Sky.py +75 -0
- honeybee_grasshopper_radiance/src/HB Cumulative Radiation.py +98 -0
- honeybee_grasshopper_radiance/src/HB Custom Sky.py +74 -0
- honeybee_grasshopper_radiance/src/HB Daylight Control Schedule.py +211 -0
- honeybee_grasshopper_radiance/src/HB Daylight Factor.py +82 -0
- honeybee_grasshopper_radiance/src/HB Deconstruct Modifier.py +47 -0
- honeybee_grasshopper_radiance/src/HB Deconstruct ModifierSet Interior.py +67 -0
- honeybee_grasshopper_radiance/src/HB Deconstruct ModifierSet.py +80 -0
- honeybee_grasshopper_radiance/src/HB Deconstruct Wea.py +44 -0
- honeybee_grasshopper_radiance/src/HB Direct Sun Hours.py +88 -0
- honeybee_grasshopper_radiance/src/HB Dynamic Aperture Group.py +90 -0
- honeybee_grasshopper_radiance/src/HB Dynamic Shade Group.py +95 -0
- honeybee_grasshopper_radiance/src/HB Dynamic State Geometry.py +68 -0
- honeybee_grasshopper_radiance/src/HB Dynamic State.py +44 -0
- honeybee_grasshopper_radiance/src/HB Exterior Modifier Subset.py +68 -0
- honeybee_grasshopper_radiance/src/HB Extract HDR.py +225 -0
- honeybee_grasshopper_radiance/src/HB False Color.py +246 -0
- honeybee_grasshopper_radiance/src/HB Get Dynamic Groups.py +57 -0
- honeybee_grasshopper_radiance/src/HB Get Grids and Views.py +82 -0
- honeybee_grasshopper_radiance/src/HB Glare Postprocess.py +225 -0
- honeybee_grasshopper_radiance/src/HB Glass Modifier 3.py +62 -0
- honeybee_grasshopper_radiance/src/HB Glass Modifier.py +58 -0
- honeybee_grasshopper_radiance/src/HB HDR to GIF.py +72 -0
- honeybee_grasshopper_radiance/src/HB Imageless Annual Glare.py +108 -0
- honeybee_grasshopper_radiance/src/HB Interior Modifier Subset.py +83 -0
- honeybee_grasshopper_radiance/src/HB Metal Modifier 3.py +70 -0
- honeybee_grasshopper_radiance/src/HB Metal Modifier.py +68 -0
- honeybee_grasshopper_radiance/src/HB Mirror Modifier 3.py +56 -0
- honeybee_grasshopper_radiance/src/HB Mirror Modifier.py +55 -0
- honeybee_grasshopper_radiance/src/HB Model to Rad Folder.py +75 -0
- honeybee_grasshopper_radiance/src/HB ModifierSet.py +127 -0
- honeybee_grasshopper_radiance/src/HB Opaque Modifier 3.py +68 -0
- honeybee_grasshopper_radiance/src/HB Opaque Modifier.py +67 -0
- honeybee_grasshopper_radiance/src/HB Point-In-Time Grid-Based.py +93 -0
- honeybee_grasshopper_radiance/src/HB Point-In-Time View-Based.py +127 -0
- honeybee_grasshopper_radiance/src/HB Radial Grid from Rooms.py +160 -0
- honeybee_grasshopper_radiance/src/HB Radial Sensor Grid.py +99 -0
- honeybee_grasshopper_radiance/src/HB Radiance Parameter.py +163 -0
- honeybee_grasshopper_radiance/src/HB Search Modifier Sets.py +58 -0
- honeybee_grasshopper_radiance/src/HB Search Modifiers.py +58 -0
- honeybee_grasshopper_radiance/src/HB Section Plane View.py +69 -0
- honeybee_grasshopper_radiance/src/HB Sensor Grid from Apertures.py +153 -0
- honeybee_grasshopper_radiance/src/HB Sensor Grid from Faces.py +147 -0
- honeybee_grasshopper_radiance/src/HB Sensor Grid from Rooms.py +210 -0
- honeybee_grasshopper_radiance/src/HB Sensor Grid.py +82 -0
- honeybee_grasshopper_radiance/src/HB Shade Modifier Subset.py +62 -0
- honeybee_grasshopper_radiance/src/HB Sky View.py +86 -0
- honeybee_grasshopper_radiance/src/HB Spatial Daylight Autonomy.py +86 -0
- honeybee_grasshopper_radiance/src/HB Subface Modifier Subset.py +90 -0
- honeybee_grasshopper_radiance/src/HB Translucent Modifier 3.py +77 -0
- honeybee_grasshopper_radiance/src/HB Translucent Modifier.py +77 -0
- honeybee_grasshopper_radiance/src/HB View from Viewport.py +85 -0
- honeybee_grasshopper_radiance/src/HB View.py +96 -0
- honeybee_grasshopper_radiance/src/HB Visualize Sky.py +141 -0
- honeybee_grasshopper_radiance/src/HB Wea From Clear Sky.py +61 -0
- honeybee_grasshopper_radiance/src/HB Wea From EPW.py +50 -0
- honeybee_grasshopper_radiance/src/HB Wea From Tau Clear Sky.py +56 -0
- honeybee_grasshopper_radiance/src/HB Wea from Zhang-Huang.py +63 -0
- honeybee_grasshopper_radiance/src/__init__.py +1 -0
- honeybee_grasshopper_radiance/user_objects/HB Adjust HDR.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Ambient Resolution.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Annual Average Values.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Annual Cumulative Values.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Annual Daylight Metrics.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Annual Daylight.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Annual Glare Metrics.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Annual Irradiance.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Annual Peak Values.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Annual Results to Data.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Annual Sunlight Exposure.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Aperture Group Schedule.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Apply Face Modifier.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Apply ModifierSet.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Apply Shade Modifier.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Apply Window Modifier.ghuser +0 -0
- Views.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Automatic Aperture Group.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB BSDF Modifier.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB CIE Standard Sky.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Certain Illuminance.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Check Scene.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Climatebased Sky.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Cumulative Radiation.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Custom Sky.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Daylight Control Schedule.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Daylight Factor.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Deconstruct Modifier.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Deconstruct ModifierSet Interior.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Deconstruct ModifierSet.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Deconstruct Wea.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Direct Sun Hours.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Dynamic Aperture Group.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Dynamic Shade Group.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Dynamic State Geometry.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Dynamic State.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Exterior Modifier Subset.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Extract HDR.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Face Radiance Attributes.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB False Color.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Get Dynamic Groups.ghuser +0 -0
- Views.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Glare Postprocess.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Glass Modifier 3.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Glass Modifier.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB HDR to GIF.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Imageless Annual Glare.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Interior Modifier Subset.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Metal Modifier 3.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Metal Modifier.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Mirror Modifier 3.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Mirror Modifier.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Model to Rad Folder.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB ModifierSet.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Opaque Modifier 3.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Opaque Modifier.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Point-In-Time Grid-Based.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Point-In-Time View-Based.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Radial Grid from Rooms.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Radial Sensor Grid.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Radiance Parameter.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Room Radiance Attributes.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Search Modifier Sets.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Search Modifiers.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Section Plane View.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Sensor Grid from Apertures.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Sensor Grid from Faces.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Sensor Grid from Rooms.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Sensor Grid.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Shade Modifier Subset.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Sky View.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Spatial Daylight Autonomy.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Subface Modifier Subset.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Translucent Modifier 3.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Translucent Modifier.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB View from Viewport.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB View.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Visualize Sky.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Wea From Clear Sky.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Wea From EPW.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Wea From Tau Clear Sky.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/HB Wea from Zhang-Huang.ghuser +0 -0
- honeybee_grasshopper_radiance/user_objects/__init__.py +1 -0
- honeybee_grasshopper_radiance-1.35.1.dist-info/METADATA +64 -0
- honeybee_grasshopper_radiance-1.35.1.dist-info/RECORD +170 -0
- honeybee_grasshopper_radiance-1.35.1.dist-info/WHEEL +5 -0
- honeybee_grasshopper_radiance-1.35.1.dist-info/licenses/LICENSE +661 -0
- honeybee_grasshopper_radiance-1.35.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# This file is part of Honeybee.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025, Ladybug Tools.
|
|
4
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
5
|
+
# along with Honeybee; If not, see <http://www.gnu.org/licenses/>.
|
|
6
|
+
#
|
|
7
|
+
# @license AGPL-3.0-or-later <https://spdx.org/licenses/AGPL-3.0-or-later>
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
Get peak irradiance or sum of illuminance values over an annual irradiance or
|
|
11
|
+
daylight simulation.
|
|
12
|
+
_
|
|
13
|
+
The _hoys_ input can also be used to filter the data for a particular time period or
|
|
14
|
+
hour/timestep of the simulation.
|
|
15
|
+
|
|
16
|
+
-
|
|
17
|
+
Args:
|
|
18
|
+
_results: An list of annual Radiance result files from either the "HB Annual Daylight"
|
|
19
|
+
or the "HB Annual Irradiance" component (containing the .ill files and
|
|
20
|
+
the sun-up-hours.txt). This can also be just the path to the folder
|
|
21
|
+
containing these result files.
|
|
22
|
+
dyn_sch_: Optional dynamic Aperture Group Schedules from the "HB Aperture Group
|
|
23
|
+
Schedule" component, which will be used to customize the behavior
|
|
24
|
+
of any dyanmic aperture geometry in the output metrics. If unsupplied,
|
|
25
|
+
all dynamic aperture groups will be in their default state in for
|
|
26
|
+
the output metrics.
|
|
27
|
+
_hoys_: An optional numbers or list of numbers to select the hours of the year (HOYs)
|
|
28
|
+
for which results will be computed. These HOYs can be obtained from the
|
|
29
|
+
"LB Calculate HOY" or the "LB Analysis Period" components. If None, all
|
|
30
|
+
hours of the results will be used.
|
|
31
|
+
grid_filter_: The name of a grid or a pattern to filter the grids. For instance,
|
|
32
|
+
first_floor_* will simulate only the sensor grids that have an
|
|
33
|
+
identifier that starts with first_floor_. By default all the grids
|
|
34
|
+
will be processed.
|
|
35
|
+
coincident_: Boolean to indicate whether output values represent the the peak
|
|
36
|
+
value for each sensor throughout the entire analysis (False) or
|
|
37
|
+
they represent the highest overall value across each sensor grid
|
|
38
|
+
at a particular timestep (True). (Default: False).
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
report: Reports, errors, warnings, etc.
|
|
42
|
+
hoys: An integer for each sesnor grid that represents the hour of the year at
|
|
43
|
+
which the peak occurs. This will be None unless coincident_ is
|
|
44
|
+
set to True.
|
|
45
|
+
values: Peak illuminance or irradiance valules for each sensor in lux or W/m2.
|
|
46
|
+
Each value is for a different sensor of the grid. These can be plugged
|
|
47
|
+
into the "LB Spatial Heatmap" component along with meshes of the sensor
|
|
48
|
+
grids to visualize results.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
ghenv.Component.Name = 'HB Annual Peak Values'
|
|
52
|
+
ghenv.Component.NickName = 'PeakValues'
|
|
53
|
+
ghenv.Component.Message = '1.9.0'
|
|
54
|
+
ghenv.Component.Category = 'HB-Radiance'
|
|
55
|
+
ghenv.Component.SubCategory = '4 :: Results'
|
|
56
|
+
ghenv.Component.AdditionalHelpFromDocStrings = '2'
|
|
57
|
+
|
|
58
|
+
import os
|
|
59
|
+
import subprocess
|
|
60
|
+
|
|
61
|
+
try:
|
|
62
|
+
from ladybug.futil import write_to_file
|
|
63
|
+
except ImportError as e:
|
|
64
|
+
raise ImportError('\nFailed to import ladybug:\n\t{}'.format(e))
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
from honeybee.config import folders
|
|
68
|
+
except ImportError as e:
|
|
69
|
+
raise ImportError('\nFailed to import honeybee:\n\t{}'.format(e))
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
from honeybee_radiance.postprocess.annualdaylight import _process_input_folder
|
|
73
|
+
except ImportError as e:
|
|
74
|
+
raise ImportError('\nFailed to import honeybee_radiance:\n\t{}'.format(e))
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
from honeybee_radiance_postprocess.dynamic import DynamicSchedule
|
|
78
|
+
except ImportError as e:
|
|
79
|
+
raise ImportError('\nFailed to import honeybee_radiance:\n\t{}'.format(e))
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
from pollination_handlers.outputs.helper import read_sensor_grid_result
|
|
83
|
+
except ImportError as e:
|
|
84
|
+
raise ImportError('\nFailed to import pollination_handlers:\n\t{}'.format(e))
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
from ladybug_rhino.grasshopper import all_required_inputs, list_to_data_tree, \
|
|
88
|
+
give_warning
|
|
89
|
+
except ImportError as e:
|
|
90
|
+
raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def parse_sun_up_hours(sun_up_hours, hoys, timestep):
|
|
94
|
+
"""Parse the sun-up hours from the result file .txt file.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
sun_up_hours: A list of integers for the sun-up hours.
|
|
98
|
+
hoys: A list of 8760 * timestep values for the hoys to select. If an empty
|
|
99
|
+
list is passed, None will be returned.
|
|
100
|
+
timestep: Integer for the timestep of the analysis.
|
|
101
|
+
"""
|
|
102
|
+
if len(hoys) != 0:
|
|
103
|
+
schedule = [False] * (8760 * timestep)
|
|
104
|
+
for hr in hoys:
|
|
105
|
+
schedule[int(hr * timestep)] = True
|
|
106
|
+
su_pattern = [schedule[int(h * timestep)] for h in sun_up_hours]
|
|
107
|
+
return su_pattern
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def peak_values(ill_file, su_pattern, coincident):
|
|
111
|
+
"""Compute average values for a given result file."""
|
|
112
|
+
max_vals, max_i = [], None
|
|
113
|
+
with open(ill_file) as results:
|
|
114
|
+
if coincident:
|
|
115
|
+
all_values = [[float(r) for r in pt_res.split()] for pt_res in results] \
|
|
116
|
+
if su_pattern is None else \
|
|
117
|
+
[[float(r) for r, is_hoy in zip(pt_res.split(), su_pattern) if is_hoy]
|
|
118
|
+
for pt_res in results]
|
|
119
|
+
max_val, max_i = 0, 0
|
|
120
|
+
for i, t_step in enumerate(zip(*all_values)):
|
|
121
|
+
tot_val = sum(t_step)
|
|
122
|
+
if tot_val > max_val:
|
|
123
|
+
max_val = tot_val
|
|
124
|
+
max_i = i
|
|
125
|
+
for sensor in all_values:
|
|
126
|
+
max_vals.append(sensor[max_i])
|
|
127
|
+
else:
|
|
128
|
+
if su_pattern is None: # no HOY filter on results
|
|
129
|
+
for pt_res in results:
|
|
130
|
+
values = [float(r) for r in pt_res.split()]
|
|
131
|
+
max_vals.append(max(values))
|
|
132
|
+
else:
|
|
133
|
+
for pt_res in results:
|
|
134
|
+
values = [float(r) for r, is_hoy in zip(pt_res.split(), su_pattern) if is_hoy]
|
|
135
|
+
max_vals.append(max(values))
|
|
136
|
+
return max_vals, max_i
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
if all_required_inputs(ghenv.Component):
|
|
140
|
+
# set up the default values
|
|
141
|
+
grid_filter_ = '*' if grid_filter_ is None else grid_filter_
|
|
142
|
+
res_folder = os.path.dirname(_results[0]) if os.path.isfile(_results[0]) \
|
|
143
|
+
else _results[0]
|
|
144
|
+
|
|
145
|
+
# check to see if results use the newer numpy arrays
|
|
146
|
+
if os.path.isdir(os.path.join(res_folder, '__static_apertures__')) or \
|
|
147
|
+
os.path.isfile(os.path.join(res_folder, 'grid_states.json')):
|
|
148
|
+
cmds = [folders.python_exe_path, '-m', 'honeybee_radiance_postprocess',
|
|
149
|
+
'post-process', 'peak-values', res_folder, '-sf', 'metrics']
|
|
150
|
+
if len(_hoys_) != 0:
|
|
151
|
+
hoys_str = '\n'.join(str(h) for h in _hoys_)
|
|
152
|
+
hoys_file = os.path.join(res_folder, 'hoys.txt')
|
|
153
|
+
write_to_file(hoys_file, hoys_str)
|
|
154
|
+
cmds.extend(['--hoys-file', hoys_file])
|
|
155
|
+
if grid_filter_ != '*':
|
|
156
|
+
cmds.extend(['--grids-filter', grid_filter_])
|
|
157
|
+
if coincident_:
|
|
158
|
+
cmds.append('--coincident')
|
|
159
|
+
if len(dyn_sch_) != 0:
|
|
160
|
+
if os.path.isfile(os.path.join(res_folder, 'grid_states.json')):
|
|
161
|
+
dyn_sch = dyn_sch_[0] if isinstance(dyn_sch_[0], DynamicSchedule) else \
|
|
162
|
+
DynamicSchedule.from_group_schedules(dyn_sch_)
|
|
163
|
+
dyn_sch_file = dyn_sch.to_json(folder=res_folder)
|
|
164
|
+
cmds.extend(['--states', dyn_sch_file])
|
|
165
|
+
else:
|
|
166
|
+
msg = 'No dynamic aperture groups were found in the Model.\n' \
|
|
167
|
+
'The input dynamic schedules will be ignored.'
|
|
168
|
+
print(msg)
|
|
169
|
+
give_warning(ghenv.Component, msg)
|
|
170
|
+
use_shell = True if os.name == 'nt' else False
|
|
171
|
+
custom_env = os.environ.copy()
|
|
172
|
+
custom_env['PYTHONHOME'] = ''
|
|
173
|
+
process = subprocess.Popen(
|
|
174
|
+
cmds, cwd=res_folder, shell=use_shell, env=custom_env,
|
|
175
|
+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
176
|
+
stdout = process.communicate() # wait for the process to finish
|
|
177
|
+
if stdout[-1] != '':
|
|
178
|
+
print(stdout[-1])
|
|
179
|
+
raise ValueError('Failed to compute peak values.')
|
|
180
|
+
avg_dir = os.path.join(res_folder, 'metrics', 'peak_values')
|
|
181
|
+
if os.path.isdir(avg_dir):
|
|
182
|
+
values = read_sensor_grid_result(avg_dir, 'peak','full_id', False)
|
|
183
|
+
values = list_to_data_tree(values)
|
|
184
|
+
with open(os.path.join(avg_dir, 'max_hoys.txt'), 'r') as max_hoys:
|
|
185
|
+
hoys = [line.rstrip() for line in max_hoys.readlines()]
|
|
186
|
+
if coincident_:
|
|
187
|
+
hoys = map(int, hoys)
|
|
188
|
+
else:
|
|
189
|
+
hoys = [None] * len(hoys)
|
|
190
|
+
|
|
191
|
+
else:
|
|
192
|
+
if len(dyn_sch_) != 0:
|
|
193
|
+
msg = 'Dynamic Schedules are currently only supported for Annual Daylight ' \
|
|
194
|
+
'simulations.\nThe input schedules will be ignored.'
|
|
195
|
+
print(msg)
|
|
196
|
+
give_warning(ghenv.Component, msg)
|
|
197
|
+
|
|
198
|
+
# extract the timestep if it exists
|
|
199
|
+
timestep = 1
|
|
200
|
+
tstep_file = os.path.join(res_folder, 'timestep.txt')
|
|
201
|
+
if os.path.isfile(tstep_file):
|
|
202
|
+
with open(tstep_file) as tf:
|
|
203
|
+
timestep = int(tf.readline())
|
|
204
|
+
|
|
205
|
+
# parse the sun-up-hours
|
|
206
|
+
grids, sun_up_hours = _process_input_folder(res_folder, grid_filter_)
|
|
207
|
+
su_pattern = parse_sun_up_hours(sun_up_hours, _hoys_, timestep)
|
|
208
|
+
filt_suh = [suh for suh in sun_up_hours if int(suh) in _hoys_] \
|
|
209
|
+
if len(_hoys_) != 0 else sun_up_hours
|
|
210
|
+
# compute the average values
|
|
211
|
+
values, hoys = [], []
|
|
212
|
+
for grid_info in grids:
|
|
213
|
+
ill_file = os.path.join(res_folder, '%s.ill' % grid_info['full_id'])
|
|
214
|
+
dgp_file = os.path.join(res_folder, '%s.dgp' % grid_info['full_id'])
|
|
215
|
+
if os.path.isfile(dgp_file):
|
|
216
|
+
max_list, max_i = peak_values(dgp_file, su_pattern, coincident_)
|
|
217
|
+
else:
|
|
218
|
+
max_list, max_i = peak_values(ill_file, su_pattern, coincident_)
|
|
219
|
+
values.append(max_list)
|
|
220
|
+
if max_i is not None:
|
|
221
|
+
hoys.append(filt_suh[max_i])
|
|
222
|
+
else:
|
|
223
|
+
hoys.append(max_i)
|
|
224
|
+
values = list_to_data_tree(values)
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# This file is part of Honeybee.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025, Ladybug Tools.
|
|
4
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
5
|
+
# along with Honeybee; If not, see <http://www.gnu.org/licenses/>.
|
|
6
|
+
#
|
|
7
|
+
# @license AGPL-3.0-or-later <https://spdx.org/licenses/AGPL-3.0-or-later>
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
Import the hourly illuminance or irradiance results of an annual daylight or irradiance
|
|
11
|
+
study to a list of data collections.
|
|
12
|
+
_
|
|
13
|
+
The resulting data collections can be visulized using the ladybug components or
|
|
14
|
+
deconstructed for detailed analysis with native Grasshopper math components.
|
|
15
|
+
|
|
16
|
+
-
|
|
17
|
+
Args:
|
|
18
|
+
_results: An list of annual Radiance result files from the "HB Annual Daylight"
|
|
19
|
+
component (containing the .ill files and the sun-up-hours.txt).
|
|
20
|
+
This can also be just the path to the folder containing these
|
|
21
|
+
result files.
|
|
22
|
+
dyn_sch_: Optional dynamic Aperture Group Schedules from the "HB Aperture Group
|
|
23
|
+
Schedule" component, which will be used to customize the behavior
|
|
24
|
+
of any dyanmic aperture geometry in the output metrics. If unsupplied,
|
|
25
|
+
all dynamic aperture groups will be in their default state in for
|
|
26
|
+
the output metrics.
|
|
27
|
+
_sel_pts: A point or list of points, which will be used to filter the sensors
|
|
28
|
+
for which data collections will be imported.
|
|
29
|
+
_all_pts: The data tree of all sensor points that were used in the simulation.
|
|
30
|
+
This is required in order to look up the index of the _sel_pts in
|
|
31
|
+
the results matrices.
|
|
32
|
+
sel_vecs_: An optional vector or list of vectors, which will be used to filter
|
|
33
|
+
the sensors for which data collections will be imported. If there
|
|
34
|
+
is an input here, the all_vecs_ must be connected.
|
|
35
|
+
all_vecs_: The data tree of all sensor directions that were used in the simulation.
|
|
36
|
+
This is required in order to look up the index of the sel_vecs_ in
|
|
37
|
+
the results matrices.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
report: Reports, errors, warnings, etc.
|
|
41
|
+
data: A list of hourly data collections containing illuminance or irradiance results.
|
|
42
|
+
These can be visulized using the ladybug components or deconstructed
|
|
43
|
+
for detailed analysis with native Grasshopper math components.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
ghenv.Component.Name = 'HB Annual Results to Data'
|
|
47
|
+
ghenv.Component.NickName = 'AnnualToData'
|
|
48
|
+
ghenv.Component.Message = '1.9.0'
|
|
49
|
+
ghenv.Component.Category = 'HB-Radiance'
|
|
50
|
+
ghenv.Component.SubCategory = '4 :: Results'
|
|
51
|
+
ghenv.Component.AdditionalHelpFromDocStrings = '2'
|
|
52
|
+
|
|
53
|
+
import os
|
|
54
|
+
import json
|
|
55
|
+
import subprocess
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
from ladybug.datatype.illuminance import Illuminance
|
|
59
|
+
from ladybug.datatype.energyflux import Irradiance
|
|
60
|
+
from ladybug.datatype.time import Time
|
|
61
|
+
from ladybug.datatype.fraction import Fraction
|
|
62
|
+
from ladybug.analysisperiod import AnalysisPeriod
|
|
63
|
+
from ladybug.header import Header
|
|
64
|
+
from ladybug.datacollection import HourlyContinuousCollection
|
|
65
|
+
from ladybug.futil import write_to_file
|
|
66
|
+
except ImportError as e:
|
|
67
|
+
raise ImportError('\nFailed to import ladybug:\n\t{}'.format(e))
|
|
68
|
+
|
|
69
|
+
try:
|
|
70
|
+
from honeybee.config import folders
|
|
71
|
+
except ImportError as e:
|
|
72
|
+
raise ImportError('\nFailed to import honeybee:\n\t{}'.format(e))
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
from honeybee_radiance.postprocess.annualdaylight import _process_input_folder
|
|
76
|
+
except ImportError as e:
|
|
77
|
+
raise ImportError('\nFailed to import honeybee_radiance:\n\t{}'.format(e))
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
from honeybee_radiance_postprocess.dynamic import DynamicSchedule
|
|
81
|
+
except ImportError as e:
|
|
82
|
+
raise ImportError('\nFailed to import honeybee_radiance:\n\t{}'.format(e))
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
from ladybug_rhino.config import tolerance
|
|
86
|
+
from ladybug_rhino.togeometry import to_point3d, to_vector3d
|
|
87
|
+
from ladybug_rhino.grasshopper import all_required_inputs, list_to_data_tree, \
|
|
88
|
+
data_tree_to_list, give_warning
|
|
89
|
+
except ImportError as e:
|
|
90
|
+
raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def file_to_data(ill_file, point_filter, su_pattern, header, timestep, grid_id):
|
|
94
|
+
"""Get a list of data collections for a given result file."""
|
|
95
|
+
data_colls = []
|
|
96
|
+
new_header = header.duplicate()
|
|
97
|
+
new_header.metadata['sensor grid'] = grid_id
|
|
98
|
+
with open(ill_file) as results:
|
|
99
|
+
if point_filter is None:
|
|
100
|
+
for pt_res in results:
|
|
101
|
+
base_values = [0] * 8760 * timestep
|
|
102
|
+
for val, hr in zip(pt_res.split(), su_pattern):
|
|
103
|
+
base_values[hr] = float(val)
|
|
104
|
+
data_colls.append(HourlyContinuousCollection(new_header, base_values))
|
|
105
|
+
else:
|
|
106
|
+
for i, pt_res in enumerate(results):
|
|
107
|
+
if i in point_filter:
|
|
108
|
+
new_header = new_header.duplicate()
|
|
109
|
+
new_header.metadata['sensor index'] = i
|
|
110
|
+
base_values = [0] * 8760 * timestep
|
|
111
|
+
for val, hr in zip(pt_res.split(), su_pattern):
|
|
112
|
+
base_values[hr] = float(val)
|
|
113
|
+
data_colls.append(HourlyContinuousCollection(new_header, base_values))
|
|
114
|
+
return data_colls
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def find_point_in_grid(s_pt, all_pts):
|
|
118
|
+
"""Find the index of a point in a list of list of grids."""
|
|
119
|
+
m_pts = []
|
|
120
|
+
for i, grid_pts in enumerate(all_pts):
|
|
121
|
+
for j, g_pt in enumerate(grid_pts):
|
|
122
|
+
if g_pt.is_equivalent(s_pt, tolerance):
|
|
123
|
+
m_pts.append((i, j))
|
|
124
|
+
return m_pts
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def find_vec_in_grid(s_v, all_vecs, pt_filter):
|
|
128
|
+
"""Find the index of a vector in a list of list of grids."""
|
|
129
|
+
m_vecs = []
|
|
130
|
+
for i, grid in enumerate(pt_filter):
|
|
131
|
+
for j in grid:
|
|
132
|
+
if all_vecs[i][j].is_equivalent(s_v, tolerance):
|
|
133
|
+
m_vecs.append((i, j))
|
|
134
|
+
return m_vecs
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if all_required_inputs(ghenv.Component):
|
|
138
|
+
# get the relevant .ill files
|
|
139
|
+
res_folder = os.path.dirname(_results[0]) if os.path.isfile(_results[0]) \
|
|
140
|
+
else _results[0]
|
|
141
|
+
grids, sun_up_hours = _process_input_folder(res_folder, '*')
|
|
142
|
+
|
|
143
|
+
# set up the sensor filter
|
|
144
|
+
pt_filter = [None for i in grids]
|
|
145
|
+
if len(_sel_pts) != 0 or len(sel_vecs_) != 0:
|
|
146
|
+
pt_filter = [[] for i in grids]
|
|
147
|
+
|
|
148
|
+
# check the sel_pts and all_pts input
|
|
149
|
+
if len(_sel_pts) != 0:
|
|
150
|
+
all_pts = [[to_point3d(pt) for pt in dat[-1]] for dat in data_tree_to_list(_all_pts)]
|
|
151
|
+
assert len(all_pts) != 0, '_all_pts must be connected in order to use _sel_pts.'
|
|
152
|
+
sel_pts = [to_point3d(pt) for pt in _sel_pts]
|
|
153
|
+
for s_pt in sel_pts:
|
|
154
|
+
m_pts = find_point_in_grid(s_pt, all_pts)
|
|
155
|
+
for i, j in m_pts:
|
|
156
|
+
pt_filter[i].append(j)
|
|
157
|
+
|
|
158
|
+
# check the sel_vecs and all_vecs input
|
|
159
|
+
if len(sel_vecs_) != 0:
|
|
160
|
+
new_pt_filter = [[] for i in grids]
|
|
161
|
+
all_vecs = [[to_vector3d(v) for v in dat[-1]] for dat in data_tree_to_list(all_vecs_)]
|
|
162
|
+
assert len(all_vecs) != 0, 'all_vecs_ must be connected in order to use sel_vecs_.'
|
|
163
|
+
sel_vecs = [to_vector3d(v) for v in sel_vecs_]
|
|
164
|
+
for s_v in sel_vecs:
|
|
165
|
+
m_vs = find_point_in_grid(s_v, all_vecs) if len(_sel_pts) == 0 else \
|
|
166
|
+
find_vec_in_grid(s_v, all_vecs, pt_filter)
|
|
167
|
+
for i, j in m_vs:
|
|
168
|
+
new_pt_filter[i].append(j)
|
|
169
|
+
pt_filter = new_pt_filter
|
|
170
|
+
|
|
171
|
+
# check to see if results use the newer numpy arrays
|
|
172
|
+
if os.path.isdir(os.path.join(res_folder, '__static_apertures__')) or \
|
|
173
|
+
os.path.isfile(os.path.join(res_folder, 'grid_states.json')):
|
|
174
|
+
cmds = [folders.python_exe_path, '-m', 'honeybee_radiance_postprocess',
|
|
175
|
+
'post-process', 'annual-to-data', res_folder]
|
|
176
|
+
if pt_filter[0] is not None:
|
|
177
|
+
sen_dict = {g['full_id']: s_ind for g, s_ind in zip(grids, pt_filter)}
|
|
178
|
+
si_file = os.path.join(res_folder, 'sensor_indices.json')
|
|
179
|
+
write_to_file(si_file, json.dumps(sen_dict))
|
|
180
|
+
cmds.extend(['--sensor-index', si_file])
|
|
181
|
+
if len(dyn_sch_) != 0:
|
|
182
|
+
if os.path.isfile(os.path.join(res_folder, 'grid_states.json')):
|
|
183
|
+
dyn_sch = dyn_sch_[0] if isinstance(dyn_sch_[0], DynamicSchedule) else \
|
|
184
|
+
DynamicSchedule.from_group_schedules(dyn_sch_)
|
|
185
|
+
dyn_sch_file = dyn_sch.to_json(folder=res_folder)
|
|
186
|
+
cmds.extend(['--states', dyn_sch_file])
|
|
187
|
+
else:
|
|
188
|
+
msg = 'No dynamic aperture groups were found in the Model.\n' \
|
|
189
|
+
'The input dynamic schedules will be ignored.'
|
|
190
|
+
print(msg)
|
|
191
|
+
give_warning(ghenv.Component, msg)
|
|
192
|
+
use_shell = True if os.name == 'nt' else False
|
|
193
|
+
custom_env = os.environ.copy()
|
|
194
|
+
custom_env['PYTHONHOME'] = ''
|
|
195
|
+
process = subprocess.Popen(
|
|
196
|
+
cmds, cwd=res_folder, shell=use_shell, env=custom_env,
|
|
197
|
+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
198
|
+
stdout, stderr = process.communicate() # wait for the process to finish
|
|
199
|
+
if stderr != '':
|
|
200
|
+
print(stderr)
|
|
201
|
+
raise ValueError('Failed to compute data collections.')
|
|
202
|
+
data_dicts = json.loads(stdout)
|
|
203
|
+
data = [[HourlyContinuousCollection.from_dict(d) for d in data]
|
|
204
|
+
for data in data_dicts]
|
|
205
|
+
data = list_to_data_tree(data)
|
|
206
|
+
|
|
207
|
+
else:
|
|
208
|
+
if len(dyn_sch_) != 0:
|
|
209
|
+
msg = 'Dynamic Schedules are currently only supported for Annual Daylight ' \
|
|
210
|
+
'simulations.\nThe input schedules will be ignored.'
|
|
211
|
+
print(msg)
|
|
212
|
+
give_warning(ghenv.Component, msg)
|
|
213
|
+
|
|
214
|
+
# extract the timestep if it exists
|
|
215
|
+
timestep, has_t_step = 1, False
|
|
216
|
+
tstep_file = os.path.join(res_folder, 'timestep.txt')
|
|
217
|
+
if os.path.isfile(tstep_file): # it's an annual irradiance simulation
|
|
218
|
+
with open(tstep_file) as tf:
|
|
219
|
+
timestep = int(tf.readline())
|
|
220
|
+
has_t_step = True
|
|
221
|
+
|
|
222
|
+
# parse the sun-up-hours
|
|
223
|
+
sun_up_hours = [int(h * timestep) for h in sun_up_hours]
|
|
224
|
+
|
|
225
|
+
# create the header that will be used for all of the data collections
|
|
226
|
+
aper = AnalysisPeriod(timestep=timestep)
|
|
227
|
+
if 'direct_sun_hours' in res_folder:
|
|
228
|
+
head = Header(Time(), 'hr', aper)
|
|
229
|
+
elif has_t_step:
|
|
230
|
+
head = Header(Irradiance(), 'W/m2', aper)
|
|
231
|
+
else:
|
|
232
|
+
head = Header(Illuminance(), 'lux', aper)
|
|
233
|
+
dgp_head = Header(Fraction(), 'fraction', aper, metadata={'type': 'Daylight Glare Probability (DGP)'})
|
|
234
|
+
|
|
235
|
+
# create the data collections from the .ill files
|
|
236
|
+
data = []
|
|
237
|
+
for grid_info, p_filt in zip(grids, pt_filter):
|
|
238
|
+
grid_id = grid_info['full_id']
|
|
239
|
+
ill_file = os.path.join(res_folder, '%s.ill' % grid_id)
|
|
240
|
+
dgp_file = os.path.join(res_folder, '%s.dgp' % grid_id)
|
|
241
|
+
if os.path.isfile(dgp_file):
|
|
242
|
+
data_list = file_to_data(dgp_file, p_filt, sun_up_hours, dgp_head, timestep, grid_id)
|
|
243
|
+
else:
|
|
244
|
+
data_list = file_to_data(ill_file, p_filt, sun_up_hours, head, timestep, grid_id)
|
|
245
|
+
data.append(data_list)
|
|
246
|
+
data = list_to_data_tree(data)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Honeybee: A Plugin for Environmental Analysis (GPL)
|
|
2
|
+
# This file is part of Honeybee.
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2025, Ladybug Tools.
|
|
5
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
6
|
+
# along with Honeybee; If not, see <http://www.gnu.org/licenses/>.
|
|
7
|
+
#
|
|
8
|
+
# @license AGPL-3.0-or-later <https://spdx.org/licenses/AGPL-3.0-or-later>
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
Calculate Annual Sunlight Exposure from a results folder.
|
|
12
|
+
_
|
|
13
|
+
Note: This component will only output a LEED compliant ASE if you've run the
|
|
14
|
+
simulation with all operable shading devices retracted. If you are using
|
|
15
|
+
results with operable shading devices, then this output is NOT LEED compliant.
|
|
16
|
+
|
|
17
|
+
-
|
|
18
|
+
Args:
|
|
19
|
+
_results: An annual results folder containing direct illuminance results.
|
|
20
|
+
This can be the output of the "HB Annual Daylight" component. This can
|
|
21
|
+
also be just the path to the results folder.
|
|
22
|
+
_occ_sch_: An annual occupancy schedule as a Ladybug Data Collection or a HB-Energy
|
|
23
|
+
schedule object. This can also be the identifier of a schedule in
|
|
24
|
+
your HB-Energy schedule library. Any value in this schedule that is
|
|
25
|
+
0.1 or above will be considered occupied. If None, a schedule from
|
|
26
|
+
8AM to 6PM on all days will be used.
|
|
27
|
+
_threshold_: The threshold (lux) that determines if a sensor is
|
|
28
|
+
overlit (default: 1000).
|
|
29
|
+
_target_hrs_: The number of occupied hours that cannot receive higher
|
|
30
|
+
illuminance than the direct threshold (default: 250).
|
|
31
|
+
grid_filter_: The name of a grid or a pattern to filter the grids. For instance,
|
|
32
|
+
first_floor_* will simulate only the sensor grids that have an
|
|
33
|
+
identifier that starts with first_floor_. By default all the grids
|
|
34
|
+
will be processed.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
report: Reports, errors, warnings, etc.
|
|
38
|
+
ASE: Annual sunlight exposure as a percentage for each sensor grid.
|
|
39
|
+
hrs_above: The number of hours above the threshold for each sensor point.
|
|
40
|
+
These can be plugged into the "LB Spatial Heatmap" component along with
|
|
41
|
+
meshes of the sensor grids to visualize results.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
ghenv.Component.Name = "HB Annual Sunlight Exposure"
|
|
45
|
+
ghenv.Component.NickName = 'ASE'
|
|
46
|
+
ghenv.Component.Message = '1.9.0'
|
|
47
|
+
ghenv.Component.Category = 'HB-Radiance'
|
|
48
|
+
ghenv.Component.SubCategory = '4 :: Results'
|
|
49
|
+
ghenv.Component.AdditionalHelpFromDocStrings = '1'
|
|
50
|
+
|
|
51
|
+
import os
|
|
52
|
+
import subprocess
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
from ladybug.datacollection import BaseCollection
|
|
56
|
+
from ladybug.futil import write_to_file
|
|
57
|
+
except ImportError as e:
|
|
58
|
+
raise ImportError('\nFailed to import ladybug:\n\t{}'.format(e))
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
from honeybee.config import folders
|
|
62
|
+
except ImportError as e:
|
|
63
|
+
raise ImportError('\nFailed to import honeybee:\n\t{}'.format(e))
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
from honeybee_energy.lib.schedules import schedule_by_identifier
|
|
67
|
+
except ImportError as e: # honeybee schedule library is not available
|
|
68
|
+
schedule_by_identifier = None
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
from pollination_handlers.outputs.daylight import read_ase_from_folder, \
|
|
72
|
+
read_hours_from_folder
|
|
73
|
+
except ImportError as e:
|
|
74
|
+
raise ImportError('\nFailed to import pollination_handlers:\n\t{}'.format(e))
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
from ladybug_rhino.grasshopper import all_required_inputs, list_to_data_tree
|
|
78
|
+
except ImportError as e:
|
|
79
|
+
raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e))
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if all_required_inputs(ghenv.Component):
|
|
83
|
+
# set default values for the thresholds and the grid filter
|
|
84
|
+
grid_filter_ = '*' if grid_filter_ is None else grid_filter_
|
|
85
|
+
_direct_threshold_ = _threshold_ if _threshold_ else 1000
|
|
86
|
+
_occ_hours_ = _target_hrs_ if _target_hrs_ else 250
|
|
87
|
+
|
|
88
|
+
# process the schedule
|
|
89
|
+
if _occ_sch_ is None:
|
|
90
|
+
schedule = None
|
|
91
|
+
elif isinstance(_occ_sch_, BaseCollection):
|
|
92
|
+
schedule = _occ_sch_.values
|
|
93
|
+
elif isinstance(_occ_sch_, str):
|
|
94
|
+
if schedule_by_identifier is not None:
|
|
95
|
+
try:
|
|
96
|
+
schedule = schedule_by_identifier(_occ_sch_).values()
|
|
97
|
+
except TypeError: # it's probably a ScheduleFixedInterval
|
|
98
|
+
schedule = schedule_by_identifier(_occ_sch_).values
|
|
99
|
+
else:
|
|
100
|
+
raise ValueError('honeybee-energy must be installed to reference '
|
|
101
|
+
'occupancy schedules by identifier.')
|
|
102
|
+
else: # assume that it is a honeybee schedule object
|
|
103
|
+
try:
|
|
104
|
+
schedule = _occ_sch_.values()
|
|
105
|
+
except TypeError: # it's probably a ScheduleFixedInterval
|
|
106
|
+
schedule = _occ_sch_.values
|
|
107
|
+
if schedule is not None:
|
|
108
|
+
bin_schedule = []
|
|
109
|
+
for val in schedule:
|
|
110
|
+
bin_val = 1 if val >= 0.1 else 0
|
|
111
|
+
bin_schedule.append(bin_val)
|
|
112
|
+
schedule = bin_schedule
|
|
113
|
+
|
|
114
|
+
# compute the annual metrics
|
|
115
|
+
res_folder = os.path.dirname(_results[0]) if os.path.isfile(_results[0]) \
|
|
116
|
+
else _results[0]
|
|
117
|
+
if os.path.isfile(os.path.join(res_folder, 'grid_states.json')):
|
|
118
|
+
cmds = [
|
|
119
|
+
folders.python_exe_path, '-m', 'honeybee_radiance_postprocess',
|
|
120
|
+
'post-process', 'annual-sunlight-exposure', res_folder, '-sf', 'metrics',
|
|
121
|
+
'-dt', str(_direct_threshold_), '-oh', str(_occ_hours_)
|
|
122
|
+
]
|
|
123
|
+
if grid_filter_ != '*':
|
|
124
|
+
cmds.extend(['--grids-filter', grid_filter_])
|
|
125
|
+
if schedule is not None:
|
|
126
|
+
sch_str = '\n'.join(str(h) for h in schedule)
|
|
127
|
+
sch_file = os.path.join(res_folder, 'schedule.txt')
|
|
128
|
+
write_to_file(sch_file, sch_str)
|
|
129
|
+
cmds.extend(['--schedule', sch_file])
|
|
130
|
+
use_shell = True if os.name == 'nt' else False
|
|
131
|
+
custom_env = os.environ.copy()
|
|
132
|
+
custom_env['PYTHONHOME'] = ''
|
|
133
|
+
process = subprocess.Popen(
|
|
134
|
+
cmds, cwd=res_folder, shell=use_shell, env=custom_env,
|
|
135
|
+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
136
|
+
stdout = process.communicate() # wait for the process to finish
|
|
137
|
+
if stdout[-1] != '':
|
|
138
|
+
print(stdout[-1])
|
|
139
|
+
raise ValueError('Failed to compute annual sunlight exposure.')
|
|
140
|
+
metric_dir = os.path.join(res_folder, 'metrics')
|
|
141
|
+
ASE = read_ase_from_folder(os.path.join(metric_dir, 'ase'))
|
|
142
|
+
hrs_above = list_to_data_tree(read_hours_from_folder(os.path.join(metric_dir, 'hours_above')))
|
|
143
|
+
else:
|
|
144
|
+
raise ValueError(
|
|
145
|
+
'Invalid results folder!\n'
|
|
146
|
+
'Make sure an enhanced daylight simulation was run'
|
|
147
|
+
)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Honeybee: A Plugin for Environmental Analysis (GPL)
|
|
2
|
+
# This file is part of Honeybee.
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2025, Ladybug Tools.
|
|
5
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
6
|
+
# along with Honeybee; If not, see <http://www.gnu.org/licenses/>.
|
|
7
|
+
#
|
|
8
|
+
# @license AGPL-3.0-or-later <https://spdx.org/licenses/AGPL-3.0-or-later>
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
Create a Dynamic Aperture Group Schedule, which can be used to process any dynamic
|
|
12
|
+
aperture geometry that was run in an annual simulation.
|
|
13
|
+
|
|
14
|
+
-
|
|
15
|
+
Args:
|
|
16
|
+
_group_aps: Honeybee Apertures that are a part of the same dynamic group and will
|
|
17
|
+
be assigned the same schedule for postprocessing. Typically, this is
|
|
18
|
+
the output of the "HB Dynamic Aperture Group" component but it can
|
|
19
|
+
also be the output of the "HB Get Dynamic Groups" component, which
|
|
20
|
+
returns all of the dynamic groups on a particular Model.
|
|
21
|
+
_schedule: A list of 8760 integers refering to the index of the aperture group state
|
|
22
|
+
to be used at each hour of the simulation. This can also be a single integer
|
|
23
|
+
for a static state to be used for the entire period of the simulation
|
|
24
|
+
or a pattern of integers that is less than 8760 in length and will be
|
|
25
|
+
repeated until the 8760 is reached. Note that 0 refers to the first
|
|
26
|
+
state, 1 refers to the second state, and so on. -1 can be used to
|
|
27
|
+
completely discout the aperture from the simulation for a given hour.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
dyn_sch: A dynamic schedule object for the input aperture group, which can be plugged
|
|
31
|
+
into any of the Results components with a syn_sch input.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
ghenv.Component.Name = 'HB Aperture Group Schedule'
|
|
35
|
+
ghenv.Component.NickName = 'GroupSch'
|
|
36
|
+
ghenv.Component.Message = '1.9.0'
|
|
37
|
+
ghenv.Component.Category = 'HB-Radiance'
|
|
38
|
+
ghenv.Component.SubCategory = '4 :: Results'
|
|
39
|
+
ghenv.Component.AdditionalHelpFromDocStrings = '1'
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
from honeybee.aperture import Aperture
|
|
43
|
+
except ImportError as e:
|
|
44
|
+
raise ImportError('\nFailed to import honeybee:\n\t{}'.format(e))
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
from honeybee_radiance_postprocess.dynamic import ApertureGroupSchedule
|
|
48
|
+
except ImportError as e:
|
|
49
|
+
raise ImportError('\nFailed to import honeybee_radiance:\n\t{}'.format(e))
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
from ladybug_rhino.grasshopper import all_required_inputs, recipe_result
|
|
53
|
+
except ImportError as e:
|
|
54
|
+
raise ImportError('\nFailed to import ladybug_rhino:\n\t{}'.format(e))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
if all_required_inputs(ghenv.Component):
|
|
58
|
+
dyn_sch = []
|
|
59
|
+
dyn_ids = set()
|
|
60
|
+
for ap in _group_aps:
|
|
61
|
+
assert isinstance(ap, Aperture), 'Expected Aperture. Got {}.'.format(type(ap))
|
|
62
|
+
dyn_grp_id = ap.properties.radiance.dynamic_group_identifier
|
|
63
|
+
if dyn_grp_id is None:
|
|
64
|
+
raise ValueError(
|
|
65
|
+
'Input Aperture "{}" is not a part of a dynamic group.'.format(ap.display_name))
|
|
66
|
+
if dyn_grp_id not in dyn_ids:
|
|
67
|
+
dyn_ids.add(dyn_grp_id)
|
|
68
|
+
_ap_group_sch = ApertureGroupSchedule(dyn_grp_id, _schedule)
|
|
69
|
+
dyn_sch.append(_ap_group_sch)
|