/*******************************************************************************
*
* 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_STACK_H
#define TRIQS_ARRAYS_H5_STACK_H
#include "../array.hpp"
#include
#include "./simple_read_write.hpp"
#include
namespace triqs {
namespace arrays {
// to be cleaned
namespace h5_impl {
template void* __get_array_data_ptr(A& x) { return h5::get_data_ptr(&(x.storage()[0])); }
h5::dataspace data_space_impl(array_stride_info info, bool is_complex);
template h5::dataspace data_space(ArrayType const& A) {
if (!A.indexmap().is_contiguous()) TRIQS_RUNTIME_ERROR << " h5 : internal error : array not contiguous";
return data_space_impl(array_stride_info{A}, triqs::is_complex::value);
}
}
/// The implementation class
template class array_stack_impl {
static const size_t dim = R;
static const bool base_is_array = dim > 0;
size_t bufsize_, step, _size;
static const bool T_is_complex = triqs::is_complex::value;
static const unsigned int RANK = dim + 1 + (T_is_complex ? 1 : 0);
utility::mini_vector dims, offset, maxdims, dim_chunk, buffer_dim, zero;
h5::dataset d_set;
array buffer;
public:
array_stack_impl(h5::group g, std::string const &name, mini_vector const &base_element_shape, size_t bufsize) {
mini_vector dim_chunk;
bufsize_ = bufsize;
step = 0;
_size = 0;
for (size_t i = 1; i <= dim; ++i) {
dims[i] = base_element_shape[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 s;
for (size_t i = 0; i <= dim; ++i) {
s[i] = buffer_dim[i];
}
buffer.resize(s);
h5::dataspace mspace1 = H5Screate_simple(RANK, dims.ptr(), maxdims.ptr());
h5::proplist cparms = H5Pcreate(H5P_DATASET_CREATE);
auto err = H5Pset_chunk(cparms, RANK, dim_chunk.ptr());
d_set = g.create_dataset(name, h5::native_type_from_C(T()), mspace1, cparms);
if (triqs::is_complex::value) h5::write_string_attribute(d_set, "__complex__", "1");
}
///
~array_stack_impl() { flush(); }
#ifdef TRIQS_DOXYGEN
/// 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
auto operator()() { return buffer(step, ellipsis()); }
/// 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
auto operator()() const { return buffer(step, ellipsis()); }
#else
auto operator()() DECL_AND_RETURN(buffer(step, ellipsis()));
auto operator()() const DECL_AND_RETURN(buffer(step, ellipsis()));
#endif
/// 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 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;
herr_t err= H5Dset_extent(d_set,dims.ptr()); // resize the data_space
h5::dataspace fspace1 = H5Dget_space(d_set);
h5::dataspace mspace = h5_impl::data_space(buffer);
err = H5Sselect_hyperslab(fspace1, H5S_SELECT_SET, offset.ptr(), NULL, buffer_dim.ptr(), NULL);
if (err < 0) TRIQS_RUNTIME_ERROR << "Cannot set hyperslab";
err = H5Sselect_hyperslab(mspace, H5S_SELECT_SET, zero.ptr(), NULL, buffer_dim.ptr(), NULL);
if (err < 0) TRIQS_RUNTIME_ERROR << "Cannot set hyperslab";
err = H5Dwrite(d_set, h5::data_type_memory(), mspace, fspace1, H5P_DEFAULT, h5_impl::__get_array_data_ptr(buffer));
if (err < 0) TRIQS_RUNTIME_ERROR << "Error writing the array_stack buffer";
offset[0] += step;
}
};
// ------------------------- User classes ------------------------------
// The simple case, 1d
template class array_stack : public array_stack_impl {
static_assert((is_scalar::value), "Only available for a scalar type");
public:
/**
* \brief Constructor
* \param g The h5 group
* \param name The name of the hdf5 array in the file/group where the stack will be stored
* \param bufsize The size of the buffer
* \exception The HDF5 exceptions will be caught and rethrown as TRIQS_RUNTIME_ERROR (with stackstrace, cf doc).
*/
array_stack(h5::group g, std::string const &name, size_t bufsize)
: array_stack_impl{g, name, mini_vector{}, bufsize} {}
};
// Specialisation for The simple case, 1d
template class array_stack> : public array_stack_impl {
public:
/**
* \brief Constructor
* \param g The h5 group
* \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 of the stack.
* \param bufsize The size of the buffer
* \exception The HDF5 exceptions will be caught and rethrown as TRIQS_RUNTIME_ERROR (with stackstrace, cf doc).
*/
array_stack(h5::group g, std::string const &name, mini_vector const &base_element_shape, size_t bufsize)
: array_stack_impl{g, name, base_element_shape, bufsize} {}
};
}
} // namespace
#endif