[docs] expand API and derivation docs
This commit is contained in:
parent
0568e1ba50
commit
5e95d66a7e
12 changed files with 608 additions and 127 deletions
|
|
@ -175,8 +175,6 @@ if the result is introduced into a space with a discretized z-axis.
|
|||
|
||||
|
||||
"""
|
||||
# TODO update module docs
|
||||
|
||||
from typing import Any
|
||||
from collections.abc import Sequence
|
||||
import numpy
|
||||
|
|
@ -339,7 +337,7 @@ def normalized_fields_e(
|
|||
mu: vfdslice | None = None,
|
||||
prop_phase: float = 0,
|
||||
) -> tuple[vcfdslice_t, vcfdslice_t]:
|
||||
"""
|
||||
r"""
|
||||
Given a vector `e_xy` containing the vectorized E_x and E_y fields,
|
||||
returns normalized, vectorized E and H fields for the system.
|
||||
|
||||
|
|
@ -357,6 +355,21 @@ def normalized_fields_e(
|
|||
Returns:
|
||||
`(e, h)`, where each field is vectorized, normalized,
|
||||
and contains all three vector components.
|
||||
|
||||
Notes:
|
||||
`e_xy` is only the transverse electric eigenvector. This helper first
|
||||
reconstructs the full three-component `E` and `H` fields with `exy2e(...)`
|
||||
and `exy2h(...)`, then normalizes them to unit forward power using
|
||||
`_normalized_fields(...)`.
|
||||
|
||||
The normalization target is
|
||||
|
||||
$$
|
||||
\Re\left[\mathrm{inner\_product}(e, h, \mathrm{conj\_h}=True)\right] = 1,
|
||||
$$
|
||||
|
||||
so the returned fields represent a unit-power forward mode under the
|
||||
discrete Yee-grid Poynting inner product.
|
||||
"""
|
||||
e = exy2e(wavenumber=wavenumber, dxes=dxes, epsilon=epsilon) @ e_xy
|
||||
h = exy2h(wavenumber=wavenumber, omega=omega, dxes=dxes, epsilon=epsilon, mu=mu) @ e_xy
|
||||
|
|
@ -374,7 +387,7 @@ def normalized_fields_h(
|
|||
mu: vfdslice | None = None,
|
||||
prop_phase: float = 0,
|
||||
) -> tuple[vcfdslice_t, vcfdslice_t]:
|
||||
"""
|
||||
r"""
|
||||
Given a vector `h_xy` containing the vectorized H_x and H_y fields,
|
||||
returns normalized, vectorized E and H fields for the system.
|
||||
|
||||
|
|
@ -392,6 +405,13 @@ def normalized_fields_h(
|
|||
Returns:
|
||||
`(e, h)`, where each field is vectorized, normalized,
|
||||
and contains all three vector components.
|
||||
|
||||
Notes:
|
||||
This is the `H_x/H_y` analogue of `normalized_fields_e(...)`. The final
|
||||
normalized mode should describe the same physical solution, but because
|
||||
the overall complex phase and sign are chosen heuristically,
|
||||
`normalized_fields_e(...)` and `normalized_fields_h(...)` need not return
|
||||
identical representatives for nearly symmetric modes.
|
||||
"""
|
||||
e = hxy2e(wavenumber=wavenumber, omega=omega, dxes=dxes, epsilon=epsilon, mu=mu) @ h_xy
|
||||
h = hxy2h(wavenumber=wavenumber, dxes=dxes, mu=mu) @ h_xy
|
||||
|
|
@ -409,7 +429,25 @@ def _normalized_fields(
|
|||
mu: vfdslice | None = None,
|
||||
prop_phase: float = 0,
|
||||
) -> tuple[vcfdslice_t, vcfdslice_t]:
|
||||
# TODO documentation
|
||||
r"""
|
||||
Normalize a reconstructed waveguide mode to unit forward power.
|
||||
|
||||
The eigenproblem solved by `solve_mode(s)` determines only the mode shape and
|
||||
propagation constant. The overall complex amplitude and sign are still free.
|
||||
This helper fixes those remaining degrees of freedom in two steps:
|
||||
|
||||
1. Compute the discrete longitudinal Poynting flux with
|
||||
`inner_product(e, h, conj_h=True)`, including the half-cell longitudinal
|
||||
phase adjustment controlled by `prop_phase`.
|
||||
2. Multiply both fields by a scalar chosen so that the real forward power is
|
||||
`1`, then choose a reproducible phase/sign representative by making a
|
||||
dominant-energy sample real and using a weighted quadrant sum to break
|
||||
mirror-symmetry ties.
|
||||
|
||||
The sign heuristic is intentionally pragmatic rather than fundamental: it is
|
||||
only there to make downstream tests and source/overlap construction choose a
|
||||
consistent representative when the physical mode is symmetric.
|
||||
"""
|
||||
shape = [s.size for s in dxes[0]]
|
||||
|
||||
# Find time-averaged Sz and normalize to it
|
||||
|
|
@ -921,7 +959,7 @@ def solve_mode(
|
|||
return vcfdfield2_t(e_xys[0]), wavenumbers[0]
|
||||
|
||||
|
||||
def inner_product( # TODO documentation
|
||||
def inner_product(
|
||||
e1: vcfdfield2,
|
||||
h2: vcfdfield2,
|
||||
dxes: dx_lists2_t,
|
||||
|
|
@ -929,6 +967,36 @@ def inner_product( # TODO documentation
|
|||
conj_h: bool = False,
|
||||
trapezoid: bool = False,
|
||||
) -> complex:
|
||||
r"""
|
||||
Compute the discrete waveguide overlap / Poynting inner product.
|
||||
|
||||
This is the 2D transverse integral corresponding to the time-averaged
|
||||
longitudinal Poynting flux,
|
||||
|
||||
$$
|
||||
\frac{1}{2}\int (E_x H_y - E_y H_x) \, dx \, dy
|
||||
$$
|
||||
|
||||
with the Yee-grid staggering and optional propagation-phase adjustment used
|
||||
by the waveguide helpers in this module.
|
||||
|
||||
Args:
|
||||
e1: Vectorized electric field, typically from `exy2e(...)` or
|
||||
`normalized_fields_e(...)`.
|
||||
h2: Vectorized magnetic field, typically from `hxy2h(...)`,
|
||||
`exy2h(...)`, or one of the normalization helpers.
|
||||
dxes: Two-dimensional Yee-grid spacing lists `[dx_e, dx_h]`.
|
||||
prop_phase: Phase advance over one propagation cell. This is used to
|
||||
shift the H field into the same longitudinal reference plane as the
|
||||
E field.
|
||||
conj_h: Whether to conjugate `h2` before forming the overlap. Use
|
||||
`True` for the usual time-averaged power normalization.
|
||||
trapezoid: Whether to use trapezoidal quadrature instead of the default
|
||||
rectangular Yee-cell sum.
|
||||
|
||||
Returns:
|
||||
Complex overlap / longitudinal power integral.
|
||||
"""
|
||||
|
||||
shape = [s.size for s in dxes[0]]
|
||||
|
||||
|
|
@ -951,5 +1019,3 @@ def inner_product( # TODO documentation
|
|||
Sz_b = E1[1] * H2[0] * dxes_real[0][0][:, None] * dxes_real[1][1][None, :]
|
||||
Sz = 0.5 * (Sz_a.sum() - Sz_b.sum())
|
||||
return Sz
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue