TRIQS/triqs_ctint 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
M3xph_tau.cpp
1// Copyright (c) 2019--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#include "./M3xph_tau.hpp"
7
8namespace triqs_ctint::measures {
9
10 M3xph_tau::M3xph_tau(params_t const &params_, qmc_config_t const &qmc_config_, container_set *results, g_tau_cv_t G0_tau_)
11 : params(params_), qmc_config(qmc_config_), G0_tau(std::move(G0_tau_)), tau_mesh{params_.beta, Fermion, params_.n_tau_M3} {
12
13 // Construct Matsubara mesh
14 mesh::prod<imtime, imtime> M3xph_tau_mesh{tau_mesh, tau_mesh};
15
16 // Init measurement container for M3xph and capture view
17 results->M3xph_tau = make_block2_gf(M3xph_tau_mesh, params.gf_struct);
18 M3xph_tau_.rebind(results->M3xph_tau.value());
19 M3xph_tau_() = 0;
20
21 // Init measurement container for equal-time component of M3xph
22 auto mesh_b = mesh::imtime({params.beta, Boson, params.n_tau});
23 results->M3xph_delta = make_block2_gf(mesh_b, params.gf_struct);
24 M3xph_delta_.rebind(*results->M3xph_delta);
25 M3xph_delta_() = 0;
26 }
27
28 void M3xph_tau::accumulate(mc_weight_t sign) {
29 // Accumulate sign
30 Z += sign;
31
32 // Vectors containing the binned tau-values vec[bl][i] (binned to G0 and M3 mesh)
33 std::vector<std::vector<idx_t>> c_vec_G0, cdag_vec_G0;
34 std::vector<std::vector<idx_t>> c_vec_M, cdag_vec_M;
35
36 // The two tau meshes in one dimension
37 auto const &G0_tau_mesh = G0_tau[0].mesh();
38 auto const &M_tau_mesh = tau_mesh;
39
40 // Precompute binned tau-points for different meshes
41 for (auto &det : qmc_config.dets) {
42
43 auto x_to_G0_mesh = [&G0_tau_mesh](c_t const &c_i) { return idx_t{G0_tau_mesh.to_index(closest_mesh_pt(double(c_i.tau))), c_i.u, c_i.tau}; };
44 auto y_to_G0_mesh = [beta = params.beta, &G0_tau_mesh](cdag_t const &cdag_j) {
45 return idx_t{G0_tau_mesh.to_index(closest_mesh_pt(beta - double(cdag_j.tau))), cdag_j.u, cdag_j.tau};
46 };
47
48 auto x_to_M_mesh = [&M_tau_mesh](c_t const &c_i) { return idx_t{M_tau_mesh.to_index(closest_mesh_pt(double(c_i.tau))), c_i.u, c_i.tau}; };
49 auto y_to_M_mesh = [&M_tau_mesh](cdag_t const &cdag_j) {
50 return idx_t{M_tau_mesh.to_index(closest_mesh_pt(double(cdag_j.tau))), cdag_j.u, cdag_j.tau};
51 };
52
53 // Careful: x and y vectors have to be used in internal storage order
54 c_vec_G0.push_back(make_vector_from_range(transform(det.get_x_internal_order(), x_to_G0_mesh)));
55 cdag_vec_G0.push_back(make_vector_from_range(transform(det.get_y_internal_order(), y_to_G0_mesh)));
56 c_vec_M.push_back(make_vector_from_range(transform(det.get_x_internal_order(), x_to_M_mesh)));
57 cdag_vec_M.push_back(make_vector_from_range(transform(det.get_y_internal_order(), y_to_M_mesh)));
58 }
59
60 // The intermediate scattering matrices
61 std::vector<matrix<dcomplex>> M_vec(params.n_blocks()); // M[bl](j, i) FIXME matrix_view does not work!
62 std::vector<matrix<dcomplex>> GM_vec(params.n_blocks()); // GM[bl](u, i)
63 std::vector<matrix<dcomplex>> MG_vec(params.n_blocks()); // MG[bl](j, u)
64 std::vector<matrix<dcomplex>> GMG_vec(params.n_blocks()); // GMG[bl](u, u)
65
66 // Calculate intermediate scattering matrices
67 for (int bl : range(params.n_blocks())) {
68
69 auto const &det = qmc_config.dets[bl];
70 int det_size = det.size();
71
72 if (det.size() == 0) continue;
73
74 auto const &c = c_vec_G0[bl];
75 auto const &cdag = cdag_vec_G0[bl];
76 int bl_size = G0_tau[bl].target_shape()[0];
77 auto G_left = matrix<dcomplex>(bl_size, det_size);
78 auto G_right = matrix<dcomplex>(det_size, bl_size);
79
80 for (int u : range(bl_size))
81 for (int i : range(det_size)) {
82 G_left(u, i) = -G0_tau[bl][cdag[i].tau_idx](u, cdag[i].u);
83 G_right(i, u) = G0_tau[bl][c[i].tau_idx](c[i].u, u);
84 }
85 M_vec[bl] = det.inverse_matrix_internal_order();
86 GM_vec[bl] = G_left * M_vec[bl];
87 MG_vec[bl] = M_vec[bl] * G_right;
88 GMG_vec[bl] = GM_vec[bl] * G_right;
89 }
90
91 // Calculate M3xph
92 for (int bl1 : range(params.n_blocks())) {
93
94 int det1_size = qmc_config.dets[bl1].size();
95
96 // Do not consider empty blocks
97 if (det1_size == 0) continue;
98
99 auto const &M = M_vec[bl1];
100 auto const &GM = GM_vec[bl1];
101 auto const &GMG = GMG_vec[bl1];
102 int bl1_size = G0_tau[bl1].target_shape()[0];
103 auto const &c1 = c_vec_M[bl1];
104 auto const &cdag1 = cdag_vec_M[bl1];
105
106 // Crossing term (equal blocks)
107 auto &M3xph_tau = M3xph_tau_(bl1, bl1);
108 auto &M3xph_delta = M3xph_delta_(bl1, bl1);
109
110 for (auto [i, j, k, l] : product_range(det1_size, bl1_size, bl1_size, det1_size)) {
111 // Take care of equal-time peak separately
112 if (c1[i].tau_pt == cdag1[l].tau_pt) {
113 M3xph_delta[c_vec_G0[bl1][i].tau_idx](c1[i].u, j, k, cdag1[l].u) += -sign * M(l, i) * GMG(j, k);
114 } else {
115 // Since the crossing term is negative by itself, we get a negative sign here
116 M3xph_tau[c1[i].tau_idx, cdag1[l].tau_idx](c1[i].u, j, k, cdag1[l].u) += -sign * M(l, i) * GMG(j, k);
117 }
118 }
119
120 for (int bl2 : range(params.n_blocks())) {
121
122 int det2_size = qmc_config.dets[bl2].size();
123
124 // Do not consider empty blocks
125 if (det2_size == 0) continue;
126
127 auto const &MG = MG_vec[bl2];
128 int bl2_size = G0_tau[bl2].target_shape()[0];
129 auto const &cdag2 = cdag_vec_M[bl2];
130 auto &M3xph_tau_bl = M3xph_tau_(bl1, bl2);
131 auto &M3xph_delta_bl = M3xph_delta_(bl1, bl2);
132
133 // Direct term
134 for (auto [i, j, k, l] : product_range(det1_size, bl1_size, bl2_size, det2_size)) {
135 // Take care of equal-time peak separately
136 if (c1[i].tau_pt == cdag2[l].tau_pt) {
137 M3xph_delta_bl[c_vec_G0[bl1][i].tau_idx](c1[i].u, j, k, cdag2[l].u) += sign * GM(j, i) * MG(l, k);
138 } else {
139 M3xph_tau_bl[c1[i].tau_idx, cdag2[l].tau_idx](c1[i].u, j, k, cdag2[l].u) += sign * GM(j, i) * MG(l, k);
140 }
141 }
142 }
143 }
144 }
145
146 void M3xph_tau::collect_results(mpi::communicator const &comm) {
147 // Collect results
148 Z = mpi::all_reduce(Z, comm);
149 M3xph_tau_ = mpi::all_reduce(M3xph_tau_, comm);
150 M3xph_delta_ = mpi::all_reduce(M3xph_delta_, comm);
151
152 // Normalize
153 int n = params.n_tau_M3 - 1;
154 double dtau = params.beta / n;
155 M3xph_tau_ = M3xph_tau_ / (Z * dtau * dtau);
156
157 int n_del = params.n_tau - 1;
158 double dtau_del = params.beta / n_del;
159 M3xph_delta_ = M3xph_delta_ / (Z * dtau_del);
160
161 // Account for edge bins beeing smaller
162 auto _ = all_t{};
163 for (auto [M, M_del] : zip(M3xph_tau_, M3xph_delta_)) {
164 M[0, _] *= 2.0;
165 M[_, 0] *= 2.0;
166 M[n, _] *= 2.0;
167 M[_, n] *= 2.0;
168 M_del[0] *= 2.0;
169 M_del[n_del] *= 2.0;
170 }
171 }
172
173} // namespace triqs_ctint::measures
void accumulate(mc_weight_t sign)
Accumulate M_tau using binning.
Definition M3xph_tau.cpp:28
void collect_results(mpi::communicator const &comm)
Collect results and normalize.