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