xref: /petsc/src/sys/fileio/sysio.c (revision 7d0a6c19129e7069c8a40e210b34ed62989173db)
1 
2 /*
3    This file contains simple binary read/write routines.
4  */
5 
6 #include "petscsys.h"
7 #include <errno.h>
8 #include <fcntl.h>
9 #if defined(PETSC_HAVE_UNISTD_H)
10 #include <unistd.h>
11 #endif
12 #if defined (PETSC_HAVE_IO_H)
13 #include <io.h>
14 #endif
15 #include "petscbt.h"
16 
17 #if !defined(PETSC_WORDS_BIGENDIAN)
18 
19 /* --------------------------------------------------------- */
20 #undef __FUNCT__
21 #define __FUNCT__ "PetscByteSwapEnum"
22 /*
23   PetscByteSwapEnum - Swap bytes in a  PETSc Enum
24 
25 */
26 PetscErrorCode  PetscByteSwapEnum(PetscEnum *buff,PetscInt n)
27 {
28   PetscInt   i,j;
29   PetscEnum   tmp = ENUM_DUMMY;
30   char       *ptr1,*ptr2 = (char*)&tmp;
31 
32   PetscFunctionBegin;
33   for (j=0; j<n; j++) {
34     ptr1 = (char*)(buff + j);
35     for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) {
36       ptr2[i] = ptr1[sizeof(PetscEnum)-1-i];
37     }
38     for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) {
39       ptr1[i] = ptr2[i];
40     }
41   }
42   PetscFunctionReturn(0);
43 }
44 
45 #undef __FUNCT__
46 #define __FUNCT__ "PetscByteSwapBool"
47 /*
48   PetscByteSwapBool - Swap bytes in a  PETSc Bool
49 
50 */
51 PetscErrorCode  PetscByteSwapBool(PetscBool *buff,PetscInt n)
52 {
53   PetscInt    i,j;
54   PetscBool   tmp = PETSC_FALSE;
55   char        *ptr1,*ptr2 = (char*)&tmp;
56 
57   PetscFunctionBegin;
58   for (j=0; j<n; j++) {
59     ptr1 = (char*)(buff + j);
60     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) {
61       ptr2[i] = ptr1[sizeof(PetscBool)-1-i];
62     }
63     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) {
64       ptr1[i] = ptr2[i];
65     }
66   }
67   PetscFunctionReturn(0);
68 }
69 
70 #undef __FUNCT__
71 #define __FUNCT__ "PetscByteSwapInt"
72 /*
73   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64 bits)
74 
75 */
76 PetscErrorCode  PetscByteSwapInt(PetscInt *buff,PetscInt n)
77 {
78   PetscInt  i,j,tmp = 0;
79   char       *ptr1,*ptr2 = (char*)&tmp;
80 
81   PetscFunctionBegin;
82   for (j=0; j<n; j++) {
83     ptr1 = (char*)(buff + j);
84     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) {
85       ptr2[i] = ptr1[sizeof(PetscInt)-1-i];
86     }
87     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) {
88       ptr1[i] = ptr2[i];
89     }
90   }
91   PetscFunctionReturn(0);
92 }
93 /* --------------------------------------------------------- */
94 #undef __FUNCT__
95 #define __FUNCT__ "PetscByteSwapShort"
96 /*
97   PetscByteSwapShort - Swap bytes in a short
98 */
99 PetscErrorCode  PetscByteSwapShort(short *buff,PetscInt n)
100 {
101   PetscInt   i,j;
102   short      tmp;
103   char       *ptr1,*ptr2 = (char*)&tmp;
104 
105   PetscFunctionBegin;
106   for (j=0; j<n; j++) {
107     ptr1 = (char*)(buff + j);
108     for (i=0; i<(PetscInt) sizeof(short); i++) {
109       ptr2[i] = ptr1[sizeof(int)-1-i];
110     }
111     for (i=0; i<(PetscInt) sizeof(short); i++) {
112       ptr1[i] = ptr2[i];
113     }
114   }
115   PetscFunctionReturn(0);
116 }
117 /* --------------------------------------------------------- */
118 #undef __FUNCT__
119 #define __FUNCT__ "PetscByteSwapScalar"
120 /*
121   PetscByteSwapScalar - Swap bytes in a double
122   Complex is dealt with as if array of double twice as long.
123 */
124 PetscErrorCode  PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
125 {
126   PetscInt  i,j;
127   PetscReal tmp,*buff1 = (PetscReal*)buff;
128   char      *ptr1,*ptr2 = (char*)&tmp;
129 
130   PetscFunctionBegin;
131 #if defined(PETSC_USE_COMPLEX)
132   n *= 2;
133 #endif
134   for (j=0; j<n; j++) {
135     ptr1 = (char*)(buff1 + j);
136     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) {
137       ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
138     }
139     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) {
140       ptr1[i] = ptr2[i];
141     }
142   }
143   PetscFunctionReturn(0);
144 }
145 /* --------------------------------------------------------- */
146 #undef __FUNCT__
147 #define __FUNCT__ "PetscByteSwapDouble"
148 /*
149   PetscByteSwapDouble - Swap bytes in a double
150 */
151 PetscErrorCode  PetscByteSwapDouble(double *buff,PetscInt n)
152 {
153   PetscInt i,j;
154   double   tmp,*buff1 = (double*)buff;
155   char     *ptr1,*ptr2 = (char*)&tmp;
156 
157   PetscFunctionBegin;
158   for (j=0; j<n; j++) {
159     ptr1 = (char*)(buff1 + j);
160     for (i=0; i<(PetscInt) sizeof(double); i++) {
161       ptr2[i] = ptr1[sizeof(double)-1-i];
162     }
163     for (i=0; i<(PetscInt) sizeof(double); i++) {
164       ptr1[i] = ptr2[i];
165     }
166   }
167   PetscFunctionReturn(0);
168 }
169 
170 #undef __FUNCT__
171 #define __FUNCT__ "PetscByteSwap"
172 PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count)
173 {
174   PetscErrorCode ierr;
175 
176   PetscFunctionBegin;
177   if      (pdtype == PETSC_INT)    {ierr = PetscByteSwapInt((PetscInt*)data,count);CHKERRQ(ierr);}
178   else if (pdtype == PETSC_ENUM)   {ierr = PetscByteSwapEnum((PetscEnum*)data,count);CHKERRQ(ierr);}
179   else if (pdtype == PETSC_BOOL)   {ierr = PetscByteSwapBool((PetscBool*)data,count);CHKERRQ(ierr);}
180   else if (pdtype == PETSC_SCALAR) {ierr = PetscByteSwapScalar((PetscScalar*)data,count);CHKERRQ(ierr);}
181   else if (pdtype == PETSC_DOUBLE) {ierr = PetscByteSwapDouble((double*)data,count);CHKERRQ(ierr);}
182   else if (pdtype == PETSC_SHORT)  {ierr = PetscByteSwapShort((short*)data,count);CHKERRQ(ierr);}
183   PetscFunctionReturn(0);
184 }
185 
186 #endif
187 /* --------------------------------------------------------- */
188 #undef __FUNCT__
189 #define __FUNCT__ "PetscBinaryRead"
190 /*@
191    PetscBinaryRead - Reads from a binary file.
192 
193    Not Collective
194 
195    Input Parameters:
196 +  fd - the file
197 .  n  - the number of items to read
198 -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
199 
200    Output Parameters:
201 .  p - the buffer
202 
203 
204 
205    Level: developer
206 
207    Notes:
208    PetscBinaryRead() uses byte swapping to work on all machines; the files
209    are written to file ALWAYS using big-endian ordering. On small-endian machines the numbers
210    are converted to the small-endian format when they are read in from the file.
211    When PETSc is ./configure with --with-64bit-indices the integers are written to the
212    file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices
213    is used.
214 
215    Concepts: files^reading binary
216    Concepts: binary files^reading
217 
218 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
219           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
220 @*/
221 PetscErrorCode  PetscBinaryRead(int fd,void *p,PetscInt n,PetscDataType type)
222 {
223   int               wsize,err;
224   size_t            m = (size_t) n,maxblock = 65536;
225   char              *pp = (char*)p;
226 #if !defined(PETSC_WORDS_BIGENDIAN)
227   PetscErrorCode    ierr;
228   void              *ptmp = p;
229 #endif
230 
231   PetscFunctionBegin;
232   if (!n) PetscFunctionReturn(0);
233 
234   if (type == PETSC_INT)          m *= sizeof(PetscInt);
235   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
236   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
237   else if (type == PETSC_SHORT)   m *= sizeof(short);
238   else if (type == PETSC_CHAR)    m *= sizeof(char);
239   else if (type == PETSC_ENUM)    m *= sizeof(PetscEnum);
240   else if (type == PETSC_BOOL)   m *= sizeof(PetscBool);
241   else if (type == PETSC_BIT_LOGICAL) m  = PetscBTLength(m)*sizeof(char);
242   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
243 
244   while (m) {
245     wsize = (m < maxblock) ? m : maxblock;
246     err = read(fd,pp,wsize);
247     if (err < 0 && errno == EINTR) continue;
248     if (!err && wsize > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Read past end of file");
249     if (err < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
250     m  -= err;
251     pp += err;
252   }
253 #if !defined(PETSC_WORDS_BIGENDIAN)
254   ierr = PetscByteSwap(ptmp,type,n);CHKERRQ(ierr);
255 #endif
256 
257   PetscFunctionReturn(0);
258 }
259 /* --------------------------------------------------------- */
260 #undef __FUNCT__
261 #define __FUNCT__ "PetscBinaryWrite"
262 /*@
263    PetscBinaryWrite - Writes to a binary file.
264 
265    Not Collective
266 
267    Input Parameters:
268 +  fd     - the file
269 .  p      - the buffer
270 .  n      - the number of items to write
271 .  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
272 -  istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.
273 
274    Level: advanced
275 
276    Notes:
277    PetscBinaryWrite() uses byte swapping to work on all machines; the files
278    are written using big-endian ordering to the file. On small-endian machines the numbers
279    are converted to the big-endian format when they are written to disk.
280    When PETSc is ./configure with --with-64bit-indices the integers are written to the
281    file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices
282    is used.
283 
284    The Buffer p should be read-write buffer, and not static data.
285    This way, byte-swapping is done in-place, and then the buffer is
286    written to the file.
287 
288    This routine restores the original contents of the buffer, after
289    it is written to the file. This is done by byte-swapping in-place
290    the second time. If the flag istemp is set to PETSC_TRUE, the second
291    byte-swapping operation is not done, thus saving some computation,
292    but the buffer corrupted is corrupted.
293 
294    Because byte-swapping may be done on the values in data it cannot be declared const
295 
296    Concepts: files^writing binary
297    Concepts: binary files^writing
298 
299 .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
300           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
301 @*/
302 PetscErrorCode  PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscBool  istemp)
303 {
304   char           *pp = (char*)p;
305   int            err,wsize;
306   size_t         m = (size_t)n,maxblock=65536;
307 #if !defined(PETSC_WORDS_BIGENDIAN)
308   PetscErrorCode ierr;
309   void           *ptmp = p;
310 #endif
311 
312   PetscFunctionBegin;
313   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
314   if (!n) PetscFunctionReturn(0);
315 
316   if (type == PETSC_INT)          m *= sizeof(PetscInt);
317   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
318   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
319   else if (type == PETSC_SHORT)   m *= sizeof(short);
320   else if (type == PETSC_CHAR)    m *= sizeof(char);
321   else if (type == PETSC_ENUM)    m *= sizeof(PetscEnum);
322   else if (type == PETSC_BOOL)   m *= sizeof(PetscBool);
323   else if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
324   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
325 
326 #if !defined(PETSC_WORDS_BIGENDIAN)
327   ierr = PetscByteSwap(ptmp,type,n);CHKERRQ(ierr);
328 #endif
329 
330   while (m) {
331     wsize = (m < maxblock) ? m : maxblock;
332     err = write(fd,pp,wsize);
333     if (err < 0 && errno == EINTR) continue;
334     if (err != wsize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_WRITE,"Error writing to file.");
335     m -= wsize;
336     pp += wsize;
337   }
338 
339 #if !defined(PETSC_WORDS_BIGENDIAN)
340   if (!istemp) {
341     ierr = PetscByteSwap(ptmp,type,n);CHKERRQ(ierr);
342   }
343 #endif
344   PetscFunctionReturn(0);
345 }
346 
347 #undef __FUNCT__
348 #define __FUNCT__ "PetscBinaryOpen"
349 /*@C
350    PetscBinaryOpen - Opens a PETSc binary file.
351 
352    Not Collective
353 
354    Input Parameters:
355 +  name - filename
356 -  type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE
357 
358    Output Parameter:
359 .  fd - the file
360 
361    Level: advanced
362 
363   Concepts: files^opening binary
364   Concepts: binary files^opening
365 
366    Notes: Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
367    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
368    PetscBinaryRead() and PetscBinaryWrite() on any machine.
369 
370 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
371           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
372 
373 @*/
374 PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
375 {
376   PetscFunctionBegin;
377 #if defined(PETSC_HAVE_O_BINARY)
378   if (mode == FILE_MODE_WRITE) {
379     if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
380       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
381     }
382   } else if (mode == FILE_MODE_READ) {
383     if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
384       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
385     }
386   } else if (mode == FILE_MODE_APPEND) {
387     if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
388       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
389     }
390 #else
391   if (mode == FILE_MODE_WRITE) {
392     if ((*fd = creat(name,0666)) == -1) {
393       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
394     }
395   } else if (mode == FILE_MODE_READ) {
396     if ((*fd = open(name,O_RDONLY,0)) == -1) {
397       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
398     }
399   }
400   else if (mode == FILE_MODE_APPEND) {
401     if ((*fd = open(name,O_WRONLY,0)) == -1) {
402       SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
403     }
404 #endif
405   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
406   PetscFunctionReturn(0);
407 }
408 
409 #undef __FUNCT__
410 #define __FUNCT__ "PetscBinaryClose"
411 /*@
412    PetscBinaryClose - Closes a PETSc binary file.
413 
414    Not Collective
415 
416    Output Parameter:
417 .  fd - the file
418 
419    Level: advanced
420 
421 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
422           PetscBinarySynchronizedSeek()
423 @*/
424 PetscErrorCode  PetscBinaryClose(int fd)
425 {
426   PetscFunctionBegin;
427   close(fd);
428   PetscFunctionReturn(0);
429 }
430 
431 
432 #undef __FUNCT__
433 #define __FUNCT__ "PetscBinarySeek"
434 /*@
435    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
436 
437    Not Collective
438 
439    Input Parameters:
440 +  fd - the file
441 .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
442             etc. in your calculation rather than sizeof() to compute byte lengths.
443 -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
444             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
445             if PETSC_BINARY_SEEK_END then off is an offset from the end of file
446 
447    Output Parameter:
448 .   offset - new offset in file
449 
450    Level: developer
451 
452    Notes:
453    Integers are stored on the file as 32 long, regardless of whether
454    they are stored in the machine as 32 or 64, this means the same
455    binary file may be read on any machine. Hence you CANNOT use sizeof()
456    to determine the offset or location.
457 
458    Concepts: files^binary seeking
459    Concepts: binary files^seeking
460 
461 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
462           PetscBinarySynchronizedSeek()
463 @*/
464 PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
465 {
466   int iwhence = 0;
467 
468   PetscFunctionBegin;
469   if (whence == PETSC_BINARY_SEEK_SET) {
470     iwhence = SEEK_SET;
471   } else if (whence == PETSC_BINARY_SEEK_CUR) {
472     iwhence = SEEK_CUR;
473   } else if (whence == PETSC_BINARY_SEEK_END) {
474     iwhence = SEEK_END;
475   } else {
476     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
477   }
478 #if defined(PETSC_HAVE_LSEEK)
479   *offset = lseek(fd,off,iwhence);
480 #elif defined(PETSC_HAVE__LSEEK)
481   *offset = _lseek(fd,(long)off,iwhence);
482 #else
483   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
484 #endif
485   PetscFunctionReturn(0);
486 }
487 
488 #undef __FUNCT__
489 #define __FUNCT__ "PetscBinarySynchronizedRead"
490 /*@C
491    PetscBinarySynchronizedRead - Reads from a binary file.
492 
493    Collective on MPI_Comm
494 
495    Input Parameters:
496 +  comm - the MPI communicator
497 .  fd - the file
498 .  n  - the number of items to read
499 -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
500 
501    Output Parameters:
502 .  p - the buffer
503 
504    Options Database Key:
505 .   -binary_longints - indicates the file was generated on a Cray vector
506          machine (not the T3E/D) and the ints are stored as 64 bit
507          quantities, otherwise they are stored as 32 bit
508 
509    Level: developer
510 
511    Notes:
512    Does a PetscBinaryRead() followed by an MPI_Bcast()
513 
514    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
515    Integers are stored on the file as 32 long, regardless of whether
516    they are stored in the machine as 32 or 64, this means the same
517    binary file may be read on any machine.
518 
519    Concepts: files^synchronized reading of binary files
520    Concepts: binary files^reading, synchronized
521 
522 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
523           PetscBinarySynchronizedSeek()
524 @*/
525 PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
526 {
527   PetscErrorCode ierr;
528   PetscMPIInt    rank;
529   MPI_Datatype   mtype;
530 
531   PetscFunctionBegin;
532   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
533   if (!rank) {
534     ierr = PetscBinaryRead(fd,p,n,type);CHKERRQ(ierr);
535   }
536   ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
537   ierr = MPI_Bcast(p,n,mtype,0,comm);CHKERRQ(ierr);
538   PetscFunctionReturn(0);
539 }
540 
541 #undef __FUNCT__
542 #define __FUNCT__ "PetscBinarySynchronizedWrite"
543 /*@C
544    PetscBinarySynchronizedWrite - writes to a binary file.
545 
546    Collective on MPI_Comm
547 
548    Input Parameters:
549 +  comm - the MPI communicator
550 .  fd - the file
551 .  n  - the number of items to write
552 .  p - the buffer
553 .  istemp - the buffer may be changed
554 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
555 
556    Level: developer
557 
558    Notes:
559    Process 0 does a PetscBinaryWrite()
560 
561    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
562    Integers are stored on the file as 32 long, regardless of whether
563    they are stored in the machine as 32 or 64, this means the same
564    binary file may be read on any machine.
565 
566    Notes: because byte-swapping may be done on the values in data it cannot be declared const
567 
568    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
569    while PetscSynchronizedFPrintf() has all processes print their strings in order.
570 
571    Concepts: files^synchronized writing of binary files
572    Concepts: binary files^reading, synchronized
573 
574 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
575           PetscBinarySynchronizedSeek()
576 @*/
577 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscBool  istemp)
578 {
579   PetscErrorCode ierr;
580   PetscMPIInt    rank;
581 
582   PetscFunctionBegin;
583   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
584   if (!rank) {
585     ierr = PetscBinaryWrite(fd,p,n,type,istemp);CHKERRQ(ierr);
586   }
587   PetscFunctionReturn(0);
588 }
589 
590 #undef __FUNCT__
591 #define __FUNCT__ "PetscBinarySynchronizedSeek"
592 /*@C
593    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
594 
595 
596    Input Parameters:
597 +  fd - the file
598 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
599             if PETSC_BINARY_SEEK_CUR then size is offset from current location
600             if PETSC_BINARY_SEEK_END then size is offset from end of file
601 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
602             etc. in your calculation rather than sizeof() to compute byte lengths.
603 
604    Output Parameter:
605 .   offset - new offset in file
606 
607    Level: developer
608 
609    Notes:
610    Integers are stored on the file as 32 long, regardless of whether
611    they are stored in the machine as 32 or 64, this means the same
612    binary file may be read on any machine. Hence you CANNOT use sizeof()
613    to determine the offset or location.
614 
615    Concepts: binary files^seeking
616    Concepts: files^seeking in binary
617 
618 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
619           PetscBinarySynchronizedSeek()
620 @*/
621 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
622 {
623   PetscErrorCode ierr;
624   PetscMPIInt    rank;
625 
626   PetscFunctionBegin;
627   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
628   if (!rank) {
629     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
630   }
631   PetscFunctionReturn(0);
632 }
633 
634 #if defined(PETSC_HAVE_MPIIO)
635 #if !defined(PETSC_WORDS_BIGENDIAN)
636 
637 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
638 EXTERN_C_BEGIN
639 /*
640       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
641     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
642 
643     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
644 
645     The next three routines are not used because MPICH does not support their use
646 
647 */
648 PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
649 {
650   MPI_Aint    ub;
651   PetscMPIInt ierr;
652 
653   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
654   return ierr;
655 }
656 
657 PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
658 {
659   PetscDataType pdtype;
660   PetscMPIInt   ierr;
661   size_t        dsize;
662 
663   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
664   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
665 
666   /* offset is given in units of MPI_Datatype */
667   userbuf = ((char *)userbuf) + dsize*position;
668 
669   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
670   ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);
671   return ierr;
672 }
673 
674 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
675 {
676   PetscDataType pdtype;
677   PetscMPIInt   ierr;
678   size_t        dsize;
679 
680   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
681   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
682 
683   /* offset is given in units of MPI_Datatype */
684   userbuf = ((char *)userbuf) + dsize*position;
685 
686   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
687   ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);
688   return ierr;
689 }
690 EXTERN_C_END
691 #endif
692 
693 #undef __FUNCT__
694 #define __FUNCT__ "MPIU_File_write_all"
695 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
696 {
697   PetscErrorCode ierr;
698   PetscDataType  pdtype;
699 
700   PetscFunctionBegin;
701   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
702   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
703   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
704   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
705   PetscFunctionReturn(0);
706 }
707 
708 #undef __FUNCT__
709 #define __FUNCT__ "MPIU_File_read_all"
710 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
711 {
712   PetscErrorCode ierr;
713   PetscDataType  pdtype;
714 
715   PetscFunctionBegin;
716   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
717   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
718   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
719   PetscFunctionReturn(0);
720 }
721 #endif
722 #endif
723