in MPI/Intracommunicator.cs [1949:2015]
public void ScatterFromFlattened<T>(T[] inValues, int[] counts, int root, ref T[] outValues)
{
if (counts.Length != Size)
throw new ArgumentException($"counts.Length ({counts.Length}) != Communicator.Size ({Size})");
MPI_Datatype datatype = FastDatatypeCache<T>.datatype;
if (datatype == Unsafe.MPI_DATATYPE_NULL)
{
if (Rank == root)
{
T[][] tempIn = new T[Size][];
int inLocation = 0;
for (int i = 0; i < Size; i++) checked
{
tempIn[i] = new T[counts[i]];
Array.Copy(inValues, inLocation, tempIn[i], 0, counts[i]);
inLocation += counts[i];
}
outValues = Scatter<T[]>(tempIn);
}
else
outValues = Scatter<T[]>(root);
}
else
{
if (outValues == null || outValues.Length != counts[Rank])
outValues = new T[counts[Rank]];
if (Rank == root)
{
int[] displs = new int[counts.Length];
displs[0] = 0;
for (int i = 1; i < counts.Length; i++) checked
{
displs[i] = displs[i - 1] + counts[i - 1];
}
int lastIndex = counts.Length - 1;
int totalCount = checked(displs[lastIndex] + counts[lastIndex]);
if (totalCount > inValues.Length)
{
throw new ArgumentException($"Sum of counts ({totalCount}) > inValues.Length ({inValues.Length})");
}
// Pin the array while we are scattering it.
GCHandle inHandle = GCHandle.Alloc(inValues, GCHandleType.Pinned);
GCHandle outHandle = GCHandle.Alloc(outValues, GCHandleType.Pinned);
int errorCode = Unsafe.MPI_Scatterv(inHandle.AddrOfPinnedObject(), counts, displs, datatype,
outHandle.AddrOfPinnedObject(), counts[Rank], datatype, root, comm);
inHandle.Free();
outHandle.Free();
if (errorCode != Unsafe.MPI_SUCCESS)
throw Environment.TranslateErrorIntoException(errorCode);
}
else
{
// Pin the array while we are scattering it.
GCHandle outHandle = GCHandle.Alloc(outValues, GCHandleType.Pinned);
int errorCode = Unsafe.MPI_Scatterv(new IntPtr(0), counts, new int[0], datatype,
outHandle.AddrOfPinnedObject(), counts[Rank], datatype, root, comm);
outHandle.Free();
if (errorCode != Unsafe.MPI_SUCCESS)
throw Environment.TranslateErrorIntoException(errorCode);
}
}
}