meanas/docs/api/waveguides.md
Forgejo Actions a08e9ce71b [eme] characterize orientation bias under modal truncation
Compare mixed and Galerkin testing against exact polarization/Fresnel interfaces and independent driven FDFD solves. Show complete-basis recovery, omitted-channel power, and the limits of longitudinal refinement, orientation averaging, and Euclidean least squares. Keep the default formulation unchanged and document its approximation limits.

Validation: 1689 tests passed, 584 skipped; Ruff and documentation build passed.
2026-10-18 23:21:29 -07:00

7.8 KiB

waveguides

::: meanas.fdfd.waveguide_2d

::: meanas.fdfd.waveguide_3d

::: meanas.fdfd.waveguide_cyl

Overlap measures and normalization

waveguide_2d.inner_product(..., measure="physical", conj_h=True) uses real Yee widths for physical Poynting power. measure="stretched" keeps complex widths for coordinate reaction. lorentz_metric and lorentz_overlap default to the stretched measure. Use the same grid and measure when constructing and using dual fields. A real overlap grid still defines a consistent constructed dual basis, even when the eigenproblem uses a separate PML grid.

normalized_fields_e/h(..., normalization="lorentz") normalizes unconjugated self-reaction to one. This fixes phase up to a sign and is distinct from unit forward power, which remains the default. Zero-power or self-orthogonal modes raise ValueError; open self-orthogonal modes require paired primal/dual normalization through ModeBasis.

Targeted and reproducible mode solving

For modes near an effective index guess, use solve_modes_near with target_wavenumbers=[omega * n_guess]. It targets the electric beta-squared operator at (omega * n_guess)**2; solve_modes_near_beta instead targets the first-order signed-beta operator. Both use the LU shift-invert backend and support eigensolver_opts={"v0": starting_vector}. Factorization cost and memory depend on the grid, so this is not universally faster than indexed solving. solve_modes keeps its global mode-number semantics and now accepts rng or v0 for reproducible initialization.

waveguide_3d.mode_from_2d accepts a supplied transverse electric eigenvector and reuses field reconstruction, normalization, numerical-dispersion correction, Yee staggering, rotation, and full-grid embedding without solving an eigenproblem.

Interface and sampled-taper scattering

All scattering matrices use outgoing rows and incoming columns, ordered [left, right]:

[b_left ]   [R_left        T_right_to_left] [a_left ]
[b_right] = [T_left_to_right       R_right] [a_right]

get_s and get_abcd require explicit dxes. Mixed Petrov-Galerkin testing is the default: left electric duals test H continuity, and right magnetic duals test E continuity. Both incidence directions are solved together with full projection matrices. Mixed scattering supports unequal mode counts. formulation="galerkin" selects equal-count left testing of both equations. Neither formulation silently clips transmission. The optional force_nogain and force_reciprocal flags are numerical projections, not general physical tests for arbitrary open or evanescent modal coordinates.

get_taper_s replaces finite-difference CMT with half propagation in the left basis, a midpoint interface, and half propagation in the right basis for each sampled interval. Redheffer composition avoids growing passive backward transfer branches. Refine section sampling and modal/PML bases to establish convergence. The ineffective rtol, atol, and max_step arguments have been removed. The existing eme_taper_cmt.py example filename is retained.

prepared = eme.prepare_taper(sections, dxes)
s_original = eme.evaluate_taper_s(prepared)
s_longer = eme.evaluate_taper_s(prepared, z_coords=prepared.z_coords * 1.2)
s_changed_beta = eme.evaluate_taper_s(
    prepared, wavenumber_matrices=beta_matrices,
)

PreparedTaper owns read-only copies of phase-aligned interface data. Beta matrix overrides have shape (section, mode, mode) in the original supplied section bases; recorded basis transforms are applied automatically. Explicit backward branches require backward beta overrides when forward beta is changed. Evaluation performs no field overlaps or eigensolves. Length sweeps reuse the sampled model; wavelength sweeps with reused fields are explicitly frozen-basis approximations. Reprepare when fields, duals, grids, or formulations change.

cascade_s(left, right, internal_modes=...) connects spatially ordered S matrices, including unequal external ports. Public abcd_to_s and s_to_abcd use [f_right, b_right] = ABCD @ [f_left, b_left] and require equal port counts. get_taper_abcd converts the stable S result; zero transmission or an unrepresentable transfer matrix raises LinAlgError. Prefer S for long lossy devices. Singular interface and cascade systems also raise contextual errors rather than silently substituting pseudoinverses.

::: meanas.fdfd.eme

Orientation bias under modal truncation

Mixed testing is a projected approximation: H continuity is tested on the left and E continuity on the right. Swapping the ports changes the testing spaces when the retained modal subspaces are incomplete. This effect survives checks of reciprocity and unitarity.

A reproducible Maxwell counterexample is a uniform isotropic medium with two degenerate linear polarizations. Keep one polarization on each port, rotated so their overlap is a=0.8. There is no material interface: true reflection is zero and transmission into the retained receiver is a. The other polarization carries the remaining transmitted power, 1-a**2=0.36.

Calculation R_left R_right T_left_to_right T_right_to_left
Exact full basis, then restrict ports 0 0 0.8 0.8
Truncated mixed 0.219512 -0.219512 0.975610 0.975610
Swap ports, mixed, then reorder -0.219512 0.219512 0.975610 0.975610
Truncated left Galerkin 0 0 1.25 0.8
Euclidean E/H least squares 0 0 0.8 0.8

An independent driven 3D FDFD solve with PML agrees with the exact reference from either incidence direction: transmission is 0.8 within 1e-12, with reflection below 2e-8 in the test fixture. Keeping both polarizations makes mixed testing match the exact complete scattering matrix and restores port-relabeling covariance.

For the single retained polarization, mixed testing yields r=(1-a**2)/(1+a**2) and t=2*a/(1+a**2). The spurious reflection is quadratic in a small angle between adjacent retained polarizations. However, longitudinal refinement alone is insufficient: rotating a single retained vector through a uniform degenerate medium makes the sampled chain approach artificial following of that vector (|T| approaches 1), while the physical endpoint overlap remains 0.8. Keeping the complete degenerate block recovers the physical result at every sampling density tested.

Two tempting corrections are insufficient. Averaging the two port orientations cancels reflection in this example but leaves transmission at 0.975610. Plain Euclidean E/H least squares gives the correct uniform-medium result, but is not a general replacement. A second fixture uses exact degenerate modes of diagonal positive epsilon/mu tensors, with electric scaling (1,2) on the left and (1,3) on the right and a 30-degree polarization rotation on both ports. After single-mode truncation, least squares has unequal directional transmissions (approximately 0.850839 and 1.092163) and a maximum singular value of 1.104947. The complete Fresnel solution is reciprocal and lossless.

The mixed default remains unchanged. Retain complete coupled/degenerate blocks when the geometry can mix them, check modal-basis convergence as well as section sampling, and compare against independent full-field results. Neither orientation averaging nor gain/reciprocity postprocessing recovers omitted-channel physics. Orientation discrepancy is a useful diagnostic, not a bound on transmission error. These examples use real power-orthonormal propagating modes; for general complex modes, the reciprocity constraint involves the modal orthogonality matrix, as derived by Svendsen, Haakestad, and Skaar.

Reproduce the analytic, full-basis, candidate-formulation, taper-refinement, and driven-FDFD checks with:

OPENBLAS_NUM_THREADS=1 python -m pytest meanas/test/test_eme_orientation.py -q