treams_core/cw/
mod.rs

1//! Cylindrical vector waves: mode labels, translation coefficients of mode pairs,
2//! expansion matrices between bases and over lattices, and the conversion to spherical
3//! waves.
4//!
5//! Upstream: `treams.cw`, and `treams.special.tl_vcw` and `tl_vcw_r`.
6//!
7//! | File | Contents | Upstream |
8//! |---|---|---|
9//! | `polar.rs` | [`polar_translation`] and [`polar_translation_array`] of one order difference, [`tl_vcw`] and [`translate`] of one mode pair | `special.tl_vcw`, `tl_vcw_r`, `cw.translate` |
10//! | `cartesian.rs` | [`cartesian_translation`]: one coefficient at a Cartesian displacement, with its derivatives | treams-rs extension |
11//! | `expansion.rs` | [`expansion()`] and [`lattice_expansion`] | `Expand`, `ExpandLattice`, `cw.translate_periodic` |
12//! | `to_sw.rs` | [`to_sw()`] and [`to_sw_matrix`] | `cw.to_sw`, `Expand` to a spherical basis |
13//!
14//! Conventions:
15//!
16//! - A translation from a source position to a destination position takes the
17//!   displacement `destination - source`. Lattice sums run over `source - destination`,
18//!   the argument of [`crate::lattice::sum`].
19//! - Two modes couple only at equal axial wavenumbers `kz` and equal polarization
20//!   indices `pol`. `kz` is an exact label: the coupling compares it bit for bit.
21//! - `pol` is the polarization index, 0 or 1, with the meanings of [`crate::sw`].
22//! - [`Radial::Regular`](crate::special::Radial::Regular) and
23//!   [`Radial::Singular`](crate::special::Radial::Singular) are the treams `modetype`
24//!   values 'regular' and 'singular'.
25//! - In [`CartesianTranslation`], every field other than `value` holds the derivative of
26//!   `value` with respect to the input it is named after; `position` holds the
27//!   derivatives with respect to the displacement components.
28//!
29//! The inline `tests` modules check how each file computes its results; the physical
30//! and adjoint identities of translations and expansions are in `properties/waves.rs`.
31
32mod cartesian;
33mod expansion;
34mod polar;
35mod to_sw;
36
37pub(crate) use cartesian::regular_harmonic;
38pub use cartesian::{CartesianTranslation, cartesian_translation};
39pub use expansion::{ExpansionResidual, LatticeExpansionResidual, expansion, lattice_expansion};
40pub use polar::{
41    PolarTranslationResidual, polar_translation, polar_translation_array, tl_vcw, translate,
42};
43pub(crate) use to_sw::coefficient;
44pub use to_sw::{ToSwResidual, to_sw, to_sw_matrix};
45
46use crate::{Complex, Error, MAX_DEGREE, Result, basis::ModeLabel, numerics::Jet};
47
48/// One cylindrical-wave mode: axial wavenumber `kz`, order `m` and polarization index
49/// `pol`.
50///
51/// Upstream: the `(kz, m, pol)` of one entry of `treams.CylindricalWaveBasis`; [`Basis`]
52/// adds the position index `pidx`.
53#[derive(Clone, Copy, Debug)]
54pub struct Mode {
55    /// Axial wavenumber (a fixed mode label for basis expansion).
56    pub kz: f64,
57    /// Integer azimuthal order.
58    pub m: i32,
59    /// Polarization index: 1 or 0, as in treams.
60    pub pol: u8,
61}
62
63impl ModeLabel for Mode {
64    /// Require a finite `kz`, `|m| <= MAX_DEGREE` and `pol` 0 or 1.
65    fn validate(self) -> Result<()> {
66        if !self.kz.is_finite() || self.m.unsigned_abs() > MAX_DEGREE.unsigned_abs() || self.pol > 1
67        {
68            return Err(Error::InvalidInput(
69                // 128 is MAX_DEGREE.
70                "require finite kz, |m| <= 128 and polarization 0 or 1".into(),
71            ));
72        }
73        Ok(())
74    }
75
76    fn pol(self) -> u8 {
77        self.pol
78    }
79}
80
81/// Transverse wavenumber `sqrt(k² - kz²)` on the branch with nonnegative imaginary part.
82pub(crate) fn transverse<const N: usize>(k: Jet<N>, kz: Jet<N>) -> Jet<N> {
83    let root = (k * k - kz * kz).sqrt();
84    if root.value.im < 0.0 { -root } else { root }
85}
86
87/// [`transverse`] of a complex wavenumber and a real axial wavenumber.
88fn transverse_wavenumber(k: Complex, kz: f64) -> Complex {
89    transverse(Jet::<0>::constant(k), Jet::constant(kz)).value
90}
91
92/// Cylindrical modes at Cartesian expansion positions.
93///
94/// Upstream: `treams.CylindricalWaveBasis`.
95pub type Basis = crate::basis::Basis<Mode>;