TRIQS/triqs_ctseg 4.0.0
A TRIQS application
Loading...
Searching...
No Matches
work_data.cpp
1// Copyright (c) 2022--present, The Simons Foundation
2// Copyright (c) 2022--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 "work_data.hpp"
8#include <algorithm>
9#include <cmath>
10#include <complex>
11#include <nda/basic_functions.hpp>
12#include <nda/traits.hpp>
13#include <triqs/gfs/functions/functions2.hpp>
14#include <triqs/operators/util/extractors.hpp>
15#include <triqs/utility/exceptions.hpp>
16#include "logs.hpp"
17#include "spdlog/common.h"
18#include "spdlog/spdlog.h"
19#include <fmt/ostream.h>
20
21using namespace triqs::operators::utils;
22
23namespace triqs_ctseg {
24
25 // Work data constructor
26 work_data_t::work_data_t(params_t const &p, inputs_t const &inputs, mpi::communicator c) {
27
28 // Set logger level
29 spdlog::set_pattern("%v");
30 spdlog::set_level(spdlog::level::info);
31 if constexpr (print_logs) spdlog::set_level(spdlog::level::debug);
32
33 // Copy data from inputs
34 double beta = p.beta;
35 gf_struct = p.gf_struct;
36
37 // Count colors
38 n_color = 0;
39 for (auto const &[bl_name, bl_size] : gf_struct) { n_color += bl_size; }
40
41 // Compute color/block conversion tables
42 for (auto const &color : range(n_color)) {
43 block_number.push_back(find_block_number(color));
44 index_in_block.push_back(find_index_in_block(color));
45 }
46
47 // Print block/index/color correspondence
48 if (c.rank() == 0) {
49 spdlog::info("\n");
50 for (auto const &color : range(n_color)) {
51 spdlog::info("Block: {} Index: {} Color: {}", gf_struct[block_number[color]].first, index_in_block[color],
52 color);
53 }
54 }
55
56 // Extract color-dependent chemical potential from the local Hamiltonian operator.
57 // h_loc0 coefficients are stored as real_or_complex and are flagged complex whenever
58 // h_loc0 is built from complex matrices (e.g. a downfolded DFT Hamiltonian), even when
59 // the imaginary part is numerical noise. CT-SEG (segment picture) uses a real local
60 // Hamiltonian, so set the imaginary part of the diagonal to zero when it is below
61 // imag_threshold and error out otherwise (same convention as cthyb).
62 mu = nda::zeros<double>(n_color);
63 auto h_loc0 = dict_to_matrix<std::complex<double>>(extract_h_dict(p.h_loc0), p.gf_struct);
64
65 double max_imag = 0.0;
66 for (auto const &col : range(n_color)) max_imag = std::max(max_imag, std::abs(h_loc0(col, col).imag()));
67 if (max_imag > p.imag_threshold)
68 TRIQS_RUNTIME_ERROR << "Largest imaginary element of the h_loc0 diagonal: " << max_imag
69 << ", is larger than the set parameter imag_threshold " << p.imag_threshold;
70 for (auto const &col : range(n_color)) mu(col) = -h_loc0(col, col).real();
71
72 // .............. Interactions .................
73 // Extract the U from the operator
74 auto U_full = dict_to_matrix(extract_U_dict2(p.h_int), p.gf_struct);
75 U = nda::matrix<double>{real(U_full)};
76 // We ensure that U(a, a) is 0, which must be true
77 for (int a = 0; a < U.extent(0); ++a)
78 ALWAYS_EXPECTS((abs(U(a, a)) < 1.e-15), "Error. A diagonal element of the interaction matrix is not 0.");
79
80 // Report
81 if (c.rank() == 0) {
82 spdlog::info("\n Interaction matrix: U = {} \n", fmt::streamed(U));
83 spdlog::info("Orbital energies: mu - eps = {} \n", fmt::streamed(mu));
84 }
85
86 // Dynamical interactions: convert Block2Gf to matrix Gf of size n_colors
87 D0t = gf<imtime>({beta, Boson, p.n_tau_bosonic}, {n_color, n_color});
88 for (int c1 : range(n_color)) {
89 for (int c2 : range(n_color)) {
90 D0t.data()(range::all, c1, c2) =
91 inputs.D0t(block_number[c1], block_number[c2]).data()(range::all, index_in_block[c1], index_in_block[c2]);
92 }
93 }
94 // Symetrize
95 for (auto t : D0t.mesh()) D0t[t] = 0.5 * make_regular(D0t[t] + transpose(D0t[t]));
96
97 // Do we have D(tau) and Jperp(tau)? Yes, unless the data is 0
98 has_Dt = max_element(abs(D0t.data())) > 1.e-13;
99 has_Jperp = max_element(abs(inputs.Jperpt.data())) > 1.e-13;
100
101 // Check: no Jperp implementation for more than 2 colors
102 if (n_color != 2) {
103 ALWAYS_EXPECTS((not has_Jperp), "Error : has_jperp is true and we have {} colors instead of 2", n_color);
104 }
105
106 // For numerical integration of the D0 and Jperp
107 auto ramp = nda::zeros<double>(p.n_tau_bosonic);
108 for (auto n : range(p.n_tau_bosonic)) { ramp(n) = n * beta / (p.n_tau_bosonic - 1); }
109
110 // Dynamical interactions
111 if (has_Dt) {
112 // Compute interaction kernels K(tau), K'(tau) by integrating D(tau)
113 K = gf<imtime>({beta, Boson, p.n_tau_bosonic}, {n_color, n_color});
114 Kprime = K;
115 for (auto c1 : range(n_color)) {
116 for (auto c2 : range(n_color)) {
117 nda::array<dcomplex, 1> D_data = D0t.data()(range::all, c1, c2);
118 auto first_integral = nda::zeros<dcomplex>(p.n_tau_bosonic);
119 auto second_integral = nda::zeros<dcomplex>(p.n_tau_bosonic);
120 // Trapezoidal integration
121 for (int i = 1; i < D_data.size(); ++i) {
122 first_integral(i) = first_integral(i - 1) + (D_data(i) + D_data(i - 1)) / 2;
123 second_integral(i) = second_integral(i - 1) + (first_integral(i) + first_integral(i - 1)) / 2;
124 }
125 // Normalize by bin size
126 first_integral *= beta / (p.n_tau_bosonic - 1);
127 second_integral *= (beta / (p.n_tau_bosonic - 1)) * (beta / (p.n_tau_bosonic - 1));
128 // Enforce K(0) = K(beta) = 0
129 Kprime.data()(range::all, c1, c2) = first_integral - second_integral(p.n_tau_bosonic - 1) / beta;
130 K.data()(range::all, c1, c2) = second_integral - ramp * second_integral(p.n_tau_bosonic - 1) / beta;
131 // Renormalize U and mu
132 if (c1 != c2) U(c1, c2) -= real(2 * Kprime.data()(0, c1, c2));
133 }
134 mu(c1) += real(Kprime.data()(0, c1, c1));
135 }
136 if (c.rank() == 0) {
137 spdlog::info("\n Renormalized interaction matrix: U = {} \n", fmt::streamed(U));
138 spdlog::info("Renormalized orbital energies: mu - eps = {} \n", fmt::streamed(mu));
139 }
140 }
141
142 // Jperp interactions
143 if (has_Jperp) {
144 Jperp = inputs.Jperpt;
145 if (not has_Dt)
146 rot_inv = false;
147 else {
148 Kprime_spin = gf<imtime>({beta, Boson, p.n_tau_bosonic}, {n_color, n_color}); // used in computation of F(tau)
149 // Integrate Jperp to obtain the S_z.S_z part of K'(tau) (called Kprime_spin)
150 auto Kprime_J = Jperp;
151 nda::array<dcomplex, 1> J_data = Jperp.data()(range::all, 0, 0);
152 auto first_integral = nda::zeros<dcomplex>(p.n_tau_bosonic);
153 // Trapezoidal integration
154 for (int i = 1; i < J_data.size(); ++i) {
155 first_integral(i) = first_integral(i - 1) + (J_data(i) + J_data(i - 1)) / 2;
156 }
157 // Noramlize by bin size
158 first_integral *= beta / (p.n_tau_bosonic - 1);
159 // Enforce Kprime_J(beta/2) = 0
160 Kprime_J.data()(range::all, 0, 0) = first_integral - first_integral((p.n_tau_bosonic - 1) / 2);
161 // Kprime_spin = +/- Kprime_J depending on color
162 for (auto c1 : range(n_color)) {
163 for (auto c2 : range(n_color)) {
164 Kprime_spin.data()(range::all, c1, c2) = (c1 == c2 ? 1 : -1) * Kprime_J.data()(range::all, 0, 0) / 4;
165 }
166 }
167 auto Kprime_0 = gf<imtime>({beta, Boson, p.n_tau_bosonic}, {n_color, n_color});
168 Kprime_0 = Kprime - Kprime_spin;
169 // The "remainder" Kprime_0 must be color-independent for there to be rotational invariance
170 if (max_element(abs(Kprime_0.data()(range::all, 0, 0) - Kprime_0.data()(range::all, 0, 1))) > 1.e-13)
171 rot_inv = false;
172 }
173 }
174
175 // Report
176 if (c.rank() == 0) {
177 spdlog::info("Dynamical interactions = {}, Jperp interactions = {} \n", has_Dt, has_Jperp);
178 if (p.measure_F_tau and !rot_inv)
179 spdlog::info("WARNING: Cannot measure F(tau) because spin-spin interaction is not rotationally invariant.");
180 }
181
182 // ................ Determinants .....................
183 // Is there a non-zero Delta(tau)?
184 for (auto const &bl : range(inputs.Delta.size())) {
185 if (max_element(abs(inputs.Delta[bl].data())) > 1.e-13) has_Delta = true;
186 // Report if Delta(tau) has imaginary part.
187 if (!is_gf_real(inputs.Delta[bl], 1e-10)) {
188 if (c.rank() == 0) {
189 spdlog::info("WARNING: The Delta(tau) block number {} is not real in tau space", bl);
190 spdlog::info("WARNING: max(Im[Delta(tau)]) = {}", max_element(abs(imag(inputs.Delta[bl].data()))));
191 spdlog::info("WARNING: Disregarding the imaginary component in the calculation.");
192 }
193 }
194 }
195 if (not has_Delta) {
196 ALWAYS_EXPECTS(has_Jperp, "Error : both Jperp(tau) and Delta(tau) are 0: there is nothing to expand.");
197 if (c.rank() == 0) { spdlog::info("Delta(tau) is 0, running only spin moves."); }
198 }
199
200 // Does gf_struct allow for off-diagonal Delta?
201 for (auto const &[s, l] : gf_struct) {
202 if (l > 1) offdiag_Delta = true;
203 }
204
205 // Take the real part of Delta(tau)
206 Delta = map([](gf_const_view<imtime> d) { return real(d); }, inputs.Delta);
207 dets.reserve(Delta.size());
208 for (auto const &bl : range(Delta.size())) {
209 // Construct the detmanip object for block bl
210 dets.emplace_back(Delta_block_adaptor{Delta[bl]}, p.det_init_size);
211 // Set parameters
212 dets.back().set_singular_threshold(p.det_singular_threshold);
213 dets.back().set_n_operations_before_check(p.det_n_operations_before_check);
214 dets.back().set_precision_warning(p.det_precision_warning);
215 dets.back().set_precision_error(p.det_precision_error);
216 }
217 } // work_data constructor
218
219 int work_data_t::block_to_color(int block, int idx) const {
220 std::vector<long> gf_block_size_partial_sum;
221 long acc = 0;
222 for (auto const &[s, l] : gf_struct) {
223 gf_block_size_partial_sum.push_back(acc);
224 acc += l;
225 }
226 return gf_block_size_partial_sum[block] + idx;
227 }
228
229 long work_data_t::find_block_number(int color) const {
230 long bl = 0;
231 long colors_so_far = 0;
232 for (auto const &[s, l] : gf_struct) {
233 colors_so_far += l;
234 if (color < colors_so_far) { return bl; }
235 bl++;
236 }
237 ALWAYS_EXPECTS((colors_so_far == n_color), "Error in color-to-block conversion.");
238 return 0;
239 }
240
241 long work_data_t::find_index_in_block(int color) const {
242 long colors_so_far = 0;
243 for (auto const &[s, l] : gf_struct) {
244 colors_so_far += l;
245 if (color < colors_so_far) { return color - (colors_so_far - l); }
246 }
247 ALWAYS_EXPECTS((colors_so_far == n_color), "Error in color-to-block conversion.");
248 return 0;
249 }
250
251 // Additional sign of the trace (computed from dets).
252 double trace_sign(work_data_t const &wdata) {
253 double sign = 1.0;
254 auto const &dets = wdata.dets;
255 // For every block, we compute the sign of the permutation that takes
256 // [(c c_dag) (c c_dag) (c c_dag) ...] with the cdag and c in increasing time order
257 // (the reference order of the det) to the decreasing-time-and-color-ordered list
258 // of operators (the order that makes the trace positive).
259 // This is equivalent to computing the sign of the permutation that takes
260 // [(c_dag c) (c_dag c) (c_dag c) ...] with the cdag and c in increasing time order
261 // to the increasing time-and-color-ordered list of operators.
262 for (auto bl : range(dets.size())) {
263 auto s = long(dets[bl].size());
264 auto n_colors_in_bl = wdata.gf_struct[bl].second;
265 std::vector<int> number_c_before(n_colors_in_bl, 0);
266 std::vector<int> number_cdag_before(n_colors_in_bl, 0);
267 if (s != 0) {
268 // We first compute the sign of the permutation that takes
269 // [(c_dag c) (c_dag c) (c_dag c) ...] with the c and c_dag time-ordered to
270 // [(c_dag c_dag ... cdag)(c c ... c)] with the c and c_dag time-ordered
271 if ((s * (s - 1) / 2) % 2 == 1) { sign *= -1; }
272 // We then compute the sign of the permutation that color-orders the c ...
273 for (int n = 0; n < s; ++n) {
274 auto c_color = dets[bl].get_y(n).second;
275 int n_higher_colors_before = 0;
276 for (int k = c_color + 1; k < n_colors_in_bl; k++) { n_higher_colors_before += number_c_before[k]; }
277 if (n_higher_colors_before % 2 == 1) sign *= -1;
278 number_c_before[c_color]++;
279 }
280 // ... the sign of the permutation that color-orders the c_dag ...
281 for (int n = 0; n < s; ++n) {
282 auto cdag_color = dets[bl].get_x(n).second;
283 int n_higher_colors_before = 0;
284 for (int k = cdag_color + 1; k < n_colors_in_bl; k++) n_higher_colors_before += number_cdag_before[k];
285 if (n_higher_colors_before % 2 == 1) sign *= -1;
286 number_cdag_before[cdag_color]++;
287 }
288 // ... and the sign of the permutation that assembles the operators by color.
289 int nb_transp = 0;
290 auto nb_ops_per_color = number_c_before;
291 for (int k = 0; k < n_colors_in_bl; ++k) {
292 for (int l = k + 1; l < n_colors_in_bl; ++l) { nb_transp += nb_ops_per_color[k] * nb_ops_per_color[l]; }
293 }
294 if (nb_transp % 2 == 1) sign *= -1;
295 // Finally, we compute the sign of the permutation that takes
296 // [Color 0 : (c_dag c_dag ... cdag)(c c ... c) ... Color n: (c_dag c_dag ... cdag)(c c ... c)]
297 // with the c and c_dag time-ordered within each color to the completely time-and-color-ordered
298 // list of operators. In practice, we compute the sign of the time ordering for each color,
299 // ignoring the other colors.
300 for (int k = 0; k < n_colors_in_bl; ++k) {
301 int cdag_to_jump = 0;
302 int idx_c = s - 1, idx_cdag = s - 1;
303 while (idx_c >= 0) {
304 auto color_c = dets[bl].get_y(idx_c).second;
305 auto time_c = dets[bl].get_y(idx_c).first;
306 if (color_c == k) {
307 bool keep_going = true;
308 while (keep_going and (idx_cdag >= 0)) {
309 auto color_cdag = dets[bl].get_x(idx_cdag).second;
310 auto time_cdag = dets[bl].get_x(idx_cdag).first;
311 keep_going = (color_cdag != k) or (time_cdag > time_c);
312 if (keep_going) {
313 idx_cdag--;
314 if (color_cdag == k) cdag_to_jump++;
315 }
316 } // loop over cdag
317 if (cdag_to_jump % 2 == 1) sign *= -1;
318 } // if color == k
319 idx_c--;
320 } // loop over c
321 } // loop over colors
322 } // if block not empty
323 } // loop over blocks
324 return sign;
325 } // sign computation
326
327 // Functions for checking if a time is already in det.
328 bool c_in_det(tau_t const &tau, det_t const &D) {
329 if (D.size() == 0) return false;
330 auto det_c_time = [&](long i) { return D.get_y(i).first; };
331 long det_index_c = lower_bound(det_c_time, D.size(), tau);
332 return (det_index_c >= D.size()) ? false : (det_c_time(det_index_c) == tau);
333 }
334
335 bool cdag_in_det(tau_t const &tau, det_t const &D) {
336 if (D.size() == 0) return false;
337 auto det_cdag_time = [&](long i) { return D.get_x(i).first; };
338 long det_index_cdag = lower_bound(det_cdag_time, D.size(), tau);
339 return (det_index_cdag >= D.size()) ? false : (det_cdag_time(det_index_cdag) == tau);
340 }
341
342} // namespace triqs_ctseg
A struct combining both constr_params_t and solve_params_t.
Definition params.hpp:187