use nalgebra::{Complex, Matrix2, Point3, Vector3};
use std::f32::consts::PI;
use goad::bins::{AngleBin, SolidAngleBin};
use goad::diff::n2f_aperture_diffraction;
const TOL: f32 = 1e-3;
fn square_aperture() -> Vec<Point3<f32>> {
vec![
Point3::new(1.0, 1.0, 0.0),
Point3::new(-1.0, 1.0, 0.0),
Point3::new(-1.0, -1.0, 0.0),
Point3::new(1.0, -1.0, 0.0),
]
}
fn forward_bin() -> SolidAngleBin {
let theta_bin = AngleBin::new(0.0, 1.0);
let phi_bin = AngleBin::new(0.0, 1.0);
SolidAngleBin::new(theta_bin, phi_bin)
}
fn is_proportional_to_identity(ampl: &Matrix2<Complex<f32>>, tol: f32) -> bool {
let off_diag_small = ampl[(0, 1)].norm() < tol && ampl[(1, 0)].norm() < tol;
let diag_ratio = if ampl[(1, 1)].norm() > 1e-10 {
(ampl[(0, 0)] / ampl[(1, 1)] - Complex::new(1.0, 0.0)).norm()
} else {
0.0
};
off_diag_small && diag_ratio < tol
}
#[test]
fn test_forward_diffraction_e_perp_along_x() {
let e_perp = Vector3::new(1.0, 0.0, 0.0);
let prop = Vector3::new(0.0, 0.0, 1.0);
let verts = square_aperture();
let ampl = Matrix2::<Complex<f32>>::identity();
let bins = vec![forward_bin()];
let wavenumber = 2.0 * PI;
let result = n2f_aperture_diffraction(&verts, ampl, prop, e_perp, &bins, wavenumber, None);
assert!(!result.is_empty(), "Should produce output for forward bin");
let forward_ampl = &result[0];
assert!(
is_proportional_to_identity(forward_ampl, TOL),
"Forward amplitude should be proportional to identity, got: {:?}",
forward_ampl
);
}
#[test]
fn test_forward_diffraction_e_perp_along_y() {
let e_perp = Vector3::new(0.0, 1.0, 0.0);
let prop = Vector3::new(0.0, 0.0, 1.0);
let verts = square_aperture();
let ampl = Matrix2::<Complex<f32>>::identity();
let bins = vec![forward_bin()];
let wavenumber = 2.0 * PI;
let result = n2f_aperture_diffraction(&verts, ampl, prop, e_perp, &bins, wavenumber, None);
assert!(!result.is_empty(), "Should produce output for forward bin");
let forward_ampl = &result[0];
assert!(
is_proportional_to_identity(forward_ampl, TOL),
"Forward amplitude should be proportional to identity, got: {:?}",
forward_ampl
);
}
#[test]
fn test_forward_diffraction_e_perp_diagonal_xy() {
let e_perp = Vector3::new(1.0, 1.0, 0.0).normalize();
let prop = Vector3::new(0.0, 0.0, 1.0);
let verts = square_aperture();
let ampl = Matrix2::<Complex<f32>>::identity();
let bins = vec![forward_bin()];
let wavenumber = 2.0 * PI;
let result = n2f_aperture_diffraction(&verts, ampl, prop, e_perp, &bins, wavenumber, None);
assert!(!result.is_empty(), "Should produce output for forward bin");
let forward_ampl = &result[0];
assert!(
is_proportional_to_identity(forward_ampl, TOL),
"Forward amplitude should be proportional to identity, got: {:?}",
forward_ampl
);
}
#[test]
fn test_forward_diffraction_e_perp_negative_x() {
let e_perp = Vector3::new(-1.0, 0.0, 0.0);
let prop = Vector3::new(0.0, 0.0, 1.0);
let verts = square_aperture();
let ampl = Matrix2::<Complex<f32>>::identity();
let bins = vec![forward_bin()];
let wavenumber = 2.0 * PI;
let result = n2f_aperture_diffraction(&verts, ampl, prop, e_perp, &bins, wavenumber, None);
assert!(!result.is_empty(), "Should produce output for forward bin");
let forward_ampl = &result[0];
assert!(
is_proportional_to_identity(forward_ampl, TOL),
"Forward amplitude should be proportional to identity, got: {:?}",
forward_ampl
);
}
#[test]
fn test_forward_diffraction_prop_along_negative_z() {
let e_perp = Vector3::new(1.0, 0.0, 0.0);
let prop = Vector3::new(0.0, 0.0, -1.0);
let verts = square_aperture();
let ampl = Matrix2::<Complex<f32>>::identity();
let theta_bin = AngleBin::new(179.0, 180.0);
let phi_bin = AngleBin::new(0.0, 1.0);
let backward_bin = SolidAngleBin::new(theta_bin, phi_bin);
let bins = vec![backward_bin];
let wavenumber = 2.0 * PI;
let result = n2f_aperture_diffraction(&verts, ampl, prop, e_perp, &bins, wavenumber, None);
assert!(!result.is_empty(), "Should produce output for forward bin");
let forward_ampl = &result[0];
assert!(
is_proportional_to_identity(forward_ampl, TOL),
"Forward amplitude should be proportional to identity, got: {:?}",
forward_ampl
);
}
#[test]
fn test_forward_diffraction_oblique_prop() {
let prop = Vector3::new(1.0, 0.0, 1.0).normalize();
let e_perp = Vector3::new(0.0, 1.0, 0.0);
let verts = square_aperture();
let ampl = Matrix2::<Complex<f32>>::identity();
let theta_bin = AngleBin::new(44.0, 46.0);
let phi_bin = AngleBin::new(-1.0, 1.0);
let forward_bin = SolidAngleBin::new(theta_bin, phi_bin);
let bins = vec![forward_bin];
let wavenumber = 2.0 * PI;
let result = n2f_aperture_diffraction(&verts, ampl, prop, e_perp, &bins, wavenumber, None);
assert!(!result.is_empty(), "Should produce output for forward bin");
let forward_ampl = &result[0];
assert!(
is_proportional_to_identity(forward_ampl, TOL),
"Forward amplitude should be proportional to identity, got: {:?}",
forward_ampl
);
}
#[test]
fn test_different_e_perp_same_intensity() {
let prop = Vector3::new(0.0, 0.0, 1.0);
let verts = square_aperture();
let bins = vec![forward_bin()];
let wavenumber = 2.0 * PI;
let e_perp_x = Vector3::new(1.0, 0.0, 0.0);
let e_perp_y = Vector3::new(0.0, 1.0, 0.0);
let e_perp_diag = Vector3::new(1.0, 1.0, 0.0).normalize();
let ampl = Matrix2::<Complex<f32>>::identity();
let result_x = n2f_aperture_diffraction(&verts, ampl, prop, e_perp_x, &bins, wavenumber, None);
let result_y = n2f_aperture_diffraction(&verts, ampl, prop, e_perp_y, &bins, wavenumber, None);
let result_diag =
n2f_aperture_diffraction(&verts, ampl, prop, e_perp_diag, &bins, wavenumber, None);
let intensity_x = result_x[0].norm_squared();
let intensity_y = result_y[0].norm_squared();
let intensity_diag = result_diag[0].norm_squared();
assert!(
(intensity_x - intensity_y).abs() / intensity_x < TOL,
"Intensity should be same for e_perp_x and e_perp_y: {} vs {}",
intensity_x,
intensity_y
);
assert!(
(intensity_x - intensity_diag).abs() / intensity_x < TOL,
"Intensity should be same for e_perp_x and e_perp_diag: {} vs {}",
intensity_x,
intensity_diag
);
}