Skip to content

Commit 74ca924

Browse files
committed
[gw] Implemented gw_sigma for DLR
1 parent cdfd23a commit 74ca924

File tree

5 files changed

+209
-40
lines changed

5 files changed

+209
-40
lines changed

c++/triqs_tprf/lattice/gw.cpp

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -169,36 +169,29 @@ namespace triqs_tprf {
169169
return sigma_r;
170170
}
171171

172-
e_k_t fock_sigma(chi_k_cvt v_k, g_wk_cvt g_wk) {
173-
174-
if (v_k.mesh() != std::get<1>(g_wk.mesh())) TRIQS_RUNTIME_ERROR << "fock_sigma: k-space meshes are not the same.\n";
175-
176-
auto _ = all_t{};
177-
auto kmesh = std::get<1>(g_wk.mesh());
178-
179-
e_k_t sigma_k(kmesh, g_wk.target_shape());
180-
sigma_k() = 0.0;
181-
182-
auto arr = mpi_view(kmesh);
183-
#pragma omp parallel for
184-
for (unsigned int idx = 0; idx < arr.size(); idx++) {
185-
auto &k = arr[idx];
186-
187-
for (auto q : kmesh) {
188-
189-
auto g_w = g_wk[_, k + q];
190-
auto dens = density(g_w);
172+
template<typename g_t>
173+
e_k_t fock_sigma_impl(chi_k_cvt v_k, g_t g_wk) {
174+
auto v_r = make_gf_from_fourier(v_k);
175+
auto rho_k = rho_k_from_g_wk(g_wk);
176+
auto rho_r = make_gf_from_fourier(rho_k);
177+
auto sigma_fock_r = fock_sigma(v_r, rho_r);
178+
auto sigma_fock_k = make_gf_from_fourier(sigma_fock_r);
179+
return sigma_fock_k;
180+
}
191181

192-
for (auto [a, b, c, d] : v_k.target_indices()) { sigma_k[k](a, b) += -v_k[q](a, c, d, b) * dens(d, c) / kmesh.size(); }
193-
}
182+
e_k_t fock_sigma(chi_k_cvt v_k, g_wk_cvt g_wk) {
183+
return fock_sigma_impl(v_k, g_wk);
194184
}
195-
sigma_k = mpi::all_reduce(sigma_k);
196-
return sigma_k;
185+
e_k_t fock_sigma(chi_k_cvt v_k, g_Dwk_cvt g_wk) {
186+
return fock_sigma_impl(v_k, g_wk);
197187
}
198188

199189
e_k_t gw_sigma(chi_k_cvt v_k, g_wk_cvt g_wk) {
200190
return fock_sigma(v_k, g_wk);
201191
}
192+
e_k_t gw_sigma(chi_k_cvt v_k, g_Dwk_cvt g_wk) {
193+
return fock_sigma(v_k, g_wk);
194+
}
202195

203196
template<typename W_dyn_t, typename W_const_t, typename g_t>
204197
auto gw_sigma_impl(W_dyn_t W_dyn_wk, W_const_t W_const_k, g_t g_wk) {
@@ -214,29 +207,20 @@ namespace triqs_tprf {
214207
TRIQS_RUNTIME_ERROR << "gw_sigma: k-space meshes are not the same.\n";
215208

216209
// Dynamic GW self energy
217-
//auto g_tr = make_gf_from_fourier<0, 1>(g_wk); // Fixme! Use parallell transform
218210
auto g_wr = fourier_wk_to_wr(g_wk);
219211
auto g_tr = fourier_wr_to_tr(g_wr);
220-
221-
//auto W_dyn_tr = make_gf_from_fourier<0, 1>(W_dyn_wk); // Fixme! Use parallell transform
222212
auto W_dyn_wr = chi_wr_from_chi_wk(W_dyn_wk);
223213
auto W_dyn_tr = chi_tr_from_chi_wr(W_dyn_wr);
224214

225215
auto sigma_dyn_tr = gw_dynamic_sigma(W_dyn_tr, g_tr);
226216

227217
// Static Fock part
228-
229-
//auto sigma_fock_k = fock_sigma(W_const_k, g_wk); // Has N_k^2 scaling, not fast..
230-
231-
auto W_const_r = make_gf_from_fourier(W_const_k);
232-
auto rho_k = rho_k_from_g_wk(g_wk);
233-
auto rho_r = make_gf_from_fourier(rho_k);
234-
auto sigma_fock_r = fock_sigma(W_const_r, rho_r);
235-
auto sigma_fock_k = make_gf_from_fourier(sigma_fock_r);
218+
auto sigma_fock_k = fock_sigma(W_const_k, g_wk);
236219

237220
// Add dynamic and static parts
238221
auto _ = all_t{};
239-
auto sigma_wk = make_gf_from_fourier<0, 1>(sigma_dyn_tr); // Fixme! Use parallell transform
222+
auto sigma_wr = fourier_tr_to_wr(sigma_dyn_tr);
223+
auto sigma_wk = fourier_wr_to_wk(sigma_wr);
240224
for (auto w : gwm) sigma_wk[w, _] += sigma_fock_k; // Single loop with no work per w, no need to parallellize over mpi
241225

242226
return sigma_wk;
@@ -247,11 +231,14 @@ namespace triqs_tprf {
247231
return gw_sigma_impl(W_dyn_wk, W_const_k, g_wk);
248232
}
249233

250-
/*
251-
g_Dwk_t gw_sigma(chi_Dwk_cvt W_wk, g_Dwk_cvt g_wk) {
252-
return gw_sigma_impl(W_wk, g_wk);
234+
g_Dwk_t gw_sigma(chi_Dwk_cvt W_wk, chi_k_cvt v_k, g_Dwk_cvt g_wk) {
235+
auto wmesh = std::get<0>(W_wk.mesh());
236+
auto _ = all_t{};
237+
chi_Dwk_t W_dyn_wk(W_wk.mesh(), W_wk.target_shape());
238+
for (auto w : wmesh) W_dyn_wk[w, _] = W_wk[w,_] - v_k;
239+
240+
return gw_sigma_impl(W_dyn_wk, v_k, g_wk);
253241
}
254-
*/
255242

256243
// ----------------------------------------------------
257244
// g0w_sigma via spectral representation

c++/triqs_tprf/lattice/gw.hpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,57 @@ namespace triqs_tprf {
9090
*/
9191

9292
g_wk_t gw_sigma(chi_wk_cvt W_wk, g_wk_cvt g_wk);
93-
93+
94+
/** GW self energy :math:`\Sigma(i\omega_n, \mathbf{k})` calculator for dynamic interactions
95+
96+
Fourier transforms the dynamic part of the interaction and the
97+
single-particle Green's function to imaginary time and real space.
98+
99+
.. math::
100+
G_{ab}(\tau, \mathbf{r}) = \mathcal{F}^{-1}
101+
\left\{ G_{ab}(i\omega_n, \mathbf{k}) \right\}
102+
103+
.. math::
104+
W^{(dyn)}_{abcd}(\tau, \mathbf{r}) = \mathcal{F}^{-1}
105+
\left\{ W^{(dyn)}_{abcd}(i\omega_n, \mathbf{k}) \right\}
106+
107+
computes the GW self-energy as the product
108+
109+
.. math::
110+
\Sigma^{(dyn)}_{ab}(\tau, \mathbf{r}) =
111+
- \sum_{cd} W^{(dyn)}_{acdb}(\tau, \mathbf{r}) G_{cd}(\tau, \mathbf{r})
112+
113+
and transforms back to frequency and momentum
114+
115+
.. math::
116+
\Sigma^{(dyn)}_{ab}(i\omega_n, \mathbf{k}) =
117+
\mathcal{F} \left\{ \Sigma^{(dyn)}_{ab}(\tau, \mathbf{r}) \right\}
118+
119+
The self-energy of the static part of the interaction is calculated
120+
as the sum
121+
122+
.. math::
123+
\Sigma^{(stat)}_{ab}(\mathbf{k}) = -\frac{1}{N_k}
124+
\sum_{\mathbf{q},cd} V_{acdb}(\mathbf{k}) \rho_{dc}(\mathbf{k} + \mathbf{q})
125+
126+
where :math:`\rho_{ab}(\mathbf{k}) = -G_{ba}(\beta, \mathbf{k})` is the density matrix of the
127+
single particle Green's function.
128+
129+
The total GW self-energy is given by
130+
131+
.. math::
132+
\Sigma_{ab}(i\omega_n, \mathbf{k}) =
133+
\Sigma^{(dyn)}_{ab}(i\omega_n, \mathbf{k})
134+
+ \Sigma^{(stat)}_{ab}(\mathbf{k})
135+
136+
@param W_wk interaction :math:`W_{abcd}(i\omega_n, \mathbf{k})`
137+
@param V_k static interaction :math:`V_{abcd}(\mathbf{q})`
138+
@param g_wk single particle Green's function :math:`G_{ab}(i\omega_n, \mathbf{k})`
139+
@return GW self-energy :math:`\Sigma_{ab}(i\omega_n, \mathbf{k})`
140+
*/
141+
142+
g_Dwk_t gw_sigma(chi_Dwk_cvt W_wk, chi_k_cvt v_k, g_Dwk_cvt g_wk);
143+
94144
/** Hartree self energy :math:`\Sigma_{ab}(\mathbf{k})` calculator
95145
96146
Computes the Hartree self-energy of a static interaction as the sum
@@ -128,6 +178,7 @@ namespace triqs_tprf {
128178
*/
129179

130180
e_k_t fock_sigma(chi_k_cvt v_k, g_wk_cvt g_wk);
181+
e_k_t fock_sigma(chi_k_cvt v_k, g_Dwk_cvt g_wk);
131182

132183
e_r_t fock_sigma(chi_r_cvt v_r, e_r_cvt rho_r);
133184

@@ -141,6 +192,7 @@ namespace triqs_tprf {
141192
*/
142193

143194
e_k_t gw_sigma(chi_k_cvt v_k, g_wk_cvt g_wk);
195+
e_k_t gw_sigma(chi_k_cvt v_k, g_Dwk_cvt g_wk);
144196

145197
/** Dynamic GW self energy :math:`\Sigma(\tau, \mathbf{r})` calculator
146198

python/triqs_tprf/lattice_desc.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,9 @@
698698
out
699699
GW self-energy :math:`\Sigma_{ab}(i\omega_n, \mathbf{k})`""")
700700

701+
702+
module.add_function ("g_Dwk_t gw_sigma(chi_Dwk_cvt W_wk, chi_k_cvt v_k, g_Dwk_cvt g_wk)")
703+
701704
module.add_function ("triqs_tprf::e_r_t triqs_tprf::hartree_sigma (triqs_tprf::chi_k_cvt v_k, triqs_tprf::e_r_cvt rho_r)")
702705
module.add_function ("triqs_tprf::e_r_t triqs_tprf::fock_sigma (triqs_tprf::chi_r_cvt v_r, triqs_tprf::e_r_cvt rho_r)")
703706

@@ -749,6 +752,8 @@
749752
out
750753
Fock self-energy :math:`\Sigma_{ab}(\mathbf{k})`""")
751754

755+
module.add_function ("e_k_t fock_sigma(chi_k_cvt v_k, g_Dwk_cvt g_wk)")
756+
752757
module.add_function ("triqs_tprf::e_k_t triqs_tprf::gw_sigma (triqs_tprf::chi_k_cvt v_k, triqs_tprf::g_wk_cvt g_wk)", doc = r"""Static GW self energy :math:`\Sigma(\mathbf{k})` calculator
753758
754759
Computes the GW self-energy (equivalent to the Fock self-energy)
@@ -766,6 +771,8 @@
766771
out
767772
Static GW self-energy (Fock) :math:`\Sigma_{ab}(\mathbf{k})`""")
768773

774+
module.add_function ("e_k_t gw_sigma(chi_k_cvt v_k, g_Dwk_cvt g_wk)")
775+
769776
module.add_function ("triqs_tprf::g_tr_t triqs_tprf::gw_dynamic_sigma (triqs_tprf::chi_tr_cvt W_tr, triqs_tprf::g_tr_cvt g_tr)", doc = r"""Dynamic GW self energy :math:`\Sigma(\tau, \mathbf{r})` calculator
770777
771778
Computes the GW self-energy as the product

test/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set(all_tests
1111
lattice_utility
1212
gf
1313
gw
14+
gw_dlr
1415
gw_hubbard_dimer
1516
gw_hubbard_dimer_dlr
1617
gw_hubbard_dimer_matrix

test/python/gw_dlr.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
# ----------------------------------------------------------------------
2+
3+
import itertools
4+
import numpy as np
5+
6+
# ----------------------------------------------------------------------
7+
8+
from triqs_tprf.tight_binding import TBLattice
9+
10+
from triqs_tprf.lattice import lattice_dyson_g0_wk
11+
from triqs_tprf.lattice import lattice_dyson_g_wk
12+
from triqs_tprf.lattice import dlr_on_imfreq, dlr_on_imtime
13+
14+
from triqs_tprf.gw import bubble_PI_wk
15+
from triqs_tprf.gw import dynamical_screened_interaction_W
16+
from triqs_tprf.gw import gw_sigma, fock_sigma
17+
18+
from triqs.gf import Gf, Idx
19+
from triqs.gf import MeshImFreq, MeshImTime, MeshDLRImFreq, MeshDLRImTime
20+
from triqs.gf.mesh_product import MeshProduct
21+
22+
from triqs.gf.gf_factories import make_gf_dlr
23+
24+
# ----------------------------------------------------------------------
25+
26+
def dlr_wk_on_imfreq_wk(g_Dwk, wmesh, g_k=None):
27+
DLRwmesh, kmesh = g_Dwk.mesh.components
28+
g_wk =Gf(mesh=MeshProduct(wmesh, kmesh), target_shape=g_Dwk.target_shape)
29+
g_wk.data[:] = 0.0
30+
31+
if(g_k is None):
32+
g_k = Gf(mesh=kmesh, target_shape=g_Dwk.target_shape)
33+
g_k.data[:] = 0.0
34+
35+
for k in kmesh:
36+
g_Dw = Gf(mesh=DLRwmesh, target_shape=g_Dwk.target_shape)
37+
g_Dw.data[:] = g_Dwk.data[:,k.data_index,:] - g_k.data[k.data_index,:]
38+
g_Dc = make_gf_dlr(g_Dw)
39+
g_wk[:,k] = dlr_on_imfreq(g_Dc, wmesh)
40+
g_wk.data[:,k.data_index,:] += g_k.data[k.data_index,:]
41+
42+
return g_wk
43+
44+
def compare_g_Dwk_and_g_wk(g_Dwk, g_wk, g_k=None, decimal=7):
45+
wmesh, kmesh = g_wk.mesh.components
46+
DLRwmesh = g_Dwk.mesh.components[0]
47+
48+
g_ref_wk = dlr_wk_on_imfreq_wk(g_Dwk, wmesh, g_k)
49+
50+
np.testing.assert_array_almost_equal(g_wk.data[:], g_ref_wk.data[:], decimal=decimal)
51+
52+
53+
def test_gw_sigma_functions():
54+
nk = 8
55+
norb = 1
56+
beta = 10.0
57+
V = 1.0
58+
mu = 0.1
59+
dlreta = 1e-10
60+
dlrwcut = 100.0
61+
62+
t = -1.0 * np.eye(norb)
63+
64+
t_r = TBLattice(
65+
units = [(1, 0, 0)],
66+
hopping = {
67+
(+1,) : t,
68+
(-1,) : t,
69+
},
70+
orbital_positions = [(0,0,0)]*norb,
71+
)
72+
73+
kmesh = t_r.get_kmesh(n_k=(nk, 1, 1))
74+
e_k = t_r.fourier(kmesh)
75+
76+
kmesh = e_k.mesh
77+
78+
wmesh_dlr = MeshDLRImFreq(beta, 'Fermion', dlrwcut, dlreta)
79+
80+
nw = int(dlrwcut * beta / (2.0 * np.pi) - 0.5)
81+
wmesh = MeshImFreq(beta, 'Fermion', nw)
82+
83+
g0_wk = lattice_dyson_g0_wk(mu=mu, e_k=e_k, mesh=wmesh)
84+
g0_Dwk = lattice_dyson_g0_wk(mu=mu, e_k=e_k, mesh=wmesh_dlr)
85+
86+
V_k = Gf(mesh=kmesh, target_shape=[norb]*4)
87+
V_k.data[:] = V
88+
89+
print('--> pi_bubble')
90+
PI_wk = bubble_PI_wk(g0_wk)
91+
PI_Dwk = bubble_PI_wk(g0_Dwk)
92+
93+
compare_g_Dwk_and_g_wk(PI_Dwk, PI_wk)
94+
95+
print('--> gw_sigma (static)')
96+
sigma_k = gw_sigma(V_k, g0_wk)
97+
sigma_dlr_k = gw_sigma(V_k, g0_Dwk)
98+
99+
np.testing.assert_array_almost_equal(sigma_k.data[:], sigma_dlr_k.data[:])
100+
101+
print('--> dynamical_screened_interaction_W')
102+
Wr_full_wk = dynamical_screened_interaction_W(PI_wk, V_k)
103+
Wr_full_Dwk = dynamical_screened_interaction_W(PI_Dwk, V_k)
104+
105+
compare_g_Dwk_and_g_wk(Wr_full_Dwk, Wr_full_wk, V_k, decimal=7)
106+
107+
print('--> gw_sigma (dynamic)')
108+
sigma_wk = gw_sigma(Wr_full_wk, g0_wk)
109+
sigma_Dwk = gw_sigma(Wr_full_Dwk, V_k, g0_Dwk)
110+
111+
compare_g_Dwk_and_g_wk(sigma_Dwk, sigma_wk, sigma_k, decimal=6)
112+
113+
print('--> lattice_dyson_g_wk')
114+
g_wk = lattice_dyson_g_wk(mu, e_k, sigma_wk)
115+
g_Dwk = lattice_dyson_g_wk(mu, e_k, sigma_Dwk)
116+
117+
compare_g_Dwk_and_g_wk(g_Dwk, g_wk)
118+
119+
120+
if __name__ == "__main__":
121+
test_gw_sigma_functions()
122+

0 commit comments

Comments
 (0)