use crate::units::conversion::{EPSILON_0, Z0};
#[derive(Debug, Clone)]
pub struct Cpml {
pub thickness: usize,
pub b_e: Vec<f64>,
pub c_e: Vec<f64>,
pub b_h: Vec<f64>,
pub c_h: Vec<f64>,
pub kappa_e: Vec<f64>,
pub kappa_h: Vec<f64>,
}
impl Cpml {
pub fn new(total_cells: usize, pml_cells: usize, d: f64, dt: f64, m: f64, r0: f64) -> Self {
let n = total_cells;
let d_pml = pml_cells as f64 * d;
let sigma_max = -(m + 1.0) * r0.ln() / (2.0 * d_pml * Z0);
let kappa_max = 1.0;
let alpha_max = 0.05 * sigma_max;
let mut b_e = vec![1.0; n];
let mut c_e = vec![0.0; n];
let mut b_h = vec![1.0; n];
let mut c_h = vec![0.0; n];
let mut kappa_e = vec![1.0; n];
let mut kappa_h = vec![1.0; n];
for i in 0..pml_cells {
let rho_e = (pml_cells - i) as f64 / pml_cells as f64;
let sigma_e = sigma_max * rho_e.powf(m);
let kappa = 1.0 + (kappa_max - 1.0) * rho_e.powf(m);
let alpha = alpha_max * (1.0 - rho_e).max(0.0);
let (b, c) = cpml_bc(sigma_e, kappa, alpha, dt, EPSILON_0);
b_e[i] = b;
c_e[i] = c;
kappa_e[i] = kappa;
let rho_h = (pml_cells as f64 - i as f64 - 0.5) / pml_cells as f64;
let sigma_h = sigma_max * rho_h.powf(m);
let kappa_h_val = 1.0 + (kappa_max - 1.0) * rho_h.powf(m);
let alpha_h = alpha_max * (1.0 - rho_h).max(0.0);
let (bh, ch) = cpml_bc(sigma_h, kappa_h_val, alpha_h, dt, EPSILON_0);
b_h[i] = bh;
c_h[i] = ch;
kappa_h[i] = kappa_h_val;
}
for i in 0..pml_cells {
let gi = n - pml_cells + i;
let rho_e = (i + 1) as f64 / pml_cells as f64;
let sigma_e = sigma_max * rho_e.powf(m);
let kappa = 1.0 + (kappa_max - 1.0) * rho_e.powf(m);
let alpha = alpha_max * (1.0 - rho_e).max(0.0);
let (b, c) = cpml_bc(sigma_e, kappa, alpha, dt, EPSILON_0);
b_e[gi] = b;
c_e[gi] = c;
kappa_e[gi] = kappa;
let rho_h = (i as f64 + 0.5) / pml_cells as f64;
let sigma_h = sigma_max * rho_h.powf(m);
let kappa_h_val = 1.0 + (kappa_max - 1.0) * rho_h.powf(m);
let alpha_h = alpha_max * (1.0 - rho_h).max(0.0);
let (bh, ch) = cpml_bc(sigma_h, kappa_h_val, alpha_h, dt, EPSILON_0);
b_h[gi] = bh;
c_h[gi] = ch;
kappa_h[gi] = kappa_h_val;
}
Self {
thickness: pml_cells,
b_e,
c_e,
b_h,
c_h,
kappa_e,
kappa_h,
}
}
}
fn cpml_bc(sigma: f64, kappa: f64, alpha: f64, dt: f64, eps_or_mu: f64) -> (f64, f64) {
let b = (-(sigma / kappa + alpha) * dt / eps_or_mu).exp();
let denom = kappa * (sigma + kappa * alpha);
let c = if denom.abs() < 1e-30 {
0.0
} else {
sigma / denom * (b - 1.0)
};
(b, c)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cpml_interior_is_identity() {
let pml = Cpml::new(100, 10, 10e-9, 1.67e-17, 3.5, 1e-8);
let mid = 50;
assert!((pml.b_e[mid] - 1.0).abs() < 1e-12);
assert!(pml.c_e[mid].abs() < 1e-12);
assert!((pml.kappa_e[mid] - 1.0).abs() < 1e-12);
}
#[test]
fn cpml_pml_cells_have_nonzero_coefficients() {
let pml = Cpml::new(100, 10, 10e-9, 1.67e-17, 3.5, 1e-8);
assert!(pml.b_e[0] < 1.0);
assert!(pml.b_e[99] < 1.0);
}
}