# Differentiable FDTD

Inverse design asks for $dJ/d\theta$, where a scalar objective $J$ depends on fields produced by geometry or material parameters $\theta$. FDTDX constructs this chain as a JAX program:

$$
\theta \longrightarrow \boldsymbol\varepsilon^{-1}(\theta)
\longrightarrow (\mathbf E,\mathbf H)
\longrightarrow J.
$$

## Reverse mode

A forward simulation may contain thousands of time steps but millions of design variables. Reverse-mode differentiation is appropriate because the objective is scalar. Naively storing every field state is expensive. FDTDX supports checkpointed, reversible, and design-local adjoint strategies that trade recomputation for memory. `initialize_planned_recorder` measures the boundary-state shapes against the visible accelerator budget, then chooses the highest-fidelity float32/float16 and temporal-reconstruction plan that fits. A rejected plan reports required and available memory before an opaque GPU OOM.

For ordinary lossless dielectric topology optimization, the design-local adjoint avoids reconstructing the primal electromagnetic fields during the reverse solve. A linear FDTD step has a field-independent state Jacobian, so the reverse pass evaluates its exact transpose at zero fields and reads a compact tape of electric update drives inside the design region. Its storage is $O(TV_d)$ for $T$ time steps and design volume $V_d$, rather than $O(TV)$ full-domain states. CPML, sources, and linear phasor monitors remain in the exact discrete transpose. The current implementation deliberately rejects conductivity, dispersion, full material tensors, nonlinear detector state, and source or field-reset overlap with the design region.

## A useful parameterization

A topology-optimization pipeline often applies

1. an unconstrained or box-constrained density $\rho$;
2. a spatial filter to impose a minimum feature scale;
3. a smooth projection toward binary material;
4. a material interpolation into inverse permittivity;
5. a Maxwell solve and normalized port objective.

The variables in the first step do not need to be pixels. The
[design-basis layer](design_bases.md) backpropagates the same adjoint
sensitivity into cosine, phase-bearing Fourier, or radial/elliptical
coefficients. This changes the geometric prior without adding Maxwell solves.

Keep these transformations inside the differentiated function. Clipping, host-side NumPy conversion, or indexing performed outside the trace can silently sever the gradient.

## Gradient checks

Before launching a long optimizer:

- verify the objective and gradient are finite;
- compare a few gradient entries with centered finite differences;
- confirm a small step improves the objective;
- assert the design stays within material bounds;
- monitor source normalization and passive output power.
- compare a representative adjoint gradient against checkpointed autodiff before changing a production optimizer.

The fast inverse-design smoke test checks that the differentiable solver produces a useful improving gradient. Full device tests are stricter: they check the physical objective against Tidy3D under the same start, symmetries, controls, wavelengths, filter/projection, and fabrication rules. Final acceptance always uses a fresh, fully binary forward solve.

## Optimizer choice

`TopologyOptimizerConfig.algorithm` accepts `"adam"`, `"sgd"`, or
`"lbfgs"`. SGD uses optional Nesterov momentum. L-BFGS is a fixed-step,
limited-memory update without a line search, so it consumes one Maxwell
objective/gradient evaluation per iteration just like Adam. This matters when
one solve lasts minutes: a conventional line search could multiply the GPU
cost. Keep a maximum parameter-step or trust-region gate around resonant and
exact-binary objectives.

On the reproducible four-port crossing comparison, all algorithms began from
the same seed and received 25 gradients. Adam reached binary FOM 0.97283, the
best momentum-SGD trial reached 0.97241, and L-BFGS reached 0.99015. This is a
useful default, not a universal ranking: objectives with discontinuous
projections or unreliable pole fits should retain atomic best-design
checkpoints and reject physically inconsistent evaluations.

```{figure} ../_static/generated/inverse_design_splitter.png
:alt: Fully binary digital splitter geometry and objective history

The plot shows realized air-hole radii mirrored into the full physical device,
not a continuous control heatmap. Fresh binary validation every 25 updates is
monotone through the generic 3× cap; the selected 0.43253 design reaches 91.62%
of Tidy3D's 0.47210. It clears the requested 90% goal while remaining visibly
below the benchmark suite's stricter 95% threshold.
```

Continue with the [worked inverse-design tutorial](../tutorials/inverse_design.md).
