35#ifdef DEAL_II_WITH_MPI
55#ifdef DEAL_II_WITH_MPI
56# define DEAL_II_MPI_CONST_CAST(expr) (expr)
66template <
int rank,
int dim,
typename Number>
68template <
int rank,
int dim,
typename Number>
70template <
typename Number>
91 const unsigned int my_partition_id,
92 const unsigned int n_partitions,
112 template <
typename T>
130 std::complex<double>,
131 std::complex<long double>,
160 std::vector<unsigned int>
185 std::vector<unsigned int>
188 const std::vector<unsigned int> &destinations);
212 const std::vector<unsigned int> &destinations);
462 template <
typename T>
470 template <
typename W,
typename G>
471 Future(W &&wait_operation, G &&get_and_cleanup_operation);
585 const
types::global_dof_index locally_owned_size);
597 const
types::global_dof_index total_size);
599#ifdef DEAL_II_WITH_MPI
615 template <
class Iterator,
typename Number =
long double>
616 std::pair<Number, typename numbers::NumberTraits<Number>::real_type>
670 std::unique_ptr<MPI_Datatype, void (*)(MPI_Datatype *)>
692 template <
typename T>
705 template <
typename T,
typename U>
718 template <
typename T>
729 template <
int rank,
int dim,
typename Number>
739 template <
int rank,
int dim,
typename Number>
752 template <
typename Number>
777 template <
typename T>
790 template <
typename T,
typename U>
803 template <
typename T>
828 template <
typename T>
841 template <
typename T,
typename U>
854 template <
typename T>
883 template <
typename T>
901 template <
typename T,
typename U>
914 template <
typename T>
1031 std::vector<MinMaxAvg>
1188 template <
typename T>
1189 std::map<unsigned int, T>
1191 const std::map<unsigned int, T> &objects_to_send);
1206 template <
typename T>
1207 [[nodiscard]] std::vector<T>
1225 template <
typename T>
1226 [[nodiscard]] std::vector<T>
1228 const T &object_to_send,
1229 const unsigned int root_process = 0);
1245 template <
typename T>
1248 const std::vector<T> &objects_to_send,
1249 const unsigned int root_process = 0);
1289 template <
typename T>
1292 const T &object_to_send,
1293 const unsigned int root_process = 0);
1311 template <
typename T>
1314 const std::size_t count,
1315 const unsigned int root,
1330 template <
typename T>
1334 const std::function<T(
const T &,
const T &)> &combiner,
1335 const unsigned int root_process = 0);
1349 template <
typename T,
typename = std::enable_if_t<is_mpi_type<T> == true>>
1350 [[nodiscard]] std::pair<T, T>
1363 template <
typename T>
1367 const std::function<T(
const T &,
const T &)> &combiner);
1390 template <
typename T>
1394 const unsigned int target_rank,
1395 const unsigned int mpi_tag = 0);
1414 template <
typename T>
1417 const unsigned int source_rank,
1418 const unsigned int mpi_tag = 0);
1464 std::vector<unsigned int>
1466 const IndexSet &indices_to_look_up,
1479 std::pair<std::vector<unsigned int>, std::map<unsigned int, IndexSet>>
1481 const IndexSet &indices_to_look_up,
1491 template <
typename T>
1498 template <
typename T>
1515#ifdef DEAL_II_WITH_MPI
1519 return MPI_CXX_BOOL;
1535 return MPI_SIGNED_CHAR;
1575 return MPI_LONG_LONG;
1583 return MPI_UNSIGNED_CHAR;
1591 return MPI_UNSIGNED_SHORT;
1599 return MPI_UNSIGNED;
1607 return MPI_UNSIGNED_LONG;
1615 return MPI_UNSIGNED_LONG_LONG;
1639 return MPI_LONG_DOUBLE;
1655 return MPI_DOUBLE_COMPLEX;
1663#ifdef DEAL_II_WITH_MPI
1681 template <
typename T>
1684 static_cast<std::remove_cv_t<std::remove_reference_t<T>
> *>(
nullptr));
1691 template <
typename T>
1700 template <
typename T>
1701 template <
typename W,
typename G>
1711 template <
typename T>
1712 Future<T>::~Future()
1722 if ((get_was_called ==
false) && get_and_cleanup_function)
1728 template <
typename T>
1732 if (is_done ==
false)
1741 template <
typename T>
1745 Assert(get_was_called ==
false,
1747 "You can't call get() more than once on a Future object."));
1748 get_was_called =
true;
1751 return get_and_cleanup_function();
1756 template <
typename T,
unsigned int N>
1758 sum(
const T (&values)[N],
const MPI_Comm mpi_communicator, T (&sums)[N])
1760 internal::all_reduce(MPI_SUM,
1761 ArrayView<const T>(values, N),
1763 ArrayView<T>(sums, N));
1768 template <
typename T,
unsigned int N>
1770 max(
const T (&values)[N],
const MPI_Comm mpi_communicator, T (&maxima)[N])
1772 internal::all_reduce(MPI_MAX,
1773 ArrayView<const T>(values, N),
1775 ArrayView<T>(maxima, N));
1780 template <
typename T,
unsigned int N>
1782 min(
const T (&values)[N],
const MPI_Comm mpi_communicator, T (&minima)[N])
1784 internal::all_reduce(MPI_MIN,
1785 ArrayView<const T>(values, N),
1787 ArrayView<T>(minima, N));
1792 template <
typename T,
unsigned int N>
1795 const MPI_Comm mpi_communicator,
1798 static_assert(std::is_integral_v<T>,
1799 "The MPI_LOR operation only allows integral data types.");
1801 internal::all_reduce(MPI_LOR,
1802 ArrayView<const T>(values, N),
1804 ArrayView<T>(results, N));
1810 logical_and(
const bool t,
const MPI_Comm mpi_communicator)
1812 bool return_value =
false;
1813 internal::all_reduce(MPI_LAND,
1814 ArrayView<const bool>(&t, 1),
1816 ArrayView<bool>(&return_value, 1));
1817 return return_value;
1822 template <
typename T>
1823 std::map<unsigned int, T>
1825 const std::map<unsigned int, T> &objects_to_send)
1827# ifndef DEAL_II_WITH_MPI
1829 Assert(objects_to_send.size() < 2,
1830 ExcMessage(
"Cannot send to more than one processor."));
1831 Assert(objects_to_send.find(0) != objects_to_send.end() ||
1832 objects_to_send.empty(),
1833 ExcMessage(
"Can only send to myself or to nobody."));
1834 return objects_to_send;
1838 std::map<unsigned int, T> received_objects;
1840 std::vector<unsigned int> send_to;
1841 send_to.reserve(objects_to_send.size());
1842 for (
const auto &m : objects_to_send)
1843 if (m.first == my_proc)
1844 received_objects[my_proc] = m.second;
1846 send_to.emplace_back(m.first);
1848 const unsigned int n_expected_incoming_messages =
1852 static CollectiveMutex mutex;
1853 CollectiveMutex::ScopedLock lock(mutex,
comm);
1859 if (send_to.empty() && n_expected_incoming_messages == 0)
1860 return received_objects;
1863 internal::Tags::compute_point_to_point_communication_pattern;
1866 std::vector<std::vector<char>> buffers_to_send(send_to.size());
1867 std::vector<MPI_Request> buffer_send_requests(send_to.size());
1870 for (
const auto &rank_obj : objects_to_send)
1871 if (rank_obj.first != my_proc)
1873 const auto &rank = rank_obj.first;
1874 buffers_to_send[i] =
1876 const int ierr = MPI_Isend(buffers_to_send[i].data(),
1877 buffers_to_send[i].size(),
1882 &buffer_send_requests[i]);
1890 std::vector<char> buffer;
1892 for (
unsigned int i = 0; i < n_expected_incoming_messages; ++i)
1896 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag,
comm, &status);
1901 ierr = MPI_Get_count(&status, MPI_CHAR, &len);
1906 const unsigned int rank = status.MPI_SOURCE;
1909 ierr = MPI_Recv(buffer.data(),
1917 Assert(received_objects.find(rank) == received_objects.end(),
1919 "I should not receive again from this rank"));
1920 received_objects[rank] =
1926 const int ierr = MPI_Waitall(send_to.size(),
1927 buffer_send_requests.data(),
1928 MPI_STATUSES_IGNORE);
1931 return received_objects;
1937 template <
typename T,
typename>
1941# ifndef DEAL_II_WITH_MPI
1968 return {prefix,
sum};
1975 template <
typename T>
1982# ifndef DEAL_II_WITH_MPI
1984 std::vector<T> v(1,
object);
1991 int n_local_data = buffer.size();
1994 std::vector<int> size_all_data(n_procs, 0);
1997 int ierr = MPI_Allgather(
1998 &n_local_data, 1, MPI_INT, size_all_data.data(), 1, MPI_INT,
comm);
2003 std::vector<int> rdispls(n_procs);
2005 for (
unsigned int i = 1; i < n_procs; ++i)
2006 rdispls[i] = rdispls[i - 1] + size_all_data[i - 1];
2009 std::vector<char> received_unrolled_buffer(rdispls.back() +
2010 size_all_data.back());
2012 ierr = MPI_Allgatherv(buffer.data(),
2015 received_unrolled_buffer.data(),
2016 size_all_data.data(),
2022 std::vector<T> received_objects(n_procs);
2023 for (
unsigned int i = 0; i < n_procs; ++i)
2025 std::vector<char> local_buffer(received_unrolled_buffer.begin() +
2027 received_unrolled_buffer.begin() +
2028 rdispls[i] + size_all_data[i]);
2029 received_objects[i] =
2033 return received_objects;
2039 template <
typename T>
2042 const T &object_to_send,
2043 const unsigned int root_process)
2045# ifndef DEAL_II_WITH_MPI
2048 std::vector<T> v(1, object_to_send);
2056 std::vector<char> buffer =
2058 int n_local_data = buffer.size();
2062 std::vector<int> size_all_data;
2063 if (my_rank == root_process)
2064 size_all_data.resize(n_procs, 0);
2067 int ierr = MPI_Gather(&n_local_data,
2070 size_all_data.data(),
2079 std::vector<int> rdispls;
2080 if (my_rank == root_process)
2082 rdispls.resize(n_procs, 0);
2083 for (
unsigned int i = 1; i < n_procs; ++i)
2084 rdispls[i] = rdispls[i - 1] + size_all_data[i - 1];
2087 std::vector<char> received_unrolled_buffer;
2088 if (my_rank == root_process)
2089 received_unrolled_buffer.resize(rdispls.back() + size_all_data.back());
2091 ierr = MPI_Gatherv(buffer.data(),
2094 received_unrolled_buffer.data(),
2095 size_all_data.data(),
2102 std::vector<T> received_objects;
2104 if (my_rank == root_process)
2106 received_objects.resize(n_procs);
2108 for (
unsigned int i = 0; i < n_procs; ++i)
2110 received_unrolled_buffer.cbegin() + rdispls[i],
2111 received_unrolled_buffer.cbegin() + rdispls[i] + size_all_data[i],
2114 return received_objects;
2120 template <
typename T>
2123 const std::vector<T> &objects_to_send,
2124 const unsigned int root_process)
2126# ifndef DEAL_II_WITH_MPI
2132 return objects_to_send[0];
2139 (my_rank != root_process && objects_to_send.empty()) ||
2140 objects_to_send.size() == n_procs,
2142 "The number of objects to be scattered must correspond to the number processes."));
2144 std::vector<char> send_buffer;
2145 std::vector<int> send_counts;
2146 std::vector<int> send_displacements;
2148 if (my_rank == root_process)
2150 send_counts.resize(n_procs, 0);
2151 send_displacements.resize(n_procs + 1, 0);
2153 for (
unsigned int i = 0; i < n_procs; ++i)
2155 const auto packed_data =
2157 send_buffer.insert(send_buffer.end(),
2158 packed_data.begin(),
2160 send_counts[i] = packed_data.size();
2163 for (
unsigned int i = 0; i < n_procs; ++i)
2164 send_displacements[i + 1] = send_displacements[i] + send_counts[i];
2168 int ierr = MPI_Scatter(send_counts.data(),
2178 std::vector<char> recv_buffer(n_local_data);
2180 ierr = MPI_Scatterv(send_buffer.data(),
2182 send_displacements.data(),
2196 template <
typename T>
2199 const std::size_t count,
2200 const unsigned int root,
2201 const MPI_Comm
comm)
2203 static_assert(is_mpi_type<T>,
2204 "This function is currently only implemented for "
2205 "MPI-supported data types.");
2207# ifndef DEAL_II_WITH_MPI
2218 const size_t max_send_count = std::numeric_limits<signed int>::max();
2220 size_t total_sent_count = 0;
2221 while (total_sent_count < count)
2223 const size_t current_count =
2224 std::min(count - total_sent_count, max_send_count);
2226 const int ierr = MPI_Bcast(buffer + total_sent_count,
2228 mpi_type_id_for_type<
decltype(*buffer)>,
2232 total_sent_count += current_count;
2239 template <
typename T>
2242 const T &object_to_send,
2243 const unsigned int root_process)
2245# ifndef DEAL_II_WITH_MPI
2248 return object_to_send;
2254 if constexpr (is_mpi_type<T>)
2256 T object = object_to_send;
2258 MPI_Bcast(&
object, 1, mpi_type_id_for_type<T>, root_process,
comm);
2265 std::vector<char> buffer;
2273 buffer_size = buffer.size();
2277 int ierr = MPI_Bcast(&buffer_size,
2279 mpi_type_id_for_type<
decltype(buffer_size)>,
2287 buffer.resize(buffer_size);
2292 return object_to_send;
2301 template <
typename T>
2303 isend(
const T &
object,
2304 MPI_Comm communicator,
2305 const unsigned int target_rank,
2306 const unsigned int mpi_tag)
2308# ifndef DEAL_II_WITH_MPI
2314 return Future<void>([]() {}, []() {});
2329 std::shared_ptr<std::vector<char>> send_buffer =
2330 std::make_unique<std::vector<char>>(
2335 MPI_Request request;
2337 MPI_Isend(send_buffer->data(),
2338 send_buffer->size(),
2339 mpi_type_id_for_type<
decltype(*send_buffer->data())>,
2359 auto wait = [request]()
mutable {
2360 const int ierr = MPI_Wait(&request, MPI_STATUS_IGNORE);
2363 auto cleanup = [send_buffer = std::move(send_buffer)]() {
2364 send_buffer->clear();
2366 return Future<void>(wait, cleanup);
2372 template <
typename T>
2374 irecv(MPI_Comm communicator,
2375 const unsigned int source_rank,
2376 const unsigned int mpi_tag)
2378# ifndef DEAL_II_WITH_MPI
2383 return Future<void>([]() {}, []() {
return T{}; });
2399 std::shared_ptr<MPI_Message> message = std::make_shared<MPI_Message>();
2400 std::shared_ptr<MPI_Status> status = std::make_shared<MPI_Status>();
2402 auto wait = [source_rank, mpi_tag, communicator, message, status]() {
2403 const int ierr = MPI_Mprobe(
2404 source_rank, mpi_tag, communicator, message.get(), status.get());
2410 auto get = [status, message]() {
2413 ierr = MPI_Get_count(status.get(), MPI_CHAR, &number_amount);
2416 std::vector<char> receive_buffer(number_amount);
2420 ierr = MPI_Mrecv(receive_buffer.data(),
2422 mpi_type_id_for_type<
decltype(*receive_buffer.data())>,
2431 return Future<T>(wait, get);
2437# ifdef DEAL_II_WITH_MPI
2438 template <
class Iterator,
typename Number>
2439 std::pair<Number, typename numbers::NumberTraits<Number>::real_type>
2442 const MPI_Comm
comm)
2457 std::for_each(
begin,
end, [&mean, &sq_sum](
const Number &v) {
2461 return std::make_pair(mean,
2462 std::sqrt(sq_sum /
static_cast<Std
>(size - 1)));
* x_component_mask set(0, true)
InitFinalize(int &argc, char **&argv, const InitializeLibrary &libraries, const unsigned int max_num_threads=numbers::invalid_unsigned_int)
void sum(const SparseMatrix< Number > &local, const MPI_Comm mpi_communicator, SparseMatrix< Number > &global)
friend class SparseMatrix
constexpr SymmetricTensor()=default
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 lock(const MPI_Comm comm)
void unlock(const MPI_Comm comm)
DuplicatedCommunicator(const DuplicatedCommunicator &)=delete
~DuplicatedCommunicator()
MPI_Comm operator*() const
DuplicatedCommunicator & operator=(const DuplicatedCommunicator &)=delete
DuplicatedCommunicator(const MPI_Comm communicator)
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)
MPI_InitFinalize(int &argc, char **&argv, const unsigned int max_num_threads=numbers::invalid_unsigned_int)
~MPI_InitFinalize()=default
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
#define DEAL_II_NAMESPACE_CLOSE
#define DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
static ::ExceptionBase & ExcNeedsMPI()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertThrowMPI(error_code)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDivideByZero()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
const bool IsBlockVector< VectorType >::value
* * * RotationFunction< dim, Number >::RotationFunction Number(dim)
MPI_Datatype mpi_type_id(const bool *)
std::vector< IndexSet > create_ascending_partitioning(const MPI_Comm comm, const types::global_dof_index locally_owned_size)
std::pair< std::vector< unsigned int >, std::map< unsigned int, IndexSet > > compute_index_owner_and_requesters(const IndexSet &owned_indices, const IndexSet &indices_to_look_up, const MPI_Comm &comm)
std::pair< T, T > partial_and_total_sum(const T &value, const MPI_Comm comm)
T sum(const T &t, const MPI_Comm mpi_communicator)
bool logical_and(const bool t, const MPI_Comm mpi_communicator)
T logical_or(const T &t, const MPI_Comm mpi_communicator)
std::unique_ptr< MPI_Datatype, void(*)(MPI_Datatype *)> create_mpi_data_type_n_bytes(const std::size_t n_bytes)
Future< T > irecv(MPI_Comm communicator, const unsigned int source_rank, const unsigned int mpi_tag=0)
std::map< unsigned int, T > some_to_some(const MPI_Comm comm, const std::map< unsigned int, T > &objects_to_send)
std::pair< Number, typename numbers::NumberTraits< Number >::real_type > mean_and_standard_deviation(const Iterator begin, const Iterator end, const MPI_Comm comm)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
T max(const T &t, const MPI_Comm mpi_communicator)
T min(const T &t, const MPI_Comm mpi_communicator)
std::vector< T > all_gather(const MPI_Comm comm, const T &object_to_send)
std::vector< unsigned int > compute_index_owner(const IndexSet &owned_indices, const IndexSet &indices_to_look_up, const MPI_Comm comm)
std::vector< T > compute_set_union(const std::vector< T > &vec, const MPI_Comm comm)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
T all_reduce(const T &local_value, const MPI_Comm comm, const std::function< T(const T &, const T &)> &combiner)
IndexSet create_evenly_distributed_partitioning(const MPI_Comm comm, const types::global_dof_index total_size)
std::vector< unsigned int > compute_point_to_point_communication_pattern(const MPI_Comm mpi_comm, const std::vector< unsigned int > &destinations)
MPI_Comm duplicate_communicator(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)
const MPI_Datatype mpi_type_id_for_type
void free_communicator(MPI_Comm mpi_communicator)
std::vector< unsigned int > mpi_processes_within_communicator(const MPI_Comm comm_large, const MPI_Comm comm_small)
unsigned int compute_n_point_to_point_communications(const MPI_Comm mpi_comm, const std::vector< unsigned int > &destinations)
std::vector< T > gather(const MPI_Comm comm, const T &object_to_send, const unsigned int root_process=0)
MinMaxAvg min_max_avg(const double my_value, const MPI_Comm mpi_communicator)
constexpr bool is_mpi_type
T scatter(const MPI_Comm comm, const std::vector< T > &objects_to_send, const unsigned int root_process=0)
Future< void > isend(const T &object, MPI_Comm communicator, const unsigned int target_rank, const unsigned int mpi_tag=0)
T broadcast(const MPI_Comm comm, const T &object_to_send, const unsigned int root_process=0)
std::size_t pack(const T &object, std::vector< char > &dest_buffer, const bool allow_compression=true)
T unpack(const std::vector< char > &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)
constexpr types::global_dof_index invalid_size_type
constexpr unsigned int invalid_unsigned_int
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
unsigned int global_dof_index
*braid_SplitCommworld & comm
static constexpr real_type abs_square(const number &x)
void gather(VectorizedArray< Number, width > &out, const std::array< const Number *, width > &ptrs, const unsigned int offset)