MPI_NEIGHBOR_ALLTOALLW_INIT(3)

πŸ“¦
version 5.0.10 Β· 4 versions
, in ubuntu stonking

πŸ’– MPI_NEIGHBOR_ALLTOALLW_INIT πŸ’–

okay bestie, gather round β€” this is the Open MPI manual page for MPI_NEIGHBOR_ALLTOALLW_INIT(3), and it's a whole family of functions, not just one. We're talking the ✨ trio ✨:

  • MPI_Neighbor_alltoallw
  • MPI_Ineighbor_alltoallw
  • MPI_Neighbor_alltoallw_init

🌸 NAME 🌸

MPI_Neighbor_alltoallw, MPI_Ineighbor_alltoallw, MPI_Neighbor_alltoallw_init β€” all processes send data of different types to, and receive data of different types from, all processes. no cap, it's giving "everyone trades custom-shaped gossip with everyone" πŸ’…


✨ SYNTAX ✨

πŸŽ€ C Syntax

#include <mpi.h>

int MPI_Neighbor_alltoallw(const void *sendbuf, const int sendcounts[],
     const MPI_Aint sdispls[], const MPI_Datatype sendtypes[],
     void *recvbuf, const int recvcounts[], const MPI_Aint rdispls[],
     const MPI_Datatype recvtypes[], MPI_Comm comm)

int MPI_Ineighbor_alltoallw(const void *sendbuf, const int sendcounts[],
     const MPI_Aint sdispls[], const MPI_Datatype sendtypes[],
     void *recvbuf, const int recvcounts[], const MPI_Aint rdispls[],
     const MPI_Datatype recvtypes[], MPI_Comm comm, MPI_Request *request)

int MPI_Neighbor_alltoallw_init(const void *sendbuf, const int sendcounts[],
     const MPI_Aint sdispls[], const MPI_Datatype sendtypes[],
     void *recvbuf, const int recvcounts[], const MPI_Aint rdispls[],
     const MPI_Datatype recvtypes[], MPI_Comm comm, MPI_Info info, MPI_Request *request)

πŸŽ€ Fortran Syntax

USE MPI
! or the older form: INCLUDE 'mpif.h'
MPI_NEIGHBOR_ALLTOALLW(SENDBUF, SENDCOUNTS, SDISPLS, SENDTYPES,
     RECVBUF, RECVCOUNTS, RDISPLS, RECVTYPES, COMM, IERROR)

     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNTS(*), SENDTYPES(*)
     INTEGER RECVCOUNTS(*), RECVTYPES(*)
     INTEGER(KIND=MPI_ADDRESS_KIND) SDISPLS(*), RDISPLS(*)
     INTEGER COMM, IERROR

MPI_INEIGHBOR_ALLTOALLW(SENDBUF, SENDCOUNTS, SDISPLS, SENDTYPES,
     RECVBUF, RECVCOUNTS, RDISPLS, RECVTYPES, COMM, REQUEST, IERROR)

     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNTS(*), SENDTYPES(*)
     INTEGER RECVCOUNTS(*), RECVTYPES(*)
     INTEGER(KIND=MPI_ADDRESS_KIND) SDISPLS(*), RDISPLS(*)
     INTEGER COMM, REQUEST, IERROR

MPI_NEIGHBOR_ALLTOALLW_INIT(SENDBUF, SENDCOUNTS, SDISPLS, SENDTYPES,
     RECVBUF, RECVCOUNTS, RDISPLS, RECVTYPES, COMM, INFO, REQUEST, IERROR)

     <type>  SENDBUF(*), RECVBUF(*)
     INTEGER SENDCOUNTS(*), SENDTYPES(*)
     INTEGER RECVCOUNTS(*), RECVTYPES(*)
     INTEGER(KIND=MPI_ADDRESS_KIND) SDISPLS(*), RDISPLS(*)
     INTEGER COMM, INFO, REQUEST, IERROR

πŸŽ€ Fortran 2008 Syntax

USE mpi_f08
MPI_Neighbor_alltoallw(sendbuf, sendcounts, sdispls, sendtypes, recvbuf,
             recvcounts, rdispls, recvtypes, comm, ierror)

     TYPE(*), DIMENSION(..), INTENT(IN) :: sendbuf
     TYPE(*), DIMENSION(..) :: recvbuf
     INTEGER, INTENT(IN) :: sendcounts(*), recvcounts(*)
     INTEGER(KIND=MPI_ADDRESS_KIND), INTENT(IN) :: sdispls(*), rdispls(*)
     TYPE(MPI_Datatype), INTENT(IN) :: sendtypes(*), recvtypes(*)
     TYPE(MPI_Comm), INTENT(IN) :: comm
     INTEGER, OPTIONAL, INTENT(OUT) :: ierror

MPI_Ineighbor_alltoallw(sendbuf, sendcounts, sdispls, sendtypes, recvbuf,
             recvcounts, rdispls, recvtypes, comm, request, ierror)

     TYPE(*), DIMENSION(..), INTENT(IN), ASYNCHRONOUS :: sendbuf
     TYPE(*), DIMENSION(..), ASYNCHRONOUS :: recvbuf
     INTEGER, INTENT(IN), ASYNCHRONOUS :: sendcounts(*), recvcounts(*)
     INTEGER(KIND=MPI_ADDRESS_KIND), INTENT(IN), ASYNCHRONOUS ::
     sdispls(*), rdispls(*)
     TYPE(MPI_Datatype), INTENT(IN), ASYNCHRONOUS :: sendtypes(*),
     recvtypes(*)
     TYPE(MPI_Comm), INTENT(IN) :: comm
     TYPE(MPI_Request), INTENT(OUT) :: request
     INTEGER, OPTIONAL, INTENT(OUT) :: ierror

MPI_Neighbor_alltoallw_init(sendbuf, sendcounts, sdispls, sendtypes, recvbuf,
             recvcounts, rdispls, recvtypes, comm, info, request, ierror)

     TYPE(*), DIMENSION(..), INTENT(IN), ASYNCHRONOUS :: sendbuf
     TYPE(*), DIMENSION(..), ASYNCHRONOUS :: recvbuf
     INTEGER, INTENT(IN), ASYNCHRONOUS :: sendcounts(*), recvcounts(*)
     INTEGER(KIND=MPI_ADDRESS_KIND), INTENT(IN), ASYNCHRONOUS ::
     sdispls(*), rdispls(*)
     TYPE(MPI_Datatype), INTENT(IN), ASYNCHRONOUS :: sendtypes(*),
     recvtypes(*)
     TYPE(MPI_Comm), INTENT(IN) :: comm
     TYPE(MPI_Info), INTENT(IN) :: info
     TYPE(MPI_Request), INTENT(OUT) :: request
     INTEGER, OPTIONAL, INTENT(OUT) :: ierror

πŸ’– INPUT PARAMETERS πŸ’–

  • sendbuf β€” starting address of the send buffer. where the goods live, bestie 🫢
  • sendcounts β€” integer array where entry i says how many elements you're sending to neighbor i.
  • sdispls β€” integer array where entry i says the displacement (in bytes, offset from sendbuf) from which to send data to neighbor i.
  • sendtypes β€” datatype array where entry i says which datatype to use when sending data to neighbor i. this is the ✨spicy✨ part β€” every neighbor can get a different type.
  • recvcounts β€” integer array where entry j says how many elements you're receiving from neighbor j.
  • rdispls β€” integer array where entry j says the displacement (in bytes, offset from recvbuf) where data from neighbor j should be written.
  • recvtypes β€” datatype array where entry j says which datatype to use when receiving data from neighbor j.
  • comm β€” the communicator over which data is to be exchanged. the group chat itself πŸ’…
  • info β€” Info (handle, persistent only).

πŸ’œ OUTPUT PARAMETERS πŸ’œ

  • recvbuf β€” address of the receive buffer.
  • request β€” Request (handle, non-blocking only).
  • ierror β€” Fortran only: error status.

🌈 DESCRIPTION 🌈

MPI_Neighbor_alltoallw is a generalized collective operation where all processes send data to and receive data from all their neighbors. it's MPI_Neighbor_alltoallv but with extra ✨le flexibility✨: you get to specify the datatype of individual data blocks, on top of displacement and element count. like, not just "how much" but "what kind of thing" too. obsessed.

you can think of it like this: each process does 2n independent point-to-point communications, where n is the number of neighbors in the topology of communicator comm. and the neighbors + buffer layout? determined by the topology of comm. slay.

MPI_Cart_get(comm, maxdims, dims, periods, coords);
for (dim = 0, i = 0 ; dim < dims ; ++dim) {
    MPI_Cart_shift(comm, dim, 1, &r0, &r1);
    MPI_Isend(sendbuf + sdispls[i]  * extent(sendtype),
              sendcount, sendtypes[i], r0, ..., comm, ...);
    MPI_Irecv(recvbuf + rdispls[i] * extent(recvtype),
              recvcount, recvtypes[i], r0, ..., comm, ...);
    ++i;
    MPI_Isend(sendbuf + sdispls[i] * extent(sendtype),
              sendcount, sendtypes[i], r1, ..., comm, &req[i]);
    MPI_Irecv(recvbuf + rdispls[i] * extent(recvtype),
              recvcount, recvtypes[i], r1, ..., comm, ...);
    ++i;
}

MPI_Wait_all (...);

MPI_Comm_size(comm, &n);
for (i = 0, i < n; i++)
  MPI_Send(sendbuf + sdispls[i], sendcounts[i],
       sendtypes[i], i, ..., comm);
for (i = 0, i < n; i++)
  MPI_Recv(recvbuf + rdispls[i], recvcounts[i],
       recvtypes[i], i, ..., comm);

process j sends the k-th block of its local sendbuf to neighbor k, which places the data in the j-th block of its local recvbuf. it's giving perfectly choreographed πŸ¦‹ coordination.

when a pair of processes exchanges data, each may pass different element count and datatype arguments β€” as long as the sender specifies the same amount of data to send (in bytes) as the receiver expects to receive. the byte counts have to match, periodt. πŸŽ€

note that process i may send a different amount of data to process j than it receives from process j. also, a process may send entirely different amounts and types of data to different processes in the communicator. it's asymmetric and it's iconic.

πŸ”₯ NOTES πŸ”₯

  • the MPI_IN_PLACE option for sendbuf is not meaningful for this operation. don't try it πŸ™ˆ
  • the specification of counts, types, and displacements should not cause any location to be written more than once. like, no double-writing, bestie, that's chaos πŸ’€
  • all arguments on all processes are significant. the comm argument, in particular, must describe the same communicator on all processes. everyone has to agree on the group chat or it's not the same group chat.
  • the offsets of sdispls and rdispls are measured in bytes. compare this to MPI_Neighbor_alltoallv, where these offsets are measured in units of sendtype and recvtype, respectively. yes, this is a trap. yes, we've all fallen in it. πŸ“

okay wait, that's only part 1 β€” there's more coming, don't go anywhere πŸ’–βœ¨

✨ ERRORS ✨

Okay bestie, story time: basically every single MPI routine hands you back an error value. In C it's the return value of the function, and in Fortran it's that pesky last argument. No escaping it, that's just the vibe. πŸ’…

But before that error value ever reaches you, something else happens first β€” the current MPI error handler attached to the communication object (think communicator, window, file, whatever) gets called. And if there's no communication object tied to the MPI call at all? Then the call gets treated as attached to MPI_COMM_SELF and it calls the handler associated with that instead. 🫢

Now, when MPI_COMM_SELF isn't initialized yet (like before MPI_Init / MPI_Init_thread, after MPI_Finalize, or if you're running the Sessions Model exclusively), the error raises the initial error handler instead. You can swap that initial error handler out by:

  • calling MPI_Comm_set_errhandler on MPI_COMM_SELF when you're using the World model, or
  • using the mpi_initial_errhandler CLI argument with mpiexec, or the info key for MPI_Comm_spawn / MPI_Comm_spawn_multiple.

And if nothing else appropriate was set? Then MPI_ERRORS_RETURN gets called for MPI I/O functions, and MPI_ERRORS_ABORT gets called for literally every other MPI function. 😭 That's just how it goes.


Three iconic predefined error handlers (Open MPI ships with these)

  • MPI_ERRORS_ARE_FATAL β€” causes the program to abort all connected MPI processes. Yep, everyone. Gone. πŸ’€
  • MPI_ERRORS_ABORT β€” an error handler you can invoke on a communicator, window, file, or session. Called on a communicator, it acts as if MPI_Abort was called on that communicator. Called on a window or file, it acts as if MPI_Abort was called on a communicator containing the group of processes in the corresponding window or file. Called on a session, it aborts only the local process.
  • MPI_ERRORS_RETURN β€” returns an error code back to the application. Polite king. πŸ‘‘

Wanna write your own error handler? Slay, you absolutely can πŸ”₯

MPI applications can implement their own by calling:

  • MPI_Comm_create_errhandler then MPI_Comm_set_errhandler
  • MPI_File_create_errhandler then MPI_File_set_errhandler
  • MPI_Session_create_errhandler then MPI_Session_set_errhandler (or at MPI_Session_init)
  • MPI_Win_create_errhandler then MPI_Win_set_errhandler
⚠️ Heads up bestie: MPI does not guarantee that an MPI program can continue past an error. Like, no promises. Plan accordingly. πŸ’€

Check the MPI man page for the full list of MPI error codes, and the Error Handling section of the MPI-3.1 standard if you want the deep lore.


πŸ‘€ See also

  • MPI_Neighbor_alltoall
  • MPI_Neighbor_alltoallv
  • MPI_Cart_create
  • MPI_Graph_create
  • MPI_Dist_graph_create

2003-2026, The Open MPI Community


And that's the whole page, bestie β€” we're done fr fr! πŸ¦‹ This was MPI_NEIGHBOR_ALLTOALLW_INIT(3), dated Sep 10, 2026, brought to you by the The Open MPI Community. Go forth and neighbor-alltoallw-init responsibly. Periodt. πŸ’–βœ¨πŸŒΈ

πŸ“¦ where this page comes from