|
7 | 7 | #include <nda/declarations.hpp> |
8 | 8 | #include <nda/mapped_functions.hxx> |
9 | 9 | #include <nda/nda.hpp> |
| 10 | +#include <triqs/mesh/dlr_imtime.hpp> |
10 | 11 | #include <triqs/mesh/imtime.hpp> |
11 | 12 | #include <triqs_xca/block_sparse.hpp> |
12 | 13 | #include <triqs_xca/block_sparse_backbone.hpp> |
@@ -78,6 +79,11 @@ void DiagramEvaluator::reset() { |
78 | 79 | } |
79 | 80 | } |
80 | 81 |
|
| 82 | +int DiagramEvaluator::get_num_backbones(nda::array<int, 2> topology) { |
| 83 | + Backbone backbone(topology, n); |
| 84 | + return static_cast<int>(backbone.fb_ix_max * backbone.o_ix_max * pow(hyb_poles.size(), backbone.m - 1)); |
| 85 | +} |
| 86 | + |
81 | 87 | void DiagramEvaluator::multiply_vertex_block(Backbone &backbone, int v_ix, nda::vector_const_view<int> ind_path, |
82 | 88 | nda::vector_const_view<int> block_dims) { |
83 | 89 | int o_ix = backbone.get_vertex_orb(v_ix); // orbital_index |
@@ -219,103 +225,119 @@ void DiagramEvaluator::multiply_prefactor(Backbone &backbone, nda::vector_const_ |
219 | 225 |
|
220 | 226 | BlockDiagOpFun &DiagramEvaluator::get_self_energy() { return Sigma; } |
221 | 227 |
|
222 | | -void DiagramEvaluator::eval_self_energy(Backbone &backbone) { |
223 | | - |
| 228 | +void DiagramEvaluator::find_path_self_energy(Backbone &backbone, int f_ix, nda::vector_view<int> ind_path, nda::vector_view<int> block_dims) { |
224 | 229 | int m = backbone.m; |
225 | | - nda::vector<int> ind_path(2 * m - 1); // tracks block indices of factors for computing a particular block of the self-energy |
226 | | - nda::vector<int> block_dims(2 * m + 1); // tracks the dimensions of the blocks in these factors |
227 | | - |
228 | | - // loop over all flat indices |
229 | | - int f_ix_max = static_cast<int>(backbone.fb_ix_max * backbone.o_ix_max * pow(hyb_poles.size(), m - 1)); |
230 | | - for (int f_ix = 0; f_ix < f_ix_max; f_ix++) { |
231 | | - backbone.set_flat_index(f_ix, hyb_poles); // set directions, pole indices, and orbital indices from a single integer index |
232 | | - /* Example of block_dims for m = 2 (OCA): each number is an index of block_dims, and each square represents a block of a matrix |
233 | | - 3 3 2 2 1 1 0 |
234 | | - -------- -------- -------- -------- -------- -------- -------- |
235 | | - 4 | F | 3 | G | 3 | F | 2 | G | 2 | F | 1 | G | 1 | F | |
236 | | - | | | | | | | | | | | | | | |
237 | | - -------- -------- -------- -------- -------- -------- -------- |
238 | | - */ |
239 | | - // ind_path can diverge at the vertex connected to vertex 0 |
240 | | - for (int b_ix = 0; b_ix < Gt.get_num_block_cols(); b_ix++) { // loop over blocks of self-energy |
241 | | - for (int p_kap = 0; p_kap < q; p_kap++) { // loop over symmetry sets on the zero vertex |
242 | | - bool path_all_nonzero = true; |
243 | | - int w = 0, ip = 0; // w loops over the vertices and edges, ip is the current block index |
244 | | - |
245 | | - if (backbone.has_vertex_dag(0)) { // if line is connected to zero is backward |
246 | | - ip = Fq.F_dags[p_kap].get_block_index(b_ix); |
247 | | - if (ip != -1) { |
248 | | - block_dims(0) = Fq.F_dags[p_kap].get_block_size(b_ix, 1); |
249 | | - block_dims(1) = Fq.F_dags[p_kap].get_block_size(b_ix, 0); |
250 | | - } else { |
251 | | - path_all_nonzero = false; |
252 | | - } |
| 230 | + backbone.set_flat_index(f_ix, hyb_poles); // set directions, pole indices, and orbital indices from a single integer index |
| 231 | + /* Example of block_dims for m = 2 (OCA): each number is an index of block_dims, and each square represents a block of a matrix |
| 232 | + 3 3 2 2 1 1 0 |
| 233 | + -------- -------- -------- -------- -------- -------- -------- |
| 234 | + 4 | F | 3 | G | 3 | F | 2 | G | 2 | F | 1 | G | 1 | F | |
| 235 | + | | | | | | | | | | | | | | |
| 236 | + -------- -------- -------- -------- -------- -------- -------- |
| 237 | + */ |
| 238 | + // ind_path can diverge at the vertex connected to vertex 0 |
| 239 | + for (int b_ix = 0; b_ix < Gt.get_num_block_cols(); b_ix++) { // loop over blocks of self-energy |
| 240 | + for (int p_kap = 0; p_kap < q; p_kap++) { // loop over symmetry sets on the zero vertex |
| 241 | + bool path_all_nonzero = true; |
| 242 | + int w = 0, ip = 0; // w loops over the vertices and edges, ip is the current block index |
| 243 | + |
| 244 | + if (backbone.has_vertex_dag(0)) { // if line is connected to zero is backward |
| 245 | + ip = Fq.F_dags[p_kap].get_block_index(b_ix); |
| 246 | + if (ip != -1) { |
| 247 | + block_dims(0) = Fq.F_dags[p_kap].get_block_size(b_ix, 1); |
| 248 | + block_dims(1) = Fq.F_dags[p_kap].get_block_size(b_ix, 0); |
253 | 249 | } else { |
254 | | - ip = Fq.Fs[p_kap].get_block_index(b_ix); |
255 | | - if (ip != -1) { |
256 | | - block_dims(0) = Fq.Fs[p_kap].get_block_size(b_ix, 1); |
257 | | - block_dims(1) = Fq.Fs[p_kap].get_block_size(b_ix, 0); |
258 | | - } else { |
259 | | - path_all_nonzero = false; |
260 | | - } |
| 250 | + path_all_nonzero = false; |
261 | 251 | } |
262 | | - // traverse factors in two halves |
263 | | - // first half: before vertex connected to zero |
264 | | - while (w < backbone.get_topology(0, 1) && path_all_nonzero) { // only continue if we have not hit a zero block |
265 | | - if (w != 0) { |
266 | | - ip = (backbone.has_vertex_dag(w)) ? Fq.F_dags[Fq.sym_set_labels(backbone.get_orb_ind(w))].get_block_index(ip) : |
267 | | - Fq.Fs[Fq.sym_set_labels(backbone.get_orb_ind(w))].get_block_index(ip); // update block index |
268 | | - } |
269 | | - if (ip == -1 || (w < 2 * m - 1 && Gt.get_zero_block_index(ip) == -1)) { // check if we hit a zero block in F or Gt |
270 | | - path_all_nonzero = false; |
271 | | - } else { // inner 'if' block unnecessary in first half |
272 | | - ind_path(w) = ip; // store the block index for the current vertex/edge, unless we are at the last vertex |
273 | | - if (w != backbone.get_topology(0, 1) - 1) { // if so, then orb_ind = -1, because w is the vertex connected to zero |
274 | | - block_dims(w + 2) = (backbone.has_vertex_dag(w + 1)) ? Fq.F_dags[Fq.sym_set_labels(backbone.get_orb_ind(w + 1))].get_block_size(ip, 0) : |
275 | | - Fq.Fs[Fq.sym_set_labels(backbone.get_orb_ind(w + 1))].get_block_size(ip, 0); |
276 | | - } |
| 252 | + } else { |
| 253 | + ip = Fq.Fs[p_kap].get_block_index(b_ix); |
| 254 | + if (ip != -1) { |
| 255 | + block_dims(0) = Fq.Fs[p_kap].get_block_size(b_ix, 1); |
| 256 | + block_dims(1) = Fq.Fs[p_kap].get_block_size(b_ix, 0); |
| 257 | + } else { |
| 258 | + path_all_nonzero = false; |
| 259 | + } |
| 260 | + } |
| 261 | + // traverse factors in two halves |
| 262 | + // first half: before vertex connected to zero |
| 263 | + while (w < backbone.get_topology(0, 1) && path_all_nonzero) { // only continue if we have not hit a zero block |
| 264 | + if (w != 0) { |
| 265 | + ip = (backbone.has_vertex_dag(w)) ? Fq.F_dags[Fq.sym_set_labels(backbone.get_orb_ind(w))].get_block_index(ip) : |
| 266 | + Fq.Fs[Fq.sym_set_labels(backbone.get_orb_ind(w))].get_block_index(ip); // update block index |
| 267 | + } |
| 268 | + if (ip == -1 || (w < 2 * m - 1 && Gt.get_zero_block_index(ip) == -1)) { // check if we hit a zero block in F or Gt |
| 269 | + path_all_nonzero = false; |
| 270 | + } else { // inner 'if' block unnecessary in first half |
| 271 | + ind_path(w) = ip; // store the block index for the current vertex/edge, unless we are at the last vertex |
| 272 | + if (w != backbone.get_topology(0, 1) - 1) { // if so, then orb_ind = -1, because w is the vertex connected to zero |
| 273 | + block_dims(w + 2) = (backbone.has_vertex_dag(w + 1)) ? Fq.F_dags[Fq.sym_set_labels(backbone.get_orb_ind(w + 1))].get_block_size(ip, 0) : |
| 274 | + Fq.Fs[Fq.sym_set_labels(backbone.get_orb_ind(w + 1))].get_block_size(ip, 0); |
277 | 275 | } |
278 | | - w += 1; |
279 | 276 | } |
| 277 | + w += 1; |
| 278 | + } |
280 | 279 |
|
281 | | - int ip1 = ip; |
282 | | - // second half |
283 | | - if (path_all_nonzero) { |
284 | | - for (int p_mu = 0; p_mu < q; p_mu++) { |
285 | | - bool fork_all_nonzero = true; |
286 | | - w = backbone.get_topology(0, 1); // reset w to the vertex connected to vertex 0 |
287 | | - // save block_dims(backbone.get_topology(0, 1) + 1) |
288 | | - block_dims(w + 1) = (backbone.has_vertex_dag(w)) ? Fq.F_dags[p_mu].get_block_size(ip1, 0) : Fq.Fs[p_mu].get_block_size(ip1, 0); |
289 | | - ip = (backbone.has_vertex_dag(w)) ? Fq.F_dags[p_mu].get_block_index(ip1) : |
290 | | - Fq.Fs[p_mu].get_block_index(ip1); // update block index for the vertex connected to zero |
291 | | - while (w < 2 * m && fork_all_nonzero) { |
292 | | - if (w != backbone.get_topology(0, 1)) { |
293 | | - ip = (backbone.has_vertex_dag(w)) ? Fq.F_dags[Fq.sym_set_labels(backbone.get_orb_ind(w))].get_block_index(ip) : |
294 | | - Fq.Fs[Fq.sym_set_labels(backbone.get_orb_ind(w))].get_block_index(ip); // update block index |
295 | | - } |
296 | | - if (ip == -1 || (w < 2 * m - 1 && Gt.get_zero_block_index(ip) == -1)) { // check if we hit a zero block in F or Gt |
297 | | - fork_all_nonzero = false; |
298 | | - } else { |
299 | | - if (w < 2 * m - 1) { // only store the block index if we are not at the last vertex |
300 | | - ind_path(w) = ip; // store the block index for the current vertex/edge |
301 | | - block_dims(w + 2) = (backbone.has_vertex_dag(w + 1)) ? |
302 | | - Fq.F_dags[Fq.sym_set_labels(backbone.get_orb_ind(w + 1))].get_block_size(ip, 0) : |
303 | | - Fq.Fs[Fq.sym_set_labels(backbone.get_orb_ind(w + 1))].get_block_size(ip, 0); |
304 | | - } |
305 | | - } |
306 | | - w += 1; |
| 280 | + int ip1 = ip; |
| 281 | + // second half |
| 282 | + if (path_all_nonzero) { |
| 283 | + for (int p_mu = 0; p_mu < q; p_mu++) { |
| 284 | + bool fork_all_nonzero = true; |
| 285 | + w = backbone.get_topology(0, 1); // reset w to the vertex connected to vertex 0 |
| 286 | + // save block_dims(backbone.get_topology(0, 1) + 1) |
| 287 | + block_dims(w + 1) = (backbone.has_vertex_dag(w)) ? Fq.F_dags[p_mu].get_block_size(ip1, 0) : Fq.Fs[p_mu].get_block_size(ip1, 0); |
| 288 | + ip = (backbone.has_vertex_dag(w)) ? Fq.F_dags[p_mu].get_block_index(ip1) : |
| 289 | + Fq.Fs[p_mu].get_block_index(ip1); // update block index for the vertex connected to zero |
| 290 | + while (w < 2 * m && fork_all_nonzero) { |
| 291 | + if (w != backbone.get_topology(0, 1)) { |
| 292 | + ip = (backbone.has_vertex_dag(w)) ? Fq.F_dags[Fq.sym_set_labels(backbone.get_orb_ind(w))].get_block_index(ip) : |
| 293 | + Fq.Fs[Fq.sym_set_labels(backbone.get_orb_ind(w))].get_block_index(ip); // update block index |
307 | 294 | } |
308 | | - if (fork_all_nonzero) { |
309 | | - // evaluate the diagram with these directions, poles, and orbital indices |
310 | | - // b_ix is the block index for the first edge |
311 | | - eval_self_energy_fixed_indices(backbone, b_ix, p_kap, p_mu, ind_path, block_dims); |
| 295 | + if (ip == -1 || (w < 2 * m - 1 && Gt.get_zero_block_index(ip) == -1)) { // check if we hit a zero block in F or Gt |
| 296 | + fork_all_nonzero = false; |
| 297 | + } else { |
| 298 | + if (w < 2 * m - 1) { // only store the block index if we are not at the last vertex |
| 299 | + ind_path(w) = ip; // store the block index for the current vertex/edge |
| 300 | + block_dims(w + 2) = (backbone.has_vertex_dag(w + 1)) ? |
| 301 | + Fq.F_dags[Fq.sym_set_labels(backbone.get_orb_ind(w + 1))].get_block_size(ip, 0) : |
| 302 | + Fq.Fs[Fq.sym_set_labels(backbone.get_orb_ind(w + 1))].get_block_size(ip, 0); |
| 303 | + } |
312 | 304 | } |
| 305 | + w += 1; |
| 306 | + } |
| 307 | + if (fork_all_nonzero) { |
| 308 | + // evaluate the diagram with these directions, poles, and orbital indices |
| 309 | + // b_ix is the block index for the first edge |
| 310 | + eval_self_energy_fixed_indices(backbone, b_ix, p_kap, p_mu, ind_path, block_dims); |
313 | 311 | } |
314 | 312 | } |
315 | 313 | } |
316 | 314 | } |
317 | | - backbone.reset_all_inds(); // reset directions, pole indices, and orbital indices for the next iteration |
318 | 315 | } |
| 316 | + backbone.reset_all_inds(); // reset directions, pole indices, and orbital indices for the next iteration |
| 317 | +} |
| 318 | + |
| 319 | +void DiagramEvaluator::eval_self_energy(Backbone &backbone, int f_ix) { |
| 320 | + int m = backbone.m; |
| 321 | + int f_ix_max = static_cast<int>(backbone.fb_ix_max * backbone.o_ix_max * pow(hyb_poles.size(), m - 1)); |
| 322 | + if (f_ix < 0 || f_ix >= f_ix_max) { |
| 323 | + throw std::runtime_error("DiagramEvaluator::eval_self_energy: f_ix out of range"); |
| 324 | + } |
| 325 | + |
| 326 | + nda::vector<int> ind_path(2 * m - 1); // tracks block indices of factors for computing a particular block of the self-energy |
| 327 | + nda::vector<int> block_dims(2 * m + 1); // tracks the dimensions of the blocks in these factors |
| 328 | + |
| 329 | + find_path_self_energy(backbone, f_ix, ind_path, block_dims); |
| 330 | + Sigma.set_zero_block_indices(); // set zero_block_indices according to current blocks |
| 331 | +} |
| 332 | + |
| 333 | +void DiagramEvaluator::eval_self_energy(Backbone &backbone) { |
| 334 | + int m = backbone.m; |
| 335 | + nda::vector<int> ind_path(2 * m - 1); // tracks block indices of factors for computing a particular block of the self-energy |
| 336 | + nda::vector<int> block_dims(2 * m + 1); // tracks the dimensions of the blocks in these factors |
| 337 | + |
| 338 | + // loop over all flat indices |
| 339 | + int f_ix_max = static_cast<int>(backbone.fb_ix_max * backbone.o_ix_max * pow(hyb_poles.size(), m - 1)); |
| 340 | + for (int f_ix = 0; f_ix < f_ix_max; f_ix++) { find_path_self_energy(backbone, f_ix, ind_path, block_dims); } |
319 | 341 | Sigma.set_zero_block_indices(); // set zero_block_indices according to current blocks |
320 | 342 | } |
321 | 343 |
|
@@ -347,19 +369,35 @@ void DiagramEvaluator::eval_self_energy_fixed_indices(Backbone &backbone, int b_ |
347 | 369 | } |
348 | 370 |
|
349 | 371 | block_gf<dlr_imtime> DiagramEvaluator::compute_self_energy(nda::array<int, 2> topology) { |
350 | | - int n = hyb.extent(1); |
351 | 372 | Backbone backbone(topology, n); |
352 | 373 | eval_self_energy(backbone); |
353 | | - BlockDiagOpFun Sigma = get_self_energy(); |
354 | | - std::vector<gf<dlr_imtime>> Sigma_blocks(Sigma.get_num_block_cols()); |
355 | | - for (int i = 0; i < Sigma.get_num_block_cols(); ++i) { |
356 | | - if (Sigma.get_zero_block_index(i) == -1) { |
357 | | - Sigma_blocks[i] = gf<dlr_imtime>(tau_mesh); // zero block |
| 374 | + BlockDiagOpFun sig = get_self_energy(); |
| 375 | + std::vector<gf<dlr_imtime>> sig_blocks(sig.get_num_block_cols()); |
| 376 | + for (int i = 0; i < sig.get_num_block_cols(); ++i) { |
| 377 | + if (sig.get_zero_block_index(i) == -1) { |
| 378 | + sig_blocks[i] = gf<dlr_imtime>(tau_mesh, 0 * Gt.get_block(i)); // zero block |
| 379 | + } else { |
| 380 | + sig_blocks[i] = gf<dlr_imtime>(tau_mesh, sig.get_block(i)); |
| 381 | + } |
| 382 | + } |
| 383 | + reset(); |
| 384 | + return {sig_blocks}; |
| 385 | +} |
| 386 | + |
| 387 | +block_gf<dlr_imtime> DiagramEvaluator::compute_self_energy(nda::array<int, 2> topology, int f_ix) { |
| 388 | + Backbone backbone(topology, n); |
| 389 | + eval_self_energy(backbone, f_ix); |
| 390 | + BlockDiagOpFun sig = get_self_energy(); |
| 391 | + std::vector<gf<dlr_imtime>> sig_blocks(sig.get_num_block_cols()); |
| 392 | + for (int i = 0; i < sig.get_num_block_cols(); ++i) { |
| 393 | + if (sig.get_zero_block_index(i) == -1) { |
| 394 | + sig_blocks[i] = gf<dlr_imtime>(tau_mesh, 0 * Gt.get_block(i)); // zero block |
358 | 395 | } else { |
359 | | - Sigma_blocks[i] = gf<dlr_imtime>(tau_mesh, Sigma.get_block(i)); |
| 396 | + sig_blocks[i] = gf<dlr_imtime>(tau_mesh, sig.get_block(i)); |
360 | 397 | } |
361 | 398 | } |
362 | | - return {Sigma_blocks}; |
| 399 | + reset(); |
| 400 | + return {sig_blocks}; |
363 | 401 | } |
364 | 402 |
|
365 | 403 | // ========== Correlator routines ========== |
|
0 commit comments