use crate::Gauge;
use crate::Model;
use crate::RMatrixData;
use crate::comm;
use ndarray::prelude::*;
use ndarray::*;
use num_complex::Complex;
use std::f64::consts::PI;
use std::ops::AddAssign;
#[cfg_attr(doc, katexit::katexit)]
pub trait Velocity {
fn gen_v<S: Data<Elem = f64>>(
&self,
kvec: &ArrayBase<S, Ix1>,
gauge: Gauge,
) -> (Array3<Complex<f64>>, Array2<Complex<f64>>);
}
impl<const SPIN: bool, const DIM: usize, R: RMatrixData> Velocity for Model<SPIN, DIM, R> {
#[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 dim = self.dim_r();
let nsta = self.nsta();
let Us: Vec<Complex<f64>> = match DIM {
1 => self
.hamR
.outer_iter()
.map(|r| Complex::new(0.0, 2.0 * PI * r[0] as f64 * kvec[0]).exp())
.collect(),
2 => self
.hamR
.outer_iter()
.map(|r| {
Complex::new(
0.0,
2.0 * PI * (r[0] as f64 * kvec[0] + r[1] as f64 * kvec[1]),
)
.exp()
})
.collect(),
3 => self
.hamR
.outer_iter()
.map(|r| {
Complex::new(
0.0,
2.0 * PI
* (r[0] as f64 * kvec[0]
+ r[1] as f64 * kvec[1]
+ r[2] as f64 * kvec[2]),
)
.exp()
})
.collect(),
_ => unreachable!(),
};
let hamR_f64 = self.hamR.mapv(|x| x as f64);
let R0: Array2<f64> = hamR_f64.dot(&self.lat);
let mut v = Array3::<Complex<f64>>::zeros((dim, nsta, nsta));
let mut hamk = Array2::<Complex<f64>>::zeros((nsta, nsta));
let hamk_slice = hamk.as_slice_mut().unwrap();
for (iR, &u) in Us.iter().enumerate() {
let hm = self.ham.index_axis(Axis(0), iR);
crate::ndarray_lapack::zaxpy(u, hm.as_slice().unwrap(), hamk_slice);
}
let (v, hamk) = match gauge {
Gauge::Atom => {
let orb_sta = if 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>> = match DIM {
1 => orb_sta
.outer_iter()
.map(|tau| Complex::new(0.0, 2.0 * PI * tau[0] * kvec[0]).exp())
.collect(),
2 => orb_sta
.outer_iter()
.map(|tau| {
Complex::new(0.0, 2.0 * PI * (tau[0] * kvec[0] + tau[1] * kvec[1]))
.exp()
})
.collect(),
3 => orb_sta
.outer_iter()
.map(|tau| {
Complex::new(
0.0,
2.0 * PI * (tau[0] * kvec[0] + tau[1] * kvec[1] + tau[2] * kvec[2]),
)
.exp()
})
.collect(),
_ => unreachable!(),
};
let orb_real = orb_sta.dot(&self.lat);
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 B = A.view().permuted_axes([0, 2, 1]);
let UU = (&B - &A).mapv(|x| Complex::<f64>::new(0.0, x));
for d in 0..dim {
let mut vv = Array2::<Complex<f64>>::zeros((nsta, nsta));
let R0_d = R0.column(d);
for (iR, &u) in Us.iter().enumerate() {
let hm = self.ham.index_axis(Axis(0), iR);
let alpha = u * R0_d[iR] * Complex::i();
crate::ndarray_lapack::zaxpy(
alpha,
hm.as_slice().unwrap(),
vv.as_slice_mut().unwrap(),
);
}
azip!((v in &mut vv, &h in &hamk, &u in &UU.slice(s![d, .., ..])) *v += h * u);
for m in 0..nsta {
let mut row = vv.slice_mut(s![m, ..]);
let conj_pm = orb_phase[m].conj();
Zip::from(&mut row)
.and(orb_phase.as_slice())
.for_each(|h, &pn| *h *= conj_pm * pn);
}
v.slice_mut(s![d, .., ..]).assign(&vv);
}
for m in 0..nsta {
let mut row = hamk.slice_mut(s![m, ..]);
let conj_pm = orb_phase[m].conj();
Zip::from(&mut row)
.and(orb_phase.as_slice())
.for_each(|h, &pn| *h *= conj_pm * pn);
}
if <R as RMatrixData>::HAS_RMATRIX {
let n_rmat = self.rmatrix.as_array4().len_of(Axis(0));
let mut rk = Array3::<Complex<f64>>::zeros((dim, nsta, nsta));
for (iR, &u) in Us[..n_rmat].iter().enumerate() {
let rm = self.rmatrix.as_array4().index_axis(Axis(0), iR);
crate::ndarray_lapack::zaxpy(
u,
rm.as_slice().unwrap(),
rk.as_slice_mut().unwrap(),
);
}
for i in 0..dim {
let mut r0 = rk.slice_mut(s![i, .., ..]);
for m in 0..nsta {
let mut row = r0.slice_mut(s![m, ..]);
let conj_pm = orb_phase[m].conj();
Zip::from(&mut row)
.and(orb_phase.as_slice())
.for_each(|h, &pn| *h *= conj_pm * pn);
}
r0.diag_mut().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));
let R0_d = R0.column(d);
for (iR, &u) in Us.iter().enumerate() {
let hm = self.ham.index_axis(Axis(0), iR);
let alpha = u * R0_d[iR] * Complex::i();
crate::ndarray_lapack::zaxpy(
alpha,
hm.as_slice().unwrap(),
vv.as_slice_mut().unwrap(),
);
}
v.slice_mut(s![d, .., ..]).assign(&vv);
}
if <R as RMatrixData>::HAS_RMATRIX {
let n_rmat = self.rmatrix.as_array4().len_of(Axis(0));
let mut rk = Array3::<Complex<f64>>::zeros((dim, nsta, nsta));
for (iR, &u) in Us[..n_rmat].iter().enumerate() {
let rm = self.rmatrix.as_array4().index_axis(Axis(0), iR);
crate::ndarray_lapack::zaxpy(
u,
rm.as_slice().unwrap(),
rk.as_slice_mut().unwrap(),
);
}
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)
}
}
impl<const SPIN: bool, const DIM: usize, R: RMatrixData> Model<SPIN, DIM, R> {
#[allow(non_snake_case)]
pub fn gen_v_projected<S: Data<Elem = f64>>(
&self,
kvec: &ArrayBase<S, Ix1>,
gauge: Gauge,
directions: &Array2<f64>,
) -> (Array3<Complex<f64>>, Array2<Complex<f64>>) {
assert_eq!(
kvec.len(),
DIM,
"kvec length {} != dim_r={}",
kvec.len(),
DIM
);
assert_eq!(
directions.len_of(Axis(1)),
DIM,
"directions has {} columns, expected dim_r={}",
directions.len_of(Axis(1)),
DIM
);
let n_proj = directions.len_of(Axis(0));
let nsta = self.nsta();
let Us: Vec<Complex<f64>> = match DIM {
1 => self
.hamR
.outer_iter()
.map(|r| Complex::new(0.0, 2.0 * PI * r[0] as f64 * kvec[0]).exp())
.collect(),
2 => self
.hamR
.outer_iter()
.map(|r| {
Complex::new(
0.0,
2.0 * PI * (r[0] as f64 * kvec[0] + r[1] as f64 * kvec[1]),
)
.exp()
})
.collect(),
3 => self
.hamR
.outer_iter()
.map(|r| {
Complex::new(
0.0,
2.0 * PI
* (r[0] as f64 * kvec[0]
+ r[1] as f64 * kvec[1]
+ r[2] as f64 * kvec[2]),
)
.exp()
})
.collect(),
_ => unreachable!(),
};
let hamR_f64 = self.hamR.mapv(|x| x as f64);
let R0: Array2<f64> = hamR_f64.dot(&self.lat);
let mut v_proj = Array3::<Complex<f64>>::zeros((n_proj, nsta, nsta));
let mut hamk = Array2::<Complex<f64>>::zeros((nsta, nsta));
let hamk_slice = hamk.as_slice_mut().unwrap();
for (iR, &u) in Us.iter().enumerate() {
let hm = self.ham.index_axis(Axis(0), iR);
crate::ndarray_lapack::zaxpy(u, hm.as_slice().unwrap(), hamk_slice);
}
match gauge {
Gauge::Atom => {
let orb_sta = if 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>> = match DIM {
1 => orb_sta
.outer_iter()
.map(|tau| Complex::new(0.0, 2.0 * PI * tau[0] * kvec[0]).exp())
.collect(),
2 => orb_sta
.outer_iter()
.map(|tau| {
Complex::new(0.0, 2.0 * PI * (tau[0] * kvec[0] + tau[1] * kvec[1]))
.exp()
})
.collect(),
3 => orb_sta
.outer_iter()
.map(|tau| {
Complex::new(
0.0,
2.0 * PI * (tau[0] * kvec[0] + tau[1] * kvec[1] + tau[2] * kvec[2]),
)
.exp()
})
.collect(),
_ => unreachable!(),
};
let orb_real = orb_sta.dot(&self.lat);
let tau_proj = directions.dot(&orb_real.t());
for p in 0..n_proj {
let dir = directions.row(p);
let mut vv = Array2::<Complex<f64>>::zeros((nsta, nsta));
let vv_slice = vv.as_slice_mut().unwrap();
for (iR, &u) in Us.iter().enumerate() {
let r_dot_w: f64 = match DIM {
1 => dir[0] * R0[[iR, 0]],
2 => dir[0] * R0[[iR, 0]] + dir[1] * R0[[iR, 1]],
3 => dir[0] * R0[[iR, 0]] + dir[1] * R0[[iR, 1]] + dir[2] * R0[[iR, 2]],
_ => unreachable!(),
};
if r_dot_w != 0.0 {
let alpha = u * Complex::i() * r_dot_w;
let hm = self.ham.index_axis(Axis(0), iR);
crate::ndarray_lapack::zaxpy(alpha, hm.as_slice().unwrap(), vv_slice);
}
}
for m in 0..nsta {
let conj_pm = orb_phase[m].conj();
for n in 0..nsta {
let diff = tau_proj[[p, n]] - tau_proj[[p, m]];
vv[[m, n]] = (vv[[m, n]] + Complex::i() * diff * hamk[[m, n]])
* conj_pm
* orb_phase[n];
}
}
v_proj.slice_mut(s![p, .., ..]).assign(&vv);
}
for m in 0..nsta {
let conj_pm = orb_phase[m].conj();
let mut row = hamk.slice_mut(s![m, ..]);
Zip::from(&mut row)
.and(orb_phase.as_slice())
.for_each(|h, &pn| *h *= conj_pm * pn);
}
if <R as RMatrixData>::HAS_RMATRIX {
let n_rmat = self.rmatrix.as_array4().len_of(Axis(0));
let mut rk = Array3::<Complex<f64>>::zeros((DIM, nsta, nsta));
for (iR, &u) in Us[..n_rmat].iter().enumerate() {
let rm = self.rmatrix.as_array4().index_axis(Axis(0), iR);
for d in 0..DIM {
crate::ndarray_lapack::zaxpy(
u,
rm.slice(s![d, .., ..]).as_slice().unwrap(),
rk.slice_mut(s![d, .., ..]).as_slice_mut().unwrap(),
);
}
}
for p in 0..n_proj {
let dir = directions.row(p);
let mut rk_p = Array2::<Complex<f64>>::zeros((nsta, nsta));
let rk_p_slice = rk_p.as_slice_mut().unwrap();
for d in 0..DIM {
let w = dir[d];
if w != 0.0 {
crate::ndarray_lapack::zaxpy(
Complex::new(w, 0.0),
rk.slice(s![d, .., ..]).as_slice().unwrap(),
rk_p_slice,
);
}
}
for m in 0..nsta {
let conj_pm = orb_phase[m].conj();
let mut row = rk_p.slice_mut(s![m, ..]);
Zip::from(&mut row)
.and(orb_phase.as_slice())
.for_each(|h, &pn| *h *= conj_pm * pn);
}
rk_p.diag_mut().assign(&Array1::zeros(nsta));
let a_comm = comm(&hamk, &rk_p) * Complex::i();
v_proj.slice_mut(s![p, .., ..]).add_assign(&a_comm);
}
}
}
Gauge::Lattice => {
for p in 0..n_proj {
let dir = directions.row(p);
let mut vv = Array2::<Complex<f64>>::zeros((nsta, nsta));
let vv_slice = vv.as_slice_mut().unwrap();
for (iR, &u) in Us.iter().enumerate() {
let r_dot_w: f64 = match DIM {
1 => dir[0] * R0[[iR, 0]],
2 => dir[0] * R0[[iR, 0]] + dir[1] * R0[[iR, 1]],
3 => dir[0] * R0[[iR, 0]] + dir[1] * R0[[iR, 1]] + dir[2] * R0[[iR, 2]],
_ => unreachable!(),
};
if r_dot_w != 0.0 {
let alpha = u * Complex::i() * r_dot_w;
let hm = self.ham.index_axis(Axis(0), iR);
crate::ndarray_lapack::zaxpy(alpha, hm.as_slice().unwrap(), vv_slice);
}
}
v_proj.slice_mut(s![p, .., ..]).assign(&vv);
}
if <R as RMatrixData>::HAS_RMATRIX {
let n_rmat = self.rmatrix.as_array4().len_of(Axis(0));
let mut rk = Array3::<Complex<f64>>::zeros((DIM, nsta, nsta));
for (iR, &u) in Us[..n_rmat].iter().enumerate() {
let rm = self.rmatrix.as_array4().index_axis(Axis(0), iR);
for d in 0..DIM {
crate::ndarray_lapack::zaxpy(
u,
rm.slice(s![d, .., ..]).as_slice().unwrap(),
rk.slice_mut(s![d, .., ..]).as_slice_mut().unwrap(),
);
}
}
for p in 0..n_proj {
let dir = directions.row(p);
let mut rk_p = Array2::<Complex<f64>>::zeros((nsta, nsta));
let rk_p_slice = rk_p.as_slice_mut().unwrap();
for d in 0..DIM {
let w = dir[d];
if w != 0.0 {
crate::ndarray_lapack::zaxpy(
Complex::new(w, 0.0),
rk.slice(s![d, .., ..]).as_slice().unwrap(),
rk_p_slice,
);
}
}
let a_comm = comm(&hamk, &rk_p) * Complex::i();
v_proj.slice_mut(s![p, .., ..]).add_assign(&a_comm);
}
}
}
}
(v_proj, hamk)
}
}