Skip to content

Commit c76747f

Browse files
committed
add four-point vertex measurement
1 parent e63249e commit c76747f

File tree

9 files changed

+363
-0
lines changed

9 files changed

+363
-0
lines changed

c++/triqs_ctseg/measures.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@
2525
#include "./measures/average_sign.hpp"
2626
#include "./measures/pert_order.hpp"
2727
#include "./measures/state_hist.hpp"
28+
#include "./measures/four_point.hpp"
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
// Copyright (c) 2024 Simons Foundation
2+
//
3+
// This program is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU General Public License as published by
5+
// the Free Software Foundation, either version 3 of the License, or
6+
// (at your option) any later version.
7+
//
8+
// This program is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU General Public License for more details.
12+
//
13+
// You may obtain a copy of the License at
14+
// https://www.gnu.org/licenses/gpl-3.0.txt
15+
//
16+
// Authors: Hao Lu
17+
18+
#include "./four_point.hpp"
19+
#include "../logs.hpp"
20+
21+
namespace triqs_ctseg::measures {
22+
23+
four_point::four_point(params_t const &p, work_data_t const &wdata, configuration_t const &config, results_t &results)
24+
: wdata{wdata}, config{config}, results{results} {
25+
26+
beta = p.beta;
27+
measure_g3w = p.measure_g3w;
28+
measure_f3w = p.measure_f3w;
29+
30+
auto g3w_vec = [&]() {
31+
std::vector<gf<prod<imfreq, imfreq, imfreq>, tensor_valued<4>>> green_v;
32+
for (auto const &[bl1_name, bl1_size] : p.gf_struct)
33+
for (auto const &[bl2_name, bl2_size] : p.gf_struct)
34+
green_v.emplace_back(gf<prod<imfreq, imfreq, imfreq>, tensor_valued<4>>(
35+
{{beta, Fermion, p.n_iw_chi4_f, imfreq::option::all_frequencies},
36+
{beta, Fermion, p.n_iw_chi4_f, imfreq::option::all_frequencies},
37+
{beta, Boson, p.n_iw_chi4_b, imfreq::option::positive_frequencies_only}},
38+
make_shape(bl1_size, bl1_size, bl2_size, bl2_size)));
39+
return green_v;
40+
};
41+
42+
std::vector<std::string> block_names;
43+
for (auto const &[bl_name, bl_size] : p.gf_struct) block_names.push_back(bl_name);
44+
auto bosonic_block_names = std::vector<std::string>{};
45+
for (auto const &str1 : block_names)
46+
for (auto const &str2 : block_names)
47+
bosonic_block_names.push_back(str1 + "|" + str2);
48+
49+
g3w = make_block_gf<prod<imfreq, imfreq, imfreq>, tensor_valued<4>>(bosonic_block_names, g3w_vec());
50+
f3w = make_block_gf<prod<imfreq, imfreq, imfreq>, tensor_valued<4>>(bosonic_block_names, g3w_vec());
51+
52+
for (auto &g : g3w)
53+
g() = 0;
54+
for (auto &f : f3w)
55+
f() = 0;
56+
57+
LOG("\n ====================== COMPUTING M-MATRIX ====================== \n");
58+
if (measure_g3w) Mw_vector = compute_Mw(false);
59+
if (measure_f3w) nMw_vector = compute_Mw(true);
60+
61+
n_w_fermionic = std::get<0>(g3w[0].mesh().components()).last_index() + 1;
62+
n_w_bosonic = std::get<2>(g3w[0].mesh().components()).last_index() + 1;
63+
64+
w_ini = (2 * (-n_w_fermionic) + 1) * M_PI / beta;
65+
w_inc = 2 * M_PI / beta;
66+
67+
}
68+
69+
// -------------------------------------
70+
71+
void four_point::accumulate(double s) {
72+
73+
LOG("\n ============ MEASURE FOUR-POINT CORRELATION FUNCTION ============ \n");
74+
75+
/// Measure the four-point correlation function
76+
/**
77+
*The four-point correlation function is defined as:
78+
*
79+
*$$\chi^{\sigma\sigma'}_{abcd}(i\omega, i\omega',i\Omega) = G^{2,\sigma,
80+
*\sigma'}_{abcd}(i\omega, i\omega',i\Omega) = \langle c_{a\sigma}(i\omega)
81+
*c^\dagger_{b\sigma}(i\omega+i\Omega) c_{c\sigma'}(i\omega'+i\Omega)
82+
*c^\dagger_{d\sigma'}(i\omega') \rangle$$
83+
*
84+
* Its improved estimator is the Fourier transform of
85+
*
86+
*$$F^{3,\sigma\sigma'}_{abcd}(\tau,\tau',\tau'') = \int \mathrm{d}\bar{\tau}
87+
*\sum_{e\bar{\sigma}} \mathcal{U}^{\sigma\bar{\sigma}}_{ae}(\bar{\tau}-\tau)
88+
*\langle c_{a\sigma}(\tau) c^\dagger_{b\sigma}(\tau') c_{c\sigma'}(\tau'')
89+
*c^\dagger_{d\sigma'}(0) \rangle$$
90+
*
91+
* The vertex corresponding to this correlation function is evaluated separately.
92+
*/
93+
94+
Z += s;
95+
96+
if (measure_g3w) {
97+
for (long bl = 0; bl < g3w.size(); bl++) { // bl : 'upup', 'updn', ...
98+
long b1 = bl / wdata.gf_struct.size();
99+
long b2 = bl % wdata.gf_struct.size();
100+
for (int a = 0; a < g3w[bl].target_shape()[0]; a++) {
101+
for (int b = 0; b < g3w[bl].target_shape()[1]; b++) {
102+
for (int c = 0; c < g3w[bl].target_shape()[2]; c++) {
103+
for (int d = 0; d < g3w[bl].target_shape()[3]; d++) {
104+
for (int n1 = -n_w_fermionic; n1 < n_w_fermionic; n1++) {
105+
for (int n4 = -n_w_fermionic; n4 < n_w_fermionic; n4++) {
106+
for (int m = 0; m < n_w_bosonic; m++) {
107+
int n2 = n1 + m;
108+
int n3 = n4 + m;
109+
g3w[bl](n1, n4, m)(a, b, c, d) += s * Mw(b1, a, b, n1, n2) * Mw(b2, c, d, n3, n4);
110+
if (b1 == b2)
111+
g3w[bl](n1, n4, m)(a, b, c, d) -= s * Mw(b1, a, d, n1, n4) * Mw(b2, c, b, n3, n2);
112+
} // m
113+
} // n4
114+
} // n1
115+
} // d
116+
} // c
117+
} // b
118+
} // a
119+
} // bl
120+
} // measure_g3w
121+
122+
if (measure_f3w) {
123+
for (long bl = 0; bl < f3w.size(); bl++) { // bl : 'upup', 'updn', ...
124+
long b1 = bl / wdata.gf_struct.size();
125+
long b2 = bl % wdata.gf_struct.size();
126+
for (int a = 0; a < f3w[bl].target_shape()[0]; a++) {
127+
for (int b = 0; b < f3w[bl].target_shape()[1]; b++) {
128+
for (int c = 0; c < f3w[bl].target_shape()[2]; c++) {
129+
for (int d = 0; d < f3w[bl].target_shape()[3]; d++) {
130+
for (int n1 = -n_w_fermionic; n1 < n_w_fermionic; n1++) {
131+
for (int n4 = -n_w_fermionic; n4 < n_w_fermionic; n4++) {
132+
for (int m = 0; m < n_w_bosonic; m++) {
133+
int n2 = n1 + m;
134+
int n3 = n4 + m;
135+
f3w[bl](n1, n4, m)(a, b, c, d) += s * nMw(b1, a, b, n1, n2) * Mw(b2, c, d, n3, n4);
136+
if (b1 == b2)
137+
f3w[bl](n1, n4, m)(a, b, c, d) -= s * nMw(b1, a, d, n1, n4) * Mw(b2, c, b, n3, n2);
138+
} // m
139+
} // n4
140+
} // n1
141+
} // d
142+
} // c
143+
} // b
144+
} // a
145+
} // bl
146+
}
147+
148+
}
149+
150+
// -------------------------------------
151+
152+
void four_point::collect_results(mpi::communicator const &c) {
153+
154+
Z = mpi::all_reduce(Z, c);
155+
if (measure_g3w) {
156+
g3w = mpi::all_reduce(g3w, c);
157+
g3w = g3w / (Z * beta);
158+
results.g3w = std::move(g3w);
159+
}
160+
if (measure_f3w) {
161+
f3w = mpi::all_reduce(f3w, c);
162+
f3w = f3w / (Z * beta);
163+
results.f3w = std::move(f3w);
164+
}
165+
166+
}
167+
168+
// -------------------------------------
169+
170+
double four_point::fprefactor(long const &block, std::pair<tau_t, long> const &y) {
171+
172+
int color = wdata.block_to_color(block, y.second);
173+
double I_tau = 0;
174+
for (auto const &[c, sl] : itertools::enumerate(config.seglists)) {
175+
auto ntau = n_tau(y.first, sl); // Density to the right of y.first in sl
176+
if (c != color) I_tau += wdata.U(c, color) * ntau;
177+
if (wdata.has_Dt) {
178+
I_tau -= K_overlap(sl, y.first, false, wdata.Kprime, c, color);
179+
if (c == color) I_tau -= 2 * real(wdata.Kprime(0)(c, c));
180+
}
181+
if (wdata.has_Jperp) {
182+
I_tau -= 4 * real(wdata.Kprime_spin(0)(c, color)) * ntau;
183+
I_tau -= 2 * K_overlap(sl, y.first, false, wdata.Kprime_spin, c, color);
184+
}
185+
}
186+
return I_tau;
187+
188+
}
189+
190+
// -------------------------------------
191+
192+
vector<array<dcomplex, 4>> four_point::compute_Mw(bool is_nMw) {
193+
int n_w_aux = 2 * n_w_fermionic + n_w_bosonic > 1 ? 2 * n_w_fermionic + n_w_bosonic - 1 : 0;
194+
vector<array<dcomplex, 4>> result;
195+
result.resize(wdata.gf_struct.size());
196+
197+
for (auto const &[bl, bl_pair] : itertools::enumerate(wdata.gf_struct)) {
198+
auto const &[bl_name, bl_size] = bl_pair;
199+
result[bl].resize(make_shape(bl_size, bl_size, n_w_aux, n_w_aux));
200+
result[bl]() = 0;
201+
202+
long N = wdata.dets[bl].size();
203+
y_exp_ini.resize(N);
204+
y_exp_inc.resize(N);
205+
x_exp_ini.resize(N);
206+
x_exp_inc.resize(N);
207+
y_inner_index.resize(N);
208+
x_inner_index.resize(N);
209+
210+
for (long id : range(N)) {
211+
auto y = wdata.dets[bl].get_y(id);
212+
auto x = wdata.dets[bl].get_x(id);
213+
y_exp_ini(id) = std::exp(dcomplex(0, w_ini * double(std::get<0>(y))));
214+
y_exp_inc(id) = std::exp(dcomplex(0, w_inc * double(std::get<0>(y))));
215+
x_exp_ini(id) = std::exp(dcomplex(0, -w_ini * double(std::get<0>(x))));
216+
x_exp_inc(id) = std::exp(dcomplex(0, -w_inc * double(std::get<0>(x))));
217+
y_inner_index(id) = std::get<1>(y);
218+
x_inner_index(id) = std::get<1>(x);
219+
}
220+
221+
for (long id_y : range(N)) {
222+
auto y = wdata.dets[bl].get_y(id_y);
223+
int yj = y_inner_index(id_y);
224+
double f_fact = is_nMw ? fprefactor(bl, y) : 1.0;
225+
226+
for (long id_x : range(N)) {
227+
int xi = x_inner_index(id_x);
228+
dcomplex y_exp = y_exp_ini(id_y);
229+
dcomplex x_exp = x_exp_ini(id_x);
230+
auto Minv = wdata.dets[bl].inverse_matrix(id_y, id_x);
231+
232+
for (int n_1 : range(n_w_aux)) {
233+
for (int n_2 : range(n_w_aux)) {
234+
auto val = Minv * y_exp * x_exp;
235+
result[bl](yj, xi, n_1, n_2) += val * f_fact;
236+
x_exp *= x_exp_inc(id_x);
237+
}
238+
x_exp = x_exp_ini(id_x);
239+
y_exp *= y_exp_inc(id_y);
240+
}
241+
}
242+
}
243+
}
244+
245+
return result;
246+
}
247+
248+
} // namespace triqs_ctseg::measures
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) 2024 Simons Foundation
2+
//
3+
// This program is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU General Public License as published by
5+
// the Free Software Foundation, either version 3 of the License, or
6+
// (at your option) any later version.
7+
//
8+
// This program is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU General Public License for more details.
12+
//
13+
// You may obtain a copy of the License at
14+
// https://www.gnu.org/licenses/gpl-3.0.txt
15+
//
16+
// Authors: Hao Lu
17+
18+
#pragma once
19+
#include "../configuration.hpp"
20+
#include "../work_data.hpp"
21+
#include "../results.hpp"
22+
23+
namespace triqs_ctseg::measures {
24+
25+
struct four_point {
26+
27+
work_data_t const &wdata;
28+
configuration_t const &config;
29+
results_t &results;
30+
double beta;
31+
double w_ini, w_inc;
32+
bool measure_g3w;
33+
bool measure_f3w;
34+
int n_w_fermionic;
35+
int n_w_bosonic;
36+
vector<array<dcomplex, 4>> Mw_vector;
37+
vector<array<dcomplex, 4>> nMw_vector;
38+
vector<dcomplex> y_exp_ini, y_exp_inc, x_exp_ini, x_exp_inc;
39+
vector<int> y_inner_index, x_inner_index;
40+
41+
block_gf<prod<imfreq, imfreq, imfreq>, tensor_valued<4>> g3w;
42+
block_gf<prod<imfreq, imfreq, imfreq>, tensor_valued<4>> f3w;
43+
44+
double Z = 0;
45+
46+
four_point(params_t const &params, work_data_t const &wdata, configuration_t const &config, results_t &results);
47+
48+
void accumulate(double s);
49+
void collect_results(mpi::communicator const &c);
50+
double fprefactor(long const &block, std::pair<tau_t, long> const &y);
51+
52+
vector<array<dcomplex, 4>> compute_Mw(bool is_nMw);
53+
54+
dcomplex Mw(long const &block, int const &i, int const &j, int const &n1, int const &n2) {
55+
return Mw_vector[block](i, j, n1 + n_w_fermionic, n2 + n_w_fermionic);
56+
}
57+
58+
dcomplex nMw(long const &block, int const &i, int const &j, int const &n1, int const &n2) {
59+
return nMw_vector[block](i, j, n1 + n_w_fermionic, n2 + n_w_fermionic);
60+
}
61+
62+
};
63+
64+
} // namespace triqs_ctseg::measures

c++/triqs_ctseg/params.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ namespace triqs_ctseg {
5151
h5_write(grp, "h_loc0", c.h_loc0);
5252
h5_write(grp, "n_tau_G", c.n_tau_G);
5353
h5_write(grp, "n_tau_chi2", c.n_tau_chi2);
54+
h5_write(grp, "n_iw_chi4_b", c.n_iw_chi4_b);
55+
h5_write(grp, "n_iw_chi4_f", c.n_iw_chi4_f);
5456
h5_write(grp, "n_cycles", c.n_cycles);
5557
h5_write(grp, "length_cycle", c.length_cycle);
5658
h5_write(grp, "n_warmup_cycles", c.n_warmup_cycles);
@@ -77,6 +79,8 @@ namespace triqs_ctseg {
7779
h5_write(grp, "measure_nn_tau", c.measure_nn_tau);
7880
h5_write(grp, "measure_Sperp_tau", c.measure_Sperp_tau);
7981
h5_write(grp, "measure_state_hist", c.measure_state_hist);
82+
h5_write(grp, "measure_g3w", c.measure_g3w);
83+
h5_write(grp, "measure_f3w", c.measure_f3w);
8084
h5_write(grp, "det_init_size", c.det_init_size);
8185
h5_write(grp, "det_n_operations_before_check", c.det_n_operations_before_check);
8286
h5_write(grp, "det_precision_warning", c.det_precision_warning);
@@ -121,6 +125,8 @@ namespace triqs_ctseg {
121125
h5_read(grp, "measure_nn_tau", c.measure_nn_tau);
122126
h5_read(grp, "measure_Sperp_tau", c.measure_Sperp_tau);
123127
h5_read(grp, "measure_state_hist", c.measure_state_hist);
128+
h5_read(grp, "measure_g3w", c.measure_g3w);
129+
h5_read(grp, "measure_f3w", c.measure_f3w);
124130
h5_read(grp, "det_init_size", c.det_init_size);
125131
h5_read(grp, "det_n_operations_before_check", c.det_n_operations_before_check);
126132
h5_read(grp, "det_precision_warning", c.det_precision_warning);

c++/triqs_ctseg/params.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ namespace triqs_ctseg {
5757
/// Number of points on which to measure 2-point functions (defaults to n_tau_bosonic)
5858
int n_tau_chi2 = 0;
5959

60+
/// Number of bosonic M-frequency points on which to measure 4-point functions
61+
int n_iw_chi4_b = 1001;
62+
63+
/// Number of fermionic M-frequency points on which to measure 4-point functions
64+
int n_iw_chi4_f = 1000;
65+
6066
/// Number of QMC cycles
6167
int n_cycles;
6268

@@ -139,6 +145,12 @@ namespace triqs_ctseg {
139145
/// Whether to measure state histograms (see measures/state_hist)
140146
bool measure_state_hist = false;
141147

148+
/// Whether to measure four-point correlation function (see measures/four_point)
149+
bool measure_g3w = false;
150+
151+
/// Whether to measure four-point correlation function improved estimator (see measures/four_point)
152+
bool measure_f3w = false;
153+
142154
// -------- Misc parameters --------------
143155

144156
/// The maximum size of the determinant matrix before a resize

c++/triqs_ctseg/results.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ namespace triqs_ctseg {
3535
h5_write(grp, "pert_order_Jperp", c.pert_order_Jperp);
3636
h5_write(grp, "average_order_Jperp", c.average_order_Jperp);
3737
h5_write(grp, "state_hist", c.state_hist);
38+
h5_write(grp, "g3w", c.g3w);
39+
h5_write(grp, "f3w", c.f3w);
3840
}
3941

4042
//------------------------------------
@@ -55,6 +57,8 @@ namespace triqs_ctseg {
5557
h5_read(grp, "pert_order_Jperp", c.pert_order_Jperp);
5658
h5_read(grp, "average_order_Jperp", c.average_order_Jperp);
5759
h5_read(grp, "state_hist", c.state_hist);
60+
h5_read(grp, "g3w", c.g3w);
61+
h5_read(grp, "f3w", c.f3w);
5862
}
5963

6064
} // namespace triqs_ctseg

0 commit comments

Comments
 (0)