use std::f64::consts::{FRAC_PI_2, PI};
use super::{
three::{SphericalAngles, ThreeMatrix, ThreeVector},
util::ra_dec_to_theta_phi,
};
pub const TENSOR_MODES: [&str; 2] = ["plus", "cross"];
pub const ALL_MODES: [&str; 6] = ["plus", "cross", "breathing", "longitudinal", "x", "y"];
#[derive(Debug)]
pub struct PolarizationMatrix {
m: ThreeVector,
n: ThreeVector,
omega: ThreeVector,
}
impl PolarizationMatrix {
pub fn new(theta: f64, phi: f64, psi: f64) -> Self {
let vec1: ThreeVector = SphericalAngles {
zenith: FRAC_PI_2,
azimuth: phi - FRAC_PI_2,
}
.into();
let vec2: ThreeVector = SphericalAngles {
zenith: theta - FRAC_PI_2,
azimuth: phi,
}
.into();
let vec3: ThreeVector = SphericalAngles {
zenith: PI - theta,
azimuth: PI + phi,
}
.into();
let matrix = ThreeMatrix {
rows: [vec1, vec2, vec3],
}
.rotate_z(-psi);
Self {
m: matrix.rows[0],
n: matrix.rows[1],
omega: matrix.rows[2],
}
}
pub fn plus(&self) -> ThreeMatrix {
self.m.outer(self.m) - self.n.outer(self.n)
}
pub fn cross(&self) -> ThreeMatrix {
symmetric_mode(self.m, self.n)
}
pub fn breathing(&self) -> ThreeMatrix {
self.m.outer(self.m) + self.n.outer(self.n)
}
pub fn longitudinal(&self) -> ThreeMatrix {
self.omega.outer(self.omega)
}
pub fn x(&self) -> ThreeMatrix {
symmetric_mode(self.m, self.omega)
}
pub fn y(&self) -> ThreeMatrix {
symmetric_mode(self.n, self.omega)
}
pub fn mode(&self, mode: &str) -> ThreeMatrix {
match mode {
"plus" => self.plus(),
"cross" => self.cross(),
"breathing" => self.breathing(),
"longitudinal" => self.longitudinal(),
"x" => self.x(),
"y" => self.y(),
_ => panic!("{mode} not a polarization mode!"),
}
}
}
fn symmetric_mode(input_1: ThreeVector, input_2: ThreeVector) -> ThreeMatrix {
input_1.outer(input_2) + input_2.outer(input_1)
}
pub fn polarization_tensor(ra: f64, dec: f64, gps_time: f64, psi: f64, mode: &str) -> ThreeMatrix {
let (theta, phi) = ra_dec_to_theta_phi(ra, dec, gps_time);
PolarizationMatrix::new(theta, phi, psi).mode(mode)
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! assert_matrix_approx_eq {
($a:expr, $b:expr) => {
const EPSILON: f64 = 1e-10;
for i in 0..3 {
assert!(($a.rows[i].x - $b.rows[i].x).abs() < EPSILON);
assert!(($a.rows[i].y - $b.rows[i].y).abs() < EPSILON);
assert!(($a.rows[i].z - $b.rows[i].z).abs() < EPSILON);
}
};
}
#[test]
fn test_plus_mode() {
let pm = PolarizationMatrix::new(1.0, 2.0, 3.0);
let result = pm.plus();
println!("{:?}", result);
let expected = ThreeMatrix {
rows: [
ThreeVector {
x: 0.6310944283106209,
y: 0.5680750305371688,
z: -0.3954588595258747,
},
ThreeVector {
x: 0.5680750305371688,
y: 0.04877662868261845,
z: 0.29910040882446337,
},
ThreeVector {
x: -0.3954588595258747,
y: 0.29910040882446337,
z: -0.6798710569932394,
},
],
};
assert_matrix_approx_eq!(result, expected);
}
#[test]
fn test_cross_mode() {
let pm = PolarizationMatrix::new(1.0, 2.0, 3.0);
let result = pm.cross();
println!("{:?}", result);
let expected = ThreeMatrix {
rows: [
ThreeVector {
x: 0.6095165675666464,
y: -0.20250177557045979,
z: 0.6818062130067495,
},
ThreeVector {
x: -0.20250177557045979,
y: -0.41166988063832005,
z: 0.45174151309178,
},
ThreeVector {
x: 0.6818062130067495,
y: 0.45174151309178,
z: -0.19784668692832622,
},
],
};
assert_matrix_approx_eq!(result, expected);
}
#[test]
fn test_breathing_mode() {
let pm = PolarizationMatrix::new(1.0, 2.0, 3.0);
let result = pm.breathing();
println!("{:?}", result);
let expected = ThreeMatrix {
rows: [
ThreeVector {
x: 0.8773771273420202,
y: 0.2679358649053266,
z: 0.1892006238269821,
},
ThreeVector {
x: 0.2679358649053266,
y: 0.41454945438440843,
z: -0.4134109052159029,
},
ThreeVector {
x: 0.1892006238269821,
y: -0.4134109052159029,
z: 0.7080734182735711,
},
],
};
assert_matrix_approx_eq!(result, expected);
}
#[test]
fn test_longitudinal_mode() {
let pm = PolarizationMatrix::new(1.0, 2.0, 3.0);
let result = pm.longitudinal();
println!("{:?}", result);
let expected = ThreeMatrix {
rows: [
ThreeVector {
x: 0.12262287265797965,
y: -0.26793586490532656,
z: -0.18920062382698202,
},
ThreeVector {
x: -0.26793586490532656,
y: 0.5854505456155917,
z: 0.413410905215903,
},
ThreeVector {
x: -0.18920062382698202,
y: 0.413410905215903,
z: 0.2919265817264287,
},
],
};
assert_matrix_approx_eq!(result, expected);
}
#[test]
fn test_vector_x_mode() {
let pm = PolarizationMatrix::new(1.0, 2.0, 3.0);
let result = pm.x();
println!("{:?}", result);
let expected = ThreeMatrix {
rows: [
ThreeVector {
x: -0.6082320535403873,
y: 0.49596132203235593,
z: 0.5108177625907906,
},
ThreeVector {
x: 0.49596132203235593,
y: 0.7365521137428442,
z: 0.16919497019111168,
},
ThreeVector {
x: 0.5108177625907906,
y: 0.16919497019111168,
z: -0.12832006020245665,
},
],
};
assert_matrix_approx_eq!(result, expected);
}
#[test]
fn test_vector_y_mode() {
let pm = PolarizationMatrix::new(1.0, 2.0, 3.0);
let result = pm.y();
println!("{:?}", result);
let expected = ThreeMatrix {
rows: [
ThreeVector {
x: -0.24576367527033288,
y: 0.4182550352491018,
z: -0.10211348383083577,
},
ThreeVector {
x: 0.4182550352491018,
y: -0.6544339544651846,
z: 0.40634453755196465,
},
ThreeVector {
x: -0.10211348383083577,
y: 0.40634453755196465,
z: 0.9001976297355173,
},
],
};
assert_matrix_approx_eq!(result, expected);
}
}