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"
9#include <triqs/utility/report_stream.hpp>
10#include <ranges>
11#include <set>
12//#include <fmt/ranges.h>
13//#include <sstream>
14
15namespace triqs::modest {
16
17 embedding::embedding(std::vector<long> sigma_embed_decomposition, std::vector<std::vector<long>> imp_decompositions, nda::array<imp_block_t, 2> psi,
18 std::vector<std::string> sigma_names)
19 : sigma_embed_decomp{std::move(sigma_embed_decomposition)},
20 imp_decomps{std::move(imp_decompositions)},
21 _sigma_names{std::move(sigma_names)},
22 psi{std::move(psi)} {
23
24 alpha_names = range(n_alpha()) | //
25 stdv::transform([](auto i) { return std::to_string(i); }) | tl::to<std::vector>();
26
27 // Compute reverse_psi
28 reverse_psi = imp_decomps | stdv::transform([&](auto &v) { return nda::array<std::vector<std::array<long, 2>>, 2>(v.size(), n_sigma()); })
29 | tl::to<std::vector>();
30
31 for (auto [alpha, sigma] : this->psi.indices()) { // beware the psi (argument) has been moved. use 2 names ?
32 auto const &y = this->psi(alpha, sigma);
33 if (y.imp_idx == -1) continue;
34 reverse_psi[y.imp_idx](y.gamma, y.tau).push_back(std::array{alpha, sigma});
35 }
36
37 // FIXME : MAKE ALL NECESSARY CHECKS.... since
38 }
39
40 embedding make_embedding(std::vector<std::string> const &spin_names, nda::array<std::vector<long>, 2> const &block_decomposition,
41 std::vector<long> const &atom_to_imp) {
42
43 // Validate inputs
44 if (spin_names.empty()) throw std::runtime_error("[make_embedding] spin_names must not be empty");
45
46 auto n_atoms = block_decomposition.extent(0);
47 if (long(atom_to_imp.size()) != n_atoms)
48 throw std::runtime_error(
49 fmt::format("[make_embedding] block_decomposition has {} atoms but atom_to_imp has {} entries", n_atoms, atom_to_imp.size()));
50
51 for (long atom = 0; atom < n_atoms; ++atom) {
52 if (atom_to_imp[atom] < 0)
53 throw std::runtime_error(fmt::format("[make_embedding] atom_to_imp[{}] = {} is negative", atom, atom_to_imp[atom]));
54 }
55
56 // Check that equivalent atoms have identical block decompositions
57 std::unordered_map<long, long> imp_to_first_atom;
58 for (long atom = 0; atom < n_atoms; ++atom) {
59 auto imp = atom_to_imp[atom];
60 if (auto it = imp_to_first_atom.find(imp); it != imp_to_first_atom.end()) {
61 auto first_atom = it->second;
62 if (block_decomposition(atom, 0) != block_decomposition(first_atom, 0))
63 throw std::runtime_error(fmt::format(
64 "[make_embedding] Atoms {} and {} are mapped to the same impurity {} but have different block decompositions", first_atom, atom, imp));
65 } else {
66 imp_to_first_atom[imp] = atom;
67 }
68 }
69
70 long n_alpha = stdr::fold_left(block_decomposition(r_all, 0) | stdv::transform([](auto const &x) { return long(x.size()); }), 0, std::plus<>());
71 long n_sigma = spin_names.size();
72
73 auto embed_bl_sizes = std::vector<long>{};
74 auto imp_decompositions = std::vector<std::vector<long>>{};
75 auto psi = nda::array<embedding::imp_block_t, 2>(n_alpha, n_sigma);
76
77 std::set<long> seen_impurities;
78
79 for (auto atom : range(n_atoms)) {
80 for (auto &&[idx, bl_size] : enumerate(block_decomposition(atom, 0))) {
81 for (auto sigma : range(n_sigma)) { psi(embed_bl_sizes.size(), sigma) = {atom_to_imp[atom], idx, sigma}; }
82 embed_bl_sizes.emplace_back(bl_size);
83 }
84 auto build_impurity = !seen_impurities.contains(atom_to_imp[atom]);
85 if (build_impurity) {
86 imp_decompositions.push_back(std::move(block_decomposition(atom, 0)));
87 seen_impurities.insert(atom_to_imp[atom]);
88 }
89 }
90 return embedding{std::move(embed_bl_sizes), std::move(imp_decompositions), std::move(psi), std::move(spin_names)};
91 }
92
93 embedding make_embedding(std::vector<std::string> const &spin_names, std::vector<std::vector<long>> const &block_decomposition,
94 std::vector<long> const &atom_to_imp) {
95 auto n_decomps = block_decomposition.size();
96 auto n_sigma = spin_names.size();
97 auto block_decomp_mat = nda::array<std::vector<long>, 2>(n_decomps, n_sigma);
98 for (auto d : range(n_decomps))
99 for (auto s : range(n_sigma)) block_decomp_mat(d, s) = block_decomposition[d];
100 return make_embedding(spin_names, block_decomp_mat, atom_to_imp);
101 }
102
103 // -------------------------------------------------------------------------------------------
104 embedding make_embedding_with_equivalences(local_space const &C_space, bool use_atom_decomp) {
105 std::unordered_map<long, long> atom_to_cls, cls_to_imp;
106 long imp_idx = 0;
107 for (auto const &[ish, sh] : enumerate(C_space.atomic_shells())) {
108 atom_to_cls[ish] = sh.cls_idx;
109 if (not cls_to_imp.contains(sh.cls_idx)) cls_to_imp[sh.cls_idx] = imp_idx++;
110 }
111
112 nda::array<std::vector<long>, 2> decomp(C_space.n_atoms(), C_space.n_sigma());
113 if (use_atom_decomp) {
114 auto atom_decomp = C_space.atomic_decomposition() | tl::to<std::vector>();
115 for (auto &&[iatom, atom] : enumerate(atom_decomp)) {
116 for (auto sigma : range(C_space.n_sigma())) { decomp(iatom, sigma).emplace_back(atom); }
117 }
118 } else {
119 decomp = C_space.atoms_block_decomposition();
120 }
121
122 auto n_atoms_in_decomp = decomp.extent(0);
123 auto atom_to_imp_idx = range(n_atoms_in_decomp) | stdv::transform([&](auto const &atom) { return cls_to_imp[atom_to_cls[atom]]; })
124 | tl::to<std::vector>();
125 return make_embedding(C_space.sigma_names(), decomp, atom_to_imp_idx);
126 };
127
128 // -------------------------------------------------------------------------------------------
129 embedding make_embedding_with_no_equivalences(local_space const &C_space, bool use_atom_decomp) {
130 nda::array<std::vector<long>, 2> decomp(C_space.n_atoms(), C_space.n_sigma());
131 if (use_atom_decomp) {
132 auto atom_decomp = C_space.atomic_decomposition() | tl::to<std::vector>();
133 for (auto &&[iatom, atom] : enumerate(atom_decomp)) {
134 for (auto sigma : range(C_space.n_sigma())) { decomp(iatom, sigma).emplace_back(atom); }
135 }
136 } else {
137 decomp = C_space.atoms_block_decomposition();
138 }
139
140 auto n_atoms_in_decomp = decomp.extent(0);
141 auto atom_to_imp_idx = range(n_atoms_in_decomp) | tl::to<std::vector>();
142 return make_embedding(C_space.sigma_names(), decomp, atom_to_imp_idx);
143 }
144
145 // -------------------------------------------------------------------------------------------
146 embedding make_embedding(local_space const &C_space, bool use_atom_equivalences, bool use_atom_decomp) {
147 return (use_atom_equivalences) ? make_embedding_with_equivalences(C_space, use_atom_decomp) :
148 make_embedding_with_no_equivalences(C_space, use_atom_decomp);
149 }
150
151 //-----------------------------------------------------------------
152
154 auto res = nda::zeros<long>(n_alpha(), n_sigma());
155 for (long alpha : range(n_alpha())) res(alpha, r_all) = sigma_embed_decomp[alpha];
156 return {.names = {alpha_names, _sigma_names}, .dims = std::move(res)};
157 }
158
159 //-----------------------------------------------------------------
160
161 std::vector<gf_struct_t> embedding::imp_block_structure() const {
162 auto l = [this](std::vector<long> const &decomp) -> gf_struct_t {
163 gf_struct_t res;
164 for (auto sigma : range(n_sigma())) {
165 for (auto const &[idx, bl_size] : enumerate(decomp)) res.emplace_back(fmt::format("{}_{}", _sigma_names[sigma], idx), bl_size);
166 }
167 return res;
168 };
169 return imp_decomps | stdv::transform(l) | tl::to<std::vector>();
170 }
171
172 //-----------------------------------------------------------------
174 if (n_sigma() != 2) throw std::runtime_error(fmt::format("Can not swap sigma when {} != 2", n_sigma()));
175 if (alpha >= n_alpha()) throw std::runtime_error(fmt::format("Out of bounds {} >= {}", alpha, n_alpha()));
176 auto new_psi = this->psi;
177 for (auto sigma : range(n_sigma())) new_psi(alpha, sigma).tau = 1 - new_psi(alpha, sigma).tau;
178 return {this->sigma_embed_decomp, this->imp_decomps, new_psi, this->_sigma_names};
179 }
180
181 //-----------------------------------------------------------------
182 embedding embedding::swap_sigma(std::vector<long> alphas) const {
183 auto res = *this;
184 for (auto alpha : alphas) { res = res.swap_sigma(alpha); }
185 return res;
186 }
187
188 //------------------------------------------------------------------
189
191 if (n_sigma() != 2) throw std::runtime_error(fmt::format("Can not slice sigma when {} != 2", n_sigma()));
192 auto new_psi = nda::array<imp_block_t, 2>(n_alpha(), 1);
193 auto new_sigma_names = std::vector<std::string>{"ud"};
194 new_psi(r_all, 0) = this->psi(r_all, 0);
195 return {this->sigma_embed_decomp, this->imp_decomps, std::move(new_psi), new_sigma_names};
196 }
197
198 //-----------------------------------------------------------------
199
201
202 // Group consecutive α blocks that belong to the same atom.
203 // Within one atom the γ values are strictly increasing (0, 1, 2, …).
204 // When γ resets or imp_idx changes we start a new group.
205 // Disconnected blocks (imp_idx == -1) are never merged.
206
207 struct group_t {
208 std::vector<long> alphas; // α indices in this group
209 long imp_idx; // impurity (or -1)
210 };
211
212 std::vector<group_t> groups;
213
214 for (long alpha = 0; alpha < n_alpha(); ++alpha) {
215 auto const &m = psi(alpha, 0); // reference spin channel for grouping
216
217 bool start_new_group = true;
218 if (m.imp_idx >= 0 && !groups.empty()) {
219 auto &prev = groups.back();
220 auto const &prev_m = psi(prev.alphas.back(), 0);
221 if (prev.imp_idx == m.imp_idx && m.gamma > prev_m.gamma) { start_new_group = false; }
222 }
223
224 if (start_new_group) {
225 groups.push_back({{alpha}, m.imp_idx});
226 } else {
227 groups.back().alphas.push_back(alpha);
228 }
229 }
230
231 // Build new sigma_embed_decomp: one entry per group, sized as the sum of members.
232 auto new_sigma_embed_decomp = std::vector<long>{};
233 for (auto const &g : groups) {
234 long total = 0;
235 for (auto a : g.alphas) total += sigma_embed_decomp[a];
236 new_sigma_embed_decomp.push_back(total);
237 }
238
239 // Build new imp_decomps: each impurity gets a single merged block.
240 // Equivalent atoms share the same solver, so only the first group
241 // for each impurity defines the block size.
242 auto new_imp_decomps = std::vector<std::vector<long>>(n_impurities());
243 auto imp_seen = std::vector<bool>(n_impurities(), false);
244 for (long g_idx = 0; g_idx < long(groups.size()); ++g_idx) {
245 auto const &g = groups[g_idx];
246 if (g.imp_idx < 0) continue;
247 if (!imp_seen[g.imp_idx]) {
248 new_imp_decomps[g.imp_idx].push_back(new_sigma_embed_decomp[g_idx]);
249 imp_seen[g.imp_idx] = true;
250 }
251 }
252
253 // Build new psi: one row per group.
254 // All groups for the same impurity map to γ=0 (single block per impurity).
255 auto new_psi = nda::array<imp_block_t, 2>(long(groups.size()), n_sigma());
256
257 for (long g_idx = 0; g_idx < long(groups.size()); ++g_idx) {
258 auto const &g = groups[g_idx];
259 if (g.imp_idx < 0) {
260 for (auto sigma : range(n_sigma())) new_psi(g_idx, sigma) = {-1, 0, 0};
261 } else {
262 for (auto sigma : range(n_sigma())) {
263 auto tau = psi(g.alphas[0], sigma).tau;
264 new_psi(g_idx, sigma) = {g.imp_idx, 0, tau};
265 }
266 }
267 }
268
269 return {std::move(new_sigma_embed_decomp), std::move(new_imp_decomps), std::move(new_psi), this->_sigma_names};
270 }
271
272 //-----------------------------------------------------------------
273
274 embedding embedding::drop_imp(long imp_idx) const {
275 auto new_imp_decomps = this->imp_decomps;
276 auto new_psi = this->psi;
277 new_imp_decomps.erase(begin(new_imp_decomps) + imp_idx);
278 new_psi = nda::map([&](imp_block_t const &b) -> imp_block_t {
279 if (b.imp_idx < imp_idx) return {b.imp_idx, b.gamma, b.tau};
280 if (b.imp_idx > imp_idx) return {b.imp_idx - 1, b.gamma, b.tau};
281 return {-1, 0, 0}; // imp_idx == b.n_imp : we connect to nothing now
282 })(new_psi);
283 return {this->sigma_embed_decomp, new_imp_decomps, new_psi, this->_sigma_names};
284 }
285
286 //-----------------------------------------------------------------
287 embedding embedding::replace_imp(long imp_idx_old, long imp_idx_new) const {
288 auto new_psi = this->psi;
289 if (imp_block_structure()[imp_idx_old] != imp_block_structure()[imp_idx_new])
290 throw std::runtime_error(fmt::format("Block structures of imp_idx_old={} and imp_idx_new={} do not match; cannot redirect.",
291 imp_idx_old, imp_idx_new));
292 new_psi = nda::map([&](imp_block_t const &b) -> imp_block_t {
293 if (b.imp_idx == imp_idx_old) return {imp_idx_new, b.gamma, b.tau};
294 return b;
295 })(new_psi);
296 return {this->sigma_embed_decomp, this->imp_decomps, new_psi, this->_sigma_names};
297 }
298
299 //-----------------------------------------------------------------
300
301 embedding embedding::split_imp(long imp_idx, std::function<bool(long)> p) const {
302 // auto res = *this; // copy. We will modify the impurities_gf_struct and the table
303 auto new_psi = this->psi;
304 auto new_imp_decomps = this->imp_decomps;
305 auto const &igs = new_imp_decomps[imp_idx];
306 auto indices = nda::range(long(igs.size())) | tl::to<std::vector>(); // {0,1,2, ... n_gamma}
307
308 // separate the block indices according to p. We put the indices in regard to the blocks and partition them
309 auto mid = std::stable_partition(begin(indices), end(indices), p);
310
311 // make 2 new gf_struct from the indices partition
312 auto get_igs = [&](int i) { return igs[i]; };
313 auto stru1 = stdr::subrange{begin(indices), mid} | stdv::transform(get_igs) | tl::to<std::vector>();
314 auto stru2 = stdr::subrange{mid, end(indices)} | stdv::transform(get_igs) | tl::to<std::vector>();
315 long L1 = long(stru1.size());
316
317 // Store the new gf_struct in result at the position of the old impurity model
318 new_imp_decomps[imp_idx] = std::move(stru1);
319 new_imp_decomps.insert(begin(new_imp_decomps) + imp_idx + 1, std::move(stru2));
320
321 // compute the inverse table of indices
322 auto indices_inv = indices;
323 for (auto i : range(indices.size())) indices_inv[indices[i]] = i;
324
325 new_psi = nda::map([&](imp_block_t const &b) -> imp_block_t {
326 if (b.imp_idx < imp_idx) return b;
327 if (b.imp_idx > imp_idx) return {b.imp_idx + 1, b.gamma, b.tau};
328 long new_gamma = indices_inv[b.gamma];
329 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});
330 })(new_psi);
331 return {this->sigma_embed_decomp, new_imp_decomps, new_psi, this->_sigma_names};
332 }
333
334 // ----------------------------------------------------------------------
335
336 embedding embedding::split_imp(long imp_idx, std::vector<long> const &block_list) const {
337 if (not stdr::all_of(block_list, [&](auto i) { return (i >= 0) and (i < n_gamma(imp_idx)); }))
338 throw std::runtime_error(fmt::format("[embedding::split_imp] The list of block indices {} is incorrect. Indices i should all be 0<= i < N_γ = {}",
339 block_list, n_gamma(imp_idx)));
340 return split_imp(imp_idx, [&](long idx) { return stdr::find(block_list, idx) != block_list.end(); });
341 }
342
343 // ----------------------------------------------------------------------
344
345 embedding embedding::split_imp_block(long imp_idx, long gamma, std::vector<long> const &new_dims) const {
346 // Validation:
347 // Impurity index
348 if (imp_idx < 0 or imp_idx >= n_impurities())
349 throw std::runtime_error(fmt::format("Invalid impurity index {} (must be 0 <= imp_idx < {})", imp_idx, n_impurities()));
350 // Gamma index for impurity
351 if (gamma < 0 or gamma >= n_gamma(imp_idx))
352 throw std::runtime_error(fmt::format("Invalid gamma {} for impurity {} (must be 0 <= gamma < {})", gamma, imp_idx, n_gamma(imp_idx)));
353 // Dimensionality check
354 auto old_dim = imp_decomps[imp_idx][gamma];
355 if (stdr::fold_left(new_dims, 0, std::plus<>()) != old_dim)
356 throw std::runtime_error(fmt::format("New dimensions sum {} != old dimension {}", stdr::fold_left(new_dims, 0, std::plus<>()), old_dim));
357
358 // Update impurity decomposition
359 auto new_imp_decomps = imp_decomps;
360 new_imp_decomps[imp_idx].erase(begin(new_imp_decomps[imp_idx]) + gamma);
361 new_imp_decomps[imp_idx].insert(begin(new_imp_decomps[imp_idx]) + gamma, begin(new_dims), end(new_dims));
362
363 // Find all (alpha, sigma) pairs that map to (imp_idx, gamma, *) and update sigma_embed_decomposition
364 std::set<long> alphas_to_split;
365 auto const &alpha_list = reverse_psi[imp_idx](gamma, 0);
366 for (auto const &[alpha, sigma] : alpha_list) { alphas_to_split.insert(alpha); }
367
368 if (alphas_to_split.empty())
369 throw std::runtime_error(fmt::format("No embedding block maps to impurity {}, gamma {}. Cannot update!", imp_idx, gamma));
370
371 std::vector<long> sorted_alphas(alphas_to_split.begin(), alphas_to_split.end());
372 stdr::sort(sorted_alphas, std::greater<>());
373
374 auto new_sigma_embed_decomp = sigma_embed_decomp;
375 long n_new_blocks = long(new_dims.size());
376 for (auto alpha : sorted_alphas) {
377 new_sigma_embed_decomp.erase(begin(new_sigma_embed_decomp) + alpha);
378 new_sigma_embed_decomp.insert(begin(new_sigma_embed_decomp) + alpha, begin(new_dims), end(new_dims));
379 }
380
381 // Build new psi mapping
382 long n_new_alphas = long(new_sigma_embed_decomp.size());
383 auto new_psi = nda::array<imp_block_t, 2>(n_new_alphas, n_sigma());
384
385 long new_alpha_idx = 0;
386 for (long old_alpha = 0; old_alpha < n_alpha(); ++old_alpha) {
387 auto old_map = psi(old_alpha, 0); // check first sigma as reference
388
389 // Check if this alpha maps to the block we're splitting
390 bool is_split_alpha = (old_map.imp_idx == imp_idx && old_map.gamma == gamma);
391
392 if (is_split_alpha) {
393 // insert n_new_blocks number of new alphas
394 for (long split_idx = 0; split_idx < n_new_blocks; ++split_idx) {
395 for (auto sigma : range(n_sigma())) {
396 auto m = psi(old_alpha, sigma);
397 new_psi(new_alpha_idx, sigma) = {m.imp_idx, gamma + split_idx, m.tau};
398 }
399 new_alpha_idx++;
400 }
401 } else {
402 // copy with potential gamma adjustment
403 for (auto sigma : range(n_sigma())) {
404 auto m = psi(old_alpha, sigma);
405 if (m.imp_idx == imp_idx && m.gamma > gamma) {
406 new_psi(new_alpha_idx, sigma) = {m.imp_idx, m.gamma + n_new_blocks - 1, m.tau};
407 } else {
408 new_psi(new_alpha_idx, sigma) = m;
409 }
410 }
411 new_alpha_idx++;
412 }
413 }
414 return {std::move(new_sigma_embed_decomp), std::move(new_imp_decomps), std::move(new_psi), this->_sigma_names};
415 }
416
417 // ----------------------- Embedding and Extracting --------------------------
418 block2_matrix_t embedding::embed(std::vector<block_matrix_t> const &Sigma_imp_static_vec) const {
419 if (long(Sigma_imp_static_vec.size()) != n_impurities())
420 throw std::runtime_error(fmt::format("[embedding::embed] Wrong number of impurity static self-energies: got {} but embedding has {} impurities",
421 Sigma_imp_static_vec.size(), n_impurities()));
422 return detail::data_array_to_block2_array(this->embed(detail::matrix_to_array(Sigma_imp_static_vec)), sigma_embed_decomp);
423 }
424
425 // ----------------------------------------------------------------------
426 std::vector<block_matrix_t> embedding::extract(block2_matrix_t const &matrix_C) const {
427 if (matrix_C.extent(1) != n_sigma())
428 throw std::runtime_error(
429 fmt::format("[embedding::extract] Wrong number of spin channels in matrix: got {} but embedding has n_sigma = {}", matrix_C.extent(1), n_sigma()));
430 if (matrix_C.extent(0) != 1) return extract(detail::gather_blocks_to_data_view(matrix_C));
431 auto data = range(n_sigma()) | stdv::transform([&](auto sigma) { return nda::array<dcomplex, 2>{matrix_C(0, sigma)}; }) | tl::to<std::vector>();
432 return detail::array_to_matrix(this->extract(data));
433 }
434 // ----------------------------------------------------------------------
435
436} // namespace triqs::modest
The embedding class.
Definition embedding.hpp:32
std::vector< gf_struct_t > imp_block_structure() const
Block structure (names and dimensions) for each impurity solver.
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 .
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:17
std::vector< std::string > sigma_names() const
The names of the sigma indices.
long n_alpha() const
Number of blocks in for the .
embedding swap_sigma(long alpha) const
Swap the (spin) assignment for block alpha.
C2PY_IGNORE gf_struct2_t embed_block_structure() const
Block structure (names and dimensions) for the embedded self-energy .
embedding slice_sigma() const
Slice the embedding to a single channel ("ud").
embedding drop_imp(long imp_idx) const
Remove an impurity from the embedding table .
embedding split_imp(long imp_idx, std::function< bool(long)> p) const
Split impurity imp_idx using a predicate.
embedding replace_imp(long imp_idx_old, long imp_idx_new) const
Redirect all entries from one impurity to another.
std::vector< std::vector< nda::array< dcomplex, Rank > > > extract(std::vector< nda::array< dcomplex, Rank > > const &X) const
Extract impurity data from embedded arrays.
embedding split_imp_block(long imp_idx, long gamma, std::vector< long > const &new_dims) const
Split a single block of an impurity into multiple blocks.
std::vector< nda::array< dcomplex, Rank > > embed(std::vector< std::vector< nda::array< dcomplex, Rank > > > const &imps_blocks) const
Embed impurity data into the full correlated space.
embedding merge_embed_block_by_imp() const
Merge consecutive blocks belonging to the same impurity into a single block.
Describe the atomic orbitals within downfolded space.
long n_sigma() const
Dimension of the index.
nda::array< std::vector< long >, 2 > const & atoms_block_decomposition() const
2-dim array of all blocks spanning space -> atoms_block_decomposition.
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.
std::vector< long > atomic_decomposition() const
Dimensions of each atomic shell, in order.
embedding make_embedding(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:40
embedding make_embedding_with_no_equivalences(local_space const &C_space, bool use_atom_decomp)
embedding make_embedding_with_equivalences(local_space const &C_space, bool use_atom_decomp)
static constexpr auto r_all
Definition defs.hpp:33
nda::array< nda::matrix< dcomplex >, 2 > block2_matrix_t
Definition embedding.hpp:18