TRIQS/triqs_ctseg 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
four_point.cpp
1// Copyright (c) 2024--present, The Simons Foundation
2// Copyright (c) 2024--present, Max Planck Institute for Polymer Research, Mainz, Germany
3// This file is part of TRIQS/ctseg and is licensed under the terms of GPLv3 or later.
4// SPDX-License-Identifier: GPL-3.0-or-later
5// See LICENSE in the root of this distribution for details.
6
7#include "./four_point.hpp"
8#include "../logs.hpp"
9
10namespace triqs_ctseg::measures {
11
12 four_point::four_point(params_t const &p, work_data_t const &wdata, configuration_t const &config, results_t &results)
13 : wdata{wdata}, config{config}, results{results} {
14
15 beta = p.beta;
16 n_w_bosonic = p.n_w_b_vertex;
17 n_w_fermionic = p.n_w_f_vertex;
18 measure_g2w = p.measure_g2w;
19 measure_g3w = p.measure_g3w;
20 mesh_bosonic = triqs::mesh::imfreq(beta, Boson , n_w_bosonic );
21 mesh_fermionic = triqs::mesh::imfreq(beta, Fermion, n_w_fermionic);
22
23 if (measure_g2w) g2w.resize(wdata.gf_struct.size());
24 if (measure_g3w) g3w.resize(wdata.gf_struct.size());
25 for (auto const &[bl1_idx, bl1] : itertools::enumerate(wdata.gf_struct)) {
26 auto &[bl1_name, bl1_size] = bl1;
27 block_names.push_back(bl1_name);
28 if (measure_g2w) g2w[bl1_idx].resize(wdata.gf_struct.size());
29 if (measure_g3w) g3w[bl1_idx].resize(wdata.gf_struct.size());
30 for (auto const &[bl2_idx, bl2] : itertools::enumerate(wdata.gf_struct)) {
31 auto &[bl2_name, bl2_size] = bl2;
32 if (measure_g2w) {
33 g2w[bl1_idx][bl2_idx] = gf<prod<imfreq, imfreq>, tensor_valued<4>>(
34 { mesh_bosonic , mesh_fermionic },
35 make_shape(bl1_size, bl1_size, bl2_size, bl2_size));
36 g2w[bl1_idx][bl2_idx]() = 0;
37 }
38 if (measure_g3w) {
39 g3w[bl1_idx][bl2_idx] = gf<prod<imfreq, imfreq, imfreq>, tensor_valued<4>>(
40 { mesh_bosonic , mesh_fermionic , mesh_fermionic },
41 make_shape(bl1_size, bl1_size, bl2_size, bl2_size));
42 g3w[bl1_idx][bl2_idx]() = 0;
43 }
44 }
45 }
46
47 }
48
49 // -------------------------------------
50
51 void four_point::accumulate(double s) {
52
53 LOG("\n ============ MEASURE FOUR-POINT CORRELATION FUNCTIONS ============ \n");
54
56
78
79 Z += s;
80
81 auto Mw = compute_Mw();
82 auto const &nb_blocks = wdata.gf_struct.size();
83
84 if (measure_g2w) {
85 auto nw = compute_nw();
86 for (auto const &b1 : range(nb_blocks)) {
87 for (auto const &b2 : range(nb_blocks)) {
88 auto const &block_shape = g2w[b1][b2].target_shape();
89 for (auto const &c : range(block_shape[2])) {
90 auto col = wdata.block_to_color(b2, c);
91 for (auto const &a : range(block_shape[0])) {
92 for (auto const &b : range(block_shape[1])) {
93 for (auto const &w : mesh_bosonic) {
94 for (auto const &nu1 : mesh_fermionic) {
95 g2w[b1][b2][w, nu1](a, b, c, c) -= s * Mw[b1][-nu1, nu1 + w](a, b) * nw[col][-w];
96 } // nu1
97 } // w
98 } // b
99 } // a
100 } // c
101 } // b2
102 } // b1
103 } // measure_g2w
104
105 if (measure_g3w) {
106 for (auto const &b1 : range(nb_blocks)) {
107 for (auto const &b2 : range(nb_blocks)) {
108 auto const &block_shape = g3w[b1][b2].target_shape();
109 for (auto const &a : range(block_shape[0])) {
110 for (auto const &b : range(block_shape[1])) {
111 for (auto const &c : range(block_shape[2])) {
112 for (auto const &d : range(block_shape[3])) {
113 for (auto const &nu1 : mesh_fermionic) {
114 for (auto const &nu2 : mesh_fermionic) {
115 for (auto const &w : mesh_bosonic) {
116 g3w[b1][b2][w, nu1, nu2](a, b, c, d) += s *
117 Mw[b1][-nu1, nu1 + w](a, b) * Mw[b2][-nu2 - w, nu2.value()](c, d);
118 if (b1 == b2)
119 g3w[b1][b2][w, nu1, nu2](a, b, c, d) -= s *
120 Mw[b1][-nu1, nu2.value()](a, d) * Mw[b2][-nu2 - w, nu1 + w](c, b);
121 } // w
122 } // nu2
123 } // nu1
124 } // d
125 } // c
126 } // b
127 } // a
128 } // b2
129 } // b1
130 } // measure_g3w
131
132 }
133
134 // -------------------------------------
135
136 void four_point::collect_results(mpi::communicator const &c) {
137
138 Z = mpi::all_reduce(Z, c);
139
140 if (measure_g2w) g2w = mpi::all_reduce(g2w, c);
141 if (measure_g3w) g3w = mpi::all_reduce(g3w, c);
142 for (auto const &b1 : range(wdata.gf_struct.size())) {
143 for (auto const &b2 : range(wdata.gf_struct.size())) {
144 if (measure_g2w) g2w[b1][b2] = g2w[b1][b2] / (Z * beta);
145 if (measure_g3w) g3w[b1][b2] = g3w[b1][b2] / (Z * beta);
146 }
147 }
148
149 if (measure_g2w) {
150 g2w_block = make_block2_gf(block_names, block_names, g2w);
151 results.g2w = std::move(g2w_block);
152 }
153 if (measure_g3w) {
154 g3w_block = make_block2_gf(block_names, block_names, g3w);
155 results.g3w = std::move(g3w_block);
156 }
157
158 }
159
160 // -------------------------------------
161
162 block_gf<prod<imfreq, imfreq>> four_point::compute_Mw() {
163
164 // Mw[bl][nu1, nu2](a, b) = \int d \tau_a \, d \tau_b e^{i(\nu_1 \tau_a + \nu_2 \tau_b)} M[bl](\tau_a, \tau_b)
165 // The time tau_a (tau_b) corresponds to a c_dag (c) operator.
166
167 int n_w_aux = n_w_fermionic + n_w_bosonic - 1;
168 auto aux_mesh = triqs::mesh::imfreq(beta, Fermion, n_w_aux);
169 auto Mw = block_gf(prod(aux_mesh, aux_mesh), wdata.gf_struct);
170 Mw() = 0;
171
172 auto w0 = aux_mesh[0].value();
173 auto dw = aux_mesh[1].value() - aux_mesh[0].value();
174
175 for (auto const &[bl, det] : itertools::enumerate(wdata.dets)) {
176 long N = det.size();
177 for (long i : range(N)) {
178 auto [tau_i, a] = det.get_x(i);
179 for (long j : range(N)) {
180 auto [tau_j, b] = det.get_y(j);
181 auto Mij = det.inverse_matrix(j, i); // The row index is i and the column index is j.
182 auto exp_i = std::exp(w0 * double(tau_i));
183 auto exp_i_dw = std::exp(dw * double(tau_i));
184 auto exp_j0 = std::exp(w0 * double(tau_j));
185 auto exp_j_dw = std::exp(dw * double(tau_j));
186 auto exp_j = exp_j0;
187 for (auto const &nu1 : aux_mesh) {
188 exp_j = exp_j0;
189 auto expMij = exp_i * Mij;
190 for (auto const &nu2 : aux_mesh) {
191 Mw[bl][nu1, nu2](a, b) += expMij * exp_j;
192 exp_j = exp_j * exp_j_dw;
193 } // nu2
194 exp_i = exp_i * exp_i_dw;
195 } // nu1
196 } // tau_j
197 } // tau_i
198 } // bl
199 return Mw;
200
201 }
202
203 // -------------------------------------
204
205 std::vector<gf<imfreq, scalar_valued>> four_point::compute_nw() {
206
207 /*
208 $$ n(col)[\omega] = \sum_{\text{segments}}
209 \int_{\tau_\mathrm{start}}^{\tau_\mathrm{end}}e^{i\omega\tau}\mathrm{d}\tau $$
210 */
211
212 std::vector<gf<imfreq, scalar_valued>> nw;
213 nw.resize(wdata.n_color);
214 for (auto const &c : range(wdata.n_color)) {
215 nw[c] = gf<imfreq, scalar_valued>(mesh_bosonic);
216 nw[c]() = 0;
217 nw[c][0] = -beta; // Take care of the convention: nw[omega = 0] = density - 1.
218
219 for (auto const &s: config.seglists[c]) {
220
221 double tau_c = double(s.tau_c);
222 double tau_cdag = double(s.tau_cdag);
223
224 // Zero frequency: Add up the all the segment lengths
225 nw[c][0] += double(s.length());
226
227 // Compute remaining frequencies
228 for (auto const &w : mesh_bosonic) {
229 if (w.n == 0) continue;
230 nw[c][w] += (std::exp(w.value() * tau_c) - std::exp(w.value() * tau_cdag)) / w.value();
231 } // w
232
233 } // s
234 } // c
235 return nw;
236
237 }
238
239} // namespace triqs_ctseg::measures