From 47255ea25a4fc5b80463229da8ad553e9f4c6b6c Mon Sep 17 00:00:00 2001 From: Guilhem Lavaux Date: Tue, 20 May 2014 16:16:46 +0200 Subject: [PATCH] HDF5 boost multi array transparent support --- sample/CMakeLists.txt | 3 + sample/testHDF5.cpp | 65 ++++++++++++++++ src/hdf5_array.hpp | 175 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 sample/testHDF5.cpp create mode 100644 src/hdf5_array.hpp diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt index 606c8d1..5180106 100644 --- a/sample/CMakeLists.txt +++ b/sample/CMakeLists.txt @@ -34,6 +34,9 @@ target_link_libraries(testPool ${tolink}) if (HDF5_FOUND) add_executable(testReadFlash testReadFlash.cpp) target_link_libraries(testReadFlash ${tolink}) + + add_executable(testHDF5 testHDF5.cpp) + target_link_libraries(testHDF5 ${tolink}) endif (HDF5_FOUND) diff --git a/sample/testHDF5.cpp b/sample/testHDF5.cpp new file mode 100644 index 0000000..82c3230 --- /dev/null +++ b/sample/testHDF5.cpp @@ -0,0 +1,65 @@ +#include +#include +#include "hdf5_array.hpp" + +using namespace std; + +int main() +{ + typedef boost::multi_array array_type; + typedef boost::multi_array array3_type; + typedef boost::multi_array, 2> arrayc_type; + typedef array_type::index index; + + H5::H5File f("test.h5", H5F_ACC_TRUNC); + + H5::Group g = f.createGroup("test_group"); + + array_type A(boost::extents[2][3]); + array_type B; + array3_type C(boost::extents[2][3][4]); + arrayc_type D, E; + + int values = 0; + for (index i = 0; i != 2; i++) + for (index j = 0; j != 3; j++) + A[i][j] = values++; + + CosmoTool::hdf5_write_array(g, "test_data", A); + + CosmoTool::hdf5_read_array(g, "test_data", B); + + int verify = 0; + for (index i = 0; i != 2; i++) + for (index j = 0; j != 3; j++) + if (B[i][j] != verify++) { + std::cout << "Invalid array content" << endl; + abort(); + } + + try + { + CosmoTool::hdf5_read_array(g, "test_data", C); + std::cout << "Did not throw InvalidDimensions" << endl; + abort(); + } + catch (const CosmoTool::InvalidDimensions&) + {} + + D.resize(boost::extents[2][3]); + D = A; + + CosmoTool::hdf5_write_array(g, "test_data_c", D); + + CosmoTool::hdf5_read_array(g, "test_data_c", E); + + verify = 0; + for (index i = 0; i != 2; i++) + for (index j = 0; j != 3; j++) + if (E[i][j].real() != verify++) { + std::cout << "Invalid array content" << endl; + abort(); + } + + return 0; +} diff --git a/src/hdf5_array.hpp b/src/hdf5_array.hpp new file mode 100644 index 0000000..46673ba --- /dev/null +++ b/src/hdf5_array.hpp @@ -0,0 +1,175 @@ +#ifndef __COSMO_HDF5_ARRAY_HPP +#define __COSMO_HDF5_ARRAY_HPP + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace CosmoTool { + + //!_______________________________________________________________________________________ + //! + //! map types to HDF5 types + //! + //! + //! Leo Goodstadt (04 March 2013), improved with enable_if by Guilhem Lavaux (May 2014) + //!_______________________________________________________________________________________ + + template struct get_hdf5_data_type + { + static H5::PredType type() + { + BOOST_MPL_ASSERT_MSG(0, Unknown_HDF5_data_type, ()); + return H5::PredType::NATIVE_DOUBLE; + } + }; + + #define HDF5_TYPE(tl, thdf5) \ + template struct get_hdf5_data_type >::type> \ + { static H5::PredType type() { return H5::PredType::thdf5; }; } + + HDF5_TYPE(char , NATIVE_CHAR); + HDF5_TYPE(long long , NATIVE_LLONG); + HDF5_TYPE(unsigned long long, NATIVE_ULLONG); + HDF5_TYPE(int8_t , NATIVE_INT8); + HDF5_TYPE(uint8_t , NATIVE_UINT8); + HDF5_TYPE(int16_t , NATIVE_INT16); + HDF5_TYPE(uint16_t , NATIVE_UINT16); + HDF5_TYPE(int32_t , NATIVE_INT32); + HDF5_TYPE(uint32_t , NATIVE_UINT32); + HDF5_TYPE(int64_t , NATIVE_INT64); + HDF5_TYPE(uint64_t , NATIVE_UINT64); + HDF5_TYPE(float , NATIVE_FLOAT); + HDF5_TYPE(double , NATIVE_DOUBLE); + HDF5_TYPE(long double , NATIVE_LDOUBLE); + + #undef HDF5_TYPE + +//!_______________________________________________________________________________________ +//! +//! write_hdf5 multi_array +//! +//! \author leo Goodstadt (04 March 2013) +//! +//!_______________________________________________________________________________________ + template + void hdf5_write_array(H5::CommonFG& fg, const std::string& data_set_name, + const boost::multi_array& data, + const hdf5_data_type& datatype) + { + std::vector dimensions(data.shape(), data.shape() + DIMENSIONS); + H5::DataSpace dataspace(DIMENSIONS, dimensions.data()); + + H5::DataSet dataset = fg.createDataSet(data_set_name, datatype, dataspace); + + dataset.write(data.data(), datatype); + } + + /* HDF5 complex type */ + template + class hdf5_ComplexType + { + public: + H5::CompType type; + + hdf5_ComplexType() + : type(sizeof(std::complex)) + { + get_hdf5_data_type hdf_data_type; + type.insertMember("r", 0, hdf_data_type.type()); + type.insertMember("i", sizeof(T), hdf_data_type.type()); + type.pack(); + } + + static const hdf5_ComplexType *ctype() + { + static hdf5_ComplexType singleton; + + return &singleton; + } + }; + + template + void hdf5_write_array(H5::CommonFG& fg, const std::string& data_set_name, const boost::multi_array& data ) + { + get_hdf5_data_type hdf_data_type; + hdf5_write_array(fg, data_set_name, data, hdf_data_type.type()); + } + + template + void hdf5_write_array(H5::CommonFG& fg, const std::string& data_set_name, const boost::multi_array, DIMENSIONS>& data ) + { + hdf5_write_array(fg, data_set_name, data, hdf5_ComplexType::ctype()->type); + } + + + // HDF5 array reader + // + // Author Guilhem Lavaux (May 2014) + + class InvalidDimensions: virtual std::exception { + }; + + template + struct hdf5_extent_gen { + typedef typename boost::detail::multi_array::extent_gen type; + + static inline type build(hsize_t *d) + { + return (hdf5_extent_gen::build(d))[d[r-1]]; + } + }; + + template<> + struct hdf5_extent_gen<0> { + static inline boost::multi_array_types::extent_gen build(hsize_t *d) + { + return boost::extents; + } + }; + + template + void hdf5_read_array(H5::CommonFG& fg, const std::string& data_set_name, + boost::multi_array& data, + const hdf5_data_type& datatype) + { + H5::DataSet dataset = fg.openDataSet(data_set_name); + H5::DataSpace dataspace = dataset.getSpace(); + std::vector dimensions(DIMENSIONS); + + if (dataspace.getSimpleExtentNdims() != DIMENSIONS) + { + throw InvalidDimensions(); + } + + dataspace.getSimpleExtentDims(dimensions.data()); + data.resize(hdf5_extent_gen::build(dimensions.data())); + dataset.read(data.data(), datatype); + } + + template + void hdf5_read_array(H5::CommonFG& fg, const std::string& data_set_name, boost::multi_array& data ) + { + get_hdf5_data_type hdf_data_type; + hdf5_read_array(fg, data_set_name, data, hdf_data_type.type()); + } + + template + void hdf5_read_array(H5::CommonFG& fg, const std::string& data_set_name, boost::multi_array, DIMENSIONS>& data ) + { + hdf5_read_array(fg, data_set_name, data, hdf5_ComplexType::ctype()->type); + } + +}; + +#endif + +