public void Reduce()

in MPI/Intercommunicator.cs [1195:1286]


        public void Reduce<T>(T[] inValues, ReductionOperation<T> op, int root, ref T[] outValues)
        {
            MPI_Datatype datatype = FastDatatypeCache<T>.datatype;
            if (root != Root)
            {
                if (datatype == Unsafe.MPI_DATATYPE_NULL)
                {
                    if (inValues == null)
                        inValues = new T[0];

                    // Gather values at the root
                    Gather(inValues, root);
                }
                else
                {
                    // Use the low-level MPI reduction operation from a non-root
                    using (Operation<T> mpiOp = new Operation<T>(op))
                    {
                        int errorCode;
                        if (inValues != null)
                        {
                            GCHandle handle = GCHandle.Alloc(inValues, GCHandleType.Pinned);
                            unsafe
                            {
                                errorCode = Unsafe.MPI_Reduce(Marshal.UnsafeAddrOfPinnedArrayElement(inValues, 0), new IntPtr(0),
                                                  inValues.Length, datatype, mpiOp.Op, root, comm);
                            }
                            handle.Free();
                        }
                        else
                        {
                            // For some reason, passing in new IntPtr(0) for both inValues and outValues did not work on Windows,
                            // so to let users continue to pass in null as they would expect, we'll use an empty array if we have to
                            inValues = new T[0];
                            GCHandle inHandle = GCHandle.Alloc(inValues, GCHandleType.Pinned);
                            unsafe
                            {
                                errorCode = Unsafe.MPI_Reduce(Marshal.UnsafeAddrOfPinnedArrayElement(inValues, 0), new IntPtr(0),
                                                  0, datatype, mpiOp.Op, root, comm);
                            }
                            inHandle.Free();
                            
                        }
                        if (errorCode != Unsafe.MPI_SUCCESS)
                            throw Environment.TranslateErrorIntoException(errorCode);
                    }
                }
            }
            else
            {
                if (outValues == null || outValues.Length == 0)
                    throw new ArgumentException("outValues array must be preallocated at the root", "outValues");

                // Make sure the resulting array is long enough
                //if (outValues == null || outValues.Length != inValues.Length)
                //    outValues = new T[inValues.Length];

                if (datatype == Unsafe.MPI_DATATYPE_NULL)
                {
                    // Gather into a temporary array
                    T[][] values = new T[RemoteSize][];
                    Gather(inValues, root, ref values);

                    // Perform reduction locally
                    for (int i = 0; i < outValues.Length; ++i)
                    {
                        outValues[i] = values[0][i];
                        for (int p = 1; p < RemoteSize; ++p)
                            outValues[i] = op(outValues[i], values[p][i]);
                    }
                }
                else
                {
                    // Use the low-level MPI reduction operation from the root
                    using (Operation<T> mpiOp = new Operation<T>(op))
                    {
                        GCHandle outHandle = GCHandle.Alloc(outValues, GCHandleType.Pinned);
                        int errorCode;
                        unsafe
                        {
                            errorCode = Unsafe.MPI_Reduce(new IntPtr(0),
                                                          Marshal.UnsafeAddrOfPinnedArrayElement(outValues, 0),
                                                          outValues.Length, datatype, mpiOp.Op, root, comm);
                        }
                        outHandle.Free();

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