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>;