TRIQS/triqs_tprf 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
gw.cpp
1/*******************************************************************************
2 *
3 * TRIQS: a Toolbox for Research in Interacting Quantum Systems
4 *
5 * Copyright (C) 2022, The Simons Foundation
6 * Authors: H. U.R. Strand, Y. in 't Veld, M. Rösner
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 <nda/nda.hpp>
24#include <nda/linalg/eigh.hpp>
25
26#include "gw.hpp"
27#include "common.hpp"
28#include "lattice_utility.hpp"
29#include "../mpi.hpp"
30
31// -- For parallell Fourier transform routines
32#include "gf.hpp"
33#include "chi_imtime.hpp"
34
35namespace triqs_tprf {
36
37 e_k_t rho_k_from_g_wk(g_wk_cvt g_wk) {
38
39 auto _ = all_t{};
40 auto kmesh = std::get<1>(g_wk.mesh());
41
42 e_k_t rho_k(kmesh, g_wk.target_shape());
43 rho_k() = 0.0;
44
45 auto arr = mpi_view(kmesh);
46#pragma omp parallel for
47 for (unsigned int idx = 0; idx < arr.size(); idx++) {
48 auto &k = arr[idx];
49 auto g_w = g_wk[_, k];
50 rho_k[k] = density(g_w);
51 }
52
53 rho_k = mpi::all_reduce(rho_k);
54 return rho_k;
55 }
56
57 e_k_t rho_k_from_g_wk(g_Dwk_cvt g_wk) {
58
59 auto _ = all_t{};
60 auto wmesh = std::get<0>(g_wk.mesh());
61 auto kmesh = std::get<1>(g_wk.mesh());
62
63 e_k_t rho_k(kmesh, g_wk.target_shape());
64 rho_k() = 0.0;
65
66 auto arr = mpi_view(kmesh);
67#pragma omp parallel for
68 for (unsigned int idx = 0; idx < arr.size(); idx++) {
69 auto &k = arr[idx];
70 auto g_w = make_gf<dlr_imfreq>({wmesh}, g_wk.target());
71 g_w = g_wk(_, k);
72 rho_k[k] = density(make_gf_dlr(g_w));
73 }
74
75 rho_k = mpi::all_reduce(rho_k);
76 return rho_k;
77 }
78
79 template<typename W_t, typename g_t>
80 auto gw_dynamic_sigma_impl(W_t W_tr, g_t g_tr) {
81
82 auto Wtm = std::get<0>(W_tr.mesh());
83 auto gtm = std::get<0>(g_tr.mesh());
84
85 if (Wtm.size() != gtm.size() || Wtm.beta() != gtm.beta()) TRIQS_RUNTIME_ERROR << "gw_sigma_tr: tau meshes are not the same.\n";
86
87 if (Wtm.statistic() != Boson || gtm.statistic() != Fermion) TRIQS_RUNTIME_ERROR << "gw_sigma_tr: statistics are incorrect.\n";
88
89 if (std::get<1>(W_tr.mesh()) != std::get<1>(g_tr.mesh())) TRIQS_RUNTIME_ERROR << "gw_sigma_tr: real-space meshes are not the same.\n";
90
91 auto sigma_tr = make_gf(g_tr);
92 sigma_tr() = 0.0;
93
94 auto arr = mpi_view(g_tr.mesh());
95#pragma omp parallel for
96 for (unsigned int idx = 0; idx < arr.size(); idx++) {
97 auto &[t, r] = arr[idx];
98
99 for (auto [a, b, c, d] : W_tr.target_indices()) { sigma_tr[t, r](a, b) += -W_tr[t, r](a, c, d, b) * g_tr[t, r](c, d); }
100 }
101
102 sigma_tr = mpi::all_reduce(sigma_tr);
103 return sigma_tr;
104 }
105
106 g_tr_t gw_dynamic_sigma(chi_tr_cvt W_tr, g_tr_cvt g_tr) {
107 return gw_dynamic_sigma_impl(W_tr, g_tr);
108 }
109
110 g_Dtr_t gw_dynamic_sigma(chi_Dtr_cvt W_tr, g_Dtr_cvt g_tr) {
111 return gw_dynamic_sigma_impl(W_tr, g_tr);
112 }
113
114
115 e_r_t hartree_sigma(chi_k_cvt v_k, e_r_cvt rho_r) {
116
117 e_r_t sigma_r(rho_r.mesh(), rho_r.target_shape());
118 sigma_r() = 0.0;
119
120 for (auto [a, b, c, d] : v_k.target_indices()) { sigma_r[{0, 0, 0}](a, b) += v_k[{0, 0, 0}](a, b, c, d) * rho_r[{0, 0, 0}](c, d); }
121
122 return sigma_r;
123 }
124
125 e_k_t hartree_sigma(chi_k_cvt v_k, g_wk_cvt g_wk) {
126
127 if (v_k.mesh() != std::get<1>(g_wk.mesh())) TRIQS_RUNTIME_ERROR << "hartree_sigma: k-space meshes are not the same.\n";
128
129 auto _ = all_t{};
130 auto kmesh = std::get<1>(g_wk.mesh());
131
132 e_k_t sigma_k(kmesh, g_wk.target_shape());
133 sigma_k() = 0.0;
134
135 auto arr = mpi_view(kmesh);
136#pragma omp parallel for
137 for (unsigned int idx = 0; idx < arr.size(); idx++) {
138 auto &k = arr[idx];
139
140 for (auto q : kmesh) {
141
142 auto g_w = g_wk[_, k + q];
143 auto dens = density(gf{g_w});
144
145 for (auto [a, b, c, d] : v_k.target_indices()) { sigma_k[k](a, b) += v_k[q](a, b, c, d) * dens(c, d) / kmesh.size(); }
146 }
147 }
148 sigma_k = mpi::all_reduce(sigma_k);
149 return sigma_k;
150 }
151
152 e_r_t fock_sigma(chi_r_cvt v_r, e_r_cvt rho_r) {
153
154 if (v_r.mesh() != rho_r.mesh()) TRIQS_RUNTIME_ERROR << "fock_sigma: r-space meshes are not the same.\n";
155
156 auto rmesh = rho_r.mesh();
157
158 e_r_t sigma_r(rmesh, rho_r.target_shape());
159 sigma_r() = 0.0;
160
161 auto arr = mpi_view(rmesh);
162#pragma omp parallel for
163 for (unsigned int idx = 0; idx < arr.size(); idx++) {
164 auto &r = arr[idx];
165
166 for (auto [a, b, c, d] : v_r.target_indices()) { sigma_r[r](a, b) += -v_r[r](a, c, d, b) * rho_r[r](d, c); }
167 }
168 sigma_r = mpi::all_reduce(sigma_r);
169 return sigma_r;
170 }
171
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 }
181
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);
184 }
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);
187 }
188
189 e_k_t gw_sigma(chi_k_cvt v_k, g_wk_cvt g_wk) {
190 return fock_sigma(v_k, g_wk);
191 }
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 }
195
196 template<typename W_dyn_t, typename W_const_t, typename g_t>
197 auto gw_sigma_impl(W_dyn_t W_dyn_wk, W_const_t W_const_k, g_t g_wk) {
198
199 auto Wwm = std::get<0>(W_dyn_wk.mesh());
200 auto gwm = std::get<0>(g_wk.mesh());
201
202 if (Wwm.beta() != gwm.beta())
203 TRIQS_RUNTIME_ERROR << "gw_sigma: inverse temperatures are not the same.\n";
204 if (Wwm.statistic() != Boson || gwm.statistic() != Fermion)
205 TRIQS_RUNTIME_ERROR << "gw_sigma: statistics are incorrect.\n";
206 if (std::get<1>(W_dyn_wk.mesh()) != std::get<1>(g_wk.mesh()))
207 TRIQS_RUNTIME_ERROR << "gw_sigma: k-space meshes are not the same.\n";
208
209 // Dynamic GW self energy
210 auto g_wr = fourier_wk_to_wr(g_wk);
211 auto g_tr = fourier_wr_to_tr(g_wr);
212 auto W_dyn_wr = chi_wr_from_chi_wk(W_dyn_wk);
213 auto W_dyn_tr = chi_tr_from_chi_wr(W_dyn_wr);
214
215 auto sigma_dyn_tr = gw_dynamic_sigma(W_dyn_tr, g_tr);
216
217 // Static Fock part
218 auto sigma_fock_k = fock_sigma(W_const_k, g_wk);
219
220 // Add dynamic and static parts
221 auto _ = all_t{};
222 auto sigma_wr = fourier_tr_to_wr(sigma_dyn_tr);
223 auto sigma_wk = fourier_wr_to_wk(sigma_wr);
224 for (auto w : gwm) sigma_wk[w, _] += sigma_fock_k; // Single loop with no work per w, no need to parallellize over mpi
225
226 return sigma_wk;
227 }
228
229 g_wk_t gw_sigma(chi_wk_cvt W_wk, g_wk_cvt g_wk) {
230 auto [W_dyn_wk, W_const_k] = split_into_dynamic_wk_and_constant_k(W_wk);
231 return gw_sigma_impl(W_dyn_wk, W_const_k, g_wk);
232 }
233
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);
241 }
242
243 // ----------------------------------------------------
244 // g0w_sigma via spectral representation
245 // dynamic part ...
246
247 g_f_t g0w_dynamic_sigma(double mu, double beta, e_k_cvt e_k, chi_fk_cvt W_fk, chi_k_cvt v_k, double delta, mesh::brzone::value_t kpoint) {
248
249 if (std::get<1>(W_fk.mesh()) != e_k.mesh()) TRIQS_RUNTIME_ERROR << "g0w_sigma: k-space meshes are not the same.\n";
250 if (e_k.mesh() != v_k.mesh()) TRIQS_RUNTIME_ERROR << "g0w_sigma: k-space meshes are not the same.\n";
251
252 auto fmesh = std::get<0>(W_fk.mesh());
253 auto kmesh = e_k.mesh();
254 int nb = e_k.target().shape()[0];
255
256 std::complex<double> idelta(0.0, delta);
257
258 g_f_t sigma_f(fmesh, e_k.target_shape());
259 sigma_f() = 0.0;
260
261 for (auto q : kmesh) {
262 auto qpoint = mesh::brzone::value_t{q};
263 auto kpqpoint = qpoint + kpoint;
264 auto kpqvec = std::array<double, 3>{kpqpoint(0), kpqpoint(1), kpqpoint(2)};
265
266 array<std::complex<double>, 2> e_kq_mat(e_k(kpqvec) - mu);
267 auto eig_kq = linalg::eigh(e_kq_mat);
268 auto ekq = eig_kq.first;
269 auto Ukq = eig_kq.second;
270
271 for (int l : range(nb)) {
272
273 for (auto f : fmesh) {
274
275 for (auto fp : fmesh) {
276
277 auto num = bose(fp * beta) + fermi(ekq(l) * beta);
278 auto den = f + idelta + fp - ekq(l);
279
280 for (auto [a, b] : sigma_f.target_indices()) {
281 auto W_spec = -1.0 / M_PI * (W_fk[fp, q](a, a, b, b) - v_k[q](a, a, b, b)).imag();
282 sigma_f[f](a, b) = sigma_f[f](a, b)
283 + Ukq(a, l) * dagger(Ukq)(l, b) * (W_spec * num / den * fmesh.delta() / kmesh.size());
284 }
285 }
286 }
287 }
288 }
289
290 return sigma_f;
291 }
292
293 g_fk_t g0w_dynamic_sigma(double mu, double beta, e_k_cvt e_k, chi_fk_cvt W_fk, chi_k_cvt v_k, double delta, mesh::brzone kmesh) {
294
295 if (std::get<1>(W_fk.mesh()) != e_k.mesh()) TRIQS_RUNTIME_ERROR << "g0w_sigma: k-space meshes are not the same.\n";
296 if (e_k.mesh() != v_k.mesh()) TRIQS_RUNTIME_ERROR << "g0w_sigma: k-space meshes are not the same.\n";
297
298 auto fmesh = std::get<0>(W_fk.mesh());
299
300 g_fk_t sigma_fk({fmesh, kmesh}, e_k.target_shape());
301 sigma_fk() = 0.0;
302
303 auto arr = mpi_view(kmesh);
304#pragma omp parallel for
305 for (unsigned int kidx = 0; kidx < arr.size(); kidx++) {
306 auto &k = arr[kidx];
307 auto kpoint = mesh::brzone::value_t{k};
308 auto sigma_f = g0w_dynamic_sigma(mu, beta, e_k, W_fk, v_k, delta, kpoint);
309 for (auto f : fmesh) { sigma_fk[f, k] = sigma_f[f]; }
310 }
311
312 sigma_fk = mpi::all_reduce(sigma_fk);
313 return sigma_fk;
314 }
315
316 g_fk_t g0w_dynamic_sigma(double mu, double beta, e_k_cvt e_k, chi_fk_cvt W_fk, chi_k_cvt v_k, double delta) {
317 return g0w_dynamic_sigma(mu, beta, e_k, W_fk, v_k, delta, e_k.mesh());
318 }
319
320 // static part ...
321
322 array<std::complex<double>, 2> g0w_sigma(double mu, double beta, e_k_cvt e_k, chi_k_cvt v_k, mesh::brzone::value_t kpoint) {
323
324 if (e_k.mesh() != v_k.mesh()) TRIQS_RUNTIME_ERROR << "g0w_sigma: k-space meshes are not the same.\n";
325
326 auto kmesh = e_k.mesh();
327 int nb = e_k.target().shape()[0];
328
329 array<std::complex<double>, 2> sigma_k(nb ,nb);
330 sigma_k() = 0.0;
331
332 for (auto q : kmesh) {
333 auto qpoint = mesh::brzone::value_t{q};
334 auto kpqpoint = qpoint + kpoint;
335 auto kpqvec = std::array<double, 3>{kpqpoint(0), kpqpoint(1), kpqpoint(2)};
336
337 array<std::complex<double>, 2> e_kq_mat(e_k(kpqvec) - mu);
338 auto eig_kq = linalg::eigh(e_kq_mat);
339 auto ekq = eig_kq.first;
340 auto Ukq = eig_kq.second;
341
342 for (int l : range(nb)) {
343 for (int a : range(nb)) {
344 for (int b : range(nb)) {
345 sigma_k(a, b) = sigma_k(a, b) - Ukq(a, l) * dagger(Ukq)(l, b) * v_k[q](a, a, b, b) * fermi(ekq(l) * beta) / kmesh.size();
346 }
347 }
348 }
349 }
350
351 return sigma_k;
352 }
353
354 e_k_t g0w_sigma(double mu, double beta, e_k_cvt e_k, chi_k_cvt v_k, mesh::brzone kmesh) {
355
356 e_k_t sigma_k(kmesh, e_k.target_shape());
357 sigma_k() = 0.0;
358
359 auto arr = mpi_view(kmesh);
360#pragma omp parallel for
361 for (unsigned int kidx = 0; kidx < arr.size(); kidx++) {
362 auto &k = arr[kidx];
363 auto kpoint = mesh::brzone::value_t{k};
364 sigma_k[k] = g0w_sigma(mu, beta, e_k, v_k, kpoint);
365 }
366
367 sigma_k = mpi::all_reduce(sigma_k);
368 return sigma_k;
369 }
370
371 e_k_t g0w_sigma(double mu, double beta, e_k_cvt e_k, chi_k_cvt v_k) {
372 return g0w_sigma(mu, beta, e_k, v_k, e_k.mesh());
373 }
374
375 // dynamic and static parts ...
376
377 g_f_t g0w_sigma(double mu, double beta, e_k_cvt e_k, chi_fk_cvt W_fk, chi_k_cvt v_k, double delta, mesh::brzone::value_t kpoint) {
378 auto sigma_stat_k = g0w_sigma(mu, beta, e_k, v_k, kpoint);
379 auto sigma_dyn_fk = g0w_dynamic_sigma(mu, beta, e_k, W_fk, v_k, delta, kpoint);
380
381 auto fmesh = std::get<0>(W_fk.mesh());
382 g_f_t sigma_fk(fmesh, e_k.target_shape());
383 sigma_fk() = 0.0;
384 for (auto f : fmesh) { sigma_fk[f] = sigma_stat_k + sigma_dyn_fk[f]; }
385
386 return sigma_fk;
387 }
388
389 g_fk_t g0w_sigma(double mu, double beta, e_k_cvt e_k, chi_fk_cvt W_fk, chi_k_cvt v_k, double delta, mesh::brzone kmesh) {
390 auto sigma_stat_k = g0w_sigma(mu, beta, e_k, v_k, kmesh);
391 auto sigma_dyn_fk = g0w_dynamic_sigma(mu, beta, e_k, W_fk, v_k, delta, kmesh);
392 auto sigma_fk = add_dynamic_and_static(sigma_dyn_fk, sigma_stat_k);
393 return sigma_fk;
394 }
395
396 g_fk_t g0w_sigma(double mu, double beta, e_k_cvt e_k, chi_fk_cvt W_fk, chi_k_cvt v_k, double delta) {
397 return g0w_sigma(mu, beta, e_k, W_fk, v_k, delta, e_k.mesh());
398 }
399} // namespace triqs_tprf