xref: /phasta/phastaIO/phastaIO.cc (revision a663ed547a5d6235aa3bcffc8f9fa412c3d80f1f)
1 /*
2  *
3  * This is the SyncIO library that uses MPI-IO collective functions to
4  * implement a flexible I/O checkpoint solution for a large number of
5  * processors.
6  *
7  * Previous developer: Ning Liu         (liun2@cs.rpi.edu)
8  *                     Jing Fu          (fuj@cs.rpi.edu)
9  * Current developers: Michel Rasquin   (Michel.Rasquin@colorado.edu),
10  *                     Ben Matthews     (benjamin.a.matthews@colorado.edu)
11  *
12  */
13 
14 #include <map>
15 #include <vector>
16 #include <string>
17 #include <cstdarg>
18 #include <string.h>
19 #include <ctype.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <math.h>
23 #include <sstream>
24 #include "phastaIO.h"
25 #include "mpi.h"
26 #include "phiotmrc.h"
27 #include "phiostats.h"
28 #include <assert.h>
29 
30 #define VERSION_INFO_HEADER_SIZE 8192
31 #define DB_HEADER_SIZE 1024
32 #define ONE_MEGABYTE 1048576
33 #define TWO_MEGABYTE 2097152
34 #define ENDIAN_TEST_NUMBER 12180 // Troy's Zip Code!!
35 #define MAX_PHASTA_FILES 64
36 #define MAX_PHASTA_FILE_NAME_LENGTH 1024
37 #define MAX_FIELDS_NUMBER ((VERSION_INFO_HEADER_SIZE/MAX_FIELDS_NAME_LENGTH)-4) // The meta data include - MPI_IO_Tag, nFields, nFields*names of the fields, nppf
38 // -3 for MPI_IO_Tag, nFields and nppf, -4 for extra security (former nFiles)
39 #define MAX_FIELDS_NAME_LENGTH 128
40 #define DefaultMHSize (4*ONE_MEGABYTE)
41 //#define DefaultMHSize (8350) //For test
42 #define LATEST_WRITE_VERSION 1
43 #define inv1024sq 953.674316406e-9 // = 1/1024/1024
44 int MasterHeaderSize = -1;
45 
46 bool PRINT_PERF = false; // default print no perf results
47 int irank = -1; // global rank, should never be manually manipulated
48 int mysize = -1;
49 
50 // Static variables are bad but used here to store the subcommunicator and associated variables
51 // Prevent MPI_Comm_split to be called more than once, especially on BGQ with the V1R2M1 driver (leak detected in MPI_Comm_split - IBM working on it)
52 static int s_assign_local_comm = 0;
53 static MPI_Comm s_local_comm;
54 static int s_local_size = -1;
55 static int s_local_rank = -1;
56 
57 // the following defines are for debug printf
58 #define PHASTAIO_DEBUG 0 //default to not print any debugging info
59 
60 void phprintf(const char* fmt, ...) {
61   (void)fmt;
62 #if PHASTAIO_DEBUG
63   char format[1024];
64   snprintf(format, sizeof(format), "phastaIO debug: %s", fmt);
65   va_list ap;
66   va_start(ap,fmt);
67   vprintf(format,ap);
68   va_end(ap);
69 #endif
70 }
71 
72 void phprintf_0(const char* fmt, ...) {
73   (void)fmt;
74 #if PHASTAIO_DEBUG
75   int rank = 0;
76   MPI_Comm_rank(MPI_COMM_WORLD, &rank);
77   if(rank == 0){
78     char format[1024];
79     snprintf(format, sizeof(format), "phastaIO debug: irank=0 %s", fmt);
80     va_list ap;
81     va_start(ap,fmt);
82     vprintf(format, ap);
83     va_end(ap);
84   }
85 #endif
86 }
87 
88 enum PhastaIO_Errors
89 {
90   MAX_PHASTA_FILES_EXCEEDED = -1,
91   UNABLE_TO_OPEN_FILE = -2,
92   NOT_A_MPI_FILE = -3,
93   GPID_EXCEEDED = -4,
94   DATA_TYPE_ILLEGAL = -5
95 };
96 
97 using namespace std;
98 
99 namespace{
100 
101   map<int, std::string> LastHeaderKey;
102   vector< FILE* > fileArray;
103   vector< bool > byte_order;
104   vector< int > header_type;
105   int DataSize=0;
106   bool LastHeaderNotFound = false;
107   bool Wrong_Endian = false ;
108   bool Strict_Error = false ;
109   bool binary_format = true;
110 
111   /***********************************************************************/
112   /***************** NEW PHASTA IO CODE STARTS HERE **********************/
113   /***********************************************************************/
114 
115   typedef struct
116   {
117     char filename[MAX_PHASTA_FILE_NAME_LENGTH];   /* defafults to 1024 */
118     unsigned long my_offset;
119     unsigned long next_start_address;
120     unsigned long **my_offset_table;
121     unsigned long **my_read_table;
122 
123     double * double_chunk;
124     double * read_double_chunk;
125 
126     int field_count;
127     int part_count;
128     int read_field_count;
129     int read_part_count;
130     int GPid;
131     int start_id;
132 
133     int mhsize;
134 
135     int myrank;
136     int numprocs;
137     int local_myrank;
138     int local_numprocs;
139 
140     int nppp;
141     int nPPF;
142     int nFiles;
143     int nFields;
144 
145     int * int_chunk;
146     int * read_int_chunk;
147 
148     int Wrong_Endian; /* default to false */
149     char * master_header;
150     MPI_File file_handle;
151     MPI_Comm local_comm;
152   } phastaio_file_t;
153 
154   typedef struct
155   {
156     int nppf, nfields;
157     char * masterHeader;
158   }serial_file;
159 
160   serial_file *SerialFile;
161   phastaio_file_t *PhastaIOActiveFiles[MAX_PHASTA_FILES];
162   int PhastaIONextActiveIndex = 0; /* indicates next index to allocate */
163 
164   // the caller has the responsibility to delete the returned string
165   // TODO: StringStipper("nbc value? ") returns NULL?
166   char* StringStripper( const char  istring[] ) {
167     int length = strlen( istring );
168     char* dest = (char *)malloc( length + 1 );
169     strcpy( dest, istring );
170     dest[ length ] = '\0';
171     if ( char* p = strpbrk( dest, " ") )
172       *p = '\0';
173     return dest;
174   }
175 
176   inline int cscompare( const char teststring[], const char targetstring[] ) {
177     char* s1 = const_cast<char*>(teststring);
178     char* s2 = const_cast<char*>(targetstring);
179 
180     while( *s1 == ' ') s1++;
181     while( *s2 == ' ') s2++;
182     while( ( *s1 )
183         && ( *s2 )
184         && ( *s2 != '?')
185         && ( tolower( *s1 )==tolower( *s2 ) ) ) {
186       s1++;
187       s2++;
188       while( *s1 == ' ') s1++;
189       while( *s2 == ' ') s2++;
190     }
191     if ( !( *s1 ) || ( *s1 == '?') ) return 1;
192     else return 0;
193   }
194 
195   inline void isBinary( const char iotype[] ) {
196     char* fname = StringStripper( iotype );
197     if ( cscompare( fname, "binary" ) ) binary_format = true;
198     else binary_format = false;
199     free (fname);
200 
201   }
202 
203   inline size_t typeSize( const char typestring[] ) {
204     char* ts1 = StringStripper( typestring );
205     if ( cscompare( "integer", ts1 ) ) {
206       free (ts1);
207       return sizeof(int);
208     } else if ( cscompare( "double", ts1 ) ) {
209       free (ts1);
210       return sizeof( double );
211     } else {
212       free (ts1);
213       fprintf(stderr,"unknown type : %s\n",ts1);
214       return 0;
215     }
216   }
217 
218   int readHeader(
219       FILE*       fileObject,
220         const char  phrase[],
221         int*        params,
222         int         expect ) {
223     char* text_header;
224     char* token;
225     char Line[1024] = "\0";
226     char junk;
227     bool FOUND = false ;
228     int real_length;
229     int skip_size, integer_value;
230     int rewind_count=0;
231 
232     if( !fgets( Line, 1024, fileObject ) && feof( fileObject ) ) {
233       rewind( fileObject );
234       clearerr( fileObject );
235       rewind_count++;
236       fgets( Line, 1024, fileObject );
237     }
238 
239     while( !FOUND  && ( rewind_count < 2 ) )  {
240       if ( ( Line[0] != '\n' ) && ( real_length = strcspn( Line, "#" )) ) {
241         text_header = (char *)malloc( real_length + 1 );
242         strncpy( text_header, Line, real_length );
243         text_header[ real_length ] =static_cast<char>(NULL);
244         token = strtok ( text_header, ":" );
245         assert(token);
246         if( cscompare( phrase , token ) ) {
247           FOUND = true ;
248           token = strtok( NULL, " ,;<>" );
249           assert(token);
250           skip_size = atoi( token );
251           int i;
252           for( i=0; i < expect && ( token = strtok( NULL," ,;<>") ); i++) {
253             assert(token);
254             params[i] = atoi( token );
255           }
256           if ( i < expect ) {
257             fprintf(stderr,
258                 "Aloha Expected # of ints not found for: %s\n",phrase );
259           }
260         } else if ( cscompare(token,"byteorder magic number") ) {
261           if ( binary_format ) {
262             fread((void*)&integer_value,sizeof(int),1,fileObject);
263             fread( &junk, sizeof(char), 1 , fileObject );
264             if ( 362436 != integer_value ) Wrong_Endian = true;
265           } else{
266             fscanf(fileObject, "%d\n", &integer_value );
267           }
268         } else {
269           /* some other header, so just skip over */
270           token = strtok( NULL, " ,;<>" );
271           assert(token);
272           skip_size = atoi( token );
273           if ( binary_format)
274             fseek( fileObject, skip_size, SEEK_CUR );
275           else
276             for( int gama=0; gama < skip_size; gama++ )
277               fgets( Line, 1024, fileObject );
278         }
279         free (text_header);
280       } // end of if before while loop
281 
282       if ( !FOUND )
283         if( !fgets( Line, 1024, fileObject ) && feof( fileObject ) ) {
284           rewind( fileObject );
285           clearerr( fileObject );
286           rewind_count++;
287           fgets( Line, 1024, fileObject );
288         }
289     }
290 
291     if ( !FOUND ) {
292       //fprintf(stderr, "Error: Could not find: %s\n", phrase);
293       if(irank == 0) printf("WARNING: Could not find: %s\n", phrase);
294       return 1;
295     }
296     return 0;
297   }
298 
299 } // end unnamed namespace
300 
301 
302 // begin of publicly visible functions
303 
304 /**
305  * This function takes a long long pointer and assign (start) phiotmrc value to it
306  */
307 void startTimer(double* start) {
308   if( !PRINT_PERF ) return;
309   MPI_Barrier(MPI_COMM_WORLD);
310   *start =  phiotmrc();
311 }
312 
313 /**
314  * This function takes a long long pointer and assign (end) phiotmrc value to it
315  */
316 void endTimer(double* end) {
317   if( !PRINT_PERF ) return;
318   *end = phiotmrc();
319   MPI_Barrier(MPI_COMM_WORLD);
320 }
321 
322 /**
323  * choose to print some performance results (or not) according to
324  * the PRINT_PERF macro
325  */
326 void printPerf(
327     const char* func_name,
328     double start,
329     double end,
330     unsigned long datasize,
331     int printdatainfo,
332     const char* extra_msg) {
333   if( !PRINT_PERF ) return;
334   unsigned long data_size = datasize;
335   double time = end - start;
336   unsigned long isizemin,isizemax,isizetot;
337   double sizemin,sizemax,sizeavg,sizetot,rate;
338   double tmin, tmax, tavg, ttot;
339 
340   MPI_Allreduce(&time, &tmin,1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
341   MPI_Allreduce(&time, &tmax,1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
342   MPI_Allreduce(&time, &ttot,1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
343   tavg = ttot/mysize;
344 
345   if(irank == 0) {
346     if ( PhastaIONextActiveIndex == 0 ) printf("** 1PFPP ");
347     else  printf("** syncIO ");
348     printf("%s(): Tmax = %f sec, Tmin = %f sec, Tavg = %f sec", func_name, tmax, tmin, tavg);
349   }
350 
351   if(printdatainfo == 1) { // if printdatainfo ==1, compute I/O rate and block size
352     MPI_Allreduce(&data_size,&isizemin,1,MPI_LONG_LONG_INT,MPI_MIN,MPI_COMM_WORLD);
353     MPI_Allreduce(&data_size,&isizemax,1,MPI_LONG_LONG_INT,MPI_MAX,MPI_COMM_WORLD);
354     MPI_Allreduce(&data_size,&isizetot,1,MPI_LONG_LONG_INT,MPI_SUM,MPI_COMM_WORLD);
355 
356     sizemin=(double)(isizemin*inv1024sq);
357     sizemax=(double)(isizemax*inv1024sq);
358     sizetot=(double)(isizetot*inv1024sq);
359     sizeavg=(double)(1.0*sizetot/mysize);
360     rate=(double)(1.0*sizetot/tmax);
361 
362     if( irank == 0) {
363       printf(", Rate = %f MB/s [%s] \n \t\t\t"
364              " block size: Min= %f MB; Max= %f MB; Avg= %f MB; Tot= %f MB\n",
365              rate, extra_msg, sizemin,sizemax,sizeavg,sizetot);
366     }
367   }
368   else {
369     if(irank == 0) {
370       printf(" \n");
371       //printf(" (%s) \n", extra_msg);
372     }
373   }
374 }
375 
376 /**
377  * This function is normally called at the beginning of a read operation, before
378  * init function.
379  * This function (uses rank 0) reads out nfields, nppf, master header size,
380  * endianess and allocates for masterHeader string.
381  * These values are essential for following read operations. Rank 0 will bcast
382  * these values to other ranks in the commm world
383  *
384  * If the file set is of old POSIX format, it would throw error and exit
385  */
386 void queryphmpiio(const char filename[],int *nfields, int *nppf)
387 {
388   MPI_Comm_rank(MPI_COMM_WORLD, &irank);
389   MPI_Comm_size(MPI_COMM_WORLD, &mysize);
390 
391   if(irank == 0) {
392     FILE * fileHandle;
393     char* fname = StringStripper( filename );
394 
395     double t0 = phiotmrc();
396     fileHandle = fopen (fname,"rb");
397     phastaio_addOpenTime(phiotmrc()-t0);
398     if (fileHandle == NULL ) {
399       printf("\nError: File %s doesn't exist! Please check!\n",fname);
400     }
401     else {
402       SerialFile =(serial_file *)calloc( 1,  sizeof( serial_file) );
403       int meta_size_limit = VERSION_INFO_HEADER_SIZE;
404       SerialFile->masterHeader = (char *)malloc( meta_size_limit );
405       fread(SerialFile->masterHeader, 1, meta_size_limit, fileHandle);
406 
407       char read_out_tag[MAX_FIELDS_NAME_LENGTH];
408       char version[MAX_FIELDS_NAME_LENGTH/4];
409       int mhsize;
410       char * token;
411       int magic_number;
412 
413       memcpy( read_out_tag,
414           SerialFile->masterHeader,
415           MAX_FIELDS_NAME_LENGTH-1 );
416 
417       if ( cscompare ("MPI_IO_Tag",read_out_tag) ) {
418         // Test endianess ...
419         memcpy (&magic_number,
420             SerialFile->masterHeader + sizeof("MPI_IO_Tag : ")-1, //-1 sizeof returns the size of the string+1 for "\0"
421             sizeof(int) );                                        // masterheader should look like "MPI_IO_Tag : 12180 " with 12180 in binary format
422 
423         if ( magic_number != ENDIAN_TEST_NUMBER ) {
424           printf("Endian is different!\n");
425           // Will do swap later
426         }
427 
428         // test version, old version, default masterheader size is 4M
429         // newer version masterheader size is read from first line
430         memcpy(version,
431             SerialFile->masterHeader + MAX_FIELDS_NAME_LENGTH/2,
432             MAX_FIELDS_NAME_LENGTH/4 - 1); //TODO: why -1?
433 
434         if( cscompare ("version",version) ) {
435           // if there is "version" tag in the file, then it is newer format
436           // read master header size from here, otherwise use default
437           // Note: if version is "1", we know mhsize is at 3/4 place...
438 
439           token = strtok(version, ":");
440           token = strtok(NULL, " ,;<>" );
441           int iversion = atoi(token);
442 
443           if( iversion == 1) {
444             memcpy( &mhsize,
445                 SerialFile->masterHeader + MAX_FIELDS_NAME_LENGTH/4*3 + sizeof("mhsize : ")-1,
446                 sizeof(int));
447             if ( magic_number != ENDIAN_TEST_NUMBER )
448               SwapArrayByteOrder(&mhsize, sizeof(int), 1);
449 
450             if( mhsize > DefaultMHSize ) {
451               //if actual headersize is larger than default, let's re-read
452               free(SerialFile->masterHeader);
453               SerialFile->masterHeader = (char *)malloc(mhsize);
454               fseek(fileHandle, 0, SEEK_SET); // reset the file stream position
455               fread(SerialFile->masterHeader,1,mhsize,fileHandle);
456             }
457           }
458           //TODO: check if this is a valid int??
459           MasterHeaderSize = mhsize;
460         }
461         else { // else it's version 0's format w/o version tag, implicating MHSize=4M
462           MasterHeaderSize = DefaultMHSize;
463         }
464 
465         memcpy( read_out_tag,
466             SerialFile->masterHeader+MAX_FIELDS_NAME_LENGTH+1,
467             MAX_FIELDS_NAME_LENGTH ); //TODO: why +1
468 
469         // Read in # fields ...
470         token = strtok( read_out_tag, ":" );
471         token = strtok( NULL," ,;<>" );
472         *nfields = atoi( token );
473         if ( *nfields > MAX_FIELDS_NUMBER) {
474           printf("Error queryphmpiio: nfields is larger than MAX_FIELDS_NUMBER!\n");
475         }
476         SerialFile->nfields=*nfields; //TODO: sanity check of this int?
477 
478         memcpy( read_out_tag,
479             SerialFile->masterHeader + MAX_FIELDS_NAME_LENGTH * 2
480             + *nfields * MAX_FIELDS_NAME_LENGTH,
481             MAX_FIELDS_NAME_LENGTH);
482 
483         token = strtok( read_out_tag, ":" );
484         token = strtok( NULL," ,;<>" );
485         *nppf = atoi( token );
486         SerialFile->nppf=*nppf; //TODO: sanity check of int
487       } // end of if("MPI_IO_TAG")
488       else {
489         printf("Error queryphmpiio: The file you opened is not of syncIO new format, please check! read_out_tag = %s\n",read_out_tag);
490         exit(1);
491       }
492       double t0 = phiotmrc();
493       fclose(fileHandle);
494       phastaio_addCloseTime(phiotmrc()-t0);
495       free(SerialFile->masterHeader);
496       free(SerialFile);
497     } //end of else
498     free(fname);
499   }
500 
501   // Bcast value to every one
502   MPI_Bcast( nfields, 1, MPI_INT, 0, MPI_COMM_WORLD );
503   MPI_Bcast( nppf, 1, MPI_INT, 0, MPI_COMM_WORLD );
504   MPI_Bcast( &MasterHeaderSize, 1, MPI_INT, 0, MPI_COMM_WORLD );
505   phprintf("Info queryphmpiio: myrank = %d, MasterHeaderSize = %d\n", irank, MasterHeaderSize);
506 }
507 
508 /**
509  * This function computes the right master header size (round to size of 2^n).
510  * This is only needed for file format version 1 in "write" mode.
511  */
512 int computeMHSize(int nfields, int nppf, int version) {
513   int mhsize=0;
514   if(version == 1) {
515     //int meta_info_size = (2+nfields+1) * MAX_FIELDS_NAME_LENGTH; // 2 is MPI_IO_TAG and nFields, the others 1 is nppf
516     int meta_info_size = VERSION_INFO_HEADER_SIZE;
517     int actual_size =  nfields * nppf * sizeof(unsigned long) + meta_info_size;
518     //printf("actual_size = %d, offset table size = %d\n", actual_size,  nfields * nppf * sizeof(long long));
519     if (actual_size > DefaultMHSize) {
520       mhsize = (int) ceil( (double) actual_size/DefaultMHSize); // it's rounded to ceiling of this value
521       mhsize *= DefaultMHSize;
522     }
523     else {
524       mhsize = DefaultMHSize;
525     }
526   } else {
527     int rank = 0;
528     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
529     if(!rank) {
530       fprintf(stderr,
531           "ERROR invalid version passed to %s... exiting\n", __func__);
532       exit(EXIT_FAILURE);
533     }
534   }
535   return mhsize;
536 }
537 
538 /**
539  * Computes correct color of a rank according to number of files.
540  */
541 extern "C" int computeColor( int myrank, int numprocs, int nfiles) {
542   int color =
543     (int)(myrank / (numprocs / nfiles));
544   return color;
545 }
546 
547 
548 /**
549  * Check the file descriptor.
550  */
551 void checkFileDescriptor(const char fctname[], int*  fileDescriptor ) {
552   if ( *fileDescriptor < 0 ) {
553     printf("Error: File descriptor = %d in %s\n",*fileDescriptor,fctname);
554     exit(1);
555   }
556 }
557 
558 /**
559  * Initialize the file struct members and allocate space for file struct
560  * buffers.
561  *
562  * Note: this function is only called when we are using new format. Old POSIX
563  * format should skip this routine and call openfile() directly instead.
564  */
565 int initphmpiio( int *nfields, int *nppf, int *nfiles, int *filehandle, const char mode[])
566 {
567   // we init irank again in case query not called (e.g. syncIO write case)
568   MPI_Comm_rank(MPI_COMM_WORLD, &irank);
569   MPI_Comm_size(MPI_COMM_WORLD, &mysize);
570 
571   phprintf("Info initphmpiio: entering function, myrank = %d, MasterHeaderSize = %d, nfields %d, nppf %d, nfiles %d\n", irank, MasterHeaderSize, *nfields, *nppf, *nfiles);
572 
573   double timer_start, timer_end;
574   startTimer(&timer_start);
575 
576   char* imode = StringStripper( mode );
577 
578   // Note: if it's read, we presume query was called prior to init and
579   // MasterHeaderSize is already set to correct value from parsing header
580   // otherwise it's write then it needs some computation to be set
581   if ( cscompare( "read", imode ) ) {
582     // do nothing
583   }
584   else if( cscompare( "write", imode ) ) {
585     MasterHeaderSize =  computeMHSize(*nfields, *nppf, LATEST_WRITE_VERSION);
586   }
587   else {
588     printf("Error initphmpiio: can't recognize the mode %s", imode);
589     exit(1);
590   }
591   free ( imode );
592 
593   phprintf("Info initphmpiio: myrank = %d, MasterHeaderSize = %d\n", irank, MasterHeaderSize);
594 
595   int i, j;
596 
597   if( PhastaIONextActiveIndex == MAX_PHASTA_FILES ) {
598     printf("Error initphmpiio: PhastaIONextActiveIndex = MAX_PHASTA_FILES");
599     endTimer(&timer_end);
600     printPerf("initphmpiio", timer_start, timer_end, 0, 0, "");
601     return MAX_PHASTA_FILES_EXCEEDED;
602   }
603   //		else if( PhastaIONextActiveIndex == 0 )  //Hang in debug mode on Intrepid
604   //		{
605   //			for( i = 0; i < MAX_PHASTA_FILES; i++ );
606   //			{
607   //				PhastaIOActiveFiles[i] = NULL;
608   //			}
609   //		}
610 
611 
612   PhastaIOActiveFiles[PhastaIONextActiveIndex] = (phastaio_file_t *)calloc( 1,  sizeof( phastaio_file_t) );
613 
614   i = PhastaIONextActiveIndex;
615   PhastaIONextActiveIndex++;
616 
617   //PhastaIOActiveFiles[i]->next_start_address = 2*TWO_MEGABYTE;
618 
619   PhastaIOActiveFiles[i]->next_start_address = MasterHeaderSize;  // what does this mean??? TODO
620 
621   PhastaIOActiveFiles[i]->Wrong_Endian = false;
622 
623   PhastaIOActiveFiles[i]->nFields = *nfields;
624   PhastaIOActiveFiles[i]->nPPF = *nppf;
625   PhastaIOActiveFiles[i]->nFiles = *nfiles;
626   MPI_Comm_rank(MPI_COMM_WORLD, &(PhastaIOActiveFiles[i]->myrank));
627   MPI_Comm_size(MPI_COMM_WORLD, &(PhastaIOActiveFiles[i]->numprocs));
628 
629 
630   if( *nfiles > 1 ) { // split the ranks according to each mpiio file
631 
632     if ( s_assign_local_comm == 0) { // call mpi_comm_split for the first (and only) time
633 
634       if (PhastaIOActiveFiles[i]->myrank == 0) printf("Building subcommunicator\n");
635 
636       int color = computeColor(PhastaIOActiveFiles[i]->myrank, PhastaIOActiveFiles[i]->numprocs, PhastaIOActiveFiles[i]->nFiles);
637       MPI_Comm_split(MPI_COMM_WORLD,
638           color,
639           PhastaIOActiveFiles[i]->myrank,
640           &(PhastaIOActiveFiles[i]->local_comm));
641       MPI_Comm_size(PhastaIOActiveFiles[i]->local_comm,
642           &(PhastaIOActiveFiles[i]->local_numprocs));
643       MPI_Comm_rank(PhastaIOActiveFiles[i]->local_comm,
644           &(PhastaIOActiveFiles[i]->local_myrank));
645 
646       // back up now these variables so that we do not need to call comm_split again
647       s_local_comm = PhastaIOActiveFiles[i]->local_comm;
648       s_local_size = PhastaIOActiveFiles[i]->local_numprocs;
649       s_local_rank = PhastaIOActiveFiles[i]->local_myrank;
650       s_assign_local_comm = 1;
651     }
652     else { // recycle the subcommunicator
653       if (PhastaIOActiveFiles[i]->myrank == 0) printf("Recycling subcommunicator\n");
654       PhastaIOActiveFiles[i]->local_comm = s_local_comm;
655       PhastaIOActiveFiles[i]->local_numprocs = s_local_size;
656       PhastaIOActiveFiles[i]->local_myrank = s_local_rank;
657     }
658   }
659   else { // *nfiles == 1 here - no need to call mpi_comm_split here
660 
661     if (PhastaIOActiveFiles[i]->myrank == 0) printf("Bypassing subcommunicator\n");
662     PhastaIOActiveFiles[i]->local_comm = MPI_COMM_WORLD;
663     PhastaIOActiveFiles[i]->local_numprocs = PhastaIOActiveFiles[i]->numprocs;
664     PhastaIOActiveFiles[i]->local_myrank = PhastaIOActiveFiles[i]->myrank;
665 
666   }
667 
668   PhastaIOActiveFiles[i]->nppp =
669     PhastaIOActiveFiles[i]->nPPF/PhastaIOActiveFiles[i]->local_numprocs;
670 
671   PhastaIOActiveFiles[i]->start_id = PhastaIOActiveFiles[i]->nPPF *
672     (int)(PhastaIOActiveFiles[i]->myrank/PhastaIOActiveFiles[i]->local_numprocs) +
673     (PhastaIOActiveFiles[i]->local_myrank * PhastaIOActiveFiles[i]->nppp);
674 
675   PhastaIOActiveFiles[i]->my_offset_table =
676     ( unsigned long ** ) calloc( MAX_FIELDS_NUMBER , sizeof( unsigned long *) );
677 
678   PhastaIOActiveFiles[i]->my_read_table =
679     ( unsigned long ** ) calloc( MAX_FIELDS_NUMBER , sizeof( unsigned long *) );
680 
681   for (j=0; j<*nfields; j++)
682   {
683     PhastaIOActiveFiles[i]->my_offset_table[j] =
684       ( unsigned long * ) calloc( PhastaIOActiveFiles[i]->nppp , sizeof( unsigned long) );
685 
686     PhastaIOActiveFiles[i]->my_read_table[j] =
687       ( unsigned long * ) calloc( PhastaIOActiveFiles[i]->nppp , sizeof( unsigned long) );
688   }
689   *filehandle = i;
690 
691   PhastaIOActiveFiles[i]->master_header = (char *)calloc(MasterHeaderSize,sizeof( char ));
692   PhastaIOActiveFiles[i]->double_chunk = (double *)calloc(1,sizeof( double ));
693   PhastaIOActiveFiles[i]->int_chunk = (int *)calloc(1,sizeof( int ));
694   PhastaIOActiveFiles[i]->read_double_chunk = (double *)calloc(1,sizeof( double ));
695   PhastaIOActiveFiles[i]->read_int_chunk = (int *)calloc(1,sizeof( int ));
696 
697   // Time monitoring
698   endTimer(&timer_end);
699   printPerf("initphmpiio", timer_start, timer_end, 0, 0, "");
700 
701   phprintf_0("Info initphmpiio: quiting function");
702 
703   return i;
704 }
705 
706 /**
707  * Destruct the file struct and free buffers allocated in init function.
708  */
709 void finalizephmpiio( int *fileDescriptor )
710 {
711   double timer_start, timer_end;
712   startTimer(&timer_start);
713 
714   int i, j;
715   i = *fileDescriptor;
716   //PhastaIONextActiveIndex--;
717 
718   /* //free the offset table for this phasta file */
719   //for(j=0; j<MAX_FIELDS_NUMBER; j++) //Danger: undefined behavior for my_*_table.[j] not allocated or not initialized to NULL
720   for(j=0; j<PhastaIOActiveFiles[i]->nFields; j++)
721   {
722     free( PhastaIOActiveFiles[i]->my_offset_table[j]);
723     free( PhastaIOActiveFiles[i]->my_read_table[j]);
724   }
725   free ( PhastaIOActiveFiles[i]->my_offset_table );
726   free ( PhastaIOActiveFiles[i]->my_read_table );
727   free ( PhastaIOActiveFiles[i]->master_header );
728   free ( PhastaIOActiveFiles[i]->double_chunk );
729   free ( PhastaIOActiveFiles[i]->int_chunk );
730   free ( PhastaIOActiveFiles[i]->read_double_chunk );
731   free ( PhastaIOActiveFiles[i]->read_int_chunk );
732 
733   if( PhastaIOActiveFiles[i]->nFiles > 1 && s_assign_local_comm ) { // the comm was split
734     if (PhastaIOActiveFiles[i]->myrank == 0) printf("Freeing subcommunicator\n");
735     s_assign_local_comm = 0;
736     MPI_Comm_free(&(PhastaIOActiveFiles[i]->local_comm));
737   }
738 
739   free( PhastaIOActiveFiles[i]);
740 
741   endTimer(&timer_end);
742   printPerf("finalizempiio", timer_start, timer_end, 0, 0, "");
743 
744   PhastaIONextActiveIndex--;
745 }
746 
747 
748 /**
749  * Special init for M2N in order to create a subcommunicator for the reduced solution (requires PRINT_PERF to be false for now)
750  * Initialize the file struct members and allocate space for file struct buffers.
751  *
752  * Note: this function is only called when we are using new format. Old POSIX
753  * format should skip this routine and call openfile() directly instead.
754  */
755 int initphmpiiosub( int *nfields, int *nppf, int *nfiles, int *filehandle, const char mode[],MPI_Comm my_local_comm)
756 {
757   // we init irank again in case query not called (e.g. syncIO write case)
758 
759   MPI_Comm_rank(my_local_comm, &irank);
760   MPI_Comm_size(my_local_comm, &mysize);
761 
762   phprintf("Info initphmpiio: entering function, myrank = %d, MasterHeaderSize = %d\n", irank, MasterHeaderSize);
763 
764   double timer_start, timer_end;
765   startTimer(&timer_start);
766 
767   char* imode = StringStripper( mode );
768 
769   // Note: if it's read, we presume query was called prior to init and
770   // MasterHeaderSize is already set to correct value from parsing header
771   // otherwise it's write then it needs some computation to be set
772   if ( cscompare( "read", imode ) ) {
773     // do nothing
774   }
775   else if( cscompare( "write", imode ) ) {
776     MasterHeaderSize =  computeMHSize(*nfields, *nppf, LATEST_WRITE_VERSION);
777   }
778   else {
779     printf("Error initphmpiio: can't recognize the mode %s", imode);
780     exit(1);
781   }
782   free ( imode );
783 
784   phprintf("Info initphmpiio: myrank = %d, MasterHeaderSize = %d\n", irank, MasterHeaderSize);
785 
786   int i, j;
787 
788   if( PhastaIONextActiveIndex == MAX_PHASTA_FILES ) {
789     printf("Error initphmpiio: PhastaIONextActiveIndex = MAX_PHASTA_FILES");
790     endTimer(&timer_end);
791     printPerf("initphmpiio", timer_start, timer_end, 0, 0, "");
792     return MAX_PHASTA_FILES_EXCEEDED;
793   }
794   //		else if( PhastaIONextActiveIndex == 0 )  //Hang in debug mode on Intrepid
795   //		{
796   //			for( i = 0; i < MAX_PHASTA_FILES; i++ );
797   //			{
798   //				PhastaIOActiveFiles[i] = NULL;
799   //			}
800   //		}
801 
802 
803   PhastaIOActiveFiles[PhastaIONextActiveIndex] = (phastaio_file_t *)calloc( 1,  sizeof( phastaio_file_t) );
804 
805   i = PhastaIONextActiveIndex;
806   PhastaIONextActiveIndex++;
807 
808   //PhastaIOActiveFiles[i]->next_start_address = 2*TWO_MEGABYTE;
809 
810   PhastaIOActiveFiles[i]->next_start_address = MasterHeaderSize;  // what does this mean??? TODO
811 
812   PhastaIOActiveFiles[i]->Wrong_Endian = false;
813 
814   PhastaIOActiveFiles[i]->nFields = *nfields;
815   PhastaIOActiveFiles[i]->nPPF = *nppf;
816   PhastaIOActiveFiles[i]->nFiles = *nfiles;
817   MPI_Comm_rank(my_local_comm, &(PhastaIOActiveFiles[i]->myrank));
818   MPI_Comm_size(my_local_comm, &(PhastaIOActiveFiles[i]->numprocs));
819 
820   int color = computeColor(PhastaIOActiveFiles[i]->myrank, PhastaIOActiveFiles[i]->numprocs, PhastaIOActiveFiles[i]->nFiles);
821   MPI_Comm_split(my_local_comm,
822       color,
823       PhastaIOActiveFiles[i]->myrank,
824       &(PhastaIOActiveFiles[i]->local_comm));
825   MPI_Comm_size(PhastaIOActiveFiles[i]->local_comm,
826       &(PhastaIOActiveFiles[i]->local_numprocs));
827   MPI_Comm_rank(PhastaIOActiveFiles[i]->local_comm,
828       &(PhastaIOActiveFiles[i]->local_myrank));
829   PhastaIOActiveFiles[i]->nppp =
830     PhastaIOActiveFiles[i]->nPPF/PhastaIOActiveFiles[i]->local_numprocs;
831 
832   PhastaIOActiveFiles[i]->start_id = PhastaIOActiveFiles[i]->nPPF *
833     (int)(PhastaIOActiveFiles[i]->myrank/PhastaIOActiveFiles[i]->local_numprocs) +
834     (PhastaIOActiveFiles[i]->local_myrank * PhastaIOActiveFiles[i]->nppp);
835 
836   PhastaIOActiveFiles[i]->my_offset_table =
837     ( unsigned long ** ) calloc( MAX_FIELDS_NUMBER , sizeof( unsigned long *) );
838 
839   PhastaIOActiveFiles[i]->my_read_table =
840     ( unsigned long ** ) calloc( MAX_FIELDS_NUMBER , sizeof( unsigned long *) );
841 
842   for (j=0; j<*nfields; j++)
843   {
844     PhastaIOActiveFiles[i]->my_offset_table[j] =
845       ( unsigned long * ) calloc( PhastaIOActiveFiles[i]->nppp , sizeof( unsigned long) );
846 
847     PhastaIOActiveFiles[i]->my_read_table[j] =
848       ( unsigned long * ) calloc( PhastaIOActiveFiles[i]->nppp , sizeof( unsigned long) );
849   }
850   *filehandle = i;
851 
852   PhastaIOActiveFiles[i]->master_header = (char *)calloc(MasterHeaderSize,sizeof( char ));
853   PhastaIOActiveFiles[i]->double_chunk = (double *)calloc(1,sizeof( double ));
854   PhastaIOActiveFiles[i]->int_chunk = (int *)calloc(1,sizeof( int ));
855   PhastaIOActiveFiles[i]->read_double_chunk = (double *)calloc(1,sizeof( double ));
856   PhastaIOActiveFiles[i]->read_int_chunk = (int *)calloc(1,sizeof( int ));
857 
858   // Time monitoring
859   endTimer(&timer_end);
860   printPerf("initphmpiiosub", timer_start, timer_end, 0, 0, "");
861 
862   phprintf_0("Info initphmpiiosub: quiting function");
863 
864   return i;
865 }
866 
867 
868 
869 /** open file for both POSIX and MPI-IO syncIO format.
870  *
871  * If it's old POSIX format, simply call posix fopen().
872  *
873  * If it's MPI-IO foramt:
874  * in "read" mode, it builds the header table that points to the offset of
875  * fields for parts;
876  * in "write" mode, it opens the file with MPI-IO open routine.
877  */
878 void openfile(const char filename[], const char mode[], int*  fileDescriptor )
879 {
880   phprintf_0("Info: entering openfile");
881 
882   double timer_start, timer_end;
883   startTimer(&timer_start);
884 
885   if ( PhastaIONextActiveIndex == 0 )
886   {
887     FILE* file=NULL ;
888     *fileDescriptor = 0;
889     char* fname = StringStripper( filename );
890     char* imode = StringStripper( mode );
891 
892     double t0 = phiotmrc();
893     if ( cscompare( "read", imode ) ) file = fopen(fname, "rb" );
894     else if( cscompare( "write", imode ) ) file = fopen(fname, "wb" );
895     else if( cscompare( "append", imode ) ) file = fopen(fname, "ab" );
896     phastaio_addOpenTime(phiotmrc()-t0);
897 
898     if ( !file ){
899       fprintf(stderr,"Error openfile: unable to open file %s\n",fname);
900     } else {
901       fileArray.push_back( file );
902       byte_order.push_back( false );
903       header_type.push_back( sizeof(int) );
904       *fileDescriptor = fileArray.size();
905     }
906     free (fname);
907     free (imode);
908   }
909   else // else it would be parallel I/O, opposed to posix io
910   {
911     char* fname = StringStripper( filename );
912     char* imode = StringStripper( mode );
913     int rc;
914     int i = *fileDescriptor;
915     checkFileDescriptor("openfile",&i);
916     char* token;
917 
918     if ( cscompare( "read", imode ) )
919     {
920       //	      if (PhastaIOActiveFiles[i]->myrank == 0)
921       //                printf("\n **********\nRead open ... ... regular version\n");
922 
923       double t0 = phiotmrc();
924       rc = MPI_File_open( PhastaIOActiveFiles[i]->local_comm,
925           fname,
926           MPI_MODE_RDONLY,
927           MPI_INFO_NULL,
928           &(PhastaIOActiveFiles[i]->file_handle) );
929       phastaio_addOpenTime(phiotmrc()-t0);
930 
931       if(rc)
932       {
933         *fileDescriptor = UNABLE_TO_OPEN_FILE;
934         int error_string_length;
935         char error_string[4096];
936         MPI_Error_string(rc, error_string, &error_string_length);
937         fprintf(stderr, "Error openfile: Unable to open file %s! MPI reports \"%s\"\n",fname,error_string);
938         endTimer(&timer_end);
939         printPerf("openfile", timer_start, timer_end, 0, 0, "");
940         return;
941       }
942 
943       MPI_Status read_tag_status;
944       char read_out_tag[MAX_FIELDS_NAME_LENGTH];
945       int j;
946       int magic_number;
947 
948       if ( PhastaIOActiveFiles[i]->local_myrank == 0 ) {
949         MPI_File_read_at( PhastaIOActiveFiles[i]->file_handle,
950             0,
951             PhastaIOActiveFiles[i]->master_header,
952             MasterHeaderSize,
953             MPI_CHAR,
954             &read_tag_status );
955       }
956 
957       MPI_Bcast( PhastaIOActiveFiles[i]->master_header,
958           MasterHeaderSize,
959           MPI_CHAR,
960           0,
961           PhastaIOActiveFiles[i]->local_comm );
962 
963       memcpy( read_out_tag,
964           PhastaIOActiveFiles[i]->master_header,
965           MAX_FIELDS_NAME_LENGTH-1 );
966 
967       if ( cscompare ("MPI_IO_Tag",read_out_tag) )
968       {
969         // Test endianess ...
970         memcpy ( &magic_number,
971             PhastaIOActiveFiles[i]->master_header+sizeof("MPI_IO_Tag : ")-1, //-1 sizeof returns the size of the string+1 for "\0"
972             sizeof(int) );                                                   // masterheader should look like "MPI_IO_Tag : 12180 " with 12180 in binary format
973 
974         if ( magic_number != ENDIAN_TEST_NUMBER )
975         {
976           PhastaIOActiveFiles[i]->Wrong_Endian = true;
977         }
978 
979         memcpy( read_out_tag,
980             PhastaIOActiveFiles[i]->master_header+MAX_FIELDS_NAME_LENGTH+1, // TODO: WHY +1???
981             MAX_FIELDS_NAME_LENGTH );
982 
983         // Read in # fields ...
984         token = strtok ( read_out_tag, ":" );
985         token = strtok( NULL," ,;<>" );
986         PhastaIOActiveFiles[i]->nFields = atoi( token );
987 
988         unsigned long **header_table;
989         header_table = ( unsigned long ** )calloc(PhastaIOActiveFiles[i]->nFields, sizeof(unsigned long *));
990 
991         for ( j = 0; j < PhastaIOActiveFiles[i]->nFields; j++ )
992         {
993           header_table[j]=( unsigned long * ) calloc( PhastaIOActiveFiles[i]->nPPF , sizeof( unsigned long));
994         }
995 
996         // Read in the offset table ...
997         for ( j = 0; j < PhastaIOActiveFiles[i]->nFields; j++ )
998         {
999           if ( PhastaIOActiveFiles[i]->local_myrank == 0 ) {
1000             memcpy( header_table[j],
1001                 PhastaIOActiveFiles[i]->master_header +
1002                 VERSION_INFO_HEADER_SIZE +
1003                 j * PhastaIOActiveFiles[i]->nPPF * sizeof(unsigned long),
1004                 PhastaIOActiveFiles[i]->nPPF * sizeof(unsigned long) );
1005           }
1006 
1007           MPI_Scatter( header_table[j],
1008               PhastaIOActiveFiles[i]->nppp,
1009               MPI_LONG_LONG_INT,
1010               PhastaIOActiveFiles[i]->my_read_table[j],
1011               PhastaIOActiveFiles[i]->nppp,
1012               MPI_LONG_LONG_INT,
1013               0,
1014               PhastaIOActiveFiles[i]->local_comm );
1015 
1016           // Swap byte order if endianess is different ...
1017           if ( PhastaIOActiveFiles[i]->Wrong_Endian ) {
1018             SwapArrayByteOrder( PhastaIOActiveFiles[i]->my_read_table[j],
1019                 sizeof(unsigned long),
1020                 PhastaIOActiveFiles[i]->nppp );
1021           }
1022         }
1023 
1024         for ( j = 0; j < PhastaIOActiveFiles[i]->nFields; j++ ) {
1025           free ( header_table[j] );
1026         }
1027         free (header_table);
1028 
1029       } // end of if MPI_IO_TAG
1030       else //else not valid MPI file
1031       {
1032         *fileDescriptor = NOT_A_MPI_FILE;
1033         printf("Error openfile: The file %s you opened is not in syncIO new format, please check again! File descriptor = %d, MasterHeaderSize = %d, read_out_tag = %s\n",fname,*fileDescriptor,MasterHeaderSize,read_out_tag);
1034         //Printing MasterHeaderSize is useful to test a compiler bug on Intrepid BGP
1035         endTimer(&timer_end);
1036         printPerf("openfile", timer_start, timer_end, 0, 0, "");
1037         return;
1038       }
1039     } // end of if "read"
1040     else if( cscompare( "write", imode ) )
1041     {
1042       double t0 = phiotmrc();
1043       rc = MPI_File_open( PhastaIOActiveFiles[i]->local_comm,
1044           fname,
1045           MPI_MODE_WRONLY | MPI_MODE_CREATE,
1046           MPI_INFO_NULL,
1047           &(PhastaIOActiveFiles[i]->file_handle) );
1048       phastaio_addOpenTime(phiotmrc()-t0);
1049       if(rc != MPI_SUCCESS)
1050       {
1051         *fileDescriptor = UNABLE_TO_OPEN_FILE;
1052         int error_string_length;
1053         char error_string[4096];
1054         MPI_Error_string(rc, error_string, &error_string_length);
1055         fprintf(stderr, "Error openfile: Unable to open file %s! MPI reports \"%s\"\n",fname,error_string);
1056         return;
1057       }
1058     } // end of if "write"
1059     free (fname);
1060     free (imode);
1061   } // end of if FileIndex != 0
1062 
1063   endTimer(&timer_end);
1064   printPerf("openfile", timer_start, timer_end, 0, 0, "");
1065 }
1066 
1067 /** close file for both POSIX and MPI-IO syncIO format.
1068  *
1069  * If it's old POSIX format, simply call posix fclose().
1070  *
1071  * If it's MPI-IO foramt:
1072  * in "read" mode, it simply close file with MPI-IO close routine.
1073  * in "write" mode, rank 0 in each group will re-assemble the master header and
1074  * offset table and write to the beginning of file, then close the file.
1075  */
1076 void closefile( int* fileDescriptor, const char mode[] )
1077 {
1078   double timer_start, timer_end;
1079   startTimer(&timer_start);
1080 
1081   int i = *fileDescriptor;
1082   checkFileDescriptor("closefile",&i);
1083 
1084   if ( PhastaIONextActiveIndex == 0 ) {
1085     char* imode = StringStripper( mode );
1086 
1087     if( cscompare( "write", imode )
1088         || cscompare( "append", imode ) ) {
1089       fflush( fileArray[ *fileDescriptor - 1 ] );
1090     }
1091 
1092     double t0 = phiotmrc();
1093     fclose( fileArray[ *fileDescriptor - 1 ] );
1094     phastaio_addCloseTime(phiotmrc()-t0);
1095     free (imode);
1096   }
1097   else {
1098     char* imode = StringStripper( mode );
1099 
1100     //write master header here:
1101     if ( cscompare( "write", imode ) ) {
1102       //	      if ( PhastaIOActiveFiles[i]->nPPF * PhastaIOActiveFiles[i]->nFields < 2*ONE_MEGABYTE/8 )  //SHOULD BE CHECKED
1103       //		MasterHeaderSize = 4*ONE_MEGABYTE;
1104       //	      else
1105       //		MasterHeaderSize = 4*ONE_MEGABYTE + PhastaIOActiveFiles[i]->nPPF * PhastaIOActiveFiles[i]->nFields * 8 - 2*ONE_MEGABYTE;
1106 
1107       MasterHeaderSize = computeMHSize( PhastaIOActiveFiles[i]->nFields, PhastaIOActiveFiles[i]->nPPF, LATEST_WRITE_VERSION);
1108       phprintf_0("Info closefile: myrank = %d, MasterHeaderSize = %d\n", PhastaIOActiveFiles[i]->myrank, MasterHeaderSize);
1109 
1110       MPI_Status write_header_status;
1111       char mpi_tag[MAX_FIELDS_NAME_LENGTH];
1112       char version[MAX_FIELDS_NAME_LENGTH/4];
1113       char mhsize[MAX_FIELDS_NAME_LENGTH/4];
1114       int magic_number = ENDIAN_TEST_NUMBER;
1115 
1116       if ( PhastaIOActiveFiles[i]->local_myrank == 0 )
1117       {
1118         bzero((void*)mpi_tag,MAX_FIELDS_NAME_LENGTH);
1119         sprintf(mpi_tag, "MPI_IO_Tag : ");
1120         memcpy(PhastaIOActiveFiles[i]->master_header,
1121             mpi_tag,
1122             MAX_FIELDS_NAME_LENGTH);
1123 
1124         bzero((void*)version,MAX_FIELDS_NAME_LENGTH/4);
1125         // this version is "1", print version in ASCII
1126         sprintf(version, "version : %d",1);
1127         memcpy(PhastaIOActiveFiles[i]->master_header + MAX_FIELDS_NAME_LENGTH/2,
1128             version,
1129             MAX_FIELDS_NAME_LENGTH/4);
1130 
1131         // master header size is computed using the formula above
1132         bzero((void*)mhsize,MAX_FIELDS_NAME_LENGTH/4);
1133         sprintf(mhsize, "mhsize : ");
1134         memcpy(PhastaIOActiveFiles[i]->master_header + MAX_FIELDS_NAME_LENGTH/4*3,
1135             mhsize,
1136             MAX_FIELDS_NAME_LENGTH/4);
1137 
1138         bzero((void*)mpi_tag,MAX_FIELDS_NAME_LENGTH);
1139         sprintf(mpi_tag,
1140             "\nnFields : %d\n",
1141             PhastaIOActiveFiles[i]->nFields);
1142         memcpy(PhastaIOActiveFiles[i]->master_header+MAX_FIELDS_NAME_LENGTH,
1143             mpi_tag,
1144             MAX_FIELDS_NAME_LENGTH);
1145 
1146         bzero((void*)mpi_tag,MAX_FIELDS_NAME_LENGTH);
1147         sprintf(mpi_tag, "\nnPPF : %d\n", PhastaIOActiveFiles[i]->nPPF);
1148         memcpy( PhastaIOActiveFiles[i]->master_header+
1149             PhastaIOActiveFiles[i]->nFields *
1150             MAX_FIELDS_NAME_LENGTH +
1151             MAX_FIELDS_NAME_LENGTH * 2,
1152             mpi_tag,
1153             MAX_FIELDS_NAME_LENGTH);
1154 
1155         memcpy( PhastaIOActiveFiles[i]->master_header+sizeof("MPI_IO_Tag : ")-1, //-1 sizeof returns the size of the string+1 for "\0"
1156             &magic_number,
1157             sizeof(int));
1158 
1159         memcpy( PhastaIOActiveFiles[i]->master_header+sizeof("mhsize : ") -1 + MAX_FIELDS_NAME_LENGTH/4*3,
1160             &MasterHeaderSize,
1161             sizeof(int));
1162       }
1163 
1164       int j = 0;
1165       unsigned long **header_table;
1166       header_table = ( unsigned long ** )calloc(PhastaIOActiveFiles[i]->nFields, sizeof(unsigned long *));
1167 
1168       for ( j = 0; j < PhastaIOActiveFiles[i]->nFields; j++ ) {
1169         header_table[j]=( unsigned long * ) calloc( PhastaIOActiveFiles[i]->nPPF , sizeof( unsigned long));
1170       }
1171 
1172       //if( irank == 0 ) printf("gonna mpi_gather, myrank = %d\n", irank);
1173       for ( j = 0; j < PhastaIOActiveFiles[i]->nFields; j++ ) {
1174         MPI_Gather( PhastaIOActiveFiles[i]->my_offset_table[j],
1175             PhastaIOActiveFiles[i]->nppp,
1176             MPI_LONG_LONG_INT,
1177             header_table[j],
1178             PhastaIOActiveFiles[i]->nppp,
1179             MPI_LONG_LONG_INT,
1180             0,
1181             PhastaIOActiveFiles[i]->local_comm );
1182       }
1183 
1184       if ( PhastaIOActiveFiles[i]->local_myrank == 0 ) {
1185 
1186         //if( irank == 0 ) printf("gonna memcpy for every procs, myrank = %d\n", irank);
1187         for ( j = 0; j < PhastaIOActiveFiles[i]->nFields; j++ ) {
1188           memcpy ( PhastaIOActiveFiles[i]->master_header +
1189               VERSION_INFO_HEADER_SIZE +
1190               j * PhastaIOActiveFiles[i]->nPPF * sizeof(unsigned long),
1191               header_table[j],
1192               PhastaIOActiveFiles[i]->nPPF * sizeof(unsigned long) );
1193         }
1194 
1195         //if( irank == 0 ) printf("gonna file_write_at(), myrank = %d\n", irank);
1196         MPI_File_write_at( PhastaIOActiveFiles[i]->file_handle,
1197             0,
1198             PhastaIOActiveFiles[i]->master_header,
1199             MasterHeaderSize,
1200             MPI_CHAR,
1201             &write_header_status );
1202       }
1203 
1204       ////free(PhastaIOActiveFiles[i]->master_header);
1205 
1206       for ( j = 0; j < PhastaIOActiveFiles[i]->nFields; j++ ) {
1207         free ( header_table[j] );
1208       }
1209       free (header_table);
1210     }
1211 
1212     //if( irank == 0 ) printf("gonna file_close(), myrank = %d\n", irank);
1213     double t0 = phiotmrc();
1214     MPI_File_close( &( PhastaIOActiveFiles[i]->file_handle ) );
1215     phastaio_addCloseTime(phiotmrc()-t0);
1216     free ( imode );
1217   }
1218 
1219   endTimer(&timer_end);
1220   printPerf("closefile_", timer_start, timer_end, 0, 0, "");
1221 }
1222 
1223 int readHeader( FILE* f, const char phrase[],
1224     int* params, int numParams, const char* iotype) {
1225   isBinary(iotype);
1226   return readHeader(f,phrase,params,numParams);
1227 }
1228 
1229 void readheader(
1230     int* fileDescriptor,
1231     const  char keyphrase[],
1232     void* valueArray,
1233     int*  nItems,
1234     const char  datatype[],
1235     const char  iotype[] )
1236 {
1237   double timer_start, timer_end;
1238 
1239   startTimer(&timer_start);
1240 
1241   int i = *fileDescriptor;
1242   checkFileDescriptor("readheader",&i);
1243 
1244   if ( PhastaIONextActiveIndex == 0 ) {
1245     int filePtr = *fileDescriptor - 1;
1246     FILE* fileObject;
1247     int* valueListInt;
1248 
1249     if ( *fileDescriptor < 1 || *fileDescriptor > (int)fileArray.size() ) {
1250       fprintf(stderr,"No file associated with Descriptor %d\n",*fileDescriptor);
1251       fprintf(stderr,"openfile_ function has to be called before \n") ;
1252       fprintf(stderr,"acessing the file\n ") ;
1253       fprintf(stderr,"fatal error: cannot continue, returning out of call\n");
1254       endTimer(&timer_end);
1255       printPerf("readheader", timer_start, timer_end, 0, 0, "");
1256       return;
1257     }
1258 
1259     LastHeaderKey[filePtr] = std::string(keyphrase);
1260     LastHeaderNotFound = false;
1261 
1262     fileObject = fileArray[ filePtr ] ;
1263     Wrong_Endian = byte_order[ filePtr ];
1264 
1265     isBinary( iotype );
1266     typeSize( datatype );   //redundant call, just avoid a compiler warning.
1267 
1268     // right now we are making the assumption that we will only write integers
1269     // on the header line.
1270 
1271     valueListInt = static_cast< int* >( valueArray );
1272     int ierr = readHeader( fileObject ,
1273         keyphrase,
1274         valueListInt,
1275         *nItems ) ;
1276 
1277     byte_order[ filePtr ] = Wrong_Endian ;
1278 
1279     if ( ierr ) LastHeaderNotFound = true;
1280 
1281     //return ; // don't return, go to the end to print perf
1282   }
1283   else {
1284     int* valueListInt;
1285     valueListInt = static_cast <int*>(valueArray);
1286     char* token = NULL;
1287     bool FOUND = false ;
1288     isBinary( iotype );
1289 
1290     MPI_Status read_offset_status;
1291     char read_out_tag[MAX_FIELDS_NAME_LENGTH];
1292     memset(read_out_tag, '\0', MAX_FIELDS_NAME_LENGTH);
1293     char readouttag[MAX_FIELDS_NUMBER][MAX_FIELDS_NAME_LENGTH];
1294     int j;
1295 
1296     int string_length = strlen( keyphrase );
1297     char* buffer = (char*) malloc ( string_length+1 );
1298 
1299     strcpy ( buffer, keyphrase );
1300     buffer[ string_length ] = '\0';
1301 
1302     char* st2 = strtok ( buffer, "@" );
1303     st2 = strtok (NULL, "@");
1304     PhastaIOActiveFiles[i]->GPid = atoi(st2);
1305     if ( char* p = strpbrk(buffer, "@") )
1306       *p = '\0';
1307 
1308     // Check if the user has input the right GPid
1309     if ( ( PhastaIOActiveFiles[i]->GPid <=
1310           PhastaIOActiveFiles[i]->myrank *
1311           PhastaIOActiveFiles[i]->nppp )||
1312         ( PhastaIOActiveFiles[i]->GPid >
1313           ( PhastaIOActiveFiles[i]->myrank + 1 ) *
1314           PhastaIOActiveFiles[i]->nppp ) )
1315     {
1316       *fileDescriptor = NOT_A_MPI_FILE;
1317       printf("Error readheader: The file is not in syncIO new format, please check! myrank = %d, GPid = %d, nppp = %d, keyphrase = %s\n", PhastaIOActiveFiles[i]->myrank, PhastaIOActiveFiles[i]->GPid, PhastaIOActiveFiles[i]->nppp, keyphrase);
1318       // It is possible atoi could not generate a clear integer from st2 because of additional garbage character in keyphrase
1319       endTimer(&timer_end);
1320       printPerf("readheader", timer_start, timer_end, 0, 0, "");
1321       return;
1322     }
1323 
1324     // Find the field we want ...
1325     //for ( j = 0; j<MAX_FIELDS_NUMBER; j++ )
1326     for ( j = 0; j<PhastaIOActiveFiles[i]->nFields; j++ )
1327     {
1328       memcpy( readouttag[j],
1329           PhastaIOActiveFiles[i]->master_header + j*MAX_FIELDS_NAME_LENGTH+MAX_FIELDS_NAME_LENGTH*2+1,
1330           MAX_FIELDS_NAME_LENGTH-1 );
1331     }
1332 
1333     for ( j = 0; j<PhastaIOActiveFiles[i]->nFields; j++ )
1334     {
1335       token = strtok ( readouttag[j], ":" );
1336 
1337       //if ( cscompare( buffer, token ) )
1338       if ( cscompare( token , buffer ) && cscompare( buffer, token ) )
1339         // This double comparison is required for the field "number of nodes" and all the other fields that start with "number of nodes" (i.g. number of nodes in the mesh").
1340         // Would be safer to rename "number of nodes" by "number of nodes in the part" so that the name are completely unique. But much more work to do that (Nspre, phParAdapt, etc).
1341         // Since the field name are unique in SyncIO (as it includes part ID), this should be safe and there should be no issue with the "?" trailing character.
1342       {
1343         PhastaIOActiveFiles[i]->read_field_count = j;
1344         FOUND = true;
1345         //printf("buffer: %s | token: %s | j: %d\n",buffer,token,j);
1346         break;
1347       }
1348     }
1349     free(buffer);
1350 
1351     if (!FOUND)
1352     {
1353       //if(irank==0) printf("Warning readheader: Not found %s \n",keyphrase); //PhastaIOActiveFiles[i]->myrank is certainly initialized here.
1354       if(PhastaIOActiveFiles[i]->myrank == 0) printf("WARNING readheader: Not found %s\n",keyphrase);
1355       endTimer(&timer_end);
1356       printPerf("readheader", timer_start, timer_end, 0, 0, "");
1357       return;
1358     }
1359 
1360     // Find the part we want ...
1361     PhastaIOActiveFiles[i]->read_part_count = PhastaIOActiveFiles[i]->GPid -
1362       PhastaIOActiveFiles[i]->myrank * PhastaIOActiveFiles[i]->nppp - 1;
1363 
1364     PhastaIOActiveFiles[i]->my_offset =
1365       PhastaIOActiveFiles[i]->my_read_table[PhastaIOActiveFiles[i]->read_field_count][PhastaIOActiveFiles[i]->read_part_count];
1366 
1367     // 	  printf("****Rank %d offset is %d\n",PhastaIOActiveFiles[i]->myrank,PhastaIOActiveFiles[i]->my_offset);
1368 
1369     // Read each datablock header here ...
1370 
1371     MPI_File_read_at_all( PhastaIOActiveFiles[i]->file_handle,
1372         PhastaIOActiveFiles[i]->my_offset+1,
1373         read_out_tag,
1374         MAX_FIELDS_NAME_LENGTH-1,
1375         MPI_CHAR,
1376         &read_offset_status );
1377     token = strtok ( read_out_tag, ":" );
1378 
1379     // 	  printf("&&&&Rank %d read_out_tag is %s\n",PhastaIOActiveFiles[i]->myrank,read_out_tag);
1380 
1381     if( cscompare( keyphrase , token ) ) //No need to compare also token with keyphrase like above. We should already have the right one. Otherwise there is a problem.
1382     {
1383       FOUND = true ;
1384       token = strtok( NULL, " ,;<>" );
1385       for( j=0; j < *nItems && ( token = strtok( NULL," ,;<>") ); j++ )
1386         valueListInt[j] = atoi( token );
1387 
1388       if ( j < *nItems )
1389       {
1390         fprintf( stderr, "Expected # of ints not found for: %s\n", keyphrase );
1391       }
1392     }
1393     else {
1394       //if(irank==0)
1395       if(PhastaIOActiveFiles[i]->myrank == 0)
1396         // If we enter this if, there is a problem with the name of some fields
1397       {
1398         printf("Error readheader: Unexpected mismatch between keyphrase = %s and token = %s\n",keyphrase,token);
1399       }
1400     }
1401   }
1402 
1403   endTimer(&timer_end);
1404   printPerf("readheader", timer_start, timer_end, 0, 0, "");
1405 
1406 }
1407 
1408 void readDataBlock(
1409     FILE* fileObject,
1410     void* valueArray,
1411     int nItems,
1412     const char  datatype[],
1413     const char  iotype[] )
1414 {
1415   isBinary(iotype);
1416   size_t type_size = typeSize( datatype );
1417   double t0 = phiotmrc();
1418   if ( binary_format ) {
1419     char junk = '\0';
1420     fread( valueArray, type_size, nItems, fileObject );
1421     fread( &junk, sizeof(char), 1 , fileObject );
1422     if ( Wrong_Endian ) SwapArrayByteOrder( valueArray, type_size, nItems );
1423   } else {
1424     char* ts1 = StringStripper( datatype );
1425     if ( cscompare( "integer", ts1 ) ) {
1426       for( int n=0; n < nItems ; n++ )
1427         fscanf(fileObject, "%d\n",(int*)((int*)valueArray+n) );
1428     } else if ( cscompare( "double", ts1 ) ) {
1429       for( int n=0; n < nItems ; n++ )
1430         fscanf(fileObject, "%lf\n",(double*)((double*)valueArray+n) );
1431     }
1432     free (ts1);
1433   }
1434   phastaio_addReadTime(phiotmrc()-t0);
1435   phastaio_addReadBytes(nItems*type_size);
1436 }
1437 
1438 void readdatablock(
1439     int*  fileDescriptor,
1440     const char keyphrase[],
1441     void* valueArray,
1442     int*  nItems,
1443     const char  datatype[],
1444     const char  iotype[] )
1445 {
1446   //if(irank == 0) printf("entering readdatablock()\n");
1447   unsigned long data_size = 0;
1448   double timer_start, timer_end;
1449   startTimer(&timer_start);
1450 
1451   int i = *fileDescriptor;
1452   checkFileDescriptor("readdatablock",&i);
1453 
1454   if ( PhastaIONextActiveIndex == 0 ) {
1455     int filePtr = *fileDescriptor - 1;
1456     FILE* fileObject;
1457 
1458     if ( *fileDescriptor < 1 || *fileDescriptor > (int)fileArray.size() ) {
1459       fprintf(stderr,"No file associated with Descriptor %d\n",*fileDescriptor);
1460       fprintf(stderr,"openfile_ function has to be called before\n") ;
1461       fprintf(stderr,"acessing the file\n ") ;
1462       fprintf(stderr,"fatal error: cannot continue, returning out of call\n");
1463       endTimer(&timer_end);
1464       printPerf("readdatablock", timer_start, timer_end, 0, 0, "");
1465       return;
1466     }
1467 
1468     // error check..
1469     // since we require that a consistant header always preceed the data block
1470     // let us check to see that it is actually the case.
1471 
1472     if ( ! cscompare( LastHeaderKey[ filePtr ].c_str(), keyphrase ) ) {
1473       fprintf(stderr, "Header not consistant with data block\n");
1474       fprintf(stderr, "Header: %s\n", LastHeaderKey[ filePtr ].c_str() );
1475       fprintf(stderr, "DataBlock: %s\n ", keyphrase );
1476       fprintf(stderr, "Please recheck read sequence \n");
1477       if( Strict_Error ) {
1478         fprintf(stderr, "fatal error: cannot continue, returning out of call\n");
1479         endTimer(&timer_end);
1480         printPerf("readdatablock", timer_start, timer_end, 0, 0, "");
1481         return;
1482       }
1483     }
1484 
1485     if ( LastHeaderNotFound ) {
1486       endTimer(&timer_end);
1487       printPerf("readdatablock", timer_start, timer_end, 0, 0, "");
1488       return;
1489     }
1490     fileObject = fileArray[ filePtr ];
1491     Wrong_Endian = byte_order[ filePtr ];
1492     LastHeaderKey.erase(filePtr);
1493     readDataBlock(fileObject,valueArray,*nItems,datatype,iotype);
1494 
1495     //return;
1496   }
1497   else {
1498     // 	  printf("read data block\n");
1499     MPI_Status read_data_status;
1500     size_t type_size = typeSize( datatype );
1501     int nUnits = *nItems;
1502     isBinary( iotype );
1503 
1504     // read datablock then
1505     //MR CHANGE
1506     //             if ( cscompare ( datatype, "double"))
1507     char* ts2 = StringStripper( datatype );
1508     if ( cscompare ( "double" , ts2))
1509       //MR CHANGE END
1510     {
1511 
1512       double t0 = phiotmrc();
1513       MPI_File_read_at_all_begin( PhastaIOActiveFiles[i]->file_handle,
1514           PhastaIOActiveFiles[i]->my_offset + DB_HEADER_SIZE,
1515           valueArray,
1516           nUnits,
1517           MPI_DOUBLE );
1518       MPI_File_read_at_all_end( PhastaIOActiveFiles[i]->file_handle,
1519           valueArray,
1520           &read_data_status );
1521       data_size=8*nUnits;
1522       phastaio_addReadTime(phiotmrc()-t0);
1523       phastaio_addReadBytes(nUnits*sizeof(double));
1524     }
1525     //MR CHANGE
1526     //             else if ( cscompare ( datatype, "integer"))
1527     else if ( cscompare ( "integer" , ts2))
1528       //MR CHANGE END
1529     {
1530       double t0 = phiotmrc();
1531       MPI_File_read_at_all_begin(PhastaIOActiveFiles[i]->file_handle,
1532           PhastaIOActiveFiles[i]->my_offset + DB_HEADER_SIZE,
1533           valueArray,
1534           nUnits,
1535           MPI_INT );
1536       MPI_File_read_at_all_end( PhastaIOActiveFiles[i]->file_handle,
1537           valueArray,
1538           &read_data_status );
1539       data_size=4*nUnits;
1540       phastaio_addReadTime(phiotmrc()-t0);
1541       phastaio_addReadBytes(nUnits*sizeof(int));
1542     }
1543     else
1544     {
1545       *fileDescriptor = DATA_TYPE_ILLEGAL;
1546       printf("readdatablock - DATA_TYPE_ILLEGAL - %s\n",datatype);
1547       endTimer(&timer_end);
1548       printPerf("readdatablock", timer_start, timer_end, 0, 0, "");
1549       return;
1550     }
1551     free(ts2);
1552 
1553 
1554     // 	  printf("%d Read finishe\n",PhastaIOActiveFiles[i]->myrank);
1555 
1556     // Swap data byte order if endianess is different ...
1557     if ( PhastaIOActiveFiles[i]->Wrong_Endian )
1558     {
1559       SwapArrayByteOrder( valueArray, type_size, nUnits );
1560     }
1561   }
1562 
1563   endTimer(&timer_end);
1564   char extra_msg[1024];
1565   memset(extra_msg, '\0', 1024);
1566   char* key = StringStripper(keyphrase);
1567   sprintf(extra_msg, " field is %s ", key);
1568   printPerf("readdatablock", timer_start, timer_end, data_size, 1, extra_msg);
1569   free(key);
1570 
1571 }
1572 
1573 void writeHeader(
1574     FILE* f,
1575     const char keyphrase[],
1576     const void* valueArray,
1577     const int nItems,
1578     const int ndataItems,
1579     const char datatype[],
1580     const char iotype[])
1581 {
1582   isBinary( iotype );
1583 
1584   const int _newline =
1585     ( ndataItems > 0 ) ? sizeof( char ) : 0;
1586   int size_of_nextblock =
1587     ( binary_format ) ? typeSize(datatype) * ndataItems + _newline : ndataItems;
1588 
1589   fprintf( f, "%s : < %d > ", keyphrase, size_of_nextblock );
1590   for( int i = 0; i < nItems; i++ )
1591     fprintf( f, "%d ", *((int*)((int*)valueArray+i)));
1592   fprintf( f, "\n");
1593 }
1594 
1595 void writeheader(
1596     const int* fileDescriptor,
1597     const char keyphrase[],
1598     const void* valueArray,
1599     const int* nItems,
1600     const int* ndataItems,
1601     const char datatype[],
1602     const char iotype[])
1603 {
1604 
1605   //if(irank == 0) printf("entering writeheader()\n");
1606 
1607   double timer_start, timer_end;
1608   startTimer(&timer_start);
1609 
1610   int i = *fileDescriptor;
1611   checkFileDescriptor("writeheader",&i);
1612 
1613   if ( PhastaIONextActiveIndex == 0 ) {
1614     int filePtr = *fileDescriptor - 1;
1615     if ( *fileDescriptor < 1 || *fileDescriptor > (int)fileArray.size() ) {
1616       fprintf(stderr,"No file associated with Descriptor %d\n",*fileDescriptor);
1617       fprintf(stderr,"openfile_ function has to be called before \n") ;
1618       fprintf(stderr,"acessing the file\n ") ;
1619       fprintf(stderr,"fatal error: cannot continue, returning out of call\n");
1620       endTimer(&timer_end);
1621       printPerf("writeheader", timer_start, timer_end, 0, 0, "");
1622       return;
1623     }
1624 
1625     LastHeaderKey[filePtr] = std::string(keyphrase);
1626     DataSize = *ndataItems;
1627     FILE* fileObject = fileArray[ filePtr ] ;
1628     header_type[ filePtr ] = typeSize( datatype );
1629     writeHeader(fileObject,keyphrase,valueArray,*nItems,
1630         *ndataItems,datatype,iotype);
1631   }
1632   else { // else it's parallel I/O
1633     DataSize = *ndataItems;
1634     size_t type_size = typeSize( datatype );
1635     isBinary( iotype );
1636     char mpi_tag[MAX_FIELDS_NAME_LENGTH];
1637 
1638     int string_length = strlen( keyphrase );
1639     char* buffer = (char*) malloc ( string_length+1 );
1640 
1641     strcpy ( buffer, keyphrase);
1642     buffer[ string_length ] = '\0';
1643 
1644     char* st2 = strtok ( buffer, "@" );
1645     st2 = strtok (NULL, "@");
1646     PhastaIOActiveFiles[i]->GPid = atoi(st2);
1647 
1648     if ( char* p = strpbrk(buffer, "@") )
1649       *p = '\0';
1650 
1651     bzero((void*)mpi_tag,MAX_FIELDS_NAME_LENGTH);
1652     sprintf(mpi_tag, "\n%s : %d\n", buffer, PhastaIOActiveFiles[i]->field_count);
1653     unsigned long offset_value;
1654 
1655     int temp = *ndataItems;
1656     unsigned long number_of_items = (unsigned long)temp;
1657     MPI_Barrier(PhastaIOActiveFiles[i]->local_comm);
1658 
1659     MPI_Scan( &number_of_items,
1660         &offset_value,
1661         1,
1662         MPI_LONG_LONG_INT,
1663         MPI_SUM,
1664         PhastaIOActiveFiles[i]->local_comm );
1665 
1666     offset_value = (offset_value - number_of_items) * type_size;
1667 
1668     offset_value += PhastaIOActiveFiles[i]->local_myrank *
1669       DB_HEADER_SIZE +
1670       PhastaIOActiveFiles[i]->next_start_address;
1671     // This offset is the starting address of each datablock header...
1672     PhastaIOActiveFiles[i]->my_offset = offset_value;
1673 
1674     // Write in my offset table ...
1675     PhastaIOActiveFiles[i]->my_offset_table[PhastaIOActiveFiles[i]->field_count][PhastaIOActiveFiles[i]->part_count] =
1676       PhastaIOActiveFiles[i]->my_offset;
1677 
1678     // Update the next-start-address ...
1679     PhastaIOActiveFiles[i]->next_start_address = offset_value +
1680       number_of_items * type_size +
1681       DB_HEADER_SIZE;
1682     MPI_Bcast( &(PhastaIOActiveFiles[i]->next_start_address),
1683         1,
1684         MPI_LONG_LONG_INT,
1685         PhastaIOActiveFiles[i]->local_numprocs-1,
1686         PhastaIOActiveFiles[i]->local_comm );
1687 
1688     // Prepare datablock header ...
1689     int _newline = (*ndataItems>0)?sizeof(char):0;
1690     unsigned int size_of_nextblock = type_size * (*ndataItems) + _newline;
1691 
1692     //char datablock_header[255];
1693     //bzero((void*)datablock_header,255);
1694     char datablock_header[DB_HEADER_SIZE];
1695     bzero((void*)datablock_header,DB_HEADER_SIZE);
1696 
1697     PhastaIOActiveFiles[i]->GPid = PhastaIOActiveFiles[i]->nppp*PhastaIOActiveFiles[i]->myrank+PhastaIOActiveFiles[i]->part_count;
1698     sprintf( datablock_header,
1699         "\n%s : < %u >",
1700         keyphrase,
1701         size_of_nextblock );
1702 
1703     for ( int j = 0; j < *nItems; j++ )
1704     {
1705       sprintf( datablock_header,
1706           "%s %d ",
1707           datablock_header,
1708           *((int*)((int*)valueArray+j)));
1709     }
1710     sprintf( datablock_header,
1711         "%s\n ",
1712         datablock_header );
1713 
1714     // Write datablock header ...
1715     //MR CHANGE
1716     // 	if ( cscompare(datatype,"double") )
1717     char* ts1 = StringStripper( datatype );
1718     if ( cscompare("double",ts1) )
1719       //MR CHANGE END
1720     {
1721       free ( PhastaIOActiveFiles[i]->double_chunk );
1722       PhastaIOActiveFiles[i]->double_chunk = ( double * )malloc( (sizeof( double )*number_of_items+ DB_HEADER_SIZE));
1723 
1724       double * aa = ( double * )datablock_header;
1725       memcpy(PhastaIOActiveFiles[i]->double_chunk, aa, DB_HEADER_SIZE);
1726     }
1727     //MR CHANGE
1728     // 	if  ( cscompare(datatype,"integer") )
1729     else if ( cscompare("integer",ts1) )
1730       //MR CHANGE END
1731     {
1732       free ( PhastaIOActiveFiles[i]->int_chunk );
1733       PhastaIOActiveFiles[i]->int_chunk = ( int * )malloc( (sizeof( int )*number_of_items+ DB_HEADER_SIZE));
1734 
1735       int * aa = ( int * )datablock_header;
1736       memcpy(PhastaIOActiveFiles[i]->int_chunk, aa, DB_HEADER_SIZE);
1737     }
1738     else {
1739       //             *fileDescriptor = DATA_TYPE_ILLEGAL;
1740       printf("writeheader - DATA_TYPE_ILLEGAL - %s\n",datatype);
1741       endTimer(&timer_end);
1742       printPerf("writeheader", timer_start, timer_end, 0, 0, "");
1743       return;
1744     }
1745     free(ts1);
1746 
1747     PhastaIOActiveFiles[i]->part_count++;
1748     if ( PhastaIOActiveFiles[i]->part_count == PhastaIOActiveFiles[i]->nppp ) {
1749       //A new field will be written
1750       if ( PhastaIOActiveFiles[i]->local_myrank == 0 ) {
1751         memcpy( PhastaIOActiveFiles[i]->master_header +
1752             PhastaIOActiveFiles[i]->field_count *
1753             MAX_FIELDS_NAME_LENGTH +
1754             MAX_FIELDS_NAME_LENGTH * 2,
1755             mpi_tag,
1756             MAX_FIELDS_NAME_LENGTH-1);
1757       }
1758       PhastaIOActiveFiles[i]->field_count++;
1759       PhastaIOActiveFiles[i]->part_count=0;
1760     }
1761     free(buffer);
1762   }
1763 
1764   endTimer(&timer_end);
1765   printPerf("writeheader", timer_start, timer_end, 0, 0, "");
1766 }
1767 
1768 void writeDataBlock(
1769     FILE* f,
1770     const void* valueArray,
1771     const int   nItems,
1772     const char  datatype[],
1773     const char  iotype[]  )
1774 {
1775   isBinary( iotype );
1776   size_t type_size = typeSize( datatype );
1777   double t0 = phiotmrc();
1778   if ( binary_format ) {
1779     fwrite( valueArray, type_size, nItems, f );
1780     fprintf( f,"\n");
1781   } else {
1782     char* ts1 = StringStripper( datatype );
1783     if ( cscompare( "integer", ts1 ) ) {
1784       const int* vals = (int*) valueArray;
1785       for( int n=0; n < nItems ; n++ )
1786         fprintf(f,"%d\n",vals[n]);
1787     } else if ( cscompare( "double", ts1 ) ) {
1788       const double* vals = (double*) valueArray;
1789       for( int n=0; n < nItems ; n++ )
1790         fprintf(f,"%f\n",vals[n]);
1791     }
1792     free (ts1);
1793   }
1794   phastaio_addWriteTime(phiotmrc()-t0);
1795   phastaio_addWriteBytes(nItems*type_size);
1796 }
1797 
1798 void writedatablock(
1799     const int* fileDescriptor,
1800     const char keyphrase[],
1801     const void* valueArray,
1802     const int* nItems,
1803     const char datatype[],
1804     const char iotype[] )
1805 {
1806   //if(irank == 0) printf("entering writedatablock()\n");
1807 
1808   unsigned long data_size = 0;
1809   double timer_start, timer_end;
1810   startTimer(&timer_start);
1811 
1812   int i = *fileDescriptor;
1813   checkFileDescriptor("writedatablock",&i);
1814 
1815   if ( PhastaIONextActiveIndex == 0 ) {
1816     int filePtr = *fileDescriptor - 1;
1817 
1818     if ( *fileDescriptor < 1 || *fileDescriptor > (int)fileArray.size() ) {
1819       fprintf(stderr,"No file associated with Descriptor %d\n",*fileDescriptor);
1820       fprintf(stderr,"openfile_ function has to be called before \n") ;
1821       fprintf(stderr,"acessing the file\n ") ;
1822       fprintf(stderr,"fatal error: cannot continue, returning out of call\n");
1823       endTimer(&timer_end);
1824       printPerf("writedatablock", timer_start, timer_end, 0, 0, "");
1825       return;
1826     }
1827     // since we require that a consistant header always preceed the data block
1828     // let us check to see that it is actually the case.
1829 
1830     if ( ! cscompare( LastHeaderKey[ filePtr ].c_str(), keyphrase ) ) {
1831       fprintf(stderr, "Header not consistant with data block\n");
1832       fprintf(stderr, "Header: %s\n", LastHeaderKey[ filePtr ].c_str() );
1833       fprintf(stderr, "DataBlock: %s\n ", keyphrase );
1834       fprintf(stderr, "Please recheck write sequence \n");
1835       if( Strict_Error ) {
1836         fprintf(stderr, "fatal error: cannot continue, returning out of call\n");
1837         endTimer(&timer_end);
1838         printPerf("writedatablock", timer_start, timer_end, 0, 0, "");
1839         return;
1840       }
1841     }
1842 
1843     FILE* fileObject =  fileArray[ filePtr ] ;
1844     size_t type_size=typeSize( datatype );
1845     isBinary( iotype );
1846 
1847     LastHeaderKey.erase(filePtr);
1848 
1849     if ( header_type[filePtr] != (int)type_size ) {
1850       fprintf(stderr,"header and datablock differ on typeof data in the block for\n");
1851       fprintf(stderr,"keyphrase : %s\n", keyphrase);
1852       if( Strict_Error ) {
1853         fprintf(stderr,"fatal error: cannot continue, returning out of call\n" );
1854         endTimer(&timer_end);
1855         printPerf("writedatablock", timer_start, timer_end, 0, 0, "");
1856         return;
1857       }
1858     }
1859 
1860     int nUnits = *nItems;
1861 
1862     if ( nUnits != DataSize ) {
1863       fprintf(stderr,"header and datablock differ on number of data items for\n");
1864       fprintf(stderr,"keyphrase : %s\n", keyphrase);
1865       if( Strict_Error ) {
1866         fprintf(stderr,"fatal error: cannot continue, returning out of call\n" );
1867         endTimer(&timer_end);
1868         printPerf("writedatablock", timer_start, timer_end, 0, 0, "");
1869         return;
1870       }
1871     }
1872     writeDataBlock(fileObject,valueArray,*nItems,datatype,iotype);
1873   }
1874   else {  // syncIO case
1875     MPI_Status write_data_status;
1876     isBinary( iotype );
1877     int nUnits = *nItems;
1878 
1879     //MR CHANGE
1880     // 	if ( cscompare(datatype,"double") )
1881     char* ts1 = StringStripper( datatype );
1882     if ( cscompare("double",ts1) )
1883       //MR CHANGE END
1884     {
1885       memcpy((PhastaIOActiveFiles[i]->double_chunk+DB_HEADER_SIZE/sizeof(double)), valueArray, nUnits*sizeof(double));
1886       double t0 = phiotmrc();
1887       MPI_File_write_at_all_begin( PhastaIOActiveFiles[i]->file_handle,
1888           PhastaIOActiveFiles[i]->my_offset,
1889           PhastaIOActiveFiles[i]->double_chunk,
1890           //BLOCK_SIZE/sizeof(double),
1891           nUnits+DB_HEADER_SIZE/sizeof(double),
1892           MPI_DOUBLE );
1893       MPI_File_write_at_all_end( PhastaIOActiveFiles[i]->file_handle,
1894           PhastaIOActiveFiles[i]->double_chunk,
1895           &write_data_status );
1896       data_size=8*nUnits;
1897       phastaio_addWriteTime(phiotmrc()-t0);
1898       phastaio_addWriteBytes((nUnits*sizeof(double))+DB_HEADER_SIZE);
1899     }
1900     //MR CHANGE
1901     // 	else if ( cscompare ( datatype, "integer"))
1902     else if ( cscompare("integer",ts1) )
1903       //MR CHANGE END
1904     {
1905       memcpy((PhastaIOActiveFiles[i]->int_chunk+DB_HEADER_SIZE/sizeof(int)), valueArray, nUnits*sizeof(int));
1906       double t0 = phiotmrc();
1907       MPI_File_write_at_all_begin( PhastaIOActiveFiles[i]->file_handle,
1908           PhastaIOActiveFiles[i]->my_offset,
1909           PhastaIOActiveFiles[i]->int_chunk,
1910           nUnits+DB_HEADER_SIZE/sizeof(int),
1911           MPI_INT );
1912       MPI_File_write_at_all_end( PhastaIOActiveFiles[i]->file_handle,
1913           PhastaIOActiveFiles[i]->int_chunk,
1914           &write_data_status );
1915       data_size=4*nUnits;
1916       phastaio_addWriteTime(phiotmrc()-t0);
1917       phastaio_addWriteBytes((nUnits*sizeof(int))+DB_HEADER_SIZE);
1918     }
1919     else {
1920       printf("Error: writedatablock - DATA_TYPE_ILLEGAL - %s\n",datatype);
1921       endTimer(&timer_end);
1922       printPerf("writedatablock", timer_start, timer_end, 0, 0, "");
1923       return;
1924     }
1925     free(ts1);
1926   }
1927 
1928   endTimer(&timer_end);
1929   char extra_msg[1024];
1930   memset(extra_msg, '\0', 1024);
1931   char* key = StringStripper(keyphrase);
1932   sprintf(extra_msg, " field is %s ", key);
1933   printPerf("writedatablock", timer_start, timer_end, data_size, 1, extra_msg);
1934   free(key);
1935 
1936 }
1937 
1938 void SwapArrayByteOrder( void* array, int nbytes, int nItems )
1939 {
1940   /* This swaps the byte order for the array of nItems each
1941      of size nbytes , This will be called only locally  */
1942   int i,j;
1943   unsigned char* ucDst = (unsigned char*)array;
1944   for(i=0; i < nItems; i++) {
1945     for(j=0; j < (nbytes/2); j++)
1946       std::swap( ucDst[j] , ucDst[(nbytes - 1) - j] );
1947     ucDst += nbytes;
1948   }
1949 }
1950 
1951 void writestring( int* fileDescriptor, const char inString[] )
1952 {
1953   int filePtr = *fileDescriptor - 1;
1954   FILE* fileObject = fileArray[filePtr] ;
1955   fprintf(fileObject,"%s",inString );
1956   return;
1957 }
1958 
1959 void Gather_Headers( int* fileDescriptor, vector< string >& headers )
1960 {
1961   FILE* fileObject;
1962   char Line[1024];
1963 
1964   fileObject = fileArray[ (*fileDescriptor)-1 ];
1965 
1966   while( !feof(fileObject) ) {
1967     fgets( Line, 1024, fileObject);
1968     if ( Line[0] == '#' ) {
1969       headers.push_back( Line );
1970     } else {
1971       break;
1972     }
1973   }
1974   rewind( fileObject );
1975   clearerr( fileObject );
1976 }
1977 
1978 void isWrong( void ) {
1979   (Wrong_Endian) ? fprintf(stdout,"YES\n") : fprintf(stdout,"NO\n");
1980 }
1981 
1982 void togglestrictmode( void ) { Strict_Error = !Strict_Error; }
1983 
1984 int isLittleEndian( void )
1985 {
1986   // this function returns a 1 if the current running architecture is
1987   // LittleEndian Byte Ordered, else it returns a zero
1988   union  {
1989     long a;
1990     char c[sizeof( long )];
1991   } endianUnion;
1992   endianUnion.a = 1 ;
1993   if ( endianUnion.c[sizeof(long)-1] != 1 ) return 1 ;
1994   else return 0;
1995 }
1996 
1997 namespace PHASTA {
1998   const char* const PhastaIO_traits<int>::type_string = "integer";
1999   const char* const PhastaIO_traits<double>::type_string = "double";
2000 }
2001