Actual source code: sysio.c

petsc-master 2020-12-02
Report Typos and Errors

  2: /*
  3:    This file contains simple binary read/write routines.
  4:  */

  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

 20: const char *const PetscFileModes[] = {"READ","WRITE","APPEND","UPDATE","APPEND_UPDATE","PetscFileMode","PETSC_FILE_",NULL};

 22: /* --------------------------------------------------------- */
 23: /*
 24:   PetscByteSwapEnum - Swap bytes in a  PETSc Enum

 26: */
 27: PetscErrorCode  PetscByteSwapEnum(PetscEnum *buff,PetscInt n)
 28: {
 29:   PetscInt  i,j;
 30:   PetscEnum tmp = ENUM_DUMMY;
 31:   char      *ptr1,*ptr2 = (char*)&tmp;

 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:   return(0);
 40: }

 42: /*
 43:   PetscByteSwapBool - Swap bytes in a  PETSc Bool

 45: */
 46: PetscErrorCode  PetscByteSwapBool(PetscBool *buff,PetscInt n)
 47: {
 48:   PetscInt  i,j;
 49:   PetscBool tmp = PETSC_FALSE;
 50:   char      *ptr1,*ptr2 = (char*)&tmp;

 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:   return(0);
 59: }

 61: /*
 62:   PetscByteSwapInt - Swap bytes in a  PETSc integer (which may be 32 or 64 bits)

 64: */
 65: PetscErrorCode  PetscByteSwapInt(PetscInt *buff,PetscInt n)
 66: {
 67:   PetscInt i,j,tmp = 0;
 68:   char     *ptr1,*ptr2 = (char*)&tmp;

 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:   return(0);
 77: }

 79: /*
 80:   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64 bits)

 82: */
 83: PetscErrorCode  PetscByteSwapInt64(PetscInt64 *buff,PetscInt n)
 84: {
 85:   PetscInt   i,j;
 86:   PetscInt64 tmp = 0;
 87:   char       *ptr1,*ptr2 = (char*)&tmp;

 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:   return(0);
 96: }

 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;

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:   return(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;

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:   return(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;

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:   return(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;

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:   return(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;

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:   return(0);
190: }

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;

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:   return(0);
208: }

210: PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count)
211: {

215:   if      (pdtype == PETSC_INT)    {PetscByteSwapInt((PetscInt*)data,count);}
216:   else if (pdtype == PETSC_ENUM)   {PetscByteSwapEnum((PetscEnum*)data,count);}
217:   else if (pdtype == PETSC_BOOL)   {PetscByteSwapBool((PetscBool*)data,count);}
218:   else if (pdtype == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)data,count);}
219:   else if (pdtype == PETSC_REAL)   {PetscByteSwapReal((PetscReal*)data,count);}
220:   else if (pdtype == PETSC_COMPLEX){PetscByteSwapReal((PetscReal*)data,2*count);}
221:   else if (pdtype == PETSC_INT64)  {PetscByteSwapInt64((PetscInt64*)data,count);}
222:   else if (pdtype == PETSC_DOUBLE) {PetscByteSwapDouble((double*)data,count);}
223:   else if (pdtype == PETSC_FLOAT)  {PetscByteSwapFloat((float*)data,count);}
224:   else if (pdtype == PETSC_SHORT)  {PetscByteSwapShort((short*)data,count);}
225:   else if (pdtype == PETSC_LONG)   {PetscByteSwapLong((long*)data,count);}
226:   return(0);
227: }

229: /*@C
230:    PetscBinaryRead - Reads from a binary file.

232:    Not Collective

234:    Input Parameters:
235: +  fd - the file descriptor
236: .  num  - the maximum number of items to read
237: -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)

239:    Output Parameters:
240: +  data - the buffer
241: -  count - the number of items read, optional

243:    Level: developer

245:    Notes:
246:    If count is not provided and the number of items read is less than
247:    the maximum number of items to read, then this routine errors.

249:    PetscBinaryRead() uses byte swapping to work on all machines; the files
250:    are written to file ALWAYS using big-endian ordering. On little-endian machines the numbers
251:    are converted to the little-endian format when they are read in from the file.
252:    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
253:    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
254:    is used.

256: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
257:           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
258: @*/
259: PetscErrorCode  PetscBinaryRead(int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
260: {
261:   size_t            typesize, m = (size_t) num, n = 0, maxblock = 65536;
262:   char              *p = (char*)data;
263: #if defined(PETSC_USE_REAL___FLOAT128)
264:   PetscBool         readdouble = PETSC_FALSE;
265:   double            *pdouble;
266: #endif
267:   void              *ptmp = data;
268:   char              *fname = NULL;
269:   PetscErrorCode    ierr;

272:   if (count) *count = 0;
273:   if (num < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to read a negative amount of data %D",num);
274:   if (!num) return(0);

276:   if (type == PETSC_FUNCTION) {
277:     m     = 64;
278:     type  = PETSC_CHAR;
279:     fname = (char*)malloc(m*sizeof(char));
280:     p     = (char*)fname;
281:     ptmp  = (void*)fname;
282:     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
283:   }
284:   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m);

286:   PetscDataTypeGetSize(type,&typesize);

288: #if defined(PETSC_USE_REAL___FLOAT128)
289:   PetscOptionsGetBool(NULL,NULL,"-binary_read_double",&readdouble,NULL);
290:   /* If using __float128 precision we still read in doubles from file */
291:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
292:     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
293:     PetscMalloc1(cnt,&pdouble);
294:     p = (char*)pdouble;
295:     typesize /= 2;
296:   }
297: #endif

299:   m *= typesize;

301:   while (m) {
302:     size_t len = (m < maxblock) ? m : maxblock;
303:     int    ret = (int)read(fd,p,len);
304:     if (ret < 0 && errno == EINTR) continue;
305:     if (!ret && len > 0) break; /* Proxy for EOF */
306:     if (ret < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
307:     m -= ret;
308:     p += ret;
309:     n += ret;
310:   }
311:   if (m && !count) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Read past end of file");

313:   num = (PetscInt)(n/typesize); /* Should we require `n % typesize == 0` ? */
314:   if (count) *count = num;      /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */

316: #if defined(PETSC_USE_REAL___FLOAT128)
317:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
318:     PetscInt  i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
319:     PetscReal *preal = (PetscReal*)data;
320:     if (!PetscBinaryBigEndian()) {PetscByteSwapDouble(pdouble,cnt);}
321:     for (i=0; i<cnt; i++) preal[i] = pdouble[i];
322:     PetscFree(pdouble);
323:     return(0);
324:   }
325: #endif

327:   if (!PetscBinaryBigEndian()) {PetscByteSwap(ptmp,type,num);}

329:   if (type == PETSC_FUNCTION) {
330: #if defined(PETSC_SERIALIZE_FUNCTIONS)
331:     PetscDLSym(NULL,fname,(void**)data);
332: #else
333:     *(void**)data = NULL;
334: #endif
335:     free(fname);
336:   }
337:   return(0);
338: }

340: /*@C
341:    PetscBinaryWrite - Writes to a binary file.

343:    Not Collective

345:    Input Parameters:
346: +  fd     - the file
347: .  p      - the buffer
348: .  n      - the number of items to write
349: -  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

351:    Level: advanced

353:    Notes:
354:    PetscBinaryWrite() uses byte swapping to work on all machines; the files
355:    are written using big-endian ordering to the file. On little-endian machines the numbers
356:    are converted to the big-endian format when they are written to disk.
357:    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
358:    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
359:    is used.

361:    If running with __float128 precision the output is in __float128 unless one uses the -binary_write_double option

363:    The Buffer p should be read-write buffer, and not static data.
364:    This way, byte-swapping is done in-place, and then the buffer is
365:    written to the file.

367:    This routine restores the original contents of the buffer, after
368:    it is written to the file. This is done by byte-swapping in-place
369:    the second time.

371:    Because byte-swapping may be done on the values in data it cannot be declared const


374: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
375:           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
376: @*/
377: PetscErrorCode  PetscBinaryWrite(int fd,const void *p,PetscInt n,PetscDataType type)
378: {
379:   const char     *pp = (char*)p;
380:   int            err,wsize;
381:   size_t         m = (size_t)n,maxblock=65536;
383:   const void     *ptmp = p;
384:   char           *fname = NULL;
385: #if defined(PETSC_USE_REAL___FLOAT128)
386:   PetscBool      writedouble = PETSC_FALSE;
387:   double         *ppp;
388:   PetscReal      *pv;
389:   PetscInt       i;
390: #endif
391:   PetscDataType  wtype = type;

394:   if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n);
395:   if (!n) return(0);

397:   if (type == PETSC_FUNCTION) {
398: #if defined(PETSC_SERIALIZE_FUNCTIONS)
399:     const char *fnametmp;
400: #endif
401:     m     = 64;
402:     fname = (char*)malloc(m*sizeof(char));
403:     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
404: #if defined(PETSC_SERIALIZE_FUNCTIONS)
405:     if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
406:     PetscFPTFind(*(void**)p,&fnametmp);
407:     PetscStrncpy(fname,fnametmp,m);
408: #else
409:     PetscStrncpy(fname,"",m);
410: #endif
411:     wtype = PETSC_CHAR;
412:     pp    = (char*)fname;
413:     ptmp  = (void*)fname;
414:   }

416: #if defined(PETSC_USE_REAL___FLOAT128)
417:   PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);
418:   /* If using __float128 precision we still write in doubles to file */
419:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
420:     wtype = PETSC_DOUBLE;
421:     PetscMalloc1(n,&ppp);
422:     pv = (PetscReal*)pp;
423:     for (i=0; i<n; i++) {
424:       ppp[i] = (double) pv[i];
425:     }
426:     pp   = (char*)ppp;
427:     ptmp = (char*)ppp;
428:   }
429: #endif

431:   if (wtype == PETSC_INT)          m *= sizeof(PetscInt);
432:   else if (wtype == PETSC_SCALAR)  m *= sizeof(PetscScalar);
433: #if defined(PETSC_HAVE_COMPLEX)
434:   else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
435: #endif
436:   else if (wtype == PETSC_REAL)    m *= sizeof(PetscReal);
437:   else if (wtype == PETSC_DOUBLE)  m *= sizeof(double);
438:   else if (wtype == PETSC_FLOAT)   m *= sizeof(float);
439:   else if (wtype == PETSC_SHORT)   m *= sizeof(short);
440:   else if (wtype == PETSC_LONG)    m *= sizeof(long);
441:   else if (wtype == PETSC_CHAR)    m *= sizeof(char);
442:   else if (wtype == PETSC_ENUM)    m *= sizeof(PetscEnum);
443:   else if (wtype == PETSC_BOOL)    m *= sizeof(PetscBool);
444:   else if (wtype == PETSC_INT64)   m *= sizeof(PetscInt64);
445:   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
446:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");

448:   if (!PetscBinaryBigEndian()) {PetscByteSwap((void*)ptmp,wtype,n);}

450:   while (m) {
451:     wsize = (m < maxblock) ? m : maxblock;
452:     err   = write(fd,pp,wsize);
453:     if (err < 0 && errno == EINTR) continue;
454:     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);
455:     m  -= wsize;
456:     pp += wsize;
457:   }

459:   if (!PetscBinaryBigEndian()) {PetscByteSwap((void*)ptmp,wtype,n);}

461:   if (type == PETSC_FUNCTION) {
462:     free(fname);
463:   }
464: #if defined(PETSC_USE_REAL___FLOAT128)
465:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
466:     PetscFree(ppp);
467:   }
468: #endif
469:   return(0);
470: }

472: /*@C
473:    PetscBinaryOpen - Opens a PETSc binary file.

475:    Not Collective

477:    Input Parameters:
478: +  name - filename
479: -  mode - open mode of binary file, one of FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND

481:    Output Parameter:
482: .  fd - the file

484:    Level: advanced


487:    Notes:
488:     Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in
489:    big-endian format. This means the file can be accessed using PetscBinaryOpen() and
490:    PetscBinaryRead() and PetscBinaryWrite() on any machine.

492: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
493:           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()

495: @*/
496: PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
497: {
499:   switch (mode) {
500:   case FILE_MODE_READ:   *fd = open(name,O_BINARY|O_RDONLY,0); break;
501:   case FILE_MODE_WRITE:  *fd = open(name,O_BINARY|O_WRONLY|O_CREAT|O_TRUNC,0666); break;
502:   case FILE_MODE_APPEND: *fd = open(name,O_BINARY|O_WRONLY|O_APPEND,0); break;
503:   default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported file mode %s",PetscFileModes[mode]);
504:   }
505:   if (*fd == -1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file %s for %s: %s",name,PetscFileModes[mode]);
506:   return(0);
507: }

509: /*@
510:    PetscBinaryClose - Closes a PETSc binary file.

512:    Not Collective

514:    Output Parameter:
515: .  fd - the file

517:    Level: advanced

519: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
520:           PetscBinarySynchronizedSeek()
521: @*/
522: PetscErrorCode  PetscBinaryClose(int fd)
523: {
525:   if (close(fd)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"close() failed on file descriptor");
526:   return(0);
527: }


530: /*@C
531:    PetscBinarySeek - Moves the file pointer on a PETSc binary file.

533:    Not Collective

535:    Input Parameters:
536: +  fd - the file
537: .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
538:             etc. in your calculation rather than sizeof() to compute byte lengths.
539: -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
540:             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
541:             if PETSC_BINARY_SEEK_END then off is an offset from the end of file

543:    Output Parameter:
544: .   offset - new offset in file

546:    Level: developer

548:    Notes:
549:    Integers are stored on the file as 32 long, regardless of whether
550:    they are stored in the machine as 32 or 64, this means the same
551:    binary file may be read on any machine. Hence you CANNOT use sizeof()
552:    to determine the offset or location.


555: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
556:           PetscBinarySynchronizedSeek()
557: @*/
558: PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
559: {
560:   int iwhence = 0;

563:   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
564:   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
565:   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
566:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
567: #if defined(PETSC_HAVE_LSEEK)
568:   *offset = lseek(fd,off,iwhence);
569: #elif defined(PETSC_HAVE__LSEEK)
570:   *offset = _lseek(fd,(long)off,iwhence);
571: #else
572:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
573: #endif
574:   return(0);
575: }

577: /*@C
578:    PetscBinarySynchronizedRead - Reads from a binary file.

580:    Collective

582:    Input Parameters:
583: +  comm - the MPI communicator
584: .  fd - the file descriptor
585: .  num  - the maximum number of items to read
586: -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)

588:    Output Parameters:
589: +  data - the buffer
590: -  count - the number of items read, optional

592:    Level: developer

594:    Notes:
595:    Does a PetscBinaryRead() followed by an MPI_Bcast()

597:    If count is not provided and the number of items read is less than
598:    the maximum number of items to read, then this routine errors.

600:    PetscBinarySynchronizedRead() uses byte swapping to work on all machines.
601:    Integers are stored on the file as 32 long, regardless of whether
602:    they are stored in the machine as 32 or 64, this means the same
603:    binary file may be read on any machine.


606: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
607:           PetscBinarySynchronizedSeek()
608: @*/
609: PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
610: {
612:   PetscMPIInt    rank;
613:   MPI_Datatype   mtype;
614:   PetscInt       ibuf[2] = {0, 0};
615:   char           *fname = NULL;
616:   void           *fptr = NULL;

619:   if (type == PETSC_FUNCTION) {
620:     num   = 64;
621:     type  = PETSC_CHAR;
622:     fname = (char*)malloc(num*sizeof(char));
623:     fptr  = data;
624:     data  = (void*)fname;
625:     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
626:   }

628:   MPI_Comm_rank(comm,&rank);
629:   if (!rank) {
630:     ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
631:   }
632:   MPI_Bcast(ibuf,2,MPIU_INT,0,comm);
633:   (PetscErrorCode)ibuf[0];
634:   PetscDataTypeToMPIDataType(type,&mtype);
635:   MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);
636:   if (count) *count = ibuf[1];

638:   if (type == PETSC_FUNCTION) {
639: #if defined(PETSC_SERIALIZE_FUNCTIONS)
640:     PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);
641: #else
642:     *(void**)fptr = NULL;
643: #endif
644:     free(fname);
645:   }
646:   return(0);
647: }

649: /*@C
650:    PetscBinarySynchronizedWrite - writes to a binary file.

652:    Collective

654:    Input Parameters:
655: +  comm - the MPI communicator
656: .  fd - the file
657: .  n  - the number of items to write
658: .  p - the buffer
659: -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

661:    Level: developer

663:    Notes:
664:    Process 0 does a PetscBinaryWrite()

666:    PetscBinarySynchronizedWrite() uses byte swapping to work on all machines.
667:    Integers are stored on the file as 32 long, regardless of whether
668:    they are stored in the machine as 32 or 64, this means the same
669:    binary file may be read on any machine.

671:    Notes:
672:     because byte-swapping may be done on the values in data it cannot be declared const

674:    WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0,
675:    while PetscSynchronizedFPrintf() has all processes print their strings in order.


678: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
679:           PetscBinarySynchronizedSeek()
680: @*/
681: PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type)
682: {
684:   PetscMPIInt    rank;

687:   MPI_Comm_rank(comm,&rank);
688:   if (!rank) {
689:     PetscBinaryWrite(fd,p,n,type);
690:   }
691:   return(0);
692: }

694: /*@C
695:    PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file.


698:    Input Parameters:
699: +  fd - the file
700: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
701:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
702:             if PETSC_BINARY_SEEK_END then size is offset from end of file
703: -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
704:             etc. in your calculation rather than sizeof() to compute byte lengths.

706:    Output Parameter:
707: .   offset - new offset in file

709:    Level: developer

711:    Notes:
712:    Integers are stored on the file as 32 long, regardless of whether
713:    they are stored in the machine as 32 or 64, this means the same
714:    binary file may be read on any machine. Hence you CANNOT use sizeof()
715:    to determine the offset or location.


718: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
719:           PetscBinarySynchronizedSeek()
720: @*/
721: PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
722: {
724:   PetscMPIInt    rank;

727:   MPI_Comm_rank(comm,&rank);
728:   if (!rank) {
729:     PetscBinarySeek(fd,off,whence,offset);
730:   }
731:   return(0);
732: }

734: #if defined(PETSC_HAVE_MPIIO)

736: #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32)
737: /*
738:       MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions.
739:     These are set into MPI in PetscInitialize() via MPI_Register_datarep()

741:     Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode)

743:     The next three routines are not used because MPICH does not support their use

745: */
746: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
747: {
748:   MPI_Aint    ub;
749:   PetscMPIInt ierr;

751:   MPI_Type_get_extent(datatype,&ub,file_extent);
752:   return ierr;
753: }

755: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
756: {
757:   PetscDataType pdtype;
758:   PetscMPIInt   ierr;
759:   size_t        dsize;

761:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
762:   PetscDataTypeGetSize(pdtype,&dsize);

764:   /* offset is given in units of MPI_Datatype */
765:   userbuf = ((char*)userbuf) + dsize*position;

767:   PetscMemcpy(userbuf,filebuf,count*dsize);
768:   if (!PetscBinaryBigEndian()) {PetscByteSwap(userbuf,pdtype,count);}
769:   return ierr;
770: }

772: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
773: {
774:   PetscDataType pdtype;
775:   PetscMPIInt   ierr;
776:   size_t        dsize;

778:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
779:   PetscDataTypeGetSize(pdtype,&dsize);

781:   /* offset is given in units of MPI_Datatype */
782:   userbuf = ((char*)userbuf) + dsize*position;

784:   PetscMemcpy(filebuf,userbuf,count*dsize);
785:   if (!PetscBinaryBigEndian()) {PetscByteSwap(filebuf,pdtype,count);}
786:   return ierr;
787: }
788: #endif

790: PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
791: {
792:   PetscDataType  pdtype;


797:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
798:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
799:   MPI_File_write_all(fd,data,cnt,dtype,status);
800:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
801:   return(0);
802: }

804: PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
805: {
806:   PetscDataType  pdtype;

810:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
811:   MPI_File_read_all(fd,data,cnt,dtype,status);
812:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
813:   return(0);
814: }

816: PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
817: {
818:   PetscDataType  pdtype;


823:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
824:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
825:   MPI_File_write_at(fd,off,data,cnt,dtype,status);
826:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
827:   return(0);
828: }

830: PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
831: {
832:   PetscDataType  pdtype;

836:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
837:   MPI_File_read_at(fd,off,data,cnt,dtype,status);
838:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
839:   return(0);
840: }

842: PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
843: {
844:   PetscDataType  pdtype;


849:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
850:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
851:   MPI_File_write_at_all(fd,off,data,cnt,dtype,status);
852:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
853:   return(0);
854: }

856: PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
857: {
858:   PetscDataType  pdtype;

862:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
863:   MPI_File_read_at_all(fd,off,data,cnt,dtype,status);
864:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
865:   return(0);
866: }

868: #endif