3#include <triqs/gfs.hpp>
4#include <triqs/mesh.hpp>
5#include <itertools/itertools.hpp>
7#include <gsl/gsl_errno.h>
8#include <gsl/gsl_integration.h>
9#include <gsl/gsl_spline.h>
17 inline double unwrap(
double x,
void *p) {
18 auto fp =
static_cast<std::function<
double(
double)
> *>(p);
27 gsl_integration_workspace *work =
nullptr;
30 void initF() noexcept {
34 integrator(
size_t _limit = 1000,
bool _exit_on_error =
false) : limit{_limit}, exit_on_error{_exit_on_error} {
35 work = gsl_integration_workspace_alloc(limit);
38 integrator(
const integrator &X) : limit{X.limit}, exit_on_error{X.exit_on_error} {
42 integrator(integrator &&X) : limit{X.limit}, exit_on_error{X.exit_on_error} {
47 integrator& operator=(
const integrator &X) {
48 if (
this==&X)
return *
this;
50 exit_on_error = X.exit_on_error;
55 integrator& operator=(integrator &&X) {
56 if (
this==&X)
return *
this;
58 exit_on_error = X.exit_on_error;
65 if (work) { gsl_integration_workspace_free(work); }
77 double operator() (std::function<
double(
double)> f,
double a,
double b,
double epsabs = 1e-14,
double epsrel = 1e-10) {
80 int status = gsl_integration_qag(&F, a, b, epsabs, epsrel, limit, GSL_INTEG_GAUSS15, work, &result, &error);
81 if (status && abs(result) > epsabs && exit_on_error) TRIQS_RUNTIME_ERROR <<
"qag error: " << status <<
" -- " << gsl_strerror(status);
90 std::vector<double> X, Y;
93 gsl_interp_accel *acc =
nullptr;
94 gsl_spline *spline =
nullptr;
96 interpolator(std::vector<double> &_X, std::vector<double> &_Y,
double _oob_value = 0.0) : X{_X}, Y{_Y}, oob_value{_oob_value} {
97 EXPECTS(std::is_sorted(X.begin(), X.end()));
98 EXPECTS(X.size() == Y.size());
99 acc = gsl_interp_accel_alloc();
101 spline = gsl_spline_alloc(gsl_interp_cspline, len);
102 gsl_spline_init(spline, &X[0], &Y[0], len);
106 interpolator(
const interpolator &I) : len{I.len}, X{I.X}, Y{I.Y}, Xmin{I.Xmin}, Xmax{I.Xmax}, oob_value{I.oob_value} {
108 if (spline) { gsl_spline_free(spline); }
109 spline = gsl_spline_alloc(gsl_interp_cspline, len);
110 gsl_spline_init(spline, &X[0], &Y[0], len);
112 interpolator(interpolator &&I) : len{I.len}, X{I.X}, Y{I.Y}, Xmin{I.Xmin}, Xmax{I.Xmax}, oob_value{I.oob_value} {
118 interpolator& operator=(
const interpolator &I) {
119 if (
this==&I)
return *
this;
125 oob_value = I.oob_value;
127 if (spline) { gsl_spline_free(spline); }
128 spline = gsl_spline_alloc(gsl_interp_cspline, len);
129 gsl_spline_init(spline, &X[0], &Y[0], len);
132 interpolator& operator=(interpolator &&I) {
133 if (
this==&I)
return *
this;
139 oob_value = I.oob_value;
147 if (spline) { gsl_spline_free(spline); }
148 if (acc) { gsl_interp_accel_free(acc); }
150 double operator() (
double x) {
return (Xmin <= x && x <= Xmax ? gsl_spline_eval(spline, x, acc) : oob_value); }
154 inline double sqr(
double x) {
return x*x; }
157 inline double imQ(
double x,
double y,
double B) {
return atan((-B + x) / y) - atan((B + x) / y); }
160 inline double reQ(
double x,
double y,
double B) {
return (-log(sqr(B - x) + sqr(y)) + log(sqr(B + x) + sqr(y))) / 2.0; }
163 inline double bandwidth(std::vector<double> X) {
164 EXPECTS(std::is_sorted(X.begin(), X.end()));
165 size_t len = X.size();
167 double Xmax = X[len-1];
168 return std::max(abs(Xmin), abs(Xmax));
182 template <
typename G> dcomplex hilbert_transform(G
const &Ain, dcomplex z,
double lim_direct = 1e-3)
requires(is_gf_v<G>) {
183 static_assert(std::is_same_v<typename G::target_t, scalar_valued>,
184 "Hilbert transform only implemented for (complex) scalar-valued spectral functions");
185 static_assert(std::is_same_v<typename G::mesh_t, mesh::refreq> or std::is_same_v<typename G::mesh_t, mesh::refreq_pts>
186 or std::is_same_v<typename G::mesh_t, mesh::refreq_log>,
187 "Hilbert transform only implemented for refreq, refreq_pts, and refreq_log meshes");
189 using DVEC = std::vector<double>;
190 DVEC Xpts, Rpts, Ipts;
198 for (
const auto &w : Ain.mesh()) {
200 double r = real(Ain[w]);
201 double i = imag(Ain[w]);
207 gsl_set_error_handler_off();
208 interpolator rhor(Xpts, Rpts);
209 interpolator rhoi(Xpts, Ipts);
213 double B = bandwidth(Xpts);
217 auto calcA = [&integr, x, y, B](
auto f3p,
auto f3m,
auto d) ->
double {
218 const double W1 = (x - B) / abs(y);
219 const double W2 = (B + x) / abs(y);
222 double lim1down = 1.0, lim1up = -1.0, lim2down = 1.0, lim2up = -1.0;
224 if (W1 < 0 && W2 > 0) {
225 const double ln1016 = -36.8;
232 if (W1 > 0 && W2 > 0) {
237 if (W1 < 0 && W2 < 0) {
244 auto result1 = (lim1down < lim1up ? integr(f3p, lim1down, lim1up) : 0.0);
245 auto result2 = (lim2down < lim2up ? integr(f3m, lim2down, lim2up) : 0.0);
246 auto result3 = (inside ? d : 0.0);
247 return result1 + result2 + result3;
249 auto calcB = [&integr, B](
auto f0) ->
double {
return integr(f0, -B, B); };
250 auto calc = [y, lim_direct, calcA, calcB](
auto f3p,
auto f3m,
auto d,
auto f0){
251 return (abs(y) < lim_direct ? calcA(f3p, f3m, d) : calcB(f0));
255 auto ref0 = [x,y,&rhor,&rhoi](
double omega) ->
double {
return ( rhor(omega)*(x-omega) + rhoi(omega)*y )/(sqr(y)+sqr(x-omega)); };
258 auto imf0 = [x,y,&rhor,&rhoi](
double omega) ->
double {
return (rhor(omega)*(-y) + rhoi(omega)*(x-omega) )/(sqr(y)+sqr(x-omega)); };
261 auto ref1 = [x,y,&rhor,&rhoi](
double omega) ->
double {
return ( (rhor(omega)-rhor(x))*(x-omega) + (rhoi(omega)-rhoi(x))*(y) )/(sqr(y)+sqr(x-omega)); };
262 auto ref2 = [x,y,ref1](
double W) ->
double {
return abs(y)*ref1(abs(y)*W+x); };
263 auto ref3p = [ref2](
double r) ->
double {
return ref2(exp(r)) * exp(r); };
264 auto ref3m = [ref2](
double r) ->
double {
return ref2(-exp(r)) * exp(r); };
265 auto red = rhor(x) * reQ(x,y,B) - rhoi(x) * imQ(x,y,B);
268 auto imf1 = [x,y,&rhor,&rhoi](
double omega) ->
double {
return ( (rhor(omega)-rhor(x))*(-y) + (rhoi(omega)-rhoi(x))*(x-omega) )/(sqr(y)+sqr(x-omega)); };
269 auto imf2 = [x,y,imf1](
double W) ->
double {
return abs(y)*imf1(abs(y)*W+x); };
270 auto imf3p = [imf2](
double r) ->
double {
return imf2(exp(r)) * exp(r); };
271 auto imf3m = [imf2](
double r) ->
double {
return imf2(-exp(r)) * exp(r); };
272 auto imd = rhor(x) * imQ(x,y,B) + rhoi(x) * reQ(x,y,B);
274 return dcomplex{calc(ref3p, ref3m, red, ref0), calc(imf3p, imf3m, imd, imf0)};
286 template <
typename G,
typename M>
287 typename G::regular_type hilbert_transform(G
const &Ain, M
const &mesh,
double eps = 1e-16)
288 requires(is_gf_v<G> and mesh::Mesh<M>) {
289 auto gout = gf<M, typename G::target_t>{mesh, Ain.target_shape()};
290 for (
const auto mp : mesh) gout[mp] = hilbert_transform(Ain, dcomplex{mp,eps});
303 template <
typename G>
304 typename G::regular_type hilbert_transform(G
const &Ain, G
const &gin)
requires(is_gf_v<G>) {
306 for (
const auto &mp : gin.mesh()) gout[mp] = hilbert_transform(Ain, gin[mp]);
318 template <
typename G> matrix<dcomplex> hilbert_transform_elementwise(G
const &Ain, dcomplex z)
requires(is_gf_v<G>) {
319 static_assert(std::is_same_v<typename G::target_t, matrix_valued>,
320 "Hilbert transform only implemented for matrix-valued spectral functions");
321 long size1 = Ain.target_shape()[0];
322 long size2 = Ain.target_shape()[1];
323 auto mat = matrix<dcomplex>(size1, size2);
324 for (
auto [i, j] : itertools::product_range(size1, size2)) {
325 auto gtemp = gf{Ain.mesh()};
326 for (
const auto &mp : Ain.mesh()) gtemp[mp] = Ain[mp](i,j);
327 mat(i,j) = hilbert_transform(gtemp, z);
339 template <
typename BG>
auto hilbert_transform(BG
const &bAin, dcomplex z)
requires(is_block_gf_v<BG>) {
340 using G =
typename BG::g_t;
341 auto l = [z](G
const &Ain) {
return hilbert_transform<G>(Ain, z); };
342 return map_block_gf(l, bAin);
353 template <
typename BG,
typename M>
354 auto hilbert_transform(BG
const &bAin, M
const &mesh,
double eps = 1e-16)
requires(is_block_gf_v<BG> and mesh::Mesh<M>) {
355 using G =
typename BG::g_t;
356 auto l = [&mesh, eps](G
const &Ain) {
return hilbert_transform<G, M>(Ain, mesh, eps); };
357 return map_block_gf(l, bAin);