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