//------------------------------------------------------- // For Imaginary Matsubara Frequency functions // ------------------------------------------------------ arrays::matrix<dcomplex> density(gf_const_view<imfreq> g) { if (g.mesh().positive_only()) TRIQS_RUNTIME_ERROR << "density is only implemented for g(i omega_n) with full mesh (positive and negative frequencies)"; tail_const_view t = g.singularity(); if (!t.is_decreasing_at_infinity()) TRIQS_RUNTIME_ERROR << " density computation : green Function is not as 1/omega or less !!!"; if (g.mesh().positive_only()) TRIQS_RUNTIME_ERROR << " imfreq gF : full mesh required in density computation"; auto sh = get_target_shape(g); int N1 = sh[0], N2 = sh[1]; arrays::matrix<dcomplex> res(sh); auto beta = g.domain().beta; double b1 = 0, b2 = 1, b3 = -1; auto F = [&beta](dcomplex a, double b) { return -a / (1 + exp(-beta * b)); }; for (int n1 = 0; n1 < N1; n1++) for (int n2 = n1; n2 < N2; n2++) { dcomplex d = t(1)(n1, n2), A = t(2)(n1, n2), B = t(3)(n1, n2); dcomplex a1 = d - B, a2 = (A + B) / 2, a3 = (B - A) / 2; dcomplex r = 0; for (auto const& w : g.mesh()) r += g[w](n1, n2) - (a1 / (w - b1) + a2 / (w - b2) + a3 / (w - b3)); res(n1, n2) = r / beta + d + F(a1, b1) + F(a2, b2) + F(a3, b3); if (n2 > n1) res(n2, n1) = conj(res(n1, n2)); } return res; }
//------------------------------------------------------- arrays::matrix<dcomplex> density(gf_const_view<legendre> gl) { arrays::matrix<dcomplex> res(get_target_shape(gl)); res() = 0.0; for (auto const& l : gl.mesh()) res -= sqrt(2 * l.index() + 1) * gl[l]; res /= gl.domain().beta; return res; }
template<typename MeshType> void check_gf_stat(gf_const_view<MeshType> g, triqs::gfs::statistic_enum expected_stat) { if(g.domain().statistic != expected_stat) fatal_error("expected a " + mesh_traits<MeshType>::name() + " Green's function with " + (expected_stat == Fermion ? "fermionic" : "bosonic") + " statistics"); }
// compute a tail from the Legendre GF // this is Eq. 8 of our paper tail_view get_tail(gf_const_view<legendre> gl, int size = 10, int omin = -1) { auto sh = gl.data().shape().front_pop(); tail t(sh, size, omin); t.data()() = 0.0; for (int p=1; p<=t.order_max(); p++) for (auto l : gl.mesh()) t(p) += (triqs::utility::legendre_t(l.index(),p)/pow(gl.domain().beta,p)) * gl[l]; return t; }
void legendre_matsubara_inverse(gf_view<legendre> gl, gf_const_view<imfreq> gw) { gl() = 0.0; // Construct a temporary imaginary-time Green's function gt // I set Nt time bins. This is ugly, one day we must code the direct // transformation without going through imaginary time int Nt = 50000; auto gt = gf<imtime>{{gw.domain(), Nt}, gw.data().shape().front_pop()}; // We first transform to imaginary time because it's been coded with the knowledge of the tails gt() = inverse_fourier(gw); legendre_matsubara_inverse(gl, gt()); }
void legendre_matsubara_inverse(gf_view<legendre> gl, gf_const_view<imtime> gt) { gl() = 0.0; legendre_generator L; auto N = gt.mesh().size() - 1; double coef; // Do the integral over imaginary time for (auto t : gt.mesh()) { if (t.index()==0 || t.index()==N) coef = 0.5; else coef = 1.0; L.reset(2 * t / gt.domain().beta - 1); for (auto l : gl.mesh()) { gl[l] += coef * sqrt(2 * l.index() + 1) * L.next() * gt[t]; } } gl.data() *= gt.mesh().delta(); }
// compute a tail from the Legendre GF // this is Eq. 8 of our paper array<dcomplex, 3> get_tail(gf_const_view<legendre> gl, int order) { auto _ = ellipsis{}; auto sh = gl.data().shape(); sh[0] = order; array<dcomplex, 3> t{sh}; t() = 0.0; for (int p = 0; p < order; p++) for (auto l : gl.mesh()) t(p, _) += (triqs::utility::legendre_t(l.index(), p) / std::pow(gl.domain().beta, p)) * gl[l]; return t; }