Change comments to new format
This commit is contained in:
parent
dcc9e7c2ad
commit
f69b8c9f11
@ -20,9 +20,10 @@ def perturbed_l3(a: float, radius: float, **kwargs) -> Pattern:
|
|||||||
"""
|
"""
|
||||||
Generate a masque.Pattern object containing a perturbed L3 cavity.
|
Generate a masque.Pattern object containing a perturbed L3 cavity.
|
||||||
|
|
||||||
:param a: Lattice constant.
|
Args:
|
||||||
:param radius: Hole radius, in units of a (lattice constant).
|
a: Lattice constant.
|
||||||
:param kwargs: Keyword arguments:
|
radius: Hole radius, in units of a (lattice constant).
|
||||||
|
**kwargs: Keyword arguments:
|
||||||
hole_dose, trench_dose, hole_layer, trench_layer: Shape properties for Pattern.
|
hole_dose, trench_dose, hole_layer, trench_layer: Shape properties for Pattern.
|
||||||
Defaults *_dose=1, hole_layer=0, trench_layer=1.
|
Defaults *_dose=1, hole_layer=0, trench_layer=1.
|
||||||
shifts_a, shifts_r: passed to pcgen.l3_shift; specifies lattice constant (1 -
|
shifts_a, shifts_r: passed to pcgen.l3_shift; specifies lattice constant (1 -
|
||||||
@ -30,11 +31,13 @@ def perturbed_l3(a: float, radius: float, **kwargs) -> Pattern:
|
|||||||
holes adjacent to the defect (same row). Defaults are 0.15 shift for
|
holes adjacent to the defect (same row). Defaults are 0.15 shift for
|
||||||
first hole, 0.075 shift for third hole, and no radius change.
|
first hole, 0.075 shift for third hole, and no radius change.
|
||||||
xy_size: [x, y] number of mirror periods in each direction; total size is
|
xy_size: [x, y] number of mirror periods in each direction; total size is
|
||||||
2 * n + 1 holes in each direction. Default [10, 10].
|
`2 * n + 1` holes in each direction. Default `[10, 10]`.
|
||||||
perturbed_radius: radius of holes perturbed to form an upwards-driected beam
|
perturbed_radius: radius of holes perturbed to form an upwards-driected beam
|
||||||
(multiplicative factor). Default 1.1.
|
(multiplicative factor). Default 1.1.
|
||||||
trench width: Width of the undercut trenches. Default 1.2e3.
|
trench width: Width of the undercut trenches. Default 1.2e3.
|
||||||
:return: masque.Pattern object containing the L3 design
|
|
||||||
|
Return:
|
||||||
|
`masque.Pattern` object containing the L3 design
|
||||||
"""
|
"""
|
||||||
|
|
||||||
default_args = {'hole_dose': 1,
|
default_args = {'hole_dose': 1,
|
||||||
|
@ -4,47 +4,54 @@ Bloch eigenmode solver/operators
|
|||||||
This module contains functions for generating and solving the
|
This module contains functions for generating and solving the
|
||||||
3D Bloch eigenproblem. The approach is to transform the problem
|
3D Bloch eigenproblem. The approach is to transform the problem
|
||||||
into the (spatial) fourier domain, transforming the equation
|
into the (spatial) fourier domain, transforming the equation
|
||||||
1/mu * curl(1/eps * curl(H)) = (w/c)^2 H
|
|
||||||
|
1/mu * curl(1/eps * curl(H)) = (w/c)^2 H
|
||||||
|
|
||||||
into
|
into
|
||||||
conv(1/mu_k, ik x conv(1/eps_k, ik x H_k)) = (w/c)^2 H_k
|
|
||||||
|
conv(1/mu_k, ik x conv(1/eps_k, ik x H_k)) = (w/c)^2 H_k
|
||||||
|
|
||||||
where:
|
where:
|
||||||
- the _k subscript denotes a 3D fourier transformed field
|
|
||||||
- each component of H_k corresponds to a plane wave with wavevector k
|
|
||||||
- x is the cross product
|
|
||||||
- conv denotes convolution
|
|
||||||
|
|
||||||
Since k and H are orthogonal for each plane wave, we can use each
|
- the `_k` subscript denotes a 3D fourier transformed field
|
||||||
k to create an orthogonal basis (k, m, n), with k x m = n, and
|
- each component of `H_k` corresponds to a plane wave with wavevector `k`
|
||||||
|m| = |n| = 1. The cross products are then simplified with
|
- `x` is the cross product
|
||||||
|
- `conv()` denotes convolution
|
||||||
|
|
||||||
k @ h = kx hx + ky hy + kz hz = 0 = hk
|
Since `k` and `H` are orthogonal for each plane wave, we can use each
|
||||||
h = hk + hm + hn = hm + hn
|
`k` to create an orthogonal basis (k, m, n), with `k x m = n`, and
|
||||||
k = kk + km + kn = kk = |k|
|
`|m| = |n| = 1`. The cross products are then simplified with
|
||||||
|
|
||||||
k x h = (ky hz - kz hy,
|
k @ h = kx hx + ky hy + kz hz = 0 = hk
|
||||||
kz hx - kx hz,
|
h = hk + hm + hn = hm + hn
|
||||||
kx hy - ky hx)
|
k = kk + km + kn = kk = |k|
|
||||||
= ((k x h) @ k, (k x h) @ m, (k x h) @ n)_kmn
|
|
||||||
= (0, (m x k) @ h, (n x k) @ h)_kmn # triple product ordering
|
|
||||||
= (0, kk (-n @ h), kk (m @ h))_kmn # (m x k) = -|k| n, etc.
|
|
||||||
= |k| (0, -h @ n, h @ m)_kmn
|
|
||||||
|
|
||||||
k x h = (km hn - kn hm,
|
k x h = (ky hz - kz hy,
|
||||||
kn hk - kk hn,
|
kz hx - kx hz,
|
||||||
kk hm - km hk)_kmn
|
kx hy - ky hx)
|
||||||
= (0, -kk hn, kk hm)_kmn
|
= ((k x h) @ k, (k x h) @ m, (k x h) @ n)_kmn
|
||||||
= (-kk hn)(mx, my, mz) + (kk hm)(nx, ny, nz)
|
= (0, (m x k) @ h, (n x k) @ h)_kmn # triple product ordering
|
||||||
= |k| (hm * (nx, ny, nz) - hn * (mx, my, mz))
|
= (0, kk (-n @ h), kk (m @ h))_kmn # (m x k) = -|k| n, etc.
|
||||||
|
= |k| (0, -h @ n, h @ m)_kmn
|
||||||
|
|
||||||
where h is shorthand for H_k, (...)_kmn deontes the (k, m, n) basis,
|
k x h = (km hn - kn hm,
|
||||||
and e.g. hm is the component of h in the m direction.
|
kn hk - kk hn,
|
||||||
|
kk hm - km hk)_kmn
|
||||||
|
= (0, -kk hn, kk hm)_kmn
|
||||||
|
= (-kk hn)(mx, my, mz) + (kk hm)(nx, ny, nz)
|
||||||
|
= |k| (hm * (nx, ny, nz) - hn * (mx, my, mz))
|
||||||
|
|
||||||
We can also simplify conv(X_k, Y_k) as fftn(X * ifftn(Y_k)).
|
where `h` is shorthand for `H_k`, `(...)_kmn` deontes the `(k, m, n)` basis,
|
||||||
|
and e.g. `hm` is the component of `h` in the `m` direction.
|
||||||
|
|
||||||
|
We can also simplify `conv(X_k, Y_k)` as `fftn(X * ifftn(Y_k))`.
|
||||||
|
|
||||||
|
Using these results and storing `H_k` as `h = (hm, hn)`, we have
|
||||||
|
|
||||||
|
e_xyz = fftn(1/eps * ifftn(|k| (hm * n - hn * m)))
|
||||||
|
b_mn = |k| (-e_xyz @ n, e_xyz @ m)
|
||||||
|
h_mn = fftn(1/mu * ifftn(b_m * m + b_n * n))
|
||||||
|
|
||||||
Using these results and storing H_k as h = (hm, hn), we have
|
|
||||||
e_xyz = fftn(1/eps * ifftn(|k| (hm * n - hn * m)))
|
|
||||||
b_mn = |k| (-e_xyz @ n, e_xyz @ m)
|
|
||||||
h_mn = fftn(1/mu * ifftn(b_m * m + b_n * n))
|
|
||||||
which forms the operator from the left side of the equation.
|
which forms the operator from the left side of the equation.
|
||||||
|
|
||||||
We can then use a preconditioned block Rayleigh iteration algorithm, as in
|
We can then use a preconditioned block Rayleigh iteration algorithm, as in
|
||||||
@ -120,12 +127,15 @@ def generate_kmn(k0: numpy.ndarray,
|
|||||||
"""
|
"""
|
||||||
Generate a (k, m, n) orthogonal basis for each k-vector in the simulation grid.
|
Generate a (k, m, n) orthogonal basis for each k-vector in the simulation grid.
|
||||||
|
|
||||||
:param k0: [k0x, k0y, k0z], Bloch wavevector, in G basis.
|
Args:
|
||||||
:param G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
k0: [k0x, k0y, k0z], Bloch wavevector, in G basis.
|
||||||
:param shape: [nx, ny, nz] shape of the simulation grid.
|
G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
||||||
:return: (|k|, m, n) where |k| has shape tuple(shape) + (1,)
|
shape: [nx, ny, nz] shape of the simulation grid.
|
||||||
and m, n have shape tuple(shape) + (3,).
|
|
||||||
All are given in the xyz basis (e.g. |k|[0,0,0] = norm(G_matrix @ k0)).
|
Returns:
|
||||||
|
`(|k|, m, n)` where `|k|` has shape `tuple(shape) + (1,)`
|
||||||
|
and `m`, `n` have shape `tuple(shape) + (3,)`.
|
||||||
|
All are given in the xyz basis (e.g. `|k|[0,0,0] = norm(G_matrix @ k0)`).
|
||||||
"""
|
"""
|
||||||
k0 = numpy.array(k0)
|
k0 = numpy.array(k0)
|
||||||
|
|
||||||
@ -159,21 +169,27 @@ def maxwell_operator(k0: numpy.ndarray,
|
|||||||
) -> Callable[[numpy.ndarray], numpy.ndarray]:
|
) -> Callable[[numpy.ndarray], numpy.ndarray]:
|
||||||
"""
|
"""
|
||||||
Generate the Maxwell operator
|
Generate the Maxwell operator
|
||||||
|
|
||||||
conv(1/mu_k, ik x conv(1/eps_k, ik x ___))
|
conv(1/mu_k, ik x conv(1/eps_k, ik x ___))
|
||||||
|
|
||||||
which is the spatial-frequency-space representation of
|
which is the spatial-frequency-space representation of
|
||||||
|
|
||||||
1/mu * curl(1/eps * curl(___))
|
1/mu * curl(1/eps * curl(___))
|
||||||
|
|
||||||
The operator is a function that acts on a vector h_mn of size (2 * epsilon[0].size)
|
The operator is a function that acts on a vector h_mn of size `2 * epsilon[0].size`
|
||||||
|
|
||||||
See the module-level docstring for more information.
|
See the `meanas.fdfd.bloch` docstring for more information.
|
||||||
|
|
||||||
:param k0: Bloch wavevector, [k0x, k0y, k0z].
|
Args:
|
||||||
:param G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
k0: Bloch wavevector, `[k0x, k0y, k0z]`.
|
||||||
:param epsilon: Dielectric constant distribution for the simulation.
|
G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
||||||
All fields are sampled at cell centers (i.e., NOT Yee-gridded)
|
epsilon: Dielectric constant distribution for the simulation.
|
||||||
:param mu: Magnetic permability distribution for the simulation.
|
All fields are sampled at cell centers (i.e., NOT Yee-gridded)
|
||||||
Default None (1 everywhere).
|
mu: Magnetic permability distribution for the simulation.
|
||||||
:return: Function which applies the maxwell operator to h_mn.
|
Default None (1 everywhere).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Function which applies the maxwell operator to h_mn.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
shape = epsilon[0].shape + (1,)
|
shape = epsilon[0].shape + (1,)
|
||||||
@ -189,8 +205,11 @@ def maxwell_operator(k0: numpy.ndarray,
|
|||||||
|
|
||||||
h is complex 2-field in (m, n) basis, vectorized
|
h is complex 2-field in (m, n) basis, vectorized
|
||||||
|
|
||||||
:param h: Raveled h_mn; size (2 * epsilon[0].size).
|
Args:
|
||||||
:return: Raveled conv(1/mu_k, ik x conv(1/eps_k, ik x h_mn)).
|
h: Raveled h_mn; size `2 * epsilon[0].size`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Raveled conv(1/mu_k, ik x conv(1/eps_k, ik x h_mn)).
|
||||||
"""
|
"""
|
||||||
hin_m, hin_n = [hi.reshape(shape) for hi in numpy.split(h, 2)]
|
hin_m, hin_n = [hi.reshape(shape) for hi in numpy.split(h, 2)]
|
||||||
|
|
||||||
@ -231,18 +250,22 @@ def hmn_2_exyz(k0: numpy.ndarray,
|
|||||||
) -> Callable[[numpy.ndarray], fdfield_t]:
|
) -> Callable[[numpy.ndarray], fdfield_t]:
|
||||||
"""
|
"""
|
||||||
Generate an operator which converts a vectorized spatial-frequency-space
|
Generate an operator which converts a vectorized spatial-frequency-space
|
||||||
h_mn into an E-field distribution, i.e.
|
`h_mn` into an E-field distribution, i.e.
|
||||||
|
|
||||||
ifft(conv(1/eps_k, ik x h_mn))
|
ifft(conv(1/eps_k, ik x h_mn))
|
||||||
|
|
||||||
The operator is a function that acts on a vector h_mn of size (2 * epsilon[0].size)
|
The operator is a function that acts on a vector `h_mn` of size `2 * epsilon[0].size`.
|
||||||
|
|
||||||
See the module-level docstring for more information.
|
See the `meanas.fdfd.bloch` docstring for more information.
|
||||||
|
|
||||||
:param k0: Bloch wavevector, [k0x, k0y, k0z].
|
Args:
|
||||||
:param G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
k0: Bloch wavevector, `[k0x, k0y, k0z]`.
|
||||||
:param epsilon: Dielectric constant distribution for the simulation.
|
G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
||||||
All fields are sampled at cell centers (i.e., NOT Yee-gridded)
|
epsilon: Dielectric constant distribution for the simulation.
|
||||||
:return: Function for converting h_mn into E_xyz
|
All fields are sampled at cell centers (i.e., NOT Yee-gridded)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Function for converting `h_mn` into `E_xyz`
|
||||||
"""
|
"""
|
||||||
shape = epsilon[0].shape + (1,)
|
shape = epsilon[0].shape + (1,)
|
||||||
epsilon = numpy.stack(epsilon, 3)
|
epsilon = numpy.stack(epsilon, 3)
|
||||||
@ -266,18 +289,22 @@ def hmn_2_hxyz(k0: numpy.ndarray,
|
|||||||
) -> Callable[[numpy.ndarray], fdfield_t]:
|
) -> Callable[[numpy.ndarray], fdfield_t]:
|
||||||
"""
|
"""
|
||||||
Generate an operator which converts a vectorized spatial-frequency-space
|
Generate an operator which converts a vectorized spatial-frequency-space
|
||||||
h_mn into an H-field distribution, i.e.
|
`h_mn` into an H-field distribution, i.e.
|
||||||
|
|
||||||
ifft(h_mn)
|
ifft(h_mn)
|
||||||
|
|
||||||
The operator is a function that acts on a vector h_mn of size (2 * epsilon[0].size)
|
The operator is a function that acts on a vector `h_mn` of size `2 * epsilon[0].size`.
|
||||||
|
|
||||||
See the module-level docstring for more information.
|
See the `meanas.fdfd.bloch` docstring for more information.
|
||||||
|
|
||||||
:param k0: Bloch wavevector, [k0x, k0y, k0z].
|
Args:
|
||||||
:param G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
k0: Bloch wavevector, `[k0x, k0y, k0z]`.
|
||||||
:param epsilon: Dielectric constant distribution for the simulation.
|
G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
||||||
Only epsilon[0].shape is used.
|
epsilon: Dielectric constant distribution for the simulation.
|
||||||
:return: Function for converting h_mn into H_xyz
|
Only `epsilon[0].shape` is used.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Function for converting `h_mn` into `H_xyz`
|
||||||
"""
|
"""
|
||||||
shape = epsilon[0].shape + (1,)
|
shape = epsilon[0].shape + (1,)
|
||||||
_k_mag, m, n = generate_kmn(k0, G_matrix, shape)
|
_k_mag, m, n = generate_kmn(k0, G_matrix, shape)
|
||||||
@ -298,18 +325,23 @@ def inverse_maxwell_operator_approx(k0: numpy.ndarray,
|
|||||||
) -> Callable[[numpy.ndarray], numpy.ndarray]:
|
) -> Callable[[numpy.ndarray], numpy.ndarray]:
|
||||||
"""
|
"""
|
||||||
Generate an approximate inverse of the Maxwell operator,
|
Generate an approximate inverse of the Maxwell operator,
|
||||||
|
|
||||||
ik x conv(eps_k, ik x conv(mu_k, ___))
|
ik x conv(eps_k, ik x conv(mu_k, ___))
|
||||||
|
|
||||||
which can be used to improve the speed of ARPACK in shift-invert mode.
|
which can be used to improve the speed of ARPACK in shift-invert mode.
|
||||||
|
|
||||||
See the module-level docstring for more information.
|
See the `meanas.fdfd.bloch` docstring for more information.
|
||||||
|
|
||||||
:param k0: Bloch wavevector, [k0x, k0y, k0z].
|
Args:
|
||||||
:param G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
k0: Bloch wavevector, `[k0x, k0y, k0z]`.
|
||||||
:param epsilon: Dielectric constant distribution for the simulation.
|
G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
||||||
All fields are sampled at cell centers (i.e., NOT Yee-gridded)
|
epsilon: Dielectric constant distribution for the simulation.
|
||||||
:param mu: Magnetic permability distribution for the simulation.
|
All fields are sampled at cell centers (i.e., NOT Yee-gridded)
|
||||||
Default None (1 everywhere).
|
mu: Magnetic permability distribution for the simulation.
|
||||||
:return: Function which applies the approximate inverse of the maxwell operator to h_mn.
|
Default None (1 everywhere).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Function which applies the approximate inverse of the maxwell operator to `h_mn`.
|
||||||
"""
|
"""
|
||||||
shape = epsilon[0].shape + (1,)
|
shape = epsilon[0].shape + (1,)
|
||||||
epsilon = numpy.stack(epsilon, 3)
|
epsilon = numpy.stack(epsilon, 3)
|
||||||
@ -325,8 +357,11 @@ def inverse_maxwell_operator_approx(k0: numpy.ndarray,
|
|||||||
|
|
||||||
h is complex 2-field in (m, n) basis, vectorized
|
h is complex 2-field in (m, n) basis, vectorized
|
||||||
|
|
||||||
:param h: Raveled h_mn; size (2 * epsilon[0].size).
|
Args:
|
||||||
:return: Raveled ik x conv(eps_k, ik x conv(mu_k, h_mn))
|
h: Raveled h_mn; size `2 * epsilon[0].size`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Raveled ik x conv(eps_k, ik x conv(mu_k, h_mn))
|
||||||
"""
|
"""
|
||||||
hin_m, hin_n = [hi.reshape(shape) for hi in numpy.split(h, 2)]
|
hin_m, hin_n = [hi.reshape(shape) for hi in numpy.split(h, 2)]
|
||||||
|
|
||||||
@ -376,16 +411,20 @@ def find_k(frequency: float,
|
|||||||
"""
|
"""
|
||||||
Search for a bloch vector that has a given frequency.
|
Search for a bloch vector that has a given frequency.
|
||||||
|
|
||||||
:param frequency: Target frequency.
|
Args:
|
||||||
:param tolerance: Target frequency tolerance.
|
frequency: Target frequency.
|
||||||
:param direction: k-vector direction to search along.
|
tolerance: Target frequency tolerance.
|
||||||
:param G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
direction: k-vector direction to search along.
|
||||||
:param epsilon: Dielectric constant distribution for the simulation.
|
G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
||||||
All fields are sampled at cell centers (i.e., NOT Yee-gridded)
|
epsilon: Dielectric constant distribution for the simulation.
|
||||||
:param mu: Magnetic permability distribution for the simulation.
|
All fields are sampled at cell centers (i.e., NOT Yee-gridded)
|
||||||
Default None (1 everywhere).
|
mu: Magnetic permability distribution for the simulation.
|
||||||
:param band: Which band to search in. Default 0 (lowest frequency).
|
Default None (1 everywhere).
|
||||||
return: (k, actual_frequency) The found k-vector and its frequency
|
band: Which band to search in. Default 0 (lowest frequency).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
`(k, actual_frequency)`
|
||||||
|
The found k-vector and its frequency.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
direction = numpy.array(direction) / norm(direction)
|
direction = numpy.array(direction) / norm(direction)
|
||||||
@ -419,16 +458,19 @@ def eigsolve(num_modes: int,
|
|||||||
Find the first (lowest-frequency) num_modes eigenmodes with Bloch wavevector
|
Find the first (lowest-frequency) num_modes eigenmodes with Bloch wavevector
|
||||||
k0 of the specified structure.
|
k0 of the specified structure.
|
||||||
|
|
||||||
:param k0: Bloch wavevector, [k0x, k0y, k0z].
|
Args:
|
||||||
:param G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
k0: Bloch wavevector, `[k0x, k0y, k0z]`.
|
||||||
:param epsilon: Dielectric constant distribution for the simulation.
|
G_matrix: 3x3 matrix, with reciprocal lattice vectors as columns.
|
||||||
All fields are sampled at cell centers (i.e., NOT Yee-gridded)
|
epsilon: Dielectric constant distribution for the simulation.
|
||||||
:param mu: Magnetic permability distribution for the simulation.
|
All fields are sampled at cell centers (i.e., NOT Yee-gridded)
|
||||||
Default None (1 everywhere).
|
mu: Magnetic permability distribution for the simulation.
|
||||||
:param tolerance: Solver stops when fractional change in the objective
|
Default `None` (1 everywhere).
|
||||||
trace(Z.H @ A @ Z @ inv(Z Z.H)) is smaller than the tolerance
|
tolerance: Solver stops when fractional change in the objective
|
||||||
:return: (eigenvalues, eigenvectors) where eigenvalues[i] corresponds to the
|
`trace(Z.H @ A @ Z @ inv(Z Z.H))` is smaller than the tolerance
|
||||||
vector eigenvectors[i, :]
|
|
||||||
|
Returns:
|
||||||
|
`(eigenvalues, eigenvectors)` where `eigenvalues[i]` corresponds to the
|
||||||
|
vector `eigenvectors[i, :]`
|
||||||
"""
|
"""
|
||||||
h_size = 2 * epsilon[0].size
|
h_size = 2 * epsilon[0].size
|
||||||
|
|
||||||
|
@ -21,27 +21,31 @@ def near_to_farfield(E_near: fdfield_t,
|
|||||||
|
|
||||||
The input fields should be complex phasors.
|
The input fields should be complex phasors.
|
||||||
|
|
||||||
:param E_near: List of 2 ndarrays containing the 2D phasor field slices for the transverse
|
Args:
|
||||||
E fields (e.g. [Ex, Ey] for calculating the farfield toward the z-direction).
|
E_near: List of 2 ndarrays containing the 2D phasor field slices for the transverse
|
||||||
:param H_near: List of 2 ndarrays containing the 2D phasor field slices for the transverse
|
E fields (e.g. [Ex, Ey] for calculating the farfield toward the z-direction).
|
||||||
H fields (e.g. [Hx, hy] for calculating the farfield towrad the z-direction).
|
H_near: List of 2 ndarrays containing the 2D phasor field slices for the transverse
|
||||||
:param dx: Cell size along x-dimension, in units of wavelength.
|
H fields (e.g. [Hx, hy] for calculating the farfield towrad the z-direction).
|
||||||
:param dy: Cell size along y-dimension, in units of wavelength.
|
dx: Cell size along x-dimension, in units of wavelength.
|
||||||
:param padded_size: Shape of the output. A single integer `n` will be expanded to `(n, n)`.
|
dy: Cell size along y-dimension, in units of wavelength.
|
||||||
Powers of 2 are most efficient for FFT computation.
|
padded_size: Shape of the output. A single integer `n` will be expanded to `(n, n)`.
|
||||||
Default is the smallest power of 2 larger than the input, for each axis.
|
Powers of 2 are most efficient for FFT computation.
|
||||||
:returns: Dict with keys
|
Default is the smallest power of 2 larger than the input, for each axis.
|
||||||
'E_far': Normalized E-field farfield; multiply by
|
|
||||||
(i k exp(-i k r) / (4 pi r)) to get the actual field value.
|
Returns:
|
||||||
'H_far': Normalized H-field farfield; multiply by
|
Dict with keys
|
||||||
(i k exp(-i k r) / (4 pi r)) to get the actual field value.
|
|
||||||
'kx', 'ky': Wavevector values corresponding to the x- and y- axes in E_far and H_far,
|
- `E_far`: Normalized E-field farfield; multiply by
|
||||||
normalized to wavelength (dimensionless).
|
(i k exp(-i k r) / (4 pi r)) to get the actual field value.
|
||||||
'dkx', 'dky': step size for kx and ky, normalized to wavelength.
|
- `H_far`: Normalized H-field farfield; multiply by
|
||||||
'theta': arctan2(ky, kx) corresponding to each (kx, ky).
|
(i k exp(-i k r) / (4 pi r)) to get the actual field value.
|
||||||
This is the angle in the x-y plane, counterclockwise from above, starting from +x.
|
- `kx`, `ky`: Wavevector values corresponding to the x- and y- axes in E_far and H_far,
|
||||||
'phi': arccos(kz / k) corresponding to each (kx, ky).
|
normalized to wavelength (dimensionless).
|
||||||
This is the angle away from +z.
|
- `dkx`, `dky`: step size for kx and ky, normalized to wavelength.
|
||||||
|
- `theta`: arctan2(ky, kx) corresponding to each (kx, ky).
|
||||||
|
This is the angle in the x-y plane, counterclockwise from above, starting from +x.
|
||||||
|
- `phi`: arccos(kz / k) corresponding to each (kx, ky).
|
||||||
|
This is the angle away from +z.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not len(E_near) == 2:
|
if not len(E_near) == 2:
|
||||||
@ -129,23 +133,27 @@ def far_to_nearfield(E_far: fdfield_t,
|
|||||||
|
|
||||||
The input fields should be complex phasors.
|
The input fields should be complex phasors.
|
||||||
|
|
||||||
:param E_far: List of 2 ndarrays containing the 2D phasor field slices for the transverse
|
Args:
|
||||||
E fields (e.g. [Ex, Ey] for calculating the nearfield toward the z-direction).
|
E_far: List of 2 ndarrays containing the 2D phasor field slices for the transverse
|
||||||
Fields should be normalized so that
|
E fields (e.g. [Ex, Ey] for calculating the nearfield toward the z-direction).
|
||||||
E_far = E_far_actual / (i k exp(-i k r) / (4 pi r))
|
Fields should be normalized so that
|
||||||
:param H_far: List of 2 ndarrays containing the 2D phasor field slices for the transverse
|
E_far = E_far_actual / (i k exp(-i k r) / (4 pi r))
|
||||||
H fields (e.g. [Hx, hy] for calculating the nearfield toward the z-direction).
|
H_far: List of 2 ndarrays containing the 2D phasor field slices for the transverse
|
||||||
Fields should be normalized so that
|
H fields (e.g. [Hx, hy] for calculating the nearfield toward the z-direction).
|
||||||
H_far = H_far_actual / (i k exp(-i k r) / (4 pi r))
|
Fields should be normalized so that
|
||||||
:param dkx: kx discretization, in units of wavelength.
|
H_far = H_far_actual / (i k exp(-i k r) / (4 pi r))
|
||||||
:param dky: ky discretization, in units of wavelength.
|
dkx: kx discretization, in units of wavelength.
|
||||||
:param padded_size: Shape of the output. A single integer `n` will be expanded to `(n, n)`.
|
dky: ky discretization, in units of wavelength.
|
||||||
Powers of 2 are most efficient for FFT computation.
|
padded_size: Shape of the output. A single integer `n` will be expanded to `(n, n)`.
|
||||||
Default is the smallest power of 2 larger than the input, for each axis.
|
Powers of 2 are most efficient for FFT computation.
|
||||||
:returns: Dict with keys
|
Default is the smallest power of 2 larger than the input, for each axis.
|
||||||
'E': E-field nearfield
|
|
||||||
'H': H-field nearfield
|
Returns:
|
||||||
'dx', 'dy': spatial discretization, normalized to wavelength (dimensionless)
|
Dict with keys
|
||||||
|
|
||||||
|
- `E`: E-field nearfield
|
||||||
|
- `H`: H-field nearfield
|
||||||
|
- `dx`, `dy`: spatial discretization, normalized to wavelength (dimensionless)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not len(E_far) == 2:
|
if not len(E_far) == 2:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
Functions for moving between a vector field (list of 3 ndarrays, [f_x, f_y, f_z])
|
Functions for moving between a vector field (list of 3 ndarrays, `[f_x, f_y, f_z]`)
|
||||||
and a 1D array representation of that field [f_x0, f_x1, f_x2,... f_y0,... f_z0,...].
|
and a 1D array representation of that field `[f_x0, f_x1, f_x2,... f_y0,... f_z0,...]`.
|
||||||
Vectorized versions of the field use row-major (ie., C-style) ordering.
|
Vectorized versions of the field use row-major (ie., C-style) ordering.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -17,11 +17,14 @@ def vec(f: fdfield_t) -> vfdfield_t:
|
|||||||
"""
|
"""
|
||||||
Create a 1D ndarray from a 3D vector field which spans a 1-3D region.
|
Create a 1D ndarray from a 3D vector field which spans a 1-3D region.
|
||||||
|
|
||||||
Returns None if called with f=None.
|
Returns `None` if called with `f=None`.
|
||||||
|
|
||||||
:param f: A vector field, [f_x, f_y, f_z] where each f_ component is a 1 to
|
Args:
|
||||||
3D ndarray (f_* should all be the same size). Doesn't fail with f=None.
|
f: A vector field, `[f_x, f_y, f_z]` where each `f_` component is a 1- to
|
||||||
:return: A 1D ndarray containing the linearized field (or None)
|
3-D ndarray (`f_*` should all be the same size). Doesn't fail with `f=None`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
1D ndarray containing the linearized field (or `None`)
|
||||||
"""
|
"""
|
||||||
if numpy.any(numpy.equal(f, None)):
|
if numpy.any(numpy.equal(f, None)):
|
||||||
return None
|
return None
|
||||||
@ -31,15 +34,17 @@ def vec(f: fdfield_t) -> vfdfield_t:
|
|||||||
def unvec(v: vfdfield_t, shape: numpy.ndarray) -> fdfield_t:
|
def unvec(v: vfdfield_t, shape: numpy.ndarray) -> fdfield_t:
|
||||||
"""
|
"""
|
||||||
Perform the inverse of vec(): take a 1D ndarray and output a 3D field
|
Perform the inverse of vec(): take a 1D ndarray and output a 3D field
|
||||||
of form [f_x, f_y, f_z] where each of f_* is a len(shape)-dimensional
|
of form `[f_x, f_y, f_z]` where each of `f_*` is a len(shape)-dimensional
|
||||||
ndarray.
|
ndarray.
|
||||||
|
|
||||||
Returns None if called with v=None.
|
Returns `None` if called with `v=None`.
|
||||||
|
|
||||||
:param v: 1D ndarray representing a 3D vector field of shape shape (or None)
|
Args:
|
||||||
:param shape: shape of the vector field
|
v: 1D ndarray representing a 3D vector field of shape shape (or None)
|
||||||
:return: [f_x, f_y, f_z] where each f_ is a len(shape) dimensional ndarray
|
shape: shape of the vector field
|
||||||
(or None)
|
|
||||||
|
Returns:
|
||||||
|
`[f_x, f_y, f_z]` where each `f_` is a `len(shape)` dimensional ndarray (or `None`)
|
||||||
"""
|
"""
|
||||||
if numpy.any(numpy.equal(v, None)):
|
if numpy.any(numpy.equal(v, None)):
|
||||||
return None
|
return None
|
||||||
|
Loading…
Reference in New Issue
Block a user