19 inline int checked_mpi_reduce(
const void* sendbuf,
void* recvbuf,
int count,
20 MPI_Datatype datatype, MPI_Op op,
int root, MPI_Comm comm)
23 throw std::invalid_argument(
"MPI_Reduce() is called with invalid count=" 24 + std::to_string(count)
27 if (sendbuf==recvbuf) {
28 throw std::invalid_argument(
"MPI_Reduce() is called with sendbuf==recvbuf" 33 const int rc=MPI_Reduce(const_cast<void*>(sendbuf), recvbuf, count, datatype, op, root, comm);
52 template<
typename T,
typename S> std::size_t copy_to_buffer(T
const & values, std::vector<S> & buffer, std::size_t offset, std::true_type) {
54 std::vector<std::size_t> extent(
get_extent(values));
55 std::size_t
size = std::accumulate(extent.begin(), extent.end(), 1, std::multiplies<std::size_t>());
56 assert(buffer.size()>=offset+size &&
"buffer has sufficient size to accommodate values");
75 template<
typename T,
typename S> std::size_t copy_to_buffer(T
const & values, std::vector<S> & buffer, std::size_t offset, std::false_type) {
77 for(
typename T::const_iterator it = values.begin(); it != values.end(); ++it)
78 offset = copy_to_buffer(*it, buffer, offset,
typename hdf5::is_continuous<typename T::value_type>::type());
103 template<
typename T,
typename S> std::size_t copy_from_buffer(T
const & values, std::vector<S> & buffer, std::size_t offset, std::true_type) {
105 std::vector<std::size_t> extent(
get_extent(values));
106 std::size_t size = std::accumulate(extent.begin(), extent.end(), 1, std::multiplies<std::size_t>());
129 template<
typename T,
typename S> std::size_t copy_from_buffer(T
const & values, std::vector<S> & buffer, std::size_t offset, std::false_type) {
130 for(
typename T::const_iterator it = values.begin(); it != values.end(); ++it)
131 offset = copy_from_buffer(*it, buffer, offset,
typename hdf5::is_continuous<typename T::value_type>::type());
135 template<
typename T,
typename Op,
typename C>
void reduce_impl(
const alps::mpi::communicator & comm, T
const & in_values, Op ,
int root, std::true_type, C) {
139 if (comm.
rank()==root) {
140 throw std::logic_error(
"reduce_impl(): 4-arg overload is called by root rank."+
ALPS_STACKTRACE);
147 template<
typename T,
typename Op>
void reduce_impl(
const alps::mpi::communicator & comm, T
const & in_values, Op ,
int root, std::false_type, std::true_type) {
150 std::vector<std::size_t> extent(
get_extent(in_values));
157 checked_mpi_reduce(const_cast<scalar_type*>(
get_pointer(in_values)), NULL,
158 std::accumulate(extent.begin(), extent.end(), 1, std::multiplies<std::size_t>()),
162 template<
typename T,
typename Op,
typename C>
void reduce_impl(
const alps::mpi::communicator & comm, T
const & in_values, T & out_values, Op ,
int root, std::true_type, C) {
163 using alps::mpi::reduce;
172 void* sendbuf=
const_cast<T*
>(&in_values);
173 if (sendbuf == &out_values) {
174 sendbuf=MPI_IN_PLACE;
180 template<
typename T,
typename Op>
void reduce_impl(
const alps::mpi::communicator & comm, T
const & in_values, T & out_values, Op ,
int root, std::false_type, std::true_type) {
183 std::vector<std::size_t> extent(
get_extent(in_values));
185 set_extent(out_values, std::vector<std::size_t>(extent.begin(), extent.end()));
193 std::accumulate(extent.begin(), extent.end(), 1, std::multiplies<std::size_t>()),
197 template<
typename T,
typename Op>
void reduce_impl(
const alps::mpi::communicator & comm, T
const & in_values, Op ,
int root, std::false_type, std::false_type) {
202 std::vector<std::size_t> extent(
get_extent(in_values));
203 std::vector<scalar_type> in_buffer(std::accumulate(extent.begin(), extent.end(), 1, std::multiplies<std::size_t>()));
204 using detail::copy_to_buffer;
205 copy_to_buffer(in_values, in_buffer, 0,
typename hdf5::is_content_continuous<T>::type());
211 checked_mpi_reduce(&in_buffer.front(), NULL, in_buffer.size(),
get_mpi_datatype(scalar_type()),
215 throw std::logic_error(
"No alps::mpi::reduce available for this type " + std::string(
typeid(T).name()) +
ALPS_STACKTRACE);
218 template<
typename T,
typename Op>
void reduce_impl(
const alps::mpi::communicator & comm, T
const & in_values, T & out_values, Op ,
int root, std::false_type, std::false_type) {
223 std::vector<std::size_t> extent(
get_extent(in_values));
224 std::vector<scalar_type> in_buffer(std::accumulate(extent.begin(), extent.end(), 1, std::multiplies<std::size_t>()));
225 std::vector<scalar_type> out_buffer(in_buffer);
226 using detail::copy_to_buffer;
227 copy_to_buffer(in_values, in_buffer, 0,
typename hdf5::is_content_continuous<T>::type());
233 checked_mpi_reduce(&in_buffer.front(), &out_buffer.front(), in_buffer.size(),
238 set_extent(out_values, std::vector<std::size_t>(extent.begin(), extent.end()));
239 using detail::copy_from_buffer;
240 copy_from_buffer(out_values, out_buffer, 0,
typename hdf5::is_content_continuous<T>::type());
242 throw std::logic_error(
"No alps::mpi::reduce available for this type " + std::string(
typeid(T).name()) +
ALPS_STACKTRACE);
246 template<
typename T,
typename Op>
void reduce(
const alps::mpi::communicator & comm, T
const & in_values, Op op,
int root) {
247 using detail::reduce_impl;
248 reduce_impl(comm, in_values, op, root,
typename std::is_scalar<T>::type(),
typename hdf5::is_content_continuous<T>::type());
251 template<
typename T,
typename Op>
void reduce(
const alps::mpi::communicator & comm, T
const & in_values, T & out_values, Op op,
int root) {
252 using detail::reduce_impl;
253 reduce_impl(comm, in_values, out_values, op, root,
typename std::is_scalar<T>::type(),
typename hdf5::is_content_continuous<T>::type());
258 #define ALPS_INST_MPI_REDUCE(T) \ 259 template void reduce(const communicator &, T const &, std::plus<T>, int); \ 260 template void reduce(const communicator &, T const &, T &, std::plus<T>, int); \ 261 template void reduce(const communicator &, std::vector<T> const &, std::plus<T>, int); \ 262 template void reduce(const communicator &, std::vector<T> const &, std::vector<T> &, std::plus<T>, int); \ 263 template void reduce(const communicator &, std::vector<std::vector<T>> const&, std::plus<T>, int); \ 264 template void reduce(const communicator &, std::vector<std::vector<T>> const&, std::vector<std::vector<T>>&, std::plus<T>, int); 266 ALPS_INST_MPI_REDUCE(boost::uint64_t)
267 ALPS_INST_MPI_REDUCE(
float)
268 ALPS_INST_MPI_REDUCE(
double)
269 ALPS_INST_MPI_REDUCE(
long double)
bool is_vectorizable(T const &value)
void set_extent(T &value, std::vector< std::size_t > const &size)
std::enable_if<!is_sequence< T >::value, std::size_t >::type size(T const &)
std::vector< std::size_t > get_extent(T const &value)
Encapsulation of an MPI communicator and some communicator-related operations.
scalar_type< T >::type * get_pointer(T &value)
Trait for MPI reduction operations.
int rank() const
Returns process rank in this communicator.
MPI_Datatype get_mpi_datatype(const T &)
Returns MPI datatype for the value of type T
count_type< T >::type count(T const &arg)