TRIQS/triqs_tprf 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
eliashberg.cpp
1/*******************************************************************************
2 *
3 * TRIQS: a Toolbox for Research in Interacting Quantum Systems
4 *
5 * Copyright (C) 2019, The Simons Foundation and S. Käser
6 * Authors: S. Käser, H. U.R. Strand
7 *
8 * TRIQS is free software: you can redistribute it and/or modify it under the
9 * terms of the GNU General Public License as published by the Free Software
10 * Foundation, either version 3 of the License, or (at your option) any later
11 * version.
12 *
13 * TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
14 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * TRIQS. If not, see <http://www.gnu.org/licenses/>.
20 *
21 ******************************************************************************/
22
23#include "common.hpp"
24
25#include "eliashberg.hpp"
26#include <omp.h>
27#include "../mpi.hpp"
28
29#include "gf.hpp"
30#include "fourier.hpp"
31
32namespace triqs_tprf {
33
34// Helper function computing F = GG \Delta
35
36template<typename F_out_t, typename g_t>
37F_out_t eliashberg_g_delta_g_product_template(g_t g_wk, g_t delta_wk) {
38
39 auto wmesh = std::get<0>(delta_wk.mesh());
40 auto kmesh = std::get<1>(delta_wk.mesh());
41
42 auto wmesh_gf = std::get<0>(g_wk.mesh());
43
44 if (wmesh.size() > wmesh_gf.size())
45 TRIQS_RUNTIME_ERROR << "The size of the Matsubara frequency mesh of the Green's function"
46 " (" << wmesh_gf.size() << ") must be atleast the size of the mesh of Delta (" <<
47 wmesh.size() << ").";
48
49 auto F_wk = make_gf(delta_wk);
50 F_wk *= 0.;
51
52 auto meshes_mpi = mpi_view(delta_wk.mesh());
53#pragma omp parallel for
54 for (unsigned int idx = 0; idx < meshes_mpi.size(); idx++){
55 auto &[w, k] = meshes_mpi[idx];
56
57 for (auto [d, c] : F_wk.target_indices()) {
58 for (auto [e, f] : delta_wk.target_indices()) {
59 F_wk[w, k](d, c) += g_wk[w, k](c, f) * nda::conj(g_wk[w, -k](e, d)) * delta_wk[w, k](e, f);
60 }
61 }
62 }
63
64 F_wk = mpi::all_reduce(F_wk);
65
66 return F_wk;
67}
68
69g_wk_t eliashberg_g_delta_g_product(g_wk_vt g_wk, g_wk_vt delta_wk) {
70 return eliashberg_g_delta_g_product_template<g_wk_t, g_wk_vt>(g_wk, delta_wk);
71}
72
73g_Dwk_t eliashberg_g_delta_g_product(g_Dwk_vt g_wk, g_Dwk_vt delta_wk) {
74
75 // Performing the product of (G*G) * delta in DLR coefficient space
76 // removes spurious eigenvectors in the linearized Eliashberg equation.
77 // (H. U.R. Strand July 2023)
78
79 auto wmesh = std::get<0>(delta_wk.mesh());
80 auto kmesh = std::get<1>(delta_wk.mesh());
81
82 auto wmesh_gf = std::get<0>(g_wk.mesh());
83
84 if (wmesh.size() > wmesh_gf.size())
85 TRIQS_RUNTIME_ERROR << "The size of the Matsubara frequency mesh of the Green's function"
86 " (" << wmesh_gf.size() << ") must be atleast the size of the mesh of Delta (" <<
87 wmesh.size() << ").";
88
89 auto F_wk = make_gf(delta_wk);
90 F_wk *= 0.;
91
92 auto tmesh = dlr_imtime(wmesh);
93 tmesh.dlr_it().convolve_init(); // NB! Initialization not thread-safe, trigger it manually here.
94
95 auto mesh_mpi = mpi_view(kmesh);
96#pragma omp parallel for
97 for (unsigned int idx = 0; idx < mesh_mpi.size(); idx++){
98 auto & k = mesh_mpi[idx];
99
100 for (auto [d, c] : g_wk.target_indices()) {
101 for (auto [e, f] : delta_wk.target_indices()) {
102
103 auto gg_w = gf(wmesh);
104 auto d_w = gf(wmesh);
105
106 for( auto w : wmesh ) {
107 gg_w[w] = g_wk[w, k](c, f) * nda::conj(g_wk[w, -k](e, d));
108 d_w[w] = delta_wk[w, k](e, f);
109 }
110
111 auto gg_c = make_gf_dlr(gg_w);
112 auto d_c = make_gf_dlr(d_w);
113
114 auto f_t = gf(tmesh);
115 f_t.data() = tmesh.dlr_it().convolve(
116 tmesh.beta(), gg_c.data(), d_c.data());
117
118 auto f_c = make_gf_dlr(f_t);
119 auto f_w = make_gf_dlr_imfreq(f_c);
120
121 for( auto w : wmesh ) {
122 F_wk[w, k](d, c) += f_w[w];
123 }
124 }
125 }
126 }
127
128 F_wk = mpi::all_reduce(F_wk);
129
130 return F_wk;
131}
132
133g_wk_t eliashberg_product(chi_wk_vt Gamma_pp, g_wk_vt g_wk,
134 g_wk_vt delta_wk) {
135
136 //auto [wmesh, kmesh] = delta_wk.mesh();
137 auto wmesh = std::get<0>(delta_wk.mesh());
138 auto kmesh = std::get<1>(delta_wk.mesh());
139
140 auto gamma_wmesh = std::get<0>(Gamma_pp.mesh());
141
142 if (2*wmesh.size() > gamma_wmesh.size())
143 TRIQS_RUNTIME_ERROR << "The size of the Matsubara frequency mesh of Gamma"
144 " (" << gamma_wmesh.size() << ") must be atleast TWICE the size of the mesh of Delta (" <<
145 wmesh.size() << ").";
146
147 auto F_wk = eliashberg_g_delta_g_product(g_wk, delta_wk);
148
149 auto delta_wk_out = make_gf(delta_wk);
150 delta_wk_out *= 0.;
151
152 auto arr = mpi_view(kmesh);
153#pragma omp parallel for
154 for (int kidx = 0; kidx < arr.size(); kidx++) {
155 auto &k = arr[kidx];
156 for (auto w : wmesh) {
157 for (auto [n, q] : delta_wk.mesh())
158 for (auto [c, a, d, b] : Gamma_pp.target_indices())
159 delta_wk_out[w, k](a, b) += -0.5 * Gamma_pp(w - n, k - q)(c, a, d, b) * F_wk[n, q](d, c);
160 }
161 }
162
163 delta_wk_out /= (wmesh.beta() * kmesh.size());
164
165 delta_wk_out = mpi::all_reduce(delta_wk_out);
166
167 return delta_wk_out;
168}
169
170std::tuple<chi_tr_t, chi_r_t> dynamic_and_constant_to_tr(chi_wk_vt Gamma_pp_dyn_wk, chi_k_vt Gamma_pp_const_k) {
171
172 auto Gamma_pp_dyn_wr = fourier_wk_to_wr_general_target(Gamma_pp_dyn_wk);
173 auto Gamma_pp_dyn_tr = fourier_wr_to_tr_general_target(Gamma_pp_dyn_wr);
174
175 auto Gamma_pp_const_r = make_gf_from_fourier<0>(Gamma_pp_const_k);
176
177 return {Gamma_pp_dyn_tr, Gamma_pp_const_r};
178}
179
180std::tuple<chi_Dtr_t, chi_r_t> dynamic_and_constant_to_tr(chi_Dwk_vt Gamma_pp_dyn_wk, chi_k_vt Gamma_pp_const_k) {
181
182 auto Gamma_pp_dyn_wr = fourier_wk_to_wr_general_target(Gamma_pp_dyn_wk);
183 auto Gamma_pp_dyn_tr = fourier_Dwr_to_Dtr_general_target(Gamma_pp_dyn_wr);
184
185 auto Gamma_pp_const_r = make_gf_from_fourier<0>(Gamma_pp_const_k);
186
187 return {Gamma_pp_dyn_tr, Gamma_pp_const_r};
188}
189
190e_r_t eliashberg_constant_gamma_f_product(chi_r_vt Gamma_pp_const_r, g_tr_t F_tr) {
191
192 auto _ = all_t{};
193
194 auto delta_r_out = make_gf(std::get<1>(F_tr.mesh()), F_tr.target());
195 delta_r_out *= 0.;
196
197 for (auto r : std::get<1>(F_tr.mesh())) {
198 auto F_t = F_tr[_, r];
199 for (auto [c, a, d, b] : Gamma_pp_const_r.target_indices()) delta_r_out[r](a, b) += -0.5 * Gamma_pp_const_r[r](c, a, d, b) * F_t(0)(d, c);
200 }
201
202 return delta_r_out;
203}
204
205e_r_t eliashberg_constant_gamma_f_product(chi_r_vt Gamma_pp_const_r, g_Dtr_t F_tr) {
206
207 auto _ = all_t{};
208 auto tmesh = std::get<0>(F_tr.mesh());
209
210 auto delta_r_out = make_gf(std::get<1>(F_tr.mesh()), F_tr.target());
211 delta_r_out *= 0.;
212
213 for (auto r : std::get<1>(F_tr.mesh())) {
214 g_Dt_t F_t({tmesh}, F_tr.target_shape());
215 F_t() = F_tr[_, r];
216 auto F_Dc = make_gf_dlr(F_t);
217 for (auto [c, a, d, b] : Gamma_pp_const_r.target_indices())
218 delta_r_out[r](a, b) += -0.5 * Gamma_pp_const_r[r](c, a, d, b) * F_Dc(0)(d, c);
219 }
220
221 return delta_r_out;
222}
223
224template<typename delta_t, typename chi_t, typename F_t>
225delta_t eliashberg_dynamic_gamma_f_product_template(chi_t Gamma_pp_dyn_tr, F_t F_tr) {
226
227 //auto [tmesh, rmesh] = F_tr.mesh();
228 auto tmesh = std::get<0>(F_tr.mesh());
229 auto rmesh = std::get<1>(F_tr.mesh());
230
231 auto delta_tr_out = make_gf(F_tr);
232 delta_tr_out *= 0.;
233
234 auto tmesh_gamma = std::get<0>(Gamma_pp_dyn_tr.mesh());
235
236 // Test if the tau meshs of delta and gamma are compatible. If not raise an error, because
237 // it would lead to wrong results.
238 if (tmesh.size() != tmesh_gamma.size())
239 TRIQS_RUNTIME_ERROR << "The size of the imaginary time mesh of Gamma"
240 " (" << tmesh_gamma.size() << ") must be the size of the mesh of Delta (" <<
241 tmesh.size() << ").";
242
243 auto meshes_mpi = mpi_view(F_tr.mesh());
244#pragma omp parallel for
245 for (unsigned int idx = 0; idx < meshes_mpi.size(); idx++){
246 auto &[t, r] = meshes_mpi[idx];
247
248 for (auto [c, a, d, b] : Gamma_pp_dyn_tr.target_indices())
249 delta_tr_out[t, r](a, b) += -0.5 * Gamma_pp_dyn_tr[t, r](c, a, d, b) * F_tr[t, r](d, c);
250 }
251
252 delta_tr_out = mpi::all_reduce(delta_tr_out);
253
254 return delta_tr_out;
255}
256
257g_tr_t eliashberg_dynamic_gamma_f_product(chi_tr_vt Gamma_pp_dyn_tr, g_tr_vt F_tr) {
258 return eliashberg_dynamic_gamma_f_product_template<g_tr_t, chi_tr_vt, g_tr_vt>(Gamma_pp_dyn_tr, F_tr);
259}
260
261g_Dtr_t eliashberg_dynamic_gamma_f_product(chi_Dtr_vt Gamma_pp_dyn_tr, g_Dtr_vt F_tr) {
262 return eliashberg_dynamic_gamma_f_product_template<g_Dtr_t, chi_Dtr_vt, g_Dtr_vt>(Gamma_pp_dyn_tr, F_tr);
263}
264
265
266template<typename delta_out_t, typename chi_t, typename g_t>
267delta_out_t eliashberg_product_fft_template(chi_t Gamma_pp_dyn_tr, chi_r_vt Gamma_pp_const_r,
268 g_t g_wk, g_t delta_wk) {
269
270 auto F_wk = eliashberg_g_delta_g_product(g_wk, delta_wk);
271 auto F_wr = fourier_wk_to_wr(F_wk);
272 auto F_tr = fourier_wr_to_tr(F_wr);
273
274 auto delta_tr_out = eliashberg_dynamic_gamma_f_product(Gamma_pp_dyn_tr, F_tr);
275 auto delta_r_out = eliashberg_constant_gamma_f_product(Gamma_pp_const_r, F_tr);
276
277 // FIXME
278 // This raises warnings when used with random delta input, e.g. eigenvalue finder
279 auto delta_wr_out = fourier_tr_to_wr(delta_tr_out);
280 // Combine dynamic and constant part
281 auto _ = all_t{};
282 for (auto w : std::get<0>(delta_wr_out.mesh())) delta_wr_out[w, _] += delta_r_out;
283
284 auto delta_wk_out = fourier_wr_to_wk(delta_wr_out);
285 return delta_wk_out;
286}
287
288g_wk_t eliashberg_product_fft(chi_tr_vt Gamma_pp_dyn_tr, chi_r_vt Gamma_pp_const_r, g_wk_vt g_wk, g_wk_vt delta_wk) {
289 return eliashberg_product_fft_template<g_wk_t, chi_tr_vt, g_wk_vt>(Gamma_pp_dyn_tr, Gamma_pp_const_r, g_wk, delta_wk);
290}
291
292g_Dwk_t eliashberg_product_fft(chi_Dtr_vt Gamma_pp_dyn_tr, chi_r_vt Gamma_pp_const_r, g_Dwk_vt g_wk, g_Dwk_vt delta_wk) {
293 return eliashberg_product_fft_template<g_Dwk_t, chi_Dtr_vt, g_Dwk_vt>(Gamma_pp_dyn_tr, Gamma_pp_const_r, g_wk, delta_wk);
294}
295
296// optimized version if there is only a constant term
297
298template<typename delta_out_t, typename g_t>
299delta_out_t eliashberg_product_fft_constant_template(chi_r_vt Gamma_pp_const_r,
300 g_t g_wk, g_t delta_wk) {
301
302 auto F_wk = eliashberg_g_delta_g_product(g_wk, delta_wk);
303 auto F_wr = fourier_wk_to_wr(F_wk);
304 auto F_tr = fourier_wr_to_tr(F_wr);
305
306 auto delta_r_out = eliashberg_constant_gamma_f_product(Gamma_pp_const_r, F_tr);
307 auto delta_k_out = make_gf_from_fourier<0>(delta_r_out);
308
309 auto delta_wk_out = make_gf(F_wk);
310 delta_wk_out *= 0.;
311
312 auto _ = all_t{};
313 for (auto w : std::get<0>(delta_wk_out.mesh())) delta_wk_out[w, _] += delta_k_out;
314
315 return delta_wk_out;
316}
317
318g_wk_t eliashberg_product_fft_constant(chi_r_vt Gamma_pp_const_r, g_wk_vt g_wk, g_wk_vt delta_wk) {
319 return eliashberg_product_fft_constant_template<g_wk_t, g_wk_vt>(Gamma_pp_const_r, g_wk, delta_wk);
320}
321
322g_Dwk_t eliashberg_product_fft_constant(chi_r_vt Gamma_pp_const_r, g_Dwk_vt g_wk, g_Dwk_vt delta_wk) {
323 return eliashberg_product_fft_constant_template<g_Dwk_t, g_Dwk_vt>(Gamma_pp_const_r, g_wk, delta_wk);
324}
325
326
327chi_wk_t construct_phi_wk(chi_wk_vt chi, array_contiguous_view<std::complex<double>, 4> U) {
328
329 using scalar_t = chi_wk_t::scalar_t;
330
331 size_t nb = chi.target_shape()[0];
332
333 auto phi_wk = make_gf(chi);
334 phi_wk *= 0;
335
336 // PH grouping of the vertex, from cc+cc+, permuting the last two indices.
337 auto U_matrix = make_matrix_view(group_indices_view(U, idx_group<0, 1>, idx_group<3, 2>));
338
339 auto meshes_mpi = mpi_view(phi_wk.mesh());
340
341#pragma omp parallel for
342 for (unsigned int idx = 0; idx < meshes_mpi.size(); idx++){
343 auto &[w, k] = meshes_mpi[idx];
344
345 array<scalar_t, 4> phi_arr{nb, nb, nb, nb};
346 array<scalar_t, 4> chi_arr{chi[w, k]};
347
348 // PH grouping of the vertex, from cc+cc+, permuting the last two indices.
349 auto phi_matrix = make_matrix_view(group_indices_view(phi_arr, idx_group<0, 1>, idx_group<3, 2>));
350 // PH grouping of the susceptibilites, from c+cc+c, permuting the last two indices.
351 auto chi_matrix = make_matrix_view(group_indices_view(chi_arr, idx_group<0, 1>, idx_group<3, 2>));
352
353 phi_matrix = U_matrix * chi_matrix * U_matrix;
354
355 phi_wk[w, k] = phi_arr;
356 }
357 phi_wk = mpi::all_reduce(phi_wk);
358
359 return phi_wk;
360}
361
362} // namespace triqs_tprf