/** * AcousticSolver — Time-domain pressure wave equation on RegularGrid3D. * * ## Governing Equation * * d²p/dt² = c² ∇²p + S(t) * * where: * p = acoustic pressure [Pa] * c = speed of sound [m/s] * S = volumetric source term [Pa/s²] * * ## Discretization * * **Spatial**: 2nd-order central differences via RegularGrid3D.laplacian() * **Temporal**: Stormer-Verlet (leapfrog) — explicit, 2nd-order accurate: * * p^{n+1} = 2·p^n - p^{n-1} + (c·dt)²·∇²p^n + dt²·S^n * * Three grids rotate each step: prev → curr → next → prev ... * * ## CFL Stability * * dt ≤ dx / (c · √3) for 3D (assumes dx = dy = dz) * * ## Boundary Conditions * * - Dirichlet (p=0): hard wall (perfect reflection, inverted) * - Neumann (dp/dn=0): soft wall (perfect reflection, same phase) * - Absorbing (1st-order Engquist-Majda): dp/dt + c·dp/dn = 0 * * @see RegularGrid3D — field storage with laplacian stencil * @see SimSolver — generic interface this solver implements via adapter */ import { RegularGrid3D } from './RegularGrid3D'; export interface AcousticSource { id: string; /** Grid cell position [i, j, k] */ position: [number, number, number]; /** Source type */ type: 'point' | 'gaussian_pulse' | 'sinusoidal' | 'ricker_wavelet'; /** Amplitude [Pa] */ amplitude: number; /** Frequency [Hz] (for sinusoidal) */ frequency?: number; /** Pulse width [s] (for gaussian_pulse) */ pulseWidth?: number; /** Whether the source is active */ active?: boolean; } export type AcousticBCType = 'hard_wall' | 'soft_wall' | 'absorbing'; export interface AcousticBC { face: 'x-' | 'x+' | 'y-' | 'y+' | 'z-' | 'z+'; type: AcousticBCType; } export interface AcousticConfig { /** Grid resolution [nx, ny, nz] */ gridResolution: [number, number, number]; /** Domain size [m] */ domainSize: [number, number, number]; /** Speed of sound [m/s] (default: 343 for air). Used when velocityField is not provided. */ speedOfSound?: number; /** * Per-cell velocity field for heterogeneous media (geophysics/seismic). * When provided, overrides the scalar speedOfSound. * Must match gridResolution dimensions. */ velocityField?: RegularGrid3D; /** Density [kg/m³] (default: 1.225 for air) */ density?: number; /** Boundary conditions (default: absorbing on all faces) */ boundaryConditions?: AcousticBC[]; /** Sources */ sources: AcousticSource[]; /** Time step [s] — auto-computed from CFL if omitted */ timeStep?: number; /** CFL safety factor (default: 0.9) */ cflSafety?: number; /** Use WebGPU stencil kernel for the interior leapfrog update when available. */ useGPU?: boolean; } export interface AcousticStats { currentTime: number; stepCount: number; timeStep: number; cflLimit: number; maxPressure: number; rmsEnergy: number; usedGPU: boolean; } export declare class AcousticSolver { private config; private speedOfSound; /** Per-cell velocity field for heterogeneous media (null = uniform) */ private velocityField; private dt; private cflLimit; private pressureCurr; private pressurePrev; private pressureNext; private useGPU; private lastStepUsedGPU; private gpuStencil; private currentTime; private stepCount; private bcMap; constructor(config: AcousticConfig); /** * Advance the simulation by one timestep. */ step(dt?: number): void; /** * Advance one timestep, using the WebGPU stencil path for the interior update * when enabled. Sources and boundary conditions remain on CPU to preserve the * existing boundary contracts. */ stepAsync(dt?: number): Promise; private stepInteriorGPU; /** * Evaluate a source term at time t. */ private evaluateSource; /** * Apply boundary conditions on all 6 faces. */ private applyBoundaryConditions; /** Get the current pressure field as a flat Float32Array. */ getPressureField(): Float32Array; /** Get the pressure grid (for coupling/stencil access). */ getPressureGrid(): RegularGrid3D; /** Get the current simulation time. */ getTime(): number; getStats(): AcousticStats; /** Set initial pressure distribution. */ setInitialPressure(fn: (x: number, y: number, z: number) => number): void; dispose(): void; } /** * Build a layered velocity field for seismic simulation. * Layers are defined by depth (z-coordinate) boundaries. * Velocity transitions at layer interfaces. * * @param resolution Grid resolution [nx, ny, nz] * @param domainSize Domain size [lx, ly, lz] in meters * @param layers Array of { depth, velocity } sorted by increasing depth. * depth is the z-coordinate of the TOP of the layer. * The first layer starts at z=0 (depth=0 implicit). * @returns RegularGrid3D with per-cell velocity */ export declare function buildLayeredVelocity(resolution: [number, number, number], domainSize: [number, number, number], layers: { depth: number; velocity: number; }[]): RegularGrid3D; //# sourceMappingURL=AcousticSolver.d.ts.map