[docs] clarify FDFD-to-FDTD field reconstruction
This commit is contained in:
parent
e50637dc1c
commit
40efe7a450
5 changed files with 51 additions and 5 deletions
14
README.md
14
README.md
|
|
@ -194,6 +194,10 @@ For a broadband or continuous-wave FDTD run:
|
|||
part of the simulation, and compare the extracted phasor to the FDFD field or
|
||||
residual.
|
||||
|
||||
This is the primary FDTD/FDFD equivalence workflow. The phasor extraction step
|
||||
filters the time-domain run down to the guided `+\omega` content that FDFD
|
||||
solves for directly, so it is the cleanest apples-to-apples comparison.
|
||||
|
||||
### Real-field reconstruction workflow
|
||||
|
||||
For a continuous-wave real-valued FDTD run:
|
||||
|
|
@ -211,4 +215,14 @@ For a continuous-wave real-valued FDTD run:
|
|||
pieces to see whether the remaining mismatch is actually in the mode or in
|
||||
weak nonguided tails.
|
||||
|
||||
This is a stricter diagnostic, not the primary equivalence benchmark. A raw
|
||||
monitor slice contains both the guided field and the remaining orthogonal
|
||||
content on that plane,
|
||||
|
||||
$$ E_{\text{monitor}} = E_{\text{guided}} + E_{\text{residual}} , $$
|
||||
|
||||
so its full-plane instantaneous error is naturally noisier than the extracted
|
||||
phasor comparison even when the underlying guided `+\omega` content matches
|
||||
well.
|
||||
|
||||
`examples/waveguide_real.py` is the reference implementation of this workflow.
|
||||
|
|
|
|||
|
|
@ -26,6 +26,15 @@ Relevant starting examples:
|
|||
mode-weighted, and guided-mode / residual comparisons
|
||||
- `examples/fdfd.py` for direct frequency-domain waveguide excitation
|
||||
|
||||
For solver equivalence, prefer the phasor-based examples first. They compare
|
||||
the extracted `+\omega` content of the FDTD run directly against the FDFD
|
||||
solution and are the main accuracy benchmarks in the test suite.
|
||||
|
||||
`examples/waveguide_real.py` answers a different, stricter question: how well a
|
||||
late raw real snapshot matches `Re(E_\omega e^{i\omega t})` on a monitor plane.
|
||||
That diagnostic is useful, but it also includes orthogonal residual structure
|
||||
that the phasor comparison intentionally filters out.
|
||||
|
||||
The API pages are better read as a toolbox map and derivation reference:
|
||||
|
||||
- Use the [FDTD API](api/fdtd.md) for time-domain stepping, CPML, phasor
|
||||
|
|
|
|||
|
|
@ -9,9 +9,12 @@ FDFD" workflow:
|
|||
3. solve the matching FDFD problem from the analytic source phasor, and
|
||||
4. compare late real monitor slices against `fdtd.reconstruct_real_e/h(...)`.
|
||||
|
||||
Unlike the complex-source examples, this script does not use phasor extraction
|
||||
as the main output. The comparison target is the real field itself, with both
|
||||
full-plane and mode-weighted monitor errors reported.
|
||||
Unlike the phasor-based examples, this script does not use extracted phasors as
|
||||
the main output. It is a stricter diagnostic: the comparison target is the raw
|
||||
real field itself, with full-plane, mode-weighted, guided-mode, and orthogonal-
|
||||
residual errors reported. Strong phasor agreement can coexist with visibly
|
||||
larger raw-snapshot error because the latter includes weak nonguided tails on
|
||||
the monitor plane.
|
||||
"""
|
||||
|
||||
import numpy
|
||||
|
|
@ -104,7 +107,7 @@ def main() -> None:
|
|||
epsilon=epsilon,
|
||||
)
|
||||
# A small global phase aligns the real-valued source with the late-cycle
|
||||
# monitor comparison. The underlying phasor problem is unchanged.
|
||||
# raw-snapshot diagnostic. The underlying phasor problem is unchanged.
|
||||
j_mode *= numpy.exp(1j * SOURCE_PHASE)
|
||||
monitor_mode = waveguide_3d.solve_mode(
|
||||
0,
|
||||
|
|
|
|||
|
|
@ -165,6 +165,11 @@ with caller-provided sample times and weights. In this codebase the matching
|
|||
electric-current convention is typically `E -= dt * J / epsilon` in FDTD and
|
||||
`-i \omega J` on the right-hand side of the FDFD wave equation.
|
||||
|
||||
For FDTD/FDFD equivalence, this phasor path is the primary comparison workflow.
|
||||
It isolates the guided `+\omega` response that the frequency-domain solver
|
||||
targets directly, regardless of whether the underlying FDTD run used real- or
|
||||
complex-valued fields.
|
||||
|
||||
For exact pulsed FDTD/FDFD equivalence it is often simplest to keep the
|
||||
injected source, fields, and CPML auxiliary state complex-valued. The
|
||||
`real_injection_scale(...)` helper is instead for the more ordinary one-run
|
||||
|
|
@ -172,6 +177,17 @@ real-valued source path, where the intended positive-frequency waveform is
|
|||
injected through `numpy.real(scale * waveform)` and any remaining negative-
|
||||
frequency leakage is controlled by the pulse bandwidth and run length.
|
||||
|
||||
`reconstruct_real(...)` is for a different question: given a phasor, what late
|
||||
real-valued field snapshot should it produce? That raw-snapshot comparison is
|
||||
stricter and noisier because a monitor plane generally contains both the guided
|
||||
field and the remaining orthogonal content,
|
||||
|
||||
$$ E_{\text{monitor}} = E_{\text{guided}} + E_{\text{residual}} . $$
|
||||
|
||||
Phasor/modal comparisons mostly validate the guided `+\omega` term. Raw
|
||||
real-field comparisons expose both terms at once, so they should be treated as
|
||||
secondary diagnostics rather than the main solver-equivalence benchmark.
|
||||
|
||||
The Ricker wavelet (normalized second derivative of a Gaussian) is commonly used for the pulse
|
||||
shape. It can be written
|
||||
|
||||
|
|
|
|||
|
|
@ -711,7 +711,11 @@ def test_straight_waveguide_fdtd_fdfd_overlap_and_flux_agree() -> None:
|
|||
assert result.overlap_phase_deg < 0.5
|
||||
|
||||
|
||||
def test_straight_waveguide_real_monitor_fields_match_reconstructed_real_fields() -> None:
|
||||
def test_straight_waveguide_real_snapshot_diagnostic_tracks_guided_content_and_bounded_residual() -> None:
|
||||
# The phasor-based waveguide tests above are the primary FDTD/FDFD
|
||||
# equivalence benchmark. This raw real-field check is intentionally stricter:
|
||||
# it validates that late monitor snapshots keep the guided content close to
|
||||
# the reconstructed FDFD field while the orthogonal residual stays bounded.
|
||||
result = _run_real_field_straight_waveguide_case()
|
||||
ranked_snapshots = sorted(
|
||||
result.snapshots,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue