use na::Matrix2;
use num::complex::Complex;
use super::common::{rotate_matrix, Angle, ComplexMatrix, JonesMatrix};
#[cfg(test)]
use proptest::prelude::*;
#[derive(Debug, Copy, Clone)]
pub struct HalfWavePlate {
mat: ComplexMatrix,
}
impl HalfWavePlate {
pub fn new(angle: Angle) -> Self {
let rad = match angle {
Angle::Degrees(deg) => deg.to_radians(),
Angle::Radians(rad) => rad,
};
let sin2 = Complex::new((2_f64 * rad).sin(), 0_f64);
let cos2 = Complex::new((2_f64 * rad).cos(), 0_f64);
let mat = Matrix2::new(cos2, sin2, sin2, -cos2);
HalfWavePlate { mat }
}
}
impl JonesMatrix for HalfWavePlate {
fn rotated(&self, angle: Angle) -> Self {
HalfWavePlate {
mat: rotate_matrix(&self.mat, &angle),
}
}
fn rotate(&mut self, angle: Angle) {
self.mat = rotate_matrix(&self.mat, &angle);
}
fn matrix(&self) -> ComplexMatrix {
self.mat
}
}
#[cfg(test)]
impl Arbitrary for HalfWavePlate {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
any::<Angle>()
.prop_map(|angle| HalfWavePlate::new(angle))
.prop_filter("half-wave plate shouldn't contain NaN", |hwp| {
let m00_okay = !hwp.matrix()[(0, 0)].is_nan();
let m01_okay = !hwp.matrix()[(0, 1)].is_nan();
let m10_okay = !hwp.matrix()[(1, 0)].is_nan();
let m11_okay = !hwp.matrix()[(1, 1)].is_nan();
m00_okay && m01_okay && m10_okay && m11_okay
})
.boxed()
}
}
#[cfg(test)]
mod test {
use super::*;
use jones::common::{are_rel_eq, Beam, JonesVector};
#[test]
fn test_hwp_ignores_parallel_beam() {
let beam = Beam::new(Complex::new(1_f64, 0_f64), Complex::new(0_f64, 0_f64));
let hwp = HalfWavePlate::new(Angle::Degrees(0.0));
let beam_after = beam.apply_element(hwp);
assert_beam_approx_eq!(beam_after, beam);
}
#[test]
fn test_hwp_ignores_perpendicular_beam() {
let beam = Beam::new(Complex::new(0_f64, 0_f64), Complex::new(1_f64, 0_f64));
let hwp = HalfWavePlate::new(Angle::Degrees(0.0));
let beam_after = beam.apply_element(hwp).apply_element(hwp);
assert_beam_approx_eq!(beam_after, beam);
}
proptest!{
#[test]
fn test_hwp_reflects_polarization(theta in 0_f64..90_f64) {
let beam = Beam::linear(Angle::Degrees(theta));
let expected_beam = Beam::linear(Angle::Degrees(-theta));
let hwp = HalfWavePlate::new(Angle::Degrees(0.0));
let beam_after = beam.apply_element(hwp);
prop_assert_beam_approx_eq!(beam_after, expected_beam);
}
#[test]
fn test_hwp_preserves_intensity(hwp: HalfWavePlate, beam: Beam) {
let intensity_before = beam.intensity();
prop_assume!(intensity_before.is_ok());
let beam_after = beam.apply_element(hwp);
let intensity_after = beam_after.intensity();
prop_assume!(intensity_after.is_ok());
prop_assert_approx_eq!(intensity_after.unwrap(), intensity_before.unwrap());
}
}
}