86. Examples

PreviousUpNext
Up: Derived Datatypes Next: Pack and Unpack Previous: Decoding a Datatype

The following examples illustrate the use of derived datatypes.


Example Send and receive a section of a 3D array.


      REAL a(100,100,100), e(9,9,9) 
      INTEGER oneslice, twoslice, threeslice, myrank, ierr 
      INTEGER (KIND=MPI_ADDRESS_KIND) lb, sizeofreal 
      INTEGER status(MPI_STATUS_SIZE) 
 
C     extract the section a(1:17:2, 3:11, 2:10) 
C     and store it in e(:,:,:). 
 
      CALL MPI_COMM_RANK(MPI_COMM_WORLD, myrank, ierr) 
 
      CALL MPI_TYPE_GET_EXTENT(MPI_REAL, lb, sizeofreal, ierr) 
 
C     create datatype for a 1D section 
      CALL MPI_TYPE_VECTOR(9, 1, 2, MPI_REAL, oneslice, ierr) 
 
C     create datatype for a 2D section 
      CALL MPI_TYPE_CREATE_HVECTOR(9, 1, 100*sizeofreal, oneslice,  
                                   twoslice, ierr) 
 
C     create datatype for the entire section 
      CALL MPI_TYPE_CREATE_HVECTOR(9, 1, 100*100*sizeofreal, twoslice, 
                                   threeslice, ierr) 
 
      CALL MPI_TYPE_COMMIT(threeslice, ierr) 
      CALL MPI_SENDRECV(a(1,3,2), 1, threeslice, myrank, 0, e, 9*9*9, 
                        MPI_REAL, myrank, 0, MPI_COMM_WORLD, status, ierr) 


Example Copy the (strictly) lower triangular part of a matrix.

      REAL a(100,100), b(100,100) 
      INTEGER  disp(100), blocklen(100), ltype, myrank, ierr 
      INTEGER status(MPI_STATUS_SIZE) 
 
C     copy lower triangular part of array a 
C     onto lower triangular part of array b 
 
      CALL MPI_COMM_RANK(MPI_COMM_WORLD, myrank, ierr) 
 
C     compute start and size of each column 
      DO i=1, 100 
        disp(i) = 100*(i-1) + i 
        blocklen(i) = 100-i 
      END DO 
 
C     create datatype for lower triangular part 
      CALL MPI_TYPE_INDEXED(100, blocklen, disp, MPI_REAL, ltype, ierr) 
 
      CALL MPI_TYPE_COMMIT(ltype, ierr) 
      CALL MPI_SENDRECV(a, 1, ltype, myrank, 0, b, 1, 
                        ltype, myrank, 0, MPI_COMM_WORLD, status, ierr) 


Example Transpose a matrix.


      REAL a(100,100), b(100,100) 
      INTEGER row, xpose, myrank, ierr 
      INTEGER (KIND=MPI_ADDRESS_KIND) lb, sizeofreal 
      INTEGER status(MPI_STATUS_SIZE) 
 
C     transpose matrix a onto b 
 
      CALL MPI_COMM_RANK(MPI_COMM_WORLD, myrank, ierr) 
 
      CALL MPI_TYPE_GET_EXTENT(MPI_REAL, lb, sizeofreal, ierr) 
 
C     create datatype for one row 
      CALL MPI_TYPE_VECTOR(100, 1, 100, MPI_REAL, row, ierr) 
 
C     create datatype for matrix in row-major order 
      CALL MPI_TYPE_CREATE_HVECTOR(100, 1, sizeofreal, row, xpose, ierr) 
 
      CALL MPI_TYPE_COMMIT(xpose, ierr) 
 
C     send matrix in row-major order and receive in column major order 
      CALL MPI_SENDRECV(a, 1, xpose, myrank, 0, b, 100*100, 
                        MPI_REAL, myrank, 0, MPI_COMM_WORLD, status, ierr) 


Example Another approach to the transpose problem:

      REAL a(100,100), b(100,100) 
      INTEGER row, row1 
      INTEGER (KIND=MPI_ADDRESS_KIND) disp(2), lb, sizeofreal 
      INTEGER myrank, ierr 
      INTEGER status(MPI_STATUS_SIZE) 
 
      CALL MPI_COMM_RANK(MPI_COMM_WORLD, myrank, ierr) 
 
C     transpose matrix a onto b 
 
      CALL MPI_TYPE_GET_EXTENT(MPI_REAL, lb, sizeofreal, ierr) 
 
C     create datatype for one row 
      CALL MPI_TYPE_VECTOR(100, 1, 100, MPI_REAL, row, ierr) 
 
C     create datatype for one row, with the extent of one real number 
      lb = 0 
      CALL MPI_TYPE_CREATE_RESIZED(row, lb, sizeofreal, row1, ierr) 
 
      CALL MPI_TYPE_COMMIT(row1, ierr) 
 
C     send 100 rows and receive in column major order 
      CALL MPI_SENDRECV(a, 100, row1, myrank, 0, b, 100*100, 
                        MPI_REAL, myrank, 0, MPI_COMM_WORLD, status, ierr) 


Example We manipulate an array of structures.


struct Partstruct 
{ 
   int    type;  /* particle type */ 
   double d[6];   /* particle coordinates */ 
   char   b[7];   /* some additional information */ 
}; 
 
struct Partstruct    particle[1000]; 
 
int          i, dest, tag; 
MPI_Comm     comm; 
 
 
/* build datatype describing structure */ 
 
MPI_Datatype Particlestruct, Particletype; 
MPI_Datatype type[3] = {MPI_INT, MPI_DOUBLE, MPI_CHAR}; 
int          blocklen[3] = {1, 6, 7}; 
MPI_Aint     disp[3]; 
MPI_Aint     base, lb, sizeofentry; 
 
 
/* compute displacements of structure components */ 
 
MPI_Get_address(particle, disp); 
MPI_Get_address(particle[0].d, disp+1); 
MPI_Get_address(particle[0].b, disp+2); 
base = disp[0]; 
for (i=0; i < 3; i++) disp[i] = MPI_Aint_diff(disp[i], base); 
 
MPI_Type_create_struct(3, blocklen, disp, type, &Particlestruct); 
 
   /* If compiler does padding in mysterious ways, 
   the following may be safer */ 
 
/* compute extent of the structure */ 
 
MPI_Get_address(particle+1, &sizeofentry); 
sizeofentry = MPI_Aint_diff(sizeofentry, base); 
 
/* build datatype describing structure */ 
 
MPI_Type_create_resized(Particlestruct, 0, sizeofentry, &Particletype); 
 
 
              /* 4.1: 
        send the entire array */ 
 
MPI_Type_commit(&Particletype); 
MPI_Send(particle, 1000, Particletype, dest, tag, comm); 
 
 
              /* 4.2: 
        send only the entries of type zero particles, 
        preceded by the number of such entries */ 
 
MPI_Datatype Zparticles;   /* datatype describing all particles 
                              with type zero (needs to be recomputed 
                              if types change) */ 
MPI_Datatype Ztype; 
 
int          zdisp[1000]; 
int          zblock[1000], j, k; 
int          zzblock[2] = {1,1}; 
MPI_Aint     zzdisp[2]; 
MPI_Datatype zztype[2]; 
 
/* compute displacements of type zero particles */ 
j = 0; 
for (i=0; i < 1000; i++) 
   if (particle[i].type == 0) 
      { 
        zdisp[j] = i; 
        zblock[j] = 1; 
        j++; 
      } 
 
/* create datatype for type zero particles  */ 
MPI_Type_indexed(j, zblock, zdisp, Particletype, &Zparticles); 
 
/* prepend particle count */ 
MPI_Get_address(&j, zzdisp); 
MPI_Get_address(particle, zzdisp+1); 
zztype[0] = MPI_INT; 
zztype[1] = Zparticles; 
MPI_Type_create_struct(2, zzblock, zzdisp, zztype, &Ztype); 
 
MPI_Type_commit(&Ztype); 
MPI_Send(MPI_BOTTOM, 1, Ztype, dest, tag, comm); 
 
 
       /* A probably more efficient way of defining Zparticles */ 
 
/* consecutive particles with index zero are handled as one block */ 
j=0; 
for (i=0; i < 1000; i++) 
   if (particle[i].type == 0) 
      { 
         for (k=i+1; (k < 1000)&&(particle[k].type == 0); k++); 
         zdisp[j] = i; 
         zblock[j] = k-i; 
         j++; 
         i = k; 
      } 
MPI_Type_indexed(j, zblock, zdisp, Particletype, &Zparticles); 
 
 
                /* 4.3: 
          send the first two coordinates of all entries */ 
 
MPI_Datatype Allpairs;      /* datatype for all pairs of coordinates */ 
 
MPI_Type_get_extent(Particletype, &lb, &sizeofentry); 
 
     /* sizeofentry can also be computed by subtracting the address 
        of particle[0] from the address of particle[1] */ 
 
MPI_Type_create_hvector(1000, 2, sizeofentry, MPI_DOUBLE, &Allpairs); 
MPI_Type_commit(&Allpairs); 
MPI_Send(particle[0].d, 1, Allpairs, dest, tag, comm); 
 
      /* an alternative solution to 4.3 */ 
 
MPI_Datatype Twodouble; 
 
MPI_Type_contiguous(2, MPI_DOUBLE, &Twodouble); 
 
MPI_Datatype Onepair;   /* datatype for one pair of coordinates, with 
                          the extent of one particle entry */ 
 
MPI_Type_create_resized(Twodouble, 0, sizeofentry, &Onepair ); 
MPI_Type_commit(&Onepair); 
MPI_Send(particle[0].d, 1000, Onepair, dest, tag, comm); 
 


Example The same manipulations as in the previous example, but use absolute addresses in datatypes.


struct Partstruct 
{ 
    int    type; 
    double d[6]; 
    char   b[7]; 
}; 
 
struct Partstruct particle[1000]; 
 
           /* build datatype describing first array entry */ 
 
MPI_Datatype Particletype; 
MPI_Datatype type[3] = {MPI_INT, MPI_DOUBLE, MPI_CHAR}; 
int          block[3] = {1, 6, 7}; 
MPI_Aint     disp[3]; 
 
MPI_Get_address(particle, disp); 
MPI_Get_address(particle[0].d, disp+1); 
MPI_Get_address(particle[0].b, disp+2); 
MPI_Type_create_struct(3, block, disp, type, &Particletype); 
 
/* Particletype describes first array entry -- using absolute 
   addresses */ 
 
                  /* 5.1: 
            send the entire array */ 
 
MPI_Type_commit(&Particletype); 
MPI_Send(MPI_BOTTOM, 1000, Particletype, dest, tag, comm); 
 
 
                 /* 5.2: 
         send the entries of type zero, 
         preceded by the number of such entries */ 
 
MPI_Datatype Zparticles, Ztype; 
 
int          zdisp[1000]; 
int          zblock[1000], i, j, k; 
int          zzblock[2] = {1,1}; 
MPI_Datatype zztype[2]; 
MPI_Aint     zzdisp[2]; 
 
j=0; 
for (i=0; i < 1000; i++) 
    if (particle[i].type == 0) 
        { 
            for (k=i+1; (k < 1000)&&(particle[k].type == 0); k++); 
            zdisp[j] = i; 
            zblock[j] = k-i; 
            j++; 
            i = k; 
        } 
MPI_Type_indexed(j, zblock, zdisp, Particletype, &Zparticles); 
/* Zparticles describe particles with type zero, using 
   their absolute addresses*/ 
 
/* prepend particle count */ 
MPI_Get_address(&j, zzdisp); 
zzdisp[1] = (MPI_Aint)0; 
zztype[0] = MPI_INT; 
zztype[1] = Zparticles; 
MPI_Type_create_struct(2, zzblock, zzdisp, zztype, &Ztype); 
 
MPI_Type_commit(&Ztype); 
MPI_Send(MPI_BOTTOM, 1, Ztype, dest, tag, comm); 
 


Example Handling of unions.


union { 
   int     ival; 
   float   fval; 
      } u[1000]; 
 
int     utype; 
 
/* All entries of u have identical type; variable 
   utype keeps track of their current type */ 
 
MPI_Datatype   mpi_utype[2]; 
MPI_Aint       i, extent; 
 
/* compute an MPI datatype for each possible union type; 
   assume values are left-aligned in union storage. */ 
 
MPI_Get_address(u, &i); 
MPI_Get_address(u+1, &extent); 
extent = MPI_Aint_diff(extent, i); 
 
MPI_Type_create_resized(MPI_INT, 0, extent, &mpi_utype[0]); 
 
MPI_Type_create_resized(MPI_FLOAT, 0, extent, &mpi_utype[1]); 
 
for(i=0; i<2; i++) MPI_Type_commit(&mpi_utype[i]); 
 
/* actual communication */ 
 
MPI_Send(u, 1000, mpi_utype[utype], dest, tag, comm); 


Example This example shows how a datatype can be decoded. The routine printdatatype prints out the elements of the datatype. Note the use of MPI_Type_free for datatypes that are not predefined.

/* 
  Example of decoding a datatype.  
 
  Returns 0 if the datatype is predefined, 1 otherwise 
 */ 
#include <stdio.h> 
#include <stdlib.h> 
#include "mpi.h" 
int printdatatype(MPI_Datatype datatype)  
{ 
    int *array_of_ints; 
    MPI_Aint *array_of_adds; 
    MPI_Datatype *array_of_dtypes; 
    int num_ints, num_adds, num_dtypes, combiner; 
    int i; 
 
    MPI_Type_get_envelope(datatype,  
                          &num_ints, &num_adds, &num_dtypes, &combiner); 
    switch (combiner) { 
    case MPI_COMBINER_NAMED: 
        printf("Datatype is named:"); 
        /* To print the specific type, we can match against the 
           predefined forms. We can NOT use a switch statement here  
           We could also use MPI_TYPE_GET_NAME if we prefered to use 
           names that the user may have changed. 
         */ 
        if      (datatype == MPI_INT)    printf( "MPI_INT\n" ); 
        else if (datatype == MPI_DOUBLE) printf( "MPI_DOUBLE\n" ); 
        ... else test for other types ... 
        return 0; 
        break; 
    case MPI_COMBINER_STRUCT: 
    case MPI_COMBINER_STRUCT_INTEGER: 
        printf("Datatype is struct containing"); 
        array_of_ints   = (int *)malloc(num_ints * sizeof(int)); 
        array_of_adds   =  
                   (MPI_Aint *) malloc(num_adds * sizeof(MPI_Aint)); 
        array_of_dtypes = (MPI_Datatype *) 
            malloc(num_dtypes * sizeof(MPI_Datatype)); 
        MPI_Type_get_contents(datatype, num_ints, num_adds, num_dtypes, 
                           array_of_ints, array_of_adds, array_of_dtypes); 
        printf(" %d datatypes:\n", array_of_ints[0]); 
        for (i=0; i<array_of_ints[0]; i++) { 
            printf("blocklength %d, displacement %ld, type:\n",  
                    array_of_ints[i+1], (long)array_of_adds[i]); 
            if (printdatatype(array_of_dtypes[i])) { 
                /* Note that we free the type ONLY if it  
                   is not predefined */ 
                MPI_Type_free(&array_of_dtypes[i]); 
            } 
        } 
        free(array_of_ints); 
        free(array_of_adds); 
        free(array_of_dtypes); 
        break; 
        ... other combiner values ... 
    default: 
        printf("Unrecognized combiner type\n"); 
    } 
    return 1; 
} 


PreviousUpNext
Up: Derived Datatypes Next: Pack and Unpack Previous: Decoding a Datatype


Return to MPI-3.1 Standard Index
Return to MPI Forum Home Page

(Unofficial) MPI-3.1 of June 4, 2015
HTML Generated on June 4, 2015