/** * FDTDSolver — 3D Finite-Difference Time-Domain solver for Maxwell's equations. * * ## Governing Equations (curl form) * * dH/dt = -(1/μ) ∇×E − (σ_m/μ) H * dE/dt = (1/ε) ∇×H − (σ/ε) E + J/ε * * ## Yee Algorithm * * E and H fields are staggered by half a cell in space (Yee grid) and * half a timestep in time (leapfrog). This ensures 2nd-order accuracy * in both space and time with zero artificial dissipation. * * ## Field Layout (Yee Grid) * * On a grid of nx×ny×nz cells: * Ex lives on x-directed edges: (i+½, j, k) → stored at [i][j][k], size nx×(ny+1)×(nz+1) * Ey lives on y-directed edges: (i, j+½, k) → stored at [i][j][k], size (nx+1)×ny×(nz+1) * Ez lives on z-directed edges: (i, j, k+½) → stored at [i][j][k], size (nx+1)×(ny+1)×nz * Hx lives on x-normal faces: (i, j+½, k+½) → stored at [i][j][k], size (nx+1)×ny×nz * Hy lives on y-normal faces: (i+½, j, k+½) → stored at [i][j][k], size nx×(ny+1)×nz * Hz lives on z-normal faces: (i+½, j+½, k) → stored at [i][j][k], size nx×ny×(nz+1) * * ## CFL Condition * * dt ≤ 1 / (c · √(1/dx² + 1/dy² + 1/dz²)) * * ## Boundary Conditions * * - PEC (Perfect Electric Conductor): tangential E = 0 (default at domain edges) * - PMC (Perfect Magnetic Conductor): tangential H = 0 * - PML (Perfectly Matched Layer): convolutional PML for open boundaries * * @see AcousticSolver — scalar wave equation (simpler, same leapfrog pattern) * @see SimSolver — generic interface * * References: * - Taflove & Hagness, "Computational Electrodynamics: The FDTD Method", 3rd ed. * - Yee, K.S., "Numerical Solution of Initial Boundary Value Problems...", IEEE, 1966 * - Roden & Gedney, "Convolution PML (CPML)...", Microwave Opt. Tech. Lett., 2000 */ export interface EMSource { id: string; type: 'point_current' | 'sinusoidal'; /** Grid cell [i, j, k] */ position: [number, number, number]; /** Polarization direction */ polarization: 'x' | 'y' | 'z'; /** Amplitude [A/m² for current] */ amplitude: number; /** Frequency [Hz] (for sinusoidal) */ frequency?: number; /** Pulse width [s] (for gaussian envelope) */ pulseWidth?: number; active?: boolean; } export interface FDTDConfig { /** Number of Yee cells [nx, ny, nz] */ cellCount: [number, number, number]; /** Cell size [dx, dy, dz] in meters */ cellSize: [number, number, number]; /** Relative permittivity (uniform or per-cell) */ permittivity?: number; /** Relative permeability (uniform, default 1) */ permeability?: number; /** Electric conductivity [S/m] (default 0) */ conductivity?: number; /** PML thickness in cells (default 0 = PEC boundaries) */ pmlThickness?: number; /** Sources */ sources: EMSource[]; /** Optional closed Huygens box for running-DFT near-to-far extraction. */ ntfSurface?: NTFSurfaceConfig; /** Time step [s] — auto-computed from CFL if omitted */ timeStep?: number; /** CFL safety factor (default 0.9) */ cflSafety?: number; } export interface FDTDStats { currentTime: number; stepCount: number; timeStep: number; cflLimit: number; maxE: number; maxH: number; cellCount: number; } export type Complex = { re: number; im: number; }; export interface NTFSurfaceConfig { /** Inclusive lower cell index [i, j, k], strictly inside any PML. */ min: [number, number, number]; /** Inclusive upper cell index [i, j, k], strictly inside the Yee cell domain. */ max: [number, number, number]; /** Frequencies [Hz] accumulated by the running DFT. */ frequencies: number[]; } export interface RunningDFTPhasor { frequency: number; samples: number; surfaceSampleCount: number; equivalentElectricCurrent: [Complex, Complex, Complex]; equivalentMagneticCurrent: [Complex, Complex, Complex]; sourceMoment: [Complex, Complex, Complex]; } export interface FarFieldResult { frequency: number; theta: number; phi: number; eTheta: Complex; ePhi: Complex; magnitude: number; power: number; directivity: number; gain: number; samples: number; } /** Flat Float32Array for a 3D Yee field component. */ declare class YeeField { readonly data: Float32Array; readonly sx: number; readonly sy: number; readonly sz: number; constructor(sx: number, sy: number, sz: number); get(i: number, j: number, k: number): number; set(i: number, j: number, k: number, v: number): void; } export declare class FDTDSolver { private config; private nx; private ny; private nz; private dx; private dy; private dz; private dt; private cflLimit; private Ce; private De; private Ch; private Dh; readonly Ex: YeeField; readonly Ey: YeeField; readonly Ez: YeeField; readonly Hx: YeeField; readonly Hy: YeeField; readonly Hz: YeeField; private cpml; private currentTime; private stepCount; private ntfSamples; private ntfDft; constructor(config: FDTDConfig); /** * Advance one FDTD timestep. * * Order: update H (half-step) → update E (full-step) → apply sources at E^n * time level → apply PEC → advance clock. * * Source-time convention (Taflove §3.4): after H advances to n+½ and before * E advances to n+1, the additive current J is evaluated at the INTEGER time * level n (i.e. `currentTime` BEFORE the clock increment). Previous code * called applySources(currentTime + dt), which evaluated the source one full * step ahead and introduced a half-step phase offset (Δφ = 2πf·dt) for all * sinusoidal and pulsed sources. */ step(): void; private initializeNTF; private accumulateNTF; private sampleE; private sampleH; /** Update H-field: H^{n+1/2} = Ch * H^{n-1/2} - Dh * curl(E^n) */ private updateH; /** Update E-field: E^{n+1} = Ce * E^n + De * curl(H^{n+1/2}) */ private updateE; /** * CPML H-field update. Identical to {@link updateH} but each spatial * derivative is replaced by its stretched-coordinate form * `(1/κ)·∂F + ψ`, with ψ advanced by the recursive convolution. Reduces * exactly to {@link updateH} in the interior (κ=1, b=1, a=0 ⇒ ψ stays 0). */ private updateH_cpml; /** CPML E-field update — mirror of {@link updateE} with stretched derivatives. */ private updateE_cpml; /** PEC boundary: tangential E = 0 at all domain faces. */ private applyPEC; /** Apply sources at the current time. */ private applySources; private evaluateSource; /** Get E-field magnitude |E| = √(Ex²+Ey²+Ez²) on the Yee grid (cell-centered average). */ getEFieldMagnitude(): Float32Array; /** Get H-field magnitude |H| on cell centers. */ getHFieldMagnitude(): Float32Array; getTime(): number; getStats(): FDTDStats; getRunningDFTPhasors(): RunningDFTPhasor[]; getRunningDFTPhasor(frequency: number): RunningDFTPhasor; getFarField(theta: number, phi: number, frequency?: number): FarFieldResult; computeFarField(theta: number, phi: number, frequency?: number): FarFieldResult; getFarFieldPattern(angles: Array<{ theta: number; phi: number; }>, frequency?: number): FarFieldResult[]; dispose(): void; } export {}; //# sourceMappingURL=FDTDSolver.d.ts.map