public void Alltoall()

in MPI/Intercommunicator.cs [653:730]


        public void Alltoall<T>(T[] inValues, ref T[] outValues)
        {
            // Make sure the outgoing array is the right size
            if (outValues == null || outValues.Length != inValues.Length)
                outValues = new T[inValues.Length];

            MPI_Datatype datatype = FastDatatypeCache<T>.datatype;
            if (datatype == Unsafe.MPI_DATATYPE_NULL)
            {
                // There is no associated MPI datatype for this type, so we will
                // need to serialize the value for transmission.
                int[] sendCounts = new int[RemoteSize];
                int[] sendOffsets = new int[RemoteSize];

                using (UnmanagedMemoryStream sendStream = new UnmanagedMemoryStream())
                {
                    // Serialize all of the outgoing data to the outgoing stream
                    for (int dest = 0; dest < RemoteSize; ++dest)
                    {
                        sendOffsets[dest] = Convert.ToInt32(sendStream.Length);
                        Serialize(sendStream, inValues[dest]);
                        sendCounts[dest] = checked(Convert.ToInt32(sendStream.Length) - sendOffsets[dest]);
                    }

                    // Use all-to-all on integers to tell every process how much data
                    // it will be receiving.
                    int[] recvCounts = Alltoall(sendCounts);

                    // Compute the offsets at which each of the streams will be received
                    int[] recvOffsets = new int[RemoteSize];
                    recvOffsets[0] = 0;
                    for (int i = 1; i < RemoteSize; ++i) checked
                    {
                        recvOffsets[i] = recvOffsets[i - 1] + recvCounts[i - 1];
                    }

                    // Total length of the receive buffer
                    int recvLength = checked(recvOffsets[RemoteSize - 1] + recvCounts[RemoteSize - 1]);

                    using (UnmanagedMemoryStream recvStream = new UnmanagedMemoryStream(recvLength))
                    {
                        // Build receive buffer and exchange all of the data
                        unsafe
                        {
                            int errorCode = Unsafe.MPI_Alltoallv(sendStream.Buffer, sendCounts, sendOffsets, Unsafe.MPI_BYTE,
                                                                 recvStream.Buffer, recvCounts, recvOffsets, Unsafe.MPI_BYTE, comm);
                            if (errorCode != Unsafe.MPI_SUCCESS)
                                throw Environment.TranslateErrorIntoException(errorCode);
                        }

                        // De-serialize the received data
                        for (int source = 0; source < RemoteSize; ++source)
                        {
                            // Seek to the proper location in the stream and de-serialize
                            recvStream.Position = recvOffsets[source];
                            outValues[source] = Deserialize<T>(recvStream);
                            
                        }
                    }
                }
            }
            else
            {
                GCHandle inHandle = GCHandle.Alloc(inValues, GCHandleType.Pinned);
                GCHandle outHandle = GCHandle.Alloc(outValues, GCHandleType.Pinned);
                int errorCode;
                unsafe
                {
                    errorCode = Unsafe.MPI_Alltoall(Marshal.UnsafeAddrOfPinnedArrayElement(inValues, 0), 1, datatype,
                                                    Marshal.UnsafeAddrOfPinnedArrayElement(outValues, 0), 1, datatype, comm);
                }
                inHandle.Free();
                outHandle.Free();

                if (errorCode != Unsafe.MPI_SUCCESS)
                    throw Environment.TranslateErrorIntoException(errorCode);
            }
        }