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