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