TRIQS/triqs_ctint 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
post_process.hpp
1// Copyright (c) 2017--present, The Simons Foundation
2// This file is part of TRIQS/ctint and is licensed under the terms of GPLv3 or later.
3// SPDX-License-Identifier: GPL-3.0-or-later
4// See LICENSE in the root of this distribution for details.
5
6#pragma once
7#include "./qmc_config.hpp"
8#include "./params.hpp"
9
10namespace triqs_ctint {
11
24 chi4_iw_t G2_conn_from_M4(chi4_iw_t::const_view_type M4_iw, g_reg_iw_cv_t M_iw, g_reg_iw_cv_t G0_iw);
25
38 chi4_iw_t G2pp_conn_from_M4pp(chi4_iw_t::const_view_type M4pp_iw, g_reg_iw_cv_t M_iw, g_reg_iw_cv_t G0_iw);
39
52 chi4_iw_t G2ph_conn_from_M4ph(chi4_iw_t::const_view_type M4ph_iw, g_reg_iw_cv_t M_iw, g_reg_iw_cv_t G0_iw);
53
64 chi4_iw_t F_from_G2c(chi4_iw_t::const_view_type G2_conn_iw, g_reg_iw_cv_t G_iw);
65
76 chi4_iw_t Fpp_from_G2pp_conn(chi4_iw_t::const_view_type G2pp_conn_iw, g_reg_iw_cv_t G_iw);
77
88 chi4_iw_t Fph_from_G2ph_conn(chi4_iw_t::const_view_type G2ph_conn_iw, g_reg_iw_cv_t G_iw);
89
100 chi4_iw_t G2_from_G2c(chi4_iw_t::const_view_type G2_conn_iw, g_reg_iw_cv_t G_iw);
101
112 chi4_iw_t G2pp_from_G2pp_conn(chi4_iw_t::const_view_type G2pp_conn_iw, g_reg_iw_cv_t G_iw);
113
124 chi4_iw_t G2ph_from_G2ph_conn(chi4_iw_t::const_view_type G2ph_conn_iw, g_reg_iw_cv_t G_iw);
125
137 chi4_iw_t chi_tilde_ph_from_G2ph_conn(chi4_iw_t::const_view_type G2ph_conn_iw, g_reg_iw_cv_t G_iw);
138
140 template <Chan_t Chan>
141 chi3_iw_t chi3_from_M3(chi3_iw_cv_t M3_iw, g_reg_iw_cv_t M_iw, g_reg_iw_cv_t G0_iw, block_matrix_t const &dens_G, block_matrix_t const &M_hartree) {
142
143 double beta = M_iw[0].mesh().beta();
144 int n_blocks = M_iw.size();
145
146 // Connected part of M3
147 chi3_iw_t M3_iw_conn = M3_iw;
148
149 // Connected part of chi3
150 chi3_iw_t chi3_iw = M3_iw;
151 chi3_iw() = 0.;
152
153 // Temporary quantities
154 g_reg_iw_t GM = G0_iw * M_iw;
155 g_reg_iw_t MG = M_iw * G0_iw;
156 g_reg_iw_t GMG = G0_iw * M_iw * G0_iw;
157 g_reg_iw_t G_iw = G0_iw + G0_iw * M_iw * G0_iw;
158
159 for (int bl1 : range(n_blocks))
160 for (int bl2 : range(n_blocks)) {
161
162 // Capture block-sizes
163 int bl1_size = M3_iw(bl1, bl2).target_shape()[0];
164 int bl2_size = M3_iw(bl1, bl2).target_shape()[2];
165
166 if constexpr (Chan == Chan_t::PP) { // ===== Particle-particle channel
167
168 M3_iw_conn(bl1, bl2)(iW_, iw_)(i_, j_, k_, l_) << M3_iw(bl1, bl2)[iW_, iw_](i_, j_, k_, l_)
169 - GM[bl1](iw_)(j_, i_) * GM[bl2](iW_ - iw_)(l_, k_) + kronecker(bl1, bl2) * GM[bl1](iw_)(l_, i_) * GM[bl2](iW_ - iw_)(j_, k_);
170
171 for (int m : range(bl1_size))
172 for (int n : range(bl2_size))
173 chi3_iw(bl1, bl2)(iW_, iw_)(i_, j_, k_, l_) << chi3_iw(bl1, bl2)[iW_, iw_](i_, j_, k_, l_)
174 + G0_iw[bl1](iw_)(m, i_) * G0_iw[bl2](iW_ - iw_)(n, k_) * M3_iw_conn(bl1, bl2)(iW_, iw_)(m, j_, n, l_);
175
176 // Disconnected part
177 chi3_iw(bl1, bl2)(iW_, iw_)(i_, j_, k_, l_) << chi3_iw(bl1, bl2)[iW_, iw_](i_, j_, k_, l_)
178 + G_iw[bl1](iw_)(j_, i_) * G_iw[bl2](iW_ - iw_)(l_, k_) - kronecker(bl1, bl2) * G_iw[bl1](iw_)(l_, i_) * G_iw[bl2](iW_ - iw_)(j_, k_);
179
180 } else if constexpr (Chan == Chan_t::PH) { // ===== Particle-hole channel
181
182 auto km_GMG = make_zero_tail(GMG, 3);
183 for (auto [km_bl, M_hartree_bl] : zip(km_GMG, M_hartree)) km_bl(2, ellipsis()) = M_hartree_bl;
184 auto tail_GMG = fit_hermitian_tail(GMG, km_GMG).first;
185 auto dens_GMG = density(GMG, tail_GMG);
186
187 M3_iw_conn(bl1, bl2)(iW_, iw_)(i_, j_, k_, l_) << M3_iw(bl1, bl2)[iW_, iw_](i_, j_, k_, l_)
188 - beta * kronecker(iW_) * M_iw[bl1](iw_)(j_, i_) * dens_GMG[bl2](l_, k_)
189 + kronecker(bl1, bl2) * GM[bl1](iw_)(l_, i_) * MG[bl2](iW_ + iw_)(j_, k_);
190
191 for (int m : range(bl1_size))
192 for (int n : range(bl1_size))
193 chi3_iw(bl1, bl2)(iW_, iw_)(i_, j_, k_, l_) << chi3_iw(bl1, bl2)[iW_, iw_](i_, j_, k_, l_)
194 + G0_iw[bl1](iw_)(m, i_) * G0_iw[bl1](iW_ + iw_)(j_, n) * M3_iw_conn(bl1, bl2)(iW_, iw_)(m, n, k_, l_);
195
196 // Disconnected part
197 chi3_iw(bl1, bl2)(iW_, iw_)(i_, j_, k_, l_) << chi3_iw(bl1, bl2)[iW_, iw_](i_, j_, k_, l_)
198 + beta * kronecker(iW_) * G_iw[bl1](iw_)(j_, i_) * dens_G[bl2](l_, k_)
199 - kronecker(bl1, bl2) * G_iw[bl1](iw_)(l_, i_) * G_iw[bl2](iW_ + iw_)(j_, k_);
200 } else if constexpr (Chan == Chan_t::XPH) { // ===== Particle-hole-cross channel
201
202 auto km_GMG = make_zero_tail(GMG, 3);
203 for (auto [km_bl, M_hartree_bl] : zip(km_GMG, M_hartree)) km_bl(2, ellipsis()) = M_hartree_bl;
204 auto tail_GMG = fit_hermitian_tail(GMG, km_GMG).first;
205 auto dens_GMG = density(GMG, tail_GMG);
206
207 M3_iw_conn(bl1, bl2)(iW_, iw_)(i_, j_, k_, l_) << M3_iw(bl1, bl2)[iW_, iw_](i_, j_, k_, l_)
208 - GM[bl1](iw_)(j_, i_) * MG[bl2](iW_ + iw_)(l_, k_)
209 + kronecker(bl1, bl2) * beta * kronecker(iW_) * M_iw[bl1](iw_)(l_, i_) * dens_GMG[bl2](j_, k_);
210
211 for (int m : range(bl1_size))
212 for (int n : range(bl1_size))
213 chi3_iw(bl1, bl2)(iW_, iw_)(i_, j_, k_, l_) << chi3_iw(bl1, bl2)[iW_, iw_](i_, j_, k_, l_)
214 + G0_iw[bl1](iw_)(m, i_) * G0_iw[bl2](iW_ + iw_)(l_, n) * M3_iw_conn(bl1, bl2)(iW_, iw_)(m, j_, k_, n);
215
216 // Disconnected part
217 chi3_iw(bl1, bl2)(iW_, iw_)(i_, j_, k_, l_) << chi3_iw(bl1, bl2)[iW_, iw_](i_, j_, k_, l_)
218 + G_iw[bl1](iw_)(j_, i_) * G_iw[bl2](iW_ + iw_)(l_, k_)
219 - kronecker(bl1, bl2) * beta * kronecker(iW_) * G_iw[bl1](iw_)(l_, i_) * dens_GMG[bl2](j_, k_);
220 }
221 }
222
223 return chi3_iw;
224 }
225
226 // Calculate the chi^{(2)} function from the building blocks chi2_conn_tau and M_iw
227 template <Chan_t Chan> chi2_tau_t chi2_from_chi2_conn(chi2_tau_cv_t chi2_tau_conn, g_reg_iw_cv_t G_iw, block_matrix_t const &dens_G) {
228
229 double beta = G_iw[0].mesh().beta();
230 int n_blocks = G_iw.size();
231
232 // Create Container for chi2
233 chi2_tau_t chi2_tau = chi2_tau_conn;
234
235 auto tau_mesh = make_adjoint_mesh(G_iw[0].mesh());
236
237 auto km_G = make_zero_tail(G_iw, 2);
238 for (auto &km_bl : km_G) matrix_view<dcomplex>{km_bl(1, ellipsis())} = 1.0;
239 auto tail_G = fit_hermitian_tail(G_iw, km_G).first;
240
241#ifdef GTAU_IS_COMPLEX
242 g_tau_t G_tau = make_gf_from_fourier(G_iw, tau_mesh, tail_G);
243#else
244 g_tau_t G_tau = real(make_gf_from_fourier(G_iw, tau_mesh, tail_G));
245 if (!is_gf_real_in_tau(G_iw, 1e-8)) std::cerr << "WARNING: Assuming real G_tau, but found Imag(G(tau)) > 1e-8. Casting to Real.\n";
246#endif
247
248 for (int bl1 : range(n_blocks))
249 for (int bl2 : range(n_blocks)) {
250
251 if constexpr (Chan == Chan_t::PP) { // ===== Particle-particle channel
252
253 // Add Disconnected part
254 chi2_tau(bl1, bl2)(t_)(i_, j_, k_, l_) << chi2_tau_conn(bl1, bl2)[t_](i_, j_, k_, l_) + G_tau[bl1](t_)(j_, i_) * G_tau[bl2](t_)(l_, k_)
255 - kronecker(bl1, bl2) * G_tau[bl1](t_)(l_, i_) * G_tau[bl2](t_)(j_, k_);
256
257 } else if constexpr (Chan == Chan_t::PH) { // ===== Particle-hole channel
258
259 chi2_tau(bl1, bl2)(t_)(i_, j_, k_, l_) << chi2_tau_conn(bl1, bl2)[t_](i_, j_, k_, l_) + dens_G[bl1](j_, i_) * dens_G[bl2](l_, k_)
260 + kronecker(bl1, bl2) * G_tau[bl1](beta - t_)(l_, i_) * G_tau[bl2](t_)(j_, k_); // Sign-change from G_tau shift
261
262 } else if constexpr (Chan == Chan_t::XPH) { // ===== Particle-hole-cross channel
263
264 chi2_tau(bl1, bl2)(t_)(i_, j_, k_, l_) << chi2_tau_conn(bl1, bl2)[t_](i_, j_, k_, l_)
265 - G_tau[bl1](beta - t_)(j_, i_) * G_tau[bl2](t_)(l_, k_) // Sign-change from G_tau shift
266 - kronecker(bl1, bl2) * dens_G[bl1](l_, i_) * dens_G[bl2](j_, k_);
267 }
268 }
269
270 return chi2_tau;
271 }
272
273 // Calculate the chi_{AB} function from chi2_tau and the operator lists A and B
274 template <Chan_t Chan>
275 gf<imtime, matrix_valued> chiAB_from_chi2(chi2_tau_cv_t chi2_tau, gf_struct_t const &gf_struct, std::vector<many_body_operator> const &A_op_vec,
276 std::vector<many_body_operator> const &B_op_vec) {
277
278 using op_term_t = std::tuple<dcomplex, std::pair<int, int>, std::pair<int, int>>;
279 std::vector<std::vector<op_term_t>> A_vec;
280 std::vector<std::vector<op_term_t>> B_vec;
281
282 for (auto A : A_op_vec) A_vec.emplace_back(get_terms(A, gf_struct));
283 for (auto B : B_op_vec) B_vec.emplace_back(get_terms(B, gf_struct));
284
285 auto chiAB_tau = gf<imtime, matrix_valued>{chi2_tau(0, 0).mesh(), make_shape(A_vec.size(), B_vec.size())};
286
287 for (auto [j, B] : enumerate(B_vec))
288 for (auto &[coef_B, bl_pair_B, idx_pair_B] : B) {
289
290 auto [idx_cdag_B, idx_c_B] = idx_pair_B;
291 auto [bl_cdag_B, bl_c_B] = bl_pair_B;
292
293 for (auto [i, A] : enumerate(A_vec))
294 for (auto &[coef_A, bl_pair_A, idx_pair_A] : A) {
295
296 auto [idx_cdag_A, idx_c_A] = idx_pair_A;
297 auto [bl_cdag_A, bl_c_A] = bl_pair_A;
298
299 if ((bl_cdag_A != bl_c_A) || (bl_cdag_B != bl_c_B)) {
300 TRIQS_RUNTIME_ERROR << "Monomials with unequal blocks not implemented for chiAB_from_chi2";
301 }
302
303 auto chiAB_tau_ij = slice_target_to_scalar(chiAB_tau, i, j);
304 auto chi2_tau_AABB_ijkl = slice_target_to_scalar(chi2_tau(bl_c_A, bl_c_B), idx_cdag_A, idx_c_A, idx_cdag_B, idx_c_B);
305 chiAB_tau_ij() += coef_A * coef_B * chi2_tau_AABB_ijkl;
306 }
307 }
308
309 return chiAB_tau;
310 }
311
313 template <Chan_t Chan>
314 chi3_tau_t M3_conn_from_M3(chi3_tau_t M3_tau, g_reg_iw_cv_t M_iw, g_reg_iw_cv_t G0_iw, g_tau_cv_t M_tau, block_matrix_t const &M_hartree) {
315
316 double beta = M_tau[0].mesh().beta();
317 int n_blocks = M_tau.size();
318
319 // Temporary quantities
320 g_reg_iw_t GM_iw = G0_iw * M_iw;
321 g_reg_iw_t MG_iw = M_iw * G0_iw;
322 g_reg_iw_t GMG_iw = G0_iw * M_iw * G0_iw;
323
324 auto km_GM = make_zero_tail(GM_iw, 2);
325 for (auto [km_bl, M_hartree_bl] : zip(km_GM, M_hartree)) km_bl(1, ellipsis()) = M_hartree_bl;
326 auto tail_GM = fit_hermitian_tail(GM_iw, km_GM).first;
327 auto tail_MG = fit_hermitian_tail(MG_iw, km_GM).first; // known moments identical to GM
328 auto tau_mesh = make_adjoint_mesh(M_iw[0].mesh());
329 auto GM = make_gf_from_fourier(GM_iw, tau_mesh, tail_GM);
330 auto MG = make_gf_from_fourier(MG_iw, tau_mesh, tail_MG);
331
332 auto km_GMG = make_zero_tail(GMG_iw, 3);
333 for (auto [km_bl, M_hartree_bl] : zip(km_GMG, M_hartree)) km_bl(2, ellipsis()) = M_hartree_bl;
334 auto tail_GMG = fit_hermitian_tail(GMG_iw, km_GMG).first;
335 auto dens_GMG = density(GMG_iw, tail_GMG);
336
337 // Connected part of M3
338 chi3_tau_t M3_tau_conn = M3_tau;
339 for (int bl1 : range(n_blocks))
340 for (int bl2 : range(n_blocks)) {
341
342 if constexpr (Chan == Chan_t::PP) { // ===== Particle-particle channel
343
344 M3_tau_conn(bl1, bl2)(t1_, t2_)(i_, j_, k_, l_) << M3_tau(bl1, bl2)[t1_, t2_](i_, j_, k_, l_) - GM[bl1](t1_)(j_, i_) * GM[bl2](t2_)(l_, k_)
345 + kronecker(bl1, bl2) * GM[bl1](t1_)(l_, i_) * GM[bl2](t2_)(j_, k_);
346
347 } else if constexpr (Chan == Chan_t::PH) { // ===== Particle-hole channel
348
349 for (auto [t1, t2] : M3_tau(0, 0).mesh()) {
350
351 // Treat the equal-time case explicitly
352 if (t1 == t2) { // We need to account for both M_tau(0+) and M_tau(0-)
353 M3_tau_conn(bl1, bl2)[t1, t2](i_, j_, k_, l_) << M3_tau(bl1, bl2)[t1, t2](i_, j_, k_, l_)
354 - (0.5 * M_tau[bl1](0.0)(j_, i_) - 0.5 * M_tau[bl1](beta)(j_, i_)) * dens_GMG[bl2](l_, k_)
355 - kronecker(bl1, bl2) * GM[bl1](beta - t1)(l_, i_) * MG[bl2](t2)(j_, k_); // Sign change from GM shift
356 continue;
357 }
358
359 double s, d_t2_t1;
360 if (t2 > t1) {
361 s = 1.0;
362 d_t2_t1 = t2 - t1;
363 } else { // t2 < t1
364 s = -1.0;
365 d_t2_t1 = t2 - t1 + beta;
366 }
367
368 M3_tau_conn(bl1, bl2)[t1, t2](i_, j_, k_, l_) << M3_tau(bl1, bl2)[t1, t2](i_, j_, k_, l_)
369 - s * M_tau[bl1](d_t2_t1)(j_, i_) * dens_GMG[bl2](l_, k_)
370 - kronecker(bl1, bl2) * GM[bl1](beta - t1)(l_, i_) * MG[bl2](t2)(j_, k_); // Sign change from GM shift
371 }
372 } else if constexpr (Chan == Chan_t::XPH) { // ===== Particle-hole-cross channel
373
374 for (auto [t1, t2] : M3_tau(0, 0).mesh()) {
375
376 // Treat the equal-time case explicitly
377 if (t1 == t2) { // We need to account for both M_tau(0+) and M_tau(0-)
378 M3_tau_conn(bl1, bl2)[t1, t2](i_, j_, k_, l_) << M3_tau(bl1, bl2)[t1, t2](i_, j_, k_, l_)
379 + kronecker(bl1, bl2) * (0.5 * M_tau[bl1](0.0)(l_, i_) - 0.5 * M_tau[bl1](beta)(l_, i_)) * dens_GMG[bl2](j_, k_)
380 + GM[bl1](beta - t1)(j_, i_) * MG[bl2](t2)(l_, k_); // Sign change from GM shift
381 continue;
382 }
383
384 double s, d_t2_t1;
385 if (t2 > t1) {
386 s = 1.0;
387 d_t2_t1 = t2 - t1;
388 } else { // t2 < t1
389 s = -1.0;
390 d_t2_t1 = t2 - t1 + beta;
391 }
392
393 M3_tau_conn(bl1, bl2)[t1, t2](i_, j_, k_, l_) << M3_tau(bl1, bl2)[t1, t2](i_, j_, k_, l_)
394 + kronecker(bl1, bl2) * s * M_tau[bl1](d_t2_t1)(l_, i_) * dens_GMG[bl2](j_, k_)
395 + GM[bl1](beta - t1)(j_, i_) * MG[bl2](t2)(l_, k_); // Sign change from GM shift
396 }
397 }
398 }
399
400 return M3_tau_conn;
401 }
402
404 template <Chan_t Chan>
405 chi2_tau_t chi2_conn_from_M3(chi3_tau_cv_t M3, chi2_tau_t M3_delta, g_reg_iw_cv_t M_iw, g_reg_iw_cv_t G0_iw, g_tau_cv_t M_tau,
406 block_matrix_t const &M_hartree, g_tau_cv_t G0_tau) {
407
408 double beta = G0_tau[0].mesh().beta();
409 int n_blocks = G0_tau.size();
410
411 auto const &tau_mesh_M3 = M3(0, 0).mesh();
412 double dtau_M3 = std::get<0>(tau_mesh_M3).delta();
413 int n_tau_M3 = std::get<0>(tau_mesh_M3).size();
414
415 auto const &tau_mesh_M3_del = M3_delta(0, 0).mesh();
416 double dtau_M3_del = tau_mesh_M3_del.delta();
417 int n_tau_M3_del = tau_mesh_M3_del.size();
418
419 // We infer the number of tau points from M3
420 // We can calculate chi2_conn accurately only inbetween two tau-points of M3
421 int n_tau_chi2 = n_tau_M3 * 2 - 1;
422 auto tau_mesh_chi2 = mesh::imtime{beta, Boson, n_tau_chi2};
423 auto chi2_conn = make_block2_gf(tau_mesh_chi2, M3);
424 chi2_conn() = 0.0;
425
426 chi3_tau_t M3_conn = M3_conn_from_M3<Chan>(M3, M_iw, G0_iw, M_tau, M_hartree);
427 M3_conn() = M3_conn() * dtau_M3 * dtau_M3;
428
429 // Calculate the density of GMG
430 g_reg_iw_t GMG_iw = G0_iw * M_iw * G0_iw;
431 auto km = make_zero_tail(GMG_iw, 3);
432 for (auto [km_bl, M_hartree_bl] : zip(km, M_hartree)) km_bl(2, ellipsis()) = M_hartree_bl;
433 auto tail = fit_hermitian_tail(GMG_iw, km).first;
434 auto dens_GMG = density(GMG_iw, tail);
435
436 // Subtract the remaining disconnected component contained in M3ph_delta
437 if constexpr (Chan == Chan_t::PH) {
438 for (auto [bl1, bl2] : product_range(n_blocks, n_blocks)) {
439 M3_delta(bl1, bl2)(t_)(i_, j_, k_, l_) << M3_delta(bl1, bl2)[t_](i_, j_, k_, l_) - M_hartree[bl1](j_, i_) * dens_GMG[bl2](l_, k_);
440 }
441 } else if constexpr (Chan == Chan_t::XPH) {
442 for (auto [bl1, bl2] : product_range(n_blocks, n_blocks)) {
443 M3_delta(bl1, bl2)(t_)(i_, j_, k_, l_) << M3_delta(bl1, bl2)[t_](i_, j_, k_, l_)
444 + kronecker(bl1, bl2) * M_hartree[bl1](l_, i_) * dens_GMG[bl2](j_, k_);
445 }
446 }
447 M3_delta() = M3_delta() * dtau_M3_del;
448
449 // Account for M3 edge bins beeing smaller
450 auto _ = all_t{};
451 for (auto [M, M_del] : zip(M3_conn, M3_delta)) {
452 M[0, _] *= 0.5;
453 M[_, 0] *= 0.5;
454 M[n_tau_M3 - 1, _] *= 0.5;
455 M[_, n_tau_M3 - 1] *= 0.5;
456 M_del[0] *= 0.5;
457 M_del[n_tau_M3_del - 1] *= 0.5;
458 }
459
460 for (auto t : tau_mesh_chi2) {
461
462 // We have to skip the points that match the M3 tau_mesh to avoid problems in the integration below
463 if (t.data_index() % 2 == 0 and t.data_index() != 0 and t.data_index() != n_tau_chi2 - 1) continue;
464
465 // ==== Precalculate all relevant G0_tau interpolation points
466
467 // Function to generate the G0(t-ti) and G0(ti-t) vectors
468 auto get_G0_vecs = [&](mesh::imtime const &tau_mesh) {
469 auto G0_d_ti_t_vec = std::vector<array<dcomplex, 3>>{};
470 auto G0_d_t_ti_vec = std::vector<array<dcomplex, 3>>{};
471
472 for (int bl : range(n_blocks)) {
473 int n_tau = tau_mesh.size();
474 auto sh = G0_tau[bl].target_shape();
475 G0_d_ti_t_vec.emplace_back(sh[0], sh[1], n_tau);
476 G0_d_t_ti_vec.emplace_back(sh[0], sh[1], n_tau);
477
478 for (auto ti : tau_mesh) {
479
480 auto [s1, d_ti_t] = cyclic_difference(ti, t);
481 auto [s2, d_t_ti] = cyclic_difference(t, ti);
482
483 // Treat t=0 and t=beta cases separately
484 if (t.data_index() == 0) {
485 s1 = 1.0;
486 d_ti_t = ti;
487
488 s2 = -1.0;
489 d_t_ti = beta - ti;
490 }
491 if (t.data_index() == n_tau_chi2 - 1) {
492 s1 = -1.0;
493 d_ti_t = ti;
494
495 s2 = 1.0;
496 d_t_ti = beta - ti;
497 }
498
499 G0_d_ti_t_vec[bl](range::all, range::all, ti.data_index()) = s1 * G0_tau[bl](d_ti_t);
500 G0_d_t_ti_vec[bl](range::all, range::all, ti.data_index()) = s2 * G0_tau[bl](d_t_ti);
501 }
502 }
503
504 return std::make_pair(G0_d_ti_t_vec, G0_d_t_ti_vec);
505 };
506
507 auto [G0_d_ti_t, G0_d_t_ti] = get_G0_vecs(std::get<0>(tau_mesh_M3));
508 auto [G0_d_ti_t_del, G0_d_t_ti_del] = get_G0_vecs(tau_mesh_M3_del);
509
510 // ==== End Precalculation
511
512 for (auto [bl1, bl2] : product_range(n_blocks, n_blocks)) {
513
514 // Capture block-sizes
515 int bl1_size = M3(bl1, bl2).target_shape()[0];
516 int bl2_size = M3(bl1, bl2).target_shape()[2];
517
518 auto chi2c = chi2_conn(bl1, bl2)[t];
519
520 if constexpr (Chan == Chan_t::PP) { // ===== Particle-particle channel
521
522 auto arr_GG = array<dcomplex, 5>(bl1_size, bl1_size, bl2_size, bl2_size, n_tau_M3_del);
523 for (auto [m, i, n, k] : product_range(bl1_size, bl1_size, bl2_size, bl2_size)) {
524 arr_GG(m, i, n, k, range::all) = G0_d_t_ti_del[bl1](m, i, range::all) * G0_d_t_ti_del[bl2](n, k, range::all);
525 }
526
527 auto M3_perm = nda::array<dcomplex, 6>{permuted_indices_view<encode(std::array{4, 5, 0, 1, 2, 3})>(M3_conn(bl1, bl2).data())};
528 auto M3_del = nda::array<dcomplex, 5>{permuted_indices_view<encode(std::array{4, 0, 1, 2, 3})>(M3_delta(bl1, bl2).data())};
529
530 for (auto [m, j, n, l] : product_range(bl1_size, bl1_size, bl2_size, bl2_size)) {
531
532 auto M3_mjnl = matrix_view<dcomplex>{M3_perm(m, j, n, l, _, _)};
533 for (auto [i, k] : product_range(bl1_size, bl2_size)) {
534 auto G1_mi = vector_view<dcomplex>(G0_d_t_ti[bl1](m, i, range::all));
535 auto G2_nk = vector_view<dcomplex>(G0_d_t_ti[bl2](n, k, range::all));
536 chi2c(i, j, k, l) += nda::blas::dot(G1_mi, M3_mjnl * G2_nk);
537 }
538
539 // We treat the delta-contribution seperately
540 auto M3_del_mjnl = vector_view<dcomplex>{M3_del(m, j, n, l, _)};
541 for (auto [i, k] : product_range(bl1_size, bl2_size)) {
542 chi2c(i, j, k, l) += nda::blas::dot(M3_del_mjnl, vector_view<dcomplex>(arr_GG(m, i, n, k, range::all)));
543 }
544 }
545
546 } else if constexpr (Chan == Chan_t::PH) { // ===== Particle-hole channel
547
548 auto arr_GG = array<dcomplex, 5>(bl1_size, bl1_size, bl1_size, bl1_size, n_tau_M3_del);
549 for (auto [m, i, j, n] : product_range(bl1_size, bl1_size, bl1_size, bl1_size)) {
550 arr_GG(m, i, j, n, range::all) = G0_d_ti_t_del[bl1](m, i, range::all) * G0_d_t_ti_del[bl1](j, n, range::all);
551 }
552
553 auto M3_perm = nda::array<dcomplex, 6>{permuted_indices_view<encode(std::array{4, 5, 0, 1, 2, 3})>(M3_conn(bl1, bl2).data())};
554 auto M3_del = nda::array<dcomplex, 5>{permuted_indices_view<encode(std::array{4, 0, 1, 2, 3})>(M3_delta(bl1, bl2).data())};
555
556 for (auto [m, n, k, l] : product_range(bl1_size, bl1_size, bl2_size, bl2_size)) {
557
558 auto M3_mnkl = matrix_view<dcomplex>{M3_perm(m, n, k, l, _, _)};
559 for (auto [i, j] : product_range(bl1_size, bl1_size)) {
560 auto G1_mi = vector_view<dcomplex>(G0_d_ti_t[bl1](m, i, range::all));
561 auto G2_jn = vector_view<dcomplex>(G0_d_t_ti[bl1](j, n, range::all));
562 chi2c(i, j, k, l) += nda::blas::dot(G1_mi, M3_mnkl * G2_jn);
563 }
564
565 // We treat the delta-contribution seperately
566 auto M3_del_mnkl = vector_view<dcomplex>{M3_del(m, n, k, l, _)};
567 for (auto [i, j] : product_range(bl1_size, bl1_size)) {
568 chi2c(i, j, k, l) += nda::blas::dot(M3_del_mnkl, vector_view<dcomplex>(arr_GG(m, i, j, n, range::all)));
569 }
570 }
571
572 } else if constexpr (Chan == Chan_t::XPH) { // ===== Particle-hole-cross channel
573
574 auto arr_GG = array<dcomplex, 5>(bl1_size, bl1_size, bl2_size, bl2_size, n_tau_M3_del);
575 for (auto [m, i, l, n] : product_range(bl1_size, bl1_size, bl2_size, bl2_size)) {
576 arr_GG(m, i, l, n, range::all) = G0_d_ti_t_del[bl1](m, i, range::all) * G0_d_t_ti_del[bl2](l, n, range::all);
577 }
578
579 auto M3_perm = nda::array<dcomplex, 6>{permuted_indices_view<encode(std::array{4, 5, 0, 1, 2, 3})>(M3_conn(bl1, bl2).data())};
580 auto M3_del = nda::array<dcomplex, 5>{permuted_indices_view<encode(std::array{4, 0, 1, 2, 3})>(M3_delta(bl1, bl2).data())};
581
582 for (auto [m, j, k, n] : product_range(bl1_size, bl1_size, bl2_size, bl2_size)) {
583
584 auto M3_mjkn = matrix_view<dcomplex>{M3_perm(m, j, k, n, _, _)};
585 for (auto [i, l] : product_range(bl1_size, bl2_size)) {
586 auto G1_mi = vector_view<dcomplex>(G0_d_ti_t[bl1](m, i, range::all));
587 auto G2_ln = vector_view<dcomplex>(G0_d_t_ti[bl2](l, n, range::all));
588 chi2c(i, j, k, l) += nda::blas::dot(G1_mi, M3_mjkn * G2_ln);
589 }
590
591 // We treat the delta-contribution seperately
592 auto M3_del_mjkn = vector_view<dcomplex>{M3_del(m, j, k, n, _)};
593 for (auto [i, l] : product_range(bl1_size, bl2_size)) {
594 chi2c(i, j, k, l) += nda::blas::dot(M3_del_mjkn, vector_view<dcomplex>(arr_GG(m, i, l, n, range::all)));
595 }
596 }
597 }
598 }
599 }
600
601 for (auto t : tau_mesh_chi2) {
602 // We perform a linear interpolation for the problematic Meshpoints of chi2_conn
603 if (t.data_index() % 2 == 0 and t.data_index() != 0 and t.data_index() != n_tau_chi2 - 1) {
604 for (auto [bl1, bl2] : product_range(n_blocks, n_blocks)) {
605 chi2_conn(bl1, bl2)[t] = 0.5 * (chi2_conn(bl1, bl2)[t.data_index() - 1] + chi2_conn(bl1, bl2)[t.data_index() + 1]);
606 }
607 }
608 }
609
610 return chi2_conn;
611 }
612
613 // Non-template wrappers exposing the channel-specific instantiations to Python.
614
629 inline chi3_iw_t chi3_from_M3_PP(chi3_iw_cv_t M3_iw, g_reg_iw_cv_t M_iw, g_reg_iw_cv_t G0_iw, block_matrix_t const &dens_G,
630 block_matrix_t const &M_hartree) {
631 return chi3_from_M3<Chan_t::PP>(M3_iw, M_iw, G0_iw, dens_G, M_hartree);
632 }
633
648 inline chi3_iw_t chi3_from_M3_PH(chi3_iw_cv_t M3_iw, g_reg_iw_cv_t M_iw, g_reg_iw_cv_t G0_iw, block_matrix_t const &dens_G,
649 block_matrix_t const &M_hartree) {
650 return chi3_from_M3<Chan_t::PH>(M3_iw, M_iw, G0_iw, dens_G, M_hartree);
651 }
652
664 inline chi2_tau_t chi2_from_chi2_conn_PP(chi2_tau_cv_t chi2_conn_tau, g_reg_iw_cv_t G_iw, block_matrix_t const &dens_G) {
665 return chi2_from_chi2_conn<Chan_t::PP>(chi2_conn_tau, G_iw, dens_G);
666 }
667
679 inline chi2_tau_t chi2_from_chi2_conn_PH(chi2_tau_cv_t chi2_conn_tau, g_reg_iw_cv_t G_iw, block_matrix_t const &dens_G) {
680 return chi2_from_chi2_conn<Chan_t::PH>(chi2_conn_tau, G_iw, dens_G);
681 }
682
695 inline gf<imtime, matrix_valued> chiAB_from_chi2_PP(chi2_tau_cv_t chi2pp_tau, gf_struct_t const &gf_struct,
696 std::vector<many_body_operator> const &A_op_vec,
697 std::vector<many_body_operator> const &B_op_vec) {
698 return chiAB_from_chi2<Chan_t::PP>(chi2pp_tau, gf_struct, A_op_vec, B_op_vec);
699 }
700
713 inline gf<imtime, matrix_valued> chiAB_from_chi2_PH(chi2_tau_cv_t chi2ph_tau, gf_struct_t const &gf_struct,
714 std::vector<many_body_operator> const &A_op_vec,
715 std::vector<many_body_operator> const &B_op_vec) {
716 return chiAB_from_chi2<Chan_t::PH>(chi2ph_tau, gf_struct, A_op_vec, B_op_vec);
717 }
718
735 inline chi2_tau_t chi2_conn_from_M3_PP(chi3_tau_t M3pp_tau, chi2_tau_t M3pp_delta, g_reg_iw_cv_t M_iw, g_reg_iw_cv_t G0_iw, g_tau_cv_t M_tau,
736 block_matrix_t const &M_hartree, g_tau_cv_t G0_tau) {
737 return chi2_conn_from_M3<Chan_t::PP>(M3pp_tau, M3pp_delta, M_iw, G0_iw, M_tau, M_hartree, G0_tau);
738 }
739
756 inline chi2_tau_t chi2_conn_from_M3_PH(chi3_tau_t M3ph_tau, chi2_tau_t M3ph_delta, g_reg_iw_cv_t M_iw, g_reg_iw_cv_t G0_iw, g_tau_cv_t M_tau,
757 block_matrix_t const &M_hartree, g_tau_cv_t G0_tau) {
758 return chi2_conn_from_M3<Chan_t::PH>(M3ph_tau, M3ph_delta, M_iw, G0_iw, M_tau, M_hartree, G0_tau);
759 }
760
761} // namespace triqs_ctint