#[derive(Debug, Clone)]
pub struct ModeMonitor {
pub ix: usize,
pub iy_range: std::ops::Range<usize>,
pub mode_e: Vec<f64>,
pub mode_h: Vec<f64>,
pub mode_power: f64,
pub recorded_e: Vec<Vec<f64>>,
pub recorded_h: Vec<Vec<f64>>,
pub dt: f64,
}
impl ModeMonitor {
pub fn new(ix: usize, iy_start: usize, mode_e: Vec<f64>, mode_h: Vec<f64>, dt: f64) -> Self {
let n = mode_e.len();
let mode_power = mode_e.iter().map(|e| e * e).sum::<f64>();
Self {
ix,
iy_range: iy_start..iy_start + n,
mode_e,
mode_h,
mode_power,
recorded_e: Vec::new(),
recorded_h: Vec::new(),
dt,
}
}
pub fn record(&mut self, ez_grid: &[f64], hy_grid: &[f64], ny: usize) {
let e_slice: Vec<f64> = self
.iy_range
.clone()
.map(|iy| {
let idx = self.ix * ny + iy;
if idx < ez_grid.len() {
ez_grid[idx]
} else {
0.0
}
})
.collect();
let h_slice: Vec<f64> = self
.iy_range
.clone()
.map(|iy| {
let idx = self.ix * ny + iy;
if idx < hy_grid.len() {
hy_grid[idx]
} else {
0.0
}
})
.collect();
self.recorded_e.push(e_slice);
self.recorded_h.push(h_slice);
}
pub fn mode_amplitude(&self, t_idx: usize) -> f64 {
if t_idx >= self.recorded_e.len() || self.mode_power < 1e-30 {
return 0.0;
}
let e = &self.recorded_e[t_idx];
let overlap: f64 = e
.iter()
.zip(self.mode_e.iter())
.map(|(ef, em)| ef * em)
.sum();
overlap / self.mode_power
}
pub fn dft_amplitude(&self, f_hz: f64) -> (f64, f64) {
use std::f64::consts::PI;
let n_t = self.recorded_e.len();
if n_t == 0 {
return (0.0, 0.0);
}
let mut re = 0.0_f64;
let mut im = 0.0_f64;
for t_idx in 0..n_t {
let t = t_idx as f64 * self.dt;
let amp = self.mode_amplitude(t_idx);
let phase = 2.0 * PI * f_hz * t;
re += amp * phase.cos();
im += amp * phase.sin();
}
(re / n_t as f64, im / n_t as f64)
}
pub fn spectral_power(&self, f_hz: f64) -> f64 {
let (re, im) = self.dft_amplitude(f_hz);
re * re + im * im
}
pub fn peak_amplitude(&self) -> f64 {
self.recorded_e
.iter()
.enumerate()
.map(|(t, _)| self.mode_amplitude(t).abs())
.fold(0.0_f64, f64::max)
}
pub fn n_steps(&self) -> usize {
self.recorded_e.len()
}
pub fn amplitude_series(&self) -> Vec<f64> {
(0..self.n_steps())
.map(|t| self.mode_amplitude(t))
.collect()
}
}
pub struct ModeFluxMonitor {
pub monitor: ModeMonitor,
}
impl ModeFluxMonitor {
pub fn new(ix: usize, iy_start: usize, mode_e: Vec<f64>, mode_h: Vec<f64>, dt: f64) -> Self {
Self {
monitor: ModeMonitor::new(ix, iy_start, mode_e, mode_h, dt),
}
}
pub fn average_power(&self) -> f64 {
let series = self.monitor.amplitude_series();
if series.is_empty() {
return 0.0;
}
series.iter().map(|a| a * a).sum::<f64>() / series.len() as f64
}
pub fn transmission(&self, p_in: f64) -> f64 {
if p_in < 1e-30 {
return 0.0;
}
self.average_power() / p_in
}
}
#[cfg(test)]
mod tests {
use super::*;
fn gaussian_mode(n: usize) -> Vec<f64> {
let w = n as f64 / 4.0;
(0..n)
.map(|i| {
let y = i as f64 - n as f64 / 2.0;
(-(y / w).powi(2)).exp()
})
.collect()
}
#[test]
fn mode_monitor_record_length() {
let mode_e = gaussian_mode(20);
let mode_h = mode_e.clone();
let mut mon = ModeMonitor::new(5, 0, mode_e, mode_h, 1e-18);
let ez = vec![1.0_f64; 10 * 20];
let hy = vec![0.001_f64; 10 * 20];
mon.record(&ez, &hy, 20);
mon.record(&ez, &hy, 20);
assert_eq!(mon.n_steps(), 2);
}
#[test]
fn mode_monitor_amplitude_nonzero() {
let mode_e = gaussian_mode(20);
let mode_h = mode_e.clone();
let mut mon = ModeMonitor::new(5, 0, mode_e, mode_h, 1e-18);
let ez = vec![1.0_f64; 10 * 20];
let hy = vec![0.0_f64; 10 * 20];
mon.record(&ez, &hy, 20);
let amp = mon.mode_amplitude(0);
assert!(amp.abs() > 0.0, "amplitude should be nonzero");
}
#[test]
fn mode_monitor_peak_nonnegative() {
let mode_e = gaussian_mode(20);
let mode_h = mode_e.clone();
let mut mon = ModeMonitor::new(5, 0, mode_e, mode_h, 1e-18);
let ez = vec![0.5_f64; 10 * 20];
let hy = vec![0.0_f64; 10 * 20];
for _ in 0..5 {
mon.record(&ez, &hy, 20);
}
assert!(mon.peak_amplitude() >= 0.0);
}
#[test]
fn mode_monitor_dft_amplitude() {
let mode_e = gaussian_mode(20);
let mode_h = mode_e.clone();
let dt = 1e-16;
let mut mon = ModeMonitor::new(5, 0, mode_e, mode_h, dt);
let ez = vec![1.0_f64; 10 * 20];
let hy = vec![0.0_f64; 10 * 20];
for _ in 0..100 {
mon.record(&ez, &hy, 20);
}
let (re, im) = mon.dft_amplitude(1.94e14);
assert!((re * re + im * im).sqrt().is_finite());
}
#[test]
fn mode_flux_monitor_average_power() {
let mode_e = gaussian_mode(20);
let mode_h = mode_e.clone();
let mut mfm = ModeFluxMonitor::new(5, 0, mode_e, mode_h, 1e-18);
let ez = vec![1.0_f64; 10 * 20];
let hy = vec![0.0_f64; 10 * 20];
for _ in 0..10 {
mfm.monitor.record(&ez, &hy, 20);
}
let p = mfm.average_power();
assert!(p >= 0.0, "power={p:.4}");
}
#[test]
fn mode_flux_transmission_ratio() {
let mode_e = gaussian_mode(20);
let mode_h = mode_e.clone();
let mut mfm = ModeFluxMonitor::new(5, 0, mode_e, mode_h, 1e-18);
let ez = vec![1.0_f64; 10 * 20];
let hy = vec![0.0_f64; 10 * 20];
for _ in 0..5 {
mfm.monitor.record(&ez, &hy, 20);
}
let p = mfm.average_power();
let t = mfm.transmission(p * 2.0);
assert!((t - 0.5).abs() < 0.01, "T={t:.3}");
}
}