vectorwaves 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.
- vectorwaves/__init__.py +88 -0
- vectorwaves/backends/__init__.py +0 -0
- vectorwaves/backends/cupy_backend.py +197 -0
- vectorwaves/backends/numba_backend.py +271 -0
- vectorwaves/backends/numpy_backend.py +193 -0
- vectorwaves/beam_stuff.py +623 -0
- vectorwaves/config_stuff.py +747 -0
- vectorwaves/engine_stuff.py +379 -0
- vectorwaves/py.typed +0 -0
- vectorwaves/singularities.py +617 -0
- vectorwaves/spectra.py +341 -0
- vectorwaves/utils.py +130 -0
- vectorwaves/version.py +5 -0
- vectorwaves-1.0.0.dist-info/METADATA +114 -0
- vectorwaves-1.0.0.dist-info/RECORD +18 -0
- vectorwaves-1.0.0.dist-info/WHEEL +5 -0
- vectorwaves-1.0.0.dist-info/licenses/LICENSE +21 -0
- vectorwaves-1.0.0.dist-info/top_level.txt +1 -0
vectorwaves/spectra.py
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
"""
|
|
2
|
+
KSpace and Polychromatic Spectras
|
|
3
|
+
========================
|
|
4
|
+
|
|
5
|
+
Mathematical implementations of spatial (k-space) and spectral (wavelength) distributions.
|
|
6
|
+
All methods are implemented with xy plane as transverse plane!
|
|
7
|
+
"""
|
|
8
|
+
import numpy as np
|
|
9
|
+
from scipy.special import eval_hermite, eval_genlaguerre
|
|
10
|
+
|
|
11
|
+
class KSpaceSpectra:
|
|
12
|
+
"""
|
|
13
|
+
Implementations of Spatial Profiles in k-space.
|
|
14
|
+
|
|
15
|
+
All functions here take a k-vector array (shape: 3 x N) and spatial parameters,
|
|
16
|
+
returning the complex amplitude of the field in k-space.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def uniform(k_vec: np.ndarray, **kwargs) -> np.ndarray:
|
|
21
|
+
"""
|
|
22
|
+
Flat angular spectrum (Uniform k-space).
|
|
23
|
+
|
|
24
|
+
Weights all plane wave directions equally. Physically, if the modes are
|
|
25
|
+
coherent (locked phase), this corresponds to an infinitesimally small
|
|
26
|
+
point source or a perfectly spherical converging wave. If phases are
|
|
27
|
+
random, this simulates isotropic diffuse light.
|
|
28
|
+
|
|
29
|
+
Formula:
|
|
30
|
+
S(k) = 1.0 + 0j
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
k_vec : np.ndarray
|
|
35
|
+
Array of k-vectors of shape (3, N) or (3,).
|
|
36
|
+
|
|
37
|
+
Returns
|
|
38
|
+
-------
|
|
39
|
+
np.ndarray
|
|
40
|
+
Array of ones matching the length of the input k-vectors.
|
|
41
|
+
"""
|
|
42
|
+
if k_vec.ndim == 1:
|
|
43
|
+
return 1.0 + 0j
|
|
44
|
+
return np.ones(k_vec.shape[1], dtype=complex)
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def gaussian(k_vec: np.ndarray, sigma_k_perp: float) -> np.ndarray:
|
|
48
|
+
"""
|
|
49
|
+
Gaussian spatial profile in k-space.
|
|
50
|
+
|
|
51
|
+
Mathematically defines a fundamental Gaussian beam (TEM00).
|
|
52
|
+
|
|
53
|
+
Formula:
|
|
54
|
+
S(kx, ky) = exp( -(kx^2 + ky^2) / (2 * sigma_k_perp^2) )
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
k_vec : np.ndarray
|
|
59
|
+
Array of k-vectors of shape (3, N) where rows are kx, ky, kz.
|
|
60
|
+
sigma_k_perp : float
|
|
61
|
+
The standard deviation of the Gaussian envelope in k-space.
|
|
62
|
+
This is inversely proportional to the real-space beam waist (w0).
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
np.ndarray
|
|
67
|
+
Complex amplitude weights for each plane wave mode.
|
|
68
|
+
"""
|
|
69
|
+
kx, ky = k_vec[0], k_vec[1]
|
|
70
|
+
gaussian_profile = np.exp(-(kx**2 + ky**2) / (2 * sigma_k_perp**2))
|
|
71
|
+
return gaussian_profile.astype(complex)
|
|
72
|
+
|
|
73
|
+
@staticmethod
|
|
74
|
+
def tophat(k_vec: np.ndarray, k_perp_max: float) -> np.ndarray:
|
|
75
|
+
"""
|
|
76
|
+
Uniform Top-Hat disk spectrum.
|
|
77
|
+
|
|
78
|
+
Defines a sharp cutoff in transverse momentum. In real space,
|
|
79
|
+
this produces a J1(r)/r (Airy disk) transverse profile.
|
|
80
|
+
|
|
81
|
+
Formula:
|
|
82
|
+
S(kx, ky) = 1.0 if (kx^2 + ky^2) <= k_perp_max^2
|
|
83
|
+
S(kx, ky) = 0.0 otherwise
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
k_vec : np.ndarray
|
|
88
|
+
Array of k-vectors of shape (3, N).
|
|
89
|
+
k_perp_max : float
|
|
90
|
+
The maximum transverse spatial frequency allowed.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
np.ndarray
|
|
95
|
+
Complex amplitude weights (1.0 or 0.0).
|
|
96
|
+
"""
|
|
97
|
+
mask = (k_vec[0]**2 + k_vec[1]**2) < k_perp_max**2
|
|
98
|
+
return mask.astype(complex)
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def laguerre_gauss(k_vec: np.ndarray, p: int, l: int, sigma_k_perp: float) -> np.ndarray:
|
|
102
|
+
"""
|
|
103
|
+
Angular spectrum for Laguerre-Gauss (Vortex) modes.
|
|
104
|
+
|
|
105
|
+
Defines a beam carrying Orbital Angular Momentum (OAM).
|
|
106
|
+
The parameter `l` defines the topological charge, and `p` defines
|
|
107
|
+
the number of radial nodes.
|
|
108
|
+
|
|
109
|
+
Formula:
|
|
110
|
+
rho^2 = kx^2 + ky^2
|
|
111
|
+
phi_k = arctan2(ky, kx)
|
|
112
|
+
X = rho^2 / sigma_k_perp^2
|
|
113
|
+
|
|
114
|
+
S(kx, ky) = X^(|l|/2) * L_p^{|l|}(X) * exp(-X/2) * exp(i * l * phi_k)
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
k_vec : np.ndarray
|
|
119
|
+
Array of k-vectors of shape (3, N).
|
|
120
|
+
p : int
|
|
121
|
+
Radial index (p >= 0). Determines the number of radial rings.
|
|
122
|
+
l : int
|
|
123
|
+
Azimuthal index (topological charge). Determines OAM.
|
|
124
|
+
sigma_k_perp : float
|
|
125
|
+
Transverse scaling parameter in k-space.
|
|
126
|
+
|
|
127
|
+
Returns
|
|
128
|
+
-------
|
|
129
|
+
np.ndarray
|
|
130
|
+
Complex amplitude weights defining the LG mode.
|
|
131
|
+
"""
|
|
132
|
+
kx, ky = k_vec[0], k_vec[1]
|
|
133
|
+
k_perp_sq = kx**2 + ky**2
|
|
134
|
+
phi = np.arctan2(ky, kx)
|
|
135
|
+
|
|
136
|
+
X = k_perp_sq / (sigma_k_perp**2)
|
|
137
|
+
poly_val = eval_genlaguerre(p, abs(l), X)
|
|
138
|
+
gaussian_env = np.exp(-0.5 * X)
|
|
139
|
+
radial = (np.sqrt(X)) ** abs(l)
|
|
140
|
+
vortex = np.exp(1j * l * phi)
|
|
141
|
+
|
|
142
|
+
res = (radial * poly_val * gaussian_env * vortex).astype(complex)
|
|
143
|
+
res = np.where(k_perp_sq == 0, 0j, res)
|
|
144
|
+
return res if res.size > 1 else res[0]
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def hermite_gauss(k_vec: np.ndarray, l: int, m: int, sigma_k_perp: float) -> np.ndarray:
|
|
148
|
+
"""
|
|
149
|
+
Angular spectrum for Hermite-Gauss modes.
|
|
150
|
+
|
|
151
|
+
Defines higher-order transverse modes in Cartesian coordinates,
|
|
152
|
+
often seen emitted by laser cavities breaking cylindrical symmetry.
|
|
153
|
+
|
|
154
|
+
Formula:
|
|
155
|
+
scale = sqrt(2) / sigma_k_perp
|
|
156
|
+
S(kx, ky) = H_l(kx * scale) * H_m(ky * scale) * exp(-(kx^2 + ky^2) / 2 sigma_k_perp^2)
|
|
157
|
+
|
|
158
|
+
Parameters
|
|
159
|
+
----------
|
|
160
|
+
k_vec : np.ndarray
|
|
161
|
+
Array of k-vectors of shape (3, N).
|
|
162
|
+
l : int
|
|
163
|
+
Transverse mode index in the x-direction (l >= 0).
|
|
164
|
+
m : int
|
|
165
|
+
Transverse mode index in the y-direction (m >= 0).
|
|
166
|
+
sigma_k_perp : float
|
|
167
|
+
Transverse scaling parameter in k-space.
|
|
168
|
+
|
|
169
|
+
Returns
|
|
170
|
+
-------
|
|
171
|
+
np.ndarray
|
|
172
|
+
Complex amplitude weights defining the HG mode.
|
|
173
|
+
"""
|
|
174
|
+
kx, ky = k_vec[0], k_vec[1]
|
|
175
|
+
|
|
176
|
+
# Dimensionless scaling: x / (w0_k / sqrt(2)) -> x * sqrt(2) / sigma
|
|
177
|
+
scale = np.sqrt(2) / sigma_k_perp
|
|
178
|
+
|
|
179
|
+
term_x = eval_hermite(l, kx * scale)
|
|
180
|
+
term_y = eval_hermite(m, ky * scale)
|
|
181
|
+
gaussian = np.exp(-(kx**2 + ky**2) / (2 * sigma_k_perp**2))
|
|
182
|
+
|
|
183
|
+
res = (term_x * term_y * gaussian).astype(complex)
|
|
184
|
+
return res
|
|
185
|
+
|
|
186
|
+
@staticmethod
|
|
187
|
+
def bessel_gauss(k_vec: np.ndarray, theta_0: float, sigma_theta: float, l: int = 0) -> np.ndarray:
|
|
188
|
+
"""
|
|
189
|
+
Angular spectrum for a Bessel-Gauss beam.
|
|
190
|
+
|
|
191
|
+
Defined by a Gaussian ring of illumination on the angular hemisphere.
|
|
192
|
+
Creates a "non-diffracting" Bessel beam core in real space, enveloped
|
|
193
|
+
by a Gaussian bounds.
|
|
194
|
+
|
|
195
|
+
Formula:
|
|
196
|
+
theta_k = arccos(kz / |k|)
|
|
197
|
+
phi_k = arctan2(ky, kx)
|
|
198
|
+
|
|
199
|
+
S(k) = exp( -(theta_k - theta_0)^2 / (2 * sigma_theta^2) ) * exp(i * l * phi_k)
|
|
200
|
+
|
|
201
|
+
Parameters
|
|
202
|
+
----------
|
|
203
|
+
k_vec : np.ndarray
|
|
204
|
+
Array of k-vectors of shape (3, N) where rows are kx, ky, kz.
|
|
205
|
+
theta_0 : float
|
|
206
|
+
Cone opening angle (in radians) of the Bessel beam in k-space.
|
|
207
|
+
sigma_theta : float
|
|
208
|
+
Angular thickness (in radians) of the Gaussian ring.
|
|
209
|
+
l : int, optional
|
|
210
|
+
Topological charge. If l != 0, creates a Higher-Order Bessel beam (vortex).
|
|
211
|
+
|
|
212
|
+
Returns
|
|
213
|
+
-------
|
|
214
|
+
np.ndarray
|
|
215
|
+
Complex amplitude weights defining the BG mode.
|
|
216
|
+
"""
|
|
217
|
+
# Extract components - each has shape (N,)
|
|
218
|
+
kx, ky, kz = k_vec[0], k_vec[1], k_vec[2]
|
|
219
|
+
k_mag = np.sqrt(kx**2 + ky**2 + kz**2)
|
|
220
|
+
res = np.zeros_like(k_mag, dtype=complex)
|
|
221
|
+
mask = k_mag > 0
|
|
222
|
+
|
|
223
|
+
theta = np.zeros_like(k_mag)
|
|
224
|
+
theta[mask] = np.arccos(np.clip(kz[mask] / k_mag[mask], -1, 1))
|
|
225
|
+
|
|
226
|
+
diff = theta - theta_0
|
|
227
|
+
ring_profile = np.exp(-(diff**2) / (2 * sigma_theta**2))
|
|
228
|
+
|
|
229
|
+
if l != 0:
|
|
230
|
+
phi = np.arctan2(ky, kx) # shape (N,)
|
|
231
|
+
vortex = np.exp(1j * l * phi) # shape (N,)
|
|
232
|
+
res[mask] = (ring_profile[mask] * vortex[mask])
|
|
233
|
+
else:
|
|
234
|
+
res[mask] = ring_profile[mask]
|
|
235
|
+
|
|
236
|
+
return res
|
|
237
|
+
|
|
238
|
+
class PolychromaticSpectra:
|
|
239
|
+
"""
|
|
240
|
+
Implementations of Polychromatic Envelopes.
|
|
241
|
+
|
|
242
|
+
All functions here take a wavelength and spectral parameters,
|
|
243
|
+
returning a real scalar weight for that specific wavelength.
|
|
244
|
+
"""
|
|
245
|
+
|
|
246
|
+
@staticmethod
|
|
247
|
+
def uniform(wavelength: float, **kwargs) -> float:
|
|
248
|
+
"""
|
|
249
|
+
Flat spectral envelope.
|
|
250
|
+
|
|
251
|
+
Formula:
|
|
252
|
+
F(lambda) = 1.0
|
|
253
|
+
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
wavelength : float
|
|
257
|
+
The wavelength to evaluate.
|
|
258
|
+
|
|
259
|
+
Returns
|
|
260
|
+
-------
|
|
261
|
+
float
|
|
262
|
+
Weight of 1.0 for all inputs.
|
|
263
|
+
"""
|
|
264
|
+
return 1.0
|
|
265
|
+
|
|
266
|
+
@staticmethod
|
|
267
|
+
def gaussian(wl: float, center: float, sigma: float) -> float:
|
|
268
|
+
"""
|
|
269
|
+
Gaussian spectral weight distribution.
|
|
270
|
+
|
|
271
|
+
Formula:
|
|
272
|
+
F(lambda) = exp( -(lambda - center)^2 / (2 * sigma^2) )
|
|
273
|
+
|
|
274
|
+
Parameters
|
|
275
|
+
----------
|
|
276
|
+
wl : float
|
|
277
|
+
The wavelength to evaluate.
|
|
278
|
+
center : float
|
|
279
|
+
The central wavelength (mean).
|
|
280
|
+
sigma : float
|
|
281
|
+
The spectral bandwidth (standard deviation).
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
float
|
|
286
|
+
Real scalar weight for the given wavelength.
|
|
287
|
+
"""
|
|
288
|
+
return float(np.exp(-(wl - center)**2 / (2 * sigma**2)))
|
|
289
|
+
|
|
290
|
+
@staticmethod
|
|
291
|
+
def lorentzian(wl: float, center: float, gamma: float) -> float:
|
|
292
|
+
"""
|
|
293
|
+
Lorentzian spectral weight distribution.
|
|
294
|
+
|
|
295
|
+
Often models natural line-broadening in atomic emission.
|
|
296
|
+
|
|
297
|
+
Formula:
|
|
298
|
+
F(lambda) = gamma^2 / ( (lambda - center)^2 + gamma^2 )
|
|
299
|
+
|
|
300
|
+
Parameters
|
|
301
|
+
----------
|
|
302
|
+
wl : float
|
|
303
|
+
The wavelength to evaluate.
|
|
304
|
+
center : float
|
|
305
|
+
The central resonance wavelength.
|
|
306
|
+
gamma : float
|
|
307
|
+
The Half-Width at Half-Maximum (HWHM) of the spectrum.
|
|
308
|
+
|
|
309
|
+
Returns
|
|
310
|
+
-------
|
|
311
|
+
float
|
|
312
|
+
Real scalar weight for the given wavelength.
|
|
313
|
+
"""
|
|
314
|
+
return float(gamma**2 / ((wl - center)**2 + gamma**2))
|
|
315
|
+
|
|
316
|
+
@staticmethod
|
|
317
|
+
def tophat(wl: float, center: float, width: float) -> float:
|
|
318
|
+
"""
|
|
319
|
+
Top-hat (Rectangular) spectral weight distribution.
|
|
320
|
+
|
|
321
|
+
Idealized bandpass filter.
|
|
322
|
+
|
|
323
|
+
Formula:
|
|
324
|
+
F(lambda) = 1.0 if |lambda - center| <= width / 2
|
|
325
|
+
F(lambda) = 0.0 otherwise
|
|
326
|
+
|
|
327
|
+
Parameters
|
|
328
|
+
----------
|
|
329
|
+
wl : float
|
|
330
|
+
The wavelength to evaluate.
|
|
331
|
+
center : float
|
|
332
|
+
The central wavelength of the bandpass.
|
|
333
|
+
width : float
|
|
334
|
+
The total spectral width of the bandpass.
|
|
335
|
+
|
|
336
|
+
Returns
|
|
337
|
+
-------
|
|
338
|
+
float
|
|
339
|
+
Real scalar weight (1.0 or 0.0).
|
|
340
|
+
"""
|
|
341
|
+
return 1.0 if abs(wl - center) <= width / 2 else 0.0
|
vectorwaves/utils.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility Functions
|
|
3
|
+
=================
|
|
4
|
+
|
|
5
|
+
Miscellaneous helper functions for calculating optical properties,
|
|
6
|
+
polarization ellipses, and basis transformations.
|
|
7
|
+
"""
|
|
8
|
+
from typing import Dict, Union, Tuple
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
def get_stokes_params(E1: np.ndarray, E2: np.ndarray, normalize: bool = False) -> Dict[str, np.ndarray]:
|
|
12
|
+
"""
|
|
13
|
+
Computes Stokes parameters from two orthogonal electric field components.
|
|
14
|
+
|
|
15
|
+
For a beam propagating along the Z-axis, you can pass `FieldResult.E[0]` (Ex)
|
|
16
|
+
and `FieldResult.E[1]` (Ey) to calculate the transverse Stokes parameters.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
E1, E2 : np.ndarray
|
|
21
|
+
Complex electric field components of the same shape.
|
|
22
|
+
normalize : bool, optional
|
|
23
|
+
If True, returns the normalized Stokes parameters (s1, s2, s3) where
|
|
24
|
+
s_i = S_i / S0. Defaults to False.
|
|
25
|
+
|
|
26
|
+
Returns
|
|
27
|
+
-------
|
|
28
|
+
dict
|
|
29
|
+
- If normalize=True: {'S0': ..., 's1': ..., 's2': ..., 's3': ...}
|
|
30
|
+
- If normalize=False: {'S0': ..., 'S1': ..., 'S2': ..., 'S3': ...}
|
|
31
|
+
"""
|
|
32
|
+
I1 = np.abs(E1)**2
|
|
33
|
+
I2 = np.abs(E2)**2
|
|
34
|
+
|
|
35
|
+
S0 = I1 + I2
|
|
36
|
+
S1 = I1 - I2
|
|
37
|
+
|
|
38
|
+
# Calculate cross term
|
|
39
|
+
cross_term = E1 * np.conj(E2)
|
|
40
|
+
S2 = 2 * np.real(cross_term)
|
|
41
|
+
S3 = 2 * np.imag(cross_term)
|
|
42
|
+
|
|
43
|
+
if normalize:
|
|
44
|
+
denom = np.where(S0 == 0, 1.0, S0)
|
|
45
|
+
return {'S0': S0, 's1': S1/denom, 's2': S2/denom, 's3': S3/denom}
|
|
46
|
+
|
|
47
|
+
return {'S0': S0, 'S1': S1, 'S2': S2, 'S3': S3}
|
|
48
|
+
|
|
49
|
+
def get_pol_ellipse_params(E1: np.ndarray, E2: np.ndarray) -> Dict[str, np.ndarray]:
|
|
50
|
+
"""
|
|
51
|
+
Calculates the geometric properties of the polarization ellipse
|
|
52
|
+
formed by two orthogonal electric field components.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
E1, E2 : np.ndarray
|
|
57
|
+
Complex electric field components of the same shape.
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
dict
|
|
62
|
+
Dictionary containing arrays of the same shape as inputs:
|
|
63
|
+
- 'psi': Orientation angle in[-pi/2, pi/2]
|
|
64
|
+
- 'chi': Ellipticity angle in [-pi/4, pi/4]
|
|
65
|
+
- 'delta': Phase difference (phi_2 - phi_1) in range [-pi, pi]
|
|
66
|
+
- 'a': Semi-major axis length (normalized to local intensity)
|
|
67
|
+
- 'b': Semi-minor axis length (normalized to local intensity)
|
|
68
|
+
- 'handedness': +1 for LCP/CCW, -1 for RCP/CW (based on S3 sign)
|
|
69
|
+
"""
|
|
70
|
+
stokes = get_stokes_params(E1, E2, normalize=True)
|
|
71
|
+
S0, s1, s2, s3 = stokes['S0'], stokes['s1'], stokes['s2'], stokes['s3']
|
|
72
|
+
|
|
73
|
+
# 1. Orientation Angle (Psi)
|
|
74
|
+
psi = 0.5 * np.arctan2(s2, s1)
|
|
75
|
+
|
|
76
|
+
# 2. Ellipticity Angle (Chi)
|
|
77
|
+
s3_norm = np.clip(s3, -1.0, 1.0)
|
|
78
|
+
chi = 0.5 * np.arcsin(s3_norm)
|
|
79
|
+
|
|
80
|
+
# 3. Phase Difference (Delta)
|
|
81
|
+
delta = np.angle(E2 * np.conj(E1))
|
|
82
|
+
|
|
83
|
+
# 4. Geometry for Plotting (Semi-axes)
|
|
84
|
+
amp = np.sqrt(S0)
|
|
85
|
+
a = amp * np.cos(chi)
|
|
86
|
+
b = amp * np.abs(np.sin(chi))
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
'psi': psi,
|
|
90
|
+
'chi': chi,
|
|
91
|
+
'delta': delta,
|
|
92
|
+
'a': a,
|
|
93
|
+
'b': b,
|
|
94
|
+
'handedness': np.sign(s3)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
def decompose_in_basis(E1: np.ndarray, E2: np.ndarray, u: Union[Tuple[complex, complex], np.ndarray]) -> Dict[str, np.ndarray]:
|
|
98
|
+
"""
|
|
99
|
+
Decomposes a 2-component complex field (E1, E2) into an orthonormal
|
|
100
|
+
polarization basis defined by the reference vector `u`.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
E1, E2 : np.ndarray
|
|
105
|
+
Complex arrays representing the field in the original basis.
|
|
106
|
+
u : tuple or np.ndarray
|
|
107
|
+
Reference vector (2,) defining the first new basis vector (in the same plane).
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
dict
|
|
112
|
+
Contains the new basis vectors and the projected field components:
|
|
113
|
+
{'u_hat': array, 'v_hat': array, 'E_u': array, 'E_v': array}
|
|
114
|
+
"""
|
|
115
|
+
u_arr = np.asarray(u, dtype=complex)
|
|
116
|
+
norm = np.linalg.norm(u_arr)
|
|
117
|
+
u_hat = u_arr / norm if norm > 0 else u_arr
|
|
118
|
+
|
|
119
|
+
# Construct orthogonal vector v_hat
|
|
120
|
+
v_hat = np.array([-np.conj(u_hat[1]), np.conj(u_hat[0])], dtype=complex)
|
|
121
|
+
|
|
122
|
+
E_u = np.conj(u_hat[0]) * E1 + np.conj(u_hat[1]) * E2
|
|
123
|
+
E_v = np.conj(v_hat[0]) * E1 + np.conj(v_hat[1]) * E2
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
"E_u": E_u,
|
|
127
|
+
"E_v": E_v,
|
|
128
|
+
"u_hat": u_hat,
|
|
129
|
+
"v_hat": v_hat,
|
|
130
|
+
}
|
vectorwaves/version.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vectorwaves
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Three-dimensional electromagnetic field simulation and topology analysis
|
|
5
|
+
Author: Mayank Soni
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Mayank Soni
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
Project-URL: Homepage, https://github.com/1Rayokelvin/VectorWaves
|
|
28
|
+
Project-URL: Repository, https://github.com/1Rayokelvin/VectorWaves
|
|
29
|
+
Project-URL: Issues, https://github.com/1Rayokelvin/VectorWaves/issues
|
|
30
|
+
Project-URL: Documentation, https://1rayokelvin.github.io/VectorWaves
|
|
31
|
+
Keywords: physics,optics,wave-optics,vector-optics,electromagnetism,electromagnetic-fields,structured-light,gaussian-beams,laguerre-gaussian,plane-wave-expansion,computational-physics,optical-singularities,polarization-singularities,phase-singularities,topological-optics,optical-vortices
|
|
32
|
+
Classifier: Development Status :: 4 - Beta
|
|
33
|
+
Classifier: Intended Audience :: Science/Research
|
|
34
|
+
Classifier: Intended Audience :: Education
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Operating System :: OS Independent
|
|
42
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
43
|
+
Classifier: Topic :: Scientific/Engineering
|
|
44
|
+
Requires-Python: >=3.10
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
License-File: LICENSE
|
|
47
|
+
Requires-Dist: numpy>=1.24.0
|
|
48
|
+
Requires-Dist: scipy>=1.10.0
|
|
49
|
+
Requires-Dist: numba>=0.59.0
|
|
50
|
+
Provides-Extra: viz
|
|
51
|
+
Requires-Dist: matplotlib>=3.7.0; extra == "viz"
|
|
52
|
+
Requires-Dist: pyvista>=0.40.0; extra == "viz"
|
|
53
|
+
Provides-Extra: progress
|
|
54
|
+
Requires-Dist: tqdm>=4.65.0; extra == "progress"
|
|
55
|
+
Provides-Extra: gpu
|
|
56
|
+
Requires-Dist: cupy-cuda12x>=12.0.0; extra == "gpu"
|
|
57
|
+
Provides-Extra: all
|
|
58
|
+
Requires-Dist: matplotlib>=3.7.0; extra == "all"
|
|
59
|
+
Requires-Dist: pyvista>=0.40.0; extra == "all"
|
|
60
|
+
Requires-Dist: tqdm>=4.65.0; extra == "all"
|
|
61
|
+
Requires-Dist: cupy-cuda12x>=12.0.0; extra == "all"
|
|
62
|
+
Dynamic: license-file
|
|
63
|
+
|
|
64
|
+
VectorWaves provides a framework for generating, computing, and analyzing fully three-dimensional electromagnetic fields and their topology through discrete plane-wave expansions.
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install vectorwaves
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
For additional features, you can install the optional dependencies:
|
|
73
|
+
|
|
74
|
+
| Extra | Purpose |
|
|
75
|
+
|---------|---------|
|
|
76
|
+
| `viz` | Matplotlib and PyVista for visualizations |
|
|
77
|
+
| `progress` | Progress bars via tqdm |
|
|
78
|
+
| `gpu` | CUDA acceleration via CuPy |
|
|
79
|
+
| `all` | All the above |
|
|
80
|
+
|
|
81
|
+
To install,
|
|
82
|
+
```bash
|
|
83
|
+
pip install vectorwaves[extra]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Features
|
|
87
|
+
|
|
88
|
+
- Physics-oriented configuration system with `numpy`, `numba`, and CuPy (GPU) backends.
|
|
89
|
+
- Exact non-paraxial 3D propagation via Fibonacci-sphere discrete plane-wave expansions.
|
|
90
|
+
- Monochromatic and polychromatic sources with arbitrary envelopes, structured light support.
|
|
91
|
+
- Stochastic process generation for speckle-like fields.
|
|
92
|
+
- Fully analytic computation of E-fields, B-fields, spatial derivatives.
|
|
93
|
+
- Topological polarization analysis: C, Cᵀ, and Lᵀ point finding with 3D line tracing.
|
|
94
|
+
|
|
95
|
+
## Quick Example
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import vectorwaves as vw
|
|
99
|
+
|
|
100
|
+
# Generate a tightly-focused Laguerre-Gaussian beam
|
|
101
|
+
config = vw.get_config()
|
|
102
|
+
config.source.k_space.laguerre_gauss(p=1, l=2, sigma_k_perp=1)
|
|
103
|
+
config.source.randomize.off()
|
|
104
|
+
|
|
105
|
+
# Construct the beam and visualize its plane-wave modes
|
|
106
|
+
beam = vw.setup_beam(config)
|
|
107
|
+
|
|
108
|
+
# Requires matplotlib, install with 'viz' extra: pip install vectorwaves[viz]
|
|
109
|
+
beam.plot_kspace_3d(plot_type='colored_vectors')
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+

|
|
113
|
+
|
|
114
|
+
For tutorials and examples, please refer to the [official documentation](https://1rayokelvin.github.io/VectorWaves). Source code is available on [GitHub](https://github.com/1Rayokelvin/VectorWaves/).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
vectorwaves/__init__.py,sha256=Rwj_-tdL6plfvaJL32xb1KXSfsZhO65YuyCC1akDBTc,1946
|
|
2
|
+
vectorwaves/beam_stuff.py,sha256=K83C7oeftVECI-EFjUkvh48bh_V94QYCjnteZoHxPik,24702
|
|
3
|
+
vectorwaves/config_stuff.py,sha256=hR6Z1woNeG4LrDtepidVwXykz4BGQQzJfrmaRJna_rY,29366
|
|
4
|
+
vectorwaves/engine_stuff.py,sha256=yDW0moLDotWJJ0s4yK9Q4ZF-Po9ZXokBPZ8LpVS65ns,13036
|
|
5
|
+
vectorwaves/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
vectorwaves/singularities.py,sha256=BkN0OJdDPzzp_5hbezVifGO-y8ERkUlHkkJ4aXWvcTE,29030
|
|
7
|
+
vectorwaves/spectra.py,sha256=jqZboP7SYneFB_L7KWbzlkhygSk-WmWorNKbgAIhmns,11050
|
|
8
|
+
vectorwaves/utils.py,sha256=gQh4qCjy6ADsCVqSlypEgoZLM72bafiQU5wX4IBnt2w,4150
|
|
9
|
+
vectorwaves/version.py,sha256=HhR0jXvoPPIUm_TZEYrtIkepM8kImipNVYUUXhnyY98,118
|
|
10
|
+
vectorwaves/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
vectorwaves/backends/cupy_backend.py,sha256=ih26VgQfaZrThup2Z0zHTFFDV6WsMro7lLAsOpiCmwQ,8213
|
|
12
|
+
vectorwaves/backends/numba_backend.py,sha256=sapN0XeC9dpQNTxU28njbV9sSjnzyvE9ACHXhJy_wKg,11364
|
|
13
|
+
vectorwaves/backends/numpy_backend.py,sha256=8qj8OdiSeW1D0NPlVopwb9TTFqFjfzFr5ZBz9CL_Vj0,7212
|
|
14
|
+
vectorwaves-1.0.0.dist-info/licenses/LICENSE,sha256=MXeu576i1y4CBMZHHPxEe1VUAetK1JJ-uGg2vqM-8y4,1087
|
|
15
|
+
vectorwaves-1.0.0.dist-info/METADATA,sha256=f_klnEXzh_sirGdTaNrdj0yOaN6HLsoDJ5lDHYfY7H8,5151
|
|
16
|
+
vectorwaves-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
17
|
+
vectorwaves-1.0.0.dist-info/top_level.txt,sha256=jpIC3lf8s6nySEu9pjTMjkK-kmtLARl07cvHdmEwl9g,12
|
|
18
|
+
vectorwaves-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mayank Soni
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vectorwaves
|