lsurf 1.0.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.
- lsurf/__init__.py +471 -0
- lsurf/analysis/__init__.py +107 -0
- lsurf/analysis/healpix_utils.py +418 -0
- lsurf/analysis/sphere_viz.py +1280 -0
- lsurf/cli/__init__.py +48 -0
- lsurf/cli/build.py +398 -0
- lsurf/cli/config_schema.py +318 -0
- lsurf/cli/gui_cmd.py +76 -0
- lsurf/cli/interactive.py +850 -0
- lsurf/cli/main.py +81 -0
- lsurf/cli/run.py +806 -0
- lsurf/detectors/__init__.py +266 -0
- lsurf/detectors/analysis.py +289 -0
- lsurf/detectors/base.py +284 -0
- lsurf/detectors/constant_size_rings.py +485 -0
- lsurf/detectors/directional.py +45 -0
- lsurf/detectors/extended/__init__.py +73 -0
- lsurf/detectors/extended/local_sphere.py +353 -0
- lsurf/detectors/extended/recording_sphere.py +368 -0
- lsurf/detectors/planar.py +45 -0
- lsurf/detectors/protocol.py +187 -0
- lsurf/detectors/recording_spheres.py +63 -0
- lsurf/detectors/results.py +1140 -0
- lsurf/detectors/small/__init__.py +79 -0
- lsurf/detectors/small/directional.py +330 -0
- lsurf/detectors/small/planar.py +401 -0
- lsurf/detectors/small/spherical.py +450 -0
- lsurf/detectors/spherical.py +45 -0
- lsurf/geometry/__init__.py +199 -0
- lsurf/geometry/builder.py +478 -0
- lsurf/geometry/cell.py +228 -0
- lsurf/geometry/cell_geometry.py +247 -0
- lsurf/geometry/detector_arrays.py +1785 -0
- lsurf/geometry/geometry.py +222 -0
- lsurf/geometry/surface_analysis.py +375 -0
- lsurf/geometry/validation.py +91 -0
- lsurf/gui/__init__.py +51 -0
- lsurf/gui/app.py +903 -0
- lsurf/gui/core/__init__.py +39 -0
- lsurf/gui/core/scene.py +343 -0
- lsurf/gui/core/simulation.py +264 -0
- lsurf/gui/renderers/__init__.py +40 -0
- lsurf/gui/renderers/ray_renderer.py +353 -0
- lsurf/gui/renderers/source_renderer.py +505 -0
- lsurf/gui/renderers/surface_renderer.py +477 -0
- lsurf/gui/views/__init__.py +48 -0
- lsurf/gui/views/config_editor.py +3199 -0
- lsurf/gui/views/properties.py +257 -0
- lsurf/gui/views/results.py +291 -0
- lsurf/gui/views/scene_tree.py +180 -0
- lsurf/gui/views/viewport_3d.py +555 -0
- lsurf/gui/views/visualizations.py +712 -0
- lsurf/materials/__init__.py +169 -0
- lsurf/materials/base/__init__.py +64 -0
- lsurf/materials/base/full_inhomogeneous.py +208 -0
- lsurf/materials/base/grid_inhomogeneous.py +319 -0
- lsurf/materials/base/homogeneous.py +342 -0
- lsurf/materials/base/material_field.py +527 -0
- lsurf/materials/base/simple_inhomogeneous.py +418 -0
- lsurf/materials/base/spectral_inhomogeneous.py +497 -0
- lsurf/materials/implementations/__init__.py +120 -0
- lsurf/materials/implementations/data/alpha_values_typical_atmosphere_updated.txt +24 -0
- lsurf/materials/implementations/duct_atmosphere.py +390 -0
- lsurf/materials/implementations/exponential_atmosphere.py +435 -0
- lsurf/materials/implementations/gaussian_lens.py +120 -0
- lsurf/materials/implementations/interpolated_data.py +123 -0
- lsurf/materials/implementations/layered_atmosphere.py +134 -0
- lsurf/materials/implementations/linear_gradient.py +109 -0
- lsurf/materials/implementations/linsley_atmosphere.py +764 -0
- lsurf/materials/implementations/standard_materials.py +126 -0
- lsurf/materials/implementations/turbulent_atmosphere.py +135 -0
- lsurf/materials/implementations/us_standard_atmosphere.py +149 -0
- lsurf/materials/utils/__init__.py +77 -0
- lsurf/materials/utils/constants.py +45 -0
- lsurf/materials/utils/device_functions.py +117 -0
- lsurf/materials/utils/dispersion.py +160 -0
- lsurf/materials/utils/factories.py +142 -0
- lsurf/propagation/__init__.py +91 -0
- lsurf/propagation/detector_gpu.py +67 -0
- lsurf/propagation/gpu_device_rays.py +294 -0
- lsurf/propagation/kernels/__init__.py +175 -0
- lsurf/propagation/kernels/absorption/__init__.py +61 -0
- lsurf/propagation/kernels/absorption/grid.py +240 -0
- lsurf/propagation/kernels/absorption/simple.py +232 -0
- lsurf/propagation/kernels/absorption/spectral.py +410 -0
- lsurf/propagation/kernels/detection/__init__.py +64 -0
- lsurf/propagation/kernels/detection/protocol.py +102 -0
- lsurf/propagation/kernels/detection/spherical.py +255 -0
- lsurf/propagation/kernels/device_functions.py +790 -0
- lsurf/propagation/kernels/fresnel/__init__.py +64 -0
- lsurf/propagation/kernels/fresnel/protocol.py +97 -0
- lsurf/propagation/kernels/fresnel/standard.py +258 -0
- lsurf/propagation/kernels/intersection/__init__.py +79 -0
- lsurf/propagation/kernels/intersection/annular_plane.py +207 -0
- lsurf/propagation/kernels/intersection/bounded_plane.py +205 -0
- lsurf/propagation/kernels/intersection/plane.py +166 -0
- lsurf/propagation/kernels/intersection/protocol.py +95 -0
- lsurf/propagation/kernels/intersection/signed_distance.py +742 -0
- lsurf/propagation/kernels/intersection/sphere.py +190 -0
- lsurf/propagation/kernels/propagation/__init__.py +85 -0
- lsurf/propagation/kernels/propagation/grid.py +527 -0
- lsurf/propagation/kernels/propagation/protocol.py +105 -0
- lsurf/propagation/kernels/propagation/simple.py +460 -0
- lsurf/propagation/kernels/propagation/spectral.py +875 -0
- lsurf/propagation/kernels/registry.py +331 -0
- lsurf/propagation/kernels/surface/__init__.py +72 -0
- lsurf/propagation/kernels/surface/bisection.py +232 -0
- lsurf/propagation/kernels/surface/detection.py +402 -0
- lsurf/propagation/kernels/surface/reduction.py +166 -0
- lsurf/propagation/propagator_protocol.py +222 -0
- lsurf/propagation/propagators/__init__.py +101 -0
- lsurf/propagation/propagators/detector_handler.py +354 -0
- lsurf/propagation/propagators/factory.py +200 -0
- lsurf/propagation/propagators/fresnel_handler.py +305 -0
- lsurf/propagation/propagators/gpu_gradient.py +566 -0
- lsurf/propagation/propagators/gpu_surface_propagator.py +707 -0
- lsurf/propagation/propagators/gradient.py +429 -0
- lsurf/propagation/propagators/intersection_handler.py +327 -0
- lsurf/propagation/propagators/material_propagator.py +398 -0
- lsurf/propagation/propagators/signed_distance_handler.py +522 -0
- lsurf/propagation/propagators/spectral_gpu_gradient.py +553 -0
- lsurf/propagation/propagators/surface_interaction.py +616 -0
- lsurf/propagation/propagators/surface_propagator.py +719 -0
- lsurf/py.typed +1 -0
- lsurf/simulation/__init__.py +70 -0
- lsurf/simulation/config.py +164 -0
- lsurf/simulation/orchestrator.py +462 -0
- lsurf/simulation/result.py +299 -0
- lsurf/simulation/simulation.py +262 -0
- lsurf/sources/__init__.py +128 -0
- lsurf/sources/base.py +264 -0
- lsurf/sources/collimated.py +252 -0
- lsurf/sources/custom.py +409 -0
- lsurf/sources/diverging.py +228 -0
- lsurf/sources/gaussian.py +272 -0
- lsurf/sources/parallel_from_positions.py +197 -0
- lsurf/sources/point.py +172 -0
- lsurf/sources/uniform_diverging.py +258 -0
- lsurf/surfaces/__init__.py +184 -0
- lsurf/surfaces/cpu/__init__.py +50 -0
- lsurf/surfaces/cpu/curved_wave.py +463 -0
- lsurf/surfaces/cpu/gerstner_wave.py +381 -0
- lsurf/surfaces/cpu/wave_params.py +118 -0
- lsurf/surfaces/gpu/__init__.py +72 -0
- lsurf/surfaces/gpu/annular_plane.py +453 -0
- lsurf/surfaces/gpu/bounded_plane.py +390 -0
- lsurf/surfaces/gpu/curved_wave.py +483 -0
- lsurf/surfaces/gpu/gerstner_wave.py +377 -0
- lsurf/surfaces/gpu/multi_curved_wave.py +520 -0
- lsurf/surfaces/gpu/plane.py +299 -0
- lsurf/surfaces/gpu/recording_sphere.py +587 -0
- lsurf/surfaces/gpu/sphere.py +311 -0
- lsurf/surfaces/protocol.py +336 -0
- lsurf/surfaces/registry.py +373 -0
- lsurf/utilities/__init__.py +175 -0
- lsurf/utilities/detector_analysis.py +814 -0
- lsurf/utilities/fresnel.py +628 -0
- lsurf/utilities/interactions.py +1215 -0
- lsurf/utilities/propagation.py +602 -0
- lsurf/utilities/ray_data.py +532 -0
- lsurf/utilities/recording_sphere.py +745 -0
- lsurf/utilities/time_spread.py +463 -0
- lsurf/visualization/__init__.py +329 -0
- lsurf/visualization/absorption_plots.py +334 -0
- lsurf/visualization/atmospheric_plots.py +754 -0
- lsurf/visualization/common.py +348 -0
- lsurf/visualization/detector_plots.py +1350 -0
- lsurf/visualization/detector_sphere_plots.py +1173 -0
- lsurf/visualization/fresnel_plots.py +1061 -0
- lsurf/visualization/ocean_simulation_plots.py +999 -0
- lsurf/visualization/polarization_plots.py +916 -0
- lsurf/visualization/raytracing_plots.py +1521 -0
- lsurf/visualization/ring_detector_plots.py +1867 -0
- lsurf/visualization/time_spread_plots.py +531 -0
- lsurf-1.0.0.dist-info/METADATA +381 -0
- lsurf-1.0.0.dist-info/RECORD +180 -0
- lsurf-1.0.0.dist-info/WHEEL +5 -0
- lsurf-1.0.0.dist-info/entry_points.txt +2 -0
- lsurf-1.0.0.dist-info/licenses/LICENSE +32 -0
- lsurf-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# The Clear BSD License
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2026 Tobias Heibges
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
|
7
|
+
# modification, are permitted (subject to the limitations in the disclaimer
|
|
8
|
+
# below) provided that the following conditions are met:
|
|
9
|
+
#
|
|
10
|
+
# * Redistributions of source code must retain the above copyright notice,
|
|
11
|
+
# this list of conditions and the following disclaimer.
|
|
12
|
+
#
|
|
13
|
+
# * Redistributions in binary form must reproduce the above copyright
|
|
14
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
15
|
+
# documentation and/or other materials provided with the distribution.
|
|
16
|
+
#
|
|
17
|
+
# * Neither the name of the copyright holder nor the names of its
|
|
18
|
+
# contributors may be used to endorse or promote products derived from this
|
|
19
|
+
# software without specific prior written permission.
|
|
20
|
+
#
|
|
21
|
+
# NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
|
|
22
|
+
# THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
23
|
+
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
24
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
25
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
26
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
27
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
28
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
29
|
+
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
30
|
+
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
GPU Device Rays - Unified GPU Ray Data Structure
|
|
36
|
+
|
|
37
|
+
Provides a single data class holding device arrays for ALL GPU operations.
|
|
38
|
+
Both material propagation kernels and surface detection kernels operate on
|
|
39
|
+
these same device arrays - no duplication.
|
|
40
|
+
|
|
41
|
+
This minimizes CPU-GPU transfers by keeping ray data GPU-resident throughout
|
|
42
|
+
the entire propagation loop.
|
|
43
|
+
|
|
44
|
+
Memory Layout
|
|
45
|
+
-------------
|
|
46
|
+
GPUDeviceRays contains:
|
|
47
|
+
- Core ray state (positions, directions, active, paths) - used by propagation
|
|
48
|
+
- Surface detection state (prev_positions, signed_dist, crossings) - used by detection
|
|
49
|
+
- Reduction output (tiny, single copy per step for loop termination)
|
|
50
|
+
|
|
51
|
+
Usage
|
|
52
|
+
-----
|
|
53
|
+
# One-time upload at start
|
|
54
|
+
gpu_rays = GPUDeviceRays.from_ray_batch(rays, num_surfaces)
|
|
55
|
+
|
|
56
|
+
# GPU-resident loop
|
|
57
|
+
for step in range(max_steps):
|
|
58
|
+
# Kernels operate on same device arrays
|
|
59
|
+
propagation_kernel[...](gpu_rays.d_positions, gpu_rays.d_directions, ...)
|
|
60
|
+
detection_kernel[...](gpu_rays.d_positions, gpu_rays.d_prev_signed_dist, ...)
|
|
61
|
+
|
|
62
|
+
# One-time download at end
|
|
63
|
+
gpu_rays.to_ray_batch(rays)
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
from dataclasses import dataclass
|
|
67
|
+
from typing import TYPE_CHECKING
|
|
68
|
+
|
|
69
|
+
import numpy as np
|
|
70
|
+
import numpy.typing as npt
|
|
71
|
+
|
|
72
|
+
# GPU support is optional
|
|
73
|
+
try:
|
|
74
|
+
from numba import cuda
|
|
75
|
+
|
|
76
|
+
HAS_CUDA = cuda.is_available()
|
|
77
|
+
except ImportError:
|
|
78
|
+
HAS_CUDA = False
|
|
79
|
+
|
|
80
|
+
class _FakeCuda:
|
|
81
|
+
@staticmethod
|
|
82
|
+
def is_available():
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def to_device(arr):
|
|
87
|
+
return arr
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def device_array(shape, dtype=np.float32):
|
|
91
|
+
return np.zeros(shape, dtype=dtype)
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def synchronize():
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
cuda = _FakeCuda() # type: ignore[assignment]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
if TYPE_CHECKING:
|
|
101
|
+
from ..utilities.ray_data import RayBatch
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@dataclass
|
|
105
|
+
class GPUDeviceRays:
|
|
106
|
+
"""
|
|
107
|
+
Unified GPU ray storage shared by propagation and surface detection.
|
|
108
|
+
|
|
109
|
+
Both GPUGradientPropagator kernels and surface detection kernels
|
|
110
|
+
operate on these same device arrays - no duplication.
|
|
111
|
+
|
|
112
|
+
Attributes
|
|
113
|
+
----------
|
|
114
|
+
d_positions : device array, shape (N, 3)
|
|
115
|
+
Ray positions (float32)
|
|
116
|
+
d_directions : device array, shape (N, 3)
|
|
117
|
+
Ray directions (float32)
|
|
118
|
+
d_active : device array, shape (N,)
|
|
119
|
+
Active mask (bool)
|
|
120
|
+
d_geo_path : device array, shape (N,)
|
|
121
|
+
Geometric path lengths (float32)
|
|
122
|
+
d_opt_path : device array, shape (N,)
|
|
123
|
+
Optical path lengths (float32)
|
|
124
|
+
d_acc_time : device array, shape (N,)
|
|
125
|
+
Accumulated time (float32)
|
|
126
|
+
d_wavelengths : device array, shape (N,)
|
|
127
|
+
Ray wavelengths (float32)
|
|
128
|
+
d_intensities : device array, shape (N,)
|
|
129
|
+
Ray intensities (float32)
|
|
130
|
+
d_optical_depth : device array, shape (N,)
|
|
131
|
+
Accumulated optical depth τ = ∫α·ds (float32)
|
|
132
|
+
d_prev_positions : device array, shape (N, 3)
|
|
133
|
+
Previous positions for bisection (float32)
|
|
134
|
+
d_prev_signed_dist : device array, shape (N, S)
|
|
135
|
+
Previous signed distances per surface (float32)
|
|
136
|
+
d_hit_surface_idx : device array, shape (N,)
|
|
137
|
+
Surface index for each hit (-1 = no hit) (int32)
|
|
138
|
+
d_hit_positions : device array, shape (N, 3)
|
|
139
|
+
Hit positions (float32)
|
|
140
|
+
d_crossing_mask : device array, shape (N,)
|
|
141
|
+
Rays that crossed a surface this step (bool)
|
|
142
|
+
d_reduction_result : device array, shape (2,)
|
|
143
|
+
[num_active, num_crossing] for loop termination (int32)
|
|
144
|
+
num_rays : int
|
|
145
|
+
Total number of rays
|
|
146
|
+
num_surfaces : int
|
|
147
|
+
Number of surfaces being tracked
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
d_positions: npt.NDArray
|
|
151
|
+
d_directions: npt.NDArray
|
|
152
|
+
d_active: npt.NDArray
|
|
153
|
+
d_geo_path: npt.NDArray
|
|
154
|
+
d_opt_path: npt.NDArray
|
|
155
|
+
d_acc_time: npt.NDArray
|
|
156
|
+
d_wavelengths: npt.NDArray
|
|
157
|
+
d_intensities: npt.NDArray
|
|
158
|
+
d_optical_depth: npt.NDArray
|
|
159
|
+
d_prev_positions: npt.NDArray
|
|
160
|
+
d_prev_signed_dist: npt.NDArray
|
|
161
|
+
d_hit_surface_idx: npt.NDArray
|
|
162
|
+
d_hit_positions: npt.NDArray
|
|
163
|
+
d_crossing_mask: npt.NDArray
|
|
164
|
+
d_reduction_result: npt.NDArray
|
|
165
|
+
num_rays: int
|
|
166
|
+
num_surfaces: int
|
|
167
|
+
|
|
168
|
+
@classmethod
|
|
169
|
+
def from_ray_batch(
|
|
170
|
+
cls,
|
|
171
|
+
rays: "RayBatch",
|
|
172
|
+
num_surfaces: int,
|
|
173
|
+
) -> "GPUDeviceRays":
|
|
174
|
+
"""
|
|
175
|
+
Upload RayBatch to GPU (one-time at start).
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
rays : RayBatch
|
|
180
|
+
Source ray batch to upload
|
|
181
|
+
num_surfaces : int
|
|
182
|
+
Number of surfaces to track for detection
|
|
183
|
+
|
|
184
|
+
Returns
|
|
185
|
+
-------
|
|
186
|
+
GPUDeviceRays
|
|
187
|
+
GPU-resident ray data
|
|
188
|
+
"""
|
|
189
|
+
n = rays.num_rays
|
|
190
|
+
|
|
191
|
+
# Initialize optical depth from rays if present, otherwise zeros
|
|
192
|
+
if rays.optical_depth is not None:
|
|
193
|
+
optical_depth_arr = cuda.to_device(rays.optical_depth.astype(np.float32))
|
|
194
|
+
else:
|
|
195
|
+
optical_depth_arr = cuda.to_device(np.zeros(n, dtype=np.float32))
|
|
196
|
+
|
|
197
|
+
return cls(
|
|
198
|
+
d_positions=cuda.to_device(rays.positions.astype(np.float32)),
|
|
199
|
+
d_directions=cuda.to_device(rays.directions.astype(np.float32)),
|
|
200
|
+
d_active=cuda.to_device(rays.active.astype(np.bool_)),
|
|
201
|
+
d_geo_path=cuda.to_device(rays.geometric_path_lengths.astype(np.float32)),
|
|
202
|
+
d_opt_path=cuda.to_device(rays.optical_path_lengths.astype(np.float32)),
|
|
203
|
+
d_acc_time=cuda.to_device(rays.accumulated_time.astype(np.float32)),
|
|
204
|
+
d_wavelengths=cuda.to_device(rays.wavelengths.astype(np.float32)),
|
|
205
|
+
d_intensities=cuda.to_device(rays.intensities.astype(np.float32)),
|
|
206
|
+
d_optical_depth=optical_depth_arr,
|
|
207
|
+
d_prev_positions=cuda.device_array((n, 3), dtype=np.float32),
|
|
208
|
+
d_prev_signed_dist=cuda.device_array((n, num_surfaces), dtype=np.float32),
|
|
209
|
+
d_hit_surface_idx=cuda.to_device(np.full(n, -1, dtype=np.int32)),
|
|
210
|
+
d_hit_positions=cuda.device_array((n, 3), dtype=np.float32),
|
|
211
|
+
d_crossing_mask=cuda.device_array(n, dtype=np.bool_),
|
|
212
|
+
d_reduction_result=cuda.device_array(2, dtype=np.int32),
|
|
213
|
+
num_rays=n,
|
|
214
|
+
num_surfaces=num_surfaces,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
def to_ray_batch(self, rays: "RayBatch") -> None:
|
|
218
|
+
"""
|
|
219
|
+
Download final state back to RayBatch (one-time at end).
|
|
220
|
+
|
|
221
|
+
Parameters
|
|
222
|
+
----------
|
|
223
|
+
rays : RayBatch
|
|
224
|
+
Target ray batch to update in-place
|
|
225
|
+
"""
|
|
226
|
+
if HAS_CUDA:
|
|
227
|
+
cuda.synchronize()
|
|
228
|
+
|
|
229
|
+
rays.positions[:] = self.d_positions.copy_to_host()
|
|
230
|
+
rays.directions[:] = self.d_directions.copy_to_host()
|
|
231
|
+
rays.active[:] = self.d_active.copy_to_host()
|
|
232
|
+
rays.geometric_path_lengths[:] = self.d_geo_path.copy_to_host()
|
|
233
|
+
rays.optical_path_lengths[:] = self.d_opt_path.copy_to_host()
|
|
234
|
+
rays.accumulated_time[:] = self.d_acc_time.copy_to_host()
|
|
235
|
+
rays.intensities[:] = self.d_intensities.copy_to_host()
|
|
236
|
+
if rays.optical_depth is not None:
|
|
237
|
+
rays.optical_depth[:] = self.d_optical_depth.copy_to_host()
|
|
238
|
+
|
|
239
|
+
def get_hit_data(self) -> tuple[npt.NDArray, npt.NDArray, npt.NDArray]:
|
|
240
|
+
"""
|
|
241
|
+
Download hit data from GPU.
|
|
242
|
+
|
|
243
|
+
Returns
|
|
244
|
+
-------
|
|
245
|
+
hit_surface_idx : ndarray, shape (N,)
|
|
246
|
+
Surface index for each hit (-1 = no hit)
|
|
247
|
+
hit_positions : ndarray, shape (N, 3)
|
|
248
|
+
Hit positions
|
|
249
|
+
hit_mask : ndarray, shape (N,)
|
|
250
|
+
True for rays that hit any surface
|
|
251
|
+
"""
|
|
252
|
+
if HAS_CUDA:
|
|
253
|
+
cuda.synchronize()
|
|
254
|
+
|
|
255
|
+
hit_surface_idx = self.d_hit_surface_idx.copy_to_host()
|
|
256
|
+
hit_positions = self.d_hit_positions.copy_to_host()
|
|
257
|
+
hit_mask = hit_surface_idx >= 0
|
|
258
|
+
|
|
259
|
+
return hit_surface_idx, hit_positions, hit_mask
|
|
260
|
+
|
|
261
|
+
def reset_crossing_state(self) -> None:
|
|
262
|
+
"""
|
|
263
|
+
Reset crossing detection state for next iteration.
|
|
264
|
+
|
|
265
|
+
Called at the start of each propagation step to clear
|
|
266
|
+
the crossing mask and reset reduction counters.
|
|
267
|
+
"""
|
|
268
|
+
# Reset crossing mask to False
|
|
269
|
+
zeros_bool = np.zeros(self.num_rays, dtype=np.bool_)
|
|
270
|
+
self.d_crossing_mask.copy_to_device(zeros_bool)
|
|
271
|
+
|
|
272
|
+
# Reset reduction result
|
|
273
|
+
zeros_int = np.zeros(2, dtype=np.int32)
|
|
274
|
+
self.d_reduction_result.copy_to_device(zeros_int)
|
|
275
|
+
|
|
276
|
+
def get_reduction_result(self) -> tuple[int, int]:
|
|
277
|
+
"""
|
|
278
|
+
Download reduction result (small transfer).
|
|
279
|
+
|
|
280
|
+
Returns
|
|
281
|
+
-------
|
|
282
|
+
num_active : int
|
|
283
|
+
Number of active rays
|
|
284
|
+
num_crossing : int
|
|
285
|
+
Number of rays that crossed a surface
|
|
286
|
+
"""
|
|
287
|
+
if HAS_CUDA:
|
|
288
|
+
cuda.synchronize()
|
|
289
|
+
|
|
290
|
+
result = self.d_reduction_result.copy_to_host()
|
|
291
|
+
return int(result[0]), int(result[1])
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
__all__ = ["GPUDeviceRays", "HAS_CUDA"]
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# The Clear BSD License
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2026 Tobias Heibges
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
|
7
|
+
# modification, are permitted (subject to the limitations in the disclaimer
|
|
8
|
+
# below) provided that the following conditions are met:
|
|
9
|
+
#
|
|
10
|
+
# * Redistributions of source code must retain the above copyright notice,
|
|
11
|
+
# this list of conditions and the following disclaimer.
|
|
12
|
+
#
|
|
13
|
+
# * Redistributions in binary form must reproduce the above copyright
|
|
14
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
15
|
+
# documentation and/or other materials provided with the distribution.
|
|
16
|
+
#
|
|
17
|
+
# * Neither the name of the copyright holder nor the names of its
|
|
18
|
+
# contributors may be used to endorse or promote products derived from this
|
|
19
|
+
# software without specific prior written permission.
|
|
20
|
+
#
|
|
21
|
+
# NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
|
|
22
|
+
# THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
23
|
+
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
24
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
25
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
26
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
27
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
28
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
29
|
+
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
30
|
+
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
GPU Kernels for Ray Tracing
|
|
36
|
+
|
|
37
|
+
This package contains all CUDA kernels organized by function:
|
|
38
|
+
|
|
39
|
+
- propagation/: Material propagation kernels (simple, spectral, grid)
|
|
40
|
+
- intersection/: Surface intersection kernels (plane, sphere, signed distance)
|
|
41
|
+
- fresnel/: Fresnel reflection/refraction kernels
|
|
42
|
+
- detection/: Ray detection kernels (spherical)
|
|
43
|
+
- device_functions: Shared device functions (integration, dispersion)
|
|
44
|
+
- registry: Kernel ID enums and registration system
|
|
45
|
+
|
|
46
|
+
All kernels support optional CUDA - they gracefully fall back to
|
|
47
|
+
no-op decorators when numba.cuda is not available.
|
|
48
|
+
|
|
49
|
+
Kernel Types
|
|
50
|
+
------------
|
|
51
|
+
- PropagationKernelID: Material propagation (SIMPLE_*, SPECTRAL_*, GRID_*)
|
|
52
|
+
- IntersectionKernelID: Surface intersection (PLANE_*, SPHERE_*, SIGNED_DISTANCE_*, SURFACE_NORMAL_*)
|
|
53
|
+
- DetectionKernelID: Ray detection (SPHERICAL_*, PLANAR_*)
|
|
54
|
+
- FresnelKernelID: Fresnel equations (STANDARD, POLARIZED)
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
# Re-export kernel registry (enums and registration)
|
|
58
|
+
from .registry import (
|
|
59
|
+
PropagationKernelID,
|
|
60
|
+
IntersectionKernelID,
|
|
61
|
+
DetectionKernelID,
|
|
62
|
+
FresnelKernelID,
|
|
63
|
+
PropagatorID,
|
|
64
|
+
KernelID,
|
|
65
|
+
register_kernel,
|
|
66
|
+
get_kernel,
|
|
67
|
+
get_registered_kernels,
|
|
68
|
+
list_kernels,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Re-export protocols
|
|
72
|
+
from .propagation.protocol import PropagationKernelProtocol
|
|
73
|
+
from .intersection.protocol import IntersectionKernelProtocol
|
|
74
|
+
from .fresnel.protocol import FresnelKernelProtocol
|
|
75
|
+
from .detection.protocol import DetectionKernelProtocol
|
|
76
|
+
|
|
77
|
+
# Re-export device functions
|
|
78
|
+
from .device_functions import (
|
|
79
|
+
device_euler_step,
|
|
80
|
+
device_rk4_step,
|
|
81
|
+
device_adaptive_step_size,
|
|
82
|
+
device_sellmeier_equation,
|
|
83
|
+
device_cauchy_equation,
|
|
84
|
+
euler_step,
|
|
85
|
+
rk4_step,
|
|
86
|
+
compute_adaptive_step_size,
|
|
87
|
+
normalize_directions,
|
|
88
|
+
euler_step_batch,
|
|
89
|
+
rk4_step_batch,
|
|
90
|
+
HAS_CUDA,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Re-export propagation kernels
|
|
94
|
+
from .propagation import (
|
|
95
|
+
_kernel_simple_inhomogeneous_euler,
|
|
96
|
+
_kernel_simple_inhomogeneous_rk4,
|
|
97
|
+
_kernel_spectral_inhomogeneous_euler,
|
|
98
|
+
_kernel_spectral_inhomogeneous_rk4,
|
|
99
|
+
_kernel_spectral_inhomogeneous_euler_perray,
|
|
100
|
+
_kernel_spectral_inhomogeneous_rk4_perray,
|
|
101
|
+
_kernel_grid_inhomogeneous_euler,
|
|
102
|
+
_kernel_grid_inhomogeneous_rk4,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Re-export intersection kernels (pure CUDA only)
|
|
106
|
+
from .intersection import (
|
|
107
|
+
kernel_plane_intersect,
|
|
108
|
+
kernel_sphere_intersect,
|
|
109
|
+
kernel_signed_distance,
|
|
110
|
+
kernel_surface_normal,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Re-export fresnel kernels (pure CUDA only)
|
|
114
|
+
from .fresnel import (
|
|
115
|
+
kernel_fresnel_standard,
|
|
116
|
+
kernel_fresnel_polarized,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Re-export detection kernels (pure CUDA only)
|
|
120
|
+
from .detection import (
|
|
121
|
+
kernel_spherical_detect_single,
|
|
122
|
+
kernel_spherical_detect_multi,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
__all__ = [
|
|
126
|
+
# Kernel registry
|
|
127
|
+
"PropagationKernelID",
|
|
128
|
+
"IntersectionKernelID",
|
|
129
|
+
"DetectionKernelID",
|
|
130
|
+
"FresnelKernelID",
|
|
131
|
+
"PropagatorID",
|
|
132
|
+
"KernelID",
|
|
133
|
+
"register_kernel",
|
|
134
|
+
"get_kernel",
|
|
135
|
+
"get_registered_kernels",
|
|
136
|
+
"list_kernels",
|
|
137
|
+
# Protocols
|
|
138
|
+
"PropagationKernelProtocol",
|
|
139
|
+
"IntersectionKernelProtocol",
|
|
140
|
+
"FresnelKernelProtocol",
|
|
141
|
+
"DetectionKernelProtocol",
|
|
142
|
+
# Device functions
|
|
143
|
+
"device_euler_step",
|
|
144
|
+
"device_rk4_step",
|
|
145
|
+
"device_adaptive_step_size",
|
|
146
|
+
"device_sellmeier_equation",
|
|
147
|
+
"device_cauchy_equation",
|
|
148
|
+
"euler_step",
|
|
149
|
+
"rk4_step",
|
|
150
|
+
"compute_adaptive_step_size",
|
|
151
|
+
"normalize_directions",
|
|
152
|
+
"euler_step_batch",
|
|
153
|
+
"rk4_step_batch",
|
|
154
|
+
"HAS_CUDA",
|
|
155
|
+
# Propagation kernels
|
|
156
|
+
"_kernel_simple_inhomogeneous_euler",
|
|
157
|
+
"_kernel_simple_inhomogeneous_rk4",
|
|
158
|
+
"_kernel_spectral_inhomogeneous_euler",
|
|
159
|
+
"_kernel_spectral_inhomogeneous_rk4",
|
|
160
|
+
"_kernel_spectral_inhomogeneous_euler_perray",
|
|
161
|
+
"_kernel_spectral_inhomogeneous_rk4_perray",
|
|
162
|
+
"_kernel_grid_inhomogeneous_euler",
|
|
163
|
+
"_kernel_grid_inhomogeneous_rk4",
|
|
164
|
+
# Intersection kernels (pure CUDA only)
|
|
165
|
+
"kernel_plane_intersect",
|
|
166
|
+
"kernel_sphere_intersect",
|
|
167
|
+
"kernel_signed_distance",
|
|
168
|
+
"kernel_surface_normal",
|
|
169
|
+
# Fresnel kernels (pure CUDA only)
|
|
170
|
+
"kernel_fresnel_standard",
|
|
171
|
+
"kernel_fresnel_polarized",
|
|
172
|
+
# Detection kernels (pure CUDA only)
|
|
173
|
+
"kernel_spherical_detect_single",
|
|
174
|
+
"kernel_spherical_detect_multi",
|
|
175
|
+
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# The Clear BSD License
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2026 Tobias Heibges
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
|
7
|
+
# modification, are permitted (subject to the limitations in the disclaimer
|
|
8
|
+
# below) provided that the following conditions are met:
|
|
9
|
+
#
|
|
10
|
+
# * Redistributions of source code must retain the above copyright notice,
|
|
11
|
+
# this list of conditions and the following disclaimer.
|
|
12
|
+
#
|
|
13
|
+
# * Redistributions in binary form must reproduce the above copyright
|
|
14
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
15
|
+
# documentation and/or other materials provided with the distribution.
|
|
16
|
+
#
|
|
17
|
+
# * Neither the name of the copyright holder nor the names of its
|
|
18
|
+
# contributors may be used to endorse or promote products derived from this
|
|
19
|
+
# software without specific prior written permission.
|
|
20
|
+
#
|
|
21
|
+
# NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
|
|
22
|
+
# THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
23
|
+
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
24
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
25
|
+
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
26
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
27
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
28
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
29
|
+
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
30
|
+
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
Absorption Kernels
|
|
36
|
+
|
|
37
|
+
GPU kernels for applying Beer-Lambert absorption after propagation.
|
|
38
|
+
These kernels are separate from propagation kernels to maintain modularity.
|
|
39
|
+
|
|
40
|
+
The kernels update:
|
|
41
|
+
- intensities: I *= exp(-α·ds) for each step
|
|
42
|
+
- optical_depth: τ += α·ds (accumulated optical depth)
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
from .simple import (
|
|
46
|
+
_kernel_absorption_simple,
|
|
47
|
+
)
|
|
48
|
+
from .spectral import (
|
|
49
|
+
_kernel_absorption_spectral,
|
|
50
|
+
_kernel_absorption_spectral_perray,
|
|
51
|
+
)
|
|
52
|
+
from .grid import (
|
|
53
|
+
_kernel_absorption_grid,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
__all__ = [
|
|
57
|
+
"_kernel_absorption_simple",
|
|
58
|
+
"_kernel_absorption_spectral",
|
|
59
|
+
"_kernel_absorption_spectral_perray",
|
|
60
|
+
"_kernel_absorption_grid",
|
|
61
|
+
]
|