Open-Domain Wave (PML & Ports)

Frequency-domain wave problems on open domains need two ingredients beyond the plain complex Helmholtz assembly of Complex-Valued FEM — Helmholtz: a way to drive and absorb waves at a boundary (ports / first-order absorbing conditions), and a perfectly matched layer (PML) that soaks up outgoing radiation without reflection. Both shipped as small, composable operators:

Two worked examples in examples/wave/ exercise them — an acoustic resonator driven through a port, and a photonic microdisk wrapped in a PML frame.

Helmholtz resonator (acoustics, ports)

examples/wave/helmholtz_resonator/helmholtz_resonator.py solves a 2D duct with a necked side cavity — the textbook Helmholtz resonator — driven by a plane-wave port at the inlet. All walls are sound-hard (natural Neumann); the port both injects the incident wave and absorbs the reflection:

\[\frac{\partial p}{\partial n} + i k\, p = 2 i k\, p_0 \quad\text{on } \Gamma_{\text{port}} .\]

In the weak form that is one boundary matrix and one boundary load on top of the usual stiffness/mass pair — the whole recipe is four lines:

Listing 12 examples/wave/helmholtz_resonator/helmholtz_resonator.py (essence)
from tensormesh import robin_operator, port_source

K = LaplaceElementAssembler.from_mesh(mesh)(points)
M = MassElementAssembler.from_mesh(mesh)(points)
B = robin_operator(mesh, inlet_mask)          # boundary mass on the port
e = port_source(mesh, inlet_mask)             # incident load

A = K - k**2 * M + 1j * k * B
p = A.solve(2j * k * p0 * e)                  # complex sparse solve

Sweeping the frequency and reading the input impedance \(Z(f) = p_{\text{avg}} / u_{\text{in}}\) at the inlet produces the resonance spectrum; the fundamental sits at 357 Hz with a cavity pressure gain of ~12x over the incident amplitude.

Helmholtz resonator pressure field and SPL at resonance

Fig. 46 The acoustic field at resonance: total pressure (top) and sound pressure level (bottom). The cavity rings at a nearly uniform high pressure while the duct stays quiet — the classic pressure-node line cuts across the neck.

Input impedance over the frequency sweep

Fig. 47 Input impedance \(|Z|/Z_0\) over the sweep — the Helmholtz resonance and the duct harmonics appear as peaks, with anti-resonances between them.

Optical ring resonator (photonics, PML)

examples/wave/optical_ring_resonator/optical_ring_resonator.py is a 2D TM photonic solve: a silicon bus waveguide evanescently couples light into a silicon microdisk (\(n = 3.48\)) in silica cladding (\(n = 1.44\)), and a stretched-coordinate PML frame makes the computational box behave as an open domain. The out-of-plane field \(E_z\) obeys the PML-modified Helmholtz equation

\[\nabla\cdot(\mathbf\Lambda\,\nabla E_z) + k_0^2\,\varepsilon_r\, s_x s_y\, E_z = \text{source}, \qquad \mathbf\Lambda = \operatorname{diag}(s_y/s_x,\ s_x/s_y),\]

with \(s_x = s_y = 1\) outside the layer. The reusable library path is three calls:

from tensormesh import cartesian_pml, AnisotropicLaplaceElementAssembler
from tensormesh.assemble import ScaledMassElementAssembler

Lam, s_prod = cartesian_pml(mesh.points, bounds=[(0, L), (0, L)], thickness=d)
K = AnisotropicLaplaceElementAssembler.from_mesh(mesh)(pts, point_data={"A": Lam})
M = ScaledMassElementAssembler.from_mesh(mesh)(pts, point_data={"c": eps_r * s_prod})
E = (K - k0**2 * M).solve(source)

(The example itself evaluates \(\varepsilon_r\) and the stretch per quadrature point with an inline assembler for sharper Si/SiO₂ interfaces; the cartesian_pml path reproduces the same operator and matches the 2D Hankel Green function to correlation 0.994.) A modal soft source launches the guided bus mode directionally toward the disk.

Waveguide-coupled silicon microdisk on resonance

Fig. 48 On resonance the disk lights up in a whispering-gallery mode — a bright rim of azimuthal lobes (left: \(\mathrm{Re}\,E_z\), right: \(|E_z|\)), the bus waveguide visibly depleted past the coupling point, and the PML frame absorbing the radiated field.

Materials, launch plane, and PML frame of the optical example

Fig. 49 The setup: materials, the two-plane directional launch, and the PML frame. Without the PML a hard box traps the radiation into a standing wave of ~8x the amplitude.

Running them

cd examples/wave/helmholtz_resonator && python helmholtz_resonator.py
cd examples/wave/optical_ring_resonator && python optical_ring_resonator.py

Both expose run_demo(...) returning diagnostics plus --no-plot / --output flags; the optical script also takes --lam0-nm, --order and --mesh-h-nm (with P1 elements numerical dispersion blue-shifts the physical 1.55 µm resonance to the default 1512 nm).

What’s next