Skip to main content

sim_lib_interference_core/
problem.rs

1//! A complete, single-frequency coherent interference problem.
2
3use std::f64::consts::TAU;
4
5use crate::{Hertz, PositiveMetres, ScalarMedium, SourceSet, WaveNumber};
6
7/// The distance at which a point emitter's field amplitude is specified.
8///
9/// Point-source propagation therefore uses a dimensionless spreading factor
10/// `POINT_SOURCE_REFERENCE_DISTANCE_METRES / r`.
11pub const POINT_SOURCE_REFERENCE_DISTANCE_METRES: f64 = 1.0;
12
13/// A coherent scalar-wave problem in one homogeneous medium.
14///
15/// The model uses the real field
16/// `u(x, t) = Re{U(x) * exp(-i * omega * t)}` and the complex wavenumber
17/// `k_tilde = omega / c + i * alpha`. Away from point sources, the phasor
18/// satisfies `laplacian(U) + k_tilde^2 * U = 0`.
19///
20/// The positive outgoing sign is `exp(i * k_tilde * distance)`: phase advances
21/// with distance while non-negative `alpha` attenuates it. Point-source
22/// amplitudes are stated at [`POINT_SOURCE_REFERENCE_DISTANCE_METRES`] and
23/// samples at or inside `singularity_radius` are outside the model.
24#[derive(Clone, Debug, PartialEq)]
25pub struct InterferenceProblem {
26    /// The one frequency shared by every coherent source.
27    pub frequency: Hertz,
28    /// The homogeneous scalar propagation medium.
29    pub medium: ScalarMedium,
30    /// The non-empty, canonically ordered coherent sources.
31    pub sources: SourceSet,
32    /// The positive exclusion radius around every point source.
33    pub singularity_radius: PositiveMetres,
34}
35
36impl InterferenceProblem {
37    /// Constructs a problem from checked components.
38    pub fn new(
39        frequency: Hertz,
40        medium: ScalarMedium,
41        sources: SourceSet,
42        singularity_radius: PositiveMetres,
43    ) -> Self {
44        Self {
45            frequency,
46            medium,
47            sources,
48            singularity_radius,
49        }
50    }
51
52    /// Returns the angular frequency `omega = 2 * pi * frequency`.
53    pub fn angular_frequency_radians_per_second(&self) -> f64 {
54        TAU * self.frequency.get()
55    }
56
57    /// Returns this problem's complex wavenumber.
58    pub fn wavenumber(&self) -> WaveNumber {
59        self.medium.wavenumber(self.frequency)
60    }
61
62    /// Returns the unattenuated wavelength `c / frequency` in metres.
63    pub fn wavelength_metres(&self) -> f64 {
64        self.medium.speed().get() / self.frequency.get()
65    }
66}