QAssemble 1.0.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.
- QAssemble/BLatDyn.py +725 -0
- QAssemble/BLatDyn.py.bak +730 -0
- QAssemble/BLatStc.py +1016 -0
- QAssemble/BLocStc.py +694 -0
- QAssemble/BPathStc.py +87 -0
- QAssemble/CLI.py +26 -0
- QAssemble/CorrelationFunction.py +320 -0
- QAssemble/Crystal.py +1020 -0
- QAssemble/FLatDyn.py +991 -0
- QAssemble/FLatDyn.py.bak +923 -0
- QAssemble/FLatStc.py +1475 -0
- QAssemble/FPathDyn.py +533 -0
- QAssemble/FPathStc.py +581 -0
- QAssemble/Run.py +606 -0
- QAssemble/__init__.py +61 -0
- QAssemble/__main__.py +4 -0
- QAssemble/migrate_hdf5.py +175 -0
- QAssemble/utility/Bare.py +374 -0
- QAssemble/utility/Common.py +481 -0
- QAssemble/utility/DLR.py +246 -0
- QAssemble/utility/Dyson.py +163 -0
- QAssemble/utility/Dyson.py.bak +165 -0
- QAssemble/utility/Embedding.py +289 -0
- QAssemble/utility/Fourier.py +611 -0
- QAssemble/utility/Mixing.py +124 -0
- QAssemble/utility/Projection.py +235 -0
- QAssemble/utility/__init__.py +1 -0
- QAssemble/utility/test/TestCommon.ipynb +199 -0
- QAssemble/utility/test/TestFourierFT.py +84 -0
- qassemble-1.0.0.dist-info/METADATA +282 -0
- qassemble-1.0.0.dist-info/RECORD +35 -0
- qassemble-1.0.0.dist-info/WHEEL +5 -0
- qassemble-1.0.0.dist-info/entry_points.txt +3 -0
- qassemble-1.0.0.dist-info/licenses/LICENSE +674 -0
- qassemble-1.0.0.dist-info/top_level.txt +1 -0
QAssemble/BLatDyn.py
ADDED
|
@@ -0,0 +1,725 @@
|
|
|
1
|
+
"""Dynamic bosonic lattice quantities, polarization, and screened interactions."""
|
|
2
|
+
import numpy as np
|
|
3
|
+
import sys, os
|
|
4
|
+
import itertools
|
|
5
|
+
import copy, gc, time, datetime
|
|
6
|
+
import h5py
|
|
7
|
+
from .Crystal import Crystal
|
|
8
|
+
from .BLatStc import V
|
|
9
|
+
from .utility.DLR import DLR
|
|
10
|
+
from .utility.Fourier import Fourier
|
|
11
|
+
from .utility.Dyson import Dyson
|
|
12
|
+
from .utility.Mixing import Mixing
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BLatDyn(object):
|
|
16
|
+
"""Base operations for dynamic bosonic lattice tensors."""
|
|
17
|
+
def __init__(self, crystal: Crystal, dlr: DLR, mixing_method: str = "pulay", npulay: int = 5):
|
|
18
|
+
"""Initialize the object and prepare derived state."""
|
|
19
|
+
self.crystal = crystal
|
|
20
|
+
self.dlr = dlr
|
|
21
|
+
self.mixer = Mixing(method=mixing_method, npulay=npulay)
|
|
22
|
+
# self.flatdyn = flatdyn
|
|
23
|
+
self._boson_phase_cache_k2r = self._get_boson_phaseK2R()
|
|
24
|
+
self._boson_phase_cache_r2k = self._get_boson_phaseR2K()
|
|
25
|
+
|
|
26
|
+
def _get_boson_phaseK2R(self) -> np.ndarray:
|
|
27
|
+
"""Build the phase matrix for bosonic k-to-real-space transforms."""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
nrk = self.crystal.rkgrid[0]*self.crystal.rkgrid[1]*self.crystal.rkgrid[2]
|
|
31
|
+
|
|
32
|
+
basis_orb = self.crystal.basisf[self.crystal.borb2atom]
|
|
33
|
+
|
|
34
|
+
kv = self.crystal.kpoint[:nrk] @ basis_orb.T
|
|
35
|
+
|
|
36
|
+
kv_delta = kv[:, :, None] - kv[:, None, :]
|
|
37
|
+
phases = np.exp(2.0j * np.pi * kv_delta)
|
|
38
|
+
phases_T = np.transpose(phases, (1, 2, 0))
|
|
39
|
+
|
|
40
|
+
return phases_T
|
|
41
|
+
|
|
42
|
+
def _get_boson_phaseR2K(self) -> np.ndarray:
|
|
43
|
+
"""Build the phase matrix for bosonic real-to-k-space transforms."""
|
|
44
|
+
|
|
45
|
+
nrk = self.crystal.rkgrid[0]*self.crystal.rkgrid[1]*self.crystal.rkgrid[2]
|
|
46
|
+
|
|
47
|
+
basis_orb = self.crystal.basisf[self.crystal.borb2atom]
|
|
48
|
+
|
|
49
|
+
kv = self.crystal.kpoint[:nrk] @ basis_orb.T
|
|
50
|
+
|
|
51
|
+
kv_delta = kv[:, :, None] - kv[:, None, :]
|
|
52
|
+
phases = np.exp(-2.0j * np.pi * kv_delta)
|
|
53
|
+
phases_T = np.transpose(phases, (1, 2, 0))
|
|
54
|
+
|
|
55
|
+
return phases_T
|
|
56
|
+
|
|
57
|
+
def Inverse(self, matin: np.ndarray) -> np.ndarray:
|
|
58
|
+
"""Return block-wise matrix inverses for the input tensor."""
|
|
59
|
+
norb = matin.shape[0]
|
|
60
|
+
ns = matin.shape[2]
|
|
61
|
+
nrk = matin.shape[4]
|
|
62
|
+
nft = matin.shape[5]
|
|
63
|
+
|
|
64
|
+
matout = np.zeros((norb, norb, ns, ns, nrk, nft), dtype=np.complex128, order="F")
|
|
65
|
+
tempmat = np.zeros((norb * ns, norb * ns), dtype=np.complex128)
|
|
66
|
+
tempmat2 = np.zeros((norb * ns, norb * ns), dtype=np.complex128)
|
|
67
|
+
|
|
68
|
+
# Make composite matrix #
|
|
69
|
+
for ift in range(nft):
|
|
70
|
+
for irk in range(nrk):
|
|
71
|
+
tempmat = self.crystal.OrbSpin2Composite(matin[:, :, :, :, irk, ift])
|
|
72
|
+
tempmat2 = np.linalg.inv(tempmat)
|
|
73
|
+
matout[:, :, :, :, irk, ift] = self.crystal.Composite2OrbSpin(tempmat2)
|
|
74
|
+
|
|
75
|
+
return matout
|
|
76
|
+
|
|
77
|
+
def Moment(self, bf: np.ndarray, oddzero: bool, highzero: bool) -> tuple:
|
|
78
|
+
"""Compute moment corrections for imaginary-frequency transforms."""
|
|
79
|
+
norb = bf.shape[0]
|
|
80
|
+
ns = bf.shape[2]
|
|
81
|
+
nrk = bf.shape[4]
|
|
82
|
+
|
|
83
|
+
moment = np.zeros((norb, norb, ns, ns, nrk, 3), dtype=np.complex128, order="F")
|
|
84
|
+
high = np.zeros((norb, norb, ns, nrk), dtype=np.complex128, order="F")
|
|
85
|
+
|
|
86
|
+
# moment, high = QAFort.fourier.blatdyn_m(self.dlr.nu, bf, oddzero, highzero)
|
|
87
|
+
moment, high = Fourier.BLatDynM(self.dlr.nu, bf, oddzero, highzero)
|
|
88
|
+
|
|
89
|
+
return moment, high
|
|
90
|
+
|
|
91
|
+
def F2T(self, bf: np.ndarray) -> np.ndarray:
|
|
92
|
+
"""Transform data from Matsubara frequency to imaginary time."""
|
|
93
|
+
norb = bf.shape[0]
|
|
94
|
+
ns = bf.shape[2]
|
|
95
|
+
nrk = bf.shape[4]
|
|
96
|
+
nfreq = bf.shape[5]
|
|
97
|
+
|
|
98
|
+
bf_t = np.moveaxis(bf, -1, 0) # (nfreq, norb, norb, ns, ns, nrk)
|
|
99
|
+
batch = norb * norb * ns * ns * nrk
|
|
100
|
+
bf_2d = np.ascontiguousarray(bf_t).reshape(nfreq, batch)
|
|
101
|
+
|
|
102
|
+
# Boson: dlr_from_matsubara uses bosonic_corr_x[:, None, None]
|
|
103
|
+
# which requires 3D input. Solve lu_solve in 2D, then apply correction.
|
|
104
|
+
from scipy.linalg import lu_solve
|
|
105
|
+
G_xaa = lu_solve((self.dlr.dB.dlrmf2cf, self.dlr.dB.mf2cfpiv), bf_2d / self.dlr.beta)
|
|
106
|
+
G_xaa /= self.dlr.dB.bosonic_corr_x[:, None]
|
|
107
|
+
|
|
108
|
+
btau_2d = np.tensordot(self.dlr.dB.T_lx, G_xaa, axes=(1, 0))
|
|
109
|
+
ntau = btau_2d.shape[0]
|
|
110
|
+
btau = btau_2d.reshape(ntau, norb, norb, ns, ns, nrk)
|
|
111
|
+
btau = np.moveaxis(btau, 0, -1) # (norb, norb, ns, ns, nrk, ntau)
|
|
112
|
+
btau = np.asfortranarray(btau)
|
|
113
|
+
|
|
114
|
+
return btau
|
|
115
|
+
|
|
116
|
+
def T2F(self, btau: np.ndarray) -> np.ndarray:
|
|
117
|
+
"""Transform data from imaginary time to Matsubara frequency."""
|
|
118
|
+
norb = btau.shape[0]
|
|
119
|
+
ns = btau.shape[2]
|
|
120
|
+
nrk = btau.shape[4]
|
|
121
|
+
ntau = btau.shape[5]
|
|
122
|
+
|
|
123
|
+
btau_t = np.moveaxis(btau, -1, 0) # (ntau, norb, norb, ns, ns, nrk)
|
|
124
|
+
batch = norb * norb * ns * ns * nrk
|
|
125
|
+
btau_2d = np.ascontiguousarray(btau_t).reshape(ntau, batch)
|
|
126
|
+
|
|
127
|
+
# Boson: lu_solve in 2D, then matsubara_from_dlr manually
|
|
128
|
+
from scipy.linalg import lu_solve
|
|
129
|
+
fxx = lu_solve((self.dlr.dB.dlrit2cf, self.dlr.dB.it2cfpiv), btau_2d)
|
|
130
|
+
bf_2d = self.dlr.beta * np.tensordot(
|
|
131
|
+
self.dlr.dB.T_qx * self.dlr.dB.bosonic_corr_x[None, :], fxx, axes=(1, 0))
|
|
132
|
+
nfreq = bf_2d.shape[0]
|
|
133
|
+
bf = bf_2d.reshape(nfreq, norb, norb, ns, ns, nrk)
|
|
134
|
+
bf = np.moveaxis(bf, 0, -1) # (norb, norb, ns, ns, nrk, nfreq)
|
|
135
|
+
bf = np.asfortranarray(bf)
|
|
136
|
+
|
|
137
|
+
return bf
|
|
138
|
+
|
|
139
|
+
def K2R(self, matk: np.ndarray) -> np.ndarray:
|
|
140
|
+
"""Transform lattice data from reciprocal space to real space."""
|
|
141
|
+
|
|
142
|
+
norb = matk.shape[0]
|
|
143
|
+
ns = matk.shape[2]
|
|
144
|
+
nrk = matk.shape[4]
|
|
145
|
+
nft = matk.shape[5]
|
|
146
|
+
|
|
147
|
+
matr = np.zeros((norb, norb, ns, ns, nrk, nft), dtype=np.complex128, order="F")
|
|
148
|
+
tempmat = matk.copy()
|
|
149
|
+
tempmat *= self._boson_phase_cache_k2r[:, :, None, None, :, None]
|
|
150
|
+
|
|
151
|
+
matr = Fourier.BLatDynK2R(tempmat, self.crystal.rkgrid)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
return matr
|
|
155
|
+
|
|
156
|
+
def R2K(self, matr: np.ndarray) -> np.ndarray:
|
|
157
|
+
"""Transform lattice data from real space to reciprocal space."""
|
|
158
|
+
norb = matr.shape[0]
|
|
159
|
+
ns = matr.shape[2]
|
|
160
|
+
nrk = matr.shape[4]
|
|
161
|
+
nft = matr.shape[5]
|
|
162
|
+
rkgrid = self.crystal.rkgrid
|
|
163
|
+
|
|
164
|
+
matk = np.zeros((norb, norb, ns, ns, nrk, nft), dtype=np.complex128, order="F")
|
|
165
|
+
tempmat = np.empty((norb, norb, ns, ns, nrk, nft), dtype=np.complex128, order="F")
|
|
166
|
+
|
|
167
|
+
tempmat = Fourier.BLatDynR2K(matr, rkgrid)
|
|
168
|
+
|
|
169
|
+
matk = tempmat * self._boson_phase_cache_r2k[:, :, None, None, :, None]
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
return matk
|
|
173
|
+
|
|
174
|
+
def GaussianLinearBroad(self, x, y, w1, temperature, cutoff):
|
|
175
|
+
"""Apply Gaussian broadening with temperature-dependent widths."""
|
|
176
|
+
norb = y.shape[0]
|
|
177
|
+
ns = y.shape[2]
|
|
178
|
+
nrk = y.shape[3]
|
|
179
|
+
nft = y.shape[4]
|
|
180
|
+
|
|
181
|
+
ynew = np.zeros((norb, norb, ns, ns, nrk, nft), dtype=np.complex128, order="F")
|
|
182
|
+
|
|
183
|
+
w0 = (1.0 - 3.0 * w1) * np.pi * temperature
|
|
184
|
+
widtharray = w0 + w1 * x
|
|
185
|
+
cnt = 0
|
|
186
|
+
for irk in range(nrk):
|
|
187
|
+
for x0 in x:
|
|
188
|
+
if x0 > cutoff + (w0 + w1 * cutoff) * 3.0:
|
|
189
|
+
ynew[..., irk, cnt] = y[..., irk, cnt]
|
|
190
|
+
else:
|
|
191
|
+
if (x0 > 3 * widtharray[cnt]) and (
|
|
192
|
+
(x[-1] - x0) > 3 * widtharray[cnt]
|
|
193
|
+
):
|
|
194
|
+
dist = (
|
|
195
|
+
1.0
|
|
196
|
+
/ np.sqrt(2 * np.pi)
|
|
197
|
+
/ widtharray[cnt]
|
|
198
|
+
* np.exp(-((x - x0) ** 2) / 2.0 / widtharray[cnt] ** 2)
|
|
199
|
+
)
|
|
200
|
+
for js in range(ns):
|
|
201
|
+
for ks in range(ns):
|
|
202
|
+
for iorb in range(norb):
|
|
203
|
+
for jorb in range(norb):
|
|
204
|
+
ynew[iorb, jorb, js, ks, irk, cnt] = sum(
|
|
205
|
+
dist * y[iorb, jorb, js, ks, irk]
|
|
206
|
+
) / sum(dist)
|
|
207
|
+
else:
|
|
208
|
+
ynew[..., irk, cnt] = y[..., irk, cnt]
|
|
209
|
+
cnt += 1
|
|
210
|
+
|
|
211
|
+
return ynew
|
|
212
|
+
|
|
213
|
+
def Mixing(self, iter: int, mix: float, Bb: np.ndarray, Bold: np.ndarray) -> np.ndarray:
|
|
214
|
+
"""Mix a new iterate with history from previous iterations."""
|
|
215
|
+
if iter == 1:
|
|
216
|
+
Bold = np.zeros_like(Bb)
|
|
217
|
+
return self.mixer(iter=iter, mix=mix, Fnew=Bb, Fold=Bold)
|
|
218
|
+
|
|
219
|
+
def Dyson(self, mat1: np.ndarray, mat2: np.ndarray) -> np.ndarray:
|
|
220
|
+
"""Solve the Dyson equation for the supplied objects."""
|
|
221
|
+
# matout = QAFort.dyson.blatdyn(mat1, mat2)
|
|
222
|
+
return Dyson.BLatDyn(mat1, mat2)
|
|
223
|
+
|
|
224
|
+
# def Projection(self, matin: np.ndarray):
|
|
225
|
+
# norbc = self.crystal.bprojector.shape[1]
|
|
226
|
+
# ns = self.crystal.ns
|
|
227
|
+
# nft = len(self.dlr.nu) # self.ft.size
|
|
228
|
+
# nspace = self.crystal.bprojector.shape[3]
|
|
229
|
+
|
|
230
|
+
# matout = np.zeros(
|
|
231
|
+
# (norbc, norbc, ns, ns, nft, nspace), dtype=np.complex128, order="F"
|
|
232
|
+
# )
|
|
233
|
+
|
|
234
|
+
# for ispace in range(nspace):
|
|
235
|
+
# matout[..., ispace] = QAFort.projection.blatdyn(
|
|
236
|
+
# matin, self.crystal.bprojector[..., ispace]
|
|
237
|
+
# )
|
|
238
|
+
|
|
239
|
+
# return matout
|
|
240
|
+
|
|
241
|
+
def Quad2Double(self, matin: np.ndarray) -> np.ndarray:
|
|
242
|
+
"""Convert a four-index tensor to paired two-index layout."""
|
|
243
|
+
# norb = len(self.crystal.bind)
|
|
244
|
+
# ns = self.crystal.ns
|
|
245
|
+
# nrk = len(self.crystal.kpoint)
|
|
246
|
+
# nft = len(self.dlr.nu)#self.ft.size
|
|
247
|
+
_, _, _, _, ns, _, nrk, nft = matin.shape
|
|
248
|
+
norb = len(self.crystal.bind)
|
|
249
|
+
|
|
250
|
+
matout = np.zeros(
|
|
251
|
+
(norb, norb, ns, ns, nrk, nft), dtype=np.complex128, order="F"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# for ift in range(nft):
|
|
255
|
+
# for irk in range(nrk):
|
|
256
|
+
for irk, ift in itertools.product(list(range(nrk)), list(range(nft))):
|
|
257
|
+
for ks, js in itertools.product(range(ns), repeat=2):
|
|
258
|
+
matout[:, :, js, ks, irk, ift] = self.crystal.Quad2Double(
|
|
259
|
+
matin[:, :, :, :, js, ks, irk, ift]
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
return matout
|
|
263
|
+
|
|
264
|
+
def Double2Quad(self, matin: np.ndarray) -> np.ndarray:
|
|
265
|
+
"""Convert a paired two-index tensor to four-index layout."""
|
|
266
|
+
norb = len(self.crystal.find)
|
|
267
|
+
# ns = self.crystal.ns
|
|
268
|
+
# nrk = len(self.crystal.kpoint)
|
|
269
|
+
# nft = len(self.dlr.nu)#self.ft.size
|
|
270
|
+
_, _, ns, _, nrk, nft = matin.shape
|
|
271
|
+
|
|
272
|
+
matout = np.zeros(
|
|
273
|
+
(norb, norb, norb, norb, ns, ns, nrk, nft), dtype=np.complex128, order="F"
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
for ift in range(nft):
|
|
277
|
+
for irk in range(nrk):
|
|
278
|
+
for ks, js in itertools.product(range(ns), repeat=2):
|
|
279
|
+
matout[:, :, :, :, js, ks, irk, ift] = self.crystal.Double2Quad(
|
|
280
|
+
matin[:, :, js, ks, irk, ift]
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
return matout
|
|
284
|
+
|
|
285
|
+
def Double2Full(self, matin: np.ndarray) -> np.ndarray:
|
|
286
|
+
"""Embed a paired two-index tensor into the full basis layout."""
|
|
287
|
+
norb = len(self.crystal.find)
|
|
288
|
+
_, _, ns, _, nrk, nft = matin.shape
|
|
289
|
+
nind = norb * norb
|
|
290
|
+
c2b = np.asarray(self.crystal.c2b, dtype=np.int64)
|
|
291
|
+
|
|
292
|
+
matout = np.zeros(
|
|
293
|
+
(nind, nind, ns, ns, nrk, nft), dtype=np.complex128, order="F"
|
|
294
|
+
)
|
|
295
|
+
matout[np.ix_(c2b, c2b)] = matin
|
|
296
|
+
|
|
297
|
+
del matin
|
|
298
|
+
gc.collect()
|
|
299
|
+
return matout
|
|
300
|
+
|
|
301
|
+
def Full2Double(self, matin: np.ndarray) -> np.ndarray:
|
|
302
|
+
"""Project a full-basis tensor into paired two-index layout."""
|
|
303
|
+
c2b = np.asarray(self.crystal.c2b, dtype=np.int64)
|
|
304
|
+
|
|
305
|
+
matout = np.asarray(matin[np.ix_(c2b, c2b)], dtype=np.complex128, order="F")
|
|
306
|
+
|
|
307
|
+
return matout
|
|
308
|
+
|
|
309
|
+
def Quad2Full(self, matin: np.ndarray) -> np.ndarray:
|
|
310
|
+
"""Embed a four-index tensor into the full basis layout."""
|
|
311
|
+
norb = len(self.crystal.find)
|
|
312
|
+
ns = self.crystal.ns
|
|
313
|
+
nrk = len(self.crystal.kpoint)
|
|
314
|
+
nft = len(self.dlr.nu) # self.ft.size
|
|
315
|
+
|
|
316
|
+
matout = np.zeros(
|
|
317
|
+
(norb * norb, norb * norb, ns, ns, nrk, nft), dtype=np.complex128, order="F"
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
for ift in range(nft):
|
|
321
|
+
for irk in range(nrk):
|
|
322
|
+
for ks, js in itertools.product(range(ns), repeat=2):
|
|
323
|
+
matout[:, :, js, ks, irk, ift] = self.crystal.Quad2Full(
|
|
324
|
+
matin[:, :, :, :, js, ks, irk, ift]
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
return matout
|
|
328
|
+
|
|
329
|
+
def Full2Quad(self, matin: np.ndarray) -> np.ndarray:
|
|
330
|
+
"""Project a full-basis tensor into four-index layout."""
|
|
331
|
+
norb = len(self.crystal.find)
|
|
332
|
+
ns = self.crystal.ns
|
|
333
|
+
nrk = len(self.crystal.kpoint)
|
|
334
|
+
nft = len(self.dlr.nu) # self.ft.size
|
|
335
|
+
|
|
336
|
+
matout = np.zeros(
|
|
337
|
+
(norb, norb, norb, norb, ns, ns, nrk, nft), dtype=np.complex128, order="F"
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
for ift in range(nft):
|
|
341
|
+
for irk in range(nrk):
|
|
342
|
+
for ks, js in itertools.product(range(ns), repeat=2):
|
|
343
|
+
matout[:, :, :, :, js, ks, irk, ift] = self.crystal.Full2Quad(
|
|
344
|
+
matin[:, :, js, ks, irk, ift]
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
return matout
|
|
348
|
+
|
|
349
|
+
def StcEmbedding(self, matin: np.ndarray) -> np.ndarray:
|
|
350
|
+
"""Embed a static tensor into a dynamic tensor layout."""
|
|
351
|
+
norb = matin.shape[0]
|
|
352
|
+
ns = matin.shape[2]
|
|
353
|
+
nrk = matin.shape[4]
|
|
354
|
+
nft = len(self.dlr.nu) # self.ft.size
|
|
355
|
+
|
|
356
|
+
matout = np.zeros(
|
|
357
|
+
(norb, norb, ns, ns, nrk, nft), dtype=np.complex128, order="F"
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
for ift in range(nft):
|
|
361
|
+
matout[..., ift] += matin
|
|
362
|
+
del matin
|
|
363
|
+
gc.collect()
|
|
364
|
+
return matout
|
|
365
|
+
|
|
366
|
+
def Save(self, matin: np.ndarray, fn: str):
|
|
367
|
+
"""Persist calculated arrays to the configured HDF5 output group."""
|
|
368
|
+
norb = matin.shape[0]
|
|
369
|
+
ns = matin.shape[2]
|
|
370
|
+
nrk = matin.shape[4]
|
|
371
|
+
nft = matin.shape[5]
|
|
372
|
+
|
|
373
|
+
if os.path.exists("blatdyn"):
|
|
374
|
+
pass
|
|
375
|
+
else:
|
|
376
|
+
os.mkdir("blatdyn")
|
|
377
|
+
os.chdir("blatdyn")
|
|
378
|
+
|
|
379
|
+
with open(fn + ".txt", "w") as f:
|
|
380
|
+
f.write("iorb, jorb, is, js, irk, ift, Re(B(k,w)), Im(B(k,w))\n")
|
|
381
|
+
for ift in range(nft):
|
|
382
|
+
for irk in range(nrk):
|
|
383
|
+
for ks, js in itertools.product(range(ns), repeat=2):
|
|
384
|
+
for jorb, iorb in itertools.product(range(norb), repeat=2):
|
|
385
|
+
f.write(
|
|
386
|
+
f"{iorb} {jorb} {js} {ks} {irk} {ift} {matin[iorb, jorb, js, ks, irk, ift].real} {matin[iorb, jorb, js, ks, irk, ift].imag}\n"
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
os.chdir("..")
|
|
390
|
+
|
|
391
|
+
return None
|
|
392
|
+
|
|
393
|
+
def R2KArb(self, matr: np.ndarray = None, kpoint: np.ndarray = None): # R2KAny
|
|
394
|
+
"""Transform real-space data to arbitrary k-points."""
|
|
395
|
+
# if self.crystal.kpath == None:
|
|
396
|
+
# print("Error, kpath doesn't generate")
|
|
397
|
+
# sys.exit()
|
|
398
|
+
# kpoint = self.crystal.kpath
|
|
399
|
+
norb = len(self.crystal.find)
|
|
400
|
+
ns = self.crystal.ns
|
|
401
|
+
nr = self.crystal.rkgrid[0] * self.crystal.rkgrid[1] * self.crystal.rkgrid[2]
|
|
402
|
+
nk = len(kpoint)
|
|
403
|
+
nft = matr.shape[4]
|
|
404
|
+
|
|
405
|
+
self.crystal.RVec()
|
|
406
|
+
tempmat = copy.deepcopy(matr)
|
|
407
|
+
matk = np.zeros((norb, norb, ns, ns, nk, nft), dtype=complex, order="F")
|
|
408
|
+
|
|
409
|
+
for ift in range(nft):
|
|
410
|
+
for ik in range(nk):
|
|
411
|
+
for ks in range(ns):
|
|
412
|
+
for js in range(ns):
|
|
413
|
+
for jorb in range(norb):
|
|
414
|
+
for iorb in range(norb):
|
|
415
|
+
temp = 0
|
|
416
|
+
for ir in range(nr):
|
|
417
|
+
temp += tempmat[
|
|
418
|
+
iorb, jorb, js, ks, ir, ift
|
|
419
|
+
] * np.exp(
|
|
420
|
+
-2.0j
|
|
421
|
+
* np.pi
|
|
422
|
+
* (kpoint[ik] @ self.crystal.rvec[ir])
|
|
423
|
+
)
|
|
424
|
+
[a, m1] = self.crystal.FAtomOrb(iorb)
|
|
425
|
+
[b, m2] = self.crystal.FAtomOrb(jorb)
|
|
426
|
+
delta = (
|
|
427
|
+
self.crystal.basisf[a, :]
|
|
428
|
+
- self.crystal.basisf[b, :]
|
|
429
|
+
)
|
|
430
|
+
phase = np.exp(-2.0j * np.pi * (kpoint[ik] @ delta))
|
|
431
|
+
matk[iorb, jorb, js, ks, ik, ift] = temp * phase
|
|
432
|
+
|
|
433
|
+
return matk
|
|
434
|
+
|
|
435
|
+
def CheckGroup(self, filepath: str, group: str):
|
|
436
|
+
"""Ensure that the requested HDF5 group exists before writing."""
|
|
437
|
+
with h5py.File(filepath, "r") as file:
|
|
438
|
+
return group in file
|
|
439
|
+
|
|
440
|
+
def RT2mRmT(self, ftau: np.ndarray):
|
|
441
|
+
"""Reorder real-space and time axes into mirrored conventions."""
|
|
442
|
+
ftau_mr = self.crystal.R2mR(ftau)
|
|
443
|
+
norb, _, ns, nr, ntau = ftau_mr.shape
|
|
444
|
+
fmtau_mr = np.zeros((norb, norb, ns, nr, ntau), dtype=np.complex128, order="F")
|
|
445
|
+
|
|
446
|
+
for ir in range(nr):
|
|
447
|
+
for js in range(ns):
|
|
448
|
+
for jorb in range(norb):
|
|
449
|
+
for iorb in range(norb):
|
|
450
|
+
fmtau_mr[iorb, jorb, js, ir] = self.dlr.T2mT(
|
|
451
|
+
ftau_mr[iorb, jorb, js, ir]
|
|
452
|
+
)
|
|
453
|
+
# fmtau_mr = self.dlr.T2mT(ftau_mr)
|
|
454
|
+
|
|
455
|
+
return fmtau_mr
|
|
456
|
+
|
|
457
|
+
def TauF2TauB(self, ftau : np.ndarray) -> np.ndarray:
|
|
458
|
+
"""Convert fermionic imaginary-time samples to bosonic time ordering."""
|
|
459
|
+
|
|
460
|
+
norb, _, ns, nk, _ = ftau.shape
|
|
461
|
+
ntau = len(self.dlr.tauB)
|
|
462
|
+
fout = np.zeros((norb, norb, ns, nk, ntau), dtype=np.complex128, order='F')
|
|
463
|
+
|
|
464
|
+
for ik in range(nk):
|
|
465
|
+
for js in range(ns):
|
|
466
|
+
for jorb, iorb in itertools.product(range(norb), repeat=2):
|
|
467
|
+
tempmat = ftau[iorb, jorb, js, ik]
|
|
468
|
+
fout[iorb, jorb, js, ik] = self.dlr.TauF2TauB(tempmat)
|
|
469
|
+
|
|
470
|
+
return fout
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
class P(BLatDyn):
|
|
474
|
+
"""Bosonic polarization calculator built from fermionic Green functions."""
|
|
475
|
+
def __init__(self,crystal: Crystal,dlr: DLR,g: np.ndarray = None,hdf5file: str = "glob.h5",group: str = None,):
|
|
476
|
+
"""Initialize the polarization calculator from Green-function data."""
|
|
477
|
+
super().__init__(crystal, dlr)
|
|
478
|
+
norb = len(self.crystal.find)
|
|
479
|
+
ns = self.crystal.ns
|
|
480
|
+
nrk = self.crystal.nk
|
|
481
|
+
nfreq = len(self.dlr.nu)
|
|
482
|
+
ntau = len(self.dlr.tauB)
|
|
483
|
+
self.rt = np.zeros(
|
|
484
|
+
(norb*norb, norb*norb, ns, ns, nrk, ntau), dtype=np.complex128, order="F"
|
|
485
|
+
)
|
|
486
|
+
self.kt = np.zeros(
|
|
487
|
+
(norb*norb, norb*norb, ns, ns, nrk, ntau), dtype=np.complex128, order="F"
|
|
488
|
+
)
|
|
489
|
+
self.rf = np.zeros(
|
|
490
|
+
(norb*norb, norb*norb, ns, ns, nrk, nfreq), dtype=np.complex128, order="F"
|
|
491
|
+
)
|
|
492
|
+
self.kf = np.zeros(
|
|
493
|
+
(norb*norb, norb*norb, ns, ns, nrk, nfreq), dtype=np.complex128, order="F"
|
|
494
|
+
)
|
|
495
|
+
self.hdf5file = hdf5file
|
|
496
|
+
self.group = group
|
|
497
|
+
self.subgroup = self.__class__.__name__
|
|
498
|
+
if g is None:
|
|
499
|
+
print("Error, There is no Green's function.")
|
|
500
|
+
sys.exit()
|
|
501
|
+
self.g = g
|
|
502
|
+
|
|
503
|
+
print("Polarizability Calculation Start")
|
|
504
|
+
start = time.time()
|
|
505
|
+
self.Cal()
|
|
506
|
+
self.kt = self.R2K(self.rt)
|
|
507
|
+
|
|
508
|
+
self.rf = self.T2F(self.rt)
|
|
509
|
+
self.kf = self.T2F(self.kt)
|
|
510
|
+
end = time.time()
|
|
511
|
+
print("Polarizability Calculation Done")
|
|
512
|
+
print(f"Calculation Time : {str(datetime.timedelta(seconds=end-start))}")
|
|
513
|
+
|
|
514
|
+
def Cal(self):
|
|
515
|
+
"""Compute the primary array represented by this object."""
|
|
516
|
+
|
|
517
|
+
ns = self.crystal.ns
|
|
518
|
+
nrk = len(self.crystal.kpoint)
|
|
519
|
+
|
|
520
|
+
ntau = len(self.dlr.tauB)
|
|
521
|
+
|
|
522
|
+
grt = self.TauF2TauB(self.g)
|
|
523
|
+
|
|
524
|
+
norb = len(self.crystal.bind)
|
|
525
|
+
|
|
526
|
+
polrt = np.zeros(
|
|
527
|
+
(norb, norb, ns, ns, nrk, ntau), dtype=np.complex128, order="F"
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
# gmrt = self.crystal.RT2mRmT(grt)
|
|
531
|
+
gmrt = self.RT2mRmT(grt)
|
|
532
|
+
|
|
533
|
+
if ns == 2:
|
|
534
|
+
map0 = np.array([self.crystal.MappingBosonFermion(i)[0] for i in range(norb)])
|
|
535
|
+
map1 = np.array([self.crystal.MappingBosonFermion(i)[1] for i in range(norb)])
|
|
536
|
+
|
|
537
|
+
term1_tensor = gmrt[map1[np.newaxis, :], map0[:, np.newaxis], :, :, :]
|
|
538
|
+
term2_tensor = grt[map1[:, np.newaxis], map0[np.newaxis, :], :, :, :]
|
|
539
|
+
diagonal_product = term1_tensor * term2_tensor
|
|
540
|
+
s_indices = np.arange(ns)
|
|
541
|
+
|
|
542
|
+
polrt[:, :, s_indices, s_indices, :, :] = diagonal_product
|
|
543
|
+
|
|
544
|
+
else:
|
|
545
|
+
if self.crystal.soc == True:
|
|
546
|
+
C = 1
|
|
547
|
+
map0 = np.array([self.crystal.MappingBosonFermion(i)[0] for i in range(norb)])
|
|
548
|
+
map1 = np.array([self.crystal.MappingBosonFermion(i)[1] for i in range(norb)])
|
|
549
|
+
|
|
550
|
+
term1_slice = gmrt[map1[np.newaxis, :], map0[:, np.newaxis], 0, :, :]
|
|
551
|
+
term2_slice = grt[map1[:, np.newaxis], map0[np.newaxis, :], 0, :, :]
|
|
552
|
+
result_slice = term1_slice * term2_slice * C
|
|
553
|
+
polrt[:, :, 0, 0, :, :] = result_slice
|
|
554
|
+
|
|
555
|
+
else:
|
|
556
|
+
C = 2
|
|
557
|
+
map0 = np.array([self.crystal.MappingBosonFermion(i)[0] for i in range(norb)])
|
|
558
|
+
map1 = np.array([self.crystal.MappingBosonFermion(i)[1] for i in range(norb)])
|
|
559
|
+
|
|
560
|
+
term1_slice = gmrt[map1[np.newaxis, :], map0[:, np.newaxis], 0, :, :]
|
|
561
|
+
term2_slice = grt[map1[:, np.newaxis], map0[np.newaxis, :], 0, :, :]
|
|
562
|
+
result_slice = term1_slice * term2_slice * C
|
|
563
|
+
polrt[:, :, 0, 0, :, :] = result_slice
|
|
564
|
+
|
|
565
|
+
self.rt = polrt
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
return None
|
|
569
|
+
|
|
570
|
+
def Save(self, fn: str):
|
|
571
|
+
"""Persist calculated arrays to the configured HDF5 output group."""
|
|
572
|
+
with h5py.File(self.hdf5file, "a") as file:
|
|
573
|
+
if self.CheckGroup(self.hdf5file, self.group):
|
|
574
|
+
group = file[self.group]
|
|
575
|
+
if self.subgroup in group:
|
|
576
|
+
p = group[self.subgroup]
|
|
577
|
+
else:
|
|
578
|
+
p = group.create_group(self.subgroup)
|
|
579
|
+
else:
|
|
580
|
+
group = file.create_group(self.group)
|
|
581
|
+
p = group.create_group(self.subgroup)
|
|
582
|
+
p.create_dataset(fn, dtype=complex, data=self.kf)
|
|
583
|
+
|
|
584
|
+
return None
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
class W(BLatDyn):
|
|
588
|
+
"""Screened interaction calculator for GW workflows."""
|
|
589
|
+
def __init__(self,crystal: Crystal,dlr: DLR,p: np.ndarray = None,v: V = None,c: float = 1.0,hdf5file: str = "glob.h5", group: str = None,):
|
|
590
|
+
"""Initialize the screened-interaction calculator."""
|
|
591
|
+
super().__init__(crystal, dlr)
|
|
592
|
+
norb = len(self.crystal.bind)
|
|
593
|
+
ns = self.crystal.ns
|
|
594
|
+
nrk = self.crystal.nk
|
|
595
|
+
nfreq = len(self.dlr.nu)
|
|
596
|
+
ntau = len(self.dlr.tauB)
|
|
597
|
+
|
|
598
|
+
# W quantity
|
|
599
|
+
self.rt = np.zeros(
|
|
600
|
+
(norb, norb, ns, ns, nrk, ntau), dtype=np.complex128, order="F"
|
|
601
|
+
)
|
|
602
|
+
self.kt = np.zeros(
|
|
603
|
+
(norb, norb, ns, ns, nrk, ntau), dtype=np.complex128, order="F"
|
|
604
|
+
)
|
|
605
|
+
self.rf = np.zeros(
|
|
606
|
+
(norb, norb, ns, ns, nrk, nfreq), dtype=np.complex128, order="F"
|
|
607
|
+
)
|
|
608
|
+
self.kf = np.zeros(
|
|
609
|
+
(norb, norb, ns, ns, nrk, nfreq), dtype=np.complex128, order="F"
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
# Wc quantity
|
|
613
|
+
self.crt = np.zeros(
|
|
614
|
+
(norb, norb, ns, ns, nrk, ntau), dtype=np.complex128, order="F"
|
|
615
|
+
) # rt to kf
|
|
616
|
+
self.ckt = np.zeros(
|
|
617
|
+
(norb, norb, ns, ns, nrk, ntau), dtype=np.complex128, order="F"
|
|
618
|
+
)
|
|
619
|
+
self.crf = np.zeros(
|
|
620
|
+
(norb, norb, ns, ns, nrk, nfreq), dtype=np.complex128, order="F"
|
|
621
|
+
)
|
|
622
|
+
self.ckf = np.zeros(
|
|
623
|
+
(norb, norb, ns, ns, nrk, nfreq), dtype=np.complex128, order="F"
|
|
624
|
+
)
|
|
625
|
+
|
|
626
|
+
self.c = c
|
|
627
|
+
self.hdf5file = hdf5file
|
|
628
|
+
self.group = group
|
|
629
|
+
self.subgroup = self.__class__.__name__
|
|
630
|
+
if p is None:
|
|
631
|
+
print("Error, polarizability doesn't exist")
|
|
632
|
+
sys.exit()
|
|
633
|
+
if v is None:
|
|
634
|
+
print("Error, bare coulomb interaction doesn't exist")
|
|
635
|
+
sys.exit()
|
|
636
|
+
self.p = p
|
|
637
|
+
self.v = v
|
|
638
|
+
|
|
639
|
+
print("Screened Coulomb Interaction Calculation Start")
|
|
640
|
+
start = time.time()
|
|
641
|
+
self.Cal()
|
|
642
|
+
|
|
643
|
+
# self.wkt = self.F2T(self.wkf,1,1)
|
|
644
|
+
# self.wrf = self.K2R(self.wkf)
|
|
645
|
+
# self.wrt = self.K2R(self.wkt)
|
|
646
|
+
|
|
647
|
+
print(f"Fourier transform in {self.__class__.__name__} start")
|
|
648
|
+
self.ckt = self.F2T(self.ckf)
|
|
649
|
+
self.crf = self.K2R(self.ckf)
|
|
650
|
+
self.crt = self.K2R(self.ckt)
|
|
651
|
+
end= time.time()
|
|
652
|
+
print(f"Fourier transform in {self.__class__.__name__} finish")
|
|
653
|
+
print("Screened Coulomb Interaction Calculation Finish")
|
|
654
|
+
print(f"Screened Coulomb interaction use time : {datetime.timedelta(seconds=end - start)} s")
|
|
655
|
+
|
|
656
|
+
def Cal(self): # calculate W and Wc
|
|
657
|
+
"""Compute the primary array represented by this object."""
|
|
658
|
+
norb = len(self.crystal.bind)
|
|
659
|
+
norbc = len(self.crystal.find)
|
|
660
|
+
ns = self.crystal.ns
|
|
661
|
+
nk = len(self.crystal.kpoint)
|
|
662
|
+
nfreq = len(self.dlr.nu)
|
|
663
|
+
####### Initialization #######
|
|
664
|
+
tempmat = np.zeros(
|
|
665
|
+
(norbc * norbc, norbc * norbc, ns, ns, nk, nfreq),
|
|
666
|
+
dtype=np.complex128,
|
|
667
|
+
order="F",
|
|
668
|
+
)
|
|
669
|
+
wkf = np.zeros((norb, norb, ns, ns, nk, nfreq), dtype=np.complex128, order="F")
|
|
670
|
+
wckf = np.zeros((norb, norb, ns, ns, nk, nfreq), dtype=np.complex128, order="F")
|
|
671
|
+
vdyn = np.zeros((norb, norb, ns, ns, nk, nfreq), dtype=np.complex128, order="F")
|
|
672
|
+
|
|
673
|
+
# for ifreq in range(nfreq):
|
|
674
|
+
# vdyn[...,ifreq] = self.v.k
|
|
675
|
+
print("Make dynamic bare Coulomb interaction start")
|
|
676
|
+
vdyn = self.StcEmbedding(self.v.k)
|
|
677
|
+
print("Make dynamic bare Coulomb interaction finish")
|
|
678
|
+
polcomp = np.zeros(
|
|
679
|
+
(norbc * norbc, norbc * norbc, ns, ns, nk, nfreq),
|
|
680
|
+
dtype=np.complex128,
|
|
681
|
+
order="F",
|
|
682
|
+
)
|
|
683
|
+
vcomp = np.zeros(
|
|
684
|
+
(norbc * norbc, norbc * norbc, ns, ns, nk, nfreq),
|
|
685
|
+
dtype=np.complex128,
|
|
686
|
+
order="F",
|
|
687
|
+
)
|
|
688
|
+
####### Initialization #######
|
|
689
|
+
polcomp = self.Double2Full(self.p) * self.c
|
|
690
|
+
# del self.p
|
|
691
|
+
vcomp = self.Double2Full(vdyn)
|
|
692
|
+
|
|
693
|
+
print("Dyson equation solving start")
|
|
694
|
+
start = time.time()
|
|
695
|
+
tempmat = self.Dyson(vcomp, polcomp)
|
|
696
|
+
wkf = self.Full2Double(tempmat)
|
|
697
|
+
end = time.time()
|
|
698
|
+
# print(f"Dyson equation solving use time: {end - start} s")
|
|
699
|
+
print("Dyson equation solving finish")
|
|
700
|
+
print(f"Dyson equation solving use time : {datetime.timedelta(seconds=end - start)} s")
|
|
701
|
+
|
|
702
|
+
self.kf = wkf
|
|
703
|
+
|
|
704
|
+
wckf = wkf - vdyn
|
|
705
|
+
|
|
706
|
+
self.ckf = wckf
|
|
707
|
+
|
|
708
|
+
return None
|
|
709
|
+
|
|
710
|
+
def Save(self, fn: str):
|
|
711
|
+
"""Persist calculated arrays to the configured HDF5 output group."""
|
|
712
|
+
with h5py.File(self.hdf5file, "a") as file:
|
|
713
|
+
if self.CheckGroup(self.hdf5file, self.group):
|
|
714
|
+
group = file[self.group]
|
|
715
|
+
if self.subgroup in group:
|
|
716
|
+
w = group[self.subgroup]
|
|
717
|
+
else:
|
|
718
|
+
w = group.create_group(self.subgroup)
|
|
719
|
+
else:
|
|
720
|
+
group = file.create_group(self.group)
|
|
721
|
+
w = group.create_group(self.subgroup)
|
|
722
|
+
|
|
723
|
+
w.create_dataset(fn, dtype=complex, data=self.kf)
|
|
724
|
+
|
|
725
|
+
return None
|