Skip to content

Validation

A simulator that looks right is not the same as one that is right. The Rust core has a set of physics tests that compare it against analytic results or against a reference run. They run on every commit (cargo test --release in rust-core/).

Test Expected Measured
Absorbing boundary: a pulse next to a 10-cell CPML compared with a domain too large to see its walls as small as possible 4.3 × 10−5 of the peak (−87 dB), TM and TE
TF/SF plane wave in an empty domain: field on the scattered side 0 below 1.8 × 10−4 of the incident amplitude in all four directions
Normal-incidence reflection from glass, n = 1.5 |r| = 0.200 0.203 (TM), 0.203 (TE)
Reflection from silicon, n = 3.48 |r| = 0.553 0.558
Reflection from a perfect conductor 1.000 0.999
Reflection from Drude silver at 600 nm about 0.98–1.0 0.999 (TM), 1.001 (TE)
Energy in a closed mirror box after the source has stopped constant drifts less than 1% over 4000 steps
Energy with absorbing walls after 2000 steps → 0 10−13 of the initial value
Spectrum of a probe next to a CW source peak at the source frequency within one FFT bin

The reflection measurements run a continuous plane wave into a half-space, wait for the transient to pass, and read the amplitude of the reflected wave on the scattered-field side of the TF/SF line, where the incident wave is absent.

The small excess in the glass and silicon reflections comes from numerical dispersion at 30–60 cells per wavelength and from the staircase interface; both shrink as the grid gets finer.

The same suite throws invalid input at the API: negative sizes, NaN and infinite coordinates, shapes entirely outside the grid, unknown material and source ids. The solver must not panic and must stay stable afterwards. One of these tests exists because the old version of PhotonLab filled the whole grid when asked to paint a rectangle with negative coordinates.

On the web side, the scene validator, share-link round trips, unit conversions and the translation files have their own tests (npm test).