Actual source code: view.c

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

      4: PetscClassId PETSC_VIEWER_CLASSID;

      6: static PetscBool PetscViewerPackageInitialized = PETSC_FALSE;

      8: /*@C
      9:   PetscViewerFinalizePackage - This function destroys any global objects created in PETSc viewers. It is
     10:   called from `PetscFinalize()`.

     12:   Level: developer

     14: .seealso: [](sec_viewers), `PetscViewer`, `PetscFinalize()`, `PetscViewerInitializePackage()`
     15: @*/
     16: PetscErrorCode PetscViewerFinalizePackage(void)
     17: {
     18:   PetscFunctionBegin;
     19:   if (Petsc_Viewer_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_keyval));
     20:   if (Petsc_Viewer_Stdout_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Stdout_keyval));
     21:   if (Petsc_Viewer_Stderr_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Stderr_keyval));
     22:   if (Petsc_Viewer_Binary_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Binary_keyval));
     23:   if (Petsc_Viewer_Draw_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Draw_keyval));
     24: #if defined(PETSC_HAVE_HDF5)
     25:   if (Petsc_Viewer_HDF5_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_HDF5_keyval));
     26: #endif
     27: #if defined(PETSC_USE_SOCKETVIEWER)
     28:   if (Petsc_Viewer_Socket_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Socket_keyval));
     29: #endif
     30:   PetscCall(PetscFunctionListDestroy(&PetscViewerList));
     31:   PetscViewerPackageInitialized = PETSC_FALSE;
     32:   PetscViewerRegisterAllCalled  = PETSC_FALSE;
     33:   PetscFunctionReturn(PETSC_SUCCESS);
     34: }

     36: /*@C
     37:   PetscViewerInitializePackage - This function initializes everything in the `PetscViewer` package.

     39:   Level: developer

     41: .seealso: [](sec_viewers), `PetscViewer`, `PetscInitialize()`, `PetscViewerFinalizePackage()`
     42: @*/
     43: PetscErrorCode PetscViewerInitializePackage(void)
     44: {
     45:   char      logList[256];
     46:   PetscBool opt, pkg;

     48:   PetscFunctionBegin;
     49:   if (PetscViewerPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
     50:   PetscViewerPackageInitialized = PETSC_TRUE;
     51:   /* Register Classes */
     52:   PetscCall(PetscClassIdRegister("Viewer", &PETSC_VIEWER_CLASSID));
     53:   /* Register Constructors */
     54:   PetscCall(PetscViewerRegisterAll());
     55:   /* Process Info */
     56:   {
     57:     PetscClassId classids[1];

     59:     classids[0] = PETSC_VIEWER_CLASSID;
     60:     PetscCall(PetscInfoProcessClass("viewer", 1, classids));
     61:   }
     62:   /* Process summary exclusions */
     63:   PetscCall(PetscOptionsGetString(NULL, NULL, "-log_exclude", logList, sizeof(logList), &opt));
     64:   if (opt) {
     65:     PetscCall(PetscStrInList("viewer", logList, ',', &pkg));
     66:     if (pkg) PetscCall(PetscLogEventExcludeClass(PETSC_VIEWER_CLASSID));
     67:   }
     68: #if defined(PETSC_HAVE_MATHEMATICA)
     69:   PetscCall(PetscViewerMathematicaInitializePackage());
     70: #endif
     71:   /* Register package finalizer */
     72:   PetscCall(PetscRegisterFinalize(PetscViewerFinalizePackage));
     73:   PetscFunctionReturn(PETSC_SUCCESS);
     74: }

     76: /*@
     77:   PetscViewerDestroy - Destroys a `PetscViewer`.

     79:   Collective

     81:   Input Parameter:
     82: . viewer - the `PetscViewer` to be destroyed.

     84:   Level: beginner

     86: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerCreate()`, `PetscViewerSocketOpen()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`
     87: @*/
     88: PetscErrorCode PetscViewerDestroy(PetscViewer *viewer)
     89: {
     90:   PetscFunctionBegin;
     91:   if (!*viewer) PetscFunctionReturn(PETSC_SUCCESS);

     94:   PetscCall(PetscViewerFlush(*viewer));
     95:   if (--((PetscObject)*viewer)->refct > 0) {
     96:     *viewer = NULL;
     97:     PetscFunctionReturn(PETSC_SUCCESS);
     98:   }

    100:   PetscCall(PetscObjectSAWsViewOff((PetscObject)*viewer));
    101:   PetscTryTypeMethod(*viewer, destroy);
    102:   PetscCall(PetscHeaderDestroy(viewer));
    103:   PetscFunctionReturn(PETSC_SUCCESS);
    104: }

    106: /*@C
    107:   PetscViewerAndFormatCreate - Creates a `PetscViewerAndFormat` struct.

    109:   Collective

    111:   Input Parameters:
    112: + viewer - the viewer
    113: - format - the format

    115:   Output Parameter:
    116: . vf - viewer and format object

    118:   Level: developer

    120:   Notes:
    121:   This increases the reference count of the viewer.

    123:   Use `PetscViewerAndFormatDestroy()` to free the struct

    125:   This is used as the context variable for many of the `TS`, `SNES`, and `KSP` monitor functions

    127:   This construct exists because it allows one to keep track of the use of a `PetscViewerFormat` without requiring the
    128:   format in the viewer to be permanently changed.

    130: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerAndFormat`, `PetscViewerFormat`, `PetscViewerSocketOpen()`, `PetscViewerASCIIOpen()`, `PetscViewerCreate()`,
    131:           `PetscViewerDrawOpen()`, `PetscViewerAndFormatDestroy()`
    132: @*/
    133: PetscErrorCode PetscViewerAndFormatCreate(PetscViewer viewer, PetscViewerFormat format, PetscViewerAndFormat **vf)
    134: {
    135:   PetscFunctionBegin;
    136:   PetscCall(PetscObjectReference((PetscObject)viewer));
    137:   PetscCall(PetscNew(vf));
    138:   (*vf)->viewer = viewer;
    139:   (*vf)->format = format;
    140:   (*vf)->data   = NULL;
    141:   PetscFunctionReturn(PETSC_SUCCESS);
    142: }

    144: /*@C
    145:   PetscViewerAndFormatDestroy - Destroys a `PetscViewerAndFormat` struct created with `PetscViewerAndFormatCreate()`

    147:   Collective

    149:   Input Parameter:
    150: . vf - the `PetscViewerAndFormat` to be destroyed.

    152:   Level: developer

    154: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerAndFormat`, `PetscViewerFormat`, `PetscViewerAndFormatCreate()`, `PetscViewerSocketOpen()`,
    155:           `PetscViewerASCIIOpen()`, `PetscViewerCreate()`, `PetscViewerDrawOpen()`
    156: @*/
    157: PetscErrorCode PetscViewerAndFormatDestroy(PetscViewerAndFormat **vf)
    158: {
    159:   PetscFunctionBegin;
    160:   PetscCall(PetscViewerDestroy(&(*vf)->viewer));
    161:   if ((*vf)->data_destroy) PetscCall((*vf)->data_destroy(&(*vf)->data));
    162:   PetscCall(PetscFree(*vf));
    163:   PetscFunctionReturn(PETSC_SUCCESS);
    164: }

    166: /*@
    167:   PetscViewerGetType - Returns the type of a `PetscViewer`.

    169:   Not Collective

    171:   Input Parameter:
    172: . viewer - the `PetscViewer`

    174:   Output Parameter:
    175: . type - `PetscViewerType`

    177:   Level: intermediate

    179:   Note:
    180:   `PetscViewerType` is actually a string

    182: .seealso: [](sec_viewers), `PetscViewerType`, `PetscViewer`, `PetscViewerCreate()`, `PetscViewerSetType()`
    183: @*/
    184: PetscErrorCode PetscViewerGetType(PetscViewer viewer, PetscViewerType *type)
    185: {
    186:   PetscFunctionBegin;
    188:   PetscAssertPointer(type, 2);
    189:   *type = ((PetscObject)viewer)->type_name;
    190:   PetscFunctionReturn(PETSC_SUCCESS);
    191: }

    193: /*@
    194:   PetscViewerSetOptionsPrefix - Sets the prefix used for searching for
    195:   `PetscViewer` options in the database during `PetscViewerSetFromOptions()`.

    197:   Logically Collective

    199:   Input Parameters:
    200: + viewer - the `PetscViewer` context
    201: - prefix - the prefix to prepend to all option names

    203:   Note:
    204:   A hyphen (-) must NOT be given at the beginning of the prefix name.
    205:   The first character of all runtime options is AUTOMATICALLY the hyphen.

    207:   Level: advanced

    209: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerSetFromOptions()`, `PetscViewerAppendOptionsPrefix()`
    210: @*/
    211: PetscErrorCode PetscViewerSetOptionsPrefix(PetscViewer viewer, const char prefix[])
    212: {
    213:   PetscFunctionBegin;
    215:   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)viewer, prefix));
    216:   PetscFunctionReturn(PETSC_SUCCESS);
    217: }

    219: /*@
    220:   PetscViewerAppendOptionsPrefix - Appends to the prefix used for searching for
    221:   `PetscViewer` options in the database during `PetscViewerSetFromOptions()`.

    223:   Logically Collective

    225:   Input Parameters:
    226: + viewer - the `PetscViewer` context
    227: - prefix - the prefix to prepend to all option names

    229:   Level: advanced

    231:   Note:
    232:   A hyphen (-) must NOT be given at the beginning of the prefix name.
    233:   The first character of all runtime options is AUTOMATICALLY the hyphen.

    235: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerGetOptionsPrefix()`, `PetscViewerSetOptionsPrefix()`
    236: @*/
    237: PetscErrorCode PetscViewerAppendOptionsPrefix(PetscViewer viewer, const char prefix[])
    238: {
    239:   PetscFunctionBegin;
    241:   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)viewer, prefix));
    242:   PetscFunctionReturn(PETSC_SUCCESS);
    243: }

    245: /*@
    246:   PetscViewerGetOptionsPrefix - Gets the prefix used for searching for
    247:   `PetscViewer` options in the database during `PetscViewerSetFromOptions()`.

    249:   Not Collective

    251:   Input Parameter:
    252: . viewer - the `PetscViewer` context

    254:   Output Parameter:
    255: . prefix - pointer to the prefix string used

    257:   Level: advanced

    259: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerAppendOptionsPrefix()`, `PetscViewerSetOptionsPrefix()`
    260: @*/
    261: PetscErrorCode PetscViewerGetOptionsPrefix(PetscViewer viewer, const char *prefix[])
    262: {
    263:   PetscFunctionBegin;
    265:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)viewer, prefix));
    266:   PetscFunctionReturn(PETSC_SUCCESS);
    267: }

    269: /*@
    270:   PetscViewerSetUp - Sets up the internal viewer data structures for the later use.

    272:   Collective

    274:   Input Parameter:
    275: . viewer - the `PetscViewer` context

    277:   Level: advanced

    279:   Note:
    280:   For basic use of the `PetscViewer` classes the user need not explicitly call
    281:   `PetscViewerSetUp()`, since these actions will happen automatically.

    283: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerCreate()`, `PetscViewerDestroy()`
    284: @*/
    285: PetscErrorCode PetscViewerSetUp(PetscViewer viewer)
    286: {
    287:   PetscFunctionBegin;
    289:   if (viewer->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
    290:   PetscTryTypeMethod(viewer, setup);
    291:   viewer->setupcalled = PETSC_TRUE;
    292:   PetscFunctionReturn(PETSC_SUCCESS);
    293: }

    295: /*@
    296:   PetscViewerViewFromOptions - View from the viewer based on options in the options database

    298:   Collective

    300:   Input Parameters:
    301: + A    - the `PetscViewer` context
    302: . obj  - Optional object that provides the prefix for the option names
    303: - name - command line option

    305:   Level: intermediate

    307:   Note:
    308:   See `PetscObjectViewFromOptions()` for details on the viewers and formats support via this interface

    310: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerView`, `PetscObjectViewFromOptions()`, `PetscViewerCreate()`
    311: @*/
    312: PetscErrorCode PetscViewerViewFromOptions(PetscViewer A, PetscObject obj, const char name[])
    313: {
    314:   PetscFunctionBegin;
    316:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
    317:   PetscFunctionReturn(PETSC_SUCCESS);
    318: }

    320: /*@
    321:   PetscViewerView - Visualizes a viewer object.

    323:   Collective

    325:   Input Parameters:
    326: + v      - the viewer to be viewed
    327: - viewer - visualization context

    329:   Level: beginner

    331: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`,
    332:           `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerLoad()`
    333: @*/
    334: PetscErrorCode PetscViewerView(PetscViewer v, PetscViewer viewer)
    335: {
    336:   PetscBool         isascii;
    337:   PetscViewerFormat format;
    338: #if defined(PETSC_HAVE_SAWS)
    339:   PetscBool issaws;
    340: #endif

    342:   PetscFunctionBegin;
    345:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)v), &viewer));
    347:   PetscCheckSameComm(v, 1, viewer, 2);

    349:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    350: #if defined(PETSC_HAVE_SAWS)
    351:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
    352: #endif
    353:   if (isascii) {
    354:     PetscCall(PetscViewerGetFormat(viewer, &format));
    355:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)v, viewer));
    356:     if (format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
    357:       if (v->format) PetscCall(PetscViewerASCIIPrintf(viewer, "  Viewer format = %s\n", PetscViewerFormats[v->format]));
    358:       PetscCall(PetscViewerASCIIPushTab(viewer));
    359:       PetscTryTypeMethod(v, view, viewer);
    360:       PetscCall(PetscViewerASCIIPopTab(viewer));
    361:     }
    362: #if defined(PETSC_HAVE_SAWS)
    363:   } else if (issaws) {
    364:     if (!((PetscObject)v)->amsmem) {
    365:       PetscCall(PetscObjectViewSAWs((PetscObject)v, viewer));
    366:       PetscTryTypeMethod(v, view, viewer);
    367:     }
    368: #endif
    369:   }
    370:   PetscFunctionReturn(PETSC_SUCCESS);
    371: }

    373: /*@C
    374:   PetscViewerRead - Reads data from a `PetscViewer`

    376:   Collective

    378:   Input Parameters:
    379: + viewer - The viewer
    380: . data   - Location to write the data, treated as an array of the type defined by `datatype`
    381: . num    - Number of items of data to read
    382: - dtype  - Type of data to read

    384:   Output Parameter:
    385: . count - number of items of data actually read, or `NULL`

    387:   Level: beginner

    389:   Notes:
    390:   If datatype is `PETSC_STRING` and `num` is negative, reads until a newline character is found,
    391:   until a maximum of (-num - 1) chars.

    393:   Only certain viewers, such as `PETSCVIEWERBINARY` can be read from, see `PetscViewerReadable()`

    395: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`,
    396:           `PetscViewerReadable()`, `PetscViewerBinaryGetDescriptor()`,
    397:           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`
    398: @*/
    399: PetscErrorCode PetscViewerRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype)
    400: {
    401:   PetscFunctionBegin;
    403:   if (dtype == PETSC_STRING) {
    404:     PetscInt c, i = 0, cnt;
    405:     char    *s = (char *)data;
    406:     if (num >= 0) {
    407:       for (c = 0; c < num; c++) {
    408:         /* Skip leading whitespaces */
    409:         do {
    410:           PetscUseTypeMethod(viewer, read, &s[i], 1, &cnt, PETSC_CHAR);
    411:           if (!cnt) break;
    412:         } while (s[i] == '\n' || s[i] == '\t' || s[i] == ' ' || s[i] == '\0' || s[i] == '\v' || s[i] == '\f' || s[i] == '\r');
    413:         i++;
    414:         /* Read strings one char at a time */
    415:         do {
    416:           PetscUseTypeMethod(viewer, read, &s[i++], 1, &cnt, PETSC_CHAR);
    417:           if (!cnt) break;
    418:         } while (s[i - 1] != '\n' && s[i - 1] != '\t' && s[i - 1] != ' ' && s[i - 1] != '\0' && s[i - 1] != '\v' && s[i - 1] != '\f' && s[i - 1] != '\r');
    419:         /* Terminate final string */
    420:         if (c == num - 1) s[i - 1] = '\0';
    421:       }
    422:     } else {
    423:       /* Read until a \n is encountered (-num is the max size allowed) */
    424:       do {
    425:         PetscUseTypeMethod(viewer, read, &s[i++], 1, &cnt, PETSC_CHAR);
    426:         if (i == -num || !cnt) break;
    427:       } while (s[i - 1] != '\n');
    428:       /* Terminate final string */
    429:       s[i - 1] = '\0';
    430:       c        = i;
    431:     }
    432:     if (count) *count = c;
    433:     else PetscCheck(c >= num, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_READ, "Insufficient data, only read %" PetscInt_FMT " < %" PetscInt_FMT " strings", c, num);
    434:   } else PetscUseTypeMethod(viewer, read, data, num, count, dtype);
    435:   PetscFunctionReturn(PETSC_SUCCESS);
    436: }

    438: /*@
    439:   PetscViewerReadable - Return a flag whether the viewer can be read from with `PetscViewerRead()`

    441:   Not Collective

    443:   Input Parameter:
    444: . viewer - the `PetscViewer` context

    446:   Output Parameter:
    447: . flg - `PETSC_TRUE` if the viewer is readable, `PETSC_FALSE` otherwise

    449:   Level: intermediate

    451:   Note:
    452:   `PETSC_TRUE` means that viewer's `PetscViewerType` supports reading, that is `PetscViewerRead()`, (this holds e.g. for `PETSCVIEWERBINARY`)
    453:   and the viewer is in a mode allowing reading, i.e. `PetscViewerFileGetMode()`
    454:   returns one of `FILE_MODE_READ`, `FILE_MODE_UPDATE`, `FILE_MODE_APPEND_UPDATE`.

    456: .seealso: [](sec_viewers), `PetscViewerRead()`, `PetscViewer`, `PetscViewerWritable()`, `PetscViewerCheckReadable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
    457: @*/
    458: PetscErrorCode PetscViewerReadable(PetscViewer viewer, PetscBool *flg)
    459: {
    460:   PetscFileMode mode;
    461:   PetscErrorCode (*f)(PetscViewer, PetscFileMode *) = NULL;

    463:   PetscFunctionBegin;
    465:   PetscAssertPointer(flg, 2);
    466:   PetscCall(PetscObjectQueryFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", &f));
    467:   *flg = PETSC_FALSE;
    468:   if (!f) PetscFunctionReturn(PETSC_SUCCESS);
    469:   PetscCall((*f)(viewer, &mode));
    470:   switch (mode) {
    471:   case FILE_MODE_READ:
    472:   case FILE_MODE_UPDATE:
    473:   case FILE_MODE_APPEND_UPDATE:
    474:     *flg = PETSC_TRUE;
    475:   default:
    476:     break;
    477:   }
    478:   PetscFunctionReturn(PETSC_SUCCESS);
    479: }

    481: /*@
    482:   PetscViewerWritable - Return a flag whether the viewer can be written to with `PetscViewerWrite()`

    484:   Not Collective

    486:   Input Parameter:
    487: . viewer - the `PetscViewer` context

    489:   Output Parameter:
    490: . flg - `PETSC_TRUE` if the viewer is writable, `PETSC_FALSE` otherwise

    492:   Level: intermediate

    494:   Note:
    495:   `PETSC_TRUE` means viewer is in a mode allowing writing, i.e. `PetscViewerFileGetMode()`
    496:   returns one of `FILE_MODE_WRITE`, `FILE_MODE_APPEND`, `FILE_MODE_UPDATE`, `FILE_MODE_APPEND_UPDATE`.

    498: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerReadable()`, `PetscViewerCheckWritable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
    499: @*/
    500: PetscErrorCode PetscViewerWritable(PetscViewer viewer, PetscBool *flg)
    501: {
    502:   PetscFileMode mode;
    503:   PetscErrorCode (*f)(PetscViewer, PetscFileMode *) = NULL;

    505:   PetscFunctionBegin;
    507:   PetscAssertPointer(flg, 2);
    508:   PetscCall(PetscObjectQueryFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", &f));
    509:   *flg = PETSC_TRUE;
    510:   if (!f) PetscFunctionReturn(PETSC_SUCCESS);
    511:   PetscCall((*f)(viewer, &mode));
    512:   if (mode == FILE_MODE_READ) *flg = PETSC_FALSE;
    513:   PetscFunctionReturn(PETSC_SUCCESS);
    514: }

    516: /*@
    517:   PetscViewerCheckReadable - Check whether the viewer can be read from, generates an error if not

    519:   Collective

    521:   Input Parameter:
    522: . viewer - the `PetscViewer` context

    524:   Level: intermediate

    526: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerReadable()`, `PetscViewerCheckWritable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
    527: @*/
    528: PetscErrorCode PetscViewerCheckReadable(PetscViewer viewer)
    529: {
    530:   PetscBool flg;

    532:   PetscFunctionBegin;
    534:   PetscCall(PetscViewerReadable(viewer, &flg));
    535:   PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Viewer doesn't support reading, or is not in reading mode (FILE_MODE_READ, FILE_MODE_UPDATE, FILE_MODE_APPEND_UPDATE)");
    536:   PetscFunctionReturn(PETSC_SUCCESS);
    537: }

    539: /*@
    540:   PetscViewerCheckWritable - Check whether the viewer can be written to, generates an error if not

    542:   Collective

    544:   Input Parameter:
    545: . viewer - the `PetscViewer` context

    547:   Level: intermediate

    549: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerWritable()`, `PetscViewerCheckReadable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
    550: @*/
    551: PetscErrorCode PetscViewerCheckWritable(PetscViewer viewer)
    552: {
    553:   PetscBool flg;

    555:   PetscFunctionBegin;
    557:   PetscCall(PetscViewerWritable(viewer, &flg));
    558:   PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Viewer doesn't support writing, or is in FILE_MODE_READ mode");
    559:   PetscFunctionReturn(PETSC_SUCCESS);
    560: }