xref: /petsc/src/sys/fileio/sysio.c (revision 5b6bfdb9644f185dbf5e5a09b808ec241507e1e7)
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     wtype = 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,ierrp=0;
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     ierrp = PetscBinaryRead(fd,p,n,type);
620   }
621   ierr = MPI_Bcast(&ierrp,1,MPI_INT,0,comm);CHKERRQ(ierr);
622   CHKERRQ(ierrp);
623   ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
624   ierr = MPI_Bcast(p,n,mtype,0,comm);CHKERRQ(ierr);
625 
626   if (type == PETSC_FUNCTION) {
627 #if defined(PETSC_SERIALIZE_FUNCTIONS)
628     ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)ptmp);CHKERRQ(ierr);
629 #else
630     *(void**)ptmp = NULL;
631 #endif
632     free(fname);
633   }
634   PetscFunctionReturn(0);
635 }
636 
637 /*@C
638    PetscBinarySynchronizedWrite - writes to a binary file.
639 
640    Collective on MPI_Comm
641 
642    Input Parameters:
643 +  comm - the MPI communicator
644 .  fd - the file
645 .  n  - the number of items to write
646 .  p - the buffer
647 .  istemp - the buffer may be changed
648 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
649 
650    Level: developer
651 
652    Notes:
653    Process 0 does a PetscBinaryWrite()
654 
655    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
656    Integers are stored on the file as 32 long, regardless of whether
657    they are stored in the machine as 32 or 64, this means the same
658    binary file may be read on any machine.
659 
660    Notes: because byte-swapping may be done on the values in data it cannot be declared const
661 
662    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
663    while PetscSynchronizedFPrintf() has all processes print their strings in order.
664 
665    Concepts: files^synchronized writing of binary files
666    Concepts: binary files^reading, synchronized
667 
668 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
669           PetscBinarySynchronizedSeek()
670 @*/
671 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscBool istemp)
672 {
673   PetscErrorCode ierr;
674   PetscMPIInt    rank;
675 
676   PetscFunctionBegin;
677   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
678   if (!rank) {
679     ierr = PetscBinaryWrite(fd,p,n,type,istemp);CHKERRQ(ierr);
680   }
681   PetscFunctionReturn(0);
682 }
683 
684 /*@C
685    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
686 
687 
688    Input Parameters:
689 +  fd - the file
690 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
691             if PETSC_BINARY_SEEK_CUR then size is offset from current location
692             if PETSC_BINARY_SEEK_END then size is offset from end of file
693 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
694             etc. in your calculation rather than sizeof() to compute byte lengths.
695 
696    Output Parameter:
697 .   offset - new offset in file
698 
699    Level: developer
700 
701    Notes:
702    Integers are stored on the file as 32 long, regardless of whether
703    they are stored in the machine as 32 or 64, this means the same
704    binary file may be read on any machine. Hence you CANNOT use sizeof()
705    to determine the offset or location.
706 
707    Concepts: binary files^seeking
708    Concepts: files^seeking in binary
709 
710 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
711           PetscBinarySynchronizedSeek()
712 @*/
713 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
714 {
715   PetscErrorCode ierr;
716   PetscMPIInt    rank;
717 
718   PetscFunctionBegin;
719   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
720   if (!rank) {
721     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
722   }
723   PetscFunctionReturn(0);
724 }
725 
726 #if defined(PETSC_HAVE_MPIIO)
727 #if !defined(PETSC_WORDS_BIGENDIAN)
728 
729 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
730 /*
731       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
732     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
733 
734     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
735 
736     The next three routines are not used because MPICH does not support their use
737 
738 */
739 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
740 {
741   MPI_Aint    ub;
742   PetscMPIInt ierr;
743 
744   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
745   return ierr;
746 }
747 
748 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
749 {
750   PetscDataType pdtype;
751   PetscMPIInt   ierr;
752   size_t        dsize;
753 
754   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
755   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
756 
757   /* offset is given in units of MPI_Datatype */
758   userbuf = ((char*)userbuf) + dsize*position;
759 
760   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
761   ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);
762   return ierr;
763 }
764 
765 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
766 {
767   PetscDataType pdtype;
768   PetscMPIInt   ierr;
769   size_t        dsize;
770 
771   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
772   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
773 
774   /* offset is given in units of MPI_Datatype */
775   userbuf = ((char*)userbuf) + dsize*position;
776 
777   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
778   ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);
779   return ierr;
780 }
781 #endif
782 
783 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
784 {
785   PetscErrorCode ierr;
786   PetscDataType  pdtype;
787 
788   PetscFunctionBegin;
789   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
790   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
791   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
792   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
793   PetscFunctionReturn(0);
794 }
795 
796 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
797 {
798   PetscErrorCode ierr;
799   PetscDataType  pdtype;
800 
801   PetscFunctionBegin;
802   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
803   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
804   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
805   PetscFunctionReturn(0);
806 }
807 #endif
808 #endif
809