Actual source code: sysio.c


  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;

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

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

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

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

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

 62: */
 63: PetscErrorCode  PetscByteSwapInt(PetscInt *buff,PetscInt n)
 64: {
 65:   PetscInt i,j,tmp = 0;
 66:   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: }

 76: /*
 77:   PetscByteSwapInt64 - Swap bytes in a  PETSc integer (64 bits)

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

 86:   for (j=0; j<n; j++) {
 87:     ptr1 = (char*)(buff + j);
 88:     for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64)-1-i];
 89:     for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i];
 90:   }
 91:   return 0;
 92: }

 94: /* --------------------------------------------------------- */
 95: /*
 96:   PetscByteSwapShort - Swap bytes in a short
 97: */
 98: PetscErrorCode  PetscByteSwapShort(short *buff,PetscInt n)
 99: {
100:   PetscInt i,j;
101:   short    tmp;
102:   char     *ptr1,*ptr2 = (char*)&tmp;

104:   for (j=0; j<n; j++) {
105:     ptr1 = (char*)(buff + j);
106:     for (i=0; i<(PetscInt) sizeof(short); i++) ptr2[i] = ptr1[sizeof(short)-1-i];
107:     for (i=0; i<(PetscInt) sizeof(short); i++) ptr1[i] = ptr2[i];
108:   }
109:   return 0;
110: }
111: /*
112:   PetscByteSwapLong - Swap bytes in a long
113: */
114: PetscErrorCode  PetscByteSwapLong(long *buff,PetscInt n)
115: {
116:   PetscInt i,j;
117:   long     tmp;
118:   char     *ptr1,*ptr2 = (char*)&tmp;

120:   for (j=0; j<n; j++) {
121:     ptr1 = (char*)(buff + j);
122:     for (i=0; i<(PetscInt) sizeof(long); i++) ptr2[i] = ptr1[sizeof(long)-1-i];
123:     for (i=0; i<(PetscInt) sizeof(long); i++) ptr1[i] = ptr2[i];
124:   }
125:   return 0;
126: }
127: /* --------------------------------------------------------- */
128: /*
129:   PetscByteSwapReal - Swap bytes in a PetscReal
130: */
131: PetscErrorCode  PetscByteSwapReal(PetscReal *buff,PetscInt n)
132: {
133:   PetscInt  i,j;
134:   PetscReal tmp,*buff1 = (PetscReal*)buff;
135:   char      *ptr1,*ptr2 = (char*)&tmp;

137:   for (j=0; j<n; j++) {
138:     ptr1 = (char*)(buff1 + j);
139:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
140:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
141:   }
142:   return 0;
143: }
144: /* --------------------------------------------------------- */
145: /*
146:   PetscByteSwapScalar - Swap bytes in a PetscScalar
147:   The complex case is dealt with with an array of PetscReal, twice as long.
148: */
149: PetscErrorCode  PetscByteSwapScalar(PetscScalar *buff,PetscInt n)
150: {
151:   PetscInt  i,j;
152:   PetscReal tmp,*buff1 = (PetscReal*)buff;
153:   char      *ptr1,*ptr2 = (char*)&tmp;

155: #if defined(PETSC_USE_COMPLEX)
156:   n *= 2;
157: #endif
158:   for (j=0; j<n; j++) {
159:     ptr1 = (char*)(buff1 + j);
160:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
161:     for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i];
162:   }
163:   return 0;
164: }
165: /* --------------------------------------------------------- */
166: /*
167:   PetscByteSwapDouble - Swap bytes in a double
168: */
169: PetscErrorCode  PetscByteSwapDouble(double *buff,PetscInt n)
170: {
171:   PetscInt i,j;
172:   double   tmp,*buff1 = (double*)buff;
173:   char     *ptr1,*ptr2 = (char*)&tmp;

175:   for (j=0; j<n; j++) {
176:     ptr1 = (char*)(buff1 + j);
177:     for (i=0; i<(PetscInt) sizeof(double); i++) ptr2[i] = ptr1[sizeof(double)-1-i];
178:     for (i=0; i<(PetscInt) sizeof(double); i++) ptr1[i] = ptr2[i];
179:   }
180:   return 0;
181: }

183: /*
184:   PetscByteSwapFloat - Swap bytes in a float
185: */
186: PetscErrorCode PetscByteSwapFloat(float *buff,PetscInt n)
187: {
188:   PetscInt i,j;
189:   float    tmp,*buff1 = (float*)buff;
190:   char     *ptr1,*ptr2 = (char*)&tmp;

192:   for (j=0; j<n; j++) {
193:     ptr1 = (char*)(buff1 + j);
194:     for (i=0; i<(PetscInt) sizeof(float); i++) ptr2[i] = ptr1[sizeof(float)-1-i];
195:     for (i=0; i<(PetscInt) sizeof(float); i++) ptr1[i] = ptr2[i];
196:   }
197:   return 0;
198: }

200: PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count)
201: {
202:   if      (pdtype == PETSC_INT)    PetscByteSwapInt((PetscInt*)data,count);
203:   else if (pdtype == PETSC_ENUM)   PetscByteSwapEnum((PetscEnum*)data,count);
204:   else if (pdtype == PETSC_BOOL)   PetscByteSwapBool((PetscBool*)data,count);
205:   else if (pdtype == PETSC_SCALAR) PetscByteSwapScalar((PetscScalar*)data,count);
206:   else if (pdtype == PETSC_REAL)   PetscByteSwapReal((PetscReal*)data,count);
207:   else if (pdtype == PETSC_COMPLEX)PetscByteSwapReal((PetscReal*)data,2*count);
208:   else if (pdtype == PETSC_INT64)  PetscByteSwapInt64((PetscInt64*)data,count);
209:   else if (pdtype == PETSC_DOUBLE) PetscByteSwapDouble((double*)data,count);
210:   else if (pdtype == PETSC_FLOAT)  PetscByteSwapFloat((float*)data,count);
211:   else if (pdtype == PETSC_SHORT)  PetscByteSwapShort((short*)data,count);
212:   else if (pdtype == PETSC_LONG)   PetscByteSwapLong((long*)data,count);
213:   return 0;
214: }

216: /*@C
217:    PetscBinaryRead - Reads from a binary file.

219:    Not Collective

221:    Input Parameters:
222: +  fd - the file descriptor
223: .  num  - the maximum number of items to read
224: -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)

226:    Output Parameters:
227: +  data - the buffer
228: -  count - the number of items read, optional

230:    Level: developer

232:    Notes:
233:    If count is not provided and the number of items read is less than
234:    the maximum number of items to read, then this routine errors.

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

243: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
244:           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
245: @*/
246: PetscErrorCode  PetscBinaryRead(int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
247: {
248:   size_t            typesize, m = (size_t) num, n = 0, maxblock = 65536;
249:   char              *p = (char*)data;
250: #if defined(PETSC_USE_REAL___FLOAT128)
251:   PetscBool         readdouble = PETSC_FALSE;
252:   double            *pdouble;
253: #endif
254:   void              *ptmp = data;
255:   char              *fname = NULL;

257:   if (count) *count = 0;
259:   if (!num) return 0;

261:   if (type == PETSC_FUNCTION) {
262:     m     = 64;
263:     type  = PETSC_CHAR;
264:     fname = (char*)malloc(m*sizeof(char));
265:     p     = (char*)fname;
266:     ptmp  = (void*)fname;
268:   }
269:   if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m);

271:   PetscDataTypeGetSize(type,&typesize);

273: #if defined(PETSC_USE_REAL___FLOAT128)
274:   PetscOptionsGetBool(NULL,NULL,"-binary_read_double",&readdouble,NULL);
275:   /* If using __float128 precision we still read in doubles from file */
276:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
277:     PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2);
278:     PetscMalloc1(cnt,&pdouble);
279:     p = (char*)pdouble;
280:     typesize /= 2;
281:   }
282: #endif

284:   m *= typesize;

286:   while (m) {
287:     size_t len = (m < maxblock) ? m : maxblock;
288:     int    ret = (int)read(fd,p,len);
289:     if (ret < 0 && errno == EINTR) continue;
290:     if (!ret && len > 0) break; /* Proxy for EOF */
292:     m -= (size_t)ret;
293:     p += ret;
294:     n += (size_t)ret;
295:   }

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

301: #if defined(PETSC_USE_REAL___FLOAT128)
302:   if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) {
303:     PetscInt  i, cnt = num * ((type == PETSC_REAL) ? 1 : 2);
304:     PetscReal *preal = (PetscReal*)data;
305:     if (!PetscBinaryBigEndian()) PetscByteSwapDouble(pdouble,cnt);
306:     for (i=0; i<cnt; i++) preal[i] = pdouble[i];
307:     PetscFree(pdouble);
308:     return 0;
309:   }
310: #endif

312:   if (!PetscBinaryBigEndian()) PetscByteSwap(ptmp,type,num);

314:   if (type == PETSC_FUNCTION) {
315: #if defined(PETSC_SERIALIZE_FUNCTIONS)
316:     PetscDLSym(NULL,fname,(void**)data);
317: #else
318:     *(void**)data = NULL;
319: #endif
320:     free(fname);
321:   }
322:   return 0;
323: }

325: /*@C
326:    PetscBinaryWrite - Writes to a binary file.

328:    Not Collective

330:    Input Parameters:
331: +  fd     - the file
332: .  p      - the buffer
333: .  n      - the number of items to write
334: -  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

336:    Level: advanced

338:    Notes:
339:    PetscBinaryWrite() uses byte swapping to work on all machines; the files
340:    are written using big-endian ordering to the file. On little-endian machines the numbers
341:    are converted to the big-endian format when they are written to disk.
342:    When PETSc is ./configure with --with-64-bit-indices the integers are written to the
343:    file as 64 bit integers, this means they can only be read back in when the option --with-64-bit-indices
344:    is used.

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

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

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

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

358: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(),
359:           PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek()
360: @*/
361: PetscErrorCode  PetscBinaryWrite(int fd,const void *p,PetscInt n,PetscDataType type)
362: {
363:   const char     *pp = (char*)p;
364:   int            err,wsize;
365:   size_t         m = (size_t)n,maxblock=65536;
366:   const void     *ptmp = p;
367:   char           *fname = NULL;
368: #if defined(PETSC_USE_REAL___FLOAT128)
369:   PetscBool      writedouble = PETSC_FALSE;
370:   double         *ppp;
371:   PetscReal      *pv;
372:   PetscInt       i;
373: #endif
374:   PetscDataType  wtype = type;

377:   if (!n) return 0;

379:   if (type == PETSC_FUNCTION) {
380: #if defined(PETSC_SERIALIZE_FUNCTIONS)
381:     const char *fnametmp;
382: #endif
383:     m     = 64;
384:     fname = (char*)malloc(m*sizeof(char));
386: #if defined(PETSC_SERIALIZE_FUNCTIONS)
388:     PetscFPTFind(*(void**)p,&fnametmp);
389:     PetscStrncpy(fname,fnametmp,m);
390: #else
391:     PetscStrncpy(fname,"",m);
392: #endif
393:     wtype = PETSC_CHAR;
394:     pp    = (char*)fname;
395:     ptmp  = (void*)fname;
396:   }

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

413:   if (wtype == PETSC_INT)          m *= sizeof(PetscInt);
414:   else if (wtype == PETSC_SCALAR)  m *= sizeof(PetscScalar);
415: #if defined(PETSC_HAVE_COMPLEX)
416:   else if (wtype == PETSC_COMPLEX) m *= sizeof(PetscComplex);
417: #endif
418:   else if (wtype == PETSC_REAL)    m *= sizeof(PetscReal);
419:   else if (wtype == PETSC_DOUBLE)  m *= sizeof(double);
420:   else if (wtype == PETSC_FLOAT)   m *= sizeof(float);
421:   else if (wtype == PETSC_SHORT)   m *= sizeof(short);
422:   else if (wtype == PETSC_LONG)    m *= sizeof(long);
423:   else if (wtype == PETSC_CHAR)    m *= sizeof(char);
424:   else if (wtype == PETSC_ENUM)    m *= sizeof(PetscEnum);
425:   else if (wtype == PETSC_BOOL)    m *= sizeof(PetscBool);
426:   else if (wtype == PETSC_INT64)   m *= sizeof(PetscInt64);
427:   else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char);
428:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");

430:   if (!PetscBinaryBigEndian()) PetscByteSwap((void*)ptmp,wtype,n);

432:   while (m) {
433:     wsize = (m < maxblock) ? m : maxblock;
434:     err   = write(fd,pp,wsize);
435:     if (err < 0 && errno == EINTR) continue;
437:     m  -= wsize;
438:     pp += wsize;
439:   }

441:   if (!PetscBinaryBigEndian()) PetscByteSwap((void*)ptmp,wtype,n);

443:   if (type == PETSC_FUNCTION) {
444:     free(fname);
445:   }
446: #if defined(PETSC_USE_REAL___FLOAT128)
447:   if ((type == PETSC_SCALAR || type == PETSC_REAL || type == PETSC_COMPLEX) && writedouble) {
448:     PetscFree(ppp);
449:   }
450: #endif
451:   return 0;
452: }

454: /*@C
455:    PetscBinaryOpen - Opens a PETSc binary file.

457:    Not Collective

459:    Input Parameters:
460: +  name - filename
461: -  mode - open mode of binary file, one of FILE_MODE_READ, FILE_MODE_WRITE, FILE_MODE_APPEND

463:    Output Parameter:
464: .  fd - the file

466:    Level: advanced

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

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

476: @*/
477: PetscErrorCode  PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd)
478: {
479:   switch (mode) {
480:   case FILE_MODE_READ:   *fd = open(name,O_BINARY|O_RDONLY,0); break;
481:   case FILE_MODE_WRITE:  *fd = open(name,O_BINARY|O_WRONLY|O_CREAT|O_TRUNC,0666); break;
482:   case FILE_MODE_APPEND: *fd = open(name,O_BINARY|O_WRONLY|O_APPEND,0); break;
483:   default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported file mode %s",PetscFileModes[mode]);
484:   }
486:   return 0;
487: }

489: /*@
490:    PetscBinaryClose - Closes a PETSc binary file.

492:    Not Collective

494:    Output Parameter:
495: .  fd - the file

497:    Level: advanced

499: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
500:           PetscBinarySynchronizedSeek()
501: @*/
502: PetscErrorCode  PetscBinaryClose(int fd)
503: {
505:   return 0;
506: }

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

511:    Not Collective

513:    Input Parameters:
514: +  fd - the file
515: .  off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
516:             etc. in your calculation rather than sizeof() to compute byte lengths.
517: -  whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file
518:             if PETSC_BINARY_SEEK_CUR then off is an offset from the current location
519:             if PETSC_BINARY_SEEK_END then off is an offset from the end of file

521:    Output Parameter:
522: .   offset - new offset in file

524:    Level: developer

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

532: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
533:           PetscBinarySynchronizedSeek()
534: @*/
535: PetscErrorCode  PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
536: {
537:   int iwhence = 0;

539:   if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET;
540:   else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR;
541:   else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END;
542:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
543: #if defined(PETSC_HAVE_LSEEK)
544:   *offset = lseek(fd,off,iwhence);
545: #elif defined(PETSC_HAVE__LSEEK)
546:   *offset = _lseek(fd,(long)off,iwhence);
547: #else
548:   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file");
549: #endif
550:   return 0;
551: }

553: /*@C
554:    PetscBinarySynchronizedRead - Reads from a binary file.

556:    Collective

558:    Input Parameters:
559: +  comm - the MPI communicator
560: .  fd - the file descriptor
561: .  num  - the maximum number of items to read
562: -  type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.)

564:    Output Parameters:
565: +  data - the buffer
566: -  count - the number of items read, optional

568:    Level: developer

570:    Notes:
571:    Does a PetscBinaryRead() followed by an MPI_Bcast()

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

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

581: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(),
582:           PetscBinarySynchronizedSeek()
583: @*/
584: PetscErrorCode  PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type)
585: {
586:   PetscMPIInt    rank,size;
587:   MPI_Datatype   mtype;
588:   PetscInt       ibuf[2] = {0, 0};
589:   char           *fname = NULL;
590:   void           *fptr = NULL;

592:   if (type == PETSC_FUNCTION) {
593:     num   = 64;
594:     type  = PETSC_CHAR;
595:     fname = (char*)malloc(num*sizeof(char));
596:     fptr  = data;
597:     data  = (void*)fname;
599:   }

601:   MPI_Comm_rank(comm,&rank);
602:   MPI_Comm_size(comm,&size);
603:   if (rank == 0) {
604:     ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type);
605:   }
606:   MPI_Bcast(ibuf,2,MPIU_INT,0,comm);
607:   (PetscErrorCode)ibuf[0];

609:   /* 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 */
610:   if (size > 1) {
611:     PetscDataTypeToMPIDataType(type,&mtype);
612:     MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);
613:   }
614:   if (count) *count = ibuf[1];

616:   if (type == PETSC_FUNCTION) {
617: #if defined(PETSC_SERIALIZE_FUNCTIONS)
618:     PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);
619: #else
620:     *(void**)fptr = NULL;
621: #endif
622:     free(fname);
623:   }
624:   return 0;
625: }

627: /*@C
628:    PetscBinarySynchronizedWrite - writes to a binary file.

630:    Collective

632:    Input Parameters:
633: +  comm - the MPI communicator
634: .  fd - the file
635: .  n  - the number of items to write
636: .  p - the buffer
637: -  type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

639:    Level: developer

641:    Notes:
642:    Process 0 does a PetscBinaryWrite()

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

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

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

655: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(),
656:           PetscBinarySynchronizedSeek()
657: @*/
658: PetscErrorCode  PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,const void *p,PetscInt n,PetscDataType type)
659: {
660:   PetscMPIInt    rank;

662:   MPI_Comm_rank(comm,&rank);
663:   if (rank == 0) {
664:     PetscBinaryWrite(fd,p,n,type);
665:   }
666:   return 0;
667: }

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

672:    Input Parameters:
673: +  fd - the file
674: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
675:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
676:             if PETSC_BINARY_SEEK_END then size is offset from end of file
677: -  off    - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
678:             etc. in your calculation rather than sizeof() to compute byte lengths.

680:    Output Parameter:
681: .   offset - new offset in file

683:    Level: developer

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

691: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(),
692:           PetscBinarySynchronizedSeek()
693: @*/
694: PetscErrorCode  PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset)
695: {
696:   PetscMPIInt    rank;

698:   MPI_Comm_rank(comm,&rank);
699:   if (rank == 0) {
700:     PetscBinarySeek(fd,off,whence,offset);
701:   }
702:   return 0;
703: }

705: #if defined(PETSC_HAVE_MPIIO)

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

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

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

716: */
717: PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state)
718: {
719:   MPI_Aint    ub;
720:   PetscMPIInt ierr;

722:   MPI_Type_get_extent(datatype,&ub,file_extent);
723:   return ierr;
724: }

726: PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
727: {
728:   PetscDataType pdtype;
729:   PetscMPIInt   ierr;
730:   size_t        dsize;

732:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
733:   PetscDataTypeGetSize(pdtype,&dsize);

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

738:   PetscMemcpy(userbuf,filebuf,count*dsize);
739:   if (!PetscBinaryBigEndian()) PetscByteSwap(userbuf,pdtype,count);
740:   return ierr;
741: }

743: PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state)
744: {
745:   PetscDataType pdtype;
746:   PetscMPIInt   ierr;
747:   size_t        dsize;

749:   PetscMPIDataTypeToPetscDataType(datatype,&pdtype);
750:   PetscDataTypeGetSize(pdtype,&dsize);

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

755:   PetscMemcpy(filebuf,userbuf,count*dsize);
756:   if (!PetscBinaryBigEndian()) PetscByteSwap(filebuf,pdtype,count);
757:   return ierr;
758: }
759: #endif

761: PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
762: {
763:   PetscDataType  pdtype;

765:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
766:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
767:   MPI_File_write_all(fd,data,cnt,dtype,status);
768:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
769:   return 0;
770: }

772: PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
773: {
774:   PetscDataType  pdtype;

776:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
777:   MPI_File_read_all(fd,data,cnt,dtype,status);
778:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
779:   return 0;
780: }

782: PetscErrorCode MPIU_File_write_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
783: {
784:   PetscDataType  pdtype;

786:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
787:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
788:   MPI_File_write_at(fd,off,data,cnt,dtype,status);
789:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
790:   return 0;
791: }

793: PetscErrorCode MPIU_File_read_at(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
794: {
795:   PetscDataType  pdtype;

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

803: PetscErrorCode MPIU_File_write_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
804: {
805:   PetscDataType  pdtype;

807:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
808:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
809:   MPI_File_write_at_all(fd,off,data,cnt,dtype,status);
810:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
811:   return 0;
812: }

814: PetscErrorCode MPIU_File_read_at_all(MPI_File fd,MPI_Offset off,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status)
815: {
816:   PetscDataType  pdtype;

818:   PetscMPIDataTypeToPetscDataType(dtype,&pdtype);
819:   MPI_File_read_at_all(fd,off,data,cnt,dtype,status);
820:   if (!PetscBinaryBigEndian()) PetscByteSwap(data,pdtype,cnt);
821:   return 0;
822: }

824: #endif