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