xref: /petsc/src/sys/fileio/sysio.c (revision fa2bb9fe3cba50bac3b093e83d6f95e65b517df9)
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:
469     Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
470    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
471    PetscBinaryRead() and PetscBinaryWrite() on any machine.
472 
473 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
474           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
475 
476 @*/
477 PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
478 {
479   PetscFunctionBegin;
480 #if defined(PETSC_HAVE_O_BINARY)
481   if (mode == FILE_MODE_WRITE) {
482     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);
483   } else if (mode == FILE_MODE_READ) {
484     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);
485   } else if (mode == FILE_MODE_APPEND) {
486     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);
487 #else
488   if (mode == FILE_MODE_WRITE) {
489     if ((*fd = creat(name,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
490   } else if (mode == FILE_MODE_READ) {
491     if ((*fd = open(name,O_RDONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
492   }
493   else if (mode == FILE_MODE_APPEND) {
494     if ((*fd = open(name,O_WRONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
495 #endif
496   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
497   PetscFunctionReturn(0);
498 }
499 
500 /*@
501    PetscBinaryClose - Closes a PETSc binary file.
502 
503    Not Collective
504 
505    Output Parameter:
506 .  fd - the file
507 
508    Level: advanced
509 
510 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
511           PetscBinarySynchronizedSeek()
512 @*/
513 PetscErrorCode  PetscBinaryClose(int fd)
514 {
515   PetscFunctionBegin;
516   close(fd);
517   PetscFunctionReturn(0);
518 }
519 
520 
521 /*@C
522    PetscBinarySeek - Moves the file pointer on a PETSc binary file.
523 
524    Not Collective
525 
526    Input Parameters:
527 +  fd - the file
528 .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
529             etc. in your calculation rather than sizeof() to compute byte lengths.
530 -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
531             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
532             if PETSC_BINARY_SEEK_END then off is an offset from the end of file
533 
534    Output Parameter:
535 .   offset - new offset in file
536 
537    Level: developer
538 
539    Notes:
540    Integers are stored on the file as 32 long, regardless of whether
541    they are stored in the machine as 32 or 64, this means the same
542    binary file may be read on any machine. Hence you CANNOT use sizeof()
543    to determine the offset or location.
544 
545    Concepts: files^binary seeking
546    Concepts: binary files^seeking
547 
548 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
549           PetscBinarySynchronizedSeek()
550 @*/
551 PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
552 {
553   int iwhence = 0;
554 
555   PetscFunctionBegin;
556   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
557   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
558   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
559   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
560 #if defined(PETSC_HAVE_LSEEK)
561   *offset = lseek(fd,off,iwhence);
562 #elif defined(PETSC_HAVE__LSEEK)
563   *offset = _lseek(fd,(long)off,iwhence);
564 #else
565   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
566 #endif
567   PetscFunctionReturn(0);
568 }
569 
570 /*@C
571    PetscBinarySynchronizedRead - Reads from a binary file.
572 
573    Collective on MPI_Comm
574 
575    Input Parameters:
576 +  comm - the MPI communicator
577 .  fd - the file
578 .  n  - the number of items to read
579 -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
580 
581    Output Parameters:
582 .  p - the buffer
583 
584    Level: developer
585 
586    Notes:
587    Does a PetscBinaryRead() followed by an MPI_Bcast()
588 
589    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
590    Integers are stored on the file as 32 long, regardless of whether
591    they are stored in the machine as 32 or 64, this means the same
592    binary file may be read on any machine.
593 
594    Concepts: files^synchronized reading of binary files
595    Concepts: binary files^reading, synchronized
596 
597 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
598           PetscBinarySynchronizedSeek()
599 @*/
600 PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
601 {
602   PetscErrorCode ierr,ierrp=0;
603   PetscMPIInt    rank;
604   MPI_Datatype   mtype;
605   char           *fname = NULL;
606   void           *ptmp = NULL;
607 
608   PetscFunctionBegin;
609   if (type == PETSC_FUNCTION) {
610     n            = 64;
611     type         = PETSC_CHAR;
612     ptmp         = p;
613     fname        = (char*)malloc(n*sizeof(char));
614     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
615     p            = (void*)fname;
616   }
617 
618   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
619   if (!rank) {
620     ierrp = PetscBinaryRead(fd,p,n,type);
621   }
622   ierr = MPI_Bcast(&ierrp,1,MPI_INT,0,comm);CHKERRQ(ierr);
623   CHKERRQ(ierrp);
624   ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr);
625   ierr = MPI_Bcast(p,n,mtype,0,comm);CHKERRQ(ierr);
626 
627   if (type == PETSC_FUNCTION) {
628 #if defined(PETSC_SERIALIZE_FUNCTIONS)
629     ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)ptmp);CHKERRQ(ierr);
630 #else
631     *(void**)ptmp = NULL;
632 #endif
633     free(fname);
634   }
635   PetscFunctionReturn(0);
636 }
637 
638 /*@C
639    PetscBinarySynchronizedWrite - writes to a binary file.
640 
641    Collective on MPI_Comm
642 
643    Input Parameters:
644 +  comm - the MPI communicator
645 .  fd - the file
646 .  n  - the number of items to write
647 .  p - the buffer
648 .  istemp - the buffer may be changed
649 -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
650 
651    Level: developer
652 
653    Notes:
654    Process 0 does a PetscBinaryWrite()
655 
656    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
657    Integers are stored on the file as 32 long, regardless of whether
658    they are stored in the machine as 32 or 64, this means the same
659    binary file may be read on any machine.
660 
661    Notes:
662     because byte-swapping may be done on the values in data it cannot be declared const
663 
664    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
665    while PetscSynchronizedFPrintf() has all processes print their strings in order.
666 
667    Concepts: files^synchronized writing of binary files
668    Concepts: binary files^reading, synchronized
669 
670 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
671           PetscBinarySynchronizedSeek()
672 @*/
673 PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscBool istemp)
674 {
675   PetscErrorCode ierr;
676   PetscMPIInt    rank;
677 
678   PetscFunctionBegin;
679   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
680   if (!rank) {
681     ierr = PetscBinaryWrite(fd,p,n,type,istemp);CHKERRQ(ierr);
682   }
683   PetscFunctionReturn(0);
684 }
685 
686 /*@C
687    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.
688 
689 
690    Input Parameters:
691 +  fd - the file
692 .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
693             if PETSC_BINARY_SEEK_CUR then size is offset from current location
694             if PETSC_BINARY_SEEK_END then size is offset from end of file
695 -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
696             etc. in your calculation rather than sizeof() to compute byte lengths.
697 
698    Output Parameter:
699 .   offset - new offset in file
700 
701    Level: developer
702 
703    Notes:
704    Integers are stored on the file as 32 long, regardless of whether
705    they are stored in the machine as 32 or 64, this means the same
706    binary file may be read on any machine. Hence you CANNOT use sizeof()
707    to determine the offset or location.
708 
709    Concepts: binary files^seeking
710    Concepts: files^seeking in binary
711 
712 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
713           PetscBinarySynchronizedSeek()
714 @*/
715 PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
716 {
717   PetscErrorCode ierr;
718   PetscMPIInt    rank;
719 
720   PetscFunctionBegin;
721   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
722   if (!rank) {
723     ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr);
724   }
725   PetscFunctionReturn(0);
726 }
727 
728 #if defined(PETSC_HAVE_MPIIO)
729 #if !defined(PETSC_WORDS_BIGENDIAN)
730 
731 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
732 /*
733       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
734     These are set into MPI in PetscInitialize() via MPI_Register_datarep()
735 
736     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)
737 
738     The next three routines are not used because MPICH does not support their use
739 
740 */
741 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
742 {
743   MPI_Aint    ub;
744   PetscMPIInt ierr;
745 
746   ierr = MPI_Type_get_extent(datatype,&ub,file_extent);
747   return ierr;
748 }
749 
750 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
751 {
752   PetscDataType pdtype;
753   PetscMPIInt   ierr;
754   size_t        dsize;
755 
756   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
757   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
758 
759   /* offset is given in units of MPI_Datatype */
760   userbuf = ((char*)userbuf) + dsize*position;
761 
762   ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr);
763   ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);
764   return ierr;
765 }
766 
767 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
768 {
769   PetscDataType pdtype;
770   PetscMPIInt   ierr;
771   size_t        dsize;
772 
773   ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr);
774   ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr);
775 
776   /* offset is given in units of MPI_Datatype */
777   userbuf = ((char*)userbuf) + dsize*position;
778 
779   ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr);
780   ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);
781   return ierr;
782 }
783 #endif
784 
785 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
786 {
787   PetscErrorCode ierr;
788   PetscDataType  pdtype;
789 
790   PetscFunctionBegin;
791   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
792   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
793   ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
794   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
795   PetscFunctionReturn(0);
796 }
797 
798 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
799 {
800   PetscErrorCode ierr;
801   PetscDataType  pdtype;
802 
803   PetscFunctionBegin;
804   ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr);
805   ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr);
806   ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);
807   PetscFunctionReturn(0);
808 }
809 #endif
810 #endif
811