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.

Files changed (152) hide show
  1. honeybee_radiance/__init__.py +11 -0
  2. honeybee_radiance/__main__.py +4 -0
  3. honeybee_radiance/_extend_honeybee.py +93 -0
  4. honeybee_radiance/cli/__init__.py +88 -0
  5. honeybee_radiance/cli/dc.py +400 -0
  6. honeybee_radiance/cli/edit.py +529 -0
  7. honeybee_radiance/cli/glare.py +118 -0
  8. honeybee_radiance/cli/grid.py +859 -0
  9. honeybee_radiance/cli/lib.py +458 -0
  10. honeybee_radiance/cli/modifier.py +133 -0
  11. honeybee_radiance/cli/mtx.py +226 -0
  12. honeybee_radiance/cli/multiphase.py +1034 -0
  13. honeybee_radiance/cli/octree.py +640 -0
  14. honeybee_radiance/cli/postprocess.py +1186 -0
  15. honeybee_radiance/cli/raytrace.py +219 -0
  16. honeybee_radiance/cli/rpict.py +125 -0
  17. honeybee_radiance/cli/schedule.py +56 -0
  18. honeybee_radiance/cli/setconfig.py +63 -0
  19. honeybee_radiance/cli/sky.py +545 -0
  20. honeybee_radiance/cli/study.py +66 -0
  21. honeybee_radiance/cli/sunpath.py +331 -0
  22. honeybee_radiance/cli/threephase.py +255 -0
  23. honeybee_radiance/cli/translate.py +400 -0
  24. honeybee_radiance/cli/util.py +121 -0
  25. honeybee_radiance/cli/view.py +261 -0
  26. honeybee_radiance/cli/viewfactor.py +347 -0
  27. honeybee_radiance/config.json +6 -0
  28. honeybee_radiance/config.py +427 -0
  29. honeybee_radiance/dictutil.py +50 -0
  30. honeybee_radiance/dynamic/__init__.py +5 -0
  31. honeybee_radiance/dynamic/group.py +479 -0
  32. honeybee_radiance/dynamic/multiphase.py +557 -0
  33. honeybee_radiance/dynamic/state.py +718 -0
  34. honeybee_radiance/dynamic/stategeo.py +352 -0
  35. honeybee_radiance/geometry/__init__.py +13 -0
  36. honeybee_radiance/geometry/bubble.py +42 -0
  37. honeybee_radiance/geometry/cone.py +215 -0
  38. honeybee_radiance/geometry/cup.py +54 -0
  39. honeybee_radiance/geometry/cylinder.py +197 -0
  40. honeybee_radiance/geometry/geometrybase.py +37 -0
  41. honeybee_radiance/geometry/instance.py +40 -0
  42. honeybee_radiance/geometry/mesh.py +38 -0
  43. honeybee_radiance/geometry/polygon.py +174 -0
  44. honeybee_radiance/geometry/ring.py +214 -0
  45. honeybee_radiance/geometry/source.py +182 -0
  46. honeybee_radiance/geometry/sphere.py +178 -0
  47. honeybee_radiance/geometry/tube.py +46 -0
  48. honeybee_radiance/lib/__init__.py +1 -0
  49. honeybee_radiance/lib/_loadmodifiers.py +72 -0
  50. honeybee_radiance/lib/_loadmodifiersets.py +69 -0
  51. honeybee_radiance/lib/modifiers.py +58 -0
  52. honeybee_radiance/lib/modifiersets.py +63 -0
  53. honeybee_radiance/lightpath.py +204 -0
  54. honeybee_radiance/lightsource/__init__.py +1 -0
  55. honeybee_radiance/lightsource/_gendaylit.py +479 -0
  56. honeybee_radiance/lightsource/dictutil.py +49 -0
  57. honeybee_radiance/lightsource/ground.py +160 -0
  58. honeybee_radiance/lightsource/sky/__init__.py +7 -0
  59. honeybee_radiance/lightsource/sky/_skybase.py +177 -0
  60. honeybee_radiance/lightsource/sky/certainirradiance.py +232 -0
  61. honeybee_radiance/lightsource/sky/cie.py +378 -0
  62. honeybee_radiance/lightsource/sky/climatebased.py +501 -0
  63. honeybee_radiance/lightsource/sky/hemisphere.py +160 -0
  64. honeybee_radiance/lightsource/sky/skydome.py +113 -0
  65. honeybee_radiance/lightsource/sky/skymatrix.py +163 -0
  66. honeybee_radiance/lightsource/sky/strutil.py +34 -0
  67. honeybee_radiance/lightsource/sky/sunmatrix.py +212 -0
  68. honeybee_radiance/lightsource/sunpath.py +247 -0
  69. honeybee_radiance/modifier/__init__.py +3 -0
  70. honeybee_radiance/modifier/material/__init__.py +30 -0
  71. honeybee_radiance/modifier/material/absdf.py +477 -0
  72. honeybee_radiance/modifier/material/antimatter.py +54 -0
  73. honeybee_radiance/modifier/material/ashik2.py +51 -0
  74. honeybee_radiance/modifier/material/brtdfunc.py +81 -0
  75. honeybee_radiance/modifier/material/bsdf.py +292 -0
  76. honeybee_radiance/modifier/material/dielectric.py +53 -0
  77. honeybee_radiance/modifier/material/glass.py +431 -0
  78. honeybee_radiance/modifier/material/glow.py +246 -0
  79. honeybee_radiance/modifier/material/illum.py +51 -0
  80. honeybee_radiance/modifier/material/interface.py +49 -0
  81. honeybee_radiance/modifier/material/light.py +206 -0
  82. honeybee_radiance/modifier/material/materialbase.py +36 -0
  83. honeybee_radiance/modifier/material/metal.py +167 -0
  84. honeybee_radiance/modifier/material/metal2.py +41 -0
  85. honeybee_radiance/modifier/material/metdata.py +41 -0
  86. honeybee_radiance/modifier/material/metfunc.py +41 -0
  87. honeybee_radiance/modifier/material/mirror.py +340 -0
  88. honeybee_radiance/modifier/material/mist.py +86 -0
  89. honeybee_radiance/modifier/material/plasdata.py +58 -0
  90. honeybee_radiance/modifier/material/plasfunc.py +59 -0
  91. honeybee_radiance/modifier/material/plastic.py +354 -0
  92. honeybee_radiance/modifier/material/plastic2.py +58 -0
  93. honeybee_radiance/modifier/material/prism1.py +57 -0
  94. honeybee_radiance/modifier/material/prism2.py +48 -0
  95. honeybee_radiance/modifier/material/spotlight.py +50 -0
  96. honeybee_radiance/modifier/material/trans.py +518 -0
  97. honeybee_radiance/modifier/material/trans2.py +49 -0
  98. honeybee_radiance/modifier/material/transdata.py +50 -0
  99. honeybee_radiance/modifier/material/transfunc.py +53 -0
  100. honeybee_radiance/modifier/mixture/__init__.py +6 -0
  101. honeybee_radiance/modifier/mixture/mixdata.py +49 -0
  102. honeybee_radiance/modifier/mixture/mixfunc.py +54 -0
  103. honeybee_radiance/modifier/mixture/mixpict.py +52 -0
  104. honeybee_radiance/modifier/mixture/mixtext.py +66 -0
  105. honeybee_radiance/modifier/mixture/mixturebase.py +28 -0
  106. honeybee_radiance/modifier/modifierbase.py +40 -0
  107. honeybee_radiance/modifier/pattern/__init__.py +9 -0
  108. honeybee_radiance/modifier/pattern/brightdata.py +49 -0
  109. honeybee_radiance/modifier/pattern/brightfunc.py +47 -0
  110. honeybee_radiance/modifier/pattern/brighttext.py +81 -0
  111. honeybee_radiance/modifier/pattern/colordata.py +56 -0
  112. honeybee_radiance/modifier/pattern/colorfunc.py +47 -0
  113. honeybee_radiance/modifier/pattern/colorpict.py +54 -0
  114. honeybee_radiance/modifier/pattern/colortext.py +73 -0
  115. honeybee_radiance/modifier/pattern/patternbase.py +34 -0
  116. honeybee_radiance/modifier/texture/__init__.py +4 -0
  117. honeybee_radiance/modifier/texture/texdata.py +29 -0
  118. honeybee_radiance/modifier/texture/texfunc.py +26 -0
  119. honeybee_radiance/modifier/texture/texturebase.py +27 -0
  120. honeybee_radiance/modifierset.py +1091 -0
  121. honeybee_radiance/mutil.py +60 -0
  122. honeybee_radiance/postprocess/__init__.py +1 -0
  123. honeybee_radiance/postprocess/annual.py +108 -0
  124. honeybee_radiance/postprocess/annualdaylight.py +425 -0
  125. honeybee_radiance/postprocess/annualglare.py +201 -0
  126. honeybee_radiance/postprocess/annualirradiance.py +187 -0
  127. honeybee_radiance/postprocess/electriclight.py +119 -0
  128. honeybee_radiance/postprocess/en17037.py +261 -0
  129. honeybee_radiance/postprocess/leed.py +304 -0
  130. honeybee_radiance/postprocess/solartracking.py +90 -0
  131. honeybee_radiance/primitive.py +554 -0
  132. honeybee_radiance/properties/__init__.py +1 -0
  133. honeybee_radiance/properties/_base.py +390 -0
  134. honeybee_radiance/properties/aperture.py +197 -0
  135. honeybee_radiance/properties/door.py +198 -0
  136. honeybee_radiance/properties/face.py +123 -0
  137. honeybee_radiance/properties/model.py +1291 -0
  138. honeybee_radiance/properties/room.py +490 -0
  139. honeybee_radiance/properties/shade.py +186 -0
  140. honeybee_radiance/properties/shademesh.py +116 -0
  141. honeybee_radiance/putil.py +44 -0
  142. honeybee_radiance/reader.py +214 -0
  143. honeybee_radiance/sensor.py +166 -0
  144. honeybee_radiance/sensorgrid.py +1008 -0
  145. honeybee_radiance/view.py +1101 -0
  146. honeybee_radiance/writer.py +951 -0
  147. honeybee_radiance-1.66.190.dist-info/METADATA +89 -0
  148. honeybee_radiance-1.66.190.dist-info/RECORD +152 -0
  149. honeybee_radiance-1.66.190.dist-info/WHEEL +5 -0
  150. honeybee_radiance-1.66.190.dist-info/entry_points.txt +2 -0
  151. honeybee_radiance-1.66.190.dist-info/licenses/LICENSE +661 -0
  152. honeybee_radiance-1.66.190.dist-info/top_level.txt +1 -0
@@ -0,0 +1,529 @@
1
+ """honeybee radiance model-editing commands."""
2
+ import click
3
+ import sys
4
+ import logging
5
+ import json
6
+
7
+ from ladybug_geometry.geometry3d import Vector3D, Face3D
8
+ from honeybee.model import Model
9
+ from honeybee.units import parse_distance_string
10
+ from honeybee.typing import clean_rad_string, clean_and_id_rad_string
11
+
12
+ from honeybee_radiance.sensorgrid import SensorGrid
13
+ from honeybee_radiance.properties.model import ModelRadianceProperties
14
+
15
+ _logger = logging.getLogger(__name__)
16
+
17
+
18
+ @click.group(help='Commands for editing radiance properties of Honeybee Models.')
19
+ def edit():
20
+ pass
21
+
22
+
23
+ @edit.command('reset-resource-ids')
24
+ @click.argument('model-file', type=click.Path(
25
+ exists=True, file_okay=True, dir_okay=False, resolve_path=True))
26
+ @click.option(
27
+ '--by-name/--by-name-and-uuid', ' /-uuid', help='Flag to note whether '
28
+ 'newly-generated resource object IDs should be derived only from a '
29
+ 'cleaned display_name or whether this new ID should also have a unique '
30
+ 'set of 8 characters appended to it to guarantee uniqueness.', default=True
31
+ )
32
+ @click.option(
33
+ '--reset-modifiers/--keep-modifiers', ' /-m', help='Flag to note whether '
34
+ 'the IDs of all modifiers in the model should be reset.',
35
+ default=True, show_default=True
36
+ )
37
+ @click.option(
38
+ '--reset-modifier-sets/--keep-modifier-sets', ' /-ms', help='Flag to '
39
+ 'note whether the IDs of all modifier sets in the model should be reset.',
40
+ default=True, show_default=True
41
+ )
42
+ @click.option(
43
+ '--output-file', '-f', help='Optional hbjson file to output the JSON '
44
+ 'string of the converted model. By default this will be printed out to '
45
+ 'stdout', type=click.File('w'), default='-', show_default=True
46
+ )
47
+ def reset_resource_ids(
48
+ model_file, by_name, reset_modifiers, reset_modifier_sets, output_file
49
+ ):
50
+ """Reset the identifiers of resource objects in a Model file.
51
+
52
+ This is useful when human-readable names are needed when the model is
53
+ exported to other formats like RAD and the uniqueness of the
54
+ identifiers is less of a concern.
55
+
56
+ \b
57
+ Args:
58
+ model_file: Full path to a Honeybee Model (HBJSON) file.
59
+ """
60
+ try:
61
+ # load the model file and separately load up the resource objects
62
+ if sys.version_info < (3, 0):
63
+ with open(model_file) as inf:
64
+ data = json.load(inf)
65
+ else:
66
+ with open(model_file, encoding='utf-8') as inf:
67
+ data = json.load(inf)
68
+ # reset the identifiers of resources in the dictionary
69
+ add_uuid = not by_name
70
+ model_dict = ModelRadianceProperties.reset_resource_ids_in_dict(
71
+ data, add_uuid, reset_modifiers, reset_modifier_sets)
72
+ # write the dictionary into a JSON
73
+ output_file.write(json.dumps(model_dict))
74
+ except Exception as e:
75
+ _logger.exception('Resetting resource identifiers failed.\n{}'.format(e))
76
+ sys.exit(1)
77
+ else:
78
+ sys.exit(0)
79
+
80
+
81
+ @edit.command('add-room-sensors')
82
+ @click.argument('model-file', type=click.Path(
83
+ exists=True, file_okay=True, dir_okay=False, resolve_path=True))
84
+ @click.option('--grid-size', '-s', help='A number for the dimension of the mesh grid '
85
+ 'cells. This can include the units of the distance (eg. 1ft) '
86
+ 'or, if no units are provided, the value will be interpreted in the '
87
+ 'honeybee model units.', type=str, default='0.5m', show_default=True)
88
+ @click.option('--offset', '-o', help='A number for the distance at which the '
89
+ 'the sensor grid should be offset from the floor. This can include the '
90
+ 'units of the distance (eg. 3ft) or, if no units are provided, the '
91
+ 'value will be interpreted in the honeybee model units.',
92
+ type=str, default='0.8m', show_default=True)
93
+ @click.option('--include-mesh/--exclude-mesh', ' /-xm', help='Flag to note whether to '
94
+ 'include a Mesh3D object that aligns with the grid positions '
95
+ 'under the "mesh" property of each grid. Excluding the mesh can greatly '
96
+ 'reduce model size but will mean Radiance results cannot be visualized '
97
+ 'as colored meshes.', default=True)
98
+ @click.option('--keep-out/--remove-out', ' /-out', help='Flag to note whether an extra '
99
+ 'check should be run to remove sensor points that lie outside the Room '
100
+ 'volume. Note that this can add significantly to the runtime and this '
101
+ 'check is not necessary in the case that all walls are vertical '
102
+ 'and all floors are horizontal.', default=True, show_default=True)
103
+ @click.option('--wall-offset', '-w', help='A number for the distance at which sensors '
104
+ 'close to walls should be removed. This can include the units of the '
105
+ 'distance (eg. 3ft) or, if no units are provided, the value will be '
106
+ 'interpreted in the honeybee model units. Note that this option has '
107
+ 'no effect unless the value is more than half of the grid-size.',
108
+ type=str, default='0m', show_default=True)
109
+ @click.option('--room', '-r', multiple=True, help='Room identifier(s) to specify the '
110
+ 'room(s) for which sensor grids should be generated. By default, all '
111
+ 'rooms will get sensor grids.')
112
+ @click.option('--output-file', '-f', help='Optional hbjson file to output the JSON '
113
+ 'string of the new model. By default this will be printed out '
114
+ 'to stdout', type=click.File('w'), default='-', show_default=True)
115
+ def add_room_sensors(model_file, grid_size, offset, include_mesh, keep_out, wall_offset,
116
+ room, output_file):
117
+ """Add SensorGrids to a honeybee model generated from the Room's floors.
118
+
119
+ The grids will have the rooms referenced in their room_identifier property.
120
+
121
+ \b
122
+ Args:
123
+ model_file: Full path to a HBJSON or HBPkl Model file.
124
+ """
125
+ try:
126
+ # re-serialize the Model and extract rooms and units
127
+ model = Model.from_file(model_file)
128
+ rooms = model.rooms if room is None or len(room) == 0 else \
129
+ [r for r in model.rooms if r.identifier in room]
130
+ grid_size = parse_distance_string(grid_size, model.units)
131
+ offset = parse_distance_string(offset, model.units)
132
+ wall_offset = parse_distance_string(wall_offset, model.units)
133
+
134
+ # loop through the rooms and generate sensor grids
135
+ sensor_grids = []
136
+ remove_out = not keep_out
137
+ for room in rooms:
138
+ sg = room.properties.radiance.generate_sensor_grid(
139
+ grid_size, offset=offset, remove_out=remove_out, wall_offset=wall_offset)
140
+ if sg is not None:
141
+ sensor_grids.append(sg)
142
+ if not include_mesh:
143
+ for sg in sensor_grids:
144
+ sg.mesh = None
145
+ model.properties.radiance.add_sensor_grids(sensor_grids)
146
+
147
+ # write the Model JSON string
148
+ output_file.write(json.dumps(model.to_dict()))
149
+ except Exception as e:
150
+ _logger.exception('Adding Model sensor grids failed.\n{}'.format(e))
151
+ sys.exit(1)
152
+ else:
153
+ sys.exit(0)
154
+
155
+
156
+ @edit.command('add-room-radial-sensors')
157
+ @click.argument('model-file', type=click.Path(
158
+ exists=True, file_okay=True, dir_okay=False, resolve_path=True))
159
+ @click.option('--grid-size', '-s', help='A number for the dimension of the '
160
+ 'radial grid. This can include the units of the distance (eg. 1ft) '
161
+ 'or, if no units are provided, the value will be interpreted in the '
162
+ 'honeybee model units.', type=str, default='0.5m', show_default=True)
163
+ @click.option('--offset', '-o', help='A number for the distance at which the '
164
+ 'the sensor grid should be offset from the floor. This can include the '
165
+ 'units of the distance (eg. 3ft) or, if no units are provided, the '
166
+ 'value will be interpreted in the honeybee model units.',
167
+ type=str, default='1.2m', show_default=True)
168
+ @click.option('--include-mesh/--exclude-mesh', ' /-xm', help='Flag to note whether to '
169
+ 'include a Mesh3D object that aligns with the grid positions '
170
+ 'under the "mesh" property of each grid. Excluding the mesh can greatly '
171
+ 'reduce model size but will mean Radiance results cannot be visualized '
172
+ 'as colored meshes.', default=True)
173
+ @click.option('--keep-out/--remove-out', ' /-out', help='Flag to note whether an extra '
174
+ 'check should be run to remove sensor points that lie outside the Room '
175
+ 'volume. Note that this can add significantly to the runtime and this '
176
+ 'check is not necessary in the case that all walls are vertical '
177
+ 'and all floors are horizontal.', default=True, show_default=True)
178
+ @click.option('--wall-offset', '-w', help='A number for the distance at which sensors '
179
+ 'close to walls should be removed. This can include the units of the '
180
+ 'distance (eg. 3ft) or, if no units are provided, the value will be '
181
+ 'interpreted in the honeybee model units. Note that this option has '
182
+ 'no effect unless the value is more than half of the grid-size.',
183
+ type=str, default='0m', show_default=True)
184
+ @click.option('--dir-count', '-d', help='A positive integer for the number of '
185
+ 'radial directions to be generated around each position.',
186
+ type=click.INT, default=8, show_default=True)
187
+ @click.option('--start-vector', '-v', help='An optional list of three values '
188
+ '(separated by spaces) set the start direction of the generated '
189
+ 'directions. This can be used to orient the resulting sensors to '
190
+ 'specific parts of the scene. It can also change the elevation of the '
191
+ 'resulting directions since this start vector will always be rotated in '
192
+ 'the XY plane to generate the resulting directions.',
193
+ type=str, default='0 -1 0', show_default=True)
194
+ @click.option('--mesh-radius', '-m', help='An optional number to override the radius '
195
+ 'of the meshes generated around each sensor. If unspecified, it will be '
196
+ 'equal to 45 percent of the grid-size. Set to zero to ensure no mesh is '
197
+ 'added to the resulting sensor grids.', type=float, default=None)
198
+ @click.option('--room', '-r', multiple=True, help='Room identifier(s) to specify the '
199
+ 'room(s) for which sensor grids should be generated. By default, all '
200
+ 'rooms will get sensor grids.')
201
+ @click.option('--output-file', '-f', help='Optional hbjson file to output the JSON '
202
+ 'string of the new model. By default this will be printed out '
203
+ 'to stdout', type=click.File('w'), default='-', show_default=True)
204
+ def add_room_radial_sensors(
205
+ model_file, grid_size, offset, include_mesh, keep_out, wall_offset,
206
+ dir_count, start_vector, mesh_radius, room, output_file):
207
+ """Add SensorGrids to a honeybee model generated from the Room's floors.
208
+
209
+ The grids will have the rooms referenced in their room_identifier property.
210
+
211
+ \b
212
+ Args:
213
+ model_file: Full path to a HBJSON or HBPkl Model file.
214
+ """
215
+ try:
216
+ # re-serialize the Model and extract rooms and units
217
+ model = Model.from_file(model_file)
218
+ rooms = model.rooms if room is None or len(room) == 0 else \
219
+ [r for r in model.rooms if r.identifier in room]
220
+ grid_size = parse_distance_string(grid_size, model.units)
221
+ offset = parse_distance_string(offset, model.units)
222
+ wall_offset = parse_distance_string(wall_offset, model.units)
223
+ vec = [float(v) for v in start_vector.split()]
224
+ st_vec = Vector3D(*vec)
225
+
226
+ # loop through the rooms and generate sensor grids
227
+ sensor_grids = []
228
+ remove_out = not keep_out
229
+ for room in rooms:
230
+ sg = room.properties.radiance.generate_sensor_grid_radial(
231
+ grid_size, offset=offset, remove_out=remove_out, wall_offset=wall_offset,
232
+ dir_count=dir_count, start_vector=st_vec, mesh_radius=mesh_radius)
233
+ if sg is not None:
234
+ sensor_grids.append(sg)
235
+ if not include_mesh:
236
+ for sg in sensor_grids:
237
+ sg.mesh = None
238
+ model.properties.radiance.add_sensor_grids(sensor_grids)
239
+
240
+ # write the Model JSON string
241
+ output_file.write(json.dumps(model.to_dict()))
242
+ except Exception as e:
243
+ _logger.exception('Adding Model sensor grids failed.\n{}'.format(e))
244
+ sys.exit(1)
245
+ else:
246
+ sys.exit(0)
247
+
248
+
249
+ @edit.command('add-face-sensors')
250
+ @click.argument('model-file', type=click.Path(
251
+ exists=True, file_okay=True, dir_okay=False, resolve_path=True))
252
+ @click.option('--grid-size', '-s', help='A number for the dimension of the mesh grid '
253
+ 'cells. This can include the units of the distance (eg. 1ft) '
254
+ 'or, if no units are provided, the value will be interpreted in the '
255
+ 'honeybee model units.', type=str, default='0.5m', show_default=True)
256
+ @click.option('--offset', '-o', help='A number for the distance at which the '
257
+ 'the sensor grid should be offset from the floor. This can include the '
258
+ 'units of the distance (eg. 3ft) or, if no units are provided, the '
259
+ 'value will be interpreted in the honeybee model units.',
260
+ type=str, default='0.1m', show_default=True)
261
+ @click.option('--face-type', '-t', help='Text to specify the type of face that will be '
262
+ 'used to generate grids. Note that only Faces with Outdoors boundary '
263
+ 'conditions will be used, meaning that most Floors will typically '
264
+ 'be excluded unless they represent the underside of a cantilever. '
265
+ 'Choose from Wall, Roof, Floor, All.',
266
+ type=str, default='Wall', show_default=True)
267
+ @click.option('--full-geometry/--punched-geometry', ' /-p', help='Flag to note whether '
268
+ 'the punched_geometry of the faces should be used with the areas '
269
+ 'of sub-faces removed from the grid or the full geometry should be used.',
270
+ default=True)
271
+ @click.option('--include-mesh/--exclude-mesh', ' /-xm', help='Flag to note whether to '
272
+ 'include a Mesh3D object that aligns with the grid positions '
273
+ 'under the "mesh" property of each grid. Excluding the mesh can greatly '
274
+ 'reduce model size but will mean Radiance results cannot be visualized '
275
+ 'as colored meshes.', default=True)
276
+ @click.option('--room', '-r', multiple=True, help='Room identifier(s) to specify the '
277
+ 'room(s) for which sensor grids should be generated. By default, all '
278
+ 'rooms will get sensor grids.')
279
+ @click.option('--output-file', '-f', help='Optional hbjson file to output the JSON '
280
+ 'string of the new model. By default this will be printed out '
281
+ 'to stdout', type=click.File('w'), default='-', show_default=True)
282
+ def add_face_sensors(model_file, grid_size, offset, face_type, full_geometry,
283
+ include_mesh, room, output_file):
284
+ """Add SensorGrids to a honeybee model generated from the model's faces.
285
+
286
+ \b
287
+ Args:
288
+ model_file: Full path to a HBJSON or HBPkl Model file.
289
+ """
290
+ try:
291
+ # re-serialize the Model and extract rooms and units
292
+ model = Model.from_file(model_file)
293
+ rooms = None if room is None or len(room) == 0 else \
294
+ [r for r in model.rooms if r.identifier in room]
295
+ grid_size = parse_distance_string(grid_size, model.units)
296
+ offset = parse_distance_string(offset, model.units)
297
+ punched_geometry = not full_geometry
298
+
299
+ # loop through the rooms and generate sensor grids
300
+ sensor_grids = []
301
+ if rooms is None:
302
+ sg = model.properties.radiance.generate_exterior_face_sensor_grid(
303
+ grid_size, offset=offset, face_type=face_type,
304
+ punched_geometry=punched_geometry)
305
+ sensor_grids.append(sg)
306
+ else:
307
+ for room in rooms:
308
+ sg = room.properties.radiance.generate_exterior_face_sensor_grid(
309
+ grid_size, offset=offset, face_type=face_type,
310
+ punched_geometry=punched_geometry)
311
+ if sg is not None:
312
+ sensor_grids.append(sg)
313
+ if not include_mesh:
314
+ for sg in sensor_grids:
315
+ sg.mesh = None
316
+ model.properties.radiance.add_sensor_grids(sensor_grids)
317
+
318
+ # write the Model JSON string
319
+ output_file.write(json.dumps(model.to_dict()))
320
+ except Exception as e:
321
+ _logger.exception('Adding Model sensor grids failed.\n{}'.format(e))
322
+ sys.exit(1)
323
+ else:
324
+ sys.exit(0)
325
+
326
+
327
+ @edit.command('add-aperture-sensors')
328
+ @click.argument('model-file', type=click.Path(
329
+ exists=True, file_okay=True, dir_okay=False, resolve_path=True))
330
+ @click.option('--grid-size', '-s', help='A number for the dimension of the mesh grid '
331
+ 'cells. This can include the units of the distance (eg. 1ft) '
332
+ 'or, if no units are provided, the value will be interpreted in the '
333
+ 'honeybee model units.', type=str, default='0.5m', show_default=True)
334
+ @click.option('--offset', '-o', help='A number for the distance at which the '
335
+ 'the sensor grid should be offset from the apertures. This can include the '
336
+ 'units of the distance (eg. 3ft) or, if no units are provided, the '
337
+ 'value will be interpreted in the honeybee model units.',
338
+ type=str, default='0.1m', show_default=True)
339
+ @click.option('--aperture-type', '-t', help='Text to specify the type of aperture that '
340
+ 'will be used to generate grids. Note that only Faces with Outdoors '
341
+ 'boundary conditions will be used, meaning that most Floors will typically'
342
+ ' be excluded unless they represent the underside of a cantilever. '
343
+ 'Choose from Window, Skylight, All.',
344
+ type=str, default='All', show_default=True)
345
+ @click.option('--include-mesh/--exclude-mesh', ' /-xm', help='Flag to note whether to '
346
+ 'include a Mesh3D object that aligns with the grid positions '
347
+ 'under the "mesh" property of each grid. Excluding the mesh can greatly '
348
+ 'reduce model size but will mean Radiance results cannot be visualized '
349
+ 'as colored meshes.', default=True)
350
+ @click.option('--room', '-r', multiple=True, help='Room identifier(s) to specify the '
351
+ 'room(s) for which sensor grids should be generated. By default, all '
352
+ 'rooms will get sensor grids.')
353
+ @click.option('--output-file', '-f', help='Optional hbjson file to output the JSON '
354
+ 'string of the new model. By default this will be printed out '
355
+ 'to stdout', type=click.File('w'), default='-', show_default=True)
356
+ def add_aperture_sensors(
357
+ model_file, grid_size, offset, aperture_type, include_mesh, room, output_file):
358
+ """Add SensorGrids to a honeybee model generated from the model's apertures.
359
+
360
+ \b
361
+ Args:
362
+ model_file: Full path to a HBJSON or HBPkl Model file.
363
+ """
364
+ try:
365
+ # re-serialize the Model and extract rooms and units
366
+ model = Model.from_file(model_file)
367
+ rooms = None if room is None or len(room) == 0 else \
368
+ [r for r in model.rooms if r.identifier in room]
369
+ grid_size = parse_distance_string(grid_size, model.units)
370
+ offset = parse_distance_string(offset, model.units)
371
+
372
+ # loop through the rooms and generate sensor grids
373
+ sensor_grids = []
374
+ if rooms is None:
375
+ sg = model.properties.radiance.generate_exterior_aperture_sensor_grid(
376
+ grid_size, offset=offset, aperture_type=aperture_type)
377
+ sensor_grids.append(sg)
378
+ else:
379
+ for room in rooms:
380
+ sg = room.properties.radiance.generate_exterior_aperture_sensor_grid(
381
+ grid_size, offset=offset, aperture_type=aperture_type)
382
+ if sg is not None:
383
+ sensor_grids.append(sg)
384
+ if not include_mesh:
385
+ for sg in sensor_grids:
386
+ sg.mesh = None
387
+ model.properties.radiance.add_sensor_grids(sensor_grids)
388
+
389
+ # write the Model JSON string
390
+ output_file.write(json.dumps(model.to_dict()))
391
+ except Exception as e:
392
+ _logger.exception('Adding Model sensor grids failed.\n{}'.format(e))
393
+ sys.exit(1)
394
+ else:
395
+ sys.exit(0)
396
+
397
+
398
+ @edit.command('add-face3d-sensors')
399
+ @click.argument('model-file', type=click.Path(
400
+ exists=True, file_okay=True, dir_okay=False, resolve_path=True))
401
+ @click.argument('face3d-file', type=click.Path(
402
+ exists=True, file_okay=True, dir_okay=False, resolve_path=True))
403
+ @click.option('--grid-name', '-n', help='Text string for the name of the SensorGrid, '
404
+ 'which will also be used to assign SensorGrid ID. This will be used to '
405
+ 'identify the object across a model and in the exported Radiance files '
406
+ 'so it is recommended that it be relatively unique. If unspecified, '
407
+ 'a random name will be generated.', type=str, default=None)
408
+ @click.option('--grid-size', '-s', help='A number for the dimension of the mesh grid '
409
+ 'cells. This can include the units of the distance (eg. 1ft) '
410
+ 'or, if no units are provided, the value will be interpreted in the '
411
+ 'honeybee model units.', type=str, default='0.5m', show_default=True)
412
+ @click.option('--offset', '-o', help='A number for the distance at which the the sensor '
413
+ 'grid should be offset from the base geometry. This can include the '
414
+ 'units of the distance (eg. 3ft) or, if no units are provided, the '
415
+ 'value will be interpreted in the honeybee model units.',
416
+ type=str, default='0', show_default=True)
417
+ @click.option('--no-flip/--flip', ' /-fl', help='Flag to note whether the mesh '
418
+ 'normals should be reversed from the direction of the face geometries'
419
+ 'and the --offset move the sensors in the opposite direction from the '
420
+ 'face normals.', default=True, show_default=True)
421
+ @click.option('--include-mesh/--exclude-mesh', ' /-xm', help='Flag to note whether to '
422
+ 'include a Mesh3D object that aligns with the grid positions '
423
+ 'under the "mesh" property of each grid. Excluding the mesh can greatly '
424
+ 'reduce model size but will mean Radiance results cannot be visualized '
425
+ 'as colored meshes.', default=True)
426
+ @click.option('--output-file', '-f', help='Optional hbjson file to output the JSON '
427
+ 'string of the new model. By default this will be printed out '
428
+ 'to stdout', type=click.File('w'), default='-', show_default=True)
429
+ def add_face3d_sensors(
430
+ model_file, face3d_file, grid_name, grid_size, offset, no_flip,
431
+ include_mesh, output_file):
432
+ """Add SensorGrids to a honeybee model generated from a JSON array of Face3D objects.
433
+
434
+ \b
435
+ Args:
436
+ model_file: Full path to a HBJSON or HBPkl Model file.
437
+ face3d_file: Full path to a JSON file containing an array of Face3D objects
438
+ that will be used to generate the sensor grid. This could also be a
439
+ nested array (list of lists of Face3Ds), in which case a separate
440
+ SensorGrid will be computed for each sub-list.
441
+ """
442
+ try:
443
+ # re-serialize the Model
444
+ model = Model.from_file(model_file)
445
+
446
+ # re-serialize the Face3Ds
447
+ with open(face3d_file) as inf:
448
+ data = json.load(inf)
449
+ face_arrays = []
450
+ for obj in data:
451
+ if isinstance(obj, list):
452
+ face_arrays.append([Face3D.from_dict(f) for f in obj])
453
+ else: # assume that it is a single Face3D
454
+ face_arrays.append([Face3D.from_dict(obj)])
455
+
456
+ # process all of the other inputs
457
+ grid_size = parse_distance_string(grid_size, model.units)
458
+ offset = parse_distance_string(offset, model.units)
459
+ base_id = clean_rad_string(grid_name) if grid_name is not None \
460
+ else clean_and_id_rad_string('SensorGrid')
461
+ flip = not no_flip
462
+
463
+ # loop through the Face3Ds and generate sensor grids
464
+ sensor_grids = []
465
+ for i, faces in enumerate(face_arrays):
466
+ grid_id = base_id if len(face_arrays) == 1 else '{}_{}'.format(base_id, i)
467
+ try:
468
+ sensor_grids.append(
469
+ SensorGrid.from_face3d(grid_id, faces, grid_size, None, offset, flip)
470
+ )
471
+ except AssertionError: # none of the Face3Ds make a valid grid
472
+ continue
473
+ if not include_mesh:
474
+ for sg in sensor_grids:
475
+ sg.mesh = None
476
+ model.properties.radiance.add_sensor_grids(sensor_grids)
477
+
478
+ # write the Model JSON string
479
+ output_file.write(json.dumps(model.to_dict()))
480
+ except Exception as e:
481
+ _logger.exception('Adding Model sensor grids failed.\n{}'.format(e))
482
+ sys.exit(1)
483
+ else:
484
+ sys.exit(0)
485
+
486
+
487
+ @edit.command('mirror-model-sensors')
488
+ @click.argument('model-file', type=click.Path(
489
+ exists=True, file_okay=True, dir_okay=False, resolve_path=True))
490
+ @click.option('--output-file', '-f', help='Optional hbjson file to output the JSON '
491
+ 'string of the converted model. By default this will be printed out '
492
+ 'to stdout', type=click.File('w'), default='-', show_default=True)
493
+ def mirror_model_sensors(model_file, output_file):
494
+ """Mirror a honeybee Model's SensorGrids and format them for thermal mapping.
495
+
496
+ This involves setting the direction of every sensor to point up (0, 0, 1) and
497
+ then adding a mirrored sensor grid with the same sensor positions that all
498
+ point downward. In thermal mapping workflows, the upward-pointing grids can
499
+ be used to account for direct and diffuse shortwave irradiance while the
500
+ downward pointing grids account for ground-reflected shortwave irradiance.
501
+
502
+ \b
503
+ Args:
504
+ model_file: Full path to a HBJSON or HBPkl Model file.
505
+ """
506
+ try:
507
+ # re-serialize the Model and loop through the sensor grids to reformat them
508
+ model = Model.from_file(model_file)
509
+ mirror_grids, up_dir, down_dir = [], None, (0, 0, -1)
510
+ for grid in model.properties.radiance.sensor_grids:
511
+ # ensure that all sensors are pointing upward
512
+ grid.group_identifier = None
513
+ for sensor in grid:
514
+ sensor.dir = up_dir
515
+ # create the mirror grid will all sensors pointing downward
516
+ mir_grid = grid.duplicate()
517
+ mir_grid.identifier = '{}_ref'.format(grid.identifier)
518
+ for sensor in mir_grid:
519
+ sensor.dir = down_dir
520
+ mirror_grids.append(mir_grid)
521
+ model.properties.radiance.add_sensor_grids(mirror_grids)
522
+
523
+ # write the Model JSON string
524
+ output_file.write(json.dumps(model.to_dict()))
525
+ except Exception as e:
526
+ _logger.exception('Model sensor grid mirroring failed.\n{}'.format(e))
527
+ sys.exit(1)
528
+ else:
529
+ sys.exit(0)
@@ -0,0 +1,118 @@
1
+ """honeybee radiance dcglare command."""
2
+ import click
3
+ import sys
4
+ import logging
5
+ import os
6
+
7
+ from honeybee_radiance.config import folders
8
+ from honeybee_radiance_command.dcglare import Dcglare, DcglareOptions
9
+
10
+
11
+ _logger = logging.getLogger(__name__)
12
+
13
+
14
+ @click.group(help='Commands to run dcglare in Radiance.')
15
+ def dcglare():
16
+ pass
17
+
18
+
19
+ @dcglare.command('two-phase')
20
+ @click.argument(
21
+ 'dc-direct',
22
+ type=click.Path(exists=True, file_okay=True, dir_okay=False, resolve_path=True)
23
+ )
24
+ @click.argument(
25
+ 'dc-total',
26
+ type=click.Path(exists=True, file_okay=True, dir_okay=False, resolve_path=True)
27
+ )
28
+ @click.argument(
29
+ 'sky-mtx',
30
+ type=click.Path(exists=True, file_okay=True, dir_okay=False, resolve_path=True)
31
+ )
32
+ @click.argument(
33
+ 'view-rays',
34
+ type=click.Path(exists=True, file_okay=True, dir_okay=False, resolve_path=True)
35
+ )
36
+ @click.option(
37
+ '--glare-limit', '-l', type=float,
38
+ help='When this option is provided, the program calculates glare autonomy, where '
39
+ 'any DGP value at or above the limit indicates the presence of glare. If the option '
40
+ 'is not provided, the program calculates DGP under each sky condition in the sky '
41
+ 'matrix instead.'
42
+ )
43
+ @click.option(
44
+ '--threshold-factor', '-b', type=float,
45
+ help='If larger than 100, it is used as constant threshold in cd/m2. If less than '
46
+ 'or equal to 100, this factor multiplied by the average luminance in each view will '
47
+ 'be used as threshold for detecting the glare sources (not recommended). The '
48
+ 'default value is 2000 (fixed threshold method).'
49
+ )
50
+ @click.option(
51
+ '--occupancy-schedule', '-sf',
52
+ type=click.Path(exists=False, dir_okay=False, resolve_path=True),
53
+ help='In the event that the sky matrix includes unoccupied hours that should not '
54
+ 'contribute to the glare autonomy calculation, file will be read to determine which '
55
+ 'entries from the sky file matrix will be included in this calculation. Each line '
56
+ 'of file is expected to contain a numeric value at the end of a comma-delimited '
57
+ 'list, with zero corresponding to unoccupied. This argument is used only if '
58
+ '--glare-limit (or -l) is specified.'
59
+ )
60
+ @click.option(
61
+ '--output', '-o', default='output.dgp',
62
+ help='Path to output file. If a relative path is provided it '
63
+ 'should be relative to project folder.'
64
+ )
65
+ @click.option(
66
+ '--dry-run', is_flag=True, default=False, show_default=True,
67
+ help='A flag to show the command without running it.'
68
+ )
69
+ def two_phase_command(
70
+ dc_direct, dc_total, sky_mtx, view_rays, glare_limit, threshold_factor,
71
+ occupancy_schedule, output, dry_run):
72
+ """Run dcglare command for dcdirect and dctotal.
73
+
74
+ \b
75
+ Args:
76
+ dc-direct: Path to direct contribution matrix calculated with a single ambient
77
+ bounce.
78
+ dc-total: Path to total contribution matrix.
79
+ sky-mtx: Path to sky mtx.
80
+ view-rays: Path to file of view rays.
81
+
82
+ """
83
+ occupancy_schedule = None if \
84
+ (occupancy_schedule and not os.path.isfile(occupancy_schedule)) \
85
+ else occupancy_schedule
86
+ try:
87
+ options = DcglareOptions()
88
+ options.vf = view_rays
89
+ if glare_limit:
90
+ options.l = glare_limit
91
+ if threshold_factor:
92
+ options.b = threshold_factor
93
+ if occupancy_schedule:
94
+ options.sf = occupancy_schedule
95
+
96
+ # create command
97
+ out_dir = os.path.dirname(output)
98
+ if not os.path.isdir(out_dir):
99
+ os.makedirs(out_dir)
100
+ dcglare = Dcglare(
101
+ options=options, output=output,
102
+ dc_direct=dc_direct, dc_total=dc_total, sky_matrix=sky_mtx
103
+ )
104
+
105
+ if dry_run:
106
+ click.echo(dcglare)
107
+ else:
108
+ env = None
109
+ if folders.env != {}:
110
+ env = folders.env
111
+ env = dict(os.environ, **env) if env else None
112
+ dcglare.run(env=env)
113
+
114
+ except Exception:
115
+ _logger.exception('Failed to run dcglare command.')
116
+ sys.exit(1)
117
+ else:
118
+ sys.exit(0)