Actual source code: sysio.c

petsc-master 2017-12-15
Report Typos and Errors

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

  6:  #include <petscsys.h>
  7: #include <errno.h>
  8: #include <fcntl.h>
  9: #if defined(PETSC_HAVE_UNISTD_H)
 10: #include <unistd.h>
 11: #endif
 12: #if defined(PETSC_HAVE_IO_H)
 13: #include <io.h>
 14: #endif
 15:  #include <petscbt.h>

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

 19: /* --------------------------------------------------------- */
 20: /*
 21:   PetscByteSwapEnum - Swap bytes in a  PETSc Enum

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

 31:   for (j=0; j<n; j++) {
 32:     ptr1 = (char*)(buff + j);
 33:     for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) ptr2[i] = ptr1[sizeof(PetscEnum)-1-i];
 34:     for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) ptr1[i] = ptr2[i];
 35:   }
 36:   return(0);
 37: }

 39: /*
 40:   PetscByteSwapBool - Swap bytes in a  PETSc Bool

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

 50:   for (j=0; j<n; j++) {
 51:     ptr1 = (char*)(buff + j);
 52:     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool)-1-i];
 53:     for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr1[i] = ptr2[i];
 54:   }
 55:   return(0);
 56: }

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

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

 68:   for (j=0; j<n; j++) {
 69:     ptr1 = (char*)(buff + j);
 70:     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt)-1-i];
 71:     for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr1[i] = ptr2[i];
 72:   }
 73:   return(0);
 74: }
 75: /* --------------------------------------------------------- */
 76: /*
 77:   PetscByteSwapShort - Swap bytes in a short
 78: */
 79: PetscErrorCode  PetscByteSwapShort(short *buff,PetscInt n)
 80: {
 81:   PetscInt i,j;
 82:   short    tmp;
 83:   char     *ptr1,*ptr2 = (char*)&tmp;

 86:   for (j=0; j<n; j++) {
 87:     ptr1 = (char*)(buff + j);
 88:     for (i=0; i<(PetscInt) sizeof(short); i++) ptr2[i] = ptr1[sizeof(short)-1-i];
 89:     for (i=0; i<(PetscInt) sizeof(short); i++) ptr1[i] = ptr2[i];
 90:   }
 91:   return(0);
 92: }
 93: /* --------------------------------------------------------- */
 94: /*
 95:   PetscByteSwapReal - Swap bytes in a PetscReal
 96: */
 97: PetscErrorCode  PetscByteSwapReal(PetscReal *buff,PetscInt n)
 98: {
 99:   PetscInt  i,j;
100:   PetscReal tmp,*buff1 = (PetscReal*)buff;
101:   char      *ptr1,*ptr2 = (char*)&tmp;

104:   for (j=0; j<n; j++) {
105:     ptr1 = (char*)(buff1 + j);
106:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
107:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
108:   }
109:   return(0);
110: }
111: /* --------------------------------------------------------- */
112: /*
113:   PetscByteSwapScalar - Swap bytes in a PetscScalar
114:   The complex case is dealt with with an array of PetscReal, twice as long.
115: */
116: PetscErrorCode  PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
117: {
118:   PetscInt  i,j;
119:   PetscReal tmp,*buff1 = (PetscReal*)buff;
120:   char      *ptr1,*ptr2 = (char*)&tmp;

123: #if defined(PETSC_USE_COMPLEX)
124:   n *= 2;
125: #endif
126:   for (j=0; j<n; j++) {
127:     ptr1 = (char*)(buff1 + j);
128:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
129:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
130:   }
131:   return(0);
132: }
133: /* --------------------------------------------------------- */
134: /*
135:   PetscByteSwapDouble - Swap bytes in a double
136: */
137: PetscErrorCode  PetscByteSwapDouble(double *buff,PetscInt n)
138: {
139:   PetscInt i,j;
140:   double   tmp,*buff1 = (double*)buff;
141:   char     *ptr1,*ptr2 = (char*)&tmp;

144:   for (j=0; j<n; j++) {
145:     ptr1 = (char*)(buff1 + j);
146:     for (i=0; i<(PetscInt) sizeof(double); i++) ptr2[i] = ptr1[sizeof(double)-1-i];
147:     for (i=0; i<(PetscInt) sizeof(double); i++) ptr1[i] = ptr2[i];
148:   }
149:   return(0);
150: }

152: /*
153:   PetscByteSwapFloat - Swap bytes in a float
154: */
155: PetscErrorCode PetscByteSwapFloat(float *buff,PetscInt n)
156: {
157:   PetscInt i,j;
158:   float    tmp,*buff1 = (float*)buff;
159:   char     *ptr1,*ptr2 = (char*)&tmp;

162:   for (j=0; j<n; j++) {
163:     ptr1 = (char*)(buff1 + j);
164:     for (i=0; i<(PetscInt) sizeof(float); i++) ptr2[i] = ptr1[sizeof(float)-1-i];
165:     for (i=0; i<(PetscInt) sizeof(float); i++) ptr1[i] = ptr2[i];
166:   }
167:   return(0);
168: }

170: PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count)
171: {

175:   if      (pdtype == PETSC_INT)    {PetscByteSwapInt((PetscInt*)data,count);}
176:   else if (pdtype == PETSC_ENUM)   {PetscByteSwapEnum((PetscEnum*)data,count);}
177:   else if (pdtype == PETSC_BOOL)   {PetscByteSwapBool((PetscBool*)data,count);}
178:   else if (pdtype == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)data,count);}
179:   else if (pdtype == PETSC_REAL)   {PetscByteSwapReal((PetscReal*)data,count);}
180:   else if (pdtype == PETSC_DOUBLE) {PetscByteSwapDouble((double*)data,count);}
181:   else if (pdtype == PETSC_FLOAT)  {PetscByteSwapFloat((float*)data,count);}
182:   else if (pdtype == PETSC_SHORT)  {PetscByteSwapShort((short*)data,count);}
183:   return(0);
184: }

186: /* --------------------------------------------------------- */
187: /*@
188:    PetscBinaryRead - Reads from a binary file.

190:    Not Collective

192:    Input Parameters:
193: +  fd - the file
194: .  n  - the number of items to read
195: -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

197:    Output Parameters:
198: .  p - the buffer



202:    Level: developer

204:    Notes:
205:    PetscBinaryRead() uses byte swapping to work on all machines; the files
206:    are written to file ALWAYS using big-endian ordering. On small-endian machines the numbers
207:    are converted to the small-endian format when they are read in from the file.
208:    When PETSc is ./configure with --with-64bit-indices the integers are written to the
209:    file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices
210:    is used.

212:    Concepts: files^reading binary
213:    Concepts: binary files^reading

215: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
216:           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
217: @*/
218: PetscErrorCode  PetscBinaryRead(int fd,void *p,PetscInt n,PetscDataType type)
219: {
220:   int               wsize,err;
221:   size_t            m = (size_t) n,maxblock = 65536;
222:   char              *pp = (char*)p;
223: #if defined(PETSC_USE_REAL___FLOAT128)
224:   PetscBool         readdouble = PETSC_FALSE;
225:   double            *ppp;
226: #endif
227: #if !defined(PETSC_WORDS_BIGENDIAN) || defined(PETSC_USE_REAL___FLOAT128)
228:   PetscErrorCode    ierr;
229: #endif
230: #if !defined(PETSC_WORDS_BIGENDIAN)
231:   void              *ptmp = p;
232: #endif
233:   char              *fname = NULL;

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

239:   if (type == PETSC_FUNCTION) {
240:     m            = 64;
241:     type         = PETSC_CHAR;
242:     fname        = (char*) malloc(m*sizeof(char));
243:     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
244:     pp           = (char*)fname;
245: #if !defined(PETSC_WORDS_BIGENDIAN)
246:     ptmp         = (void*)fname;
247: #endif
248:   }

250:   if (type == PETSC_INT)          m *= sizeof(PetscInt);
251:   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
252:   else if (type == PETSC_REAL)    m *= sizeof(PetscReal);
253:   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
254:   else if (type == PETSC_FLOAT)   m *= sizeof(float);
255:   else if (type == PETSC_SHORT)   m *= sizeof(short);
256:   else if (type == PETSC_CHAR)    m *= sizeof(char);
257:   else if (type == PETSC_ENUM)    m *= sizeof(PetscEnum);
258:   else if (type == PETSC_BOOL)   m *= sizeof(PetscBool);
259:   else if (type == PETSC_BIT_LOGICAL) m  = PetscBTLength(m)*sizeof(char);
260:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");

262: #if defined(PETSC_USE_REAL___FLOAT128)
263:   PetscOptionsGetBool(NULL,NULL,"-binary_read_double",&readdouble,NULL);
264:   /* If using __float128 precision we still read in doubles from file */
265:   if ((type == PETSC_SCALAR || type == PETSC_REAL) && readdouble) {
266:     m    = m/2;
267:     PetscMalloc1(n,&ppp);
268:     pp   = (char*)ppp;
269:   }
270: #endif

272:   while (m) {
273:     wsize = (m < maxblock) ? m : maxblock;
274:     err   = read(fd,pp,wsize);
275:     if (err < 0 && errno == EINTR) continue;
276:     if (!err && wsize > 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Read past end of file");
277:     if (err < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno);
278:     m  -= err;
279:     pp += err;
280:   }

282: #if defined(PETSC_USE_REAL___FLOAT128)
283:   if ((type == PETSC_SCALAR || type == PETSC_REAL) && readdouble) {
284:     PetscScalar *pv = (PetscScalar*) p;
285:     PetscInt    i;
286: #if !defined(PETSC_WORDS_BIGENDIAN)
287:     PetscByteSwapDouble(ppp,n);
288: #endif
289:     for (i=0; i<n; i++) pv[i] = ppp[i];
290:     PetscFree(ppp);
291:     return(0);
292:   }
293: #endif

295: #if !defined(PETSC_WORDS_BIGENDIAN)
296:   PetscByteSwap(ptmp,type,n);
297: #endif

299:   if (type == PETSC_FUNCTION) {
300: #if defined(PETSC_SERIALIZE_FUNCTIONS)
301:     PetscDLSym(NULL,fname,(void**)p);
302: #else
303:     *(void**)p = NULL;
304: #endif
305:     free(fname);
306:   }
307:   return(0);
308: }
309: /* --------------------------------------------------------- */
310: /*@
311:    PetscBinaryWrite - Writes to a binary file.

313:    Not Collective

315:    Input Parameters:
316: +  fd     - the file
317: .  p      - the buffer
318: .  n      - the number of items to write
319: .  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
320: -  istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise.

322:    Level: advanced

324:    Notes:
325:    PetscBinaryWrite() uses byte swapping to work on all machines; the files
326:    are written using big-endian ordering to the file. On small-endian machines the numbers
327:    are converted to the big-endian format when they are written to disk.
328:    When PETSc is ./configure with --with-64bit-indices the integers are written to the
329:    file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices
330:    is used.

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

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

338:    This routine restores the original contents of the buffer, after
339:    it is written to the file. This is done by byte-swapping in-place
340:    the second time. If the flag istemp is set to PETSC_TRUE, the second
341:    byte-swapping operation is not done, thus saving some computation,
342:    but the buffer is left corrupted.

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

346:    Concepts: files^writing binary
347:    Concepts: binary files^writing

349: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
350:           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
351: @*/
352: PetscErrorCode  PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscBool  istemp)
353: {
354:   char           *pp = (char*)p;
355:   int            err,wsize;
356:   size_t         m = (size_t)n,maxblock=65536;
358: #if !defined(PETSC_WORDS_BIGENDIAN)
359:   void           *ptmp = p;
360: #endif
361:   char           *fname = NULL;
362: #if defined(PETSC_USE_REAL___FLOAT128)
363:   PetscBool      writedouble = PETSC_FALSE;
364:   double         *ppp;
365:   PetscReal      *pv;
366:   PetscInt       i;
367: #endif
368:   PetscDataType  wtype = type;

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

374:   if (type == PETSC_FUNCTION) {
375: #if defined(PETSC_SERIALIZE_FUNCTIONS)
376:     const char *fnametmp;
377: #endif
378:     m     = 64;
379:     fname = (char*)malloc(m*sizeof(char));
380:     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
381: #if defined(PETSC_SERIALIZE_FUNCTIONS)
382:     if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time");
383:     PetscFPTFind(*(void**)p,&fnametmp);
384:     PetscStrncpy(fname,fnametmp,m);
385: #else
386:     PetscStrncpy(fname,"",m);
387: #endif
388:     wtype = PETSC_CHAR;
389:     pp    = (char*)fname;
390: #if !defined(PETSC_WORDS_BIGENDIAN)
391:     ptmp  = (void*)fname;
392: #endif
393:   }

395: #if defined(PETSC_USE_REAL___FLOAT128)
396:   PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);
397:   /* If using __float128 precision we still write in doubles to file */
398:   if ((type == PETSC_SCALAR || type == PETSC_REAL) && writedouble) {
399:     wtype = PETSC_DOUBLE;
400:     PetscMalloc1(n,&ppp);
401:     pv = (PetscReal*)pp;
402:     for (i=0; i<n; i++) {
403:       ppp[i] = (double) pv[i];
404:     }
405:     pp   = (char*)ppp;
406:     ptmp = (char*)ppp;
407:   }
408: #endif

410:   if (wtype == PETSC_INT)          m *= sizeof(PetscInt);
411:   else if (wtype == PETSC_SCALAR)  m *= sizeof(PetscScalar);
412:   else if (wtype == PETSC_REAL)    m *= sizeof(PetscReal);
413:   else if (wtype == PETSC_DOUBLE)  m *= sizeof(double);
414:   else if (wtype == PETSC_FLOAT)   m *= sizeof(float);
415:   else if (wtype == PETSC_SHORT)   m *= sizeof(short);
416:   else if (wtype == PETSC_CHAR)    m *= sizeof(char);
417:   else if (wtype == PETSC_ENUM)    m *= sizeof(PetscEnum);
418:   else if (wtype == PETSC_BOOL)    m *= sizeof(PetscBool);
419:   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
420:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");

422: #if !defined(PETSC_WORDS_BIGENDIAN)
423:   PetscByteSwap(ptmp,wtype,n);
424: #endif

426:   while (m) {
427:     wsize = (m < maxblock) ? m : maxblock;
428:     err   = write(fd,pp,wsize);
429:     if (err < 0 && errno == EINTR) continue;
430:     if (err != wsize) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_WRITE,"Error writing to file total size %d err %d wsize %d",(int)n,(int)err,(int)wsize);
431:     m  -= wsize;
432:     pp += wsize;
433:   }

435: #if !defined(PETSC_WORDS_BIGENDIAN)
436:   if (!istemp) {
437:     PetscByteSwap(ptmp,wtype,n);
438:   }
439: #endif
440:   if (type == PETSC_FUNCTION) {
441:     free(fname);
442:   }
443: #if defined(PETSC_USE_REAL___FLOAT128)
444:   if ((type == PETSC_SCALAR || type == PETSC_REAL) && writedouble) {
445:     PetscFree(ppp);
446:   }
447: #endif
448:   return(0);
449: }

451: /*@C
452:    PetscBinaryOpen - Opens a PETSc binary file.

454:    Not Collective

456:    Input Parameters:
457: +  name - filename
458: -  type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE

460:    Output Parameter:
461: .  fd - the file

463:    Level: advanced

465:   Concepts: files^opening binary
466:   Concepts: binary files^opening

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

472: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(),
473:           PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()

475: @*/
476: PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
477: {
479: #if defined(PETSC_HAVE_O_BINARY)
480:   if (mode == FILE_MODE_WRITE) {
481:     if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
482:   } else if (mode == FILE_MODE_READ) {
483:     if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
484:   } else if (mode == FILE_MODE_APPEND) {
485:     if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
486: #else
487:   if (mode == FILE_MODE_WRITE) {
488:     if ((*fd = creat(name,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
489:   } else if (mode == FILE_MODE_READ) {
490:     if ((*fd = open(name,O_RDONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
491:   }
492:   else if (mode == FILE_MODE_APPEND) {
493:     if ((*fd = open(name,O_WRONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
494: #endif
495:   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode");
496:   return(0);
497: }

499: /*@
500:    PetscBinaryClose - Closes a PETSc binary file.

502:    Not Collective

504:    Output Parameter:
505: .  fd - the file

507:    Level: advanced

509: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
510:           PetscBinarySynchronizedSeek()
511: @*/
512: PetscErrorCode  PetscBinaryClose(int fd)
513: {
515:   close(fd);
516:   return(0);
517: }


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

523:    Not Collective

525:    Input Parameters:
526: +  fd - the file
527: .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
528:             etc. in your calculation rather than sizeof() to compute byte lengths.
529: -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
530:             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
531:             if PETSC_BINARY_SEEK_END then off is an offset from the end of file

533:    Output Parameter:
534: .   offset - new offset in file

536:    Level: developer

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

544:    Concepts: files^binary seeking
545:    Concepts: binary files^seeking

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;

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

569: /*@C
570:    PetscBinarySynchronizedRead - Reads from a binary file.

572:    Collective on MPI_Comm

574:    Input Parameters:
575: +  comm - the MPI communicator
576: .  fd - the file
577: .  n  - the number of items to read
578: -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

580:    Output Parameters:
581: .  p - the buffer

583:    Level: developer

585:    Notes:
586:    Does a PetscBinaryRead() followed by an MPI_Bcast()

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

593:    Concepts: files^synchronized reading of binary files
594:    Concepts: binary files^reading, synchronized

596: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
597:           PetscBinarySynchronizedSeek()
598: @*/
599: PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type)
600: {
602:   PetscMPIInt    rank;
603:   MPI_Datatype   mtype;
604:   char           *fname = NULL;
605:   void           *ptmp = NULL;

608:   if (type == PETSC_FUNCTION) {
609:     n            = 64;
610:     type         = PETSC_CHAR;
611:     ptmp         = p;
612:     fname        = (char*)malloc(n*sizeof(char));
613:     if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name");
614:     p            = (void*)fname;
615:   }

617:   MPI_Comm_rank(comm,&rank);
618:   if (!rank) {
619:     PetscBinaryRead(fd,p,n,type);
620:   }
621:   PetscDataTypeToMPIDataType(type,&mtype);
622:   MPI_Bcast(p,n,mtype,0,comm);

624:   if (type == PETSC_FUNCTION) {
625: #if defined(PETSC_SERIALIZE_FUNCTIONS)
626:     PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)ptmp);
627: #else
628:     *(void**)ptmp = NULL;
629: #endif
630:     free(fname);
631:   }
632:   return(0);
633: }

635: /*@C
636:    PetscBinarySynchronizedWrite - writes to a binary file.

638:    Collective on MPI_Comm

640:    Input Parameters:
641: +  comm - the MPI communicator
642: .  fd - the file
643: .  n  - the number of items to write
644: .  p - the buffer
645: .  istemp - the buffer may be changed
646: -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

648:    Level: developer

650:    Notes:
651:    Process 0 does a PetscBinaryWrite()

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

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

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

663:    Concepts: files^synchronized writing of binary files
664:    Concepts: binary files^reading, synchronized

666: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
667:           PetscBinarySynchronizedSeek()
668: @*/
669: PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscBool istemp)
670: {
672:   PetscMPIInt    rank;

675:   MPI_Comm_rank(comm,&rank);
676:   if (!rank) {
677:     PetscBinaryWrite(fd,p,n,type,istemp);
678:   }
679:   return(0);
680: }

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


686:    Input Parameters:
687: +  fd - the file
688: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
689:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
690:             if PETSC_BINARY_SEEK_END then size is offset from end of file
691: -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
692:             etc. in your calculation rather than sizeof() to compute byte lengths.

694:    Output Parameter:
695: .   offset - new offset in file

697:    Level: developer

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

705:    Concepts: binary files^seeking
706:    Concepts: files^seeking in binary

708: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
709:           PetscBinarySynchronizedSeek()
710: @*/
711: PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
712: {
714:   PetscMPIInt    rank;

717:   MPI_Comm_rank(comm,&rank);
718:   if (!rank) {
719:     PetscBinarySeek(fd,off,whence,offset);
720:   }
721:   return(0);
722: }

724: #if defined(PETSC_HAVE_MPIIO)
725: #if !defined(PETSC_WORDS_BIGENDIAN)

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

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

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

736: */
737: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
738: {
739:   MPI_Aint    ub;
740:   PetscMPIInt ierr;

742:   MPI_Type_get_extent(datatype,&ub,file_extent);
743:   return ierr;
744: }

746: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
747: {
748:   PetscDataType pdtype;
749:   PetscMPIInt   ierr;
750:   size_t        dsize;

752:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
753:   PetscDataTypeGetSize(pdtype,&dsize);

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

758:   PetscMemcpy(userbuf,filebuf,count*dsize);
759:   PetscByteSwap(userbuf,pdtype,count);
760:   return ierr;
761: }

763: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
764: {
765:   PetscDataType pdtype;
766:   PetscMPIInt   ierr;
767:   size_t        dsize;

769:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
770:   PetscDataTypeGetSize(pdtype,&dsize);

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

775:   PetscMemcpy(filebuf,userbuf,count*dsize);
776:   PetscByteSwap(filebuf,pdtype,count);
777:   return ierr;
778: }
779: #endif

781: PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
782: {
784:   PetscDataType  pdtype;

787:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
788:   PetscByteSwap(data,pdtype,cnt);
789:   MPI_File_write_all(fd,data,cnt,dtype,status);
790:   PetscByteSwap(data,pdtype,cnt);
791:   return(0);
792: }

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

800:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
801:   MPI_File_read_all(fd,data,cnt,dtype,status);
802:   PetscByteSwap(data,pdtype,cnt);
803:   return(0);
804: }
805: #endif
806: #endif