Skip to content

Commit 1b717dc

Browse files
committed
update
1 parent 6cec494 commit 1b717dc

File tree

5 files changed

+201
-110
lines changed

5 files changed

+201
-110
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ dptb/tests/**/*.traj
88
dptb/tests/**/out*/*
99
examples/_*
1010
*.dat
11-
*log*
11+
*log.*
1212
dptb/tests/data/**/out*/config_*.json
1313
bandstructure.npy
1414
dptb/tests/data/hBN/data/set.0/xdat2.traj

dptb/entrypoints/run.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from dptb.utils.tools import j_loader
1111
from dptb.utils.tools import j_must_have
1212
from dptb.postprocess.write_ham import write_ham
13+
from dptb.postprocess.optical.optical_cond import AcCond
1314
import torch
1415
import h5py
1516

@@ -85,6 +86,26 @@ def run(
8586
emin=jdata["task_options"].get("emin", None),
8687
emax=jdata["task_options"].get("emax", None))
8788
log.info(msg='band calculation successfully completed.')
89+
elif task == 'ac_cond':
90+
accondcal = AcCond(model=model, results_path=results_path, use_gui=use_gui)
91+
92+
accondcal.get_accond(struct=struct_file,
93+
AtomicData_options=jdata['AtomicData_options'],
94+
task_options=jdata['task_options'],
95+
emax=jdata['task_options'].get('emax'),
96+
num_omega=jdata['task_options'].get('num_omega',1000),
97+
mesh_grid=jdata['task_options'].get('mesh_grid',[1,1,1]),
98+
nk_per_loop=jdata['task_options'].get('nk_per_loop',None),
99+
delta=jdata['task_options'].get('delta',0.03),
100+
e_fermi=jdata['task_options'].get('e_fermi',0),
101+
valence_e=jdata['task_options'].get('valence_e',None),
102+
gap_corr=jdata['task_options'].get('gap_corr',0),
103+
T=jdata['task_options'].get('T',300),
104+
direction=jdata['task_options'].get('direction','xx'),
105+
g_s=jdata['task_options'].get('g_s',2)
106+
)
107+
accondcal.optical_plot()
108+
log.info(msg='ac optical conductivity calculation successfully completed.')
88109

89110
elif task=='write_block':
90111
task = torch.load(init_model, map_location="cpu")["task"]

dptb/plugins/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .train_logger import Logger
2+
from .base_plugin import Plugin, PluginUser
3+
from .monitor import Monitor
4+
from .saver import Saver
Lines changed: 173 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
import numpy as np
33
from dptb.data import AtomicDataDict
4+
from dptb.data import AtomicData
5+
46
import torch
57
from dptb.nn.hr2hk import HR2HK
68
from dptb.nn.hr2dhk import Hr2dHk
@@ -9,6 +11,10 @@
911
from dptb.utils.make_kpoints import kmesh_sampling_negf
1012
import time
1113
import logging
14+
import os
15+
from ase.io import read
16+
import matplotlib.pyplot as plt
17+
1218

1319
log = logging.getLogger(__name__)
1420

@@ -19,117 +25,175 @@ def gauss(x,mu,sigma):
1925
res = torch.exp(-0.5*((x-mu)/sigma)**2)/(sigma*torch.sqrt(2*torch.tensor(math.pi)))
2026
return res
2127

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):
8050

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
9464
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)
11770

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}')
124192

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
128198

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

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ cmake.verbose = true
6262
logging.level = "DEBUG"
6363
experimental = true
6464

65+
66+
6567
[tool.scikit-build.metadata.version]
6668
provider = "scikit_build_core.metadata.setuptools_scm"
6769

0 commit comments

Comments
 (0)