20#include "./fourier_common.hpp"
26namespace triqs_tprf::fourier {
31 template <
typename A>
auto oneFermion(A &&a,
double b,
double tau,
double beta) {
32 return -a * (b >= 0 ? exp(-b * tau) / (1 + exp(-beta * b)) : exp(b * (beta - tau)) / (1 + exp(beta * b)));
35 template <
typename A>
auto oneBoson(A &&a,
double b,
double tau,
double beta) {
36 return a * (b >= 0 ? exp(-b * tau) / (exp(-beta * b) - 1) : exp(b * (beta - tau)) / (1 - exp(b * beta)));
42 array<dcomplex, 2> fit_derivatives(gf_const_view<imtime, tensor_valued<1>> gt) {
43 using matrix_t = arrays::matrix<dcomplex>;
46 auto d_vec_left = matrix_t(fit_order, gt.target_shape()[0]);
47 auto d_vec_right = d_vec_left;
48 int n_tau = gt.mesh().size();
49 for (
int m : range(1, fit_order + 1)) {
50 d_vec_left(m - 1, _) = (gt[m] - gt[0]) / gt.mesh()[m];
51 d_vec_right(m - 1, _) = (gt[n_tau - 1] - gt[n_tau - 1 - m]) / gt.mesh()[m];
56 auto V_inv = matrix_t{{8.000000000008853, -28.000000000055913, 56.000000000151815, -70.00000000021936, 56.00000000020795, -28.000000000115904,
57 8.00000000003683, -1.0000000000049232},
58 {-13.742857142879107, 62.10000000013776, -133.5333333337073, 172.75000000055635, -141.00000000052023, 71.43333333362274,
59 -20.600000000091182, 2.592857142869304},
60 {9.694444444465196, -50.98055555568518, 119.55000000035201, -161.8888888894241, 135.86111111160685, -70.12500000027573,
61 20.494444444530682, -2.6055555555670558},
62 {-3.6555555555654573, 21.23472222228416, -53.60000000016842, 76.34027777803497, -66.27777777801586, 35.03750000013273,
63 -10.422222222263619, 1.3430555555610917},
64 {0.7986111111137331, -4.97222222223865, 13.312500000044732, -19.888888888957325, 17.923611111174495, -9.750000000035401,
65 2.9652777777888164, -0.38888888889036743},
66 {-0.1013888888892789, 0.6638888888913357, -1.862500000006671, 2.902777777787997, -2.71527777778725, 1.5250000000052975,
67 -0.47638888889054154, 0.06388888888911043},
68 {0.0069444444444749, -0.047222222222413485, 0.13750000000052204, -0.22222222222302282, 0.2152777777785205,
69 -0.12500000000041575, 0.04027777777790756, -0.00555555555557296},
70 {-0.0001984126984136688, 0.0013888888888949882, -0.00416666666668333, 0.006944444444470023, -0.006944444444468193,
71 0.004166666666679969, -0.0013888888888930434, 0.00019841269841325577}};
88 matrix_t g_vec_left = V_inv * d_vec_left;
89 matrix_t g_vec_right = V_inv * d_vec_right;
90 double sign = (gt.mesh().statistic() == Fermion) ? -1 : 1;
91 array<dcomplex, 2> m23(2, g_vec_left.shape()[1]);
92 m23(0, _) = g_vec_left(0, _) - sign * g_vec_right(0, _);
93 m23(1, _) = -(g_vec_left(1, _) + sign * g_vec_right(1, _)) * 2 / gt.mesh().delta();
102 fourier_plan _fourier_plan(mesh::imfreq
const &iw_mesh, gf_vec_cvt<imtime> gt) {
104 auto L = gt.mesh().size() - 1;
105 if (L < 2 * (iw_mesh.last_index() + 1))
106 TRIQS_RUNTIME_ERROR <<
"Fourier: The time mesh mush be at least twice as long as the "
107 "number of positive frequencies :\n gt.mesh().size() = "
108 << gt.mesh().size() <<
" gw.mesh().last_index()" << iw_mesh.last_index();
110 int n_others = gt.data().shape()[1];
112 array<dcomplex, 2> _gout(L,
115 array<dcomplex, 2> _gin(L + 1, n_others);
117 int dims[] = {int(L)};
118 auto plan = _fourier_base_plan(_gin, _gout, 1, dims, n_others, FFTW_BACKWARD);
123 gf_vec_t<imfreq> _fourier_impl(mesh::imfreq
const &iw_mesh, gf_vec_cvt<imtime> gt, fourier_plan &p, arrays::array_const_view<dcomplex, 2> mom_23) {
124 if (mom_23.is_empty())
return _fourier_impl(iw_mesh, gt, p, fit_derivatives(gt));
126 double beta = gt.mesh().beta();
127 auto L = gt.mesh().size() - 1;
128 if (L < 2 * (iw_mesh.last_index() + 1))
129 TRIQS_RUNTIME_ERROR <<
"Fourier: The time mesh mush be at least twice as long as the "
130 "number of positive frequencies :\n gt.mesh().size() = "
131 << gt.mesh().size() <<
" gw.mesh().last_index()" << iw_mesh.last_index();
133 int n_others = gt.data().shape()[1];
135 array<dcomplex, 2> _gout(L,
138 array<dcomplex, 2> _gin(L + 1, n_others);
140 bool is_fermion = (iw_mesh.statistic() == Fermion);
141 double fact = beta / L;
142 dcomplex iomega = M_PI * 1i / beta;
145 array<dcomplex, 1> m1, a1, a2, a3;
147 auto m2 = mom_23(0, _);
148 auto m3 = mom_23(1, _);
151 m1 = -(gt[0] + gt[L]);
159 for (
auto t : gt.mesh())
160 _gin(t.index(), _) = fact * exp(iomega * t) * (gt[t] - (oneFermion(a1, b1, t, beta) + oneFermion(a2, b2, t, beta) + oneFermion(a3, b3, t, beta)));
163 m1 = -(gt[0] - gt[L]);
167 a1 = 4 * (m1 - m3) / 3;
168 a2 = m3 - (m1 + m2) / 2;
169 a3 = m1 / 6 + m2 / 2 + m3 / 3;
171 for (
auto t : gt.mesh()) _gin(t.index(), _) = fact * (gt[t] - (oneBoson(a1, b1, t, beta) + oneBoson(a2, b2, t, beta) + oneBoson(a3, b3, t, beta)));
176 _fourier_base(_gin, _gout, p);
178 auto gw = gf_vec_t<imfreq>{iw_mesh, {int(n_others)}};
181 for (
auto w : iw_mesh) gw[w] = _gout((w.index() + L) % L, _) + a1 / (w - b1) + a2 / (w - b2) + a3 / (w - b3);
186 gf_vec_t<imfreq> _fourier_impl(mesh::imfreq
const &iw_mesh, gf_vec_cvt<imtime> gt, arrays::array_const_view<dcomplex, 2> mom_23) {
187 auto p = _fourier_plan(iw_mesh, gt);
188 auto gw = _fourier_impl(iw_mesh, gt, p, mom_23);
194 fourier_plan _fourier_plan(mesh::imtime
const &tau_mesh, gf_vec_cvt<imfreq> gw) {
196 TRIQS_ASSERT2(!gw.mesh().positive_only(),
197 "Fourier is only implemented for g(i omega_n) with full mesh "
198 "(positive and negative frequencies)");
200 long L = tau_mesh.size() - 1;
201 if (L < 2 * (gw.mesh().last_index() + 1))
202 TRIQS_RUNTIME_ERROR <<
"Inverse Fourier: The time mesh mush be at least twice as long as "
203 "the freq mesh :\n gt.mesh().size() = "
204 << tau_mesh.size() <<
" gw.mesh().last_index()" << gw.mesh().last_index();
206 int n_others = gw.data().shape()[1];
208 array<dcomplex, 2> _gin(L,
211 array<dcomplex, 2> _gout(L + 1, n_others);
213 int dims[] = {int(L)};
214 auto plan = _fourier_base_plan(_gin, _gout, 1, dims, n_others, FFTW_FORWARD);
218 gf_vec_t<imtime> _fourier_impl(mesh::imtime
const &tau_mesh, gf_vec_cvt<imfreq> gw, fourier_plan &p,
219 arrays::array_const_view<dcomplex, 2> mom_123) {
221 TRIQS_ASSERT2(!gw.mesh().positive_only(),
222 "Fourier is only implemented for g(i omega_n) with full mesh "
223 "(positive and negative frequencies)");
225 if (mom_123.is_empty()) {
226 auto [tail, error] = fit_tail(gw);
227 TRIQS_ASSERT2((error < 1e-3),
228 "ERROR: High frequency moments have an error "
229 "greater than 1e-3.\n Error = "
230 + std::to_string(error));
232 std::cerr <<
"WARNING: High frequency moments have an error greater than "
235 TRIQS_ASSERT2((tail.shape()[0] > 4),
236 "ERROR: Inverse Fourier implementation requires at least a "
237 "proper 3rd high-frequency moment\n");
238 double _abs_tail0 = max_element(abs(tail(0, range::all)));
239 if (_abs_tail0 > 1e-6) std::cerr <<
"WARNING: High frequency tail is not zero: " << _abs_tail0;
246 return _fourier_impl(tau_mesh, gw, p, tail(range(1, 4), range::all));
249 double beta = tau_mesh.beta();
250 long L = tau_mesh.size() - 1;
251 if (L < 2 * (gw.mesh().last_index() + 1))
252 TRIQS_RUNTIME_ERROR <<
"Inverse Fourier: The time mesh mush be at least twice as long as "
253 "the freq mesh :\n gt.mesh().size() = "
254 << tau_mesh.size() <<
" gw.mesh().last_index()" << gw.mesh().last_index();
256 int n_others = gw.data().shape()[1];
258 array<dcomplex, 2> _gin(L,
261 array<dcomplex, 2> _gout(L + 1, n_others);
263 bool is_fermion = (gw.mesh().statistic() == Fermion);
264 double fact = 1.0 / beta;
265 dcomplex iomega = M_PI * 1i / beta;
268 array<dcomplex, 1> a1, a2, a3;
270 auto m1 = mom_123(0, _);
271 auto m2 = mom_123(1, _);
272 auto m3 = mom_123(2, _);
285 a1 = 4 * (m1 - m3) / 3;
286 a2 = m3 - (m1 + m2) / 2;
287 a3 = m1 / 6 + m2 / 2 + m3 / 3;
290 for (
auto w : gw.mesh()) _gin((w.index() + L) % L, _) = fact * (gw[w] - (a1 / (w - b1) + a2 / (w - b2) + a3 / (w - b3)));
294 _fourier_base(_gin, _gout, p);
296 auto gt = gf_vec_t<imtime>{tau_mesh, {int(n_others)}};
299 for (
auto t : tau_mesh)
300 gt[t] = _gout(t.index(), _) * exp(-iomega * t) + oneFermion(a1, b1, t, beta) + oneFermion(a2, b2, t, beta) + oneFermion(a3, b3, t, beta);
302 for (
auto t : tau_mesh) gt[t] = _gout(t.index(), _) + oneBoson(a1, b1, t, beta) + oneBoson(a2, b2, t, beta) + oneBoson(a3, b3, t, beta);
304 double pm = (is_fermion ? -1 : 1);
305 gt[L] = pm * (gt[0] + m1);
310 gf_vec_t<imtime> _fourier_impl(mesh::imtime
const &tau_mesh, gf_vec_cvt<imfreq> gw, arrays::array_const_view<dcomplex, 2> mom_123) {
311 auto p = _fourier_plan(tau_mesh, gw);
312 auto gt = _fourier_impl(tau_mesh, gw, p, mom_123);