1 #include <petsc/private/viewerimpl.h> /*I "petscviewer.h" I*/ 2 3 /* 4 This needs to start the same as PetscViewer_Socket. 5 */ 6 typedef struct { 7 int fdes; /* file descriptor, ignored if using MPI IO */ 8 PetscInt flowcontrol; /* allow only <flowcontrol> messages outstanding at a time while doing IO */ 9 PetscBool skipheader; /* don't write header, only raw data */ 10 #if defined(PETSC_HAVE_MPIIO) 11 PetscBool usempiio; 12 MPI_File mfdes; /* ignored unless using MPI IO */ 13 MPI_File mfsub; /* subviewer support */ 14 MPI_Offset moff; 15 #endif 16 char *filename; /* file name */ 17 PetscFileMode filemode; /* read/write/append mode */ 18 FILE *fdes_info; /* optional file containing info on binary file*/ 19 PetscBool storecompressed; /* gzip the write binary file when closing it*/ 20 char *ogzfilename; /* gzip can be run after the filename has been updated */ 21 PetscBool skipinfo; /* Don't create info file for writing; don't use for reading */ 22 PetscBool skipoptions; /* don't use PETSc options database when loading */ 23 PetscBool matlabheaderwritten; /* if format is PETSC_VIEWER_BINARY_MATLAB has the MATLAB .info header been written yet */ 24 PetscBool setfromoptionscalled; 25 } PetscViewer_Binary; 26 27 static PetscErrorCode PetscViewerBinaryClearFunctionList(PetscViewer v) 28 { 29 PetscFunctionBegin; 30 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetFlowControl_C", NULL)); 31 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetFlowControl_C", NULL)); 32 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipHeader_C", NULL)); 33 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipHeader_C", NULL)); 34 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipOptions_C", NULL)); 35 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipOptions_C", NULL)); 36 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipInfo_C", NULL)); 37 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipInfo_C", NULL)); 38 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetInfoPointer_C", NULL)); 39 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileGetName_C", NULL)); 40 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetName_C", NULL)); 41 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileGetMode_C", NULL)); 42 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetMode_C", NULL)); 43 #if defined(PETSC_HAVE_MPIIO) 44 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetUseMPIIO_C", NULL)); 45 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetUseMPIIO_C", NULL)); 46 #endif 47 PetscFunctionReturn(PETSC_SUCCESS); 48 } 49 50 #if defined(PETSC_HAVE_MPIIO) 51 static PetscErrorCode PetscViewerBinarySyncMPIIO(PetscViewer viewer) 52 { 53 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 54 55 PetscFunctionBegin; 56 if (vbinary->filemode == FILE_MODE_READ) PetscFunctionReturn(PETSC_SUCCESS); 57 if (vbinary->mfsub != MPI_FILE_NULL) PetscCallMPI(MPI_File_sync(vbinary->mfsub)); 58 if (vbinary->mfdes != MPI_FILE_NULL) { 59 PetscCallMPI(MPI_Barrier(PetscObjectComm((PetscObject)viewer))); 60 PetscCallMPI(MPI_File_sync(vbinary->mfdes)); 61 } 62 PetscFunctionReturn(PETSC_SUCCESS); 63 } 64 #endif 65 66 static PetscErrorCode PetscViewerGetSubViewer_Binary(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer) 67 { 68 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 69 PetscMPIInt rank; 70 71 PetscFunctionBegin; 72 PetscCall(PetscViewerSetUp(viewer)); 73 74 /* Return subviewer in process zero */ 75 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 76 if (rank == 0) { 77 PetscMPIInt flg; 78 79 PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, comm, &flg)); 80 PetscCheck(flg == MPI_IDENT || flg == MPI_CONGRUENT, PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscViewerGetSubViewer() for PETSCVIEWERBINARY requires a singleton MPI_Comm"); 81 PetscCall(PetscViewerCreate(comm, outviewer)); 82 PetscCall(PetscViewerSetType(*outviewer, PETSCVIEWERBINARY)); 83 PetscCall(PetscMemcpy((*outviewer)->data, vbinary, sizeof(PetscViewer_Binary))); 84 (*outviewer)->setupcalled = PETSC_TRUE; 85 } else { 86 *outviewer = NULL; 87 } 88 89 #if defined(PETSC_HAVE_MPIIO) 90 if (vbinary->usempiio && *outviewer) { 91 PetscViewer_Binary *obinary = (PetscViewer_Binary *)(*outviewer)->data; 92 /* Parent viewer opens a new MPI file handle on PETSC_COMM_SELF and keeps track of it for future reuse */ 93 if (vbinary->mfsub == MPI_FILE_NULL) { 94 int amode; 95 switch (vbinary->filemode) { 96 case FILE_MODE_READ: 97 amode = MPI_MODE_RDONLY; 98 break; 99 case FILE_MODE_WRITE: 100 amode = MPI_MODE_WRONLY; 101 break; 102 case FILE_MODE_APPEND: 103 amode = MPI_MODE_WRONLY; 104 break; 105 default: 106 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vbinary->filemode]); 107 } 108 PetscCallMPI(MPI_File_open(PETSC_COMM_SELF, vbinary->filename, amode, MPI_INFO_NULL, &vbinary->mfsub)); 109 } 110 /* Subviewer gets the MPI file handle on PETSC_COMM_SELF */ 111 obinary->mfdes = vbinary->mfsub; 112 obinary->mfsub = MPI_FILE_NULL; 113 obinary->moff = vbinary->moff; 114 } 115 #endif 116 117 #if defined(PETSC_HAVE_MPIIO) 118 PetscCall(PetscViewerBinarySyncMPIIO(viewer)); 119 #endif 120 PetscFunctionReturn(PETSC_SUCCESS); 121 } 122 123 static PetscErrorCode PetscViewerRestoreSubViewer_Binary(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer) 124 { 125 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 126 PetscMPIInt rank; 127 #if defined(PETSC_HAVE_MPIIO) 128 MPI_Offset moff = 0; 129 #endif 130 131 PetscFunctionBegin; 132 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 133 PetscCheck(rank == 0 || !*outviewer, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Subviewer not obtained from viewer"); 134 135 #if defined(PETSC_HAVE_MPIIO) 136 if (vbinary->usempiio && *outviewer) { 137 PetscViewer_Binary *obinary = (PetscViewer_Binary *)(*outviewer)->data; 138 PetscCheck(obinary->mfdes == vbinary->mfsub, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Subviewer not obtained from viewer"); 139 if (obinary->mfsub != MPI_FILE_NULL) PetscCallMPI(MPI_File_close(&obinary->mfsub)); 140 moff = obinary->moff; 141 } 142 #endif 143 144 if (*outviewer) { 145 PetscViewer_Binary *obinary = (PetscViewer_Binary *)(*outviewer)->data; 146 PetscCheck(obinary->fdes == vbinary->fdes, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Subviewer not obtained from viewer"); 147 PetscCall(PetscFree((*outviewer)->data)); 148 PetscCall(PetscViewerBinaryClearFunctionList(*outviewer)); 149 PetscCall(PetscHeaderDestroy(outviewer)); 150 } 151 152 #if defined(PETSC_HAVE_MPIIO) 153 if (vbinary->usempiio) { 154 PetscInt64 ioff = (PetscInt64)moff; /* We could use MPI_OFFSET datatype (requires MPI 2.2) */ 155 PetscCallMPI(MPI_Bcast(&ioff, 1, MPIU_INT64, 0, PetscObjectComm((PetscObject)viewer))); 156 vbinary->moff = (MPI_Offset)ioff; 157 } 158 #endif 159 160 #if defined(PETSC_HAVE_MPIIO) 161 PetscCall(PetscViewerBinarySyncMPIIO(viewer)); 162 #endif 163 PetscFunctionReturn(PETSC_SUCCESS); 164 } 165 166 #if defined(PETSC_HAVE_MPIIO) 167 /*@C 168 PetscViewerBinaryGetMPIIOOffset - Gets the current global offset that should be passed to `MPI_File_set_view()` or `MPI_File_{write|read}_at[_all]()` 169 170 Not Collective; No Fortran Support 171 172 Input Parameter: 173 . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 174 175 Output Parameter: 176 . off - the current global offset 177 178 Level: advanced 179 180 Note: 181 Use `PetscViewerBinaryAddMPIIOOffset()` to increase this value after you have written a view. 182 183 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryAddMPIIOOffset()` 184 @*/ 185 PetscErrorCode PetscViewerBinaryGetMPIIOOffset(PetscViewer viewer, MPI_Offset *off) 186 { 187 PetscViewer_Binary *vbinary; 188 189 PetscFunctionBegin; 190 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERBINARY); 191 PetscAssertPointer(off, 2); 192 vbinary = (PetscViewer_Binary *)viewer->data; 193 *off = vbinary->moff; 194 PetscFunctionReturn(PETSC_SUCCESS); 195 } 196 197 /*@C 198 PetscViewerBinaryAddMPIIOOffset - Adds to the current global offset 199 200 Logically Collective; No Fortran Support 201 202 Input Parameters: 203 + viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 204 - off - the addition to the global offset 205 206 Level: advanced 207 208 Note: 209 Use `PetscViewerBinaryGetMPIIOOffset()` to get the value that you should pass to `MPI_File_set_view()` or `MPI_File_{write|read}_at[_all]()` 210 211 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()` 212 @*/ 213 PetscErrorCode PetscViewerBinaryAddMPIIOOffset(PetscViewer viewer, MPI_Offset off) 214 { 215 PetscViewer_Binary *vbinary; 216 217 PetscFunctionBegin; 218 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERBINARY); 219 PetscValidLogicalCollectiveInt(viewer, (PetscInt)off, 2); 220 vbinary = (PetscViewer_Binary *)viewer->data; 221 vbinary->moff += off; 222 PetscFunctionReturn(PETSC_SUCCESS); 223 } 224 225 /*@C 226 PetscViewerBinaryGetMPIIODescriptor - Extracts the MPI IO file descriptor from a `PetscViewer`. 227 228 Not Collective; No Fortran Support 229 230 Input Parameter: 231 . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 232 233 Output Parameter: 234 . fdes - file descriptor 235 236 Level: advanced 237 238 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()` 239 @*/ 240 PetscErrorCode PetscViewerBinaryGetMPIIODescriptor(PetscViewer viewer, MPI_File *fdes) 241 { 242 PetscViewer_Binary *vbinary; 243 244 PetscFunctionBegin; 245 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERBINARY); 246 PetscAssertPointer(fdes, 2); 247 PetscCall(PetscViewerSetUp(viewer)); 248 vbinary = (PetscViewer_Binary *)viewer->data; 249 *fdes = vbinary->mfdes; 250 PetscFunctionReturn(PETSC_SUCCESS); 251 } 252 #endif 253 254 /*@ 255 PetscViewerBinarySetUseMPIIO - Sets a binary viewer to use MPI-IO for reading/writing. Must be called 256 before `PetscViewerFileSetName()` 257 258 Logically Collective 259 260 Input Parameters: 261 + viewer - the `PetscViewer`; must be a `PETSCVIEWERBINARY` 262 - use - `PETSC_TRUE` means MPI-IO will be used 263 264 Options Database Key: 265 . -viewer_binary_mpiio - <true or false> flag for using MPI-IO 266 267 Level: advanced 268 269 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`, 270 `PetscViewerBinaryGetUseMPIIO()` 271 @*/ 272 PetscErrorCode PetscViewerBinarySetUseMPIIO(PetscViewer viewer, PetscBool use) 273 { 274 PetscFunctionBegin; 275 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 276 PetscValidLogicalCollectiveBool(viewer, use, 2); 277 PetscTryMethod(viewer, "PetscViewerBinarySetUseMPIIO_C", (PetscViewer, PetscBool), (viewer, use)); 278 PetscFunctionReturn(PETSC_SUCCESS); 279 } 280 281 #if defined(PETSC_HAVE_MPIIO) 282 static PetscErrorCode PetscViewerBinarySetUseMPIIO_Binary(PetscViewer viewer, PetscBool use) 283 { 284 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 285 PetscFunctionBegin; 286 PetscCheck(!viewer->setupcalled || vbinary->usempiio == use, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ORDER, "Cannot change MPIIO to %s after setup", PetscBools[use]); 287 vbinary->usempiio = use; 288 PetscFunctionReturn(PETSC_SUCCESS); 289 } 290 #endif 291 292 /*@ 293 PetscViewerBinaryGetUseMPIIO - Returns `PETSC_TRUE` if the binary viewer uses MPI-IO. 294 295 Not Collective 296 297 Input Parameter: 298 . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`; must be a `PETSCVIEWERBINARY` 299 300 Output Parameter: 301 . use - `PETSC_TRUE` if MPI-IO is being used 302 303 Level: advanced 304 305 Note: 306 If MPI-IO is not available, this function will always return `PETSC_FALSE` 307 308 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()` 309 @*/ 310 PetscErrorCode PetscViewerBinaryGetUseMPIIO(PetscViewer viewer, PetscBool *use) 311 { 312 PetscFunctionBegin; 313 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 314 PetscAssertPointer(use, 2); 315 *use = PETSC_FALSE; 316 PetscTryMethod(viewer, "PetscViewerBinaryGetUseMPIIO_C", (PetscViewer, PetscBool *), (viewer, use)); 317 PetscFunctionReturn(PETSC_SUCCESS); 318 } 319 320 #if defined(PETSC_HAVE_MPIIO) 321 static PetscErrorCode PetscViewerBinaryGetUseMPIIO_Binary(PetscViewer viewer, PetscBool *use) 322 { 323 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 324 325 PetscFunctionBegin; 326 *use = vbinary->usempiio; 327 PetscFunctionReturn(PETSC_SUCCESS); 328 } 329 #endif 330 331 /*@ 332 PetscViewerBinarySetFlowControl - Sets how many messages are allowed to be outstanding at the same time during parallel IO reads/writes 333 334 Not Collective 335 336 Input Parameters: 337 + viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 338 - fc - the number of messages, defaults to 256 if this function was not called 339 340 Level: advanced 341 342 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetFlowControl()` 343 @*/ 344 PetscErrorCode PetscViewerBinarySetFlowControl(PetscViewer viewer, PetscInt fc) 345 { 346 PetscFunctionBegin; 347 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 348 PetscValidLogicalCollectiveInt(viewer, fc, 2); 349 PetscTryMethod(viewer, "PetscViewerBinarySetFlowControl_C", (PetscViewer, PetscInt), (viewer, fc)); 350 PetscFunctionReturn(PETSC_SUCCESS); 351 } 352 353 static PetscErrorCode PetscViewerBinarySetFlowControl_Binary(PetscViewer viewer, PetscInt fc) 354 { 355 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 356 357 PetscFunctionBegin; 358 PetscCheck(fc > 1, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_OUTOFRANGE, "Flow control count must be greater than 1, %" PetscInt_FMT " was set", fc); 359 vbinary->flowcontrol = fc; 360 PetscFunctionReturn(PETSC_SUCCESS); 361 } 362 363 /*@ 364 PetscViewerBinaryGetFlowControl - Returns how many messages are allowed to be outstanding at the same time during parallel IO reads/writes 365 366 Not Collective 367 368 Input Parameter: 369 . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 370 371 Output Parameter: 372 . fc - the number of messages 373 374 Level: advanced 375 376 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinarySetFlowControl()` 377 @*/ 378 PetscErrorCode PetscViewerBinaryGetFlowControl(PetscViewer viewer, PetscInt *fc) 379 { 380 PetscFunctionBegin; 381 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 382 PetscAssertPointer(fc, 2); 383 PetscUseMethod(viewer, "PetscViewerBinaryGetFlowControl_C", (PetscViewer, PetscInt *), (viewer, fc)); 384 PetscFunctionReturn(PETSC_SUCCESS); 385 } 386 387 PETSC_INTERN PetscErrorCode PetscViewerBinaryGetFlowControl_Binary(PetscViewer viewer, PetscInt *fc) 388 { 389 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 390 391 PetscFunctionBegin; 392 *fc = vbinary->flowcontrol; 393 PetscFunctionReturn(PETSC_SUCCESS); 394 } 395 396 /*@C 397 PetscViewerBinaryGetDescriptor - Extracts the file descriptor from a `PetscViewer` of `PetscViewerType` `PETSCVIEWERBINARY`. 398 399 Collective because it may trigger a `PetscViewerSetUp()` call; No Fortran Support 400 401 Input Parameter: 402 . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 403 404 Output Parameter: 405 . fdes - file descriptor 406 407 Level: advanced 408 409 Note: 410 For writable binary `PetscViewer`s, the descriptor will only be valid for the 411 first processor in the communicator that shares the `PetscViewer`. For readable 412 files it will only be valid on processes that have the file. If MPI rank 0 does not 413 have the file it generates an error even if another MPI process does have the file. 414 415 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()` 416 @*/ 417 PetscErrorCode PetscViewerBinaryGetDescriptor(PetscViewer viewer, int *fdes) 418 { 419 PetscViewer_Binary *vbinary; 420 421 PetscFunctionBegin; 422 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERBINARY); 423 PetscAssertPointer(fdes, 2); 424 PetscCall(PetscViewerSetUp(viewer)); 425 vbinary = (PetscViewer_Binary *)viewer->data; 426 *fdes = vbinary->fdes; 427 PetscFunctionReturn(PETSC_SUCCESS); 428 } 429 430 /*@ 431 PetscViewerBinarySkipInfo - Binary file will not have `.info` file created with it 432 433 Not Collective 434 435 Input Parameter: 436 . viewer - `PetscViewer` context, obtained from `PetscViewerCreate()` 437 438 Options Database Key: 439 . -viewer_binary_skip_info - true indicates do not generate `.info` file 440 441 Level: advanced 442 443 Notes: 444 This must be called after `PetscViewerSetType()`. If you use `PetscViewerBinaryOpen()` then 445 you can only skip the info file with the `-viewer_binary_skip_info` flag. To use the function you must open the 446 viewer with `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinarySkipInfo()`. 447 448 The `.info` files contains meta information about the data in the binary file, for example the block size if it was 449 set for a vector or matrix. 450 451 This routine is deprecated, use `PetscViewerBinarySetSkipInfo()` 452 453 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySetSkipOptions()`, 454 `PetscViewerBinaryGetSkipOptions()`, `PetscViewerBinaryGetSkipInfo()` 455 @*/ 456 PetscErrorCode PetscViewerBinarySkipInfo(PetscViewer viewer) 457 { 458 PetscFunctionBegin; 459 PetscCall(PetscViewerBinarySetSkipInfo(viewer, PETSC_TRUE)); 460 PetscFunctionReturn(PETSC_SUCCESS); 461 } 462 463 /*@ 464 PetscViewerBinarySetSkipInfo - Binary file will not have `.info` file created with it 465 466 Not Collective 467 468 Input Parameters: 469 + viewer - PetscViewer context, obtained from `PetscViewerCreate()` 470 - skip - `PETSC_TRUE` implies the `.info` file will not be generated 471 472 Options Database Key: 473 . -viewer_binary_skip_info - true indicates do not generate `.info` file 474 475 Level: advanced 476 477 Notes: 478 This must be called after `PetscViewerSetType()`. If you use `PetscViewerBinaryOpen()` then 479 you can only skip the info file with the `-viewer_binary_skip_info` flag. To use the function you must open the 480 viewer with `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinarySkipInfo()`. 481 482 The `.info` file contains meta information about the data in the binary file, for example the block size if it was 483 set for a vector or matrix. 484 485 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySetSkipOptions()`, 486 `PetscViewerBinaryGetSkipOptions()`, `PetscViewerBinaryGetSkipInfo()`, `PetscViewerBinaryGetInfoPointer()` 487 @*/ 488 PetscErrorCode PetscViewerBinarySetSkipInfo(PetscViewer viewer, PetscBool skip) 489 { 490 PetscFunctionBegin; 491 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 492 PetscValidLogicalCollectiveBool(viewer, skip, 2); 493 PetscTryMethod(viewer, "PetscViewerBinarySetSkipInfo_C", (PetscViewer, PetscBool), (viewer, skip)); 494 PetscFunctionReturn(PETSC_SUCCESS); 495 } 496 497 static PetscErrorCode PetscViewerBinarySetSkipInfo_Binary(PetscViewer viewer, PetscBool skip) 498 { 499 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 500 501 PetscFunctionBegin; 502 vbinary->skipinfo = skip; 503 PetscFunctionReturn(PETSC_SUCCESS); 504 } 505 506 /*@ 507 PetscViewerBinaryGetSkipInfo - check if viewer wrote a `.info` file 508 509 Not Collective 510 511 Input Parameter: 512 . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 513 514 Output Parameter: 515 . skip - `PETSC_TRUE` implies the `.info` file was not generated 516 517 Level: advanced 518 519 Note: 520 This must be called after `PetscViewerSetType()` 521 522 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, 523 `PetscViewerBinarySetSkipOptions()`, `PetscViewerBinarySetSkipInfo()`, `PetscViewerBinaryGetInfoPointer()` 524 @*/ 525 PetscErrorCode PetscViewerBinaryGetSkipInfo(PetscViewer viewer, PetscBool *skip) 526 { 527 PetscFunctionBegin; 528 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 529 PetscAssertPointer(skip, 2); 530 PetscUseMethod(viewer, "PetscViewerBinaryGetSkipInfo_C", (PetscViewer, PetscBool *), (viewer, skip)); 531 PetscFunctionReturn(PETSC_SUCCESS); 532 } 533 534 static PetscErrorCode PetscViewerBinaryGetSkipInfo_Binary(PetscViewer viewer, PetscBool *skip) 535 { 536 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 537 538 PetscFunctionBegin; 539 *skip = vbinary->skipinfo; 540 PetscFunctionReturn(PETSC_SUCCESS); 541 } 542 543 /*@ 544 PetscViewerBinarySetSkipOptions - do not use values in the PETSc options database when loading objects 545 546 Not Collective 547 548 Input Parameters: 549 + viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 550 - skip - `PETSC_TRUE` means do not use the options from the options database 551 552 Options Database Key: 553 . -viewer_binary_skip_options <true or false> - true means do not use the options from the options database 554 555 Level: advanced 556 557 Note: 558 This must be called after `PetscViewerSetType()` 559 560 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`, 561 `PetscViewerBinaryGetSkipOptions()` 562 @*/ 563 PetscErrorCode PetscViewerBinarySetSkipOptions(PetscViewer viewer, PetscBool skip) 564 { 565 PetscFunctionBegin; 566 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 567 PetscValidLogicalCollectiveBool(viewer, skip, 2); 568 PetscTryMethod(viewer, "PetscViewerBinarySetSkipOptions_C", (PetscViewer, PetscBool), (viewer, skip)); 569 PetscFunctionReturn(PETSC_SUCCESS); 570 } 571 572 static PetscErrorCode PetscViewerBinarySetSkipOptions_Binary(PetscViewer viewer, PetscBool skip) 573 { 574 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 575 576 PetscFunctionBegin; 577 vbinary->skipoptions = skip; 578 PetscFunctionReturn(PETSC_SUCCESS); 579 } 580 581 /*@ 582 PetscViewerBinaryGetSkipOptions - checks if viewer uses the PETSc options database when loading objects 583 584 Not Collective 585 586 Input Parameter: 587 . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 588 589 Output Parameter: 590 . skip - `PETSC_TRUE` means do not use 591 592 Level: advanced 593 594 Note: 595 This must be called after `PetscViewerSetType()` 596 597 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`, 598 `PetscViewerBinarySetSkipOptions()` 599 @*/ 600 PetscErrorCode PetscViewerBinaryGetSkipOptions(PetscViewer viewer, PetscBool *skip) 601 { 602 PetscFunctionBegin; 603 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 604 PetscAssertPointer(skip, 2); 605 PetscUseMethod(viewer, "PetscViewerBinaryGetSkipOptions_C", (PetscViewer, PetscBool *), (viewer, skip)); 606 PetscFunctionReturn(PETSC_SUCCESS); 607 } 608 609 static PetscErrorCode PetscViewerBinaryGetSkipOptions_Binary(PetscViewer viewer, PetscBool *skip) 610 { 611 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 612 613 PetscFunctionBegin; 614 *skip = vbinary->skipoptions; 615 PetscFunctionReturn(PETSC_SUCCESS); 616 } 617 618 /*@ 619 PetscViewerBinarySetSkipHeader - do not write a header with size information on output, just raw data 620 621 Not Collective 622 623 Input Parameters: 624 + viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 625 - skip - `PETSC_TRUE` means do not write header 626 627 Options Database Key: 628 . -viewer_binary_skip_header <true or false> - true means do not write header 629 630 Level: advanced 631 632 Notes: 633 This must be called after `PetscViewerSetType()` 634 635 If this option is selected, the output file cannot be read with the `XXXLoad()` such as `VecLoad()` 636 637 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`, 638 `PetscViewerBinaryGetSkipHeader()` 639 @*/ 640 PetscErrorCode PetscViewerBinarySetSkipHeader(PetscViewer viewer, PetscBool skip) 641 { 642 PetscFunctionBegin; 643 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 644 PetscValidLogicalCollectiveBool(viewer, skip, 2); 645 PetscTryMethod(viewer, "PetscViewerBinarySetSkipHeader_C", (PetscViewer, PetscBool), (viewer, skip)); 646 PetscFunctionReturn(PETSC_SUCCESS); 647 } 648 649 static PetscErrorCode PetscViewerBinarySetSkipHeader_Binary(PetscViewer viewer, PetscBool skip) 650 { 651 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 652 653 PetscFunctionBegin; 654 vbinary->skipheader = skip; 655 PetscFunctionReturn(PETSC_SUCCESS); 656 } 657 658 /*@ 659 PetscViewerBinaryGetSkipHeader - checks whether to write a header with size information on output, or just raw data 660 661 Not Collective 662 663 Input Parameter: 664 . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 665 666 Output Parameter: 667 . skip - `PETSC_TRUE` means do not write header 668 669 Level: advanced 670 671 Notes: 672 This must be called after PetscViewerSetType() 673 674 Returns `PETSC_FALSE` for `PETSCSOCKETVIEWER`, you cannot skip the header for it. 675 676 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`, 677 `PetscViewerBinarySetSkipHeader()` 678 @*/ 679 PetscErrorCode PetscViewerBinaryGetSkipHeader(PetscViewer viewer, PetscBool *skip) 680 { 681 PetscFunctionBegin; 682 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 683 PetscAssertPointer(skip, 2); 684 PetscUseMethod(viewer, "PetscViewerBinaryGetSkipHeader_C", (PetscViewer, PetscBool *), (viewer, skip)); 685 PetscFunctionReturn(PETSC_SUCCESS); 686 } 687 688 static PetscErrorCode PetscViewerBinaryGetSkipHeader_Binary(PetscViewer viewer, PetscBool *skip) 689 { 690 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 691 692 PetscFunctionBegin; 693 *skip = vbinary->skipheader; 694 PetscFunctionReturn(PETSC_SUCCESS); 695 } 696 697 /*@C 698 PetscViewerBinaryGetInfoPointer - Extracts the file pointer for the ASCII 699 `.info` file associated with a binary file. 700 701 Not Collective; No Fortran Support 702 703 Input Parameter: 704 . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()` 705 706 Output Parameter: 707 . file - file pointer Always returns `NULL` if not a binary viewer 708 709 Level: advanced 710 711 Note: 712 For writable binary `PetscViewer`s, the file pointer will only be valid for the 713 first processor in the MPI communicator that shares the `PetscViewer`. 714 715 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinaryGetSkipInfo()`, 716 `PetscViewerBinarySetSkipInfo()` 717 @*/ 718 PetscErrorCode PetscViewerBinaryGetInfoPointer(PetscViewer viewer, FILE **file) 719 { 720 PetscFunctionBegin; 721 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 722 PetscAssertPointer(file, 2); 723 *file = NULL; 724 PetscTryMethod(viewer, "PetscViewerBinaryGetInfoPointer_C", (PetscViewer, FILE **), (viewer, file)); 725 PetscFunctionReturn(PETSC_SUCCESS); 726 } 727 728 static PetscErrorCode PetscViewerBinaryGetInfoPointer_Binary(PetscViewer viewer, FILE **file) 729 { 730 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 731 732 PetscFunctionBegin; 733 PetscCall(PetscViewerSetUp(viewer)); 734 *file = vbinary->fdes_info; 735 if (viewer->format == PETSC_VIEWER_BINARY_MATLAB && !vbinary->matlabheaderwritten) { 736 if (vbinary->fdes_info) { 737 FILE *info = vbinary->fdes_info; 738 PetscCall(PetscFPrintf(PETSC_COMM_SELF, info, "#--- begin code written by PetscViewerBinary for MATLAB format ---#\n")); 739 PetscCall(PetscFPrintf(PETSC_COMM_SELF, info, "#$$ Set.filename = '%s';\n", vbinary->filename)); 740 PetscCall(PetscFPrintf(PETSC_COMM_SELF, info, "#$$ fd = PetscOpenFile(Set.filename);\n")); 741 PetscCall(PetscFPrintf(PETSC_COMM_SELF, info, "#--- end code written by PetscViewerBinary for MATLAB format ---#\n\n")); 742 } 743 vbinary->matlabheaderwritten = PETSC_TRUE; 744 } 745 PetscFunctionReturn(PETSC_SUCCESS); 746 } 747 748 #if defined(PETSC_HAVE_MPIIO) 749 static PetscErrorCode PetscViewerFileClose_BinaryMPIIO(PetscViewer v) 750 { 751 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)v->data; 752 753 PetscFunctionBegin; 754 if (vbinary->mfdes != MPI_FILE_NULL) PetscCallMPI(MPI_File_close(&vbinary->mfdes)); 755 if (vbinary->mfsub != MPI_FILE_NULL) PetscCallMPI(MPI_File_close(&vbinary->mfsub)); 756 vbinary->moff = 0; 757 PetscFunctionReturn(PETSC_SUCCESS); 758 } 759 #endif 760 761 static PetscErrorCode PetscViewerFileClose_BinarySTDIO(PetscViewer v) 762 { 763 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)v->data; 764 765 PetscFunctionBegin; 766 if (vbinary->fdes != -1) { 767 PetscCall(PetscBinaryClose(vbinary->fdes)); 768 vbinary->fdes = -1; 769 if (vbinary->storecompressed) { 770 char cmd[8 + PETSC_MAX_PATH_LEN], out[64 + PETSC_MAX_PATH_LEN] = ""; 771 const char *gzfilename = vbinary->ogzfilename ? vbinary->ogzfilename : vbinary->filename; 772 /* compress the file */ 773 PetscCall(PetscStrncpy(cmd, "gzip -f ", sizeof(cmd))); 774 PetscCall(PetscStrlcat(cmd, gzfilename, sizeof(cmd))); 775 #if defined(PETSC_HAVE_POPEN) 776 { 777 FILE *fp; 778 PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, cmd, "r", &fp)); 779 PetscCheck(!fgets(out, (int)(sizeof(out) - 1), fp), PETSC_COMM_SELF, PETSC_ERR_LIB, "Error from command %s\n%s", cmd, out); 780 PetscCall(PetscPClose(PETSC_COMM_SELF, fp)); 781 } 782 #endif 783 } 784 } 785 PetscCall(PetscFree(vbinary->ogzfilename)); 786 PetscFunctionReturn(PETSC_SUCCESS); 787 } 788 789 static PetscErrorCode PetscViewerFileClose_BinaryInfo(PetscViewer v) 790 { 791 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)v->data; 792 793 PetscFunctionBegin; 794 if (v->format == PETSC_VIEWER_BINARY_MATLAB && vbinary->matlabheaderwritten) { 795 if (vbinary->fdes_info) { 796 FILE *info = vbinary->fdes_info; 797 PetscCall(PetscFPrintf(PETSC_COMM_SELF, info, "#--- begin code written by PetscViewerBinary for MATLAB format ---#\n")); 798 PetscCall(PetscFPrintf(PETSC_COMM_SELF, info, "#$$ close(fd);\n")); 799 PetscCall(PetscFPrintf(PETSC_COMM_SELF, info, "#--- end code written by PetscViewerBinary for MATLAB format ---#\n\n")); 800 } 801 } 802 if (vbinary->fdes_info) { 803 FILE *info = vbinary->fdes_info; 804 vbinary->fdes_info = NULL; 805 PetscCheck(!fclose(info), PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file"); 806 } 807 PetscFunctionReturn(PETSC_SUCCESS); 808 } 809 810 static PetscErrorCode PetscViewerFileClose_Binary(PetscViewer v) 811 { 812 PetscFunctionBegin; 813 #if defined(PETSC_HAVE_MPIIO) 814 PetscCall(PetscViewerFileClose_BinaryMPIIO(v)); 815 #endif 816 PetscCall(PetscViewerFileClose_BinarySTDIO(v)); 817 PetscCall(PetscViewerFileClose_BinaryInfo(v)); 818 PetscFunctionReturn(PETSC_SUCCESS); 819 } 820 821 static PetscErrorCode PetscViewerDestroy_Binary(PetscViewer v) 822 { 823 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)v->data; 824 825 PetscFunctionBegin; 826 PetscCall(PetscViewerFileClose_Binary(v)); 827 PetscCall(PetscFree(vbinary->filename)); 828 PetscCall(PetscFree(vbinary)); 829 PetscCall(PetscViewerBinaryClearFunctionList(v)); 830 PetscFunctionReturn(PETSC_SUCCESS); 831 } 832 833 /*@C 834 PetscViewerBinaryOpen - Opens a file for binary input/output. 835 836 Collective 837 838 Input Parameters: 839 + comm - MPI communicator 840 . name - name of file 841 - mode - open mode of file 842 .vb 843 FILE_MODE_WRITE - create new file for binary output 844 FILE_MODE_READ - open existing file for binary input 845 FILE_MODE_APPEND - open existing file for binary output 846 .ve 847 848 Output Parameter: 849 . viewer - PetscViewer for binary input/output to use with the specified file 850 851 Options Database Keys: 852 + -viewer_binary_filename <name> - name of file to use 853 . -viewer_binary_skip_info - true to skip opening an info file 854 . -viewer_binary_skip_options - true to not use options database while creating viewer 855 . -viewer_binary_skip_header - true to skip output object headers to the file 856 - -viewer_binary_mpiio - true to use MPI-IO for input and output to the file (more scalable for large problems) 857 858 Level: beginner 859 860 Note: 861 This `PetscViewer` should be destroyed with `PetscViewerDestroy()`. 862 863 For reading files, the filename may begin with ftp:// or http:// and/or 864 end with .gz; in this case file is brought over and uncompressed. 865 866 For creating files, if the file name ends with .gz it is automatically 867 compressed when closed. 868 869 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, 870 `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`, 871 `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`, `PetscViewerBinarySetUseMPIIO()`, 872 `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()` 873 @*/ 874 PetscErrorCode PetscViewerBinaryOpen(MPI_Comm comm, const char name[], PetscFileMode mode, PetscViewer *viewer) 875 { 876 PetscFunctionBegin; 877 PetscCall(PetscViewerCreate(comm, viewer)); 878 PetscCall(PetscViewerSetType(*viewer, PETSCVIEWERBINARY)); 879 PetscCall(PetscViewerFileSetMode(*viewer, mode)); 880 PetscCall(PetscViewerFileSetName(*viewer, name)); 881 PetscCall(PetscViewerSetFromOptions(*viewer)); 882 PetscFunctionReturn(PETSC_SUCCESS); 883 } 884 885 #if defined(PETSC_HAVE_MPIIO) 886 static PetscErrorCode PetscViewerBinaryWriteReadMPIIO(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype, PetscBool write) 887 { 888 MPI_Comm comm = PetscObjectComm((PetscObject)viewer); 889 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 890 MPI_File mfdes = vbinary->mfdes; 891 MPI_Datatype mdtype; 892 PetscMPIInt rank, cnt; 893 MPI_Status status; 894 MPI_Aint ul, dsize; 895 896 PetscFunctionBegin; 897 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 898 PetscCall(PetscMPIIntCast(num, &cnt)); 899 PetscCall(PetscDataTypeToMPIDataType(dtype, &mdtype)); 900 if (write) { 901 if (rank == 0) PetscCall(MPIU_File_write_at(mfdes, vbinary->moff, data, cnt, mdtype, &status)); 902 } else { 903 if (rank == 0) { 904 PetscCall(MPIU_File_read_at(mfdes, vbinary->moff, data, cnt, mdtype, &status)); 905 if (cnt > 0) PetscCallMPI(MPI_Get_count(&status, mdtype, &cnt)); 906 } 907 PetscCallMPI(MPI_Bcast(&cnt, 1, MPI_INT, 0, comm)); 908 PetscCallMPI(MPI_Bcast(data, cnt, mdtype, 0, comm)); 909 } 910 PetscCallMPI(MPI_Type_get_extent(mdtype, &ul, &dsize)); 911 vbinary->moff += dsize * cnt; 912 if (count) *count = cnt; 913 PetscFunctionReturn(PETSC_SUCCESS); 914 } 915 #endif 916 917 /*@C 918 PetscViewerBinaryRead - Reads from a binary file, all processors get the same result 919 920 Collective; No Fortran Support 921 922 Input Parameters: 923 + viewer - the `PETSCVIEWERBINARY` viewer 924 . num - number of items of data to read 925 - dtype - type of data to read 926 927 Output Parameters: 928 + data - location of the read data, treated as an array of the type indicated by `dtype` 929 - count - number of items of data actually read, or `NULL`. 930 931 Level: beginner 932 933 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, 934 `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`, 935 `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer` 936 @*/ 937 PetscErrorCode PetscViewerBinaryRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype) 938 { 939 PetscViewer_Binary *vbinary; 940 941 PetscFunctionBegin; 942 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERBINARY); 943 PetscValidLogicalCollectiveInt(viewer, num, 3); 944 PetscCall(PetscViewerSetUp(viewer)); 945 vbinary = (PetscViewer_Binary *)viewer->data; 946 #if defined(PETSC_HAVE_MPIIO) 947 if (vbinary->usempiio) { 948 PetscCall(PetscViewerBinaryWriteReadMPIIO(viewer, data, num, count, dtype, PETSC_FALSE)); 949 } else { 950 #endif 951 PetscCall(PetscBinarySynchronizedRead(PetscObjectComm((PetscObject)viewer), vbinary->fdes, data, num, count, dtype)); 952 #if defined(PETSC_HAVE_MPIIO) 953 } 954 #endif 955 PetscFunctionReturn(PETSC_SUCCESS); 956 } 957 958 /*@C 959 PetscViewerBinaryWrite - writes to a binary file, only from the first MPI rank 960 961 Collective; No Fortran Support 962 963 Input Parameters: 964 + viewer - the `PETSCVIEWERBINARY` viewer 965 . data - location of data, treated as an array of the type indicated by `dtype` 966 . count - number of items of data to write 967 - dtype - type of data to write 968 969 Level: beginner 970 971 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, 972 `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`, `PetscDataType` 973 `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()` 974 @*/ 975 PetscErrorCode PetscViewerBinaryWrite(PetscViewer viewer, const void *data, PetscInt count, PetscDataType dtype) 976 { 977 PetscViewer_Binary *vbinary; 978 979 PetscFunctionBegin; 980 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERBINARY); 981 PetscValidLogicalCollectiveInt(viewer, count, 3); 982 PetscCall(PetscViewerSetUp(viewer)); 983 vbinary = (PetscViewer_Binary *)viewer->data; 984 #if defined(PETSC_HAVE_MPIIO) 985 if (vbinary->usempiio) { 986 PetscCall(PetscViewerBinaryWriteReadMPIIO(viewer, (void *)data, count, NULL, dtype, PETSC_TRUE)); 987 } else { 988 #endif 989 PetscCall(PetscBinarySynchronizedWrite(PetscObjectComm((PetscObject)viewer), vbinary->fdes, data, count, dtype)); 990 #if defined(PETSC_HAVE_MPIIO) 991 } 992 #endif 993 PetscFunctionReturn(PETSC_SUCCESS); 994 } 995 996 static PetscErrorCode PetscViewerBinaryWriteReadAll(PetscViewer viewer, PetscBool write, void *data, PetscInt count, PetscInt64 start, PetscInt64 total, PetscDataType dtype) 997 { 998 MPI_Comm comm = PetscObjectComm((PetscObject)viewer); 999 PetscMPIInt size, rank; 1000 MPI_Datatype mdtype; 1001 PETSC_UNUSED MPI_Aint lb; 1002 MPI_Aint dsize; 1003 PetscBool useMPIIO; 1004 1005 PetscFunctionBegin; 1006 PetscValidHeaderSpecificType(viewer, PETSC_VIEWER_CLASSID, 1, PETSCVIEWERBINARY); 1007 PetscValidLogicalCollectiveBool(viewer, ((start >= 0) || (start == PETSC_DETERMINE)), 5); 1008 PetscValidLogicalCollectiveBool(viewer, ((total >= 0) || (total == PETSC_DETERMINE)), 6); 1009 PetscValidLogicalCollectiveInt(viewer, total, 6); 1010 PetscCall(PetscViewerSetUp(viewer)); 1011 1012 PetscCall(PetscDataTypeToMPIDataType(dtype, &mdtype)); 1013 PetscCallMPI(MPI_Type_get_extent(mdtype, &lb, &dsize)); 1014 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1015 PetscCallMPI(MPI_Comm_size(comm, &size)); 1016 1017 PetscCall(PetscViewerBinaryGetUseMPIIO(viewer, &useMPIIO)); 1018 #if defined(PETSC_HAVE_MPIIO) 1019 if (useMPIIO) { 1020 MPI_File mfdes; 1021 MPI_Offset off; 1022 PetscMPIInt cnt; 1023 1024 if (start == PETSC_DETERMINE) { 1025 PetscInt64 pcnt = count; 1026 PetscCallMPI(MPI_Scan(&pcnt, &start, 1, MPIU_INT64, MPI_SUM, comm)); 1027 start -= count; 1028 } 1029 if (total == PETSC_DETERMINE) { 1030 total = start + count; 1031 PetscCallMPI(MPI_Bcast(&total, 1, MPIU_INT64, size - 1, comm)); 1032 } 1033 PetscCall(PetscMPIIntCast(count, &cnt)); 1034 PetscCall(PetscViewerBinaryGetMPIIODescriptor(viewer, &mfdes)); 1035 PetscCall(PetscViewerBinaryGetMPIIOOffset(viewer, &off)); 1036 off += (MPI_Offset)(start * dsize); 1037 if (write) { 1038 PetscCall(MPIU_File_write_at_all(mfdes, off, data, cnt, mdtype, MPI_STATUS_IGNORE)); 1039 } else { 1040 PetscCall(MPIU_File_read_at_all(mfdes, off, data, cnt, mdtype, MPI_STATUS_IGNORE)); 1041 } 1042 off = (MPI_Offset)(total * dsize); 1043 PetscCall(PetscViewerBinaryAddMPIIOOffset(viewer, off)); 1044 PetscFunctionReturn(PETSC_SUCCESS); 1045 } 1046 #endif 1047 { 1048 int fdes; 1049 char *workbuf = NULL; 1050 PetscInt tcount = rank == 0 ? 0 : count, maxcount = 0, message_count, flowcontrolcount; 1051 PetscMPIInt tag, cnt, maxcnt, scnt = 0, rcnt = 0, j; 1052 MPI_Status status; 1053 1054 PetscCall(PetscCommGetNewTag(comm, &tag)); 1055 PetscCallMPI(MPI_Reduce(&tcount, &maxcount, 1, MPIU_INT, MPI_MAX, 0, comm)); 1056 PetscCall(PetscMPIIntCast(maxcount, &maxcnt)); 1057 PetscCall(PetscMPIIntCast(count, &cnt)); 1058 1059 PetscCall(PetscViewerBinaryGetDescriptor(viewer, &fdes)); 1060 PetscCall(PetscViewerFlowControlStart(viewer, &message_count, &flowcontrolcount)); 1061 if (rank == 0) { 1062 PetscCall(PetscMalloc(maxcnt * dsize, &workbuf)); 1063 if (write) { 1064 PetscCall(PetscBinaryWrite(fdes, data, cnt, dtype)); 1065 } else { 1066 PetscCall(PetscBinaryRead(fdes, data, cnt, NULL, dtype)); 1067 } 1068 for (j = 1; j < size; j++) { 1069 PetscCall(PetscViewerFlowControlStepMain(viewer, j, &message_count, flowcontrolcount)); 1070 if (write) { 1071 PetscCallMPI(MPI_Recv(workbuf, maxcnt, mdtype, j, tag, comm, &status)); 1072 PetscCallMPI(MPI_Get_count(&status, mdtype, &rcnt)); 1073 PetscCall(PetscBinaryWrite(fdes, workbuf, rcnt, dtype)); 1074 } else { 1075 PetscCallMPI(MPI_Recv(&scnt, 1, MPI_INT, j, tag, comm, MPI_STATUS_IGNORE)); 1076 PetscCall(PetscBinaryRead(fdes, workbuf, scnt, NULL, dtype)); 1077 PetscCallMPI(MPI_Send(workbuf, scnt, mdtype, j, tag, comm)); 1078 } 1079 } 1080 PetscCall(PetscFree(workbuf)); 1081 PetscCall(PetscViewerFlowControlEndMain(viewer, &message_count)); 1082 } else { 1083 PetscCall(PetscViewerFlowControlStepWorker(viewer, rank, &message_count)); 1084 if (write) { 1085 PetscCallMPI(MPI_Send(data, cnt, mdtype, 0, tag, comm)); 1086 } else { 1087 PetscCallMPI(MPI_Send(&cnt, 1, MPI_INT, 0, tag, comm)); 1088 PetscCallMPI(MPI_Recv(data, cnt, mdtype, 0, tag, comm, MPI_STATUS_IGNORE)); 1089 } 1090 PetscCall(PetscViewerFlowControlEndWorker(viewer, &message_count)); 1091 } 1092 } 1093 PetscFunctionReturn(PETSC_SUCCESS); 1094 } 1095 1096 /*@C 1097 PetscViewerBinaryReadAll - reads from a binary file from all MPI processes, each rank receives its own portion of the data 1098 1099 Collective; No Fortran Support 1100 1101 Input Parameters: 1102 + viewer - the `PETSCVIEWERBINARY` viewer 1103 . count - local number of items of data to read 1104 . start - local start, can be `PETSC_DETERMINE` 1105 . total - global number of items of data to read, can be `PETSC_DETERMINE` 1106 - dtype - type of data to read 1107 1108 Output Parameter: 1109 . data - location of data, treated as an array of type indicated by `dtype` 1110 1111 Level: advanced 1112 1113 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryRead()`, `PetscViewerBinaryWriteAll()` 1114 @*/ 1115 PetscErrorCode PetscViewerBinaryReadAll(PetscViewer viewer, void *data, PetscInt count, PetscInt64 start, PetscInt64 total, PetscDataType dtype) 1116 { 1117 PetscFunctionBegin; 1118 PetscCall(PetscViewerBinaryWriteReadAll(viewer, PETSC_FALSE, data, count, start, total, dtype)); 1119 PetscFunctionReturn(PETSC_SUCCESS); 1120 } 1121 1122 /*@C 1123 PetscViewerBinaryWriteAll - writes to a binary file from all MPI processes, each rank writes its own portion of the data 1124 1125 Collective; No Fortran Support 1126 1127 Input Parameters: 1128 + viewer - the `PETSCVIEWERBINARY` viewer 1129 . data - location of data 1130 . count - local number of items of data to write, treated as an array of type indicated by `dtype` 1131 . start - local start, can be `PETSC_DETERMINE` 1132 . total - global number of items of data to write, can be `PETSC_DETERMINE` 1133 - dtype - type of data to write 1134 1135 Level: advanced 1136 1137 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryReadAll()` 1138 @*/ 1139 PetscErrorCode PetscViewerBinaryWriteAll(PetscViewer viewer, const void *data, PetscInt count, PetscInt64 start, PetscInt64 total, PetscDataType dtype) 1140 { 1141 PetscFunctionBegin; 1142 PetscCall(PetscViewerBinaryWriteReadAll(viewer, PETSC_TRUE, (void *)data, count, start, total, dtype)); 1143 PetscFunctionReturn(PETSC_SUCCESS); 1144 } 1145 1146 /*@C 1147 PetscViewerBinaryWriteStringArray - writes to a binary file, only from the first MPI rank, an array of strings 1148 1149 Collective; No Fortran Support 1150 1151 Input Parameters: 1152 + viewer - the `PETSCVIEWERBINARY` viewer 1153 - data - location of the array of strings 1154 1155 Level: intermediate 1156 1157 Note: 1158 The array of strings must be `NULL` terminated 1159 1160 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, 1161 `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`, 1162 `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()` 1163 @*/ 1164 PetscErrorCode PetscViewerBinaryWriteStringArray(PetscViewer viewer, const char *const *data) 1165 { 1166 PetscInt i, n = 0, *sizes; 1167 size_t len; 1168 1169 PetscFunctionBegin; 1170 PetscCall(PetscViewerSetUp(viewer)); 1171 /* count number of strings */ 1172 while (data[n++]) 1173 ; 1174 n--; 1175 PetscCall(PetscMalloc1(n + 1, &sizes)); 1176 sizes[0] = n; 1177 for (i = 0; i < n; i++) { 1178 PetscCall(PetscStrlen(data[i], &len)); 1179 sizes[i + 1] = (PetscInt)len + 1; /* size includes space for the null terminator */ 1180 } 1181 PetscCall(PetscViewerBinaryWrite(viewer, sizes, n + 1, PETSC_INT)); 1182 for (i = 0; i < n; i++) PetscCall(PetscViewerBinaryWrite(viewer, (void *)data[i], sizes[i + 1], PETSC_CHAR)); 1183 PetscCall(PetscFree(sizes)); 1184 PetscFunctionReturn(PETSC_SUCCESS); 1185 } 1186 1187 /*@C 1188 PetscViewerBinaryReadStringArray - reads a binary file an array of strings to all MPI processes 1189 1190 Collective; No Fortran Support 1191 1192 Input Parameter: 1193 . viewer - the `PETSCVIEWERBINARY` viewer 1194 1195 Output Parameter: 1196 . data - location of the array of strings 1197 1198 Level: intermediate 1199 1200 Note: 1201 The array of strings must `NULL` terminated 1202 1203 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, 1204 `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`, 1205 `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()` 1206 @*/ 1207 PetscErrorCode PetscViewerBinaryReadStringArray(PetscViewer viewer, char ***data) 1208 { 1209 PetscInt i, n, *sizes, N = 0; 1210 1211 PetscFunctionBegin; 1212 PetscCall(PetscViewerSetUp(viewer)); 1213 /* count number of strings */ 1214 PetscCall(PetscViewerBinaryRead(viewer, &n, 1, NULL, PETSC_INT)); 1215 PetscCall(PetscMalloc1(n, &sizes)); 1216 PetscCall(PetscViewerBinaryRead(viewer, sizes, n, NULL, PETSC_INT)); 1217 for (i = 0; i < n; i++) N += sizes[i]; 1218 PetscCall(PetscMalloc((n + 1) * sizeof(char *) + N * sizeof(char), data)); 1219 (*data)[0] = (char *)((*data) + n + 1); 1220 for (i = 1; i < n; i++) (*data)[i] = (*data)[i - 1] + sizes[i - 1]; 1221 PetscCall(PetscViewerBinaryRead(viewer, (*data)[0], N, NULL, PETSC_CHAR)); 1222 (*data)[n] = NULL; 1223 PetscCall(PetscFree(sizes)); 1224 PetscFunctionReturn(PETSC_SUCCESS); 1225 } 1226 1227 /*@C 1228 PetscViewerFileSetMode - Sets the open mode of file 1229 1230 Logically Collective 1231 1232 Input Parameters: 1233 + viewer - the `PetscViewer`; must be a a `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`, `PETSCVIEWERHDF5`, or `PETSCVIEWERASCII` `PetscViewer` 1234 - mode - open mode of file 1235 .vb 1236 FILE_MODE_WRITE - create new file for output 1237 FILE_MODE_READ - open existing file for input 1238 FILE_MODE_APPEND - open existing file for output 1239 .ve 1240 1241 Level: advanced 1242 1243 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()` 1244 @*/ 1245 PetscErrorCode PetscViewerFileSetMode(PetscViewer viewer, PetscFileMode mode) 1246 { 1247 PetscFunctionBegin; 1248 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1249 PetscValidLogicalCollectiveEnum(viewer, mode, 2); 1250 PetscCheck(mode != FILE_MODE_UNDEFINED, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Cannot set FILE_MODE_UNDEFINED"); 1251 PetscCheck(mode >= FILE_MODE_UNDEFINED && mode <= FILE_MODE_APPEND_UPDATE, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_OUTOFRANGE, "Invalid file mode %d", (int)mode); 1252 PetscTryMethod(viewer, "PetscViewerFileSetMode_C", (PetscViewer, PetscFileMode), (viewer, mode)); 1253 PetscFunctionReturn(PETSC_SUCCESS); 1254 } 1255 1256 static PetscErrorCode PetscViewerFileSetMode_Binary(PetscViewer viewer, PetscFileMode mode) 1257 { 1258 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 1259 1260 PetscFunctionBegin; 1261 PetscCheck(!viewer->setupcalled || vbinary->filemode == mode, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ORDER, "Cannot change mode to %s after setup", PetscFileModes[mode]); 1262 vbinary->filemode = mode; 1263 PetscFunctionReturn(PETSC_SUCCESS); 1264 } 1265 1266 /*@C 1267 PetscViewerFileGetMode - Gets the open mode of a file associated with a `PetscViewer` 1268 1269 Not Collective 1270 1271 Input Parameter: 1272 . viewer - the `PetscViewer`; must be a `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`, `PETSCVIEWERHDF5`, or `PETSCVIEWERASCII` `PetscViewer` 1273 1274 Output Parameter: 1275 . mode - open mode of file 1276 .vb 1277 FILE_MODE_WRITE - create new file for binary output 1278 FILE_MODE_READ - open existing file for binary input 1279 FILE_MODE_APPEND - open existing file for binary output 1280 .ve 1281 1282 Level: advanced 1283 1284 .seealso: [](sec_viewers), `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()` 1285 @*/ 1286 PetscErrorCode PetscViewerFileGetMode(PetscViewer viewer, PetscFileMode *mode) 1287 { 1288 PetscFunctionBegin; 1289 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1); 1290 PetscAssertPointer(mode, 2); 1291 PetscUseMethod(viewer, "PetscViewerFileGetMode_C", (PetscViewer, PetscFileMode *), (viewer, mode)); 1292 PetscFunctionReturn(PETSC_SUCCESS); 1293 } 1294 1295 static PetscErrorCode PetscViewerFileGetMode_Binary(PetscViewer viewer, PetscFileMode *mode) 1296 { 1297 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 1298 1299 PetscFunctionBegin; 1300 *mode = vbinary->filemode; 1301 PetscFunctionReturn(PETSC_SUCCESS); 1302 } 1303 1304 static PetscErrorCode PetscViewerFileSetName_Binary(PetscViewer viewer, const char name[]) 1305 { 1306 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 1307 1308 PetscFunctionBegin; 1309 if (viewer->setupcalled && vbinary->filename) { 1310 /* gzip can be run after the file with the previous filename has been closed */ 1311 PetscCall(PetscFree(vbinary->ogzfilename)); 1312 PetscCall(PetscStrallocpy(vbinary->filename, &vbinary->ogzfilename)); 1313 } 1314 PetscCall(PetscFree(vbinary->filename)); 1315 PetscCall(PetscStrallocpy(name, &vbinary->filename)); 1316 viewer->setupcalled = PETSC_FALSE; 1317 PetscFunctionReturn(PETSC_SUCCESS); 1318 } 1319 1320 static PetscErrorCode PetscViewerFileGetName_Binary(PetscViewer viewer, const char **name) 1321 { 1322 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 1323 1324 PetscFunctionBegin; 1325 *name = vbinary->filename; 1326 PetscFunctionReturn(PETSC_SUCCESS); 1327 } 1328 1329 #if defined(PETSC_HAVE_MPIIO) 1330 static PetscErrorCode PetscViewerFileSetUp_BinaryMPIIO(PetscViewer viewer) 1331 { 1332 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 1333 int amode; 1334 1335 PetscFunctionBegin; 1336 vbinary->storecompressed = PETSC_FALSE; 1337 1338 vbinary->moff = 0; 1339 switch (vbinary->filemode) { 1340 case FILE_MODE_READ: 1341 amode = MPI_MODE_RDONLY; 1342 break; 1343 case FILE_MODE_WRITE: 1344 amode = MPI_MODE_WRONLY | MPI_MODE_CREATE; 1345 break; 1346 case FILE_MODE_APPEND: 1347 amode = MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_APPEND; 1348 break; 1349 case FILE_MODE_UNDEFINED: 1350 SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode() before PetscViewerSetUp()"); 1351 default: 1352 SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vbinary->filemode]); 1353 } 1354 PetscCallMPI(MPI_File_open(PetscObjectComm((PetscObject)viewer), vbinary->filename, amode, MPI_INFO_NULL, &vbinary->mfdes)); 1355 /* 1356 The MPI standard does not have MPI_MODE_TRUNCATE. We emulate this behavior by setting the file size to zero. 1357 */ 1358 if (vbinary->filemode == FILE_MODE_WRITE) PetscCallMPI(MPI_File_set_size(vbinary->mfdes, 0)); 1359 /* 1360 Initially, all processes view the file as a linear byte stream. Therefore, for files opened with MPI_MODE_APPEND, 1361 MPI_File_get_position[_shared](fh, &offset) returns the absolute byte position at the end of file. 1362 Otherwise, we would need to call MPI_File_get_byte_offset(fh, offset, &byte_offset) to convert 1363 the offset in etype units to an absolute byte position. 1364 */ 1365 if (vbinary->filemode == FILE_MODE_APPEND) PetscCallMPI(MPI_File_get_position(vbinary->mfdes, &vbinary->moff)); 1366 PetscFunctionReturn(PETSC_SUCCESS); 1367 } 1368 #endif 1369 1370 static PetscErrorCode PetscViewerFileSetUp_BinarySTDIO(PetscViewer viewer) 1371 { 1372 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 1373 const char *fname; 1374 char bname[PETSC_MAX_PATH_LEN], *gz = NULL; 1375 PetscBool found; 1376 PetscMPIInt rank; 1377 1378 PetscFunctionBegin; 1379 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1380 1381 /* if file name ends in .gz strip that off and note user wants file compressed */ 1382 vbinary->storecompressed = PETSC_FALSE; 1383 if (vbinary->filemode == FILE_MODE_WRITE) { 1384 PetscCall(PetscStrstr(vbinary->filename, ".gz", &gz)); 1385 if (gz && gz[3] == 0) { 1386 *gz = 0; 1387 vbinary->storecompressed = PETSC_TRUE; 1388 } 1389 } 1390 #if !defined(PETSC_HAVE_POPEN) 1391 PetscCheck(!vbinary->storecompressed, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP_SYS, "Cannot run gzip on this machine"); 1392 #endif 1393 1394 fname = vbinary->filename; 1395 if (vbinary->filemode == FILE_MODE_READ) { /* possibly get the file from remote site or compressed file */ 1396 PetscCall(PetscFileRetrieve(PetscObjectComm((PetscObject)viewer), fname, bname, PETSC_MAX_PATH_LEN, &found)); 1397 PetscCheck(found, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_OPEN, "Cannot locate file: %s", fname); 1398 fname = bname; 1399 } 1400 1401 vbinary->fdes = -1; 1402 if (rank == 0) { /* only first processor opens file*/ 1403 PetscFileMode mode = vbinary->filemode; 1404 if (mode == FILE_MODE_APPEND) { 1405 /* check if asked to append to a non-existing file */ 1406 PetscCall(PetscTestFile(fname, '\0', &found)); 1407 if (!found) mode = FILE_MODE_WRITE; 1408 } 1409 PetscCall(PetscBinaryOpen(fname, mode, &vbinary->fdes)); 1410 } 1411 PetscFunctionReturn(PETSC_SUCCESS); 1412 } 1413 1414 #include <errno.h> 1415 static PetscErrorCode PetscViewerFileSetUp_BinaryInfo(PetscViewer viewer) 1416 { 1417 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 1418 PetscMPIInt rank; 1419 PetscBool found; 1420 1421 PetscFunctionBegin; 1422 vbinary->fdes_info = NULL; 1423 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 1424 if (!vbinary->skipinfo && (vbinary->filemode == FILE_MODE_READ || rank == 0)) { 1425 char infoname[PETSC_MAX_PATH_LEN], iname[PETSC_MAX_PATH_LEN], *gz; 1426 1427 PetscCall(PetscStrncpy(infoname, vbinary->filename, sizeof(infoname))); 1428 /* remove .gz if it ends file name */ 1429 PetscCall(PetscStrstr(infoname, ".gz", &gz)); 1430 if (gz && gz[3] == 0) *gz = 0; 1431 1432 PetscCall(PetscStrlcat(infoname, ".info", sizeof(infoname))); 1433 if (vbinary->filemode == FILE_MODE_READ) { 1434 PetscCall(PetscFixFilename(infoname, iname)); 1435 PetscCall(PetscFileRetrieve(PetscObjectComm((PetscObject)viewer), iname, infoname, PETSC_MAX_PATH_LEN, &found)); 1436 if (found) PetscCall(PetscOptionsInsertFile(PetscObjectComm((PetscObject)viewer), ((PetscObject)viewer)->options, infoname, PETSC_FALSE)); 1437 } else if (rank == 0) { /* write or append */ 1438 const char *omode = (vbinary->filemode == FILE_MODE_APPEND) ? "a" : "w"; 1439 vbinary->fdes_info = fopen(infoname, omode); 1440 PetscCheck(vbinary->fdes_info, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open .info file %s for writing due to \"%s\"", infoname, strerror(errno)); 1441 } 1442 } 1443 PetscFunctionReturn(PETSC_SUCCESS); 1444 } 1445 1446 static PetscErrorCode PetscViewerSetUp_Binary(PetscViewer viewer) 1447 { 1448 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data; 1449 PetscBool usempiio; 1450 1451 PetscFunctionBegin; 1452 if (!vbinary->setfromoptionscalled) PetscCall(PetscViewerSetFromOptions(viewer)); 1453 PetscCheck(vbinary->filename, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call PetscViewerFileSetName()"); 1454 PetscCheck(vbinary->filemode != (PetscFileMode)-1, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Must call PetscViewerFileSetMode()"); 1455 PetscCall(PetscViewerFileClose_Binary(viewer)); 1456 1457 PetscCall(PetscViewerBinaryGetUseMPIIO(viewer, &usempiio)); 1458 if (usempiio) { 1459 #if defined(PETSC_HAVE_MPIIO) 1460 PetscCall(PetscViewerFileSetUp_BinaryMPIIO(viewer)); 1461 #endif 1462 } else { 1463 PetscCall(PetscViewerFileSetUp_BinarySTDIO(viewer)); 1464 } 1465 PetscCall(PetscViewerFileSetUp_BinaryInfo(viewer)); 1466 1467 PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", vbinary->filename)); 1468 PetscFunctionReturn(PETSC_SUCCESS); 1469 } 1470 1471 static PetscErrorCode PetscViewerView_Binary(PetscViewer v, PetscViewer viewer) 1472 { 1473 PetscViewer_Binary *vbinary = (PetscViewer_Binary *)v->data; 1474 const char *fname = vbinary->filename ? vbinary->filename : "not yet set"; 1475 const char *fmode = vbinary->filemode != (PetscFileMode)-1 ? PetscFileModes[vbinary->filemode] : "not yet set"; 1476 PetscBool usempiio; 1477 1478 PetscFunctionBegin; 1479 PetscCall(PetscViewerBinaryGetUseMPIIO(v, &usempiio)); 1480 PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", fname)); 1481 PetscCall(PetscViewerASCIIPrintf(viewer, "Mode: %s (%s)\n", fmode, usempiio ? "mpiio" : "stdio")); 1482 PetscFunctionReturn(PETSC_SUCCESS); 1483 } 1484 1485 static PetscErrorCode PetscViewerSetFromOptions_Binary(PetscViewer viewer, PetscOptionItems *PetscOptionsObject) 1486 { 1487 PetscViewer_Binary *binary = (PetscViewer_Binary *)viewer->data; 1488 char defaultname[PETSC_MAX_PATH_LEN]; 1489 PetscBool flg; 1490 1491 PetscFunctionBegin; 1492 if (viewer->setupcalled) PetscFunctionReturn(PETSC_SUCCESS); 1493 PetscOptionsHeadBegin(PetscOptionsObject, "Binary PetscViewer Options"); 1494 PetscCall(PetscSNPrintf(defaultname, PETSC_MAX_PATH_LEN - 1, "binaryoutput")); 1495 PetscCall(PetscOptionsString("-viewer_binary_filename", "Specify filename", "PetscViewerFileSetName", defaultname, defaultname, sizeof(defaultname), &flg)); 1496 if (flg) PetscCall(PetscViewerFileSetName_Binary(viewer, defaultname)); 1497 PetscCall(PetscOptionsBool("-viewer_binary_skip_info", "Skip writing/reading .info file", "PetscViewerBinarySetSkipInfo", binary->skipinfo, &binary->skipinfo, NULL)); 1498 PetscCall(PetscOptionsBool("-viewer_binary_skip_options", "Skip parsing Vec/Mat load options", "PetscViewerBinarySetSkipOptions", binary->skipoptions, &binary->skipoptions, NULL)); 1499 PetscCall(PetscOptionsBool("-viewer_binary_skip_header", "Skip writing/reading header information", "PetscViewerBinarySetSkipHeader", binary->skipheader, &binary->skipheader, NULL)); 1500 #if defined(PETSC_HAVE_MPIIO) 1501 PetscCall(PetscOptionsBool("-viewer_binary_mpiio", "Use MPI-IO functionality to write/read binary file", "PetscViewerBinarySetUseMPIIO", binary->usempiio, &binary->usempiio, NULL)); 1502 #else 1503 PetscCall(PetscOptionsBool("-viewer_binary_mpiio", "Use MPI-IO functionality to write/read binary file (NOT AVAILABLE)", "PetscViewerBinarySetUseMPIIO", PETSC_FALSE, &flg, NULL)); 1504 #endif 1505 PetscOptionsHeadEnd(); 1506 binary->setfromoptionscalled = PETSC_TRUE; 1507 PetscFunctionReturn(PETSC_SUCCESS); 1508 } 1509 1510 /*MC 1511 PETSCVIEWERBINARY - A viewer that saves to binary files 1512 1513 Level: beginner 1514 1515 .seealso: [](sec_viewers), `PetscViewerBinaryOpen()`, `PETSC_VIEWER_STDOUT_()`, `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, 1516 `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`, `PETSCVIEWERDRAW`, `PETSCVIEWERSOCKET` 1517 `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`, 1518 `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()` 1519 M*/ 1520 1521 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Binary(PetscViewer v) 1522 { 1523 PetscViewer_Binary *vbinary; 1524 1525 PetscFunctionBegin; 1526 PetscCall(PetscNew(&vbinary)); 1527 v->data = (void *)vbinary; 1528 1529 v->ops->setfromoptions = PetscViewerSetFromOptions_Binary; 1530 v->ops->destroy = PetscViewerDestroy_Binary; 1531 v->ops->view = PetscViewerView_Binary; 1532 v->ops->setup = PetscViewerSetUp_Binary; 1533 v->ops->flush = NULL; /* Should we support Flush() ? */ 1534 v->ops->getsubviewer = PetscViewerGetSubViewer_Binary; 1535 v->ops->restoresubviewer = PetscViewerRestoreSubViewer_Binary; 1536 v->ops->read = PetscViewerBinaryRead; 1537 1538 vbinary->fdes = -1; 1539 #if defined(PETSC_HAVE_MPIIO) 1540 vbinary->usempiio = PETSC_FALSE; 1541 vbinary->mfdes = MPI_FILE_NULL; 1542 vbinary->mfsub = MPI_FILE_NULL; 1543 #endif 1544 vbinary->filename = NULL; 1545 vbinary->filemode = FILE_MODE_UNDEFINED; 1546 vbinary->fdes_info = NULL; 1547 vbinary->skipinfo = PETSC_FALSE; 1548 vbinary->skipoptions = PETSC_TRUE; 1549 vbinary->skipheader = PETSC_FALSE; 1550 vbinary->storecompressed = PETSC_FALSE; 1551 vbinary->ogzfilename = NULL; 1552 vbinary->flowcontrol = 256; /* seems a good number for Cray XT-5 */ 1553 1554 vbinary->setfromoptionscalled = PETSC_FALSE; 1555 1556 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetFlowControl_C", PetscViewerBinaryGetFlowControl_Binary)); 1557 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetFlowControl_C", PetscViewerBinarySetFlowControl_Binary)); 1558 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipHeader_C", PetscViewerBinaryGetSkipHeader_Binary)); 1559 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipHeader_C", PetscViewerBinarySetSkipHeader_Binary)); 1560 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipOptions_C", PetscViewerBinaryGetSkipOptions_Binary)); 1561 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipOptions_C", PetscViewerBinarySetSkipOptions_Binary)); 1562 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetSkipInfo_C", PetscViewerBinaryGetSkipInfo_Binary)); 1563 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetSkipInfo_C", PetscViewerBinarySetSkipInfo_Binary)); 1564 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetInfoPointer_C", PetscViewerBinaryGetInfoPointer_Binary)); 1565 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileGetName_C", PetscViewerFileGetName_Binary)); 1566 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetName_C", PetscViewerFileSetName_Binary)); 1567 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_Binary)); 1568 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_Binary)); 1569 #if defined(PETSC_HAVE_MPIIO) 1570 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinaryGetUseMPIIO_C", PetscViewerBinaryGetUseMPIIO_Binary)); 1571 PetscCall(PetscObjectComposeFunction((PetscObject)v, "PetscViewerBinarySetUseMPIIO_C", PetscViewerBinarySetUseMPIIO_Binary)); 1572 #endif 1573 PetscFunctionReturn(PETSC_SUCCESS); 1574 } 1575 1576 /* 1577 The variable Petsc_Viewer_Binary_keyval is used to indicate an MPI attribute that 1578 is attached to a communicator, in this case the attribute is a PetscViewer. 1579 */ 1580 PetscMPIInt Petsc_Viewer_Binary_keyval = MPI_KEYVAL_INVALID; 1581 1582 /*@C 1583 PETSC_VIEWER_BINARY_ - Creates a `PETSCVIEWERBINARY` `PetscViewer` shared by all processors 1584 in a communicator. 1585 1586 Collective 1587 1588 Input Parameter: 1589 . comm - the MPI communicator to share the `PETSCVIEWERBINARY` 1590 1591 Level: intermediate 1592 1593 Options Database Keys: 1594 + -viewer_binary_filename <name> - filename in which to store the binary data, defaults to binaryoutput 1595 . -viewer_binary_skip_info - true means do not create .info file for this viewer 1596 . -viewer_binary_skip_options - true means do not use the options database for this viewer 1597 . -viewer_binary_skip_header - true means do not store the usual header information in the binary file 1598 - -viewer_binary_mpiio - true means use the file via MPI-IO, maybe faster for large files and many MPI ranks 1599 1600 Environmental variable: 1601 - PETSC_VIEWER_BINARY_FILENAME - filename in which to store the binary data, defaults to binaryoutput 1602 1603 Notes: 1604 This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it 1605 1606 Unlike almost all other PETSc routines, `PETSC_VIEWER_BINARY_` does not return 1607 an error code. The binary PetscViewer is usually used in the form 1608 $ XXXView(XXX object, PETSC_VIEWER_BINARY_(comm)); 1609 1610 .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PETSC_VIEWER_BINARY_WORLD`, `PETSC_VIEWER_BINARY_SELF`, `PetscViewerBinaryOpen()`, `PetscViewerCreate()`, 1611 `PetscViewerDestroy()` 1612 @*/ 1613 PetscViewer PETSC_VIEWER_BINARY_(MPI_Comm comm) 1614 { 1615 PetscErrorCode ierr; 1616 PetscMPIInt mpi_ierr; 1617 PetscBool flg; 1618 PetscViewer viewer; 1619 char fname[PETSC_MAX_PATH_LEN]; 1620 MPI_Comm ncomm; 1621 1622 PetscFunctionBegin; 1623 ierr = PetscCommDuplicate(comm, &ncomm, NULL); 1624 if (ierr) { 1625 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_BINARY_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 1626 PetscFunctionReturn(NULL); 1627 } 1628 if (Petsc_Viewer_Binary_keyval == MPI_KEYVAL_INVALID) { 1629 mpi_ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Binary_keyval, NULL); 1630 if (mpi_ierr) { 1631 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_BINARY_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 1632 PetscFunctionReturn(NULL); 1633 } 1634 } 1635 mpi_ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Binary_keyval, (void **)&viewer, (int *)&flg); 1636 if (mpi_ierr) { 1637 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_BINARY_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 1638 PetscFunctionReturn(NULL); 1639 } 1640 if (!flg) { /* PetscViewer not yet created */ 1641 ierr = PetscOptionsGetenv(ncomm, "PETSC_VIEWER_BINARY_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg); 1642 if (ierr) { 1643 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_BINARY_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 1644 PetscFunctionReturn(NULL); 1645 } 1646 if (!flg) { 1647 ierr = PetscStrncpy(fname, "binaryoutput", sizeof(fname)); 1648 if (ierr) { 1649 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_BINARY_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 1650 PetscFunctionReturn(NULL); 1651 } 1652 } 1653 ierr = PetscViewerBinaryOpen(ncomm, fname, FILE_MODE_WRITE, &viewer); 1654 ((PetscObject)viewer)->persistent = PETSC_TRUE; 1655 if (ierr) { 1656 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_BINARY_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 1657 PetscFunctionReturn(NULL); 1658 } 1659 ierr = PetscObjectRegisterDestroy((PetscObject)viewer); 1660 if (ierr) { 1661 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_BINARY_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 1662 PetscFunctionReturn(NULL); 1663 } 1664 mpi_ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Binary_keyval, (void *)viewer); 1665 if (mpi_ierr) { 1666 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_BINARY_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " "); 1667 PetscFunctionReturn(NULL); 1668 } 1669 } 1670 ierr = PetscCommDestroy(&ncomm); 1671 if (ierr) { 1672 ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_BINARY_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " "); 1673 PetscFunctionReturn(NULL); 1674 } 1675 PetscFunctionReturn(viewer); 1676 } 1677