xref: /petsc/src/sys/classes/viewer/interface/view.c (revision 0e6b6b5985dd9b1172860d21fb88bd3966bf7c54)
1 
2 #include <petsc/private/viewerimpl.h> /*I "petscviewer.h" I*/
3 #include <petscdraw.h>
4 
5 PetscClassId PETSC_VIEWER_CLASSID;
6 
7 static PetscBool PetscViewerPackageInitialized = PETSC_FALSE;
8 /*@C
9   PetscViewerFinalizePackage - This function destroys any global objects created in the Petsc viewers. It is
10   called from `PetscFinalize()`.
11 
12   Level: developer
13 
14 .seealso: `PetscFinalize()`
15 @*/
16 PetscErrorCode   PetscViewerFinalizePackage(void) {
17     PetscFunctionBegin;
18     if (Petsc_Viewer_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_keyval));
19   if (Petsc_Viewer_Stdout_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Stdout_keyval));
20   if (Petsc_Viewer_Stderr_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Stderr_keyval));
21   if (Petsc_Viewer_Binary_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Binary_keyval));
22   if (Petsc_Viewer_Draw_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Draw_keyval));
23 #if defined(PETSC_HAVE_HDF5)
24   if (Petsc_Viewer_HDF5_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_HDF5_keyval));
25 #endif
26 #if defined(PETSC_USE_SOCKETVIEWER)
27   if (Petsc_Viewer_Socket_keyval != MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_free_keyval(&Petsc_Viewer_Socket_keyval));
28 #endif
29   PetscCall(PetscFunctionListDestroy(&PetscViewerList));
30   PetscViewerPackageInitialized = PETSC_FALSE;
31   PetscViewerRegisterAllCalled  = PETSC_FALSE;
32   PetscFunctionReturn(0);
33 }
34 
35 /*@C
36   PetscViewerInitializePackage - This function initializes everything in the `PetscViewer` package.
37 
38   Level: developer
39 
40 .seealso: `PetscInitialize()`
41 @*/
42 PetscErrorCode PetscViewerInitializePackage(void) {
43   char      logList[256];
44   PetscBool opt, pkg;
45 
46   PetscFunctionBegin;
47   if (PetscViewerPackageInitialized) PetscFunctionReturn(0);
48   PetscViewerPackageInitialized = PETSC_TRUE;
49   /* Register Classes */
50   PetscCall(PetscClassIdRegister("Viewer", &PETSC_VIEWER_CLASSID));
51   /* Register Constructors */
52   PetscCall(PetscViewerRegisterAll());
53   /* Process Info */
54   {
55     PetscClassId classids[1];
56 
57     classids[0] = PETSC_VIEWER_CLASSID;
58     PetscCall(PetscInfoProcessClass("viewer", 1, classids));
59   }
60   /* Process summary exclusions */
61   PetscCall(PetscOptionsGetString(NULL, NULL, "-log_exclude", logList, sizeof(logList), &opt));
62   if (opt) {
63     PetscCall(PetscStrInList("viewer", logList, ',', &pkg));
64     if (pkg) PetscCall(PetscLogEventExcludeClass(PETSC_VIEWER_CLASSID));
65   }
66 #if defined(PETSC_HAVE_MATHEMATICA)
67   PetscCall(PetscViewerMathematicaInitializePackage());
68 #endif
69   /* Register package finalizer */
70   PetscCall(PetscRegisterFinalize(PetscViewerFinalizePackage));
71   PetscFunctionReturn(0);
72 }
73 
74 /*@
75    PetscViewerDestroy - Destroys a `PetscViewer`.
76 
77    Collective on viewer
78 
79    Input Parameters:
80 .  viewer - the `PetscViewer` to be destroyed.
81 
82    Level: beginner
83 
84 .seealso: `PetscViewer`, `PetscViewerSocketOpen()`, `PetscViewerASCIIOpen()`, `PetscViewerCreate()`, `PetscViewerDrawOpen()`
85 @*/
86 PetscErrorCode PetscViewerDestroy(PetscViewer *viewer) {
87   PetscFunctionBegin;
88   if (!*viewer) PetscFunctionReturn(0);
89   PetscValidHeaderSpecific(*viewer, PETSC_VIEWER_CLASSID, 1);
90 
91   PetscCall(PetscViewerFlush(*viewer));
92   if (--((PetscObject)(*viewer))->refct > 0) {
93     *viewer = NULL;
94     PetscFunctionReturn(0);
95   }
96 
97   PetscCall(PetscObjectSAWsViewOff((PetscObject)*viewer));
98   if ((*viewer)->ops->destroy) PetscCall((*(*viewer)->ops->destroy)(*viewer));
99   PetscCall(PetscHeaderDestroy(viewer));
100   PetscFunctionReturn(0);
101 }
102 
103 /*@C
104    PetscViewerAndFormatCreate - Creates a `PetscViewerAndFormat` struct.
105 
106    Collective on viewer
107 
108    Input Parameters:
109 +  viewer - the viewer
110 -  format - the format
111 
112    Output Parameter:
113 .   vf - viewer and format object
114 
115    Level: developer
116 
117    Notes:
118    This increases the reference count of the viewer so you can destroy the viewer object after this call
119 
120    This is used as the context variable for many of the `TS`, `SNES`, and `KSP` monitor functions
121 
122 .seealso: `PetscViewerSocketOpen()`, `PetscViewerASCIIOpen()`, `PetscViewerCreate()`, `PetscViewerDrawOpen()`, `PetscViewerAndFormatDestroy()`
123 @*/
124 PetscErrorCode PetscViewerAndFormatCreate(PetscViewer viewer, PetscViewerFormat format, PetscViewerAndFormat **vf) {
125   PetscFunctionBegin;
126   PetscCall(PetscObjectReference((PetscObject)viewer));
127   PetscCall(PetscNew(vf));
128   (*vf)->viewer = viewer;
129   (*vf)->format = format;
130   (*vf)->lg     = NULL;
131   (*vf)->data   = NULL;
132   PetscFunctionReturn(0);
133 }
134 
135 /*@C
136    PetscViewerAndFormatDestroy - Destroys a `PetscViewerAndFormat` struct.
137 
138    Collective on vf
139 
140    Input Parameters:
141 .  vf - the `PetscViewerAndFormat` to be destroyed.
142 
143    Level: developer
144 
145 .seealso: `PetscViewerSocketOpen()`, `PetscViewerASCIIOpen()`, `PetscViewerCreate()`, `PetscViewerDrawOpen()`, `PetscViewerAndFormatCreate()`
146 @*/
147 PetscErrorCode PetscViewerAndFormatDestroy(PetscViewerAndFormat **vf) {
148   PetscFunctionBegin;
149   PetscCall(PetscViewerDestroy(&(*vf)->viewer));
150   PetscCall(PetscDrawLGDestroy(&(*vf)->lg));
151   PetscCall(PetscFree(*vf));
152   PetscFunctionReturn(0);
153 }
154 
155 /*@C
156    PetscViewerGetType - Returns the type of a `PetscViewer`.
157 
158    Not Collective
159 
160    Input Parameter:
161 .   viewer - the `PetscViewer`
162 
163    Output Parameter:
164 .  type - PetscViewer type (see below)
165 
166    Available Types Include:
167 +  `PETSCVIEWERSOCKET` - Socket PetscViewer
168 .  `PETSCVIEWERASCII` - ASCII PetscViewer
169 .  `PETSCVIEWERBINARY` - binary file PetscViewer
170 .  `PETSCVIEWERSTRING` - string PetscViewer
171 -  `PETSCVIEWERDRAW` - drawing PetscViewer
172 
173    Level: intermediate
174 
175    Note:
176    See include/petscviewer.h for a complete list of `PetscViewer`s.
177 
178    `PetscViewerType` is actually a string
179 
180 .seealso: `PetscViewerType`, `PetscViewer`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerType`
181 @*/
182 PetscErrorCode PetscViewerGetType(PetscViewer viewer, PetscViewerType *type) {
183   PetscFunctionBegin;
184   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
185   PetscValidPointer(type, 2);
186   *type = ((PetscObject)viewer)->type_name;
187   PetscFunctionReturn(0);
188 }
189 
190 /*@C
191    PetscViewerSetOptionsPrefix - Sets the prefix used for searching for all
192    `PetscViewer` options in the database.
193 
194    Logically Collective on viewer
195 
196    Input Parameters:
197 +  viewer - the `PetscViewer` context
198 -  prefix - the prefix to prepend to all option names
199 
200    Note:
201    A hyphen (-) must NOT be given at the beginning of the prefix name.
202    The first character of all runtime options is AUTOMATICALLY the hyphen.
203 
204    Level: advanced
205 
206 .seealso: `PetscViewer`, `PetscViewerSetFromOptions()`
207 @*/
208 PetscErrorCode PetscViewerSetOptionsPrefix(PetscViewer viewer, const char prefix[]) {
209   PetscFunctionBegin;
210   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
211   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)viewer, prefix));
212   PetscFunctionReturn(0);
213 }
214 
215 /*@C
216    PetscViewerAppendOptionsPrefix - Appends to the prefix used for searching for all
217    `PetscViewer` options in the database.
218 
219    Logically Collective on viewer
220 
221    Input Parameters:
222 +  viewer - the PetscViewer context
223 -  prefix - the prefix to prepend to all option names
224 
225    Note:
226    A hyphen (-) must NOT be given at the beginning of the prefix name.
227    The first character of all runtime options is AUTOMATICALLY the hyphen.
228 
229    Level: advanced
230 
231 .seealso: `PetscViewer`, `PetscViewerGetOptionsPrefix()`
232 @*/
233 PetscErrorCode PetscViewerAppendOptionsPrefix(PetscViewer viewer, const char prefix[]) {
234   PetscFunctionBegin;
235   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
236   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)viewer, prefix));
237   PetscFunctionReturn(0);
238 }
239 
240 /*@C
241    PetscViewerGetOptionsPrefix - Sets the prefix used for searching for all
242    PetscViewer options in the database.
243 
244    Not Collective
245 
246    Input Parameter:
247 .  viewer - the `PetscViewer` context
248 
249    Output Parameter:
250 .  prefix - pointer to the prefix string used
251 
252    Fortran Note:
253    The user should pass in a string 'prefix' of sufficient length to hold the prefix.
254 
255    Level: advanced
256 
257 .seealso: `PetscViewer`, `PetscViewerAppendOptionsPrefix()`
258 @*/
259 PetscErrorCode PetscViewerGetOptionsPrefix(PetscViewer viewer, const char *prefix[]) {
260   PetscFunctionBegin;
261   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
262   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)viewer, prefix));
263   PetscFunctionReturn(0);
264 }
265 
266 /*@
267    PetscViewerSetUp - Sets up the internal viewer data structures for the later use.
268 
269    Collective on viewer
270 
271    Input Parameters:
272 .  viewer - the `PetscViewer` context
273 
274    Note:
275    For basic use of the `PetscViewer` classes the user need not explicitly call
276    `PetscViewerSetUp()`, since these actions will happen automatically.
277 
278    Level: advanced
279 
280 .seealso: `PetscViewer`, `PetscViewerCreate()`, `PetscViewerDestroy()`
281 @*/
282 PetscErrorCode PetscViewerSetUp(PetscViewer viewer) {
283   PetscFunctionBegin;
284   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
285   if (viewer->setupcalled) PetscFunctionReturn(0);
286   PetscTryTypeMethod(viewer, setup);
287   viewer->setupcalled = PETSC_TRUE;
288   PetscFunctionReturn(0);
289 }
290 
291 /*@C
292    PetscViewerViewFromOptions - View from the viewer based on the options database values
293 
294    Collective on A
295 
296    Input Parameters:
297 +  A - the `PetscViewer` context
298 .  obj - Optional object that provides the prefix for the option names
299 -  name - command line option
300 
301    Level: intermediate
302 
303 .seealso: `PetscViewer`, `PetscViewerView`, `PetscObjectViewFromOptions()`, `PetscViewerCreate()`
304 @*/
305 PetscErrorCode PetscViewerViewFromOptions(PetscViewer A, PetscObject obj, const char name[]) {
306   PetscFunctionBegin;
307   PetscValidHeaderSpecific(A, PETSC_VIEWER_CLASSID, 1);
308   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
309   PetscFunctionReturn(0);
310 }
311 
312 /*@C
313    PetscViewerView - Visualizes a viewer object.
314 
315    Collective on v
316 
317    Input Parameters:
318 +  v - the viewer to be viewed
319 -  viewer - visualization context
320 
321   Note:
322   The available visualization contexts include
323 .vb
324   PETSC_VIEWER_STDOUT_SELF - standard output (default)
325   PETSC_VIEWER_STDOUT_WORLD - synchronized standard output where only the first rank opens the file. Other processors send their data to the first rank
326   PETSC_VIEWER_DRAW_WORLD - graphical display of nonzero structure
327 .ve
328 
329    Level: beginner
330 
331 .seealso: `PetscViewer`, `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`,
332           `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerLoad()`
333 @*/
334 PetscErrorCode PetscViewerView(PetscViewer v, PetscViewer viewer) {
335   PetscBool         iascii;
336   PetscViewerFormat format;
337 #if defined(PETSC_HAVE_SAWS)
338   PetscBool issaws;
339 #endif
340 
341   PetscFunctionBegin;
342   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
343   PetscValidType(v, 1);
344   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)v), &viewer));
345   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
346   PetscCheckSameComm(v, 1, viewer, 2);
347 
348   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
349 #if defined(PETSC_HAVE_SAWS)
350   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
351 #endif
352   if (iascii) {
353     PetscCall(PetscViewerGetFormat(viewer, &format));
354     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)v, viewer));
355     if (format == PETSC_VIEWER_DEFAULT || format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
356       if (v->format) PetscCall(PetscViewerASCIIPrintf(viewer, "  Viewer format = %s\n", PetscViewerFormats[v->format]));
357       PetscCall(PetscViewerASCIIPushTab(viewer));
358       PetscTryTypeMethod(v, view, viewer);
359       PetscCall(PetscViewerASCIIPopTab(viewer));
360     }
361 #if defined(PETSC_HAVE_SAWS)
362   } else if (issaws) {
363     if (!((PetscObject)v)->amsmem) {
364       PetscCall(PetscObjectViewSAWs((PetscObject)v, viewer));
365       PetscTryTypeMethod(v, view, viewer);
366     }
367 #endif
368   }
369   PetscFunctionReturn(0);
370 }
371 
372 /*@C
373    PetscViewerRead - Reads data from a `PetscViewer`
374 
375    Collective
376 
377    Input Parameters:
378 +  viewer   - The viewer
379 .  data     - Location to write the data
380 .  num      - Number of items of data to read
381 -  datatype - Type of data to read
382 
383    Output Parameters:
384 .  count - number of items of data actually read, or NULL
385 
386    Note:
387    If datatype is `PETSC_STRING` and num is negative, reads until a newline character is found,
388    until a maximum of (-num - 1) chars.
389 
390    Level: beginner
391 
392 .seealso: `PetscViewer`, `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`,
393           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
394           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`
395 @*/
396 PetscErrorCode PetscViewerRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype) {
397   PetscFunctionBegin;
398   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
399   if (dtype == PETSC_STRING) {
400     PetscInt c, i = 0, cnt;
401     char    *s = (char *)data;
402     if (num >= 0) {
403       for (c = 0; c < num; c++) {
404         /* Skip leading whitespaces */
405         do {
406           PetscCall((*viewer->ops->read)(viewer, &(s[i]), 1, &cnt, PETSC_CHAR));
407           if (!cnt) break;
408         } while (s[i] == '\n' || s[i] == '\t' || s[i] == ' ' || s[i] == '\0' || s[i] == '\v' || s[i] == '\f' || s[i] == '\r');
409         i++;
410         /* Read strings one char at a time */
411         do {
412           PetscCall((*viewer->ops->read)(viewer, &(s[i++]), 1, &cnt, PETSC_CHAR));
413           if (!cnt) break;
414         } 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');
415         /* Terminate final string */
416         if (c == num - 1) s[i - 1] = '\0';
417       }
418     } else {
419       /* Read until a \n is encountered (-num is the max size allowed) */
420       do {
421         PetscCall((*viewer->ops->read)(viewer, &(s[i++]), 1, &cnt, PETSC_CHAR));
422         if (i == -num || !cnt) break;
423       } while (s[i - 1] != '\n');
424       /* Terminate final string */
425       s[i - 1] = '\0';
426       c        = i;
427     }
428     if (count) *count = c;
429     else PetscCheck(c >= num, PetscObjectComm((PetscObject)viewer), PETSC_ERR_FILE_READ, "Insufficient data, only read %" PetscInt_FMT " < %" PetscInt_FMT " strings", c, num);
430   } else PetscUseTypeMethod(viewer, read, data, num, count, dtype);
431   PetscFunctionReturn(0);
432 }
433 
434 /*@
435    PetscViewerReadable - Return a flag whether the viewer can be read from
436 
437    Not Collective
438 
439    Input Parameters:
440 .  viewer - the `PetscViewer` context
441 
442    Output Parameters:
443 .  flg - `PETSC_TRUE` if the viewer is readable, `PETSC_FALSE` otherwise
444 
445    Note:
446    `PETSC_TRUE` means that viewer's `PetscViewerType` supports reading (this holds e.g. for `PETSCVIEWERBINARY`)
447    and viewer is in a mode allowing reading, i.e. `PetscViewerFileGetMode()`
448    returns one of `FILE_MODE_READ`, `FILE_MODE_UPDATE`, `FILE_MODE_APPEND_UPDATE`.
449 
450    Level: intermediate
451 
452 .seealso: `PetscViewer`, `PetscViewerWritable()`, `PetscViewerCheckReadable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
453 @*/
454 PetscErrorCode PetscViewerReadable(PetscViewer viewer, PetscBool *flg) {
455   PetscFileMode mode;
456   PetscErrorCode (*f)(PetscViewer, PetscFileMode *) = NULL;
457 
458   PetscFunctionBegin;
459   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
460   PetscValidBoolPointer(flg, 2);
461   PetscCall(PetscObjectQueryFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", &f));
462   *flg = PETSC_FALSE;
463   if (!f) PetscFunctionReturn(0);
464   PetscCall((*f)(viewer, &mode));
465   switch (mode) {
466   case FILE_MODE_READ:
467   case FILE_MODE_UPDATE:
468   case FILE_MODE_APPEND_UPDATE: *flg = PETSC_TRUE;
469   default: break;
470   }
471   PetscFunctionReturn(0);
472 }
473 
474 /*@
475    PetscViewerWritable - Return a flag whether the viewer can be written to
476 
477    Not Collective
478 
479    Input Parameters:
480 .  viewer - the `PetscViewer` context
481 
482    Output Parameters:
483 .  flg - `PETSC_TRUE` if the viewer is writable, `PETSC_FALSE` otherwise
484 
485    Note:
486    `PETSC_TRUE` means viewer is in a mode allowing writing, i.e. `PetscViewerFileGetMode()`
487    returns one of `FILE_MODE_WRITE`, `FILE_MODE_APPEND`, `FILE_MODE_UPDATE`, `FILE_MODE_APPEND_UPDATE`.
488 
489    Level: intermediate
490 
491 .seealso: `PetscViewer`, `PetscViewerReadable()`, `PetscViewerCheckWritable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
492 @*/
493 PetscErrorCode PetscViewerWritable(PetscViewer viewer, PetscBool *flg) {
494   PetscFileMode mode;
495   PetscErrorCode (*f)(PetscViewer, PetscFileMode *) = NULL;
496 
497   PetscFunctionBegin;
498   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
499   PetscValidBoolPointer(flg, 2);
500   PetscCall(PetscObjectQueryFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", &f));
501   *flg = PETSC_TRUE;
502   if (!f) PetscFunctionReturn(0);
503   PetscCall((*f)(viewer, &mode));
504   if (mode == FILE_MODE_READ) *flg = PETSC_FALSE;
505   PetscFunctionReturn(0);
506 }
507 
508 /*@
509    PetscViewerCheckReadable - Check whether the viewer can be read from, generates an error if not
510 
511    Collective
512 
513    Input Parameters:
514 .  viewer - the `PetscViewer` context
515 
516    Level: intermediate
517 
518 .seealso: `PetscViewer`, `PetscViewerReadable()`, `PetscViewerCheckWritable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
519 @*/
520 PetscErrorCode PetscViewerCheckReadable(PetscViewer viewer) {
521   PetscBool flg;
522 
523   PetscFunctionBegin;
524   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
525   PetscCall(PetscViewerReadable(viewer, &flg));
526   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)");
527   PetscFunctionReturn(0);
528 }
529 
530 /*@
531    PetscViewerCheckWritable - Check whether the viewer can be written to, generates an error if not
532 
533    Collective
534 
535    Input Parameters:
536 .  viewer - the `PetscViewer` context
537 
538    Level: intermediate
539 
540 .seealso: `PetscViewer`, `PetscViewerWritable()`, `PetscViewerCheckReadable()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetType()`
541 @*/
542 PetscErrorCode PetscViewerCheckWritable(PetscViewer viewer) {
543   PetscBool flg;
544 
545   PetscFunctionBegin;
546   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
547   PetscCall(PetscViewerWritable(viewer, &flg));
548   PetscCheck(flg, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Viewer doesn't support writing, or is in FILE_MODE_READ mode");
549   PetscFunctionReturn(0);
550 }
551