gf<imtime, T, S> make_gf_from_inverse_fourier(gf_const_view<imfreq, T, S, E> const& gw, int n_tau = -1) { if (n_tau == -1) n_tau = 2*(gw.mesh().last_index() + 1) +1; auto m = gf_mesh<imtime>{gw.mesh().domain(), n_tau}; auto gt = gf<imtime, T, S, E>{m, get_target_shape(gw)}; gt() = inverse_fourier(gw); return gt; }
bool is_gf_real_in_tau(gf_const_view<imfreq, T, S, E> g, double tolerance = 1.e-13) { if (g.mesh().positive_only()) return true; using triqs::arrays::max_element; // the case real, complex is not found by ADL for (auto const &w : g.mesh().get_positive_freq()) if (max_element(abs(conj(g(-w)) - g(w))) > tolerance) return false; return true; }
void check_input_gf(gf_const_view<GfOpts...> g, gf_const_view<GfOpts...> S) { if(g.mesh() != S.mesh() || get_target_shape(g) != get_target_shape(S)) fatal_error("input quantity and the error-bar function S must have equivalent structure"); auto shape = get_target_shape(g); if(shape[0] != shape[1]) fatal_error("matrix-valued input quantities must be square"); }
//------------------------------------------------------- // 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<imfreq, T, S> make_gf_from_fourier(gf_const_view<imtime, T, S, E> const& gt, int n_iw = -1) { if (n_iw == -1) n_iw = (gt.mesh().size() - 1) / 2; auto m = gf_mesh<imfreq>{gt.mesh().domain(), n_iw}; auto gw = gf<imfreq, T, S>{m, get_target_shape(gt)}; gw() = fourier(gt); return gw; }
//------------------------------------------------------- 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; }
static void write(h5::group gr, gf_const_view<block_index2, Target> g) { auto const &m0 = std::get<0>(g.mesh()); auto const &m1 = std::get<1>(g.mesh()); for (int i = 0; i < m0.size(); ++i) for (int j = 0; j < m1.size(); ++j) h5_write(gr, m0.domain().names()[i] + "_" + m1.domain().names()[j], g._data[i][j]); h5_write(gr, "block_names", m0.domain().names()); }
// 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}; }
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 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; }
// Legendre coefficients som_core::som_core(gf_const_view<legendre> g_l, gf_const_view<legendre> S_l, observable_kind kind, vector<double> const& norms) : mesh(g_l.mesh()), kind(kind), norms(make_default_norms(norms,get_target_shape(g_l)[0])), rhs(input_data_r_t()), error_bars(input_data_r_t()) { if(is_stat_relevant(kind)) check_gf_stat(g_l, observable_statistics(kind)); check_input_gf(g_l,S_l); if(!is_gf_real(g_l) || !is_gf_real(S_l)) fatal_error("Legendre " + observable_name(kind) + " must be real"); gf<legendre, matrix_real_valued> g_l_real = real(g_l), S_l_real = real(S_l); set_input_data(make_const_view(g_l_real), make_const_view(S_l_real)); }
// 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; }
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; }
void legendre_matsubara_direct(gf_view<imtime> gt, gf_const_view<legendre> gl) { gt() = 0.0; legendre_generator L; for (auto t : gt.mesh()) { L.reset(2 * t / gt.domain().beta - 1); for (auto l : gl.mesh()) { gt[t] += sqrt(2 * l.index() + 1) / gt.domain().beta * gl[l] * L.next(); } } gt.singularity() = get_tail(gl, gt.singularity().size(), gt.singularity().order_min()); }
void legendre_matsubara_direct(gf_view<imfreq> gw, gf_const_view<legendre> gl) { gw() = 0.0; triqs::arrays::range R; // Use the transformation matrix for (auto om : gw.mesh()) { for (auto l : gl.mesh()) { gw[om] += legendre_T(om.index(), l.index()) * gl[l]; } } gw.singularity() = get_tail(gl, gw.singularity().size(), gw.singularity().order_min()); }
// Imaginary frequency som_core::som_core(gf_const_view<imfreq> g_iw, gf_const_view<imfreq> S_iw, observable_kind kind, vector<double> const& norms) : mesh(g_iw.mesh()), kind(kind), norms(make_default_norms(norms,get_target_shape(g_iw)[0])), rhs(input_data_c_t()), error_bars(input_data_c_t()) { if(is_stat_relevant(kind)) check_gf_stat(g_iw, observable_statistics(kind)); check_input_gf(g_iw,S_iw); if(!is_gf_real_in_tau(g_iw) || !is_gf_real_in_tau(S_iw)) fatal_error("imaginary frequency " + observable_name(kind) + " must be real in \\tau-domain"); auto g_iw_pos = positive_freq_view(g_iw); auto S_iw_pos = positive_freq_view(S_iw); check_input_gf(g_iw_pos,S_iw_pos); set_input_data(g_iw_pos,S_iw_pos); }
//------------------------------------------------------- // 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; }
static void write(h5::group gr, gf_const_view<block_index, Target, Opt> g) { for (size_t i = 0; i < g.mesh().size(); ++i) h5_write(gr, g.mesh().domain().names()[i], g._data[i]); // h5_write(gr,"symmetry",g._symmetry); }
static void write(h5::group gr, gf_const_view<block_index, Target> g) { for (size_t i = 0; i < g.mesh().size(); ++i) h5_write(gr, g.mesh().domain().names()[i], g._data[i]); h5_write(gr, "block_names", g.mesh().domain().names()); }
gf<retime, Target, Singularity> make_gf_from_inverse_fourier(gf_const_view<refreq, Target, Singularity, Evaluator> const& gw) { auto gt = gf<retime, Target>{make_mesh_fourier_compatible(gw.mesh()), get_target_shape(gw)}; gt() = inverse_fourier(gw); return gt; }
gf<refreq, Target, Singularity> make_gf_from_fourier(gf_const_view<retime, Target, Singularity, Evaluator> const& gt) { auto gw = gf<refreq, Target>{make_mesh_fourier_compatible(gt.mesh()), get_target_shape(gt)}; gw() = fourier(gt); return gw; }
/// 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 }