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