1
1
2
2
import numpy as np
3
3
from dptb .data import AtomicDataDict
4
+ from dptb .data import AtomicData
5
+
4
6
import torch
5
7
from dptb .nn .hr2hk import HR2HK
6
8
from dptb .nn .hr2dhk import Hr2dHk
9
11
from dptb .utils .make_kpoints import kmesh_sampling_negf
10
12
import time
11
13
import logging
14
+ import os
15
+ from ase .io import read
16
+ import matplotlib .pyplot as plt
17
+
12
18
13
19
log = logging .getLogger (__name__ )
14
20
@@ -19,117 +25,175 @@ def gauss(x,mu,sigma):
19
25
res = torch .exp (- 0.5 * ((x - mu )/ sigma )** 2 )/ (sigma * torch .sqrt (2 * torch .tensor (math .pi )))
20
26
return res
21
27
22
-
23
- def cal_cond (model , data , e_fermi , mesh_grid , emax , num_val = None , gap_corr = 0 , num_omega = 1000 , nk_per_loop = None , delta = 0.005 , T = 300 , direction = 'xx' , g_s = 2 ):
24
-
25
- h2k = HR2HK (
26
- idp = model .idp ,
27
- device = model .device ,
28
- dtype = model .dtype )
29
-
30
- h2dk = Hr2dHk (
31
- idp = model .idp ,
32
- device = model .device ,
33
- dtype = model .dtype )
34
- data = model .idp (data )
35
- data = model (data )
36
-
37
- log .info ('application of the model is done' )
38
-
39
- KB = 8.617333262e-5
40
- beta = 1 / (KB * T )
41
- kpoints , kweight = kmesh_sampling_negf (mesh_grid )
42
- assert len (direction ) == 2
43
- kpoints = torch .as_tensor (kpoints , dtype = torch .float32 )
44
- kweight = torch .as_tensor (kweight , dtype = torch .float64 )
45
- assert kpoints .shape [0 ] == kweight .shape [0 ]
46
-
47
- tot_numk = kpoints .shape [0 ]
48
- if nk_per_loop is None :
49
- nk_per_loop = tot_numk
50
- num_loop = math .ceil (tot_numk / nk_per_loop )
51
- omegas = torch .linspace (0 ,emax ,num_omega , dtype = torch .float64 )
52
-
53
- log .info ('tot_numk:' ,tot_numk , 'nk_per_loop:' ,nk_per_loop , 'num_loop:' ,num_loop )
54
-
55
- ac_cond = np .zeros ((len (omegas )),dtype = np .complex128 )
56
- ac_cond_ik = np .zeros ((len (omegas )),dtype = np .complex128 )
57
-
58
- ac_cond_linhard = np .zeros ((len (omegas )),dtype = np .complex128 )
59
- ac_cond_linhard_ik = np .zeros ((len (omegas )),dtype = np .complex128 )
60
-
61
- for ik in range (num_loop ):
62
- t_start = time .time ()
63
- log .info ('<><><><><' * 5 )
64
- log .info (f'loop { ik + 1 } in { num_loop } circles' )
65
- istart = ik * nk_per_loop
66
- iend = min ((ik + 1 ) * nk_per_loop , tot_numk )
67
- kpoints_ = kpoints [istart :iend ]
68
- kweight_ = kweight [istart :iend ]
69
-
70
- data [AtomicDataDict .KPOINT_KEY ] = torch .nested .as_nested_tensor ([kpoints_ ])
71
- data = h2k (data )
72
- dhdk = h2dk (data ,direction = direction )
73
-
74
- # Hamiltonian = data['hamiltonian'].detach().to(torch.complex128)
75
- # dhdk = {k: v.detach().to(torch.complex128) for k, v in dhdk.items()}
76
-
77
- log .info (f' - get H and dHdk ...' )
78
-
79
- eigs , eigv = torch .linalg .eigh (data ['hamiltonian' ])
28
+ class AcCond :
29
+ def __init__ (self , model :torch .nn .Module , results_path : str = None , use_gui : bool = False , device : str = 'cpu' ):
30
+ self .model = model
31
+ self .results_path = results_path
32
+ self .use_gui = use_gui
33
+ self .device = device
34
+ os .makedirs (results_path , exist_ok = True )
35
+
36
+ def get_accond (self ,
37
+ struct ,
38
+ AtomicData_options ,
39
+ emax ,
40
+ num_omega = 1000 ,
41
+ mesh_grid = [1 ,1 ,1 ],
42
+ nk_per_loop = None ,
43
+ delta = 0.03 ,
44
+ e_fermi = 0 ,
45
+ valence_e = None ,
46
+ gap_corr = 0 ,
47
+ T = 300 ,
48
+ direction = 'xx' ,
49
+ g_s = 2 ):
80
50
81
- if num_val is not None and abs ( gap_corr ) > 1e-3 :
82
- log . info ( f' - gap correction is applied with { gap_corr } ' )
83
- assert num_val > 0
84
- assert eigs [:, num_val ]. min () - eigs [:, num_val - 1 ]. max () > 1e-3 , f'the gap between the VBM { num_val - 1 } and the CBM { num_val } is too small'
85
-
86
- eigs [:,: num_val ] = eigs [:,: num_val ] - gap_corr / 2
87
- eigs [:, num_val :] = eigs [:, num_val :] + gap_corr / 2
88
-
89
- log . info ( f' - diagonalization of H ...' )
90
-
91
- dh1 = eigv . conj (). transpose ( 1 , 2 ) @ dhdk [ direction [ 0 ]] @ eigv
92
- if direction [ 0 ] == direction [ 1 ]:
93
- dh2 = dh1
51
+ log . info ( '<><><><>' * 5 )
52
+ # 调用from_ase方法,生成一个硅的AtomicData类型数据
53
+ dataset = AtomicData . from_ase ( atoms = read ( struct ), ** AtomicData_options )
54
+ data = AtomicData . to_AtomicDataDict ( dataset )
55
+ if valence_e is None and abs ( gap_corr ) > 1e-3 :
56
+ uniq_type , counts = np . unique ( data [ 'atom_types' ]. numpy (), return_counts = True )
57
+ tot_num_e = 0
58
+ for i in range ( len ( uniq_type )):
59
+ symbol = self . model . idp . type_to_chemical_symbol [ uniq_type [ i ]]
60
+ assert symbol in valence_e
61
+ tot_num_e += counts [ i ] * valence_e [ symbol ]
62
+
63
+ num_val = tot_num_e // g_s
94
64
else :
95
- dh2 = eigv .conj ().transpose (1 ,2 ) @ dhdk [direction [1 ]] @ eigv
96
-
97
- p1p2 = dh1 * dh2 .transpose (1 ,2 )
98
-
99
-
100
- log .info (f' - get p matrix from dHdk ...' )
101
-
102
- p1p2 .to (torch .complex128 )
103
- eigs .to (torch .float64 )
104
-
105
- eig_diff = eigs [:,:,None ] - eigs [:,None ,:]
106
-
107
- fdv = fermi_dirac (eigs , e_fermi , beta )
108
- fd_diff = fdv [:,:,None ] - fdv [:,None ,:]
109
- #fd_ed = torch.zeros_like(eig_diff)
110
- ind = torch .abs (eig_diff ) > 1e-6
111
- ind2 = torch .abs (eig_diff ) <= 1e-6
112
- fd_diff [ind ] = fd_diff [ind ] / eig_diff [ind ]
113
- fd_diff [ind2 ] = 0.0
114
-
115
- p1p2 = p1p2 * fd_diff
116
- p1p2 = p1p2 * kweight_ [:,None ,None ]
65
+ num_val = None
66
+
67
+ self .omegas , self .ac_cond_gauss , self .ac_cond_linhard = AcCond .cal_cond (model = self .model , data = data , e_fermi = e_fermi , mesh_grid = mesh_grid ,
68
+ emax = emax , num_val = num_val , gap_corr = gap_corr , num_omega = num_omega , nk_per_loop = nk_per_loop ,
69
+ delta = delta , T = T , direction = direction , g_s = g_s )
117
70
118
- kpoints_ .shape [1 ]
119
- ac_cond_ik = ac_cond_ik * 0
120
- acdf2py .ac_cond_gauss (eig_diff .permute (1 ,2 ,0 ).detach ().numpy (), p1p2 .permute (1 ,2 ,0 ).detach ().numpy (), omegas , delta , 1 , kpoints_ .shape [0 ], ac_cond_ik )
121
- acdf2py .ac_cond_f (eig_diff .permute (1 ,2 ,0 ).detach ().numpy (), p1p2 .permute (1 ,2 ,0 ).detach ().numpy (), omegas , delta , 1 , kpoints_ .shape [0 ], ac_cond_linhard_ik )
122
- ac_cond = ac_cond + ac_cond_ik
123
- ac_cond_linhard = ac_cond_linhard + ac_cond_linhard_ik
71
+ np .save (f"{ self .results_path } /AC_cond_sig_{ delta } .npy" , {'energy' :self .omegas , 'ac_cond_g' : self .ac_cond_gauss , 'ac_cond_l' : self .ac_cond_linhard })
72
+ log .info ('<><><><>' * 5 )
73
+
74
+ def plot_optcond (self ):
75
+ fig = plt .figure (figsize = (6 ,6 ),dpi = 200 )
76
+ plt .plot (self .omegas , self .ac_cond_gauss .real , label = 'Gaussian' )
77
+ plt .plot (self .omegas , self .ac_cond_linhard .real , label = 'Linhard:real' )
78
+ plt .plot (self .omegas , self .ac_cond_linhard .imag , label = 'Linhard:real' )
79
+ plt .xlabel ("Energy (eV)" )
80
+ plt .ylabel ("sigma_xx" )
81
+ plt .savefig ("ACxx.png" )
82
+ if self .use_gui :
83
+ plt .show ()
84
+ plt .close ()
85
+
86
+ @staticmethod
87
+ def cal_cond (model , data , e_fermi , mesh_grid , emax , num_val = None , gap_corr = 0 , num_omega = 1000 , nk_per_loop = None , delta = 0.005 , T = 300 , direction = 'xx' , g_s = 2 ):
88
+ h2k = HR2HK (
89
+ idp = model .idp ,
90
+ device = model .device ,
91
+ dtype = model .dtype )
92
+
93
+ h2dk = Hr2dHk (
94
+ idp = model .idp ,
95
+ device = model .device ,
96
+ dtype = model .dtype )
97
+ data = model .idp (data )
98
+ data = model (data )
99
+
100
+ log .info ('application of the model is done' )
101
+
102
+ KB = 8.617333262e-5
103
+ beta = 1 / (KB * T )
104
+ kpoints , kweight = kmesh_sampling_negf (mesh_grid )
105
+ assert len (direction ) == 2
106
+ kpoints = torch .as_tensor (kpoints , dtype = torch .float32 )
107
+ kweight = torch .as_tensor (kweight , dtype = torch .float64 )
108
+ assert kpoints .shape [0 ] == kweight .shape [0 ]
109
+
110
+ tot_numk = kpoints .shape [0 ]
111
+ if nk_per_loop is None :
112
+ log .warning ('nk_per_loop is not set, will use all kpoints in one loop, which may cause memory error.' )
113
+ nk_per_loop = tot_numk
114
+ num_loop = math .ceil (tot_numk / nk_per_loop )
115
+ omegas = torch .linspace (0 ,emax ,num_omega , dtype = torch .float64 )
116
+
117
+ log .info ('tot_numk:' ,tot_numk , 'nk_per_loop:' ,nk_per_loop , 'num_loop:' ,num_loop )
118
+
119
+ ac_cond = np .zeros ((len (omegas )),dtype = np .complex128 )
120
+ ac_cond_ik = np .zeros ((len (omegas )),dtype = np .complex128 )
121
+
122
+ ac_cond_linhard = np .zeros ((len (omegas )),dtype = np .complex128 )
123
+ ac_cond_linhard_ik = np .zeros ((len (omegas )),dtype = np .complex128 )
124
+
125
+ for ik in range (num_loop ):
126
+ t_start = time .time ()
127
+ log .info ('<><><><><' * 5 )
128
+ log .info (f'loop { ik + 1 } in { num_loop } circles' )
129
+ istart = ik * nk_per_loop
130
+ iend = min ((ik + 1 ) * nk_per_loop , tot_numk )
131
+ kpoints_ = kpoints [istart :iend ]
132
+ kweight_ = kweight [istart :iend ]
133
+
134
+ data [AtomicDataDict .KPOINT_KEY ] = torch .nested .as_nested_tensor ([kpoints_ ])
135
+ data = h2k (data )
136
+ dhdk = h2dk (data ,direction = direction )
137
+
138
+ # Hamiltonian = data['hamiltonian'].detach().to(torch.complex128)
139
+ # dhdk = {k: v.detach().to(torch.complex128) for k, v in dhdk.items()}
140
+
141
+ log .info (f' - get H and dHdk ...' )
142
+
143
+ eigs , eigv = torch .linalg .eigh (data ['hamiltonian' ])
144
+
145
+ if num_val is not None and abs (gap_corr ) > 1e-3 :
146
+ log .info (f' - gap correction is applied with { gap_corr } ' )
147
+ assert num_val > 0
148
+ assert eigs [:,num_val ].min () - eigs [:,num_val - 1 ].max () > 1e-3 , f'the gap between the VBM { num_val - 1 } and the CBM { num_val } is too small'
149
+
150
+ eigs [:,:num_val ] = eigs [:,:num_val ] - gap_corr / 2
151
+ eigs [:,num_val :] = eigs [:,num_val :] + gap_corr / 2
152
+
153
+ log .info (f' - diagonalization of H ...' )
154
+
155
+ dh1 = eigv .conj ().transpose (1 ,2 ) @ dhdk [direction [0 ]] @ eigv
156
+ if direction [0 ] == direction [1 ]:
157
+ dh2 = dh1
158
+ else :
159
+ dh2 = eigv .conj ().transpose (1 ,2 ) @ dhdk [direction [1 ]] @ eigv
160
+
161
+ p1p2 = dh1 * dh2 .transpose (1 ,2 )
162
+
163
+
164
+ log .info (f' - get p matrix from dHdk ...' )
165
+
166
+ p1p2 .to (torch .complex128 )
167
+ eigs .to (torch .float64 )
168
+
169
+ eig_diff = eigs [:,:,None ] - eigs [:,None ,:]
170
+
171
+ fdv = fermi_dirac (eigs , e_fermi , beta )
172
+ fd_diff = fdv [:,:,None ] - fdv [:,None ,:]
173
+ #fd_ed = torch.zeros_like(eig_diff)
174
+ ind = torch .abs (eig_diff ) > 1e-6
175
+ ind2 = torch .abs (eig_diff ) <= 1e-6
176
+ fd_diff [ind ] = fd_diff [ind ] / eig_diff [ind ]
177
+ fd_diff [ind2 ] = 0.0
178
+
179
+ p1p2 = p1p2 * fd_diff
180
+ p1p2 = p1p2 * kweight_ [:,None ,None ]
181
+
182
+ kpoints_ .shape [1 ]
183
+ ac_cond_ik = ac_cond_ik * 0
184
+ acdf2py .ac_cond_gauss (eig_diff .permute (1 ,2 ,0 ).detach ().numpy (), p1p2 .permute (1 ,2 ,0 ).detach ().numpy (), omegas , delta , 1 , kpoints_ .shape [0 ], ac_cond_ik )
185
+ acdf2py .ac_cond_f (eig_diff .permute (1 ,2 ,0 ).detach ().numpy (), p1p2 .permute (1 ,2 ,0 ).detach ().numpy (), omegas , delta , 1 , kpoints_ .shape [0 ], ac_cond_linhard_ik )
186
+ ac_cond = ac_cond + ac_cond_ik
187
+ ac_cond_linhard = ac_cond_linhard + ac_cond_linhard_ik
188
+
189
+ log .info (f' - get ac_cond ...' )
190
+ t_end = time .time ()
191
+ log .info (f'time cost: { t_end - t_start :.4f} s in loop { ik + 1 } ' )
124
192
125
- log .info (f' - get ac_cond ...' )
126
- t_end = time .time ()
127
- log .info (f'time cost: { t_end - t_start :.4f} s in loop { ik + 1 } ' )
193
+ ac_cond = 1.0j * ac_cond * np .pi
194
+ volume = data ['cell' ][0 ] @ (data ['cell' ][1 ].cross (data ['cell' ][2 ],dim = 0 ))
195
+ prefactor = 2 * g_s * 1j / (volume .numpy ())
196
+ ac_cond = ac_cond * prefactor
197
+ ac_cond_linhard = ac_cond_linhard * prefactor
128
198
129
- ac_cond = 1.0j * ac_cond * np .pi
130
- volume = data ['cell' ][0 ] @ (data ['cell' ][1 ].cross (data ['cell' ][2 ],dim = 0 ))
131
- prefactor = 2 * g_s * 1j / (volume .numpy ())
132
- ac_cond = ac_cond * prefactor
133
- ac_cond_linhard = ac_cond_linhard * prefactor
134
-
135
- return omegas , ac_cond , ac_cond_linhard
199
+ return omegas , ac_cond , ac_cond_linhard
0 commit comments