adapol 0.1.0__tar.gz
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.
- adapol-0.1.0/MANIFEST.in +8 -0
- adapol-0.1.0/PKG-INFO +56 -0
- adapol-0.1.0/README.md +39 -0
- adapol-0.1.0/pyproject.toml +35 -0
- adapol-0.1.0/setup.cfg +4 -0
- adapol-0.1.0/src/adapol/__init__.py +4 -0
- adapol-0.1.0/src/adapol/aaa.py +123 -0
- adapol-0.1.0/src/adapol/anacont.py +210 -0
- adapol-0.1.0/src/adapol/fit_utils.py +278 -0
- adapol-0.1.0/src/adapol/hybfit.py +229 -0
- adapol-0.1.0/src/adapol.egg-info/PKG-INFO +56 -0
- adapol-0.1.0/src/adapol.egg-info/SOURCES.txt +13 -0
- adapol-0.1.0/src/adapol.egg-info/dependency_links.txt +1 -0
- adapol-0.1.0/src/adapol.egg-info/requires.txt +3 -0
- adapol-0.1.0/src/adapol.egg-info/top_level.txt +1 -0
adapol-0.1.0/MANIFEST.in
ADDED
adapol-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: adapol
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Adaptive Pole Fitting for Quantum Many-Body Physics
|
|
5
|
+
Author-email: Zhen Huang <hertz@berkeley.edu>, Chia-Nan Yeh <cyeh@flatironinstitute.org>, Nils Wentzell <nwentzell@flatironinstitute.org>, Jason Kaye <jkaye@flatironinstitute.org>, Lin Lin <linlin@berkeley.edu>
|
|
6
|
+
Project-URL: Homepage, https://flatironinstitute.github.io/adapol
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/flatironinstitute/adapol/issues
|
|
8
|
+
Keywords: Bath,Fitting,Hybridization,DMFT,Matsubara
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.7
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: numpy
|
|
15
|
+
Requires-Dist: scipy
|
|
16
|
+
Requires-Dist: cvxpy
|
|
17
|
+
|
|
18
|
+
# adapol: Adaptive Pole Fitting for Quantum Many-Body Physics
|
|
19
|
+
[`adapol`](https://github.com/Hertz4/Adapol) (pronounced "add a pole") is a python package for fitting Matsubara functions with the following form:
|
|
20
|
+
```math
|
|
21
|
+
G(\mathrm i \omega_k) = \sum_l \frac{V_lV_l^{\dagger}}{\mathrm i\omega_k - E_l}.
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Current applications include
|
|
25
|
+
(1) hybridization fitting, (2) analytic continuation.
|
|
26
|
+
|
|
27
|
+
We also provide a [TRIQS](https://triqs.github.io/) interface if the Matsubara functions are stored in `triqs` Green's function container.
|
|
28
|
+
|
|
29
|
+
# Installation
|
|
30
|
+
`adapol` has `numpy` and `scipy` as its prerequisites. [`cvxpy`](https://www.cvxpy.org/) is also required for hybridization fitting of matrix-valued (instead of scalar-valued) Matsubara functions.
|
|
31
|
+
|
|
32
|
+
To install `adapol`, run
|
|
33
|
+
```terminal
|
|
34
|
+
pip install adapol
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Documentation
|
|
40
|
+
|
|
41
|
+
See the detailed [documentation](https://flatironinstitute.github.io/adapol/) for physical background, algorithms and user manual.
|
|
42
|
+
|
|
43
|
+
`Adapol` is a stand-alone package. For TRIQS users, we also provide a TRIQS interface. See [user manual](https://flatironinstitute.github.io/adapol/latest/python.html#triqs-interface) for details.
|
|
44
|
+
|
|
45
|
+
# Examples
|
|
46
|
+
In the `tutorial` page, we provide two examples [`discrete.ipynb`](https://flatironinstitute.github.io/adapol/latest/tutorials/discrete.html) and [`semicircle.ipynb`](https://flatironinstitute.github.io/adapol/latest/tutorials/semicircle.html), showcasing how to use `adapol` for both discrete spectrum and continuous spectrum.
|
|
47
|
+
|
|
48
|
+
In these notebooks, we also demonstrate how to use our code through the triqs interface.
|
|
49
|
+
|
|
50
|
+
# References
|
|
51
|
+
To cite this work, please include a reference to this GitHub repository, and
|
|
52
|
+
cite the following references:
|
|
53
|
+
|
|
54
|
+
1. Huang, Zhen, Emanuel Gull, and Lin Lin. "Robust analytic continuation of Green's functions via projection, pole estimation, and semidefinite relaxation." Physical Review B 107.7 (2023): 075151.
|
|
55
|
+
2. Mejuto-Zaera, Carlos, et al. "Efficient hybridization fitting for dynamical mean-field theory via semi-definite relaxation." Physical Review B 101.3 (2020): 035143.
|
|
56
|
+
3. Nakatsukasa, Yuji, Olivier Sète, and Lloyd N. Trefethen. "The AAA algorithm for rational approximation." SIAM Journal on Scientific Computing 40.3 (2018): A1494-A1522.
|
adapol-0.1.0/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# adapol: Adaptive Pole Fitting for Quantum Many-Body Physics
|
|
2
|
+
[`adapol`](https://github.com/Hertz4/Adapol) (pronounced "add a pole") is a python package for fitting Matsubara functions with the following form:
|
|
3
|
+
```math
|
|
4
|
+
G(\mathrm i \omega_k) = \sum_l \frac{V_lV_l^{\dagger}}{\mathrm i\omega_k - E_l}.
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
Current applications include
|
|
8
|
+
(1) hybridization fitting, (2) analytic continuation.
|
|
9
|
+
|
|
10
|
+
We also provide a [TRIQS](https://triqs.github.io/) interface if the Matsubara functions are stored in `triqs` Green's function container.
|
|
11
|
+
|
|
12
|
+
# Installation
|
|
13
|
+
`adapol` has `numpy` and `scipy` as its prerequisites. [`cvxpy`](https://www.cvxpy.org/) is also required for hybridization fitting of matrix-valued (instead of scalar-valued) Matsubara functions.
|
|
14
|
+
|
|
15
|
+
To install `adapol`, run
|
|
16
|
+
```terminal
|
|
17
|
+
pip install adapol
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Documentation
|
|
23
|
+
|
|
24
|
+
See the detailed [documentation](https://flatironinstitute.github.io/adapol/) for physical background, algorithms and user manual.
|
|
25
|
+
|
|
26
|
+
`Adapol` is a stand-alone package. For TRIQS users, we also provide a TRIQS interface. See [user manual](https://flatironinstitute.github.io/adapol/latest/python.html#triqs-interface) for details.
|
|
27
|
+
|
|
28
|
+
# Examples
|
|
29
|
+
In the `tutorial` page, we provide two examples [`discrete.ipynb`](https://flatironinstitute.github.io/adapol/latest/tutorials/discrete.html) and [`semicircle.ipynb`](https://flatironinstitute.github.io/adapol/latest/tutorials/semicircle.html), showcasing how to use `adapol` for both discrete spectrum and continuous spectrum.
|
|
30
|
+
|
|
31
|
+
In these notebooks, we also demonstrate how to use our code through the triqs interface.
|
|
32
|
+
|
|
33
|
+
# References
|
|
34
|
+
To cite this work, please include a reference to this GitHub repository, and
|
|
35
|
+
cite the following references:
|
|
36
|
+
|
|
37
|
+
1. Huang, Zhen, Emanuel Gull, and Lin Lin. "Robust analytic continuation of Green's functions via projection, pole estimation, and semidefinite relaxation." Physical Review B 107.7 (2023): 075151.
|
|
38
|
+
2. Mejuto-Zaera, Carlos, et al. "Efficient hybridization fitting for dynamical mean-field theory via semi-definite relaxation." Physical Review B 101.3 (2020): 035143.
|
|
39
|
+
3. Nakatsukasa, Yuji, Olivier Sète, and Lloyd N. Trefethen. "The AAA algorithm for rational approximation." SIAM Journal on Scientific Computing 40.3 (2018): A1494-A1522.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.setuptools.packages.find]
|
|
6
|
+
where = ["src"]
|
|
7
|
+
|
|
8
|
+
[project]
|
|
9
|
+
name = "adapol"
|
|
10
|
+
version = "0.1.0"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name="Zhen Huang", email="hertz@berkeley.edu" },
|
|
13
|
+
{ name="Chia-Nan Yeh", email="cyeh@flatironinstitute.org"},
|
|
14
|
+
{ name="Nils Wentzell", email="nwentzell@flatironinstitute.org"},
|
|
15
|
+
{ name="Jason Kaye", email="jkaye@flatironinstitute.org"},
|
|
16
|
+
{ name="Lin Lin", email="linlin@berkeley.edu"}
|
|
17
|
+
]
|
|
18
|
+
description = "Adaptive Pole Fitting for Quantum Many-Body Physics "
|
|
19
|
+
readme = "README.md"
|
|
20
|
+
keywords = ["Bath", "Fitting", "Hybridization", "DMFT", "Matsubara"]
|
|
21
|
+
requires-python = ">=3.7"
|
|
22
|
+
classifiers = [
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
|
25
|
+
"Operating System :: OS Independent",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"numpy",
|
|
29
|
+
"scipy",
|
|
30
|
+
"cvxpy"
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
"Homepage" = "https://flatironinstitute.github.io/adapol"
|
|
35
|
+
"Bug Tracker" = "https://github.com/flatironinstitute/adapol/issues"
|
adapol-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This code implements a specific variant of the AAA algorithm.
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import scipy.linalg
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def aaa_matrix_real(F, Z, tol=1e-13, mmax=100):
|
|
11
|
+
""" """
|
|
12
|
+
Z = np.asanyarray(Z).ravel()
|
|
13
|
+
|
|
14
|
+
# only use input z that are on iR_+. Will map them to iR_- by taking conjugate of function value.
|
|
15
|
+
half_index = np.imag(Z) > 0
|
|
16
|
+
Z_half = Z[half_index]
|
|
17
|
+
F_half = F[half_index, :, :]
|
|
18
|
+
M_half = len(Z_half)
|
|
19
|
+
|
|
20
|
+
Z = np.append(Z_half, np.conjugate(Z_half))
|
|
21
|
+
|
|
22
|
+
Norb = F.shape[1]
|
|
23
|
+
F_other_half = np.zeros_like(F_half)
|
|
24
|
+
for i in range(M_half):
|
|
25
|
+
F_other_half[i, :, :] = np.conjugate(np.transpose(F_half[i, :, :]))
|
|
26
|
+
F = np.concatenate((F_half, F_other_half), axis=0)
|
|
27
|
+
|
|
28
|
+
M = M_half * 2
|
|
29
|
+
|
|
30
|
+
F_mat = np.reshape(F, (M, Norb * Norb))
|
|
31
|
+
|
|
32
|
+
J = list(range(M))
|
|
33
|
+
zj = np.empty(0, dtype=Z.dtype)
|
|
34
|
+
fj = np.empty((0, Norb * Norb), dtype=F.dtype)
|
|
35
|
+
C = np.empty([M, 0], dtype=F.dtype)
|
|
36
|
+
errors = []
|
|
37
|
+
|
|
38
|
+
reltol = tol * np.linalg.norm(F_mat, np.inf)
|
|
39
|
+
|
|
40
|
+
R = np.mean(F_mat) * np.ones_like(F_mat)
|
|
41
|
+
|
|
42
|
+
mlist = range(2, mmax + 1, 2)
|
|
43
|
+
|
|
44
|
+
for m in mlist:
|
|
45
|
+
# find largest residual
|
|
46
|
+
jj = np.argmax(np.sum(abs(F_mat - R) ** 2, 1))
|
|
47
|
+
zj = np.append(zj, (Z[jj],))
|
|
48
|
+
fj = np.concatenate((fj, F_mat[jj : jj + 1, :]), axis=0)
|
|
49
|
+
J.remove(jj)
|
|
50
|
+
|
|
51
|
+
# Cauchy matrix containing the basis functions as columns
|
|
52
|
+
|
|
53
|
+
jj2 = (jj + M_half) % M
|
|
54
|
+
zj = np.append(zj, (Z[jj2],))
|
|
55
|
+
fj = np.concatenate((fj, F_mat[jj2 : jj2 + 1, :]), axis=0)
|
|
56
|
+
|
|
57
|
+
J.remove(jj2)
|
|
58
|
+
|
|
59
|
+
C = 1.0 / (Z[J, None] - zj[None, :])
|
|
60
|
+
|
|
61
|
+
# Loewner matrix
|
|
62
|
+
Apart = np.zeros(((M - m) * Norb * Norb, m), dtype=F.dtype)
|
|
63
|
+
for i in range(Norb * Norb):
|
|
64
|
+
Fhere = F_mat[:, i]
|
|
65
|
+
fjhere = fj[:, i]
|
|
66
|
+
|
|
67
|
+
Apart[range(0 + i, i + (M - m) * Norb * Norb, Norb * Norb), :] = (
|
|
68
|
+
Fhere[J, None] - fjhere[None, :]
|
|
69
|
+
) * C
|
|
70
|
+
|
|
71
|
+
Awidth = np.size(Apart, 1)
|
|
72
|
+
Apart_l = Apart[:, range(0, Awidth, 2)]
|
|
73
|
+
Apart_r = Apart[:, range(1, Awidth, 2)]
|
|
74
|
+
Anew = np.concatenate((Apart_l + Apart_r, (Apart_l - Apart_r) * 1j), axis=1)
|
|
75
|
+
Anew = np.concatenate((np.real(Anew), np.imag(Anew)), axis=0)
|
|
76
|
+
|
|
77
|
+
# compute weights as right singular vector for smallest singular value
|
|
78
|
+
_, _, Vh = np.linalg.svd(Anew, full_matrices=False)
|
|
79
|
+
|
|
80
|
+
wj_r = Vh[-1, :]
|
|
81
|
+
|
|
82
|
+
wj_r = np.reshape(wj_r, (2, int(m / 2)))
|
|
83
|
+
wj_c = np.zeros((2, int(m / 2)), dtype=np.complex128)
|
|
84
|
+
wj_c[0, :] = wj_r[0, :] + 1j * wj_r[1, :]
|
|
85
|
+
wj_c[1, :] = wj_r[0, :] - 1j * wj_r[1, :]
|
|
86
|
+
|
|
87
|
+
wj = np.asanyarray(wj_c.T).ravel()
|
|
88
|
+
|
|
89
|
+
# approximation: numerator / denominator
|
|
90
|
+
|
|
91
|
+
D = C.dot(wj)
|
|
92
|
+
|
|
93
|
+
# update residual
|
|
94
|
+
R = F_mat.copy()
|
|
95
|
+
|
|
96
|
+
for i in range(Norb * Norb):
|
|
97
|
+
fjhere = fj[:, i]
|
|
98
|
+
N = C.dot(wj * fjhere) # needs to change N and R
|
|
99
|
+
R[J, i] = N / D
|
|
100
|
+
|
|
101
|
+
# check for convergence
|
|
102
|
+
errors.append(np.linalg.norm(F_mat - R, np.inf))
|
|
103
|
+
if errors[-1] <= reltol:
|
|
104
|
+
break
|
|
105
|
+
|
|
106
|
+
fj = fj.reshape(m, Norb, Norb)
|
|
107
|
+
pol = aaa_pol(zj, wj)
|
|
108
|
+
return pol, zj, fj, wj
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def aaa_pol(zj, wj):
|
|
112
|
+
"""Return the poles and residues of the rational function."""
|
|
113
|
+
|
|
114
|
+
m = len(wj)
|
|
115
|
+
|
|
116
|
+
# compute poles
|
|
117
|
+
B = np.eye(m + 1)
|
|
118
|
+
B[0, 0] = 0
|
|
119
|
+
E = np.block([[0, wj], [np.ones((m, 1)), np.diag(zj)]])
|
|
120
|
+
evals = scipy.linalg.eigvals(E, B)
|
|
121
|
+
pol = np.real_if_close(evals[np.isfinite(evals)])
|
|
122
|
+
|
|
123
|
+
return pol
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from .fit_utils import pole_fitting, eval_with_pole
|
|
3
|
+
|
|
4
|
+
def anacont(
|
|
5
|
+
Delta,
|
|
6
|
+
iwn_vec,
|
|
7
|
+
tol=None,
|
|
8
|
+
Np=None,
|
|
9
|
+
solver="lstsq",
|
|
10
|
+
maxiter=500,
|
|
11
|
+
mmin=4,
|
|
12
|
+
mmax=50,
|
|
13
|
+
verbose=False,
|
|
14
|
+
):
|
|
15
|
+
"""
|
|
16
|
+
The function for analytical continuation.
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
----------
|
|
20
|
+
|
|
21
|
+
- Analytic continuation with :math:`N_p` poles:
|
|
22
|
+
:code:`func = anacont(Np = Np)`
|
|
23
|
+
|
|
24
|
+
- Fitting with fixed error tolerance tol:
|
|
25
|
+
:code:`func = anacont(tol = tol)`
|
|
26
|
+
|
|
27
|
+
- Analytic continuation with improved accuracy:
|
|
28
|
+
:code:`fitting(Np = Np, flag = flag, solver = "sdp")`
|
|
29
|
+
|
|
30
|
+
Parameters:
|
|
31
|
+
------------
|
|
32
|
+
:code:`Delta`: np.array, :math:`(N_w, N_\mathrm{orb}, N_\mathrm{orb})`
|
|
33
|
+
The input hybridization function in Matsubara frequency.
|
|
34
|
+
|
|
35
|
+
:code:`iwn_vec`: np.array, :math:`(N_w,)`
|
|
36
|
+
The Matsubara frequency vector, complex-valued
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
:code:`tol`: Fitting error tolreance, float
|
|
40
|
+
If tol is specified, the fitting will be conducted with fixed error tolerance tol.
|
|
41
|
+
default: None
|
|
42
|
+
|
|
43
|
+
:code:`Np`: number of poles, integer
|
|
44
|
+
If Np is specified, the fitting will be conducted with fixed number of poles Np.
|
|
45
|
+
default: None
|
|
46
|
+
Np needs to be an odd integer, and number of supoort points is Np + 1.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
:code:`solver`: string
|
|
50
|
+
The solver that is used for optimization.
|
|
51
|
+
choices: "lstsq", "sdp"
|
|
52
|
+
default: "lstsq"
|
|
53
|
+
|
|
54
|
+
:code:`maxiter`: int
|
|
55
|
+
maximum number of iterations
|
|
56
|
+
default: 500
|
|
57
|
+
|
|
58
|
+
:code:`mmin`, :code:`mmax`: number of minimum or maximum poles, integer
|
|
59
|
+
default: mmin = 4, mmax = 50
|
|
60
|
+
if tol is specified, mmin and mmax will be used as the minimum and maximum number of poles.
|
|
61
|
+
if Np is specified, mmin and mmax will not be used.
|
|
62
|
+
|
|
63
|
+
:code:`verbose`: bool
|
|
64
|
+
whether to display optimization details
|
|
65
|
+
default: False
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
---------
|
|
72
|
+
:code:`func`: function
|
|
73
|
+
Analytic continuation function:
|
|
74
|
+
:math:`f(z) = \sum_n \mathrm{Weight}[n]/(z-\mathrm{pol}[n]).`
|
|
75
|
+
|
|
76
|
+
:code:`fitting_error`: float
|
|
77
|
+
fitting error
|
|
78
|
+
|
|
79
|
+
:code:`pol`: np.array, :math:`(N_p,)`
|
|
80
|
+
poles obtained from fitting
|
|
81
|
+
|
|
82
|
+
:code:`weight`: np.array, :math:`(N_p, N_\mathrm{orb}, N_\mathrm{orb})`
|
|
83
|
+
weights obtained from fitting
|
|
84
|
+
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
# Check dimensions
|
|
88
|
+
assert len(iwn_vec.shape) == 1 or len(iwn_vec.shape) == 2
|
|
89
|
+
if len(iwn_vec.shape) == 2:
|
|
90
|
+
assert iwn_vec.shape[1] == 1
|
|
91
|
+
iwn_vec = iwn_vec.flatten()
|
|
92
|
+
assert len(Delta.shape) == 3 or len(Delta.shape) == 1
|
|
93
|
+
if len(Delta.shape) == 1:
|
|
94
|
+
assert Delta.shape[0] == iwn_vec.shape[0]
|
|
95
|
+
Delta = Delta[:, None, None]
|
|
96
|
+
if len(Delta.shape) == 3:
|
|
97
|
+
assert Delta.shape[0] == iwn_vec.shape[0]
|
|
98
|
+
assert Delta.shape[1] == Delta.shape[2]
|
|
99
|
+
|
|
100
|
+
solver = solver.lower()
|
|
101
|
+
assert solver == "lstsq" or solver == "sdp"
|
|
102
|
+
|
|
103
|
+
# Check input tol or Np
|
|
104
|
+
if tol is None and Np is None:
|
|
105
|
+
raise ValueError("Please specify either tol or Np")
|
|
106
|
+
if tol is not None and Np is not None:
|
|
107
|
+
raise ValueError(
|
|
108
|
+
"Please specify either tol or Np. One can not specify both of them."
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
wn_vec = np.imag(iwn_vec)
|
|
112
|
+
|
|
113
|
+
if Np is not None:
|
|
114
|
+
pol, weight, fitting_error = pole_fitting(
|
|
115
|
+
Delta, wn_vec, Ns=Np+1, maxiter=maxiter, solver=solver, disp=verbose
|
|
116
|
+
)
|
|
117
|
+
elif tol is not None:
|
|
118
|
+
pol, weight, fitting_error = pole_fitting(
|
|
119
|
+
Delta,
|
|
120
|
+
wn_vec,
|
|
121
|
+
tol=tol,
|
|
122
|
+
mmin=mmin,
|
|
123
|
+
mmax=mmax,
|
|
124
|
+
maxiter=maxiter,
|
|
125
|
+
solver=solver,
|
|
126
|
+
disp=verbose,
|
|
127
|
+
)
|
|
128
|
+
def func(Z):
|
|
129
|
+
return eval_with_pole(pol, Z, weight)
|
|
130
|
+
return func, fitting_error, pol, weight
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def anacont_triqs(
|
|
134
|
+
Delta_triqs,
|
|
135
|
+
tol=None,
|
|
136
|
+
Np=None,
|
|
137
|
+
solver="lstsq",
|
|
138
|
+
maxiter=500,
|
|
139
|
+
mmin=4,
|
|
140
|
+
mmax=50,
|
|
141
|
+
verbose=False,
|
|
142
|
+
debug=False
|
|
143
|
+
):
|
|
144
|
+
"""
|
|
145
|
+
The triqs interface for analytical continuation.
|
|
146
|
+
The function requires triqs package in python.
|
|
147
|
+
|
|
148
|
+
Parameters:
|
|
149
|
+
------------
|
|
150
|
+
:code:`Delta_triqs`: triqs Green's function container
|
|
151
|
+
The input hybridization function in Matsubara frequency
|
|
152
|
+
|
|
153
|
+
:code:`debug`: bool
|
|
154
|
+
return additional outputs for debugging.
|
|
155
|
+
Default: False
|
|
156
|
+
|
|
157
|
+
:code:`tol`, :code:`Np`, :code:`solver`, :code:`maxiter`, :code:`mmin`, :code:`mmax`, :code:`verbose`:
|
|
158
|
+
same as in anacont
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
---------
|
|
163
|
+
:code:`func`: function
|
|
164
|
+
Analytic continuation function:
|
|
165
|
+
:math:`f(z) = \sum_n \mathrm{Weight}[n]/(z-\mathrm{pol}[n]).`
|
|
166
|
+
|
|
167
|
+
if debug == True:
|
|
168
|
+
:code:`fitting_error`: float
|
|
169
|
+
fitting error
|
|
170
|
+
|
|
171
|
+
:code:`pol`: np.array, :math:`(N_p,)`
|
|
172
|
+
poles obtained from fitting
|
|
173
|
+
|
|
174
|
+
:code:`weight`: np.array, :math:`(N_p, N_\mathrm{orb}, N_\mathrm{orb})`
|
|
175
|
+
weights obtained from fitting
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
try:
|
|
179
|
+
from triqs.gf import Gf, BlockGf, MeshImFreq, MeshDLRImFreq
|
|
180
|
+
except ImportError:
|
|
181
|
+
raise ImportError("Failed to import the triqs package (https://triqs.github.io/triqs/latest/). "
|
|
182
|
+
"Please ensure it is installed.")
|
|
183
|
+
|
|
184
|
+
if isinstance(Delta_triqs, Gf) and isinstance(Delta_triqs.mesh, (MeshImFreq, MeshDLRImFreq)):
|
|
185
|
+
iwn_vec = np.array([iw.value for iw in Delta_triqs.mesh.values()])
|
|
186
|
+
func, fit_error, pol, weight = anacont(Delta_triqs.data, iwn_vec, tol, Np, solver, maxiter,
|
|
187
|
+
mmin, mmax, verbose)
|
|
188
|
+
print('optimization finished with fitting error {:.3e}'.format(fit_error))
|
|
189
|
+
|
|
190
|
+
if debug:
|
|
191
|
+
return func, fit_error, pol, weight
|
|
192
|
+
else:
|
|
193
|
+
return func
|
|
194
|
+
elif isinstance(Delta_triqs, BlockGf) and isinstance(Delta_triqs.mesh, (MeshImFreq, MeshDLRImFreq)):
|
|
195
|
+
func_list, error_list, pol_list, weight_list = [], [], [], []
|
|
196
|
+
for j, (block, delta_blk) in enumerate(Delta_triqs):
|
|
197
|
+
func, fit_error, pol, weight = anacont_triqs(delta_blk, tol, Np, solver, maxiter, mmin,
|
|
198
|
+
mmax, verbose)
|
|
199
|
+
func_list.append(func)
|
|
200
|
+
if debug:
|
|
201
|
+
error_list.append(fit_error)
|
|
202
|
+
pol_list.append(pol)
|
|
203
|
+
weight_list.append(weight)
|
|
204
|
+
|
|
205
|
+
if debug:
|
|
206
|
+
return func_list, error_list, pol_list, weight_list
|
|
207
|
+
else:
|
|
208
|
+
return func_list
|
|
209
|
+
else:
|
|
210
|
+
raise RuntimeError("Error: Delta_triqs.mesh must be an instance of MeshImFreq or MeshDLRImFreq.")
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# This is a python implementation for analytic continuation of Fermionic Green's functions/self energy
|
|
2
|
+
# using PES (ES) method
|
|
3
|
+
# Reference: PhysRevB.107.075151
|
|
4
|
+
import numpy as np
|
|
5
|
+
import scipy
|
|
6
|
+
import scipy.optimize
|
|
7
|
+
import cvxpy as cp
|
|
8
|
+
from .aaa import aaa_matrix_real
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# import mosek
|
|
12
|
+
def eval_with_pole(pol, Z, weight):
|
|
13
|
+
pol_t = np.reshape(pol, [pol.size, 1])
|
|
14
|
+
M = 1 / (Z - pol_t)
|
|
15
|
+
M = M.transpose()
|
|
16
|
+
if len(weight.shape) == 1:
|
|
17
|
+
return M @ weight
|
|
18
|
+
else:
|
|
19
|
+
G = M @ np.reshape(weight, (weight.shape[0], weight.shape[1] * weight.shape[2]))
|
|
20
|
+
return np.reshape(G, (G.shape[0], weight.shape[1], weight.shape[2]))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_weight(
|
|
24
|
+
pol, Z, G, cleanflag=True, maxiter=1000, complex=True, fast=False, eps=1e-8
|
|
25
|
+
):
|
|
26
|
+
pol_t = np.reshape(pol, [pol.size, 1])
|
|
27
|
+
M = 1 / (Z - pol_t)
|
|
28
|
+
M = M.transpose()
|
|
29
|
+
MM = np.concatenate([M.real, M.imag])
|
|
30
|
+
if len(G.shape) == 1:
|
|
31
|
+
GG = np.concatenate([G.real, G.imag])
|
|
32
|
+
if cleanflag:
|
|
33
|
+
R = np.linalg.lstsq(MM, GG, rcond=0)[0]
|
|
34
|
+
else:
|
|
35
|
+
[R, rnorm] = scipy.optimize.nnls(MM, GG, maxiter=maxiter)
|
|
36
|
+
residue = G - M @ R
|
|
37
|
+
else:
|
|
38
|
+
Np = len(pol)
|
|
39
|
+
Norb = G.shape[1]
|
|
40
|
+
R = np.zeros((Np, Norb, Norb), dtype=np.complex128)
|
|
41
|
+
if cleanflag:
|
|
42
|
+
for i in range(Norb):
|
|
43
|
+
GG = np.concatenate([G[:, i, i].real, G[:, i, i].imag])
|
|
44
|
+
R[:, i, i] = np.linalg.lstsq(MM, GG, rcond=0)[0]
|
|
45
|
+
for j in range(i + 1, Norb):
|
|
46
|
+
g1 = (G[:, j, i] + G[:, i, j]) / 2.0
|
|
47
|
+
g2 = (G[:, i, j] - G[:, j, i]) / 2.0
|
|
48
|
+
GG1 = np.concatenate([g1.real, g1.imag])
|
|
49
|
+
GG2 = np.concatenate([g2.imag, -g2.real])
|
|
50
|
+
R1 = np.linalg.lstsq(MM, GG1, rcond=0)[0]
|
|
51
|
+
R2 = np.linalg.lstsq(MM, GG2, rcond=0)[0]
|
|
52
|
+
R[:, i, j] = R1 + 1j * R2
|
|
53
|
+
R[:, j, i] = R1 - 1j * R2
|
|
54
|
+
else:
|
|
55
|
+
if not fast:
|
|
56
|
+
Nw = len(Z)
|
|
57
|
+
|
|
58
|
+
if complex:
|
|
59
|
+
X = [cp.Variable((Norb, Norb), hermitian=True) for i in range(Np)]
|
|
60
|
+
constraints = [X[i] >> 0 for i in range(Np)]
|
|
61
|
+
else:
|
|
62
|
+
X = [cp.Variable((Norb, Norb), PSD=True) for i in range(Np)]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
Gfit = []
|
|
66
|
+
for w in range(Nw):
|
|
67
|
+
Gfit.append(cp.sum_squares(sum([ M[w,i]*X[i] for i in range(Np)]) - G[w,:,:]))
|
|
68
|
+
|
|
69
|
+
if complex:
|
|
70
|
+
prob = cp.Problem(cp.Minimize(sum(Gfit)), constraints)
|
|
71
|
+
else:
|
|
72
|
+
prob = cp.Problem(cp.Minimize(sum(Gfit)))
|
|
73
|
+
prob.solve(solver="SCS", verbose=False, eps=eps)
|
|
74
|
+
# MOSEK parameters
|
|
75
|
+
# mosek_params_dict = {"MSK_DPAR_INTPNT_CO_TOL_PFEAS": 1.e-8,\
|
|
76
|
+
# "MSK_DPAR_INTPNT_CO_TOL_DFEAS": 1.e-8,
|
|
77
|
+
# "MSK_DPAR_INTPNT_CO_TOL_REL_GAP": 1.e-8,
|
|
78
|
+
# "MSK_DPAR_INTPNT_CO_TOL_NEAR_REL": 1000}
|
|
79
|
+
# result = prob.solve(solver = "MOSEK", verbose=False,\
|
|
80
|
+
# mosek_params = mosek_params_dict)
|
|
81
|
+
|
|
82
|
+
for i in range(Np):
|
|
83
|
+
R[i] = X[i].value
|
|
84
|
+
else:
|
|
85
|
+
for i in range(Norb):
|
|
86
|
+
GG = np.concatenate([G[:, i, i].real, G[:, i, i].imag])
|
|
87
|
+
Rii = scipy.optimize.nnls(MM, GG, maxiter=maxiter)[0]
|
|
88
|
+
R[:, i, i] = Rii
|
|
89
|
+
MM2 = np.concatenate([M, np.conj(M)])
|
|
90
|
+
for i in range(Norb):
|
|
91
|
+
for j in range(i + 1, Norb):
|
|
92
|
+
GG = np.concatenate([G[:, i, j], np.conj(G[:, j, i])])
|
|
93
|
+
bound = np.sqrt(np.abs(R[:, i, i] * R[:, j, j]))
|
|
94
|
+
x = cp.Variable(MM.shape[1], complex=True)
|
|
95
|
+
constraints = [
|
|
96
|
+
cp.abs(x[k]) <= bound[k] for k in range(MM.shape[1])
|
|
97
|
+
]
|
|
98
|
+
objective = cp.Minimize(cp.sum_squares(MM2 @ x - GG))
|
|
99
|
+
prob = cp.Problem(objective, constraints)
|
|
100
|
+
prob.solve(solver="SCS", verbose=False, eps=eps)
|
|
101
|
+
# result = prob.solve(solver = cp.MOSEK,verbose = False,mosek_params = mosek_params_dict)
|
|
102
|
+
R[:, i, j] = x.value
|
|
103
|
+
R[:, j, i] = np.conj(x.value)
|
|
104
|
+
|
|
105
|
+
residue = 1.0 * G
|
|
106
|
+
for i in range(Np):
|
|
107
|
+
residue = residue - M[:, i, None, None] * R[i]
|
|
108
|
+
return R, M, residue
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def aaa_reduce(pol, R, eps=1e-6):
|
|
112
|
+
Np = R.shape[0]
|
|
113
|
+
Rnorm = np.zeros(Np)
|
|
114
|
+
for i in range(Np):
|
|
115
|
+
Rnorm[i] = np.linalg.norm(R[i])
|
|
116
|
+
nonz_index = Rnorm > eps
|
|
117
|
+
return pol[nonz_index], R[nonz_index]
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def erroreval(pol, Z, G, cleanflag=True, maxiter=1000, fast=False, complex=True):
|
|
121
|
+
R, M, residue = get_weight(
|
|
122
|
+
pol, Z, G, cleanflag=cleanflag, maxiter=maxiter, complex=complex, fast=fast
|
|
123
|
+
)
|
|
124
|
+
if len(G.shape) == 1:
|
|
125
|
+
y = np.linalg.norm(residue)
|
|
126
|
+
grad = np.real(np.dot(np.conj(residue), (R * (M**2))))
|
|
127
|
+
else:
|
|
128
|
+
y = np.linalg.norm(residue.flatten())
|
|
129
|
+
|
|
130
|
+
Np = len(pol)
|
|
131
|
+
grad = np.zeros(Np)
|
|
132
|
+
Nw = len(Z)
|
|
133
|
+
for k in range(Np):
|
|
134
|
+
for w in range(Nw):
|
|
135
|
+
grad[k] = grad[k] + np.real(
|
|
136
|
+
np.sum((M[w, k] ** 2) * (np.conj(residue[w, :, :]) * R[k]))
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
grad = -grad / y
|
|
140
|
+
return y, grad
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def pole_fitting(
|
|
144
|
+
Delta,
|
|
145
|
+
Z,
|
|
146
|
+
tol=None,
|
|
147
|
+
Ns=None,
|
|
148
|
+
mmin=None,
|
|
149
|
+
mmax=50,
|
|
150
|
+
maxiter=50,
|
|
151
|
+
solver="lstsq",
|
|
152
|
+
fast=False,
|
|
153
|
+
disp=False,
|
|
154
|
+
complex=True,
|
|
155
|
+
):
|
|
156
|
+
# set cleanflag
|
|
157
|
+
if solver == "lstsq":
|
|
158
|
+
cleanflag = True
|
|
159
|
+
if solver == "sdp":
|
|
160
|
+
cleanflag = False
|
|
161
|
+
|
|
162
|
+
# pole estimation
|
|
163
|
+
# tol needs to be fixed
|
|
164
|
+
if Ns is None and tol is None:
|
|
165
|
+
raise Exception(
|
|
166
|
+
"One needs to specify either the number of poles or the fitting error tolerance."
|
|
167
|
+
)
|
|
168
|
+
if Ns is not None and tol is not None:
|
|
169
|
+
raise Exception(
|
|
170
|
+
"One can not specify both the number of poles and the fitting error tolerance. Only specify one of them."
|
|
171
|
+
)
|
|
172
|
+
if Ns is None:
|
|
173
|
+
if mmin is None or mmin < 4:
|
|
174
|
+
mmin = 4
|
|
175
|
+
if mmin % 2 == 1:
|
|
176
|
+
mmin = mmin + 1
|
|
177
|
+
if mmax > 2 * (Z.shape[0] // 2):
|
|
178
|
+
mmax = 2 * (Z.shape[0] // 2)
|
|
179
|
+
else:
|
|
180
|
+
if Ns % 2 == 1:
|
|
181
|
+
Ns = Ns + 1
|
|
182
|
+
mmin, mmax = Ns, Ns
|
|
183
|
+
if len(Delta.shape) == 1:
|
|
184
|
+
Delta = Delta.reshape(Delta.shape[0], 1, 1)
|
|
185
|
+
|
|
186
|
+
for m in range(mmin, mmax + 1, 2):
|
|
187
|
+
pol, _, _, _ = aaa_matrix_real(Delta, 1j * Z, mmax=m)
|
|
188
|
+
pol = np.real(pol)
|
|
189
|
+
weight, _, residue = get_weight(
|
|
190
|
+
pol, 1.0j * Z, Delta, cleanflag=cleanflag, complex=complex, fast=fast
|
|
191
|
+
)
|
|
192
|
+
# print(np.max(np.abs(residue)))
|
|
193
|
+
if tol is not None:
|
|
194
|
+
if np.max(np.abs(residue)) > tol * 10:
|
|
195
|
+
continue
|
|
196
|
+
if Ns is None:
|
|
197
|
+
pol, weight = aaa_reduce(pol, weight, 1e-5)
|
|
198
|
+
# print("Number of poles is ", len(pol))
|
|
199
|
+
if cleanflag:
|
|
200
|
+
if maxiter > 0:
|
|
201
|
+
|
|
202
|
+
def fhere(pole):
|
|
203
|
+
return erroreval(
|
|
204
|
+
pole, 1j * Z, Delta, cleanflag=cleanflag, complex=complex
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
# fhere = lambda pole: erroreval(pole,1j*Z,Delta,cleanflag=cleanflag,complex=complex)
|
|
208
|
+
res = scipy.optimize.minimize(
|
|
209
|
+
fhere,
|
|
210
|
+
pol,
|
|
211
|
+
method="L-BFGS-B",
|
|
212
|
+
jac=True,
|
|
213
|
+
options={
|
|
214
|
+
"disp": disp,
|
|
215
|
+
"maxiter": maxiter,
|
|
216
|
+
"gtol": 1e-10,
|
|
217
|
+
"ftol": 1e-10,
|
|
218
|
+
},
|
|
219
|
+
)
|
|
220
|
+
else:
|
|
221
|
+
|
|
222
|
+
def fhere1(pole):
|
|
223
|
+
return erroreval(pole, 1j * Z, Delta, cleanflag=True, complex=complex)
|
|
224
|
+
|
|
225
|
+
# fhere = lambda pole: erroreval(pole,1j*Z,Delta,cleanflag=True,complex=complex)
|
|
226
|
+
res = scipy.optimize.minimize(
|
|
227
|
+
fhere1,
|
|
228
|
+
pol,
|
|
229
|
+
method="L-BFGS-B",
|
|
230
|
+
jac=True,
|
|
231
|
+
options={"disp": False, "gtol": 1e-10, "ftol": 1e-10},
|
|
232
|
+
)
|
|
233
|
+
if maxiter > 0:
|
|
234
|
+
|
|
235
|
+
def fhere2(pole):
|
|
236
|
+
return erroreval(
|
|
237
|
+
pole, 1j * Z, Delta, cleanflag=False, complex=complex, fast=fast
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# fhere = lambda pole: erroreval(pole,1j*Z,Delta,cleanflag=False,complex= complex,fast = fast)
|
|
241
|
+
res = scipy.optimize.minimize(
|
|
242
|
+
fhere2,
|
|
243
|
+
res.x,
|
|
244
|
+
method="L-BFGS-B",
|
|
245
|
+
jac=True,
|
|
246
|
+
options={
|
|
247
|
+
"disp": disp,
|
|
248
|
+
"maxiter": maxiter,
|
|
249
|
+
"gtol": 1e-10,
|
|
250
|
+
"ftol": 1e-10,
|
|
251
|
+
},
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
weight, _, residuenew = get_weight(
|
|
255
|
+
res.x, 1j * Z, Delta, cleanflag=cleanflag, fast=fast, complex=complex
|
|
256
|
+
)
|
|
257
|
+
if not check_psd(weight):
|
|
258
|
+
weight, _, residuenew = get_weight(
|
|
259
|
+
res.x, 1j * Z, Delta, cleanflag=False, complex=complex
|
|
260
|
+
)
|
|
261
|
+
err = np.max(np.abs(residuenew))
|
|
262
|
+
if tol is not None:
|
|
263
|
+
if err < tol:
|
|
264
|
+
return res.x, weight, err
|
|
265
|
+
else:
|
|
266
|
+
return res.x, weight, err
|
|
267
|
+
|
|
268
|
+
if tol is not None:
|
|
269
|
+
print("Fail to reach desired fitting error!")
|
|
270
|
+
return res.x, weight, np.max(np.abs(residuenew))
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def check_psd(weight, atol=1e-6):
|
|
274
|
+
check_psd = True
|
|
275
|
+
for i in range(weight.shape[0]):
|
|
276
|
+
val, _ = np.linalg.eig(weight[i])
|
|
277
|
+
check_psd = check_psd and np.min(val.real) > -atol
|
|
278
|
+
return check_psd
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from .fit_utils import pole_fitting, eval_with_pole
|
|
3
|
+
|
|
4
|
+
def hybfit(
|
|
5
|
+
Delta,
|
|
6
|
+
iwn_vec,
|
|
7
|
+
tol=None,
|
|
8
|
+
Np=None,
|
|
9
|
+
svdtol=1e-7,
|
|
10
|
+
solver="lstsq",
|
|
11
|
+
maxiter=500,
|
|
12
|
+
mmin=4,
|
|
13
|
+
mmax=50,
|
|
14
|
+
verbose=False,
|
|
15
|
+
):
|
|
16
|
+
"""
|
|
17
|
+
The function for hybridization fitting.
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
----------
|
|
21
|
+
|
|
22
|
+
- Fitting with :math:`N_p` poles:
|
|
23
|
+
:code:`hybfit(Delta, iwn_vec, Np = Np)`
|
|
24
|
+
|
|
25
|
+
- Fitting with fixed error tolerance tol :
|
|
26
|
+
:code:`hybfit(Delta, iwn_vec, tol = tol)`
|
|
27
|
+
|
|
28
|
+
Parameters:
|
|
29
|
+
------------
|
|
30
|
+
:code:`Delta`: np.array, :math:`(N_w, N_\mathrm{orb}, N_\mathrm{orb})`
|
|
31
|
+
The input hybridization function in Matsubara frequency.
|
|
32
|
+
|
|
33
|
+
:code:`iwn_vec`: np.array, :math:`(N_w)`
|
|
34
|
+
The Matsubara frequency vector, complex-valued
|
|
35
|
+
|
|
36
|
+
:code:`svdtol`: float, optional
|
|
37
|
+
Truncation threshold for bath orbitals while doing SVD of weight matrices in hybridization fitting
|
|
38
|
+
default:1e-7
|
|
39
|
+
|
|
40
|
+
:code:`tol`, :code:`Np`, :code:`solver`, :code:`maxiter`, :code:`mmin`, :code:`mmax`, :code:`verbose`:
|
|
41
|
+
see below in anacont
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
---------
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
:code:`bathenergy` :math:`E`: np.array, :math:`(N_b)`
|
|
49
|
+
Bath energy
|
|
50
|
+
|
|
51
|
+
:code:`bathhyb` :math:`V`: np.array, :math:`(N_b,N_{\mathrm{orb}})`
|
|
52
|
+
Bath hybridization
|
|
53
|
+
|
|
54
|
+
:code:`final_error`: float
|
|
55
|
+
final fitting error
|
|
56
|
+
|
|
57
|
+
:code:`func`: function
|
|
58
|
+
Hybridization function evaluator
|
|
59
|
+
:math:`f(z) = \sum_n V_{ni}V_{nj}^*/(z-E_n).`
|
|
60
|
+
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# Check dimensions
|
|
65
|
+
assert len(iwn_vec.shape) == 1 or len(iwn_vec.shape) == 2
|
|
66
|
+
if len(iwn_vec.shape) == 2:
|
|
67
|
+
assert iwn_vec.shape[1] == 1
|
|
68
|
+
iwn_vec = iwn_vec.flatten()
|
|
69
|
+
assert len(Delta.shape) == 3 or len(Delta.shape) == 1
|
|
70
|
+
if len(Delta.shape) == 1:
|
|
71
|
+
assert Delta.shape[0] == iwn_vec.shape[0]
|
|
72
|
+
Delta = Delta[:, None, None]
|
|
73
|
+
if len(Delta.shape) == 3:
|
|
74
|
+
assert Delta.shape[0] == iwn_vec.shape[0]
|
|
75
|
+
assert Delta.shape[1] == Delta.shape[2]
|
|
76
|
+
|
|
77
|
+
solver = solver.lower()
|
|
78
|
+
assert solver == "lstsq" or solver == "sdp"
|
|
79
|
+
|
|
80
|
+
# Check input tol or Np
|
|
81
|
+
if tol is None and Np is None:
|
|
82
|
+
raise ValueError("Please specify either tol or Np")
|
|
83
|
+
if tol is not None and Np is not None:
|
|
84
|
+
raise ValueError(
|
|
85
|
+
"Please specify either tol or Np. One can not specify both of them."
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
wn_vec = np.imag(iwn_vec)
|
|
89
|
+
|
|
90
|
+
if Np is not None:
|
|
91
|
+
pol, weight, fitting_error = pole_fitting(
|
|
92
|
+
Delta, wn_vec, Ns=Np + 1, maxiter=maxiter, solver=solver, disp=verbose
|
|
93
|
+
)
|
|
94
|
+
elif tol is not None:
|
|
95
|
+
pol, weight, fitting_error = pole_fitting(
|
|
96
|
+
Delta,
|
|
97
|
+
wn_vec,
|
|
98
|
+
tol=tol,
|
|
99
|
+
mmin=mmin,
|
|
100
|
+
mmax=mmax,
|
|
101
|
+
maxiter=maxiter,
|
|
102
|
+
solver=solver,
|
|
103
|
+
disp=verbose,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
bathenergy, bathhyb, bath_mat = obtain_orbitals(pol, weight, svdtol=svdtol)
|
|
107
|
+
def func(Z):
|
|
108
|
+
return eval_with_pole(bathenergy, Z, bath_mat)
|
|
109
|
+
Delta_reconstruct = func(iwn_vec)
|
|
110
|
+
final_error = np.max(np.abs(Delta - Delta_reconstruct))
|
|
111
|
+
return bathenergy, bathhyb, final_error, func
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def hybfit_triqs(
|
|
115
|
+
Delta_triqs,
|
|
116
|
+
tol=None,
|
|
117
|
+
Np=None,
|
|
118
|
+
svdtol=1e-7,
|
|
119
|
+
solver="lstsq",
|
|
120
|
+
maxiter=500,
|
|
121
|
+
mmin=4,
|
|
122
|
+
mmax=50,
|
|
123
|
+
verbose=False,
|
|
124
|
+
debug=False
|
|
125
|
+
):
|
|
126
|
+
"""
|
|
127
|
+
The triqs interface for hybridization fitting.
|
|
128
|
+
The function requires triqs package in python.
|
|
129
|
+
|
|
130
|
+
Examples:
|
|
131
|
+
----------
|
|
132
|
+
|
|
133
|
+
- Fitting with :math:`N_p` poles:
|
|
134
|
+
:code:`hybfit_triqs(delta_triqs, Np = Np)`
|
|
135
|
+
|
|
136
|
+
- Fitting with fixed error tolerance tol :
|
|
137
|
+
:code:`hybfit_triqs(delta_triqs, tol = tol)`
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
Parameters:
|
|
141
|
+
------------
|
|
142
|
+
:code:`Delta_triqs`: triqs Green's function container
|
|
143
|
+
The input hybridization function in Matsubara frequency
|
|
144
|
+
|
|
145
|
+
:code:`debug`: bool
|
|
146
|
+
return additional outputs for debugging.
|
|
147
|
+
Default: False
|
|
148
|
+
|
|
149
|
+
:code:`svdtol`: float, optional
|
|
150
|
+
Truncation threshold for bath orbitals while doing SVD of weight matrices in hybridization fitting
|
|
151
|
+
default: 1e-7
|
|
152
|
+
|
|
153
|
+
:code:`tol`, :code:`Np`, :code:`solver`, :code:`maxiter`, :code:`mmin`, :code:`mmax`, :code:`verbose`:
|
|
154
|
+
same as in hybfit
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
---------
|
|
158
|
+
|
|
159
|
+
:code:`bathhyb`: np.array :math:`(N_b, N_\mathrm{orb})`
|
|
160
|
+
Bath hybridization
|
|
161
|
+
|
|
162
|
+
:code:`bathenergy`: np.array :math:`(N_b,)`
|
|
163
|
+
Bath energy
|
|
164
|
+
|
|
165
|
+
:code:`Delta_fit`: triqs Gf or BlockGf
|
|
166
|
+
Discretized hybridization function
|
|
167
|
+
The input hybridization function in Matsubara frequency
|
|
168
|
+
|
|
169
|
+
if debug is True:
|
|
170
|
+
:code:`final_error`: float
|
|
171
|
+
final fitting error
|
|
172
|
+
|
|
173
|
+
:code:`weight`: np.array :math:`(N_p, N_\mathrm{orb}, N_\mathrm{orb})`
|
|
174
|
+
weights obtained from fitting
|
|
175
|
+
"""
|
|
176
|
+
try:
|
|
177
|
+
from triqs.gf import Gf, BlockGf, MeshImFreq, MeshDLRImFreq
|
|
178
|
+
except ImportError:
|
|
179
|
+
raise ImportError("Failed to import the triqs package (https://triqs.github.io/triqs/latest/). "
|
|
180
|
+
"Please ensure it is installed.")
|
|
181
|
+
|
|
182
|
+
if isinstance(Delta_triqs, Gf) and isinstance(Delta_triqs.mesh, (MeshImFreq, MeshDLRImFreq)):
|
|
183
|
+
iwn_vec = np.array([iw.value for iw in Delta_triqs.mesh.values()])
|
|
184
|
+
eps_opt, V_opt, final_error, func = hybfit(Delta_triqs.data, iwn_vec, tol, Np,
|
|
185
|
+
svdtol, solver, maxiter, mmin, mmax, verbose)
|
|
186
|
+
print('optimization finished with fitting error {:.3e}'.format(final_error))
|
|
187
|
+
|
|
188
|
+
delta_fit = Gf(mesh=Delta_triqs.mesh, target_shape=Delta_triqs.target_shape)
|
|
189
|
+
delta_fit.data[:] = func(iwn_vec)
|
|
190
|
+
|
|
191
|
+
if debug:
|
|
192
|
+
return V_opt.T.conj(), eps_opt, delta_fit, final_error
|
|
193
|
+
else:
|
|
194
|
+
return V_opt.T.conj(), eps_opt, delta_fit
|
|
195
|
+
elif isinstance(Delta_triqs, BlockGf) and isinstance(Delta_triqs.mesh, (MeshImFreq, MeshDLRImFreq)):
|
|
196
|
+
V_list, eps_list, delta_list, error_list = [], [], [], []
|
|
197
|
+
for j, (block, delta_blk) in enumerate(Delta_triqs):
|
|
198
|
+
res = hybfit_triqs(delta_blk, tol, Np, svdtol, solver, maxiter, mmin, mmax, verbose, debug)
|
|
199
|
+
V_list.append(res[0])
|
|
200
|
+
eps_list.append(res[1])
|
|
201
|
+
delta_list.append(res[2])
|
|
202
|
+
if debug:
|
|
203
|
+
error_list.append(res[3])
|
|
204
|
+
|
|
205
|
+
if debug:
|
|
206
|
+
return V_list, eps_list, BlockGf(name_list=list(Delta_triqs.indices), block_list=delta_list), error_list
|
|
207
|
+
else:
|
|
208
|
+
return V_list, eps_list, BlockGf(name_list=list(Delta_triqs.indices), block_list=delta_list)
|
|
209
|
+
else:
|
|
210
|
+
raise RuntimeError("Error: Delta_triqs.mesh must be an instance of MeshImFreq or MeshDLRImFreq.")
|
|
211
|
+
|
|
212
|
+
def obtain_orbitals(pol, weight, svdtol=1e-7):
|
|
213
|
+
"""
|
|
214
|
+
obtaining bath orbitals through svd
|
|
215
|
+
"""
|
|
216
|
+
polelist = []
|
|
217
|
+
veclist = []
|
|
218
|
+
matlist = []
|
|
219
|
+
for i in range(weight.shape[0]):
|
|
220
|
+
eigval, eigvec = np.linalg.eig(weight[i])
|
|
221
|
+
for j in range(eigval.shape[0]):
|
|
222
|
+
if eigval[j] > svdtol:
|
|
223
|
+
polelist.append(pol[i])
|
|
224
|
+
veclist.append(eigvec[:, j] * np.sqrt(eigval[j]))
|
|
225
|
+
matlist.append(
|
|
226
|
+
(eigvec[:, j, None] * np.conjugate(eigvec[:, j].T)) * (eigval[j])
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
return np.array(polelist), np.array(veclist), np.array(matlist)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: adapol
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Adaptive Pole Fitting for Quantum Many-Body Physics
|
|
5
|
+
Author-email: Zhen Huang <hertz@berkeley.edu>, Chia-Nan Yeh <cyeh@flatironinstitute.org>, Nils Wentzell <nwentzell@flatironinstitute.org>, Jason Kaye <jkaye@flatironinstitute.org>, Lin Lin <linlin@berkeley.edu>
|
|
6
|
+
Project-URL: Homepage, https://flatironinstitute.github.io/adapol
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/flatironinstitute/adapol/issues
|
|
8
|
+
Keywords: Bath,Fitting,Hybridization,DMFT,Matsubara
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.7
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: numpy
|
|
15
|
+
Requires-Dist: scipy
|
|
16
|
+
Requires-Dist: cvxpy
|
|
17
|
+
|
|
18
|
+
# adapol: Adaptive Pole Fitting for Quantum Many-Body Physics
|
|
19
|
+
[`adapol`](https://github.com/Hertz4/Adapol) (pronounced "add a pole") is a python package for fitting Matsubara functions with the following form:
|
|
20
|
+
```math
|
|
21
|
+
G(\mathrm i \omega_k) = \sum_l \frac{V_lV_l^{\dagger}}{\mathrm i\omega_k - E_l}.
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Current applications include
|
|
25
|
+
(1) hybridization fitting, (2) analytic continuation.
|
|
26
|
+
|
|
27
|
+
We also provide a [TRIQS](https://triqs.github.io/) interface if the Matsubara functions are stored in `triqs` Green's function container.
|
|
28
|
+
|
|
29
|
+
# Installation
|
|
30
|
+
`adapol` has `numpy` and `scipy` as its prerequisites. [`cvxpy`](https://www.cvxpy.org/) is also required for hybridization fitting of matrix-valued (instead of scalar-valued) Matsubara functions.
|
|
31
|
+
|
|
32
|
+
To install `adapol`, run
|
|
33
|
+
```terminal
|
|
34
|
+
pip install adapol
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Documentation
|
|
40
|
+
|
|
41
|
+
See the detailed [documentation](https://flatironinstitute.github.io/adapol/) for physical background, algorithms and user manual.
|
|
42
|
+
|
|
43
|
+
`Adapol` is a stand-alone package. For TRIQS users, we also provide a TRIQS interface. See [user manual](https://flatironinstitute.github.io/adapol/latest/python.html#triqs-interface) for details.
|
|
44
|
+
|
|
45
|
+
# Examples
|
|
46
|
+
In the `tutorial` page, we provide two examples [`discrete.ipynb`](https://flatironinstitute.github.io/adapol/latest/tutorials/discrete.html) and [`semicircle.ipynb`](https://flatironinstitute.github.io/adapol/latest/tutorials/semicircle.html), showcasing how to use `adapol` for both discrete spectrum and continuous spectrum.
|
|
47
|
+
|
|
48
|
+
In these notebooks, we also demonstrate how to use our code through the triqs interface.
|
|
49
|
+
|
|
50
|
+
# References
|
|
51
|
+
To cite this work, please include a reference to this GitHub repository, and
|
|
52
|
+
cite the following references:
|
|
53
|
+
|
|
54
|
+
1. Huang, Zhen, Emanuel Gull, and Lin Lin. "Robust analytic continuation of Green's functions via projection, pole estimation, and semidefinite relaxation." Physical Review B 107.7 (2023): 075151.
|
|
55
|
+
2. Mejuto-Zaera, Carlos, et al. "Efficient hybridization fitting for dynamical mean-field theory via semi-definite relaxation." Physical Review B 101.3 (2020): 035143.
|
|
56
|
+
3. Nakatsukasa, Yuji, Olivier Sète, and Lloyd N. Trefethen. "The AAA algorithm for rational approximation." SIAM Journal on Scientific Computing 40.3 (2018): A1494-A1522.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/adapol/__init__.py
|
|
5
|
+
src/adapol/aaa.py
|
|
6
|
+
src/adapol/anacont.py
|
|
7
|
+
src/adapol/fit_utils.py
|
|
8
|
+
src/adapol/hybfit.py
|
|
9
|
+
src/adapol.egg-info/PKG-INFO
|
|
10
|
+
src/adapol.egg-info/SOURCES.txt
|
|
11
|
+
src/adapol.egg-info/dependency_links.txt
|
|
12
|
+
src/adapol.egg-info/requires.txt
|
|
13
|
+
src/adapol.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
adapol
|