24 #ifndef __MPI_DOLFIN_WRAPPER_H 25 #define __MPI_DOLFIN_WRAPPER_H 30 #include <type_traits> 35 #define MPICH_IGNORE_CXX_SEEK 1 39 #include <dolfin/log/log.h> 40 #include <dolfin/log/Table.h> 44 #define MPI_COMM_WORLD 2 45 #define MPI_COMM_SELF 1 46 #define MPI_COMM_NULL 0 58 MPI_Info& operator*();
103 void reset(MPI_Comm comm);
106 unsigned int rank()
const;
111 unsigned int size()
const;
114 void barrier()
const;
117 MPI_Comm comm()
const;
126 static unsigned int rank(MPI_Comm comm);
130 static unsigned int size(MPI_Comm comm);
134 static bool is_broadcaster(MPI_Comm comm);
138 static bool is_receiver(MPI_Comm comm);
141 static void barrier(MPI_Comm comm);
146 static void all_to_all(MPI_Comm comm,
147 std::vector<std::vector<T>>& in_values,
148 std::vector<std::vector<T>>& out_values);
154 static void all_to_all(MPI_Comm comm,
155 std::vector<std::vector<T>>& in_values,
156 std::vector<T>& out_values);
160 static void broadcast(MPI_Comm comm, std::vector<T>& value,
161 unsigned int broadcaster=0);
165 static void broadcast(MPI_Comm comm, T& value,
166 unsigned int broadcaster=0);
170 static void scatter(MPI_Comm comm,
171 const std::vector<std::vector<T>>& in_values,
172 std::vector<T>& out_value,
173 unsigned int sending_process=0);
177 static void scatter(MPI_Comm comm,
178 const std::vector<T>& in_values,
179 T& out_value,
unsigned int sending_process=0);
183 static void gather(MPI_Comm comm,
const std::vector<T>& in_values,
184 std::vector<T>& out_values,
185 unsigned int receiving_process=0);
188 static void gather(MPI_Comm comm,
const std::string& in_values,
189 std::vector<std::string>& out_values,
190 unsigned int receiving_process=0);
195 static void all_gather(MPI_Comm comm,
196 const std::vector<T>& in_values,
197 std::vector<T>& out_values);
201 static void all_gather(MPI_Comm comm,
202 const std::vector<T>& in_values,
203 std::vector<std::vector<T>>& out_values);
207 static void all_gather(MPI_Comm comm,
const T in_value,
208 std::vector<T>& out_values);
212 static void all_gather(MPI_Comm comm,
const std::string& in_values,
213 std::vector<std::string>& out_values);
216 template<
typename T>
static T max(MPI_Comm comm,
const T& value);
219 template<
typename T>
static T min(MPI_Comm comm,
const T& value);
222 template<
typename T>
static T sum(MPI_Comm comm,
const T& value);
225 template<
typename T>
static T avg(MPI_Comm comm,
const T& value);
228 template<
typename T,
typename X>
static 229 T all_reduce(MPI_Comm comm,
const T& value, X op);
233 static std::size_t global_offset(MPI_Comm comm,
234 std::size_t range,
bool exclusive);
238 static void send_recv(MPI_Comm comm,
239 const std::vector<T>& send_value,
240 unsigned int dest,
int send_tag,
241 std::vector<T>& recv_value,
242 unsigned int source,
int recv_tag);
246 static void send_recv(MPI_Comm comm,
247 const std::vector<T>& send_value,
unsigned int dest,
248 std::vector<T>& recv_value,
unsigned int source);
252 static std::pair<std::int64_t, std::int64_t>
253 local_range(MPI_Comm comm, std::int64_t N);
257 static std::pair<std::int64_t, std::int64_t>
258 local_range(MPI_Comm comm,
int process, std::int64_t N);
262 static std::pair<std::int64_t, std::int64_t>
263 compute_local_range(
int process, std::int64_t N,
int size);
266 static unsigned int index_owner(MPI_Comm comm,
267 std::size_t index, std::size_t N);
270 static MPI_Op MPI_AVG();
278 static void error_no_mpi(
const char *where)
282 "DOLFIN has been configured without MPI support");
289 struct dependent_false : std::false_type {};
290 template<
typename T>
static MPI_Datatype mpi_type()
292 static_assert(dependent_false<T>::value,
"Unknown MPI type");
294 "perform MPI operation",
295 "MPI data type unknown");
302 static std::map<MPI_Op, std::string> operation_map;
309 template<>
inline MPI_Datatype MPI::mpi_type<float>() {
return MPI_FLOAT; }
310 template<>
inline MPI_Datatype MPI::mpi_type<double>() {
return MPI_DOUBLE; }
311 template<>
inline MPI_Datatype MPI::mpi_type<short int>() {
return MPI_SHORT; }
312 template<>
inline MPI_Datatype MPI::mpi_type<int>() {
return MPI_INT; }
313 template<>
inline MPI_Datatype MPI::mpi_type<long int>() {
return MPI_LONG; }
314 template<>
inline MPI_Datatype MPI::mpi_type<unsigned int>() {
return MPI_UNSIGNED; }
315 template<>
inline MPI_Datatype MPI::mpi_type<unsigned long int>() {
return MPI_UNSIGNED_LONG; }
316 template<>
inline MPI_Datatype MPI::mpi_type<long long>() {
return MPI_LONG_LONG; }
321 unsigned int broadcaster)
325 std::size_t bsize = value.size();
326 MPI_Bcast(&bsize, 1, mpi_type<std::size_t>(), broadcaster, comm);
330 MPI_Bcast(const_cast<T*>(value.data()), bsize, mpi_type<T>(),
337 unsigned int broadcaster)
340 MPI_Bcast(&value, 1, mpi_type<T>(), broadcaster, comm);
346 std::vector<std::vector<T>>& in_values,
347 std::vector<std::vector<T>>& out_values)
350 const std::size_t comm_size =
MPI::size(comm);
353 dolfin_assert(in_values.size() == comm_size);
354 std::vector<int> data_size_send(comm_size);
355 std::vector<int> data_offset_send(comm_size + 1, 0);
356 for (std::size_t p = 0; p < comm_size; ++p)
358 data_size_send[p] = in_values[p].size();
359 data_offset_send[p + 1] = data_offset_send[p] + data_size_send[p];
363 std::vector<int> data_size_recv(comm_size);
364 MPI_Alltoall(data_size_send.data(), 1, mpi_type<int>(),
365 data_size_recv.data(), 1, mpi_type<int>(),
369 std::vector<int> data_offset_recv(comm_size + 1 ,0);
370 std::vector<T> data_send(data_offset_send[comm_size]);
371 for (std::size_t p = 0; p < comm_size; ++p)
373 data_offset_recv[p + 1] = data_offset_recv[p] + data_size_recv[p];
374 std::copy(in_values[p].
begin(), in_values[p].
end(),
375 data_send.begin() + data_offset_send[p]);
379 std::vector<T> data_recv(data_offset_recv[comm_size]);
380 MPI_Alltoallv(data_send.data(), data_size_send.data(),
381 data_offset_send.data(), mpi_type<T>(),
382 data_recv.data(), data_size_recv.data(),
383 data_offset_recv.data(), mpi_type<T>(), comm);
386 out_values.resize(comm_size);
387 for (std::size_t p = 0; p < comm_size; ++p)
389 out_values[p].resize(data_size_recv[p]);
390 std::copy(data_recv.begin() + data_offset_recv[p],
391 data_recv.begin() + data_offset_recv[p + 1],
392 out_values[p].begin());
395 dolfin_assert(in_values.size() == 1);
396 out_values = in_values;
402 std::vector<std::vector<T>>& in_values,
403 std::vector<T>& out_values)
406 const std::size_t comm_size =
MPI::size(comm);
409 dolfin_assert(in_values.size() == comm_size);
410 std::vector<int> data_size_send(comm_size);
411 std::vector<int> data_offset_send(comm_size + 1, 0);
412 for (std::size_t p = 0; p < comm_size; ++p)
414 data_size_send[p] = in_values[p].size();
415 data_offset_send[p + 1] = data_offset_send[p] + data_size_send[p];
419 std::vector<int> data_size_recv(comm_size);
420 MPI_Alltoall(data_size_send.data(), 1, mpi_type<int>(),
421 data_size_recv.data(), 1, mpi_type<int>(),
425 std::vector<int> data_offset_recv(comm_size + 1 ,0);
426 std::vector<T> data_send(data_offset_send[comm_size]);
427 for (std::size_t p = 0; p < comm_size; ++p)
429 data_offset_recv[p + 1] = data_offset_recv[p] + data_size_recv[p];
430 std::copy(in_values[p].
begin(), in_values[p].
end(),
431 data_send.begin() + data_offset_send[p]);
435 out_values.resize(data_offset_recv[comm_size]);
436 MPI_Alltoallv(data_send.data(), data_size_send.data(),
437 data_offset_send.data(), mpi_type<T>(),
438 out_values.data(), data_size_recv.data(),
439 data_offset_recv.data(), mpi_type<T>(), comm);
442 dolfin_assert(in_values.size() == 1);
443 out_values = in_values[0];
447 #ifndef DOXYGEN_IGNORE 450 std::vector<std::vector<bool>>& in_values,
451 std::vector<std::vector<bool>>& out_values)
455 std::vector<std::vector<short int>> send(in_values.size());
456 for (std::size_t i = 0; i < in_values.size(); ++i)
457 send[i].
assign(in_values[i].
begin(), in_values[i].end());
460 std::vector<std::vector<short int>> recv;
461 all_to_all(comm, send, recv);
464 out_values.resize(recv.size());
465 for (std::size_t i = 0; i < recv.size(); ++i)
466 out_values[i].
assign(recv[i].
begin(), recv[i].end());
468 dolfin_assert(in_values.size() == 1);
469 out_values = in_values;
475 std::vector<std::vector<bool>>& in_values,
476 std::vector<bool>& out_values)
480 std::vector<std::vector<short int>> send(in_values.size());
481 for (std::size_t i = 0; i < in_values.size(); ++i)
482 send[i].
assign(in_values[i].
begin(), in_values[i].end());
485 std::vector<short int> recv;
486 all_to_all(comm, send, recv);
489 out_values.assign(recv.begin(), recv.end());
491 dolfin_assert(in_values.size() == 1);
492 out_values = in_values[0];
500 const std::vector<std::vector<T>>& in_values,
501 std::vector<T>& out_value,
502 unsigned int sending_process)
507 const std::size_t comm_size =
MPI::size(comm);
508 std::vector<int> all_num_values;
511 dolfin_assert(in_values.size() == comm_size);
512 all_num_values.resize(comm_size);
513 for (std::size_t i = 0; i < comm_size; ++i)
514 all_num_values[i] = in_values[i].size();
516 int my_num_values = 0;
517 scatter(comm, all_num_values, my_num_values, sending_process);
520 std::vector<T> sendbuf;
521 std::vector<int> offsets;
525 offsets.resize(comm_size + 1, 0);
526 for (std::size_t i = 1; i <= comm_size; ++i)
527 offsets[i] = offsets[i - 1] + all_num_values[i - 1];
530 const std::size_t n = std::accumulate(all_num_values.begin(),
531 all_num_values.end(), 0);
533 for (std::size_t p = 0; p < in_values.size(); ++p)
535 std::copy(in_values[p].
begin(), in_values[p].
end(),
536 sendbuf.begin() + offsets[p]);
541 out_value.resize(my_num_values);
542 MPI_Scatterv(const_cast<T*>(sendbuf.data()), all_num_values.data(),
543 offsets.data(), mpi_type<T>(),
544 out_value.data(), my_num_values,
545 mpi_type<T>(), sending_process, comm);
547 dolfin_assert(sending_process == 0);
548 dolfin_assert(in_values.size() == 1);
549 out_value = in_values[0];
553 #ifndef DOXYGEN_IGNORE 556 const std::vector<std::vector<bool>>& in_values,
557 std::vector<bool>& out_value,
558 unsigned int sending_process)
562 std::vector<std::vector<short int>> in(in_values.size());
563 for (std::size_t i = 0; i < in_values.size(); ++i)
564 in[i] = std::vector<short int>(in_values[i].
begin(), in_values[i].end());
566 std::vector<short int> out;
567 scatter(comm, in, out, sending_process);
569 out_value.resize(out.size());
570 std::copy(out.begin(), out.end(), out_value.begin());
572 dolfin_assert(sending_process == 0);
573 dolfin_assert(in_values.size() == 1);
574 out_value = in_values[0];
581 const std::vector<T>& in_values,
582 T& out_value,
unsigned int sending_process)
586 dolfin_assert(in_values.size() ==
MPI::size(comm));
588 MPI_Scatter(const_cast<T*>(in_values.data()), 1, mpi_type<T>(),
589 &out_value, 1, mpi_type<T>(), sending_process, comm);
591 dolfin_assert(sending_process == 0);
592 dolfin_assert(in_values.size() == 1);
593 out_value = in_values[0];
599 const std::vector<T>& in_values,
600 std::vector<T>& out_values,
601 unsigned int receiving_process)
604 const std::size_t comm_size =
MPI::size(comm);
607 std::vector<int> pcounts(comm_size);
608 const int local_size = in_values.size();
609 MPI_Gather(const_cast<int*>(&local_size), 1, mpi_type<int>(),
610 pcounts.data(), 1, mpi_type<int>(),
611 receiving_process, comm);
614 std::vector<int> offsets(comm_size + 1, 0);
615 for (std::size_t i = 1; i <= comm_size; ++i)
616 offsets[i] = offsets[i - 1] + pcounts[i - 1];
618 const std::size_t n = std::accumulate(pcounts.begin(), pcounts.end(), 0);
619 out_values.resize(n);
620 MPI_Gatherv(const_cast<T*>(in_values.data()), in_values.size(),
622 out_values.data(), pcounts.data(), offsets.data(),
623 mpi_type<T>(), receiving_process, comm);
625 out_values = in_values;
630 const std::string& in_values,
631 std::vector<std::string>& out_values,
632 unsigned int receiving_process)
635 const std::size_t comm_size =
MPI::size(comm);
638 std::vector<int> pcounts(comm_size);
639 int local_size = in_values.size();
640 MPI_Gather(&local_size, 1, MPI_INT,
641 pcounts.data(), 1,MPI_INT,
642 receiving_process, comm);
645 std::vector<int> offsets(comm_size + 1, 0);
646 for (std::size_t i = 1; i <= comm_size; ++i)
647 offsets[i] = offsets[i - 1] + pcounts[i - 1];
650 const std::size_t n = std::accumulate(pcounts.begin(), pcounts.end(), 0);
651 std::vector<char> _out(n);
652 MPI_Gatherv(const_cast<char*>(in_values.data()), in_values.size(),
654 _out.data(), pcounts.data(), offsets.data(),
655 MPI_CHAR, receiving_process, comm);
658 out_values.resize(comm_size);
659 for (std::size_t p = 0; p < comm_size; ++p)
661 out_values[p] = std::string(_out.begin() + offsets[p],
662 _out.begin() + offsets[p + 1]);
666 out_values.push_back(in_values);
671 const std::string& in_values,
672 std::vector<std::string>& out_values)
675 const std::size_t comm_size =
MPI::size(comm);
678 std::vector<int> pcounts(comm_size);
679 int local_size = in_values.size();
680 MPI_Allgather(&local_size, 1, MPI_INT, pcounts.data(), 1, MPI_INT, comm);
683 std::vector<int> offsets(comm_size + 1, 0);
684 for (std::size_t i = 1; i <= comm_size; ++i)
685 offsets[i] = offsets[i - 1] + pcounts[i - 1];
688 const std::size_t n = std::accumulate(pcounts.begin(), pcounts.end(), 0);
689 std::vector<char> _out(n);
690 MPI_Allgatherv(const_cast<char*>(in_values.data()), in_values.size(),
691 MPI_CHAR, _out.data(), pcounts.data(), offsets.data(),
695 out_values.resize(comm_size);
696 for (std::size_t p = 0; p < comm_size; ++p)
698 out_values[p] = std::string(_out.begin() + offsets[p],
699 _out.begin() + offsets[p + 1]);
703 out_values.push_back(in_values);
709 const std::vector<T>& in_values,
710 std::vector<T>& out_values)
713 out_values.resize(in_values.size()*
MPI::size(comm));
714 MPI_Allgather(const_cast<T*>(in_values.data()), in_values.size(),
716 out_values.data(), in_values.size(), mpi_type<T>(),
719 out_values = in_values;
725 const std::vector<T>& in_values,
726 std::vector<std::vector<T>>& out_values)
729 const std::size_t comm_size =
MPI::size(comm);
732 std::vector<int> pcounts;
733 const int local_size = in_values.size();
735 dolfin_assert(pcounts.size() == comm_size);
738 std::vector<int> offsets(comm_size + 1, 0);
739 for (std::size_t i = 1; i <= comm_size; ++i)
740 offsets[i] = offsets[i - 1] + pcounts[i - 1];
743 const std::size_t n = std::accumulate(pcounts.begin(), pcounts.end(), 0);
744 std::vector<T> recvbuf(n);
745 MPI_Allgatherv(const_cast<T*>(in_values.data()), in_values.size(),
747 recvbuf.data(), pcounts.data(), offsets.data(),
748 mpi_type<T>(), comm);
751 out_values.resize(comm_size);
752 for (std::size_t p = 0; p < comm_size; ++p)
754 out_values[p].resize(pcounts[p]);
755 for (
int i = 0; i < pcounts[p]; ++i)
756 out_values[p][i] = recvbuf[offsets[p] + i];
760 out_values.push_back(in_values);
766 std::vector<T>& out_values)
770 MPI_Allgather(const_cast<T*>(&in_value), 1, mpi_type<T>(),
771 out_values.data(), 1, mpi_type<T>(), comm);
774 out_values.push_back(in_value);
778 template<
typename T,
typename X>
783 MPI_Allreduce(const_cast<T*>(&value), &out, 1, mpi_type<T>(), op, comm);
795 MPI_Op op =
static_cast<MPI_Op
>(MPI_MAX);
796 return all_reduce(comm, value, op);
807 MPI_Op op =
static_cast<MPI_Op
>(MPI_MIN);
808 return all_reduce(comm, value, op);
819 MPI_Op op =
static_cast<MPI_Op
>(MPI_SUM);
820 return all_reduce(comm, value, op);
830 "perform average reduction",
831 "Not implemented for this type");
839 const std::vector<T>& send_value,
840 unsigned int dest,
int send_tag,
841 std::vector<T>& recv_value,
842 unsigned int source,
int recv_tag)
845 std::size_t send_size = send_value.size();
846 std::size_t recv_size = 0;
847 MPI_Status mpi_status;
848 MPI_Sendrecv(&send_size, 1, mpi_type<std::size_t>(), dest, send_tag,
849 &recv_size, 1, mpi_type<std::size_t>(), source, recv_tag,
852 recv_value.resize(recv_size);
853 MPI_Sendrecv(const_cast<T*>(send_value.data()), send_value.size(),
854 mpi_type<T>(), dest, send_tag,
855 recv_value.data(), recv_size, mpi_type<T>(),
856 source, recv_tag, comm, &mpi_status);
859 "call MPI::send_recv",
860 "DOLFIN has been configured without MPI support");
866 const std::vector<T>& send_value,
868 std::vector<T>& recv_value,
static void scatter(MPI_Comm comm, const std::vector< std::vector< T >> &in_values, std::vector< T > &out_value, unsigned int sending_process=0)
Scatter vector in_values[i] to process i.
Definition: MPI.h:499
static T avg(MPI_Comm comm, const T &value)
Return average across comm; implemented only for T == Table.
Definition: MPI.h:826
static T all_reduce(MPI_Comm comm, const T &value, X op)
All reduce.
Definition: MPI.h:779
void begin(std::string msg,...)
Begin task (increase indentation level)
Definition: log.cpp:153
static T min(MPI_Comm comm, const T &value)
Return global min value.
Definition: MPI.h:802
static unsigned int rank(MPI_Comm comm)
Return process rank for the communicator.
Definition: MPI.cpp:143
static unsigned int size(MPI_Comm comm)
Definition: MPI.cpp:154
static void all_to_all(MPI_Comm comm, std::vector< std::vector< T >> &in_values, std::vector< std::vector< T >> &out_values)
Definition: MPI.h:345
void end()
End task (decrease indentation level)
Definition: log.cpp:168
static T sum(MPI_Comm comm, const T &value)
Sum values and return sum.
Definition: MPI.h:814
static T max(MPI_Comm comm, const T &value)
Return global max value.
Definition: MPI.h:790
void assign(std::shared_ptr< Function > receiving_func, std::shared_ptr< const Function > assigning_func)
Definition: assign.cpp:27
static void all_gather(MPI_Comm comm, const std::vector< T > &in_values, std::vector< T > &out_values)
Definition: MPI.h:708
static void send_recv(MPI_Comm comm, const std::vector< T > &send_value, unsigned int dest, int send_tag, std::vector< T > &recv_value, unsigned int source, int recv_tag)
Send-receive data between processes (blocking)
Definition: MPI.h:838
void dolfin_error(std::string location, std::string task, std::string reason,...)
Definition: log.cpp:129
static void broadcast(MPI_Comm comm, std::vector< T > &value, unsigned int broadcaster=0)
Broadcast vector of value from broadcaster to all processes.
Definition: MPI.h:320
static void gather(MPI_Comm comm, const std::vector< T > &in_values, std::vector< T > &out_values, unsigned int receiving_process=0)
Gather values on one process.
Definition: MPI.h:598