Hi,
This question follows my false bug report at
In short, I am trying to specify a custom-MPI-datatype for a custom-MPI-operator. The custom-MPI-datatype is defined as follows
---------------------------------------------------------------------
def mpi_custom_datatype(char_code):
""" User-defined data type for MPI. """
cc = char_code.split(',')
for _ in cc:
assert _[0] in 'iuf'
np_dtype = np.dtype(char_code) # NumPy structured datatype
nbytes = [np.dtype(_).itemsize for _ in cc]
nbytes = np.hstack(([0], np.add.accumulate(nbytes)[:-1]))
mpi_dtype = MPI.Datatype.Create_struct(
list(range(len(cc))), # block lengths for fields of struct
nbytes, # displacements/offsets in bytes for fields of struct
[MPI.LONG_LONG, MPI.DOUBLE]) # hard-coded for simplicity
extent = np.zeros(1, dtype=np_dtype).nbytes
if mpi_dtype.extent != extent:
mpi_dtype = mpi_dtype.Create_resized(0, extent)
mpi_dtype.Commit()
return np_dtype, mpi_dtype
---------------------------------------------------------------------
To use the custom datatype on the lower case reduce is straightforward, as the following example (a1, a2 are np.ndarray)
---------------------------------------------------------------------
def find_min(a1, a2, datatype):
""" Custom MPI operator to get the one with the smaller 2nd term. """
if a1[0][1] > a2[0][1]:
return a2
else:
return a1
rank = comm.rank
RS = np.random.RandomState(rank)
char_code = 'i8,f8'
np_dtype, mpi_dtype = mpi_custom_datatype(char_code)
a = array([(RS.randint(0,int(1e12)), RS.random())], dtype=np_dtype)
print(rank, a)
FIND_MIN = MPI.Op.Create(find_min, commute=True)
amin = comm.reduce(a, op=FIND_MIN, root=0)
if rank == 0:
print(amin)
---------------------------------------------------------------------
which gives the following (correct) outputs, where the one with the smallest 2nd item is returned by the lower case reduce function.
---------------------------------------------------------------------
1 [(163196666091, 0.72032449)]
2 [(722349427215, 0.02592623)]
3 [(455570294424, 0.70814782)]
0 [(741280623151, 0.71518937)]
[(722349427215, 0.02592623)]
---------------------------------------------------------------------
However, I am not sure how to use the custom-MPI-operator with the upper case Reduce function. Here is my testing code (a1, a2 are MPI.memory objects)
---------------------------------------------------------------------
def find_min(a1, a2, datatype):
""" Custom MPI operator to get the one with the smaller 2nd term.
"""
dim = (1,) # Hard-coded
a1p = to_ndarray(a1, datatype, dim)
a2p = to_ndarray(a2, datatype, dim)
if a1p[0][1] < a2p[0][1]:
a2p[0][0] = a1p[0][0]
a2p[0][1] = a1p[0][1]
def to_ndarray(a:MPI.memory, dtype:type, dim:Tuple[int,...]):
""" Convert a mpi4py.MPI.memory object to a numpy ndarray. """
buf = np.array(a, dtype='B', copy=False)
return np.ndarray(buffer=buf, dtype=dtype, shape=dim)
---------------------------------------------------------------------
It raises the following error message
"return np.ndarray(buffer=buf, dtype=dtype, shape=dim)
TypeError: data type not understood"
The error persists if I specifically provide the custom-MPI-operator to the function definition:
def find_min(a1, a2, datatype=mpi_dtype)
It will be much appreciated if the problem can be solved. Thank you.