TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
dlr.hpp
Go to the documentation of this file.
1// Copyright (c) 2023 Simons Foundation
2// Copyright (c) 2023 Hugo U.R. Strand
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You may obtain a copy of the License at
15// https://www.gnu.org/licenses/gpl-3.0.txt
16//
17// Authors: Michel Ferrero, Olivier Parcollet, Hugo U. R. Strand, Nils Wentzell
18
23
24#pragma once
25
26#include "../gf/flatten.hpp"
27#include "../gf/gf.hpp"
28#include "../block/block_gf.hpp"
31
32#include "../../mesh/dlr.hpp"
35#include "../../mesh/imfreq.hpp"
36#include "../../mesh/imtime.hpp"
37#include "../../mesh/prod.hpp"
38
39#include <array>
40#include <cmath>
41#include <vector>
42
43namespace triqs::gfs {
44
45 // Elevate the DLR mesh types into the triqs::gfs namespace.
46 using mesh::dlr;
47 using mesh::dlr_imfreq;
48 using mesh::dlr_imtime;
49
54
55 //-------------------------------------------------------
56 // Transformation of DLR Green's functions
57 // ------------------------------------------------------
58
59 // Apply f to mesh component N: helper for the make_gf_dlr* transforms; recurses over product-mesh components and blocks.
60 template <int N, int... Ns, typename F, typename G>
61 requires(MemoryGf<G> or is_block_gf_v<G>)
62 auto apply_to_mesh(F const &f, G const &g) {
63 using M = typename G::mesh_t;
64 if constexpr (sizeof...(Ns) > 0) {
65 return apply_to_mesh<Ns...>(f, apply_to_mesh<N>(f, g));
66 } else if constexpr (is_block_gf_v<G>) {
67 return map_block_gf([&](auto const &gbl) { return apply_to_mesh<N>(f, gbl); }, g);
68 } else {
69 static_assert(mesh::is_product<M>, "requires product mesh");
70 auto gfl = f(flatten_gf_2d<N>(g));
71 auto out_mesh = mesh::prod{triqs::tuple::replace<N>(g.mesh(), gfl.mesh())};
72 auto g_out = gf{out_mesh, g.target_shape()};
73 unflatten_gf_2d<N>(g_out, gfl);
74 return g_out;
75 }
76 }
77
92 template <int N = 0, int... Ns, typename G>
93 requires(MemoryGf<G> or is_block_gf_v<G>)
94 auto make_gf_dlr(G const &g) {
95 using M = typename G::mesh_t;
96 if constexpr (is_block_gf_v<G>) {
97 return map_block_gf([&](auto const &gbl) { return make_gf_dlr<N, Ns...>(gbl); }, g);
98 } else if constexpr (mesh::is_product<M>) {
99 return apply_to_mesh<N, Ns...>([&](auto const &gfl) { return make_gf_dlr(gfl); }, g);
100 } else {
101 static_assert(N == 0, "N must be 0 for non-product meshes");
102 static_assert(nda::AnyOf<M, dlr_imtime, dlr_imfreq>, "Mesh must be dlr_imtime or dlr_imfreq");
103 auto result = gf{dlr{g.mesh()}, g.target_shape()};
104 if constexpr (std::is_same_v<M, dlr_imtime>)
105 result.data() = result.mesh().dlr_it().vals2coefs(g.data());
106 else { // dlr_imfreq
107 auto beta_inv = 1. / result.mesh().beta();
108 result.data() = beta_inv * result.mesh().dlr_if().vals2coefs(g.data());
109 }
110 return result;
111 }
112 }
113
127 template <int N = 0, int... Ns, typename G>
128 requires(MemoryGf<G> or is_block_gf_v<G>)
129 auto fit_gf_dlr(G const &g, mesh::dlr const &dlr_mesh) {
130 using M = typename G::mesh_t;
131 if constexpr (is_block_gf_v<G>) {
132 return map_block_gf([&](auto const &gbl) { return fit_gf_dlr<N, Ns...>(gbl, dlr_mesh); }, g);
133 } else if constexpr (mesh::is_product<M>) {
134 return apply_to_mesh<N, Ns...>([&](auto const &gfl) { return fit_gf_dlr(gfl, dlr_mesh); }, g);
135 } else {
136 static_assert(N == 0, "N must be 0 for non-product meshes");
137 static_assert(std::is_same_v<M, mesh::imtime>, "Input mesh must be imtime");
138 auto tvals = nda::array_adapter(std::array{g.mesh().size()}, [&](auto i) { return g.mesh()[i].value() / g.mesh().beta(); });
139 auto result = gf{dlr_mesh, g.target_shape()};
140 result.data() = result.mesh().dlr_it().fitvals2coefs(make_regular(tvals), g.data());
141 return result;
142 }
143 }
144
161 template <int N = 0, int... Ns, typename G>
162 requires(MemoryGf<G> or is_block_gf_v<G>)
163 auto fit_gf_dlr(G const &g, double w_max, double eps, bool symmetrize = true) {
164 // Build the DLR mesh once from a representative imtime mesh and delegate to the
165 // mesh overload, which handles the block / product / leaf recursion.
166 auto const &imt = get_mesh<N>(g);
167 auto dlr_mesh = dlr{imt.beta(), imt.statistic(), w_max, eps, symmetrize};
168 return fit_gf_dlr<N, Ns...>(g, dlr_mesh);
169 }
170
183 template <int N = 0, int... Ns, typename G>
184 requires(MemoryGf<G> or is_block_gf_v<G>)
185 auto make_gf_dlr_imtime(G const &g) {
186 using M = typename G::mesh_t;
187 if constexpr (is_block_gf_v<G>) {
188 return map_block_gf([&](auto const &gbl) { return make_gf_dlr_imtime<N, Ns...>(gbl); }, g);
189 } else if constexpr (mesh::is_product<M>) {
190 return apply_to_mesh<N, Ns...>([&](auto const &gfl) { return make_gf_dlr_imtime(gfl); }, g);
191 } else if constexpr (std::is_same_v<M, dlr_imfreq>) {
193 } else {
194 static_assert(N == 0, "N must be 0 for non-product meshes");
195 static_assert(std::is_same_v<M, mesh::dlr>, "Input mesh must be dlr");
196 auto result = gf{dlr_imtime{g.mesh()}, g.target_shape()};
197 result.data() = g.mesh().dlr_it().coefs2vals(g.data());
198 return result;
199 }
200 }
201
214 template <int N = 0, int... Ns, typename G>
215 requires(MemoryGf<G> or is_block_gf_v<G>)
216 auto make_gf_dlr_imfreq(G const &g) {
217 using M = typename G::mesh_t;
218 if constexpr (is_block_gf_v<G>) {
219 return map_block_gf([&](auto const &gbl) { return make_gf_dlr_imfreq<N, Ns...>(gbl); }, g);
220 } else if constexpr (mesh::is_product<M>) {
221 return apply_to_mesh<N, Ns...>([&](auto const &gfl) { return make_gf_dlr_imfreq(gfl); }, g);
222 } else if constexpr (std::is_same_v<M, dlr_imtime>) {
224 } else {
225 static_assert(N == 0, "N must be 0 for non-product meshes");
226 static_assert(std::is_same_v<M, mesh::dlr>, "Input mesh must be dlr");
227 auto result = gf{dlr_imfreq{g.mesh()}, g.target_shape()};
228 auto beta = result.mesh().beta();
229 result.data() = beta * g.mesh().dlr_if().coefs2vals(g.data());
230 return result;
231 }
232 }
233
234 namespace detail {
235 template <typename G>
236 requires(MemoryGf<G> or is_block_gf_v<G>)
237 mesh::imfreq const &imfreq_mesh_of(G const &g) {
238 if constexpr (is_block_gf_v<G>)
239 return g[0].mesh();
240 else
241 return g.mesh();
242 }
243
244 // Factored out so make_gf_dlr_imfreq and find_w_max build the dlr_imfreq mesh
245 // once (the cppdlr SVD is not cheap) and reuse it across blocks / search iterations.
246 template <typename G>
247 requires(MemoryGf<G> or is_block_gf_v<G>)
248 auto sample_on_dlr_imfreq(G const &g, dlr_imfreq const &dlr_mesh) {
249 if constexpr (is_block_gf_v<G>) {
250 return map_block_gf([&](auto const &gbl) { return sample_on_dlr_imfreq(gbl, dlr_mesh); }, g);
251 } else {
252 static_assert(std::is_same_v<typename G::mesh_t, mesh::imfreq>, "Input mesh must be imfreq");
253 auto const &iw_mesh = g.mesh();
254 auto [iw_lo, iw_hi] = dlr_mesh.min_max_frequencies();
255 if (not iw_mesh.is_index_valid(iw_lo.n) or not iw_mesh.is_index_valid(iw_hi.n))
256 TRIQS_RUNTIME_ERROR << "make_gf_dlr_imfreq: input imfreq mesh does not cover the requested DLR frequency range";
257 auto result = gf{dlr_mesh, g.target_shape()};
258 for (auto const &mp : dlr_mesh) result[mp] = g[iw_mesh(mp.index())];
259 return result;
260 }
261 }
262 } // namespace detail
263
289 template <int N = 0, int... Ns, typename G>
290 requires(MemoryGf<G> or is_block_gf_v<G>)
291 auto make_gf_dlr_imfreq(G const &g, double w_max, double eps, bool symmetrize = true) {
292 using M = typename G::mesh_t;
293 if constexpr (mesh::is_product<M>) {
294 return apply_to_mesh<N, Ns...>([&](auto const &gfl) { return make_gf_dlr_imfreq(gfl, w_max, eps, symmetrize); }, g);
295 } else {
296 static_assert(N == 0, "N must be 0 for non-product meshes");
297 auto const &m0 = detail::imfreq_mesh_of(g);
298 auto dlr_mesh = dlr_imfreq{m0.beta(), m0.statistic(), w_max, eps, symmetrize};
299 return detail::sample_on_dlr_imfreq(g, dlr_mesh);
300 }
301 }
302
333 template <int = 0, typename G>
334 requires(MemoryGf<G> or is_block_gf_v<G>)
335 double find_w_max(G const &g, double eps = 1e-10, bool symmetrize = true, double w_max_init = 1.0, double w_max_max = 200.0) {
336 if (w_max_init > w_max_max) TRIQS_RUNTIME_ERROR << "find_w_max: w_max_init (" << w_max_init << ") > w_max_max (" << w_max_max << ")";
337
338 auto const &m0 = detail::imfreq_mesh_of(g);
339
340 // NOLINTNEXTLINE(bugprone-float-loop-counter): intentional geometric (x1.5) growth of the real-valued DLR cutoff
341 for (double w_max = w_max_init; w_max <= w_max_max; w_max *= 1.5) {
342 auto dlr_mesh = dlr_imfreq{m0.beta(), m0.statistic(), w_max, eps, symmetrize};
343 auto [iw_lo, iw_hi] = dlr_mesh.min_max_frequencies();
344 if (not m0.is_index_valid(iw_lo.n) or not m0.is_index_valid(iw_hi.n)) continue;
345
346 auto g_dlr_iw = detail::sample_on_dlr_imfreq(g, dlr_mesh);
347 auto g_rec = make_gf_imfreq(make_gf_dlr(g_dlr_iw), m0.n_iw());
348 auto data_err = [](auto const &x, auto const &y) { return double(max_element(abs(x.data() - y.data()))); };
349 double max_err = 0.0;
350 if constexpr (is_block_gf_v<G>) {
351 for (long b = 0; b < long(g.size()); ++b) max_err = std::max(max_err, data_err(g[b], g_rec[b]));
352 } else {
353 max_err = data_err(g, g_rec);
354 }
355 if (max_err < eps) return w_max;
356 }
357 TRIQS_RUNTIME_ERROR << "find_w_max: no w_max <= " << w_max_max << " yields round-trip error < eps = " << eps;
358 }
359
373 template <int N = 0, int... Ns, typename G>
374 requires(MemoryGf<G> or is_block_gf_v<G>)
375 auto make_gf_imtime(G const &g, long n_tau) {
376 using M = typename G::mesh_t;
377 if constexpr (is_block_gf_v<G>) {
378 return map_block_gf([&](auto const &gbl) { return make_gf_imtime<N, Ns...>(gbl, n_tau); }, g);
379 } else if constexpr (mesh::is_product<M>) {
380 return apply_to_mesh<N, Ns...>([&](auto const &gfl) { return make_gf_imtime(gfl, n_tau); }, g);
381 } else if constexpr (nda::AnyOf<M, dlr_imtime, dlr_imfreq>) {
382 return make_gf_imtime(make_gf_dlr(g), n_tau);
383 } else { // M == dlr
384 static_assert(N == 0, "N must be 0 for non-product meshes");
385 static_assert(std::is_same_v<M, dlr>, "Input mesh must be dlr");
386 auto result = gf{mesh::imtime{g.mesh().beta(), g.mesh().statistic(), n_tau}, g.target_shape()};
387 for (auto tau : result.mesh()) result[tau] = g(tau.value());
388 return result;
389 }
390 }
391
405 template <int N = 0, int... Ns, typename G>
406 requires(MemoryGf<G> or is_block_gf_v<G>)
407 auto make_gf_imfreq(G const &g, long n_iw) {
408 using M = typename G::mesh_t;
409 if constexpr (is_block_gf_v<G>) {
410 return map_block_gf([&](auto const &gbl) { return make_gf_imfreq<N, Ns...>(gbl, n_iw); }, g);
411 } else if constexpr (mesh::is_product<M>) {
412 return apply_to_mesh<N, Ns...>([&](auto const &gfl) { return make_gf_imfreq(gfl, n_iw); }, g);
413 } else if constexpr (nda::AnyOf<M, dlr_imtime, dlr_imfreq>) {
414 return make_gf_imfreq(make_gf_dlr(g), n_iw);
415 } else { // M == dlr
416 static_assert(N == 0, "N must be 0 for non-product meshes");
417 static_assert(std::is_same_v<M, dlr>, "Input mesh must be dlr");
418 auto result = gf{mesh::imfreq{g.mesh().beta(), g.mesh().statistic(), n_iw}, g.target_shape()};
419 for (auto w : result.mesh()) result[w] = g(w.value());
420 return result;
421 }
422 }
423
432 template <typename G>
433 requires(MemoryGf<G> or is_block_gf_v<G>)
434 auto tau_L2_norm(G const &g) {
435 using M = typename G::mesh_t;
436 static_assert(nda::AnyOf<M, dlr, dlr_imfreq, dlr_imtime>, "Input mesh must be one of dlr, dlr_imfreq, dlr_imtime");
437 if constexpr (is_block_gf_v<G>) {
438 // Manual loop with a concrete element type. map_block_gf would deduce
439 // std::vector<std::invoke_result_t<lambda, gf>> (the lambda is local),
440 // and a function-scoped `using elem_t = ...` alias would also leak its
441 // spelling -- in both cases clair-c2py fails to render the type.
442 constexpr int rank = std::decay_t<G>::g_t::target_t::rank;
443 if constexpr (rank == 0) {
444 std::vector<double> result;
445 result.reserve(g.data().size());
446 for (auto const &gbl : g.data()) result.push_back(tau_L2_norm(gbl));
447 return result;
448 } else {
449 std::vector<nda::array<double, rank>> result;
450 result.reserve(g.data().size());
451 for (auto const &gbl : g.data()) result.push_back(tau_L2_norm(gbl));
452 return result;
453 }
454 } else if constexpr (nda::AnyOf<M, dlr_imtime, dlr_imfreq>) {
455 return tau_L2_norm(make_gf_dlr(g));
456 } else { // M == dlr
457 if constexpr (G::target_rank == 0) {
458 // use abs here to avoid sqrt of negative numbers, which can happen due to numerical errors
459 return std::sqrt(std::abs(g.mesh().dlr_it().innerprod(g.data(), g.data())));
460 } else {
461 auto result = nda::array<double, G::target_rank>(g.target_shape());
462 nda::for_each(g.target_shape(), [&](auto... is) {
463 auto dat = g.data()(nda::range::all, is...);
464 result(is...) = std::sqrt(std::abs(g.mesh().dlr_it().innerprod(dat, dat)));
465 });
466
467 return result;
468 }
469 }
470 }
471
473
474} // namespace triqs::gfs
Provides the block Green's function container.
The owning Green's function container.
Definition gf.hpp:194
data_t & data() &
Get the data array.
Definition gf.hpp:280
mesh_t const & mesh() const
Get the mesh of the Green's function.
Definition gf.hpp:274
Imaginary frequency discrete Lehmann representation (DLR) mesh type.
auto min_max_frequencies() const noexcept
Get a pair containing the smallest and largest Matsubara frequency in the mesh.
Imaginary time discrete Lehmann representation (DLR) mesh type.
Discrete Lehmann representation (DLR) mesh type.
Definition dlr.hpp:96
Imaginary frequency mesh type.
Definition imfreq.hpp:102
Imaginary time mesh type.
Definition imtime.hpp:68
Concept checking that a type behaves like an in-memory Green's function.
Definition gf.hpp:133
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 utilities to flatten the data of arrays and Green's functions into a two-dimensional form.
Provides the Green's function class.
gf(M, DataArray) -> gf< M, target_from_array< DataArray, n_variables< M > > >
Deduce a triqs::gfs::gf type from a mesh and a data array.
auto make_gf_dlr_imtime(G const &g)
Build a DLR imaginary-time Green's function from a DLR-coefficient or DLR-Matsubara input.
Definition dlr.hpp:185
auto make_gf_dlr(G const &g)
Transform a DLR imaginary-time or DLR Matsubara Green's function to its DLR-coefficient representatio...
Definition dlr.hpp:94
auto fit_gf_dlr(G const &g, mesh::dlr const &dlr_mesh)
Fit an imaginary-time Green's function on a given DLR coefficient mesh.
Definition dlr.hpp:129
auto make_gf_dlr_imfreq(G const &g)
Build a DLR Matsubara Green's function from a DLR-coefficient or DLR-imaginary-time input.
Definition dlr.hpp:216
auto make_gf_imfreq(G const &g, long n_iw)
Build a uniform Matsubara Green's function from any DLR representation.
Definition dlr.hpp:407
auto tau_L2_norm(G const &g)
Calculate the norm of a DLR Green's function.
Definition dlr.hpp:434
auto make_gf_imtime(G const &g, long n_tau)
Build a uniform imaginary-time Green's function from any DLR representation.
Definition dlr.hpp:375
double find_w_max(G const &g, double eps=1e-10, bool symmetrize=true, double w_max_init=1.0, double w_max_max=200.0)
Find a DLR energy cutoff that reproduces an imfreq Green's function within tolerance eps after a DLR...
Definition dlr.hpp:335
auto map_block_gf(F &&f, G &&g)
Apply a callable to each block of a block Green's function.
Definition map.hpp:131
void unflatten_gf_2d(MemoryGf auto &g, Gfl const &gfl)
Inverse of triqs::gfs::flatten_gf_2d: scatter a flattened Green's function back into a higher-rank on...
Definition flatten.hpp:100
auto flatten_gf_2d(G const &g)
Flatten a Green's function into a single-mesh, tensor-valued Green's function.
Definition flatten.hpp:85
constexpr bool is_block_gf_v
Trait to check whether a type is a block Green's function.
Definition block_gf.hpp:119
auto const & get_mesh(BG const &bg)
Get the mesh of a block Green's function, or its N-th component for a product mesh.
Definition block_gf.hpp:158
static constexpr bool is_product
Constexpr bool that is true if the given triqs::mesh::Mesh type is a product of meshes,...
Definition utils.hpp:151
#define TRIQS_RUNTIME_ERROR
Throw a triqs::runtime_error with the current source location.
auto replace(T &&t, R &&r)
Return a copy of a tuple with the elements at the given positions replaced by a given value.
Provides a mesh type for the discrete Lehmann representation.
Provides a mesh type on the imaginary frequency axis.
Provides a mesh type on the imaginary time axis.
Provides a product mesh type.
Generic tuple manipulation tools.