27 #include <boost/signals2.hpp>
35 #if !defined(DEAL_II_WITH_MPI) && !defined(DEAL_II_WITH_PETSC)
40 using MPI_Request = int;
41 using MPI_Datatype = int;
43 # ifndef MPI_COMM_WORLD
44 # define MPI_COMM_WORLD 0
46 # ifndef MPI_COMM_SELF
47 # define MPI_COMM_SELF 0
49 # ifndef MPI_COMM_NULL
50 # define MPI_COMM_NULL 0
52 # ifndef MPI_REQUEST_NULL
53 # define MPI_REQUEST_NULL 0
84 #ifdef DEAL_II_WITH_MPI
85 # define DEAL_II_MPI_CONST_CAST(expr) (expr)
95 template <
int rank,
int dim,
typename Number>
97 template <
int rank,
int dim,
typename Number>
99 template <
typename Number>
120 const unsigned int my_partition_id,
121 const unsigned int n_partitions,
141 template <
typename T>
159 std::complex<double>,
160 std::complex<long double>,
189 const std::vector<unsigned int>
191 const MPI_Comm &comm_small);
214 std::vector<unsigned int>
216 const MPI_Comm & mpi_comm,
217 const std::vector<unsigned int> &destinations);
240 const MPI_Comm & mpi_comm,
241 const std::vector<unsigned int> &destinations);
491 template <
typename T>
499 template <
typename W,
typename G>
500 Future(W &&wait_operation, G &&get_and_cleanup_operation);
606 #ifdef DEAL_II_WITH_MPI
609 const MPI_Group &group,
611 MPI_Comm * new_comm);
622 std::vector<IndexSet>
624 const MPI_Comm &
comm,
636 const MPI_Comm &
comm,
639 #ifdef DEAL_II_WITH_MPI
655 template <
class Iterator,
typename Number =
long double>
656 std::pair<Number, typename numbers::NumberTraits<Number>::real_type>
659 const MPI_Comm &
comm);
710 std::unique_ptr<MPI_Datatype, void (*)(MPI_Datatype *)>
732 template <
typename T>
734 sum(
const T &t,
const MPI_Comm &mpi_communicator);
745 template <
typename T,
typename U>
758 template <
typename T>
761 const MPI_Comm & mpi_communicator,
769 template <
int rank,
int dim,
typename Number>
772 const MPI_Comm & mpi_communicator);
779 template <
int rank,
int dim,
typename Number>
782 const MPI_Comm & mpi_communicator);
792 template <
typename Number>
795 const MPI_Comm & mpi_communicator,
817 template <
typename T>
819 max(
const T &t,
const MPI_Comm &mpi_communicator);
830 template <
typename T,
typename U>
832 max(
const T &
values,
const MPI_Comm &mpi_communicator,
U &maxima);
843 template <
typename T>
846 const MPI_Comm & mpi_communicator,
868 template <
typename T>
870 min(
const T &t,
const MPI_Comm &mpi_communicator);
881 template <
typename T,
typename U>
883 min(
const T &
values,
const MPI_Comm &mpi_communicator,
U &minima);
894 template <
typename T>
897 const MPI_Comm & mpi_communicator,
923 template <
typename T>
941 template <
typename T,
typename U>
954 template <
typename T>
957 const MPI_Comm & mpi_communicator,
1036 min_max_avg(
const double my_value,
const MPI_Comm &mpi_communicator);
1049 std::vector<MinMaxAvg>
1051 const MPI_Comm & mpi_communicator);
1069 const MPI_Comm & mpi_communicator);
1201 register_request(MPI_Request &request);
1207 unregister_request(MPI_Request &request);
1273 template <
typename T>
1274 std::map<unsigned int, T>
1276 const std::map<unsigned int, T> &objects_to_send);
1291 template <
typename T>
1310 template <
typename T>
1313 const T & object_to_send,
1314 const unsigned int root_process = 0);
1351 template <
typename T>
1352 std::enable_if_t<is_mpi_type<T> ==
false,
T>
1354 const T & object_to_send,
1355 const unsigned int root_process = 0);
1379 template <
typename T>
1380 std::enable_if_t<is_mpi_type<T> ==
true,
T>
1382 const T & object_to_send,
1383 const unsigned int root_process = 0);
1401 template <
typename T>
1405 const unsigned int root,
1406 const MPI_Comm &
comm);
1420 template <
typename T>
1423 const MPI_Comm &
comm,
1424 const std::function<
T(
const T &,
const T &)> &combiner,
1425 const unsigned int root_process = 0);
1436 template <
typename T>
1439 const MPI_Comm &
comm,
1440 const std::function<
T(
const T &,
const T &)> &combiner);
1463 template <
typename T>
1466 MPI_Comm communicator,
1467 const unsigned int target_rank,
1468 const unsigned int mpi_tag = 0);
1487 template <
typename T>
1490 const unsigned int source_rank,
1491 const unsigned int mpi_tag = 0);
1536 std::vector<unsigned int>
1538 const IndexSet &indices_to_look_up,
1539 const MPI_Comm &
comm);
1548 template <
typename T>
1555 template <
typename T>
1570 namespace MPIDataTypes
1572 #ifdef DEAL_II_WITH_MPI
1576 return MPI_CXX_BOOL;
1592 return MPI_SIGNED_CHAR;
1632 return MPI_LONG_LONG;
1640 return MPI_UNSIGNED_CHAR;
1648 return MPI_UNSIGNED_SHORT;
1656 return MPI_UNSIGNED;
1664 return MPI_UNSIGNED_LONG;
1672 return MPI_UNSIGNED_LONG_LONG;
1696 return MPI_LONG_DOUBLE;
1712 return MPI_DOUBLE_COMPLEX;
1720 #ifdef DEAL_II_WITH_MPI
1738 template <
typename T>
1741 static_cast<std::remove_cv_t<std::remove_reference_t<T>
> *>(
nullptr));
1748 template <
typename T>
1752 const MPI_Comm & mpi_communicator,
1757 template <
typename T>
1758 template <
typename W,
typename G>
1768 template <
typename T>
1769 Future<T>::~Future()
1779 if ((get_was_called ==
false) && get_and_cleanup_function)
1785 template <
typename T>
1789 if (is_done ==
false)
1798 template <
typename T>
1802 Assert(get_was_called ==
false,
1804 "You can't call get() more than once on a Future object."));
1805 get_was_called =
true;
1808 return get_and_cleanup_function();
1813 template <
typename T,
unsigned int N>
1815 sum(
const T (&
values)[
N],
const MPI_Comm &mpi_communicator,
T (&sums)[
N])
1825 template <
typename T,
unsigned int N>
1827 max(
const T (&
values)[
N],
const MPI_Comm &mpi_communicator,
T (&maxima)[
N])
1837 template <
typename T,
unsigned int N>
1839 min(
const T (&
values)[
N],
const MPI_Comm &mpi_communicator,
T (&minima)[
N])
1849 template <
typename T,
unsigned int N>
1852 const MPI_Comm &mpi_communicator,
1855 static_assert(std::is_integral<T>::value,
1856 "The MPI_LOR operation only allows integral data types.");
1866 template <
typename T>
1867 std::map<unsigned int, T>
1869 const std::map<unsigned int, T> &objects_to_send)
1871 # ifndef DEAL_II_WITH_MPI
1873 Assert(objects_to_send.size() < 2,
1874 ExcMessage(
"Cannot send to more than one processor."));
1875 Assert(objects_to_send.find(0) != objects_to_send.end() ||
1876 objects_to_send.size() == 0,
1877 ExcMessage(
"Can only send to myself or to nobody."));
1878 return objects_to_send;
1882 std::map<unsigned int, T> received_objects;
1884 std::vector<unsigned int> send_to;
1885 send_to.reserve(objects_to_send.size());
1886 for (
const auto &m : objects_to_send)
1887 if (m.first == my_proc)
1888 received_objects[my_proc] = m.second;
1890 send_to.emplace_back(m.first);
1892 const unsigned int n_expected_incoming_messages =
1896 static CollectiveMutex mutex;
1897 CollectiveMutex::ScopedLock lock(mutex,
comm);
1903 if (send_to.size() == 0 && n_expected_incoming_messages == 0)
1904 return received_objects;
1910 std::vector<std::vector<char>> buffers_to_send(send_to.size());
1911 std::vector<MPI_Request> buffer_send_requests(send_to.size());
1914 for (
const auto &rank_obj : objects_to_send)
1915 if (rank_obj.first != my_proc)
1917 const auto &rank = rank_obj.first;
1920 const int ierr = MPI_Isend(buffers_to_send[i].data(),
1921 buffers_to_send[i].size(),
1926 &buffer_send_requests[i]);
1934 std::vector<char> buffer;
1936 for (
unsigned int i = 0; i < n_expected_incoming_messages; ++i)
1940 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag,
comm, &status);
1945 ierr = MPI_Get_count(&status, MPI_CHAR, &len);
1950 const unsigned int rank = status.MPI_SOURCE;
1953 ierr = MPI_Recv(buffer.data(),
1961 Assert(received_objects.find(rank) == received_objects.end(),
1963 "I should not receive again from this rank"));
1964 received_objects[rank] =
1965 Utilities::unpack<T>(buffer,
1971 const int ierr = MPI_Waitall(send_to.size(),
1972 buffer_send_requests.data(),
1973 MPI_STATUSES_IGNORE);
1976 return received_objects;
1982 template <
typename T>
1989 # ifndef DEAL_II_WITH_MPI
1991 std::vector<T> v(1,
object);
1998 int n_local_data = buffer.size();
2001 std::vector<int> size_all_data(n_procs, 0);
2004 int ierr = MPI_Allgather(
2005 &n_local_data, 1, MPI_INT, size_all_data.data(), 1, MPI_INT,
comm);
2010 std::vector<int> rdispls(n_procs);
2012 for (
unsigned int i = 1; i < n_procs; ++i)
2013 rdispls[i] = rdispls[i - 1] + size_all_data[i - 1];
2016 std::vector<char> received_unrolled_buffer(rdispls.back() +
2017 size_all_data.back());
2019 ierr = MPI_Allgatherv(buffer.data(),
2022 received_unrolled_buffer.data(),
2023 size_all_data.data(),
2029 std::vector<T> received_objects(n_procs);
2030 for (
unsigned int i = 0; i < n_procs; ++i)
2032 std::vector<char> local_buffer(received_unrolled_buffer.begin() +
2034 received_unrolled_buffer.begin() +
2035 rdispls[i] + size_all_data[i]);
2036 received_objects[i] = Utilities::unpack<T>(local_buffer);
2039 return received_objects;
2045 template <
typename T>
2048 const T & object_to_send,
2049 const unsigned int root_process)
2051 # ifndef DEAL_II_WITH_MPI
2054 std::vector<T> v(1, object_to_send);
2063 int n_local_data = buffer.size();
2067 std::vector<int> size_all_data;
2068 if (my_rank == root_process)
2069 size_all_data.resize(n_procs, 0);
2072 int ierr = MPI_Gather(&n_local_data,
2075 size_all_data.data(),
2084 std::vector<int> rdispls;
2085 if (my_rank == root_process)
2087 rdispls.resize(n_procs, 0);
2088 for (
unsigned int i = 1; i < n_procs; ++i)
2089 rdispls[i] = rdispls[i - 1] + size_all_data[i - 1];
2092 std::vector<char> received_unrolled_buffer;
2093 if (my_rank == root_process)
2094 received_unrolled_buffer.resize(rdispls.back() + size_all_data.back());
2096 ierr = MPI_Gatherv(buffer.data(),
2099 received_unrolled_buffer.data(),
2100 size_all_data.data(),
2107 std::vector<T> received_objects;
2109 if (my_rank == root_process)
2111 received_objects.resize(n_procs);
2113 for (
unsigned int i = 0; i < n_procs; ++i)
2115 const std::vector<char> local_buffer(
2116 received_unrolled_buffer.begin() + rdispls[i],
2117 received_unrolled_buffer.begin() + rdispls[i] +
2119 received_objects[i] = Utilities::unpack<T>(local_buffer);
2122 return received_objects;
2128 template <
typename T>
2132 const unsigned int root,
2133 const MPI_Comm &
comm)
2135 # ifndef DEAL_II_WITH_MPI
2148 size_t total_sent_count = 0;
2149 while (total_sent_count < count)
2151 const size_t current_count =
2152 std::min(count - total_sent_count, max_send_count);
2154 const int ierr = MPI_Bcast(buffer + total_sent_count,
2160 total_sent_count += current_count;
2167 template <
typename T>
2168 std::enable_if_t<is_mpi_type<T> ==
false,
T>
2170 const T & object_to_send,
2171 const unsigned int root_process)
2173 # ifndef DEAL_II_WITH_MPI
2176 return object_to_send;
2182 std::vector<char> buffer;
2190 buffer_size = buffer.size();
2194 int ierr = MPI_Bcast(&buffer_size,
2204 buffer.resize(buffer_size);
2209 return object_to_send;
2211 return Utilities::unpack<T>(buffer,
false);
2217 template <
typename T>
2218 std::enable_if_t<is_mpi_type<T> ==
true,
T>
2220 const T & object_to_send,
2221 const unsigned int root_process)
2223 # ifndef DEAL_II_WITH_MPI
2226 return object_to_send;
2229 T object = object_to_send;
2231 MPI_Bcast(&
object, 1, mpi_type_id_for_type<T>, root_process,
comm);
2239 template <
typename T>
2242 MPI_Comm communicator,
2243 const unsigned int target_rank,
2244 const unsigned int mpi_tag)
2246 # ifndef DEAL_II_WITH_MPI
2249 "This function is not useful when called without MPI."));
2254 return Future<void>([]() {}, []() {});
2269 std::shared_ptr<std::vector<char>> send_buffer =
2274 MPI_Request request;
2276 MPI_Isend(send_buffer->data(),
2277 send_buffer->size(),
2298 auto wait = [request]()
mutable {
2299 const int ierr = MPI_Wait(&request, MPI_STATUS_IGNORE);
2302 auto cleanup = [send_buffer = std::move(send_buffer)]() {
2303 send_buffer->clear();
2305 return Future<void>(wait, cleanup);
2311 template <
typename T>
2313 irecv(MPI_Comm communicator,
2314 const unsigned int source_rank,
2315 const unsigned int mpi_tag)
2317 # ifndef DEAL_II_WITH_MPI
2320 "This function is not useful when called without MPI."));
2324 return Future<void>([]() {}, []() {
return T{}; });
2340 std::shared_ptr<MPI_Message> message = std::make_shared<MPI_Message>();
2341 std::shared_ptr<MPI_Status> status = std::make_shared<MPI_Status>();
2343 auto wait = [source_rank, mpi_tag, communicator, message, status]() {
2344 const int ierr = MPI_Mprobe(
2345 source_rank, mpi_tag, communicator, message.get(), status.get());
2351 auto get = [status, message]() {
2354 ierr = MPI_Get_count(status.get(), MPI_CHAR, &number_amount);
2357 std::vector<char> receive_buffer(number_amount);
2361 ierr = MPI_Mrecv(receive_buffer.data(),
2369 return Utilities::unpack<T>(receive_buffer,
false);
2372 return Future<T>(wait, get);
2378 # ifdef DEAL_II_WITH_MPI
2379 template <
class Iterator,
typename Number>
2380 std::pair<Number, typename numbers::NumberTraits<Number>::real_type>
2383 const MPI_Comm &
comm)
2391 const Number
sum = std::accumulate(
begin,
end, Number(0.));
2398 std::for_each(
begin,
end, [&
mean, &sq_sum](
const Number &v) {
2402 return std::make_pair(
mean,
2403 std::sqrt(sq_sum /
static_cast<Std
>(size - 1)));
void sum(const SparseMatrix< Number > &local, const MPI_Comm &mpi_communicator, SparseMatrix< Number > &global)
SymmetricTensor< rank, dim, Number > sum(const SymmetricTensor< rank, dim, Number > &local, const MPI_Comm &mpi_communicator)
Tensor< rank, dim, Number > sum(const Tensor< rank, dim, Number > &local, const MPI_Comm &mpi_communicator)
ScopedLock(CollectiveMutex &mutex, const MPI_Comm &comm)
void unlock(const MPI_Comm &comm)
void lock(const MPI_Comm &comm)
DuplicatedCommunicator(const DuplicatedCommunicator &)=delete
DuplicatedCommunicator(const MPI_Comm &communicator)
~DuplicatedCommunicator()
DuplicatedCommunicator & operator=(const DuplicatedCommunicator &)=delete
const MPI_Comm & operator*() const
Future(const Future &)=delete
Future(Future &&) noexcept=default
std::function< void()> wait_function
std::function< T()> get_and_cleanup_function
Future(W &&wait_operation, G &&get_and_cleanup_operation)
static std::set< MPI_Request * > requests
#define DEAL_II_DEPRECATED
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
__global__ void set(Number *val, const Number s, const size_type N)
static ::ExceptionBase & ExcDivideByZero()
static ::ExceptionBase & ExcInternalError()
#define Assert(cond, exc)
#define AssertThrowMPI(error_code)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcMessage(std::string arg1)
VectorType::value_type * begin(VectorType &V)
VectorType::value_type * end(VectorType &V)
MPI_Datatype mpi_type_id(const bool *)
MPI_Datatype mpi_type_id(const std::complex< double > *)
std::pair< Number, typename numbers::NumberTraits< Number >::real_type > mean_and_standard_deviation(const Iterator begin, const Iterator end, const MPI_Comm &comm)
std::map< unsigned int, T > some_to_some(const MPI_Comm &comm, const std::map< unsigned int, T > &objects_to_send)
void free_communicator(MPI_Comm &mpi_communicator)
std::vector< unsigned int > compute_index_owner(const IndexSet &owned_indices, const IndexSet &indices_to_look_up, const MPI_Comm &comm)
std::vector< T > gather(const MPI_Comm &comm, const T &object_to_send, const unsigned int root_process=0)
void sum(const SparseMatrix< Number > &local, const MPI_Comm &mpi_communicator, SparseMatrix< Number > &global)
void logical_or(const ArrayView< const T > &values, const MPI_Comm &mpi_communicator, const ArrayView< T > &results)
void broadcast(T *buffer, const size_t count, const unsigned int root, const MPI_Comm &comm)
T logical_or(const T &t, const MPI_Comm &mpi_communicator)
std::enable_if_t< is_mpi_type< T >==false, T > broadcast(const MPI_Comm &comm, const T &object_to_send, const unsigned int root_process=0)
void min(const ArrayView< const T > &values, const MPI_Comm &mpi_communicator, const ArrayView< T > &minima)
std::unique_ptr< MPI_Datatype, void(*)(MPI_Datatype *)> create_mpi_data_type_n_bytes(const std::size_t n_bytes)
std::vector< IndexSet > create_ascending_partitioning(const MPI_Comm &comm, const types::global_dof_index locally_owned_size)
std::vector< T > compute_set_union(const std::vector< T > &vec, const MPI_Comm &comm)
IndexSet create_evenly_distributed_partitioning(const MPI_Comm &comm, const types::global_dof_index total_size)
unsigned int compute_n_point_to_point_communications(const MPI_Comm &mpi_comm, const std::vector< unsigned int > &destinations)
T all_reduce(const T &local_value, const MPI_Comm &comm, const std::function< T(const T &, const T &)> &combiner)
Future< void > isend(const T &object, MPI_Comm communicator, const unsigned int target_rank, const unsigned int mpi_tag=0)
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
std::vector< unsigned int > compute_point_to_point_communication_pattern(const MPI_Comm &mpi_comm, const std::vector< unsigned int > &destinations)
void max(const ArrayView< const T > &values, const MPI_Comm &mpi_communicator, const ArrayView< T > &maxima)
T min(const T &t, const MPI_Comm &mpi_communicator)
T reduce(const T &local_value, const MPI_Comm &comm, const std::function< T(const T &, const T &)> &combiner, const unsigned int root_process=0)
MPI_Comm duplicate_communicator(const MPI_Comm &mpi_communicator)
T sum(const T &t, const MPI_Comm &mpi_communicator)
const std::vector< unsigned int > mpi_processes_within_communicator(const MPI_Comm &comm_large, const MPI_Comm &comm_small)
const MPI_Datatype mpi_type_id_for_type
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
std::vector< T > all_gather(const MPI_Comm &comm, const T &object_to_send)
MinMaxAvg min_max_avg(const double my_value, const MPI_Comm &mpi_communicator)
T max(const T &t, const MPI_Comm &mpi_communicator)
Future< T > irecv(MPI_Comm communicator, const unsigned int source_rank, const unsigned int mpi_tag=0)
constexpr bool is_mpi_type
int create_group(const MPI_Comm &comm, const MPI_Group &group, const int tag, MPI_Comm *new_comm)
size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
IndexSet create_evenly_distributed_partitioning(const unsigned int my_partition_id, const unsigned int n_partitions, const types::global_dof_index total_size)
static const unsigned int invalid_unsigned_int
const types::global_dof_index invalid_size_type
unsigned int global_dof_index
boost::signals2::signal< void()> at_mpi_init
boost::signals2::signal< void()> at_mpi_finalize
static constexpr std::enable_if_t< std::is_same< Dummy, number >::value &&is_cuda_compatible< Dummy >::value, real_type > abs_square(const number &x)
void gather(VectorizedArray< Number, width > &out, const std::array< Number *, width > &ptrs, const unsigned int offset)