use dsmc::{dka_method, vieta_formula};
use num_complex::Complex;
fn relative_residual(coeffs: &[Complex<f64>], r: Complex<f64>) -> f64 {
let (mut value, mut scale) = (Complex::new(0.0, 0.0), 0.0);
for (k, c) in coeffs.iter().enumerate() {
let term = c * r.powi((coeffs.len() - 1 - k) as i32);
value += term;
scale += term.norm();
}
value.norm() / scale
}
#[test]
fn test_roots_plot() {
use dsmc::Polynomial;
use dsmc::logger::DataStorage;
let omega_c = -300.0;
let roots: Vec<Complex<f64>> = vec![
Complex::new(omega_c, 0.0),
Complex::new(omega_c, 0.0),
Complex::new(omega_c, 0.0),
];
let coeffs = vieta_formula(&roots);
let gains = coeffs.0[1..]
.iter()
.map(|x| x.re)
.collect::<Vec<_>>();
let iter = 20;
for i in 0..=iter {
let alpha = 0.8 + 0.4 / iter as f64 * i as f64;
let gains_fluctuated = gains.iter().map(|x| x * alpha).collect::<Vec<_>>();
let mut coeffs = vec![1.0];
coeffs.extend_from_slice(&gains_fluctuated);
let coeffs = coeffs
.into_iter()
.map(|x| Complex::new(x, 0.0))
.collect::<Vec<_>>();
let coeffs = Polynomial(coeffs);
let roots = dka_method(&coeffs);
let found = roots.as_ref().expect("dka_method failed");
assert_eq!(found.len(), 3, "alpha = {alpha}");
for r in found {
assert!(relative_residual(&coeffs.0, *r) < 1e-9, "alpha = {alpha}: {r} is not a root");
assert!(found.iter().any(|q| (q - r.conj()).norm() < 1e-6 * r.norm()), "alpha = {alpha}: no conjugate for {r}");
}
if (alpha - 1.0).abs() < 1e-12 {
for r in found {
assert!((r - Complex::new(omega_c, 0.0)).norm() < 1e-2, "triple root: {r}");
}
}
let mut storage = DataStorage::new(format!("./out/roots_locus/roots_locus_alpha_{:.02}.csv", alpha)).unwrap();
if let Some(roots) = roots {
for root in roots {
storage.add(&[root.re, root.im]).unwrap();
}
storage.close().unwrap();
}
}
}
#[test]
fn test_roots_plot_2order() {
use dsmc::Polynomial;
use dsmc::logger::DataStorage;
let omega_c = 300.0;
let iter = 20;
for i in 0..=iter {
let zeta = 0.0 + 2.0 / iter as f64 * i as f64;
let coeffs = vec![1.0, 2.0 * zeta * omega_c, omega_c * omega_c];
let coeffs = coeffs
.into_iter()
.map(|x| Complex::new(x, 0.0))
.collect::<Vec<_>>();
let coeffs = Polynomial(coeffs);
let roots = dka_method(&coeffs);
let disc = Complex::new(zeta * zeta - 1.0, 0.0).sqrt() * omega_c;
let expected = [Complex::new(-zeta * omega_c, 0.0) + disc, Complex::new(-zeta * omega_c, 0.0) - disc];
let found = roots.as_ref().expect("dka_method failed");
assert_eq!(found.len(), 2, "zeta = {zeta}");
for e in expected {
assert!(found.iter().any(|r| (r - e).norm() < 1e-3), "zeta = {zeta}: {e} not in {found:?}");
}
let mut storage = DataStorage::new(format!("./out/roots_locus_2order/roots_locus_zeta_{:.01}.csv", zeta)).unwrap();
if let Some(roots) = roots {
for root in roots {
storage.add(&[root.re, root.im]).unwrap();
}
storage.close().unwrap();
}
}
}