TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
imfreq.hpp
Go to the documentation of this file.
1// Copyright (c) 2016-2018 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2// Copyright (c) 2016-2018 Centre national de la recherche scientifique (CNRS)
3// Copyright (c) 2018-2023 Simons Foundation
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You may obtain a copy of the License at
16// https://www.gnu.org/licenses/gpl-3.0.txt
17//
18// Authors: Michel Ferrero, Olivier Parcollet, Nils Wentzell
19
24
25#pragma once
26
27#include "./functions2.hpp"
28#include "../gf/gf.hpp"
29#include "../gf/gf_view.hpp"
30#include "../block/block_gf.hpp"
33
36#include "../../mesh/imfreq.hpp"
37#include "../../mesh/imtime.hpp"
38
39#include <algorithm>
40#include <cmath>
41#include <type_traits>
42#include <utility>
43
44namespace triqs::gfs {
45
46 // Elevated from nda (name not found via ADL on some compilers).
47 using nda::conj; // not found on gcc 5
48
49 // --------------------------- A few specific functions ---------------------------------
50
63 if (!g.mesh().positive_only()) TRIQS_RUNTIME_ERROR << "gf imfreq is not for omega_n >0, real_to_complex does not apply";
64 auto const &dat = g.data();
65 auto sh = dat.shape();
66 int is_boson = (g.mesh().statistic() == Boson);
67 long L = sh[0];
68 sh[0] = 2 * sh[0] - is_boson;
69 array<dcomplex, std::decay_t<decltype(dat)>::rank> new_data(sh);
70 auto ell = nda::ellipsis{};
71 if (is_boson) new_data(L - 1, ell) = dat(0, ell);
72 long L1 = (is_boson ? L - 1 : L);
73 for (long u = is_boson; u < L; ++u) {
74 new_data(L1 + u, ell) = dat(u, ell);
75 new_data(L - 1 - u, ell) = conj(dat(u, ell));
76 }
77 return {mesh::imfreq{g.mesh().beta(), g.mesh().statistic(), L}, std::move(new_data)};
78 }
79
88 template <typename G>
90 positive_freq_view(G &&g) // NOLINT(cppcoreguidelines-missing-std-forward): the returned view binds to g's data; g is not moved
91 requires(is_gf_v<G>)
92 {
93 static_assert(std::is_same_v<typename std::decay_t<G>::mesh_t, mesh::imfreq>, "positive_freq_view only makes senses for imfreq gf");
94 static_assert(std::decay_t<G>::is_view or std::is_lvalue_reference_v<G>, "Cannot construct a positive_freq_view from a temporary gf");
95 if (g.mesh().positive_only()) return g;
96 long L = g.mesh().size();
97 long L1 = (L + 1) / 2; // fermion : L is even. boson, L = 2p+1 --> p+1
98 int is_boson = (g.mesh().statistic() == Boson);
99 return {g.mesh().get_positive_freq(), g.data()(range(L1 - is_boson, L), nda::ellipsis())};
100 }
101
122 template <typename G>
123 bool is_gf_hermitian(G const &g, double tolerance = 1.e-12)
124 requires(is_gf_v<G> or is_block_gf_v<G>)
125 {
126 if constexpr (is_gf_v<G>) {
127 using target_t = typename G::target_t;
128 using mesh_t = typename std::decay_t<G>::mesh_t;
129 static_assert(std::is_same_v<mesh_t, mesh::imfreq> or std::is_same_v<mesh_t, mesh::imtime> or std::is_same_v<mesh_t, mesh::dlr_imfreq>
130 or std::is_same_v<mesh_t, mesh::dlr_imtime>,
131 "is_gf_hermitian requires an imfreq, imtime, dlr_imfreq or dlr_imtime Green function");
132 static_assert(target_t::rank == 0 or target_t::rank == 2 or target_t::rank == 4,
133 "is_gf_hermitian requires a Green function with a target rank of 0, 2 or 4.");
134
135 if constexpr (std::is_same_v<mesh_t, mesh::imfreq>) { // === gf<imfreq>
136 if (g.mesh().positive_only()) return true;
137 //for (auto w : g.mesh().get_positive_freq()) {
138 for (auto w : g.mesh()) {
139 if constexpr (target_t::rank == 0) { // ------ scalar_valued
140 if (abs(conj(g[-w]) - g[w]) > tolerance) return false;
141 } else if constexpr (target_t::rank == 2) { // matrix_valued
142 if (max_element(abs(dagger(g[-w]) - g[w])) > tolerance) return false;
143 } else { // ---------------------------------- tensor_valued<4>
144 for (auto [i, j, k, l] : g.target_indices())
145 if (abs(conj(g[-w](k, l, i, j)) - g[w](i, j, k, l)) > tolerance) return false;
146 }
147 }
148 return true;
149 } else if constexpr (std::is_same_v<mesh_t, mesh::dlr_imfreq>) { // === gf<dlr_imfreq>
150 // Requires symmetrize=true so that DLR nodes come in (iw, -iw) pairs
151 TRIQS_ASSERT(g.mesh().symmetrize());
152 long N = g.mesh().size();
153 for (long d = 0; d < N / 2; ++d) {
154 long d_neg = N - 1 - d;
155 if constexpr (target_t::rank == 0) { // ------ scalar_valued
156 if (abs(conj(g.data()(d_neg)) - g.data()(d)) > tolerance) return false;
157 } else if constexpr (target_t::rank == 2) { // matrix_valued
158 if (max_element(abs(dagger(g.data()(d_neg, ellipsis())) - g.data()(d, ellipsis()))) > tolerance) return false;
159 } else { // ---------------------------------- tensor_valued<4>
160 for (auto [i, j, k, l] : g.target_indices())
161 if (abs(conj(g.data()(d_neg, k, l, i, j)) - g.data()(d, i, j, k, l)) > tolerance) return false;
162 }
163 }
164 return true;
165 } else if constexpr (std::is_same_v<mesh_t, mesh::dlr_imtime>) { // === gf<dlr_imtime>
166 for (long d = 0; d < g.mesh().size(); ++d) {
167 if constexpr (target_t::rank == 0) { // ------ scalar_valued
168 if (abs(conj(g.data()(d)) - g.data()(d)) > tolerance) return false;
169 } else if constexpr (target_t::rank == 2) { // matrix_valued
170 for (auto [i, j] : g.target_indices())
171 if (abs(conj(g.data()(d, j, i)) - g.data()(d, i, j)) > tolerance) return false;
172 } else { // ---------------------------------- tensor_valued<4>
173 for (auto [i, j, k, l] : g.target_indices())
174 if (abs(conj(g.data()(d, k, l, i, j)) - g.data()(d, i, j, k, l)) > tolerance) return false;
175 }
176 }
177 return true;
178 } else { // === gf<imtime>
179 for (auto t : g.mesh()) {
180 if constexpr (target_t::rank == 0) { // ------ scalar_valued
181 if (abs(conj(g[t]) - g[t]) > tolerance) return false;
182 } else if constexpr (target_t::rank == 2) { // matrix_valued
183 for (auto [i, j] : g.target_indices())
184 if (abs(conj(g[t](j, i)) - g[t](i, j)) > tolerance) return false;
185 } else { // ---------------------------------- tensor_valued<4>
186 for (auto [i, j, k, l] : g.target_indices())
187 if (abs(conj(g[t](k, l, i, j)) - g[t](i, j, k, l)) > tolerance) return false;
188 }
189 }
190 return true;
191 }
192 } else { // Block Green function
193 return std::all_of(g.begin(), g.end(), [&](auto &g_bl) { return is_gf_hermitian<typename G::g_t>(g_bl, tolerance); });
194 }
195 }
196
211 template <typename G> bool is_gf_real_in_tau(G const &g, double tolerance = 1.e-12) {
212 if constexpr (is_gf_v<G>) {
213 using target_t = typename G::target_t;
214 using mesh_t = typename std::decay_t<G>::mesh_t;
215 static_assert(std::is_same_v<mesh_t, mesh::imfreq>, "is_gf_hermitian requires an imfreq Green function");
216
217 if (g.mesh().positive_only()) return true;
218 for (auto w : g.mesh()) {
219 if constexpr (target_t::rank == 0) { // ---- scalar_valued
220 if (abs(conj(g[-w]) - g[w]) > tolerance) return false;
221 } else {
222 if (max_element(abs(conj(g[-w]) - g[w])) > tolerance) return false;
223 }
224 }
225 return true;
226 } else { // Block Green function
227 return std::all_of(g.begin(), g.end(), [&](auto &g_bl) { return is_gf_real_in_tau<typename G::g_t>(g_bl, tolerance); });
228 }
229 }
230
250 template <typename G>
251 typename G::regular_type make_hermitian(G const &g)
252 requires(is_gf_v<G> or is_block_gf_v<G>)
253 {
254 if constexpr (is_gf_v<G>) {
255 using target_t = typename G::target_t;
256 using mesh_t = typename std::decay_t<G>::mesh_t;
257 static_assert(std::is_same_v<mesh_t, mesh::imfreq> or std::is_same_v<mesh_t, mesh::imtime> or std::is_same_v<mesh_t, mesh::dlr_imfreq>
258 or std::is_same_v<mesh_t, mesh::dlr_imtime>,
259 "make_hermitian requires an imfreq, imtime, dlr_imfreq or dlr_imtime Green function");
260 static_assert(target_t::rank == 0 or target_t::rank == 2 or target_t::rank == 4,
261 "make_hermitian requires a Green function with a target rank of 0, 2 or 4.");
262
263 if constexpr (std::is_same_v<mesh_t, mesh::imfreq>) { // === gf<imfreq>
264 if (g.mesh().positive_only()) return typename G::regular_type{g};
265 auto g_sym = typename G::regular_type{g};
266 for (auto w : g.mesh()) {
267 if constexpr (target_t::rank == 0) // ---- scalar_valued
268 g_sym[w] = 0.5 * (g[w] + conj(g[-w]));
269 else if constexpr (target_t::rank == 2) // matrix_valued
270 g_sym[w] = 0.5 * (g[w] + dagger(g[-w]));
271 else // ---------------------------------- tensor_valued<4>
272 for (auto [i, j, k, l] : g.target_indices()) g_sym[w](i, j, k, l) = 0.5 * (g[w](i, j, k, l) + conj(g[-w](k, l, i, j)));
273 }
274 return g_sym;
275
276 } else if constexpr (std::is_same_v<mesh_t, mesh::dlr_imfreq>) { // === gf<dlr_imfreq>
277 TRIQS_ASSERT(g.mesh().symmetrize());
278 auto g_sym = typename G::regular_type{g};
279 long N = g.mesh().size();
280 for (long d = 0; d < N; ++d) {
281 long d_neg = N - 1 - d;
282 if constexpr (target_t::rank == 0)
283 g_sym.data()(d) = 0.5 * (g.data()(d) + conj(g.data()(d_neg)));
284 else if constexpr (target_t::rank == 2)
285 g_sym.data()(d, ellipsis()) = 0.5 * (g.data()(d, ellipsis()) + dagger(g.data()(d_neg, ellipsis())));
286 else
287 for (auto [i, j, k, l] : g.target_indices())
288 g_sym.data()(d, i, j, k, l) = 0.5 * (g.data()(d, i, j, k, l) + conj(g.data()(d_neg, k, l, i, j)));
289 }
290 return g_sym;
291 } else { // === gf<imtime> or gf<dlr_imtime>
292 auto g_sym = typename G::regular_type{g};
293 for (long d = 0; d < g.mesh().size(); ++d) {
294 if constexpr (target_t::rank == 0) // ---- scalar_valued
295 g_sym.data()(d) = 0.5 * (g.data()(d) + conj(g.data()(d)));
296 else if constexpr (target_t::rank == 2) // matrix_valued
297 for (auto [i, j] : g.target_indices()) g_sym.data()(d, i, j) = 0.5 * (g.data()(d, i, j) + conj(g.data()(d, j, i)));
298 else // ---------------------------------- tensor_valued<4>
299 for (auto [i, j, k, l] : g.target_indices())
300 g_sym.data()(d, i, j, k, l) = 0.5 * (g.data()(d, i, j, k, l) + conj(g.data()(d, k, l, i, j)));
301 }
302 return g_sym;
303 }
304 } else if (is_block_gf_v<G>) { // Block Green function
306 }
307 }
308
322 template <typename G>
323 typename G::regular_type make_real_in_tau(G const &g)
324 requires(is_gf_v<G> or is_block_gf_v<G>)
325 {
326 if constexpr (is_gf_v<G>) {
327 using mesh_t = typename std::decay_t<G>::mesh_t;
328 static_assert(std::is_same_v<mesh_t, mesh::imfreq>, "make_real_in_tau requires an imfreq Green function");
329
330 if (g.mesh().positive_only()) return typename G::regular_type{g};
331 auto g_sym = typename G::regular_type{g};
332 for (auto w : g.mesh()) { g_sym[w] = 0.5 * (g[w] + conj(g[-w])); }
333 return g_sym;
334 } else if (is_block_gf_v<G>) { // Block Green function
336 }
337 }
338
339 // ------------------------------------------------------------------------------------------------------
340
351 template <template <typename, typename, typename...> typename G, typename T> auto restricted_view(G<mesh::imfreq, T> const &g, int n_max) {
352 auto iw_mesh = mesh::imfreq{g.mesh().beta(), Fermion, n_max};
353
354 auto const &old_mesh = g.mesh();
355 int idx_min = old_mesh.to_data_index(iw_mesh.first_index());
356 int idx_max = old_mesh.to_data_index(iw_mesh.last_index());
357 auto data_view = g.data()(range(idx_min, idx_max + 1), ellipsis());
358
359 return typename G<mesh::imfreq, T>::const_view_type{iw_mesh, data_view};
360 }
361
374 template <typename T> void replace_by_tail(gf_view<mesh::imfreq, T> g, array_const_view<dcomplex, 1 + T::rank> tail, int n_min) {
375 for (auto iw : g.mesh())
376 if (iw.n >= n_min or iw.n < -n_min) g[iw] = mesh::detail::tail_eval(tail, iw);
377 }
378
390 template <typename T> void replace_by_tail_in_fit_window(gf_view<mesh::imfreq, T> g, array_const_view<dcomplex, 1 + T::rank> tail) {
391 int n_pts_in_fit_range = int(std::round(g.mesh().get_tail_fitter().get_tail_fraction() * g.mesh().size() / 2));
392 int n_min = g.mesh().last_index() - n_pts_in_fit_range;
393 replace_by_tail(g, tail, n_min);
394 }
395
414 template <template <typename, typename, typename...> typename G, typename T>
415 auto fit_tail_on_window(G<mesh::imfreq, T> const &g, int n_min, int n_max, array_const_view<dcomplex, 3> known_moments, int n_tail_max,
416 int expansion_order) {
417 if (n_max == -1) n_max = g.mesh().last_index();
418 auto g_rview = restricted_view(g, n_max);
419 double tail_fraction = static_cast<double>(n_max - n_min) / n_max;
420 g_rview.mesh().set_tail_fit_parameters(tail_fraction, n_tail_max, expansion_order);
421 return fit_tail(g_rview, known_moments);
422 }
423
441 template <template <typename, typename...> typename G, typename T>
442 auto fit_hermitian_tail_on_window(G<mesh::imfreq, T> const &g, int n_min, int n_max, array_const_view<dcomplex, 3> known_moments, int n_tail_max,
443 int expansion_order) {
444 if (n_max == -1) n_max = g.mesh().last_index();
445 auto g_rview = restricted_view(g, n_max);
446 double tail_fraction = static_cast<double>(n_max - n_min) / n_max;
447 g_rview.mesh().set_tail_fit_parameters(tail_fraction, n_tail_max, expansion_order);
448 return fit_hermitian_tail(g_rview, known_moments);
449 }
450} // namespace triqs::gfs
int size() const
Get the total number of blocks.
Provides the block Green's function container.
A read-only, non-owning view of a Green's function.
mesh_t const & mesh() const
Get the mesh of the Green's function.
data_t & data() &
Get the data array view.
A mutable, non-owning view of a Green's function.
Definition gf_view.hpp:48
mesh_t const & mesh() const
Get the mesh of the Green's function.
Definition gf_view.hpp:125
The owning Green's function container.
Definition gf.hpp:194
Imaginary frequency mesh type.
Definition imfreq.hpp:102
data_index_t to_data_index(index_t n) const noexcept
Map a Matsubara index to its corresponding data index .
Definition imfreq.hpp:230
Provides a mesh type for the discrete Lehmann representation in imaginary frequency space.
Provides a mesh type for the discrete Lehmann representation in imaginary time.
TRIQS exception hierarchy and related macros.
Provides tail fitting, slicing, inversion, reality and matrix-multiplication functions for Green's fu...
Provides a mutable non-owning view of a Green's function.
Provides the Green's function class.
auto map_block_gf(F &&f, G &&g)
Apply a callable to each block of a block Green's function.
Definition map.hpp:131
G::regular_type make_real_in_tau(G const &g)
Symmetrize a Matsubara Green's function so that its imaginary-time partner is real-valued.
Definition imfreq.hpp:323
G::regular_type make_hermitian(G const &g)
Symmetrize a Green's function so that it satisfies the hermitian symmetry.
Definition imfreq.hpp:251
G::regular_type conj(G const &g)
Complex-conjugate a Green's function, returning a new Green's function.
bool is_gf_hermitian(G const &g, double tolerance=1.e-12)
Test whether a Green's function satisfies the hermitian symmetry up to a tolerance .
Definition imfreq.hpp:123
gf< mesh::imfreq, T > make_gf_from_real_gf(gf_const_view< mesh::imfreq, T, Layout > g)
Build a full-mesh Matsubara Green's function from one defined on positive frequencies only.
Definition imfreq.hpp:62
bool is_gf_real_in_tau(G const &g, double tolerance=1.e-12)
Test whether a Matsubara Green's function corresponds to a real imaginary-time Green's function.
Definition imfreq.hpp:211
view_or_type_t< std::decay_t< G > > positive_freq_view(G &&g)
Make a view of the positive-frequency part of a Matsubara Green's function.
Definition imfreq.hpp:90
auto restricted_view(G< mesh::imfreq, T > const &g, int n_max)
Make a const view of a Matsubara Green's function restricted to the first n_max frequency indices.
Definition imfreq.hpp:351
std::pair< typename A::regular_type, double > fit_hermitian_tail(G const &g, A const &known_moments={})
Fit the high-frequency tail of a Green's function, imposing hermitian symmetry on the fitted moments.
void replace_by_tail_in_fit_window(gf_view< mesh::imfreq, T > g, array_const_view< dcomplex, 1+T::rank > tail)
Overwrite the high-frequency portion of a Matsubara Green's function with the tail expansion.
Definition imfreq.hpp:390
auto fit_hermitian_tail_on_window(G< mesh::imfreq, T > const &g, int n_min, int n_max, array_const_view< dcomplex, 3 > known_moments, int n_tail_max, int expansion_order)
Fit the high-frequency tail on a restricted window, imposing hermitian moment matrices.
Definition imfreq.hpp:442
void replace_by_tail(gf_view< mesh::imfreq, T > g, array_const_view< dcomplex, 1+T::rank > tail, int n_min)
Overwrite the high-frequency tail of a Matsubara Green's function.
Definition imfreq.hpp:374
auto fit_tail_on_window(G< mesh::imfreq, T > const &g, int n_min, int n_max, array_const_view< dcomplex, 3 > known_moments, int n_tail_max, int expansion_order)
Fit the high-frequency tail of a Matsubara Green's function on a restricted frequency window.
Definition imfreq.hpp:415
std::pair< typename A::regular_type, double > fit_tail(G const &g, A const &known_moments={})
Fit the high-frequency tail of a Green's function using a least-squares procedure.
constexpr bool is_block_gf_v
Trait to check whether a type is a block Green's function.
Definition block_gf.hpp:119
constexpr bool is_gf_v
Trait to check whether a type models the Green's function concept.
Definition gf.hpp:101
auto tail_eval(nda::array_const_view< std::complex< double >, R > A, std::complex< double > z_0)
Evaluate the tail expansion of a function at a given point .
#define TRIQS_RUNTIME_ERROR
Throw a triqs::runtime_error with the current source location.
#define TRIQS_ASSERT(X)
Throw a triqs::runtime_error if the boolean expression X evaluates to false.
typename details::_view_or_type< T >::type view_or_type_t
Get the view type of a given type T if it exists.
Provides a mesh type on the imaginary frequency axis.
Provides a mesh type on the imaginary time axis.
Aliases that map a TRIQS container type to its regular / view / const-view companion.