# FDTD Electromagnetics

Yee-grid leapfrog solver for Maxwell's equations on a 3D periodic torus. Vacuum permittivity / permeability are normalized to ε = μ = c = 1; physical quantities are reconstructed from the user's wavelength and grid step.

## Algorithm

Yee staggering places E on edges and H on faces at half-cell offsets. The leapfrog update is:

```
H^{n+1/2} = H^{n-1/2} - (dt/μ) ∇ × E^n
E^{n+1}   = E^n       + (dt/ε) ∇ × H^{n+1/2}
```

The 3D Yee stability limit is `c dt ≤ dx / √3`. The engine takes a Courant safety factor (default 0.5) and computes dt automatically.

## Validation

- Vacuum no-source run: fields stay identically zero (sanity check the stencil isn't injecting energy)
- Dipole source: total field energy grows linearly while the Gaussian-modulated pulse pumps, then plateaus
- Field at center oscillates sign through the run (verifies the leapfrog sign convention)

## Substrate framing

The Yee 3D stencil is radius-1 on the same HVP-indexed neighbor table that BSSN uses (`wasm/src/gpu/bssn/mesh.rs::BssnMesh`), with the stencil pruned from 18 axial directions to the 6 needed for `curl E` and `curl H`. The mesh ports directly; tile streaming for resolutions above the resident GPU budget reuses the same bloom-gradient gating.

## Parameters

| Field | Meaning | Default |
|-------|---------|---------|
| nx, ny, nz | grid dimensions | 32 |
| box_length | physical L | 1.0 |
| n_steps | leapfrog time steps | 200 |
| courant | safety factor in [0, 1]; max is 1/√3 of dt_max | 0.5 |
| source | `dipole_gauss` or `none` | dipole_gauss |
| frequency | dipole carrier frequency | 10.0 |
| pulse_width | Gaussian envelope width in light-crossings of one cell | 0.05 |
| pml_thickness | UPML cell count (0 disables; PML follow-up) | 0 |
