/*
** MPI_Type_create_struct example
** Copyright Rolf Riesen 2008
**
*/
#include <stdio.h>
#include <stdlib.h>     /* For malloc() */
#include <string.h>     /* For memset() */
#include <mpi.h>


#define ELTS            (3) /* # elemtns in data structure */

typedef struct   {
    double value;
    char id;
    int neighbors[6];
} ex_struct_t;



int
main(int argc, char *argv[])
{

int my_rank, nproc;
int blocklengths[ELTS];
MPI_Datatype types[ELTS];
MPI_Aint displacements[ELTS];

int size;
MPI_Aint lb, extent;

MPI_Datatype mpi_struct_t;
ex_struct_t ex_struct;

long long int addr_struct;
long long int addr_struct_value;
long long int addr_struct_id;
long long int addr_struct_neighbors;

MPI_Aint mpi_addr_struct;
MPI_Aint mpi_addr_struct_value;
MPI_Aint mpi_addr_struct_id;
MPI_Aint mpi_addr_struct_neighbors;



    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);


    /* Print some information about the example struct */
    printf("Information about C data structure:\n");
    printf("Size of C struct:               %ld\n", (long)sizeof(ex_struct));
    printf("Element              Address          Offset\n");

    addr_struct= (long long int)&ex_struct;
    addr_struct_value= (long long int)&(ex_struct.value);
    addr_struct_id= (long long int)&(ex_struct.id);
    addr_struct_neighbors= (long long int)&(ex_struct.neighbors[5]);

    printf("ex_struct            0x%08llx   %lld\n",
            addr_struct, addr_struct - addr_struct);
    printf("ex_struct.value      0x%08llx   %lld\n",
            addr_struct_value, addr_struct_value - addr_struct);
    printf("ex_struct.id         0x%08llx   %lld\n",
            addr_struct_id, addr_struct_id - addr_struct);
    printf("ex_struct.neighbors  0x%08llx   %lld\n",
            addr_struct_neighbors, addr_struct_neighbors - addr_struct);
    printf("\n");

    

    /* Print MPI address information */
    MPI_Get_address(&ex_struct, &mpi_addr_struct);
    MPI_Get_address(&ex_struct.value, &mpi_addr_struct_value);
    MPI_Get_address(&ex_struct.id, &mpi_addr_struct_id);
    MPI_Get_address(&ex_struct.neighbors, &mpi_addr_struct_neighbors);

    printf("Information about MPI addresses:\n");
    printf("ex_struct            0x%08llx   %lld\n",
            (long long int)mpi_addr_struct,
            (long long int)mpi_addr_struct - mpi_addr_struct);
    printf("ex_struct.value      0x%08llx   %lld\n",
            (long long int)mpi_addr_struct_value,
            (long long int)mpi_addr_struct_value - mpi_addr_struct);
    printf("ex_struct.id         0x%08llx   %lld\n",
            (long long int)mpi_addr_struct_id,
            (long long int)mpi_addr_struct_id - mpi_addr_struct);
    printf("ex_struct.neighbors  0x%08llx   %lld\n",
            (long long int)mpi_addr_struct_neighbors,
            (long long int)mpi_addr_struct_neighbors - mpi_addr_struct);



    /* Create a data type describing a row of our array */
    types[0]= MPI_DOUBLE;
    types[1]= MPI_CHAR;
    types[2]= MPI_INT;

    blocklengths[0]= 1;         /* 1 double */
    blocklengths[1]= 1;         /* 1 char */
    blocklengths[2]= 6;         /* 6 ints */

    displacements[0]= 0;
    displacements[1]= mpi_addr_struct_id - mpi_addr_struct;
    displacements[2]= mpi_addr_struct_neighbors - mpi_addr_struct;

    MPI_Type_create_struct(ELTS, blocklengths, displacements,
            types, &mpi_struct_t);



    /* Print some info about the type we created */
    MPI_Type_get_extent(mpi_struct_t, &lb, &extent);
    MPI_Type_size(mpi_struct_t, &size);


    printf("Type           LB   Extent   Size\n");
    printf("-------------+----+--------+-----\n");
    printf("mpi_struct_t   %2lld     %3lld    %3d\n",
	    (long long)lb, (long long)extent, size);


    MPI_Finalize();
    return 0;

}  /* end of main() */
