|
|
@ -179,8 +179,9 @@ to account for numerical dispersion if the result is introduced into a space wit
|
|
|
|
# TODO update module docs
|
|
|
|
# TODO update module docs
|
|
|
|
|
|
|
|
|
|
|
|
from typing import List, Tuple, Optional, Any
|
|
|
|
from typing import List, Tuple, Optional, Any
|
|
|
|
import numpy # type: ignore
|
|
|
|
import numpy
|
|
|
|
from numpy.linalg import norm # type: ignore
|
|
|
|
from numpy.typing import NDArray, ArrayLike
|
|
|
|
|
|
|
|
from numpy.linalg import norm
|
|
|
|
import scipy.sparse as sparse # type: ignore
|
|
|
|
import scipy.sparse as sparse # type: ignore
|
|
|
|
|
|
|
|
|
|
|
|
from ..fdmath.operators import deriv_forward, deriv_back, cross
|
|
|
|
from ..fdmath.operators import deriv_forward, deriv_back, cross
|
|
|
@ -191,11 +192,12 @@ from ..eigensolvers import signed_eigensolve, rayleigh_quotient_iteration
|
|
|
|
__author__ = 'Jan Petykiewicz'
|
|
|
|
__author__ = 'Jan Petykiewicz'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def operator_e(omega: complex,
|
|
|
|
def operator_e(
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
omega: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Waveguide operator of the form
|
|
|
|
Waveguide operator of the form
|
|
|
|
|
|
|
|
|
|
|
@ -257,11 +259,12 @@ def operator_e(omega: complex,
|
|
|
|
return op
|
|
|
|
return op
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def operator_h(omega: complex,
|
|
|
|
def operator_h(
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
omega: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Waveguide operator of the form
|
|
|
|
Waveguide operator of the form
|
|
|
|
|
|
|
|
|
|
|
@ -324,14 +327,15 @@ def operator_h(omega: complex,
|
|
|
|
return op
|
|
|
|
return op
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def normalized_fields_e(e_xy: numpy.ndarray,
|
|
|
|
def normalized_fields_e(
|
|
|
|
wavenumber: complex,
|
|
|
|
e_xy: ArrayLike,
|
|
|
|
omega: complex,
|
|
|
|
wavenumber: complex,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
omega: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
prop_phase: float = 0,
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
) -> Tuple[vfdfield_t, vfdfield_t]:
|
|
|
|
prop_phase: float = 0,
|
|
|
|
|
|
|
|
) -> Tuple[vfdfield_t, vfdfield_t]:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Given a vector `e_xy` containing the vectorized E_x and E_y fields,
|
|
|
|
Given a vector `e_xy` containing the vectorized E_x and E_y fields,
|
|
|
|
returns normalized, vectorized E and H fields for the system.
|
|
|
|
returns normalized, vectorized E and H fields for the system.
|
|
|
@ -358,14 +362,15 @@ def normalized_fields_e(e_xy: numpy.ndarray,
|
|
|
|
return e_norm, h_norm
|
|
|
|
return e_norm, h_norm
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def normalized_fields_h(h_xy: numpy.ndarray,
|
|
|
|
def normalized_fields_h(
|
|
|
|
wavenumber: complex,
|
|
|
|
h_xy: ArrayLike,
|
|
|
|
omega: complex,
|
|
|
|
wavenumber: complex,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
omega: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
prop_phase: float = 0,
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
) -> Tuple[vfdfield_t, vfdfield_t]:
|
|
|
|
prop_phase: float = 0,
|
|
|
|
|
|
|
|
) -> Tuple[vfdfield_t, vfdfield_t]:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Given a vector `h_xy` containing the vectorized H_x and H_y fields,
|
|
|
|
Given a vector `h_xy` containing the vectorized H_x and H_y fields,
|
|
|
|
returns normalized, vectorized E and H fields for the system.
|
|
|
|
returns normalized, vectorized E and H fields for the system.
|
|
|
@ -392,14 +397,15 @@ def normalized_fields_h(h_xy: numpy.ndarray,
|
|
|
|
return e_norm, h_norm
|
|
|
|
return e_norm, h_norm
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _normalized_fields(e: numpy.ndarray,
|
|
|
|
def _normalized_fields(
|
|
|
|
h: numpy.ndarray,
|
|
|
|
e: ArrayLike,
|
|
|
|
omega: complex,
|
|
|
|
h: ArrayLike,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
omega: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
prop_phase: float = 0,
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
) -> Tuple[vfdfield_t, vfdfield_t]:
|
|
|
|
prop_phase: float = 0,
|
|
|
|
|
|
|
|
) -> Tuple[vfdfield_t, vfdfield_t]:
|
|
|
|
# TODO documentation
|
|
|
|
# TODO documentation
|
|
|
|
shape = [s.size for s in dxes[0]]
|
|
|
|
shape = [s.size for s in dxes[0]]
|
|
|
|
dxes_real = [[numpy.real(d) for d in numpy.meshgrid(*dxes[v], indexing='ij')] for v in (0, 1)]
|
|
|
|
dxes_real = [[numpy.real(d) for d in numpy.meshgrid(*dxes[v], indexing='ij')] for v in (0, 1)]
|
|
|
@ -434,12 +440,13 @@ def _normalized_fields(e: numpy.ndarray,
|
|
|
|
return e, h
|
|
|
|
return e, h
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def exy2h(wavenumber: complex,
|
|
|
|
def exy2h(
|
|
|
|
omega: complex,
|
|
|
|
wavenumber: complex,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
omega: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Operator which transforms the vector `e_xy` containing the vectorized E_x and E_y fields,
|
|
|
|
Operator which transforms the vector `e_xy` containing the vectorized E_x and E_y fields,
|
|
|
|
into a vectorized H containing all three H components
|
|
|
|
into a vectorized H containing all three H components
|
|
|
@ -459,12 +466,13 @@ def exy2h(wavenumber: complex,
|
|
|
|
return e2hop @ exy2e(wavenumber=wavenumber, dxes=dxes, epsilon=epsilon)
|
|
|
|
return e2hop @ exy2e(wavenumber=wavenumber, dxes=dxes, epsilon=epsilon)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def hxy2e(wavenumber: complex,
|
|
|
|
def hxy2e(
|
|
|
|
omega: complex,
|
|
|
|
wavenumber: complex,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
omega: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Operator which transforms the vector `h_xy` containing the vectorized H_x and H_y fields,
|
|
|
|
Operator which transforms the vector `h_xy` containing the vectorized H_x and H_y fields,
|
|
|
|
into a vectorized E containing all three E components
|
|
|
|
into a vectorized E containing all three E components
|
|
|
@ -484,10 +492,11 @@ def hxy2e(wavenumber: complex,
|
|
|
|
return h2eop @ hxy2h(wavenumber=wavenumber, dxes=dxes, mu=mu)
|
|
|
|
return h2eop @ hxy2h(wavenumber=wavenumber, dxes=dxes, mu=mu)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def hxy2h(wavenumber: complex,
|
|
|
|
def hxy2h(
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
wavenumber: complex,
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Operator which transforms the vector `h_xy` containing the vectorized H_x and H_y fields,
|
|
|
|
Operator which transforms the vector `h_xy` containing the vectorized H_x and H_y fields,
|
|
|
|
into a vectorized H containing all three H components
|
|
|
|
into a vectorized H containing all three H components
|
|
|
@ -517,10 +526,11 @@ def hxy2h(wavenumber: complex,
|
|
|
|
return op
|
|
|
|
return op
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def exy2e(wavenumber: complex,
|
|
|
|
def exy2e(
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
wavenumber: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Operator which transforms the vector `e_xy` containing the vectorized E_x and E_y fields,
|
|
|
|
Operator which transforms the vector `e_xy` containing the vectorized E_x and E_y fields,
|
|
|
|
into a vectorized E containing all three E components
|
|
|
|
into a vectorized E containing all three E components
|
|
|
@ -550,7 +560,8 @@ def exy2e(wavenumber: complex,
|
|
|
|
return op
|
|
|
|
return op
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def e2h(wavenumber: complex,
|
|
|
|
def e2h(
|
|
|
|
|
|
|
|
wavenumber: complex,
|
|
|
|
omega: complex,
|
|
|
|
omega: complex,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
@ -574,7 +585,8 @@ def e2h(wavenumber: complex,
|
|
|
|
return op
|
|
|
|
return op
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def h2e(wavenumber: complex,
|
|
|
|
def h2e(
|
|
|
|
|
|
|
|
wavenumber: complex,
|
|
|
|
omega: complex,
|
|
|
|
omega: complex,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
epsilon: vfdfield_t
|
|
|
|
epsilon: vfdfield_t
|
|
|
@ -636,13 +648,14 @@ def curl_h(wavenumber: complex, dxes: dx_lists_t) -> sparse.spmatrix:
|
|
|
|
return cross([Dbx, Dby, Bz])
|
|
|
|
return cross([Dbx, Dby, Bz])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def h_err(h: vfdfield_t,
|
|
|
|
def h_err(
|
|
|
|
wavenumber: complex,
|
|
|
|
h: vfdfield_t,
|
|
|
|
omega: complex,
|
|
|
|
wavenumber: complex,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
omega: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: vfdfield_t = None
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
) -> float:
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
|
|
|
|
) -> float:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Calculates the relative error in the H field
|
|
|
|
Calculates the relative error in the H field
|
|
|
|
|
|
|
|
|
|
|
@ -670,13 +683,14 @@ def h_err(h: vfdfield_t,
|
|
|
|
return norm(op) / norm(h)
|
|
|
|
return norm(op) / norm(h)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def e_err(e: vfdfield_t,
|
|
|
|
def e_err(
|
|
|
|
wavenumber: complex,
|
|
|
|
e: vfdfield_t,
|
|
|
|
omega: complex,
|
|
|
|
wavenumber: complex,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
omega: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: vfdfield_t = None
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
) -> float:
|
|
|
|
mu: vfdfield_t = Optional[None]
|
|
|
|
|
|
|
|
) -> float:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Calculates the relative error in the E field
|
|
|
|
Calculates the relative error in the E field
|
|
|
|
|
|
|
|
|
|
|
@ -703,13 +717,14 @@ def e_err(e: vfdfield_t,
|
|
|
|
return norm(op) / norm(e)
|
|
|
|
return norm(op) / norm(e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def solve_modes(mode_numbers: List[int],
|
|
|
|
def solve_modes(
|
|
|
|
omega: complex,
|
|
|
|
mode_numbers: List[int],
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
omega: complex,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
mu: vfdfield_t = None,
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
mode_margin: int = 2,
|
|
|
|
mu: vfdfield_t = None,
|
|
|
|
) -> Tuple[numpy.ndarray, List[complex]]:
|
|
|
|
mode_margin: int = 2,
|
|
|
|
|
|
|
|
) -> Tuple[NDArray[numpy.float64], List[complex]]:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Given a 2D region, attempts to solve for the eigenmode with the specified mode numbers.
|
|
|
|
Given a 2D region, attempts to solve for the eigenmode with the specified mode numbers.
|
|
|
|
|
|
|
|
|
|
|
@ -752,10 +767,11 @@ def solve_modes(mode_numbers: List[int],
|
|
|
|
return e_xys, wavenumbers
|
|
|
|
return e_xys, wavenumbers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def solve_mode(mode_number: int,
|
|
|
|
def solve_mode(
|
|
|
|
*args: Any,
|
|
|
|
mode_number: int,
|
|
|
|
**kwargs: Any,
|
|
|
|
*args: Any,
|
|
|
|
) -> Tuple[vfdfield_t, complex]:
|
|
|
|
**kwargs: Any,
|
|
|
|
|
|
|
|
) -> Tuple[vfdfield_t, complex]:
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Wrapper around `solve_modes()` that solves for a single mode.
|
|
|
|
Wrapper around `solve_modes()` that solves for a single mode.
|
|
|
|
|
|
|
|
|
|
|
|