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)->lg     = NULL;
141:   (*vf)->data   = NULL;
142:   PetscFunctionReturn(PETSC_SUCCESS);
143: }

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

148:   Collective

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

153:   Level: developer

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

168: /*@
169:   PetscViewerGetType - Returns the type of a `PetscViewer`.

171:   Not Collective

173:   Input Parameter:
174: . viewer - the `PetscViewer`

176:   Output Parameter:
177: . type - `PetscViewerType`

179:   Level: intermediate

181:   Note:
182:   `PetscViewerType` is actually a string

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

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

199:   Logically Collective

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

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

209:   Level: advanced

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

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

225:   Logically Collective

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

231:   Level: advanced

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

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

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

251:   Not Collective

253:   Input Parameter:
254: . viewer - the `PetscViewer` context

256:   Output Parameter:
257: . prefix - pointer to the prefix string used

259:   Level: advanced

261:   Fortran Notes:
262:   The user should pass in a string 'prefix' of sufficient length to hold the prefix.

264: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerAppendOptionsPrefix()`, `PetscViewerSetOptionsPrefix()`
265: @*/
266: PetscErrorCode PetscViewerGetOptionsPrefix(PetscViewer viewer, const char *prefix[])
267: {
268:   PetscFunctionBegin;
270:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)viewer, prefix));
271:   PetscFunctionReturn(PETSC_SUCCESS);
272: }

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

277:   Collective

279:   Input Parameter:
280: . viewer - the `PetscViewer` context

282:   Level: advanced

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

288: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerCreate()`, `PetscViewerDestroy()`
289: @*/
290: PetscErrorCode PetscViewerSetUp(PetscViewer viewer)
291: {
292:   PetscFunctionBegin;
294:   if (viewer->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
295:   PetscTryTypeMethod(viewer, setup);
296:   viewer->setupcalled = PETSC_TRUE;
297:   PetscFunctionReturn(PETSC_SUCCESS);
298: }

300: /*@
301:   PetscViewerViewFromOptions - View from the viewer based on options in the options database

303:   Collective

305:   Input Parameters:
306: + A    - the `PetscViewer` context
307: . obj  - Optional object that provides the prefix for the option names
308: - name - command line option

310:   Level: intermediate

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

315: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerView`, `PetscObjectViewFromOptions()`, `PetscViewerCreate()`
316: @*/
317: PetscErrorCode PetscViewerViewFromOptions(PetscViewer A, PetscObject obj, const char name[])
318: {
319:   PetscFunctionBegin;
321:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
322:   PetscFunctionReturn(PETSC_SUCCESS);
323: }

325: /*@
326:   PetscViewerView - Visualizes a viewer object.

328:   Collective

330:   Input Parameters:
331: + v      - the viewer to be viewed
332: - viewer - visualization context

334:   Level: beginner

336: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`,
337:           `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerLoad()`
338: @*/
339: PetscErrorCode PetscViewerView(PetscViewer v, PetscViewer viewer)
340: {
341:   PetscBool         iascii;
342:   PetscViewerFormat format;
343: #if defined(PETSC_HAVE_SAWS)
344:   PetscBool issaws;
345: #endif

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

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

378: /*@C
379:   PetscViewerRead - Reads data from a `PetscViewer`

381:   Collective

383:   Input Parameters:
384: + viewer - The viewer
385: . data   - Location to write the data, treated as an array of the type defined by `datatype`
386: . num    - Number of items of data to read
387: - dtype  - Type of data to read

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

392:   Level: beginner

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

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

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

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

446:   Not Collective

448:   Input Parameter:
449: . viewer - the `PetscViewer` context

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

454:   Level: intermediate

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

461: .seealso: [](sec_viewers), `PetscViewerRead()`, `PetscViewer`, `PetscViewerWritable()`, `PetscViewerCheckReadable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
462: @*/
463: PetscErrorCode PetscViewerReadable(PetscViewer viewer, PetscBool *flg)
464: {
465:   PetscFileMode mode;
466:   PetscErrorCode (*f)(PetscViewer, PetscFileMode *) = NULL;

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

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

489:   Not Collective

491:   Input Parameter:
492: . viewer - the `PetscViewer` context

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

497:   Level: intermediate

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

503: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerReadable()`, `PetscViewerCheckWritable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
504: @*/
505: PetscErrorCode PetscViewerWritable(PetscViewer viewer, PetscBool *flg)
506: {
507:   PetscFileMode mode;
508:   PetscErrorCode (*f)(PetscViewer, PetscFileMode *) = NULL;

510:   PetscFunctionBegin;
512:   PetscAssertPointer(flg, 2);
513:   PetscCall(PetscObjectQueryFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", &f));
514:   *flg = PETSC_TRUE;
515:   if (!f) PetscFunctionReturn(PETSC_SUCCESS);
516:   PetscCall((*f)(viewer, &mode));
517:   if (mode == FILE_MODE_READ) *flg = PETSC_FALSE;
518:   PetscFunctionReturn(PETSC_SUCCESS);
519: }

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

524:   Collective

526:   Input Parameter:
527: . viewer - the `PetscViewer` context

529:   Level: intermediate

531: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerReadable()`, `PetscViewerCheckWritable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
532: @*/
533: PetscErrorCode PetscViewerCheckReadable(PetscViewer viewer)
534: {
535:   PetscBool flg;

537:   PetscFunctionBegin;
539:   PetscCall(PetscViewerReadable(viewer, &flg));
540:   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)");
541:   PetscFunctionReturn(PETSC_SUCCESS);
542: }

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

547:   Collective

549:   Input Parameter:
550: . viewer - the `PetscViewer` context

552:   Level: intermediate

554: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerWritable()`, `PetscViewerCheckReadable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
555: @*/
556: PetscErrorCode PetscViewerCheckWritable(PetscViewer viewer)
557: {
558:   PetscBool flg;

560:   PetscFunctionBegin;
562:   PetscCall(PetscViewerWritable(viewer, &flg));
563:   PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Viewer doesn't support writing, or is in FILE_MODE_READ mode");
564:   PetscFunctionReturn(PETSC_SUCCESS);
565: }