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: /*
 23:   PetscByteSwapInt - Swap bytes in an integer
 24: */
 25: int PetscByteSwapInt(int *buff,int n)
 26: {
 27:   int  i,j,tmp =0;
 28:   int  *tptr = &tmp;                /* Need to access tmp indirectly to get */
 29:   char *ptr1,*ptr2 = (char*)&tmp; /* arround the bug in DEC-ALPHA g++ */
 30: 
 32:   for (j=0; j<n; j++) {
 33:     ptr1 = (char*)(buff + j);
 34:     for (i=0; i<(int) sizeof(int); i++) {
 35:       ptr2[i] = ptr1[sizeof(int)-1-i];
 36:     }
 37:     buff[j] = *tptr;
 38:   }
 39:   return(0);
 40: }
 41: /* --------------------------------------------------------- */
 42: /*
 43:   PetscByteSwapShort - Swap bytes in a short
 44: */
 45: int PetscByteSwapShort(short *buff,int n)
 46: {
 47:   int   i,j;
 48:   short tmp;
 49:   short *tptr = &tmp;           /* take care pf bug in DEC-ALPHA g++ */
 50:   char  *ptr1,*ptr2 = (char*)&tmp;

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

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

 99:   for (j=0; j<n; j++) {
100:     ptr1 = (char*)(buff1 + j);
101:     for (i=0; i<(int) sizeof(double); i++) {
102:       ptr2[i] = ptr1[sizeof(double)-1-i];
103:     }
104:     buff1[j] = *tptr;
105:   }
106:   return(0);
107: }
108: #endif
109: /* --------------------------------------------------------- */
110: /*@C
111:    PetscBinaryRead - Reads from a binary file.

113:    Not Collective

115:    Input Parameters:
116: +  fd - the file
117: .  n  - the number of items to read 
118: -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

120:    Output Parameters:
121: .  p - the buffer

123:    Options Database:
124: .   -binary_longints - indicates the file was generated on a Cray vector 
125:          machine (not the T3E/D) and the ints are stored as 64 bit 
126:          quantities, otherwise they are stored as 32 bit

128:    Level: developer

130:    Notes: 
131:    PetscBinaryRead() uses byte swapping to work on all machines.
132:    Integers are stored on the file as 32 long, regardless of whether
133:    they are stored in the machine as 32 or 64, this means the same
134:    binary file may be read on any machine.

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

141:    Concepts: files^reading binary
142:    Concepts: binary files^reading

144: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose()
145: @*/
146: int PetscBinaryRead(int fd,void *p,int n,PetscDataType type)
147: {
148:   int               maxblock = 65536,wsize,err,m = n,ierr;
149:   static PetscTruth longintset = PETSC_FALSE,longintfile = PETSC_FALSE;
150:   PetscTruth        flg;
151:   char              *pp = (char*)p;
152: #if (PETSC_SIZEOF_SHORT != 8)
153:   void              *ptmp = p;
154: #endif

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

159:   if (!longintset) {
160:     PetscOptionsHasName(PETSC_NULL,"-binary_longints",&longintfile);
161:     PetscOptionsHasName(PETSC_NULL,"-help",&flg);
162:     if (flg) {
163:       (*PetscHelpPrintf)(PETSC_COMM_SELF,"-binary_longints - for binary file generatedn
164:    on a Cray vector machine (not T3E/T3D)n");
165:     }
166:     longintset = PETSC_TRUE;
167:   }

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

224: #if (PETSC_SIZEOF_INT == 8 && PETSC_SIZEOF_SHORT == 4)
225:   if (type == PETSC_INT){
226:     if (!longintfile) {
227:       int   *p_int = (int*)p,i;
228:       short *p_short = (short *)ptmp;
229:       for (i=0; i<n; i++) {
230:         p_int[i] = (int)p_short[i];
231:       }
232:       PetscFree(ptmp);
233:     }
234:   }
235: #elif (PETSC_SIZEOF_INT == 8 && PETSC_SIZEOF_SHORT == 8)
236: #else
237:   if (type == PETSC_INT){
238:     if (longintfile) {
239:     /* 
240:        take the longs (treated as pair of ints) and convert them to ints
241:     */
242:       int   *p_int  = (int*)p,i;
243:       int   *p_intl = (int *)ptmp;
244:       for (i=0; i<n; i++) {
245:         p_int[i] = (int)p_intl[2*i+1];
246:       }
247:       PetscFree(ptmp);
248:     }
249:   }
250: #endif

252:   return(0);
253: }
254: /* --------------------------------------------------------- */
255: /*@C
256:    PetscBinaryWrite - Writes to a binary file.

258:    Not Collective

260:    Input Parameters:
261: +  fd     - the file
262: .  p      - the buffer
263: .  n      - the number of items to write
264: .  type   - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)
265: -  istemp - 0 if buffer data should be preserved, 1 otherwise.

267:    Level: advanced

269:    Notes: 
270:    PetscBinaryWrite() uses byte swapping to work on all machines.
271:    Integers are stored on the file as 32 long, regardless of whether
272:    they are stored in the machine as 32 or 64, this means the same
273:    binary file may be read on any machine.

275:    The Buffer p should be read-write buffer, and not static data.
276:    This way, byte-swapping is done in-place, and then the buffer is
277:    written to the file.
278:    
279:    This routine restores the original contents of the buffer, after 
280:    it is written to the file. This is done by byte-swapping in-place 
281:    the second time. If the flag istemp is set to 1, the second
282:    byte-swapping operation is not done, thus saving some computation,
283:    but the buffer corrupted is corrupted.

285:    Concepts: files^writing binary
286:    Concepts: binary files^writing

288: .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose()
289: @*/
290: int PetscBinaryWrite(int fd,void *p,int n,PetscDataType type,int istemp)
291: {
292:   char *pp = (char*)p;
293:   int  err,maxblock,wsize,m = n;
294: #if !defined(PETSC_WORDS_BIGENDIAN) || (PETSC_SIZEOF_INT == 8)
295:   int  ierr;
296:   void *ptmp = p;
297: #endif

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

302:   maxblock = 65536;

304: #if !defined(PETSC_WORDS_BIGENDIAN)
305:   if      (type == PETSC_INT)    {PetscByteSwapInt((int*)ptmp,n);}
306:   else if (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
307:   else if (type == PETSC_DOUBLE) {PetscByteSwapDouble((double*)ptmp,n);}
308:   else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
309: #endif

311: #if (PETSC_SIZEOF_INT == 8)
312:   if (type == PETSC_INT){
313:     /* 
314:       integers on the Cray T3d/e are 64 bits so we copy the big
315:       integers into a short array and write those out.
316:     */
317:     int   *p_int = (int*)p,i;
318:     short *p_short;
319:     m       *= sizeof(short);
320:     ierr    = PetscMalloc(m,&pp);
321:     ptmp    = (void*)pp;
322:     p_short = (short*)pp;

324:     for (i=0; i<n; i++) {
325:       p_short[i] = (short) p_int[i];
326:     }
327:   }
328: #else
329:   if (type == PETSC_INT)          m *= sizeof(int);
330: #endif
331:   else if (type == PETSC_SCALAR)  m *= sizeof(PetscScalar);
332:   else if (type == PETSC_DOUBLE)  m *= sizeof(double);
333:   else if (type == PETSC_SHORT)   m *= sizeof(short);
334:   else if (type == PETSC_CHAR)    m *= sizeof(char);
335:   else if (type == PETSC_LOGICAL) m = PetscBTLength(m)*sizeof(char);
336:   else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown type");

338:   while (m) {
339:     wsize = (m < maxblock) ? m : maxblock;
340:     err = write(fd,pp,wsize);
341:     if (err < 0 && errno == EINTR) continue;
342:     if (err != wsize) SETERRQ(PETSC_ERR_FILE_WRITE,"Error writing to file.");
343:     m -= wsize;
344:     pp += wsize;
345:   }

347: #if !defined(PETSC_WORDS_BIGENDIAN)
348:   if (!istemp) {
349:     if      (type == PETSC_SCALAR) {PetscByteSwapScalar((PetscScalar*)ptmp,n);}
350:     else if (type == PETSC_SHORT)  {PetscByteSwapShort((short*)ptmp,n);}
351:     else if (type == PETSC_INT)    {PetscByteSwapInt((int*)ptmp,n);}
352:   }
353: #endif

355: #if (PETSC_SIZEOF_INT == 8)
356:   if (type == PETSC_INT){
357:     PetscFree(ptmp);
358:   }
359: #endif

361:   return(0);
362: }

364: /*@C
365:    PetscBinaryOpen - Opens a PETSc binary file.

367:    Not Collective

369:    Input Parameters:
370: +  name - filename
371: -  type - type of binary file, on of PETSC_BINARY_RDONLY, PETSC_BINARY_WRONLY, PETSC_BINARY_CREATE

373:    Output Parameter:
374: .  fd - the file

376:    Level: advanced

378:   Concepts: files^opening binary
379:   Concepts: binary files^opening

381: .seealso: PetscBinaryRead(), PetscBinaryWrite()
382: @*/
383: int PetscBinaryOpen(const char name[],int type,int *fd)
384: {
386: #if defined(PARCH_win32_gnu) || defined(PARCH_win32) 
387:   if (type == PETSC_BINARY_CREATE) {
388:     if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) {
389:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
390:     }
391:   } else if (type == PETSC_BINARY_RDONLY) {
392:     if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) {
393:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
394:     }
395:   } else if (type == PETSC_BINARY_WRONLY) {
396:     if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) {
397:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
398:     }
399: #else
400:   if (type == PETSC_BINARY_CREATE) {
401:     if ((*fd = creat(name,0666)) == -1) {
402:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name);
403:     }
404:   } else if (type == PETSC_BINARY_RDONLY) {
405:     if ((*fd = open(name,O_RDONLY,0)) == -1) {
406:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name);
407:     }
408:   }
409:   else if (type == PETSC_BINARY_WRONLY) {
410:     if ((*fd = open(name,O_WRONLY,0)) == -1) {
411:       SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name);
412:     }
413: #endif
414:   } else SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown file type");
415:   return(0);
416: }

418: /*@C
419:    PetscBinaryClose - Closes a PETSc binary file.

421:    Not Collective

423:    Output Parameter:
424: .  fd - the file

426:    Level: advanced

428: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
429: @*/
430: int PetscBinaryClose(int fd)
431: {
433:   close(fd);
434:   return(0);
435: }


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

441:    Not Collective

443:    Input Parameters:
444: +  fd - the file
445: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
446:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
447:             if PETSC_BINARY_SEEK_END then size is offset from end of file
448: -  size - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
449:             etc. in your calculation rather than sizeof() to compute byte lengths.

451:    Output Parameter:
452: .   offset - new offset in file

454:    Level: developer

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

462:    Concepts: files^binary seeking
463:    Concepts: binary files^seeking

465: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
466: @*/
467: int PetscBinarySeek(int fd,int size,PetscBinarySeekType whence,int *offset)
468: {
469:   int iwhence=0;

472:   if (whence == PETSC_BINARY_SEEK_SET) {
473:     iwhence = SEEK_SET;
474:   } else if (whence == PETSC_BINARY_SEEK_CUR) {
475:     iwhence = SEEK_CUR;
476:   } else if (whence == PETSC_BINARY_SEEK_END) {
477:     iwhence = SEEK_END;
478:   } else {
479:     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location");
480:   }
481: #if defined(PARCH_win32)
482:   *offset = _lseek(fd,(long)size,iwhence);
483: #else
484:   *offset = lseek(fd,(off_t)size,iwhence);
485: #endif

487:   return(0);
488: }

490: /*@C
491:    PetscSynchronizedBinaryRead - Reads from a binary file.

493:    Collective on MPI_Comm

495:    Input Parameters:
496: +  comm - the MPI communicator 
497: .  fd - the file
498: .  n  - the number of items to read 
499: -  type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR)

501:    Output Parameters:
502: .  p - the buffer

504:    Options Database:
505: .   -binary_longints - indicates the file was generated on a Cray vector 
506:          machine (not the T3E/D) and the ints are stored as 64 bit 
507:          quantities, otherwise they are stored as 32 bit

509:    Level: developer

511:    Notes: 
512:    Does a PetscBinaryRead() followed by an MPI_Bcast()

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

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

524:    Concepts: files^synchronized reading of binary files
525:    Concepts: binary files^reading, synchronized

527: .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead()
528: @*/
529: int PetscSynchronizedBinaryRead(MPI_Comm comm,int fd,void *p,int n,PetscDataType type)
530: {
531:   int          ierr,rank;
532:   MPI_Datatype mtype;

535:   MPI_Comm_rank(comm,&rank);
536:   if (!rank) {
537:     PetscBinaryRead(fd,p,n,type);
538:   }
539:   PetscDataTypeToMPIDataType(type,&mtype);
540:   MPI_Bcast(p,n,mtype,0,comm);
541:   return(0);
542: }

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

547:    Not Collective

549:    Input Parameters:
550: +  fd - the file
551: .  whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file
552:             if PETSC_BINARY_SEEK_CUR then size is offset from current location
553:             if PETSC_BINARY_SEEK_END then size is offset from end of file
554: -  size - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE,
555:             etc. in your calculation rather than sizeof() to compute byte lengths.

557:    Output Parameter:
558: .   offset - new offset in file

560:    Level: developer

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

568:    Concepts: binary files^seeking
569:    Concepts: files^seeking in binary 

571: .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen()
572: @*/
573: int PetscSynchronizedBinarySeek(MPI_Comm comm,int fd,int size,PetscBinarySeekType whence,int *offset)
574: {
575:   int ierr,rank;

578:   MPI_Comm_rank(comm,&rank);
579:   if (!rank) {
580:     PetscBinarySeek(fd,size,whence,offset);
581:   }
582:   return(0);
583: }