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)
 22: #undef __FUNCT__  
 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: /* --------------------------------------------------------- */
 44: #undef __FUNCT__  
 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: /* --------------------------------------------------------- */
 67: #undef __FUNCT__  
 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: /* --------------------------------------------------------- */
 94: #undef __FUNCT__  
 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: /* --------------------------------------------------------- */
118: #undef __FUNCT__  
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 generatedn
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: /* --------------------------------------------------------- */
265: #undef __FUNCT__  
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) return(0);

314:   maxblock = 65536;

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

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

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

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

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

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

373:   return(0);
374: }

376: #undef __FUNCT__  
378: /*@C
379:    PetscBinaryOpen - Opens a PETSc binary file.

381:    Not Collective

383:    Input Parameters:
384: +  name - filename
385: -  type - type of binary file, on of PETSC_BINARY_RDONLY, PETSC_BINARY_WRONLY, PETSC_BINARY_CREATE

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

390:    Level: advanced

392:   Concepts: files^opening binary
393:   Concepts: binary files^opening

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

432: #undef __FUNCT__  
434: /*@C
435:    PetscBinaryClose - Closes a PETSc binary file.

437:    Not Collective

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

442:    Level: advanced

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


454: #undef __FUNCT__  
456: /*@C
457:    PetscBinarySeek - Moves the file pointer on a PETSc binary file.

459:    Not Collective

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

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

472:    Level: developer

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

480:    Concepts: files^binary seeking
481:    Concepts: binary files^seeking

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

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

505:   return(0);
506: }

508: #undef __FUNCT__  
510: /*@C
511:    PetscSynchronizedBinaryRead - Reads from a binary file.

513:    Collective on MPI_Comm

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

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

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

529:    Level: developer

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

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

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

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

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

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

564: #undef __FUNCT__  
566: /*@C
567:    PetscSynchronizedBinarySeek - Moves the file pointer on a PETSc binary file.

569:    Not Collective

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

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

582:    Level: developer

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

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

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

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