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.
Files changed (180) hide show
  1. lsurf/__init__.py +471 -0
  2. lsurf/analysis/__init__.py +107 -0
  3. lsurf/analysis/healpix_utils.py +418 -0
  4. lsurf/analysis/sphere_viz.py +1280 -0
  5. lsurf/cli/__init__.py +48 -0
  6. lsurf/cli/build.py +398 -0
  7. lsurf/cli/config_schema.py +318 -0
  8. lsurf/cli/gui_cmd.py +76 -0
  9. lsurf/cli/interactive.py +850 -0
  10. lsurf/cli/main.py +81 -0
  11. lsurf/cli/run.py +806 -0
  12. lsurf/detectors/__init__.py +266 -0
  13. lsurf/detectors/analysis.py +289 -0
  14. lsurf/detectors/base.py +284 -0
  15. lsurf/detectors/constant_size_rings.py +485 -0
  16. lsurf/detectors/directional.py +45 -0
  17. lsurf/detectors/extended/__init__.py +73 -0
  18. lsurf/detectors/extended/local_sphere.py +353 -0
  19. lsurf/detectors/extended/recording_sphere.py +368 -0
  20. lsurf/detectors/planar.py +45 -0
  21. lsurf/detectors/protocol.py +187 -0
  22. lsurf/detectors/recording_spheres.py +63 -0
  23. lsurf/detectors/results.py +1140 -0
  24. lsurf/detectors/small/__init__.py +79 -0
  25. lsurf/detectors/small/directional.py +330 -0
  26. lsurf/detectors/small/planar.py +401 -0
  27. lsurf/detectors/small/spherical.py +450 -0
  28. lsurf/detectors/spherical.py +45 -0
  29. lsurf/geometry/__init__.py +199 -0
  30. lsurf/geometry/builder.py +478 -0
  31. lsurf/geometry/cell.py +228 -0
  32. lsurf/geometry/cell_geometry.py +247 -0
  33. lsurf/geometry/detector_arrays.py +1785 -0
  34. lsurf/geometry/geometry.py +222 -0
  35. lsurf/geometry/surface_analysis.py +375 -0
  36. lsurf/geometry/validation.py +91 -0
  37. lsurf/gui/__init__.py +51 -0
  38. lsurf/gui/app.py +903 -0
  39. lsurf/gui/core/__init__.py +39 -0
  40. lsurf/gui/core/scene.py +343 -0
  41. lsurf/gui/core/simulation.py +264 -0
  42. lsurf/gui/renderers/__init__.py +40 -0
  43. lsurf/gui/renderers/ray_renderer.py +353 -0
  44. lsurf/gui/renderers/source_renderer.py +505 -0
  45. lsurf/gui/renderers/surface_renderer.py +477 -0
  46. lsurf/gui/views/__init__.py +48 -0
  47. lsurf/gui/views/config_editor.py +3199 -0
  48. lsurf/gui/views/properties.py +257 -0
  49. lsurf/gui/views/results.py +291 -0
  50. lsurf/gui/views/scene_tree.py +180 -0
  51. lsurf/gui/views/viewport_3d.py +555 -0
  52. lsurf/gui/views/visualizations.py +712 -0
  53. lsurf/materials/__init__.py +169 -0
  54. lsurf/materials/base/__init__.py +64 -0
  55. lsurf/materials/base/full_inhomogeneous.py +208 -0
  56. lsurf/materials/base/grid_inhomogeneous.py +319 -0
  57. lsurf/materials/base/homogeneous.py +342 -0
  58. lsurf/materials/base/material_field.py +527 -0
  59. lsurf/materials/base/simple_inhomogeneous.py +418 -0
  60. lsurf/materials/base/spectral_inhomogeneous.py +497 -0
  61. lsurf/materials/implementations/__init__.py +120 -0
  62. lsurf/materials/implementations/data/alpha_values_typical_atmosphere_updated.txt +24 -0
  63. lsurf/materials/implementations/duct_atmosphere.py +390 -0
  64. lsurf/materials/implementations/exponential_atmosphere.py +435 -0
  65. lsurf/materials/implementations/gaussian_lens.py +120 -0
  66. lsurf/materials/implementations/interpolated_data.py +123 -0
  67. lsurf/materials/implementations/layered_atmosphere.py +134 -0
  68. lsurf/materials/implementations/linear_gradient.py +109 -0
  69. lsurf/materials/implementations/linsley_atmosphere.py +764 -0
  70. lsurf/materials/implementations/standard_materials.py +126 -0
  71. lsurf/materials/implementations/turbulent_atmosphere.py +135 -0
  72. lsurf/materials/implementations/us_standard_atmosphere.py +149 -0
  73. lsurf/materials/utils/__init__.py +77 -0
  74. lsurf/materials/utils/constants.py +45 -0
  75. lsurf/materials/utils/device_functions.py +117 -0
  76. lsurf/materials/utils/dispersion.py +160 -0
  77. lsurf/materials/utils/factories.py +142 -0
  78. lsurf/propagation/__init__.py +91 -0
  79. lsurf/propagation/detector_gpu.py +67 -0
  80. lsurf/propagation/gpu_device_rays.py +294 -0
  81. lsurf/propagation/kernels/__init__.py +175 -0
  82. lsurf/propagation/kernels/absorption/__init__.py +61 -0
  83. lsurf/propagation/kernels/absorption/grid.py +240 -0
  84. lsurf/propagation/kernels/absorption/simple.py +232 -0
  85. lsurf/propagation/kernels/absorption/spectral.py +410 -0
  86. lsurf/propagation/kernels/detection/__init__.py +64 -0
  87. lsurf/propagation/kernels/detection/protocol.py +102 -0
  88. lsurf/propagation/kernels/detection/spherical.py +255 -0
  89. lsurf/propagation/kernels/device_functions.py +790 -0
  90. lsurf/propagation/kernels/fresnel/__init__.py +64 -0
  91. lsurf/propagation/kernels/fresnel/protocol.py +97 -0
  92. lsurf/propagation/kernels/fresnel/standard.py +258 -0
  93. lsurf/propagation/kernels/intersection/__init__.py +79 -0
  94. lsurf/propagation/kernels/intersection/annular_plane.py +207 -0
  95. lsurf/propagation/kernels/intersection/bounded_plane.py +205 -0
  96. lsurf/propagation/kernels/intersection/plane.py +166 -0
  97. lsurf/propagation/kernels/intersection/protocol.py +95 -0
  98. lsurf/propagation/kernels/intersection/signed_distance.py +742 -0
  99. lsurf/propagation/kernels/intersection/sphere.py +190 -0
  100. lsurf/propagation/kernels/propagation/__init__.py +85 -0
  101. lsurf/propagation/kernels/propagation/grid.py +527 -0
  102. lsurf/propagation/kernels/propagation/protocol.py +105 -0
  103. lsurf/propagation/kernels/propagation/simple.py +460 -0
  104. lsurf/propagation/kernels/propagation/spectral.py +875 -0
  105. lsurf/propagation/kernels/registry.py +331 -0
  106. lsurf/propagation/kernels/surface/__init__.py +72 -0
  107. lsurf/propagation/kernels/surface/bisection.py +232 -0
  108. lsurf/propagation/kernels/surface/detection.py +402 -0
  109. lsurf/propagation/kernels/surface/reduction.py +166 -0
  110. lsurf/propagation/propagator_protocol.py +222 -0
  111. lsurf/propagation/propagators/__init__.py +101 -0
  112. lsurf/propagation/propagators/detector_handler.py +354 -0
  113. lsurf/propagation/propagators/factory.py +200 -0
  114. lsurf/propagation/propagators/fresnel_handler.py +305 -0
  115. lsurf/propagation/propagators/gpu_gradient.py +566 -0
  116. lsurf/propagation/propagators/gpu_surface_propagator.py +707 -0
  117. lsurf/propagation/propagators/gradient.py +429 -0
  118. lsurf/propagation/propagators/intersection_handler.py +327 -0
  119. lsurf/propagation/propagators/material_propagator.py +398 -0
  120. lsurf/propagation/propagators/signed_distance_handler.py +522 -0
  121. lsurf/propagation/propagators/spectral_gpu_gradient.py +553 -0
  122. lsurf/propagation/propagators/surface_interaction.py +616 -0
  123. lsurf/propagation/propagators/surface_propagator.py +719 -0
  124. lsurf/py.typed +1 -0
  125. lsurf/simulation/__init__.py +70 -0
  126. lsurf/simulation/config.py +164 -0
  127. lsurf/simulation/orchestrator.py +462 -0
  128. lsurf/simulation/result.py +299 -0
  129. lsurf/simulation/simulation.py +262 -0
  130. lsurf/sources/__init__.py +128 -0
  131. lsurf/sources/base.py +264 -0
  132. lsurf/sources/collimated.py +252 -0
  133. lsurf/sources/custom.py +409 -0
  134. lsurf/sources/diverging.py +228 -0
  135. lsurf/sources/gaussian.py +272 -0
  136. lsurf/sources/parallel_from_positions.py +197 -0
  137. lsurf/sources/point.py +172 -0
  138. lsurf/sources/uniform_diverging.py +258 -0
  139. lsurf/surfaces/__init__.py +184 -0
  140. lsurf/surfaces/cpu/__init__.py +50 -0
  141. lsurf/surfaces/cpu/curved_wave.py +463 -0
  142. lsurf/surfaces/cpu/gerstner_wave.py +381 -0
  143. lsurf/surfaces/cpu/wave_params.py +118 -0
  144. lsurf/surfaces/gpu/__init__.py +72 -0
  145. lsurf/surfaces/gpu/annular_plane.py +453 -0
  146. lsurf/surfaces/gpu/bounded_plane.py +390 -0
  147. lsurf/surfaces/gpu/curved_wave.py +483 -0
  148. lsurf/surfaces/gpu/gerstner_wave.py +377 -0
  149. lsurf/surfaces/gpu/multi_curved_wave.py +520 -0
  150. lsurf/surfaces/gpu/plane.py +299 -0
  151. lsurf/surfaces/gpu/recording_sphere.py +587 -0
  152. lsurf/surfaces/gpu/sphere.py +311 -0
  153. lsurf/surfaces/protocol.py +336 -0
  154. lsurf/surfaces/registry.py +373 -0
  155. lsurf/utilities/__init__.py +175 -0
  156. lsurf/utilities/detector_analysis.py +814 -0
  157. lsurf/utilities/fresnel.py +628 -0
  158. lsurf/utilities/interactions.py +1215 -0
  159. lsurf/utilities/propagation.py +602 -0
  160. lsurf/utilities/ray_data.py +532 -0
  161. lsurf/utilities/recording_sphere.py +745 -0
  162. lsurf/utilities/time_spread.py +463 -0
  163. lsurf/visualization/__init__.py +329 -0
  164. lsurf/visualization/absorption_plots.py +334 -0
  165. lsurf/visualization/atmospheric_plots.py +754 -0
  166. lsurf/visualization/common.py +348 -0
  167. lsurf/visualization/detector_plots.py +1350 -0
  168. lsurf/visualization/detector_sphere_plots.py +1173 -0
  169. lsurf/visualization/fresnel_plots.py +1061 -0
  170. lsurf/visualization/ocean_simulation_plots.py +999 -0
  171. lsurf/visualization/polarization_plots.py +916 -0
  172. lsurf/visualization/raytracing_plots.py +1521 -0
  173. lsurf/visualization/ring_detector_plots.py +1867 -0
  174. lsurf/visualization/time_spread_plots.py +531 -0
  175. lsurf-1.0.0.dist-info/METADATA +381 -0
  176. lsurf-1.0.0.dist-info/RECORD +180 -0
  177. lsurf-1.0.0.dist-info/WHEEL +5 -0
  178. lsurf-1.0.0.dist-info/entry_points.txt +2 -0
  179. lsurf-1.0.0.dist-info/licenses/LICENSE +32 -0
  180. lsurf-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,258 @@
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
+ Uniform Diverging Beam Source Implementation
36
+
37
+ Provides a diverging beam source with uniform solid angle distribution,
38
+ suitable for modeling sources that emit uniformly over a cone.
39
+
40
+ This differs from DivergingBeam which samples phi uniformly (creating
41
+ higher ray density near the cone axis). UniformDivergingBeam samples
42
+ cos(phi) uniformly, giving uniform ray density per solid angle.
43
+
44
+ Examples
45
+ --------
46
+ >>> from lsurf.sources import UniformDivergingBeam
47
+ >>>
48
+ >>> source = UniformDivergingBeam(
49
+ ... origin=(0, 0, 0),
50
+ ... mean_direction=(0, 0, 1),
51
+ ... divergence_angle=0.1, # ~5.7 degrees
52
+ ... num_rays=1000,
53
+ ... wavelength=850e-9,
54
+ ... power=1.0
55
+ ... )
56
+ >>> rays = source.generate()
57
+ """
58
+
59
+ import numpy as np
60
+
61
+ from ..utilities.ray_data import RayBatch
62
+ from .base import RaySource
63
+
64
+
65
+ class UniformDivergingBeam(RaySource):
66
+ """
67
+ Beam with angular divergence and uniform solid angle distribution.
68
+
69
+ Generates rays from a single point with directions uniformly distributed
70
+ over the solid angle of a cone around the mean direction. Each element
71
+ of solid angle receives equal ray density.
72
+
73
+ This is physically correct for sources that emit uniformly over a cone
74
+ (e.g., idealized point sources with angular limits).
75
+
76
+ Parameters
77
+ ----------
78
+ origin : tuple of float
79
+ Source position (x, y, z) in meters.
80
+ mean_direction : tuple of float
81
+ Mean beam direction (dx, dy, dz), will be normalized.
82
+ divergence_angle : float
83
+ Half-angle divergence in radians (cone half-angle).
84
+ Must be in range (0, π/2).
85
+ num_rays : int
86
+ Number of rays to generate.
87
+ wavelength : float or tuple of float
88
+ Single wavelength (m) or (min, max) range.
89
+ power : float, optional
90
+ Total source power in watts. Default is 1.0.
91
+
92
+ Attributes
93
+ ----------
94
+ origin : ndarray, shape (3,)
95
+ Source position.
96
+ mean_direction : ndarray, shape (3,)
97
+ Normalized mean beam direction.
98
+ divergence_angle : float
99
+ Cone half-angle in radians.
100
+ solid_angle : float
101
+ Solid angle of the cone in steradians: Ω = 2π(1 - cos(θ))
102
+
103
+ Notes
104
+ -----
105
+ The key difference from DivergingBeam is the sampling of the polar angle:
106
+
107
+ - DivergingBeam: phi ~ Uniform(0, divergence_angle)
108
+ This creates higher ray density near the cone axis.
109
+
110
+ - UniformDivergingBeam: cos(phi) ~ Uniform(cos(divergence_angle), 1)
111
+ This creates uniform ray density per solid angle.
112
+
113
+ The solid angle of a cone with half-angle θ is:
114
+ Ω = 2π(1 - cos(θ))
115
+
116
+ For uniform sampling over this solid angle, we need:
117
+ dN/dΩ = constant
118
+
119
+ This requires sampling cos(phi) uniformly, not phi.
120
+
121
+ Examples
122
+ --------
123
+ >>> # Uniform emission over 10 degree cone
124
+ >>> source = UniformDivergingBeam(
125
+ ... origin=(0, 0, 0),
126
+ ... mean_direction=(0, 0, 1),
127
+ ... divergence_angle=np.radians(10),
128
+ ... num_rays=5000,
129
+ ... wavelength=1550e-9,
130
+ ... power=1e-3
131
+ ... )
132
+
133
+ >>> # Compare solid angle coverage
134
+ >>> # Expected: uniform distribution in cos(phi)
135
+ """
136
+
137
+ def __init__(
138
+ self,
139
+ origin: tuple[float, float, float],
140
+ mean_direction: tuple[float, float, float],
141
+ divergence_angle: float,
142
+ num_rays: int,
143
+ wavelength: float | tuple[float, float],
144
+ power: float = 1.0,
145
+ ):
146
+ """
147
+ Initialize uniform diverging beam.
148
+
149
+ Parameters
150
+ ----------
151
+ origin : tuple of float
152
+ Source position (x, y, z) in meters.
153
+ mean_direction : tuple of float
154
+ Mean beam direction, will be normalized.
155
+ divergence_angle : float
156
+ Cone half-angle in radians.
157
+ num_rays : int
158
+ Number of rays to generate.
159
+ wavelength : float or tuple of float
160
+ Wavelength in meters or (min, max) range.
161
+ power : float, optional
162
+ Total source power in watts. Default is 1.0.
163
+
164
+ Raises
165
+ ------
166
+ ValueError
167
+ If divergence_angle not in (0, π/2).
168
+ """
169
+ super().__init__(num_rays, wavelength, power)
170
+ self.origin = np.array(origin, dtype=np.float32)
171
+ self.divergence_angle = divergence_angle
172
+
173
+ # Normalize mean direction
174
+ mean_direction_arr = np.array(mean_direction, dtype=np.float32)
175
+ self.mean_direction = mean_direction_arr / np.linalg.norm(mean_direction_arr)
176
+
177
+ if divergence_angle <= 0 or divergence_angle >= np.pi / 2:
178
+ raise ValueError("divergence_angle must be in (0, π/2)")
179
+
180
+ @property
181
+ def solid_angle(self) -> float:
182
+ """
183
+ Solid angle of the cone in steradians.
184
+
185
+ Returns
186
+ -------
187
+ float
188
+ Ω = 2π(1 - cos(θ)) where θ is the divergence half-angle.
189
+ """
190
+ return 2 * np.pi * (1 - np.cos(self.divergence_angle))
191
+
192
+ def generate(self) -> RayBatch:
193
+ """
194
+ Generate uniformly diverging beam.
195
+
196
+ Creates rays from the origin with directions uniformly distributed
197
+ over the solid angle of a cone around the mean direction.
198
+
199
+ Returns
200
+ -------
201
+ RayBatch
202
+ Ray batch with uniform solid angle distribution.
203
+
204
+ Notes
205
+ -----
206
+ The sampling uses:
207
+ - theta ~ Uniform(0, 2π) for azimuthal angle
208
+ - cos(phi) ~ Uniform(cos(divergence_angle), 1) for polar angle
209
+
210
+ This ensures dN/dΩ = constant over the cone.
211
+ """
212
+ rays = self._allocate_rays()
213
+
214
+ # All rays start at origin
215
+ rays.positions[:] = self.origin
216
+
217
+ # Create perpendicular basis for direction perturbation
218
+ v1, v2 = self._create_perpendicular_basis(self.mean_direction)
219
+
220
+ # Generate random angles within cone
221
+ # Azimuthal angle: uniform in [0, 2π)
222
+ theta = np.random.uniform(0, 2 * np.pi, self.num_rays)
223
+
224
+ # Polar angle: sample cos(phi) uniformly for uniform solid angle distribution
225
+ # cos(phi) ~ Uniform(cos(divergence_angle), 1)
226
+ cos_phi = np.random.uniform(np.cos(self.divergence_angle), 1.0, self.num_rays)
227
+ phi = np.arccos(cos_phi)
228
+
229
+ # Compute perturbed directions
230
+ sin_phi = np.sin(phi)
231
+
232
+ # Direction in local coordinates (z = mean_direction)
233
+ local_x = sin_phi * np.cos(theta)
234
+ local_y = sin_phi * np.sin(theta)
235
+ local_z = cos_phi
236
+
237
+ # Transform to global coordinates
238
+ rays.directions[:] = (
239
+ local_x[:, np.newaxis] * v1
240
+ + local_y[:, np.newaxis] * v2
241
+ + local_z[:, np.newaxis] * self.mean_direction
242
+ )
243
+
244
+ # Normalize (should already be normalized, but ensure numerical stability)
245
+ norms = np.linalg.norm(rays.directions, axis=1, keepdims=True)
246
+ rays.directions[:] /= norms
247
+
248
+ self._assign_wavelengths(rays)
249
+
250
+ return rays
251
+
252
+ def __repr__(self) -> str:
253
+ """Return string representation."""
254
+ return (
255
+ f"UniformDivergingBeam(origin={self.origin.tolist()}, "
256
+ f"divergence_angle={self.divergence_angle:.4f}, "
257
+ f"solid_angle={self.solid_angle:.6f} sr)"
258
+ )
@@ -0,0 +1,184 @@
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
+ Surfaces Module
36
+
37
+ Unified surface interface for ray tracing. All surfaces follow the same
38
+ protocol regardless of GPU capability.
39
+
40
+ Surface Types
41
+ -------------
42
+ GPU-Capable (fast signed distance computation):
43
+ - PlaneSurface: Infinite flat plane (geometry_id=1)
44
+ - SphereSurface: Spherical surface (geometry_id=2)
45
+ - GPUGerstnerWaveSurface: Flat-earth Gerstner wave, single wave (geometry_id=3)
46
+ - GPUCurvedWaveSurface: Curved-earth wave, single wave (geometry_id=4)
47
+ - GPUMultiCurvedWaveSurface: Curved-earth wave, multi-wave up to 8 (geometry_id=5)
48
+ - BoundedPlaneSurface: Bounded rectangular plane (geometry_id=6)
49
+ - AnnularPlaneSurface: Annular (ring-shaped) plane (geometry_id=7)
50
+
51
+ CPU-Only (complex geometry, ray marching, multiple waves):
52
+ - GerstnerWaveSurface: Flat-earth ocean waves (multi-wave)
53
+ - CurvedWaveSurface: Curved-earth ocean waves (multi-wave)
54
+
55
+ Protocol
56
+ --------
57
+ All surfaces provide:
58
+ - role: SurfaceRole (DETECTOR, OPTICAL, ABSORBER)
59
+ - name: Human-readable identifier
60
+ - gpu_capable: Whether GPU acceleration is available
61
+ - geometry_id: Integer ID for GPU kernels (0 for CPU-only)
62
+ - intersect(): CPU ray intersection (always available)
63
+ - normal_at(): CPU surface normals (always available)
64
+ - get_materials(): Return materials for Fresnel calculation
65
+
66
+ GPU-capable surfaces additionally provide:
67
+ - signed_distance(): For GPU kernels
68
+ - get_gpu_parameters(): Parameters for GPU kernels
69
+
70
+ Examples
71
+ --------
72
+ >>> from lsurf.surfaces import PlaneSurface, GerstnerWaveSurface, SurfaceRole
73
+ >>> from lsurf.materials import AIR_STP, WATER
74
+ >>>
75
+ >>> # GPU-capable plane
76
+ >>> detector = PlaneSurface(
77
+ ... point=(0, 0, 1000),
78
+ ... normal=(0, 0, 1),
79
+ ... role=SurfaceRole.DETECTOR,
80
+ ... name="detector",
81
+ ... )
82
+ >>> print(detector.gpu_capable) # True
83
+ >>>
84
+ >>> # CPU-only wave surface
85
+ >>> from lsurf.surfaces import GerstnerWaveParams
86
+ >>> wave = GerstnerWaveParams(amplitude=1.0, wavelength=50.0)
87
+ >>> ocean = GerstnerWaveSurface(
88
+ ... wave_params=[wave],
89
+ ... role=SurfaceRole.OPTICAL,
90
+ ... name="ocean",
91
+ ... material_front=AIR_STP,
92
+ ... material_back=WATER,
93
+ ... )
94
+ >>> print(ocean.gpu_capable) # False
95
+ """
96
+
97
+ # Protocol and enums
98
+ from .protocol import (
99
+ Surface,
100
+ SurfaceRole,
101
+ GPUSurface, # Alias for backwards compatibility
102
+ )
103
+
104
+ # Surface type registry
105
+ from .registry import (
106
+ # New names
107
+ SurfaceTypeInfo,
108
+ register_surface_type,
109
+ get_surface_type,
110
+ get_surface_type_id,
111
+ get_surface_class,
112
+ is_gpu_capable,
113
+ list_surface_types,
114
+ surface_type_exists,
115
+ # Backwards compatibility aliases
116
+ GeometryInfo,
117
+ register_geometry,
118
+ get_geometry_info,
119
+ get_geometry_id,
120
+ list_geometries,
121
+ geometry_exists,
122
+ )
123
+
124
+ # GPU-capable surfaces
125
+ from .gpu import (
126
+ PlaneSurface,
127
+ SphereSurface,
128
+ RecordingSphereSurface,
129
+ LocalRecordingSphereSurface,
130
+ GPUGerstnerWaveSurface,
131
+ GPUCurvedWaveSurface,
132
+ GPUMultiCurvedWaveSurface,
133
+ BoundedPlaneSurface,
134
+ AnnularPlaneSurface,
135
+ )
136
+
137
+ # CPU-only surfaces
138
+ from .cpu import (
139
+ GerstnerWaveSurface,
140
+ CurvedWaveSurface,
141
+ GerstnerWaveParams,
142
+ )
143
+
144
+ # Constants
145
+ EARTH_RADIUS = 6.371e6 # Earth's mean radius in meters
146
+
147
+ __all__ = [
148
+ # Protocol
149
+ "Surface",
150
+ "SurfaceRole",
151
+ "GPUSurface",
152
+ # Surface type registry
153
+ "SurfaceTypeInfo",
154
+ "register_surface_type",
155
+ "get_surface_type",
156
+ "get_surface_type_id",
157
+ "get_surface_class",
158
+ "is_gpu_capable",
159
+ "list_surface_types",
160
+ "surface_type_exists",
161
+ # Backwards compatibility
162
+ "GeometryInfo",
163
+ "register_geometry",
164
+ "get_geometry_info",
165
+ "get_geometry_id",
166
+ "list_geometries",
167
+ "geometry_exists",
168
+ # GPU-capable surfaces
169
+ "PlaneSurface",
170
+ "SphereSurface",
171
+ "RecordingSphereSurface",
172
+ "LocalRecordingSphereSurface",
173
+ "GPUGerstnerWaveSurface",
174
+ "GPUCurvedWaveSurface",
175
+ "GPUMultiCurvedWaveSurface",
176
+ "BoundedPlaneSurface",
177
+ "AnnularPlaneSurface",
178
+ # CPU-only surfaces
179
+ "GerstnerWaveSurface",
180
+ "CurvedWaveSurface",
181
+ "GerstnerWaveParams",
182
+ # Constants
183
+ "EARTH_RADIUS",
184
+ ]
@@ -0,0 +1,50 @@
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
+ CPU-Only Surfaces
36
+
37
+ Surfaces with complex geometry that require CPU-based ray marching.
38
+ These surfaces do not support GPU acceleration but provide the same
39
+ interface as GPU-capable surfaces.
40
+ """
41
+
42
+ from .gerstner_wave import GerstnerWaveSurface
43
+ from .curved_wave import CurvedWaveSurface
44
+ from .wave_params import GerstnerWaveParams
45
+
46
+ __all__ = [
47
+ "GerstnerWaveSurface",
48
+ "CurvedWaveSurface",
49
+ "GerstnerWaveParams",
50
+ ]