Build a trustworthy validation case#
A benchmark should answer one narrow question and remain interpretable when it fails. This project uses a layered strategy.
1. State the physical claim#
Examples: “phase velocity in a dielectric is \(c/n\),” “the two-port straight guide transmits unit mode power,” or “the optimizer reaches 95% of the Tidy3D best FOM.” Name the observable before writing geometry.
2. Prefer independent references#
Use, in order:
an analytical formula or conservation law;
an independent numerical method such as transfer matrices or Mie theory;
a frozen result from a converged external solver.
Tidy3D goldens in this repo are compact, pinned files. Normal benchmark execution never launches a paid task.
3. Declare resolution honestly#
If local GPU memory requires a coarser grid than the reference, set resolution_factor < 1 and declare resolution_power for every metric. The comparator uses
Document the reason in case.yaml; never quietly widen a threshold after looking at a failure.
4. Separate comparisons#
Record both shape and pointwise metrics for spectra (rel_l2, abs_max), plus conservation/finite checks where meaningful. A relative metric alone becomes unstable near zero; an absolute metric alone can miss scale-dependent error.
5. Treat inverse design differently#
Compare the best FOM reached within a generous cap. Do not require matching geometry or optimization speed. Add bounds that exclude unphysical normalization wins.
6. Run in the right order#
uv run fdtdx-bench run --case your_case
uv run fdtdx-bench smoke
uv run fdtdx-bench report
The smoke suite must remain green after solver changes. report refreshes the human-readable capability record from machine state.
7. Block rather than disguise#
After repeated sincere attempts, record a blocked reason. A non-converged golden, an ambiguous source convention, or a missing solver feature is valuable information when it is explicit. The public validation page includes those boundaries.