Actual source code: sysio.c

  1: /*$Id: sysio.c,v 1.81 2001/08/10 17:39:07 balay Exp $*/

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

 7:  #include petsc.h
 8:  #include petscsys.h

 10: #include <errno.h>
 11: #include <fcntl.h>
 12: #if defined(PETSC_HAVE_UNISTD_H)
 13: #include <unistd.h>
 14: #endif
 15: #if defined (PARCH_win32)
 16: #include <io.h>
 17: #endif
 18:  #include petscbt.h


 21: #if !defined(PETSC_WORDS_BIGENDIAN)
 24: /*
 25:   PetscByteSwapInt - Swap bytes in an integer
 26: */
 27: int PetscByteSwapInt(int *buff,int n)
 28: {
 29:   int  i,j,tmp =0;
 30:   int  *tptr = &tmp;                /* Need to access tmp indirectly to get */
 31:   char *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
 32: 
 34:   for (j=0; j<n; j++) {
 35:     ptr1 = (char*)(buff + j);
 36:     for (i=0; i<(int) sizeof(int); i++) {
 37:       ptr2[i] = ptr1[sizeof(int)-1-i];
 38:     }
 39:     buff[j] = *tptr;
 40:   }
 41:   return(0);
 42: }
 43: /* --------------------------------------------------------- */
 46: /*
 47:   PetscByteSwapShort - Swap bytes in a short
 48: */
 49: int PetscByteSwapShort(short *buff,int n)
 50: {
 51:   int   i,j;
 52:   short tmp;
 53:   short *tptr = &tmp;           /* take care pf bug in DEC-ALPHA g++ */
 54:   char  *ptr1,*ptr2 = (char*)&tmp;

 57:   for (j=0; j<n; j++) {
 58:     ptr1 = (char*)(buff + j);
 59:     for (i=0; i<(int) sizeof(short); i++) {
 60:       ptr2[i] = ptr1[sizeof(int)-1-i];
 61:     }
 62:     buff[j] = *tptr;
 63:   }
 64:   return(0);
 65: }
 66: /* --------------------------------------------------------- */
 69: /*
 70:   PetscByteSwapScalar - Swap bytes in a double
 71:   Complex is dealt with as if array of double twice as long.
 72: */
 73: int PetscByteSwapScalar(PetscScalar *buff,int n)
 74: {
 75:   int       i,j;
 76:   PetscReal tmp,*buff1 = (PetscReal*)buff;
 77:   PetscReal *tptr = &tmp;          /* take care pf bug in DEC-ALPHA g++ */
 78:   char      *ptr1,*ptr2 = (char*)&tmp;

 81: #if defined(PETSC_USE_COMPLEX)
 82:   n *= 2;
 83: #endif
 84:   for (j=0; j<n; j++) {
 85:     ptr1 = (char*)(buff1 + j);
 86:     for (i=0; i<(int) sizeof(PetscReal); i++) {
 87:       ptr2[i] = ptr1[sizeof(PetscReal)-1-i];
 88:     }
 89:     buff1[j] = *tptr;
 90:   }
 91:   return(0);
 92: }
 93: /* --------------------------------------------------------- */
 96: /*
 97:   PetscByteSwapDouble - Swap bytes in a double
 98: */
 99: int PetscByteSwapDouble(double *buff,int n)
100: {
101:   int    i,j;
102:   double tmp,*buff1 = (double*)buff;
103:   double *tptr = &tmp;          /* take care pf bug in DEC-ALPHA g++ */
104:   char   *ptr1,*ptr2 = (char*)&tmp;

107:   for (j=0; j<n; j++) {
108:     ptr1 = (char*)(buff1 + j);
109:     for (i=0; i<(int) sizeof(double); i++) {
110:       ptr2[i] = ptr1[sizeof(double)-1-i];
111:     }
112:     buff1[j] = *tptr;
113:   }
114:   return(0);
115: }
116: #endif
117: /* --------------------------------------------------------- */
120: /*@C
121:    PetscBinaryRead - Reads from a binary file.

123:    Not Collective

125:    Input Parameters:
126: +  fd - the file
127: .  n  - the number of items to read 
128: -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

130:    Output Parameters:
131: .  p - the buffer

133:    Options Database Key:
134: .   -binary_longints - indicates the file was generated on a Cray vector 
135:          machine (not the T3E/D) and the ints are stored as 64 bit 
136:          quantities, otherwise they are stored as 32 bit

138:    Level: developer

140:    Notes: 
141:    PetscBinaryRead() uses byte swapping to work on all machines.
142:    Integers are stored on the file as 32 long, regardless of whether
143:    they are stored in the machine as 32 or 64, this means the same
144:    binary file may be read on any machine.

146:    Note that Cray C90 and similar machines cannot generate files with 
147:    32 bit integers; use the flag -binary_longints to read files from the 
148:    C90 on non-C90 machines. Cray T3E/T3D are the same as other Unix
149:    machines, not the same as the C90.

151:    Concepts: files^reading binary
152:    Concepts: binary files^reading

154: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose()
155: @*/
156: int PetscBinaryRead(int fd,void *p,int n,PetscDataType type)
157: {
158:   int               maxblock = 65536,wsize,err,m = n,ierr;
159:   static PetscTruth longintset = PETSC_FALSE,longintfile = PETSC_FALSE;
160:   PetscTruth        flg;
161:   char              *pp = (char*)p;
162: #if (PETSC_SIZEOF_SHORT != 8)
163:   void              *ptmp = p;
164: #endif

167:   if (!n) return(0);

169:   if (!longintset) {
170:     PetscOptionsHasName(PETSC_NULL,"-binary_longints",&longintfile);
171:     PetscOptionsHasName(PETSC_NULL,"-help",&flg);
172:     if (flg) {
173:       (*PetscHelpPrintf)(PETSC_COMM_SELF,"-binary_longints - for binary file generated\n\
174:    on a Cray vector machine (not T3E/T3D)\n");
175:     }
176:     longintset = PETSC_TRUE;
177:   }

179: #if (PETSC_SIZEOF_INT == 8 && PETSC_SIZEOF_SHORT == 4)
180:   if (type == PETSC_INT){
181:     if (longintfile) {
182:       m *= sizeof(int);
183:     } else {
184:       /* read them in as shorts, later stretch into ints */
185:       m   *= sizeof(short);
186:       PetscMalloc(m,&pp);
187:       ptmp = (void*)pp;
188:     }
189:   }
190: #elif (PETSC_SIZEOF_INT == 8 && PETSC_SIZEOF_SHORT == 8)
191:   if (type == PETSC_INT){
192:     if (longintfile) {
193:       m *= sizeof(int);
194:     } else {
195:       SETERRQ(1,"Can only process data file generated on Cray vector machine;\n\
196:       if this data WAS then run program with -binary_longints option");
197:     }
198:   }
199: #else
200:   if (type == PETSC_INT) {
201:     if (longintfile) {
202:        /* read in twice as many ints and later discard every other one */
203:        m    *= 2*sizeof(int);
204:        PetscMalloc(m,&pp);
205:        ptmp =  (void*)pp;
206:     } else {
207:        m *= sizeof(int);
208:     }
209:   }
210: #endif
211:   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
212:   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
213:   else if (type == PETSC_SHORT)   m *= sizeof(short);
214:   else if (type == PETSC_CHAR)    m *= sizeof(char);
215:   else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
216:   else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");
217: 
218:   while (m) {
219:     wsize = (m < maxblock) ? m : maxblock;
220:     err = read(fd,pp,wsize);
221:     if (err < 0 && errno == EINTR) continue;
222:     if (err == 0 && wsize > 0) SETERRQ(PETSC_ERR_FILE_READ,"Read past end of file");
223:     if (err < 0) SETERRQ(PETSC_ERR_FILE_READ,"Error reading from file");
224:     m  -= err;
225:     pp += err;
226:   }
227: #if !defined(PETSC_WORDS_BIGENDIAN)
228:   if      (type == PETSC_INT)    {PetscByteSwapInt((int*)ptmp,n);}
229:   else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
230:   else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
231:   else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
232: #endif

234: #if (PETSC_SIZEOF_INT == 8 && PETSC_SIZEOF_SHORT == 4)
235:   if (type == PETSC_INT){
236:     if (!longintfile) {
237:       int   *p_int = (int*)p,i;
238:       short *p_short = (short *)ptmp;
239:       for (i=0; i<n; i++) {
240:         p_int[i] = (int)p_short[i];
241:       }
242:       PetscFree(ptmp);
243:     }
244:   }
245: #elif (PETSC_SIZEOF_INT == 8 && PETSC_SIZEOF_SHORT == 8)
246: #else
247:   if (type == PETSC_INT){
248:     if (longintfile) {
249:     /* 
250:        take the longs (treated as pair of ints) and convert them to ints
251:     */
252:       int   *p_int  = (int*)p,i;
253:       int   *p_intl = (int *)ptmp;
254:       for (i=0; i<n; i++) {
255:         p_int[i] = (int)p_intl[2*i+1];
256:       }
257:       PetscFree(ptmp);
258:     }
259:   }
260: #endif

262:   return(0);
263: }
264: /* --------------------------------------------------------- */
267: /*@C
268:    PetscBinaryWrite - Writes to a binary file.

270:    Not Collective

272:    Input Parameters:
273: +  fd     - the file
274: .  p      - the buffer
275: .  n      - the number of items to write
276: .  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
277: -  istemp - 0 if buffer data should be preserved, 1 otherwise.

279:    Level: advanced

281:    Notes: 
282:    PetscBinaryWrite() uses byte swapping to work on all machines.
283:    Integers are stored on the file as 32 long, regardless of whether
284:    they are stored in the machine as 32 or 64, this means the same
285:    binary file may be read on any machine.

287:    The Buffer p should be read-write buffer, and not static data.
288:    This way, byte-swapping is done in-place, and then the buffer is
289:    written to the file.
290:    
291:    This routine restores the original contents of the buffer, after 
292:    it is written to the file. This is done by byte-swapping in-place 
293:    the second time. If the flag istemp is set to 1, the second
294:    byte-swapping operation is not done, thus saving some computation,
295:    but the buffer corrupted is corrupted.

297:    Concepts: files^writing binary
298:    Concepts: binary files^writing

300: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose()
301: @*/
302: int PetscBinaryWrite(int fd,void *p,int n,PetscDataType type,int istemp)
303: {
304:   char *pp = (char*)p;
305:   int  err,maxblock,wsize,m = n;
306: #if !defined(PETSC_WORDS_BIGENDIAN) || (PETSC_SIZEOF_INT == 8)
307:   int  ierr;
308:   void *ptmp = p;
309: #endif

312:   if (n < 0) SETERRQ1(1,"Trying to write a negative amount of data %d",n);
313:   if (!n) return(0);

315:   maxblock = 65536;

317: #if !defined(PETSC_WORDS_BIGENDIAN)
318:   if      (type == PETSC_INT)    {PetscByteSwapInt((int*)ptmp,n);}
319:   else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
320:   else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
321:   else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
322: #endif

324: #if (PETSC_SIZEOF_INT == 8)
325:   if (type == PETSC_INT){
326:     /* 
327:       integers on the Cray T3d/e are 64 bits so we copy the big
328:       integers into a short array and write those out.
329:     */
330:     int   *p_int = (int*)p,i;
331:     short *p_short;
332:     m       *= sizeof(short);
333:     PetscMalloc(m,&pp);
334:     ptmp    = (void*)pp;
335:     p_short = (short*)pp;

337:     for (i=0; i<n; i++) {
338:       p_short[i] = (short) p_int[i];
339:     }
340:   }
341: #else
342:   if (type == PETSC_INT)          m *= sizeof(int);
343: #endif
344:   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
345:   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
346:   else if (type == PETSC_SHORT)   m *= sizeof(short);
347:   else if (type == PETSC_CHAR)    m *= sizeof(char);
348:   else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
349:   else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");

351:   while (m) {
352:     wsize = (m < maxblock) ? m : maxblock;
353:     err = write(fd,pp,wsize);
354:     if (err < 0 && errno == EINTR) continue;
355:     if (err != wsize) SETERRQ(PETSC_ERR_FILE_WRITE,"Error writing to file.");
356:     m -= wsize;
357:     pp += wsize;
358:   }

360: #if !defined(PETSC_WORDS_BIGENDIAN)
361:   if (!istemp) {
362:     if      (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
363:     else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
364:     else if (type == PETSC_INT)    {PetscByteSwapInt((int*)ptmp,n);}
365:   }
366: #endif

368: #if (PETSC_SIZEOF_INT == 8)
369:   if (type == PETSC_INT){
370:     PetscFree(ptmp);
371:   }
372: #endif

374:   return(0);
375: }

379: /*@C
380:    PetscBinaryOpen - Opens a PETSc binary file.

382:    Not Collective

384:    Input Parameters:
385: +  name - filename
386: -  type - type of binary file, on of PETSC_FILE_RDONLY, PETSC_FILE_WRONLY, PETSC_FILE_CREATE

388:    Output Parameter:
389: .  fd - the file

391:    Level: advanced

393:   Concepts: files^opening binary
394:   Concepts: binary files^opening

396: .seealso: PetscBinaryRead(), PetscBinaryWrite()
397: @*/
398: int PetscBinaryOpen(const char name[],int type,int *fd)
399: {
401: #if defined(PARCH_win32_gnu) || defined(PARCH_win32) 
402:   if (type == PETSC_FILE_CREATE) {
403:     if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
404:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
405:     }
406:   } else if (type == PETSC_FILE_RDONLY) {
407:     if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
408:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
409:     }
410:   } else if (type == PETSC_FILE_WRONLY) {
411:     if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
412:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
413:     }
414: #else
415:   if (type == PETSC_FILE_CREATE) {
416:     if ((*fd = creat(name,0666)) == -1) {
417:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
418:     }
419:   } else if (type == PETSC_FILE_RDONLY) {
420:     if ((*fd = open(name,O_RDONLY,0)) == -1) {
421:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
422:     }
423:   }
424:   else if (type == PETSC_FILE_WRONLY) {
425:     if ((*fd = open(name,O_WRONLY,0)) == -1) {
426:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
427:     }
428: #endif
429:   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file type");
430:   return(0);
431: }

435: /*@C
436:    PetscBinaryClose - Closes a PETSc binary file.

438:    Not Collective

440:    Output Parameter:
441: .  fd - the file

443:    Level: advanced

445: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
446: @*/
447: int PetscBinaryClose(int fd)
448: {
450:   close(fd);
451:   return(0);
452: }


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

460:    Not Collective

462:    Input Parameters:
463: +  fd - the file
464: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
465:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
466:             if PETSC_BINARY_SEEK_END then size is offset from end of file
467: -  size - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
468:             etc. in your calculation rather than sizeof() to compute byte lengths.

470:    Output Parameter:
471: .   offset - new offset in file

473:    Level: developer

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

481:    Concepts: files^binary seeking
482:    Concepts: binary files^seeking

484: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
485: @*/
486: int PetscBinarySeek(int fd,int size,PetscBinarySeekType whence,int *offset)
487: {
488:   int iwhence=0;

491:   if (whence == PETSC_BINARY_SEEK_SET) {
492:     iwhence = SEEK_SET;
493:   } else if (whence == PETSC_BINARY_SEEK_CUR) {
494:     iwhence = SEEK_CUR;
495:   } else if (whence == PETSC_BINARY_SEEK_END) {
496:     iwhence = SEEK_END;
497:   } else {
498:     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
499:   }
500: #if defined(PARCH_win32)
501:   *offset = _lseek(fd,(long)size,iwhence);
502: #else
503:   *offset = lseek(fd,(off_t)size,iwhence);
504: #endif

506:   return(0);
507: }

511: /*@C
512:    PetscSynchronizedBinaryRead - Reads from a binary file.

514:    Collective on MPI_Comm

516:    Input Parameters:
517: +  comm - the MPI communicator 
518: .  fd - the file
519: .  n  - the number of items to read 
520: -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

522:    Output Parameters:
523: .  p - the buffer

525:    Options Database Key:
526: .   -binary_longints - indicates the file was generated on a Cray vector 
527:          machine (not the T3E/D) and the ints are stored as 64 bit 
528:          quantities, otherwise they are stored as 32 bit

530:    Level: developer

532:    Notes: 
533:    Does a PetscBinaryRead() followed by an MPI_Bcast()

535:    PetscSynchronizedBinaryRead() uses byte swapping to work on all machines.
536:    Integers are stored on the file as 32 long, regardless of whether
537:    they are stored in the machine as 32 or 64, this means the same
538:    binary file may be read on any machine.

540:    Note that Cray C90 and similar machines cannot generate files with 
541:    32 bit integers; use the flag -binary_longints to read files from the 
542:    C90 on non-C90 machines. Cray T3E/T3D are the same as other Unix
543:    machines, not the same as the C90.

545:    Concepts: files^synchronized reading of binary files
546:    Concepts: binary files^reading, synchronized

548: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
549: @*/
550: int PetscSynchronizedBinaryRead(MPI_Comm comm,int fd,void *p,int n,PetscDataType type)
551: {
552:   int          ierr,rank;
553:   MPI_Datatype mtype;

556:   MPI_Comm_rank(comm,&rank);
557:   if (!rank) {
558:     PetscBinaryRead(fd,p,n,type);
559:   }
560:   PetscDataTypeToMPIDataType(type,&mtype);
561:   MPI_Bcast(p,n,mtype,0,comm);
562:   return(0);
563: }

567: /*@C
568:    PetscSynchronizedBinarySeek - Moves the file pointer on a PETSc binary file.

570:    Not Collective

572:    Input Parameters:
573: +  fd - the file
574: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
575:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
576:             if PETSC_BINARY_SEEK_END then size is offset from end of file
577: -  size - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
578:             etc. in your calculation rather than sizeof() to compute byte lengths.

580:    Output Parameter:
581: .   offset - new offset in file

583:    Level: developer

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

591:    Concepts: binary files^seeking
592:    Concepts: files^seeking in binary 

594: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
595: @*/
596: int PetscSynchronizedBinarySeek(MPI_Comm comm,int fd,int size,PetscBinarySeekType whence,int *offset)
597: {
598:   int ierr,rank;

601:   MPI_Comm_rank(comm,&rank);
602:   if (!rank) {
603:     PetscBinarySeek(fd,size,whence,offset);
604:   }
605:   return(0);
606: }