use crate::Model;
use crate::RMatrixData;
use crate::solve_ham::Solve;
use ndarray::prelude::*;
use ndarray::*;
use ndarray_linalg::*;
use num_complex::Complex;
use rayon::prelude::*;
use std::f64::consts::PI;
pub trait Berry {
fn berry_loop<S>(&self, kvec: &ArrayBase<S, Ix2>, occ: &Vec<usize>) -> Array1<f64>
where
S: Data<Elem = f64>;
fn berry_loop_det<S>(&self, kvec: &ArrayBase<S, Ix2>, occ: &Vec<usize>) -> f64
where
S: Data<Elem = f64>;
fn berry_flux(
&self,
occ: &Vec<usize>,
k_start: &Array1<f64>,
dir_1: &Array1<f64>,
dir_2: &Array1<f64>,
nk1: usize,
nk2: usize,
) -> Array3<f64>;
fn berry_phase(&self, occ: &Vec<usize>, kvec: &Array3<f64>) -> Array2<f64>;
fn wannier_centre(
&self,
occ: &Vec<usize>,
k_start: &Array1<f64>,
dir_1: &Array1<f64>,
dir_2: &Array1<f64>,
nk1: usize,
nk2: usize,
) -> Array2<f64>;
}
impl<const SPIN: bool, const DIM: usize, R: RMatrixData> Berry for Model<SPIN, DIM, R> {
fn berry_loop<S>(&self, kvec: &ArrayBase<S, Ix2>, occ: &Vec<usize>) -> Array1<f64>
where
S: Data<Elem = f64>,
{
let n_k = kvec.nrows();
let diff = &kvec.row(n_k - 1) - &kvec.row(0);
for i in diff.iter() {
if (i - i.round()).abs() > 1e-9 {
panic!(
"wrong, the end of this loop must differ from the beginning by an integer grid vector. yours {}\n",
i.fract()
)
}
}
let use_orb = if SPIN {
let mut orb0 = self.orb.to_owned();
orb0.append(Axis(0), self.orb.view())
.expect("appending spin-doubled orbitals must succeed");
orb0
} else {
self.orb.to_owned()
};
let add_phase = diff.dot(&use_orb.t());
let add_phase = add_phase.mapv(|x| Complex::new(0.0, -2.0 * x * PI).exp());
let (_eval, mut evec) = self.solve_all(kvec);
let first_evec: &ArrayRef<_, Dim<[_; 2]>> = &evec.slice(s![0, .., ..]);
let add_phase = Array2::from_diag(&add_phase);
let end_evec = first_evec.to_owned().dot(&add_phase);
evec.slice_mut(s![n_k - 1, .., ..]).assign(&end_evec);
let evec = evec.select(Axis(1), occ);
let n_occ = occ.len();
let evec_conj = evec.map(|x| x.conj());
let evec = evec.slice(s![1..n_k, .., ..]).to_owned();
let evec_conj = evec_conj.slice(s![0..n_k - 1, .., ..]).to_owned();
let mut ovr = Array3::zeros((n_k - 1, n_occ, n_occ));
Zip::from(ovr.outer_iter_mut())
.and(evec.outer_iter())
.and(evec_conj.outer_iter())
.for_each(|mut O, e, e_j| {
for (i, a) in e_j.outer_iter().enumerate() {
for (j, b) in e.outer_iter().enumerate() {
O[[i, j]] = a.dot(&b);
}
}
});
Zip::from(ovr.outer_iter_mut()).for_each(|mut O| {
let (U, _S, V) = O.svd(true, true).unwrap();
let U = U.unwrap();
let V = V.unwrap();
O.assign(&U.dot(&V));
});
let result: Array2<Complex<f64>> = ovr.outer_iter().fold(
Array2::from_diag(&Array1::<Complex<f64>>::ones(n_occ)),
|acc, x| acc.dot(&x),
);
let result = result.eigvals().unwrap();
let result = result.mapv(|x| -x.arg());
result
}
fn berry_loop_det<S>(&self, kvec: &ArrayBase<S, Ix2>, occ: &Vec<usize>) -> f64
where
S: Data<Elem = f64>,
{
let n_k = kvec.nrows();
let diff = &kvec.row(n_k - 1) - &kvec.row(0);
for i in diff.iter() {
if (i - i.round()).abs() > 1e-9 {
panic!(
"wrong, the end of this loop must differ from the beginning by an integer grid vector. yours {}\n",
i.fract()
)
}
}
let use_orb = if SPIN {
let mut orb0 = self.orb.to_owned();
orb0.append(Axis(0), self.orb.view())
.expect("appending spin-doubled orbitals must succeed");
orb0
} else {
self.orb.to_owned()
};
let add_phase = diff.dot(&use_orb.t());
let add_phase = add_phase.mapv(|x| Complex::new(0.0, -2.0 * x * PI).exp());
let (_eval, mut evec) = self.solve_all(kvec);
let first_evec: &ArrayRef<_, Dim<[_; 2]>> = &evec.slice(s![0, .., ..]);
let add_phase = Array2::from_diag(&add_phase);
let end_evec = first_evec.to_owned().dot(&add_phase);
evec.slice_mut(s![n_k - 1, .., ..]).assign(&end_evec);
let evec = evec.select(Axis(1), occ);
let n_occ = occ.len();
let evec_conj = evec.map(|x| x.conj());
let evec = evec.slice(s![1..n_k, .., ..]).to_owned();
let evec_conj = evec_conj.slice(s![0..n_k - 1, .., ..]).to_owned();
let mut ovr = Array3::zeros((n_k - 1, n_occ, n_occ));
Zip::from(ovr.outer_iter_mut())
.and(evec.outer_iter())
.and(evec_conj.outer_iter())
.for_each(|mut O, e, e_j| {
for (i, a) in e_j.outer_iter().enumerate() {
for (j, b) in e.outer_iter().enumerate() {
O[[i, j]] = a.dot(&b);
}
}
});
let result: Array2<Complex<f64>> = ovr.outer_iter().fold(
Array2::from_diag(&Array1::<Complex<f64>>::ones(n_occ)),
|acc, x| acc.dot(&x),
);
let result = result.det().unwrap();
let result = -result.arg();
result
}
fn berry_flux(
&self,
occ: &Vec<usize>,
k_start: &Array1<f64>,
dir_1: &Array1<f64>,
dir_2: &Array1<f64>,
nk1: usize,
nk2: usize,
) -> Array3<f64> {
assert_eq!(
k_start.len(),
self.dim_r(),
"Wrong!, the k_start's length is {} but dim_r is {}, it's not equal!",
k_start.len(),
self.dim_r()
);
assert_eq!(
dir_1.len(),
self.dim_r(),
"Wrong!, the dir_1's length is {} but dim_r is {}, it's not equal!",
dir_1.len(),
self.dim_r()
);
assert_eq!(
dir_2.len(),
self.dim_r(),
"Wrong!, the dir_2's length is {} but dim_r is {}, it's not equal!",
dir_2.len(),
self.dim_r()
);
assert!(
nk1 >= 1 && nk2 >= 1,
"Wrong!, nk1 and nk2 must be at least 1, but nk1={} and nk2={}",
nk1,
nk2
);
let mut k_loop = Array3::<f64>::zeros((nk1 * nk2, 5, self.dim_r()));
for i in 0..nk1 {
for j in 0..nk2 {
let i0 = (i as f64) / (nk1 as f64);
let j0 = (j as f64) / (nk2 as f64);
let dx = 1.0 / (nk1 as f64);
let dy = 1.0 / (nk2 as f64);
let mut s = k_loop.slice_mut(s![i * nk2 + j, 0, ..]);
s.assign(&(k_start + (i0) * dir_1 + (j0) * dir_2));
let mut s = k_loop.slice_mut(s![i * nk2 + j, 1, ..]);
s.assign(&(k_start + (i0 + dx) * dir_1 + j0 * dir_2));
let mut s = k_loop.slice_mut(s![i * nk2 + j, 2, ..]);
s.assign(&(k_start + (i0 + dx) * dir_1 + (j0 + dy) * dir_2));
let mut s = k_loop.slice_mut(s![i * nk2 + j, 3, ..]);
s.assign(&(k_start + (i0) * dir_1 + (j0 + dy) * dir_2));
let mut s = k_loop.slice_mut(s![i * nk2 + j, 4, ..]);
s.assign(&(k_start + (i0) * dir_1 + (j0) * dir_2));
}
}
let berry_flux: Vec<_> = k_loop
.outer_iter()
.into_par_iter()
.map(|x| self.berry_loop(&x, occ).to_vec())
.collect();
let berry_flux = Array3::from_shape_vec(
(nk1, nk2, occ.len()),
berry_flux.into_iter().flatten().collect(),
)
.unwrap();
berry_flux
}
fn berry_phase(&self, occ: &Vec<usize>, kvec: &Array3<f64>) -> Array2<f64> {
let nk1 = kvec.shape()[0];
let _nk2 = kvec.shape()[1];
let nocc = occ.len();
let mut wcc = Array2::zeros((nk1, nocc));
Zip::from(wcc.outer_iter_mut())
.and(kvec.outer_iter())
.par_for_each(|mut w, k| {
w.assign(&self.berry_loop(&k.to_owned(), occ));
});
for mut row in wcc.outer_iter_mut() {
row.as_slice_mut()
.unwrap()
.sort_by(|a, b| a.partial_cmp(b).unwrap());
}
let wcc = wcc.reversed_axes();
wcc
}
fn wannier_centre(
&self,
occ: &Vec<usize>,
k_start: &Array1<f64>,
dir_1: &Array1<f64>,
dir_2: &Array1<f64>,
nk1: usize,
nk2: usize,
) -> Array2<f64> {
assert_eq!(
k_start.len(),
self.dim_r(),
"Wrong!, the k_start's length is {} but dim_r is {}, it's not equal!",
k_start.len(),
self.dim_r()
);
assert_eq!(
dir_1.len(),
self.dim_r(),
"Wrong!, the dir_1's length is {} but dim_r is {}, it's not equal!",
dir_1.len(),
self.dim_r()
);
assert_eq!(
dir_2.len(),
self.dim_r(),
"Wrong!, the dir_2's length is {} but dim_r is {}, it's not equal!",
dir_2.len(),
self.dim_r()
);
assert!(
nk1 >= 2 && nk2 >= 2,
"Wrong!, nk1 and nk2 must be at least 2 for a finite-difference k-mesh, but nk1={} and nk2={}",
nk1,
nk2
);
let mut kvec = Array3::zeros((nk1, nk2, self.dim_r()));
for i in 0..nk1 {
for j in 0..nk2 {
let mut s = kvec.slice_mut(s![i, j, ..]);
let used_k = k_start
+ dir_1 * (i as f64) / ((nk1 - 1) as f64)
+ dir_2 * (j as f64) / ((nk2 - 1) as f64);
s.assign(&used_k);
}
}
let nocc = occ.len();
let mut wcc = Array2::zeros((nk1, nocc));
Zip::from(wcc.outer_iter_mut())
.and(kvec.outer_iter())
.par_for_each(|mut w, k| {
w.assign(&self.berry_loop(&k.to_owned(), occ));
});
for mut row in wcc.outer_iter_mut() {
row.as_slice_mut()
.unwrap()
.sort_by(|a, b| a.partial_cmp(b).unwrap());
}
let wcc = wcc.reversed_axes();
wcc
}
}