Actual source code: binv.c

      1: #include <petsc/private/viewerimpl.h>

      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;

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

     50: #if defined(PETSC_HAVE_MPIIO)
     51: static PetscErrorCode PetscViewerBinarySyncMPIIO(PetscViewer viewer)
     52: {
     53:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

     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

     66: static PetscErrorCode PetscViewerGetSubViewer_Binary(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer)
     67: {
     68:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;
     69:   PetscMPIInt         rank;

     71:   PetscFunctionBegin;
     72:   PetscCall(PetscViewerSetUp(viewer));

     74:   /* Return subviewer in process zero */
     75:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
     76:   if (rank == 0) {
     77:     PetscMPIInt flg;

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

     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

    117: #if defined(PETSC_HAVE_MPIIO)
    118:   PetscCall(PetscViewerBinarySyncMPIIO(viewer));
    119: #endif
    120:   PetscFunctionReturn(PETSC_SUCCESS);
    121: }

    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

    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");

    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

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

    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

    160: #if defined(PETSC_HAVE_MPIIO)
    161:   PetscCall(PetscViewerBinarySyncMPIIO(viewer));
    162: #endif
    163:   PetscFunctionReturn(PETSC_SUCCESS);
    164: }

    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]()`

    170:   Not Collective; No Fortran Support

    172:   Input Parameter:
    173: . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`

    175:   Output Parameter:
    176: . off - the current global offset

    178:   Level: advanced

    180:   Note:
    181:   Use `PetscViewerBinaryAddMPIIOOffset()` to increase this value after you have written a view.

    183: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryAddMPIIOOffset()`
    184: @*/
    185: PetscErrorCode PetscViewerBinaryGetMPIIOOffset(PetscViewer viewer, MPI_Offset *off)
    186: {
    187:   PetscViewer_Binary *vbinary;

    189:   PetscFunctionBegin;
    191:   PetscAssertPointer(off, 2);
    192:   vbinary = (PetscViewer_Binary *)viewer->data;
    193:   *off    = vbinary->moff;
    194:   PetscFunctionReturn(PETSC_SUCCESS);
    195: }

    197: /*@C
    198:   PetscViewerBinaryAddMPIIOOffset - Adds to the current global offset

    200:   Logically Collective; No Fortran Support

    202:   Input Parameters:
    203: + viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`
    204: - off    - the addition to the global offset

    206:   Level: advanced

    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]()`

    211: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()`
    212: @*/
    213: PetscErrorCode PetscViewerBinaryAddMPIIOOffset(PetscViewer viewer, MPI_Offset off)
    214: {
    215:   PetscViewer_Binary *vbinary;

    217:   PetscFunctionBegin;
    220:   vbinary = (PetscViewer_Binary *)viewer->data;
    221:   vbinary->moff += off;
    222:   PetscFunctionReturn(PETSC_SUCCESS);
    223: }

    225: /*@C
    226:   PetscViewerBinaryGetMPIIODescriptor - Extracts the MPI IO file descriptor from a `PetscViewer`.

    228:   Not Collective; No Fortran Support

    230:   Input Parameter:
    231: . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`

    233:   Output Parameter:
    234: . fdes - file descriptor

    236:   Level: advanced

    238: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetUseMPIIO()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()`
    239: @*/
    240: PetscErrorCode PetscViewerBinaryGetMPIIODescriptor(PetscViewer viewer, MPI_File *fdes)
    241: {
    242:   PetscViewer_Binary *vbinary;

    244:   PetscFunctionBegin;
    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

    254: /*@
    255:   PetscViewerBinarySetUseMPIIO - Sets a binary viewer to use MPI-IO for reading/writing. Must be called
    256:   before `PetscViewerFileSetName()`

    258:   Logically Collective

    260:   Input Parameters:
    261: + viewer - the `PetscViewer`; must be a `PETSCVIEWERBINARY`
    262: - use    - `PETSC_TRUE` means MPI-IO will be used

    264:   Options Database Key:
    265: . -viewer_binary_mpiio (true|false) - flag for using MPI-IO

    267:   Level: advanced

    269: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`,
    270:           `PetscViewerBinaryGetUseMPIIO()`
    271: @*/
    272: PetscErrorCode PetscViewerBinarySetUseMPIIO(PetscViewer viewer, PetscBool use)
    273: {
    274:   PetscFunctionBegin;
    277:   PetscTryMethod(viewer, "PetscViewerBinarySetUseMPIIO_C", (PetscViewer, PetscBool), (viewer, use));
    278:   PetscFunctionReturn(PETSC_SUCCESS);
    279: }

    281: #if defined(PETSC_HAVE_MPIIO)
    282: static PetscErrorCode PetscViewerBinarySetUseMPIIO_Binary(PetscViewer viewer, PetscBool use)
    283: {
    284:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    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

    293: /*@
    294:   PetscViewerBinaryGetUseMPIIO - Returns `PETSC_TRUE` if the binary viewer uses MPI-IO.

    296:   Not Collective

    298:   Input Parameter:
    299: . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`; must be a `PETSCVIEWERBINARY`

    301:   Output Parameter:
    302: . use - `PETSC_TRUE` if MPI-IO is being used

    304:   Level: advanced

    306:   Note:
    307:   If MPI-IO is not available, this function will always return `PETSC_FALSE`

    309: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinarySetUseMPIIO()`, `PetscViewerBinaryGetMPIIOOffset()`
    310: @*/
    311: PetscErrorCode PetscViewerBinaryGetUseMPIIO(PetscViewer viewer, PetscBool *use)
    312: {
    313:   PetscFunctionBegin;
    315:   PetscAssertPointer(use, 2);
    316:   *use = PETSC_FALSE;
    317:   PetscTryMethod(viewer, "PetscViewerBinaryGetUseMPIIO_C", (PetscViewer, PetscBool *), (viewer, use));
    318:   PetscFunctionReturn(PETSC_SUCCESS);
    319: }

    321: #if defined(PETSC_HAVE_MPIIO)
    322: static PetscErrorCode PetscViewerBinaryGetUseMPIIO_Binary(PetscViewer viewer, PetscBool *use)
    323: {
    324:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    326:   PetscFunctionBegin;
    327:   *use = vbinary->usempiio;
    328:   PetscFunctionReturn(PETSC_SUCCESS);
    329: }
    330: #endif

    332: /*@
    333:   PetscViewerBinarySetFlowControl - Sets how many messages are allowed to be outstanding at the same time during parallel IO reads/writes

    335:   Not Collective

    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

    341:   Level: advanced

    343: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinaryGetFlowControl()`
    344: @*/
    345: PetscErrorCode PetscViewerBinarySetFlowControl(PetscViewer viewer, PetscInt fc)
    346: {
    347:   PetscFunctionBegin;
    350:   PetscTryMethod(viewer, "PetscViewerBinarySetFlowControl_C", (PetscViewer, PetscInt), (viewer, fc));
    351:   PetscFunctionReturn(PETSC_SUCCESS);
    352: }

    354: static PetscErrorCode PetscViewerBinarySetFlowControl_Binary(PetscViewer viewer, PetscInt fc)
    355: {
    356:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

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

    364: /*@
    365:   PetscViewerBinaryGetFlowControl - Returns how many messages are allowed to be outstanding at the same time during parallel IO reads/writes

    367:   Not Collective

    369:   Input Parameter:
    370: . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`

    372:   Output Parameter:
    373: . fc - the number of messages

    375:   Level: advanced

    377: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`, `PetscViewerBinarySetFlowControl()`
    378: @*/
    379: PetscErrorCode PetscViewerBinaryGetFlowControl(PetscViewer viewer, PetscInt *fc)
    380: {
    381:   PetscFunctionBegin;
    383:   PetscAssertPointer(fc, 2);
    384:   PetscUseMethod(viewer, "PetscViewerBinaryGetFlowControl_C", (PetscViewer, PetscInt *), (viewer, fc));
    385:   PetscFunctionReturn(PETSC_SUCCESS);
    386: }

    388: PETSC_INTERN PetscErrorCode PetscViewerBinaryGetFlowControl_Binary(PetscViewer viewer, PetscInt *fc)
    389: {
    390:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    392:   PetscFunctionBegin;
    393:   *fc = vbinary->flowcontrol;
    394:   PetscFunctionReturn(PETSC_SUCCESS);
    395: }

    397: /*@C
    398:   PetscViewerBinaryGetDescriptor - Extracts the file descriptor from a `PetscViewer` of `PetscViewerType` `PETSCVIEWERBINARY`.

    400:   Collective because it may trigger a `PetscViewerSetUp()` call; No Fortran Support

    402:   Input Parameter:
    403: . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`

    405:   Output Parameter:
    406: . fdes - file descriptor

    408:   Level: advanced

    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.

    416: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetInfoPointer()`
    417: @*/
    418: PetscErrorCode PetscViewerBinaryGetDescriptor(PetscViewer viewer, int *fdes)
    419: {
    420:   PetscViewer_Binary *vbinary;

    422:   PetscFunctionBegin;
    424:   PetscAssertPointer(fdes, 2);
    425:   PetscCall(PetscViewerSetUp(viewer));
    426:   vbinary = (PetscViewer_Binary *)viewer->data;
    427:   *fdes   = vbinary->fdes;
    428:   PetscFunctionReturn(PETSC_SUCCESS);
    429: }

    431: /*@
    432:   PetscViewerBinarySkipInfo - Binary file will not have `.info` file created with it

    434:   Not Collective

    436:   Input Parameter:
    437: . viewer - `PetscViewer` context, obtained from `PetscViewerCreate()`

    439:   Options Database Key:
    440: . -viewer_binary_skip_info - true indicates do not generate `.info` file

    442:   Level: advanced

    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()`.

    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.

    452:   This routine is deprecated, use `PetscViewerBinarySetSkipInfo()`

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

    464: /*@
    465:   PetscViewerBinarySetSkipInfo - Binary file will not have `.info` file created with it

    467:   Not Collective

    469:   Input Parameters:
    470: + viewer - PetscViewer context, obtained from `PetscViewerCreate()`
    471: - skip   - `PETSC_TRUE` implies the `.info` file will not be generated

    473:   Options Database Key:
    474: . -viewer_binary_skip_info - true indicates do not generate `.info` file

    476:   Level: advanced

    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()`.

    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.

    486: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySetSkipOptions()`,
    487:           `PetscViewerBinaryGetSkipOptions()`, `PetscViewerBinaryGetSkipInfo()`, `PetscViewerBinaryGetInfoPointer()`
    488: @*/
    489: PetscErrorCode PetscViewerBinarySetSkipInfo(PetscViewer viewer, PetscBool skip)
    490: {
    491:   PetscFunctionBegin;
    494:   PetscTryMethod(viewer, "PetscViewerBinarySetSkipInfo_C", (PetscViewer, PetscBool), (viewer, skip));
    495:   PetscFunctionReturn(PETSC_SUCCESS);
    496: }

    498: static PetscErrorCode PetscViewerBinarySetSkipInfo_Binary(PetscViewer viewer, PetscBool skip)
    499: {
    500:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    502:   PetscFunctionBegin;
    503:   vbinary->skipinfo = skip;
    504:   PetscFunctionReturn(PETSC_SUCCESS);
    505: }

    507: /*@
    508:   PetscViewerBinaryGetSkipInfo - check if viewer wrote a `.info` file

    510:   Not Collective

    512:   Input Parameter:
    513: . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`

    515:   Output Parameter:
    516: . skip - `PETSC_TRUE` implies the `.info` file was not generated

    518:   Level: advanced

    520:   Note:
    521:   This must be called after `PetscViewerSetType()`

    523: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`,
    524:           `PetscViewerBinarySetSkipOptions()`, `PetscViewerBinarySetSkipInfo()`, `PetscViewerBinaryGetInfoPointer()`
    525: @*/
    526: PetscErrorCode PetscViewerBinaryGetSkipInfo(PetscViewer viewer, PetscBool *skip)
    527: {
    528:   PetscFunctionBegin;
    530:   PetscAssertPointer(skip, 2);
    531:   PetscUseMethod(viewer, "PetscViewerBinaryGetSkipInfo_C", (PetscViewer, PetscBool *), (viewer, skip));
    532:   PetscFunctionReturn(PETSC_SUCCESS);
    533: }

    535: static PetscErrorCode PetscViewerBinaryGetSkipInfo_Binary(PetscViewer viewer, PetscBool *skip)
    536: {
    537:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    539:   PetscFunctionBegin;
    540:   *skip = vbinary->skipinfo;
    541:   PetscFunctionReturn(PETSC_SUCCESS);
    542: }

    544: /*@
    545:   PetscViewerBinarySetSkipOptions - do not use values in the PETSc options database when loading objects

    547:   Not Collective

    549:   Input Parameters:
    550: + viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`
    551: - skip   - `PETSC_TRUE` means do not use the options from the options database

    553:   Options Database Key:
    554: . -viewer_binary_skip_options (true|false) - true means do not use the options from the options database

    556:   Level: advanced

    558:   Note:
    559:   This must be called after `PetscViewerSetType()`

    561: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`,
    562:           `PetscViewerBinaryGetSkipOptions()`
    563: @*/
    564: PetscErrorCode PetscViewerBinarySetSkipOptions(PetscViewer viewer, PetscBool skip)
    565: {
    566:   PetscFunctionBegin;
    569:   PetscTryMethod(viewer, "PetscViewerBinarySetSkipOptions_C", (PetscViewer, PetscBool), (viewer, skip));
    570:   PetscFunctionReturn(PETSC_SUCCESS);
    571: }

    573: static PetscErrorCode PetscViewerBinarySetSkipOptions_Binary(PetscViewer viewer, PetscBool skip)
    574: {
    575:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    577:   PetscFunctionBegin;
    578:   vbinary->skipoptions = skip;
    579:   PetscFunctionReturn(PETSC_SUCCESS);
    580: }

    582: /*@
    583:   PetscViewerBinaryGetSkipOptions - checks if viewer uses the PETSc options database when loading objects

    585:   Not Collective

    587:   Input Parameter:
    588: . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`

    590:   Output Parameter:
    591: . skip - `PETSC_TRUE` means do not use

    593:   Level: advanced

    595:   Note:
    596:   This must be called after `PetscViewerSetType()`

    598: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`,
    599:           `PetscViewerBinarySetSkipOptions()`
    600: @*/
    601: PetscErrorCode PetscViewerBinaryGetSkipOptions(PetscViewer viewer, PetscBool *skip)
    602: {
    603:   PetscFunctionBegin;
    605:   PetscAssertPointer(skip, 2);
    606:   PetscUseMethod(viewer, "PetscViewerBinaryGetSkipOptions_C", (PetscViewer, PetscBool *), (viewer, skip));
    607:   PetscFunctionReturn(PETSC_SUCCESS);
    608: }

    610: static PetscErrorCode PetscViewerBinaryGetSkipOptions_Binary(PetscViewer viewer, PetscBool *skip)
    611: {
    612:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    614:   PetscFunctionBegin;
    615:   *skip = vbinary->skipoptions;
    616:   PetscFunctionReturn(PETSC_SUCCESS);
    617: }

    619: /*@
    620:   PetscViewerBinarySetSkipHeader - do not write a header with size information on output, just raw data

    622:   Not Collective

    624:   Input Parameters:
    625: + viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`
    626: - skip   - `PETSC_TRUE` means do not write header

    628:   Options Database Key:
    629: . -viewer_binary_skip_header (true|false) - true means do not write header

    631:   Level: advanced

    633:   Notes:
    634:   This must be called after `PetscViewerSetType()`

    636:   If this option is selected, the output file cannot be read with the `XXXLoad()` such as `VecLoad()`

    638: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`,
    639:           `PetscViewerBinaryGetSkipHeader()`
    640: @*/
    641: PetscErrorCode PetscViewerBinarySetSkipHeader(PetscViewer viewer, PetscBool skip)
    642: {
    643:   PetscFunctionBegin;
    646:   PetscTryMethod(viewer, "PetscViewerBinarySetSkipHeader_C", (PetscViewer, PetscBool), (viewer, skip));
    647:   PetscFunctionReturn(PETSC_SUCCESS);
    648: }

    650: static PetscErrorCode PetscViewerBinarySetSkipHeader_Binary(PetscViewer viewer, PetscBool skip)
    651: {
    652:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    654:   PetscFunctionBegin;
    655:   vbinary->skipheader = skip;
    656:   PetscFunctionReturn(PETSC_SUCCESS);
    657: }

    659: /*@
    660:   PetscViewerBinaryGetSkipHeader - checks whether to write a header with size information on output, or just raw data

    662:   Not Collective

    664:   Input Parameter:
    665: . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`

    667:   Output Parameter:
    668: . skip - `PETSC_TRUE` means do not write header

    670:   Level: advanced

    672:   Notes:
    673:   This must be called after PetscViewerSetType()

    675:   Returns `PETSC_FALSE` for `PETSCSOCKETVIEWER`, you cannot skip the header for it.

    677: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinarySkipInfo()`,
    678:           `PetscViewerBinarySetSkipHeader()`
    679: @*/
    680: PetscErrorCode PetscViewerBinaryGetSkipHeader(PetscViewer viewer, PetscBool *skip)
    681: {
    682:   PetscFunctionBegin;
    684:   PetscAssertPointer(skip, 2);
    685:   PetscUseMethod(viewer, "PetscViewerBinaryGetSkipHeader_C", (PetscViewer, PetscBool *), (viewer, skip));
    686:   PetscFunctionReturn(PETSC_SUCCESS);
    687: }

    689: static PetscErrorCode PetscViewerBinaryGetSkipHeader_Binary(PetscViewer viewer, PetscBool *skip)
    690: {
    691:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    693:   PetscFunctionBegin;
    694:   *skip = vbinary->skipheader;
    695:   PetscFunctionReturn(PETSC_SUCCESS);
    696: }

    698: /*@C
    699:   PetscViewerBinaryGetInfoPointer - Extracts the file pointer for the ASCII
    700:   `.info` file associated with a binary file.

    702:   Not Collective; No Fortran Support

    704:   Input Parameter:
    705: . viewer - `PetscViewer` context, obtained from `PetscViewerBinaryOpen()`

    707:   Output Parameter:
    708: . file - file pointer  Always returns `NULL` if not a binary viewer

    710:   Level: advanced

    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`.

    716: .seealso: [](sec_viewers), `PETSCVIEWERBINARY`, `PetscViewerBinaryOpen()`, `PetscViewerBinaryGetDescriptor()`, `PetscViewerBinaryGetSkipInfo()`,
    717:           `PetscViewerBinarySetSkipInfo()`
    718: @*/
    719: PetscErrorCode PetscViewerBinaryGetInfoPointer(PetscViewer viewer, FILE **file)
    720: {
    721:   PetscFunctionBegin;
    723:   PetscAssertPointer(file, 2);
    724:   *file = NULL;
    725:   PetscTryMethod(viewer, "PetscViewerBinaryGetInfoPointer_C", (PetscViewer, FILE **), (viewer, file));
    726:   PetscFunctionReturn(PETSC_SUCCESS);
    727: }

    729: static PetscErrorCode PetscViewerBinaryGetInfoPointer_Binary(PetscViewer viewer, FILE **file)
    730: {
    731:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

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

    749: #if defined(PETSC_HAVE_MPIIO)
    750: static PetscErrorCode PetscViewerFileClose_BinaryMPIIO(PetscViewer v)
    751: {
    752:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)v->data;

    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

    762: static PetscErrorCode PetscViewerFileClose_BinarySTDIO(PetscViewer v)
    763: {
    764:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)v->data;

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

    790: static PetscErrorCode PetscViewerFileClose_BinaryInfo(PetscViewer v)
    791: {
    792:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)v->data;

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

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

    822: static PetscErrorCode PetscViewerDestroy_Binary(PetscViewer v)
    823: {
    824:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)v->data;

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

    834: /*@
    835:   PetscViewerBinaryOpen - Opens a file for binary input/output.

    837:   Collective

    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

    849:   Output Parameter:
    850: . viewer - PetscViewer for binary input/output to use with the specified file

    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)

    859:   Level: beginner

    861:   Note:
    862:   This `PetscViewer` should be destroyed with `PetscViewerDestroy()`.

    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.

    867:   For creating files, if the file name ends with .gz it is automatically
    868:   compressed when closed.

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

    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;

    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

    918: /*@C
    919:   PetscViewerBinaryRead - Reads from a binary file, all processors get the same result

    921:   Collective; No Fortran Support

    923:   Input Parameters:
    924: + viewer - the `PETSCVIEWERBINARY` viewer
    925: . num    - number of items of data to read
    926: - dtype  - type of data to read

    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`.

    932:   Level: beginner

    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;

    942:   PetscFunctionBegin;
    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: }

    959: /*@C
    960:   PetscViewerBinaryWrite - writes to a binary file, only from the first MPI rank

    962:   Collective; No Fortran Support

    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

    970:   Level: beginner

    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;

    980:   PetscFunctionBegin;
    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: }

    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;

    1006:   PetscFunctionBegin;
    1011:   PetscCall(PetscViewerSetUp(viewer));

    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));

    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;

    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;

    1055:     PetscCall(PetscCommGetNewTag(comm, &tag));
    1056:     PetscCallMPI(MPI_Reduce(&tcount, &maxcount, 1, MPIU_COUNT, MPI_MAX, 0, comm));
    1057:     PetscCall(PetscMPIIntCast(maxcount, &maxcnt));

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

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

    1099: /*@C
    1100:   PetscViewerBinaryReadAll - reads from a binary file from all MPI processes, each rank receives its own portion of the data

    1102:   Collective; No Fortran Support

    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

    1111:   Output Parameter:
    1112: . data - location of data, treated as an array of type indicated by `dtype`

    1114:   Level: advanced

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

    1125: /*@C
    1126:   PetscViewerBinaryWriteAll - writes to a binary file from all MPI processes, each rank writes its own portion of the data

    1128:   Collective; No Fortran Support

    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

    1138:   Level: advanced

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

    1149: /*@C
    1150:   PetscViewerBinaryWriteStringArray - writes to a binary file, only from the first MPI rank, an array of strings

    1152:   Collective; No Fortran Support

    1154:   Input Parameters:
    1155: + viewer - the `PETSCVIEWERBINARY` viewer
    1156: - data   - location of the array of strings

    1158:   Level: intermediate

    1160:   Note:
    1161:   The array of strings must be `NULL` terminated

    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;

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

    1189: /*@C
    1190:   PetscViewerBinaryReadStringArray - reads a binary file an array of strings to all MPI processes

    1192:   Collective; No Fortran Support

    1194:   Input Parameter:
    1195: . viewer - the `PETSCVIEWERBINARY` viewer

    1197:   Output Parameter:
    1198: . data - location of the array of strings

    1200:   Level: intermediate

    1202:   Note:
    1203:   The array of strings must `NULL` terminated

    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;

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

    1229: /*@
    1230:   PetscViewerFileSetMode - Sets the open mode of file

    1232:   Logically Collective

    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

    1243:   Level: advanced

    1245: .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`
    1246: @*/
    1247: PetscErrorCode PetscViewerFileSetMode(PetscViewer viewer, PetscFileMode mode)
    1248: {
    1249:   PetscFunctionBegin;
    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: }

    1258: static PetscErrorCode PetscViewerFileSetMode_Binary(PetscViewer viewer, PetscFileMode mode)
    1259: {
    1260:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

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

    1268: /*@
    1269:   PetscViewerFileGetMode - Gets the open mode of a file associated with a `PetscViewer`

    1271:   Not Collective

    1273:   Input Parameter:
    1274: . viewer - the `PetscViewer`; must be a `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`, `PETSCVIEWERHDF5`, or `PETSCVIEWERASCII`  `PetscViewer`

    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

    1284:   Level: advanced

    1286: .seealso: [](sec_viewers), `PetscViewerFileSetMode()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerBinaryOpen()`
    1287: @*/
    1288: PetscErrorCode PetscViewerFileGetMode(PetscViewer viewer, PetscFileMode *mode)
    1289: {
    1290:   PetscFunctionBegin;
    1292:   PetscAssertPointer(mode, 2);
    1293:   PetscUseMethod(viewer, "PetscViewerFileGetMode_C", (PetscViewer, PetscFileMode *), (viewer, mode));
    1294:   PetscFunctionReturn(PETSC_SUCCESS);
    1295: }

    1297: static PetscErrorCode PetscViewerFileGetMode_Binary(PetscViewer viewer, PetscFileMode *mode)
    1298: {
    1299:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    1301:   PetscFunctionBegin;
    1302:   *mode = vbinary->filemode;
    1303:   PetscFunctionReturn(PETSC_SUCCESS);
    1304: }

    1306: static PetscErrorCode PetscViewerFileSetName_Binary(PetscViewer viewer, const char name[])
    1307: {
    1308:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

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

    1322: static PetscErrorCode PetscViewerFileGetName_Binary(PetscViewer viewer, const char **name)
    1323: {
    1324:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;

    1326:   PetscFunctionBegin;
    1327:   *name = vbinary->filename;
    1328:   PetscFunctionReturn(PETSC_SUCCESS);
    1329: }

    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;

    1337:   PetscFunctionBegin;
    1338:   vbinary->storecompressed = PETSC_FALSE;

    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

    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;

    1380:   PetscFunctionBegin;
    1381:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));

    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

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

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

    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;

    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;

    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;

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

    1448: static PetscErrorCode PetscViewerSetUp_Binary(PetscViewer viewer)
    1449: {
    1450:   PetscViewer_Binary *vbinary = (PetscViewer_Binary *)viewer->data;
    1451:   PetscBool           usempiio;

    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));

    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));

    1469:   PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", vbinary->filename));
    1470:   PetscFunctionReturn(PETSC_SUCCESS);
    1471: }

    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;

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

    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;

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

    1512: /*MC
    1513:    PETSCVIEWERBINARY - A viewer that saves to binary files

    1515:   Level: beginner

    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*/

    1523: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Binary(PetscViewer v)
    1524: {
    1525:   PetscViewer_Binary *vbinary;

    1527:   PetscFunctionBegin;
    1528:   PetscCall(PetscNew(&vbinary));
    1529:   v->data = (void *)vbinary;

    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;

    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 */

    1556:   vbinary->setfromoptionscalled = PETSC_FALSE;

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

    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;

    1584: /*@C
    1585:    PETSC_VIEWER_BINARY_ - Creates a `PETSCVIEWERBINARY` `PetscViewer` shared by all processes in a communicator.

    1587:    Collective

    1589:    Input Parameter:
    1590: .  comm - the MPI communicator to share the `PETSCVIEWERBINARY`

    1592:    Level: intermediate

    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

    1601:    Environmental variable:
    1602: -   PETSC_VIEWER_BINARY_FILENAME - filename in which to store the binary data, defaults to binaryoutput

    1604:    Notes:
    1605:   This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it

    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

    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:   PetscMPIInt iflg;
    1620:   PetscViewer viewer;
    1621:   char        fname[PETSC_MAX_PATH_LEN];
    1622:   MPI_Comm    ncomm;

    1624:   PetscFunctionBegin;
    1625:   PetscCallNull(PetscCommDuplicate(comm, &ncomm, NULL));
    1626:   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));
    1627:   PetscCallMPINull(MPI_Comm_get_attr(ncomm, Petsc_Viewer_Binary_keyval, (void **)&viewer, &iflg));
    1628:   if (!iflg) { /* PetscViewer not yet created */
    1629:     PetscCallNull(PetscOptionsGetenv(ncomm, "PETSC_VIEWER_BINARY_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg));
    1630:     if (!flg) PetscCallNull(PetscStrncpy(fname, "binaryoutput", sizeof(fname)));
    1631:     PetscCallNull(PetscViewerBinaryOpen(ncomm, fname, FILE_MODE_WRITE, &viewer));
    1632:     PetscCallNull(PetscObjectRegisterDestroy((PetscObject)viewer));
    1633:     PetscCallMPINull(MPI_Comm_set_attr(ncomm, Petsc_Viewer_Binary_keyval, (void *)viewer));
    1634:   }
    1635:   PetscCallNull(PetscCommDestroy(&ncomm));
    1636:   PetscFunctionReturn(viewer);
    1637: }