KaMPIng 0.1.1
Flexible and (near) zero-overhead C++ bindings for MPI
Loading...
Searching...
No Matches
alltoall.hpp
1// This file is part of KaMPIng.
2//
3// Copyright 2022-2024 The KaMPIng Authors
4//
5// KaMPIng is free software : you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
7// version. KaMPIng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
9// for more details.
10//
11// You should have received a copy of the GNU Lesser General Public License along with KaMPIng. If not, see
12// <https://www.gnu.org/licenses/>.
13
14#pragma once
15
16#include <cstddef>
17#include <numeric>
18#include <tuple>
19#include <type_traits>
20
21#include <kassert/kassert.hpp>
22#include <mpi.h>
23
24#include "kamping/assertion_levels.hpp"
26#include "kamping/collectives/barrier.hpp"
27#include "kamping/collectives/collectives_helpers.hpp"
28#include "kamping/collectives/ibarrier.hpp"
29#include "kamping/comm_helper/is_same_on_all_ranks.hpp"
30#include "kamping/communicator.hpp"
35#include "kamping/p2p/iprobe.hpp"
36#include "kamping/p2p/isend.hpp"
37#include "kamping/p2p/recv.hpp"
38#include "kamping/request_pool.hpp"
39#include "kamping/result.hpp"
40
41/// @addtogroup kamping_collectives
42/// @{
43
44/// @brief Wrapper for \c MPI_Alltoall.
45///
46/// This wrapper for \c MPI_Alltoall sends the same amount of data from each rank to each rank. The following
47/// buffers are required:
48/// - \ref kamping::send_buf() containing the data that is sent to each rank. This buffer has to be the same size at
49/// each rank and divisible by the size of the communicator unless a send_count or a send_type is explicitly given as
50/// parameter. Each rank receives the same number of elements from this buffer.
51///
52/// The following parameters are optional:
53/// - \ref kamping::send_count() specifying how many elements are sent. If
54/// omitted, the size of send buffer divided by communicator size is used.
55/// This parameter is mandatory if \ref kamping::send_type() is given.
56///
57/// - \ref kamping::recv_count() specifying how many elements are received. If
58/// omitted, the value of send_counts will be used.
59/// This parameter is mandatory if \ref kamping::recv_type() is given.
60///
61/// - \ref kamping::recv_buf() specifying a buffer for the output. A buffer of at least
62/// `recv_count * communicator size` is required.
63///
64/// - \ref kamping::send_type() specifying the \c MPI datatype to use as send type. If omitted, the \c MPI datatype is
65/// derived automatically based on send_buf's underlying \c value_type.
66///
67/// - \ref kamping::recv_type() specifying the \c MPI datatype to use as recv type. If omitted, the \c MPI datatype is
68/// derived automatically based on recv_buf's underlying \c value_type.
69///
70/// Inplace alltoall is supported by passing send_recv_buf as parameter. This changes the requirements for the other
71/// parameters, see \ref Communicator::alltoall_inplace.
72///
73/// @tparam Args Automatically deduced template parameters.
74/// @param args All required and any number of the optional buffers described above.
75/// @return Result type wrapping the output parameters to be returned by value.
76///
77/// @see \ref docs/parameter_handling.md for general information about parameter handling in KaMPIng.
78/// <hr>
79/// \include{doc} docs/resize_policy.dox
80template <
81 template <typename...>
82 typename DefaultContainerType,
83 template <typename, template <typename...> typename>
84 typename... Plugins>
85template <typename... Args>
87 using namespace internal;
89 if constexpr (inplace) {
90 return this->alltoall_inplace(std::forward<Args>(args)...);
91 } else {
93 Args,
96 );
97
98 // Get the buffers
99 auto const&& send_buf =
100 internal::select_parameter_type<internal::ParameterType::send_buf>(args...).construct_buffer_or_rebind();
101 using send_value_type = typename std::remove_reference_t<decltype(send_buf)>::value_type;
102 using default_recv_value_type = std::remove_const_t<send_value_type>;
103
106 auto&& recv_buf =
107 internal::select_parameter_type_or_default<internal::ParameterType::recv_buf, default_recv_buf_type>(
108 std::tuple(),
109 args...
110 )
112 using recv_value_type = typename std::remove_reference_t<decltype(recv_buf)>::value_type;
113
114 static_assert(!std::is_const_v<recv_value_type>, "The receive buffer must not have a const value_type.");
115
116 auto&& [send_type, recv_type] =
117 internal::determine_mpi_datatypes<send_value_type, recv_value_type, decltype(recv_buf)>(args...);
118 [[maybe_unused]] constexpr bool recv_type_has_to_be_deduced = has_to_be_computed<decltype(recv_type)>;
119
120 // Get the send counts
122 auto&& send_count =
123 internal::select_parameter_type_or_default<internal::ParameterType::send_count, default_send_count_type>(
124 std::tuple(),
125 args...
126 )
127 .construct_buffer_or_rebind();
129 if constexpr (do_compute_send_count) {
130 send_count.underlying() = asserting_cast<int>(send_buf.size() / size());
131 }
132 // Get the recv counts
134 auto&& recv_count =
135 internal::select_parameter_type_or_default<internal::ParameterType::recv_count, default_recv_count_type>(
136 std::tuple(),
137 args...
138 )
139 .construct_buffer_or_rebind();
140
142 if constexpr (do_compute_recv_count) {
143 recv_count.underlying() = send_count.get_single_element();
144 }
145
146 KASSERT(
147 (!do_compute_send_count || send_buf.size() % size() == 0lu),
148 "There are no send counts given and the number of elements in send_buf is not divisible by the number of "
149 "ranks "
150 "in the communicator.",
152 );
153
154 auto compute_required_recv_buf_size = [&]() {
155 return asserting_cast<size_t>(recv_count.get_single_element()) * size();
156 };
157 recv_buf.resize_if_requested(compute_required_recv_buf_size);
158 KASSERT(
159 // if the recv type is user provided, kamping cannot make any assumptions about the required size of the
160 // recv buffer
162 "Recv buffer is not large enough to hold all received elements.",
164 );
165
166 // These KASSERTs are required to avoid a false warning from g++ in release mode
167 KASSERT(send_buf.data() != nullptr, assert::light);
168 KASSERT(recv_buf.data() != nullptr, assert::light);
169
170 [[maybe_unused]] int err = MPI_Alltoall(
171 send_buf.data(), // send_buf
172 send_count.get_single_element(), // send_count
173 send_type.get_single_element(), // send_type
174 recv_buf.data(), // recv_buf
175 recv_count.get_single_element(), // recv_count
176 recv_type.get_single_element(), // recv_type
177 mpi_communicator() // comm
178 );
179
180 this->mpi_error_hook(err, "MPI_Alltoall");
181 return make_mpi_result<std::tuple<Args...>>(
182 std::move(recv_buf), // recv_buf
183 std::move(send_count), // send_count
184 std::move(recv_count), // recv_count
185 std::move(send_type), // send_type
186 std::move(recv_type) // recv_type
187 );
188 }
189}
190
191/// @brief Wrapper for the in-place version of \ref Communicator::alltoall.
192///
193/// This variant must be called collectively by all ranks in the communicator. It sends the same amount of data from
194/// each rank to each rank, using the same buffer for sending and receiving data.
195///
196/// The following parameteres are required:
197///
198/// - \ref kamping::send_recv_buf() containing the data that is sent to each rank and received from each rank. The size
199/// of this buffer has to be the same at each rank and divisible by the size of the communicator unless a
200/// send_recv_count or a send_recv_type is explicitly given as parameter. Each rank receives the same number of elements
201/// from this buffer.
202///
203/// The following parameters are optional:
204///
205/// - \ref kamping::send_recv_count() specifying how many elements are sent and received. If
206/// omitted, the size of send_recv_buf divided by communicator size is used.
207/// This parameter is mandatory if \ref kamping::send_recv_type() is given.
208/// -
209/// \ref kamping::send_recv_type() specifying the \c MPI datatype to use as send and recv type. If omitted, the \c MPI
210/// datatype is derived automatically based on send_recv_buf's underlying \c value_type.
211///
212/// @tparam Args Automatically deduced template parameters.
213/// @param args All required and any number of the optional buffers described above.
214/// @return Result type wrapping the output parameters to be returned by value.
215///
216/// @see \ref docs/parameter_handling.md for general information about parameter handling in KaMPIng.
217/// <hr>
218/// \include{doc} docs/resize_policy.dox
219template <
220 template <typename...>
221 typename DefaultContainerType,
222 template <typename, template <typename...> typename>
223 typename... Plugins>
224template <typename... Args>
226 using namespace internal;
228 Args,
231 );
232
233 auto&& send_recv_buf =
234 internal::select_parameter_type<internal::ParameterType::send_recv_buf>(args...).construct_buffer_or_rebind();
235 using send_recv_value_type = typename std::remove_reference_t<decltype(send_recv_buf)>::value_type;
236 auto&& send_recv_type =
237 internal::determine_mpi_send_recv_datatype<send_recv_value_type, decltype(send_recv_buf)>(args...);
238 [[maybe_unused]] constexpr bool send_recv_type_has_to_be_deduced = has_to_be_computed<decltype(send_recv_type)>;
239
240 // Get the optional recv_count parameter. If the parameter is not given, allocate a new container.
242 auto&& count_param = internal::select_parameter_type_or_default<ParameterType::send_recv_count, default_count_type>(
243 std::tuple(),
244 args...
245 )
246 .construct_buffer_or_rebind();
247 constexpr bool count_has_to_be_computed = has_to_be_computed<decltype(count_param)>;
248
249 KASSERT(
250 (!count_has_to_be_computed || send_recv_buf.size() % size() == 0lu),
251 "There is no send_recv_count given and the number of elements in send_recv_buf is not divisible by the number "
252 "of "
253 "ranks "
254 "in the communicator.",
256 );
257
258 if constexpr (count_has_to_be_computed) {
259 count_param.underlying() = asserting_cast<int>(send_recv_buf.size() / size());
260 }
261 auto compute_required_recv_buf_size = [&]() {
262 return asserting_cast<size_t>(count_param.get_single_element()) * size();
263 };
265 KASSERT(
266 // if the type is user provided, kamping cannot make any assumptions about the required size of the
267 // buffer
269 "send_recv_buf is not large enough to hold all received elements.",
271 );
272 int err = MPI_Alltoall(
273 MPI_IN_PLACE, // send_buf
274 0, // send_count (ignored)
275 MPI_DATATYPE_NULL, // send_type (ignored)
276 send_recv_buf.data(), // recv_buf
277 count_param.get_single_element(), // recv_count
278 send_recv_type.get_single_element(), // recv_type
279 mpi_communicator() // comm
280 );
281 this->mpi_error_hook(err, "MPI_Alltoall");
282
283 return make_mpi_result<std::tuple<Args...>>(
284 std::move(send_recv_buf),
285 std::move(count_param),
286 std::move(send_recv_type)
287 );
288}
289
290/// @brief Wrapper for \c MPI_Alltoallv.
291///
292/// This wrapper for \c MPI_Alltoallv sends the different amounts of data from each rank to each rank. The following
293/// buffers are required:
294/// - \ref kamping::send_buf() containing the data that is sent to each rank. The size of this buffer has to be at least
295/// the sum of the send_counts argument.
296///
297/// - \ref kamping::send_counts() containing the number of elements to send to each rank.
298///
299/// The following parameters are optional but result in communication overhead if omitted:
300/// - \ref kamping::recv_counts() containing the number of elements to receive from each rank.
301/// This parameter is mandatory if \ref kamping::recv_type() is given.
302///
303/// The following buffers are optional:
304/// - \ref kamping::recv_buf() specifying a buffer for the output. Afterwards, this buffer will contain
305/// the data received as specified for send_buf. A buffer size of at least `max(recv_counts[i] +
306/// recv_displs[i])` for \c i in `[0, communicator size)` elements is required.
307///
308/// - \ref kamping::send_displs() containing the offsets of the messages in send_buf. The `send_counts[i]` elements
309/// starting at `send_buf[send_displs[i]]` will be sent to rank `i`. If omitted, this is calculated as the exclusive
310/// prefix-sum of `send_counts`.
311///
312/// - \ref kamping::recv_displs() containing the offsets of the messages in recv_buf. The `recv_counts[i]` elements
313/// starting at `recv_buf[recv_displs[i]]` will be received from rank `i`. If omitted, this is calculated as the
314/// exclusive prefix-sum of `recv_counts`.
315///
316/// - \ref kamping::send_type() specifying the \c MPI datatype to use as send type. If omitted, the \c MPI datatype is
317/// derived automatically based on send_buf's underlying \c value_type.
318///
319/// - \ref kamping::recv_type() specifying the \c MPI datatype to use as recv type. If omitted, the \c MPI datatype is
320/// derived automatically based on recv_buf's underlying \c value_type.
321///
322/// @tparam Args Automatically deduced template parameters.
323/// @param args All required and any number of the optional buffers described above.
324/// @return Result object wrapping the output parameters to be returned by value.
325///
326/// @see \ref docs/parameter_handling.md for general information about parameter handling in KaMPIng.
327/// <hr>
328/// \include{doc} docs/resize_policy.dox
329template <
330 template <typename...>
331 typename DefaultContainerType,
332 template <typename, template <typename...> typename>
333 typename... Plugins>
334template <typename... Args>
336 // Get all parameter objects
338 Args,
341 );
342
343 // Get send_buf
344 auto const& send_buf =
345 internal::select_parameter_type<internal::ParameterType::send_buf>(args...).construct_buffer_or_rebind();
346 using send_value_type = typename std::remove_reference_t<decltype(send_buf)>::value_type;
347 using default_recv_value_type = std::remove_const_t<send_value_type>;
348
349 // Get recv_buf
351 auto&& recv_buf =
352 internal::select_parameter_type_or_default<internal::ParameterType::recv_buf, default_recv_buf_type>(
353 std::tuple(),
354 args...
355 )
357 using recv_value_type = typename std::remove_reference_t<decltype(recv_buf)>::value_type;
358
359 // Get send/recv types
360 auto&& [send_type, recv_type] =
361 internal::determine_mpi_datatypes<send_value_type, recv_value_type, decltype(recv_buf)>(args...);
364
365 // Get send_counts
366 auto const& send_counts = internal::select_parameter_type<internal::ParameterType::send_counts>(args...)
368 using send_counts_type = typename std::remove_reference_t<decltype(send_counts)>::value_type;
369 static_assert(std::is_same_v<std::remove_const_t<send_counts_type>, int>, "Send counts must be of type int");
370 static_assert(
372 "Send counts must be given as an input parameter"
373 );
374 KASSERT(send_counts.size() >= this->size(), "Send counts buffer is not large enough.", assert::light);
375
376 // Get recv_counts
378 auto&& recv_counts =
379 internal::select_parameter_type_or_default<internal::ParameterType::recv_counts, default_recv_counts_type>(
380 std::tuple(),
381 args...
382 )
384 using recv_counts_type = typename std::remove_reference_t<decltype(recv_counts)>::value_type;
385 static_assert(std::is_same_v<std::remove_const_t<recv_counts_type>, int>, "Recv counts must be of type int");
386
387 // Get send_displs
389 auto&& send_displs =
390 internal::select_parameter_type_or_default<internal::ParameterType::send_displs, default_send_displs_type>(
391 std::tuple(),
392 args...
393 )
395 using send_displs_type = typename std::remove_reference_t<decltype(send_displs)>::value_type;
396 static_assert(std::is_same_v<std::remove_const_t<send_displs_type>, int>, "Send displs must be of type int");
397
398 // Get recv_displs
400 auto&& recv_displs =
401 internal::select_parameter_type_or_default<internal::ParameterType::recv_displs, default_recv_displs_type>(
402 std::tuple(),
403 args...
404 )
406 using recv_displs_type = typename std::remove_reference_t<decltype(recv_displs)>::value_type;
407 static_assert(std::is_same_v<std::remove_const_t<recv_displs_type>, int>, "Recv displs must be of type int");
408
409 static_assert(!std::is_const_v<recv_value_type>, "The receive buffer must not have a const value_type.");
410
411 // Calculate recv_counts if necessary
413 KASSERT(
414 is_same_on_all_ranks(do_calculate_recv_counts),
415 "Receive counts are given on some ranks and have to be computed on others",
417 );
418 if constexpr (do_calculate_recv_counts) {
419 /// @todo make it possible to test whether this additional communication is skipped
420 recv_counts.resize_if_requested([&]() { return this->size(); });
421 KASSERT(recv_counts.size() >= this->size(), "Recv counts buffer is not large enough.", assert::light);
422 this->alltoall(kamping::send_buf(send_counts.get()), kamping::recv_buf(recv_counts.get()));
423 } else {
424 KASSERT(recv_counts.size() >= this->size(), "Recv counts buffer is not large enough.", assert::light);
425 }
426
427 // Calculate send_displs if necessary
429 KASSERT(
430 is_same_on_all_ranks(do_calculate_send_displs),
431 "Send displacements are given on some ranks and have to be computed on others",
433 );
434
435 if constexpr (do_calculate_send_displs) {
436 send_displs.resize_if_requested([&]() { return this->size(); });
437 KASSERT(send_displs.size() >= this->size(), "Send displs buffer is not large enough.", assert::light);
438 std::exclusive_scan(send_counts.data(), send_counts.data() + this->size(), send_displs.data(), 0);
439 } else {
440 KASSERT(send_displs.size() >= this->size(), "Send displs buffer is not large enough.", assert::light);
441 }
442
443 // Check that send displs and send counts are large enough
444 KASSERT(
445 // if the send type is user provided, kamping cannot make any assumptions about the size of the send
446 // buffer
448 || *(send_counts.data() + this->size() - 1) + // Last element of send_counts
449 *(send_displs.data() + this->size() - 1) // Last element of send_displs
450 <= asserting_cast<int>(send_buf.size()),
452 );
453
454 // Calculate recv_displs if necessary
456 KASSERT(
457 is_same_on_all_ranks(do_calculate_recv_displs),
458 "Receive displacements are given on some ranks and have to be computed on others",
460 );
461 if constexpr (do_calculate_recv_displs) {
462 recv_displs.resize_if_requested([&]() { return this->size(); });
463 KASSERT(recv_displs.size() >= this->size(), "Recv displs buffer is not large enough.", assert::light);
464 std::exclusive_scan(recv_counts.data(), recv_counts.data() + this->size(), recv_displs.data(), 0);
465 } else {
466 KASSERT(recv_displs.size() >= this->size(), "Recv displs buffer is not large enough.", assert::light);
467 }
468
469 auto compute_required_recv_buf_size = [&]() {
470 return compute_required_recv_buf_size_in_vectorized_communication(recv_counts, recv_displs, this->size());
471 };
472
473 recv_buf.resize_if_requested(compute_required_recv_buf_size);
474 KASSERT(
475 // if the recv type is user provided, kamping cannot make any assumptions about the required size of the recv
476 // buffer
478 "Recv buffer is not large enough to hold all received elements.",
480 );
481
482 // Do the actual alltoallv
484 send_buf.data(), // send_buf
485 send_counts.data(), // send_counts
486 send_displs.data(), // send_displs
487 send_type.get_single_element(), // send_type
488 recv_buf.data(), // send_counts
489 recv_counts.data(), // recv_counts
490 recv_displs.data(), // recv_displs
491 recv_type.get_single_element(), // recv_type
492 mpi_communicator() // comm
493 );
494
495 this->mpi_error_hook(err, "MPI_Alltoallv");
496
497 return internal::make_mpi_result<std::tuple<Args...>>(
498 std::move(recv_buf), // recv_buf
499 std::move(recv_counts), // recv_counts
500 std::move(recv_displs), // recv_displs
501 std::move(send_displs), // send_displs
502 std::move(send_type), // send_type
503 std::move(recv_type) // recv_type
504 );
505}
506/// @}
Helper functions that make casts safer.
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
T value_type
The value type.
Definition allocator.hpp:53
constexpr int light
Assertion level for lightweight assertions.
Definition assertion_levels.hpp:13
constexpr int light_communication
Assertions that perform lightweight communication.
Definition assertion_levels.hpp:25
auto alltoall(Args... args) const
Wrapper for MPI_Alltoall.
Definition alltoall.hpp:86
auto alltoall_inplace(Args... args) const
Wrapper for the in-place version of Communicator::alltoall.
Definition alltoall.hpp:225
auto alltoallv(Args... args) const
Wrapper for MPI_Alltoallv.
Definition alltoall.hpp:335
static constexpr auto alloc_new
Convenience wrapper for creating library allocated containers. See AllocNewT for details.
Definition data_buffer.hpp:194
auto send_count(int count)
Passes count as send count to the underlying call.
Definition named_parameters.hpp:321
auto recv_counts(Container &&container)
Passes a container as recv counts to the underlying call, i.e. the container's storage must contain t...
Definition named_parameters.hpp:366
auto send_type(MPI_Datatype send_type)
Passes send_type as send type to the underlying call.
Definition named_parameters.hpp:1195
auto recv_buf(Container &&container)
Passes a container, into which the received elements will be written, to the underlying call....
Definition named_parameters.hpp:859
auto send_buf(internal::ignore_t< Data > ignore)
Generates a dummy send buf that wraps a nullptr.
Definition named_parameters.hpp:51
auto send_count_out()
Indicates to deduce the send count and return it to the caller as part of the underlying call's resul...
Definition named_parameters.hpp:347
auto send_recv_buf(Data &&data)
Passes a container/single value as a send or receive buffer to the underlying MPI call.
Definition named_parameters.hpp:137
auto recv_counts_out()
Indicates to construct a container with type kamping::Communicator::default_container_type<int>,...
Definition named_parameters.hpp:478
auto recv_displs_out()
Indicates to construct a container with type kamping::Communicator::default_container_type<int>,...
Definition named_parameters.hpp:802
auto send_counts(Container &&container)
Passes a container as send counts to the underlying call, i.e. the container's storage must contain t...
Definition named_parameters.hpp:203
auto send_recv_count(int count)
Passes count as send/recv count to the underlying call.
Definition named_parameters.hpp:529
auto recv_displs(Container &&container)
Passes a container as receive displacements to the underlying call, i.e. the container's storage must...
Definition named_parameters.hpp:697
auto recv_count(int count)
Passes count as recv count to the underlying call.
Definition named_parameters.hpp:490
auto send_displs_out()
Indicates to construct a container with type kamping::Communicator::default_container_type<int>,...
Definition named_parameters.hpp:679
auto recv_type(MPI_Datatype recv_type)
Passes recv_type as recv type to the underlying call.
Definition named_parameters.hpp:1238
auto send_displs(Container &&container)
Passes a container as send displacements to the underlying call, i.e. the container's storage must co...
Definition named_parameters.hpp:574
auto send_recv_type(MPI_Datatype send_recv_type)
Passes send_recv_type as send/recv type to the underlying call. (This parameter is in MPI routines su...
Definition named_parameters.hpp:1282
auto recv_count_out()
Indicates to deduce the recv count and return it to the caller as part of the underlying call's resul...
Definition named_parameters.hpp:516
auto send_recv_count_out()
Indicates to deduce the send/recv count and return it to the caller as part of the underlying call's ...
Definition named_parameters.hpp:555
constexpr bool has_parameter_type()
Checks if parameter with requested parameter type exists.
Definition named_parameter_selection.hpp:186
Utility that maps C++ types to types that can be understood by MPI.
Template magic to check named parameters passed to wrappers at compile time.
#define KAMPING_REQUIRED_PARAMETERS(...)
Wrapper to pass (possibly empty) list of parameter type names as required parameters to KAMPING_CHECK...
Definition named_parameter_check.hpp:52
#define KAMPING_OPTIONAL_PARAMETERS(...)
Wrapper to pass (possibly empty) list of parameter type names as optional parameters to KAMPING_CHECK...
Definition named_parameter_check.hpp:58
#define KAMPING_CHECK_PARAMETERS(args, required, optional)
Assertion macro that checks if passed parameters are correct, i.e., all parameter types are unique,...
Definition named_parameter_check.hpp:80
Template magic to implement named parameters in cpp.
Factory methods for buffer wrappers.
auto make_mpi_result(Buffers &&... buffers)
Construct result object for a wrapped MPI call. Four different cases are handled: a) The recv_buffer ...
Definition result.hpp:1017
static constexpr bool has_to_be_computed
Checks if the buffer has to be computed by kamping, i.e. if it is an output parameter or the buffer h...
Definition named_parameter_check.hpp:398
Some functions and types simplifying/enabling the development of wrapped MPI calls in KaMPIng.