Change comments to new format

This commit is contained in:
Jan Petykiewicz 2020-01-07 21:31:16 -08:00
parent dcc9e7c2ad
commit f69b8c9f11
4 changed files with 208 additions and 150 deletions

View File

@ -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,

View File

@ -4,18 +4,23 @@ 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
into
conv(1/mu_k, ik x conv(1/eps_k, ik x H_k)) = (w/c)^2 H_k
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 1/mu * curl(1/eps * curl(H)) = (w/c)^2 H
k to create an orthogonal basis (k, m, n), with k x m = n, and
|m| = |n| = 1. The cross products are then simplified with into
conv(1/mu_k, ik x conv(1/eps_k, ik x H_k)) = (w/c)^2 H_k
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
`k` to create an orthogonal basis (k, m, n), with `k x m = n`, and
`|m| = |n| = 1`. The cross products are then simplified with
k @ h = kx hx + ky hy + kz hz = 0 = hk k @ h = kx hx + ky hy + kz hz = 0 = hk
h = hk + hm + hn = hm + hn h = hk + hm + hn = hm + hn
@ -36,15 +41,17 @@ This module contains functions for generating and solving the
= (-kk hn)(mx, my, mz) + (kk hm)(nx, ny, nz) = (-kk hn)(mx, my, mz) + (kk hm)(nx, ny, nz)
= |k| (hm * (nx, ny, nz) - hn * (mx, my, mz)) = |k| (hm * (nx, ny, nz) - hn * (mx, my, mz))
where h is shorthand for H_k, (...)_kmn deontes the (k, m, n) basis, 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. 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)). 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
Using these results and storing H_k as h = (hm, hn), we have
e_xyz = fftn(1/eps * ifftn(|k| (hm * n - hn * m))) e_xyz = fftn(1/eps * ifftn(|k| (hm * n - hn * m)))
b_mn = |k| (-e_xyz @ n, e_xyz @ m) b_mn = |k| (-e_xyz @ n, e_xyz @ m)
h_mn = fftn(1/mu * ifftn(b_m * m + b_n * n)) 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.
epsilon: Dielectric constant distribution for the simulation.
All fields are sampled at cell centers (i.e., NOT Yee-gridded) All fields are sampled at cell centers (i.e., NOT Yee-gridded)
:param mu: Magnetic permability distribution for the simulation. mu: Magnetic permability distribution for the simulation.
Default None (1 everywhere). Default None (1 everywhere).
:return: Function which applies the maxwell operator to h_mn.
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.
epsilon: Dielectric constant distribution for the simulation.
All fields are sampled at cell centers (i.e., NOT Yee-gridded) All fields are sampled at cell centers (i.e., NOT Yee-gridded)
:return: Function for converting h_mn into E_xyz
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.
epsilon: Dielectric constant distribution for the simulation.
All fields are sampled at cell centers (i.e., NOT Yee-gridded) All fields are sampled at cell centers (i.e., NOT Yee-gridded)
:param mu: Magnetic permability distribution for the simulation. mu: Magnetic permability distribution for the simulation.
Default None (1 everywhere). Default None (1 everywhere).
:return: Function which applies the approximate inverse of the maxwell operator to h_mn.
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.
epsilon: Dielectric constant distribution for the simulation.
All fields are sampled at cell centers (i.e., NOT Yee-gridded) All fields are sampled at cell centers (i.e., NOT Yee-gridded)
:param mu: Magnetic permability distribution for the simulation. mu: Magnetic permability distribution for the simulation.
Default None (1 everywhere). Default None (1 everywhere).
:param band: Which band to search in. Default 0 (lowest frequency). band: Which band to search in. Default 0 (lowest frequency).
return: (k, actual_frequency) The found k-vector and its 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.
epsilon: Dielectric constant distribution for the simulation.
All fields are sampled at cell centers (i.e., NOT Yee-gridded) All fields are sampled at cell centers (i.e., NOT Yee-gridded)
:param mu: Magnetic permability distribution for the simulation. mu: Magnetic permability distribution for the simulation.
Default None (1 everywhere). Default `None` (1 everywhere).
:param tolerance: Solver stops when fractional change in the objective tolerance: Solver stops when fractional change in the objective
trace(Z.H @ A @ Z @ inv(Z Z.H)) is smaller than the tolerance `trace(Z.H @ A @ Z @ inv(Z Z.H))` is smaller than the tolerance
:return: (eigenvalues, eigenvectors) where eigenvalues[i] corresponds to the
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

View File

@ -21,26 +21,30 @@ 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_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). E fields (e.g. [Ex, Ey] for calculating the farfield toward the z-direction).
:param H_near: List of 2 ndarrays containing the 2D phasor field slices for the transverse H_near: List of 2 ndarrays containing the 2D phasor field slices for the transverse
H fields (e.g. [Hx, hy] for calculating the farfield towrad the z-direction). H fields (e.g. [Hx, hy] for calculating the farfield towrad the z-direction).
:param dx: Cell size along x-dimension, in units of wavelength. dx: Cell size along x-dimension, in units of wavelength.
:param dy: Cell size along y-dimension, in units of wavelength. dy: Cell size along y-dimension, in units of wavelength.
:param padded_size: Shape of the output. A single integer `n` will be expanded to `(n, n)`. padded_size: Shape of the output. A single integer `n` will be expanded to `(n, n)`.
Powers of 2 are most efficient for FFT computation. Powers of 2 are most efficient for FFT computation.
Default is the smallest power of 2 larger than the input, for each axis. Default is the smallest power of 2 larger than the input, for each axis.
:returns: Dict with keys
'E_far': Normalized E-field farfield; multiply by Returns:
Dict with keys
- `E_far`: Normalized E-field farfield; multiply by
(i k exp(-i k r) / (4 pi r)) to get the actual field value. (i k exp(-i k r) / (4 pi r)) to get the actual field value.
'H_far': Normalized H-field farfield; multiply by - `H_far`: Normalized H-field farfield; multiply by
(i k exp(-i k r) / (4 pi r)) to get the actual field value. (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, - `kx`, `ky`: Wavevector values corresponding to the x- and y- axes in E_far and H_far,
normalized to wavelength (dimensionless). normalized to wavelength (dimensionless).
'dkx', 'dky': step size for kx and ky, normalized to wavelength. - `dkx`, `dky`: step size for kx and ky, normalized to wavelength.
'theta': arctan2(ky, kx) corresponding to each (kx, ky). - `theta`: arctan2(ky, kx) corresponding to each (kx, ky).
This is the angle in the x-y plane, counterclockwise from above, starting from +x. This is the angle in the x-y plane, counterclockwise from above, starting from +x.
'phi': arccos(kz / k) corresponding to each (kx, ky). - `phi`: arccos(kz / k) corresponding to each (kx, ky).
This is the angle away from +z. This is the angle away from +z.
""" """
@ -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_far: List of 2 ndarrays containing the 2D phasor field slices for the transverse
E fields (e.g. [Ex, Ey] for calculating the nearfield toward the z-direction). E fields (e.g. [Ex, Ey] for calculating the nearfield toward the z-direction).
Fields should be normalized so that Fields should be normalized so that
E_far = E_far_actual / (i k exp(-i k r) / (4 pi r)) E_far = E_far_actual / (i k exp(-i k r) / (4 pi r))
:param H_far: List of 2 ndarrays containing the 2D phasor field slices for the transverse H_far: List of 2 ndarrays containing the 2D phasor field slices for the transverse
H fields (e.g. [Hx, hy] for calculating the nearfield toward the z-direction). H fields (e.g. [Hx, hy] for calculating the nearfield toward the z-direction).
Fields should be normalized so that Fields should be normalized so that
H_far = H_far_actual / (i k exp(-i k r) / (4 pi r)) H_far = H_far_actual / (i k exp(-i k r) / (4 pi r))
:param dkx: kx discretization, in units of wavelength. dkx: kx discretization, in units of wavelength.
:param dky: ky discretization, in units of wavelength. dky: ky discretization, in units of wavelength.
:param padded_size: Shape of the output. A single integer `n` will be expanded to `(n, n)`. padded_size: Shape of the output. A single integer `n` will be expanded to `(n, n)`.
Powers of 2 are most efficient for FFT computation. Powers of 2 are most efficient for FFT computation.
Default is the smallest power of 2 larger than the input, for each axis. Default is the smallest power of 2 larger than the input, for each axis.
:returns: Dict with keys
'E': E-field nearfield Returns:
'H': H-field nearfield Dict with keys
'dx', 'dy': spatial discretization, normalized to wavelength (dimensionless)
- `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:

View File

@ -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