/*******************************************************************************
*
* 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