Date: 2021-03-03T22:25:41+00:00

Actual source code: sysio.c
petsc-3.14.5 2021-03-03
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,size;
    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:   MPI_Comm_size(comm,&size);
    630:   if (!rank) {
    631:     ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
    632:   }
    633:   MPI_Bcast(ibuf,2,MPIU_INT,0,comm);
    634:   (PetscErrorCode)ibuf[0];

    636:   /* 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 */
    637:   if (size > 1) {
    638:     PetscDataTypeToMPIDataType(type,&mtype);
    639:     MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);
    640:   }
    641:   if (count) *count = ibuf[1];

    643:   if (type == PETSC_FUNCTION) {
    644: #if defined(PETSC_SERIALIZE_FUNCTIONS)
    645:     PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);
    646: #else
    647:     *(void**)fptr = NULL;
    648: #endif
    649:     free(fname);
    650:   }
    651:   return(0);
    652: }

    654: /*@C
    655:    PetscBinarySynchronizedWrite - writes to a binary file.

    657:    Collective

    659:    Input Parameters:
    660: +  comm - the MPI communicator
    661: .  fd - the file
    662: .  n  - the number of items to write
    663: .  p - the buffer
    664: -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

    666:    Level: developer

    668:    Notes:
    669:    Process 0 does a PetscBinaryWrite()

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

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

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

    683: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
    684:           PetscBinarySynchronizedSeek()
    685: @*/
    686: PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type)
    687: {
    689:   PetscMPIInt    rank;

    692:   MPI_Comm_rank(comm,&rank);
    693:   if (!rank) {
    694:     PetscBinaryWrite(fd,p,n,type);
    695:   }
    696:   return(0);
    697: }

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

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

    711:    Output Parameter:
    712: .   offset - new offset in file

    714:    Level: developer

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

    723: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
    724:           PetscBinarySynchronizedSeek()
    725: @*/
    726: PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
    727: {
    729:   PetscMPIInt    rank;

    732:   MPI_Comm_rank(comm,&rank);
    733:   if (!rank) {
    734:     PetscBinarySeek(fd,off,whence,offset);
    735:   }
    736:   return(0);
    737: }

    739: #if defined(PETSC_HAVE_MPIIO)

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

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

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

    750: */
    751: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
    752: {
    753:   MPI_Aint    ub;
    754:   PetscMPIInt ierr;

    756:   MPI_Type_get_extent(datatype,&ub,file_extent);
    757:   return ierr;
    758: }

    760: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
    761: {
    762:   PetscDataType pdtype;
    763:   PetscMPIInt   ierr;
    764:   size_t        dsize;

    766:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
    767:   PetscDataTypeGetSize(pdtype,&dsize);

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

    772:   PetscMemcpy(userbuf,filebuf,count*dsize);
    773:   if (!PetscBinaryBigEndian()) {PetscByteSwap(userbuf,pdtype,count);}
    774:   return ierr;
    775: }

    777: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
    778: {
    779:   PetscDataType pdtype;
    780:   PetscMPIInt   ierr;
    781:   size_t        dsize;

    783:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
    784:   PetscDataTypeGetSize(pdtype,&dsize);

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

    789:   PetscMemcpy(filebuf,userbuf,count*dsize);
    790:   if (!PetscBinaryBigEndian()) {PetscByteSwap(filebuf,pdtype,count);}
    791:   return ierr;
    792: }
    793: #endif

    795: PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    796: {
    797:   PetscDataType  pdtype;

    802:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    803:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
    804:   MPI_File_write_all(fd,data,cnt,dtype,status);
    805:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
    806:   return(0);
    807: }

    809: PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    810: {
    811:   PetscDataType  pdtype;

    815:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    816:   MPI_File_read_all(fd,data,cnt,dtype,status);
    817:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
    818:   return(0);
    819: }

    821: PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    822: {
    823:   PetscDataType  pdtype;

    828:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    829:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
    830:   MPI_File_write_at(fd,off,data,cnt,dtype,status);
    831:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
    832:   return(0);
    833: }

    835: PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    836: {
    837:   PetscDataType  pdtype;

    841:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    842:   MPI_File_read_at(fd,off,data,cnt,dtype,status);
    843:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
    844:   return(0);
    845: }

    847: PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    848: {
    849:   PetscDataType  pdtype;

    854:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    855:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
    856:   MPI_File_write_at_all(fd,off,data,cnt,dtype,status);
    857:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
    858:   return(0);
    859: }

    861: PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
    862: {
    863:   PetscDataType  pdtype;

    867:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
    868:   MPI_File_read_at_all(fd,off,data,cnt,dtype,status);
    869:   if (!PetscBinaryBigEndian()) {PetscByteSwap(data,pdtype,cnt);}
    870:   return(0);
    871: }

    873: #endif