use crate::Gauge;
use crate::Model;
use crate::comm;
use crate::solve_ham::*;
use ndarray::prelude::*;
use ndarray::*;
use ndarray_linalg::conjugate;
use ndarray_linalg::*;
use num_complex::Complex;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use std::f64::consts::PI;
use std::ops::AddAssign;
#[inline]
fn apply_gauge_transform(mat: &mut [Complex<f64>], phase: &[Complex<f64>]) {
let nsta = phase.len();
for m in 0..nsta {
let conj_pm = phase[m].conj();
let row = m * nsta;
for n in 0..nsta {
mat[row + n] *= conj_pm * phase[n];
}
}
}
pub trait Velocity {
fn gen_v<S: Data<Elem = f64>>(
&self,
kvec: &ArrayBase<S, Ix1>,
gauge: Gauge,
) -> (Array3<Complex<f64>>, Array2<Complex<f64>>);
}
impl Velocity for Model {
#[allow(non_snake_case)]
#[inline(always)]
fn gen_v<S: Data<Elem = f64>>(
&self,
kvec: &ArrayBase<S, Ix1>,
gauge: Gauge,
) -> (Array3<Complex<f64>>, Array2<Complex<f64>>) {
assert_eq!(
kvec.len(),
self.dim_r(),
"Wrong, the k-vector's length {} must equal to the dimension of model {}.",
kvec.len(),
self.dim_r()
);
let n_r = self.hamR.nrows();
let dim = self.dim_r();
let nsta = self.nsta();
let Us: Vec<Complex<f64>> = (0..n_r)
.map(|i| {
let mut phase = 0.0f64;
for d in 0..dim {
phase += self.hamR[[i, d]] as f64 * kvec[d];
}
Complex::new(0.0, 2.0 * PI * phase).exp()
})
.collect();
let mut v = Array3::<Complex<f64>>::zeros((dim, nsta, nsta));
let R0 = &self.hamR.mapv(|x| Complex::<f64>::new(x as f64, 0.0));
let R0 = R0.dot(&self.lat.mapv(|x| Complex::new(x, 0.0)));
let mut hamk = Array2::<Complex<f64>>::zeros((nsta, nsta));
for i in 0..n_r {
let u = Us[i];
let hm = self.ham.slice(s![i, .., ..]);
Zip::from(&mut hamk).and(&hm).for_each(|a, &b| *a += b * u);
}
let (v, hamk) = match gauge {
Gauge::Atom => {
let orb_sta = if self.spin {
let orb0 = concatenate(Axis(0), &[self.orb.view(), self.orb.view()]).unwrap();
orb0
} else {
self.orb.to_owned()
};
let orb_phase: Vec<Complex<f64>> = orb_sta
.outer_iter()
.map(|tau| {
let mut phase = 0.0f64;
for d in 0..dim {
phase += tau[d] * kvec[d];
}
Complex::new(0.0, 2.0 * PI * phase).exp()
})
.collect();
let orb_real = orb_sta.dot(&self.lat);
let mut UU = Array3::<f64>::zeros((self.dim_r(), self.nsta(), self.nsta()));
let A = orb_real.view().insert_axis(Axis(2));
let A = A
.broadcast((self.nsta(), self.dim_r(), self.nsta()))
.unwrap()
.permuted_axes([1, 0, 2]);
let mut B = A.view().permuted_axes([0, 2, 1]);
let UU = &B - &A;
let UU = UU.mapv(|x| Complex::<f64>::new(0.0, x)); for d in 0..dim {
let mut vv = Array2::<Complex<f64>>::zeros((nsta, nsta));
for i_r in 0..n_r {
let factor = Us[i_r] * R0[[i_r, d]] * Complex::i();
let hm = self.ham.slice(s![i_r, .., ..]);
Zip::from(&mut vv).and(&hm).for_each(|a, &b| *a += b * factor);
}
let mut vv = &vv + &hamk * &UU.slice(s![d, .., ..]);
apply_gauge_transform(vv.as_slice_mut().unwrap(), &orb_phase);
v.slice_mut(s![d, .., ..]).assign(&vv);
}
apply_gauge_transform(hamk.as_slice_mut().unwrap(), &orb_phase);
if self.rmatrix.len_of(Axis(0)) != 1 {
let n_rmat = self.rmatrix.len_of(Axis(0));
let mut rk = Array3::<Complex<f64>>::zeros((dim, nsta, nsta));
for i_r in 0..n_rmat {
let u = Us[i_r];
let rm = self.rmatrix.slice(s![i_r, .., .., ..]);
Zip::from(&mut rk).and(&rm).for_each(|a, &b| *a += b * u);
}
for i in 0..dim {
let mut r0 = rk.slice_mut(s![i, .., ..]);
let phase = orb_phase.as_slice();
let r0_slice = r0.as_slice_mut().unwrap();
for m in 0..nsta {
let conj_pm = phase[m].conj();
let row = m * nsta;
for n in 0..nsta {
r0_slice[row + n] *= conj_pm * phase[n];
}
}
let mut dig = r0.diag_mut();
dig.assign(&Array1::zeros(nsta));
let a_comm = comm(&hamk, &r0) * Complex::i();
v.slice_mut(s![i, .., ..]).add_assign(&a_comm);
}
}
(v, hamk)
}
Gauge::Lattice => {
for d in 0..dim {
let mut vv = Array2::<Complex<f64>>::zeros((nsta, nsta));
for i_r in 0..n_r {
let factor = Us[i_r] * R0[[i_r, d]] * Complex::i();
let hm = self.ham.slice(s![i_r, .., ..]);
Zip::from(&mut vv).and(&hm).for_each(|a, &b| *a += b * factor);
}
v.slice_mut(s![d, .., ..]).assign(&vv);
}
if self.rmatrix.len_of(Axis(0)) != 1 {
let n_rmat = self.rmatrix.len_of(Axis(0));
let mut rk = Array3::<Complex<f64>>::zeros((dim, nsta, nsta));
for i_r in 0..n_rmat {
let u = Us[i_r];
let rm = self.rmatrix.slice(s![i_r, .., .., ..]);
Zip::from(&mut rk).and(&rm).for_each(|a, &b| *a += b * u);
}
for i in 0..dim {
let r0 = rk.slice(s![i, .., ..]);
let a_comm = comm(&hamk, &r0) * Complex::i();
v.slice_mut(s![i, .., ..]).add_assign(&a_comm);
}
}
(v, hamk)
}
};
(v, hamk)
}
}