TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
fourier.hpp
Go to the documentation of this file.
1// Copyright (c) 2018 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2// Copyright (c) 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: Philipp Dumitrescu, Michel Ferrero, Olivier Parcollet, Nils Wentzell
19
24
25#pragma once
26
27#include "../gf/flatten.hpp"
28#include "../gf/gf.hpp"
30#include "../gf/gf_view.hpp"
31#include "../gf/targets.hpp"
32#include "../block/block_gf.hpp"
33#include "../block/map.hpp"
34#include "../functions/dlr.hpp"
35
37#include "../../mesh/brzone.hpp"
38#include "../../mesh/cyclat.hpp"
41#include "../../mesh/imfreq.hpp"
42#include "../../mesh/imtime.hpp"
43#include "../../mesh/prod.hpp"
44#include "../../mesh/refreq.hpp"
45#include "../../mesh/retime.hpp"
48
49#include <itertools/itertools.hpp>
50
51#include <tuple>
52#include <type_traits>
53#include <utility>
54#include <vector>
55
56namespace triqs::gfs {
57
58 // Names elevated from nda for the declarations below.
59 using nda::array;
60 using nda::array_const_view;
61
62 // Trait yielding the conjugate (Fourier-adjoint) mesh of V, used for static checks below.
63 template <typename V> using _mesh_fourier_image = decltype(make_adjoint_mesh(V()));
64
65 // Vector-valued (tensor_valued<1>) Green's function aliases used by the core FFTW implementation.
66 template <typename V> using gf_vec_t = gf<V, tensor_valued<1>>;
67 template <typename V> using gf_vec_vt = gf_view<V, tensor_valued<1>>;
68 template <typename V> using gf_vec_cvt = gf_const_view<V, tensor_valued<1>>;
69
70 // matsubara
71 gf_vec_t<mesh::imfreq> _fourier_impl(mesh::imfreq const &iw_mesh, gf_vec_cvt<mesh::imtime> gt, array_const_view<dcomplex, 2> known_moments = {});
72 gf_vec_t<mesh::imtime> _fourier_impl(mesh::imtime const &tau_mesh, gf_vec_cvt<mesh::imfreq> gw, array_const_view<dcomplex, 2> known_moments = {});
73
74 // dlr
75 inline gf_vec_t<mesh::dlr_imfreq> _fourier_impl(mesh::dlr_imfreq const &, gf_vec_cvt<mesh::dlr_imtime> gt) { return make_gf_dlr_imfreq(gt); }
76 inline gf_vec_t<mesh::dlr_imtime> _fourier_impl(mesh::dlr_imtime const &, gf_vec_cvt<mesh::dlr_imfreq> gw) { return make_gf_dlr_imtime(gw); }
77
78 // real
79 gf_vec_t<mesh::refreq> _fourier_impl(mesh::refreq const &w_mesh, gf_vec_cvt<mesh::retime> gt, array_const_view<dcomplex, 2> known_moments = {});
80 gf_vec_t<mesh::retime> _fourier_impl(mesh::retime const &t_mesh, gf_vec_cvt<mesh::refreq> gw, array_const_view<dcomplex, 2> known_moments = {});
81
82 // lattice
83 gf_vec_t<mesh::cyclat> _fourier_impl(mesh::cyclat const &r_mesh, gf_vec_cvt<mesh::brzone> gk);
84 gf_vec_t<mesh::brzone> _fourier_impl(mesh::brzone const &k_mesh, gf_vec_cvt<mesh::cyclat> gr);
85
86 // Regroup the gf data, call the vector-valued core implementation, then unflatten the result (gin: input, gout: output, opt_args: e.g. moments).
87 template <int N, typename M1, typename M2, typename T1, typename T2, typename... OptArgs>
88 void _fourier(gf_const_view<M1, T1> gin, gf_view<M2, T2> gout, OptArgs const &...opt_args) {
89
90 static_assert(std::is_same_v<typename T1::complex_t, T2>, "Incompatible target types for fourier transform");
91
92 // pb std::get<0> would not work on a non composite mesh. We use a little lambda to deduce ref and type
93 auto const &out_mesh = [&gout]() -> auto const & { // NB must return a reference
94 using m_t = std::decay_t<decltype(gout.mesh())>;
95 if constexpr (mesh::is_product<m_t>)
96 return std::get<N>(gout.mesh());
97 else
98 return gout.mesh();
99 }();
100
101 // FIXME : Code failed with nda optimisation relaxing assumption on iterator order.
102 // between nda::for_each and the flatten which were not inverse of each other any more
103 // TODO : put back the optimisation in nda (MACRO ??)
104 // some tests will fail and check in a test that flatten_2d and the inverse op are indeed inverse...
105 auto gin_fl = [&gin]() {
106 using gfl_t = typename decltype(flatten_gf_2d<N>(gin))::complex_t;
107 return gfl_t{flatten_gf_2d<N>(gin)};
108 }();
109
110 auto gout_fl = _fourier_impl(out_mesh, gin_fl, flatten_2d(opt_args)...);
111 unflatten_gf_2d<N>(gout, gout_fl);
112 }
113
140 template <int N = 0, typename M1, typename M2, typename T, typename... OptArgs>
141 auto make_gf_from_fourier(gf_const_view<M1, T> gin, M2 const &mesh, OptArgs const &...opt_args) {
142 static_assert(N >= 0 && N < n_variables<M1>, "Mesh index exceeds Gf Mesh Rank");
143 static_assert(n_variables<M2> == 1, "Cannot fourier transform on cartesian product mesh");
144
145 if constexpr (n_variables<M1> == 1) { // === single mesh
146 static_assert(n_variables<M2> == 1, "Incompatible mesh ranks");
147 static_assert(N == 0, "Fourier transforming gf with mesh of rank 1 but fourier index N > 1");
148 static_assert(std::is_same_v<M2, _mesh_fourier_image<M1>>, "There is no Fourier transform between these two meshes");
149 auto gout = gf<M2, typename T::complex_t>{mesh, gin.target_shape()};
150 _fourier<N>(gin, gout(), opt_args...);
151 return gout;
152 } else { // === prod mesh
153 static_assert(std::is_same_v<M2, _mesh_fourier_image<std::tuple_element_t<N, M1>>>, "There is no Fourier transform between these two meshes");
154 auto mesh_tpl = triqs::tuple::replace<N>(gin.mesh().components(), mesh);
155 auto out_mesh = mesh::prod{mesh_tpl};
156 using mesh_t = typename std::decay_t<decltype(out_mesh)>;
157 auto gout = gf<mesh_t, typename T::complex_t>{out_mesh, gin.target_shape()};
158 _fourier<N>(gin, gout(), opt_args...);
159 return gout;
160 }
161 }
162
164 template <int N = 0, typename T> auto make_gf_from_fourier(gf_const_view<mesh::brzone, T> gin) {
165 return make_gf_from_fourier(gin, make_adjoint_mesh(gin.mesh()));
166 }
167
169 template <int N = 0, typename T> auto make_gf_from_fourier(gf_const_view<mesh::cyclat, T> gin) {
170 return make_gf_from_fourier(gin, make_adjoint_mesh(gin.mesh()));
171 }
172
174 template <int N = 0, typename T> gf<mesh::imtime, T> make_gf_from_fourier(gf_const_view<mesh::imfreq, T> gin, int n_tau = -1) {
175 return make_gf_from_fourier(gin, make_adjoint_mesh(gin.mesh(), n_tau));
176 }
177
180 return make_gf_from_fourier(gin, make_adjoint_mesh(gin.mesh(), n_iw));
181 }
182
187
192
194 template <int N = 0, typename T> gf<mesh::retime, T> make_gf_from_fourier(gf_const_view<mesh::refreq, T> gin, bool shift_half_bin = false) {
195 return make_gf_from_fourier(gin, make_adjoint_mesh(gin.mesh(), shift_half_bin));
196 }
197
199 template <int N = 0, typename T>
201 return make_gf_from_fourier(gin, make_adjoint_mesh(gin.mesh(), shift_half_bin));
202 }
203
204 // Worker tag used by make_gf_from_multi_fourier to fold one per-axis transform via operator&.
205 template <int N> struct _fou_wk {};
206
207 // Apply the N-th axis Fourier transform of gin (the operator& building block of make_gf_from_multi_fourier).
208 template <int N, typename G>
209 auto operator&(G &&gin, _fou_wk<N> const &) { // NOLINT(cppcoreguidelines-missing-std-forward): gin is only read, not forwarded into a sink
210 return make_gf_from_fourier<N>(gin, make_adjoint_mesh(std::get<N>(gin.mesh())));
211 }
212
225 template <int... Ns, typename V, typename T> auto make_gf_from_multi_fourier(gf_const_view<V, T> gin) { return (gin() & ... & _fou_wk<Ns>{}); }
226
228 template <int N1, int N2, typename M1, typename M2, typename... Vs, typename T>
229 auto make_gf_from_fourier(gf_const_view<mesh::prod<Vs...>, T> gin, M1 &&m1, M2 &&m2) {
230 static_assert(sizeof...(Vs) >= 2, "Green function mesh rank incompatible with mesh indices");
231
232 auto g1 = make_gf_from_fourier<N1>(gin(), std::forward<M1>(m1));
233 auto g2 = make_gf_from_fourier<N2>(g1(), std::forward<M2>(m2));
234
235 return g2;
236 }
237
239 template <int N1, int N2, int N3, typename M1, typename M2, typename M3, typename... Vs, typename T>
240 auto make_gf_from_fourier(gf_const_view<mesh::prod<Vs...>, T> gin, M1 &&m1, M2 &&m2, M3 &&m3) {
241 static_assert(sizeof...(Vs) >= 3, "Green function mesh rank incompatible with mesh indices");
242
243 auto g1 = make_gf_from_fourier<N1, N2>(gin(), std::forward<M1>(m1), std::forward<M2>(m2));
244 auto g2 = make_gf_from_fourier<N3>(g1(), std::forward<M3>(m3));
245
246 return g2;
247 }
248
250 template <int... Ns, typename... Vs, typename T> auto make_gf_from_fourier(gf_const_view<mesh::prod<Vs...>, T> gin) {
251 return make_gf_from_fourier<Ns...>(gin(), make_adjoint_mesh(std::get<Ns>(gin.mesh()))...);
252 }
253
255 template <int N = 0, typename G, typename M, int R>
256 auto make_gf_from_fourier(G const &gin, M const &m, std::vector<array<dcomplex, R>> const &known_moments)
257 requires(is_block_gf_v<G>)
258 {
259
260 using r_t = decltype(make_gf_from_fourier<N>(gin[0], m, known_moments[0]));
261 std::vector<r_t> g_vec;
262
263 TRIQS_ASSERT2(gin.size() == known_moments.size(), "Fourier: Require equal number of blocks in block_gf and known_moments vector");
264
265 for (auto [gin_bl, km_bl] : itertools::zip(gin, known_moments)) g_vec.push_back(make_gf_from_fourier<N>(gin_bl, m, km_bl));
266 return make_block_gf(gin.block_names(), std::move(g_vec));
267 }
268
270 template <int N = 0, typename G, typename M, int R>
271 auto make_gf_from_fourier(G const &gin, M const &m, std::vector<std::vector<array<dcomplex, R>>> const &known_moments)
272 requires(is_block_gf_v<G>)
273 {
274
275 using r_t = decltype(make_gf_from_fourier<N>(gin(0, 0), m, known_moments[0][0]));
276 std::vector<std::vector<r_t>> g_vecvec;
277
278 TRIQS_ASSERT2(gin.size1() == known_moments.size(), "Fourier: Require matching block structure between gin and known_moments");
279
280 for (int i : range(gin.size1())) {
281 TRIQS_ASSERT2(gin.size2() == known_moments[i].size(), "Fourier: Require matching block structure between gin and known_moments");
282
283 std::vector<r_t> g_vec;
284 for (int j : range(gin.size2())) g_vec.push_back(make_gf_from_fourier<N>(gin(i, j), m, known_moments[i][j]));
285
286 g_vecvec.push_back(std::move(g_vec));
287 }
288 return block2_gf_of<r_t>{gin.block_names(), std::move(g_vecvec)};
289 }
290
292 template <int N = 0, int... Ns, typename G, typename... Args>
293 auto make_gf_from_fourier(G const &gin, Args const &...args)
294 requires(is_block_gf_v<G>)
295 {
296 auto l = [&](auto &&g_bl) { return make_gf_from_fourier<N, Ns...>(make_const_view(g_bl), args...); };
297 return map_block_gf(l, gin);
298 }
299
301 template <int N = 0, int... Ns, typename V, typename T, typename... Args> auto make_gf_from_fourier(gf_view<V, T> gin, Args &&...args) {
302 return make_gf_from_fourier<N, Ns...>(make_const_view(gin), std::forward<Args>(args)...);
303 }
304
306 template <int N = 0, int... Ns, typename V, typename T, typename... Args> auto make_gf_from_fourier(gf<V, T> const &gin, Args &&...args) {
307 return make_gf_from_fourier<N, Ns...>(gf_const_view{gin}, std::forward<Args>(args)...);
308 }
309
310 // Lazy Fourier expression: keeps a const view on the source gf and the (possibly reference) optional arguments of the call.
311 template <int N, typename GCV, typename... Args> struct _fourier_lazy {
312 GCV g;
313 std::tuple<Args...> args; // Args can be a ref.
314 };
315
331 template <int N = 0, typename G, typename... Args> _fourier_lazy<N, typename G::const_view_type, Args...> fourier(G const &g, Args &&...args) {
332 return {g(), {std::forward<Args>(args)...}};
333 }
334
335 // Realize the lazy Fourier expression for gx = fourier(gy): static-checks the mesh/target compatibility and calls _fourier.
336 template <int N, typename M1, typename T1, typename M2, typename T2, typename... Args>
337 void triqs_gf_view_assign_delegation(gf_view<M1, T1> lhs_g, _fourier_lazy<N, gf_const_view<M2, T2>, Args...> const &rhs) {
338 static_assert(std::is_same_v<typename T1::real_t, typename T2::real_t>, "Error : in gx = fourier(gy), gx and gy must have the same target");
339
340 if constexpr (n_variables<M1> == 1) // === single mesh
341 static_assert(std::is_same_v<M2, _mesh_fourier_image<M1>>, "There is no Fourier transform between these two meshes");
342 else { // === prod mesh
343 using mesh_res_t = decltype(triqs::tuple::replace<N>(rhs.g.mesh().components(), make_adjoint_mesh(std::get<N>(rhs.g.mesh()))));
344 static_assert(std::is_same_v<typename M1::m_tuple_t, mesh_res_t>, "Meshes in assignment don't match");
345 }
346
347 // check the size of the "inactive" dimensions
348
349 std::apply([&](auto &&...u) { _fourier<N>(rhs.g, lhs_g, u...); }, rhs.args); // calls _fourier( rhs.g, lhs_g, rhs.args...)
350 }
351
352} // namespace triqs::gfs
353
354namespace nda::clef {
355 // Make fourier usable inside lazy CLEF expressions.
356 TRIQS_CLEF_MAKE_FNT_LAZY(fourier);
357} // namespace nda::clef
Provides functions to create adjoint meshes.
Provides the block Green's function container.
Provides a mesh type for Brillouin zones.
A read-only, non-owning view of a Green's function.
mesh_t const & mesh() const
Get the mesh of the Green's function.
std::array< long, Target::rank > target_shape() const
Get the shape of the target.
A mutable, non-owning view of a Green's function.
Definition gf_view.hpp:48
The owning Green's function container.
Definition gf.hpp:194
Product mesh type for combining multiple meshes.
Definition prod.hpp:138
Provides a mesh type for Bravais lattices with Born-von Karman periodic boundary conditions.
static constexpr int n_variables
Constexpr variable that holds the number of meshes in a triqs::mesh::Mesh type ( for non-product mes...
Definition utils.hpp:154
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 triqs::gfs::gf_const_view container, a read-only non-owning view of a Green's function.
Provides a mutable non-owning view of a Green's function.
Provides conversions between Green's functions and the Discrete Lehmann Representation (DLR).
Provides the Green's function class.
imfreq make_adjoint_mesh(imtime const &m, long n_iw=-1)
Create the adjoint imaginary-frequency mesh to a given imaginary-time mesh.
Definition adjoint.hpp:50
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_imfreq(G const &g)
Build a DLR Matsubara Green's function from a DLR-coefficient or DLR-imaginary-time input.
Definition dlr.hpp:216
block_gf< V, T, L > make_block_gf(int n, gf< V, T, L > const &g)
Make a triqs::gfs::block_gf of n copies of a Green's function (block names default to "0",...
Definition factories.hpp:50
auto make_gf_from_multi_fourier(gf_const_view< V, T > gin)
Fourier transform several components of a product-mesh Green's function at once.
Definition fourier.hpp:225
auto make_gf_from_fourier(block_gf< M, T, L, A > &g)
Apply make_gf_from_fourier block-wise to each block of the block Green's function.
auto fourier(block_gf< V, T, L, A > const &g)
Lazily apply the Fourier transform block by block to a block Green's function.
Definition functions.hpp:44
auto map_block_gf(F &&f, G &&g)
Apply a callable to each block of a block Green's function.
Definition map.hpp:131
auto flatten_2d(A const &v)
Flatten an array into two dimensions, keeping one dimension and collapsing the rest.
Definition flatten.hpp:50
auto make_const_view(Gf const &g)
Make a const view of a Green's function.
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
block2_gf< get_mesh_t< G >, get_target_t< G > > block2_gf_of
The triqs::gfs::block2_gf type matching the mesh and target of G.
Definition block_gf.hpp:181
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_ASSERT2(X,...)
Like TRIQS_ASSERT but lets the caller add a custom message.
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 the function applying a callable block by block to a block Green's function.
Provides a mesh type on the imaginary frequency axis.
Provides a mesh type on the imaginary time axis.
Provides a product mesh type.
Provides a mesh type on the real frequency axis.
Provides a mesh type on the real time axis.
Provides the target types that fix the value stored at each mesh point of a Green's function.
Generic tuple manipulation tools.