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