/*
 * example for MPI-2 I/O :
 * node data (f.i. molecular dynamics application) is dumped
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>

#define   FILENAME   "OUT1"
#define   SIZE   100    /* number of particles per task */

typedef struct {
  int      id, host;
  double   xPos, yPos;
  double   m;
} Particle;


void init(Particle *p) {
  /* initialize particle array */

  int   myId;
  int   i;

  MPI_Comm_rank(MPI_COMM_WORLD, &myId);

  for (i=0; i<SIZE; i++) {
    p[i].id   = i;
    p[i].host = myId;
    p[i].xPos = 1.0 + myId;
    p[i].yPos = 42.0 * i;
    p[i].m    = 17 + 4*i - myId;
  }
}

void check(void) {
  /* master reads back particle file and checks data */

  Particle   in, test;
  FILE       *fp;
  int        myId, nTasks;
  int        i, id, host;

  MPI_Comm_size(MPI_COMM_WORLD, &nTasks);
  MPI_Comm_rank(MPI_COMM_WORLD, &myId);
  if (myId != 0) {
    return;
  }

  fp = fopen(FILENAME, "r");
  for (i=0; i<SIZE*nTasks; i++) {
    if (fread(&in, sizeof(Particle), 1, fp) != 1) {
      printf("error during file read at index i = %d\n", i);
      return;
    }
    test.id   = in.id;
    test.host = in.host;
    test.xPos = 1.0 + in.host;
    test.yPos = 42 * in.id;
    test.m    = 17 + 4*in.id - in.host;

    if ( (test.xPos != in.xPos) || (test.yPos != in.yPos) ||
	 (test.m != in.m) ) {
      printf("error in data: \n");
      printf("read     : (%d,%d,%lf,%lf,%lf)\n", 
	     in.id, in.host, in.xPos, in.yPos, in.m);
      printf("should be: (%d,%d,%lf,%lf,%lf)\n", 
	     test.id, test.host, test.xPos, test.yPos, test.m);
      return;
    }
  }

  fclose(fp);
  printf("check ok\n");
  return;
}

void create_pType(MPI_Datatype *pType) {
  /* creates type for particle  */

  int           blocks[3] = {1, 1, 3};
  MPI_Datatype  types[3]  = {MPI_INT, MPI_INT, MPI_DOUBLE};
  MPI_Aint      disps[3]  = {0, 8, 16};

  MPI_Type_struct(3, blocks, disps, types, pType);
  MPI_Type_commit(pType);
}


void main(int argc, char *argv[]) {
  MPI_File       fh;
  MPI_Datatype   pType;
  MPI_Status     status;
  Particle       p[SIZE];

  MPI_Init(&argc, &argv);
  init(p);
  create_pType(&pType);

  MPI_File_open(MPI_COMM_WORLD, FILENAME, MPI_MODE_WRONLY|MPI_MODE_CREATE,
		MPI_INFO_NULL, &fh); 
  MPI_File_set_view(fh, 0, pType, pType, "native", MPI_INFO_NULL); 

  MPI_File_write_shared(fh, p, SIZE, pType, &status); 
  MPI_File_close(&fh);

  check();

  MPI_Finalize();
}