mirror of
https://github.com/paboyle/Grid.git
synced 2024-11-13 01:05:36 +00:00
Still one issue on write
This commit is contained in:
parent
3b05f91f5c
commit
91be028507
@ -73,7 +73,7 @@ namespace Grid {
|
|||||||
template<typename T> struct is_tensor_of_container<T, typename std::enable_if<is_tensor<T>::value && is_container<typename T::Scalar>::value, void>::type> : public std::true_type {};
|
template<typename T> struct is_tensor_of_container<T, typename std::enable_if<is_tensor<T>::value && is_container<typename T::Scalar>::value, void>::type> : public std::true_type {};
|
||||||
|
|
||||||
// Is this a fixed-size Eigen tensor
|
// Is this a fixed-size Eigen tensor
|
||||||
template<typename T, typename C = void> struct is_tensor_fixed : public std::false_type {};
|
template<typename T> struct is_tensor_fixed : public std::false_type {};
|
||||||
template<typename Scalar_, typename Dimensions_, int Options_, typename IndexType>
|
template<typename Scalar_, typename Dimensions_, int Options_, typename IndexType>
|
||||||
struct is_tensor_fixed<Eigen::TensorFixedSize<Scalar_, Dimensions_, Options_, IndexType>>
|
struct is_tensor_fixed<Eigen::TensorFixedSize<Scalar_, Dimensions_, Options_, IndexType>>
|
||||||
: public std::true_type {};
|
: public std::true_type {};
|
||||||
@ -89,86 +89,81 @@ namespace Grid {
|
|||||||
&& !is_tensor_fixed<T>::value, void>::type> : public std::true_type {};
|
&& !is_tensor_fixed<T>::value, void>::type> : public std::true_type {};
|
||||||
|
|
||||||
// These traits describe the Eigen tensor scalar and container objects supported for IO
|
// These traits describe the Eigen tensor scalar and container objects supported for IO
|
||||||
// Containers arbitrarily deeply nested compositions of fixed size objects:
|
// Containers are arbitrarily deeply nested compositions of fixed size objects,
|
||||||
// ... grid tensors (iScalar, iVector, and iMatrix) and fixed size arrays
|
// ... grid tensors (iScalar, iVector, and iMatrix) and std::array
|
||||||
|
// EigenIO::Traits are not defined for Eigen tensors, but rather their top-level scalar
|
||||||
|
// This is because Eigen tensors have a dynamic size flavour, but the scalars are all fixed size
|
||||||
|
// This allows the traits to all be defined as constexpr
|
||||||
template <typename T, typename C = void> struct Traits {}; // C needed for specialisation
|
template <typename T, typename C = void> struct Traits {}; // C needed for specialisation
|
||||||
// This defines the bottom level - i.e. it's a description of the underlying scalar
|
// This defines the bottom level - i.e. it's a description of the underlying scalar
|
||||||
template <typename T> struct Traits<T, typename std::enable_if<is_scalar<T>::value, void>::type> {
|
template <typename T> struct Traits<T, typename std::enable_if<is_scalar<T>::value, void>::type> {
|
||||||
using scalar_type = T; // Type of the underlying scalar
|
using scalar_type = T; // Type of the underlying scalar
|
||||||
using scalar_real = typename RealType<scalar_type>::type; // real type underlying scalar_type
|
using scalar_real = typename RealType<scalar_type>::type; // real type underlying scalar_type
|
||||||
static constexpr unsigned int rank = 0; // The rank of the grid tensor (i.e. how many indices used)
|
static constexpr unsigned int rank = 0; // The rank of the grid tensor (i.e. how many indices used)
|
||||||
static constexpr unsigned int rank_non_trivial = 0; // As per rank, but excludes those of dimension 1
|
//static constexpr unsigned int rank_non_trivial = 0; // As per rank, but excludes those of dimension 1
|
||||||
static constexpr unsigned int count = 1; // total number of elements (i.e. product of dimensions)
|
static constexpr unsigned int count = 1; // total number of elements (i.e. product of dimensions)
|
||||||
static constexpr std::size_t scalar_size = sizeof(T); // Size of the underlying scalar in bytes
|
static constexpr std::size_t scalar_size = sizeof(T); // Size of the underlying scalar in bytes
|
||||||
static constexpr std::size_t size = scalar_size * count; // total size of elements in bytes
|
static constexpr std::size_t size = scalar_size * count; // total size of elements in bytes
|
||||||
static constexpr std::size_t Dimension(unsigned int dim) { return 0; } // Dimension size
|
static constexpr std::size_t Dimension(unsigned int dim) { return 0; } // Dimension size
|
||||||
static constexpr std::size_t DimensionNT(unsigned int dim) { return 0; } // non-trivial dim size
|
//static constexpr std::size_t DimensionNT(unsigned int dim) { return 0; } // non-trivial dim size
|
||||||
// e.g. iScalar<iVector<Complex,1>>
|
// e.g. iScalar<iVector<Complex,1>>
|
||||||
// depth = 2
|
// rank = 2
|
||||||
// rank = 1
|
|
||||||
// rank_non_trivial = 0
|
// rank_non_trivial = 0
|
||||||
// count = 1
|
// count = 1
|
||||||
// e.g. iVector<iMatrix<Complex,3>,4>
|
// e.g. iVector<iMatrix<Complex,3>,1>
|
||||||
// depth = 2
|
|
||||||
// rank = 3
|
// rank = 3
|
||||||
|
// rank_non_trivial = 2
|
||||||
|
// count = 9
|
||||||
|
// e.g. iScalar<iVector<iMatrix<Complex,3>,4>>
|
||||||
|
// rank = 4
|
||||||
// rank_non_trivial = 3
|
// rank_non_trivial = 3
|
||||||
// count = 36
|
// count = 36
|
||||||
// e.g. iScalar<iVector<iMatrix<Complex,4>,3>>
|
|
||||||
// depth = 3
|
|
||||||
// rank = 3
|
|
||||||
// rank_non_trivial = 3
|
|
||||||
// count = 48
|
|
||||||
};
|
};
|
||||||
template <typename T> struct Traits<iScalar<T>> {
|
template <typename T> struct Traits<iScalar<T>> {
|
||||||
using scalar_type = typename Traits<T>::scalar_type;
|
using scalar_type = typename Traits<T>::scalar_type;
|
||||||
using scalar_real = typename RealType<scalar_type>::type;
|
using scalar_real = typename RealType<scalar_type>::type;
|
||||||
static constexpr unsigned int rank = 1 + Traits<T>::rank;
|
static constexpr unsigned int rank = 1 + Traits<T>::rank;
|
||||||
static constexpr unsigned int rank_non_trivial = 0 + Traits<T>::rank_non_trivial;
|
//static constexpr unsigned int rank_non_trivial = 0 + Traits<T>::rank_non_trivial;
|
||||||
static constexpr unsigned int count = 1 * Traits<T>::count;
|
static constexpr unsigned int count = 1 * Traits<T>::count;
|
||||||
static constexpr std::size_t scalar_size = Traits<T>::scalar_size;
|
static constexpr std::size_t scalar_size = Traits<T>::scalar_size;
|
||||||
static constexpr std::size_t size = scalar_size * count;
|
static constexpr std::size_t size = scalar_size * count;
|
||||||
static constexpr std::size_t Dimension(unsigned int dim) {
|
static constexpr std::size_t Dimension(unsigned int dim) {
|
||||||
return ( dim == 0 ) ? 1 : Traits<T>::Dimension(dim - 1); }
|
return ( dim == 0 ) ? 1 : Traits<T>::Dimension(dim - 1); }
|
||||||
static constexpr std::size_t DimensionNT(unsigned int dim) {
|
//static constexpr std::size_t DimensionNT(unsigned int dim) {
|
||||||
return Traits<T>::DimensionNT(dim); }
|
//return Traits<T>::DimensionNT(dim); }
|
||||||
};
|
};
|
||||||
template <typename T, int N> struct Traits<iVector<T, N>> {
|
template <typename T, int N> struct Traits<iVector<T, N>> {
|
||||||
using scalar_type = typename Traits<T>::scalar_type;
|
using scalar_type = typename Traits<T>::scalar_type;
|
||||||
using scalar_real = typename RealType<scalar_type>::type;
|
using scalar_real = typename RealType<scalar_type>::type;
|
||||||
static constexpr unsigned int rank = 1 + Traits<T>::rank;
|
static constexpr unsigned int rank = 1 + Traits<T>::rank;
|
||||||
static constexpr unsigned int rank_non_trivial = (N>1 ? 1 : 0) + Traits<T>::rank_non_trivial;
|
//static constexpr unsigned int rank_non_trivial = (N>1 ? 1 : 0) + Traits<T>::rank_non_trivial;
|
||||||
static constexpr unsigned int count = N * Traits<T>::count;
|
static constexpr unsigned int count = N * Traits<T>::count;
|
||||||
static constexpr std::size_t scalar_size = Traits<T>::scalar_size;
|
static constexpr std::size_t scalar_size = Traits<T>::scalar_size;
|
||||||
static constexpr std::size_t size = scalar_size * count;
|
static constexpr std::size_t size = scalar_size * count;
|
||||||
static constexpr std::size_t Dimension(unsigned int dim) {
|
static constexpr std::size_t Dimension(unsigned int dim) {
|
||||||
return ( dim == 0 ) ? N : Traits<T>::Dimension(dim - 1); }
|
return ( dim == 0 ) ? N : Traits<T>::Dimension(dim - 1); }
|
||||||
static constexpr std::size_t DimensionNT(unsigned int dim) {
|
//static constexpr std::size_t DimensionNT(unsigned int dim) {
|
||||||
return ( N == 1 ) ? Traits<T>::DimensionNT(dim) : ( dim == 0 ) ? N : Traits<T>::DimensionNT(dim - 1);
|
//return ( N == 1 ) ? Traits<T>::DimensionNT(dim) : ( dim == 0 ) ? N : Traits<T>::DimensionNT(dim - 1);
|
||||||
}
|
//}
|
||||||
};
|
};
|
||||||
template <typename T, int N> struct Traits<iMatrix<T, N>> {
|
template <typename T, int N> struct Traits<iMatrix<T, N>> {
|
||||||
using scalar_type = typename Traits<T>::scalar_type;
|
using scalar_type = typename Traits<T>::scalar_type;
|
||||||
using scalar_real = typename RealType<scalar_type>::type;
|
using scalar_real = typename RealType<scalar_type>::type;
|
||||||
static constexpr unsigned int rank = 2 + Traits<T>::rank;
|
static constexpr unsigned int rank = 2 + Traits<T>::rank;
|
||||||
static constexpr unsigned int rank_non_trivial = (N>1 ? 2 : 0) + Traits<T>::rank_non_trivial;
|
//static constexpr unsigned int rank_non_trivial = (N>1 ? 2 : 0) + Traits<T>::rank_non_trivial;
|
||||||
static constexpr unsigned int count = N * N * Traits<T>::count;
|
static constexpr unsigned int count = N * N * Traits<T>::count;
|
||||||
static constexpr std::size_t scalar_size = Traits<T>::scalar_size;
|
static constexpr std::size_t scalar_size = Traits<T>::scalar_size;
|
||||||
static constexpr std::size_t size = scalar_size * count;
|
static constexpr std::size_t size = scalar_size * count;
|
||||||
static constexpr std::size_t Dimension(unsigned int dim) {
|
static constexpr std::size_t Dimension(unsigned int dim) {
|
||||||
return ( dim == 0 || dim == 1 ) ? N : Traits<T>::Dimension(dim - 2); }
|
return ( dim == 0 || dim == 1 ) ? N : Traits<T>::Dimension(dim - 2); }
|
||||||
static constexpr std::size_t DimensionNT(unsigned int dim) {
|
//static constexpr std::size_t DimensionNT(unsigned int dim) {
|
||||||
return ( N == 1 ) ? Traits<T>::DimensionNT(dim) : ( dim == 0 || dim == 1 ) ? N : Traits<T>::DimensionNT(dim - 2);
|
//return ( N == 1 ) ? Traits<T>::DimensionNT(dim) : ( dim == 0 || dim == 1 ) ? N : Traits<T>::DimensionNT(dim - 2);
|
||||||
}
|
//}
|
||||||
};
|
};
|
||||||
template <typename T, int N> struct Traits<std::array<T, N>> : Traits<iVector<T, N>> {};
|
template <typename T, int N> struct Traits<std::array<T, N>> : Traits<iVector<T, N>> {};
|
||||||
// Tensors have the same traits as their top-level scalar
|
|
||||||
// Shouldn't be necessary ... but I make the mistake of getting traits of the tensor so often
|
|
||||||
// that I am tempted to define this.
|
|
||||||
// HOWEVER, Eigen tensors have a dynamic size flavour, but the scalars are (currently) all fixed size
|
|
||||||
//template <typename T> struct Traits<T, typename std::enable_if<is_tensor<T>::value, void>::type> : Traits<T> {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// for_all helper function to call the lambda
|
// for_all helper function to call the lambda for scalar
|
||||||
template <typename ETensor, typename Lambda>
|
template <typename ETensor, typename Lambda>
|
||||||
typename std::enable_if<EigenIO::is_tensor_of_scalar<ETensor>::value, void>::type
|
typename std::enable_if<EigenIO::is_tensor_of_scalar<ETensor>::value, void>::type
|
||||||
for_all_do_lambda( Lambda lambda, typename ETensor::Scalar &scalar, typename ETensor::Index &Seq,
|
for_all_do_lambda( Lambda lambda, typename ETensor::Scalar &scalar, typename ETensor::Index &Seq,
|
||||||
@ -177,19 +172,19 @@ namespace Grid {
|
|||||||
lambda( scalar, Seq++, MyIndex );
|
lambda( scalar, Seq++, MyIndex );
|
||||||
}
|
}
|
||||||
|
|
||||||
// for_all helper function to call the lambda
|
// for_all helper function to call the lambda for container
|
||||||
template <typename ETensor, typename Lambda>
|
template <typename ETensor, typename Lambda>
|
||||||
typename std::enable_if<EigenIO::is_tensor_of_container<ETensor>::value, void>::type
|
typename std::enable_if<EigenIO::is_tensor_of_container<ETensor>::value, void>::type
|
||||||
for_all_do_lambda( Lambda lambda, typename ETensor::Scalar &scalar, typename ETensor::Index &Seq,
|
for_all_do_lambda( Lambda lambda, typename ETensor::Scalar &container, typename ETensor::Index &Seq,
|
||||||
std::array<std::size_t, ETensor::NumIndices + EigenIO::Traits<typename ETensor::Scalar>::rank> &MyIndex)
|
std::array<std::size_t, ETensor::NumIndices + EigenIO::Traits<typename ETensor::Scalar>::rank> &MyIndex)
|
||||||
{
|
{
|
||||||
using Scalar = typename ETensor::Scalar; // This could be a Container - we'll check later
|
using Traits = EigenIO::Traits<typename ETensor::Scalar>;
|
||||||
const auto InnerRank = EigenIO::Traits<Scalar>::rank_non_trivial;
|
|
||||||
const auto rank{ETensor::NumIndices};
|
const auto rank{ETensor::NumIndices};
|
||||||
for( typename EigenIO::Traits<Scalar>::scalar_type &Source : scalar ) {
|
const auto InnerRank = Traits::rank;
|
||||||
|
for( typename Traits::scalar_type &Source : container ) {
|
||||||
lambda(Source, Seq++, MyIndex );
|
lambda(Source, Seq++, MyIndex );
|
||||||
// Now increment SubIndex
|
// Now increment SubIndex
|
||||||
for( auto i = InnerRank - 1; i != -1 && ++MyIndex[rank + i] == EigenIO::Traits<Scalar>::DimensionNT(i); i-- )
|
for( auto i = InnerRank - 1; i != -1 && ++MyIndex[rank + i] == Traits::Dimension(i); i-- )
|
||||||
MyIndex[rank + i] = 0;
|
MyIndex[rank + i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,23 +252,43 @@ namespace Grid {
|
|||||||
// Would have preferred to define template variables for this, but that's c++ 17
|
// Would have preferred to define template variables for this, but that's c++ 17
|
||||||
template <typename ETensor>
|
template <typename ETensor>
|
||||||
typename std::enable_if<EigenIO::is_tensor<ETensor>::value && !EigenIO::is_complex<typename EigenIO::Traits<typename ETensor::Scalar>::scalar_type>::value, void>::type
|
typename std::enable_if<EigenIO::is_tensor<ETensor>::value && !EigenIO::is_complex<typename EigenIO::Traits<typename ETensor::Scalar>::scalar_type>::value, void>::type
|
||||||
SequentialInit( ETensor &ET, typename EigenIO::Traits<typename ETensor::Scalar>::scalar_type Inc = 1 )
|
SequentialInit( ETensor &ET, typename EigenIO::Traits<typename ETensor::Scalar>::scalar_type Inc = 1,
|
||||||
|
unsigned short Precision = 0 )
|
||||||
{
|
{
|
||||||
using Traits = EigenIO::Traits<typename ETensor::Scalar>;
|
using Traits = EigenIO::Traits<typename ETensor::Scalar>;
|
||||||
using scalar_type = typename Traits::scalar_type;
|
using scalar_type = typename Traits::scalar_type;
|
||||||
for_all( ET, [&](scalar_type &c, typename ETensor::Index n, const std::array<size_t, ETensor::NumIndices + Traits::rank_non_trivial> &Dims ) {
|
for_all( ET, [&](scalar_type &c, typename ETensor::Index n, const std::array<size_t, ETensor::NumIndices + Traits::rank> &Dims ) {
|
||||||
c = Inc * static_cast<scalar_type>(n);
|
scalar_type x = Inc * static_cast<scalar_type>(n);
|
||||||
|
if( Precision ) {
|
||||||
|
std::stringstream s;
|
||||||
|
s << std::scientific << std::setprecision(Precision) << x;
|
||||||
|
s >> x;
|
||||||
|
}
|
||||||
|
c = x;
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ETensor>
|
template <typename ETensor>
|
||||||
typename std::enable_if<EigenIO::is_tensor<ETensor>::value && EigenIO::is_complex<typename EigenIO::Traits<typename ETensor::Scalar>::scalar_type>::value, void>::type
|
typename std::enable_if<EigenIO::is_tensor<ETensor>::value && EigenIO::is_complex<typename EigenIO::Traits<typename ETensor::Scalar>::scalar_type>::value, void>::type
|
||||||
SequentialInit( ETensor &ET, typename EigenIO::Traits<typename ETensor::Scalar>::scalar_type Inc={1,-1})
|
SequentialInit( ETensor &ET, typename EigenIO::Traits<typename ETensor::Scalar>::scalar_type Inc={1,-1},
|
||||||
|
unsigned short Precision = 0 )
|
||||||
{
|
{
|
||||||
using Traits = EigenIO::Traits<typename ETensor::Scalar>;
|
using Traits = EigenIO::Traits<typename ETensor::Scalar>;
|
||||||
using scalar_type = typename Traits::scalar_type;
|
using scalar_type = typename Traits::scalar_type;
|
||||||
for_all( ET, [&](scalar_type &c, typename ETensor::Index n, const std::array<size_t, ETensor::NumIndices + Traits::rank> &Dims ) {
|
for_all( ET, [&](scalar_type &c, typename ETensor::Index n, const std::array<size_t, ETensor::NumIndices + Traits::rank> &Dims ) {
|
||||||
c = Inc * static_cast<typename RealType<scalar_type>::type>(n);
|
auto re = Inc.real();
|
||||||
|
auto im = Inc.imag();
|
||||||
|
re *= n;
|
||||||
|
im *= n;
|
||||||
|
if( Precision ) {
|
||||||
|
std::stringstream s;
|
||||||
|
s << std::scientific << std::setprecision(Precision) << re;
|
||||||
|
s >> re;
|
||||||
|
s.clear();
|
||||||
|
s << im;
|
||||||
|
s >> im;
|
||||||
|
}
|
||||||
|
c = scalar_type(re,im);
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,7 +576,7 @@ namespace Grid {
|
|||||||
Writer<T>::write(const std::string &s, const ETensor &output)
|
Writer<T>::write(const std::string &s, const ETensor &output)
|
||||||
{
|
{
|
||||||
using Index = typename ETensor::Index;
|
using Index = typename ETensor::Index;
|
||||||
using Container = typename ETensor::Scalar; // NB: could be same as Scalar
|
using Container = typename ETensor::Scalar; // NB: could be same as scalar
|
||||||
using Traits = EigenIO::Traits<Container>;
|
using Traits = EigenIO::Traits<Container>;
|
||||||
using Scalar = typename Traits::scalar_type; // type of the underlying scalar
|
using Scalar = typename Traits::scalar_type; // type of the underlying scalar
|
||||||
constexpr unsigned int TensorRank{ETensor::NumIndices};
|
constexpr unsigned int TensorRank{ETensor::NumIndices};
|
||||||
@ -711,85 +726,49 @@ namespace Grid {
|
|||||||
typename std::enable_if<EigenIO::is_tensor<ETensor>::value, void>::type
|
typename std::enable_if<EigenIO::is_tensor<ETensor>::value, void>::type
|
||||||
Reader<T>::read(const std::string &s, ETensor &output)
|
Reader<T>::read(const std::string &s, ETensor &output)
|
||||||
{
|
{
|
||||||
// alias to element type
|
using Index = typename ETensor::Index;
|
||||||
using Container = typename ETensor::Scalar;
|
using Container = typename ETensor::Scalar; // NB: could be same as scalar
|
||||||
using Traits = EigenIO::Traits<Container>;
|
using Traits = EigenIO::Traits<Container>;
|
||||||
using Scalar = typename Traits::scalar_type;
|
using Scalar = typename Traits::scalar_type; // type of the underlying scalar
|
||||||
|
constexpr unsigned int TensorRank{ETensor::NumIndices};
|
||||||
|
constexpr unsigned int ContainerRank{Traits::rank}; // Only non-zero for containers
|
||||||
|
constexpr unsigned int TotalRank{TensorRank + ContainerRank};
|
||||||
|
using ETDims = std::array<Index, TensorRank>; // Dimensions of the tensor
|
||||||
|
|
||||||
// read the (flat) data and dimensionality
|
// read the (flat) data and dimensionality
|
||||||
std::vector<std::size_t> dimData;
|
std::vector<std::size_t> dimData;
|
||||||
std::vector<Scalar> buf;
|
std::vector<Scalar> buf;
|
||||||
upcast->readMultiDim( s, buf, dimData );
|
upcast->readMultiDim( s, buf, dimData );
|
||||||
|
assert(dimData.size() == TotalRank && "EigenIO: Tensor rank mismatch" );
|
||||||
// Make sure that the number of elements read matches dimensions read
|
// Make sure that the number of elements read matches dimensions read
|
||||||
std::size_t NumElements = 1;
|
std::size_t NumElements = 1;
|
||||||
std::size_t RankRequired = 0;
|
for( auto d : dimData )
|
||||||
std::vector<typename ETensor::Index> dimNonTrivial;
|
|
||||||
dimNonTrivial.reserve(dimData.size());
|
|
||||||
for( auto d : dimData ) {
|
|
||||||
NumElements *= d;
|
NumElements *= d;
|
||||||
if( d > 1 ) {
|
assert( NumElements == buf.size() && "EigenIO: Number of elements != product of dimensions" );
|
||||||
RankRequired++;
|
|
||||||
dimNonTrivial.push_back(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert( NumElements == buf.size() && "Number of elements read back <> product of dimensions" );
|
|
||||||
// If our scalar object is a Container, make sure it's dimensions match what we read back
|
// If our scalar object is a Container, make sure it's dimensions match what we read back
|
||||||
const auto InnerRank{Traits::rank_non_trivial};
|
for( auto i = 0 ; i < ContainerRank ; i++ )
|
||||||
if ( InnerRank > 0 ) {
|
assert( dimData[TensorRank+i] == Traits::Dimension(i) && "Tensor Container dimensions don't match data" );
|
||||||
assert( RankRequired >= InnerRank && "Tensor Container too complex for data" );
|
// Now see whether the tensor is the right shape, or can be made to be
|
||||||
for( auto i = InnerRank - 1 ; i != -1 ; i-- ) {
|
|
||||||
auto d = dimNonTrivial[--RankRequired];
|
|
||||||
assert( d == Traits::DimensionNT(i) && "Tensor Container dimensions don't match data" );
|
|
||||||
NumElements /= d;
|
|
||||||
dimNonTrivial.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Make sure our object has the right rank
|
|
||||||
assert( ETensor::NumDimensions >= RankRequired );
|
|
||||||
bool bShapeOK = true;
|
|
||||||
std::size_t RankNonTrivial = 0;
|
|
||||||
const auto & dims{output.dimensions()};
|
const auto & dims{output.dimensions()};
|
||||||
using ETDims = std::array<typename ETensor::Index, ETensor::NumDimensions>;
|
bool bShapeOK = (output.data() != nullptr);
|
||||||
ETDims dimsNew;
|
for( auto i = 0; bShapeOK && i < TensorRank ; i++ )
|
||||||
// Make sure fixed dimension objects have allocated memory
|
if( dims[i] != dimData[i] )
|
||||||
/*if constexpr( EigenIO::is_tensor_fixed<ETensor>::value ) {
|
|
||||||
for( auto &d : dimsNew ) d = 0;
|
|
||||||
output( dimsNew ) = 0;
|
|
||||||
}*/
|
|
||||||
for( auto i = 0, j = 0 ; bShapeOK && i < ETensor::NumDimensions ; i++ ) {
|
|
||||||
auto d = dims[i];
|
|
||||||
if( d < 1 )
|
|
||||||
bShapeOK = false;
|
bShapeOK = false;
|
||||||
else if( d > 1 ) {
|
|
||||||
RankNonTrivial++;
|
|
||||||
if( d != dimNonTrivial[j] )
|
|
||||||
bShapeOK = false;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
dimsNew[i] = d;
|
|
||||||
}
|
|
||||||
//if( RankNonTrivial == 0 ) RankNonTrivial++;
|
|
||||||
// Make the tensor the same size as the data read
|
// Make the tensor the same size as the data read
|
||||||
if ( !bShapeOK || RankNonTrivial != RankRequired ) {
|
ETDims MyIndex;
|
||||||
for( auto i = 0 ; i < ETensor::NumDimensions ; i++ )
|
if( !bShapeOK ) {
|
||||||
dimsNew[i] = ( i < RankRequired ) ? dimNonTrivial[i] : 1;
|
for( auto i = 0 ; i < TensorRank ; i++ )
|
||||||
Reshape(output, dimsNew);
|
MyIndex[i] = dimData[i];
|
||||||
|
Reshape(output, MyIndex);
|
||||||
}
|
}
|
||||||
// Copy the data into the tensor
|
// Copy the data into the tensor
|
||||||
ETDims MyIndex;
|
|
||||||
for( auto &d : MyIndex ) d = 0;
|
for( auto &d : MyIndex ) d = 0;
|
||||||
const Scalar * pSource = &buf[0];
|
const Scalar * pSource = &buf[0];
|
||||||
for( auto n = 0 ; n < NumElements ; n++ ) {
|
for( auto n = 0 ; n < NumElements ; n++ ) {
|
||||||
Container & c = output( MyIndex );
|
Container & c = output( MyIndex );
|
||||||
/*if constexpr ( EigenIO::is_scalar<Container>::value ) {
|
|
||||||
c = buf[idx++];
|
|
||||||
} else {
|
|
||||||
for( Scalar & s : c )
|
|
||||||
s = buf[idx++];
|
|
||||||
}*/
|
|
||||||
copyScalars( c, pSource );
|
copyScalars( c, pSource );
|
||||||
// Now increment the index
|
// Now increment the index
|
||||||
for( int i = ETensor::NumDimensions - 1; i >= 0 && ++MyIndex[i] == dims[i]; i-- )
|
for( int i = TensorRank - 1; i != -1 && ++MyIndex[i] == dims[i]; i-- )
|
||||||
MyIndex[i] = 0;
|
MyIndex[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -811,22 +790,6 @@ namespace Grid {
|
|||||||
t.resize( dims );
|
t.resize( dims );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*template <typename T>
|
|
||||||
template <typename ETensor>
|
|
||||||
typename std::enable_if<EigenIO::is_tensor_fixed<ETensor>::value, std::size_t>::type
|
|
||||||
Reader<T>::DimSize(ETensor &t, std::size_t dim )
|
|
||||||
{
|
|
||||||
return 0;//ETensor::Dimension[dim];
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
template <typename ETensor>
|
|
||||||
typename std::enable_if<EigenIO::is_tensor_variable<ETensor>::value, std::size_t>::type
|
|
||||||
Reader<T>::DimSize(ETensor &t, std::size_t dim )
|
|
||||||
{
|
|
||||||
return t.dimension(dim);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
template <typename U>
|
template <typename U>
|
||||||
void Reader<T>::fromString(U &output, const std::string &s)
|
void Reader<T>::fromString(U &output, const std::string &s)
|
||||||
@ -880,21 +843,24 @@ namespace Grid {
|
|||||||
for( auto i = 0 ; bReturnValue && i < T1::NumIndices ; i++ )
|
for( auto i = 0 ; bReturnValue && i < T1::NumIndices ; i++ )
|
||||||
bReturnValue = ( lhs.dimension(i)) == rhs.dimension(i);
|
bReturnValue = ( lhs.dimension(i)) == rhs.dimension(i);
|
||||||
if( bReturnValue ) {
|
if( bReturnValue ) {
|
||||||
Eigen::Tensor<bool, 0, T1::Options> bResult = (lhs == rhs).all();
|
using Traits = EigenIO::Traits<typename T1::Scalar>;
|
||||||
bReturnValue = bResult(0);
|
using scalar_type = typename Traits::scalar_type;
|
||||||
|
for_all( lhs, [&](scalar_type &c, typename T1::Index n, const std::array<size_t, T1::NumIndices + Traits::rank> &Dims ) {
|
||||||
|
scalar_type x = c - rhs[Dims];
|
||||||
|
if( x < 1e-10 )
|
||||||
|
bReturnValue = false;
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
return bReturnValue;
|
return bReturnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline typename std::enable_if<std::is_base_of<Eigen::TensorBase<T, Eigen::ReadOnlyAccessors>, T>::value, bool>::type
|
static inline typename std::enable_if<EigenIO::is_tensor<T>::value, bool>::type
|
||||||
CompareMember(const std::vector<T> &lhs, const std::vector<T> &rhs) {
|
CompareMember(const std::vector<T> &lhs, const std::vector<T> &rhs) {
|
||||||
const auto NumElements{lhs.size()};
|
const auto NumElements{lhs.size()};
|
||||||
bool bResult = ( NumElements == rhs.size() );
|
bool bResult = ( NumElements == rhs.size() );
|
||||||
for( auto i = 0 ; i < NumElements && bResult ; i++ ) {
|
for( auto i = 0 ; i < NumElements && bResult ; i++ )
|
||||||
Eigen::Tensor<bool, 0, T::Options> b = (lhs[i] == rhs[i]).all();
|
bResult = CompareMember(lhs[i], rhs[i]);
|
||||||
bResult = b(0);
|
|
||||||
}
|
|
||||||
return bResult;
|
return bResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,9 +143,9 @@ namespace Grid
|
|||||||
d /= Primes[PrimeIdx];
|
d /= Primes[PrimeIdx];
|
||||||
}
|
}
|
||||||
const char ErrorMsg[] = " dimension > 4GB without small prime factors. "
|
const char ErrorMsg[] = " dimension > 4GB without small prime factors. "
|
||||||
"Hdf5IO chunk size will be inefficient.";
|
"Hdf5IO chunk size will be inefficient. NB Serialisation is not intended for large datasets - please consider alternatives.";
|
||||||
if( d > MaxElements ) {
|
if( d > MaxElements ) {
|
||||||
std::cout << GridLogMessage << "Individual" << ErrorMsg << std::endl;
|
std::cout << GridLogWarning << "Individual" << ErrorMsg << std::endl;
|
||||||
hsize_t quotient = d / MaxElements;
|
hsize_t quotient = d / MaxElements;
|
||||||
if( d % MaxElements )
|
if( d % MaxElements )
|
||||||
quotient++;
|
quotient++;
|
||||||
|
@ -80,17 +80,19 @@ double d = 2*M_PI;
|
|||||||
bool b = false;
|
bool b = false;
|
||||||
|
|
||||||
template <typename W, typename R, typename O>
|
template <typename W, typename R, typename O>
|
||||||
void ioTest(const std::string &filename, const O &object, const std::string &name, const char * tag = "testobject" )
|
void ioTest(const std::string &filename, const O &object, const std::string &name,
|
||||||
|
const char * tag = "testobject", unsigned short Precision = 0 )
|
||||||
{
|
{
|
||||||
std::cout << "IO test: " << name << " -> " << filename << " ...";
|
std::cout << "IO test: " << name << " -> " << filename << " ...";
|
||||||
// writer needs to be destroyed so that writing physically happens
|
// writer needs to be destroyed so that writing physically happens
|
||||||
{
|
{
|
||||||
W writer(filename);
|
W writer(filename);
|
||||||
writer.setPrecision(std::numeric_limits<double>::digits10 + 1);
|
if( Precision )
|
||||||
|
writer.setPrecision(Precision);
|
||||||
write(writer, tag , object);
|
write(writer, tag , object);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << " done. reading...";
|
std::cout << " done. reading ...";
|
||||||
R reader(filename);
|
R reader(filename);
|
||||||
std::unique_ptr<O> buf( new O ); // In case object too big for stack
|
std::unique_ptr<O> buf( new O ); // In case object too big for stack
|
||||||
|
|
||||||
@ -99,7 +101,7 @@ void ioTest(const std::string &filename, const O &object, const std::string &nam
|
|||||||
if (!good) {
|
if (!good) {
|
||||||
std::cout << " failure!" << std::endl;
|
std::cout << " failure!" << std::endl;
|
||||||
if (EigenIO::is_tensor<O>::value)
|
if (EigenIO::is_tensor<O>::value)
|
||||||
dump_tensor(*buf,"???");
|
dump_tensor(*buf);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
std::cout << " done." << std::endl;
|
std::cout << " done." << std::endl;
|
||||||
@ -108,16 +110,17 @@ void ioTest(const std::string &filename, const O &object, const std::string &nam
|
|||||||
#ifdef HAVE_HDF5
|
#ifdef HAVE_HDF5
|
||||||
typedef std::complex<double> TestScalar;
|
typedef std::complex<double> TestScalar;
|
||||||
typedef Eigen::TensorFixedSize<unsigned short, Eigen::Sizes<5,4,3,2,1>> TensorRank5UShort;
|
typedef Eigen::TensorFixedSize<unsigned short, Eigen::Sizes<5,4,3,2,1>> TensorRank5UShort;
|
||||||
typedef Eigen::TensorFixedSize<unsigned short, Eigen::Sizes<5,4,3,2>, Eigen::StorageOptions::RowMajor> TensorRank5UShortAlt;
|
typedef Eigen::TensorFixedSize<unsigned short, Eigen::Sizes<5,4,3,2,1>, Eigen::StorageOptions::RowMajor> TensorRank5UShortAlt;
|
||||||
typedef Eigen::Tensor<TestScalar, 3, Eigen::StorageOptions::RowMajor> TensorRank3;
|
typedef Eigen::Tensor<TestScalar, 3, Eigen::StorageOptions::RowMajor> TensorRank3;
|
||||||
typedef Eigen::TensorFixedSize<TestScalar, Eigen::Sizes<9,4,2>, Eigen::StorageOptions::RowMajor> Tensor_9_4_2;
|
typedef Eigen::TensorFixedSize<TestScalar, Eigen::Sizes<9,4,2>, Eigen::StorageOptions::RowMajor> Tensor_9_4_2;
|
||||||
typedef std::vector<Tensor_9_4_2> aTensor_9_4_2;
|
typedef std::vector<Tensor_9_4_2> aTensor_9_4_2;
|
||||||
typedef Eigen::TensorFixedSize<SpinColourVector, Eigen::Sizes<6,5>> LSCTensor;
|
typedef Eigen::TensorFixedSize<SpinColourVector, Eigen::Sizes<6,5>> LSCTensor;
|
||||||
#ifndef DEBUG
|
#ifndef NO_STRESS_TESTS
|
||||||
typedef Eigen::TensorFixedSize<iMatrix<iVector<iMatrix<iVector<LorentzColourMatrix,5>,2>,7>,3>, Eigen::Sizes<2,4,11,10,9>, Eigen::StorageOptions::RowMajor> LCMTensor;
|
typedef Eigen::TensorFixedSize<iMatrix<iVector<iMatrix<iVector<LorentzColourMatrix,5>,2>,7>,3>, Eigen::Sizes<2,4,11,10,9>, Eigen::StorageOptions::RowMajor> LCMTensor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class PerambIOTestClass: Serializable {
|
class PerambIOTestClass: Serializable {
|
||||||
|
Grid_complex<double> Flag;
|
||||||
public:
|
public:
|
||||||
using PerambTensor = Eigen::Tensor<SpinColourVector, 6, Eigen::StorageOptions::RowMajor>;
|
using PerambTensor = Eigen::Tensor<SpinColourVector, 6, Eigen::StorageOptions::RowMajor>;
|
||||||
GRID_SERIALIZABLE_CLASS_MEMBERS(PerambIOTestClass
|
GRID_SERIALIZABLE_CLASS_MEMBERS(PerambIOTestClass
|
||||||
@ -134,45 +137,52 @@ public:
|
|||||||
, LSCTensor, MyLSCTensor
|
, LSCTensor, MyLSCTensor
|
||||||
);
|
);
|
||||||
PerambIOTestClass()
|
PerambIOTestClass()
|
||||||
: DistilParameterNames {"alpha", "beta", "gamma", "delta", "epsilon", "zeta"}
|
: DistilParameterNames {"do", "androids", "dream", "of", "electric", "sheep?"}
|
||||||
, DistilParameterValues{2,3,1,4,5,1}
|
, DistilParameterValues{2,3,1,4,5,1}
|
||||||
, Perambulator(2,3,1,4,5,1)
|
, Perambulator(2,3,1,4,5,1)
|
||||||
, Perambulator2(7,1,6,1,5,1)
|
, Perambulator2(7,1,6,1,5,1)
|
||||||
, tensorRank3(7,3,2)
|
, tensorRank3(7,3,2)
|
||||||
, atensor_9_4_2(3)
|
, atensor_9_4_2(3)
|
||||||
|
//, Flag(1,-3.1415927)
|
||||||
|
, Flag(1,-1)
|
||||||
{
|
{
|
||||||
//Grid_complex<double> Flag{1,-3.1415927}; // Gives errors on readback for text types
|
|
||||||
Grid_complex<double> Flag{1,-1};
|
|
||||||
SequentialInit(Perambulator, Flag);
|
SequentialInit(Perambulator, Flag);
|
||||||
SequentialInit(Perambulator2, Flag);
|
SequentialInit(Perambulator2, Flag);
|
||||||
SequentialInit(tensorRank5UShort);
|
SequentialInit(tensorRank5UShort);
|
||||||
SequentialInit(tensorRank3, Flag);
|
SequentialInit(tensorRank3, Flag);
|
||||||
SequentialInit(tensor_9_4_2, Flag);
|
SequentialInit(tensor_9_4_2, Flag);
|
||||||
for( auto &t : atensor_9_4_2 ) SequentialInit(t, Flag);
|
for( auto &t : atensor_9_4_2 ) SequentialInit(t, Flag);
|
||||||
SequentialInit( MyLSCTensor );
|
SequentialInit( MyLSCTensor, Flag );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TensorWriteReadInnerNoInit( T ) \
|
#define TensorWriteReadInnerNoInit( T ) \
|
||||||
filename = "iotest_" + std::to_string(++TestNum) + "_" #T + pszExtension; \
|
filename = "iotest_" + std::to_string(++TestNum) + "_" #T + pszExtension; \
|
||||||
ioTest<WTR_, RDR_, T>(filename, t, #T, #T);
|
ioTest<WTR_, RDR_, T>(filename, t, #T, #T);
|
||||||
#define TensorWriteReadInner( T ) SequentialInit( t ); TensorWriteReadInnerNoInit( T )
|
#define TensorWriteReadInner( T ) SequentialInit( t, Flag, Precision ); TensorWriteReadInnerNoInit( T )
|
||||||
#define TensorWriteRead( T ) { T t ; TensorWriteReadInner( T ) }
|
#define TensorWriteRead( T ) { T t ; TensorWriteReadInner( T ) }
|
||||||
#define TensorWriteReadV(T, ... ) { T t( __VA_ARGS__ ); TensorWriteReadInner( T ) }
|
#define TensorWriteReadV(T, ... ) { T t( __VA_ARGS__ ); TensorWriteReadInner( T ) }
|
||||||
#define TensorWriteReadLarge( T ) { std::unique_ptr<T> p{new T}; T &t{*p}; TensorWriteReadInnerNoInit(T) }
|
#define TensorWriteReadLarge( T ) { std::unique_ptr<T> p{new T}; T &t{*p}; TensorWriteReadInnerNoInit(T) }
|
||||||
|
|
||||||
template <typename WTR_, typename RDR_>
|
template <typename WTR_, typename RDR_>
|
||||||
void EigenHdf5IOTest(const char * pszExtension)
|
void EigenHdf5IOTest(const char * pszExtension, unsigned short Precision = 0)
|
||||||
{
|
{
|
||||||
unsigned int TestNum = 0;
|
unsigned int TestNum = 0;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
using TensorSingle = Eigen::TensorFixedSize<int, Eigen::Sizes<1>>;
|
{
|
||||||
TensorWriteRead( TensorSingle )
|
int Flag = 7;
|
||||||
|
unsigned short Precision = 0;
|
||||||
|
using TensorSingle = Eigen::TensorFixedSize<int, Eigen::Sizes<1>>;
|
||||||
|
TensorWriteRead( TensorSingle )
|
||||||
|
}
|
||||||
|
TestScalar Flag{1,-3.1415927};
|
||||||
using TensorSimple = Eigen::Tensor<iMatrix<TestScalar,1>, 6>;
|
using TensorSimple = Eigen::Tensor<iMatrix<TestScalar,1>, 6>;
|
||||||
TensorWriteReadV( TensorSimple, 1, 1, 1, 1, 1, 1 )
|
TensorWriteReadV( TensorSimple, 1, 1, 1, 1, 1, 1 )
|
||||||
TensorWriteReadV( TensorRank3, 6, 3, 2 )
|
TensorWriteReadV( TensorRank3, 6, 3, 2 )
|
||||||
TensorWriteRead ( Tensor_9_4_2 )
|
TensorWriteRead ( Tensor_9_4_2 )
|
||||||
{
|
{
|
||||||
|
unsigned short Flag = 1;
|
||||||
|
unsigned short Precision = 0;
|
||||||
TensorRank5UShort t;
|
TensorRank5UShort t;
|
||||||
TensorWriteReadInner ( TensorRank5UShort );
|
TensorWriteReadInner ( TensorRank5UShort );
|
||||||
std::cout << " Testing alternate memory order read ... ";
|
std::cout << " Testing alternate memory order read ... ";
|
||||||
@ -193,7 +203,7 @@ void EigenHdf5IOTest(const char * pszExtension)
|
|||||||
}
|
}
|
||||||
TensorWriteRead ( LSCTensor )
|
TensorWriteRead ( LSCTensor )
|
||||||
TensorWriteReadLarge( PerambIOTestClass )
|
TensorWriteReadLarge( PerambIOTestClass )
|
||||||
#ifndef DEBUG
|
#ifndef NO_STRESS_TESTS
|
||||||
std::cout << "sizeof( LCMTensor ) = " << sizeof( LCMTensor ) / 1024 / 1024 << " MB" << std::endl;
|
std::cout << "sizeof( LCMTensor ) = " << sizeof( LCMTensor ) / 1024 / 1024 << " MB" << std::endl;
|
||||||
TensorWriteReadLarge ( LCMTensor )
|
TensorWriteReadLarge ( LCMTensor )
|
||||||
// Also write > 4GB of complex numbers (I suspect this will fail inside Hdf5)
|
// Also write > 4GB of complex numbers (I suspect this will fail inside Hdf5)
|
||||||
@ -285,22 +295,24 @@ int main(int argc,char **argv)
|
|||||||
ioTest<TextWriter, TextReader>("iotest.dat", obj, "text (object) ");
|
ioTest<TextWriter, TextReader>("iotest.dat", obj, "text (object) ");
|
||||||
ioTest<TextWriter, TextReader>("iotest.dat", vec, "text (vector of objects)");
|
ioTest<TextWriter, TextReader>("iotest.dat", vec, "text (vector of objects)");
|
||||||
//// text
|
//// text
|
||||||
ioTest<JSONWriter, JSONReader>("iotest.json", obj, "JSON (object) ");
|
//ioTest<JSONWriter, JSONReader>("iotest.json", obj, "JSON (object) ");
|
||||||
ioTest<JSONWriter, JSONReader>("iotest.json", vec, "JSON (vector of objects)");
|
//ioTest<JSONWriter, JSONReader>("iotest.json", vec, "JSON (vector of objects)");
|
||||||
|
|
||||||
//// HDF5
|
//// HDF5
|
||||||
#ifdef HAVE_HDF5
|
#ifdef HAVE_HDF5
|
||||||
ioTest<Hdf5Writer, Hdf5Reader>("iotest.h5", obj, "HDF5 (object) ");
|
ioTest<Hdf5Writer, Hdf5Reader>("iotest.h5", obj, "HDF5 (object) ");
|
||||||
ioTest<Hdf5Writer, Hdf5Reader>("iotest.h5", vec, "HDF5 (vector of objects)");
|
ioTest<Hdf5Writer, Hdf5Reader>("iotest.h5", vec, "HDF5 (vector of objects)");
|
||||||
|
#endif
|
||||||
|
std::cout << "\n==== detailed text tensor tests (Grid::EigenIO)" << std::endl;
|
||||||
|
EigenHdf5IOTest<TextWriter, TextReader>(".dat", 6);
|
||||||
|
std::cout << "\n==== detailed xml tensor tests (Grid::EigenIO)" << std::endl;
|
||||||
|
EigenHdf5IOTest<XmlWriter, XmlReader>(".xml", 4);
|
||||||
|
std::cout << "\n==== detailed binary tensor tests (Grid::EigenIO)" << std::endl;
|
||||||
|
EigenHdf5IOTest<BinaryWriter, BinaryReader>(".bin");
|
||||||
|
#ifdef HAVE_HDF5
|
||||||
std::cout << "\n==== detailed Hdf5 tensor tests (Grid::EigenIO)" << std::endl;
|
std::cout << "\n==== detailed Hdf5 tensor tests (Grid::EigenIO)" << std::endl;
|
||||||
EigenHdf5IOTest<Hdf5Writer, Hdf5Reader>(".h5");
|
EigenHdf5IOTest<Hdf5Writer, Hdf5Reader>(".h5");
|
||||||
#endif
|
#endif
|
||||||
std::cout << "\n==== detailed binary tensor tests (Grid::EigenIO)" << std::endl;
|
|
||||||
EigenHdf5IOTest<BinaryWriter, BinaryReader>(".bin");
|
|
||||||
std::cout << "\n==== detailed text tensor tests (Grid::EigenIO)" << std::endl;
|
|
||||||
EigenHdf5IOTest<TextWriter, TextReader>(".dat");
|
|
||||||
std::cout << "\n==== detailed xml tensor tests (Grid::EigenIO)" << std::endl;
|
|
||||||
EigenHdf5IOTest<XmlWriter, XmlReader>(".xml");
|
|
||||||
|
|
||||||
std::cout << "\n==== vector flattening/reconstruction" << std::endl;
|
std::cout << "\n==== vector flattening/reconstruction" << std::endl;
|
||||||
typedef std::vector<std::vector<std::vector<double>>> vec3d;
|
typedef std::vector<std::vector<std::vector<double>>> vec3d;
|
||||||
|
Loading…
Reference in New Issue
Block a user