TRIQS/triqs_modest 3.3.0
Modular Electronic Structure Toolkit
Loading...
Searching...
No Matches
gloc_fixed_grid.hpp
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#pragma once
7#include "./density.hpp"
9#include <triqs/mesh.hpp>
10#include "utils/gf_supp.hpp"
11
12namespace triqs::modest {
13
14// omp reduction operation for block2_gf
15#pragma omp declare reduction(block2_gf_sum : block2_gf<imfreq, matrix_valued> : omp_out += omp_in) \
16 initializer(omp_priv = make_block2_gf(omp_orig(0, 0).mesh(), get_struct(omp_orig)))
17#pragma omp declare reduction(block2_gf_sum : block2_gf<dlr_imfreq, matrix_valued> : omp_out += omp_in) \
18 initializer(omp_priv = make_block2_gf(omp_orig(0, 0).mesh(), get_struct(omp_orig)))
19
20 namespace detail {
21
22 template <typename Mesh>
23 constexpr auto upfold_self_energy_at_freq(one_body_elements_on_grid const &obe, downfolding_projector const &Proj,
24 block2_gf<Mesh, matrix_valued> const &Sigma_dynamic,
25 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static, long w_idx, long k_idx, long sigma_idx) {
26 auto N_nu = obe.H.N_nu(sigma_idx, k_idx);
27 auto out = nda::zeros<dcomplex>(N_nu, N_nu);
28 for (auto &&[alpha, R] : enumerated_sub_slices(get_struct(Sigma_dynamic).dims(r_all, 0) | tl::to<std::vector>())) {
29 auto P = Proj.P(sigma_idx, k_idx)(R, r_all);
30 out(r_all, r_all) +=
31 dagger(P) * nda::matrix<dcomplex>{Sigma_dynamic(alpha, sigma_idx).data()(w_idx, r_all, r_all) + Sigma_static(alpha, sigma_idx)} * P;
32 }
33 return out;
34 }
35
36 // --------------------------------------------------------------------
37 template <typename Mesh>
38 constexpr auto local_gf_at_k(one_body_elements_on_grid const &obe, double const &mu, downfolding_projector const &Proj,
39 block2_gf<Mesh, matrix_valued> const &Sigma_dynamic, nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static) {
40 return [&](auto const &k_idx, auto const &sigma_idx) {
41 auto const n_M = obe.C_space.dim();
42 auto const &mesh = Sigma_dynamic(0, 0).mesh();
43 auto out = gf{mesh, {n_M, n_M}};
44 auto P = obe.P.P(sigma_idx, k_idx);
45 for (auto &&[n, w] : enumerate(mesh)) {
46 auto PSP = upfold_self_energy_at_freq(obe, Proj, Sigma_dynamic, Sigma_static, n, k_idx, sigma_idx);
47 out.data()(n, r_all, r_all) = P * inverse(w + mu - obe.H.H(sigma_idx, k_idx) - PSP) * dagger(P);
48 }
49 return out;
50 };
51 }
52
53 template <typename Mesh>
54 constexpr auto lattice_gf_at_k(one_body_elements_on_grid const &obe, double const &mu, block2_gf<Mesh, matrix_valued> const &Sigma_dynamic,
55 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static) {
56 return [&](auto const &k_idx, auto const &sigma_idx) {
57 auto const &mesh = Sigma_dynamic(0, 0).mesh();
58 auto N_nu = obe.H.N_nu(sigma_idx, k_idx);
59 auto Glatt = gf{mesh, {N_nu, N_nu}};
60 for (auto &&[n, w] : enumerate(mesh)) {
61 auto PSP = upfold_self_energy_at_freq(obe, obe.P, Sigma_dynamic, Sigma_static, n, k_idx, sigma_idx);
62 Glatt.data()(n, r_all, r_all) = inverse(w + mu - obe.H.H(sigma_idx, k_idx) - PSP);
63 }
64 return Glatt;
65 };
66 }
67 } // namespace detail
68
80 template <typename Mesh>
81 block2_gf<Mesh, matrix_valued> gloc_for_matrix_valued_dispersion_impl(one_body_elements_on_grid const &obe, double mu,
82 block2_gf<Mesh, matrix_valued> const &Sigma_dynamic,
83 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static) {
84
85 auto n_sigma = obe.C_space.n_sigma();
86 auto n_kpts = long(obe.H.n_k());
87
88 auto gloc_k = detail::local_gf_at_k(obe, mu, obe.P, Sigma_dynamic, Sigma_static);
89 auto gloc_result = make_block2_gf(Sigma_dynamic(0, 0).mesh(), obe.C_space.Gc_block_shape());
90
91 mpi::communicator comm = {};
92#pragma omp parallel for collapse(2) reduction(block2_gf_sum : gloc_result) default(none) shared(comm, gloc_k, n_kpts, n_sigma, obe, r_all)
93 for (auto k_idx : mpi::chunk(range(n_kpts), comm)) {
94 for (auto sigma : range(n_sigma)) {
95 auto P = obe.P.P(sigma, k_idx);
96 gloc_result(0, sigma).data()(r_all, r_all, r_all) += obe.H.k_weights(k_idx) * gloc_k(k_idx, sigma).data();
97 }
98 }
99
100 gloc_result = mpi::all_reduce(gloc_result);
101
102 if (auto const &S = obe.ibz_symm_ops; S) { gloc_result = S->symmetrize(gloc_result, obe.C_space.atomic_decomposition()); }
103 return gloc_result;
104 }
107 // ------------------------------------------------------------------
108
112
138 template <typename Mesh>
139 block2_gf<Mesh, matrix_valued> gloc(one_body_elements_on_grid const &obe, double mu, block2_gf<Mesh, matrix_valued> const &Sigma_dynamic,
140 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static) {
141
142 // intercept if the dispersion in obe is matrix valued. The Woodbury offers no performance gain for this case.
143 if (obe.H.matrix_valued) return gloc_for_matrix_valued_dispersion_impl(obe, mu, Sigma_dynamic, Sigma_static);
144
145 auto n_sigma = Sigma_dynamic.size2();
146 auto M = obe.C_space.dim();
147 auto n_kpts = long(obe.H.n_k());
148 auto const &mesh = Sigma_dynamic(0, 0).mesh();
149 auto gloc_result = make_block2_gf(mesh, obe.C_space.Gc_block_shape());
150 auto omegas = mesh | tl::to<std::vector<dcomplex>>();
151
152 // Embedding decomposition from structure of Sigma
153 auto embedding_decomp = get_struct(Sigma_dynamic).dims(r_all, 0) | tl::to<std::vector>();
154
155 auto timer = scoped_timer{};
156 // ---------
157 // NOTE: Is there any reason why sigma loop should be the external one?
158 // Internal is favorable for maximum parallelization.
159 mpi::communicator comm = {};
160#pragma omp parallel for collapse(2) reduction(block2_gf_sum : gloc_result) default(none) \
161 shared(comm, r_all, n_kpts, n_sigma, obe, mu, omegas, mesh, M, embedding_decomp, Sigma_dynamic, Sigma_static)
162 for (auto k_idx : mpi::chunk(range(n_kpts), comm)) {
163 for (auto sigma : range(n_sigma)) {
164 auto Y = detail::G0_C_k_sigma(obe, mu, k_idx, sigma, omegas, false);
165 for (auto &&[n, om] : itertools::enumerate(mesh)) {
166 auto Y1 = Y(n, r_all, r_all);
167 auto B = detail::calc_inv_G_G0(M, embedding_decomp, Sigma_dynamic, Sigma_static, om, sigma, Y1, Y1);
168 gloc_result(0, sigma).data()(n, r_all, r_all) += obe.H.k_weights(k_idx) * B;
169 }
170 }
171 // No normalization: the Pk are in obe ALREADY normalized.
172 }
173 gloc_result = mpi::all_reduce(gloc_result);
174
175 // FIXME :: the IBZ should work on a proper gf_view with atomic decomposition
176 // CHANGE IBZ accordingly ...
177 if (auto const &S = obe.ibz_symm_ops; S) gloc_result = S->symmetrize(gloc_result, obe.C_space.atomic_decomposition());
178 return gloc_result;
179 }
180
193 template <typename Mesh> block2_gf<Mesh, matrix_valued> gloc(Mesh const &mesh, one_body_elements_on_grid const &obe, double mu) {
194 auto Sigma_dynamic = make_block2_gf(mesh, obe.C_space.Gc_block_shape());
195 auto Sigma_static = nda::array<nda::matrix<dcomplex>, 2>(1, obe.C_space.n_sigma());
196 for (auto [i, j] : Sigma_static.indices()) { Sigma_static(i, j) = nda::zeros<dcomplex>(obe.C_space.dim(), obe.C_space.dim()); }
197 return gloc(obe, mu, Sigma_dynamic, Sigma_static);
198 }
200
212 template <typename Mesh>
213 block_gf<Mesh, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels, block_gf<Mesh, matrix_valued> const &Gloc,
214 block_gf<Mesh, matrix_valued> const &Sigma_dynamic,
215 std::vector<nda::matrix<dcomplex>> const &Sigma_static) {
216 auto gf_struct = get_struct(Gloc);
217 auto mesh = Gloc[0].mesh();
218 auto Delta = block_gf{mesh, gf_struct};
219 auto n_blocks = gf_struct.size();
220 for (auto bl : range(n_blocks)) {
221 for (auto &&[n, w] : enumerate(mesh))
222 Delta[bl].data()(n, r_all, r_all) =
223 (w - epsilon_levels[bl] - inverse(Gloc[bl]).data()(n, r_all, r_all) - (Sigma_dynamic[bl].data()(n, r_all, r_all) + Sigma_static[bl]));
224 }
225 return Delta;
226 }
227
237 template <typename Mesh>
238 block_gf<Mesh, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels, block_gf<Mesh, matrix_valued> const &Gloc) {
239 auto Sigma_static = get_struct(Gloc) | stdv::transform([](auto &x) { return nda::zeros<dcomplex>(x.second, x.second); })
240 | tl::to<std::vector<nda::matrix<dcomplex>>>();
241 auto Sigma_dynamic = block_gf{Gloc[0].mesh(), get_struct(Gloc)};
242 return hybridization(epsilon_levels, Gloc, Sigma_dynamic, Sigma_static);
243 }
244
245 // ------------------------------------------------------
246
247 template block2_gf<imfreq, matrix_valued> gloc(one_body_elements_on_grid const &one_body, double mu,
248 block2_gf<imfreq, matrix_valued> const &Sigma_dynamic,
249 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static);
250 template block2_gf<imfreq, matrix_valued> gloc(imfreq const &mesh, one_body_elements_on_grid const &obe, double mu);
251 template block2_gf<dlr_imfreq, matrix_valued> gloc(one_body_elements_on_grid const &one_body, double mu,
252 block2_gf<dlr_imfreq, matrix_valued> const &Sigma_dynamic,
253 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static);
254 template block2_gf<dlr_imfreq, matrix_valued> gloc(dlr_imfreq const &mesh, one_body_elements_on_grid const &obe, double mu);
255 template block_gf<imfreq, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels,
256 block_gf<imfreq, matrix_valued> const &Gloc);
257 template block_gf<imfreq, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels,
258 block_gf<imfreq, matrix_valued> const &Gloc,
259 block_gf<imfreq, matrix_valued> const &Sigma_dynamic,
260 std::vector<nda::matrix<dcomplex>> const &Sigma_static);
261 template block_gf<dlr_imfreq, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels,
262 block_gf<dlr_imfreq, matrix_valued> const &Gloc);
263 template block_gf<dlr_imfreq, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels,
264 block_gf<dlr_imfreq, matrix_valued> const &Gloc,
265 block_gf<dlr_imfreq, matrix_valued> const &Sigma_dynamic,
266 std::vector<nda::matrix<dcomplex>> const &Sigma_static);
267
268} // namespace triqs::modest
long n_sigma() const
Dimension of the index.
auto atomic_decomposition() const
Transformed view containing the dimension of each atomic shell.
long dim() const
Dimension of the correlated space.
C2PY_IGNORE gf_struct2_t Gc_block_shape() const
Shape of the Green function in the correlated space, without block decomposition.
A utility class for measuring the execution time of a scope.
block2_gf< Mesh, matrix_valued > gloc(one_body_elements_on_grid const &obe, double mu, block2_gf< Mesh, matrix_valued > const &Sigma_dynamic, nda::array< nda::matrix< dcomplex >, 2 > const &Sigma_static)
Compute local Green's function on a mesh.
block_gf< Mesh, matrix_valued > hybridization(std::vector< nda::matrix< dcomplex > > const &epsilon_levels, block_gf< Mesh, matrix_valued > const &Gloc, block_gf< Mesh, matrix_valued > const &Sigma_dynamic, std::vector< nda::matrix< dcomplex > > const &Sigma_static)
Compute the hybridization function from the effective impurity levels, the local Green's function,...
block2_gf< Mesh, matrix_valued > make_block2_gf(Mesh const &mesh, gf_struct2_t const &gf_s)
Definition gf_supp.hpp:41
gf_struct_t get_struct(block_gf< Mesh > const &g)
Definition gf_supp.hpp:51
static constexpr auto r_all
Definition defs.hpp:40
generator< std::pair< long, nda::range > > enumerated_sub_slices(auto sub_div)
bool matrix_valued
Is the dispersion matrix-valued?
nda::array< double, 1 > k_weights
Weight in the BZ for each k-point.
long n_k() const
Number of k-points in the grid.
A one-body elements struct where all of the underlying data exists on a fixed momentum grid.
band_dispersion H
Band dispersion.
C2PY_IGNORE std::optional< ibz_symmetry_ops > ibz_symm_ops
IBZ symmetrizer after a k-sum.