/******************************************************************************* * * TRIQS: a Toolbox for Research in Interacting Quantum Systems * * Copyright (C) 2012-2013 by M. Ferrero, 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 . * ******************************************************************************/ #ifndef TRIQS_GF_GFBASECLASS_H #define TRIQS_GF_GFBASECLASS_H #include #include #include #include #include #include #include "./tools.hpp" #include "./data_proxies.hpp" namespace triqs { namespace gfs { using utility::factory; using arrays::make_shape; // GENERALISE matrxi TO DEFAULT template class gf; // the value class template class gf_view; // the view class // various implementation traits namespace gfs_implementation { // never use using of this... // what is the mesh template struct mesh; // evaluator regroup functions to evaluate the function. Cf descriptors template struct evaluator{ static constexpr int arity = 0;}; // closest_point mechanism template struct get_closest_point; // singularity template struct singularity { typedef nothing type;}; // symmetry template struct symmetry { typedef nothing type;}; // factories regroup all factories (constructors..) for all types of gf. template struct factories; // data_proxy contains function to manipulate the data array, but no data itself. // this is used to specialize this part of the code to array of dim 3 (matrix gf), dim 1 (scalar gf) and vector (e.g. block gf, ...) template struct data_proxy; // This trait contains functions to read/write in hdf5 files. Can be specialized for some descriptor (Cf block) template struct h5_name; // value is a const char * template struct h5_name { static std::string invoke(){ return h5_name::invoke() + "_s";}}; template struct h5_ops { template static void write(h5::group g, std::string const & s, DataType const & data, GF const &) { h5_write(g,"data",data); } template static void read (h5::group g, std::string const & s, DataType & data, GF const &) { h5_read(g,"data",data);} }; } // gfs_implementation // make_gf and make_gf_view forward any args to them template gf make_gf(U && ... x) { return gfs_implementation::factories::make_gf(std::forward(x)...);} template gf_view make_gf_view(U && ... x) { return gfs_implementation::factories::make_gf_view(std::forward(x)...);} template typename gfs_implementation::mesh::type make_gf_mesh(U && ... x) { return gfs_implementation::mesh::make(std::forward(x)...);} template struct gf_desc{}; template struct gf_tag{}; // The trait that "marks" the Green function TRIQS_DEFINE_CONCEPT_AND_ASSOCIATED_TRAIT(ImmutableGreenFunction); // ---------------------- implementation -------------------------------- /// A common implementation class for gf and gf_view. They will only redefine contructor and = ... template class gf_impl : TRIQS_MODEL_CONCEPT(ImmutableGreenFunction), gf_tag> { public : // Pattern : ValueView typedef gf_view view_type; typedef gf regular_type; typedef gf_desc descriptor_t; typedef Variable variable_t; typedef Opt option_t; typedef typename gfs_implementation::mesh::type mesh_t; typedef typename mesh_t::domain_t domain_t; typedef typename mesh_t::mesh_point_t mesh_point_t; typedef typename mesh_t::index_t mesh_index_t; typedef typename gfs_implementation::symmetry::type symmetry_t; typedef gfs_implementation::evaluator evaluator_t; typedef gfs_implementation::data_proxy data_proxy_t; typedef typename data_proxy_t::storage_t data_regular_t; typedef typename data_proxy_t::storage_view_t data_view_t; typedef typename std::conditional::type data_t; typedef typename gfs_implementation::singularity::type singularity_non_view_t; typedef typename view_type_if_exists_else_type::type singularity_view_t; typedef typename std::conditional::type singularity_t; mesh_t const & mesh() const { return _mesh;} domain_t const & domain() const { return _mesh.domain();} data_t & data() { return _data;} data_t const & data() const { return _data;} singularity_t & singularity() { return _singularity;} singularity_t const & singularity() const { return _singularity;} symmetry_t const & symmetry() const { return _symmetry;} evaluator_t const & get_evaluator() const { return _evaluator;} protected: mesh_t _mesh; data_t _data; singularity_t _singularity; symmetry_t _symmetry; evaluator_t _evaluator; data_proxy_t _data_proxy; // --------------------------------Constructors ----------------------------------------------- // all protected but one, this is an implementation class, see gf/gf_view later for public one gf_impl() {} // all arrays of zero size (empty) public : //everyone can make a copy (for clef lib in particular, this one needs to be public) gf_impl(gf_impl const & x) : _mesh(x.mesh()), _data(factory(x.data())), _singularity(factory(x.singularity())), _symmetry(x.symmetry()), _evaluator(x._evaluator){} gf_impl(gf_impl &&) = default; protected: gf_impl(gf_impl const & x): _mesh(x.mesh()), _data(factory(x.data())), _singularity(factory(x.singularity())), _symmetry(x.symmetry()), _evaluator(x.get_evaluator()){} template gf_impl(M && m, D && dat, S && sing, SY && sy, EV && ev) : _mesh(std::forward(m)), _data(std::forward(dat)), _singularity(std::forward(sing)),_symmetry(std::forward(sy)), _evaluator(std::forward(ev)){} void operator = (gf_impl const & rhs) = delete; // done in derived class. void swap_impl (gf_impl & b) noexcept { using std::swap; swap(this->_mesh, b._mesh); swap(this->_data, b._data); swap (this->_singularity,b._singularity); swap(this->_symmetry,b._symmetry); swap(this->_evaluator,b._evaluator); } public: // ------------- All the call operators ----------------------------- // First, a simple () returns a view, like for an array... view_type operator()() const { return *this;} /// Calls are (perfectly) forwarded to the evaluator::operator(), except mesh_point_t and when /// there is at least one lazy argument ... template // match any argument list, picking out the first type : () is not permitted typename std::add_const< typename boost::lazy_disable_if< // disable the template if one the following conditions it true boost::mpl::or_< // starting condition [OR] clef::is_any_lazy // One of Args is a lazy expression , boost::mpl::bool_<(sizeof...(Args)!= evaluator_t::arity -1 ) && (evaluator_t::arity !=-1)> // if -1 : no check >, // end of OR std::result_of // what is the result type of call >::type // end of lazy_disable_if >::type // end of add_Const operator() (Arg0&& arg0, Args&&... args) const { return _evaluator(this,std::forward( arg0), std::forward(args)...); } // Interaction with the CLEF library : calling the gf with any clef expression as argument build a new clef expression template typename clef::result_of::make_expr_call::type //typename clef::result_of::make_expr_call::type operator()(Arg0 arg0, Args... args) const { return clef::make_expr_call(view_type(*this),arg0, args...); } /* // on mesh component for composite meshes // enable iif the first arg is a mesh_point_t for the first component of the mesh_t template::value > typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, r_type>::type operator() (Arg0 const & arg0, Args const & ... args) { return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));} template::value > typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, cr_type>::type operator() (Arg0 const & arg0, Args const & ... args) const { return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));} */ //// [] and access to the grid point typedef typename std::result_of::type r_type; typedef typename std::result_of::type cr_type; r_type operator[] (mesh_index_t const & arg) { return _data_proxy(_data,_mesh.index_to_linear(arg));} cr_type operator[] (mesh_index_t const & arg) const { return _data_proxy(_data,_mesh.index_to_linear(arg));} r_type operator[] (mesh_point_t const & x) { return _data_proxy(_data, x.linear_index());} cr_type operator[] (mesh_point_t const & x) const { return _data_proxy(_data, x.linear_index());} template r_type operator[] (closest_pt_wrap const & p) { return _data_proxy(_data, _mesh.index_to_linear( gfs_implementation::get_closest_point::invoke(this,p)));} template cr_type operator[] (closest_pt_wrap const & p) const { return _data_proxy(_data, _mesh.index_to_linear( gfs_implementation::get_closest_point::invoke(this,p)));} // Interaction with the CLEF library : calling the gf with any clef expression as argument build a new clef expression template typename boost::lazy_enable_if< // enable the template if clef::is_any_lazy, // One of Args is a lazy expression clef::result_of::make_expr_subscript >::type // end of lazy_enable_if operator[](Arg && arg) const { return clef::make_expr_subscript(view_type(*this),std::forward(arg));} /// A direct access to the grid point template r_type on_mesh (Args&&... args) { return _data_proxy(_data,_mesh.index_to_linear(mesh_index_t(std::forward(args)...)));} /// A direct access to the grid point (const version) template cr_type on_mesh (Args&&... args) const { return _data_proxy(_data,_mesh.index_to_linear(mesh_index_t(std::forward(args)...)));} private: struct _on_mesh_wrapper_const { gf_impl const & f; _on_mesh_wrapper_const (gf_impl const & _f) : f(_f) {} template cr_type operator ()(Args && ... args) const { return f.on_mesh(std::forward(args)...);} }; struct _on_mesh_wrapper { gf_impl & f; _on_mesh_wrapper (gf_impl & _f) : f(_f) {} template r_type operator ()(Args && ... args) const { return f.on_mesh(std::forward(args)...);} }; _on_mesh_wrapper_const friend on_mesh(gf_impl const & f) { return f;} _on_mesh_wrapper friend on_mesh(gf_impl & f) { return f;} public: //----------------------------- HDF5 ----------------------------- friend std::string get_triqs_hdf5_data_scheme(gf_impl const & g) { return "Gf" + gfs_implementation::h5_name::invoke();} /// Write into HDF5 friend void h5_write (h5::group fg, std::string subgroup_name, gf_impl const & g) { auto gr = fg.create_group(subgroup_name); gr.write_triqs_hdf5_data_scheme(g); gfs_implementation::h5_ops::write(gr, "data", g._data, g);//can be specialized for some descriptors (E.g. blocks) h5_write(gr,"singularity",g._singularity); h5_write(gr,"mesh",g._mesh); h5_write(gr,"symmetry",g._symmetry); } /// Read from HDF5 friend void h5_read (h5::group fg, std::string subgroup_name, gf_impl & g) { auto gr = fg.open_group(subgroup_name); // Check the attribute or throw auto tag_file = gr.read_triqs_hdf5_data_scheme(); auto tag_expected= get_triqs_hdf5_data_scheme(g); if (tag_file != tag_expected) TRIQS_RUNTIME_ERROR<< "h5_read : mismatch of the tag TRIQS_HDF5_data_scheme tag in the h5 group : found "<::read(gr, "data", g._data, g);//can be specialized for some descriptors (E.g. blocks) h5_read(gr,"singularity",g._singularity); h5_read(gr,"mesh",g._mesh); h5_read(gr,"symmetry",g._symmetry); } //----------------------------- BOOST Serialization ----------------------------- friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int version) { ar & boost::serialization::make_nvp("data",_data); ar & boost::serialization::make_nvp("singularity",_singularity); ar & boost::serialization::make_nvp("mesh",_mesh); ar & boost::serialization::make_nvp("symmetry",_symmetry); } /// print friend std::ostream & operator << (std::ostream & out, gf_impl const & x) { return out<<(IsView ? "gf_view": "gf");} friend std::ostream & triqs_nvl_formal_print(std::ostream & out, gf_impl const & x) { return out<<(IsView ? "gf_view": "gf");} }; // --------------------------------------------------------------------------------- ///The regular class of GF template class gf : public gf_impl { typedef gf_impl B; public : gf():B() {} gf(gf const & g): B(g){} gf(gf && g) noexcept : B(std::move(g)){} gf(gf_view const & g): B(g){} template gf(GfType const & x): B() { *this = x;} template // anything from which the factory can make the data ... gf(typename B::mesh_t const & m, DataViewType && dat, typename B::singularity_view_t const & si, typename B::symmetry_t const & s , typename B::evaluator_t const & eval = typename B::evaluator_t () ) : B(m,factory(std::forward(dat)),si,s,eval) {} friend void swap (gf & a, gf & b) noexcept { a.swap_impl (b);} gf & operator = (gf const & rhs) { *this = gf(rhs); return *this;} // use move = gf & operator = (gf & rhs) { *this = gf(rhs); return *this;} // use move = gf & operator = (gf && rhs) noexcept { swap(*this, rhs); return *this;} template void operator = (RHS && rhs) { this->_mesh = rhs.mesh(); B::data_proxy_t::assign_with_resize(this->data(), std::forward(rhs).data()); // looks strange for && this->_singularity = rhs.singularity(); // to be implemented : there is none in the gf_expr in particular.... //this->_symmetry = rhs.symmetry(); } }; // --------------------------------------------------------------------------------- ///The View class of GF template class gf_view : public gf_impl { typedef gf_impl B; public : gf_view(gf_view const & g): B(g){} gf_view(gf_view && g) noexcept : B(std::move(g)){} template gf_view(gf_impl const & g): B(g){} template gf_view (typename B::mesh_t const & m, D const & dat,T const & t,typename B::symmetry_t const & s, typename B::evaluator_t const &e = typename B::evaluator_t () ) : B(m,factory(dat),t,s,e) {} friend void swap (gf_view & a, gf_view & b) noexcept { a.swap_impl (b);} void rebind (gf_view const &X) noexcept { this->_mesh = X._mesh; this->_symmetry = X._symmetry; this->_data_proxy.rebind(this->_data,X); this->_singularity.rebind(X._singularity); } gf_view & operator = (gf_view const & rhs) { triqs_gf_view_assign_delegation(*this,rhs); return *this;} template gf_view & operator = (RHS const & rhs) { triqs_gf_view_assign_delegation(*this,rhs); return *this;} // Interaction with the CLEF library : auto assignment of the gf (gf(om_) << expression fills the functions by evaluation of expression) template friend void triqs_clef_auto_assign (gf_view & g, RHS rhs) { // access to the data . Beware, we view it as a *matrix* NOT an array... (crucial for assignment to scalars !) g.triqs_clef_auto_assign_impl(rhs, typename std::is_base_of::type()); assign_from_expression(g.singularity(),rhs); // if f is an expression, replace the placeholder with a simple tail. If f is a function callable on freq_infty, // it uses the fact that tail_non_view_t can be casted into freq_infty } private: template void triqs_clef_auto_assign_impl (RHS const & rhs, std::integral_constant) { for (auto const & w: this->mesh()) (*this)[w] = rhs(w); //for (auto const & w: this->mesh()) (*this)[w] = rhs(typename B::mesh_t::mesh_point_t::cast_t(w)); } template void triqs_clef_auto_assign_impl (RHS const & rhs, std::integral_constant) { for (auto const & w: this->mesh()) (*this)[w] = triqs::tuple::apply(rhs,w.components_tuple()); //for (auto w: this->mesh()) triqs::tuple::apply(*this,w.components_tuple()) = triqs::tuple::apply(rhs,w.components_tuple()); } }; // class gf_view // delegate = so that I can overload it for specific RHS... template DISABLE_IF(arrays::is_scalar) triqs_gf_view_assign_delegation( gf_view & g, RHS const & rhs) { if (!(g.mesh() == rhs.mesh())) TRIQS_RUNTIME_ERROR<<"Gf Assignment in View : incompatible mesh"; gf_view::data_proxy_t::assign_no_resize(g.data(),rhs.data()); g.singularity() = rhs.singularity(); } template ENABLE_IF(arrays::is_scalar) triqs_gf_view_assign_delegation( gf_view & g, T const & x) { gf_view::data_proxy_t::assign_to_scalar(g.data(), x); g.singularity() = x; } // tool for lazy transformation template struct gf_keeper{ gf_view g; gf_keeper (gf_view const & g_) : g(g_) {} }; // ---------------------------------- slicing ------------------------------------ //slice template gf_view slice_target (gf_impl const & g, Args... args) { static_assert(std::is_same::value, "slice_target only for matrix_valued GF's"); using arrays::range; //auto sg=slice_target (g.singularity(),range(args,args+1)...); return gf_view(g.mesh(), g.data()(range(), args... ), slice_target (g.singularity(),args...) , g.symmetry()); } template gf_view slice_target_to_scalar (gf_impl const & g, Args... args) { static_assert(std::is_same::value, "slice_target only for matrix_valued GF's"); using arrays::range; auto sg=slice_target (g.singularity(),range(args,args+1)...); return gf_view(g.mesh(), g.data()(range(), args... ), sg, g.symmetry()); } // a scalar_valued gf can be viewed as a 1x1 matrix template gf_view reinterpret_scalar_valued_gf_as_matrix_valued (gf_impl const & g) { typedef arrays::array_view::storage_t::value_type,3> a_t; auto a = a_t {typename a_t::indexmap_type (arrays::mini_vector(g.data().shape()[0],1,1)), g.data().storage()}; return gf_view(g.mesh(), a, g.singularity(), g.symmetry()); } /* template gf_view slice_mesh (gf_impl const & g, Args... args) { return gf_view(g.mesh().slice(args...), g.data()(g.mesh().slice_get_range(args...),arrays::ellipsis()), g.singularity(), g.symmetry()); }*/ }} #include "./gf_expr.hpp" #endif