structured-optics 0.5__tar.gz → 0.6__tar.gz

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 (24) hide show
  1. {structured_optics-0.5/structured_optics.egg-info → structured_optics-0.6}/PKG-INFO +17 -6
  2. {structured_optics-0.5 → structured_optics-0.6}/README.md +90 -79
  3. {structured_optics-0.5 → structured_optics-0.6}/pyproject.toml +1 -1
  4. structured_optics-0.6/structured_optics/__init__.py +5 -0
  5. structured_optics-0.6/structured_optics/diagnostics.py +280 -0
  6. {structured_optics-0.5 → structured_optics-0.6}/structured_optics/hologram.py +3 -4
  7. structured_optics-0.6/structured_optics/masks.py +206 -0
  8. {structured_optics-0.5 → structured_optics-0.6}/structured_optics/modes.py +18 -8
  9. structured_optics-0.6/structured_optics/polarization.py +76 -0
  10. {structured_optics-0.5 → structured_optics-0.6}/structured_optics/prop_methods.py +4 -4
  11. {structured_optics-0.5 → structured_optics-0.6}/structured_optics/struct_opt.py +102 -674
  12. {structured_optics-0.5 → structured_optics-0.6}/structured_optics/utils.py +0 -29
  13. {structured_optics-0.5 → structured_optics-0.6/structured_optics.egg-info}/PKG-INFO +17 -6
  14. {structured_optics-0.5 → structured_optics-0.6}/structured_optics.egg-info/SOURCES.txt +2 -0
  15. structured_optics-0.5/structured_optics/__init__.py +0 -4
  16. structured_optics-0.5/structured_optics/polarization.py +0 -25
  17. {structured_optics-0.5 → structured_optics-0.6}/LICENSE +0 -0
  18. {structured_optics-0.5 → structured_optics-0.6}/setup.cfg +0 -0
  19. {structured_optics-0.5 → structured_optics-0.6}/structured_optics/algebra_utils.py +0 -0
  20. {structured_optics-0.5 → structured_optics-0.6}/structured_optics/bluestein.py +0 -0
  21. {structured_optics-0.5 → structured_optics-0.6}/structured_optics/slmdisplay.py +0 -0
  22. {structured_optics-0.5 → structured_optics-0.6}/structured_optics.egg-info/dependency_links.txt +0 -0
  23. {structured_optics-0.5 → structured_optics-0.6}/structured_optics.egg-info/requires.txt +0 -0
  24. {structured_optics-0.5 → structured_optics-0.6}/structured_optics.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: structured_optics
3
- Version: 0.5
3
+ Version: 0.6
4
4
  Summary: Package for Structured Light simulation
5
5
  Author: Altilano C. Barbosa
6
6
  License-Expression: BSD-3-Clause
@@ -47,15 +47,14 @@ pip install structured-optics
47
47
  ```python
48
48
  import structured_optics as so
49
49
 
50
- # Create a beam on a 10mm x 10mm (2*5e-3) grid with 256x256 points
51
- beam = so.Beam(nix=5e-3, Dx=256, waist=1e-3, lamb=1064e-9)
50
+ # Create a beam on a 10mm x 10mm (2*5e-3) grid with 512x512 points
51
+ beam = so.Beam(nix=5e-3, Dx=512, waist=1e-3, lamb=1064e-9)
52
52
 
53
53
  # Set the field to a Laguerre-Gaussian mode with l=2, p=0
54
54
  beam.lg(l=2, p=0)
55
55
 
56
- # Propagate 10 cm and check total power
57
- beam.propagate(z=0.1, method='fresnel')
58
- print(beam.Power())
56
+ # Propagate 10 cm using Fresnel Convolution
57
+ beam.propagate(z=0.1, method='fres_c')
59
58
 
60
59
  # Look at the intensity profile
61
60
  import matplotlib.pyplot as plt
@@ -63,6 +62,9 @@ plt.pcolormesh(beam.x, beam.y, beam.int_profile())
63
62
  plt.show()
64
63
  ```
65
64
 
65
+ Expected output:
66
+ ([examples/image_examples/LG_20 prop.png](https://github.com/Altilano/structured-optics/blob/main/examples/image_examples/LG_20%20prop.png))
67
+
66
68
  ## Documentation
67
69
 
68
70
  Full API documentation, including all mode types, propagation methods, and
@@ -90,4 +92,13 @@ This project is licensed under the BSD-3-Clause License. See `LICENSE` for detai
90
92
 
91
93
  ## Citation
92
94
 
95
+ ## To do
96
+
97
+ - Documentation.
98
+ - Benchmark and optimization.
99
+ - Support for high NA focalization. (Non paraxial propagation)
100
+ - Cuda and ROCm speed up.
101
+ - Support for propagation inside linear medium.
102
+
103
+
93
104
 
@@ -1,79 +1,90 @@
1
- # structured-optics
2
-
3
- A Python library for generating, propagating, and analyzing structured light beams
4
- (Hermite-Gaussian, Laguerre-Gaussian, Bessel, Ince-Gaussian, fiber LP modes, and more)
5
- on a discretized transverse grid.
6
-
7
- [![PyPI version](https://img.shields.io/pypi/v/structured-optics.svg)](https://pypi.org/project/structured-optics/)
8
-
9
- [![License: BSD-3-Clause](https://img.shields.io/badge/License-BSD--3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
10
-
11
- ## Features
12
-
13
- - **Mode generation**: Hermite-Gaussian, Laguerre-Gaussian, Bessel, Gaussian-Bessel,
14
- Ince-Gaussian (even/odd/helical), fractional OAM, fiber LP modes, and geometric
15
- apertures (circle, square, triangle).
16
- - **Propagation**: Fresnel, Fraunhofer, and incoherent propagation methods.
17
- - **Polarization**: vector beams with Ex/Ey/Ez components, Jones-matrix optics
18
- (waveplates, polarizers).
19
- - **Optical elements**: lenses (spherical, astigmatic, tilted), slits, irises,
20
- and other amplitude/phase masks.
21
- - **Analysis**: power, intensity and phase profiles, centroid, beam size (std),
22
- angular sections, and modal decomposition (HG/LG/Bessel basis projections).
23
- - **Holography**: SLM and DMD hologram generation for experimental beam shaping.
24
-
25
- ## Installation
26
-
27
- ```bash
28
- pip install structured-optics
29
- ```
30
-
31
- ## Quick start
32
-
33
- ```python
34
- import structured_optics as so
35
-
36
- # Create a beam on a 10mm x 10mm (2*5e-3) grid with 256x256 points
37
- beam = so.Beam(nix=5e-3, Dx=256, waist=1e-3, lamb=1064e-9)
38
-
39
- # Set the field to a Laguerre-Gaussian mode with l=2, p=0
40
- beam.lg(l=2, p=0)
41
-
42
- # Propagate 10 cm and check total power
43
- beam.propagate(z=0.1, method='fresnel')
44
- print(beam.Power())
45
-
46
- # Look at the intensity profile
47
- import matplotlib.pyplot as plt
48
- plt.pcolormesh(beam.x, beam.y, beam.int_profile())
49
- plt.show()
50
- ```
51
-
52
- ## Documentation
53
-
54
- Full API documentation, including all mode types, propagation methods, and
55
- optical elements, is available at:
56
-
57
- Soon...
58
-
59
- ## Requirements
60
-
61
- - Python 3.9+
62
- - numpy
63
- - scipy
64
- - screeninfo
65
-
66
-
67
-
68
- ## Contributing
69
-
70
- Issues and pull requests are welcome at
71
- [github.com/Altilano/structured-optics](https://github.com/Altilano/structured-optics).
72
-
73
- ## License
74
-
75
- This project is licensed under the BSD-3-Clause License. See `LICENSE` for details.
76
-
77
- ## Citation
78
-
79
-
1
+ # structured-optics
2
+
3
+ A Python library for generating, propagating, and analyzing structured light beams
4
+ (Hermite-Gaussian, Laguerre-Gaussian, Bessel, Ince-Gaussian, fiber LP modes, and more)
5
+ on a discretized transverse grid.
6
+
7
+ [![PyPI version](https://img.shields.io/pypi/v/structured-optics.svg)](https://pypi.org/project/structured-optics/)
8
+
9
+ [![License: BSD-3-Clause](https://img.shields.io/badge/License-BSD--3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
10
+
11
+ ## Features
12
+
13
+ - **Mode generation**: Hermite-Gaussian, Laguerre-Gaussian, Bessel, Gaussian-Bessel,
14
+ Ince-Gaussian (even/odd/helical), fractional OAM, fiber LP modes, and geometric
15
+ apertures (circle, square, triangle).
16
+ - **Propagation**: Fresnel, Fraunhofer, and incoherent propagation methods.
17
+ - **Polarization**: vector beams with Ex/Ey/Ez components, Jones-matrix optics
18
+ (waveplates, polarizers).
19
+ - **Optical elements**: lenses (spherical, astigmatic, tilted), slits, irises,
20
+ and other amplitude/phase masks.
21
+ - **Analysis**: power, intensity and phase profiles, centroid, beam size (std),
22
+ angular sections, and modal decomposition (HG/LG/Bessel basis projections).
23
+ - **Holography**: SLM and DMD hologram generation for experimental beam shaping.
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pip install structured-optics
29
+ ```
30
+
31
+ ## Quick start
32
+
33
+ ```python
34
+ import structured_optics as so
35
+
36
+ # Create a beam on a 10mm x 10mm (2*5e-3) grid with 512x512 points
37
+ beam = so.Beam(nix=5e-3, Dx=512, waist=1e-3, lamb=1064e-9)
38
+
39
+ # Set the field to a Laguerre-Gaussian mode with l=2, p=0
40
+ beam.lg(l=2, p=0)
41
+
42
+ # Propagate 10 cm using Fresnel Convolution
43
+ beam.propagate(z=0.1, method='fres_c')
44
+
45
+ # Look at the intensity profile
46
+ import matplotlib.pyplot as plt
47
+ plt.pcolormesh(beam.x, beam.y, beam.int_profile())
48
+ plt.show()
49
+ ```
50
+
51
+ Expected output:
52
+ ([examples/image_examples/LG_20 prop.png](https://github.com/Altilano/structured-optics/blob/main/examples/image_examples/LG_20%20prop.png))
53
+
54
+ ## Documentation
55
+
56
+ Full API documentation, including all mode types, propagation methods, and
57
+ optical elements, is available at:
58
+
59
+ Soon...
60
+
61
+ ## Requirements
62
+
63
+ - Python 3.9+
64
+ - numpy
65
+ - scipy
66
+ - screeninfo
67
+
68
+
69
+
70
+ ## Contributing
71
+
72
+ Issues and pull requests are welcome at
73
+ [github.com/Altilano/structured-optics](https://github.com/Altilano/structured-optics).
74
+
75
+ ## License
76
+
77
+ This project is licensed under the BSD-3-Clause License. See `LICENSE` for details.
78
+
79
+ ## Citation
80
+
81
+ ## To do
82
+
83
+ - Documentation.
84
+ - Benchmark and optimization.
85
+ - Support for high NA focalization. (Non paraxial propagation)
86
+ - Cuda and ROCm speed up.
87
+ - Support for propagation inside linear medium.
88
+
89
+
90
+
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "structured_optics"
7
- version = "0.5"
7
+ version = "0.6"
8
8
  description = "Package for Structured Light simulation"
9
9
  readme = "README.md"
10
10
  license = "BSD-3-Clause"
@@ -0,0 +1,5 @@
1
+ from .struct_opt import *
2
+ from .modes import *
3
+ from .masks import *
4
+ from .polarization import *
5
+ from .utils import overlap, int_overlap
@@ -0,0 +1,280 @@
1
+ import numpy as np
2
+
3
+ from .utils import get_section
4
+
5
+
6
+ class BeamDiagnostics:
7
+ """
8
+ Mixin providing measurement/diagnostic methods for Beam: power,
9
+ intensity/phase profiles, centroid and width statistics, angular
10
+ sections, normalization and more.
11
+ """
12
+
13
+ def Power(self, pol_index=None) -> float:
14
+ """Get the total optical Power via numerical integration of the intensity profile
15
+ (trapezoidal-like Riemann sum with the grid's cell area)
16
+
17
+ Parameters
18
+ ----------
19
+ pol_index: int, optional
20
+ Polarization component into which the resulting power is measured. Default is power of
21
+ all field components.
22
+
23
+ Returns
24
+ -------
25
+ float
26
+ """
27
+ return np.sum(self.int_profile(pol_index))*(4*self.nix/self.Dx)*(self.niy/self.Dy)
28
+
29
+
30
+ def zr(self) -> float:
31
+ """
32
+ Compute the Rayleigh range of the beam from its `waist` and `lamb`.
33
+
34
+ Returns
35
+ -------
36
+ float
37
+ Rayleigh range, zr = pi*waist**2/lamb.
38
+ """
39
+ return np.pi*self.waist**2/self.lamb
40
+
41
+ def k(self) -> float:
42
+ """
43
+ Compute k vector magnitude in vacum.
44
+
45
+ Returns
46
+ -------
47
+ float
48
+ k vector magniture in vaccum"""
49
+ return 2*np.pi/self.lamb
50
+
51
+ def int_profile(self, pol_index=None) -> np.ndarray:
52
+ """
53
+ Get intensity profile.
54
+
55
+ pol_index=None -> total intensity
56
+ pol_index=0 -> Ex intensity
57
+ pol_index=1 -> Ey intensity
58
+ pol_index=2 -> Ez intensity
59
+
60
+ Parameters
61
+ ----------
62
+ pol_index: int, optional
63
+ Polarization component into which the resulting intensity profile is measured. Default is sum of
64
+ all intensity components.
65
+
66
+ Return
67
+ ------
68
+ ndarray
69
+ Array with intensity profile (x,y).
70
+ """
71
+ if pol_index is None:
72
+ return np.sum(np.abs(self.field)**2, axis=0)
73
+ return np.abs(self.field[pol_index])**2
74
+
75
+
76
+ def phase(self, pol_index=None, twopi=False) -> np.ndarray:
77
+ """
78
+ Parameters
79
+ ----------
80
+ pol_index : int or None, optional
81
+ None returns phase of all components; 0/1/2 returns the phase of
82
+ Ex/Ey/Ez respectively.
83
+ twopi : bool, optional
84
+ If True, wrap phase into [0, 2*pi) instead of the default (-pi, pi].
85
+
86
+ Returns
87
+ -------
88
+ ndarray
89
+ Phase profile, shape (Dy, Dx) if pol_index is given or pol==1,
90
+ otherwise shape (pol, Dy, Dx).
91
+ """
92
+ if pol_index is None:
93
+ field = self.field
94
+ else:
95
+ field = self.field[pol_index]
96
+ p = np.angle(field)
97
+ if twopi:
98
+ p = np.mod(p, 2*np.pi)
99
+ if self.pol == 1:
100
+ return p[0]
101
+ return p
102
+
103
+
104
+ def center_mass(self, pol_index=None) -> tuple:
105
+ """
106
+ Compute the intensity-weighted center of mass of the field in physical x and y coordinates.
107
+
108
+ Parameters
109
+ ----------
110
+ pol_index : int, optional
111
+ Polarization component to use; None uses total intensity.
112
+
113
+ Returns
114
+ -------
115
+ tuple (x_cm, y_cm)
116
+ center-of-mass coordinates in physical units. """
117
+ I = self.int_profile(pol_index)
118
+
119
+ x = np.asarray(self.x)
120
+ y = np.asarray(self.y)
121
+ if x.ndim == 2:
122
+ x = x[0, :] if x.shape[0] == 1 else x[0, :]
123
+ if y.ndim == 2:
124
+ y = y[:, 0] if y.shape[1] == 1 else y[:, 0]
125
+ # Total intensity
126
+ norm = np.sum(I)
127
+
128
+ if norm == 0:
129
+ raise ValueError("Cannot calculate center of mass of zero intensity.")
130
+
131
+ # Intensity marginalized along each direction
132
+ Ix = np.sum(I, axis=0)
133
+ Iy = np.sum(I, axis=1)
134
+
135
+ # Physical center of mass
136
+ x_cm = np.sum(x * Ix) / norm
137
+ y_cm = np.sum(y * Iy) / norm
138
+
139
+ return x_cm, y_cm
140
+
141
+ def std(self, pol_index=None):
142
+ """
143
+ Calculate the intensity-weighted spatial standard deviation
144
+ along x and y.
145
+
146
+ Parameters
147
+ ----------
148
+ pol_index : int, optional
149
+ Polarization component to use; None uses total intensity.
150
+
151
+ Returns
152
+ -------
153
+ sigma_x, sigma_y : float
154
+ Intensity-weighted spatial standard deviations.
155
+ """
156
+ I = self.int_profile(pol_index)
157
+ x = np.asarray(self.x)
158
+ y = np.asarray(self.y)
159
+ x = x[0, :] if x.ndim == 2 else x
160
+ y = y[:, 0] if y.ndim == 2 else y
161
+ norm = np.sum(I)
162
+ Ix = np.sum(I, axis=0)
163
+ Iy = np.sum(I, axis=1)
164
+ x_cm, y_cm = self.center_mass(pol_index)
165
+ var_x = np.sum(Ix * (x - x_cm)**2) / norm
166
+ var_y = np.sum(Iy * (y - y_cm)**2) / norm
167
+ return np.sqrt(var_x), np.sqrt(var_y)
168
+
169
+ def radial_std(self, pol_index=None) -> float:
170
+ """
171
+ Calculate the intensity-weighted radial standard deviation of the field
172
+ about its center of mass.
173
+
174
+ Parameters
175
+ ----------
176
+ pol_index : int, optional
177
+ Polarization component to use; None uses total intensity.
178
+
179
+ Returns
180
+ -------
181
+ float
182
+ Intensity-weighted radial standard deviation.
183
+ """
184
+ sx, sy = self.std(pol_index)
185
+
186
+ return np.sqrt(sx**2 + sy**2)
187
+
188
+ def section(self, ang_min:float, ang_max:float, pol_index:int=0) -> np.ndarray:
189
+ """
190
+ Parameters
191
+ ----------
192
+ ang_min : float
193
+ Minimum angle (radians) defining the angular wedge.
194
+ ang_max : float
195
+ Maximum angle (radians) defining the angular wedge.
196
+ pol_index : int, optional
197
+ Polarization component to extract the section from.
198
+
199
+ Returns
200
+ -------
201
+ ndarray
202
+ Complex field values restricted to the angular wedge [ang_min, ang_max].
203
+ """
204
+ return get_section(self, ang_min, ang_max, pol_index = pol_index)
205
+
206
+ def int_section(self, ang_min:float, ang_max:float, pol_index:int=0)-> np.ndarray:
207
+ """
208
+ Parameters
209
+ ----------
210
+ ang_min : float
211
+ Minimum angle (radians) defining the angular wedge.
212
+ ang_max : float
213
+ Maximum angle (radians) defining the angular wedge.
214
+ pol_index : int, optional
215
+ Polarization component to extract the section from.
216
+
217
+ Returns
218
+ -------
219
+ ndarray
220
+ Intensity |field|^2 within the angular wedge [ang_min, ang_max].
221
+ """
222
+ return np.abs(self.section(ang_min, ang_max, pol_index = pol_index))**2
223
+
224
+ def Power_section(self, ang_min:float, ang_max:float, pol_index:int=0)-> float:
225
+ """
226
+ Parameters
227
+ ----------
228
+ ang_min : float
229
+ Minimum angle (radians) defining the angular wedge.
230
+ ang_max : float
231
+ Maximum angle (radians) defining the angular wedge.
232
+ pol_index : int, optional
233
+ Polarization component to compute power for.
234
+
235
+ Returns
236
+ -------
237
+ float
238
+ Optical power contained within the angular wedge [ang_min, ang_max].
239
+ """
240
+ return np.sum(np.abs(self.section(ang_min, ang_max, pol_index = pol_index))**2*(4*self.nix/self.Dx)*(self.niy/self.Dy))
241
+
242
+ def norm_beam(self)-> object:
243
+ """
244
+ Returns
245
+ -------
246
+ Beam
247
+ self, with field rescaled in place so that self.Power() == 1.
248
+ """
249
+ self.field = self.field/np.sqrt(self.Power())
250
+ return self
251
+
252
+ def Max_int1(self)-> object:
253
+ """
254
+ Returns
255
+ -------
256
+ Beam
257
+ self, with field rescaled in place so that the peak intensity equals 1.
258
+ """
259
+ self.field = self.field/np.sqrt(np.max(self.int_profile()))
260
+ return self
261
+
262
+
263
+ """
264
+ Parameters
265
+ ----------
266
+ center : tuple of float, optional
267
+ (x, y) center of the crop window. Defaults to the beam's own centroid.
268
+ std : float, optional
269
+ Standard deviation used to size the crop window. Defaults to the
270
+ beam's own computed std.
271
+ window : float, optional
272
+ Multiplier on `std` defining the half-width of the crop region.
273
+
274
+ Returns
275
+ -------
276
+ Beam
277
+ A new, spatially cropped Beam.
278
+ """
279
+ return get_crop(self, center, std, window)
280
+
@@ -1,7 +1,6 @@
1
- from structured_optics.struct_opt import *
2
1
  import numpy as np
3
- from structured_optics.utils import *
4
- import time
2
+ from .utils import inv_J0, inv_J1, inv_sinc
3
+
5
4
 
6
5
 
7
6
  def slm_hologram(Beam, x_grating, y_grating, method, input_beam, eps, max_range):
@@ -40,7 +39,7 @@ def slm_hologram(Beam, x_grating, y_grating, method, input_beam, eps, max_range)
40
39
  elif method == 'bessel1':
41
40
  H = inv_J1(A_rel)*np.sin(phi_relg)
42
41
  else:
43
- print('Error! method must be simple, g_holo, davis, bolduc, bessel0 or bessel1.')
42
+ raise ValueError('Error! method must be simple, g_holo, davis, bolduc, bessel0 or bessel1.')
44
43
  H = max_range * (H - H.min()) / (H.max() - H.min())
45
44
  return H.astype(np.uint8)
46
45