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 using nda::linalg::inv;
42 auto const n_M = obe.C_space.dim();
43 auto const &mesh = Sigma_dynamic(0, 0).mesh();
44 auto out = gf{mesh, {n_M, n_M}};
45 auto P = obe.P.P(sigma_idx, k_idx);
46 for (auto &&[n, w] : enumerate(mesh)) {
47 auto PSP = upfold_self_energy_at_freq(obe, Proj, Sigma_dynamic, Sigma_static, n, k_idx, sigma_idx);
48 out.data()(n, r_all, r_all) = P * inv(w + mu - obe.H.H(sigma_idx, k_idx) - PSP) * dagger(P);
49 }
50 return out;
51 };
52 }
53
54 template <typename Mesh>
55 constexpr auto lattice_gf_at_k(one_body_elements_on_grid const &obe, double const &mu, block2_gf<Mesh, matrix_valued> const &Sigma_dynamic,
56 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static) {
57 return [&](auto const &k_idx, auto const &sigma_idx) {
58 using nda::linalg::inv;
59 auto const &mesh = Sigma_dynamic(0, 0).mesh();
60 auto N_nu = obe.H.N_nu(sigma_idx, k_idx);
61 auto Glatt = gf{mesh, {N_nu, N_nu}};
62 for (auto &&[n, w] : enumerate(mesh)) {
63 auto PSP = upfold_self_energy_at_freq(obe, obe.P, Sigma_dynamic, Sigma_static, n, k_idx, sigma_idx);
64 Glatt.data()(n, r_all, r_all) = inv(w + mu - obe.H.H(sigma_idx, k_idx) - PSP);
65 }
66 return Glatt;
67 };
68 }
69 } // namespace detail
70
82 template <typename Mesh>
83 block2_gf<Mesh, matrix_valued> gloc_for_matrix_valued_dispersion_impl(one_body_elements_on_grid const &obe, double mu,
84 block2_gf<Mesh, matrix_valued> const &Sigma_dynamic,
85 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static) {
86
87 auto n_sigma = obe.C_space.n_sigma();
88 auto n_kpts = long(obe.H.n_k());
89
90 auto gloc_k = detail::local_gf_at_k(obe, mu, obe.P, Sigma_dynamic, Sigma_static);
91 auto gloc_result = make_block2_gf(Sigma_dynamic(0, 0).mesh(), obe.C_space.Gc_block_shape());
92
93 mpi::communicator comm = {};
94#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)
95 for (auto k_idx : mpi::chunk(range(n_kpts), comm)) {
96 for (auto sigma : range(n_sigma)) {
97 auto P = obe.P.P(sigma, k_idx);
98 gloc_result(0, sigma).data()(r_all, r_all, r_all) += obe.H.k_weights(k_idx) * gloc_k(k_idx, sigma).data();
99 }
100 }
101
102 gloc_result = mpi::all_reduce(gloc_result);
103
104 if (auto const &S = obe.ibz_symm_ops; S) { gloc_result = S->symmetrize(gloc_result, obe.C_space.atomic_decomposition()); }
105 return gloc_result;
106 }
109 // ------------------------------------------------------------------
110
114
140 template <typename Mesh>
141 block2_gf<Mesh, matrix_valued> gloc(one_body_elements_on_grid const &obe, double mu, block2_gf<Mesh, matrix_valued> const &Sigma_dynamic,
142 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static) {
143
144 // intercept if the dispersion in obe is matrix valued. The Woodbury offers no performance gain for this case.
145 if (obe.H.matrix_valued) return gloc_for_matrix_valued_dispersion_impl(obe, mu, Sigma_dynamic, Sigma_static);
146
147 auto n_sigma = Sigma_dynamic.size2();
148 auto M = obe.C_space.dim();
149 auto n_kpts = long(obe.H.n_k());
150 auto const &mesh = Sigma_dynamic(0, 0).mesh();
151 auto gloc_result = make_block2_gf(mesh, obe.C_space.Gc_block_shape());
152 auto omegas = mesh | tl::to<std::vector<dcomplex>>();
153
154 // Embedding decomposition from structure of Sigma
155 auto embedding_decomp = get_struct(Sigma_dynamic).dims(r_all, 0) | tl::to<std::vector>();
156
157 auto timer = scoped_timer{};
158 // ---------
159 // NOTE: Is there any reason why sigma loop should be the external one?
160 // Internal is favorable for maximum parallelization.
161 mpi::communicator comm = {};
162#pragma omp parallel for collapse(2) reduction(block2_gf_sum : gloc_result) default(none) \
163 shared(comm, r_all, n_kpts, n_sigma, obe, mu, omegas, mesh, M, embedding_decomp, Sigma_dynamic, Sigma_static)
164 for (auto k_idx : mpi::chunk(range(n_kpts), comm)) {
165 for (auto sigma : range(n_sigma)) {
166 auto Y = detail::G0_C_k_sigma(obe, mu, k_idx, sigma, omegas, false);
167 for (auto &&[n, om] : itertools::enumerate(mesh)) {
168 auto Y1 = Y(n, r_all, r_all);
169 auto B = detail::calc_inv_G_G0(M, embedding_decomp, Sigma_dynamic, Sigma_static, om, sigma, Y1, Y1);
170 gloc_result(0, sigma).data()(n, r_all, r_all) += obe.H.k_weights(k_idx) * B;
171 }
172 }
173 // No normalization: the Pk are in obe ALREADY normalized.
174 }
175 gloc_result = mpi::all_reduce(gloc_result);
176
177 // FIXME :: the IBZ should work on a proper gf_view with atomic decomposition
178 // CHANGE IBZ accordingly ...
179 if (auto const &S = obe.ibz_symm_ops; S) gloc_result = S->symmetrize(gloc_result, obe.C_space.atomic_decomposition());
180 return gloc_result;
181 }
182
195 template <typename Mesh> block2_gf<Mesh, matrix_valued> gloc(Mesh const &mesh, one_body_elements_on_grid const &obe, double mu) {
196 auto Sigma_dynamic = make_block2_gf(mesh, obe.C_space.Gc_block_shape());
197 auto Sigma_static = nda::array<nda::matrix<dcomplex>, 2>(1, obe.C_space.n_sigma());
198 for (auto [i, j] : Sigma_static.indices()) { Sigma_static(i, j) = nda::zeros<dcomplex>(obe.C_space.dim(), obe.C_space.dim()); }
199 return gloc(obe, mu, Sigma_dynamic, Sigma_static);
200 }
202
214 template <typename Mesh>
215 block_gf<Mesh, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels, block_gf<Mesh, matrix_valued> const &Gloc,
216 block_gf<Mesh, matrix_valued> const &Sigma_dynamic,
217 std::vector<nda::matrix<dcomplex>> const &Sigma_static) {
218 auto gf_struct = Gloc.gf_struct();
219 auto mesh = Gloc[0].mesh();
220 auto Delta = block_gf{mesh, gf_struct};
221 auto n_blocks = gf_struct.size();
222 for (auto bl : range(n_blocks)) {
223 for (auto &&[n, w] : enumerate(mesh))
224 Delta[bl].data()(n, r_all, r_all) =
225 (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]));
226 }
227 return Delta;
228 }
229
239 template <typename Mesh>
240 block_gf<Mesh, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels, block_gf<Mesh, matrix_valued> const &Gloc) {
241 auto Sigma_static = Gloc.gf_struct() | stdv::transform([](auto &x) { return nda::zeros<dcomplex>(x.second, x.second); })
242 | tl::to<std::vector<nda::matrix<dcomplex>>>();
243 auto Sigma_dynamic = block_gf{Gloc[0].mesh(), Gloc.gf_struct()};
244 return hybridization(epsilon_levels, Gloc, Sigma_dynamic, Sigma_static);
245 }
246
247 // ------------------------------------------------------
248
249 template block2_gf<imfreq, matrix_valued> gloc(one_body_elements_on_grid const &one_body, double mu,
250 block2_gf<imfreq, matrix_valued> const &Sigma_dynamic,
251 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static);
252 template block2_gf<imfreq, matrix_valued> gloc(imfreq const &mesh, one_body_elements_on_grid const &obe, double mu);
253 template block2_gf<dlr_imfreq, matrix_valued> gloc(one_body_elements_on_grid const &one_body, double mu,
254 block2_gf<dlr_imfreq, matrix_valued> const &Sigma_dynamic,
255 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static);
256 template block2_gf<dlr_imfreq, matrix_valued> gloc(dlr_imfreq const &mesh, one_body_elements_on_grid const &obe, double mu);
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 template block_gf<imfreq, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels,
260 block_gf<imfreq, matrix_valued> const &Gloc,
261 block_gf<imfreq, matrix_valued> const &Sigma_dynamic,
262 std::vector<nda::matrix<dcomplex>> const &Sigma_static);
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 template block_gf<dlr_imfreq, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels,
266 block_gf<dlr_imfreq, matrix_valued> const &Gloc,
267 block_gf<dlr_imfreq, matrix_valued> const &Sigma_dynamic,
268 std::vector<nda::matrix<dcomplex>> const &Sigma_static);
269
270} // 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,...
gf_struct2_t get_struct(block2_gf< Mesh, matrix_valued > const &g)
Definition gf_supp.hpp:52
block2_gf< Mesh, matrix_valued > make_block2_gf(Mesh const &mesh, gf_struct2_t const &gf_s)
Definition gf_supp.hpp:41
static constexpr auto r_all
Definition defs.hpp:40
generator< std::pair< long, nda::range > > enumerated_sub_slices(auto sub_div)
nda::array< long, 2 > dims
Definition gf_supp.hpp:37
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.
std::optional< ibz_symmetry_ops > ibz_symm_ops
IBZ symmetrizer after a k-sum.
band_dispersion H
Band dispersion.