xref: /petsc/src/sys/classes/viewer/interface/viewreg.c (revision 0ea77eda237b1068ff0d8bfa28c3463dc2087695)
1 
2 #include <petsc/private/viewerimpl.h> /*I "petscviewer.h" I*/
3 #include <petsc/private/hashtable.h>
4 #if defined(PETSC_HAVE_SAWS)
5 #include <petscviewersaws.h>
6 #endif
7 
8 PetscFunctionList PetscViewerList = NULL;
9 
10 PetscOptionsHelpPrinted PetscOptionsHelpPrintedSingleton = NULL;
11 KHASH_SET_INIT_STR(HTPrinted)
12 struct _n_PetscOptionsHelpPrinted {
13   khash_t(HTPrinted) * printed;
14   PetscSegBuffer strings;
15 };
16 
17 PetscErrorCode PetscOptionsHelpPrintedDestroy(PetscOptionsHelpPrinted *hp) {
18   PetscFunctionBegin;
19   if (!*hp) PetscFunctionReturn(0);
20   kh_destroy(HTPrinted, (*hp)->printed);
21   PetscCall(PetscSegBufferDestroy(&(*hp)->strings));
22   PetscCall(PetscFree(*hp));
23   PetscFunctionReturn(0);
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      Not collective
31 
32     Level: developer
33 
34 .seealso: `PetscOptionsHelpPrintedCheck()`, `PetscOptionsHelpPrintChecked()`
35 @*/
36 PetscErrorCode PetscOptionsHelpPrintedCreate(PetscOptionsHelpPrinted *hp) {
37   PetscFunctionBegin;
38   PetscCall(PetscNew(hp));
39   (*hp)->printed = kh_init(HTPrinted);
40   PetscCall(PetscSegBufferCreate(sizeof(char), 10000, &(*hp)->strings));
41   PetscFunctionReturn(0);
42 }
43 
44 /*@C
45       PetscOptionsHelpPrintedCheck - Checks if a particular pre, name pair has previous been entered (meaning the help message was printed)
46 
47      Not collective
48 
49     Input Parameters:
50 +     hp - the object used to manage tracking what help messages have been printed
51 .     pre - the prefix part of the string, many be NULL
52 -     name - the string to look for (cannot be NULL)
53 
54     Output Parameter:
55 .     found - PETSC_TRUE if the string was already set
56 
57     Level: intermediate
58 
59 .seealso: `PetscOptionsHelpPrintedCreate()`
60 @*/
61 PetscErrorCode PetscOptionsHelpPrintedCheck(PetscOptionsHelpPrinted hp, const char *pre, const char *name, PetscBool *found) {
62   size_t l1, l2;
63 #if !defined(PETSC_HAVE_THREADSAFETY)
64   char *both;
65   int   newitem;
66 #endif
67 
68   PetscFunctionBegin;
69   PetscCall(PetscStrlen(pre, &l1));
70   PetscCall(PetscStrlen(name, &l2));
71   if (l1 + l2 == 0) {
72     *found = PETSC_FALSE;
73     PetscFunctionReturn(0);
74   }
75 #if !defined(PETSC_HAVE_THREADSAFETY)
76   PetscCall(PetscSegBufferGet(hp->strings, l1 + l2 + 1, &both));
77   PetscCall(PetscStrcpy(both, pre));
78   PetscCall(PetscStrcat(both, name));
79   kh_put(HTPrinted, hp->printed, both, &newitem);
80   if (!newitem) PetscCall(PetscSegBufferUnuse(hp->strings, l1 + l2 + 1));
81   *found = newitem ? PETSC_FALSE : PETSC_TRUE;
82 #else
83   *found = PETSC_FALSE;
84 #endif
85   PetscFunctionReturn(0);
86 }
87 
88 static PetscBool noviewer = PETSC_FALSE;
89 static PetscBool noviewers[PETSCVIEWERGETVIEWEROFFPUSHESMAX];
90 static PetscInt  inoviewers = 0;
91 
92 /*@
93   PetscOptionsPushGetViewerOff - sets if a `PetscOptionsGetViewer()` returns a viewer.
94 
95   Logically Collective
96 
97   Input Parameter:
98 . flg - `PETSC_TRUE` to turn off viewer creation, `PETSC_FALSE` to turn it on.
99 
100   Level: developer
101 
102   Note:
103     Calling XXXViewFromOptions in an inner loop can be very expensive.  This can appear, for example, when using
104    many small subsolves.  Call this function to control viewer creation in `PetscOptionsGetViewer()`, thus removing the expensive XXXViewFromOptions calls.
105 
106 .seealso: `PetscOptionsGetViewer()`, `PetscOptionsPopGetViewerOff()`
107 @*/
108 PetscErrorCode PetscOptionsPushGetViewerOff(PetscBool flg) {
109   PetscFunctionBegin;
110   PetscCheck(inoviewers < PETSCVIEWERGETVIEWEROFFPUSHESMAX, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many PetscOptionsPushGetViewerOff(), perhaps you forgot PetscOptionsPopGetViewerOff()?");
111 
112   noviewers[inoviewers++] = noviewer;
113   noviewer                = flg;
114   PetscFunctionReturn(0);
115 }
116 
117 /*@
118   PetscOptionsPopGetViewerOff - reset whether `PetscOptionsGetViewer()` returns a viewer.
119 
120   Logically Collective
121 
122   Level: developer
123 
124   Note:
125     Calling XXXViewFromOptions in an inner loop can be very expensive.  This can appear, for example, when using
126    many small subsolves.  Call this function to control viewer creation in `PetscOptionsGetViewer()`, thus removing the expensive XXXViewFromOptions calls.
127 
128 .seealso: `PetscOptionsGetViewer()`, `PetscOptionsPushGetViewerOff()`
129 @*/
130 PetscErrorCode PetscOptionsPopGetViewerOff(void) {
131   PetscFunctionBegin;
132   PetscCheck(inoviewers, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many PetscOptionsPopGetViewerOff(), perhaps you forgot PetscOptionsPushGetViewerOff()?");
133   noviewer = noviewers[--inoviewers];
134   PetscFunctionReturn(0);
135 }
136 
137 /*@
138   PetscOptionsGetViewerOff - does `PetscOptionsGetViewer()` return a viewer?
139 
140   Logically Collective
141 
142   Output Parameter:
143 . flg - whether viewers are returned.
144 
145   Level: developer
146 
147   Note:
148     Calling XXXViewFromOptions in an inner loop can be very expensive.  This can appear, for example, when using
149    many small subsolves.
150 
151 .seealso: `PetscOptionsGetViewer()`, `PetscOptionsPushGetViewerOff()`, `PetscOptionsPopGetViewerOff()`
152 @*/
153 PetscErrorCode PetscOptionsGetViewerOff(PetscBool *flg) {
154   PetscFunctionBegin;
155   PetscValidBoolPointer(flg, 1);
156   *flg = noviewer;
157   PetscFunctionReturn(0);
158 }
159 
160 /*@C
161    PetscOptionsGetViewer - Gets a viewer appropriate for the type indicated by the user
162 
163    Collective
164 
165    Input Parameters:
166 +  comm - the communicator to own the viewer
167 .  options - options database, use NULL for default global database
168 .  pre - the string to prepend to the name or NULL
169 -  name - the option one is seeking
170 
171    Output Parameters:
172 +  viewer - the viewer, pass NULL if not needed
173 .  format - the `PetscViewerFormat` requested by the user, pass NULL if not needed
174 -  set - `PETSC_TRUE` if found, else `PETSC_FALSE`
175 
176    Level: intermediate
177 
178    Notes:
179     If no value is provided ascii:stdout is used
180 +       ascii[:[filename][:[format][:append]]]  -  defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
181                                                   for example ascii::ascii_info prints just the information about the object not all details
182                                                   unless :append is given filename opens in write mode, overwriting what was already there
183 .       binary[:[filename][:[format][:append]]] -  defaults to the file binaryoutput
184 .       draw[:drawtype[:filename]]              -  for example, draw:tikz, draw:tikz:figure.tex  or draw:x
185 .       socket[:port]                           -  defaults to the standard output port
186 -       saws[:communicatorname]                 -   publishes object to the Scientific Application Webserver (SAWs)
187 
188    Use `PetscViewerDestroy()` after using the viewer, otherwise a memory leak will occur
189 
190    You can control whether calls to this function create a viewer (or return early with *set of `PETSC_FALSE`) with
191    `PetscOptionsPushGetViewerOff()`.  This is useful if calling many small subsolves, in which case XXXViewFromOptions can take
192    an appreciable fraction of the runtime.
193 
194    If PETSc is configured with --with-viewfromoptions=0 this function always returns with *set of `PETSC_FALSE`
195 
196 .seealso: `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
197           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
198           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
199           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
200           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
201           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
202           `PetscOptionsFList()`, `PetscOptionsEList()`, `PetscOptionsPushGetViewerOff()`, `PetscOptionsPopGetViewerOff()`,
203           `PetscOptionsGetViewerOff()`
204 @*/
205 PetscErrorCode PetscOptionsGetViewer(MPI_Comm comm, PetscOptions options, const char pre[], const char name[], PetscViewer *viewer, PetscViewerFormat *format, PetscBool *set) {
206   const char *value;
207   PetscBool   flag, hashelp;
208 
209   PetscFunctionBegin;
210   PetscValidCharPointer(name, 4);
211 
212   if (viewer) *viewer = NULL;
213   if (format) *format = PETSC_VIEWER_DEFAULT;
214   if (set) *set = PETSC_FALSE;
215   PetscCall(PetscOptionsGetViewerOff(&flag));
216   if (flag) PetscFunctionReturn(0);
217 
218   PetscCall(PetscOptionsHasHelp(NULL, &hashelp));
219   if (hashelp) {
220     PetscBool found;
221 
222     if (!PetscOptionsHelpPrintedSingleton) PetscCall(PetscOptionsHelpPrintedCreate(&PetscOptionsHelpPrintedSingleton));
223     PetscCall(PetscOptionsHelpPrintedCheck(PetscOptionsHelpPrintedSingleton, pre, name, &found));
224     if (!found && viewer) {
225       PetscCall((*PetscHelpPrintf)(comm, "----------------------------------------\nViewer (-%s%s) options:\n", pre ? pre : "", name + 1));
226       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s ascii[:[filename][:[format][:append]]]: %s (%s)\n", pre ? pre : "", name + 1, "Prints object to stdout or ASCII file", "PetscOptionsGetViewer"));
227       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s binary[:[filename][:[format][:append]]]: %s (%s)\n", pre ? pre : "", name + 1, "Saves object to a binary file", "PetscOptionsGetViewer"));
228       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s draw[:[drawtype][:filename|format]] %s (%s)\n", pre ? pre : "", name + 1, "Draws object", "PetscOptionsGetViewer"));
229       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s socket[:port]: %s (%s)\n", pre ? pre : "", name + 1, "Pushes object to a Unix socket", "PetscOptionsGetViewer"));
230       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s saws[:communicatorname]: %s (%s)\n", pre ? pre : "", name + 1, "Publishes object to SAWs", "PetscOptionsGetViewer"));
231     }
232   }
233 
234   if (format) *format = PETSC_VIEWER_DEFAULT;
235   PetscCall(PetscOptionsFindPair(options, pre, name, &value, &flag));
236   if (flag) {
237     if (set) *set = PETSC_TRUE;
238     if (!value) {
239       if (viewer) {
240         PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
241         PetscCall(PetscObjectReference((PetscObject)*viewer));
242       }
243     } else {
244       char       *loc0_vtype, *loc1_fname, *loc2_fmt = NULL, *loc3_fmode = NULL;
245       PetscInt    cnt;
246       const char *viewers[] = {PETSCVIEWERASCII, PETSCVIEWERBINARY, PETSCVIEWERDRAW, PETSCVIEWERSOCKET, PETSCVIEWERMATLAB, PETSCVIEWERSAWS, PETSCVIEWERVTK, PETSCVIEWERHDF5, PETSCVIEWERGLVIS, PETSCVIEWEREXODUSII, NULL};
247 
248       PetscCall(PetscStrallocpy(value, &loc0_vtype));
249       PetscCall(PetscStrchr(loc0_vtype, ':', &loc1_fname));
250       if (loc1_fname) {
251         *loc1_fname++ = 0;
252         PetscCall(PetscStrchr(loc1_fname, ':', &loc2_fmt));
253       }
254       if (loc2_fmt) {
255         *loc2_fmt++ = 0;
256         PetscCall(PetscStrchr(loc2_fmt, ':', &loc3_fmode));
257       }
258       if (loc3_fmode) *loc3_fmode++ = 0;
259       PetscCall(PetscStrendswithwhich(*loc0_vtype ? loc0_vtype : "ascii", viewers, &cnt));
260       PetscCheck(cnt <= (PetscInt)sizeof(viewers) - 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "Unknown viewer type: %s", loc0_vtype);
261       if (viewer) {
262         if (!loc1_fname) {
263           switch (cnt) {
264           case 0: PetscCall(PetscViewerASCIIGetStdout(comm, viewer)); break;
265           case 1:
266             if (!(*viewer = PETSC_VIEWER_BINARY_(comm))) PetscCall(PETSC_ERR_PLIB);
267             break;
268           case 2:
269             if (!(*viewer = PETSC_VIEWER_DRAW_(comm))) PetscCall(PETSC_ERR_PLIB);
270             break;
271 #if defined(PETSC_USE_SOCKET_VIEWER)
272           case 3:
273             if (!(*viewer = PETSC_VIEWER_SOCKET_(comm))) PetscCall(PETSC_ERR_PLIB);
274             break;
275 #endif
276 #if defined(PETSC_HAVE_MATLAB_ENGINE)
277           case 4:
278             if (!(*viewer = PETSC_VIEWER_MATLAB_(comm))) PetscCall(PETSC_ERR_PLIB);
279             break;
280 #endif
281 #if defined(PETSC_HAVE_SAWS)
282           case 5:
283             if (!(*viewer = PETSC_VIEWER_SAWS_(comm))) PetscCall(PETSC_ERR_PLIB);
284             break;
285 #endif
286 #if defined(PETSC_HAVE_HDF5)
287           case 7:
288             if (!(*viewer = PETSC_VIEWER_HDF5_(comm))) PetscCall(PETSC_ERR_PLIB);
289             break;
290 #endif
291           case 8:
292             if (!(*viewer = PETSC_VIEWER_GLVIS_(comm))) PetscCall(PETSC_ERR_PLIB);
293             break;
294 #if defined(PETSC_HAVE_EXODUSII)
295           case 9:
296             if (!(*viewer = PETSC_VIEWER_EXODUSII_(comm))) PetscCall(PETSC_ERR_PLIB);
297             break;
298 #endif
299           default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported viewer %s", loc0_vtype);
300           }
301           PetscCall(PetscObjectReference((PetscObject)*viewer));
302         } else {
303           if (loc2_fmt && !*loc1_fname && (cnt == 0)) { /* ASCII format without file name */
304             PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
305             PetscCall(PetscObjectReference((PetscObject)*viewer));
306           } else {
307             PetscFileMode fmode;
308             PetscCall(PetscViewerCreate(comm, viewer));
309             PetscCall(PetscViewerSetType(*viewer, *loc0_vtype ? loc0_vtype : "ascii"));
310             fmode = FILE_MODE_WRITE;
311             if (loc3_fmode && *loc3_fmode) { /* Has non-empty file mode ("write" or "append") */
312               PetscCall(PetscEnumFind(PetscFileModes, loc3_fmode, (PetscEnum *)&fmode, &flag));
313               PetscCheck(flag, comm, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown file mode: %s", loc3_fmode);
314             }
315             if (loc2_fmt) {
316               PetscBool tk, im;
317               PetscCall(PetscStrcmp(loc1_fname, "tikz", &tk));
318               PetscCall(PetscStrcmp(loc1_fname, "image", &im));
319               if (tk || im) {
320                 PetscCall(PetscViewerDrawSetInfo(*viewer, NULL, loc2_fmt, PETSC_DECIDE, PETSC_DECIDE, PETSC_DECIDE, PETSC_DECIDE));
321                 *loc2_fmt = 0;
322               }
323             }
324             PetscCall(PetscViewerFileSetMode(*viewer, flag ? fmode : FILE_MODE_WRITE));
325             PetscCall(PetscViewerFileSetName(*viewer, loc1_fname));
326             if (*loc1_fname) PetscCall(PetscViewerDrawSetDrawType(*viewer, loc1_fname));
327             PetscCall(PetscViewerSetFromOptions(*viewer));
328           }
329         }
330       }
331       if (viewer) PetscCall(PetscViewerSetUp(*viewer));
332       if (loc2_fmt && *loc2_fmt) {
333         PetscViewerFormat tfmt;
334 
335         PetscCall(PetscEnumFind(PetscViewerFormats, loc2_fmt, (PetscEnum *)&tfmt, &flag));
336         if (format) *format = tfmt;
337         PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown viewer format %s", loc2_fmt);
338       } else if (viewer && (cnt == 6) && format) { /* Get format from VTK viewer */
339         PetscCall(PetscViewerGetFormat(*viewer, format));
340       }
341       PetscCall(PetscFree(loc0_vtype));
342     }
343   }
344   PetscFunctionReturn(0);
345 }
346 
347 /*@
348    PetscViewerCreate - Creates a viewing context. A `PetscViewer` represents a file, a graphical window, a Unix socket or a variety of other ways of viewing a PETSc object
349 
350    Collective
351 
352    Input Parameter:
353 .  comm - MPI communicator
354 
355    Output Parameter:
356 .  inviewer - location to put the `PetscViewer` context
357 
358    Level: advanced
359 
360 .seealso: `PetscViewer`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerType`
361 @*/
362 PetscErrorCode PetscViewerCreate(MPI_Comm comm, PetscViewer *inviewer) {
363   PetscViewer viewer;
364 
365   PetscFunctionBegin;
366   *inviewer = NULL;
367   PetscCall(PetscViewerInitializePackage());
368   PetscCall(PetscHeaderCreate(viewer, PETSC_VIEWER_CLASSID, "PetscViewer", "PetscViewer", "Viewer", comm, PetscViewerDestroy, PetscViewerView));
369   *inviewer    = viewer;
370   viewer->data = NULL;
371   PetscFunctionReturn(0);
372 }
373 
374 /*@C
375    PetscViewerSetType - Builds `PetscViewer` for a particular implementation.
376 
377    Collective on viewer
378 
379    Input Parameters:
380 +  viewer      - the `PetscViewer` context obtained with `PetscViewerCreate()`
381 -  type        - for example, `PETSCVIEWERASCII`
382 
383    Options Database Command:
384 .  -viewer_type  <type> - Sets the type; use -help for a list
385     of available methods (for instance, ascii)
386 
387    Level: advanced
388 
389    Note:
390    See "include/petscviewer.h" for available methods (for instance,
391    `PETSCVIEWERSOCKET`)
392 
393 .seealso: `PetscViewer`, `PetscViewerCreate()`, `PetscViewerGetType()`, `PetscViewerType`, `PetscViewerPushFormat()`
394 @*/
395 PetscErrorCode PetscViewerSetType(PetscViewer viewer, PetscViewerType type) {
396   PetscBool match;
397   PetscErrorCode (*r)(PetscViewer);
398 
399   PetscFunctionBegin;
400   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
401   PetscValidCharPointer(type, 2);
402   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, type, &match));
403   if (match) PetscFunctionReturn(0);
404 
405   /* cleanup any old type that may be there */
406   PetscTryTypeMethod(viewer, destroy);
407   viewer->ops->destroy = NULL;
408   viewer->data         = NULL;
409 
410   PetscCall(PetscMemzero(viewer->ops, sizeof(struct _PetscViewerOps)));
411 
412   PetscCall(PetscFunctionListFind(PetscViewerList, type, &r));
413   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscViewer type given: %s", type);
414 
415   PetscCall(PetscObjectChangeTypeName((PetscObject)viewer, type));
416   PetscCall((*r)(viewer));
417   PetscFunctionReturn(0);
418 }
419 
420 /*@C
421    PetscViewerRegister - Adds a viewer to those available for use
422 
423    Not Collective
424 
425    Input Parameters:
426 +  name_solver - name of a new user-defined viewer
427 -  routine_create - routine to create method context
428 
429    Level: developer
430 
431    Note:
432    `PetscViewerRegister()` may be called multiple times to add several user-defined viewers.
433 
434    Sample usage:
435 .vb
436    PetscViewerRegister("my_viewer_type",MyViewerCreate);
437 .ve
438 
439    Then, your solver can be chosen with the procedural interface via
440 $     PetscViewerSetType(viewer,"my_viewer_type")
441    or at runtime via the option
442 $     -viewer_type my_viewer_type
443 
444 .seealso: `PetscViewerRegisterAll()`
445  @*/
446 PetscErrorCode PetscViewerRegister(const char *sname, PetscErrorCode (*function)(PetscViewer)) {
447   PetscFunctionBegin;
448   PetscCall(PetscViewerInitializePackage());
449   PetscCall(PetscFunctionListAdd(&PetscViewerList, sname, function));
450   PetscFunctionReturn(0);
451 }
452 
453 /*@C
454    PetscViewerSetFromOptions - Sets various options for a viewer from the options database.
455 
456    Collective on viewer
457 
458    Input Parameter:
459 .     viewer - the viewer context
460 
461    Level: intermediate
462 
463    Note:
464     Must be called after PetscViewerCreate() before the PetscViewer is used.
465 
466 .seealso: `PetscViewer`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerType`
467 @*/
468 PetscErrorCode PetscViewerSetFromOptions(PetscViewer viewer) {
469   char      vtype[256];
470   PetscBool flg;
471 
472   PetscFunctionBegin;
473   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
474 
475   if (!PetscViewerList) PetscCall(PetscViewerRegisterAll());
476   PetscObjectOptionsBegin((PetscObject)viewer);
477   PetscCall(PetscOptionsFList("-viewer_type", "Type of PetscViewer", "None", PetscViewerList, (char *)(((PetscObject)viewer)->type_name ? ((PetscObject)viewer)->type_name : PETSCVIEWERASCII), vtype, 256, &flg));
478   if (flg) PetscCall(PetscViewerSetType(viewer, vtype));
479   /* type has not been set? */
480   if (!((PetscObject)viewer)->type_name) PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII));
481   PetscTryTypeMethod(viewer, setfromoptions, PetscOptionsObject);
482 
483   /* process any options handlers added with PetscObjectAddOptionsHandler() */
484   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)viewer, PetscOptionsObject));
485   PetscCall(PetscViewerViewFromOptions(viewer, NULL, "-viewer_view"));
486   PetscOptionsEnd();
487   PetscFunctionReturn(0);
488 }
489 
490 PetscErrorCode PetscViewerFlowControlStart(PetscViewer viewer, PetscInt *mcnt, PetscInt *cnt) {
491   PetscFunctionBegin;
492   PetscCall(PetscViewerBinaryGetFlowControl(viewer, mcnt));
493   PetscCall(PetscViewerBinaryGetFlowControl(viewer, cnt));
494   PetscFunctionReturn(0);
495 }
496 
497 PetscErrorCode PetscViewerFlowControlStepMain(PetscViewer viewer, PetscInt i, PetscInt *mcnt, PetscInt cnt) {
498   MPI_Comm comm;
499 
500   PetscFunctionBegin;
501   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
502   if (i >= *mcnt) {
503     *mcnt += cnt;
504     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
505   }
506   PetscFunctionReturn(0);
507 }
508 
509 PetscErrorCode PetscViewerFlowControlEndMain(PetscViewer viewer, PetscInt *mcnt) {
510   MPI_Comm comm;
511   PetscFunctionBegin;
512   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
513   *mcnt = 0;
514   PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
515   PetscFunctionReturn(0);
516 }
517 
518 PetscErrorCode PetscViewerFlowControlStepWorker(PetscViewer viewer, PetscMPIInt rank, PetscInt *mcnt) {
519   MPI_Comm comm;
520   PetscFunctionBegin;
521   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
522   while (PETSC_TRUE) {
523     if (rank < *mcnt) break;
524     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
525   }
526   PetscFunctionReturn(0);
527 }
528 
529 PetscErrorCode PetscViewerFlowControlEndWorker(PetscViewer viewer, PetscInt *mcnt) {
530   MPI_Comm comm;
531   PetscFunctionBegin;
532   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
533   while (PETSC_TRUE) {
534     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
535     if (!*mcnt) break;
536   }
537   PetscFunctionReturn(0);
538 }
539