voxcity 0.6.15__py3-none-any.whl → 0.7.0__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.
Files changed (78) hide show
  1. voxcity/__init__.py +14 -8
  2. voxcity/downloader/__init__.py +2 -1
  3. voxcity/downloader/citygml.py +32 -18
  4. voxcity/downloader/gba.py +210 -0
  5. voxcity/downloader/gee.py +5 -1
  6. voxcity/downloader/mbfp.py +1 -1
  7. voxcity/downloader/oemj.py +80 -8
  8. voxcity/downloader/osm.py +23 -7
  9. voxcity/downloader/overture.py +26 -1
  10. voxcity/downloader/utils.py +73 -73
  11. voxcity/errors.py +30 -0
  12. voxcity/exporter/__init__.py +13 -4
  13. voxcity/exporter/cityles.py +633 -535
  14. voxcity/exporter/envimet.py +728 -708
  15. voxcity/exporter/magicavoxel.py +334 -297
  16. voxcity/exporter/netcdf.py +238 -0
  17. voxcity/exporter/obj.py +1481 -655
  18. voxcity/generator/__init__.py +44 -0
  19. voxcity/generator/api.py +675 -0
  20. voxcity/generator/grids.py +379 -0
  21. voxcity/generator/io.py +94 -0
  22. voxcity/generator/pipeline.py +282 -0
  23. voxcity/generator/voxelizer.py +380 -0
  24. voxcity/geoprocessor/__init__.py +75 -6
  25. voxcity/geoprocessor/conversion.py +153 -0
  26. voxcity/geoprocessor/draw.py +62 -12
  27. voxcity/geoprocessor/heights.py +199 -0
  28. voxcity/geoprocessor/io.py +101 -0
  29. voxcity/geoprocessor/merge_utils.py +91 -0
  30. voxcity/geoprocessor/mesh.py +806 -790
  31. voxcity/geoprocessor/network.py +708 -679
  32. voxcity/geoprocessor/overlap.py +84 -0
  33. voxcity/geoprocessor/raster/__init__.py +82 -0
  34. voxcity/geoprocessor/raster/buildings.py +428 -0
  35. voxcity/geoprocessor/raster/canopy.py +258 -0
  36. voxcity/geoprocessor/raster/core.py +150 -0
  37. voxcity/geoprocessor/raster/export.py +93 -0
  38. voxcity/geoprocessor/raster/landcover.py +156 -0
  39. voxcity/geoprocessor/raster/raster.py +110 -0
  40. voxcity/geoprocessor/selection.py +85 -0
  41. voxcity/geoprocessor/utils.py +18 -14
  42. voxcity/models.py +113 -0
  43. voxcity/simulator/common/__init__.py +22 -0
  44. voxcity/simulator/common/geometry.py +98 -0
  45. voxcity/simulator/common/raytracing.py +450 -0
  46. voxcity/simulator/solar/__init__.py +43 -0
  47. voxcity/simulator/solar/integration.py +336 -0
  48. voxcity/simulator/solar/kernels.py +62 -0
  49. voxcity/simulator/solar/radiation.py +648 -0
  50. voxcity/simulator/solar/temporal.py +434 -0
  51. voxcity/simulator/view.py +36 -2286
  52. voxcity/simulator/visibility/__init__.py +29 -0
  53. voxcity/simulator/visibility/landmark.py +392 -0
  54. voxcity/simulator/visibility/view.py +508 -0
  55. voxcity/utils/logging.py +61 -0
  56. voxcity/utils/orientation.py +51 -0
  57. voxcity/utils/weather/__init__.py +26 -0
  58. voxcity/utils/weather/epw.py +146 -0
  59. voxcity/utils/weather/files.py +36 -0
  60. voxcity/utils/weather/onebuilding.py +486 -0
  61. voxcity/visualizer/__init__.py +24 -0
  62. voxcity/visualizer/builder.py +43 -0
  63. voxcity/visualizer/grids.py +141 -0
  64. voxcity/visualizer/maps.py +187 -0
  65. voxcity/visualizer/palette.py +228 -0
  66. voxcity/visualizer/renderer.py +928 -0
  67. {voxcity-0.6.15.dist-info → voxcity-0.7.0.dist-info}/METADATA +113 -36
  68. voxcity-0.7.0.dist-info/RECORD +77 -0
  69. {voxcity-0.6.15.dist-info → voxcity-0.7.0.dist-info}/WHEEL +1 -1
  70. voxcity/generator.py +0 -1137
  71. voxcity/geoprocessor/grid.py +0 -1568
  72. voxcity/geoprocessor/polygon.py +0 -1344
  73. voxcity/simulator/solar.py +0 -2329
  74. voxcity/utils/visualization.py +0 -2660
  75. voxcity/utils/weather.py +0 -817
  76. voxcity-0.6.15.dist-info/RECORD +0 -37
  77. {voxcity-0.6.15.dist-info → voxcity-0.7.0.dist-info/licenses}/AUTHORS.rst +0 -0
  78. {voxcity-0.6.15.dist-info → voxcity-0.7.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,450 @@
1
+ import numpy as np
2
+ from numba import njit, prange
3
+
4
+
5
+ @njit
6
+ def calculate_transmittance(length, tree_k=0.6, tree_lad=1.0):
7
+ return np.exp(-tree_k * tree_lad * length)
8
+
9
+
10
+ @njit
11
+ def trace_ray_generic(voxel_data, origin, direction, hit_values, meshsize, tree_k, tree_lad, inclusion_mode=True):
12
+ nx, ny, nz = voxel_data.shape
13
+ x0, y0, z0 = origin
14
+ dx, dy, dz = direction
15
+
16
+ length = np.sqrt(dx*dx + dy*dy + dz*dz)
17
+ if length == 0.0:
18
+ return False, 1.0
19
+ dx /= length
20
+ dy /= length
21
+ dz /= length
22
+
23
+ x, y, z = x0 + 0.5, y0 + 0.5, z0 + 0.5
24
+ i, j, k = int(x0), int(y0), int(z0)
25
+
26
+ step_x = 1 if dx >= 0 else -1
27
+ step_y = 1 if dy >= 0 else -1
28
+ step_z = 1 if dz >= 0 else -1
29
+
30
+ EPSILON = 1e-10
31
+
32
+ if abs(dx) > EPSILON:
33
+ t_max_x = ((i + (step_x > 0)) - x) / dx
34
+ t_delta_x = abs(1 / dx)
35
+ else:
36
+ t_max_x = np.inf
37
+ t_delta_x = np.inf
38
+
39
+ if abs(dy) > EPSILON:
40
+ t_max_y = ((j + (step_y > 0)) - y) / dy
41
+ t_delta_y = abs(1 / dy)
42
+ else:
43
+ t_max_y = np.inf
44
+ t_delta_y = np.inf
45
+
46
+ if abs(dz) > EPSILON:
47
+ t_max_z = ((k + (step_z > 0)) - z) / dz
48
+ t_delta_z = abs(1 / dz)
49
+ else:
50
+ t_max_z = np.inf
51
+ t_delta_z = np.inf
52
+
53
+ cumulative_transmittance = 1.0
54
+ last_t = 0.0
55
+
56
+ while (0 <= i < nx) and (0 <= j < ny) and (0 <= k < nz):
57
+ voxel_value = voxel_data[i, j, k]
58
+
59
+ t_next = min(t_max_x, t_max_y, t_max_z)
60
+ segment_length = (t_next - last_t) * meshsize
61
+ if segment_length < 0.0:
62
+ segment_length = 0.0
63
+
64
+ if voxel_value == -2:
65
+ transmittance = calculate_transmittance(segment_length, tree_k, tree_lad)
66
+ cumulative_transmittance *= transmittance
67
+ if cumulative_transmittance < 0.01:
68
+ if inclusion_mode:
69
+ return False, cumulative_transmittance
70
+ else:
71
+ return True, cumulative_transmittance
72
+
73
+ if inclusion_mode:
74
+ for hv in hit_values:
75
+ if voxel_value == hv:
76
+ return True, cumulative_transmittance
77
+ if voxel_value != 0 and voxel_value != -2:
78
+ return False, cumulative_transmittance
79
+ else:
80
+ in_set = False
81
+ for hv in hit_values:
82
+ if voxel_value == hv:
83
+ in_set = True
84
+ break
85
+ if not in_set and voxel_value != -2:
86
+ return True, cumulative_transmittance
87
+
88
+ last_t = t_next
89
+
90
+ TIE_EPS = 1e-12
91
+ eq_x = abs(t_max_x - t_next) <= TIE_EPS
92
+ eq_y = abs(t_max_y - t_next) <= TIE_EPS
93
+ eq_z = abs(t_max_z - t_next) <= TIE_EPS
94
+
95
+ if inclusion_mode and ((eq_x and eq_y) or (eq_x and eq_z) or (eq_y and eq_z)):
96
+ if eq_x:
97
+ ii = i + step_x
98
+ if 0 <= ii < nx:
99
+ val = voxel_data[ii, j, k]
100
+ is_target = False
101
+ for hv in hit_values:
102
+ if val == hv:
103
+ is_target = True
104
+ break
105
+ if (val != 0) and (val != -2) and (not is_target):
106
+ return False, cumulative_transmittance
107
+ if eq_y:
108
+ jj = j + step_y
109
+ if 0 <= jj < ny:
110
+ val = voxel_data[i, jj, k]
111
+ is_target = False
112
+ for hv in hit_values:
113
+ if val == hv:
114
+ is_target = True
115
+ break
116
+ if (val != 0) and (val != -2) and (not is_target):
117
+ return False, cumulative_transmittance
118
+ if eq_z:
119
+ kk = k + step_z
120
+ if 0 <= kk < nz:
121
+ val = voxel_data[i, j, kk]
122
+ is_target = False
123
+ for hv in hit_values:
124
+ if val == hv:
125
+ is_target = True
126
+ break
127
+ if (val != 0) and (val != -2) and (not is_target):
128
+ return False, cumulative_transmittance
129
+
130
+ stepped = False
131
+ if eq_x:
132
+ t_max_x += t_delta_x
133
+ i += step_x
134
+ stepped = True
135
+ if eq_y:
136
+ t_max_y += t_delta_y
137
+ j += step_y
138
+ stepped = True
139
+ if eq_z:
140
+ t_max_z += t_delta_z
141
+ k += step_z
142
+ stepped = True
143
+
144
+ if not stepped:
145
+ if t_max_x < t_max_y:
146
+ if t_max_x < t_max_z:
147
+ t_max_x += t_delta_x; i += step_x
148
+ else:
149
+ t_max_z += t_delta_z; k += step_z
150
+ else:
151
+ if t_max_y < t_max_z:
152
+ t_max_y += t_delta_y; j += step_y
153
+ else:
154
+ t_max_z += t_delta_z; k += step_z
155
+
156
+ return False, cumulative_transmittance
157
+
158
+
159
+ @njit
160
+ def compute_vi_generic(observer_location, voxel_data, ray_directions, hit_values, meshsize, tree_k, tree_lad, inclusion_mode=True):
161
+ total_rays = ray_directions.shape[0]
162
+ visibility_sum = 0.0
163
+ for idx in range(total_rays):
164
+ direction = ray_directions[idx]
165
+ hit, value = trace_ray_generic(voxel_data, observer_location, direction, hit_values, meshsize, tree_k, tree_lad, inclusion_mode)
166
+ if inclusion_mode:
167
+ if hit:
168
+ if -2 in hit_values:
169
+ contrib = 1.0 - max(0.0, min(1.0, value))
170
+ visibility_sum += contrib
171
+ else:
172
+ visibility_sum += 1.0
173
+ else:
174
+ if not hit:
175
+ visibility_sum += value
176
+ return visibility_sum / total_rays
177
+
178
+
179
+ @njit(parallel=True)
180
+ def compute_vi_map_generic(voxel_data, ray_directions, view_height_voxel, hit_values, meshsize, tree_k, tree_lad, inclusion_mode=True):
181
+ nx, ny, nz = voxel_data.shape
182
+ vi_map = np.full((nx, ny), np.nan)
183
+ for x in prange(nx):
184
+ for y in range(ny):
185
+ found_observer = False
186
+ for z in range(1, nz):
187
+ if voxel_data[x, y, z] in (0, -2) and voxel_data[x, y, z - 1] not in (0, -2):
188
+ if (voxel_data[x, y, z - 1] in (7, 8, 9)) or (voxel_data[x, y, z - 1] < 0):
189
+ vi_map[x, y] = np.nan
190
+ found_observer = True
191
+ break
192
+ else:
193
+ observer_location = np.array([x, y, z + view_height_voxel], dtype=np.float64)
194
+ vi_value = compute_vi_generic(observer_location, voxel_data, ray_directions, hit_values, meshsize, tree_k, tree_lad, inclusion_mode)
195
+ vi_map[x, y] = vi_value
196
+ found_observer = True
197
+ break
198
+ if not found_observer:
199
+ vi_map[x, y] = np.nan
200
+ return np.flipud(vi_map)
201
+
202
+
203
+ def _prepare_masks_for_vi(voxel_data: np.ndarray, hit_values, inclusion_mode: bool):
204
+ is_tree = (voxel_data == -2)
205
+ if inclusion_mode:
206
+ is_target = np.isin(voxel_data, hit_values)
207
+ is_blocker_inc = (voxel_data != 0) & (~is_tree) & (~is_target)
208
+ return is_tree, is_target, None, is_blocker_inc
209
+ else:
210
+ is_allowed = np.isin(voxel_data, hit_values)
211
+ return is_tree, None, is_allowed, None
212
+
213
+
214
+ @njit(cache=True, fastmath=True)
215
+ def _trace_ray_inclusion_masks(is_tree, is_target, is_blocker_inc, origin, direction, meshsize, tree_k, tree_lad):
216
+ nx, ny, nz = is_tree.shape
217
+ x0, y0, z0 = origin
218
+ dx, dy, dz = direction
219
+ length = (dx*dx + dy*dy + dz*dz) ** 0.5
220
+ if length == 0.0:
221
+ return False, 1.0
222
+ dx /= length; dy /= length; dz /= length
223
+ x, y, z = x0 + 0.5, y0 + 0.5, z0 + 0.5
224
+ i, j, k = int(x0), int(y0), int(z0)
225
+ step_x = 1 if dx >= 0 else -1
226
+ step_y = 1 if dy >= 0 else -1
227
+ step_z = 1 if dz >= 0 else -1
228
+ EPS = 1e-10
229
+ if abs(dx) > EPS:
230
+ t_max_x = ((i + (step_x > 0)) - x) / dx
231
+ t_delta_x = abs(1.0 / dx)
232
+ else:
233
+ t_max_x = np.inf; t_delta_x = np.inf
234
+ if abs(dy) > EPS:
235
+ t_max_y = ((j + (step_y > 0)) - y) / dy
236
+ t_delta_y = abs(1.0 / dy)
237
+ else:
238
+ t_max_y = np.inf; t_delta_y = np.inf
239
+ if abs(dz) > EPS:
240
+ t_max_z = ((k + (step_z > 0)) - z) / dz
241
+ t_delta_z = abs(1.0 / dz)
242
+ else:
243
+ t_max_z = np.inf; t_delta_z = np.inf
244
+ cumulative_transmittance = 1.0
245
+ last_t = 0.0
246
+ while (0 <= i < nx) and (0 <= j < ny) and (0 <= k < nz):
247
+ t_next = t_max_x
248
+ axis = 0
249
+ if t_max_y < t_next:
250
+ t_next = t_max_y; axis = 1
251
+ if t_max_z < t_next:
252
+ t_next = t_max_z; axis = 2
253
+ segment_length = (t_next - last_t) * meshsize
254
+ if segment_length < 0.0:
255
+ segment_length = 0.0
256
+ if is_tree[i, j, k]:
257
+ trans = np.exp(-tree_k * tree_lad * segment_length)
258
+ cumulative_transmittance *= trans
259
+ if cumulative_transmittance < 1e-2:
260
+ return False, cumulative_transmittance
261
+ if is_target[i, j, k]:
262
+ return True, cumulative_transmittance
263
+ if is_blocker_inc[i, j, k]:
264
+ return False, cumulative_transmittance
265
+ last_t = t_next
266
+ if axis == 0:
267
+ t_max_x += t_delta_x; i += step_x
268
+ elif axis == 1:
269
+ t_max_y += t_delta_y; j += step_y
270
+ else:
271
+ t_max_z += t_delta_z; k += step_z
272
+ return False, cumulative_transmittance
273
+
274
+
275
+ @njit(cache=True, fastmath=True)
276
+ def _trace_ray_exclusion_masks(is_tree, is_allowed, origin, direction, meshsize, tree_k, tree_lad):
277
+ nx, ny, nz = is_tree.shape
278
+ x0, y0, z0 = origin
279
+ dx, dy, dz = direction
280
+ length = (dx*dx + dy*dy + dz*dz) ** 0.5
281
+ if length == 0.0:
282
+ return False, 1.0
283
+ dx /= length; dy /= length; dz /= length
284
+ x, y, z = x0 + 0.5, y0 + 0.5, z0 + 0.5
285
+ i, j, k = int(x0), int(y0), int(z0)
286
+ step_x = 1 if dx >= 0 else -1
287
+ step_y = 1 if dy >= 0 else -1
288
+ step_z = 1 if dz >= 0 else -1
289
+ EPS = 1e-10
290
+ if abs(dx) > EPS:
291
+ t_max_x = ((i + (step_x > 0)) - x) / dx
292
+ t_delta_x = abs(1.0 / dx)
293
+ else:
294
+ t_max_x = np.inf; t_delta_x = np.inf
295
+ if abs(dy) > EPS:
296
+ t_max_y = ((j + (step_y > 0)) - y) / dy
297
+ t_delta_y = abs(1.0 / dy)
298
+ else:
299
+ t_max_y = np.inf; t_delta_y = np.inf
300
+ if abs(dz) > EPS:
301
+ t_max_z = ((k + (step_z > 0)) - z) / dz
302
+ t_delta_z = abs(1.0 / dz)
303
+ else:
304
+ t_max_z = np.inf; t_delta_z = np.inf
305
+ cumulative_transmittance = 1.0
306
+ last_t = 0.0
307
+ while (0 <= i < nx) and (0 <= j < ny) and (0 <= k < nz):
308
+ t_next = t_max_x
309
+ axis = 0
310
+ if t_max_y < t_next:
311
+ t_next = t_max_y; axis = 1
312
+ if t_max_z < t_next:
313
+ t_next = t_max_z; axis = 2
314
+ segment_length = (t_next - last_t) * meshsize
315
+ if segment_length < 0.0:
316
+ segment_length = 0.0
317
+ if is_tree[i, j, k]:
318
+ trans = np.exp(-tree_k * tree_lad * segment_length)
319
+ cumulative_transmittance *= trans
320
+ if cumulative_transmittance < 1e-2:
321
+ return True, cumulative_transmittance
322
+ if (not is_allowed[i, j, k]) and (not is_tree[i, j, k]):
323
+ return True, cumulative_transmittance
324
+ last_t = t_next
325
+ if axis == 0:
326
+ t_max_x += t_delta_x; i += step_x
327
+ elif axis == 1:
328
+ t_max_y += t_delta_y; j += step_y
329
+ else:
330
+ t_max_z += t_delta_z; k += step_z
331
+ return False, cumulative_transmittance
332
+
333
+
334
+ @njit(parallel=True, cache=True, fastmath=True)
335
+ def _compute_vi_map_generic_fast(voxel_data, ray_directions, view_height_voxel, meshsize, tree_k, tree_lad, is_tree, is_target, is_allowed, is_blocker_inc, inclusion_mode, trees_in_targets):
336
+ nx, ny, nz = voxel_data.shape
337
+ vi_map = np.full((nx, ny), np.nan)
338
+ obs_base_z = _precompute_observer_base_z(voxel_data)
339
+ for x in prange(nx):
340
+ for y in range(ny):
341
+ base_z = obs_base_z[x, y]
342
+ if base_z < 0:
343
+ vi_map[x, y] = np.nan
344
+ continue
345
+ below = voxel_data[x, y, base_z]
346
+ if (below == 7) or (below == 8) or (below == 9) or (below < 0):
347
+ vi_map[x, y] = np.nan
348
+ continue
349
+ oz = base_z + 1 + view_height_voxel
350
+ obs = np.array([x, y, oz], dtype=np.float64)
351
+ visibility_sum = 0.0
352
+ n_rays = ray_directions.shape[0]
353
+ for r in range(n_rays):
354
+ direction = ray_directions[r]
355
+ if inclusion_mode:
356
+ hit, value = _trace_ray_inclusion_masks(is_tree, is_target, is_blocker_inc, obs, direction, meshsize, tree_k, tree_lad)
357
+ if hit:
358
+ if trees_in_targets:
359
+ contrib = 1.0 - max(0.0, min(1.0, value))
360
+ visibility_sum += contrib
361
+ else:
362
+ visibility_sum += 1.0
363
+ else:
364
+ hit, value = _trace_ray_exclusion_masks(is_tree, is_allowed, obs, direction, meshsize, tree_k, tree_lad)
365
+ if not hit:
366
+ visibility_sum += value
367
+ vi_map[x, y] = visibility_sum / n_rays
368
+ return np.flipud(vi_map)
369
+
370
+
371
+ @njit(cache=True, fastmath=True)
372
+ def _precompute_observer_base_z(voxel_data):
373
+ nx, ny, nz = voxel_data.shape
374
+ out = np.empty((nx, ny), dtype=np.int32)
375
+ for x in range(nx):
376
+ for y in range(ny):
377
+ found = False
378
+ for z in range(1, nz):
379
+ v_above = voxel_data[x, y, z]
380
+ v_base = voxel_data[x, y, z - 1]
381
+ if (v_above == 0 or v_above == -2) and not (v_base == 0 or v_base == -2):
382
+ out[x, y] = z - 1
383
+ found = True
384
+ break
385
+ if not found:
386
+ out[x, y] = -1
387
+ return out
388
+
389
+
390
+ @njit(cache=True, fastmath=True, nogil=True)
391
+ def _trace_ray(vox_is_tree, vox_is_opaque, origin, target, att, att_cutoff):
392
+ nx, ny, nz = vox_is_opaque.shape
393
+ x0, y0, z0 = origin[0], origin[1], origin[2]
394
+ x1, y1, z1 = target[0], target[1], target[2]
395
+ dx = x1 - x0
396
+ dy = y1 - y0
397
+ dz = z1 - z0
398
+ length = (dx*dx + dy*dy + dz*dz) ** 0.5
399
+ if length == 0.0:
400
+ return True
401
+ inv_len = 1.0 / length
402
+ dx *= inv_len; dy *= inv_len; dz *= inv_len
403
+ x = x0 + 0.5
404
+ y = y0 + 0.5
405
+ z = z0 + 0.5
406
+ i = int(x0); j = int(y0); k = int(z0)
407
+ step_x = 1 if dx >= 0.0 else -1
408
+ step_y = 1 if dy >= 0.0 else -1
409
+ step_z = 1 if dz >= 0.0 else -1
410
+ BIG = 1e30
411
+ if dx != 0.0:
412
+ t_max_x = (((i + (1 if step_x > 0 else 0)) - x) / dx)
413
+ t_delta_x = abs(1.0 / dx)
414
+ else:
415
+ t_max_x = BIG; t_delta_x = BIG
416
+ if dy != 0.0:
417
+ t_max_y = (((j + (1 if step_y > 0 else 0)) - y) / dy)
418
+ t_delta_y = abs(1.0 / dy)
419
+ else:
420
+ t_max_y = BIG; t_delta_y = BIG
421
+ if dz != 0.0:
422
+ t_max_z = (((k + (1 if step_z > 0 else 0)) - z) / dz)
423
+ t_delta_z = abs(1.0 / dz)
424
+ else:
425
+ t_max_z = BIG; t_delta_z = BIG
426
+ T = 1.0
427
+ ti = int(x1); tj = int(y1); tk = int(z1)
428
+ while True:
429
+ if (i < 0) or (i >= nx) or (j < 0) or (j >= ny) or (k < 0) or (k >= nz):
430
+ return False
431
+ if vox_is_opaque[i, j, k]:
432
+ return False
433
+ if vox_is_tree[i, j, k]:
434
+ T *= att
435
+ if T < att_cutoff:
436
+ return False
437
+ if (i == ti) and (j == tj) and (k == tk):
438
+ return True
439
+ if t_max_x < t_max_y:
440
+ if t_max_x < t_max_z:
441
+ t_max_x += t_delta_x; i += step_x
442
+ else:
443
+ t_max_z += t_delta_z; k += step_z
444
+ else:
445
+ if t_max_y < t_max_z:
446
+ t_max_y += t_delta_y; j += step_y
447
+ else:
448
+ t_max_z += t_delta_z; k += step_z
449
+
450
+
@@ -0,0 +1,43 @@
1
+ """
2
+ Solar Irradiance Simulation Package
3
+
4
+ Public API exports for the refactored solar simulator. The implementation
5
+ is decomposed into focused stages:
6
+ 1) kernels.py - Low-level kernels for visibility/irradiance
7
+ 2) radiation.py - Physics: convert geometry to irradiance
8
+ 3) temporal.py - Time-series integration and solar position
9
+ 4) integration.py- High-level workflows and I/O
10
+ """
11
+
12
+ # Stage 1: Kernels / Solar position
13
+ from .kernels import ( # noqa: F401
14
+ compute_direct_solar_irradiance_map_binary,
15
+ )
16
+ from .temporal import ( # noqa: F401
17
+ get_solar_positions_astral,
18
+ )
19
+
20
+ # Stage 2: Radiation
21
+ from .radiation import ( # noqa: F401
22
+ get_direct_solar_irradiance_map,
23
+ get_diffuse_solar_irradiance_map,
24
+ get_global_solar_irradiance_map,
25
+ compute_solar_irradiance_for_all_faces,
26
+ get_building_solar_irradiance,
27
+ )
28
+
29
+ # Stage 3: Temporal
30
+ from .temporal import ( # noqa: F401
31
+ get_cumulative_global_solar_irradiance,
32
+ get_cumulative_building_solar_irradiance,
33
+ _configure_num_threads,
34
+ _auto_time_batch_size,
35
+ )
36
+
37
+ # Stage 4: Integration
38
+ from .integration import ( # noqa: F401
39
+ get_global_solar_irradiance_using_epw,
40
+ get_building_global_solar_irradiance_using_epw,
41
+ save_irradiance_mesh,
42
+ load_irradiance_mesh,
43
+ )