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