hpro 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- HPRO/__init__.py +5 -0
- HPRO/aodiag.py +563 -0
- HPRO/config.py +22 -0
- HPRO/constants.py +6 -0
- HPRO/data/periodic_table.json +1 -0
- HPRO/from_gpaw/gaunt.py +87 -0
- HPRO/from_gpaw/spherical_harmonics.py +221 -0
- HPRO/io/aodata.py +450 -0
- HPRO/io/bgwio.py +393 -0
- HPRO/io/deephio.py +230 -0
- HPRO/io/gpawio.py +126 -0
- HPRO/io/hrloader.py +107 -0
- HPRO/io/siestaio.py +131 -0
- HPRO/io/siestaio_old.py +208 -0
- HPRO/io/struio.py +177 -0
- HPRO/kernel.py +484 -0
- HPRO/matao/findpairs.py +288 -0
- HPRO/matao/matao.py +616 -0
- HPRO/matao/mataocsr.py +292 -0
- HPRO/pw/hgdata.py +390 -0
- HPRO/pw/wfndata.py +202 -0
- HPRO/pwproj.py +238 -0
- HPRO/utils/math.py +364 -0
- HPRO/utils/misc.py +266 -0
- HPRO/utils/mpi.py +147 -0
- HPRO/utils/orbutils.py +236 -0
- HPRO/utils/structure.py +91 -0
- HPRO/utils/supercell.py +137 -0
- HPRO/v2h/gridintg.py +234 -0
- HPRO/v2h/gridintg_old.py +382 -0
- HPRO/v2h/twocenter.py +194 -0
- HPRO/v2h/vkb.py +85 -0
- hpro-0.3.0.dist-info/METADATA +155 -0
- hpro-0.3.0.dist-info/RECORD +37 -0
- hpro-0.3.0.dist-info/WHEEL +5 -0
- hpro-0.3.0.dist-info/licenses/LICENSE +674 -0
- hpro-0.3.0.dist-info/top_level.txt +1 -0
HPRO/__init__.py
ADDED
HPRO/aodiag.py
ADDED
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import os, sys
|
|
3
|
+
import time, datetime
|
|
4
|
+
|
|
5
|
+
from .constants import hartree2ev
|
|
6
|
+
from .utils.mpi import is_master, MPI, comm, mpi_watch, distrib_grps
|
|
7
|
+
from .utils.misc import simple_timer, mytqdm
|
|
8
|
+
from .io.deephio import load_mat_deeph
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
use_slepc4py = True
|
|
12
|
+
try:
|
|
13
|
+
import slepc4py
|
|
14
|
+
slepc4py.init(sys.argv)
|
|
15
|
+
from petsc4py import PETSc
|
|
16
|
+
from slepc4py import SLEPc
|
|
17
|
+
except ModuleNotFoundError:
|
|
18
|
+
use_slepc4py = False
|
|
19
|
+
|
|
20
|
+
from scipy.sparse.linalg import eigsh
|
|
21
|
+
from scipy.linalg import qr, eigh
|
|
22
|
+
|
|
23
|
+
'''
|
|
24
|
+
This module has several functions to diagonalize atomic orbital Hamiltonians.
|
|
25
|
+
'''
|
|
26
|
+
|
|
27
|
+
ILL_EIG_FILLING = 999. # in eV
|
|
28
|
+
|
|
29
|
+
class AODiagKernel:
|
|
30
|
+
|
|
31
|
+
@mpi_watch
|
|
32
|
+
def __init__(self, matH=None, matS=None):
|
|
33
|
+
self.matH = matH
|
|
34
|
+
self.matS = matS
|
|
35
|
+
|
|
36
|
+
self.nk = None
|
|
37
|
+
self.kpts = None
|
|
38
|
+
self.hskpos = None
|
|
39
|
+
self.hsksymbol = None
|
|
40
|
+
|
|
41
|
+
self.nao = None
|
|
42
|
+
self.eigs = None
|
|
43
|
+
self.wfnao = None
|
|
44
|
+
|
|
45
|
+
self.nkpools = None
|
|
46
|
+
self.igrp = None
|
|
47
|
+
self.comm_pool = None
|
|
48
|
+
self.count_proc = None
|
|
49
|
+
|
|
50
|
+
@mpi_watch
|
|
51
|
+
@simple_timer('\nLoad matrices done, total wall time = {t}')
|
|
52
|
+
def load_deeph_mats(self, folder, hmatfname=None, smatfname=None):
|
|
53
|
+
|
|
54
|
+
assert self.kpts is not None, 'Must call setk() before loading matrices'
|
|
55
|
+
|
|
56
|
+
if is_master(comm=self.comm_pool):
|
|
57
|
+
if is_master(): print('Loading Hamiltonian and overlap matrices')
|
|
58
|
+
start_time = time.time()
|
|
59
|
+
matH = load_mat_deeph(folder, 'h', fname_override=hmatfname)
|
|
60
|
+
matS = load_mat_deeph(folder, 'o', fname_override=smatfname)
|
|
61
|
+
if is_master(): print('Done, elapsed time:', datetime.timedelta(seconds=int(time.time()-start_time)))
|
|
62
|
+
self.matH = matH
|
|
63
|
+
self.matS = matS
|
|
64
|
+
|
|
65
|
+
errorh = matH.hermitianize()
|
|
66
|
+
if is_master(): print('Hamiltonian non-Hermiticity error (Ha):', errorh)
|
|
67
|
+
errors = matS.hermitianize()
|
|
68
|
+
if is_master(): print('Overlap non-Hermiticity error:', errors)
|
|
69
|
+
matH.to_csr()
|
|
70
|
+
matS.to_csr()
|
|
71
|
+
|
|
72
|
+
nao = matH.norb_total
|
|
73
|
+
|
|
74
|
+
else:
|
|
75
|
+
nao = 0
|
|
76
|
+
|
|
77
|
+
if comm is not None:
|
|
78
|
+
nao = self.comm_pool.bcast(nao, root=0)
|
|
79
|
+
self.nao = nao
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@mpi_watch
|
|
83
|
+
def setk(self, kpts, kptwts=None, kptsymbol=None, type='path', nkpools=None):
|
|
84
|
+
'''
|
|
85
|
+
Example: G-K-M-G
|
|
86
|
+
kpts =
|
|
87
|
+
[[0.000000000000, 0.000000000000, 0.000000000000],
|
|
88
|
+
[0.333333333333, 0.333333333333, 0.000000000000],
|
|
89
|
+
[0.500000000000, 0.000000000000, 0.000000000000],
|
|
90
|
+
[0.000000000000, 0.000000000000, 0.000000000000]]
|
|
91
|
+
kptwts =
|
|
92
|
+
[20, 10, 17, 1]
|
|
93
|
+
kptsymbol =
|
|
94
|
+
['G', 'K', 'M', 'G']
|
|
95
|
+
'''
|
|
96
|
+
|
|
97
|
+
kpts = np.array(kpts)
|
|
98
|
+
|
|
99
|
+
if type == 'path':
|
|
100
|
+
kptwts = np.array(kptwts)
|
|
101
|
+
assert len(kpts) == len(kptwts)
|
|
102
|
+
assert kptwts[-1] == 1
|
|
103
|
+
|
|
104
|
+
nk = np.sum(kptwts)
|
|
105
|
+
kpts_full = np.empty((nk, 3), dtype='f8')
|
|
106
|
+
pos = 0
|
|
107
|
+
ikhs = -1
|
|
108
|
+
for ikhs in range(len(kpts)-1):
|
|
109
|
+
wk = kptwts[ikhs]
|
|
110
|
+
arange = np.arange(0, wk, 1) / wk
|
|
111
|
+
kstart = kpts[ikhs]
|
|
112
|
+
kend = kpts[ikhs+1]
|
|
113
|
+
kpts_full[pos:pos+wk, :] = kstart[None, :] + (kend - kstart)[None, :] * arange[:, None]
|
|
114
|
+
pos += wk
|
|
115
|
+
kpts_full[pos, :] = kpts[ikhs+1]
|
|
116
|
+
pos += 1
|
|
117
|
+
assert pos == nk
|
|
118
|
+
elif type == 'path_siesta':
|
|
119
|
+
kptwts = np.array(kptwts)
|
|
120
|
+
assert len(kpts) == len(kptwts)
|
|
121
|
+
assert kptwts[0] == 1
|
|
122
|
+
|
|
123
|
+
nk = np.sum(kptwts)
|
|
124
|
+
kpts_full = np.empty((nk, 3), dtype='f8')
|
|
125
|
+
pos = 0
|
|
126
|
+
ikhs = -1
|
|
127
|
+
for ikhs in range(1, len(kpts)):
|
|
128
|
+
wk = kptwts[ikhs]
|
|
129
|
+
arange = np.arange(0., 1., 1/wk)
|
|
130
|
+
kstart = kpts[ikhs-1]
|
|
131
|
+
kend = kpts[ikhs]
|
|
132
|
+
kpts_full[pos:pos+wk, :] = kstart[None, :] + (kend - kstart)[None, :] * arange[:, None]
|
|
133
|
+
pos += wk
|
|
134
|
+
kpts_full[pos, :] = kpts[ikhs]
|
|
135
|
+
pos += 1
|
|
136
|
+
assert pos == nk
|
|
137
|
+
|
|
138
|
+
elif type == 'grid':
|
|
139
|
+
kpts_full = kpts
|
|
140
|
+
else:
|
|
141
|
+
raise NotImplementedError(type)
|
|
142
|
+
|
|
143
|
+
self.nk = len(kpts_full)
|
|
144
|
+
self.kpts = kpts_full
|
|
145
|
+
self.hskpos = list(np.concatenate(([0], np.cumsum(kptwts)[:-1])))
|
|
146
|
+
self.hsksymbol = kptsymbol
|
|
147
|
+
|
|
148
|
+
# print(self.kpts)
|
|
149
|
+
# print(self.hskpos)
|
|
150
|
+
# print(self.kpts[self.hskpos])
|
|
151
|
+
|
|
152
|
+
if comm is not None:
|
|
153
|
+
# distribute kpoints into groups
|
|
154
|
+
|
|
155
|
+
if nkpools is None:
|
|
156
|
+
nkpools = min(self.nk, comm.size)
|
|
157
|
+
assert nkpools <= comm.size
|
|
158
|
+
|
|
159
|
+
count_proc, displ_proc = distrib_grps(comm.size, nkpools, displ_last_elem=True)
|
|
160
|
+
igrp = np.searchsorted(displ_proc, comm.rank, side='right') - 1
|
|
161
|
+
if nkpools == min(self.nk, comm.size):
|
|
162
|
+
comm_pool = MPI.COMM_SELF
|
|
163
|
+
else:
|
|
164
|
+
msg = 'Number of k point pools must be equal to min(# k points, # processors) when slepc4py is not installed'
|
|
165
|
+
assert use_slepc4py, msg
|
|
166
|
+
comm_pool = comm.Split(color=igrp, key=comm.rank)
|
|
167
|
+
# comm_pool = comm.Split(color=igrp, key=comm.rank)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
else:
|
|
171
|
+
igrp = 0
|
|
172
|
+
count_proc = [1]
|
|
173
|
+
comm_pool = None
|
|
174
|
+
nkpools = 1
|
|
175
|
+
|
|
176
|
+
self.igrp = igrp
|
|
177
|
+
self.count_proc = count_proc
|
|
178
|
+
self.comm_pool = comm_pool
|
|
179
|
+
self.nkpools = nkpools
|
|
180
|
+
|
|
181
|
+
@mpi_watch
|
|
182
|
+
@simple_timer('\nJob done, total wall time = {t}\n')
|
|
183
|
+
def diag(self, nbnd, efermi=None, tole=1e-8, max_it=100, sort=None, ill_project=False, ill_threshold=1e-3):
|
|
184
|
+
'''
|
|
185
|
+
efermi is provided in eV, not Hartree
|
|
186
|
+
|
|
187
|
+
Parameters:
|
|
188
|
+
---------
|
|
189
|
+
ill_project: whether to project out eigenvalues and eigenvectors living in the ill-conditioned subspace
|
|
190
|
+
of the overlap matrix
|
|
191
|
+
ill_threshold: eigenvalues of S with absolute value smaller than this value are considered as ill-conditioned
|
|
192
|
+
'''
|
|
193
|
+
|
|
194
|
+
if efermi is not None:
|
|
195
|
+
efermi /= hartree2ev
|
|
196
|
+
|
|
197
|
+
if sort is None:
|
|
198
|
+
# sort is by default True if efermi not provided
|
|
199
|
+
sort = efermi is None
|
|
200
|
+
|
|
201
|
+
# distribute kpoints into groups
|
|
202
|
+
comm_pool = self.comm_pool
|
|
203
|
+
count_k, displ_k = distrib_grps(self.nk, self.nkpools, displ_last_elem=True)
|
|
204
|
+
nkloc = count_k[self.igrp]
|
|
205
|
+
if is_master():
|
|
206
|
+
print('\nParallization report:')
|
|
207
|
+
print('Total number of k points:', self.nk)
|
|
208
|
+
if comm is not None:
|
|
209
|
+
print('Total number of MPI tasks:', comm.size)
|
|
210
|
+
else:
|
|
211
|
+
print('Module mpi4py not found, executing serially')
|
|
212
|
+
print(f'K points are distributed into {self.nkpools} pools')
|
|
213
|
+
print(f'Each pool has {np.min(self.count_proc)} to {np.max(self.count_proc)} MPI tasks')
|
|
214
|
+
print(' Note: if the above number is larger than 1, please make sure MKL cluster Pardiso is linked to PETSc')
|
|
215
|
+
print(f'Each pool is dealing with {np.min(count_k)} to {np.max(count_k)} k-points')
|
|
216
|
+
print(f'Each MPI task has {os.environ.get("OMP_NUM_THREADS", 1)} OMP threads\n')
|
|
217
|
+
|
|
218
|
+
if use_slepc4py:
|
|
219
|
+
print('Using SLEPc diagonalization with MKL Pardiso')
|
|
220
|
+
else:
|
|
221
|
+
print('Using scipy diagonalization with ARPACK')
|
|
222
|
+
|
|
223
|
+
if ill_project:
|
|
224
|
+
if use_slepc4py:
|
|
225
|
+
print('WARNING: ill_project is not supported when using SLEPc diagonalization, ill_project will be ignored')
|
|
226
|
+
else:
|
|
227
|
+
print(f'Projecting out ill-conditioned subspace of the overlap matrix. Projected out subspace will be filled with eigenvalues {ILL_EIG_FILLING} eV and all-zero eigenvectors.')
|
|
228
|
+
|
|
229
|
+
eigs = np.empty((nkloc, nbnd), dtype='f8')
|
|
230
|
+
if is_master(comm=comm_pool):
|
|
231
|
+
wfnao = np.empty((nkloc, nbnd, self.nao), dtype='c16')
|
|
232
|
+
else:
|
|
233
|
+
wfnao = None
|
|
234
|
+
|
|
235
|
+
if is_master(): print('Begin diagonalization')
|
|
236
|
+
for ikpt in mytqdm(range(count_k[self.igrp])):
|
|
237
|
+
kpt = self.kpts[ikpt + displ_k[self.igrp]]
|
|
238
|
+
|
|
239
|
+
if is_master(comm=comm_pool):
|
|
240
|
+
Hk = self.matH.r2k(kpt)
|
|
241
|
+
Sk = self.matS.r2k(kpt)
|
|
242
|
+
if use_slepc4py:
|
|
243
|
+
Hpetsc = mat_scipy2petsc(Hk, comm=comm_pool)
|
|
244
|
+
Spetsc = mat_scipy2petsc(Sk, comm=comm_pool)
|
|
245
|
+
else:
|
|
246
|
+
if use_slepc4py:
|
|
247
|
+
Hpetsc = mat_scipy2petsc(None, comm=comm_pool)
|
|
248
|
+
Spetsc = mat_scipy2petsc(None, comm=comm_pool)
|
|
249
|
+
|
|
250
|
+
if use_slepc4py:
|
|
251
|
+
if efermi is None:
|
|
252
|
+
eigmax, _ = diag_slepc(Hpetsc, Spetsc, 1, 'LM', tole=0.1, comm=comm_pool)
|
|
253
|
+
eigmax = eigmax.item()
|
|
254
|
+
if eigmax > 0:
|
|
255
|
+
eigmin, _ = diag_slepc(Hpetsc - eigmax * Spetsc, Spetsc, 1, 'LM', tole=0.1, comm=comm_pool)
|
|
256
|
+
eigmin = eigmin.item()
|
|
257
|
+
sigma = eigmin + eigmax
|
|
258
|
+
else:
|
|
259
|
+
sigma = eigmax
|
|
260
|
+
else:
|
|
261
|
+
sigma = efermi
|
|
262
|
+
eigs_k, vecs_k = diag_slepc(Hpetsc, Spetsc, nbnd, 'TR', sigma=sigma, comm=comm_pool, tole=tole, max_it=max_it)
|
|
263
|
+
|
|
264
|
+
Hpetsc.destroy()
|
|
265
|
+
Spetsc.destroy()
|
|
266
|
+
|
|
267
|
+
else:
|
|
268
|
+
assert is_master(comm_pool)
|
|
269
|
+
if efermi is None:
|
|
270
|
+
eigs_k, vecs_k = eigsh(Hk, k=nbnd, M=Sk, which='SR', tol=tole, maxiter=max_it)
|
|
271
|
+
else:
|
|
272
|
+
eigs_k, vecs_k = eigsh(Hk, k=nbnd, M=Sk, sigma=efermi, tol=tole, maxiter=max_it)
|
|
273
|
+
|
|
274
|
+
# project out the ill-conditioned subspace of S_k
|
|
275
|
+
if ill_project:
|
|
276
|
+
Q, _ = qr(vecs_k) # orthogonalize the eigenvectors of H_k to make it an orthonormal basis
|
|
277
|
+
Q = Q[:,:nbnd] # shape: (nbasis, nbnd)
|
|
278
|
+
Sk_sub = Q.T.conj() @ Sk @ Q # shape: (nbnd, nbnd)
|
|
279
|
+
eigs_Sk, vecs_Sk = eigh(Sk_sub)
|
|
280
|
+
project_index = np.where(np.abs(eigs_Sk) > ill_threshold)[0]
|
|
281
|
+
# if len(project_index) < len(eigs_Sk):
|
|
282
|
+
# print(f"ill-conditioned eigenvalues detected, projected out {(len(eigs_Sk) - len(project_index))} eigenvalues")
|
|
283
|
+
vecs_Sk = vecs_Sk[:,project_index]
|
|
284
|
+
projector = Q @ vecs_Sk
|
|
285
|
+
Sk_sub = projector.conj().T @ Sk @ projector
|
|
286
|
+
Hk_sub = projector.conj().T @ Hk @ projector
|
|
287
|
+
eigs_k_sub, vecs_k_sub = eigh(Hk_sub, Sk_sub)
|
|
288
|
+
assert np.all(eigs_k_sub < ILL_EIG_FILLING/hartree2ev)
|
|
289
|
+
eigs_k = np.concatenate((eigs_k_sub, np.full((nbnd-len(eigs_k_sub),), ILL_EIG_FILLING/hartree2ev)))
|
|
290
|
+
vecs_k = np.zeros((self.nao, nbnd), dtype='c16')
|
|
291
|
+
vecs_k[:, :len(eigs_k_sub)] = projector @ vecs_k_sub
|
|
292
|
+
|
|
293
|
+
vecs_k = vecs_k.T
|
|
294
|
+
|
|
295
|
+
if sort:
|
|
296
|
+
argsort = np.argsort(eigs_k)
|
|
297
|
+
eigs_k = eigs_k[argsort]
|
|
298
|
+
if is_master(comm_pool): vecs_k = vecs_k[argsort, :]
|
|
299
|
+
|
|
300
|
+
eigs[ikpt, :] = eigs_k
|
|
301
|
+
if is_master(comm=comm_pool):
|
|
302
|
+
wfnao[ikpt, :, :] = vecs_k
|
|
303
|
+
|
|
304
|
+
# Collect eigs and wfnao from groups
|
|
305
|
+
if comm is not None:
|
|
306
|
+
comm_m = comm.Split(color=0 if is_master(comm=comm_pool) else 1, key=comm.rank)
|
|
307
|
+
if is_master(comm=comm_pool):
|
|
308
|
+
assert comm_m.rank == self.igrp
|
|
309
|
+
if is_master(comm=comm_m):
|
|
310
|
+
eigs_recv = np.empty((self.nk, nbnd), dtype='f8')
|
|
311
|
+
wfnao_recv = np.empty((self.nk, nbnd, self.nao), dtype='c16')
|
|
312
|
+
else:
|
|
313
|
+
eigs_recv = wfnao_recv = None
|
|
314
|
+
comm_m.Gatherv([eigs, nkloc * nbnd, MPI.REAL8],
|
|
315
|
+
[eigs_recv, count_k*nbnd, displ_k[:-1]*nbnd, MPI.REAL8], root=0)
|
|
316
|
+
comm_m.Gatherv([wfnao, nkloc*nbnd*self.nao, MPI.COMPLEX16],
|
|
317
|
+
[wfnao_recv, count_k*nbnd*self.nao, displ_k[:-1]*nbnd*self.nao, MPI.COMPLEX16], root=0)
|
|
318
|
+
eigs = eigs_recv
|
|
319
|
+
wfnao = wfnao_recv
|
|
320
|
+
|
|
321
|
+
if is_master(comm=comm):
|
|
322
|
+
for ikpt in range(self.nk):
|
|
323
|
+
kpt = self.kpts[ikpt]
|
|
324
|
+
print(f'k ={kpt[0]:9.5f}{kpt[1]:9.5f}{kpt[2]:9.5f} nbnd ={nbnd:4d}', end='')
|
|
325
|
+
if self.hsksymbol is None:
|
|
326
|
+
print()
|
|
327
|
+
elif ikpt in self.hskpos:
|
|
328
|
+
print(' ', self.hsksymbol[self.hskpos.index(ikpt)])
|
|
329
|
+
else:
|
|
330
|
+
print()
|
|
331
|
+
for ibnd in range(nbnd):
|
|
332
|
+
print(f' {eigs[ikpt, ibnd]*hartree2ev:9.4f}', end='')
|
|
333
|
+
if ibnd % 8 == 7:
|
|
334
|
+
print()
|
|
335
|
+
if ibnd % 8 != 7:
|
|
336
|
+
print()
|
|
337
|
+
|
|
338
|
+
# debug: check wfn
|
|
339
|
+
# wfn = wfnao[ikpt, 0]
|
|
340
|
+
# Hk = self.matH.r2k(kpt)
|
|
341
|
+
# Sk = self.matS.r2k(kpt)
|
|
342
|
+
# print(np.sum(Sk.dot(wfn) * wfn.conj()))
|
|
343
|
+
# print(np.sum(Hk.dot(wfn) * wfn.conj() * hartree2ev))
|
|
344
|
+
|
|
345
|
+
self.eigs = eigs
|
|
346
|
+
self.wfnao = wfnao
|
|
347
|
+
|
|
348
|
+
@mpi_watch
|
|
349
|
+
def write(self, path='./', eigfname='eig.dat'):
|
|
350
|
+
if not is_master():
|
|
351
|
+
return
|
|
352
|
+
os.makedirs(path, exist_ok=True)
|
|
353
|
+
nbnd = self.eigs.shape[1]
|
|
354
|
+
f = open(f'{path}/{eigfname}', 'w')
|
|
355
|
+
f.write('Band energies in eV\n')
|
|
356
|
+
f.write(' nk nbnd\n')
|
|
357
|
+
f.write(f'{self.nk:8d} {nbnd:8d}\n')
|
|
358
|
+
for ikpt in range(self.nk):
|
|
359
|
+
kpt = self.kpts[ikpt]
|
|
360
|
+
f.write(f' {kpt[0]:12.9f} {kpt[1]:12.9f} {kpt[2]:12.9f} {nbnd:7d}')
|
|
361
|
+
if ikpt in self.hskpos:
|
|
362
|
+
f.write(' ' + self.hsksymbol[self.hskpos.index(ikpt)] + '\n')
|
|
363
|
+
else:
|
|
364
|
+
f.write('\n')
|
|
365
|
+
for ibnd in range(nbnd):
|
|
366
|
+
f.write(f' {1:7d} {ibnd+1:7d} {self.eigs[ikpt, ibnd]*hartree2ev:14.9f}\n')
|
|
367
|
+
f.close()
|
|
368
|
+
# todo: write wavefunctions
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def mat_scipy2petsc(matcsr, comm=comm):
|
|
372
|
+
if is_master(comm=comm):
|
|
373
|
+
auxdata = np.array([matcsr.shape[0], matcsr.shape[1], len(matcsr.indptr), len(matcsr.indices)], dtype='i8')
|
|
374
|
+
else:
|
|
375
|
+
auxdata = np.empty(4, dtype='i8')
|
|
376
|
+
if comm is not None:
|
|
377
|
+
comm.Bcast([auxdata, 4, MPI.INTEGER8], root=0)
|
|
378
|
+
shape1, shape2, len_indptr, len_data = auxdata
|
|
379
|
+
|
|
380
|
+
# if is_master():
|
|
381
|
+
# print('Matrix size:', shape1)
|
|
382
|
+
|
|
383
|
+
A = PETSc.Mat().create(comm=comm)
|
|
384
|
+
A.setSizes([shape1, shape2])
|
|
385
|
+
A.setFromOptions()
|
|
386
|
+
A.setUp()
|
|
387
|
+
|
|
388
|
+
ranges = A.getOwnershipRanges()
|
|
389
|
+
rstart, rend = A.getOwnershipRange()
|
|
390
|
+
|
|
391
|
+
if is_master(comm=comm):
|
|
392
|
+
indptr = matcsr.indptr
|
|
393
|
+
assert indptr.dtype == np.int32
|
|
394
|
+
else:
|
|
395
|
+
indptr = np.empty(len_indptr, dtype='i4')
|
|
396
|
+
if comm is not None:
|
|
397
|
+
comm.Bcast([indptr, len_indptr, MPI.INTEGER4], root=0)
|
|
398
|
+
|
|
399
|
+
# indices
|
|
400
|
+
ranges_dat = indptr[ranges]
|
|
401
|
+
counts = np.diff(ranges_dat)
|
|
402
|
+
disps = ranges_dat[:-1]
|
|
403
|
+
if is_master(comm=comm):
|
|
404
|
+
send = matcsr.indices
|
|
405
|
+
assert send.dtype == np.int32
|
|
406
|
+
else:
|
|
407
|
+
send = None
|
|
408
|
+
if comm is not None:
|
|
409
|
+
count_loc = counts[comm.rank]
|
|
410
|
+
indices = np.empty(count_loc, dtype='i4')
|
|
411
|
+
comm.Scatterv([send, counts, disps, MPI.INTEGER4],
|
|
412
|
+
[indices, count_loc, MPI.INTEGER4], root=0)
|
|
413
|
+
else:
|
|
414
|
+
indices = send
|
|
415
|
+
|
|
416
|
+
# data
|
|
417
|
+
if is_master(comm=comm):
|
|
418
|
+
send = matcsr.data
|
|
419
|
+
assert send.dtype == np.complex128
|
|
420
|
+
else:
|
|
421
|
+
send = None
|
|
422
|
+
if comm is not None:
|
|
423
|
+
count_loc = counts[comm.rank]
|
|
424
|
+
data = np.empty(count_loc, dtype='c16')
|
|
425
|
+
comm.Scatterv([send, counts, disps, MPI.COMPLEX16],
|
|
426
|
+
[data, count_loc, MPI.COMPLEX16], root=0)
|
|
427
|
+
else:
|
|
428
|
+
data = send
|
|
429
|
+
|
|
430
|
+
indptr = indptr[rstart:rend+1] - indptr[rstart]
|
|
431
|
+
A.setValuesCSR(indptr, indices, data)
|
|
432
|
+
A.assemble()
|
|
433
|
+
|
|
434
|
+
return A
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def diag_slepc(matA, matB, nev, which, sigma=None, tole=1e-8, max_it=100, PC=None, comm=comm):
|
|
438
|
+
'''
|
|
439
|
+
matA, matB: PETSc matrices
|
|
440
|
+
nev: number of eigenvalues
|
|
441
|
+
which: LM = largest magnitude; TR = target real
|
|
442
|
+
sigma: must provide sigma when which=TR
|
|
443
|
+
'''
|
|
444
|
+
|
|
445
|
+
size, _ = matA.getSize()
|
|
446
|
+
# get the ownership of petsc vectors within pool
|
|
447
|
+
V = PETSc.Vec().create(comm=comm)
|
|
448
|
+
V.setSizes(size)
|
|
449
|
+
V.setUp()
|
|
450
|
+
vranges = V.getOwnershipRanges()
|
|
451
|
+
vrange_loc = V.getOwnershipRange()
|
|
452
|
+
V.destroy()
|
|
453
|
+
# print(vranges)
|
|
454
|
+
# print(vrange_loc)
|
|
455
|
+
vec_loc = np.empty(vrange_loc[1] - vrange_loc[0], dtype='c16')
|
|
456
|
+
counts_vec = np.diff(vranges)
|
|
457
|
+
disps_vec = vranges[:-1]
|
|
458
|
+
|
|
459
|
+
eigs = np.empty(nev)
|
|
460
|
+
if is_master(comm):
|
|
461
|
+
vecs = np.empty((nev, size), dtype='c16')
|
|
462
|
+
else:
|
|
463
|
+
vecs = None
|
|
464
|
+
|
|
465
|
+
Eps = SLEPc.EPS()
|
|
466
|
+
Eps.create(comm=comm)
|
|
467
|
+
Eps.setOperators(matA, matB)
|
|
468
|
+
Eps.setProblemType(SLEPc.EPS.ProblemType.GHEP)
|
|
469
|
+
Eps.setDimensions(nev=nev)
|
|
470
|
+
Eps.setType(Eps.Type.KRYLOVSCHUR)
|
|
471
|
+
if which == 'TR':
|
|
472
|
+
assert sigma is not None
|
|
473
|
+
Eps.setWhichEigenpairs(Eps.Which.TARGET_MAGNITUDE)
|
|
474
|
+
Eps.setTarget(sigma)
|
|
475
|
+
elif which == 'LM':
|
|
476
|
+
Eps.setWhichEigenpairs(Eps.Which.LARGEST_MAGNITUDE)
|
|
477
|
+
else:
|
|
478
|
+
raise NotImplementedError(which)
|
|
479
|
+
Eps.setTolerances(tol=tole, max_it=max_it)
|
|
480
|
+
Eps.setFromOptions()
|
|
481
|
+
|
|
482
|
+
# set numerical tolerence: sometimes we have nonzero imaginary part of inner product,
|
|
483
|
+
# we want to ignore these by increasing tolerance
|
|
484
|
+
BV = Eps.getBV()
|
|
485
|
+
BV.setDefiniteTolerance(1e-8)
|
|
486
|
+
|
|
487
|
+
ST = Eps.getST()
|
|
488
|
+
KSP = ST.getKSP()
|
|
489
|
+
if which == 'TR':
|
|
490
|
+
# set spectral transformation type
|
|
491
|
+
ST.setType(ST.Type.SINVERT) # shift-and-invert is the most stable
|
|
492
|
+
elif which == 'LM':
|
|
493
|
+
pass
|
|
494
|
+
|
|
495
|
+
if PC is None:
|
|
496
|
+
PC = KSP.getPC()
|
|
497
|
+
# set factorization solver
|
|
498
|
+
PC.setType(PC.Type.LU)
|
|
499
|
+
if comm.size == 1:
|
|
500
|
+
PC.setFactorSolverType(PETSc.Mat().SolverType.MKL_PARDISO)
|
|
501
|
+
else:
|
|
502
|
+
PC.setFactorSolverType(PETSc.Mat().SolverType.MKL_CPARDISO)
|
|
503
|
+
else:
|
|
504
|
+
KSP.setPC(PC)
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
Eps.solve()
|
|
508
|
+
|
|
509
|
+
nconv = Eps.getConverged()
|
|
510
|
+
msg = 'Some bands not converged'
|
|
511
|
+
assert nconv >= nev, msg
|
|
512
|
+
|
|
513
|
+
vr, wr = matA.getVecs()
|
|
514
|
+
vi, wi = matA.getVecs()
|
|
515
|
+
|
|
516
|
+
for iev in range(nev):
|
|
517
|
+
e = Eps.getEigenpair(iev, vr, vi)
|
|
518
|
+
eigs[iev] = e.real
|
|
519
|
+
# if ibnd == 0: print(e.real * hartree2ev)
|
|
520
|
+
vr_np = vr.getArray(readonly=True)
|
|
521
|
+
vi_np = vi.getArray(readonly=True)
|
|
522
|
+
vec_loc[:] = vr_np + 1j * vi_np
|
|
523
|
+
if comm is not None and comm.size > 1:
|
|
524
|
+
recv = vecs[iev] if is_master(comm=comm) else None
|
|
525
|
+
comm.Gatherv([vec_loc, len(vec_loc), MPI.COMPLEX16],
|
|
526
|
+
[recv, counts_vec, disps_vec, MPI.COMPLEX16], root=0)
|
|
527
|
+
else:
|
|
528
|
+
vecs[iev, :] = vec_loc
|
|
529
|
+
|
|
530
|
+
# Eps.view()
|
|
531
|
+
Eps.destroy()
|
|
532
|
+
|
|
533
|
+
return eigs, vecs
|
|
534
|
+
|
|
535
|
+
def load_eigdat(filename):
|
|
536
|
+
f = open(filename, 'r')
|
|
537
|
+
f.readline(); f.readline()
|
|
538
|
+
line_sp = f.readline().split()
|
|
539
|
+
nk, nbnd = map(int, line_sp)
|
|
540
|
+
eigs = np.empty((nk, nbnd))
|
|
541
|
+
kpts = np.empty((nk, 3))
|
|
542
|
+
hsk_idcs = []
|
|
543
|
+
hsk_symbols = []
|
|
544
|
+
line = f.readline()
|
|
545
|
+
ik = 0
|
|
546
|
+
while line:
|
|
547
|
+
line_sp = line.split()
|
|
548
|
+
if len(line_sp)>0 and '.' in line_sp[0]:
|
|
549
|
+
kpts[ik] = list(map(float, line_sp[:3]))
|
|
550
|
+
assert nbnd == int(line_sp[3])
|
|
551
|
+
if len(line_sp) == 5:
|
|
552
|
+
hsk_symbols.append(line_sp[4])
|
|
553
|
+
hsk_idcs.append(ik)
|
|
554
|
+
for _ in range(nbnd):
|
|
555
|
+
line = f.readline()
|
|
556
|
+
line_sp = line.split()
|
|
557
|
+
ibnd = int(line_sp[1]) - 1
|
|
558
|
+
eigs[ik, ibnd] = float(line_sp[2])
|
|
559
|
+
ik += 1
|
|
560
|
+
line = f.readline()
|
|
561
|
+
assert ik == nk
|
|
562
|
+
f.close()
|
|
563
|
+
return eigs
|
HPRO/config.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from math import sqrt
|
|
2
|
+
|
|
3
|
+
# Spherical harmonics
|
|
4
|
+
SPHERICAL_HARMONICS_LMAX = 10 # Maximum angular momentum for spherical harmonics
|
|
5
|
+
|
|
6
|
+
# pairs info
|
|
7
|
+
BASE_TRANSLATIONS = 20 # Assume all primitive translations are within [-BASE//2, BASE//2)
|
|
8
|
+
|
|
9
|
+
# two-center integrals
|
|
10
|
+
TWOCENTER_RGRID_DEN = 100. / 12. # 100 points at 12 bohr
|
|
11
|
+
AOFT_QGRID_DEN = 1 / sqrt(500) * 2048 # 2048 points at 500 Hartree
|
|
12
|
+
|
|
13
|
+
# mataocsr to matao
|
|
14
|
+
DEBUG_CSR_CNVRT = False
|
|
15
|
+
|
|
16
|
+
# real-space integrals
|
|
17
|
+
GRIDINTG_NSUBDIV_RANGE = (13, 20)
|
|
18
|
+
GRIDINTG_USE_HERMITICITY = False
|
|
19
|
+
GRIDINTG_ENABLE_TQDM = True
|
|
20
|
+
|
|
21
|
+
# use new deeph data interface
|
|
22
|
+
DEEPH_USE_NEW_INTERFACE = True
|