3
0
mirror of https://github.com/triqs/dft_tools synced 2024-11-01 19:53:45 +01:00
dft_tools/triqs/arrays/h5/array_stack.hpp
Olivier Parcollet f2c7d449cc First commit : triqs libs version 1.0 alpha1
for earlier commits, see TRIQS0.x repository.
2013-07-17 19:24:07 +02:00

158 lines
7.3 KiB
C++

/*******************************************************************************
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
*
* Copyright (C) 2011 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 <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#ifndef TRIQS_ARRAYS_H5_STACK_H
#define TRIQS_ARRAYS_H5_STACK_H
#include "../array.hpp"
#include <triqs/h5.hpp>
#include "./simple_read_write.hpp"
namespace triqs { namespace arrays {
namespace h5_stack_details { // to be replaced by ellipsis
template<class T, size_t N, ull_t Opt> array_view<T,N-1,Opt> slice0( array<T,N,Opt> & A, size_t ind);
#define AUX(z,p,unused) BOOST_PP_COMMA_IF(p) range()
#define IMPL(z, NN, unused) \
template<class T, ull_t Opt> array_view<T,BOOST_PP_INC(NN),Opt> slice0( array<T,BOOST_PP_INC(NN)+1,Opt> & A, size_t ind) {\
return A(ind,BOOST_PP_REPEAT(BOOST_PP_INC(NN),AUX,nil));}
BOOST_PP_REPEAT(ARRAY_NRANK_MAX , IMPL, nil);
#undef IMPL
#undef AUX
template<class T, ull_t Opt> T & slice0( array<T,1,Opt> & A, size_t ind) { return A(ind);}
template<typename B, typename Enable = void> struct get_value_type { typedef B type; static const size_t rank = 0;};
template<typename B> struct get_value_type<B, typename boost::enable_if<is_amv_value_class<B> >::type > {
typedef typename B::value_type type;static const size_t rank = B::rank;};
}
/**
* \brief Hdf5 array stack
* \tparam BaseElementType The type of the base element of the stack. Can be an array/matrix/vector or a scalar.
* If it in a scalar, the array_stack will write an hdf5 array of dimension 1
* If it in an array/matrix/vector, the array_stack will write an hdf5 array of dimension BaseElementType::rank +1
*
*/
template< typename BaseElementType>
class array_stack {
typedef BaseElementType base_element_type;
static_assert( (is_amv_value_class<BaseElementType>::value || is_scalar<BaseElementType>::value), "BaseElementType must be an array/matrix/vector or a simple number");
typedef typename h5_stack_details::get_value_type<BaseElementType>::type T;
static const size_t dim = h5_stack_details::get_value_type<BaseElementType>::rank;
static const bool base_is_array = dim >0;
size_t bufsize_, step, _size;
static const bool T_is_complex = boost::is_complex<T>::value;
static const unsigned int RANK = dim + 1 + (T_is_complex ? 1 : 0);
utility::mini_vector<hsize_t,RANK> dims, offset, maxdims, dim_chunk, buffer_dim, zero;
H5::DataSet dataset;
array<T,dim+1> buffer;
template <typename FileGroupType >
void construct_delegate ( FileGroupType g, std::string const & name, mini_vector<size_t,dim> const & a_dims, size_t bufsize) {
mini_vector<hsize_t,RANK> dim_chunk;
bufsize_ = bufsize; step = 0; _size =0;
for (size_t i =1; i<=dim; ++i) { dims[i] = a_dims[i-1];}
if (T_is_complex) { dims[RANK-1] =2; }
maxdims = dims; buffer_dim = dims; dim_chunk = dims;
dims[0] = 0; maxdims[0] = H5S_UNLIMITED; dim_chunk[0]=1; buffer_dim[0] = bufsize_;
mini_vector<size_t,dim+1> s; for (size_t i =0; i<=dim; ++i) {s[i] = buffer_dim[i];}
buffer.resize(s);
H5::DataSpace mspace1( RANK, dims.ptr(), maxdims.ptr());
H5::DSetCreatPropList cparms; cparms.setChunk( RANK, dim_chunk.ptr() ); // Modify dataset creation properties, i.e. enable chunking.
try {
dataset = g.create_dataset(name,h5::native_type_from_C(typename h5::remove_complex<T>::type()), mspace1, cparms );
if (boost::is_complex<T>::value) h5::write_string_attribute(&dataset,"__complex__","1");
}
TRIQS_ARRAYS_H5_CATCH_EXCEPTION;
}
public :
/**
* \brief Constructor
* \param g The h5 file or group, of type FileGroupType
* \param name The name of the hdf5 array in the file/group where the stack will be stored
* \param base_element_shape The shape of the base array/matrix/vector [or mini_vector<size_t,0>() for a scalar]
* \param bufsize The size of the bufferThe name of the hdf5 array in the file/group where the stack will be stored
* \exception The HDF5 exceptions will be caught and rethrown as TRIQS_RUNTIME_ERROR (with stackstrace, cf doc).
*/
template <typename FileGroupType >
array_stack( FileGroupType g, std::string const & name, mini_vector<size_t,dim> const & base_element_shape, size_t bufsize) {
construct_delegate ( g, name, base_element_shape, bufsize);
}
/**
* \brief Constructor : valid only if the base is a scalar
* \param g The h5 file or group, of type FileGroupType
* \param name The name of the hdf5 array in the file/group where the stack will be stored
* \param bufsize The size of the bufferThe name of the hdf5 array in the file/group where the stack will be stored
* \exception The HDF5 exceptions will be caught and rethrown as TRIQS_RUNTIME_ERROR (with stackstrace, cf doc).
*/
template <typename FileGroupType >
array_stack( FileGroupType g, std::string const & name, size_t bufsize) {
static_assert( (is_scalar<BaseElementType>::value), "This constructor is only available for a scalar BaseElementType");
construct_delegate ( g, name,mini_vector<size_t,0>() , bufsize);
}
///
~array_stack() {flush();}
/// The type of the base of the stack (a view or a reference)
typedef typename boost::mpl::if_c< base_is_array , array_view<T,dim>, T &>::type slice_type;
/**
* \return A view (for an array/matrix/vector base) or a reference (for a scalar base) to the top of the stack
* i.e. the next element to be assigned to
*/
slice_type operator() () { return h5_stack_details::slice0(buffer, step); }
/// Advance the stack by one
void operator++() { ++step; ++_size; if (step==bufsize_) flush(); }
/// Flush the buffer to the disk. Automatically called at destruction.
void flush() { save_buffer(); step=0;}
/**
* \brief Add a element onto the stack and advance it by one.
* S << A is equivalent to S() = A; ++S;
*/
template<class AType> void operator << ( AType const & A) { (*this)() = A; ++(*this);}
/// Current size of the stack
size_t size() const { return _size;}
private:
void save_buffer () {
if (step==0) return;
dims[0] += step;
buffer_dim[0] = step;
dataset.extend(dims.ptr());
H5::DataSpace fspace1 = dataset.getSpace (), mspace = h5_impl::data_space(buffer);
fspace1.selectHyperslab( H5S_SELECT_SET, buffer_dim.ptr(), offset.ptr() );
mspace.selectHyperslab( H5S_SELECT_SET, buffer_dim.ptr(), zero.ptr() );
try { dataset.write( h5_impl::get_array_data_ptr(buffer), h5::data_type_memory<T>(), mspace, fspace1 ); }
TRIQS_ARRAYS_H5_CATCH_EXCEPTION;
offset [0] += step;
}
};
}} // namespace
#endif