/******************************************************************************* * * TRIQS: a Toolbox for Research in Interacting Quantum Systems * * Copyright (C) 2013 by O. Parcollet * * TRIQS is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * TRIQS. If not, see . * ******************************************************************************/ #pragma once #include "./tools.hpp" #include "./gf.hpp" #include "./meshes/product.hpp" #include "./evaluators.hpp" namespace triqs { namespace gfs { template struct cartesian_product { using type = std::tuple; static constexpr size_t size = sizeof...(Ms); }; // use alias template struct cartesian_product> : cartesian_product {}; // the mesh is simply a cartesian product template struct gf_mesh, Opt> : mesh_product...> { // using mesh_product< gf_mesh ... >::mesh_product< gf_mesh ... > ; using B = mesh_product...>; gf_mesh() = default; gf_mesh(gf_mesh... ms) : B{std::move(ms)...} {} }; namespace gfs_implementation { /// --------------------------- hdf5 --------------------------------- // h5 name : name1_x_name2_..... template struct h5_name, matrix_valued, Opt> { static std::string invoke() { return triqs::tuple::fold([](std::string a, std::string b) { return a + std::string(b.empty() ? "" : "_x_") + b; }, std::make_tuple(h5_name::invoke()...), std::string()); } }; template struct h5_name, tensor_valued, Opt> : h5_name, matrix_valued, Opt> {}; // a slight difference with the generic case : reinterpret the data array to avoid flattening the variables template struct h5_rw, tensor_valued, Opt> { using g_t = gf, tensor_valued, Opt>; static void write(h5::group gr, typename g_t::const_view_type g) { h5_write(gr, "data", reinterpret_linear_array(g.mesh(), g().data())); h5_write(gr, "singularity", g._singularity); h5_write(gr, "mesh", g._mesh); h5_write(gr, "symmetry", g._symmetry); } template static void read(h5::group gr, gf_impl, tensor_valued, Opt, IsView, false> &g) { using G_t = gf_impl, tensor_valued, Opt, IsView, false>; h5_read(gr, "mesh", g._mesh); auto arr = arrays::array{}; h5_read(gr, "data", arr); auto sh = arr.shape(); arrays::mini_vector sh2; sh2[0] = g._mesh.size(); for (int u = 1; u < R + 1; ++u) sh2[u] = sh[sizeof...(Ms) - 1 + u]; g._data = arrays::array{sh2, std::move(arr.storage())}; h5_read(gr, "singularity", g._singularity); h5_read(gr, "symmetry", g._symmetry); } }; /// --------------------------- data access --------------------------------- template struct data_proxy, scalar_valued, Opt> : data_proxy_array, 1> {}; template struct data_proxy, matrix_valued, Opt> : data_proxy_array, 3> {}; template struct data_proxy, tensor_valued, Opt> : data_proxy_array, R + 1> {}; /// --------------------------- evaluator --------------------------------- /** * This the multi-dimensional evaluator. * It combine the evaluator of each components, as long as they are a linear form * eval(g, x) = \sum_i w_i g( n_i(x)) , with w some weight and n_i some points on the grid. * Mathematically, it is written as (example of evaluating g(x1,x2,x3,x4)). * Notation : eval(X) : g -> g(X) * eval(x1,x2,x3,x4) (g) = eval (x1) ( binder ( g, (), (x2,x3,x4)) ) * binder( g, (), (x2,x3,x4)) (p1) = eval(x2)(binder (g,(p1),(x3,x4))) * binder( g, (p1), (x3,x4)) (p2) = eval(x3)(binder (g,(p1,p2),(x4))) * binder( g, (p1,p2), (x4)) (p3) = eval(x4)(binder (g,(p1,p2,p3),())) * binder( g, (p1,p2,p3),()) (p4) = g[p1,p2,p3,p4] * * p_i are points on the grids, x_i points in the domain. * * Unrolling the formula gives (for 2 variables, with 2 points interpolation) * eval(xa,xb) (g) = eval (xa) ( binder ( g, (), (xb)) ) = * w_1(xa) binder ( g, (), (xb))( n_1(xa)) + w_2(xa) binder ( g, (), (xb))( n_2(xa)) * = w_1(xa) ( eval(xb)( binder ( g, (n_1(xa) ), ()))) + 1 <-> 2 * = w_1(xa) ( W_1(xb) * binder ( g, (n_1(xa) ), ())(N_1(xb)) + 1<->2 ) + 1 <-> 2 * = w_1(xa) ( W_1(xb) * g[n_1(xa), N_1(xb)] + 1<->2 ) + 1 <-> 2 * = w_1(xa) ( W_1(xb) * g[n_1(xa), N_1(xb)] + W_2(xb) * g[n_1(xa), N_2(xb)] ) + 1 <-> 2 * which is the expected formula */ // implementation : G = gf, Tn : tuple of n points, Ev : tuple of evaluators (the evals functions), // pos = counter from #args-1 =>0 // NB : the tuple is build in reverse with respect to the previous comment. template struct binder; template binder make_binder(G const *g, Tn tn, Ev const &ev) { return binder{g, std::move(tn), ev}; } template struct binder { G const *g; Tn tn; Ev const &evals; auto operator()(size_t p) const DECL_AND_RETURN(std::get(evals)(make_binder(g, triqs::tuple::push_front(tn, p), evals))); }; template struct binder { G const *g; Tn tn; Ev const &evals; auto operator()(size_t p) const DECL_AND_RETURN(triqs::tuple::apply(on_mesh(*g), triqs::tuple::push_front(tn, p))); }; // now the multi d evaluator itself. template struct evaluator, Target, Opt> { static constexpr int arity = sizeof...(Ms); mutable std::tuple...> evals; struct _poly_lambda { // replace by a polymorphic lambda in C++14 template void operator()(A &a, B const &b, C const &c) const { a = A{b, c}; } }; template // std::complex operator() (G const * g, Args && ... args) const { auto operator()(G const *g, Args &&... args) const -> decltype(std::get(evals)(make_binder(g, std::make_tuple(), evals))) // when do we get C++14 decltype(auto) ...!? { static constexpr int R = sizeof...(Args); // build the evaluators, as a tuple of ( evaluator ( mesh_component, args)) triqs::tuple::call_on_zip(_poly_lambda(), evals, g->mesh().components(), std::make_tuple(args...)); return std::get(evals)(make_binder(g, std::make_tuple(), evals)); } }; } // gf_implementation } }