TRIQS/triqs_modest unstable
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"
8#include <triqs/mesh.hpp>
9#include "utils/gf_supp.hpp"
10
11namespace triqs::modest {
12
13// omp reduction operation for block2_gf
14#pragma omp declare reduction(block2_gf_sum : block2_gf<imfreq, matrix_valued> : omp_out += omp_in) \
15 initializer(omp_priv = make_block2_gf(omp_orig(0, 0).mesh(), get_struct(omp_orig)))
16#pragma omp declare reduction(block2_gf_sum : block2_gf<dlr_imfreq, matrix_valued> : omp_out += omp_in) \
17 initializer(omp_priv = make_block2_gf(omp_orig(0, 0).mesh(), get_struct(omp_orig)))
18
19 namespace detail {
20
21 template <typename Mesh>
22 constexpr auto upfold_self_energy_at_freq(one_body_elements_on_grid const &obe, downfolding_projector const &Proj,
23 block2_gf<Mesh, matrix_valued> const &Sigma_dynamic,
24 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static, long w_idx, long k_idx, long sigma_idx) {
25 auto N_nu = obe.H.N_nu(sigma_idx, k_idx);
26 auto out = nda::zeros<dcomplex>(N_nu, N_nu);
27 for (auto &&[alpha, R] : enumerated_sub_slices(get_struct(Sigma_dynamic).dims(r_all, 0) | tl::to<std::vector>())) {
28 auto P = Proj.P(sigma_idx, k_idx)(R, r_all);
29 out(r_all, r_all) +=
30 dagger(P) * nda::matrix<dcomplex>{Sigma_dynamic(alpha, sigma_idx).data()(w_idx, r_all, r_all) + Sigma_static(alpha, sigma_idx)} * P;
31 }
32 return out;
33 }
34
35 // --------------------------------------------------------------------
36 template <typename Mesh>
37 constexpr auto local_gf_at_k(one_body_elements_on_grid const &obe, double const &mu, downfolding_projector const &Proj,
38 block2_gf<Mesh, matrix_valued> const &Sigma_dynamic, nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static) {
39 return [&](auto const &k_idx, auto const &sigma_idx) {
40 using nda::linalg::inv;
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 * inv(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 using nda::linalg::inv;
58 auto const &mesh = Sigma_dynamic(0, 0).mesh();
59 auto N_nu = obe.H.N_nu(sigma_idx, k_idx);
60 auto Glatt = gf{mesh, {N_nu, N_nu}};
61 for (auto &&[n, w] : enumerate(mesh)) {
62 auto PSP = upfold_self_energy_at_freq(obe, obe.P, Sigma_dynamic, Sigma_static, n, k_idx, sigma_idx);
63 Glatt.data()(n, r_all, r_all) = inv(w + mu - obe.H.H(sigma_idx, k_idx) - PSP);
64 }
65 return Glatt;
66 };
67 }
68 } // namespace detail
69
81 template <typename Mesh>
82 block2_gf<Mesh, matrix_valued> gloc_for_matrix_valued_dispersion_impl(one_body_elements_on_grid const &obe, double mu,
83 block2_gf<Mesh, matrix_valued> const &Sigma_dynamic,
84 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static) {
85
86 auto n_sigma = obe.C_space.n_sigma();
87 auto n_kpts = long(obe.H.n_k());
88
89 auto gloc_k = detail::local_gf_at_k(obe, mu, obe.P, Sigma_dynamic, Sigma_static);
90 auto gloc_result = make_block2_gf(Sigma_dynamic(0, 0).mesh(), obe.C_space.Gc_block_shape());
91
92 mpi::communicator comm = {};
93#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)
94 for (auto k_idx : mpi::chunk(range(n_kpts), comm)) {
95 for (auto sigma : range(n_sigma)) { gloc_result(0, sigma).data()(r_all, r_all, r_all) += obe.H.k_weights(k_idx) * gloc_k(k_idx, sigma).data(); }
96 }
97
98 gloc_result = mpi::all_reduce(gloc_result);
99
100 if (auto const &S = obe.ibz_symm_ops; S) { gloc_result = S->symmetrize(gloc_result, obe.C_space.atomic_decomposition()); }
101 return gloc_result;
102 }
104
105 // ------------------------------------------------------------------
106
110
136 template <typename Mesh>
137 block2_gf<Mesh, matrix_valued> gloc(one_body_elements_on_grid const &obe, double mu, block2_gf<Mesh, matrix_valued> const &Sigma_dynamic,
138 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static) {
139
140 // intercept if the dispersion in obe is matrix valued. The Woodbury offers no performance gain for this case.
141 if (obe.H.matrix_valued) return gloc_for_matrix_valued_dispersion_impl(obe, mu, Sigma_dynamic, Sigma_static);
142
143 auto n_sigma = Sigma_dynamic.size2();
144 auto M = obe.C_space.dim();
145 auto n_kpts = long(obe.H.n_k());
146 auto const &mesh = Sigma_dynamic(0, 0).mesh();
147 auto gloc_result = make_block2_gf(mesh, obe.C_space.Gc_block_shape());
148 auto omegas = mesh | tl::to<std::vector<dcomplex>>();
149
150 // Embedding decomposition from structure of Sigma
151 auto embedding_decomp = get_struct(Sigma_dynamic).dims(r_all, 0) | tl::to<std::vector>();
152
153 // ---------
154 // NOTE: Is there any reason why sigma loop should be the external one?
155 // Internal is favorable for maximum parallelization.
156 mpi::communicator comm = {};
157#pragma omp parallel for collapse(2) reduction(block2_gf_sum : gloc_result) default(none) \
158 shared(comm, r_all, n_kpts, n_sigma, obe, mu, omegas, mesh, M, embedding_decomp, Sigma_dynamic, Sigma_static)
159 for (auto k_idx : mpi::chunk(range(n_kpts), comm)) {
160 for (auto sigma : range(n_sigma)) {
161 auto Y = detail::G0_C_k_sigma(obe, mu, k_idx, sigma, omegas, false);
162 for (auto &&[n, om] : itertools::enumerate(mesh)) {
163 auto Y1 = Y(n, r_all, r_all);
164 auto B = detail::calc_inv_G_G0(M, embedding_decomp, Sigma_dynamic, Sigma_static, om, sigma, Y1, Y1);
165 gloc_result(0, sigma).data()(n, r_all, r_all) += obe.H.k_weights(k_idx) * B;
166 }
167 }
168 // No normalization: the Pk are in obe ALREADY normalized.
169 }
170 gloc_result = mpi::all_reduce(gloc_result);
171
172 // FIXME :: the IBZ should work on a proper gf_view with atomic decomposition
173 // CHANGE IBZ accordingly ...
174 if (auto const &S = obe.ibz_symm_ops; S) gloc_result = S->symmetrize(gloc_result, obe.C_space.atomic_decomposition());
175 return gloc_result;
176 }
177
190 template <typename Mesh> block2_gf<Mesh, matrix_valued> gloc(Mesh const &mesh, one_body_elements_on_grid const &obe, double mu) {
191 auto Sigma_dynamic = make_block2_gf(mesh, obe.C_space.Gc_block_shape());
192 auto Sigma_static = nda::array<nda::matrix<dcomplex>, 2>(1, obe.C_space.n_sigma());
193 for (auto [i, j] : Sigma_static.indices()) { Sigma_static(i, j) = nda::zeros<dcomplex>(obe.C_space.dim(), obe.C_space.dim()); }
194 return gloc(obe, mu, Sigma_dynamic, Sigma_static);
195 }
196
197
209 template <typename Mesh>
210 block_gf<Mesh, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels, block_gf<Mesh, matrix_valued> const &Gloc,
211 block_gf<Mesh, matrix_valued> const &Sigma_dynamic,
212 std::vector<nda::matrix<dcomplex>> const &Sigma_static) {
213 auto gf_struct = Gloc.gf_struct();
214 auto mesh = Gloc[0].mesh();
215 auto Delta = block_gf{mesh, gf_struct};
216 auto n_blocks = gf_struct.size();
217 for (auto bl : range(n_blocks)) {
218 for (auto &&[n, w] : enumerate(mesh))
219 Delta[bl].data()(n, r_all, r_all) =
220 (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]));
221 }
222 return Delta;
223 }
224
234 template <typename Mesh>
235 block_gf<Mesh, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels, block_gf<Mesh, matrix_valued> const &Gloc) {
236 auto Sigma_static = Gloc.gf_struct() | stdv::transform([](auto &x) { return nda::zeros<dcomplex>(x.second, x.second); })
237 | tl::to<std::vector<nda::matrix<dcomplex>>>();
238 auto Sigma_dynamic = block_gf{Gloc[0].mesh(), Gloc.gf_struct()};
239 return hybridization(epsilon_levels, Gloc, Sigma_dynamic, Sigma_static);
240 }
241
242 // ------------------------------------------------------
243
244 template block2_gf<imfreq, matrix_valued> gloc(one_body_elements_on_grid const &one_body, double mu,
245 block2_gf<imfreq, matrix_valued> const &Sigma_dynamic,
246 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static);
247 template block2_gf<imfreq, matrix_valued> gloc(imfreq const &mesh, one_body_elements_on_grid const &obe, double mu);
248 template block2_gf<dlr_imfreq, matrix_valued> gloc(one_body_elements_on_grid const &one_body, double mu,
249 block2_gf<dlr_imfreq, matrix_valued> const &Sigma_dynamic,
250 nda::array<nda::matrix<dcomplex>, 2> const &Sigma_static);
251 template block2_gf<dlr_imfreq, matrix_valued> gloc(dlr_imfreq const &mesh, one_body_elements_on_grid const &obe, double mu);
252 template block_gf<imfreq, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels,
253 block_gf<imfreq, matrix_valued> const &Gloc);
254 template block_gf<imfreq, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels,
255 block_gf<imfreq, matrix_valued> const &Gloc,
256 block_gf<imfreq, matrix_valued> const &Sigma_dynamic,
257 std::vector<nda::matrix<dcomplex>> const &Sigma_static);
258 template block_gf<dlr_imfreq, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels,
259 block_gf<dlr_imfreq, matrix_valued> const &Gloc);
260 template block_gf<dlr_imfreq, matrix_valued> hybridization(std::vector<nda::matrix<dcomplex>> const &epsilon_levels,
261 block_gf<dlr_imfreq, matrix_valued> const &Gloc,
262 block_gf<dlr_imfreq, matrix_valued> const &Sigma_dynamic,
263 std::vector<nda::matrix<dcomplex>> const &Sigma_static);
264
265} // namespace triqs::modest
long n_sigma() const
Dimension of the index.
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.
std::vector< long > atomic_decomposition() const
Dimensions of each atomic shell, in order.
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:33
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.