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: }