1 2 /* 3 This file contains simple binary read/write routines. 4 */ 5 6 #include <petscsys.h> 7 #include <errno.h> 8 #include <fcntl.h> 9 #if defined(PETSC_HAVE_UNISTD_H) 10 #include <unistd.h> 11 #endif 12 #if defined(PETSC_HAVE_IO_H) 13 #include <io.h> 14 #endif 15 #include <petscbt.h> 16 17 const char *const PetscFileModes[] = {"READ","WRITE","APPEND","UPDATE","APPEND_UPDATE","PetscFileMode","PETSC_FILE_",0}; 18 19 /* --------------------------------------------------------- */ 20 /* 21 PetscByteSwapEnum - Swap bytes in a PETSc Enum 22 23 */ 24 PetscErrorCode PetscByteSwapEnum(PetscEnum *buff,PetscInt n) 25 { 26 PetscInt i,j; 27 PetscEnum tmp = ENUM_DUMMY; 28 char *ptr1,*ptr2 = (char*)&tmp; 29 30 PetscFunctionBegin; 31 for (j=0; j<n; j++) { 32 ptr1 = (char*)(buff + j); 33 for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) ptr2[i] = ptr1[sizeof(PetscEnum)-1-i]; 34 for (i=0; i<(PetscInt)sizeof(PetscEnum); i++) ptr1[i] = ptr2[i]; 35 } 36 PetscFunctionReturn(0); 37 } 38 39 /* 40 PetscByteSwapBool - Swap bytes in a PETSc Bool 41 42 */ 43 PetscErrorCode PetscByteSwapBool(PetscBool *buff,PetscInt n) 44 { 45 PetscInt i,j; 46 PetscBool tmp = PETSC_FALSE; 47 char *ptr1,*ptr2 = (char*)&tmp; 48 49 PetscFunctionBegin; 50 for (j=0; j<n; j++) { 51 ptr1 = (char*)(buff + j); 52 for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr2[i] = ptr1[sizeof(PetscBool)-1-i]; 53 for (i=0; i<(PetscInt)sizeof(PetscBool); i++) ptr1[i] = ptr2[i]; 54 } 55 PetscFunctionReturn(0); 56 } 57 58 /* 59 PetscByteSwapInt - Swap bytes in a PETSc integer (which may be 32 or 64 bits) 60 61 */ 62 PetscErrorCode PetscByteSwapInt(PetscInt *buff,PetscInt n) 63 { 64 PetscInt i,j,tmp = 0; 65 char *ptr1,*ptr2 = (char*)&tmp; 66 67 PetscFunctionBegin; 68 for (j=0; j<n; j++) { 69 ptr1 = (char*)(buff + j); 70 for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr2[i] = ptr1[sizeof(PetscInt)-1-i]; 71 for (i=0; i<(PetscInt)sizeof(PetscInt); i++) ptr1[i] = ptr2[i]; 72 } 73 PetscFunctionReturn(0); 74 } 75 76 /* 77 PetscByteSwapInt64 - Swap bytes in a PETSc integer (64 bits) 78 79 */ 80 PetscErrorCode PetscByteSwapInt64(PetscInt64 *buff,PetscInt n) 81 { 82 PetscInt i,j; 83 PetscInt64 tmp = 0; 84 char *ptr1,*ptr2 = (char*)&tmp; 85 86 PetscFunctionBegin; 87 for (j=0; j<n; j++) { 88 ptr1 = (char*)(buff + j); 89 for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr2[i] = ptr1[sizeof(PetscInt64)-1-i]; 90 for (i=0; i<(PetscInt)sizeof(PetscInt64); i++) ptr1[i] = ptr2[i]; 91 } 92 PetscFunctionReturn(0); 93 } 94 95 /* --------------------------------------------------------- */ 96 /* 97 PetscByteSwapShort - Swap bytes in a short 98 */ 99 PetscErrorCode PetscByteSwapShort(short *buff,PetscInt n) 100 { 101 PetscInt i,j; 102 short tmp; 103 char *ptr1,*ptr2 = (char*)&tmp; 104 105 PetscFunctionBegin; 106 for (j=0; j<n; j++) { 107 ptr1 = (char*)(buff + j); 108 for (i=0; i<(PetscInt) sizeof(short); i++) ptr2[i] = ptr1[sizeof(short)-1-i]; 109 for (i=0; i<(PetscInt) sizeof(short); i++) ptr1[i] = ptr2[i]; 110 } 111 PetscFunctionReturn(0); 112 } 113 /* 114 PetscByteSwapLong - Swap bytes in a long 115 */ 116 PetscErrorCode PetscByteSwapLong(long *buff,PetscInt n) 117 { 118 PetscInt i,j; 119 long tmp; 120 char *ptr1,*ptr2 = (char*)&tmp; 121 122 PetscFunctionBegin; 123 for (j=0; j<n; j++) { 124 ptr1 = (char*)(buff + j); 125 for (i=0; i<(PetscInt) sizeof(long); i++) ptr2[i] = ptr1[sizeof(long)-1-i]; 126 for (i=0; i<(PetscInt) sizeof(long); i++) ptr1[i] = ptr2[i]; 127 } 128 PetscFunctionReturn(0); 129 } 130 /* --------------------------------------------------------- */ 131 /* 132 PetscByteSwapReal - Swap bytes in a PetscReal 133 */ 134 PetscErrorCode PetscByteSwapReal(PetscReal *buff,PetscInt n) 135 { 136 PetscInt i,j; 137 PetscReal tmp,*buff1 = (PetscReal*)buff; 138 char *ptr1,*ptr2 = (char*)&tmp; 139 140 PetscFunctionBegin; 141 for (j=0; j<n; j++) { 142 ptr1 = (char*)(buff1 + j); 143 for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i]; 144 for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i]; 145 } 146 PetscFunctionReturn(0); 147 } 148 /* --------------------------------------------------------- */ 149 /* 150 PetscByteSwapScalar - Swap bytes in a PetscScalar 151 The complex case is dealt with with an array of PetscReal, twice as long. 152 */ 153 PetscErrorCode PetscByteSwapScalar(PetscScalar *buff,PetscInt n) 154 { 155 PetscInt i,j; 156 PetscReal tmp,*buff1 = (PetscReal*)buff; 157 char *ptr1,*ptr2 = (char*)&tmp; 158 159 PetscFunctionBegin; 160 #if defined(PETSC_USE_COMPLEX) 161 n *= 2; 162 #endif 163 for (j=0; j<n; j++) { 164 ptr1 = (char*)(buff1 + j); 165 for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr2[i] = ptr1[sizeof(PetscReal)-1-i]; 166 for (i=0; i<(PetscInt) sizeof(PetscReal); i++) ptr1[i] = ptr2[i]; 167 } 168 PetscFunctionReturn(0); 169 } 170 /* --------------------------------------------------------- */ 171 /* 172 PetscByteSwapDouble - Swap bytes in a double 173 */ 174 PetscErrorCode PetscByteSwapDouble(double *buff,PetscInt n) 175 { 176 PetscInt i,j; 177 double tmp,*buff1 = (double*)buff; 178 char *ptr1,*ptr2 = (char*)&tmp; 179 180 PetscFunctionBegin; 181 for (j=0; j<n; j++) { 182 ptr1 = (char*)(buff1 + j); 183 for (i=0; i<(PetscInt) sizeof(double); i++) ptr2[i] = ptr1[sizeof(double)-1-i]; 184 for (i=0; i<(PetscInt) sizeof(double); i++) ptr1[i] = ptr2[i]; 185 } 186 PetscFunctionReturn(0); 187 } 188 189 /* 190 PetscByteSwapFloat - Swap bytes in a float 191 */ 192 PetscErrorCode PetscByteSwapFloat(float *buff,PetscInt n) 193 { 194 PetscInt i,j; 195 float tmp,*buff1 = (float*)buff; 196 char *ptr1,*ptr2 = (char*)&tmp; 197 198 PetscFunctionBegin; 199 for (j=0; j<n; j++) { 200 ptr1 = (char*)(buff1 + j); 201 for (i=0; i<(PetscInt) sizeof(float); i++) ptr2[i] = ptr1[sizeof(float)-1-i]; 202 for (i=0; i<(PetscInt) sizeof(float); i++) ptr1[i] = ptr2[i]; 203 } 204 PetscFunctionReturn(0); 205 } 206 207 PetscErrorCode PetscByteSwap(void *data,PetscDataType pdtype,PetscInt count) 208 { 209 PetscErrorCode ierr; 210 211 PetscFunctionBegin; 212 if (pdtype == PETSC_INT) {ierr = PetscByteSwapInt((PetscInt*)data,count);CHKERRQ(ierr);} 213 else if (pdtype == PETSC_ENUM) {ierr = PetscByteSwapEnum((PetscEnum*)data,count);CHKERRQ(ierr);} 214 else if (pdtype == PETSC_BOOL) {ierr = PetscByteSwapBool((PetscBool*)data,count);CHKERRQ(ierr);} 215 else if (pdtype == PETSC_SCALAR) {ierr = PetscByteSwapScalar((PetscScalar*)data,count);CHKERRQ(ierr);} 216 else if (pdtype == PETSC_REAL) {ierr = PetscByteSwapReal((PetscReal*)data,count);CHKERRQ(ierr);} 217 else if (pdtype == PETSC_COMPLEX){ierr = PetscByteSwapReal((PetscReal*)data,2*count);CHKERRQ(ierr);} 218 else if (pdtype == PETSC_INT64) {ierr = PetscByteSwapInt64((PetscInt64*)data,count);CHKERRQ(ierr);} 219 else if (pdtype == PETSC_DOUBLE) {ierr = PetscByteSwapDouble((double*)data,count);CHKERRQ(ierr);} 220 else if (pdtype == PETSC_FLOAT) {ierr = PetscByteSwapFloat((float*)data,count);CHKERRQ(ierr);} 221 else if (pdtype == PETSC_SHORT) {ierr = PetscByteSwapShort((short*)data,count);CHKERRQ(ierr);} 222 else if (pdtype == PETSC_LONG) {ierr = PetscByteSwapLong((long*)data,count);CHKERRQ(ierr);} 223 PetscFunctionReturn(0); 224 } 225 226 /*@C 227 PetscBinaryRead - Reads from a binary file. 228 229 Not Collective 230 231 Input Parameters: 232 + fd - the file descriptor 233 . num - the maximum number of items to read 234 - type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.) 235 236 Output Parameters: 237 + data - the buffer 238 - count - the number of items read, optional 239 240 241 242 Level: developer 243 244 Notes: 245 If count is not provided and the number of items read is less than 246 the maximum number of items to read, then this routine errors. 247 248 PetscBinaryRead() uses byte swapping to work on all machines; the files 249 are written to file ALWAYS using big-endian ordering. On small-endian machines the numbers 250 are converted to the small-endian format when they are read in from the file. 251 When PETSc is ./configure with --with-64bit-indices the integers are written to the 252 file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices 253 is used. 254 255 256 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(), 257 PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek() 258 @*/ 259 PetscErrorCode PetscBinaryRead(int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type) 260 { 261 size_t typesize, m = (size_t) num, n = 0, maxblock = 65536; 262 char *p = (char*)data; 263 #if defined(PETSC_USE_REAL___FLOAT128) 264 PetscBool readdouble = PETSC_FALSE; 265 double *pdouble; 266 #endif 267 void *ptmp = data; 268 char *fname = NULL; 269 PetscErrorCode ierr; 270 271 PetscFunctionBegin; 272 if (count) *count = 0; 273 if (num < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to read a negative amount of data %D",num); 274 if (!num) PetscFunctionReturn(0); 275 276 if (type == PETSC_FUNCTION) { 277 m = 64; 278 type = PETSC_CHAR; 279 fname = (char*)malloc(m*sizeof(char)); 280 p = (char*)fname; 281 ptmp = (void*)fname; 282 if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name"); 283 } 284 if (type == PETSC_BIT_LOGICAL) m = PetscBTLength(m); 285 286 ierr = PetscDataTypeGetSize(type,&typesize);CHKERRQ(ierr); 287 288 #if defined(PETSC_USE_REAL___FLOAT128) 289 ierr = PetscOptionsGetBool(NULL,NULL,"-binary_read_double",&readdouble,NULL);CHKERRQ(ierr); 290 /* If using __float128 precision we still read in doubles from file */ 291 if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) { 292 PetscInt cnt = num * ((type == PETSC_REAL) ? 1 : 2); 293 ierr = PetscMalloc1(cnt,&pdouble);CHKERRQ(ierr); 294 p = (char*)pdouble; 295 typesize /= 2; 296 } 297 #endif 298 299 m *= typesize; 300 301 while (m) { 302 size_t len = (m < maxblock) ? m : maxblock; 303 int ret = (int)read(fd,p,len); 304 if (ret < 0 && errno == EINTR) continue; 305 if (!ret && len > 0) break; /* Proxy for EOF */ 306 if (ret < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Error reading from file, errno %d",errno); 307 m -= ret; 308 p += ret; 309 n += ret; 310 } 311 if (m && !count) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Read past end of file"); 312 313 num = (PetscInt)(n/typesize); /* Should we require `n % typesize == 0` ? */ 314 if (count) *count = num; /* TODO: This is most likely wrong for PETSC_BIT_LOGICAL */ 315 316 #if defined(PETSC_USE_REAL___FLOAT128) 317 if ((type == PETSC_REAL || type == PETSC_COMPLEX) && readdouble) { 318 PetscInt i, cnt = num * ((type == PETSC_REAL) ? 1 : 2); 319 PetscReal *preal = (PetscReal*)data; 320 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwapDouble(pdouble,cnt);CHKERRQ(ierr);} 321 for (i=0; i<cnt; i++) preal[i] = pdouble[i]; 322 ierr = PetscFree(pdouble);CHKERRQ(ierr); 323 PetscFunctionReturn(0); 324 } 325 #endif 326 327 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(ptmp,type,num);CHKERRQ(ierr);} 328 329 if (type == PETSC_FUNCTION) { 330 #if defined(PETSC_SERIALIZE_FUNCTIONS) 331 ierr = PetscDLSym(NULL,fname,(void**)data);CHKERRQ(ierr); 332 #else 333 *(void**)data = NULL; 334 #endif 335 free(fname); 336 } 337 PetscFunctionReturn(0); 338 } 339 340 /*@C 341 PetscBinaryWrite - Writes to a binary file. 342 343 Not Collective 344 345 Input Parameters: 346 + fd - the file 347 . p - the buffer 348 . n - the number of items to write 349 . type - the type of items to read (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR) 350 - istemp - PETSC_FALSE if buffer data should be preserved, PETSC_TRUE otherwise. 351 352 Level: advanced 353 354 Notes: 355 PetscBinaryWrite() uses byte swapping to work on all machines; the files 356 are written using big-endian ordering to the file. On small-endian machines the numbers 357 are converted to the big-endian format when they are written to disk. 358 When PETSc is ./configure with --with-64bit-indices the integers are written to the 359 file as 64 bit integers, this means they can only be read back in when the option --with-64bit-indices 360 is used. 361 362 If running with __float128 precision the output is in __float128 unless one uses the -binary_write_double option 363 364 The Buffer p should be read-write buffer, and not static data. 365 This way, byte-swapping is done in-place, and then the buffer is 366 written to the file. 367 368 This routine restores the original contents of the buffer, after 369 it is written to the file. This is done by byte-swapping in-place 370 the second time. If the flag istemp is set to PETSC_TRUE, the second 371 byte-swapping operation is not done, thus saving some computation, 372 but the buffer is left corrupted. 373 374 Because byte-swapping may be done on the values in data it cannot be declared const 375 376 377 .seealso: PetscBinaryRead(), PetscBinaryOpen(), PetscBinaryClose(), PetscViewerBinaryGetDescriptor(), PetscBinarySynchronizedWrite(), 378 PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek() 379 @*/ 380 PetscErrorCode PetscBinaryWrite(int fd,void *p,PetscInt n,PetscDataType type,PetscBool istemp) 381 { 382 char *pp = (char*)p; 383 int err,wsize; 384 size_t m = (size_t)n,maxblock=65536; 385 PetscErrorCode ierr; 386 void *ptmp = p; 387 char *fname = NULL; 388 #if defined(PETSC_USE_REAL___FLOAT128) 389 PetscBool writedouble = PETSC_FALSE; 390 double *ppp; 391 PetscReal *pv; 392 PetscInt i; 393 #endif 394 PetscDataType wtype = type; 395 396 PetscFunctionBegin; 397 if (n < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to write a negative amount of data %D",n); 398 if (!n) PetscFunctionReturn(0); 399 400 if (type == PETSC_FUNCTION) { 401 #if defined(PETSC_SERIALIZE_FUNCTIONS) 402 const char *fnametmp; 403 #endif 404 m = 64; 405 fname = (char*)malloc(m*sizeof(char)); 406 if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name"); 407 #if defined(PETSC_SERIALIZE_FUNCTIONS) 408 if (n > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only binary view a single function at a time"); 409 ierr = PetscFPTFind(*(void**)p,&fnametmp);CHKERRQ(ierr); 410 ierr = PetscStrncpy(fname,fnametmp,m);CHKERRQ(ierr); 411 #else 412 ierr = PetscStrncpy(fname,"",m);CHKERRQ(ierr); 413 #endif 414 wtype = PETSC_CHAR; 415 pp = (char*)fname; 416 ptmp = (void*)fname; 417 } 418 419 #if defined(PETSC_USE_REAL___FLOAT128) 420 ierr = PetscOptionsGetBool(NULL,NULL,"-binary_write_double",&writedouble,NULL);CHKERRQ(ierr); 421 /* If using __float128 precision we still write in doubles to file */ 422 if ((type == PETSC_SCALAR || type == PETSC_REAL) && writedouble) { 423 wtype = PETSC_DOUBLE; 424 ierr = PetscMalloc1(n,&ppp);CHKERRQ(ierr); 425 pv = (PetscReal*)pp; 426 for (i=0; i<n; i++) { 427 ppp[i] = (double) pv[i]; 428 } 429 pp = (char*)ppp; 430 ptmp = (char*)ppp; 431 } 432 #endif 433 434 if (wtype == PETSC_INT) m *= sizeof(PetscInt); 435 else if (wtype == PETSC_SCALAR) m *= sizeof(PetscScalar); 436 else if (wtype == PETSC_REAL) m *= sizeof(PetscReal); 437 else if (wtype == PETSC_DOUBLE) m *= sizeof(double); 438 else if (wtype == PETSC_FLOAT) m *= sizeof(float); 439 else if (wtype == PETSC_SHORT) m *= sizeof(short); 440 else if (wtype == PETSC_LONG) m *= sizeof(long); 441 else if (wtype == PETSC_CHAR) m *= sizeof(char); 442 else if (wtype == PETSC_ENUM) m *= sizeof(PetscEnum); 443 else if (wtype == PETSC_BOOL) m *= sizeof(PetscBool); 444 else if (wtype == PETSC_INT64) m *= sizeof(PetscInt64); 445 else if (wtype == PETSC_BIT_LOGICAL) m = PetscBTLength(m)*sizeof(char); 446 else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown type"); 447 448 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(ptmp,wtype,n);CHKERRQ(ierr);} 449 450 while (m) { 451 wsize = (m < maxblock) ? m : maxblock; 452 err = write(fd,pp,wsize); 453 if (err < 0 && errno == EINTR) continue; 454 if (err != wsize) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_FILE_WRITE,"Error writing to file total size %d err %d wsize %d",(int)n,(int)err,(int)wsize); 455 m -= wsize; 456 pp += wsize; 457 } 458 459 if (!istemp) { 460 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(ptmp,wtype,n);CHKERRQ(ierr);} 461 } 462 if (type == PETSC_FUNCTION) { 463 free(fname); 464 } 465 #if defined(PETSC_USE_REAL___FLOAT128) 466 if ((type == PETSC_SCALAR || type == PETSC_REAL) && writedouble) { 467 ierr = PetscFree(ppp);CHKERRQ(ierr); 468 } 469 #endif 470 PetscFunctionReturn(0); 471 } 472 473 /*@C 474 PetscBinaryOpen - Opens a PETSc binary file. 475 476 Not Collective 477 478 Input Parameters: 479 + name - filename 480 - type - type of binary file, one of FILE_MODE_READ, FILE_MODE_APPEND, FILE_MODE_WRITE 481 482 Output Parameter: 483 . fd - the file 484 485 Level: advanced 486 487 488 Notes: 489 Files access with PetscBinaryRead() and PetscBinaryWrite() are ALWAYS written in 490 big-endian format. This means the file can be accessed using PetscBinaryOpen() and 491 PetscBinaryRead() and PetscBinaryWrite() on any machine. 492 493 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscFileMode, PetscViewerFileSetMode(), PetscViewerBinaryGetDescriptor(), 494 PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), PetscBinarySynchronizedSeek() 495 496 @*/ 497 PetscErrorCode PetscBinaryOpen(const char name[],PetscFileMode mode,int *fd) 498 { 499 PetscFunctionBegin; 500 #if defined(PETSC_HAVE_O_BINARY) 501 if (mode == FILE_MODE_WRITE) { 502 if ((*fd = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name); 503 } else if (mode == FILE_MODE_READ) { 504 if ((*fd = open(name,O_RDONLY|O_BINARY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name); 505 } else if (mode == FILE_MODE_APPEND) { 506 if ((*fd = open(name,O_WRONLY|O_BINARY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name); 507 #else 508 if (mode == FILE_MODE_WRITE) { 509 if ((*fd = creat(name,0666)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot create file for writing: %s",name); 510 } else if (mode == FILE_MODE_READ) { 511 if ((*fd = open(name,O_RDONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for reading: %s",name); 512 } 513 else if (mode == FILE_MODE_APPEND) { 514 if ((*fd = open(name,O_WRONLY,0)) == -1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot open file for writing: %s",name); 515 #endif 516 } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown file mode"); 517 PetscFunctionReturn(0); 518 } 519 520 /*@ 521 PetscBinaryClose - Closes a PETSc binary file. 522 523 Not Collective 524 525 Output Parameter: 526 . fd - the file 527 528 Level: advanced 529 530 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), 531 PetscBinarySynchronizedSeek() 532 @*/ 533 PetscErrorCode PetscBinaryClose(int fd) 534 { 535 PetscFunctionBegin; 536 close(fd); 537 PetscFunctionReturn(0); 538 } 539 540 541 /*@C 542 PetscBinarySeek - Moves the file pointer on a PETSc binary file. 543 544 Not Collective 545 546 Input Parameters: 547 + fd - the file 548 . off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE, 549 etc. in your calculation rather than sizeof() to compute byte lengths. 550 - whence - if PETSC_BINARY_SEEK_SET then off is an absolute location in the file 551 if PETSC_BINARY_SEEK_CUR then off is an offset from the current location 552 if PETSC_BINARY_SEEK_END then off is an offset from the end of file 553 554 Output Parameter: 555 . offset - new offset in file 556 557 Level: developer 558 559 Notes: 560 Integers are stored on the file as 32 long, regardless of whether 561 they are stored in the machine as 32 or 64, this means the same 562 binary file may be read on any machine. Hence you CANNOT use sizeof() 563 to determine the offset or location. 564 565 566 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), 567 PetscBinarySynchronizedSeek() 568 @*/ 569 PetscErrorCode PetscBinarySeek(int fd,off_t off,PetscBinarySeekType whence,off_t *offset) 570 { 571 int iwhence = 0; 572 573 PetscFunctionBegin; 574 if (whence == PETSC_BINARY_SEEK_SET) iwhence = SEEK_SET; 575 else if (whence == PETSC_BINARY_SEEK_CUR) iwhence = SEEK_CUR; 576 else if (whence == PETSC_BINARY_SEEK_END) iwhence = SEEK_END; 577 else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Unknown seek location"); 578 #if defined(PETSC_HAVE_LSEEK) 579 *offset = lseek(fd,off,iwhence); 580 #elif defined(PETSC_HAVE__LSEEK) 581 *offset = _lseek(fd,(long)off,iwhence); 582 #else 583 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP_SYS,"System does not have a way of seeking on a file"); 584 #endif 585 PetscFunctionReturn(0); 586 } 587 588 /*@C 589 PetscBinarySynchronizedRead - Reads from a binary file. 590 591 Collective 592 593 Input Parameters: 594 + comm - the MPI communicator 595 . fd - the file descriptor 596 . num - the maximum number of items to read 597 - type - the type of items to read (PETSC_INT, PETSC_REAL, PETSC_SCALAR, etc.) 598 599 Output Parameters: 600 + data - the buffer 601 - count - the number of items read, optional 602 603 Level: developer 604 605 Notes: 606 Does a PetscBinaryRead() followed by an MPI_Bcast() 607 608 If count is not provided and the number of items read is less than 609 the maximum number of items to read, then this routine errors. 610 611 PetscBinarySynchronizedRead() uses byte swapping to work on all machines. 612 Integers are stored on the file as 32 long, regardless of whether 613 they are stored in the machine as 32 or 64, this means the same 614 binary file may be read on any machine. 615 616 617 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedWrite(), 618 PetscBinarySynchronizedSeek() 619 @*/ 620 PetscErrorCode PetscBinarySynchronizedRead(MPI_Comm comm,int fd,void *data,PetscInt num,PetscInt *count,PetscDataType type) 621 { 622 PetscErrorCode ierr; 623 PetscMPIInt rank; 624 MPI_Datatype mtype; 625 PetscInt ibuf[2] = {0, 0}; 626 char *fname = NULL; 627 void *fptr = NULL; 628 629 PetscFunctionBegin; 630 if (type == PETSC_FUNCTION) { 631 num = 64; 632 type = PETSC_CHAR; 633 fname = (char*)malloc(num*sizeof(char)); 634 fptr = data; 635 data = (void*)fname; 636 if (!fname) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Cannot allocate space for function name"); 637 } 638 639 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 640 if (!rank) { 641 ibuf[0] = PetscBinaryRead(fd,data,num,count?&ibuf[1]:NULL,type); 642 } 643 ierr = MPI_Bcast(ibuf,2,MPIU_INT,0,comm);CHKERRQ(ierr); 644 ierr = (PetscErrorCode)ibuf[0];CHKERRQ(ierr); 645 ierr = PetscDataTypeToMPIDataType(type,&mtype);CHKERRQ(ierr); 646 ierr = MPI_Bcast(data,count?ibuf[1]:num,mtype,0,comm);CHKERRQ(ierr); 647 if (count) *count = ibuf[1]; 648 649 if (type == PETSC_FUNCTION) { 650 #if defined(PETSC_SERIALIZE_FUNCTIONS) 651 ierr = PetscDLLibrarySym(PETSC_COMM_SELF,&PetscDLLibrariesLoaded,NULL,fname,(void**)fptr);CHKERRQ(ierr); 652 #else 653 *(void**)fptr = NULL; 654 #endif 655 free(fname); 656 } 657 PetscFunctionReturn(0); 658 } 659 660 /*@C 661 PetscBinarySynchronizedWrite - writes to a binary file. 662 663 Collective 664 665 Input Parameters: 666 + comm - the MPI communicator 667 . fd - the file 668 . n - the number of items to write 669 . p - the buffer 670 . istemp - the buffer may be changed 671 - type - the type of items to write (PETSC_INT, PETSC_DOUBLE or PETSC_SCALAR) 672 673 Level: developer 674 675 Notes: 676 Process 0 does a PetscBinaryWrite() 677 678 PetscBinarySynchronizedWrite() uses byte swapping to work on all machines. 679 Integers are stored on the file as 32 long, regardless of whether 680 they are stored in the machine as 32 or 64, this means the same 681 binary file may be read on any machine. 682 683 Notes: 684 because byte-swapping may be done on the values in data it cannot be declared const 685 686 WARNING: This is NOT like PetscSynchronizedFPrintf()! This routine ignores calls on all but process 0, 687 while PetscSynchronizedFPrintf() has all processes print their strings in order. 688 689 690 .seealso: PetscBinaryWrite(), PetscBinaryOpen(), PetscBinaryClose(), PetscBinaryRead(), PetscBinarySynchronizedRead(), 691 PetscBinarySynchronizedSeek() 692 @*/ 693 PetscErrorCode PetscBinarySynchronizedWrite(MPI_Comm comm,int fd,void *p,PetscInt n,PetscDataType type,PetscBool istemp) 694 { 695 PetscErrorCode ierr; 696 PetscMPIInt rank; 697 698 PetscFunctionBegin; 699 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 700 if (!rank) { 701 ierr = PetscBinaryWrite(fd,p,n,type,istemp);CHKERRQ(ierr); 702 } 703 PetscFunctionReturn(0); 704 } 705 706 /*@C 707 PetscBinarySynchronizedSeek - Moves the file pointer on a PETSc binary file. 708 709 710 Input Parameters: 711 + fd - the file 712 . whence - if PETSC_BINARY_SEEK_SET then size is an absolute location in the file 713 if PETSC_BINARY_SEEK_CUR then size is offset from current location 714 if PETSC_BINARY_SEEK_END then size is offset from end of file 715 - off - number of bytes to move. Use PETSC_BINARY_INT_SIZE, PETSC_BINARY_SCALAR_SIZE, 716 etc. in your calculation rather than sizeof() to compute byte lengths. 717 718 Output Parameter: 719 . offset - new offset in file 720 721 Level: developer 722 723 Notes: 724 Integers are stored on the file as 32 long, regardless of whether 725 they are stored in the machine as 32 or 64, this means the same 726 binary file may be read on any machine. Hence you CANNOT use sizeof() 727 to determine the offset or location. 728 729 730 .seealso: PetscBinaryRead(), PetscBinaryWrite(), PetscBinaryOpen(), PetscBinarySynchronizedWrite(), PetscBinarySynchronizedRead(), 731 PetscBinarySynchronizedSeek() 732 @*/ 733 PetscErrorCode PetscBinarySynchronizedSeek(MPI_Comm comm,int fd,off_t off,PetscBinarySeekType whence,off_t *offset) 734 { 735 PetscErrorCode ierr; 736 PetscMPIInt rank; 737 738 PetscFunctionBegin; 739 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 740 if (!rank) { 741 ierr = PetscBinarySeek(fd,off,whence,offset);CHKERRQ(ierr); 742 } 743 PetscFunctionReturn(0); 744 } 745 746 #if defined(PETSC_HAVE_MPIIO) 747 748 #if defined(PETSC_USE_PETSC_MPI_EXTERNAL32) 749 /* 750 MPICH does not provide the external32 representation for MPI_File_set_view() so we need to provide the functions. 751 These are set into MPI in PetscInitialize() via MPI_Register_datarep() 752 753 Note I use PetscMPIInt for the MPI error codes since that is what MPI uses (instead of the standard PetscErrorCode) 754 755 The next three routines are not used because MPICH does not support their use 756 757 */ 758 PETSC_EXTERN PetscMPIInt PetscDataRep_extent_fn(MPI_Datatype datatype,MPI_Aint *file_extent,void *extra_state) 759 { 760 MPI_Aint ub; 761 PetscMPIInt ierr; 762 763 ierr = MPI_Type_get_extent(datatype,&ub,file_extent); 764 return ierr; 765 } 766 767 PETSC_EXTERN PetscMPIInt PetscDataRep_read_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state) 768 { 769 PetscDataType pdtype; 770 PetscMPIInt ierr; 771 size_t dsize; 772 773 ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr); 774 ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr); 775 776 /* offset is given in units of MPI_Datatype */ 777 userbuf = ((char*)userbuf) + dsize*position; 778 779 ierr = PetscMemcpy(userbuf,filebuf,count*dsize);CHKERRQ(ierr); 780 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(userbuf,pdtype,count);CHKERRQ(ierr);} 781 return ierr; 782 } 783 784 PetscMPIInt PetscDataRep_write_conv_fn(void *userbuf, MPI_Datatype datatype,PetscMPIInt count,void *filebuf, MPI_Offset position,void *extra_state) 785 { 786 PetscDataType pdtype; 787 PetscMPIInt ierr; 788 size_t dsize; 789 790 ierr = PetscMPIDataTypeToPetscDataType(datatype,&pdtype);CHKERRQ(ierr); 791 ierr = PetscDataTypeGetSize(pdtype,&dsize);CHKERRQ(ierr); 792 793 /* offset is given in units of MPI_Datatype */ 794 userbuf = ((char*)userbuf) + dsize*position; 795 796 ierr = PetscMemcpy(filebuf,userbuf,count*dsize);CHKERRQ(ierr); 797 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(filebuf,pdtype,count);CHKERRQ(ierr);} 798 return ierr; 799 } 800 #endif 801 802 PetscErrorCode MPIU_File_write_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) 803 { 804 PetscDataType pdtype; 805 PetscErrorCode ierr; 806 807 808 PetscFunctionBegin; 809 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); 810 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 811 ierr = MPI_File_write_all(fd,data,cnt,dtype,status);CHKERRQ(ierr); 812 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 813 PetscFunctionReturn(0); 814 } 815 816 PetscErrorCode MPIU_File_read_all(MPI_File fd,void *data,PetscMPIInt cnt,MPI_Datatype dtype,MPI_Status *status) 817 { 818 PetscDataType pdtype; 819 PetscErrorCode ierr; 820 821 PetscFunctionBegin; 822 ierr = PetscMPIDataTypeToPetscDataType(dtype,&pdtype);CHKERRQ(ierr); 823 ierr = MPI_File_read_all(fd,data,cnt,dtype,status);CHKERRQ(ierr); 824 if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(data,pdtype,cnt);CHKERRQ(ierr);} 825 PetscFunctionReturn(0); 826 } 827 828 #endif 829