diff --git a/Grid/serialisation/Hdf5IO.h b/Grid/serialisation/Hdf5IO.h index 6f61ad76..6b77ba3c 100644 --- a/Grid/serialisation/Hdf5IO.h +++ b/Grid/serialisation/Hdf5IO.h @@ -36,10 +36,10 @@ namespace Grid template void writeRagged(const std::string &s, const std::vector &x); template - typename std::enable_if>::is_number, void>::type + typename std::enable_if>::value>::type writeDefault(const std::string &s, const std::vector &x); template - typename std::enable_if>::is_number, void>::type + typename std::enable_if>::value>::type writeDefault(const std::string &s, const std::vector &x) { writeRagged(s, x); } template void writeMultiDim(const std::string &s, const std::vector & Dimensions, const U * pDataRowMajor, size_t NumElements); @@ -68,10 +68,10 @@ namespace Grid template void readRagged(const std::string &s, std::vector &x); template - typename std::enable_if>::is_number, void>::type + typename std::enable_if>::value>::type readDefault(const std::string &s, std::vector &x); template - typename std::enable_if>::is_number, void>::type + typename std::enable_if>::value>::type readDefault(const std::string &s, std::vector &x) { readRagged(s, x); } template void readMultiDim(const std::string &s, std::vector &buf, std::vector &dim); @@ -180,13 +180,13 @@ namespace Grid } template - typename std::enable_if>::is_number, void>::type + typename std::enable_if>::value>::type Hdf5Writer::writeDefault(const std::string &s, const std::vector &x) { - if (isFlat(x)) + if (isRegularShape(x)) { // alias to element type - typedef typename element>::type Element; + using Scalar = typename is_flattenable>::type; // flatten the vector and getting dimensions Flatten> flat(x); @@ -194,7 +194,7 @@ namespace Grid const auto &flatx = flat.getFlatVector(); for (auto &d: flat.getDim()) dim.push_back(d); - writeMultiDim(s, dim, &flatx[0], flatx.size()); + writeMultiDim(s, dim, &flatx[0], flatx.size()); } else { @@ -239,7 +239,7 @@ namespace Grid void Hdf5Reader::readMultiDim(const std::string &s, std::vector &buf, std::vector &dim) { // alias to element type - typedef typename element>::type Element; + using Scalar = typename is_flattenable>::type; // read the dimensions H5NS::DataSpace dataSpace; @@ -270,19 +270,19 @@ namespace Grid H5NS::DataSet dataSet; dataSet = group_.openDataSet(s); - dataSet.read(buf.data(), Hdf5Type::type()); + dataSet.read(buf.data(), Hdf5Type::type()); } else { H5NS::Attribute attribute; attribute = group_.openAttribute(s); - attribute.read(Hdf5Type::type(), buf.data()); + attribute.read(Hdf5Type::type(), buf.data()); } } template - typename std::enable_if>::is_number, void>::type + typename std::enable_if>::value>::type Hdf5Reader::readDefault(const std::string &s, std::vector &x) { if (H5Lexists (group_.getId(), s.c_str(), H5P_DEFAULT) > 0 @@ -293,10 +293,10 @@ namespace Grid else { // alias to element type - typedef typename element>::type Element; + using Scalar = typename is_flattenable>::type; std::vector dim; - std::vector buf; + std::vector buf; readMultiDim( s, buf, dim ); // reconstruct the multidimensional vector diff --git a/Grid/serialisation/VectorUtils.h b/Grid/serialisation/VectorUtils.h index 8982ba9a..10471113 100644 --- a/Grid/serialisation/VectorUtils.h +++ b/Grid/serialisation/VectorUtils.h @@ -236,21 +236,36 @@ namespace Grid { } } - // Vector element trait ////////////////////////////////////////////////////// - template - struct element + // is_flattenable::value is true if T is a std::vector<> which can be flattened ////////////////////// + template + struct is_flattenable : std::false_type { - typedef T type; - static constexpr bool is_number = false; + using type = T; + using grid_type = T; + static constexpr int vecRank = 0; + static constexpr bool isGridTensor = false; + static constexpr bool children_flattenable = std::is_arithmetic::value or is_complex::value; }; - + template - struct element> + struct is_flattenable::value>::type> : std::false_type { - typedef typename element::type type; - static constexpr bool is_number = std::is_arithmetic::value - or is_complex::value - or element::is_number; + using type = typename GridTypeMapper::scalar_type; + using grid_type = T; + static constexpr int vecRank = 0; + static constexpr bool isGridTensor = true; + static constexpr bool children_flattenable = true; + }; + + template + struct is_flattenable, typename std::enable_if::children_flattenable>::type> + : std::true_type + { + using type = typename is_flattenable::type; + using grid_type = typename is_flattenable::grid_type; + static constexpr bool isGridTensor = is_flattenable::isGridTensor; + static constexpr int vecRank = is_flattenable::vecRank + 1; + static constexpr bool children_flattenable = true; }; // Vector flattening utility class //////////////////////////////////////////// @@ -259,23 +274,30 @@ namespace Grid { class Flatten { public: - typedef typename element::type Element; + using Scalar = typename is_flattenable::type; + static constexpr bool isGridTensor = is_flattenable::isGridTensor; public: - explicit Flatten(const V &vector); - const V & getVector(void); - const std::vector & getFlatVector(void); - const std::vector & getDim(void); + explicit Flatten(const V &vector); + const V & getVector(void) const { return vector_; } + const std::vector & getFlatVector(void) const { return flatVector_; } + const std::vector & getDim(void) const { return dim_; } private: - void accumulate(const Element &e); - template - void accumulate(const W &v); - void accumulateDim(const Element &e); - template - void accumulateDim(const W &v); + template typename std::enable_if::value && !is_flattenable::isGridTensor>::type + accumulate(const W &e); + template typename std::enable_if::value && is_flattenable::isGridTensor>::type + accumulate(const W &e); + template typename std::enable_if< is_flattenable::value>::type + accumulate(const W &v); + template typename std::enable_if::value && !is_flattenable::isGridTensor>::type + accumulateDim(const W &e) {} // Innermost is a scalar - do nothing + template typename std::enable_if::value && is_flattenable::isGridTensor>::type + accumulateDim(const W &e); + template typename std::enable_if< is_flattenable::value>::type + accumulateDim(const W &v); private: - const V &vector_; - std::vector flatVector_; - std::vector dim_; + const V &vector_; + std::vector flatVector_; + std::vector dim_; }; // Class to reconstruct a multidimensional std::vector @@ -283,38 +305,57 @@ namespace Grid { class Reconstruct { public: - typedef typename element::type Element; + using Scalar = typename is_flattenable::type; + static constexpr bool isGridTensor = is_flattenable::isGridTensor; public: - Reconstruct(const std::vector &flatVector, + Reconstruct(const std::vector &flatVector, const std::vector &dim); - const V & getVector(void); - const std::vector & getFlatVector(void); - const std::vector & getDim(void); + const V & getVector(void) const { return vector_; } + const std::vector & getFlatVector(void) const { return flatVector_; } + const std::vector & getDim(void) const { return dim_; } private: - void fill(std::vector &v); - template - void fill(W &v); - void resize(std::vector &v, const unsigned int dim); - template - void resize(W &v, const unsigned int dim); + template typename std::enable_if::value && !is_flattenable::isGridTensor>::type + fill(W &v); + template typename std::enable_if::value && is_flattenable::isGridTensor>::type + fill(W &v); + template typename std::enable_if< is_flattenable::value>::type + fill(W &v); + template typename std::enable_if< is_flattenable::value && is_flattenable::vecRank==1>::type + resize(W &v, const unsigned int dim); + template typename std::enable_if< is_flattenable::value && (is_flattenable::vecRank>1)>::type + resize(W &v, const unsigned int dim); + template typename std::enable_if::isGridTensor>::type + checkInnermost(const W &e) {} // Innermost is a scalar - do nothing + template typename std::enable_if< is_flattenable::isGridTensor>::type + checkInnermost(const W &e); private: - V vector_; - const std::vector &flatVector_; - std::vector dim_; - size_t ind_{0}; - unsigned int dimInd_{0}; + V vector_; + const std::vector &flatVector_; + std::vector dim_; + size_t ind_{0}; + unsigned int dimInd_{0}; }; // Flatten class template implementation template - void Flatten::accumulate(const Element &e) + template typename std::enable_if::value && !is_flattenable::isGridTensor>::type + Flatten::accumulate(const W &e) { flatVector_.push_back(e); } template - template - void Flatten::accumulate(const W &v) + template typename std::enable_if::value && is_flattenable::isGridTensor>::type + Flatten::accumulate(const W &e) + { + for (const Scalar &x: e) { + flatVector_.push_back(x); + } + } + + template + template typename std::enable_if::value>::type + Flatten::accumulate(const W &v) { for (auto &e: v) { @@ -323,11 +364,17 @@ namespace Grid { } template - void Flatten::accumulateDim(const Element &e) {}; + template typename std::enable_if::value && is_flattenable::isGridTensor>::type + Flatten::accumulateDim(const W &e) + { + using Traits = GridTypeMapper::grid_type>; + for (int rank=0; rank < Traits::Rank; ++rank) + dim_.push_back(Traits::Dimension(rank)); + } template - template - void Flatten::accumulateDim(const W &v) + template typename std::enable_if::value>::type + Flatten::accumulateDim(const W &v) { dim_.push_back(v.size()); accumulateDim(v[0]); @@ -337,42 +384,36 @@ namespace Grid { Flatten::Flatten(const V &vector) : vector_(vector) { - accumulate(vector_); accumulateDim(vector_); - } - - template - const V & Flatten::getVector(void) - { - return vector_; - } - - template - const std::vector::Element> & - Flatten::getFlatVector(void) - { - return flatVector_; - } - - template - const std::vector & Flatten::getDim(void) - { - return dim_; + std::size_t TotalSize{ dim_[0] }; + for (int i = 1; i < dim_.size(); ++i) { + TotalSize *= dim_[i]; + } + flatVector_.reserve(TotalSize); + accumulate(vector_); } // Reconstruct class template implementation template - void Reconstruct::fill(std::vector &v) + template typename std::enable_if::value && !is_flattenable::isGridTensor>::type + Reconstruct::fill(W &v) + { + v = flatVector_[ind_++]; + } + + template + template typename std::enable_if::value && is_flattenable::isGridTensor>::type + Reconstruct::fill(W &v) { for (auto &e: v) { e = flatVector_[ind_++]; } } - + template - template - void Reconstruct::fill(W &v) + template typename std::enable_if::value>::type + Reconstruct::fill(W &v) { for (auto &e: v) { @@ -381,14 +422,15 @@ namespace Grid { } template - void Reconstruct::resize(std::vector &v, const unsigned int dim) + template typename std::enable_if::value && is_flattenable::vecRank==1>::type + Reconstruct::resize(W &v, const unsigned int dim) { v.resize(dim_[dim]); } template - template - void Reconstruct::resize(W &v, const unsigned int dim) + template typename std::enable_if::value && (is_flattenable::vecRank>1)>::type + Reconstruct::resize(W &v, const unsigned int dim) { v.resize(dim_[dim]); for (auto &e: v) @@ -398,34 +440,31 @@ namespace Grid { } template - Reconstruct::Reconstruct(const std::vector &flatVector, + template typename std::enable_if::isGridTensor>::type + Reconstruct::checkInnermost(const W &) + { + using Traits = GridTypeMapper::grid_type>; + const int gridRank{Traits::Rank}; + const int dimRank{static_cast(dim_.size())}; + assert(dimRank >= gridRank && "Tensor rank too low for Grid tensor"); + for (int i=0; i + Reconstruct::Reconstruct(const std::vector &flatVector, const std::vector &dim) : flatVector_(flatVector) , dim_(dim) { + checkInnermost(vector_); + assert(dim_.size() == is_flattenable::vecRank && "Tensor rank doesn't match nested std::vector rank"); resize(vector_, 0); fill(vector_); } - template - const V & Reconstruct::getVector(void) - { - return vector_; - } - - template - const std::vector::Element> & - Reconstruct::getFlatVector(void) - { - return flatVector_; - } - - template - const std::vector & Reconstruct::getDim(void) - { - return dim_; - } - // Vector IO utilities /////////////////////////////////////////////////////// // helper function to read space-separated values template @@ -460,18 +499,18 @@ namespace Grid { return os; } - // In general, scalar types are considered "flat" (regularly shaped) + // In general, scalar types are considered "flattenable" (regularly shaped) template - bool isFlat(const T &t) { return true; } + bool isRegularShape(const T &t) { return true; } // Return non-zero if all dimensions of this std::vector> are regularly shaped template - bool isFlat(const std::vector> &v) + bool isRegularShape(const std::vector> &v) { // Make sure all of my rows are the same size for (std::size_t i = 0; i < v.size(); ++i) { - if (v[i].size() != v[0].size() || !isFlat(v[i])) + if (v[i].size() != v[0].size() || !isRegularShape(v[i])) { return false; }