use num_complex::Complex64;
use crate::transform::Transform;
#[derive(Debug, Clone)]
pub struct XafsOutput {
pub r: Vec<f64>,
pub chir_re: Vec<f64>,
pub chir_im: Vec<f64>,
pub chir_mag: Vec<f64>,
pub chir_pha: Vec<f64>,
pub q: Vec<f64>,
pub chiq_re: Vec<f64>,
pub chiq_im: Vec<f64>,
pub chiq_mag: Vec<f64>,
pub chiq_pha: Vec<f64>,
}
#[derive(Debug, Clone)]
pub struct DataSetOutput {
pub data: XafsOutput,
pub model: XafsOutput,
pub paths: Vec<XafsOutput>,
}
fn round_half_even(x: f64) -> f64 {
let lower = x.floor();
let frac = x - lower;
if frac < 0.5 {
lower
} else if frac > 0.5 {
lower + 1.0
} else if (lower as i64) % 2 == 0 {
lower
} else {
lower + 1.0
}
}
fn complex_phase(z: &[Complex64]) -> Vec<f64> {
let phase: Vec<f64> = z.iter().map(|c| c.im.atan2(c.re)).collect();
let mut out = phase.clone();
let mut cum = 0.0;
for i in 1..phase.len() {
let d = (phase[i] - phase[i - 1]) / std::f64::consts::PI;
cum += round_half_even(d.abs()) * d.signum();
out[i] -= std::f64::consts::PI * cum;
}
out
}
fn linspace(start: f64, stop: f64, num: usize) -> Vec<f64> {
if num == 0 {
return Vec::new();
}
if num == 1 {
return vec![start];
}
let step = (stop - start) / (num - 1) as f64;
let mut v: Vec<f64> = (0..num).map(|i| start + i as f64 * step).collect();
v[num - 1] = stop;
v
}
pub fn xafsft(trans: &Transform, chi: &[f64], rmax_out: f64) -> XafsOutput {
let kw0 = trans.kweight[0];
let outr = trans.fftf(chi, kw0);
let rstep = trans.rstep();
let nfft_half = trans.nfft as f64 / 2.0;
let irmax = nfft_half.min(1.01 + rmax_out / rstep) as usize;
let r: Vec<f64> = (0..irmax).map(|i| rstep * i as f64).collect();
let chir_re: Vec<f64> = outr[..irmax].iter().map(|c| c.re).collect();
let chir_im: Vec<f64> = outr[..irmax].iter().map(|c| c.im).collect();
let chir_mag: Vec<f64> = outr[..irmax].iter().map(|c| c.norm()).collect();
let chir_pha = complex_phase(&outr[..irmax]);
let outq = trans.fftr(&outr);
let qmax_out = trans.kmax + 2.0;
let nq = (1.05 + qmax_out / trans.kstep) as usize;
let q = linspace(0.0, qmax_out, nq);
let chiq_re: Vec<f64> = outq[..nq].iter().map(|c| c.re).collect();
let chiq_im: Vec<f64> = outq[..nq].iter().map(|c| c.im).collect();
let chiq_mag: Vec<f64> = outq[..nq].iter().map(|c| c.norm()).collect();
let chiq_pha = complex_phase(&outq[..nq]);
XafsOutput {
r,
chir_re,
chir_im,
chir_mag,
chir_pha,
q,
chiq_re,
chiq_im,
chiq_mag,
chiq_pha,
}
}