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