xref: /petsc/src/sys/classes/viewer/interface/viewreg.c (revision 98d129c30f3ee9fdddc40fdbc5a989b7be64f888)
1 #include <petsc/private/viewerimpl.h> /*I "petscviewer.h" I*/
2 #include <petsc/private/hashtable.h>
3 #if defined(PETSC_HAVE_SAWS)
4   #include <petscviewersaws.h>
5 #endif
6 
7 PetscFunctionList PetscViewerList = NULL;
8 
9 PetscOptionsHelpPrinted PetscOptionsHelpPrintedSingleton = NULL;
10 KHASH_SET_INIT_STR(HTPrinted)
11 struct _n_PetscOptionsHelpPrinted {
12   khash_t(HTPrinted) *printed;
13   PetscSegBuffer      strings;
14 };
15 
16 PetscErrorCode PetscOptionsHelpPrintedDestroy(PetscOptionsHelpPrinted *hp)
17 {
18   PetscFunctionBegin;
19   if (!*hp) PetscFunctionReturn(PETSC_SUCCESS);
20   kh_destroy(HTPrinted, (*hp)->printed);
21   PetscCall(PetscSegBufferDestroy(&(*hp)->strings));
22   PetscCall(PetscFree(*hp));
23   PetscFunctionReturn(PETSC_SUCCESS);
24 }
25 
26 /*@C
27   PetscOptionsHelpPrintedCreate - Creates an object used to manage tracking which help messages have
28   been printed so they will not be printed again.
29 
30   Output Parameter:
31 . hp - the created object
32 
33   Not Collective
34 
35   Level: developer
36 
37 .seealso: `PetscOptionsHelpPrintedCheck()`, `PetscOptionsHelpPrintChecked()`
38 @*/
39 PetscErrorCode PetscOptionsHelpPrintedCreate(PetscOptionsHelpPrinted *hp)
40 {
41   PetscFunctionBegin;
42   PetscCall(PetscNew(hp));
43   (*hp)->printed = kh_init(HTPrinted);
44   PetscCall(PetscSegBufferCreate(sizeof(char), 10000, &(*hp)->strings));
45   PetscFunctionReturn(PETSC_SUCCESS);
46 }
47 
48 /*@C
49   PetscOptionsHelpPrintedCheck - Checks if a particular pre, name pair has previous been entered (meaning the help message was printed)
50 
51   Not Collective
52 
53   Input Parameters:
54 + hp   - the object used to manage tracking what help messages have been printed
55 . pre  - the prefix part of the string, many be `NULL`
56 - name - the string to look for (cannot be `NULL`)
57 
58   Output Parameter:
59 . found - `PETSC_TRUE` if the string was already set
60 
61   Level: intermediate
62 
63 .seealso: `PetscOptionsHelpPrintedCreate()`
64 @*/
65 PetscErrorCode PetscOptionsHelpPrintedCheck(PetscOptionsHelpPrinted hp, const char *pre, const char *name, PetscBool *found)
66 {
67   size_t l1, l2;
68 #if !defined(PETSC_HAVE_THREADSAFETY)
69   char *both;
70   int   newitem;
71 #endif
72 
73   PetscFunctionBegin;
74   PetscCall(PetscStrlen(pre, &l1));
75   PetscCall(PetscStrlen(name, &l2));
76   if (l1 + l2 == 0) {
77     *found = PETSC_FALSE;
78     PetscFunctionReturn(PETSC_SUCCESS);
79   }
80 #if !defined(PETSC_HAVE_THREADSAFETY)
81   size_t lboth = l1 + l2 + 1;
82   PetscCall(PetscSegBufferGet(hp->strings, lboth, &both));
83   PetscCall(PetscStrncpy(both, pre, lboth));
84   PetscCall(PetscStrncpy(both + l1, name, l2 + 1));
85   kh_put(HTPrinted, hp->printed, both, &newitem);
86   if (!newitem) PetscCall(PetscSegBufferUnuse(hp->strings, lboth));
87   *found = newitem ? PETSC_FALSE : PETSC_TRUE;
88 #else
89   *found = PETSC_FALSE;
90 #endif
91   PetscFunctionReturn(PETSC_SUCCESS);
92 }
93 
94 static PetscBool noviewer = PETSC_FALSE;
95 static PetscBool noviewers[PETSCVIEWERGETVIEWEROFFPUSHESMAX];
96 static PetscInt  inoviewers = 0;
97 
98 /*@
99   PetscOptionsPushGetViewerOff - sets if a `PetscOptionsGetViewer()` returns a viewer.
100 
101   Logically Collective
102 
103   Input Parameter:
104 . flg - `PETSC_TRUE` to turn off viewer creation, `PETSC_FALSE` to turn it on.
105 
106   Level: developer
107 
108   Note:
109   Calling `XXXViewFromOptions` in an inner loop can be expensive.  This can appear, for example, when using
110   many small subsolves.  Call this function to control viewer creation in `PetscOptionsGetViewer()`, thus removing the expensive `XXXViewFromOptions` calls.
111 
112   Developer Notes:
113   Instead of using this approach, the calls to `PetscOptionsGetViewer()` can be moved into `XXXSetFromOptions()`
114 
115 .seealso: [](sec_viewers), `PetscOptionsGetViewer()`, `PetscOptionsPopGetViewerOff()`
116 @*/
117 PetscErrorCode PetscOptionsPushGetViewerOff(PetscBool flg)
118 {
119   PetscFunctionBegin;
120   PetscCheck(inoviewers < PETSCVIEWERGETVIEWEROFFPUSHESMAX, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many PetscOptionsPushGetViewerOff(), perhaps you forgot PetscOptionsPopGetViewerOff()?");
121 
122   noviewers[inoviewers++] = noviewer;
123   noviewer                = flg;
124   PetscFunctionReturn(PETSC_SUCCESS);
125 }
126 
127 /*@
128   PetscOptionsPopGetViewerOff - reset whether `PetscOptionsGetViewer()` returns a viewer.
129 
130   Logically Collective
131 
132   Level: developer
133 
134   Note:
135   See `PetscOptionsPushGetViewerOff()`
136 
137 .seealso: [](sec_viewers), `PetscOptionsGetViewer()`, `PetscOptionsPushGetViewerOff()`
138 @*/
139 PetscErrorCode PetscOptionsPopGetViewerOff(void)
140 {
141   PetscFunctionBegin;
142   PetscCheck(inoviewers, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many PetscOptionsPopGetViewerOff(), perhaps you forgot PetscOptionsPushGetViewerOff()?");
143   noviewer = noviewers[--inoviewers];
144   PetscFunctionReturn(PETSC_SUCCESS);
145 }
146 
147 /*@
148   PetscOptionsGetViewerOff - does `PetscOptionsGetViewer()` return a viewer?
149 
150   Logically Collective
151 
152   Output Parameter:
153 . flg - whether viewers are returned.
154 
155   Level: developer
156 
157   Note:
158   See `PetscOptionsPushGetViewerOff()`
159 
160 .seealso: [](sec_viewers), `PetscOptionsGetViewer()`, `PetscOptionsPushGetViewerOff()`, `PetscOptionsPopGetViewerOff()`
161 @*/
162 PetscErrorCode PetscOptionsGetViewerOff(PetscBool *flg)
163 {
164   PetscFunctionBegin;
165   PetscAssertPointer(flg, 1);
166   *flg = noviewer;
167   PetscFunctionReturn(PETSC_SUCCESS);
168 }
169 
170 static PetscErrorCode PetscOptionsGetViewers_Single(MPI_Comm comm, const char value[], PetscViewer *viewer, PetscViewerFormat *format)
171 {
172   char       *loc0_vtype = NULL, *loc1_fname = NULL, *loc2_fmt = NULL, *loc3_fmode = NULL;
173   PetscInt    cnt;
174   size_t      viewer_string_length;
175   const char *viewers[] = {PETSCVIEWERASCII, PETSCVIEWERBINARY, PETSCVIEWERDRAW, PETSCVIEWERSOCKET, PETSCVIEWERMATLAB, PETSCVIEWERSAWS, PETSCVIEWERVTK, PETSCVIEWERHDF5, PETSCVIEWERGLVIS, PETSCVIEWEREXODUSII, NULL};
176 
177   PetscFunctionBegin;
178   PetscCall(PetscStrlen(value, &viewer_string_length));
179   if (!viewer_string_length) {
180     if (format) *format = PETSC_VIEWER_DEFAULT;
181     if (viewer) PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
182     PetscFunctionReturn(PETSC_SUCCESS);
183   }
184 
185   PetscCall(PetscStrallocpy(value, &loc0_vtype));
186   PetscCall(PetscStrchr(loc0_vtype, ':', &loc1_fname));
187   if (loc1_fname) {
188     *loc1_fname++ = 0;
189     PetscCall(PetscStrchr(loc1_fname, ':', &loc2_fmt));
190   }
191   if (loc2_fmt) {
192     *loc2_fmt++ = 0;
193     PetscCall(PetscStrchr(loc2_fmt, ':', &loc3_fmode));
194   }
195   if (loc3_fmode) *loc3_fmode++ = 0;
196   PetscCall(PetscStrendswithwhich(*loc0_vtype ? loc0_vtype : "ascii", viewers, &cnt));
197   PetscCheck(cnt <= (PetscInt)sizeof(viewers) - 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "Unknown viewer type: %s", loc0_vtype);
198   if (viewer) {
199     if (!loc1_fname) {
200       switch (cnt) {
201       case 0:
202         PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
203         break;
204       case 1:
205         if (!(*viewer = PETSC_VIEWER_BINARY_(comm))) PetscCall(PETSC_ERR_PLIB);
206         break;
207       case 2:
208         if (!(*viewer = PETSC_VIEWER_DRAW_(comm))) PetscCall(PETSC_ERR_PLIB);
209         break;
210 #if defined(PETSC_USE_SOCKET_VIEWER)
211       case 3:
212         if (!(*viewer = PETSC_VIEWER_SOCKET_(comm))) PetscCall(PETSC_ERR_PLIB);
213         break;
214 #endif
215 #if defined(PETSC_HAVE_MATLAB)
216       case 4:
217         if (!(*viewer = PETSC_VIEWER_MATLAB_(comm))) PetscCall(PETSC_ERR_PLIB);
218         break;
219 #endif
220 #if defined(PETSC_HAVE_SAWS)
221       case 5:
222         if (!(*viewer = PETSC_VIEWER_SAWS_(comm))) PetscCall(PETSC_ERR_PLIB);
223         break;
224 #endif
225 #if defined(PETSC_HAVE_HDF5)
226       case 7:
227         if (!(*viewer = PETSC_VIEWER_HDF5_(comm))) PetscCall(PETSC_ERR_PLIB);
228         break;
229 #endif
230       case 8:
231         if (!(*viewer = PETSC_VIEWER_GLVIS_(comm))) PetscCall(PETSC_ERR_PLIB);
232         break;
233 #if defined(PETSC_HAVE_EXODUSII)
234       case 9:
235         if (!(*viewer = PETSC_VIEWER_EXODUSII_(comm))) PetscCall(PETSC_ERR_PLIB);
236         break;
237 #endif
238       default:
239         SETERRQ(comm, PETSC_ERR_SUP, "Unsupported viewer %s", loc0_vtype);
240       }
241     } else {
242       if (loc2_fmt && !*loc1_fname && (cnt == 0)) { /* ASCII format without file name */
243         PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
244       } else {
245         PetscFileMode fmode;
246         PetscBool     flag = PETSC_FALSE;
247 
248         PetscCall(PetscViewerCreate(comm, viewer));
249         PetscCall(PetscViewerSetType(*viewer, *loc0_vtype ? loc0_vtype : "ascii"));
250         fmode = FILE_MODE_WRITE;
251         if (loc3_fmode && *loc3_fmode) { /* Has non-empty file mode ("write" or "append") */
252           PetscCall(PetscEnumFind(PetscFileModes, loc3_fmode, (PetscEnum *)&fmode, &flag));
253           PetscCheck(flag, comm, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown file mode: %s", loc3_fmode);
254         }
255         if (loc2_fmt) {
256           PetscBool tk, im;
257           PetscCall(PetscStrcmp(loc1_fname, "tikz", &tk));
258           PetscCall(PetscStrcmp(loc1_fname, "image", &im));
259           if (tk || im) {
260             PetscCall(PetscViewerDrawSetInfo(*viewer, NULL, loc2_fmt, PETSC_DECIDE, PETSC_DECIDE, PETSC_DECIDE, PETSC_DECIDE));
261             *loc2_fmt = 0;
262           }
263         }
264         PetscCall(PetscViewerFileSetMode(*viewer, flag ? fmode : FILE_MODE_WRITE));
265         PetscCall(PetscViewerFileSetName(*viewer, loc1_fname));
266         if (*loc1_fname) PetscCall(PetscViewerDrawSetDrawType(*viewer, loc1_fname));
267         PetscCall(PetscViewerSetFromOptions(*viewer));
268       }
269     }
270   }
271   if (viewer) PetscCall(PetscViewerSetUp(*viewer));
272   if (loc2_fmt && *loc2_fmt) {
273     PetscViewerFormat tfmt;
274     PetscBool         flag;
275 
276     PetscCall(PetscEnumFind(PetscViewerFormats, loc2_fmt, (PetscEnum *)&tfmt, &flag));
277     if (format) *format = tfmt;
278     PetscCheck(flag, comm, PETSC_ERR_SUP, "Unknown viewer format %s", loc2_fmt);
279   } else if (viewer && (cnt == 6) && format) { /* Get format from VTK viewer */
280     PetscCall(PetscViewerGetFormat(*viewer, format));
281   }
282   PetscCall(PetscFree(loc0_vtype));
283   PetscFunctionReturn(PETSC_SUCCESS);
284 }
285 
286 static PetscErrorCode PetscOptionsGetViewers_Internal(MPI_Comm comm, PetscOptions options, const char pre[], const char name[], PetscInt *n_max_p, PetscViewer viewer[], PetscViewerFormat format[], PetscBool *set, const char func_name[], PetscBool allow_multiple)
287 {
288   const char *value;
289   PetscBool   flag, hashelp;
290   PetscInt    n_max;
291 
292   PetscFunctionBegin;
293   PetscAssertPointer(name, 4);
294   PetscAssertPointer(n_max_p, 5);
295   n_max = *n_max_p;
296   PetscCheck(n_max >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid size %" PetscInt_FMT " of passed arrays", *n_max_p);
297   *n_max_p = 0;
298 
299   if (set) *set = PETSC_FALSE;
300   PetscCall(PetscOptionsGetViewerOff(&flag));
301   if (flag) PetscFunctionReturn(PETSC_SUCCESS);
302 
303   PetscCall(PetscOptionsHasHelp(NULL, &hashelp));
304   if (hashelp) {
305     PetscBool found;
306 
307     if (!PetscOptionsHelpPrintedSingleton) PetscCall(PetscOptionsHelpPrintedCreate(&PetscOptionsHelpPrintedSingleton));
308     PetscCall(PetscOptionsHelpPrintedCheck(PetscOptionsHelpPrintedSingleton, pre, name, &found));
309     if (!found && viewer) {
310       PetscCall((*PetscHelpPrintf)(comm, "----------------------------------------\nViewer (-%s%s) options:\n", pre ? pre : "", name + 1));
311       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s ascii[:[filename][:[format][:append]]]: %s (%s)\n", pre ? pre : "", name + 1, "Prints object to stdout or ASCII file", func_name));
312       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s binary[:[filename][:[format][:append]]]: %s (%s)\n", pre ? pre : "", name + 1, "Saves object to a binary file", func_name));
313       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s draw[:[drawtype][:filename|format]] %s (%s)\n", pre ? pre : "", name + 1, "Draws object", func_name));
314       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s socket[:port]: %s (%s)\n", pre ? pre : "", name + 1, "Pushes object to a Unix socket", func_name));
315       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s saws[:communicatorname]: %s (%s)\n", pre ? pre : "", name + 1, "Publishes object to SAWs", func_name));
316       if (allow_multiple) PetscCall((*PetscHelpPrintf)(comm, "  -%s%s v1[,v2,...]: %s (%s)\n", pre ? pre : "", name + 1, "Multiple viewers", func_name));
317     }
318   }
319 
320   PetscCall(PetscOptionsFindPair(options, pre, name, &value, &flag));
321   if (flag) {
322     if (set) *set = PETSC_TRUE;
323     if (!value) {
324       PetscCheck(n_max > 0, comm, PETSC_ERR_ARG_SIZ, "More viewers (1) than max available (0)");
325       if (format) *format = PETSC_VIEWER_DEFAULT;
326       if (viewer) PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
327       *n_max_p = 1;
328     } else {
329       char  *loc0_viewer_string = NULL, *this_viewer_string = NULL;
330       size_t viewer_string_length;
331 
332       PetscCall(PetscStrallocpy(value, &loc0_viewer_string));
333       PetscCall(PetscStrlen(loc0_viewer_string, &viewer_string_length));
334       this_viewer_string = loc0_viewer_string;
335 
336       do {
337         PetscViewer       *this_viewer;
338         PetscViewerFormat *this_viewer_format;
339         char              *next_viewer_string = NULL;
340         char              *comma_separator    = NULL;
341         PetscInt           n                  = *n_max_p;
342 
343         PetscCheck(n < n_max, comm, PETSC_ERR_PLIB, "More viewers than max available (%d)", (int)n_max);
344 
345         PetscCall(PetscStrchr(this_viewer_string, ',', &comma_separator));
346         if (comma_separator) {
347           PetscCheck(allow_multiple, comm, PETSC_ERR_ARG_OUTOFRANGE, "Trying to pass multiple viewers to %s: only one allowed.  Use PetscOptionsGetViewers() instead", func_name);
348           *comma_separator   = 0;
349           next_viewer_string = comma_separator + 1;
350         }
351         this_viewer = PetscSafePointerPlusOffset(viewer, n);
352         if (this_viewer) *this_viewer = NULL;
353         this_viewer_format = PetscSafePointerPlusOffset(format, n);
354         if (this_viewer_format) *this_viewer_format = PETSC_VIEWER_DEFAULT;
355         PetscCall(PetscOptionsGetViewers_Single(comm, this_viewer_string, this_viewer, this_viewer_format));
356         this_viewer_string = next_viewer_string;
357         (*n_max_p)++;
358       } while (this_viewer_string);
359       PetscCall(PetscFree(loc0_viewer_string));
360     }
361   }
362   PetscFunctionReturn(PETSC_SUCCESS);
363 }
364 
365 /*@C
366   PetscOptionsGetViewer - Gets a viewer appropriate for the type indicated by the user
367 
368   Collective
369 
370   Input Parameters:
371 + comm    - the communicator to own the viewer
372 . options - options database, use `NULL` for default global database
373 . pre     - the string to prepend to the name or `NULL`
374 - name    - the options database name that will be checked for
375 
376   Output Parameters:
377 + viewer - the viewer, pass `NULL` if not needed
378 . format - the `PetscViewerFormat` requested by the user, pass `NULL` if not needed
379 - set    - `PETSC_TRUE` if found, else `PETSC_FALSE`
380 
381   Level: intermediate
382 
383   Notes:
384   The argument has the following form
385 .vb
386     type:filename:format:filemode
387 .ve
388   where all parts are optional, but you need to include the colon to access the next part. The mode argument must a valid `PetscFileMode`, i.e. read, write, append, update, or append_update. For example, to read from an HDF5 file, use
389 .vb
390     hdf5:sol.h5::read
391 .ve
392 
393   If no value is provided ascii:stdout is used
394 +       ascii[:[filename][:[format][:append]]]  -  defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
395   for example ascii::ascii_info prints just the information about the object not all details
396   unless :append is given filename opens in write mode, overwriting what was already there
397 .       binary[:[filename][:[format][:append]]] -  defaults to the file binaryoutput
398 .       draw[:drawtype[:filename]]              -  for example, draw:tikz, draw:tikz:figure.tex  or draw:x
399 .       socket[:port]                           -  defaults to the standard output port
400 -       saws[:communicatorname]                 -   publishes object to the Scientific Application Webserver (SAWs)
401 
402   Use `PetscOptionsRestoreViewer()` after using the viewer, do not use `PetscViewerDestroy()`
403 
404   You can control whether calls to this function create a viewer (or return early with *set of `PETSC_FALSE`) with
405   `PetscOptionsPushGetViewerOff()`.  This is useful if calling many small subsolves, in which case XXXViewFromOptions can take
406   an appreciable fraction of the runtime.
407 
408   If PETSc is configured with `--with-viewfromoptions=0` this function always returns with *set of `PETSC_FALSE`
409 
410   This routine is thread-safe for accessing predefined `PetscViewer`s like `PETSC_VIEWER_STDOUT_SELF` but not for accessing
411   files by name.
412 
413 .seealso: [](sec_viewers), `PetscOptionsRestoreViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
414           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
415           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
416           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
417           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
418           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
419           `PetscOptionsFList()`, `PetscOptionsEList()`, `PetscOptionsPushGetViewerOff()`, `PetscOptionsPopGetViewerOff()`,
420           `PetscOptionsGetViewerOff()`
421 @*/
422 PetscErrorCode PetscOptionsGetViewer(MPI_Comm comm, PetscOptions options, const char pre[], const char name[], PetscViewer *viewer, PetscViewerFormat *format, PetscBool *set)
423 {
424   PetscInt  n_max = 1;
425   PetscBool set_internal;
426 
427   PetscFunctionBegin;
428   if (viewer) *viewer = NULL;
429   if (format) *format = PETSC_VIEWER_DEFAULT;
430   PetscCall(PetscOptionsGetViewers_Internal(comm, options, pre, name, &n_max, viewer, format, &set_internal, PETSC_FUNCTION_NAME, PETSC_FALSE));
431   if (set_internal) PetscAssert(n_max == 1, comm, PETSC_ERR_PLIB, "Unexpected: %d != 1 viewers set", (int)n_max);
432   if (set) *set = set_internal;
433   PetscFunctionReturn(PETSC_SUCCESS);
434 }
435 
436 /*@C
437   PetscOptionsRestoreViewer - restore a `PetscViewer` obtained from `PetscOptionsGetViewer()` or `PetscOptionsGetViewers()`
438 
439   Collective
440 
441   Input Parameter:
442 . viewer - the viewer
443 
444   Level: intermediate
445 
446   Developer Note:
447   This function exists to handle persistent viewers such as `PETSC_VIEWER_STDOUT_SELF` that may be shared between threads where
448   changing the reference count would not be thread safe.
449 
450 .seealso: [](sec_viewers), `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
451           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
452           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
453           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
454           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
455           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
456           `PetscOptionsFList()`, `PetscOptionsEList()`, `PetscOptionsPushGetViewerOff()`, `PetscOptionsPopGetViewerOff()`,
457           `PetscOptionsGetViewerOff()`
458 @*/
459 PetscErrorCode PetscOptionsRestoreViewer(PetscViewer *viewer)
460 {
461   PetscFunctionBegin;
462   if (!*viewer) PetscFunctionReturn(PETSC_SUCCESS);
463   if (!((PetscObject)*viewer)->persistent) PetscCall(PetscViewerDestroy(viewer));
464   else *viewer = NULL;
465   PetscFunctionReturn(PETSC_SUCCESS);
466 }
467 
468 /*@C
469   PetscOptionsGetViewers - Get multiple viewers from a comma-separated list in the options database
470 
471   Collective
472 
473   Input Parameters:
474 + comm    - the communicator to own the viewers
475 . options - options database, use `NULL` for default global database
476 . pre     - the string to prepend to the name or `NULL`
477 . name    - the options database name that will be checked for
478 - n_max   - on input: the maximum number of viewers; on output: the number of viewers in the comma-separated list
479 
480   Output Parameters:
481 + viewers - an array to hold at least `n_max` `PetscViewer`s, or `NULL` if not needed; on output: if not `NULL`, the
482              first `n_max` entries are initialized `PetscViewer`s
483 . formats - an array to hold at least `n_max` `PetscViewerFormat`s, or `NULL` if not needed; on output: if not
484              `NULL`, the first `n_max` entries are valid `PetscViewewFormat`s
485 - set     - `PETSC_TRUE` if found, else `PETSC_FALSE`
486 
487   Level: intermediate
488 
489   Note:
490   See `PetscOptionsGetViewer()` for how the format strings for the viewers are interpreted.  Use `PetscOptionsRestoreViewer()` on each viewer, otherwise a memory leak will occur.
491 
492   If PETSc is configured with `--with-viewfromoptions=0` this function always returns with `n_max` of 0 and `set` of `PETSC_FALSE`
493 
494 .seealso: [](sec_viewers), `PetscOptionsGetViewer()`
495 @*/
496 PetscErrorCode PetscOptionsGetViewers(MPI_Comm comm, PetscOptions options, const char pre[], const char name[], PetscInt *n_max, PetscViewer viewers[], PetscViewerFormat formats[], PetscBool *set)
497 {
498   PetscFunctionBegin;
499   PetscCall(PetscOptionsGetViewers_Internal(comm, options, pre, name, n_max, viewers, formats, set, PETSC_FUNCTION_NAME, PETSC_TRUE));
500   PetscFunctionReturn(PETSC_SUCCESS);
501 }
502 
503 /*@
504   PetscViewerCreate - Creates a viewing context. A `PetscViewer` represents a file, a graphical window, a Unix socket or a variety of other ways
505   of viewing a PETSc object
506 
507   Collective
508 
509   Input Parameter:
510 . comm - MPI communicator
511 
512   Output Parameter:
513 . inviewer - location to put the `PetscViewer` context
514 
515   Level: advanced
516 
517 .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerType`
518 @*/
519 PetscErrorCode PetscViewerCreate(MPI_Comm comm, PetscViewer *inviewer)
520 {
521   PetscViewer viewer;
522 
523   PetscFunctionBegin;
524   *inviewer = NULL;
525   PetscCall(PetscViewerInitializePackage());
526   PetscCall(PetscHeaderCreate(viewer, PETSC_VIEWER_CLASSID, "PetscViewer", "PetscViewer", "Viewer", comm, PetscViewerDestroy, PetscViewerView));
527   *inviewer    = viewer;
528   viewer->data = NULL;
529   PetscFunctionReturn(PETSC_SUCCESS);
530 }
531 
532 /*@C
533   PetscViewerSetType - Builds `PetscViewer` for a particular implementation.
534 
535   Collective
536 
537   Input Parameters:
538 + viewer - the `PetscViewer` context obtained with `PetscViewerCreate()`
539 - type   - for example, `PETSCVIEWERASCII`
540 
541   Options Database Key:
542 . -viewer_type  <type> - Sets the type; use -help for a list of available methods (for instance, ascii)
543 
544   Level: advanced
545 
546   Note:
547   See `PetscViewerType` for possible values
548 
549 .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerCreate()`, `PetscViewerGetType()`, `PetscViewerType`, `PetscViewerPushFormat()`
550 @*/
551 PetscErrorCode PetscViewerSetType(PetscViewer viewer, PetscViewerType type)
552 {
553   PetscBool match;
554   PetscErrorCode (*r)(PetscViewer);
555 
556   PetscFunctionBegin;
557   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
558   PetscAssertPointer(type, 2);
559   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, type, &match));
560   if (match) PetscFunctionReturn(PETSC_SUCCESS);
561 
562   /* cleanup any old type that may be there */
563   PetscTryTypeMethod(viewer, destroy);
564   viewer->ops->destroy = NULL;
565   viewer->data         = NULL;
566 
567   PetscCall(PetscMemzero(viewer->ops, sizeof(struct _PetscViewerOps)));
568 
569   PetscCall(PetscFunctionListFind(PetscViewerList, type, &r));
570   PetscCheck(r, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscViewer type given: %s", type);
571 
572   PetscCall(PetscObjectChangeTypeName((PetscObject)viewer, type));
573   PetscCall((*r)(viewer));
574   PetscFunctionReturn(PETSC_SUCCESS);
575 }
576 
577 /*@C
578   PetscViewerRegister - Adds a viewer to those available for use with `PetscViewerSetType()`
579 
580   Not Collective
581 
582   Input Parameters:
583 + sname    - name of a new user-defined viewer
584 - function - routine to create method context
585 
586   Level: developer
587 
588   Note:
589   `PetscViewerRegister()` may be called multiple times to add several user-defined viewers.
590 
591   Example Usage:
592 .vb
593    PetscViewerRegister("my_viewer_type", MyViewerCreate);
594 .ve
595 
596   Then, your solver can be chosen with the procedural interface via
597 $     PetscViewerSetType(viewer, "my_viewer_type")
598   or at runtime via the option
599 $     -viewer_type my_viewer_type
600 
601 .seealso: [](sec_viewers), `PetscViewerRegisterAll()`
602  @*/
603 PetscErrorCode PetscViewerRegister(const char *sname, PetscErrorCode (*function)(PetscViewer))
604 {
605   PetscFunctionBegin;
606   PetscCall(PetscViewerInitializePackage());
607   PetscCall(PetscFunctionListAdd(&PetscViewerList, sname, function));
608   PetscFunctionReturn(PETSC_SUCCESS);
609 }
610 
611 /*@C
612   PetscViewerSetFromOptions - Sets various options for a viewer based on values in the options database.
613 
614   Collective
615 
616   Input Parameter:
617 . viewer - the viewer context
618 
619   Level: intermediate
620 
621   Note:
622   Must be called after `PetscViewerCreate()` but before the `PetscViewer` is used.
623 
624 .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerType`
625 @*/
626 PetscErrorCode PetscViewerSetFromOptions(PetscViewer viewer)
627 {
628   char      vtype[256];
629   PetscBool flg;
630 
631   PetscFunctionBegin;
632   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
633 
634   if (!PetscViewerList) PetscCall(PetscViewerRegisterAll());
635   PetscObjectOptionsBegin((PetscObject)viewer);
636   PetscCall(PetscOptionsFList("-viewer_type", "Type of PetscViewer", "None", PetscViewerList, (char *)(((PetscObject)viewer)->type_name ? ((PetscObject)viewer)->type_name : PETSCVIEWERASCII), vtype, 256, &flg));
637   if (flg) PetscCall(PetscViewerSetType(viewer, vtype));
638   /* type has not been set? */
639   if (!((PetscObject)viewer)->type_name) PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII));
640   PetscTryTypeMethod(viewer, setfromoptions, PetscOptionsObject);
641 
642   /* process any options handlers added with PetscObjectAddOptionsHandler() */
643   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)viewer, PetscOptionsObject));
644   PetscCall(PetscViewerViewFromOptions(viewer, NULL, "-viewer_view"));
645   PetscOptionsEnd();
646   PetscFunctionReturn(PETSC_SUCCESS);
647 }
648 
649 PetscErrorCode PetscViewerFlowControlStart(PetscViewer viewer, PetscInt *mcnt, PetscInt *cnt)
650 {
651   PetscFunctionBegin;
652   PetscCall(PetscViewerBinaryGetFlowControl(viewer, mcnt));
653   PetscCall(PetscViewerBinaryGetFlowControl(viewer, cnt));
654   PetscFunctionReturn(PETSC_SUCCESS);
655 }
656 
657 PetscErrorCode PetscViewerFlowControlStepMain(PetscViewer viewer, PetscInt i, PetscInt *mcnt, PetscInt cnt)
658 {
659   MPI_Comm comm;
660 
661   PetscFunctionBegin;
662   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
663   if (i >= *mcnt) {
664     *mcnt += cnt;
665     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
666   }
667   PetscFunctionReturn(PETSC_SUCCESS);
668 }
669 
670 PetscErrorCode PetscViewerFlowControlEndMain(PetscViewer viewer, PetscInt *mcnt)
671 {
672   MPI_Comm comm;
673 
674   PetscFunctionBegin;
675   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
676   *mcnt = 0;
677   PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
678   PetscFunctionReturn(PETSC_SUCCESS);
679 }
680 
681 PetscErrorCode PetscViewerFlowControlStepWorker(PetscViewer viewer, PetscMPIInt rank, PetscInt *mcnt)
682 {
683   MPI_Comm comm;
684 
685   PetscFunctionBegin;
686   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
687   while (PETSC_TRUE) {
688     if (rank < *mcnt) break;
689     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
690   }
691   PetscFunctionReturn(PETSC_SUCCESS);
692 }
693 
694 PetscErrorCode PetscViewerFlowControlEndWorker(PetscViewer viewer, PetscInt *mcnt)
695 {
696   MPI_Comm comm;
697 
698   PetscFunctionBegin;
699   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
700   while (PETSC_TRUE) {
701     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
702     if (!*mcnt) break;
703   }
704   PetscFunctionReturn(PETSC_SUCCESS);
705 }
706