TRIQS/triqs_tprf 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
chi_imfreq.cpp
1/*******************************************************************************
2 *
3 * TRIQS: a Toolbox for Research in Interacting Quantum Systems
4 *
5 * Copyright (C) 2017, H. U.R. Strand
6 * Copyright (C) 2020, S. Käser
7 * Authors: H. U.R. Strand, S. Käser
8 *
9 * TRIQS is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * TRIQS. If not, see <http://www.gnu.org/licenses/>.
21 *
22 ******************************************************************************/
23
24#include <triqs/utility/timer.hpp>
25#include <triqs/utility/timestamp.hpp>
26#include <omp.h>
27
28#include "../fourier/fourier.hpp"
29#include "../linalg.hpp"
30#include "../mpi.hpp"
31
32#include "chi_imfreq.hpp"
33#include "common.hpp"
34
35namespace triqs_tprf {
36
37namespace {
38using fourier::_fourier_plan;
39using fourier::_fourier_with_plan;
40placeholder<1> inu;
41} // namespace
42
43// ----------------------------------------------------
44// chi0 bubble in Matsubara frequency
45
46/*
47chi0r_t chi0r_from_gr_PH(int nw, int nnu, gr_iw_vt gr) {
48
49int nb = gr.target().shape()[0];
50auto &clmesh = std::get<1>(gr.mesh());
51double beta = std::get<0>(gr.mesh()).beta();
52
53chi0r_t chi0r{{{beta, Boson, nw}, {beta, Fermion, nnu}, clmesh},
54 {nb, nb, nb, nb}};
55
56chi0r(iw, inu, r)(a, b, c, d)
57 << -beta * gr(inu, r)(d, a) * gr(inu + iw, -r)(b, c);
58
59return chi0r;
60}
61*/
62
63chi_wnr_t chi0r_from_gr_PH(int nw, int nn, g_wr_cvt g_nr) {
64
65 mpi::communicator comm;
66
67 triqs::utility::timer t_alloc, t_calc, t_mpi_all_reduce;
68
69 auto _ = all_t{};
70
71 int nb = g_nr.target().shape()[0];
72 auto const &rmesh = std::get<1>(g_nr.mesh());
73
74 double beta = std::get<0>(g_nr.mesh()).beta();
75
76 auto wmesh = mesh::imfreq{beta, Boson, nw};
77 auto nmesh = mesh::imfreq{beta, Fermion, nn};
78
79 t_alloc.start();
80 chi0r_t chi0_wnr{{wmesh, nmesh, rmesh}, {nb, nb, nb, nb}};
81 chi0_wnr *= 0.;
82 t_alloc.stop();
83
84 auto chi_target = chi0_wnr.target();
85 auto g_target = g_nr.target();
86
87 auto arr = mpi_view(rmesh);
88
89 std::cout << "rank " << comm.rank() << " has arr.size() = "
90 << arr.size() << " of " << rmesh.size() << std::endl;
91
92 t_calc.start();
93#pragma omp parallel for
94 for (unsigned int idx = 0; idx < arr.size(); idx++) {
95 auto &r = arr[idx];
96
97 auto chi0_wn =
98 make_gf<prod<imfreq, imfreq>>({wmesh, nmesh}, chi_target);
99 auto g_pr_n = make_gf<imfreq>(nmesh, g_target);
100 auto g_mr_n = make_gf<imfreq>(nmesh, g_target);
101
102#pragma omp critical
103 {
104 g_pr_n = g_nr[_, r];
105 g_mr_n = g_nr(_, -r);
106 }
107
108 for (auto w : wmesh)
109 for (auto n : nmesh) chi0_wn[w, n](a, b, c, d) << -beta * g_pr_n(n)(d, a) * g_mr_n(n + w)(b, c);
110
111#pragma omp critical
112 chi0_wnr[_, _, r] = chi0_wn;
113
114 // chi0r(iw, inu, r)(a, b, c, d) << -beta * gr(inu, r)(d, a) * gr(inu + iw,
115 // -r)(b, c);
116 }
117 t_calc.stop();
118
119 t_mpi_all_reduce.start();
120
121 // This (surprisingly gives incorrect results, for sufficiently large arguments...
122 //chi0_wnr = mpi::all_reduce(chi0_wnr);
123
124 /* // Does not give correct result either...
125 for (auto w : wmesh )
126 chi0_wnr[w, _, _] = mpi::all_reduce(chi0_wnr[w, _, _]);
127 */
128
129 for (auto w : wmesh)
130 for (auto n : nmesh) chi0_wnr[w, n, _] = mpi::all_reduce(chi0_wnr[w, n, _]);
131
132 t_mpi_all_reduce.stop();
133
134 std::cout << "--> chi0r_from_gr_PH: alloc " << double(t_alloc)
135 << " s, calc " << double(t_calc) << " s, mpi::all_reduce "
136 << double(t_mpi_all_reduce) << " s." << std::endl;
137
138 return chi0_wnr;
139}
140
141chi_nr_t chi0_nr_from_gr_PH_at_specific_w(int nw_index, int nn, g_wr_cvt g_nr) {
142
143 auto _ = all_t{};
144
145 int nb = g_nr.target().shape()[0];
146 auto &rmesh = std::get<1>(g_nr.mesh());
147
148 double beta = std::get<0>(g_nr.mesh()).beta();
149 auto w = matsubara_freq{nw_index, beta, Boson};
150
151 auto nmesh = mesh::imfreq{beta, Fermion, nn};
152 chi_nr_t chi0_nr{{nmesh, rmesh}, {nb, nb, nb, nb}};
153 chi0_nr *= 0.;
154
155 auto chi_target = chi0_nr.target();
156 auto g_target = g_nr.target();
157
158 auto arr = mpi_view(rmesh);
159#pragma omp parallel for
160 for (unsigned int idx = 0; idx < arr.size(); idx++) {
161 auto &r = arr[idx];
162
163 auto chi0_n = make_gf<imfreq>(nmesh, chi_target);
164 auto g_pr_n = make_gf<imfreq>(nmesh, g_target);
165 auto g_mr_n = make_gf<imfreq>(nmesh, g_target);
166
167#pragma omp critical
168 {
169 g_pr_n = g_nr[_, r];
170 g_mr_n = g_nr(_, -r);
171 }
172
173 for (auto n : nmesh) chi0_n[n](a, b, c, d) << -beta * g_pr_n(n)(d, a) * g_mr_n(n + w)(b, c);
174
175#pragma omp critical
176 chi0_nr[_, r] = chi0_n;
177 }
178
179 for (auto n : nmesh) chi0_nr[n, _] = mpi::all_reduce(chi0_nr[n, _]);
180
181 return chi0_nr;
182}
183
184
185 // ---
186
187
188chi_wnr_t chi0r_from_gr_PH_nompi(int nw, int nn, g_wr_cvt g_nr) {
189
190 triqs::utility::timer t_alloc, t_calc, t_mpi_all_reduce;
191
192 auto _ = all_t{};
193
194 int nb = g_nr.target().shape()[0];
195 auto const &rmesh = std::get<1>(g_nr.mesh());
196
197 double beta = std::get<0>(g_nr.mesh()).beta();
198
199 auto wmesh = mesh::imfreq{beta, Boson, nw};
200 auto nmesh = mesh::imfreq{beta, Fermion, nn};
201
202 t_alloc.start();
203 chi0r_t chi0_wnr{{wmesh, nmesh, rmesh}, {nb, nb, nb, nb}};
204 chi0_wnr *= 0.;
205 t_alloc.stop();
206
207 auto chi_target = chi0_wnr.target();
208 auto g_target = g_nr.target();
209
210 t_calc.start();
211
212#pragma omp parallel for
213 for (unsigned int idx = 0; idx < rmesh.size(); idx++) {
214 auto r = *std::next(rmesh.begin(), idx);
215
216 auto chi0_wn =
217 make_gf<prod<imfreq, imfreq>>({wmesh, nmesh}, chi_target);
218 auto g_pr_n = make_gf<imfreq>(nmesh, g_target);
219 auto g_mr_n = make_gf<imfreq>(nmesh, g_target);
220
221#pragma omp critical
222 {
223 g_pr_n = g_nr[_, r];
224 g_mr_n = g_nr(_, -r);
225 }
226
227 for (auto w : wmesh)
228 for (auto n : nmesh) chi0_wn[w, n](a, b, c, d) << -beta * g_pr_n(n)(d, a) * g_mr_n(n + w)(b, c);
229
230#pragma omp critical
231 chi0_wnr[_, _, r] = chi0_wn;
232
233 // chi0r(iw, inu, r)(a, b, c, d) << -beta * gr(inu, r)(d, a) * gr(inu + iw,
234 // -r)(b, c);
235 }
236 t_calc.stop();
237
238 t_mpi_all_reduce.start();
239 //chi0_wnr = mpi::all_reduce(chi0_wnr);
240 t_mpi_all_reduce.stop();
241
242 std::cout << "--> chi0r_from_gr_PH: alloc " << double(t_alloc)
243 << " s, calc " << double(t_calc) << " s, mpi::all_reduce "
244 << double(t_mpi_all_reduce) << " s." << std::endl;
245
246 return chi0_wnr;
247}
248
249// ----------------------------------------------------
250
251// Helper function compiting chi0 for fixed bosonic frequency w and momentum q.
252
253C2PY_IGNORE
254gf<imfreq, tensor_valued<4>> chi0_n_from_g_wk_PH(mesh::imfreq::mesh_point_t w, mesh::brzone::mesh_point_t q, mesh::imfreq fmesh, g_wk_cvt g_wk) {
255
256 int nb = g_wk.target().shape()[0];
257 auto const &kmesh = std::get<1>(g_wk.mesh());
258
259 double beta = fmesh.beta();
260
261 gf<imfreq, tensor_valued<4>> chi0_n{fmesh, {nb, nb, nb, nb}};
262
263 // 100x times slower
264 // chi0_n(inu)(a, b, c, d) << -beta/kmesh.size() * sum(g_wk(inu, k)(d, a) *
265 // g_wk(inu + w, k - q)(b, c), k=kmesh);
266
267 for (auto n : fmesh) {
268 for (auto k : kmesh) {
269 auto g_da = g_wk[n.value(), k.index()];
270 auto g_bc = g_wk(n + w, k - q);
271 for (auto a : range(nb))
272 for (auto b : range(nb))
273 for (auto c : range(nb))
274 for (auto d : range(nb))
275 chi0_n[n](a, b, c, d) -= g_da(d, a) * g_bc(b, c);
276 }
277 }
278
279 chi0_n *= beta / kmesh.size();
280
281 return chi0_n;
282}
283
284// ----------------------------------------------------
285
286// Helper function compiting chi0 for fixed bosonic frequency w and momentum q.
287// using the self energy and the dispersion (instead of the greens function)
288
289C2PY_IGNORE
290gf<imfreq, tensor_valued<4>> chi0_n_from_e_k_sigma_w_PH(mesh::imfreq::mesh_point_t w, mesh::brzone::mesh_point_t q, mesh::imfreq fmesh, double mu,
291 e_k_cvt e_k, g_w_cvt sigma_w) {
292
293 int nb = e_k.target().shape()[0];
294 auto kmesh = e_k.mesh();
295
296 auto fmesh_large = sigma_w.mesh();
297
298 assert(fmesh.size() < fmesh_large.size());
299
300 double beta = fmesh.beta();
301 auto I = nda::eye<ek_vt::scalar_t>(e_k.target_shape()[0]);
302
303 gf<imfreq, tensor_valued<4>> chi0_n{fmesh, {nb, nb, nb, nb}};
304
305 for (auto k : kmesh) {
306 for (auto n : fmesh) {
307
308 auto g_da = nda::linalg::inv((n + mu) * I - e_k[k] - sigma_w[matsubara_freq(n)]);
309 auto g_bc = nda::linalg::inv((n + mu) * I - e_k[k - q] - sigma_w[n + w]);
310
311 for (auto a : range(nb))
312 for (auto b : range(nb))
313 for (auto c : range(nb))
314 for (auto d : range(nb))
315 chi0_n[n](a, b, c, d) -= g_da(d, a) * g_bc(b, c);
316 }
317 }
318
319 chi0_n *= beta / kmesh.size();
320
321 return chi0_n;
322}
323
324// ----------------------------------------------------
325
326chi_wnk_t chi0q_from_g_wk_PH(int nw, int nn, g_wk_cvt g_wk) {
327
328 auto const &kmesh = std::get<1>(g_wk.mesh());
329
330 int nb = g_wk.target().shape()[0];
331 double beta = std::get<0>(g_wk.mesh()).beta();
332
333 mesh::imfreq bmesh{beta, Boson, nw};
334 mesh::imfreq fmesh{beta, Fermion, nn};
335
336 chi0q_t chi0_wnk({bmesh, fmesh, kmesh}, {nb, nb, nb, nb});
337
338 auto _ = all_t{};
339 for (auto [w, q] : prod{bmesh, kmesh}) { chi0_wnk[w, _, q] = chi0_n_from_g_wk_PH(w, q, fmesh, g_wk); }
340
341 return chi0_wnk;
342}
343
344// ----------------------------------------------------
345// momentum <-> realspace transforms
346
347/*
348chi0r_t chi0r_from_chi0q(chi0q_vt chi0_wnk) {
349
350auto [bmesh, fmesh, kmesh] = chi0_wnk.mesh();
351auto rmesh = make_adjoint_mesh(kmesh);
352
353auto chi0_wnr =
354 make_gf<chi0r_t::mesh_t>({bmesh, fmesh, rmesh}, chi0_wnk.target());
355
356auto _ = all_t{};
357for (auto [w, n] : mpi_view(prod{bmesh, fmesh}))
358 chi0_wnr[w, n, _] = fourier(chi0_wnk[w, n, _]);
359chi0_wnr = mpi::all_reduce(chi0_wnr);
360
361return chi0_wnr;
362}
363*/
364
365chi_wnr_t chi0r_from_chi0q(chi_wnk_cvt chi_wnk) {
366
367 auto _ = all_t{};
368 auto target = chi_wnk.target();
369
370 //auto &[bmesh, fmesh, kmesh] = chi0_wnk.mesh(); // clang+OpenMP can not handle this...
371 auto &bmesh = std::get<0>(chi_wnk.mesh());
372 auto &fmesh = std::get<1>(chi_wnk.mesh());
373 auto &kmesh = std::get<2>(chi_wnk.mesh());
374 auto rmesh = make_adjoint_mesh(kmesh);
375
376 chi_wnr_t chi_wnr({bmesh, fmesh, rmesh}, chi_wnk.target_shape());
377
378 auto w0 = *bmesh.begin();
379 auto n0 = *fmesh.begin();
380 auto p = _fourier_plan<0>(gf_const_view(chi_wnk[w0, n0, _]),
381 gf_view(chi_wnr[w0, n0, _]));
382
383 auto arr = mpi_view(prod{bmesh, fmesh});
384#pragma omp parallel for shared(kmesh, rmesh)
385 for (unsigned int idx = 0; idx < arr.size(); idx++) {
386 auto &[w, n] = arr[idx];
387
388 auto chi_r = make_gf<cyclat>(rmesh, target);
389 auto chi_k = make_gf<brzone>(kmesh, target);
390
391#pragma omp critical
392 chi_k = chi_wnk[w, n, _];
393
394 _fourier_with_plan<0>(gf_const_view(chi_k), gf_view(chi_r), p);
395
396#pragma omp critical
397 chi_wnr[w, n, _] = chi_r;
398 }
399
400 //chi_wnr = mpi::all_reduce(chi_wnr); // Incorrect results for large args!!
401
402 // Workaround.. :P
403 for (auto w : bmesh)
404 for (auto n : fmesh) chi_wnr[w, n, _] = mpi::all_reduce(chi_wnr[w, n, _]);
405
406 return chi_wnr;
407}
408
409// --
410/*
411chi0q_t chi0q_from_chi0r(chi0r_vt chi0_wnr) {
412
413auto [bmesh, fmesh, rmesh] = chi0_wnr.mesh();
414auto kmesh = make_adjoint_mesh(rmesh);
415
416auto chi0_wnk =
417 make_gf<chi0q_t::mesh_t>({bmesh, fmesh, kmesh}, chi0_wnr.target());
418
419auto _ = all_t{};
420for (auto [w, n] : mpi_view(prod{bmesh, fmesh}))
421 chi0_wnk[w, n, _] = triqs::gfs::fourier(chi0_wnr[w, n, _]);
422chi0_wnk = mpi::all_reduce(chi0_wnk);
423
424return chi0_wnk;
425}
426*/
427
428chi_wnk_t chi0q_from_chi0r(chi_wnr_cvt chi_wnr) {
429
430 triqs::utility::timer t_alloc, t_calc, t_mpi_all_reduce;
431
432 auto _ = all_t{};
433 auto target = chi_wnr.target();
434
435 //auto &[bmesh, fmesh, rmesh] = chi_wnr.mesh();
436 auto &bmesh = std::get<0>(chi_wnr.mesh());
437 auto &fmesh = std::get<1>(chi_wnr.mesh());
438 auto &rmesh = std::get<2>(chi_wnr.mesh());
439 auto kmesh = make_adjoint_mesh(rmesh);
440
441 t_alloc.start();
442 chi_wnk_t chi_wnk({bmesh, fmesh, kmesh}, chi_wnr.target_shape());
443
444 auto w0 = *bmesh.begin();
445 auto n0 = *fmesh.begin();
446 auto p = _fourier_plan<0>(gf_const_view(chi_wnr[w0, n0, _]),
447 gf_view(chi_wnk[w0, n0, _]));
448
449 t_alloc.stop();
450 t_calc.start();
451
452 auto arr = mpi_view(prod{bmesh, fmesh});
453#pragma omp parallel for
454 for (unsigned int idx = 0; idx < arr.size(); idx++) {
455 auto &[w, n] = arr[idx];
456
457 auto chi_r = make_gf<cyclat>(rmesh, target);
458 auto chi_k = make_gf<brzone>(kmesh, target);
459
460 #pragma omp critical
461 chi_r = chi_wnr[w, n, _];
462
463 _fourier_with_plan<0>(gf_const_view(chi_r), gf_view(chi_k), p);
464
465 #pragma omp critical
466 chi_wnk[w, n, _] = chi_k;
467 }
468
469 t_calc.stop();
470 t_mpi_all_reduce.start();
471
472 //chi_wnk = mpi::all_reduce(chi_wnk); // Incorrect results for large args!!
473
474 // Workaround.. :P
475 for (auto w : bmesh)
476 for (auto n : fmesh) chi_wnk[w, n, _] = mpi::all_reduce(chi_wnk[w, n, _]);
477
478 t_mpi_all_reduce.stop();
479
480 std::cout << "--> chi0q_from_chi0r: alloc " << double(t_alloc)
481 << " s, calc " << double(t_calc) << " s, mpi::all_reduce "
482 << double(t_mpi_all_reduce) << " s." << std::endl;
483
484 return chi_wnk;
485}
486
487// ----------------------------------------------------
488
489chi_wk_t chi0q_sum_nu(chi_wnk_cvt chi_wnk) {
490
491 //auto &[wmesh, nmesh, kmesh] = chi_wnk.mesh();
492 auto &wmesh = std::get<0>(chi_wnk.mesh());
493 auto &nmesh = std::get<1>(chi_wnk.mesh());
494 auto &kmesh = std::get<2>(chi_wnk.mesh());
495
496 chi_wk_t chi_wk({wmesh, kmesh}, chi_wnk.target_shape());
497 chi_wk *= 0.;
498
499 double beta = wmesh.beta();
500
501 auto arr = mpi_view(chi_wk.mesh());
502#pragma omp parallel for
503 for (unsigned int idx = 0; idx < arr.size(); idx++) {
504 auto &[w, k] = arr[idx];
505
506 for (auto n : nmesh) chi_wk[w, k] += chi_wnk[w, n, k];
507 chi_wk[w, k] /= beta * beta;
508 }
509
510 //chi_wk(iw, k) << sum(chi_wnk(iw, inu, k), inu = mesh) / (beta * beta);
511
512 chi_wk = mpi::all_reduce(chi_wk);
513 return chi_wk;
514}
515
516// ----------------------------------------------------
517
518chi_wk_t chi0q_sum_nu_tail_corr_PH(chi_wnk_cvt chi_wnk) {
519
520 auto _ = all_t{};
521
522 //auto &[wmesh, nmesh, qmesh] = chi_wnk.mesh();
523 auto &wmesh = std::get<0>(chi_wnk.mesh());
524 auto &nmesh = std::get<1>(chi_wnk.mesh());
525 auto &qmesh = std::get<2>(chi_wnk.mesh());
526
527 chi_wk_t chi_wk({wmesh, qmesh}, chi_wnk.target_shape());
528
529 int nb = chi_wnk.target_shape()[0];
530 double beta = wmesh.beta();
531
532 auto chi_target = chi_wnk.target();
533
534 // for (auto w : wmesh) {
535 // for (auto q : qmesh) {
536
537 auto arr = mpi_view(chi_wk.mesh()); // FIXME Use library implementation
538#pragma omp parallel for
539 for (unsigned int idx = 0; idx < arr.size(); idx++) {
540 auto &[w, q] = arr[idx];
541
542 auto chi = make_gf<imfreq>(nmesh, chi_target);
543 array<std::complex<double>, 4> dens(nb, nb, nb, nb);
544
545#pragma omp critical
546 chi = chi_wnk[w, _, q];
547
548 for (auto a : range(nb)) {
549 for (auto b : range(nb)) {
550 for (auto c : range(nb)) {
551 for (auto d : range(nb)) {
552 auto chi_abcd = slice_target_to_scalar(chi, a, b, c, d);
553 // chi0q_w[w, q](a, b, c, d) = density(chi_abcd) / beta;
554 dens(a, b, c, d) = density(chi_abcd) / beta;
555 }
556 }
557 }
558 }
559
560#pragma omp critical
561 chi_wk[w, q] = dens;
562 }
563
564 chi_wk = mpi::all_reduce(chi_wk);
565 return chi_wk;
566}
567
568// ----------------------------------------------------
569
570chi_w_t chi0q_sum_nu_q(chi_wnk_cvt chi_wnk) {
571
572 auto const &[mesh_b, mesh_f, mesh_k] = chi_wnk.mesh();
573 chi_w_t chi_w(mesh_b, chi_wnk.target_shape());
574
575 for (auto [w, n, k] : chi_wnk.mesh()) chi_w[w] += chi_wnk[w, n, k];
576
577 double nk = mesh_k.size();
578 double beta = mesh_f.beta();
579 chi_w = chi_w / nk / (beta * beta);
580
581 return chi_w;
582}
583
584// ----------------------------------------------------
585// chi
586
587/*
588chiq_t chiq_from_chi0q_and_gamma_PH(chi0q_vt chi0q, g2_iw_vt gamma_ph) {
589
590 auto _ = all_t{};
591
592 auto const &[mb, mf, mbz] = chi0q.mesh();
593
594 auto chiq = make_gf<chiq_t::mesh_t>({mbz, mb, mf, mf}, chi0q.target());
595
596 for (auto k : mbz) {
597
598 // -- Construct matrix version of chi0q_k
599
600 // -- If we could make this a 1,1,1 g2_iw_t function and do the PH inverse
601 // -- only in the target space we would save one global inverse!
602
603 auto chi0q_k =
604 make_gf<g2_iw_t::mesh_t>({mb, mf, mf}, chi0q.target());
605
606 for (auto w : mb) {
607 for (auto n : mf) {
608 chi0q_k[w, n, n] = chi0q[w, n, k];
609 }
610 }
611
612 g2_iw_t chiq_inv_k = inverse<Channel_t::PH>(chi0q_k) - gamma_ph;
613
614 chiq[k, _, _, _] = inverse<Channel_t::PH>(chiq_inv_k);
615 }
616
617 return chiq;
618}
619*/
620
621// ----------------------------------------------------
622
623chi_kwnn_t chiq_from_chi0q_and_gamma_PH(chi_wnk_cvt chi0_wnk, chi_wnn_cvt gamma_ph_wnn) {
624
625 auto _ = all_t{};
626
627 auto &mb = std::get<0>(chi0_wnk.mesh());
628 auto &mf = std::get<1>(chi0_wnk.mesh());
629 auto &mbz = std::get<2>(chi0_wnk.mesh());
630
631 chi_kwnn_t chi_kwnn({mbz, mb, mf, mf}, chi0_wnk.target_shape());
632
633#pragma omp parallel for
634 for (unsigned int idx = 0; idx < mbz.size(); idx++) {
635 auto k = *std::next(mbz.begin(), idx);
636
637 auto chi0 = make_gf<g2_nn_t::mesh_t>({mf, mf}, chi0_wnk.target());
638 auto I = identity<Channel_t::PH>(chi0);
639
640 for (auto w : mb) {
641
642 chi0 *= 0.;
643 for (auto n : mf) { chi0[n, n] = chi0_wnk[w, n, k]; }
644
645 // this step could be optimized, using the diagonality of chi0 and I
646 auto denom = chi_nn_t{I - product<Channel_t::PH>(chi0, gamma_ph_wnn[w, _, _])};
647
648 // also the last product here
649 chi_nn_t chi = product<Channel_t::PH>(inverse<Channel_t::PH>(denom), chi0);
650
651#pragma omp critical
652 chi_kwnn[k, w, _, _] = chi;
653 }
654 }
655
656 return chi_kwnn;
657}
658
659// ----------------------------------------------------
660
661chi_kw_t chiq_sum_nu_from_chi0q_and_gamma_and_L_wn_PH(chi_wnk_cvt chi0_wnk, chi_wnn_cvt gamma_ph_wnn, chi_nn_cvt L_wn) {
662
663 auto _ = all_t{};
664
665 mpi::communicator comm;
666
667 auto target_shape = chi0_wnk.target_shape();
668 // auto &[bmesh, fmesh, kmesh] = chi0_wnk.mesh();
669 auto &bmesh = std::get<0>(chi0_wnk.mesh());
670 auto &fmesh = std::get<1>(chi0_wnk.mesh());
671 auto &kmesh = std::get<2>(chi0_wnk.mesh());
672
673 chi_kw_t chi_kw({kmesh, bmesh}, target_shape);
674
675 auto arr = mpi_view(chi_kw.mesh()); // FIXME Use library implementation
676 std::cout << "DBSE rank " << comm.rank() << " of " << comm.size() << " has "
677 << arr.size() << " jobs." << std::endl;
678
679 triqs::utility::timer t;
680 t.start();
681
682#pragma omp parallel for
683 for (unsigned int idx = 0; idx < arr.size(); idx++) {
684 auto &[k, w] = arr[idx];
685
686 //triqs::utility::timer t_copy_1, t_chi0_nn, t_bse, t_chi_tr, t_copy_2;
687
688 // ----------------------------------------------------
689 //t_copy_1.start();
690
691 chi_w_t chi0_n(fmesh, target_shape);
692
693#pragma omp critical
694 chi0_n = chi0_wnk[w, _, k];
695
696 //t_copy_1.stop();
697 //std::cout << "BSE: copy_1 " << double(t_copy_1) << " s" << std::endl;
698 // ----------------------------------------------------
699 //t_chi0_nn.start();
700
701 chi_nn_t chi0_nn({fmesh, fmesh}, target_shape);
702 chi0_nn *= 0.;
703
704 for (auto n : fmesh) chi0_nn[n, n] = chi0_n[n];
705
706 //t_chi0_nn.stop();
707 //std::cout << "BSE: chi0_nn " << double(t_chi0_nn) << " s" << std::endl;
708 // ----------------------------------------------------
709 //t_bse.start();
710
711 auto I = identity<Channel_t::PH>(chi0_nn);
712
713 chi_nn_t gamma_nn({fmesh, fmesh}, target_shape);
714
715#pragma omp critical
716 gamma_nn = gamma_ph_wnn[w, _, _];
717
718 // this step could be optimized, using the diagonality of chi0 and I
719 auto denom = chi_nn_t{I - product<Channel_t::PH>(chi0_nn, gamma_nn)};
720
721 // also the last product here
722 auto chi = chi_nn_t{product<Channel_t::PH>(inverse<Channel_t::PH>(denom), chi0_nn)};
723
724 //t_bse.stop();
725 //std::cout << "BSE: bse inv " << double(t_bse) << " s" << std::endl;
726 // ----------------------------------------------------
727 //t_chi_tr.start();
728
729 // trace out fermionic frequencies
730 array<std::complex<double>, 4> tr_chi(target_shape);
731 tr_chi = scalar_product_PH(L_wn[w, _], chi, L_wn[w, _]);
732
733 /*
734 tr_chi() = 0;
735
736 for (auto n1 : fmesh) {
737 auto Ll = L_wn[w, n1];
738 for (auto n2 : fmesh) {
739 auto Lr = L_wn[w, n2];
740 auto C = chi[n1, n2];
741 for (auto const &[a, b, c, d] : chi.target_indices()) {
742 for (auto const &[e, f, g, h] : chi.target_indices()) {
743 tr_chi(a,b,c,d) += Ll(e,f,b,a) * C(e,f,g,h) * Lr(h,g,c,d);
744 }
745 }
746 }
747 }
748
749 array<std::complex<double>, 4> tr_chi_ref(target_shape);
750 tr_chi_ref = scalar_product_PH(L_wn[w, _], chi, L_wn[w, _]);
751
752 for (auto const &[a, b, c, d] : chi.target_indices()) {
753 auto diff = std::abs( tr_chi(a,b,c,d) - tr_chi_ref(a,b,c,d) );
754 std::cout << a << ", " << b << ", " << c << ", " << d << " - " << diff << "\n";
755 if(diff > 1e-6) {
756 exit(0);
757 }
758 }
759 */
760
761 //t_chi_tr.stop();
762 //std::cout << "BSE: chi tr " << double(t_chi_tr) << " s" << std::endl;
763 // ----------------------------------------------------
764 //t_copy_2.start();
765
766#pragma omp critical
767 chi_kw[k, w] = tr_chi;
768
769 //t_copy_2.stop();
770 //std::cout << "BSE: copy_2 " << double(t_copy_2) << " s" << std::endl;
771 // ----------------------------------------------------
772
773 if(comm.rank() == 0 && omp_get_thread_num() == 0) {
774
775 int Nomp = omp_get_num_threads();
776 int N = int(floor(arr.size() / double(Nomp)));
777
778 //double t_left = double(t) * ( N / (idx + 1) - 1. );
779 int done_percent = (N == 0) ? 100 : int(floor(100 * double(idx + 1) / N));
780
781 std::cout << "DBSE " << triqs::utility::timestamp() << " "
782 << std::setfill(' ') << std::setw(3) << done_percent << "% "
783 << "ETA " << triqs::utility::estimate_time_left(N, idx, t)
784 << " job no "
785 << std::setfill(' ') << std::setw(5) << int(idx)
786 << " of approx " << N << " jobs/thread/rank." << std::endl;
787 }
788
789 }
790
791 chi_kw = mpi::all_reduce(chi_kw);
792
793 t.stop();
794 if(comm.rank() == 0 )
795 std::cout << "DBSE TIME: " << double(t) << " s" << std::endl;
796
797 return chi_kw;
798}
799
800// ----------------------------------------------------
801
802chi_kw_t chiq_sum_nu_from_chi0q_and_gamma_PH(chi_wnk_cvt chi0_wnk, chi_wnn_cvt gamma_ph_wnn) {
803
804 auto _ = all_t{};
805
806 mpi::communicator c;
807
808 auto target_shape = chi0_wnk.target_shape();
809 // auto &[bmesh, fmesh, kmesh] = chi0_wnk.mesh();
810 auto &bmesh = std::get<0>(chi0_wnk.mesh());
811 auto &fmesh = std::get<1>(chi0_wnk.mesh());
812 auto &kmesh = std::get<2>(chi0_wnk.mesh());
813
814 double beta = fmesh.beta();
815
816 chi_kw_t chi_kw({kmesh, bmesh}, target_shape);
817
818 auto arr = mpi_view(chi_kw.mesh()); // FIXME Use library implementation
819 std::cout << "BSE rank " << c.rank() << " of " << c.size() << " has "
820 << arr.size() << " jobs." << std::endl;
821
822 triqs::utility::timer t;
823 t.start();
824
825#pragma omp parallel for
826 for (unsigned int idx = 0; idx < arr.size(); idx++) {
827 auto &[k, w] = arr[idx];
828
829 //triqs::utility::timer t_copy_1, t_chi0_nn, t_bse, t_chi_tr, t_copy_2;
830
831 // ----------------------------------------------------
832 //t_copy_1.start();
833
834 chi_w_t chi0_n(fmesh, target_shape);
835
836#pragma omp critical
837 chi0_n = chi0_wnk[w, _, k];
838
839 //t_copy_1.stop();
840 //std::cout << "BSE: copy_1 " << double(t_copy_1) << " s" << std::endl;
841 // ----------------------------------------------------
842 //t_chi0_nn.start();
843
844 chi_nn_t chi0_nn({fmesh, fmesh}, target_shape);
845 chi0_nn *= 0.;
846
847 for (auto n : fmesh) chi0_nn[n, n] = chi0_n[n];
848
849 //t_chi0_nn.stop();
850 //std::cout << "BSE: chi0_nn " << double(t_chi0_nn) << " s" << std::endl;
851 // ----------------------------------------------------
852 //t_bse.start();
853
854 auto I = identity<Channel_t::PH>(chi0_nn);
855
856 chi_nn_t gamma_nn({fmesh, fmesh}, target_shape);
857
858#pragma omp critical
859 gamma_nn = gamma_ph_wnn[w, _, _];
860
861 // this step could be optimized, using the diagonality of chi0 and I
862 auto denom = chi_nn_t{I - product<Channel_t::PH>(chi0_nn, gamma_nn)};
863
864 // also the last product here
865 auto chi = chi_nn_t{product<Channel_t::PH>(inverse<Channel_t::PH>(denom), chi0_nn)};
866
867 //t_bse.stop();
868 //std::cout << "BSE: bse inv " << double(t_bse) << " s" << std::endl;
869 // ----------------------------------------------------
870 //t_chi_tr.start();
871
872 // trace out fermionic frequencies
873 array<std::complex<double>, 4> tr_chi(target_shape);
874
875 tr_chi *= 0.0;
876 for (auto n1 : fmesh)
877 for (auto n2 : fmesh) tr_chi += chi[n1, n2];
878
879 tr_chi /= beta * beta;
880
881 //t_chi_tr.stop();
882 //std::cout << "BSE: chi tr " << double(t_chi_tr) << " s" << std::endl;
883 // ----------------------------------------------------
884 //t_copy_2.start();
885
886#pragma omp critical
887 chi_kw[k, w] = tr_chi;
888
889 //t_copy_2.stop();
890 //std::cout << "BSE: copy_2 " << double(t_copy_2) << " s" << std::endl;
891 // ----------------------------------------------------
892
893 if(c.rank() == 0 && omp_get_thread_num() == 0) {
894
895 int Nomp = omp_get_num_threads();
896 int N = int(floor(arr.size() / double(Nomp)));
897
898 //double t_left = double(t) * ( N / (idx + 1) - 1. );
899 int done_percent = (N == 0) ? 100 : int(floor(100 * double(idx + 1) / N));
900
901 std::cout << "BSE " << triqs::utility::timestamp() << " "
902 << std::setfill(' ') << std::setw(3) << done_percent << "% "
903 << "ETA " << triqs::utility::estimate_time_left(N, idx, t)
904 << " job no "
905 << std::setfill(' ') << std::setw(5) << int(idx)
906 << " of approx " << N << " jobs/thread/rank." << std::endl;
907 }
908
909 }
910
911 chi_kw = mpi::all_reduce(chi_kw);
912
913 t.stop();
914 if(c.rank() == 0 )
915 std::cout << "BSE TIME: " << double(t) << " s" << std::endl;
916
917 return chi_kw;
918}
919
920// ----------------------------------------------------
921
922gf<prod<brzone, imfreq>, tensor_valued<4>>
923chiq_sum_nu_from_g_wk_and_gamma_PH(gk_iw_t g_wk, g2_iw_vt gamma_ph_wnn,
924 int tail_corr_nwf) {
925
926 auto _ = all_t{};
927
928 auto target = gamma_ph_wnn.target();
929 auto const &kmesh = std::get<1>(g_wk.mesh());
930 auto const &bmesh = std::get<0>(gamma_ph_wnn.mesh());
931 auto const &fmesh = std::get<1>(gamma_ph_wnn.mesh());
932
933 double beta = fmesh.beta();
934
935 auto chi_kw = make_gf<prod<brzone, imfreq>>(
936 {kmesh, bmesh}, target);
937
938 auto chi0_n = make_gf<imfreq>(fmesh, target);
939 auto chi0_nn = make_gf<g2_nn_t::mesh_t>({fmesh, fmesh}, target);
940 auto I = identity<Channel_t::PH>(chi0_nn);
941
942 int nb = gamma_ph_wnn.target_shape()[0];
943
944 mesh::imfreq fmesh_tail;
945 if (tail_corr_nwf > 0)
946 fmesh_tail = mesh::imfreq{beta, Fermion, tail_corr_nwf};
947 else
948 fmesh_tail = fmesh;
949
950 if (fmesh_tail.size() < fmesh.size())
951 TRIQS_RUNTIME_ERROR
952 << "BSE: tail size has to be larger than gamma fermi mesh.\n";
953
954 array<std::complex<double>, 4> tr_chi(gamma_ph_wnn.target_shape());
955 array<std::complex<double>, 4> tr_chi0(gamma_ph_wnn.target_shape());
956 array<std::complex<double>, 4> tr_chi0_tail_corr(gamma_ph_wnn.target_shape());
957
958 for (auto [k, w] : mpi::chunk(chi_kw.mesh())) {
959
960 triqs::utility::timer t_chi0_n, t_chi0_tr, t_bse_1, t_bse_2, t_bse_3;
961
962 // ----------------------------------------------------
963 // Build the bare bubble at k, w
964
965 t_chi0_n.start();
966 std::cout << "BSE: chi0_n ";
967
968 auto chi0_n_tail = chi0_n_from_g_wk_PH(w, k, fmesh_tail, g_wk);
969 for (auto n : fmesh) chi0_n[n] = chi0_n_tail(n);
970
971 std::cout << double(t_chi0_n) << " s\n";
972
973 // ----------------------------------------------------
974 // trace the bare bubble with and without tail corrections
975
976 t_chi0_tr.start();
977 std::cout << "BSE: Tr[chi0_n] ";
978
979 // tr_chi0_tail_corr(a, b, c, d) << density(slice_target_to_scalar(chi0_n,
980 // a, b, c, d)) / beta; // does not compile
981
982 for (auto a : range(nb)) {
983 for (auto b : range(nb)) {
984 for (auto c : range(nb)) {
985 for (auto d : range(nb)) {
986 tr_chi0_tail_corr(a, b, c, d) =
987 density(slice_target_to_scalar(chi0_n_tail, a, b, c, d)) / beta;
988 }
989 }
990 }
991 }
992
993 tr_chi0(a, b, c, d) << sum(chi0_n(inu)(a, b, c, d), inu = fmesh) /
994 (beta * beta);
995
996 std::cout << double(t_chi0_tr) << " s\n";
997
998 // ----------------------------------------------------
999 // Make two frequency object
1000
1001 t_bse_1.start();
1002 std::cout << "BSE: chi0_nn ";
1003
1004 for (auto n : fmesh) chi0_nn[n, n] = chi0_n[n];
1005
1006 std::cout << double(t_bse_1) << " s\n";
1007
1008 // ----------------------------------------------------
1009
1010 t_bse_2.start();
1011 std::cout << "BSE: I - chi0 * gamma ";
1012
1013 auto denom = g2_nn_t{I - product<Channel_t::PH>(chi0_nn, gamma_ph_wnn[w, _, _])};
1014
1015 std::cout << double(t_bse_2) << " s\n";
1016
1017 t_bse_3.start();
1018 std::cout << "BSE: chi = [I - chi0 * gamma]^{-1} chi0 ";
1019
1020 auto chi_nn = g2_nn_t{product<Channel_t::PH>(inverse<Channel_t::PH>(denom), chi0_nn)};
1021
1022 std::cout << double(t_bse_3) << " s\n";
1023
1024 // trace out fermionic frequencies
1025 std::cout << "BSE: Tr[chi] \n";
1026 tr_chi *= 0.0;
1027 for (auto [n1, n2] : chi_nn.mesh()) tr_chi += chi_nn[n1, n2];
1028 tr_chi /= beta * beta;
1029
1030 // 0th order high frequency correction using the bare bubble chi0
1031 tr_chi += tr_chi0_tail_corr - tr_chi0;
1032
1033 chi_kw[k, w] = tr_chi;
1034 }
1035
1036 chi_kw = mpi::all_reduce(chi_kw);
1037
1038 return chi_kw;
1039}
1040
1041gf<prod<brzone, imfreq>, tensor_valued<4>>
1042chiq_sum_nu_from_e_k_sigma_w_and_gamma_PH(double mu, ek_vt e_k, g_iw_vt sigma_w,
1043 g2_iw_vt gamma_ph_wnn,
1044 int tail_corr_nwf) {
1045
1046 auto _ = all_t{};
1047
1048 auto target = gamma_ph_wnn.target();
1049 // auto [fmesh_large, kmesh] = g_wk.mesh();
1050
1051 auto const &kmesh = e_k.mesh();
1052 auto const &[bmesh, fmesh, f2mesh] = gamma_ph_wnn.mesh();
1053
1054 double beta = fmesh.beta();
1055
1056 auto chi_kw = make_gf<prod<brzone, imfreq>>(
1057 {kmesh, bmesh}, target);
1058
1059 auto chi0_n = make_gf<imfreq>(fmesh, target);
1060 auto chi0_nn = make_gf<g2_nn_t::mesh_t>({fmesh, fmesh}, target);
1061 auto I = identity<Channel_t::PH>(chi0_nn);
1062
1063 int nb = gamma_ph_wnn.target_shape()[0];
1064
1065 mesh::imfreq fmesh_tail;
1066 if (tail_corr_nwf > 0)
1067 fmesh_tail = mesh::imfreq{beta, Fermion, tail_corr_nwf};
1068 else
1069 fmesh_tail = fmesh;
1070
1071 if (fmesh_tail.size() < fmesh.size())
1072 TRIQS_RUNTIME_ERROR
1073 << "BSE: tail size has to be larger than gamma fermi mesh.\n";
1074
1075 array<std::complex<double>, 4> tr_chi(gamma_ph_wnn.target_shape());
1076 array<std::complex<double>, 4> tr_chi0(gamma_ph_wnn.target_shape());
1077 array<std::complex<double>, 4> tr_chi0_tail_corr(gamma_ph_wnn.target_shape());
1078
1079 for (auto [k, w] : mpi_view(chi_kw.mesh())) {
1080
1081 triqs::utility::timer t_chi0_n, t_chi0_tr, t_bse_1, t_bse_2, t_bse_3;
1082
1083 // ----------------------------------------------------
1084 // Build the bare bubble at k, w
1085
1086 t_chi0_n.start();
1087 std::cout << "BSE: chi0_n ";
1088
1089 // auto chi0_n_tail = chi0_n_from_g_wk_PH(w, k, fmesh_tail, g_wk);
1090
1091 auto chi0_n_tail =
1092 chi0_n_from_e_k_sigma_w_PH(w, k, fmesh_tail, mu, e_k, sigma_w);
1093
1094 for (auto n : fmesh) chi0_n[n] = chi0_n_tail(n);
1095
1096 std::cout << double(t_chi0_n) << " s\n";
1097
1098 // ----------------------------------------------------
1099 // trace the bare bubble with and without tail corrections
1100
1101 t_chi0_tr.start();
1102 std::cout << "BSE: Tr[chi0_n] ";
1103
1104 // tr_chi0_tail_corr(a, b, c, d) << density(slice_target_to_scalar(chi0_n,
1105 // a, b, c, d)) / beta; // does not compile
1106
1107 for (auto a : range(nb)) {
1108 for (auto b : range(nb)) {
1109 for (auto c : range(nb)) {
1110 for (auto d : range(nb)) {
1111 tr_chi0_tail_corr(a, b, c, d) =
1112 density(slice_target_to_scalar(chi0_n_tail, a, b, c, d)) / beta;
1113 }
1114 }
1115 }
1116 }
1117
1118 tr_chi0(a, b, c, d) << sum(chi0_n(inu)(a, b, c, d), inu = fmesh) /
1119 (beta * beta);
1120
1121 std::cout << double(t_chi0_tr) << " s\n";
1122
1123 // ----------------------------------------------------
1124 // Make two frequency object
1125
1126 t_bse_1.start();
1127 std::cout << "BSE: chi0_nn ";
1128
1129 for (auto n : fmesh) chi0_nn[n, n] = chi0_n[n];
1130
1131 std::cout << double(t_bse_1) << " s\n";
1132
1133 // ----------------------------------------------------
1134
1135 t_bse_2.start();
1136 std::cout << "BSE: I - chi0 * gamma ";
1137
1138 auto denom = g2_nn_t{I - product<Channel_t::PH>(chi0_nn, gamma_ph_wnn[w, _, _])};
1139
1140 std::cout << double(t_bse_2) << " s\n";
1141
1142 t_bse_3.start();
1143 std::cout << "BSE: chi = [I - chi0 * gamma]^{-1} chi0 ";
1144
1145 g2_nn_t chi_nn =
1146 product<Channel_t::PH>(inverse<Channel_t::PH>(denom), chi0_nn);
1147
1148 std::cout << double(t_bse_3) << " s\n";
1149
1150 // trace out fermionic frequencies
1151 std::cout << "BSE: Tr[chi] \n";
1152 tr_chi *= 0.0;
1153 for (auto [n1, n2] : chi_nn.mesh()) tr_chi += chi_nn[n1, n2];
1154 tr_chi /= beta * beta;
1155
1156 // 0th order high frequency correction using the bare bubble chi0
1157 tr_chi += tr_chi0_tail_corr - tr_chi0;
1158
1159 chi_kw[k, w] = tr_chi;
1160 }
1161
1162 chi_kw = mpi::all_reduce(chi_kw);
1163
1164 return chi_kw;
1165}
1166
1167gf<prod<brzone, imfreq>, tensor_valued<4>>
1168chiq_sum_nu(chiq_t chiq) {
1169
1170 auto &mesh_k = std::get<0>(chiq.mesh());
1171 auto &mesh_b = std::get<1>(chiq.mesh());
1172 auto &mesh_f = std::get<2>(chiq.mesh());
1173 auto chiq_w = make_gf<prod<brzone, imfreq>>(
1174 {mesh_k, mesh_b}, chiq.target());
1175
1176 // Does not compile due to treatment of the tail (singularity)
1177 // chiq_w(k, iw) << sum(chiq(k, iw, inu, inup), inu=mesh, inup=mesh);
1178
1179 for (auto [k, w, n1, n2] : chiq.mesh()) chiq_w[k, w] += chiq[k, w, n1, n2];
1180
1181 double beta = mesh_f.beta();
1182 chiq_w = chiq_w / (beta * beta);
1183
1184 return chiq_w;
1185}
1186
1187gf<imfreq, tensor_valued<4>> chiq_sum_nu_q(chiq_t chiq) {
1188
1189 auto &mesh_k = std::get<0>(chiq.mesh());
1190 auto &mesh_b = std::get<1>(chiq.mesh());
1191 auto &mesh_f = std::get<2>(chiq.mesh());
1192 auto chi_w = make_gf<imfreq>(mesh_b, chiq.target());
1193
1194 for (auto [k, w, n1, n2] : chiq.mesh()) chi_w[w] += chiq[k, w, n1, n2];
1195
1196 double nk = mesh_k.size();
1197 double beta = mesh_f.beta();
1198 chi_w = chi_w / nk / (beta * beta);
1199
1200 return chi_w;
1201}
1202
1203chi_wk_t attatch_tri_vert(chi_nn_cvt L_wn, chi_kwnn_cvt chi_kwnn) {
1204
1205 auto _ = all_t{};
1206
1207 auto &mesh_k = std::get<0>(chi_kwnn.mesh());
1208 auto &mesh_b = std::get<1>(chi_kwnn.mesh());
1209
1210 auto chi_wk = make_gf<prod<imfreq, brzone>>({mesh_b, mesh_k}, chi_kwnn.target());
1211
1212 std::cout << "--> attatch_tri_vert: Hybrid parallell OpenMP+MPI\n";
1213
1214 auto arr = mpi_view(chi_wk.mesh());
1215#pragma omp parallel for
1216 for (int idx = 0; idx < arr.size(); idx++) {
1217 auto &[w, k] = arr[idx];
1218
1219 /*
1220 //for (auto [k, w, n1, n2] : chi_kwnn.mesh()) {
1221 for (auto [a, b, c, d] : chi_kwnn.target_indices())
1222 for (auto [e, f, g, h] : chi_kwnn.target_indices())
1223 chi_wk[w, k](a, b, g, h) +=
1224 L_wn[w, n1](a, b, c, d) * chi_kwnn[k, w, n1, n2](c, d, e, f) * L_wn[w, n2](e, f, g, h);
1225 */
1226
1227 chi_wk[w, k] = scalar_product_PH(L_wn[w, _], chi_kwnn[k, w, _, _], L_wn[w, _]);
1228 }
1229
1230 chi_wk = mpi::all_reduce(chi_wk);
1231
1232 return chi_wk;
1233}
1234
1235} // namespace triqs_tprf