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 ADDED
@@ -0,0 +1,5 @@
1
+ from .kernel import PW2AOkernel
2
+ from .aodiag import AODiagKernel
3
+ from .utils.misc import Timer
4
+
5
+ __version__ = "0.3.0"
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
HPRO/constants.py ADDED
@@ -0,0 +1,6 @@
1
+ import numpy as np
2
+
3
+ hartree2ev = 27.211386024367243
4
+ bohr2ang = 0.5291772105638411
5
+
6
+ hpro_rng = np.random.default_rng(seed=42)