Update examples for sampled-interface tapers, explicit physical CPML spacing, copied SCPML widths, and the consolidated complex mode solver. Document breaking API changes, overlap measures, and PML convergence.
4.4 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