pub mod conductivity{
use crate::{Model,gen_kmesh,gen_krange,comm,anti_comm};
use num_complex::Complex;
use ndarray::linalg::kron;
use ndarray::*;
use ndarray::prelude::*;
use ndarray_linalg::*;
use std::f64::consts::PI;
use ndarray_linalg::conjugate;
use rayon::prelude::*;
use std::ops::AddAssign;
use std::ops::MulAssign;
#[inline(always)]
pub fn adapted_integrate_quick(f0:&dyn Fn(&Array1::<f64>)->f64,k_range:&Array2::<f64>,re_err:f64,ab_err:f64)->f64{
let dim=k_range.len_of(Axis(0));
if dim==1{
let mut use_range=vec![(k_range.clone(),re_err,ab_err)];
let mut result=0.0;
while let Some((k_range,re_err,ab_err))=use_range.pop() {
let kvec_l:Array1::<f64>=arr1(&[k_range[[0,0]]]);
let kvec_r:Array1::<f64>=arr1(&[k_range[[0,1]]]);
let kvec_m:Array1::<f64>=arr1(&[(k_range[[0,1]]+k_range[[0,0]])/2.0]);
let dk:f64=k_range[[0,1]]-k_range[[0,0]];
let y_l:f64=f0(&kvec_l);
let y_r:f64=f0(&kvec_r);
let y_m:f64=f0(&kvec_m);
let all:f64=(y_l+y_r)*dk/2.0;
let all_1=(y_l+y_m)*dk/4.0;
let all_2=(y_r+y_m)*dk/4.0;
let err=all_1+all_2-all;
let abs_err= if ab_err>all*re_err{ab_err} else {all*re_err};
if err< abs_err{
result+=all_1+all_2;
}else{
let k_range_l=arr2(&[[kvec_l[[0]],kvec_m[[0]]]]);
let k_range_r=arr2(&[[kvec_m[[0]],kvec_r[[0]]]]);
use_range.push((k_range_l,re_err,ab_err/2.0));
use_range.push((k_range_r,re_err,ab_err/2.0));
}
}
return result;
}else if dim==2{
let area_1:Array2::<f64>=arr2(&[[k_range.row(0)[0],k_range.row(1)[0]],[k_range.row(0)[1],k_range.row(1)[0]],[k_range.row(0)[0],k_range.row(1)[1]]]);let area_2:Array2::<f64>=arr2(&[[k_range.row(0)[1],k_range.row(1)[1]],[k_range.row(0)[1],k_range.row(1)[0]],[k_range.row(0)[0],k_range.row(1)[1]]]);#[inline(always)]
fn adapt_integrate_triangle(f0:&dyn Fn(&Array1::<f64>)->f64,kvec:&Array2::<f64>,re_err:f64,ab_err:f64,s1:f64,s2:f64,s3:f64)->f64{
let mut result=0.0;
let mut use_kvec=vec![(kvec.clone(),re_err,ab_err,s1,s2,s3)];
while let Some((kvec,re_err,ab_err,s1,s2,s3))=use_kvec.pop() {
let S:f64=((kvec[[1,0]]*kvec[[2,1]]-kvec[[2,0]]*kvec[[1,1]])-(kvec[[0,0]]*kvec[[2,1]]-kvec[[0,1]]*kvec[[2,0]])+(kvec[[0,0]]*kvec[[1,1]]-kvec[[1,0]]*kvec[[0,1]])).abs();
let kvec_m=kvec.mean_axis(Axis(0)).unwrap();
let sm:f64=f0(&kvec_m.to_owned());
let mut kvec_1=Array2::<f64>::zeros((0,2));
kvec_1.push_row(kvec.row(0));
kvec_1.push_row(kvec.row(1));
kvec_1.push_row(kvec_m.view());
let mut kvec_2=Array2::<f64>::zeros((0,2));
kvec_2.push_row(kvec.row(0));
kvec_2.push_row(kvec_m.view());
kvec_2.push_row(kvec.row(2));
let mut kvec_3=Array2::<f64>::zeros((0,2));
kvec_3.push_row(kvec_m.view());
kvec_3.push_row(kvec.row(1));
kvec_3.push_row(kvec.row(2));
let all:f64=(s1+s2+s3)*S/6.0;
let all_new:f64=all/3.0*2.0+sm*S/6.0;
let abs_err:f64= if ab_err>all*re_err{ab_err} else {all*re_err};
if (all_new-all).abs() > abs_err && S>1e-8{
use_kvec.push((kvec_1,re_err,ab_err/3.0,s1,s2,sm));
use_kvec.push((kvec_2,re_err,ab_err/3.0,s1,sm,s3));
use_kvec.push((kvec_3,re_err,ab_err/3.0,sm,s2,s3));
}else{
result+=all_new;
}
}
result
}
let s1=f0(&arr1(&[k_range.row(0)[0],k_range.row(1)[0]]));
let s2=f0(&arr1(&[k_range.row(0)[1],k_range.row(1)[0]]));
let s3=f0(&arr1(&[k_range.row(0)[0],k_range.row(1)[1]]));
let s4=f0(&arr1(&[k_range.row(0)[1],k_range.row(1)[1]]));
let all_1=adapt_integrate_triangle(f0,&area_1,re_err,ab_err/2.0,s1,s2,s3);
let all_2=adapt_integrate_triangle(f0,&area_2,re_err,ab_err/2.0,s4,s2,s3);
return all_1+all_2;
}else if dim==3{
#[inline(always)]
fn adapt_integrate_tetrahedron(f0:&dyn Fn(&Array1::<f64>)->f64,kvec:&Array2::<f64>,re_err:f64,ab_err:f64,s1:f64,s2:f64,s3:f64,s4:f64,S:f64)->f64{
let mut result=0.0;
let mut use_kvec=vec![(kvec.clone(),re_err,ab_err,s1,s2,s3,s4,S)];
while let Some((kvec,re_err,ab_err,s1,s2,s3,s4,S))=use_kvec.pop() {
let kvec_m=kvec.mean_axis(Axis(0)).unwrap();
let sm=f0(&kvec_m.to_owned());
let mut kvec_1=Array2::<f64>::zeros((0,3));
kvec_1.push_row(kvec.row(0));
kvec_1.push_row(kvec.row(1));
kvec_1.push_row(kvec.row(2));
kvec_1.push_row(kvec_m.view());
let mut kvec_2=Array2::<f64>::zeros((0,3));
kvec_2.push_row(kvec.row(0));
kvec_2.push_row(kvec.row(1));
kvec_2.push_row(kvec_m.view());
kvec_2.push_row(kvec.row(3));
let mut kvec_3=Array2::<f64>::zeros((0,3));
kvec_3.push_row(kvec.row(0));
kvec_3.push_row(kvec_m.view());
kvec_3.push_row(kvec.row(2));
kvec_3.push_row(kvec.row(3));
let mut kvec_4=Array2::<f64>::zeros((0,3));
kvec_4.push_row(kvec_m.view());
kvec_4.push_row(kvec.row(1));
kvec_4.push_row(kvec.row(2));
kvec_4.push_row(kvec.row(3));
let all=(s1+s2+s3+s4)*S/24.0;
let all_new=all/4.0*3.0+sm*S/24.0;
let S1=S/4.0;
let abs_err= if ab_err>all*re_err{ab_err} else {all*re_err};
if (all_new-all).abs()> abs_err && S > 1e-9{
use_kvec.push((kvec_1,re_err,ab_err*0.25,s1,s2,s3,sm,S1));
use_kvec.push((kvec_2,re_err,ab_err*0.25,s1,s2,sm,s4,S1));
use_kvec.push((kvec_3,re_err,ab_err*0.25,s1,sm,s3,s4,S1));
use_kvec.push((kvec_4,re_err,ab_err*0.25,sm,s2,s3,s4,S1));
}else{
result+=all_new;
}
}
result
}
let area_1:Array2::<f64>=arr2(&[[k_range.row(0)[0],k_range.row(1)[0],k_range.row(2)[0]],
[k_range.row(0)[1],k_range.row(1)[0],k_range.row(2)[0]],
[k_range.row(0)[0],k_range.row(1)[1],k_range.row(2)[0]],
[k_range.row(0)[0],k_range.row(1)[0],k_range.row(2)[1]]]);let area_2:Array2::<f64>=arr2(&[[k_range.row(0)[1],k_range.row(1)[1],k_range.row(2)[0]],
[k_range.row(0)[1],k_range.row(1)[0],k_range.row(2)[0]],
[k_range.row(0)[0],k_range.row(1)[1],k_range.row(2)[0]],
[k_range.row(0)[1],k_range.row(1)[1],k_range.row(2)[1]]]);let area_3:Array2::<f64>=arr2(&[[k_range.row(0)[1],k_range.row(1)[0],k_range.row(2)[1]],
[k_range.row(0)[1],k_range.row(1)[0],k_range.row(2)[0]],
[k_range.row(0)[0],k_range.row(1)[0],k_range.row(2)[1]],
[k_range.row(0)[1],k_range.row(1)[1],k_range.row(2)[1]]]);let area_4:Array2::<f64>=arr2(&[[k_range.row(0)[0],k_range.row(1)[1],k_range.row(2)[1]],
[k_range.row(0)[0],k_range.row(1)[0],k_range.row(2)[1]],
[k_range.row(0)[0],k_range.row(1)[1],k_range.row(2)[0]],
[k_range.row(0)[1],k_range.row(1)[1],k_range.row(2)[1]]]);let area_5:Array2::<f64>=arr2(&[[k_range.row(0)[0],k_range.row(1)[0],k_range.row(2)[1]],
[k_range.row(0)[1],k_range.row(1)[1],k_range.row(2)[1]],
[k_range.row(0)[0],k_range.row(1)[1],k_range.row(2)[0]],
[k_range.row(0)[1],k_range.row(1)[0],k_range.row(2)[0]]]);let s1=f0(&area_1.row(0).to_owned());
let s2=f0(&area_1.row(1).to_owned());
let s3=f0(&area_2.row(0).to_owned());
let s4=f0(&area_1.row(2).to_owned());
let s5=f0(&area_1.row(3).to_owned());
let s6=f0(&area_3.row(0).to_owned());
let s7=f0(&area_2.row(3).to_owned());
let s8=f0(&area_4.row(0).to_owned());
let V=(k_range[[0,1]]-k_range[[0,0]])*(k_range[[1,1]]-k_range[[1,0]])*(k_range[[2,1]]-k_range[[2,0]]);
let all_1=adapt_integrate_tetrahedron(f0,&area_1,re_err,ab_err/6.0,s1,s2,s4,s5,V/6.0);
let all_2=adapt_integrate_tetrahedron(f0,&area_2,re_err,ab_err/6.0,s3,s2,s4,s7,V/6.0);
let all_3=adapt_integrate_tetrahedron(f0,&area_3,re_err,ab_err/6.0,s6,s2,s5,s7,V/6.0);
let all_4=adapt_integrate_tetrahedron(f0,&area_4,re_err,ab_err/6.0,s8,s5,s4,s7,V/6.0);
let all_5=adapt_integrate_tetrahedron(f0,&area_5,re_err,ab_err/3.0,s5,s7,s4,s2,V/3.0);
return all_1+all_2+all_3+all_4+all_5
}else{
panic!("wrong, the row_dim if k_range must be 1,2 or 3, but you's give {}",dim);
}
}
#[allow(non_snake_case)]
impl Model{
#[allow(non_snake_case)]
#[inline(always)]
pub fn berry_curvature_n_onek<S:Data<Elem=f64>>(&self,k_vec:&ArrayBase<S,Ix1>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,og:f64,spin:usize,eta:f64)->(Array1::<f64>,Array1::<f64>){
let li:Complex<f64>=1.0*Complex::i();
let (band,evec)=self.solve_onek(&k_vec);
let mut v:Array3::<Complex<f64>>=self.gen_v(k_vec);
let mut J:Array3::<Complex<f64>>=v.clone();
let (J,v)=if self.spin {
let mut X:Array2::<Complex<f64>>=Array2::eye(self.nsta);
let pauli:Array2::<Complex<f64>>= match spin{
0=> arr2(&[[1.0+0.0*li,0.0+0.0*li],[0.0+0.0*li,1.0+0.0*li]]),
1=> arr2(&[[0.0+0.0*li,1.0+0.0*li],[1.0+0.0*li,0.0+0.0*li]])/2.0,
2=> arr2(&[[0.0+0.0*li,0.0-1.0*li],[0.0+1.0*li,0.0+0.0*li]])/2.0,
3=> arr2(&[[1.0+0.0*li,0.0+0.0*li],[0.0+0.0*li,-1.0+0.0*li]])/2.0,
_=>panic!("Wrong, spin should be 0, 1, 2, 3, but you input {}",spin),
};
X=kron(&pauli,&Array2::eye(self.norb));
let J=J.outer_iter().zip(dir_1.iter()).fold(Array2::zeros((self.nsta,self.nsta)),|acc,(x,d)| {acc+&anti_comm(&X,&x)*(*d*0.5+0.0*li)});
let v=v.outer_iter().zip(dir_2.iter()).fold(Array2::zeros((self.nsta,self.nsta)),|acc,(x,d)| {acc+&x*(*d+0.0*li)});
(J,v)
}else{
if spin !=0{
println!("Warning, the model haven't got spin, so the spin input will be ignord");
}
let J=J.outer_iter().zip(dir_1.iter()).fold(Array2::zeros((self.nsta,self.nsta)),|acc,(x,d)| {acc+&x*(*d+0.0*li)});
let v=v.outer_iter().zip(dir_2.iter()).fold(Array2::zeros((self.nsta,self.nsta)),|acc,(x,d)| {acc+&x*(*d+0.0*li)});
(J,v)
};
let evec_conj:Array2::<Complex<f64>>=evec.mapv(|x| x.conj());
let evec=evec.t();
let A1=J.dot(&evec);
let A1=&evec_conj.dot(&A1);
let A2=v.dot(&evec);
let A2=&evec_conj.dot(&A2).reversed_axes();
let mut U0=Array2::<Complex<f64>>::zeros((self.nsta,self.nsta));
let a0=(og+li*eta).powi(2);
for i in 0..self.nsta{
for j in 0..self.nsta{
U0[[i,j]]=((band[[i]]-band[[j]]).powi(2)-a0).finv();
}
U0[[i,i]]=Complex::new(0.0,0.0);
}
let mut omega_n=Array1::<f64>::zeros(self.nsta);
let A1=A1*U0;
let A1=A1.outer_iter();
let A2=A2.outer_iter();
omega_n.iter_mut().zip(A1.zip(A2)).for_each(|(mut x,(a,b))| {*x=-2.0*(a.dot(&b)).im;});
(omega_n,band)
}
#[allow(non_snake_case)]
pub fn berry_curvature_onek<S:Data<Elem=f64>>(&self,k_vec:&ArrayBase<S,Ix1>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,mu:f64,T:f64,og:f64,spin:usize,eta:f64)->f64{
let (omega_n,band)=self.berry_curvature_n_onek(&k_vec,&dir_1,&dir_2,og,spin,eta);
let mut omega:f64=0.0;
if T==0.0{
omega=omega_n.iter().zip(band.iter()).fold(0.0,|acc,(x,y)| {if *y> mu {acc} else {acc+*x}});
}else{
let beta=(T*8.617e-5).recip();
let fermi_dirac=band.mapv(|x| ((beta*(x-mu)).exp()+1.0).recip());
omega=(omega_n*fermi_dirac).sum();
}
omega
}
#[allow(non_snake_case)]
pub fn berry_curvature<S:Data<Elem=f64>>(&self,k_vec:&ArrayBase<S,Ix2>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,mu:f64,T:f64,og:f64,spin:usize,eta:f64)->Array1::<f64>{
if dir_1.len() !=self.dim_r || dir_2.len() != self.dim_r{
panic!("Wrong, the dir_1 or dir_2 you input has wrong length, it must equal to dim_r={}, but you input {},{}",self.dim_r,dir_1.len(),dir_2.len())
}
let nk=k_vec.len_of(Axis(0));
let omega:Vec<f64>=k_vec.axis_iter(Axis(0)).into_par_iter().map(|x| {
let omega_one=self.berry_curvature_onek(&x.to_owned(),&dir_1,&dir_2,mu,T,og,spin,eta);
omega_one
}).collect();
let omega=arr1(&omega);
omega
}
#[allow(non_snake_case)]
pub fn Hall_conductivity(&self,k_mesh:&Array1::<usize>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,mu:f64,T:f64,og:f64,spin:usize,eta:f64)->f64{
let kvec:Array2::<f64>=gen_kmesh(&k_mesh);
let nk:usize=kvec.len_of(Axis(0));
let omega=self.berry_curvature(&kvec,&dir_1,&dir_2,mu,T,og,spin,eta);
let conductivity:f64=omega.sum()/(nk as f64)*(2.0*PI).powi(self.dim_r as i32)/self.lat.det().unwrap();
conductivity
}
#[allow(non_snake_case)]
pub fn Hall_conductivity_adapted(&self,k_mesh:&Array1::<usize>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,mu:f64,T:f64,og:f64,spin:usize,eta:f64,re_err:f64,ab_err:f64)->f64{
let mut k_range=gen_krange(k_mesh);let n_range=k_range.len_of(Axis(0));
let ab_err=ab_err/(n_range as f64);
let use_fn=|k0:&Array1::<f64>| self.berry_curvature_onek(k0,&dir_1,&dir_2,mu,T,og,spin,eta);
let inte=|k_range| adapted_integrate_quick(&use_fn,&k_range,re_err,ab_err);
let omega:Vec<f64>=k_range.axis_iter(Axis(0)).into_par_iter().map(|x| { inte(x.to_owned())}).collect();
let omega:Array1::<f64>=arr1(&omega);
let conductivity:f64=omega.sum()*(2.0*PI).powi(self.dim_r as i32)/self.lat.det().unwrap();
conductivity
}
pub fn Hall_conductivity_mu(&self,k_mesh:&Array1::<usize>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,mu:&Array1::<f64>,T:f64,og:f64,spin:usize,eta:f64)->Array1::<f64>{
let kvec:Array2::<f64>=gen_kmesh(&k_mesh);
let nk:usize=kvec.len_of(Axis(0));
let (omega_n,band):(Vec<_>,Vec<_>)=kvec.axis_iter(Axis(0)).into_par_iter().map(|x| {
let (omega_n,band)=self.berry_curvature_n_onek(&x.to_owned(),&dir_1,&dir_2,og,spin,eta);
(omega_n,band)
}).collect();
let omega_n=Array2::<f64>::from_shape_vec((nk, self.nsta),omega_n.into_iter().flatten().collect()).unwrap();
let band=Array2::<f64>::from_shape_vec((nk, self.nsta),band.into_iter().flatten().collect()).unwrap();
let n_mu:usize=mu.len();
let conductivity=if T==0.0{
let conductivity_new:Vec<f64>=mu.into_par_iter().map(|x| {
let mut omega=Array1::<f64>::zeros(nk);
for k in 0..nk{
for i in 0..self.nsta{
omega[[k]]+= if band[[k,i]]> *x {0.0} else {omega_n[[k,i]]};
}
}
omega.sum()*(2.0*PI).powi(self.dim_r as i32)/self.lat.det().unwrap()/(nk as f64)
}).collect();
Array1::<f64>::from_vec(conductivity_new)
}else{
let beta=1.0/(T*8.617e-5);
let conductivity_new:Vec<f64>=mu.into_par_iter().map(|x| {
let fermi_dirac=band.mapv(|x0| 1.0/((beta*(x0-x)).exp()+1.0));
let omega:Vec<f64>=omega_n.axis_iter(Axis(0)).zip(fermi_dirac.axis_iter(Axis(0))).map(|(a,b)| {(&a*&b).sum()}).collect();
let omega:Array1::<f64>=arr1(&omega);
omega.sum()*(2.0*PI).powi(self.dim_r as i32)/self.lat.det().unwrap()/(nk as f64)
}).collect();
Array1::<f64>::from_vec(conductivity_new)
};
conductivity
}
pub fn berry_curvature_dipole_n_onek(&self,k_vec:&Array1::<f64>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,dir_3:&Array1::<f64>,og:f64,spin:usize,eta:f64)->(Array1<f64>,Array1<f64>){
let li:Complex<f64>=1.0*Complex::i();
let (band,evec)=self.solve_onek(&k_vec);
let mut v:Array3::<Complex<f64>>=self.gen_v(k_vec);
let mut J:Array3::<Complex<f64>>=v.clone();
let mut v0=Array2::<Complex<f64>>::zeros((self.nsta,self.nsta));for r in 0..self.dim_r{
v0=v0+v.slice(s![r,..,..]).to_owned()*dir_3[[r]];
}
if self.spin {
let mut X:Array2::<Complex<f64>>=Array2::eye(self.nsta);
let pauli:Array2::<Complex<f64>>= match spin{
0=> arr2(&[[1.0+0.0*li,0.0+0.0*li],[0.0+0.0*li,1.0+0.0*li]]),
1=> arr2(&[[0.0+0.0*li,1.0+0.0*li],[1.0+0.0*li,0.0+0.0*li]])/2.0,
2=> arr2(&[[0.0+0.0*li,0.0-1.0*li],[0.0+1.0*li,0.0+0.0*li]])/2.0,
3=> arr2(&[[1.0+0.0*li,0.0+0.0*li],[0.0+0.0*li,-1.0+0.0*li]])/2.0,
_=>panic!("Wrong, spin should be 0, 1, 2, 3, but you input {}",spin),
};
X=kron(&pauli,&Array2::eye(self.norb));
for i in 0..self.dim_r{
let j=J.slice(s![i,..,..]).to_owned();
let j=anti_comm(&X,&j)/2.0; J.slice_mut(s![i,..,..]).assign(&(j*dir_1[[i]]));
v.slice_mut(s![i,..,..]).mul_assign(Complex::new(dir_2[[i]],0.0));
}
}else{
if spin !=0{
println!("Warning, the model haven't got spin, so the spin input will be ignord");
}
for i in 0..self.dim_r{
J.slice_mut(s![i,..,..]).mul_assign(Complex::new(dir_1[[i]],0.0));
v.slice_mut(s![i,..,..]).mul_assign(Complex::new(dir_2[[i]],0.0));
}
};
let J:Array2::<Complex<f64>>=J.sum_axis(Axis(0));
let v:Array2::<Complex<f64>>=v.sum_axis(Axis(0));
let evec_conj:Array2::<Complex<f64>>=evec.clone().map(|x| x.conj()).to_owned();
let v0=v0.dot(&evec.clone().reversed_axes());
let v0=&evec_conj.dot(&v0);
let partial_ve=v0.diag().map(|x| x.re);
let A1=J.dot(&evec.clone().reversed_axes());
let A1=&evec_conj.dot(&A1);
let A2=v.dot(&evec.reversed_axes());
let A2=&evec_conj.dot(&A2);
let mut U0=Array2::<Complex<f64>>::zeros((self.nsta,self.nsta));
for i in 0..self.nsta{
for j in 0..self.nsta{
if i != j{
U0[[i,j]]=1.0/((band[[i]]-band[[j]]).powi(2)-(og+li*eta).powi(2));
}else{
U0[[i,j]]=Complex::new(0.0,0.0);
}
}
}
let mut omega_n=Array1::<f64>::zeros(self.nsta);
let A1=A1*U0;
for i in 0..self.nsta{
omega_n[[i]]=-2.0*A1.slice(s![i,..]).dot(&A2.slice(s![..,i])).im;
}
let omega_n:Array1::<f64>=omega_n*partial_ve;
(omega_n,band) }
pub fn berry_curvature_dipole_n(&self,k_vec:&Array2::<f64>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,dir_3:&Array1::<f64>,og:f64,spin:usize,eta:f64)->(Array2::<f64>,Array2::<f64>){
if dir_1.len() !=self.dim_r || dir_2.len() != self.dim_r || dir_3.len() != self.dim_r{
panic!("Wrong, the dir_1 or dir_2 you input has wrong length, it must equal to dim_r={}, but you input {},{}",self.dim_r,dir_1.len(),dir_2.len())
}
let nk=k_vec.len_of(Axis(0));
let (omega,band):(Vec<_>,Vec<_>)=k_vec.axis_iter(Axis(0)).into_par_iter().map(|x| {
let (omega_one,band)=self.berry_curvature_dipole_n_onek(&x.to_owned(),&dir_1,&dir_2,&dir_3,og,spin,eta);
(omega_one,band)
}).collect();
let omega=Array2::<f64>::from_shape_vec((nk, self.nsta),omega.into_iter().flatten().collect()).unwrap();
let band=Array2::<f64>::from_shape_vec((nk, self.nsta),band.into_iter().flatten().collect()).unwrap();
(omega,band)
}
pub fn Nonlinear_Hall_conductivity_Extrinsic(&self,k_mesh:&Array1::<usize>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,dir_3:&Array1::<f64>,mu:&Array1<f64>,T:f64,og:f64,spin:usize,eta:f64)->Array1<f64>{
if dir_1.len() !=self.dim_r || dir_2.len() != self.dim_r || dir_3.len() != self.dim_r{
panic!("Wrong, the dir_1 or dir_2 you input has wrong length, it must equal to dim_r={}, but you input {},{}",self.dim_r,dir_1.len(),dir_2.len())
}
let kvec:Array2::<f64>=gen_kmesh(&k_mesh);
let nk:usize=kvec.len_of(Axis(0));
let (omega,band)=self.berry_curvature_dipole_n(&kvec,&dir_1,&dir_2,&dir_3,og,spin,eta);
let omega=omega.into_raw_vec();
let band=band.into_raw_vec();
let n_e=mu.len();
let mut conductivity=Array1::<f64>::zeros(n_e);
if T !=0.0{
let beta=1.0/T/(8.617e-5);
let use_iter=band.iter().zip(omega.iter()).par_bridge();
conductivity=use_iter.fold(|| Array1::<f64>::zeros(n_e),|acc,(energy,omega0)|{
let f=1.0/(beta*(mu-*energy)).mapv(|x| x.exp()+1.0);
acc+&f*(1.0-&f)*beta**omega0
}).reduce(|| Array1::<f64>::zeros(n_e), |acc, x| acc + x);
conductivity=conductivity.clone()/(nk as f64)*(2.0*PI).powi(self.dim_r as i32)/self.lat.det().unwrap();
}else{
panic!("When T=0, the algorithm have not been writed, please wait for next version");
}
return conductivity
}
pub fn berry_connection_dipole_onek(&self,k_vec:&Array1::<f64>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,dir_3:&Array1::<f64>,spin:usize)->(Array1::<f64>,Array1::<f64>,Option<Array1<f64>>){
let mut v:Array3::<Complex<f64>>=self.gen_v(&k_vec);let mut J=v.clone();
let (band,evec)=self.solve_onek(&k_vec);let evec_conj=evec.clone().mapv(|x| x.conj());for i in 0..self.dim_r{
let v_s=v.slice(s![i,..,..]).to_owned();
let v_s=evec_conj.clone().dot(&(v_s.dot(&evec.clone().reversed_axes())));v.slice_mut(s![i,..,..]).assign(&v_s);}
let mut v_1=Array2::<Complex<f64>>::zeros((self.nsta,self.nsta));let mut v_2=Array2::<Complex<f64>>::zeros((self.nsta,self.nsta));
let mut v_3=Array2::<Complex<f64>>::zeros((self.nsta,self.nsta));
for i in 0..self.dim_r{
v_1=v_1.clone()+v.slice(s![i,..,..]).to_owned()*Complex::new(dir_1[[i]],0.0);
v_2=v_2.clone()+v.slice(s![i,..,..]).to_owned()*Complex::new(dir_2[[i]],0.0);
v_3=v_3.clone()+v.slice(s![i,..,..]).to_owned()*Complex::new(dir_3[[i]],0.0);
}
let mut U0=Array2::<f64>::zeros((self.nsta,self.nsta));
for i in 0..self.nsta{
for j in 0..self.nsta{
if (band[[i]]-band[[j]]).abs() < 1e-5{
U0[[i,j]]=0.0;
}else{
U0[[i,j]]=1.0/(band[[i]]-band[[j]]);
}
}
}
let partial_ve_1=v_1.diag().map(|x| x.re);
let partial_ve_2=v_2.diag().map(|x| x.re);
let partial_ve_3=v_3.diag().map(|x| x.re);
if self.spin{let mut S:Array2::<Complex<f64>>=Array2::eye(self.nsta);
let li=Complex::<f64>::new(0.0,1.0);
let pauli:Array2::<Complex<f64>>= match spin{
0=> Array2::<Complex<f64>>::eye(2),
1=> arr2(&[[0.0+0.0*li,1.0+0.0*li],[1.0+0.0*li,0.0+0.0*li]])/2.0,
2=> arr2(&[[0.0+0.0*li,0.0-1.0*li],[0.0+1.0*li,0.0+0.0*li]])/2.0,
3=> arr2(&[[1.0+0.0*li,0.0+0.0*li],[0.0+0.0*li,-1.0+0.0*li]])/2.0,
_=>panic!("Wrong, spin should be 0, 1, 2, 3, but you input {}",spin),
};
let X=kron(&pauli,&Array2::eye(self.norb));
let mut S=Array3::<Complex<f64>>::zeros((self.dim_r,self.nsta,self.nsta));
for i in 0..self.dim_r{
let v0=J.slice(s![i,..,..]).to_owned();
let v0=anti_comm(&X,&v0)/2.0;
let v0=evec_conj.clone().dot(&(v0.dot(&evec.clone().reversed_axes())));S.slice_mut(s![i,..,..]).assign(&v0);
}
let mut s_1=Array2::<Complex<f64>>::zeros((self.nsta,self.nsta));let mut s_2=Array2::<Complex<f64>>::zeros((self.nsta,self.nsta));
let mut s_3=Array2::<Complex<f64>>::zeros((self.nsta,self.nsta));
for i in 0..self.dim_r{
s_1=s_1.clone()+S.slice(s![i,..,..]).to_owned()*Complex::new(dir_1[[i]],0.0);
s_2=s_2.clone()+S.slice(s![i,..,..]).to_owned()*Complex::new(dir_2[[i]],0.0);
s_3=s_3.clone()+S.slice(s![i,..,..]).to_owned()*Complex::new(dir_3[[i]],0.0);
}
let G_23:Array1::<f64>={let A=&v_2*(U0.map(|x| Complex::<f64>::new(x.powi(3),0.0)));
let mut G=Array1::<f64>::zeros(self.nsta);
for i in 0..self.nsta{
G[[i]]=A.slice(s![i,..]).dot(&v_3.slice(s![..,i])).re*2.0
}
G
};
let G_13_h:Array1::<f64>={let A=&s_1*(U0.map(|x| Complex::<f64>::new(x.powi(3),0.0)));
let mut G=Array1::<f64>::zeros(self.nsta);
for i in 0..self.nsta{
G[[i]]=A.slice(s![i,..]).dot(&v_3.slice(s![..,i])).re*2.0
}
G
};
let partial_s_1=s_1.clone().diag().map(|x| x.re);
let partial_s_2=s_2.clone().diag().map(|x| x.re);
let partial_s_3=s_3.clone().diag().map(|x| x.re);
let mut partial_s=Array2::<f64>::zeros((self.dim_r,self.nsta));
for r in 0..self.dim_r{
let s0=S.slice(s![r,..,..]).to_owned();
partial_s.slice_mut(s![r,..]).assign(&s0.diag().map(|x| x.re));}
let partial_G:Array1::<f64>={
let mut A=Array1::<Complex<f64>>::zeros(self.nsta);for i in 0..self.nsta{
for j in 0..self.nsta{
A[[i]]+=3.0*(partial_s_1[[i]]-partial_s_1[[j]])*v_2[[i,j]]*v_3[[j,i]]*U0[[i,j]].powi(4);
}
}
let mut B=Array1::<Complex<f64>>::zeros(self.nsta);for n in 0..self.nsta{
for n1 in 0..self.nsta{
for n2 in 0..self.nsta{
B[[n]]+=s_1[[n,n2]]*(v_2[[n2,n1]]*v_3[[n1,n]]+v_3[[n2,n1]]*v_2[[n1,n]])*U0[[n,n1]].powi(3)*U0[[n,n2]];
}
}
}
let mut C=Array1::<Complex<f64>>::zeros(self.nsta);for n in 0..self.nsta{
for n1 in 0..self.nsta{
for n2 in 0..self.nsta{
C[[n]]+=s_1[[n1,n2]]*(v_2[[n2,n]]*v_3[[n,n1]]+v_3[[n2,n]]*v_2[[n,n1]])*U0[[n,n1]].powi(3)*U0[[n1,n2]];
}
}
}
2.0*(A-B-C).map(|x| x.re)
};
return ((partial_s_1*G_23-partial_ve_2*G_13_h),band,Some(partial_G))
}else{
let G_23:Array1::<f64>={let A=&v_2*(U0.map(|x| Complex::<f64>::new(x.powi(3),0.0)));
let mut G=Array1::<f64>::zeros(self.nsta);
for i in 0..self.nsta{
G[[i]]=A.slice(s![i,..]).dot(&v_3.slice(s![..,i])).re*2.0
}
G
};
let G_13:Array1::<f64>={let A=&v_1*(U0.map(|x| Complex::<f64>::new(x.powi(3),0.0)));
let mut G=Array1::<f64>::zeros(self.nsta);
for i in 0..self.nsta{
G[[i]]=A.slice(s![i,..]).dot(&v_3.slice(s![..,i])).re*2.0
}
G
};
return (partial_ve_1*G_23-partial_ve_2*G_13,band,None)
}
}
pub fn berry_connection_dipole(&self,k_vec:&Array2::<f64>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,dir_3:&Array1::<f64>,spin:usize)->(Array2<f64>,Array2<f64>,Option<Array2<f64>>){
if dir_1.len() !=self.dim_r || dir_2.len() != self.dim_r || dir_3.len() != self.dim_r{
panic!("Wrong, the dir_1 or dir_2 you input has wrong length, it must equal to dim_r={}, but you input {},{}",self.dim_r,dir_1.len(),dir_2.len())
}
let nk=k_vec.len_of(Axis(0));
if self.spin{
let ((omega,band),partial_G):((Vec<_>,Vec<_>),Vec<_>)=k_vec.axis_iter(Axis(0)).into_par_iter().map(|x| {
let (omega_one,band,partial_G)=self.berry_connection_dipole_onek(&x.to_owned(),&dir_1,&dir_2,&dir_3,spin);
let partial_G=partial_G.unwrap();
((omega_one,band),partial_G)
}).collect();
let omega=Array2::<f64>::from_shape_vec((nk, self.nsta),omega.into_iter().flatten().collect()).unwrap();
let band=Array2::<f64>::from_shape_vec((nk, self.nsta),band.into_iter().flatten().collect()).unwrap();
let partial_G=Array2::<f64>::from_shape_vec((nk, self.nsta),partial_G.into_iter().flatten().collect()).unwrap();
return (omega,band,Some(partial_G))
}else{
let (omega,band):(Vec<_>,Vec<_>)=k_vec.axis_iter(Axis(0)).into_par_iter().map(|x| {
let (omega_one,band,partial_G)=self.berry_connection_dipole_onek(&x.to_owned(),&dir_1,&dir_2,&dir_3,spin);
(omega_one,band)
}).collect();
let omega=Array2::<f64>::from_shape_vec((nk, self.nsta),omega.into_iter().flatten().collect()).unwrap();
let band=Array2::<f64>::from_shape_vec((nk, self.nsta),band.into_iter().flatten().collect()).unwrap();
return (omega,band,None)
}
}
pub fn Nonlinear_Hall_conductivity_Intrinsic(&self,k_mesh:&Array1::<usize>,dir_1:&Array1::<f64>,dir_2:&Array1::<f64>,dir_3:&Array1::<f64>,mu:&Array1<f64>,T:f64,spin:usize)->Array1<f64>{
let kvec:Array2::<f64>=gen_kmesh(&k_mesh);
let nk:usize=kvec.len_of(Axis(0));
let (omega,band,mut partial_G):(Array2<f64>,Array2<f64>,Option<Array2<f64>>)=self.berry_connection_dipole(&kvec,&dir_1,&dir_2,&dir_3,spin);
let omega=omega.into_raw_vec();
let omega=Array1::from(omega);
let band0=band.clone();
let band=band.into_raw_vec();
let band=Array1::from(band);
let n_e=mu.len();
let mut conductivity=Array1::<f64>::zeros(n_e);
if T !=0.0{
let beta=1.0/T/8.617e-5;
let use_iter=band.iter().zip(omega.iter()).par_bridge();
conductivity=use_iter.fold(|| Array1::<f64>::zeros(n_e),|acc,(energy,omega0)|{
let f=1.0/((beta*(mu-*energy)).mapv(|x| x.exp()+1.0));
acc+&f*(1.0-&f)*beta**omega0
}).reduce(|| Array1::<f64>::zeros(n_e), |acc, x| acc + x);
if self.spin{
let partial_G=partial_G.unwrap();
let conductivity_new:Vec<f64>=mu.into_par_iter().map(|x| {
let f=band0.map(|x0| 1.0/((beta*(x-x0)).exp()+1.0));
let mut omega=Array1::<f64>::zeros(nk);
for i in 0..nk{
omega[[i]]=(partial_G.row(i).to_owned()*f.row(i).to_owned()).sum();
}
omega.sum()/2.0
}).collect();
let conductivity_new=Array1::<f64>::from_vec(conductivity_new);
conductivity=conductivity.clone()+conductivity_new;
}
conductivity=conductivity.clone()/(nk as f64)*(2.0*PI).powi(self.dim_r as i32)/self.lat.det().unwrap();
}else{
panic!("the code can not support for T=0");
}
return conductivity
}
}
}