TRIQS/triqs_modest 3.3.0
Modular Electronic Structure Toolkit
Loading...
Searching...
No Matches
embedding.cpp
Go to the documentation of this file.
1// Copyright (c) 2025--present, The Simons Foundation
2// This file is part of TRIQS/modest 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 "embedding.hpp"
7#include "utils/gf_supp.hpp"
8#include "utils/defs.hpp"
11#include <ranges>
12#include <set>
13//#include <fmt/ranges.h>
14//#include <sstream>
15
16namespace triqs::modest {
17
18 embedding::embedding(std::vector<long> sigma_embed_decomposition, std::vector<std::vector<long>> imp_decompositions, nda::array<imp_block_t, 2> psi,
19 std::vector<std::string> sigma_names)
20 : sigma_embed_decomp{std::move(sigma_embed_decomposition)},
21 imp_decomps{std::move(imp_decompositions)},
22 _sigma_names{std::move(sigma_names)},
23 psi{std::move(psi)} {
24
25 alpha_names = range(n_alpha()) | //
26 stdv::transform([](auto i) { return std::to_string(i); }) | tl::to<std::vector>();
27
28 // Compute reverse_psi
29 reverse_psi = imp_decomps | stdv::transform([&](auto &v) { return nda::array<std::vector<std::array<long, 2>>, 2>(v.size(), n_sigma()); })
30 | tl::to<std::vector>();
31
32 for (auto [alpha, sigma] : this->psi.indices()) { // beware the psi (argument) has been moved. use 2 names ?
33 auto const &y = this->psi(alpha, sigma);
34 if (y.imp_idx == -1) continue;
35 reverse_psi[y.imp_idx](y.gamma, y.tau).push_back(std::array{alpha, sigma});
36 }
37
38 // FIXME : MAKE ALL NECESSARY CHECKS.... since
39 }
40
41 embedding embedding_builder(std::vector<std::string> const &spin_names, nda::array<std::vector<long>, 2> const &block_decomposition,
42 std::vector<long> const &atom_to_imp) {
43
44 long n_alpha = stdr::fold_left(block_decomposition(r_all, 0) | stdv::transform([](auto const &x) { return long(x.size()); }), 0, std::plus<>());
45 long n_sigma = spin_names.size();
46
47 auto embed_bl_sizes = std::vector<long>{};
48 auto imp_decompositions = std::vector<std::vector<long>>{};
49 auto psi = nda::array<embedding::imp_block_t, 2>(n_alpha, n_sigma);
50
51 std::set<long> seen_impurities;
52
53 auto n_atoms = block_decomposition.extent(0);
54 for (auto atom : range(n_atoms)) {
55 for (auto &&[idx, bl_size] : enumerate(block_decomposition(atom, 0))) {
56 for (auto sigma : range(n_sigma)) { psi(embed_bl_sizes.size(), sigma) = {atom_to_imp[atom], idx, sigma}; }
57 embed_bl_sizes.emplace_back(bl_size);
58 }
59 auto build_impurity = !seen_impurities.contains(atom_to_imp[atom]);
60 if (build_impurity) {
61 imp_decompositions.push_back(std::move(block_decomposition(atom, 0)));
62 seen_impurities.insert(atom_to_imp[atom]);
63 }
64 }
65 return embedding{std::move(embed_bl_sizes), std::move(imp_decompositions), std::move(psi), std::move(spin_names)};
66 }
67
68 embedding embedding_builder(std::vector<std::string> const &spin_names, std::vector<std::vector<long>> const &block_decomposition,
69 std::vector<long> const &atom_to_imp) {
70 auto n_decomps = block_decomposition.size();
71 auto n_sigma = spin_names.size();
72 auto block_decomp_mat = nda::array<std::vector<long>, 2>(n_decomps, n_sigma);
73 for (auto d : range(n_decomps))
74 for (auto s : range(n_sigma)) block_decomp_mat(d, s) = block_decomposition[d];
75 return embedding_builder(spin_names, block_decomp_mat, atom_to_imp);
76 }
77
78 // -------------------------------------------------------------------------------------------
79 embedding make_embedding_with_equivalences(local_space const &C_space, bool use_atom_decomp) {
80 std::unordered_map<long, long> atom_to_cls, cls_to_imp;
81 long imp_idx = 0;
82 for (auto const &[ish, sh] : enumerate(C_space.atomic_shells())) {
83 atom_to_cls[ish] = sh.cls_idx;
84 if (not cls_to_imp.contains(sh.cls_idx)) cls_to_imp[sh.cls_idx] = imp_idx++;
85 }
86 auto atom_to_imp_idx = range(C_space.atomic_shells().size()) | stdv::transform([&](auto const &atom) { return cls_to_imp[atom_to_cls[atom]]; })
87 | tl::to<std::vector>();
88
89 nda::array<std::vector<long>, 2> decomp(C_space.n_atoms(), C_space.n_sigma());
90 if (use_atom_decomp) {
91 auto atom_decomp = C_space.atomic_decomposition();
92 for (auto &&[iatom, atom] : enumerate(atom_decomp)) {
93 for (auto sigma : range(C_space.n_sigma())) { decomp(atom, sigma).emplace_back(atom); }
94 }
95 } else {
96 decomp = C_space.atoms_block_decomposition();
97 }
98 return embedding_builder(C_space.sigma_names(), decomp, atom_to_imp_idx);
99 };
100
101 // -------------------------------------------------------------------------------------------
102 embedding make_embedding_with_no_equivalences(local_space const &C_space, bool use_atom_decomp) {
103 nda::array<std::vector<long>, 2> decomp(C_space.n_atoms(), C_space.n_sigma());
104 if (use_atom_decomp) {
105 auto atom_decomp = C_space.atomic_decomposition();
106 for (auto &&[iatom, atom] : enumerate(atom_decomp)) {
107 for (auto sigma : range(C_space.n_sigma())) { decomp(atom, sigma).emplace_back(atom); }
108 }
109 } else {
110 decomp = C_space.atoms_block_decomposition();
111 }
112
113 auto atom_to_imp_idx = range(C_space.atomic_shells().size()) | tl::to<std::vector>();
114 return embedding_builder(C_space.sigma_names(), decomp, atom_to_imp_idx);
115 }
116
117 // -------------------------------------------------------------------------------------------
118 embedding make_embedding(local_space const &C_space, bool use_atom_equivalences, bool use_atom_decomp) {
119 return (use_atom_equivalences) ? make_embedding_with_equivalences(C_space, use_atom_decomp) :
120 make_embedding_with_no_equivalences(C_space, use_atom_decomp);
121 }
122
123 // ------------------------------ PRINTING -------------------------------------------------------------
124
125 auto format_as(embedding::imp_block_t const &p) {
126 //return fmt::format("({},{},{})", p.n_imp, p.gamma, p.tau);
127 return fmt::format("(imp_idx = {}, γ = {}, τ = {})", p.imp_idx, p.gamma, p.tau);
128 }
129
130 // -------------------------------------------------------------------------------------------------------
131
132 std::string embedding::description(bool verbosity) const {
133 auto sigma_embed_shape = this->sigma_embed_block_shape();
134 auto impurities_shape_list = this->imp_block_shape();
135
136 std::ostringstream out;
137 auto out1 = indented_ostream(out, 2); // same stream, but shifted by 2 spaces
138 auto out2 = indented_ostream(out, 4);
139 auto out3 = indented_ostream(out, 6);
140
141 if (!verbosity) {
142 out << "Embedding: ";
143 out << fmt::format("{} impurities\n", this->n_impurities());
144 out1 << "Σ_embed block decomposition:\n";
145 auto pr_vec = [](auto const &V) {
146 return fmt::format("{}\n", fmt::join(V | stdv::transform([](auto x) { return fmt::format("{:>3}", x); }), " "));
147 };
148 out2 << "dim_α: " << pr_vec(this->sigma_embed_decomp);
149 out2 << " α: " << pr_vec(range(this->sigma_embed_decomp.size()));
150 out1 << "\nImpurities\n";
151 out2 << "Block dimensions, dim_γ for all γ:\n";
152 for (auto &&[n, dec] : enumerate(this->imp_decomps)) {
153 auto head = fmt::format("[n_imp = {}]", n);
154 out3 << fmt::format("{} dim_γ = {}", head, pr_vec(dec));
155 out3 << fmt::format("{:>{}} γ = {}", " ", head.size(), pr_vec(range(dec.size())));
156 }
157 return out.str();
158 }
159
160 out << "Embedding:\n";
161 out1 << fmt::format("Spin index (σ/τ) names: {}\n\n", this->sigma_names());
162 out1 << "Σ_embed block decomposition:\n";
163 auto pr_vec = [](auto const &V) {
164 return fmt::format("{}\n", fmt::join(V | stdv::transform([](auto x) { return fmt::format("{:>3}", x); }), " "));
165 };
166 out2 << "dim_α: " << pr_vec(this->sigma_embed_decomp);
167 out2 << " α: " << pr_vec(range(this->sigma_embed_decomp.size()));
168 //out << fmt::format(" {}\n", enumerate(E.sigma_embed_decomp));
169 out1 << "\nImpurities\n";
170 out2 << "Block dimensions, dim_γ for all γ:\n";
171 for (auto &&[n, dec] : enumerate(this->imp_decomps)) {
172 auto head = fmt::format("[n_imp = {}]", n);
173 out3 << fmt::format("{} dim_γ = {}", head, pr_vec(dec));
174 out3 << fmt::format("{:>{}} γ = {}", " ", head.size(), pr_vec(range(dec.size())));
175 }
176 out2 << "Gf Block structures for solvers as names, [dim]:\n";
177 for (auto &&[n, ish] : enumerate(impurities_shape_list)) {
178 auto formatted_vec = ish | stdv::transform([](auto &&p) { return fmt::format("{} [{}]", p.first, p.second); }) | tl::to<std::vector>();
179 out3 << fmt::format("[imp_idx = {}] {}\n", n, fmt::join(formatted_vec, ", "));
180 }
181 out1 << "\nMapping ψ(α,σ) = (imp_idx, γ, τ) \n";
182 //out2 << fmt::format("{}", E.psi);
183 auto row_labels = range(this->n_alpha()) | stdv::transform([](auto x) { return fmt::format("α = {}", x); }) | tl::to<std::vector>();
184 auto col_labels = range(this->n_sigma()) | stdv::transform([&](auto i) { return fmt::format("σ = {} / {}", i, this->sigma_names()[i]); })
185 | tl::to<std::vector>();
186 nda::format_as_table(out3, this->psi, row_labels, col_labels);
187
188 return out.str();
189 }
190
191 std::ostream &operator<<(std::ostream &out, embedding const &E) {
192 out << E.description(false);
193 return out;
194 }
195
196 //-----------------------------------------------------------------
197
199 auto res = nda::zeros<long>(n_alpha(), n_sigma());
200 for (long alpha : range(n_alpha())) res(alpha, r_all) = sigma_embed_decomp[alpha];
201 return {.names = {alpha_names, _sigma_names}, .dims = std::move(res)};
202 }
203
204 //-----------------------------------------------------------------
205
206 std::vector<gf_struct_t> embedding::imp_block_shape() const {
207 auto l = [this](std::vector<long> const &decomp) -> gf_struct_t {
208 gf_struct_t res;
209 for (auto sigma : range(n_sigma())) {
210 for (auto const &[idx, bl_size] : enumerate(decomp)) res.emplace_back(fmt::format("{}_{}", _sigma_names[sigma], idx), bl_size);
211 }
212 return res;
213 };
214 return imp_decomps | stdv::transform(l) | tl::to<std::vector>();
215 }
216
217 //-----------------------------------------------------------------
218 embedding embedding::flip_spin(long alpha) const {
219 if (n_sigma() != 2) throw std::runtime_error(fmt::format("Can not flip spin when {} != 2", n_sigma()));
220 if (alpha >= n_alpha()) throw std::runtime_error(fmt::format("Out of bounds {} >= {}", alpha, n_alpha()));
221 auto new_psi = this->psi;
222 for (auto sigma : range(n_sigma())) new_psi(alpha, sigma).tau = 1 - new_psi(alpha, sigma).tau;
223 return {this->sigma_embed_decomp, this->imp_decomps, new_psi, this->_sigma_names};
224 }
225
226 //-----------------------------------------------------------------
227 embedding embedding::flip_spin(std::vector<long> alphas) const {
228 auto res = *this;
229 for (auto alpha : alphas) { res = res.flip_spin(alpha); }
230 return res;
231 }
232
233 //-----------------------------------------------------------------
234
235 embedding embedding::drop(long imp_idx) const {
236 auto new_imp_decomps = this->imp_decomps;
237 auto new_psi = this->psi;
238 new_imp_decomps.erase(begin(new_imp_decomps) + imp_idx);
239 new_psi = nda::map([&](imp_block_t const &b) -> imp_block_t {
240 if (b.imp_idx < imp_idx) return {b.imp_idx, b.gamma, b.tau};
241 if (b.imp_idx > imp_idx) return {b.imp_idx - 1, b.gamma, b.tau};
242 return {-1, 0, 0}; // imp_idx == b.n_imp : we connect to nothing now
243 })(new_psi);
244 return {this->sigma_embed_decomp, new_imp_decomps, new_psi, this->_sigma_names};
245 }
246
247 //-----------------------------------------------------------------
248 // HL: re-implementation of replace. Please review.
249 embedding embedding::replace(long imp_idx_to_remove, long imp_idx_to_replace_with) const {
250 auto new_psi = this->psi;
251 if (imp_block_shape()[imp_idx_to_remove] != imp_block_shape()[imp_idx_to_replace_with])
252 throw std::runtime_error(fmt::format("The number of blocks that imp_to_remove= {} and imp_to_replace_with={} connect to do not match!",
253 imp_idx_to_remove, imp_idx_to_replace_with));
254 new_psi = nda::map([&](imp_block_t const &b) -> imp_block_t {
255 if (b.imp_idx == imp_idx_to_remove) return {imp_idx_to_replace_with, b.gamma, b.tau};
256 return b;
257 })(new_psi);
258 return embedding(this->sigma_embed_decomp, this->imp_decomps, new_psi, this->_sigma_names).drop(imp_idx_to_remove);
259 }
260
261 //-----------------------------------------------------------------
262
263 embedding embedding::split(long imp_idx, std::function<bool(long)> p) const {
264 // auto res = *this; // copy. We will modify the impurities_gf_struct and the table
265 auto new_psi = this->psi;
266 auto new_imp_decomps = this->imp_decomps;
267 auto const &igs = new_imp_decomps[imp_idx];
268 auto indices = nda::range(long(igs.size())) | tl::to<std::vector>(); // {0,1,2, ... n_gamma}
269
270 // separate the block indices according to p. We put the indices in regard to the blocks and partition them
271 auto mid = std::stable_partition(begin(indices), end(indices), p);
272
273 // make 2 new gf_struct from the indices partition
274 auto get_igs = [&](int i) { return igs[i]; };
275 auto stru1 = stdr::subrange{begin(indices), mid} | stdv::transform(get_igs) | tl::to<std::vector>();
276 auto stru2 = stdr::subrange{mid, end(indices)} | stdv::transform(get_igs) | tl::to<std::vector>();
277 long L1 = long(stru1.size());
278
279 // Store the new gf_struct in result at the position of the old impurity model
280 new_imp_decomps[imp_idx] = std::move(stru1);
281 new_imp_decomps.insert(begin(new_imp_decomps) + imp_idx + 1, std::move(stru2));
282
283 // compute the inverse table of indices
284 auto indices_inv = indices;
285 for (auto i : range(indices.size())) indices_inv[indices[i]] = i;
286
287 new_psi = nda::map([&](imp_block_t const &b) -> imp_block_t {
288 if (b.imp_idx < imp_idx) return b;
289 if (b.imp_idx > imp_idx) return {b.imp_idx + 1, b.gamma, b.tau};
290 long new_gamma = indices_inv[b.gamma];
291 return (new_gamma < L1 ? imp_block_t{b.imp_idx, new_gamma, b.tau} : imp_block_t{b.imp_idx + 1, new_gamma - L1, b.tau});
292 })(new_psi);
293 return {this->sigma_embed_decomp, new_imp_decomps, new_psi, this->_sigma_names};
294 }
295
296 // ----------------------------------------------------------------------
297
298 embedding embedding::split(long imp_idx, std::vector<long> const &block_list) const {
299 if (not stdr::all_of(block_list, [&](auto i) { return (i >= 0) and (i < n_gamma(imp_idx)); }))
300 throw std::runtime_error(fmt::format("[embedding::split] The list of block indices {} is incorrect. Indices i should all be 0<= i < N_γ = {}",
301 block_list, n_gamma(imp_idx)));
302 return split(imp_idx, [&](long idx) { return stdr::find(block_list, idx) != block_list.end(); });
303 }
304
305 // ----------------------- Embedding and Extracting --------------------------
306
307 // T = Block Matrix
308
309 // ----------------------------------------------------------------------
310 block2_matrix_t embedding::embed(std::vector<block_matrix_t> const &Sigma_imp_static_vec) const {
311 auto Sigma_static_embed = nda::array<nda::matrix<dcomplex>, 2>(n_alpha(), n_sigma());
312 for (auto &&[alpha, sigma] : psi.indices()) {
313 auto bl_size = sigma_embed_decomp[alpha];
314 Sigma_static_embed(alpha, sigma) = nda::zeros<dcomplex>(bl_size, bl_size);
315 }
316 for (auto &&[S, m] : zip(Sigma_static_embed, psi)) {
317 if (m.imp_idx == -1) continue;
318 S = Sigma_imp_static_vec[m.imp_idx][m.gamma + n_gamma(m.imp_idx) * m.tau];
319 }
320 return Sigma_static_embed;
321 }
322
323 // TODO: helper functions to scatter and gather to avoid code duplication:
324 // A common pattern is to scatter/ gather from/to a large matrix to/from smaller matrices
325 block_matrix_t embedding::embed_ij(std::vector<block_matrix_t> const &Sigma_imp_static_vec) const {
326 auto Sigma_static_embed = this->embed(Sigma_imp_static_vec);
327 auto dim_C = stdr::fold_left(sigma_embed_decomp, 0, std::plus<>());
328 block_matrix_t Sigma_static_embed_ij;
329 for (auto const &sigma : range(n_sigma())) {
330 auto mat = nda::zeros<dcomplex>(dim_C, dim_C);
331 for (auto &&[alpha, r_alpha] : enumerated_sub_slices(sigma_embed_decomp)) { mat(r_alpha, r_alpha) = Sigma_static_embed(alpha, sigma); }
332 Sigma_static_embed_ij.push_back(mat);
333 }
334 return Sigma_static_embed_ij;
335 }
336
337 // ----------------------------------------------------------------------
338 std::vector<block_matrix_t> embedding::extract(block2_matrix_t const &matrix_C) const {
339
340 auto imp_gf_stru_list = imp_block_shape();
341
342 auto matrix_E = nda::matrix<nda::matrix<dcomplex>>(n_alpha(), n_sigma());
343 for (auto [alpha, r_alpha] : enumerated_sub_slices(sigma_embed_decomp)) {
344 for (auto sigma : range(n_sigma())) { matrix_E(alpha, sigma) = matrix_C(0, sigma)(r_alpha, r_alpha); }
345 }
346
347 auto extract_one_imp = [&](long n_imp) {
348 auto matrix_imp = std::vector<nda::matrix<dcomplex>>{};
349 for (auto [bl, bl_size] : imp_gf_stru_list[n_imp]) { matrix_imp.emplace_back(bl_size, bl_size); }
350 auto const &rpsi = reverse_psi[n_imp];
351 for (auto [gamma, tau] : rpsi.indices()) {
352 auto [alpha, sigma] = rpsi(gamma, tau)[0];
353 matrix_imp[gamma + n_gamma(n_imp) * tau] = matrix_E(alpha, sigma);
354 }
355 return matrix_imp;
356 };
357
358 return range(n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
359 }
360
361 // T = Tensors
362
363 // ----------------------------------------------------------------------
364 std::vector<nda::array<dcomplex, 4>> embedding::extract_ijkl(nda::array<dcomplex, 4> const &U_tensor) const {
365
366 auto imp_gf_stru_list = imp_block_shape();
367
368 auto tensor_E = std::vector<nda::array<dcomplex, 4>>(n_alpha());
369 for (auto [alpha, r_alpha] : enumerated_sub_slices(sigma_embed_decomp)) { tensor_E[alpha] = U_tensor(r_alpha, r_alpha, r_alpha, r_alpha); }
370
371 auto extract_one_imp = [&](long n_imp) {
372 auto bl_size = imp_decomposition(n_imp)[0];
373 auto tensor_imp = nda::zeros<dcomplex>(bl_size, bl_size, bl_size, bl_size);
374 auto alpha = reverse_psi[n_imp](0, 0)[0][0];
375 return tensor_E[alpha];
376 };
377 return range(n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
378 }
379
380 // --------------------------------------------------------------------------------------------
381 nda::array<dcomplex, 4> embedding::embed_ijkl(std::vector<nda::array<dcomplex, 4>> const &U_tensor_vec) const {
382 auto Utensor_E = std::vector<nda::array<dcomplex, 4>>(n_alpha());
383
384 for (auto alpha : range(n_alpha())) {
385 auto bl_size = sigma_embed_decomp[alpha];
386 Utensor_E[alpha] = nda::zeros<dcomplex>(bl_size, bl_size, bl_size, bl_size);
387 }
388
389 for (auto &&[U, a] : zip(Utensor_E, range(n_alpha()))) {
390 if (psi(a, 0).imp_idx == -1) continue;
391 U = U_tensor_vec[psi(a, 0).imp_idx];
392 }
393
394 auto dim_C = stdr::fold_left(sigma_embed_decomp, 0, std::plus<>());
395 auto U_tensor_C = nda::array<dcomplex, 4>(dim_C, dim_C, dim_C, dim_C);
396 for (auto &&[index, sli] : enumerated_sub_slices(sigma_embed_decomp)) { U_tensor_C(sli, sli, sli, sli) = Utensor_E[index]; }
397 return U_tensor_C;
398 }
399
400 // T = Block Green's functions
401 // --------------------------------------------------------------------------------------------
402 std::vector<std::vector<nda::array<dcomplex, 3>>> embedding::extract_wij(nda::array<dcomplex, 4> const &g_loc) const {
403
404 auto imp_gf_stru_list = imp_block_shape();
405 auto n_w = g_loc.extent(0);
406
407 auto gloc_E = nda::array<nda::array<dcomplex, 3>, 2>(n_alpha(), n_sigma());
408 for (auto [alpha, r_alpha] : enumerated_sub_slices(sigma_embed_decomp)) {
409 for (auto sigma : range(n_sigma())) { gloc_E(alpha, sigma) = g_loc(r_all, sigma, r_alpha, r_alpha); }
410 }
411 auto extract_one_imp = [&](long n_imp) {
412 auto g_imp = std::vector<nda::array<dcomplex, 3>>{};
413 for (auto [bl, bl_size] : imp_gf_stru_list[n_imp]) { g_imp.emplace_back(n_w, bl_size, bl_size); }
414 auto const &rpsi = reverse_psi[n_imp];
415 for (auto [gamma, tau] : rpsi.indices()) {
416 auto [alpha, sigma] = rpsi(gamma, tau)[0];
417 g_imp[gamma + n_gamma(n_imp) * tau] = gloc_E(alpha, sigma);
418 }
419 return g_imp;
420 };
421
422 return range(n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
423 }
424
425 // --------------------------------------------------------------------------------------------
426 std::vector<nda::array<dcomplex, 3>> embedding::embed_wij(std::vector<std::vector<nda::array<dcomplex, 3>>> const &Sigma_imp_vec) const {
427
428 auto Sigma_embed = nda::array<nda::array<dcomplex, 3>, 2>(n_alpha(), n_sigma());
429 auto n_w = Sigma_imp_vec[0][0].extent(0);
430
431 for (auto &&[alpha, sigma] : psi.indices()) {
432 auto bl_size = sigma_embed_decomp[alpha];
433 Sigma_embed(alpha, sigma) = nda::zeros<dcomplex>(n_w, bl_size, bl_size);
434 }
435
436 for (auto &&[S, m] : zip(Sigma_embed, psi)) {
437 if (m.imp_idx == -1) continue;
438 S = Sigma_imp_vec[m.imp_idx][m.gamma + n_gamma(m.imp_idx) * m.tau];
439 }
440
441 auto dim_C = stdr::fold_left(sigma_embed_decomp, 0, std::plus<>());
442 auto Sigma_C =
443 range(n_sigma()) | stdv::transform([n_w, dim_C](auto) { return nda::array<dcomplex, 3>(n_w, dim_C, dim_C); }) | tl::to<std::vector>();
444
445 for (auto sigma : range(n_sigma())) {
446 for (auto &&[index, sli] : enumerated_sub_slices(sigma_embed_decomp)) { Sigma_C[sigma](r_all, sli, sli) = Sigma_embed(index, sigma); }
447 }
448
449 return Sigma_C;
450 }
451
452 // --------------------------------------------------------------------------------------------
453 //FIXME : protect this function as it will only work with a Pi_embed_decomp
454 std::vector<nda::array<dcomplex, 5>> embedding::extract_wijkl(nda::array<dcomplex, 5> const &pi_loc) const {
455
456 auto Pi_E = std::vector<nda::array<dcomplex, 5>>{};
457 for (auto [alpha, r_alpha] : enumerated_sub_slices(sigma_embed_decomp)) { Pi_E.emplace_back(pi_loc(r_all, r_alpha, r_alpha, r_alpha, r_alpha)); }
458
459 auto extract_one_imp = [&](long n_imp) {
460 auto const &rpsi = reverse_psi[n_imp];
461 auto [alpha, sigma] = rpsi(0, 0)[0];
462 return Pi_E[alpha];
463 };
464
465 return range(n_impurities()) | stdv::transform(extract_one_imp) | tl::to<std::vector>();
466 }
467 // --------------------------------------------------------------------------------------------
468
469 //FIXME : protect this function as it will only work with a Pi_embed_decomp
470 nda::array<dcomplex, 5> embedding::embed_wijkl(std::vector<nda::array<dcomplex, 5>> const &pi_imp_vec) const {
471
472 auto n_w = pi_imp_vec[0].extent(0);
473
474 auto Pi_embed = std::vector<nda::array<dcomplex, 5>>(n_alpha());
475 for (auto alpha : range(n_alpha())) {
476 auto bl_size = sigma_embed_decomp[alpha];
477 Pi_embed[alpha] = nda::zeros<dcomplex>(n_w, bl_size, bl_size, bl_size, bl_size);
478 }
479
480 for (auto alpha : range(n_alpha())) {
481 auto const &m = psi(alpha, 0);
482 if (m.imp_idx == -1) continue; // check
483 Pi_embed[alpha] = pi_imp_vec[m.imp_idx];
484 }
485
486 auto dim_C = stdr::fold_left(sigma_embed_decomp, 0, std::plus<>());
487 auto Pi_C = nda::array<dcomplex, 5>(n_w, dim_C, dim_C, dim_C, dim_C);
488 for (auto &&[alpha, sli] : enumerated_sub_slices(sigma_embed_decomp)) { Pi_C(r_all, sli, sli, sli, sli) = Pi_embed[alpha]; }
489
490 return Pi_C;
491 }
492
493 //-------------------------------------------------------------------------
494 std::vector<nda::array<dcomplex, 3>> rotate_embedded_self_energy(std::vector<nda::array<dcomplex, 3>> const &Sigma_embed_dynamic_loc,
495 nda::matrix<dcomplex> const &U) {
496 auto n_sigma = Sigma_embed_dynamic_loc.size();
497 auto n_w = Sigma_embed_dynamic_loc[0].extent(0);
498 auto Sigma_embed_dynamic_rotated = range(Sigma_embed_dynamic_loc.size())
499 | stdv::transform([&](auto) { return nda::zeros<dcomplex>(Sigma_embed_dynamic_loc[0].shape()); }) | tl::to<std::vector>();
500 for (auto const &sigma : range(n_sigma))
501 for (auto const &w : range(n_w))
502 Sigma_embed_dynamic_rotated[sigma](w, r_all, r_all) = U * nda::matrix<dcomplex>{Sigma_embed_dynamic_loc[sigma](w, r_all, r_all)} * dagger(U);
503 return Sigma_embed_dynamic_rotated;
504 }
505
506 //-------------------------------------------------------------------------
507 std::vector<nda::array<dcomplex, 3>> rotate_embedded_self_energy(std::vector<nda::array<dcomplex, 3>> const &Sigma_embed_dynamic_loc,
508 one_body_elements_on_grid const &obe) {
509 auto const &U = obe.C_space.rotation_from_dft_to_local_basis()(r_all, 0) | tl::to<std::vector<nda::matrix<dcomplex>>>();
510 return rotate_embedded_self_energy(Sigma_embed_dynamic_loc, nda::block_diag(U));
511 }
512
513 //-------------------------------------------------------------------------
514 std::vector<nda::matrix<dcomplex>> rotate_embedded_self_energy(std::vector<nda::matrix<dcomplex>> const &Sigma_embed_static_loc,
515 nda::matrix<dcomplex> const &U) {
516 return range(Sigma_embed_static_loc.size()) | stdv::transform([&](auto sigma) { return U * Sigma_embed_static_loc[sigma] * dagger(U); })
517 | tl::to<std::vector>();
518 }
519
520 //-------------------------------------------------------------------------
521 std::vector<nda::matrix<dcomplex>> rotate_embedded_self_energy(std::vector<nda::matrix<dcomplex>> const &Sigma_embed_static_loc,
522 one_body_elements_on_grid const &obe) {
523 auto const &U = obe.C_space.rotation_from_dft_to_local_basis()(r_all, 0) | tl::to<std::vector<nda::matrix<dcomplex>>>();
524 return rotate_embedded_self_energy(Sigma_embed_static_loc, nda::block_diag(U));
525 }
526
527} // namespace triqs::modest
A custom output stream that automatically indents each new line by a specified number of spaces.
Definition streams.hpp:88
The embedding class.
Definition embedding.hpp:30
C2PY_IGNORE gf_struct2_t sigma_embed_block_shape() const
Gf block structure for .
long n_impurities() const
Number of impurities.
long n_gamma(long imp_idx) const
Number of blocks in for the [imp_idx].
long n_sigma() const
Number of blocks in for the .
std::vector< gf_struct_t > imp_block_shape() const
Gf block structure for the impurity solvers.
embedding flip_spin(long alpha) const
Flip the spins ( ) for block .
block_matrix_t embed_ij(std::vector< block_matrix_t > const &Sigma_imp_static_vec) const
embedding(std::vector< long > sigma_embed_decomposition, std::vector< std::vector< long > > imp_decompositions, nda::array< imp_block_t, 2 > psi, std::vector< std::string > sigma_names)
Construct an embedding object.
Definition embedding.cpp:18
std::vector< std::string > sigma_names() const
The names of the sigma indices.
std::vector< block_gf< Mesh, matrix_valued > > extract(block2_gf< Mesh, matrix_valued > const &g_loc) const
Extract single-particle quantities (TRIQS/ModEST).
std::vector< nda::array< dcomplex, 4 > > extract_ijkl(nda::array< dcomplex, 4 > const &U_tensor) const
Extract tensors (CoQui).
long n_alpha() const
Number of blocks in for the .
std::vector< long > imp_decomposition(long imp_idx) const
The impurity decomposition.
nda::array< dcomplex, 4 > embed_ijkl(std::vector< nda::array< dcomplex, 4 > > const &U_tensor_vec) const
Embed tensors (CoQui).
std::string description(bool verbosity=false) const
Summarize the embedding object.
embedding drop(long imp_idx) const
Remove an impurity from the embedding table .
std::vector< nda::array< dcomplex, 5 > > extract_wijkl(nda::array< dcomplex, 5 > const &Pi_loc) const
Extract two-particle quantities (CoQui).
embedding split(long imp_idx, std::function< bool(long)> p) const
Split impurity imp_idx.
std::vector< std::vector< nda::array< dcomplex, 3 > > > extract_wij(nda::array< dcomplex, 4 > const &g_loc) const
Extract single-particle quantities (CoQui).
embedding replace(long imp_idx_to_remove, long imp_idx_to_replace_with) const
Replaces one impurity in the embedding table .
nda::array< dcomplex, 5 > embed_wijkl(std::vector< nda::array< dcomplex, 5 > > const &pi_imp_vec) const
Embed two-particle quantities (CoQui).
block2_gf< Mesh, matrix_valued > embed(std::vector< block_gf< Mesh, matrix_valued > > const &Sigma_imp_vec) const
Embed single-particle quantities (TRIQS/ModEST).
std::vector< nda::array< dcomplex, 3 > > embed_wij(std::vector< std::vector< nda::array< dcomplex, 3 > > > const &Sigma_imp_vec) const
Embed single-particle quantities (CoQui).
Describe the atomic orbitals within downfolded space.
long n_sigma() const
Dimension of the index.
nda::array< nda::matrix< dcomplex >, 2 > const & rotation_from_dft_to_local_basis() const
2-dim array of all local rotation matices that rotate the data.
nda::array< std::vector< long >, 2 > const & atoms_block_decomposition() const
2-dim array of all blocks spanning space -> atoms_block_decomposition.
auto atomic_decomposition() const
Transformed view containing the dimension of each atomic shell.
std::vector< atomic_orbs > const & atomic_shells() const
List of all atomic shells spanning the space.
long n_atoms() const
The number of atoms.
std::vector< std::string > sigma_names() const
Names of spin indices for naming blocks in block GFs.
embedding make_embedding(local_space const &C_space, bool use_atom_equivalences, bool use_atom_decomp)
Make an embedding from the local space.
void format_as_table(std::ostream &out, nda::Matrix auto const &mat, auto const &row_labels, auto const &col_labels)
Format the matrix mat as a table, with row/col_labels.
nda::array< T, 2 > block_diag(std::vector< nda::matrix< T > > const &matrices)
Definition nda_supp.hpp:40
std::ostream & operator<<(std::ostream &out, one_body_elements_on_grid const &)
Definition printing.cpp:73
std::vector< nda::array< dcomplex, 3 > > rotate_embedded_self_energy(std::vector< nda::array< dcomplex, 3 > > const &Sigma_embed_dynamic_loc, nda::matrix< dcomplex > const &U)
Rotate the dynamic part of the embedded self-energy from the local (solver) basis to the orbital basi...
embedding make_embedding_with_no_equivalences(local_space const &C_space, bool use_atom_decomp)
auto format_as(embedding::imp_block_t const &p)
embedding make_embedding_with_equivalences(local_space const &C_space, bool use_atom_decomp)
Definition embedding.cpp:79
embedding embedding_builder(std::vector< std::string > const &spin_names, nda::array< std::vector< long >, 2 > const &block_decomposition, std::vector< long > const &atom_to_imp)
Definition embedding.cpp:41
nda::array< nda::matrix< dcomplex >, 2 > block2_matrix_t
Definition embedding.hpp:16
static constexpr auto r_all
Definition defs.hpp:40
generator< std::pair< long, nda::range > > enumerated_sub_slices(auto sub_div)
std::vector< nda::matrix< dcomplex > > block_matrix_t
Definition embedding.hpp:15
A one-body elements struct where all of the underlying data exists on a fixed momentum grid.