use std::f64::consts::PI;
use crate::xasproc::mathutils::remove_dups;
use crate::xasproc::mback::{MbackParams, mback};
const TINY_ENERGY: f64 = 0.00050;
const FOPI: f64 = 4.0 / PI;
const TINY: f64 = 1e-20;
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
}
fn interp1d_linear(x: &[f64], y: &[f64], xnew: &[f64], fill: f64) -> Vec<f64> {
let n = x.len();
xnew.iter()
.map(|&v| {
if v < x[0] || v > x[n - 1] {
return fill;
}
let idx = x.partition_point(|&xi| xi < v).clamp(1, n - 1);
let lo = idx - 1;
let hi = idx;
let slope = (y[hi] - y[lo]) / (x[hi] - x[lo]);
slope * (v - x[lo]) + y[lo]
})
.collect()
}
fn kkmclr_sca(e: &[f64], finp: &[f64]) -> Vec<f64> {
let npts = e.len();
assert!(npts >= 2, "array too short in kkmclr");
assert!(
npts.is_multiple_of(2),
"array has an odd number of elements in kkmclr"
);
let factor = -FOPI * (e[npts - 1] - e[0]) / (npts - 1) as f64;
let nptsk = npts / 2;
let mut fout = vec![0.0f64; npts];
for i in 0..npts {
let ei2 = e[i] * e[i];
let ioff = (i % 2) as isize - 1;
let mut acc = 0.0f64;
for k in 0..nptsk {
let mut j = 2 * k as isize + ioff;
if j < 0 {
j += npts as isize;
}
let j = j as usize;
let mut de2 = e[j] * e[j] - ei2;
if de2.abs() <= TINY {
de2 = TINY;
}
acc += e[j] * finp[j] / de2;
}
fout[i] = acc * factor;
}
fout
}
#[derive(Debug, Clone)]
pub struct DiffKK {
pub f1: Vec<f64>,
pub f2: Vec<f64>,
pub fpp: Vec<f64>,
pub fp: Vec<f64>,
pub grid: Vec<f64>,
pub e0: f64,
}
pub fn diffkk(
energy_in: &[f64],
mu_in: &[f64],
f1: &[f64],
f2: &[f64],
mb: &MbackParams,
) -> DiffKK {
let energy = remove_dups(energy_in, TINY_ENERGY);
let n = energy.len();
assert_eq!(mu_in.len(), n, "energy and mu length mismatch");
assert_eq!(f1.len(), n, "energy and f1 length mismatch");
assert_eq!(f2.len(), n, "energy and f2 length mismatch");
let matched = mback(&energy, mu_in, f2, Some(f1), mb);
let fpp = matched.fpp;
let span = (energy[n - 1] - energy[0]).trunc() as i64;
let npts = (span + span % 2) as usize;
let grid = linspace(energy[0], energy[n - 1], npts);
let diff: Vec<f64> = (0..n).map(|j| f2[j] - fpp[j]).collect();
let fpp_grid = interp1d_linear(&energy, &diff, &grid, 0.0);
let fp_grid = kkmclr_sca(&grid, &fpp_grid);
let fp_back = interp1d_linear(&grid, &fp_grid, &energy, 0.0);
let fp: Vec<f64> = (0..n).map(|j| f1[j] + fp_back[j]).collect();
DiffKK {
f1: f1.to_vec(),
f2: f2.to_vec(),
fpp,
fp,
grid,
e0: matched.e0,
}
}