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);
}
}
}
}