TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
fourier_real.cpp
Go to the documentation of this file.
1// Copyright (c) 2013-2018 Commissariat à l'énergie atomique et aux énergies alternatives (CEA)
2// Copyright (c) 2013-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, Laura Messio, Olivier Parcollet, Nils Wentzell
19
24
25#include "./fourier.hpp"
26#include "./fourier_common.hpp"
27
29
30#include <array>
31#include <cmath>
32#include <string>
33
34namespace triqs::gfs {
35
36 namespace {
37 constexpr dcomplex I{0, 1};
38 inline dcomplex th_expo(double t, double a) { return (t > 0 ? -I * exp(-a * t) : (t < 0 ? 0 : -0.5 * I * exp(-a * t))); }
39 inline dcomplex th_expo_neg(double t, double a) { return (t < 0 ? I * exp(a * t) : (t > 0 ? 0 : 0.5 * I * exp(a * t))); }
40 inline dcomplex th_expo_inv(double w, double a) { return 1. / (w + I * a); }
41 inline dcomplex th_expo_neg_inv(double w, double a) { return 1. / (w - I * a); }
42 } // namespace
43
44 // ------------------------ DIRECT TRANSFORM --------------------------------------------
45
46 gf_vec_t<mesh::refreq> _fourier_impl(mesh::refreq const &w_mesh, gf_vec_cvt<mesh::retime> gt, nda::array_const_view<dcomplex, 2> known_moments) {
47
48 nda::array_const_view<dcomplex, 2> mom_12;
49 if (known_moments.is_empty())
50 // If no known_moments are passed we do a fourier transform on the raw data
51 return _fourier_impl(w_mesh, gt, make_zero_tail(gt, 3));
52 else {
53 TRIQS_ASSERT2(known_moments.shape()[0] >= 3, " Direct RealTime Fourier transform requires known moments up to order 2.")
54 double _abs_tail0 = max_element(abs(known_moments(0, range::all)));
55 TRIQS_ASSERT2((_abs_tail0 < 1e-8),
56 "ERROR: Direct Fourier implementation requires vanishing 0th moment\n error is :" + std::to_string(_abs_tail0));
57 mom_12.rebind(known_moments(range(1, 3), range::all));
58 }
59
60 long L = gt.mesh().size();
61 if (w_mesh.size() != L) TRIQS_RUNTIME_ERROR << "Meshes are different";
62 double test = std::abs(gt.mesh().delta() * w_mesh.delta() * static_cast<double>(L) / (2 * M_PI) - 1);
63 if (test > 1.e-10) TRIQS_RUNTIME_ERROR << "Meshes are not compatible";
64
65 long n_others = second_dim(gt.data());
66 array<dcomplex, 2> _gout(L, n_others);
67 array<dcomplex, 2> _gin(L, n_others);
68
69 const double tmin = gt.mesh().t_min();
70 const double wmin = w_mesh.w_min();
71 //a is a number very larger than delta_w and very smaller than wmax-wmin, used in the tail computation
72 const double a = w_mesh.delta() * std::sqrt(static_cast<double>(L));
73
74 auto _ = range::all;
75 auto m1 = mom_12(0, _);
76 auto m2 = mom_12(1, _);
77
78 array<dcomplex, 1> a1 = (m1 + I * m2 / a) / 2., a2 = (m1 - I * m2 / a) / 2.;
79
80 for (auto t : gt.mesh()) _gin(t.index(), _) = (gt[t] - (a1 * th_expo(t, a) + a2 * th_expo_neg(t, a))) * std::exp(I * t * wmin);
81
82 std::array<int, 1> dims{static_cast<int>(L)};
83 _fourier_base(_gin, _gout, 1, dims.data(), static_cast<int>(n_others), FFTW_BACKWARD);
84
85 auto gw = gf_vec_t<mesh::refreq>{w_mesh, {n_others}};
86 for (auto w : w_mesh)
87 gw[w] = gt.mesh().delta() * std::exp(I * (w - wmin) * tmin) * _gout(w.index(), _) + a1 * th_expo_inv(w, a) + a2 * th_expo_neg_inv(w, a);
88
89 return gw;
90 }
91
92 // ------------------------ INVERSE TRANSFORM --------------------------------------------
93
94 gf_vec_t<mesh::retime> _fourier_impl(mesh::retime const &t_mesh, gf_vec_cvt<mesh::refreq> gw, nda::array_const_view<dcomplex, 2> known_moments) {
95
96 nda::array_const_view<dcomplex, 2> mom_12;
97
98 if (known_moments.is_empty())
99 // If no known_moments are passed we do a fourier transform on the raw data
100 return _fourier_impl(t_mesh, gw, make_zero_tail(gw, 3));
101 else {
102 TRIQS_ASSERT2(known_moments.shape()[0] >= 3, " Direct Real-Frequency Fourier transform requires known moments up to order 2.")
103
104 double _abs_tail0 = max_element(abs(known_moments(0, range::all)));
105 TRIQS_ASSERT2((_abs_tail0 < 1e-8),
106 "ERROR: Inverse Fourier implementation requires vanishing 0th moment\n error is :" + std::to_string(_abs_tail0));
107
108 mom_12.rebind(known_moments(range(1, 3), range::all));
109 }
110
111 long L = gw.mesh().size();
112 if (L != t_mesh.size()) TRIQS_RUNTIME_ERROR << "Meshes are of different size: " << L << " vs " << t_mesh.size();
113 double test = std::abs(t_mesh.delta() * gw.mesh().delta() * static_cast<double>(L) / (2 * M_PI) - 1);
114 if (test > 1.e-10) TRIQS_RUNTIME_ERROR << "Meshes are not compatible";
115
116 const double tmin = t_mesh.t_min();
117 const double wmin = gw.mesh().w_min();
118 //a is a number very larger than delta_w and very smaller than wmax-wmin, used in the tail computation
119 const double a = gw.mesh().delta() * std::sqrt(static_cast<double>(L));
120
121 long n_others = second_dim(gw.data());
122
123 array<dcomplex, 2> _gin(L, n_others);
124 array<dcomplex, 2> _gout(L, n_others);
125
126 auto _ = range::all;
127 auto m1 = mom_12(0, _);
128 auto m2 = mom_12(1, _);
129
130 array<dcomplex, 1> a1 = (m1 + I * m2 / a) / 2., a2 = (m1 - I * m2 / a) / 2.;
131
132 for (auto w : gw.mesh()) _gin(w.index(), _) = (gw[w] - a1 * th_expo_inv(w, a) - a2 * th_expo_neg_inv(w, a)) * std::exp(-I * w * tmin);
133
134 std::array<int, 1> dims{static_cast<int>(L)};
135 _fourier_base(_gin, _gout, 1, dims.data(), static_cast<int>(n_others), FFTW_FORWARD);
136
137 auto gt = gf_vec_t<mesh::retime>{t_mesh, {n_others}};
138 const double corr = 1.0 / (t_mesh.delta() * static_cast<double>(L));
139 for (auto t : t_mesh) gt[t] = corr * std::exp(I * wmin * (tmin - t)) * _gout(t.index(), _) + a1 * th_expo(t, a) + a2 * th_expo_neg(t, a);
140
141 return gt;
142 }
143
144} // namespace triqs::gfs
data_t & data()
Direct access to the blocks.
int size() const
Get the total number of blocks.
Provides the Fourier transform factories and the lazy fourier(...) assignment for Green's functions.
Declares the low-level FFTW wrapper shared by the Fourier transform implementations.
Provides tail fitting, slicing, inversion, reality and matrix-multiplication functions for Green's fu...
auto make_zero_tail(G const &g, int n_moments=10)
Create a zero-initialized tail object for a given Green function object.
#define TRIQS_RUNTIME_ERROR
Throw a triqs::runtime_error with the current source location.
#define TRIQS_ASSERT2(X,...)
Like TRIQS_ASSERT but lets the caller add a custom message.
constexpr nda::clef::placeholder< 3 > w
Placeholder for the frequency .