Skip to content

Commit 2c1a073

Browse files
committed
[bug] relax iaft leakage warning and protect sparse-ir import
1 parent 4503dc7 commit 2c1a073

1 file changed

Lines changed: 48 additions & 55 deletions

File tree

  • python/solid_dmft/gw_embedding

python/solid_dmft/gw_embedding/iaft.py

Lines changed: 48 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import sys
22
import numpy as np
3-
import sparse_ir
43

54
"""
6-
Fourier transform on the imaginary axis based on IR basis and the sparse sampling technique.
5+
Fourier transform on the imaginary axis based on IR basis and the sparse sampling technique.
76
"""
87

98

@@ -45,6 +44,7 @@ class IAFT(object):
4544
nw_b: int
4645
Number of bosonic frequency sampling points
4746
"""
47+
4848
def __init__(self, beta: float, lmbda: float, prec: float = 1e-15, verbal: bool = True):
4949
"""
5050
:param beta: float
@@ -54,6 +54,10 @@ def __init__(self, beta: float, lmbda: float, prec: float = 1e-15, verbal: bool
5454
:param prec: float
5555
Precision for IR basis
5656
"""
57+
try:
58+
import sparse_ir
59+
except ImportError:
60+
raise ImportError('sparse_ir is required for IAFT functionality. ' 'Install with: pip install sparse-ir[xprec]')
5761
self.beta = beta
5862
self.lmbda = lmbda
5963
self.prec = prec
@@ -89,14 +93,15 @@ def __init__(self, beta: float, lmbda: float, prec: float = 1e-15, verbal: bool
8993
sys.stdout.flush()
9094

9195
def __str__(self):
92-
return ("Mesh details on the imaginary axis\n" \
93-
"----------------------------------\n" \
94-
"precision = {}\n" \
95-
"beta = {}\n" \
96-
"lambda = {}\n" \
97-
"nt_f, nw_f = {}, {}\n" \
98-
"nt_b, nw_b = {}, {}\n".format(self.prec, self.beta, self.lmbda, self.nt_f, self.nw_f,
99-
self.nt_b, self.nw_b))
96+
return (
97+
'Mesh details on the imaginary axis\n'
98+
'----------------------------------\n'
99+
'precision = {}\n'
100+
'beta = {}\n'
101+
'lambda = {}\n'
102+
'nt_f, nw_f = {}, {}\n'
103+
'nt_b, nw_b = {}, {}\n'.format(self.prec, self.beta, self.lmbda, self.nt_f, self.nw_f, self.nt_b, self.nw_b)
104+
)
100105

101106
def wn_mesh(self, stats: str, ir_notation: bool = True):
102107
"""
@@ -111,11 +116,10 @@ def wn_mesh(self, stats: str, ir_notation: bool = True):
111116
Matsubara frequency indices
112117
"""
113118
if stats not in self.statisics:
114-
raise ValueError("Unknown statistics '{}'. "
115-
"Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
119+
raise ValueError("Unknown statistics '{}'. " "Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
116120
wn_mesh = np.array(self._wn_mesh_f, dtype=int) if stats == 'f' else np.array(self._wn_mesh_b, dtype=int)
117121
if not ir_notation:
118-
wn_mesh = (wn_mesh-1)//2 if stats == 'f' else wn_mesh//2
122+
wn_mesh = (wn_mesh - 1) // 2 if stats == 'f' else wn_mesh // 2
119123
return wn_mesh
120124

121125
def tau_to_w(self, Ot, stats: str):
@@ -130,12 +134,10 @@ def tau_to_w(self, Ot, stats: str):
130134
Matsubara-frequency object with dimensions (nw, ...)
131135
"""
132136
if stats not in self.statisics:
133-
raise ValueError("Unknown statistics '{}'. "
134-
"Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
137+
raise ValueError("Unknown statistics '{}'. " "Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
135138
Twt = self.Twt_ff if stats == 'f' else self.Twt_bb
136139
if Ot.shape[0] != Twt.shape[1]:
137-
raise ValueError(
138-
"tau_to_w: Number of tau points are inconsistent: {} and {}".format(Ot.shape[0], Twt.shape[1]))
140+
raise ValueError('tau_to_w: Number of tau points are inconsistent: {} and {}'.format(Ot.shape[0], Twt.shape[1]))
139141

140142
Ot_shape = Ot.shape
141143
Ot = Ot.reshape(Ot.shape[0], -1)
@@ -157,13 +159,12 @@ def tau_to_w_phsym(self, Ot, stats: str):
157159
Matsubara-frequency object with dimensions (nw, ...)
158160
"""
159161
if stats != 'b':
160-
raise ValueError("FT w/ particle-hole symmetry only support bosonic correlation functions")
162+
raise ValueError('FT w/ particle-hole symmetry only support bosonic correlation functions')
161163

162164
nw_half = self.nw_b // 2 if self.nw_b % 2 == 0 else self.nw_b // 2 + 1
163165
nt_half = self.nt_b // 2 if self.nt_b % 2 == 0 else self.nt_b // 2 + 1
164166
if Ot.shape[0] != nt_half:
165-
raise ValueError(
166-
"tau_to_w_phsym: Number of tau points are inconsistent: {} and {}".format(Ot.shape[0], nt_half))
167+
raise ValueError('tau_to_w_phsym: Number of tau points are inconsistent: {} and {}'.format(Ot.shape[0], nt_half))
167168

168169
Twt_pos = np.zeros((nw_half, nt_half), dtype=self.Twt_bb.dtype)
169170
for n in range(nw_half):
@@ -193,12 +194,10 @@ def w_to_tau(self, Ow, stats):
193194
Imaginary-time object with dimensions (nt, ...)
194195
"""
195196
if stats not in self.statisics:
196-
raise ValueError("Unknown statistics '{}'. "
197-
"Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
197+
raise ValueError("Unknown statistics '{}'. " "Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
198198
Ttw = self.Ttw_ff if stats == 'f' else self.Ttw_bb
199199
if Ow.shape[0] != Ttw.shape[1]:
200-
raise ValueError(
201-
"w_to_tau: Number of w points are inconsistent: {} and {}".format(Ow.shape[0], Ttw.shape[1]))
200+
raise ValueError('w_to_tau: Number of w points are inconsistent: {} and {}'.format(Ow.shape[0], Ttw.shape[1]))
202201

203202
Ow_shape = Ow.shape
204203
Ow = Ow.reshape(Ow.shape[0], -1)
@@ -221,13 +220,12 @@ def w_to_tau_phsym(self, Ow, stats):
221220
Imaginary-time object with dimensions (nt, ...)
222221
"""
223222
if stats != 'b':
224-
raise ValueError("FT w/ particle-hole symmetry only support bosonic correlation functions")
223+
raise ValueError('FT w/ particle-hole symmetry only support bosonic correlation functions')
225224

226225
nw_half = self.nw_b // 2 if self.nw_b % 2 == 0 else self.nw_b // 2 + 1
227226
nt_half = self.nt_b // 2 if self.nt_b % 2 == 0 else self.nt_b // 2 + 1
228227
if Ow.shape[0] != nw_half:
229-
raise ValueError(
230-
"w_to_tau_phsym: Number of w points are inconsistent: {} and {}".format(Ow.shape[0], nw_half))
228+
raise ValueError('w_to_tau_phsym: Number of w points are inconsistent: {} and {}'.format(Ow.shape[0], nw_half))
231229

232230
Ttw_pos = np.zeros((nt_half, nw_half), dtype=self.Ttw_bb.dtype)
233231
for it in range(nt_half):
@@ -244,7 +242,6 @@ def w_to_tau_phsym(self, Ow, stats):
244242
Ot = Ot.reshape((Ttw_pos.shape[0],) + Ow_shape[1:])
245243
return Ot
246244

247-
248245
def w_interpolate(self, Ow, wn_mesh_interp, stats: str, ir_notation: bool = True):
249246
"""
250247
Interpolate a dynamic object to arbitrary points on the Matsubara axis.
@@ -264,16 +261,14 @@ def w_interpolate(self, Ow, wn_mesh_interp, stats: str, ir_notation: bool = True
264261
Matsubara-frequency object with dimensions (nw_interp, ...)
265262
"""
266263
if stats not in self.statisics:
267-
raise ValueError("Unknown statistics '{}'. "
268-
"Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
264+
raise ValueError("Unknown statistics '{}'. " "Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
269265
if ir_notation:
270266
wn_indices = np.asarray(wn_mesh_interp)
271267
else:
272-
wn_indices = np.array([2*n+1 if stats == 'f' else 2*n for n in wn_mesh_interp], dtype=int)
268+
wn_indices = np.array([2 * n + 1 if stats == 'f' else 2 * n for n in wn_mesh_interp], dtype=int)
273269
Tlw = self.Tlw_ff if stats == 'f' else self.Tlw_bb
274270
if Ow.shape[0] != Tlw.shape[1]:
275-
raise ValueError(
276-
"w_interpolate: Number of w points are inconsistent: {} and {}".format(Ow.shape[0], Tlw.shape[1]))
271+
raise ValueError('w_interpolate: Number of w points are inconsistent: {} and {}'.format(Ow.shape[0], Tlw.shape[1]))
277272

278273
Twl_interp = self.bases.basis_f.uhat(wn_indices).T if stats == 'f' else self.bases.basis_b.uhat(wn_indices).T
279274
Tww = np.dot(Twl_interp, Tlw)
@@ -305,18 +300,17 @@ def w_interpolate_phsym(self, Ow, wn_mesh_interp, stats: str, ir_notation: bool
305300
Matsubara-frequency object with dimensions (nw_interp, ...)
306301
"""
307302
if stats != 'b':
308-
raise ValueError("FT w/ particle-hole symmetry only support bosonic correlation functions")
303+
raise ValueError('FT w/ particle-hole symmetry only support bosonic correlation functions')
309304

310305
nw_half = self.nw_b // 2 if self.nw_b % 2 == 0 else self.nw_b // 2 + 1
311306
nt_half = self.nt_b // 2 if self.nt_b % 2 == 0 else self.nt_b // 2 + 1
312307
if Ow.shape[0] != nw_half:
313-
raise ValueError(
314-
"w_interpolate_phsym: Number of w points are inconsistent: {} and {}".format(Ow.shape[0], nw_half))
308+
raise ValueError('w_interpolate_phsym: Number of w points are inconsistent: {} and {}'.format(Ow.shape[0], nw_half))
315309

316310
if ir_notation:
317311
wn_indices = np.asarray(wn_mesh_interp)
318312
else:
319-
wn_indices = np.array([2*n for n in wn_mesh_interp], dtype=int)
313+
wn_indices = np.array([2 * n for n in wn_mesh_interp], dtype=int)
320314
Tlw = self.Tlw_bb
321315
Tlw_pos = np.zeros((Tlw.shape[0], nw_half), dtype=Tlw.dtype)
322316
for l in range(Tlw.shape[0]):
@@ -351,12 +345,10 @@ def tau_interpolate(self, Ot, tau_mesh_interp, stats: str):
351345
Imaginary-time object with dimensions (nt_interp, ...)
352346
"""
353347
if stats not in self.statisics:
354-
raise ValueError("Unknown statistics '{}'. "
355-
"Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
348+
raise ValueError("Unknown statistics '{}'. " "Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
356349
Tlt = self.Tlt_ff if stats == 'f' else self.Tlt_bb
357350
if Ot.shape[0] != Tlt.shape[1]:
358-
raise ValueError(
359-
"t_interpolate: Number of tau points are inconsistent: {} and {}".format(Ot.shape[0], Tlt.shape[1]))
351+
raise ValueError('t_interpolate: Number of tau points are inconsistent: {} and {}'.format(Ot.shape[0], Tlt.shape[1]))
360352

361353
Ttl_interp = self.bases.basis_f.u(tau_mesh_interp).T if stats == 'f' else self.bases.basis_b.u(tau_mesh_interp).T
362354
Ttt = np.dot(Ttl_interp, Tlt)
@@ -384,13 +376,12 @@ def tau_interpolate_phsym(self, Ot, tau_mesh_interp, stats: str):
384376
Imaginary-time object with dimensions (nt_interp, ...)
385377
"""
386378
if stats != 'b':
387-
raise ValueError("FT w/ particle-hole symmetry only support bosonic correlation functions")
379+
raise ValueError('FT w/ particle-hole symmetry only support bosonic correlation functions')
388380

389381
nw_half = self.nw_b // 2 if self.nw_b % 2 == 0 else self.nw_b // 2 + 1
390382
nt_half = self.nt_b // 2 if self.nt_b % 2 == 0 else self.nt_b // 2 + 1
391383
if Ot.shape[0] != nt_half:
392-
raise ValueError(
393-
"tau_interpolate_phsym: Number of tau points are inconsistent: {} and {}".format(Ot.shape[0], nw_half))
384+
raise ValueError('tau_interpolate_phsym: Number of tau points are inconsistent: {} and {}'.format(Ot.shape[0], nw_half))
394385

395386
Tlt = self.Tlt_ff if stats == 'f' else self.Tlt_bb
396387
Tlt_pos = np.zeros((Tlt.shape[0], nt_half), dtype=Tlt.dtype)
@@ -410,7 +401,7 @@ def tau_interpolate_phsym(self, Ot, tau_mesh_interp, stats: str):
410401
Ot_interp = Ot_interp.reshape((np.shape(tau_mesh_interp)[0],) + Ot_shape[1:])
411402
return Ot_interp
412403

413-
def check_leakage(self, Ot, stats: str, name: str = "", w_input: bool = False):
404+
def check_leakage(self, Ot, stats: str, name: str = '', w_input: bool = False):
414405
"""
415406
Check decay of the IR coefficients to assess the quality of IR basis for the beta and lambda.
416407
The coefficients should decay exponentially, and the leakage is defined as:
@@ -427,12 +418,11 @@ def check_leakage(self, Ot, stats: str, name: str = "", w_input: bool = False):
427418
return
428419

429420
if stats not in self.statisics:
430-
raise ValueError("Unknown statistics '{}'. "
431-
"Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
421+
raise ValueError("Unknown statistics '{}'. " "Acceptable options are 'f' for fermion and 'b' for bosons.".format(stats))
432422
nts = self.nt_f if stats == 'f' else self.nt_b
433423
Tlt = self.Tlt_ff if stats == 'f' else self.Tlt_bb
434424
if nts != Ot.shape[0]:
435-
raise ValueError("Inconsistency between nts = {} and Ot.shape[0] = {}".format(nts, Ot.shape[0]))
425+
raise ValueError('Inconsistency between nts = {} and Ot.shape[0] = {}'.format(nts, Ot.shape[0]))
436426

437427
# coeff_first
438428
O_l0_i = np.einsum('t,ti->i', Tlt[0], Ot.reshape(nts, -1))
@@ -442,11 +432,14 @@ def check_leakage(self, Ot, stats: str, name: str = "", w_input: bool = False):
442432
O_lm2_t = np.einsum('lt,ti->li', Tlt[-2:], Ot.reshape(nts, -1))
443433
coeff_last = np.max(np.abs(O_lm2_t))
444434

445-
leakage = coeff_last/coeff_first
446-
print("IAFT leakage of {}: {}".format(name, leakage))
447-
if leakage >= 1e-8:
448-
print("[WARNING] check_leakage: coeff_last/coeff_first = {} >= 1e-8; "
449-
"coeff_last = {}, coeff_first = {}".format(leakage, coeff_last, coeff_first))
435+
leakage = coeff_last / coeff_first
436+
print('IAFT leakage of {}: {}'.format(name, leakage))
437+
if leakage >= 1e-5:
438+
print(
439+
'[WARNING] check_leakage: coeff_last/coeff_first = {} >= 1e-8; ' 'coeff_last = {}, coeff_first = {}'.format(
440+
leakage, coeff_last, coeff_first
441+
)
442+
)
450443
sys.stdout.flush()
451444

452445

@@ -466,12 +459,12 @@ def check_leakage(self, Ot, stats: str, name: str = "", w_input: bool = False):
466459
print(Gt_interp.shape)
467460

468461
# wn in spare_ir notation
469-
w_interp = np.array([-1,1,3,5], dtype=int)
462+
w_interp = np.array([-1, 1, 3, 5], dtype=int)
470463
Gw_interp = ft.w_interpolate(Gw, w_interp, 'f', True)
471464
print(Gw_interp.shape)
472465

473466
# wn in physical notation
474-
w_interp = np.array([-1,0,1,2,3,4], dtype=int)
467+
w_interp = np.array([-1, 0, 1, 2, 3, 4], dtype=int)
475468
Gw_interp = ft.w_interpolate(Gw, w_interp, 'f', False)
476469
print(Gw_interp.shape)
477470

0 commit comments

Comments
 (0)