Rustb/
conductivity.rs

1//! Calculation of linear and nonlinear conductivity tensors using Kubo formalism.
2//!
3//! This module implements various conductivity calculations including:
4//! - Anomalous Hall conductivity
5//! - Spin Hall conductivity  
6//! - Nonlinear Hall conductivity
7//! - Berry curvature and orbital magnetization
8//!
9//! The implementations are based on the Kubo formula and semiclassical wave-packet
10//! dynamics, providing both intrinsic and extrinsic contributions to transport.
11
12//!# Niu qian 方程推导非线性霍尔效应
13//!以下是用niuqian 方程来推导各阶线性和非线性霍尔效应的公式过程
14
15//!出发点是如下公式
16//!$$\bm J=-e\int_\tx{BZ}\dd\bm k\sum_n f_n\bm v_n$$
17//!这里 n 表示能带, 而 $f_n$ 是feimi-dirac distribution. 这里速度算符的定义按照 niuqian
18//!老师的定义为 $$\bm v=\f{1}{\hbar}\f{\p\ve_n}{\p\bm k}-\f{e}{\hbar}\bm E\times\bm\Og_n$$
19//!我们设第 $n$ 阶霍尔电导的定义为
20//!$$\sg_{\ap_1,\ap_2,\cdots,\ap_n;d}=\f{1}{n!}\left\.\f{\p^n J_d}{\p E_{\ap_1}\cdots\p E_{\ap_n}}\right\vert_{\bm E=0}$$
21//!为了得到其表达式, 我们定义级数展开
22//!$$\lt\\\{\\begin{aligned}
23//!f_n=f_n^{(0)}+f_n^{(1)}+f_n^{(2)}\cdots\\\\
24//!\bm v_n=\bm v_n^{(0)}+\bm v_n^{(1)}+\bm v_n^{(2)}\cdots\\\\
25//!\\end{aligned}\rt\.$$
26//!这样我们有
27//!$$ \\begin{aligned}\bm J^{(0)}&=-e\int_\tx{BZ}\dd\bm k\sum_n f_n^{(0)}\bm v_n^{(0)}\\\\
28//!\bm J^{(1)}&=-e\int_\tx{BZ}\dd\bm k\sum_n f_n^{(1)}\bm v_n^{(0)}+f_n^{(0)}\bm v_n^{(1)}\\\\
29//!\bm J^{(2)}&=-e\int_\tx{BZ}\dd\bm k\sum_n f_n^{(2)}\bm v_n^{(0)}+f_n^{(1)}\bm v_n^{(1)}+f_n^{(0)}\bm v_n^{(2)}\\\\
30//!\\end{aligned}$$
31
32//!接下来我们考虑 $f$ 的各阶修正. 利用玻尔兹曼方程, 我们有
33//!$$\p_t f-\f{e}{\hbar}\bm E\cdot\nb_{\bm k} f=-\f{f-f_0}{\tau}$$
34//!令 $f=\sum_{s=1}e^{is\og t} f_n^{(s)}$, 我们有
35//!$$\\begin{aligned} is\og\sum_{s=1}f_n^{(s)}-\f{e}{\hbar}\bm E\cdot\nb_{\bm k}\sum_{s=0} f_n^{(s)}=-\f{1}{\tau}\sum_{s=1} f_n^{(s)}\\\\
36//!\Rightarrow (is\og+\f{1}{\tau})\sum_{s=1} f_n^{(i)}-\f{e}{\hbar}\bm E\cdot\nb_{\bm k}\sum_{i=0} f_n^{(i)}=0\\\\
37//!\\end{aligned}$$
38//!最终, 我们能够得到高阶的费米分布, 为
39//!$$f_n^{(l)}=\f{e}{\hbar} \f{\bm E\nb_{\bm k} f_n^{(l-1)}}{i l \og+1/\tau}=\lt(\f{e/\hbar}{i\og+1/\tau}\rt)\bm E^l\nb^l_{\bm k} f_n^{(0)}$$
40//!取零频极限, 我们有 $$\lim_{\og\to 0} f_n^{(l)}\approx \lt(\f{e\tau}{\hbar}\rt)^l \bm E^l\nb^l_{\bm k} f_n^{(0)}$$
41
42//!关于费米速度 $\bm v_n=\f{1}{\hbar}\pdv{\ve_n}{\bm k}+\f{e}{\hbar}\bm E\times\bm \Og_n$,
43//!我们可以定义各阶展开
44//!$$\\begin{aligned}
45//!\bm v_n^{(0)}&=\f{1}{\hbar}\pdv{\ve_n^{(0)}}{\bm k}\\\\
46//!\bm v_n^{(1)}&=\f{1}{\hbar}\pdv{\ve_n^{(1)}}{\bm k}+\f{e}{\hbar}\bm E\times\bm \Og_n^{(0)}\\\\
47//!\bm v_n^{(2)}&=\f{1}{\hbar}\pdv{\ve_n^{(2)}}{\bm k}+\f{e}{\hbar}\bm E\times\bm \Og_n^{(1)}\\\\
48//!\\end{aligned}$$
49//!对于接下来我们的出发点是电场下的哈密顿量
50//!$$H_{\bm k}=\sum_{mn}\lt(\ve_n^{(0)}\dt_{nm}-e\bm E\cdot\bra{\psi_n}\bm r\ket{\psi_n}\rt)\ket{\psi_n}\bra{\psi_m}$$
51//!我们将其拆成两部分, 对角部分和非对角部分
52//!$$\\begin{aligned}
53//!H_{\bm k}^{(0)}&=\sum_{n}\lt(\ve_{n\bm k}^{(0)}-e\bm E\cdot\bm A_n\rt)\dyad{\psi_n}\\\\
54//!H_{\bm k}^{(1)}&=\sum_{n=\not m}\lt(-e\bm E\cdot\bm A_{mn}\rt)\ket{\psi_m}\bra{\psi_n}\\\\
55//!\\end{aligned}$$
56//!这里 $\bm A_{mn}=\bra{\psi_m}\bm r\ket{\psi_n}=i\bra{\psi_m}\p_{\bm k}\ket{\psi_n}$
57
58//!显然, 我们知道公式
59//!$$e^{\hat S}\hat{\mathcal{O}}e^{-\hat S}=\mathcal{O}+\lt[\hat S,\hat{\mcl{O}}\rt]+\f{1}{2}\lt[\hat S,\lt[\hat S,\hat{\mcl{O}}\rt]\rt]+\f{1}{6}\lt[\hat S,\lt[\hat S,\lt[\hat S,\hat{\mcl{O}}\rt]\rt]\rt]\cdots$$
60//! 为了方便计算, 我们可以选择一个 $\hat S$, 让 $H_{\bm k}^{(1)}+\lt[\hat S,\hat H_{\bm k}^{(0)}\rt]=0$, 我们有
61//!$$\\begin{aligned}
62//!H^\prime_{\bm k}&=e^{\hat S}H_{\bm k} e^{-\hat S}=H_{\bm k}^{(0)}+\lt(H_{\bm k}^{(1)}+\lt[\hat S,\hat H_{\bm k}^{(0)}\rt]\rt)+\lt(\lt[\hat S,\hat H_{\bm k}^{(1)}\rt]+\f{1}{2}\lt[\hat S,\lt[\hat S,\hat H_{\bm k}^{(0)}\rt]\rt]\rt)\cdots\\\\
63//!&=H_{\bm k}^{(0)}+\f{1}{2}\lt[S,H_{\bm k}^{(1)}\rt]+\f{1}{3}\lt[S,\lt[S,H_{\bm k}^{(1)}\rt]\rt]\cdots
64//!\\end{aligned}$$
65//!为了满足条件, 我们选择 $$S_{nn}=0,\ S_{nm}=\f{-e\bm E\cdot \bm A_{nm}}{\ve_{nm}-e\bm E\cdot \bm A_{nm}}$$
66
67//!因为我们有
68//!$$\\begin{aligned} \lt[S,H_{\bm k}^{(0)}\rt]&=SH_{\bm k}^{(0)}-H_{\bm k}^{(0)}S=\sum_{j=\not m} S_{mj}H_{\bm k,jn}^{(0)}-\sum_{j=\not n }H_{\bm k,mj}^{(0)}S_{jn}\\\\
69//!&=\sum_{j=\not m}\f{-e\bm E\cdot \bm A_{mj}\lt(\ve_j^{(0)}-e\bm E\cdot\bm A_j\rt)\dt_{jn}}{\ve_{mj}-e\bm E\cdot\lt(\bm A_m-\bm A_j\rt)}-\sum_{j=\not n}\f{-e\lt(\ve_j^{(0)}-e\bm E\cdot\bm A_j\rt)\lt(\bm E\cdot \bm A_{jn}\rt)\dt_{mj}}{\ve_{jn}-e\bm E\cdot\lt(\bm A_j-\bm A_n\rt)}\\\\
70//!&=\f{e\lt(\bm E\cdot\bm A_{mn}\rt)\lt[\ve_{mn}- e\bm E\cdot\lt(\bm A_m-\bm A_n\rt)\rt]}{\ve_{mn}-e\bm E\cdot(\bm A_m-\bm A_n)}=-H_{\bm k}^{(1)}
71//!\\end{aligned}$$
72//!这样我们就验证了我们的结果, 我们将 $\hat S$ 进行化简和展开有
73//!$$S_{nm}\approx \f{-e\bm E\cdot\bm A_{nm}}{\ve_n^{(0)}-\ve_m^{(0)}}-\f{ e^2\lt(\bm E\cdot\bm A_{nm}\rt)\lt(\bm E\cdot\lt(\bm A_n-\bm A_m\rt)\rt)}{\lt(\ve_n^{(0)}-\ve_m^{(0)}\rt)^2}$$
74//!这样我们就能得到能带的各阶扰动
75//!$$\\begin{aligned}
76//!\ve_n^{(1)}&=-e\bm E\cdot\bm A_n\\\\
77//!\ve_n^{(2)}&=\f{e^2}{2}E_a E_b \sum_{m=\not n}\f{A_{nm}^a A_{mn}^b+A_{mn}^a A_{nm}^b}{\ve_n-\ve_m}=e^2 G_n^{ab}E_a E_b\\\\
78//!\ve_n^{(3)}&=-e^3E_a E_b E_c \lt( \sum_{m=\not n}\sum_{l=\not m,n}\f{A_{nl}^a A_{lm}^b A_{mn}^c}{(\ve_n-\ve_m)(\ve_n-\ve_l)}\rt)+e^3 E_a E_b E_c\lt( \sum_{m=\not n}\sum_{l=\not m,n}\f{A_{nm}^a A_{mn}^b (A_n^c-A_m^c)}{(\ve_n-\ve_m)^2}\rt)\\\\
79//!\\end{aligned}$$
80//!这里 $$G_n^{ab}=\sum_{m=\not n}\f{A_{nm}^a A_{mn}^b+A_{mn}^a A_{nm}^b}{\ve_n-\ve_m}=\sum_{m=\not n} 2\tx{Re}\f{v_{nm}^a v_{mn}^b}{(\ve_n-\ve_m)^3}$$
81//!到这里, 我们将能带的扰动得到了. 但是有一个问题, 就是 $\bm A$ 是一个规范变换, 所以并不是唯一的,
82//!同时, 对于带内的贡献 $\bm A_{n}=i\bra{\psi_{n\bm k}}\p_{\bm k}\ket{\psi_{n\bm k}}$, 没有好的求解方法,因为 $\bm A=-e\bra{\psi_n}\bm r\ket{\psi_n}$ 破坏了平移对称性. 但是我们总是可以选择一个规范.
83//!在这里我们选择 $-e\bm E\cdot\bm A_n=0$, 这个规范令 $\ve_n^{(1)}=0$. 这种规范在物理的意义上, 可以理解为贝利联络和电场的方向垂直. 对于贝利曲率的高阶项, 利用 $\bm A\to\bm A^\prime=A+\lt[\hat S,\bm A\rt]+\f{1}{2}\lt[\hat S,\lt[\hat S,\bm A\rt]\rt]\cdots$, 我们有
84//!$$\\begin{aligned}
85//!\lt(A_n^b\rt)^{(1)}&=-e\bm E_a G_n^{ab}\\\\
86//!\lt(A_n^c\rt)^{(2)}&=e^2 E_a E_b \lt( \sum_{m=\not n}\sum_{l=\not m,n}\f{A_{nl}^a A_{lm}^b A_{mn}^c}{(\ve_n-\ve_m)(\ve_n-\ve_l)}\rt)+e^2 E_a E_b\lt( \sum_{m=\not n}\f{A_{nm}^a A_{mn}^b (A_n^c-A_m^c)}{(\ve_n-\ve_m)^2}\rt)\\\\
87//!&=e^2 E_a E_b\lt(S_n^{abc}-F_n^{abc}\rt)
88//!\\end{aligned}$$
89
90//!这样利用贝利曲率公式 $\Og_n^{ab}=\p_a A_n^b -\p_b A_n^a$
91//!我们有 $$\\begin{aligned}
92//!\lt(\Og_n^{ab}\rt)^{(1)}&=-e E_c\lt(\p_a G_n^{bc}-\p_b G_n^{ac}\rt)\\\\
93//!\lt(\Og_n^{ab}\rt)^{(2)}&=e^2 E_{\ap}E_{\bt}\lt(\p_a S^{\ap\bt b}-\p_b S^{\ap\bt a}-\p_a F^{\ap\bt b}+\p_b F^{\ap\bt a}\rt)
94//!\\end{aligned}$$
95//!最终我们带入到电导率公式中, 有
96//!$$\begin{aligned}
97//!\sigma_{ab}=&-\f{e^2}{\hbar}\int_\tx{BZ} \f{\dd\bm k}{(2\pi)^3}\sum_n f_n\Og_n^{ab}+\f{e^2\tau}{\hbar^2}\sum_n \int_\tx{BZ}\f{\dd\bm k}{(2\pi)^3}\f{\p^2\ve_n}{\p k_a\p k_b}\\\\
98//!\sigma_{abc}=&-\f{e^3\tau^2}{\hbar^3}\sum_n\int_\tx{BZ}\f{\dd\bm k}{(2\pi)^3}\f{\p^3\ve_n}{\p k_a \p k_b \p k_c}
99//!+\f{e^3\tau}{\hbar^2}\sum_n \int_\tx{BZ}\f{\dd\bm k}{(2\pi)^3} \f{1}{2} f_n \lt(\p_a\Og_n^{bc}+\p_b\Og_n^{ac}\rt)\\\\
100//!&-\f{e^3}{\hbar}\sum_n\int_\tx{BZ}\f{\dd\bm k}{(2\pi)^3} f_n\lt(2\p_c G_n^{ab}-\f{1}{2}\lt(\p_a G_n^{bc}+\p_b G_n^{ac}\rt)\rt)
101//!\end{aligned}$$
102
103//! ## Berry connection 的化简
104
105//!为了实际的计算, 我们需要将 Berry connection 的形式修改一下, 我们首先按照微分的定理有 $$\p_{\bm k}\lt(H_{\bm k}\ket{\psi_{n\bm k}}\rt)=\lt(\p_{\bm k}H_{\bm k}+H_{\bm k}\p_{\bm k}\rt)\ket{\psi_{n\bm k}}$$
106//!然后我们又因为 $H_{\bm k}\ket{\psi_{n\bm k}}=\ve_{n\bm k}\ket{\psi_{n\bm k}}$, 所以 $$\p_{\bm k}\lt(H_{\bm k}\ket{\psi_{n\bm k}}\rt)=\p_{\bm k}\ve_{n\bm k}\ket{\psi_{n\bm k}}+\ve_{n\bm k}\p_{\bm k}\ket{\psi_{n\bm k}}$$
107//!所以我们有 $$\\begin{aligned}
108//!\p_{\bm k}H_{\bm k}\ket{\psi_{n\bm k}}+H_{\bm k}\p_{\bm k}\ket{\psi_{n\bm k}}=\p_{\bm k}\ve_{n\bm k}\ket{\psi_{n\bm k}}+\ve_{n\bm k}\p_{\bm k}\ket{\psi_{n\bm k}}
109//!\\end{aligned}$$
110//!显然我们将上式等号两边的左侧插入一个完备算符 $\sum_m \dyad{\psi_{m\bm k}}$ 有 $$\sum_m\lt[\bra{\psi_{m\bm k}}\p_{\bm k}H_{\bm k}\ket{\psi_{n\bm k}}+\lt(\ve_{m\bm k}-\ve_{n\bm k}\rt)\bra{\psi_{m\bm k}}\p_{\bm k}\ket{\psi_{n\bm k}}\rt]\ket{\psi_{m\bm k}}=\bra{\psi_{n\bm k}}\p_{\bm k}\ket{\psi_{n\bm k}}\ket{\psi_{n\bm k}} $$
111//!根据上面的式子, 我们很容易得到当 $m=\not n$ 时 $$\bra{\psi_{m\bm k}}\p_{\bm k}\ket{\psi_{n\bm k}}=\f{\bra{\psi_{m\bm k}}\p_{\bm k}\ket{\psi_{n\bm k}}}{\ve_{n\bm k}-\ve_{m\bm k}}$$
112//!也就是说, 我们能够最终得到 $$\bm A_{mn}=i\f{\bra{\psi_{m\bm k}}\p_{\bm k}\ket{\psi_{n\bm k}}}{\ve_{n\bm k}-\ve_{m\bm k}}$$
113
114use crate::error::{Result, TbError};
115use crate::kpoints::{gen_kmesh, gen_krange};
116use crate::math::*;
117use crate::phy_const::mu_B;
118use crate::{Gauge, Model};
119use ndarray::linalg::kron;
120use ndarray::prelude::*;
121use ndarray::*;
122use ndarray_linalg::conjugate;
123use ndarray_linalg::*;
124use num_complex::Complex;
125use rayon::prelude::*;
126use std::f64::consts::PI;
127use std::ops::AddAssign;
128use std::ops::MulAssign;
129
130/**
131这个函数是用来做自适应积分算法的
132
133对于任意维度的积分 n, 我们的将区域刨分成 n+1面体的小块, 然后用线性插值来近似这个n+1的积分结果
134
135设被积函数为 $f(x_1,x_2,...,x_n)$, 存在 $n+1$ 个点 $(y_{01},y_{02},\cdots y_{0n})\cdots(y_{n1},y_{n2}\cdots y_{nn})$, 对应的值为 $z_0,z_1,...,z_n$
136
137这样我们就能得到这一块积分的近似值为 $$ \f{1}{(n+1)!}\times\sum_{i=0}^n z_i *\dd V.$$ 其中$\dd V$ 是正 $n+1$ 面体的体积.
138
139在这里, 对于一维体系, 线性插值积分等价于梯形积分. 在两个相邻的数据点 ($x_1$,$f_1$) 和 ($x_2,$f_2$), 其积分结果为$\Delta=\f{f_1+f_2}{2}*(x_2-x_2)$.
140
141对于二维系统, 用三角形进行近似, 对于任意的小三角形得到的积分结果为 $\Delta=S\sum_{i=1}^3 f_i/3!$
142
143对于三维系统, 线性插值的结果为 $\Delta=S\sum_{i=1}^4 f_i/4!$
144*/
145
146#[inline(always)]
147pub fn adapted_integrate_quick(
148    f0: &dyn Fn(&Array1<f64>) -> f64,
149    k_range: &Array2<f64>,
150    re_err: f64,
151    ab_err: f64,
152) -> f64 {
153    let dim = k_range.len_of(Axis(0));
154    match dim {
155        1 => {
156            //对于一维情况, 我们就是用梯形算法的 (a+b)*h/2, 这里假设的是函数的插值为线性插值.
157            let mut use_range = vec![(k_range.clone(), re_err, ab_err)];
158            let mut result = 0.0;
159            while let Some((k_range, re_err, ab_err)) = use_range.pop() {
160                let kvec_l: Array1<f64> = arr1(&[k_range[[0, 0]]]);
161                let kvec_r: Array1<f64> = arr1(&[k_range[[0, 1]]]);
162                let kvec_m: Array1<f64> = arr1(&[(k_range[[0, 1]] + k_range[[0, 0]]) / 2.0]);
163                let dk: f64 = k_range[[0, 1]] - k_range[[0, 0]];
164                let y_l: f64 = f0(&kvec_l);
165                let y_r: f64 = f0(&kvec_r);
166                let y_m: f64 = f0(&kvec_m);
167                let all: f64 = (y_l + y_r) * dk / 2.0;
168                let all_1 = (y_l + y_m) * dk / 4.0;
169                let all_2 = (y_r + y_m) * dk / 4.0;
170                let err = all_1 + all_2 - all;
171                let abs_err = if ab_err > all * re_err {
172                    ab_err
173                } else {
174                    all * re_err
175                };
176                if err < abs_err {
177                    result += all_1 + all_2;
178                } else {
179                    let k_range_l = arr2(&[[kvec_l[[0]], kvec_m[[0]]]]);
180                    let k_range_r = arr2(&[[kvec_m[[0]], kvec_r[[0]]]]);
181                    use_range.push((k_range_l, re_err, ab_err / 2.0));
182                    use_range.push((k_range_r, re_err, ab_err / 2.0));
183                }
184            }
185            return result;
186        }
187        2 => {
188            //对于二维, 我们依旧假设线性插值, 这样我们考虑的就是二维平面上的三角形上的任意一点的值是到其余三个点的距离的加权系数的平均值, 我们将四边形变成两个三角形来考虑.
189            let area_1: Array2<f64> = arr2(&[
190                [k_range.row(0)[0], k_range.row(1)[0]],
191                [k_range.row(0)[1], k_range.row(1)[0]],
192                [k_range.row(0)[0], k_range.row(1)[1]],
193            ]); //第一个三角形
194            let area_2: Array2<f64> = arr2(&[
195                [k_range.row(0)[1], k_range.row(1)[1]],
196                [k_range.row(0)[1], k_range.row(1)[0]],
197                [k_range.row(0)[0], k_range.row(1)[1]],
198            ]); //第二个三角形
199            #[inline(always)]
200            fn adapt_integrate_triangle(
201                f0: &dyn Fn(&Array1<f64>) -> f64,
202                kvec: &Array2<f64>,
203                re_err: f64,
204                ab_err: f64,
205                s1: f64,
206                s2: f64,
207                s3: f64,
208                S: f64,
209            ) -> f64 {
210                //这个函数是用来进行自适应算法的
211                let mut result = 0.0;
212                let mut use_kvec = vec![(kvec.clone(), re_err, ab_err, s1, s2, s3, S)];
213                while let Some((kvec, re_err, ab_err, s1, s2, s3, S)) = use_kvec.pop() {
214                    let kvec_m = kvec.mean_axis(Axis(0)).unwrap();
215                    let sm: f64 = f0(&kvec_m.to_owned());
216
217                    let mut new_kvec = kvec.to_owned();
218                    new_kvec.push_row(kvec_m.view());
219                    let kvec_1 = new_kvec.select(Axis(0), &[0, 1, 3]);
220                    let kvec_2 = new_kvec.select(Axis(0), &[0, 3, 2]);
221                    let kvec_3 = new_kvec.select(Axis(0), &[3, 1, 2]);
222                    let all: f64 = (s1 + s2 + s3) * S / 6.0;
223                    let all_new: f64 = all / 3.0 * 2.0 + sm * S / 6.0;
224                    let abs_err: f64 = if ab_err > all * re_err {
225                        ab_err
226                    } else {
227                        all * re_err
228                    };
229                    if (all_new - all).abs() > abs_err && S > 1e-8 {
230                        let S1 = S / 3.0;
231                        use_kvec.push((kvec_1, re_err, ab_err / 3.0, s1, s2, sm, S1));
232                        use_kvec.push((kvec_2, re_err, ab_err / 3.0, s1, sm, s3, S1));
233                        use_kvec.push((kvec_3, re_err, ab_err / 3.0, sm, s2, s3, S1));
234                    } else {
235                        result += all_new;
236                    }
237                }
238                result
239            }
240            let S = (k_range[[0, 1]] - k_range[[0, 0]]) * (k_range[[1, 1]] - k_range[[1, 0]]);
241            let s1 = f0(&arr1(&[k_range.row(0)[0], k_range.row(1)[0]]));
242            let s2 = f0(&arr1(&[k_range.row(0)[1], k_range.row(1)[0]]));
243            let s3 = f0(&arr1(&[k_range.row(0)[0], k_range.row(1)[1]]));
244            let s4 = f0(&arr1(&[k_range.row(0)[1], k_range.row(1)[1]]));
245            let all_1 = adapt_integrate_triangle(f0, &area_1, re_err, ab_err / 2.0, s1, s2, s3, S);
246            let all_2 = adapt_integrate_triangle(f0, &area_2, re_err, ab_err / 2.0, s4, s2, s3, S);
247            return all_1 + all_2;
248        }
249        3 => {
250            //对于三位情况, 需要用到四面体, 所以需要先将6面体变成6个四面体
251            #[inline(always)]
252            fn adapt_integrate_tetrahedron(
253                f0: &dyn Fn(&Array1<f64>) -> f64,
254                kvec: &Array2<f64>,
255                re_err: f64,
256                ab_err: f64,
257                s1: f64,
258                s2: f64,
259                s3: f64,
260                s4: f64,
261                S: f64,
262            ) -> f64 {
263                //这个函数是用来进行自适应算法的
264                let mut result = 0.0;
265                let mut use_kvec = vec![(kvec.clone(), re_err, ab_err, s1, s2, s3, s4, S)];
266                while let Some((kvec, re_err, ab_err, s1, s2, s3, s4, S)) = use_kvec.pop() {
267                    let kvec_m = kvec.mean_axis(Axis(0)).unwrap();
268                    let sm = f0(&kvec_m.to_owned());
269                    let mut new_kvec = kvec.to_owned();
270                    new_kvec.push_row(kvec_m.view());
271                    let kvec_1 = new_kvec.select(Axis(0), &[0, 1, 2, 4]);
272                    let kvec_2 = new_kvec.select(Axis(0), &[0, 1, 4, 3]);
273                    let kvec_3 = new_kvec.select(Axis(0), &[0, 4, 2, 3]);
274                    let kvec_4 = new_kvec.select(Axis(0), &[4, 1, 2, 3]);
275
276                    let all = (s1 + s2 + s3 + s4) * S / 24.0;
277                    let all_new = all * 0.75 + sm * S / 24.0;
278                    let S1 = S * 0.25;
279                    let abs_err = if ab_err > all * re_err {
280                        ab_err
281                    } else {
282                        all * re_err
283                    };
284                    if (all_new - all).abs() > abs_err && S > 1e-9 {
285                        use_kvec.push((kvec_1, re_err, ab_err * 0.25, s1, s2, s3, sm, S1));
286                        use_kvec.push((kvec_2, re_err, ab_err * 0.25, s1, s2, sm, s4, S1));
287                        use_kvec.push((kvec_3, re_err, ab_err * 0.25, s1, sm, s3, s4, S1));
288                        use_kvec.push((kvec_4, re_err, ab_err * 0.25, sm, s2, s3, s4, S1));
289                    } else {
290                        result += all_new;
291                    }
292                }
293                result
294            }
295
296            let k_points: Array2<f64> = arr2(&[
297                [k_range.row(0)[0], k_range.row(1)[0], k_range.row(2)[0]],
298                [k_range.row(0)[1], k_range.row(1)[0], k_range.row(2)[0]],
299                [k_range.row(0)[0], k_range.row(1)[1], k_range.row(2)[0]],
300                [k_range.row(0)[1], k_range.row(1)[1], k_range.row(2)[0]],
301                [k_range.row(0)[0], k_range.row(1)[0], k_range.row(2)[1]],
302                [k_range.row(0)[1], k_range.row(1)[0], k_range.row(2)[1]],
303                [k_range.row(0)[0], k_range.row(1)[1], k_range.row(2)[1]],
304                [k_range.row(0)[1], k_range.row(1)[1], k_range.row(2)[1]],
305            ]); //六面体的顶点
306
307            let area_1 = k_points.select(Axis(0), &[0, 1, 2, 5]);
308            let area_2 = k_points.select(Axis(0), &[0, 2, 4, 5]);
309            let area_3 = k_points.select(Axis(0), &[6, 2, 4, 5]);
310            let area_4 = k_points.select(Axis(0), &[1, 2, 3, 5]);
311            let area_5 = k_points.select(Axis(0), &[7, 2, 3, 5]);
312            let area_6 = k_points.select(Axis(0), &[7, 2, 6, 5]);
313            let s0 = f0(&k_points.row(0).to_owned());
314            let s1 = f0(&k_points.row(1).to_owned());
315            let s2 = f0(&k_points.row(2).to_owned());
316            let s3 = f0(&k_points.row(3).to_owned());
317            let s4 = f0(&k_points.row(4).to_owned());
318            let s5 = f0(&k_points.row(5).to_owned());
319            let s6 = f0(&k_points.row(6).to_owned());
320            let s7 = f0(&k_points.row(7).to_owned());
321            let V = (k_range[[0, 1]] - k_range[[0, 0]])
322                * (k_range[[1, 1]] - k_range[[1, 0]])
323                * (k_range[[2, 1]] - k_range[[2, 0]]);
324            let all_1 =
325                adapt_integrate_tetrahedron(f0, &area_1, re_err, ab_err / 6.0, s0, s1, s2, s5, V);
326            let all_2 =
327                adapt_integrate_tetrahedron(f0, &area_2, re_err, ab_err / 6.0, s0, s2, s4, s5, V);
328            let all_3 =
329                adapt_integrate_tetrahedron(f0, &area_3, re_err, ab_err / 6.0, s6, s2, s4, s5, V);
330            let all_4 =
331                adapt_integrate_tetrahedron(f0, &area_4, re_err, ab_err / 6.0, s1, s2, s3, s5, V);
332            let all_5 =
333                adapt_integrate_tetrahedron(f0, &area_5, re_err, ab_err / 6.0, s7, s2, s3, s5, V);
334            let all_6 =
335                adapt_integrate_tetrahedron(f0, &area_5, re_err, ab_err / 6.0, s7, s2, s6, s5, V);
336            return all_1 + all_2 + all_3 + all_4 + all_5 + all_6;
337        }
338        _ => {
339            panic!(
340                "wrong, the row_dim if k_range must be 1,2 or 3, but you's give {}",
341                dim
342            );
343        }
344    }
345}
346
347#[allow(non_snake_case)]
348impl Model {
349    //! 这个模块是用来提供电导率张量的, 包括自旋霍尔电导率和霍尔电导率, 以及非线性霍尔电导率.
350    //!
351    //!
352    //!
353    #[allow(non_snake_case)]
354    #[inline(always)]
355    pub fn berry_curvature_n_onek<S: Data<Elem = f64>>(
356        &self,
357        k_vec: &ArrayBase<S, Ix1>,
358        dir_1: &Array1<f64>,
359        dir_2: &Array1<f64>,
360        spin: usize,
361        eta: f64,
362    ) -> (Array1<f64>, Array1<f64>) {
363        let li: Complex<f64> = 1.0 * Complex::i();
364        //let (band, evec) = self.solve_onek(&k_vec);
365        let (mut v, hamk): (Array3<Complex<f64>>, Array2<Complex<f64>>) =
366            self.gen_v(&k_vec, Gauge::Atom); //这是速度算符
367        let (band, evec) = if let Ok((eigvals, eigvecs)) = hamk.eigh(UPLO::Lower) {
368            (eigvals, eigvecs)
369        } else {
370            todo!()
371        };
372        let mut J = v.view();
373        let (J, v) = if self.spin {
374            let J = match spin {
375                0 => {
376                    let J = J
377                        .outer_iter()
378                        .zip(dir_1.iter())
379                        .fold(Array2::zeros((self.nsta(), self.nsta())), |acc, (x, d)| {
380                            acc + &x * (*d + 0.0 * li)
381                        });
382                    J
383                }
384                1 => {
385                    let pauli = arr2(&[
386                        [0.0 + 0.0 * li, 1.0 + 0.0 * li],
387                        [1.0 + 0.0 * li, 0.0 + 0.0 * li],
388                    ]) / 2.0;
389                    let mut X: Array2<Complex<f64>> = Array2::eye(self.nsta());
390                    X = kron(&pauli, &Array2::eye(self.norb()));
391                    let J = J
392                        .outer_iter()
393                        .zip(dir_1.iter())
394                        .fold(Array2::zeros((self.nsta(), self.nsta())), |acc, (x, d)| {
395                            acc + &anti_comm(&X, &x) * (*d * 0.5 + 0.0 * li)
396                        });
397                    J
398                }
399                2 => {
400                    let pauli = arr2(&[
401                        [0.0 + 0.0 * li, 0.0 - 1.0 * li],
402                        [0.0 + 1.0 * li, 0.0 + 0.0 * li],
403                    ]) / 2.0;
404                    let mut X: Array2<Complex<f64>> = Array2::eye(self.nsta());
405                    X = kron(&pauli, &Array2::eye(self.norb()));
406                    let J = J
407                        .outer_iter()
408                        .zip(dir_1.iter())
409                        .fold(Array2::zeros((self.nsta(), self.nsta())), |acc, (x, d)| {
410                            acc + &anti_comm(&X, &x) * (*d * 0.5 + 0.0 * li)
411                        });
412                    J
413                }
414                3 => {
415                    let pauli = arr2(&[
416                        [1.0 + 0.0 * li, 0.0 + 0.0 * li],
417                        [0.0 + 0.0 * li, -1.0 + 0.0 * li],
418                    ]) / 2.0;
419                    let mut X: Array2<Complex<f64>> = Array2::eye(self.nsta());
420                    X = kron(&pauli, &Array2::eye(self.norb()));
421                    let J = J
422                        .outer_iter()
423                        .zip(dir_1.iter())
424                        .fold(Array2::zeros((self.nsta(), self.nsta())), |acc, (x, d)| {
425                            acc + &anti_comm(&X, &x) * (*d * 0.5 + 0.0 * li)
426                        });
427                    J
428                }
429                _ => panic!("Wrong, spin should be 0, 1, 2, 3, but you input {}", spin),
430            };
431            let v = v
432                .outer_iter()
433                .zip(dir_2.iter())
434                .fold(Array2::zeros((self.nsta(), self.nsta())), |acc, (x, d)| {
435                    acc + &x * (*d + 0.0 * li)
436                });
437            (J, v)
438        } else {
439            if spin != 0 {
440                println!("Warning, the model haven't got spin, so the spin input will be ignord");
441            }
442
443            let J = J
444                .outer_iter()
445                .zip(dir_1.iter())
446                .fold(Array2::zeros((self.nsta(), self.nsta())), |acc, (x, d)| {
447                    acc + &x * (*d + 0.0 * li)
448                });
449            let v = v
450                .outer_iter()
451                .zip(dir_2.iter())
452                .fold(Array2::zeros((self.nsta(), self.nsta())), |acc, (x, d)| {
453                    acc + &x * (*d + 0.0 * li)
454                });
455            (J, v)
456        };
457
458        let evec_conj = evec.t();
459        let evec = evec.mapv(|x| x.conj());
460        let A1 = J.dot(&evec);
461        let A1 = &evec_conj.dot(&A1);
462        let A2 = v.dot(&evec);
463        let A2 = evec_conj.dot(&A2);
464        let A2 = A2.reversed_axes();
465        let AA = A1 * A2;
466        let Complex { re, im } = AA.view().split_complex();
467        let im = im.mapv(|x| -2.0 * x);
468        assert_eq!(
469            band.len(),
470            self.nsta(),
471            "this is strange for band's length is not equal to self.nsta()"
472        );
473        let mut UU = Array2::<f64>::zeros((self.nsta(), self.nsta()));
474        for i in 0..self.nsta() {
475            for j in 0..self.nsta() {
476                let a = band[[i]] - band[[j]];
477                //这里用η进行展宽
478                UU[[i, j]] = 1.0 / (a.powi(2) + eta.powi(2));
479                /*
480                if a.abs() < 1e-8 {
481                    UU[[i, j]] = 0.0;
482                } else {
483                    UU[[i, j]] = 1.0 / (a.powi(2)+eta.powi(2));
484                }
485                */
486            }
487        }
488        let omega_n = im
489            .outer_iter()
490            .zip(UU.outer_iter())
491            .map(|(a, b)| a.dot(&b))
492            .collect();
493        let omega_n = Array1::from_vec(omega_n);
494        (omega_n, band)
495    }
496
497    #[allow(non_snake_case)]
498    pub fn berry_curvature_onek<S: Data<Elem = f64>>(
499        &self,
500        k_vec: &ArrayBase<S, Ix1>,
501        dir_1: &Array1<f64>,
502        dir_2: &Array1<f64>,
503        mu: f64,
504        T: f64,
505        spin: usize,
506        eta: f64,
507    ) -> f64 {
508        //!给定一个 k 点, 指定 dir_1=$\alpha$, dir_2=$\beta$, T 代表温度, og= $\og$,
509        //!mu=$\mu$ 为费米能级, spin=0,1,2,3 为$\sg_0,\sg_x,\sg_y,\sg_z$,
510        //!当体系不存在自旋的时候无论如何输入spin都默认 spin=0
511        //!eta=$\eta$ 是一个小量
512        //! 这个函数返回的是
513        //! $$ \sum_n f_n\Omega_{n,\ap\bt}^\gm(\bm k)=\sum_n \f{1}{e^{(\ve_{n\bm k}-\mu)/T/k_B}+1} \sum_{m=\not n}\f{J_{\ap,nm}^\gm v_{\bt,mn}}{(\ve_{n\bm k}-\ve_{m\bm k})^2-(\og+i\eta)^2}$$
514        //! 其中 $J_\ap^\gm=\\{s_\gm,v_\ap\\}$
515        let (omega_n, band) = self.berry_curvature_n_onek(&k_vec, &dir_1, &dir_2, spin, eta);
516        let mut omega: f64 = 0.0;
517        let fermi_dirac = if T == 0.0 {
518            band.mapv(|x| if x > mu { 0.0 } else { 1.0 })
519        } else {
520            let beta = 1.0 / T / 8.617e-5;
521            band.mapv(|x| ((beta * (x - mu)).exp() + 1.0).recip())
522        };
523        let omega = omega_n.dot(&fermi_dirac);
524        omega
525    }
526    #[allow(non_snake_case)]
527    pub fn berry_curvature<S: Data<Elem = f64>>(
528        &self,
529        k_vec: &ArrayBase<S, Ix2>,
530        dir_1: &Array1<f64>,
531        dir_2: &Array1<f64>,
532        mu: f64,
533        T: f64,
534        spin: usize,
535        eta: f64,
536    ) -> Array1<f64> {
537        //!这个是用来并行计算大量k点的贝利曲率
538        //!这个可以用来画能带上的贝利曲率, 或者画一个贝利曲率的热图
539        if dir_1.len() != self.dim_r() || dir_2.len() != self.dim_r() {
540            panic!(
541                "Wrong, the dir_1 or dir_2 you input has wrong length, it must equal to dim_r={}, but you input {},{}",
542                self.dim_r(),
543                dir_1.len(),
544                dir_2.len()
545            )
546        }
547        let nk = k_vec.len_of(Axis(0));
548        let omega: Vec<f64> = k_vec
549            .axis_iter(Axis(0))
550            .into_par_iter()
551            .map(|x| {
552                let omega_one =
553                    self.berry_curvature_onek(&x.to_owned(), &dir_1, &dir_2, mu, T, spin, eta);
554                omega_one
555            })
556            .collect();
557        let omega = arr1(&omega);
558        omega
559    }
560    ///这个是计算某个费米能级, 某个温度下的Hall conductivity 的, 输出的单位为 $e^2/\hbar/\AA$.
561    #[allow(non_snake_case)]
562    pub fn Hall_conductivity(
563        &self,
564        k_mesh: &Array1<usize>,
565        dir_1: &Array1<f64>,
566        dir_2: &Array1<f64>,
567        mu: f64,
568        T: f64,
569        spin: usize,
570        eta: f64,
571    ) -> Result<f64> {
572        //!这个是用来计算霍尔电导的.
573        //!这里采用的是均匀撒点的方法, 利用 berry_curvature, 我们有
574        //!$$\sg_{\ap\bt}^\gm=\f{1}{N(2\pi)^r V}\sum_{\bm k} \Og_{\ap\bt}(\bm k),$$ 其中 $N$ 是 k 点数目,
575        let kvec: Array2<f64> = gen_kmesh(&k_mesh)?;
576        let nk: usize = kvec.len_of(Axis(0));
577        let omega = self.berry_curvature(&kvec, &dir_1, &dir_2, mu, T, spin, eta);
578        //目前求积分的方法上, 还是直接求和最有用, 其他的典型积分方法, 如gauss 法等,
579        //都因为存在间断点而效率不高.
580        //对于非零温的, 使用梯形法应该效果能好一些.
581        let conductivity: f64 = omega.sum() / (nk as f64) / self.lat.det().unwrap();
582        Ok(conductivity)
583    }
584    #[allow(non_snake_case)]
585    ///这个是采用自适应积分算法来计算霍尔电导的, 一般来说, 我们建议 re_err 设置为 1, 而 ab_err 设置为 0.01
586    pub fn Hall_conductivity_adapted(
587        &self,
588        k_mesh: &Array1<usize>,
589        dir_1: &Array1<f64>,
590        dir_2: &Array1<f64>,
591        mu: f64,
592        T: f64,
593        spin: usize,
594        eta: f64,
595        re_err: f64,
596        ab_err: f64,
597    ) -> Result<f64> {
598        let mut k_range = gen_krange(k_mesh)?; //将要计算的区域分成小块
599        let n_range = k_range.len_of(Axis(0));
600        let ab_err = ab_err / (n_range as f64);
601        let use_fn =
602            |k0: &Array1<f64>| self.berry_curvature_onek(k0, &dir_1, &dir_2, mu, T, spin, eta);
603        let inte = |k_range| adapted_integrate_quick(&use_fn, &k_range, re_err, ab_err);
604        let omega: Vec<f64> = k_range
605            .axis_iter(Axis(0))
606            .into_par_iter()
607            .map(|x| inte(x.to_owned()))
608            .collect();
609        let omega: Array1<f64> = arr1(&omega);
610        let conductivity: f64 = omega.sum() / self.lat.det().unwrap();
611        Ok(conductivity)
612    }
613    ///用来计算多个 $\mu$ 值的, 这个函数是先求出 $\Omega_n$, 然后再分别用不同的费米能级来求和, 这样速度更快, 因为避免了重复求解 $\Omega_n$, 但是相对来说更耗内存, 而且不能做到自适应积分算法.
614    pub fn Hall_conductivity_mu(
615        &self,
616        k_mesh: &Array1<usize>,
617        dir_1: &Array1<f64>,
618        dir_2: &Array1<f64>,
619        mu: &Array1<f64>,
620        T: f64,
621        spin: usize,
622        eta: f64,
623    ) -> Result<Array1<f64>> {
624        let kvec: Array2<f64> = gen_kmesh(&k_mesh)?;
625        let nk: usize = kvec.len_of(Axis(0));
626        let (omega_n, band): (Vec<_>, Vec<_>) = kvec
627            .axis_iter(Axis(0))
628            .into_par_iter()
629            .map(|x| {
630                let (omega_n, band) =
631                    self.berry_curvature_n_onek(&x.to_owned(), &dir_1, &dir_2, spin, eta);
632                (omega_n, band)
633            })
634            .collect();
635        let omega_n = Array2::<f64>::from_shape_vec(
636            (nk, self.nsta()),
637            omega_n.into_iter().flatten().collect(),
638        )
639        .unwrap();
640        let band =
641            Array2::<f64>::from_shape_vec((nk, self.nsta()), band.into_iter().flatten().collect())
642                .unwrap();
643        let n_mu: usize = mu.len();
644        let conductivity = if T == 0.0 {
645            let conductivity_new: Vec<f64> = mu
646                .into_par_iter()
647                .map(|x| {
648                    let mut omega = Array1::<f64>::zeros(nk);
649                    for k in 0..nk {
650                        for i in 0..self.nsta() {
651                            omega[[k]] += if band[[k, i]] > *x {
652                                0.0
653                            } else {
654                                omega_n[[k, i]]
655                            };
656                        }
657                    }
658                    omega.sum() / self.lat.det().unwrap() / (nk as f64)
659                })
660                .collect();
661            Array1::<f64>::from_vec(conductivity_new)
662        } else {
663            let beta = 1.0 / (T * 8.617e-5);
664            let conductivity_new: Vec<f64> = mu
665                .into_par_iter()
666                .map(|x| {
667                    let fermi_dirac = band.mapv(|x0| 1.0 / ((beta * (x0 - x)).exp() + 1.0));
668                    let omega: Vec<f64> = omega_n
669                        .axis_iter(Axis(0))
670                        .zip(fermi_dirac.axis_iter(Axis(0)))
671                        .map(|(a, b)| (&a * &b).sum())
672                        .collect();
673                    let omega: Array1<f64> = arr1(&omega);
674                    omega.sum() / self.lat.det().unwrap() / (nk as f64)
675                })
676                .collect();
677            Array1::<f64>::from_vec(conductivity_new)
678        };
679        Ok(conductivity)
680    }
681
682    pub fn berry_curvature_dipole_n_onek(
683        &self,
684        k_vec: &Array1<f64>,
685        dir_1: &Array1<f64>,
686        dir_2: &Array1<f64>,
687        dir_3: &Array1<f64>,
688        og: f64,
689        spin: usize,
690        eta: f64,
691    ) -> (Array1<f64>, Array1<f64>) {
692        //! 这个是用来计算 $$\pdv{\ve_{n\bm k}}{k_\gm}\Og_{n,\ap\bt}$$
693        //!
694        //!这里需要注意的一点是, 一般来说对于 $\p_\ap\ve_{\bm k}$, 需要用差分法来求解, 我这里提供了一个算法.
695        //!$$ \ve_{\bm k}=U^\dag H_{\bm k} U\Rightarrow \pdv{\ve_{\bm k}}{\bm k}=U^\dag\pdv{H_{\bm k}}{\bm k}U+\pdv{U^\dag}{\bm k} H_{\bm k}U+U^\dag H_{\bm k}\pdv{U}{\bm k}$$
696        //!因为 $U^\dag U=1\Rightarrow \p_{\bm k}U^\dag U=-U^\dag\p_{\bm k}U$, $\p_{\bm k}H_{\bm k}=v_{\bm k}$我们有
697        //!$$\pdv{\ve_{\bm k}}{\bm k}=v_{\bm k}+\lt[\ve_{\bm k},U^\dag\p_{\bm k}U\rt]$$
698        //!而这里面唯一比较难求的项是 $D_{\bm k}=U^\dag\p_{\bm k}U$. 按照 vanderbilt 2008 年的论文中的公式, 用微扰论有
699        //!$$D_{mn,\bm k}=\left\\{\\begin{aligned}\f{v_{mn,\bm k}}{\ve_n-\ve_m} \quad &\text{if}\\ m\\ =\not n\\\ 0 \quad \quad &\text{if}\\ m\\ = n\\end{aligned}\right\.$$
700        //!我们观察到第二项对对角部分没有贡献, 所以我们可以直接设置为
701        //!$$\pdv{\ve_{\bm k}}{\bm k}=\text{diag}\lt(v_{\bm k}\rt)$$
702        //我们首先求解 omega_n 和 U^\dag j
703
704        let li: Complex<f64> = 1.0 * Complex::i();
705        //let (band, evec) = self.solve_onek(&k_vec);
706        let (mut v, hamk): (Array3<Complex<f64>>, Array2<Complex<f64>>) =
707            self.gen_v(&k_vec, Gauge::Atom); //这是速度算符
708        let mut J: Array3<Complex<f64>> = v.clone();
709        let mut v0 = Array2::<Complex<f64>>::zeros((self.nsta(), self.nsta())); //这个是速度项, 对应的dir_3 的速度
710        for r in 0..self.dim_r() {
711            v0 = v0 + v.slice(s![r, .., ..]).to_owned() * dir_3[[r]];
712        }
713        if self.spin {
714            let mut X: Array2<Complex<f64>> = Array2::eye(self.nsta());
715            let pauli: Array2<Complex<f64>> = match spin {
716                0 => arr2(&[
717                    [1.0 + 0.0 * li, 0.0 + 0.0 * li],
718                    [0.0 + 0.0 * li, 1.0 + 0.0 * li],
719                ]),
720                1 => {
721                    arr2(&[
722                        [0.0 + 0.0 * li, 1.0 + 0.0 * li],
723                        [1.0 + 0.0 * li, 0.0 + 0.0 * li],
724                    ]) / 2.0
725                }
726                2 => {
727                    arr2(&[
728                        [0.0 + 0.0 * li, 0.0 - 1.0 * li],
729                        [0.0 + 1.0 * li, 0.0 + 0.0 * li],
730                    ]) / 2.0
731                }
732                3 => {
733                    arr2(&[
734                        [1.0 + 0.0 * li, 0.0 + 0.0 * li],
735                        [0.0 + 0.0 * li, -1.0 + 0.0 * li],
736                    ]) / 2.0
737                }
738                _ => panic!("Wrong, spin should be 0, 1, 2, 3, but you input {}", spin),
739            };
740            X = kron(&pauli, &Array2::eye(self.norb()));
741            for i in 0..self.dim_r() {
742                let j = J.slice(s![i, .., ..]).to_owned();
743                let j = anti_comm(&X, &j) / 2.0; //这里做反对易
744                J.slice_mut(s![i, .., ..]).assign(&(j * dir_1[[i]]));
745                v.slice_mut(s![i, .., ..])
746                    .mul_assign(Complex::new(dir_2[[i]], 0.0));
747            }
748        } else {
749            if spin != 0 {
750                println!("Warning, the model haven't got spin, so the spin input will be ignord");
751            }
752            for i in 0..self.dim_r() {
753                J.slice_mut(s![i, .., ..])
754                    .mul_assign(Complex::new(dir_1[[i]], 0.0));
755                v.slice_mut(s![i, .., ..])
756                    .mul_assign(Complex::new(dir_2[[i]], 0.0));
757            }
758        };
759
760        let J: Array2<Complex<f64>> = J.sum_axis(Axis(0));
761        let v: Array2<Complex<f64>> = v.sum_axis(Axis(0));
762
763        let (band, evec) = if let Ok((eigvals, eigvecs)) = hamk.eigh(UPLO::Lower) {
764            (eigvals, eigvecs)
765        } else {
766            todo!()
767        };
768        let evec_conj = evec.t();
769        let evec = evec.mapv(|x| x.conj());
770
771        let v0 = v0.dot(&evec.t());
772        let v0 = &evec_conj.dot(&v0);
773        let partial_ve = v0.diag().map(|x| x.re);
774        let A1 = J.dot(&evec.t());
775        let A1 = &evec_conj.dot(&A1);
776        let A2 = v.dot(&evec.t());
777        let A2 = &evec_conj.dot(&A2);
778        let mut U0 = Array2::<Complex<f64>>::zeros((self.nsta(), self.nsta()));
779        for i in 0..self.nsta() {
780            for j in 0..self.nsta() {
781                if i != j {
782                    U0[[i, j]] = 1.0 / ((band[[i]] - band[[j]]).powi(2) - (og + li * eta).powi(2));
783                } else {
784                    U0[[i, j]] = Complex::new(0.0, 0.0);
785                }
786            }
787        }
788        //let omega_n:Array1::<f64>=(-Complex::new(2.0,0.0)*(A1*U0).dot(&A2)).diag().map(|x| x.im).to_owned();
789        let mut omega_n = Array1::<f64>::zeros(self.nsta());
790        let A1 = A1 * U0;
791        for i in 0..self.nsta() {
792            omega_n[[i]] = -2.0 * A1.slice(s![i, ..]).dot(&A2.slice(s![.., i])).im;
793        }
794
795        //let (omega_n,band)=self.berry_curvature_n_onek(&k_vec,&dir_1,&dir_2,og,spin,eta);
796        let omega_n: Array1<f64> = omega_n * partial_ve;
797        (omega_n, band) //最后得到的 D
798    }
799    pub fn berry_curvature_dipole_n(
800        &self,
801        k_vec: &Array2<f64>,
802        dir_1: &Array1<f64>,
803        dir_2: &Array1<f64>,
804        dir_3: &Array1<f64>,
805        og: f64,
806        spin: usize,
807        eta: f64,
808    ) -> (Array2<f64>, Array2<f64>) {
809        //这个是在 onek的基础上进行并行计算得到一系列k点的berry curvature dipole
810        //!This function performs parallel computation based on the onek function to obtain a series of Berry curvature dipoles at different k-points.
811        //!这个方法用的是对费米分布的修正, 因为高阶的dipole 修正导致的非线性霍尔电导为 $$\sg_{\ap\bt\gm}=\tau\int\dd\bm k\sum_n\p_\gm\ve_{n\bm k}\Og_{n,\ap\bt}\lt\.\pdv{f_{\bm k}}{\ve}\rt\rvert_{E=\ve_{n\bm k}}.$$ 所以我们这里输出的是
812        //!$$\p_\gm\ve_{n\bm k}\Og_{n,\ap\bt}.$$
813        if dir_1.len() != self.dim_r() || dir_2.len() != self.dim_r() || dir_3.len() != self.dim_r()
814        {
815            panic!(
816                "Wrong, the dir_1 or dir_2 you input has wrong length, it must equal to dim_r={}, but you input {},{}",
817                self.dim_r(),
818                dir_1.len(),
819                dir_2.len()
820            )
821        }
822        let nk = k_vec.len_of(Axis(0));
823        let (omega, band): (Vec<_>, Vec<_>) = k_vec
824            .axis_iter(Axis(0))
825            .into_par_iter()
826            .map(|x| {
827                let (omega_one, band) = self.berry_curvature_dipole_n_onek(
828                    &x.to_owned(),
829                    &dir_1,
830                    &dir_2,
831                    &dir_3,
832                    og,
833                    spin,
834                    eta,
835                );
836                (omega_one, band)
837            })
838            .collect();
839        let omega =
840            Array2::<f64>::from_shape_vec((nk, self.nsta()), omega.into_iter().flatten().collect())
841                .unwrap();
842        let band =
843            Array2::<f64>::from_shape_vec((nk, self.nsta()), band.into_iter().flatten().collect())
844                .unwrap();
845        (omega, band)
846    }
847    pub fn Nonlinear_Hall_conductivity_Extrinsic(
848        &self,
849        k_mesh: &Array1<usize>,
850        dir_1: &Array1<f64>,
851        dir_2: &Array1<f64>,
852        dir_3: &Array1<f64>,
853        mu: &Array1<f64>,
854        T: f64,
855        og: f64,
856        spin: usize,
857        eta: f64,
858    ) -> Result<Array1<f64>> {
859        //这个是用 berry curvature dipole 对整个布里渊去做积分得到非线性霍尔电导, 是extrinsic 的
860        //!This function calculates the extrinsic nonlinear Hall conductivity by integrating the Berry curvature dipole over the entire Brillouin zone. The Berry curvature dipole is first computed at a series of k-points using parallel computation based on the onek function.
861
862        //! 我们基于 berry_curvature_n_dipole 来并行得到所有 k 点的 $\p_\gm\ve_{n\bm k}\Og_{n,\ap\bt}$,
863        //! 但是我们最后的公式为
864        //! $$\\mathcal D_{\ap\bt\gm}=\int \dd\bm k \sum_n\lt(-\pdv{f_{n}}{\ve}\rt)\p_\gm\ve_{n\bm k}\Og_{n,\ap\bt}$$
865        //! 然而,
866        //! $$-\pdv{f_{n}}{\ve}=\beta\f{e^{beta(\ve_n-\mu)}}{(e^{beta(\ve_n-\mu)}+1)^2}=\beta f_n(1-f_n)$$
867        //! 对于 T=0 的情况, 我们将采用四面体积分来替代, 这个需要很高的k点密度, 不建议使用
868        //! 对于 T!=0 的情况, 我们会采用类似 Dos 的方法来计算
869
870        if dir_1.len() != self.dim_r() || dir_2.len() != self.dim_r() || dir_3.len() != self.dim_r()
871        {
872            panic!(
873                "Wrong, the dir_1 or dir_2 you input has wrong length, it must equal to dim_r={}, but you input {},{}",
874                self.dim_r(),
875                dir_1.len(),
876                dir_2.len()
877            )
878        }
879        let kvec: Array2<f64> = gen_kmesh(&k_mesh)?;
880        let nk: usize = kvec.len_of(Axis(0));
881        //为了节省内存, 本来是可以直接算完求和, 但是为了方便, 我是先存下来再算, 让程序结构更合理
882        let (omega, band) =
883            self.berry_curvature_dipole_n(&kvec, &dir_1, &dir_2, &dir_3, og, spin, eta);
884        let omega = omega.into_raw_vec();
885        let band = band.into_raw_vec();
886        let n_e = mu.len();
887        let mut conductivity = Array1::<f64>::zeros(n_e);
888        if T != 0.0 {
889            let beta = 1.0 / T / (8.617e-5);
890            let use_iter = band.iter().zip(omega.iter()).par_bridge();
891            conductivity = use_iter
892                .fold(
893                    || Array1::<f64>::zeros(n_e),
894                    |acc, (energy, omega0)| {
895                        let f = 1.0 / (beta * (mu - *energy)).mapv(|x| x.exp() + 1.0);
896                        acc + &f * (1.0 - &f) * beta * *omega0
897                    },
898                )
899                .reduce(|| Array1::<f64>::zeros(n_e), |acc, x| acc + x);
900            conductivity = conductivity.clone() / (nk as f64) / self.lat.det().unwrap();
901        } else {
902            //采用四面体积分法, 或者对于二维体系, 采用三角形积分法
903            //积分的思路是, 通过将一个六面体变成5个四面体, 然后用线性插值的方法, 得到费米面,
904            //以及费米面上的数, 最后, 通过积分算出来结果
905            panic!("When T=0, the algorithm have not been writed, please wait for next version");
906        }
907        Ok(conductivity)
908    }
909
910    pub fn berry_connection_dipole_onek(
911        &self,
912        k_vec: &Array1<f64>,
913        dir_1: &Array1<f64>,
914        dir_2: &Array1<f64>,
915        dir_3: &Array1<f64>,
916        spin: usize,
917    ) -> (Array1<f64>, Array1<f64>, Option<Array1<f64>>) {
918        //!这个是根据 Nonlinear_Hall_conductivity_intrinsic 的注释, 当不存在自旋的时候提供
919        //!$$v_\ap G_{\bt\gm}-v_\bt G_{\ap\gm}$$
920        //!其中 $$ G_{ij}=-2\text{Re}\sum_{m=\not n}\f{v_{i,nm}v_{j,mn}}{\lt(\ve_n-\ve_m\rt)^3} $$
921        //!如果存在自旋, 即spin不等于0, 则还存在 $\p_{h_i} G_{jk}$ 项, 具体请看下面的非线性霍尔部分
922        //!我们这里暂时不考虑磁场, 只考虑电场
923        let (mut v, hamk): (Array3<Complex<f64>>, Array2<Complex<f64>>) =
924            self.gen_v(&k_vec, Gauge::Atom); //这是速度算符
925        let mut J = v.clone();
926        //let (band, evec) = self.solve_onek(&k_vec); //能带和本征值
927        let (band, evec) = if let Ok((eigvals, eigvecs)) = hamk.eigh(UPLO::Lower) {
928            (eigvals, eigvecs)
929        } else {
930            todo!()
931        };
932        let evec_conj = evec.t();
933        let evec = evec.mapv(|x| x.conj());
934        for i in 0..self.dim_r() {
935            let v_s = v.slice(s![i, .., ..]).to_owned();
936            let v_s = evec_conj
937                .clone()
938                .dot(&(v_s.dot(&evec.clone().reversed_axes()))); //变换到本征态基函数
939            v.slice_mut(s![i, .., ..]).assign(&v_s); //将 v 变换到以本征态为基底
940        }
941        //现在速度算符已经是以本征态为基函数
942        let mut v_1 = Array2::<Complex<f64>>::zeros((self.nsta(), self.nsta())); //三个方向的速度算符
943        let mut v_2 = Array2::<Complex<f64>>::zeros((self.nsta(), self.nsta()));
944        let mut v_3 = Array2::<Complex<f64>>::zeros((self.nsta(), self.nsta()));
945        for i in 0..self.dim_r() {
946            v_1 = v_1.clone() + v.slice(s![i, .., ..]).to_owned() * Complex::new(dir_1[[i]], 0.0);
947            v_2 = v_2.clone() + v.slice(s![i, .., ..]).to_owned() * Complex::new(dir_2[[i]], 0.0);
948            v_3 = v_3.clone() + v.slice(s![i, .., ..]).to_owned() * Complex::new(dir_3[[i]], 0.0);
949        }
950        //三个方向的速度算符都得到了
951        let mut U0 = Array2::<f64>::zeros((self.nsta(), self.nsta()));
952        for i in 0..self.nsta() {
953            for j in 0..self.nsta() {
954                if (band[[i]] - band[[j]]).abs() < 1e-5 {
955                    U0[[i, j]] = 0.0;
956                } else {
957                    U0[[i, j]] = 1.0 / (band[[i]] - band[[j]]);
958                }
959            }
960        }
961        //这样U0[[i,j]]=1/(E_i-E_j), 这样就可以省略判断, 减少计算量
962
963        //开始计算能带的导数, 详细的公式请看 berry_curvature_dipole_onek 的公式
964        //其实就是速度算符的对角项
965        //开始计算速度的偏导项, 这里偏导来自实空间
966        let partial_ve_1 = v_1.diag().map(|x| x.re);
967        let partial_ve_2 = v_2.diag().map(|x| x.re);
968        let partial_ve_3 = v_3.diag().map(|x| x.re);
969
970        //开始最后的计算
971        if self.spin {
972            //如果考虑自旋, 我们就计算 \partial_h G_{ij}
973            let mut S: Array2<Complex<f64>> = Array2::eye(self.nsta());
974            let li = Complex::<f64>::new(0.0, 1.0);
975            let pauli: Array2<Complex<f64>> = match spin {
976                0 => Array2::<Complex<f64>>::eye(2),
977                1 => {
978                    arr2(&[
979                        [0.0 + 0.0 * li, 1.0 + 0.0 * li],
980                        [1.0 + 0.0 * li, 0.0 + 0.0 * li],
981                    ]) / 2.0
982                }
983                2 => {
984                    arr2(&[
985                        [0.0 + 0.0 * li, 0.0 - 1.0 * li],
986                        [0.0 + 1.0 * li, 0.0 + 0.0 * li],
987                    ]) / 2.0
988                }
989                3 => {
990                    arr2(&[
991                        [1.0 + 0.0 * li, 0.0 + 0.0 * li],
992                        [0.0 + 0.0 * li, -1.0 + 0.0 * li],
993                    ]) / 2.0
994                }
995                _ => panic!("Wrong, spin should be 0, 1, 2, 3, but you input {}", spin),
996            };
997            let X = kron(&pauli, &Array2::eye(self.norb()));
998            let mut S = Array3::<Complex<f64>>::zeros((self.dim_r(), self.nsta(), self.nsta()));
999            for i in 0..self.dim_r() {
1000                let v0 = J.slice(s![i, .., ..]).to_owned();
1001                let v0 = anti_comm(&X, &v0) / 2.0;
1002                let v0 = evec_conj
1003                    .clone()
1004                    .dot(&(v0.dot(&evec.clone().reversed_axes()))); //变换到本征态基函数
1005                S.slice_mut(s![i, .., ..]).assign(&v0);
1006            }
1007            let mut s_1 = Array2::<Complex<f64>>::zeros((self.nsta(), self.nsta())); //三个方向的速度算符
1008            let mut s_2 = Array2::<Complex<f64>>::zeros((self.nsta(), self.nsta()));
1009            let mut s_3 = Array2::<Complex<f64>>::zeros((self.nsta(), self.nsta()));
1010            for i in 0..self.dim_r() {
1011                s_1 =
1012                    s_1.clone() + S.slice(s![i, .., ..]).to_owned() * Complex::new(dir_1[[i]], 0.0);
1013                s_2 =
1014                    s_2.clone() + S.slice(s![i, .., ..]).to_owned() * Complex::new(dir_2[[i]], 0.0);
1015                s_3 =
1016                    s_3.clone() + S.slice(s![i, .., ..]).to_owned() * Complex::new(dir_3[[i]], 0.0);
1017            }
1018            let G_23: Array1<f64> = {
1019                //用来计算  beta gamma 的 G
1020                let A = &v_2 * (U0.map(|x| Complex::<f64>::new(x.powi(3), 0.0)));
1021                let mut G = Array1::<f64>::zeros(self.nsta());
1022                for i in 0..self.nsta() {
1023                    G[[i]] = A.slice(s![i, ..]).dot(&v_3.slice(s![.., i])).re * 2.0
1024                }
1025                G
1026            };
1027            let G_13_h: Array1<f64> = {
1028                //用来计算 alpha gamma 的 G
1029                let A = &s_1 * (U0.map(|x| Complex::<f64>::new(x.powi(3), 0.0)));
1030                let mut G = Array1::<f64>::zeros(self.nsta());
1031                for i in 0..self.nsta() {
1032                    G[[i]] = A.slice(s![i, ..]).dot(&v_3.slice(s![.., i])).re * 2.0
1033                }
1034                G
1035            };
1036            //开始计算partial_s
1037            let partial_s_1 = s_1.clone().diag().map(|x| x.re);
1038            let partial_s_2 = s_2.clone().diag().map(|x| x.re);
1039            let partial_s_3 = s_3.clone().diag().map(|x| x.re);
1040            let mut partial_s = Array2::<f64>::zeros((self.dim_r(), self.nsta()));
1041            for r in 0..self.dim_r() {
1042                let s0 = S.slice(s![r, .., ..]).to_owned();
1043                partial_s
1044                    .slice_mut(s![r, ..])
1045                    .assign(&s0.diag().map(|x| x.re)); //\p_i s算符的对角项
1046            }
1047            //开始计算partial G
1048            let partial_G: Array1<f64> = {
1049                let mut A = Array1::<Complex<f64>>::zeros(self.nsta()); //第一项
1050                for i in 0..self.nsta() {
1051                    for j in 0..self.nsta() {
1052                        A[[i]] += 3.0
1053                            * (partial_s_1[[i]] - partial_s_1[[j]])
1054                            * v_2[[i, j]]
1055                            * v_3[[j, i]]
1056                            * U0[[i, j]].powi(4);
1057                    }
1058                }
1059                let mut B = Array1::<Complex<f64>>::zeros(self.nsta()); //第二项
1060                for n in 0..self.nsta() {
1061                    for n1 in 0..self.nsta() {
1062                        for n2 in 0..self.nsta() {
1063                            B[[n]] += s_1[[n, n2]]
1064                                * (v_2[[n2, n1]] * v_3[[n1, n]] + v_3[[n2, n1]] * v_2[[n1, n]])
1065                                * U0[[n, n1]].powi(3)
1066                                * U0[[n, n2]];
1067                        }
1068                    }
1069                }
1070                let mut C = Array1::<Complex<f64>>::zeros(self.nsta()); //第三项
1071                for n in 0..self.nsta() {
1072                    for n1 in 0..self.nsta() {
1073                        for n2 in 0..self.nsta() {
1074                            C[[n]] += s_1[[n1, n2]]
1075                                * (v_2[[n2, n]] * v_3[[n, n1]] + v_3[[n2, n]] * v_2[[n, n1]])
1076                                * U0[[n, n1]].powi(3)
1077                                * U0[[n1, n2]];
1078                        }
1079                    }
1080                }
1081                2.0 * (A - B - C).map(|x| x.re)
1082            };
1083            //计算结束
1084            //开始最后的输出
1085            return (
1086                (partial_s_1 * G_23 - partial_ve_2 * G_13_h),
1087                band,
1088                Some(partial_G),
1089            );
1090        } else {
1091            //开始计算 G_{ij}
1092            //G_{ij}=2Re\sum_{m\neq n} v_{i,nm}v_{j,mn}/(E_n-E_m)^3
1093            let G_23: Array1<f64> = {
1094                //用来计算  beta gamma 的 G
1095                let A = &v_2 * (U0.map(|x| Complex::<f64>::new(x.powi(3), 0.0)));
1096                let mut G = Array1::<f64>::zeros(self.nsta());
1097                for i in 0..self.nsta() {
1098                    G[[i]] = A.slice(s![i, ..]).dot(&v_3.slice(s![.., i])).re * 2.0
1099                }
1100                G
1101            };
1102            let G_13: Array1<f64> = {
1103                //用来计算 alpha gamma 的 G
1104                let A = &v_1 * (U0.map(|x| Complex::<f64>::new(x.powi(3), 0.0)));
1105                let mut G = Array1::<f64>::zeros(self.nsta());
1106                for i in 0..self.nsta() {
1107                    G[[i]] = A.slice(s![i, ..]).dot(&v_3.slice(s![.., i])).re * 2.0
1108                }
1109                G
1110            };
1111            return (partial_ve_1 * G_23 - partial_ve_2 * G_13, band, None);
1112        }
1113    }
1114    pub fn berry_connection_dipole(
1115        &self,
1116        k_vec: &Array2<f64>,
1117        dir_1: &Array1<f64>,
1118        dir_2: &Array1<f64>,
1119        dir_3: &Array1<f64>,
1120        spin: usize,
1121    ) -> (Array2<f64>, Array2<f64>, Option<Array2<f64>>) {
1122        //! 这个是基于 onek 的, 进行关于 k 点并行求解
1123        if dir_1.len() != self.dim_r() || dir_2.len() != self.dim_r() || dir_3.len() != self.dim_r()
1124        {
1125            panic!(
1126                "Wrong, the dir_1 or dir_2 you input has wrong length, it must equal to dim_r={}, but you input {},{}",
1127                self.dim_r(),
1128                dir_1.len(),
1129                dir_2.len()
1130            )
1131        }
1132        let nk = k_vec.len_of(Axis(0));
1133
1134        if self.spin {
1135            let ((omega, band), partial_G): ((Vec<_>, Vec<_>), Vec<_>) = k_vec
1136                .axis_iter(Axis(0))
1137                .into_par_iter()
1138                .map(|x| {
1139                    let (omega_one, band, partial_G) = self.berry_connection_dipole_onek(
1140                        &x.to_owned(),
1141                        &dir_1,
1142                        &dir_2,
1143                        &dir_3,
1144                        spin,
1145                    );
1146                    let partial_G = partial_G.unwrap();
1147                    ((omega_one, band), partial_G)
1148                })
1149                .collect();
1150
1151            let omega = Array2::<f64>::from_shape_vec(
1152                (nk, self.nsta()),
1153                omega.into_iter().flatten().collect(),
1154            )
1155            .unwrap();
1156            let band = Array2::<f64>::from_shape_vec(
1157                (nk, self.nsta()),
1158                band.into_iter().flatten().collect(),
1159            )
1160            .unwrap();
1161            let partial_G = Array2::<f64>::from_shape_vec(
1162                (nk, self.nsta()),
1163                partial_G.into_iter().flatten().collect(),
1164            )
1165            .unwrap();
1166
1167            return (omega, band, Some(partial_G));
1168        } else {
1169            let (omega, band): (Vec<_>, Vec<_>) = k_vec
1170                .axis_iter(Axis(0))
1171                .into_par_iter()
1172                .map(|x| {
1173                    let (omega_one, band, partial_G) = self.berry_connection_dipole_onek(
1174                        &x.to_owned(),
1175                        &dir_1,
1176                        &dir_2,
1177                        &dir_3,
1178                        spin,
1179                    );
1180                    (omega_one, band)
1181                })
1182                .collect();
1183            let omega = Array2::<f64>::from_shape_vec(
1184                (nk, self.nsta()),
1185                omega.into_iter().flatten().collect(),
1186            )
1187            .unwrap();
1188            let band = Array2::<f64>::from_shape_vec(
1189                (nk, self.nsta()),
1190                band.into_iter().flatten().collect(),
1191            )
1192            .unwrap();
1193            return (omega, band, None);
1194        }
1195    }
1196    pub fn Nonlinear_Hall_conductivity_Intrinsic(
1197        &self,
1198        k_mesh: &Array1<usize>,
1199        dir_1: &Array1<f64>,
1200        dir_2: &Array1<f64>,
1201        dir_3: &Array1<f64>,
1202        mu: &Array1<f64>,
1203        T: f64,
1204        spin: usize,
1205    ) -> Result<Array1<f64>> {
1206        //! The Intrinsic Nonlinear Hall Conductivity arises from the correction of the Berry connection by the electric and magnetic fields [PRL 112, 166601 (2014)]. The formula employed is:
1207        //!$$\tilde\bm\Og_{\bm k}=\nb_{\bm k}\times\lt(\bm A_{\bm k}+\bm A_{\bm k}^\prime\rt)$$
1208        //!and the $\bm A_{i,\bm k}^\prime=F_{ij}B_j+G_{ij}E_j$, where
1209        //!$$
1210        //!\\begin{aligned}
1211        //!F_{ij}&=\text{Im}\sum_{m=\not n}\f{v_{i,nm}\og_{j,mn}}{\lt(\ve_{n}-\ve_m\rt)^2}\\\\
1212        //!G_{ij}&=2\text{Re}\sum_{m=\not n}\f{v_{i,nm}v_{j,mn}}{\lt(\ve_n-\ve_m\rt)^3}\\\\
1213        //!\og_{\ap,mn}&=-i\ep_{\ap\bt\gm}\sum_{l=\not n}\f{\lt(v_{\bt,ml}+\p_\bt \ve_{\bm k}\dt_{ml}\rt)v_{\gm,ln}}{\ve_l-\ve_n}
1214        //!\\end{aligned}
1215        //!$$
1216        //!最后我们有
1217        //!$$
1218        //!\bm j^\prime=\bm E\times\int\f{\dd\bm k}{(2\pi)^3}\lt[\p_{\bm k}\ve_{\bm k}\times\bm A^\prime+\bm\Og\lt(\bm B\cdot\bm m\rt)\rt]\pdv{f_{\bm k}}{\ve}
1219        //!$$
1220        //!对其对电场和磁场进行偏导, 有
1221        //!$$
1222        //!\\begin{aligned}
1223        //!\f{\p^2 j_{\ap}^\prime}{\p E_\bt\p E_\gm}&=\int\f{\dd\bm k}{(2\pi)^3}\lt(\p_\ap\ve_{\bm k} G_{\bt\gm}-\p_\bt\ve_{\bm k} G_{\ap\gm}\rt)\pdv{f_{\bm k}}{\ve}\\\\
1224        //!\f{\p^2 j_{\ap}^\prime}{\p E_\bt\p B_\gm}&=\int\f{\dd\bm k}{(2\pi)^3}\lt(\p_\ap\ve_{\bm k} F_{\bt\gm}-\p_\bt\ve_{\bm k} F_{\ap\gm}+\ep_{\ap\bt\ell}\Og_{\ell} m_\gm\rt)\pdv{f_{\bm k}}{\ve}
1225        //!\\end{aligned}
1226        //!$$
1227        //!由于存在 $\pdv{f_{\bm k}}{\ve}$, 不建议将温度 T=0
1228        //!
1229        //!可以考虑当 T=0 时候, 利用高斯公式, 将费米面内的部分进行积分, 得到精确解. 但是我现在还没办法很好的求解费米面, 所以暂时不考虑这个算法.而且对于二维体系, 公式还不一样, 还得分步讨论, 后面有时间再考虑这个程序.
1230        //!
1231        //!对于自旋霍尔效应, 按照文章 [PRL 112, 166601 (2014)], 非线性自旋霍尔电导为
1232        //!$$\sg_{\ap\bt\gm}^i=-\int\dd\bm k \lt[\f{1}{2}f_{\bm k}\pdv{G_{\bt\gm}}{h_\ap}+\pdv{f_{\bm k}}{\ve}\lt(\p_{\ap}s_{\bm k}^i G_{\bt\gm}-\p_\bt\ve_{\bm k}G_{\ap\gm}^h\rt)\rt]$$
1233        //!其中
1234        //!$$\f{\p G_{\bt\gm,n}}{\p h_\ap}=2\text{Re}\sum_{n^\pr =\not n}\f{3\lt(s^i_{\ap,n}-s^i_{\ap,n_1}\rt)v_{\bt,nn_1} v_{\gm,n^\pr n}}{\lt(\ve_n-\ve_{n^\pr}\rt)^4}-2\text{Re}\sum_{n_1=\not n}\sum_{n_2=\not n}\lt[\f{s^i_{\ap,nn_2} v_{\bt,n_2n_1} v_{\gm,n_1 n}}{\lt(\ve_n-\ve_{n_1}\rt)^3(\ve_n-\ve_{n_2})}+(\bt \leftrightarrow \gm)\rt]-2\text{Re}\sum_{n_1=\not n}\sum_{n_2=\not n_1}\lt[\f{s^i_{\ap,n_1n_2} v_{\bt,n_2n} v_{\gm,n n_1}}{\lt(\ve_n-\ve_{n_1}\rt)^3(\ve_{n_1}-\ve_{n_2})}+(\bt \leftrightarrow \gm)\rt]$$
1235        //!以及
1236        //!$$
1237        //!\lt\\\{\\begin{aligned}
1238        //!G_{\ap\bt}&=2\text{Re}\sum_{m=\not n}\f{v_{\ap,nm}v_{\bt,mn}}{\lt(\ve_n-\ve_m\rt)^3}\\\\
1239        //!G_{\ap\bt}^h&=2\text{Re}\sum_{m=\not n}\f{s^i_{\ap,nm}v_{\bt,mn}}{\lt(\ve_n-\ve_m\rt)^3}\\\\
1240        //!\\end{aligned}\rt\.
1241        //!$$
1242        //!
1243        //!这里 $s^i_{\ap,mn}$ 的具体形式, 原文中没有明确给出, 但是我根据霍尔效应的类比, 我猜是
1244        //!$\\\{\hat s^i,v_\ap\\\}$
1245
1246        let kvec: Array2<f64> = gen_kmesh(&k_mesh)?;
1247        let nk: usize = kvec.len_of(Axis(0));
1248        let (omega, band, mut partial_G): (Array2<f64>, Array2<f64>, Option<Array2<f64>>) =
1249            self.berry_connection_dipole(&kvec, &dir_1, &dir_2, &dir_3, spin);
1250        let omega = omega.into_raw_vec();
1251        let omega = Array1::from(omega);
1252        let band0 = band.clone();
1253        let band = band.into_raw_vec();
1254        let band = Array1::from(band);
1255        let n_e = mu.len();
1256        let mut conductivity = Array1::<f64>::zeros(n_e);
1257        if T != 0.0 {
1258            let beta = 1.0 / T / 8.617e-5;
1259            let use_iter = band.iter().zip(omega.iter()).par_bridge();
1260            conductivity = use_iter
1261                .fold(
1262                    || Array1::<f64>::zeros(n_e),
1263                    |acc, (energy, omega0)| {
1264                        let f = 1.0 / ((beta * (mu - *energy)).mapv(|x| x.exp() + 1.0));
1265                        acc + &f * (1.0 - &f) * beta * *omega0
1266                    },
1267                )
1268                .reduce(|| Array1::<f64>::zeros(n_e), |acc, x| acc + x);
1269            if self.spin {
1270                let partial_G = partial_G.unwrap();
1271                let conductivity_new: Vec<f64> = mu
1272                    .into_par_iter()
1273                    .map(|x| {
1274                        let f = band0.map(|x0| 1.0 / ((beta * (x - x0)).exp() + 1.0));
1275                        let mut omega = Array1::<f64>::zeros(nk);
1276                        for i in 0..nk {
1277                            omega[[i]] = (partial_G.row(i).to_owned() * f.row(i).to_owned()).sum();
1278                        }
1279                        omega.sum() / 2.0
1280                    })
1281                    .collect();
1282                let conductivity_new = Array1::<f64>::from_vec(conductivity_new);
1283                conductivity = conductivity.clone() + conductivity_new;
1284            }
1285            conductivity = conductivity.clone() / (nk as f64) / self.lat.det().unwrap();
1286        } else {
1287            //采用四面体积分法, 或者对于二维体系, 采用三角形积分法
1288            //积分的思路是, 通过将一个六面体变成5个四面体, 然后用线性插值的方法, 得到费米面,
1289            //以及费米面上的数, 最后, 通过积分算出来结果
1290            panic!("the code can not support for T=0");
1291        }
1292        Ok(conductivity)
1293    }
1294}
1295impl Model {
1296    //! This module calculates the orbital Hall conductivity
1297    //!
1298    //! The calculation using the orbial magnetism , refer to PHYSICAL REVIEW B 106, 104414 (2022).
1299    //!
1300    pub fn orbital_angular_momentum_onek(&self, kvec: &Array1<f64>) -> Array3<Complex<f64>> {
1301        //! 这个函数是用来计算单个 k 点的轨道角动量的
1302        //! 轨道角动量的定义为 $$\bra{u_{m\bm k}}\bm L\ket{u_{n\bm k}}=\frac{1}{4i
1303        //! g_L\mu_B}\sum_{\ell=\not m,n}\f{2\ve_{\ell\bm k}-\ve_{m\bm k}-\ve_{n\bm k}}{(\ve_{m\bm
1304        //! k}-\ve_{\ell\bm k})(\ve_{n\bm k}-\ve_{\ell\bm k})}\bra{u_{m\bm k}}\p_{\bm k} H_{\bm k}\ket{u_{\ell\bm k}}\times\bra{u_{\ell\bm k}}\p_{\bm k} H_{\bm k}\ket{u_{n\bm k}}$$
1305
1306        let li = Complex::<f64>::new(0.0, 1.0);
1307        let (v, hamk) = self.gen_v(kvec, Gauge::Atom);
1308        let (band, evec) = if let Ok((eigvals, eigvecs)) = hamk.eigh(UPLO::Lower) {
1309            (eigvals, eigvecs)
1310        } else {
1311            todo!()
1312        };
1313        let mut L = Array3::zeros((self.dim_r(), self.nsta(), self.nsta()));
1314        // m,n,l
1315        let mut U = Array3::zeros((self.nsta(), self.nsta(), self.nsta()));
1316        for (i, e1) in evec.iter().enumerate() {
1317            for (j, e2) in evec.iter().enumerate() {
1318                for (k, e3) in evec.iter().enumerate() {
1319                    U[[i, j, k]] = (2.0 * e3 - e1 - e2) / (e1 - e3) / (e2 - e3);
1320                }
1321            }
1322        }
1323        //g_L 是朗德g因子, 这个朗德g因子也是随着轨道而变化的
1324        let g_L = 1.0;
1325        for r in 0..self.dim_r() {
1326            for i in 0..self.nsta() {
1327                for j in 0..self.nsta() {
1328                    L[[r, i, j]] = -li / 4.0 / g_L / mu_B;
1329                }
1330            }
1331        }
1332        L
1333    }
1334}
1335
1336impl Model {
1337    //! This module calculates the optical conductivity
1338    //! The adopted definition is
1339    //! $$\sigma_{\ap\bt}=\f{2ie^2\hbar}{V}\sum_{\bm k}\sum_{n} f_n (g_{n,\ap\bt}+\f{i}{2}\Og_{n,\ap\bt})$$
1340    //!
1341    //! Where
1342    //! $$\\begin{aligned}
1343    //! g_{n\ap\bt}&=\sum_{m=\not n}\f{\og-i\eta}{\ve_{n\bm k}-\ve_{m\bm k}}\f{\text{Re} \bra{\psi_{n\bm k}}\p_\ap H\ket{\psi_{m\bm k}}\bra{\psi_{m\bm k}}\p_\bt H\ket{\psi_{n\bm k}}}{(\ve_{n\bm k}-\ve_{m\bm k})^2-(\og-i\eta)^2}\\\\
1344    //! \Og_{n\ap\bt}&=\sum_{m=\not n}\f{\text{Re} \bra{\psi_{n\bm k}}\p_\ap H\ket{\psi_{m\bm k}}\bra{\psi_{m\bm k}}\p_\bt H\ket{\psi_{n\bm k}}}{(\ve_{n\bm k}-\ve_{m\bm k})^2-(\og-i\eta)^2}
1345    //! \\end{aligned}
1346    //! $$
1347
1348    #[inline(always)]
1349    pub fn optical_geometry_n_onek<S: Data<Elem = f64>>(
1350        &self,
1351        k_vec: &ArrayBase<S, Ix1>,
1352        dir_1: &Array1<f64>,
1353        dir_2: &Array1<f64>,
1354        og: &Array1<f64>,
1355        eta: f64,
1356    ) -> (Array2<Complex<f64>>, Array2<Complex<f64>>, Array1<f64>) {
1357        //! This function calculates $g_{n,\ap\bt}$ and $\og_{n\ap\bt}$
1358        //!
1359        //! `og` represents the frequency
1360        //!
1361        //! `eta` is a small quantity
1362
1363        let li: Complex<f64> = 1.0 * Complex::i();
1364        //let (band, evec) = self.solve_onek(&k_vec);
1365
1366        let (mut v, hamk): (Array3<Complex<f64>>, Array2<Complex<f64>>) =
1367            self.gen_v(&k_vec, Gauge::Atom); //这是速度算符
1368        let mut J = v.view();
1369
1370        // Project the velocity operator onto the direction dir_1
1371        let J = J
1372            .outer_iter()
1373            .zip(dir_1.iter())
1374            .fold(Array2::zeros((self.nsta(), self.nsta())), |acc, (x, d)| {
1375                acc + &x * (*d + 0.0 * li)
1376            });
1377
1378        // Project the velocity operator onto the direction dir_2
1379        let v = v
1380            .outer_iter()
1381            .zip(dir_2.iter())
1382            .fold(Array2::zeros((self.nsta(), self.nsta())), |acc, (x, d)| {
1383                acc + &x * (*d + 0.0 * li)
1384            });
1385
1386        let (band, evec) = if let Ok((eigvals, eigvecs)) = hamk.eigh(UPLO::Lower) {
1387            (eigvals, eigvecs)
1388        } else {
1389            todo!()
1390        };
1391        let evec_conj = evec.t();
1392        let evec = evec.mapv(|x| x.conj());
1393
1394        let A1 = J.dot(&evec);
1395        let A1 = &evec_conj.dot(&A1);
1396        let A2 = v.dot(&evec);
1397        let A2 = evec_conj.dot(&A2);
1398        let A2 = A2.reversed_axes();
1399        let AA = A1 * A2;
1400
1401        let Complex { re, im } = AA.view().split_complex();
1402        let re = re.mapv(|x| Complex::new(2.0 * x, 0.0));
1403        let im = im.mapv(|x| Complex::new(0.0, -2.0 * x));
1404
1405        let n_og = og.len();
1406        assert_eq!(
1407            band.len(),
1408            self.nsta(),
1409            "this is strange for band's length is not equal to self.nsta()"
1410        );
1411
1412        let mut U0 = Array2::<Complex<f64>>::zeros((self.nsta(), self.nsta()));
1413        let mut Us = Array2::<Complex<f64>>::zeros((self.nsta(), self.nsta()));
1414
1415        // Calculate the energy differences and their inverses
1416        for i in 0..self.nsta() {
1417            for j in 0..self.nsta() {
1418                let a = band[[i]] - band[[j]];
1419                U0[[i, j]] = Complex::new(a, 0.0);
1420                Us[[i, j]] = if a.abs() > 1e-6 {
1421                    Complex::new(1.0 / a, 0.0)
1422                } else {
1423                    Complex::new(0.0, 0.0)
1424                };
1425            }
1426        }
1427
1428        let mut matric_n = Array2::zeros((n_og, self.nsta()));
1429        let mut omega_n = Array2::zeros((n_og, self.nsta()));
1430
1431        // Calculate the matrices for each frequency
1432        Zip::from(omega_n.outer_iter_mut())
1433            .and(matric_n.outer_iter_mut())
1434            .and(og.view())
1435            .for_each(|mut omega, mut matric, a0| {
1436                let li_eta = a0 + li * eta;
1437                let UU = U0.mapv(|x| (x * x - li_eta * li_eta).finv());
1438                let U1 = &UU * &Us * li_eta;
1439
1440                let o = im
1441                    .outer_iter()
1442                    .zip(UU.outer_iter())
1443                    .map(|(a, b)| a.dot(&b))
1444                    .collect();
1445                let m = re
1446                    .outer_iter()
1447                    .zip(U1.outer_iter())
1448                    .map(|(a, b)| a.dot(&b))
1449                    .collect();
1450                let o = Array1::from_vec(o);
1451                let m = Array1::from_vec(m);
1452                omega.assign(&o);
1453                matric.assign(&m);
1454            });
1455
1456        (matric_n, omega_n, band)
1457    }
1458
1459    pub fn optical_conductivity(
1460        &self,
1461        k_mesh: &Array1<usize>,
1462        dir_1: &Array1<f64>,
1463        dir_2: &Array1<f64>,
1464        T: f64,
1465        mu: f64,
1466        og: &Array1<f64>,
1467        eta: f64,
1468    ) -> Result<(Array1<Complex<f64>>, Array1<Complex<f64>>)>
1469//针对单个的
1470    {
1471        let li: Complex<f64> = 1.0 * Complex::i();
1472        let kvec: Array2<f64> = gen_kmesh(k_mesh)?;
1473        let nk: usize = kvec.len_of(Axis(0));
1474        let n_og = og.len();
1475        let (matric_sum, omega_sum) = kvec
1476            .outer_iter()
1477            .into_par_iter()
1478            .map(|k| {
1479                let (matric_n, omega_n, band) =
1480                    self.optical_geometry_n_onek(&k, dir_1, dir_2, og, eta);
1481                let fermi_dirac = if T == 0.0 {
1482                    band.mapv(|x| if x > mu { 0.0 } else { 1.0 })
1483                } else {
1484                    let beta = 1.0 / T / 8.617e-5;
1485                    band.mapv(|x| ((beta * (x - mu)).exp() + 1.0).recip())
1486                };
1487                let fermi_dirac = fermi_dirac.mapv(|x| Complex::new(x, 0.0));
1488                let matric = matric_n.dot(&fermi_dirac);
1489                let omega = omega_n.dot(&fermi_dirac);
1490                (matric, omega)
1491            })
1492            .reduce(
1493                || (Array1::zeros(n_og), Array1::zeros(n_og)),
1494                |(matric_acc, omega_acc), (matric, omega)| (matric_acc + matric, omega_acc + omega),
1495            );
1496        let matric_sum = li * matric_sum / self.lat.det().unwrap() / (nk as f64);
1497        let omega_sum = li * omega_sum / self.lat.det().unwrap() / (nk as f64);
1498        Ok((matric_sum, omega_sum))
1499    }
1500
1501    pub fn optical_conductivity_T(
1502        &self,
1503        k_mesh: &Array1<usize>,
1504        dir_1: &Array1<f64>,
1505        dir_2: &Array1<f64>,
1506        T: &Array1<f64>,
1507        mu: f64,
1508        og: &Array1<f64>,
1509        eta: f64,
1510    ) -> Result<(Array2<Complex<f64>>, Array2<Complex<f64>>)> {
1511        let li: Complex<f64> = 1.0 * Complex::i();
1512        let kvec: Array2<f64> = gen_kmesh(k_mesh)?;
1513        let nk: usize = kvec.len_of(Axis(0));
1514        let n_og = og.len();
1515        let n_T = T.len();
1516        let (matric_sum, omega_sum) = kvec
1517            .outer_iter()
1518            .into_par_iter()
1519            .map(|k| {
1520                let (matric_n, omega_n, band) =
1521                    self.optical_geometry_n_onek(&k, dir_1, dir_2, og, eta);
1522                let beta = T.mapv(|x| 1.0 / x / 8.617e-5);
1523                let nsta = band.len();
1524                let n_T = beta.len();
1525                let mut fermi_dirac: Array2<Complex<f64>> = Array2::zeros((nsta, n_T));
1526                Zip::from(fermi_dirac.outer_iter_mut())
1527                    .and(band.view())
1528                    .for_each(|mut f0, e0| {
1529                        let a = beta
1530                            .map(|x0| Complex::new(((x0 * (e0 - mu)).exp() + 1.0).recip(), 0.0));
1531                        f0.assign(&a);
1532                    });
1533                let matric = matric_n.dot(&fermi_dirac);
1534                let omega = omega_n.dot(&fermi_dirac);
1535                (matric, omega)
1536            })
1537            .reduce(
1538                || (Array2::zeros((n_og, n_T)), Array2::zeros((n_og, n_T))),
1539                |(matric_acc, omega_acc), (matric, omega)| (matric_acc + matric, omega_acc + omega),
1540            );
1541        let matric_sum = li * matric_sum / self.lat.det().unwrap() / (nk as f64);
1542        let omega_sum = li * omega_sum / self.lat.det().unwrap() / (nk as f64);
1543        Ok((matric_sum, omega_sum))
1544    }
1545
1546    ///直接计算 xx, yy, zz, xy, yz, xz 这六个量的光电导, 分为对称和反对称部分.
1547    ///输出格式为 ($\sigma_{ab}^S$, $\sigma_{ab}^A), 这里 S 和 A 表示 symmetry and antisymmetry.
1548    ///$sigma_{ab}^S$ 是 $6\times n_\omega$
1549    ///如果是二维系统, 那么输出 xx yy xy 这三个分量
1550    pub fn optical_conductivity_all_direction(
1551        &self,
1552        k_mesh: &Array1<usize>,
1553        T: f64,
1554        mu: f64,
1555        og: &Array1<f64>,
1556        eta: f64,
1557    ) -> Result<(Array2<Complex<f64>>, Array2<Complex<f64>>)> {
1558        let li: Complex<f64> = 1.0 * Complex::i();
1559        let kvec: Array2<f64> = gen_kmesh(k_mesh)?;
1560        let nk: usize = kvec.len_of(Axis(0));
1561        let n_og = og.len();
1562        let (matric,omega):(Vec<_>,Vec<_>)=kvec.outer_iter().into_par_iter()
1563            .map(|k| {
1564                //let (band, evec) = self.solve_onek(&k);
1565                let (mut v, hamk): (Array3<Complex<f64>>,Array2<Complex<f64>>) = self.gen_v(&k,Gauge::Atom); //这是速度算符
1566                let (band, evec) = if let Ok((eigvals, eigvecs)) = hamk.eigh(UPLO::Lower) {
1567                    (eigvals, eigvecs)
1568                } else {
1569                    todo!()
1570                };
1571                let evec_conj=evec.t();
1572                let evec= evec.mapv(|x| x.conj());
1573
1574                let mut A = Array3::zeros((self.dim_r(),self.nsta(),self.nsta()));
1575                //transfrom the basis into bolch state
1576                Zip::from(A.outer_iter_mut()).and(v.outer_iter()).for_each(|mut a,v| a.assign(&evec_conj.dot(&v.dot(&evec))));
1577
1578                // Calculate the energy differences and their inverses
1579                let mut U0=Array2::zeros((self.nsta(),self.nsta()));
1580                let mut Us=Array2::zeros((self.nsta(),self.nsta()));
1581                for i in 0..self.nsta() {
1582                    for j in 0..self.nsta() {
1583                        let a = band[[i]] - band[[j]];
1584                        U0[[i, j]] = Complex::new(a, 0.0);
1585                        Us[[i, j]] = if a.abs() > 1e-6 {
1586                            Complex::new(1.0 / a, 0.0)
1587                        } else {
1588                            Complex::new(0.0, 0.0)
1589                        };
1590                    }
1591                }
1592
1593                let fermi_dirac=if T==0.0{
1594                    band.mapv(|x| if x>mu {0.0} else {1.0})
1595                }else{
1596                    let beta=1.0/T/8.617e-5;
1597                    band.mapv(|x| {((beta*(x-mu)).exp()+1.0).recip()})
1598                };
1599                let fermi_dirac=fermi_dirac.mapv(|x| Complex::new(x,0.0));
1600
1601                let n_og=og.len();
1602                assert_eq!(band.len(), self.nsta(), "this is strange for band's length is not equal to self.nsta()");
1603
1604                let (matric_n,omega_n)=match self.dim_r(){
1605                    3=>{
1606                        let mut matric_n=Array2::zeros((6,n_og));
1607                        let mut omega_n=Array2::zeros((3,n_og));
1608                        let A_xx=&A.slice(s![0,..,..])*&A.slice(s![0,..,..]).t();
1609                        let A_yy=&A.slice(s![1,..,..])*&A.slice(s![1,..,..]).t();
1610                        let A_zz=&A.slice(s![2,..,..])*&A.slice(s![2,..,..]).t();
1611                        let A_xy=&A.slice(s![0,..,..])*&A.slice(s![1,..,..]).t();
1612                        let A_yz=&A.slice(s![1,..,..])*&A.slice(s![2,..,..]).t();
1613                        let A_xz=&A.slice(s![0,..,..])*&A.slice(s![2,..,..]).t();
1614                        let re_xx:Array2<Complex<f64>> = Complex::new(2.0,0.0)*A_xx;
1615                        let re_yy:Array2<Complex<f64>> = Complex::new(2.0,0.0)*A_yy;
1616                        let re_zz:Array2<Complex<f64>> = Complex::new(2.0,0.0)*A_zz;
1617                        let Complex { re, im } = A_xy.view().split_complex();
1618                        let re_xy:Array2<Complex<f64>> = re.mapv(|x| Complex::new(2.0*x, 0.0));
1619                        let im_xy:Array2<Complex<f64>> = im.mapv(|x| Complex::new(0.0, -2.0*x));
1620                        let Complex { re, im } = A_yz.view().split_complex();
1621                        let re_yz:Array2<Complex<f64>> = re.mapv(|x| Complex::new(2.0*x, 0.0));
1622                        let im_yz:Array2<Complex<f64>> = im.mapv(|x| Complex::new(0.0, -2.0*x));
1623                        let Complex { re, im } = A_xz.view().split_complex();
1624                        let re_xz:Array2<Complex<f64>> = re.mapv(|x| Complex::new(2.0*x, 0.0));
1625                        let im_xz:Array2<Complex<f64>> = im.mapv(|x| Complex::new(0.0, -2.0*x));
1626                        // Calculate the matrices for each frequency
1627                        Zip::from(omega_n.axis_iter_mut(Axis(1)))
1628                            .and(matric_n.axis_iter_mut(Axis(1)))
1629                            .and(og.view())
1630                            .par_for_each(|mut omega, mut matric, a0| {
1631                                let li_eta = a0 + li * eta;
1632                                let UU = U0.mapv(|x| (x*x - li_eta*li_eta).finv());
1633                                let U1:Array2<Complex<f64>> = &UU * &Us * li_eta;
1634
1635                                let m = re_xx.outer_iter().zip(U1.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1636                                let m = Array1::from_vec(m).dot(&fermi_dirac);
1637                                matric[[0]]=m;
1638                                let m = re_yy.outer_iter().zip(U1.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1639                                let m = Array1::from_vec(m).dot(&fermi_dirac);
1640                                matric[[1]]=m;
1641                                let m = re_zz.outer_iter().zip(U1.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1642                                let m = Array1::from_vec(m).dot(&fermi_dirac);
1643                                matric[[2]]=m;
1644
1645                                let o = im_xy.outer_iter().zip(UU.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1646                                let m = re_xy.outer_iter().zip(U1.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1647                                let o = Array1::from_vec(o).dot(&fermi_dirac);
1648                                let m = Array1::from_vec(m).dot(&fermi_dirac);
1649                                omega[[0]]=o;
1650                                matric[[3]]=m;
1651                                let o = im_yz.outer_iter().zip(UU.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1652                                let m = re_yz.outer_iter().zip(U1.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1653                                let o = Array1::from_vec(o).dot(&fermi_dirac);
1654                                let m = Array1::from_vec(m).dot(&fermi_dirac);
1655                                omega[[1]]=o;
1656                                matric[[4]]=m;
1657                                let o = im_xz.outer_iter().zip(UU.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1658                                let m = re_xz.outer_iter().zip(U1.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1659                                let o = Array1::from_vec(o).dot(&fermi_dirac);
1660                                let m = Array1::from_vec(m).dot(&fermi_dirac);
1661                                omega[[2]]=o;
1662                                matric[[5]]=m;
1663                            });
1664                        (matric_n,omega_n)
1665                    },
1666                    2=>{
1667                        let mut matric_n=Array2::zeros((3,n_og));
1668                        let mut omega_n=Array2::zeros((1,n_og));
1669                        let A_xx=&A.slice(s![0,..,..])*&(A.slice(s![0,..,..]).reversed_axes());
1670                        let A_yy=&A.slice(s![1,..,..])*&(A.slice(s![1,..,..]).reversed_axes());
1671                        let A_xy=&A.slice(s![0,..,..])*&(A.slice(s![1,..,..]).reversed_axes());
1672                        let re_xx:Array2<Complex<f64>> = Complex::new(2.0,0.0)*A_xx;
1673                        let re_yy:Array2<Complex<f64>> = Complex::new(2.0,0.0)*A_yy;
1674                        let Complex { re, im } = A_xy.view().split_complex();
1675                        let re_xy:Array2<Complex<f64>> = re.mapv(|x| Complex::new(2.0*x, 0.0));
1676                        let im_xy:Array2<Complex<f64>> = im.mapv(|x| Complex::new(0.0, -2.0*x));
1677                        // Calculate the matrices for each frequency
1678                        Zip::from(omega_n.axis_iter_mut(Axis(1)))
1679                            .and(matric_n.axis_iter_mut(Axis(1)))
1680                            .and(og.view())
1681                            .par_for_each(|mut omega, mut matric, a0| {
1682                                let li_eta = a0 + li * eta;
1683                                let UU = U0.mapv(|x| (x*x - li_eta*li_eta).finv());
1684                                let U1:Array2<Complex<f64>> = &UU * &Us * li_eta;
1685
1686                                let m = re_xx.outer_iter().zip(U1.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1687                                let m = Array1::from_vec(m).dot(&fermi_dirac);
1688                                matric[[0]]=m;
1689                                let m = re_yy.outer_iter().zip(U1.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1690                                let m = Array1::from_vec(m).dot(&fermi_dirac);
1691                                matric[[1]]=m;
1692
1693                                let o = im_xy.outer_iter().zip(UU.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1694                                let m = re_xy.outer_iter().zip(U1.outer_iter()).map(|(a, b)| a.dot(&b)).collect();
1695                                let o = Array1::from_vec(o).dot(&fermi_dirac);
1696                                let m = Array1::from_vec(m).dot(&fermi_dirac);
1697                                omega[[0]]=o;
1698                                matric[[2]]=m;
1699                            });
1700                        (matric_n,omega_n)
1701                    },
1702                    _=>panic!("Wrong, self.dim_r must be 2 or 3 for using optical_conductivity_all_direction")
1703                };
1704                (matric_n,omega_n)
1705            }).collect();
1706        let (matric_sum, omega_sum) = match self.dim_r() {
1707            3 => {
1708                let omega = omega
1709                    .into_iter()
1710                    .fold(Array2::zeros((3, n_og)), |omega_acc, omega| {
1711                        omega_acc + omega
1712                    });
1713                let matric = matric
1714                    .into_iter()
1715                    .fold(Array2::zeros((6, n_og)), |matric_acc, matric| {
1716                        matric_acc + matric
1717                    });
1718                (matric, omega)
1719            }
1720            2 => {
1721                let omega = omega
1722                    .into_iter()
1723                    .fold(Array2::zeros((1, n_og)), |omega_acc, omega| {
1724                        omega_acc + omega
1725                    });
1726                let matric = matric
1727                    .into_iter()
1728                    .fold(Array2::zeros((3, n_og)), |matric_acc, matric| {
1729                        matric_acc + matric
1730                    });
1731                (matric, omega)
1732            }
1733            _ => panic!(
1734                "Wrong, self.dim_r must be 2 or 3 for using optical_conductivity_all_direction"
1735            ),
1736        };
1737        let matric_sum = li * matric_sum / self.lat.det().unwrap() / (nk as f64);
1738        let omega_sum = li * omega_sum / self.lat.det().unwrap() / (nk as f64);
1739        Ok((matric_sum, omega_sum))
1740    }
1741}