use crate::Model;
use crate::error::{Result, TbError};
use ndarray::prelude::*;
use ndarray::*;
use ndarray_linalg::Inverse;
use num_complex::Complex;
use rayon::prelude::*;
use std::f64::consts::PI;
pub trait Kpath {
fn k_path(
&self,
path: &Array2<f64>,
nk: usize,
) -> Result<(Array2<f64>, Array1<f64>, Array1<f64>)>;
}
impl Kpath for Model {
fn k_path(
&self,
path: &Array2<f64>,
nk: usize,
) -> Result<(Array2<f64>, Array1<f64>, Array1<f64>)> {
if self.dim_r() == 0 {
return Err(TbError::ZeroDimKPathError);
}
let n_node: usize = path.len_of(Axis(0));
if self.dim_r() != path.len_of(Axis(1)) {
return Err(TbError::PathLengthMismatch {
expected: self.dim_r(),
actual: path.len_of(Axis(1)),
});
}
let k_metric = (self.lat.dot(&self.lat.t())).inv().unwrap();
let mut k_node = Array1::<f64>::zeros(n_node);
for n in 1..n_node {
let dk = path.row(n).to_owned() - path.slice(s![n - 1, ..]).to_owned();
let a = k_metric.dot(&dk);
let dklen: f64 = dk.dot(&a).sqrt();
k_node[[n]] = k_node[[n - 1]] + dklen;
}
let mut node_index: Vec<usize> = vec![0];
for n in 1..n_node - 1 {
let frac = k_node[[n]] / k_node[[n_node - 1]];
let a = (frac * ((nk - 1) as f64).round()) as usize;
node_index.push(a)
}
node_index.push(nk - 1);
let mut k_dist = Array1::<f64>::zeros(nk);
let mut k_vec = Array2::<f64>::zeros((nk, self.dim_r()));
k_vec.row_mut(0).assign(&path.row(0));
for n in 1..n_node {
let n_i = node_index[n - 1];
let n_f = node_index[n];
let kd_i = k_node[[n - 1]];
let kd_f = k_node[[n]];
let k_i = path.row(n - 1);
let k_f = path.row(n);
for j in n_i..n_f + 1 {
let frac: f64 = ((j - n_i) as f64) / ((n_f - n_i) as f64);
k_dist[[j]] = kd_i + frac * (kd_f - kd_i);
k_vec
.row_mut(j)
.assign(&((1.0 - frac) * k_i.to_owned() + frac * k_f.to_owned()));
}
}
Ok((k_vec, k_dist, k_node))
}
}