//------------------------------------------------------- // 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; }
gf<imtime> change_mesh(gf_const_view<imtime> old_gf, int new_n_tau) { auto const& old_m = old_gf.mesh(); gf<imtime> new_gf{{old_m.domain().beta, old_m.domain().statistic, new_n_tau, old_m.kind()}, get_target_shape(old_gf)}; auto const& new_m = new_gf.mesh(); new_gf.data()() = 0; double f = old_m.delta()/new_m.delta(); for(auto tau : old_m) new_gf[closest_mesh_pt(double(tau))] += f*old_gf[tau]; new_gf[0] *= 2.0; new_gf[new_n_tau-1] *= 2.0; new_gf.singularity() = old_gf.singularity(); return new_gf; }
// This function takes a g(i omega_n) on half mesh (positive omega_n) and returns a gf on the whole mesh // using G(-i omega_n) = G(i omega_n)^* for real G(tau) functions. template <typename T, typename S, typename E> gf<imfreq, T, S, E> make_gf_from_real_gf(gf_const_view<imfreq, T, S, E> g) { if (!g.mesh().positive_only()) TRIQS_RUNTIME_ERROR << "gf imfreq is not for omega_n >0, real_to_complex does not apply"; auto const &dat = g.data(); auto sh = dat.shape(); int is_boson = (g.mesh().domain().statistic == Boson); long L = sh[0]; sh[0] = 2 * sh[0] - is_boson; array<dcomplex, std14::decay_t<decltype(dat)>::rank> new_data(sh); auto _ = arrays::ellipsis{}; if (is_boson) new_data(L - 1, _) = dat(0, _); int L1 = (is_boson ? L - 1 : L); for (int u = is_boson; u < L; ++u) { new_data(L1 + u, _) = dat(u, _); new_data(L - 1 - u, _) = conj(dat(u, _)); } return {gf_mesh<imfreq>{g.mesh().domain(), L}, std::move(new_data), g.singularity(), g.symmetry(), g.indices(), g.name}; }
//------------------------------------------------------- // For Imaginary Time functions // ------------------------------------------------------ gf<imtime> rebinning_tau(gf_const_view<imtime> const& g, int new_n_tau) { auto const& old_m = g.mesh(); gf<imtime> new_gf{{old_m.domain().beta, old_m.domain().statistic, new_n_tau}, get_target_shape(g)}; auto const& new_m = new_gf.mesh(); new_gf.data()() = 0; long prev_index = 0; long norm = 0; for (auto const & tau : old_m) { long index = std::round((double(tau) - new_m.x_min()) / new_m.delta()); if (index == prev_index) { norm++; } else { new_gf[index - 1] /= double(norm); prev_index = index; norm = 1; } new_gf[index] += g[tau]; } if (norm != 1) new_gf[new_m.size() - 1] /= norm; new_gf.singularity() = g.singularity(); return new_gf; }
/// Takes the real part of g without check, and returns a new gf with a real target template <typename M, typename T, typename S, typename E> gf<M, real_target_t<T>, S> real(gf_const_view<M, T, S, E> g) { return {g.mesh(), real(g.data()), g.singularity(), g.symmetry(), {}, {}}; // no indices for real_valued, internal C++ use only }