use ndarray::{
Array3, ArrayBase, ArrayView1, ArrayViewMut1, ArrayViewMut3, AsArray, Axis, Ix3, ViewRepr, Zip,
};
use rayon::prelude::*;
use crate::phasor::plot;
use crate::prelude::*;
#[inline]
pub fn calibrate_coords(g: f64, s: f64, modulation: f64, phase: f64) -> (f64, f64) {
let g_trans = modulation * phase.cos();
let s_trans = modulation * phase.sin();
let g_cal = g * g_trans - s * s_trans;
let s_cal = g * s_trans + s * g_trans;
(g_cal, s_cal)
}
#[inline]
pub fn calibrate_gs_image<'a, T, A>(
data: A,
modulation: f64,
phase: f64,
axis: Option<usize>,
threads: Option<usize>,
) -> Array3<f64>
where
A: AsArray<'a, T, Ix3>,
T: 'a + AsNumeric,
{
let data: ArrayBase<ViewRepr<&'a T>, Ix3> = data.into();
let axis = axis.unwrap_or(2);
let shape = data.dim();
let mut c_data = Array3::<f64>::zeros(shape);
let g_trans = modulation * phase.cos();
let s_trans = modulation * phase.sin();
let src_lanes = data.lanes(Axis(axis));
let dst_lanes = c_data.lanes_mut(Axis(axis));
let gs_calibration_calc = |s: ArrayView1<T>, d: &mut ArrayViewMut1<f64>| {
d[0] = s[0].to_f64() * g_trans - s[1].to_f64() * s_trans;
d[1] = s[0].to_f64() * s_trans + s[1].to_f64() * g_trans;
};
par!(threads,
seq_exp: Zip::from(src_lanes).and(dst_lanes)
.for_each(|s, mut d| gs_calibration_calc(s, &mut d)),
par_exp: Zip::from(src_lanes).and(dst_lanes)
.par_for_each(|s, mut d| gs_calibration_calc(s, &mut d)));
c_data
}
#[inline]
pub fn calibrate_gs_image_mut(
mut data: ArrayViewMut3<f64>,
modulation: f64,
phase: f64,
axis: Option<usize>,
threads: Option<usize>,
) {
let axis = axis.unwrap_or(2);
let g_trans = modulation * phase.cos();
let s_trans = modulation * phase.sin();
let lanes = data.lanes_mut(Axis(axis));
let gs_calibration_calc = |ln: &mut ArrayViewMut1<f64>| {
let g_cal = ln[0] * g_trans - ln[1] * s_trans;
let s_cal = ln[0] * s_trans + ln[1] * g_trans;
ln[0] = g_cal;
ln[1] = s_cal;
};
par!(threads,
seq_exp: lanes.into_iter().for_each(|mut ln| gs_calibration_calc(&mut ln)),
par_exp: lanes.into_iter().par_bridge()
.for_each(|mut ln| gs_calibration_calc(&mut ln)))
}
#[inline]
pub fn modulation_and_phase(g: f64, s: f64, tau: f64, omega: f64) -> (f64, f64) {
let cal_point = plot::monoexponential_coords(tau, omega);
let cal_mod = plot::gs_modulation(cal_point.0, cal_point.1);
let cal_phs = plot::gs_phase(cal_point.0, cal_point.1);
let data_mod = plot::gs_modulation(g, s);
let data_phs = plot::gs_phase(g, s);
let d_mod = cal_mod / data_mod;
let d_phs = cal_phs - data_phs;
(d_mod, d_phs)
}