|
|
|
@ -179,8 +179,9 @@ to account for numerical dispersion if the result is introduced into a space wit
|
|
|
|
|
# TODO update module docs
|
|
|
|
|
|
|
|
|
|
from typing import List, Tuple, Optional, Any
|
|
|
|
|
import numpy # type: ignore
|
|
|
|
|
from numpy.linalg import norm # type: ignore
|
|
|
|
|
import numpy
|
|
|
|
|
from numpy.typing import NDArray, ArrayLike
|
|
|
|
|
from numpy.linalg import norm
|
|
|
|
|
import scipy.sparse as sparse # type: ignore
|
|
|
|
|
|
|
|
|
|
from ..fdmath.operators import deriv_forward, deriv_back, cross
|
|
|
|
@ -191,7 +192,8 @@ from ..eigensolvers import signed_eigensolve, rayleigh_quotient_iteration
|
|
|
|
|
__author__ = 'Jan Petykiewicz'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def operator_e(omega: complex,
|
|
|
|
|
def operator_e(
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
@ -257,7 +259,8 @@ def operator_e(omega: complex,
|
|
|
|
|
return op
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def operator_h(omega: complex,
|
|
|
|
|
def operator_h(
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
|
mu: Optional[vfdfield_t] = None,
|
|
|
|
@ -324,7 +327,8 @@ def operator_h(omega: complex,
|
|
|
|
|
return op
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def normalized_fields_e(e_xy: numpy.ndarray,
|
|
|
|
|
def normalized_fields_e(
|
|
|
|
|
e_xy: ArrayLike,
|
|
|
|
|
wavenumber: complex,
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
@ -358,7 +362,8 @@ def normalized_fields_e(e_xy: numpy.ndarray,
|
|
|
|
|
return e_norm, h_norm
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def normalized_fields_h(h_xy: numpy.ndarray,
|
|
|
|
|
def normalized_fields_h(
|
|
|
|
|
h_xy: ArrayLike,
|
|
|
|
|
wavenumber: complex,
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
@ -392,8 +397,9 @@ def normalized_fields_h(h_xy: numpy.ndarray,
|
|
|
|
|
return e_norm, h_norm
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _normalized_fields(e: numpy.ndarray,
|
|
|
|
|
h: numpy.ndarray,
|
|
|
|
|
def _normalized_fields(
|
|
|
|
|
e: ArrayLike,
|
|
|
|
|
h: ArrayLike,
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
@ -434,7 +440,8 @@ def _normalized_fields(e: numpy.ndarray,
|
|
|
|
|
return e, h
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def exy2h(wavenumber: complex,
|
|
|
|
|
def exy2h(
|
|
|
|
|
wavenumber: complex,
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
@ -459,7 +466,8 @@ def exy2h(wavenumber: complex,
|
|
|
|
|
return e2hop @ exy2e(wavenumber=wavenumber, dxes=dxes, epsilon=epsilon)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def hxy2e(wavenumber: complex,
|
|
|
|
|
def hxy2e(
|
|
|
|
|
wavenumber: complex,
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
@ -484,7 +492,8 @@ def hxy2e(wavenumber: complex,
|
|
|
|
|
return h2eop @ hxy2h(wavenumber=wavenumber, dxes=dxes, mu=mu)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def hxy2h(wavenumber: complex,
|
|
|
|
|
def hxy2h(
|
|
|
|
|
wavenumber: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
@ -517,7 +526,8 @@ def hxy2h(wavenumber: complex,
|
|
|
|
|
return op
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def exy2e(wavenumber: complex,
|
|
|
|
|
def exy2e(
|
|
|
|
|
wavenumber: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
|
) -> sparse.spmatrix:
|
|
|
|
@ -550,7 +560,8 @@ def exy2e(wavenumber: complex,
|
|
|
|
|
return op
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def e2h(wavenumber: complex,
|
|
|
|
|
def e2h(
|
|
|
|
|
wavenumber: complex,
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
@ -574,7 +585,8 @@ def e2h(wavenumber: complex,
|
|
|
|
|
return op
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def h2e(wavenumber: complex,
|
|
|
|
|
def h2e(
|
|
|
|
|
wavenumber: complex,
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
epsilon: vfdfield_t
|
|
|
|
@ -636,12 +648,13 @@ def curl_h(wavenumber: complex, dxes: dx_lists_t) -> sparse.spmatrix:
|
|
|
|
|
return cross([Dbx, Dby, Bz])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def h_err(h: vfdfield_t,
|
|
|
|
|
def h_err(
|
|
|
|
|
h: vfdfield_t,
|
|
|
|
|
wavenumber: complex,
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
|
mu: vfdfield_t = None
|
|
|
|
|
mu: Optional[vfdfield_t] = None
|
|
|
|
|
) -> float:
|
|
|
|
|
"""
|
|
|
|
|
Calculates the relative error in the H field
|
|
|
|
@ -670,12 +683,13 @@ def h_err(h: vfdfield_t,
|
|
|
|
|
return norm(op) / norm(h)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def e_err(e: vfdfield_t,
|
|
|
|
|
def e_err(
|
|
|
|
|
e: vfdfield_t,
|
|
|
|
|
wavenumber: complex,
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
|
mu: vfdfield_t = None
|
|
|
|
|
mu: vfdfield_t = Optional[None]
|
|
|
|
|
) -> float:
|
|
|
|
|
"""
|
|
|
|
|
Calculates the relative error in the E field
|
|
|
|
@ -703,13 +717,14 @@ def e_err(e: vfdfield_t,
|
|
|
|
|
return norm(op) / norm(e)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def solve_modes(mode_numbers: List[int],
|
|
|
|
|
def solve_modes(
|
|
|
|
|
mode_numbers: List[int],
|
|
|
|
|
omega: complex,
|
|
|
|
|
dxes: dx_lists_t,
|
|
|
|
|
epsilon: vfdfield_t,
|
|
|
|
|
mu: vfdfield_t = None,
|
|
|
|
|
mode_margin: int = 2,
|
|
|
|
|
) -> Tuple[numpy.ndarray, List[complex]]:
|
|
|
|
|
) -> Tuple[NDArray[numpy.float64], List[complex]]:
|
|
|
|
|
"""
|
|
|
|
|
Given a 2D region, attempts to solve for the eigenmode with the specified mode numbers.
|
|
|
|
|
|
|
|
|
@ -752,7 +767,8 @@ def solve_modes(mode_numbers: List[int],
|
|
|
|
|
return e_xys, wavenumbers
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def solve_mode(mode_number: int,
|
|
|
|
|
def solve_mode(
|
|
|
|
|
mode_number: int,
|
|
|
|
|
*args: Any,
|
|
|
|
|
**kwargs: Any,
|
|
|
|
|
) -> Tuple[vfdfield_t, complex]:
|
|
|
|
|