/******************************************************************************* * * TRIQS: a Toolbox for Research in Interacting Quantum Systems * * Copyright (C) 2011-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 . * ******************************************************************************/ #ifndef TRIQS_ARRAYS_H5_LOWLEVEL_H #define TRIQS_ARRAYS_H5_LOWLEVEL_H #include #include #include #include "../cache.hpp" namespace triqs { namespace arrays { namespace h5_impl { template const void* __get_array_data_cptr(A const& a) { return h5::get_data_ptr(&(a.storage()[0])); } template void* __get_array_data_ptr(A& x) { return h5::get_data_ptr(&(x.storage()[0])); } // the dataspace corresponding to the array. Contiguous data only... template H5::DataSpace data_space(ArrayType const& A) { if (!A.indexmap().is_contiguous()) TRIQS_RUNTIME_ERROR << " h5 : internal error : array not contiguous"; static const unsigned int R = ArrayType::rank; mini_vector S; auto const& S1(A.indexmap().strides()); for (int u = 0; u < R; ++u) { if (S1[u] <= 0) TRIQS_RUNTIME_ERROR << " negative strides not permitted in h5"; S[u] = 1; } static const bool is_complex = boost::is_complex::value; return h5::dataspace_from_LS(A.indexmap().domain().lengths(), A.indexmap().domain().lengths(), S); } /******************** resize or check the size ****************************************************/ template ENABLE_IF(is_amv_value_class) resize_or_check(A& a, mini_vector const& dimsf) { a.resize(indexmaps::cuboid::domain_t(dimsf)); } template ENABLE_IF(is_amv_view_class) resize_or_check(A const& a, mini_vector const& dimsf) { if (a.indexmap().domain().lengths() != dimsf) TRIQS_RUNTIME_ERROR << "Dimension error : the view can not be resized : " << "\n in file : " << dimsf.to_string() << "\n in view : " << a.indexmap().domain().lengths().to_string(); } /*********************************** WRITE array ****************************************************************/ /* * Write an array or a view into an hdf5 file * * f The h5 file or group of type H5::H5File or H5::Group * name The name of the hdf5 array in the file/group where the stack will be stored * A The array to be stored * C_reorder bool If true [default] the data will be stored in C order in the hdf5, hence making a temporary * cache of the data to reorder them in memory. * If false, the array is stored as it [if you know what you are doing] * The HDF5 exceptions will be caught and rethrown as TRIQS_RUNTIME_ERROR (with a full stackstrace, cf triqs doc). */ template void write_array_impl(h5::group g, std::string const& name, array_const_view A, bool C_reorder) { static_assert(!std::is_base_of::value, " Not implemented"); // 1d is below if (C_reorder) { write_array_impl(g, name, make_const_cache(A).view(), false); return; } try { H5::DataSet ds = g.create_dataset(name, h5::data_type_file(), data_space(A)); ds.write(__get_array_data_cptr(A), h5::data_type_memory(), data_space(A)); // if complex, to be python compatible, we add the __complex__ attribute if (boost::is_complex::value) h5::write_string_attribute(&ds, "__complex__", "1"); } TRIQS_ARRAYS_H5_CATCH_EXCEPTION; } template void write_array(h5::group g, std::string const& name, A const& a, bool C_reorder = true) { write_array_impl(g, name, typename A::const_view_type{a}, C_reorder); } /*********************************** READ array ****************************************************************/ /* * Read an array or a view from an hdf5 file * ArrayType The type of the array/matrix/vector, etc.. * f The h5 file or group of type H5::H5File or H5::Group * name The name of the hdf5 array in the file/group where the stack will be stored * A The array to be stored * C_reorder bool If true [default] the data will be stored in C order in the hdf5, hence making a temporary * cache of the data to reorder them in memory. If false, the array is stored as it [if you know what you are doing] * The HDF5 exceptions will be caught and rethrown as TRIQS_RUNTIME_ERROR (with a full stackstrace, cf triqs doc). */ template void read_array(h5::group g, std::string const& name, ArrayType1&& A, bool C_reorder = true) { typedef typename std::remove_reference::type ArrayType; static_assert(!std::is_base_of::value, " Not implemented"); // 1d is below try { H5::DataSet ds = g.open_dataset(name); H5::DataSpace dataspace = ds.getSpace(); static const unsigned int Rank = ArrayType::rank + (boost::is_complex::value ? 1 : 0); int rank = dataspace.getSimpleExtentNdims(); if (rank != Rank) TRIQS_RUNTIME_ERROR << "triqs::array::h5::read. Rank mismatch : the array has rank = " << Rank << " while the array stored in the hdf5 file has rank = " << rank; mini_vector dims_out; dataspace.getSimpleExtentDims(&dims_out[0], NULL); mini_vector d2; for (size_t u = 0; u < ArrayType::rank; ++u) d2[u] = dims_out[u]; resize_or_check(A, d2); if (C_reorder) { read_array(g, name, make_cache(A).view(), false); //read_array(g, name, cache(A).view(), false); } else ds.read(__get_array_data_ptr(A), h5::data_type_memory(), data_space(A), dataspace); } TRIQS_ARRAYS_H5_CATCH_EXCEPTION; } // overload : special treatment for arrays of strings (one dimension only). inline void write_array(h5::group f, std::string const& name, vector_const_view V) { h5::detail::write_1darray_vector_of_string_impl(f, name, V); } inline void write_array(h5::group f, std::string const& name, array_const_view V) { write_array(f, name, vector_const_view(V)); } inline void read_array(h5::group f, std::string const& name, arrays::vector& V) { h5::detail::read_1darray_vector_of_string_impl(f, name, V); } // I can not use the generic code, just because the resize of the array take a shape, not a size_t as std::vector and vector inline void read_array(h5::group f, std::string const& name, arrays::array& V) { arrays::vector res; read_array(f, name, res); V = res; } } // namespace h5_impl // a trait to detect if A::value_type exists and is a scalar or a string // used to exclude array> template struct has_scalar_or_string_value_type : std::false_type {}; template struct has_scalar_or_string_value_type< A, decltype(nop(std::declval< typename A::value_type>()))> : std::integral_constant::value || std::is_base_of::value> {}; // get_triqs_hdf5_data_scheme template TYPE_ENABLE_IFC(std::string, is_amv_value_or_view_class::value) get_triqs_hdf5_data_scheme(ArrayType const&) { using triqs::get_triqs_hdf5_data_scheme; // for the basic types, not found by ADL std::stringstream fs; fs << "array<" << get_triqs_hdf5_data_scheme(typename ArrayType::value_type()) << "," << ArrayType::rank << ">"; return fs.str(); } /* * Read an array or a view from an hdf5 file * ArrayType The type of the array/matrix/vector, etc.. * g The h5 group * name The name of the hdf5 array in the file/group where the stack will be stored * A The array to be stored * The HDF5 exceptions will be caught and rethrown as TRIQS_RUNTIME_ERROR (with a full stackstrace, cf triqs doc). */ template ENABLE_IFC(is_amv_value_or_view_class::value&& has_scalar_or_string_value_type::value) h5_read(h5::group g, std::string const& name, ArrayType& A) { h5_impl::read_array(g, name, A); } /* * Write an array or a view into an hdf5 file * ArrayType The type of the array/matrix/vector, etc.. * g The h5 group * name The name of the hdf5 array in the file/group where the stack will be stored * A The array to be stored * The HDF5 exceptions will be caught and rethrown as TRIQS_RUNTIME_ERROR (with a full stackstrace, cf triqs doc). */ template ENABLE_IFC(is_amv_value_or_view_class::value&& has_scalar_or_string_value_type::value) h5_write(h5::group g, std::string const& name, ArrayType const& A) { if (A.is_empty()) TRIQS_RUNTIME_ERROR << " Can not save an empty array into hdf5"; h5_impl::write_array(g, name, array_const_view(A)); } // details for generic save/read of arrays. namespace h5_impl { inline std::string _h5_name() { return ""; } template std::string _h5_name(T0 const& t0, Ts const&... ts) { auto r = std::to_string(t0); auto r1 = _h5_name(ts...); if (r1 != "") r += "_" + r1; return r; } #ifndef __cpp_generic_lambdas template struct _save_lambda { ArrayType const& a; h5::group g; template void operator()(Is const&... is) const { h5_write(g, _h5_name(is...), a(is...)); } }; template struct _load_lambda { ArrayType& a; h5::group g; template void operator()(Is const&... is) { h5_read(g, _h5_name(is...), a(is...)); } }; #endif } // details /* * Write an array or a view into an hdf5 file when type is not fundamental * ArrayType The type of the array/matrix/vector, etc.. * g The h5 group * name The name of the hdf5 array in the file/group where the stack will be stored * A The array to be stored * The HDF5 exceptions will be caught and rethrown as TRIQS_RUNTIME_ERROR (with a full stackstrace, cf triqs doc). */ template std::c14::enable_if_t::value && !has_scalar_or_string_value_type::value> h5_write(h5::group gr, std::string name, ArrayType const& a) { if (a.is_empty()) TRIQS_RUNTIME_ERROR << " Can not save an empty array into hdf5"; auto gr2 = gr.create_group(name); gr2.write_triqs_hdf5_data_scheme(a); // save the shape array sha(ArrayType::rank); for (int u = 0; u < ArrayType::rank; ++u) sha(u) = a.shape()[u]; h5_write(gr2, "shape", sha); #ifndef __cpp_generic_lambdas foreach(a, h5_impl::_save_lambda{a, gr2}); #else foreach(a, [&](auto... is) { h5_write(gr2, h5_impl::_h5_name(is...), a(is...)); }); #endif } /* * Read an array or a view from an hdf5 file when type is not fundamental * ArrayType The type of the array/matrix/vector, etc.. * g The h5 group * name The name of the hdf5 array in the file/group where the stack will be stored * A The array to be stored * The HDF5 exceptions will be caught and rethrown as TRIQS_RUNTIME_ERROR (with a full stackstrace, cf triqs doc). */ template std::c14::enable_if_t::value && !has_scalar_or_string_value_type::value> h5_read(h5::group gr, std::string name, ArrayType& a) { static_assert(!std::is_const::value, "Can not read in const object"); auto gr2 = gr.open_group(name); // TODO checking scheme... // load the shape auto sha2 = a.shape(); array sha; h5_read(gr2, "shape", sha); if (first_dim(sha) != sha2.size()) TRIQS_RUNTIME_ERROR << " array> load : rank mismatch. Expected " << sha2.size()<< " Got " << first_dim(sha); for (int u = 0; u < sha2.size(); ++u) sha2[u] = sha(u); if (a.shape() != sha2) a.resize(sha2); #ifndef __cpp_generic_lambdas foreach(a, h5_impl::_load_lambda{a, gr2}); #else foreach(a, [&](auto... is) { h5_read(gr2, h5_impl::_h5_name(is...), a(is...)); }); #endif } } } #endif