xref: /petsc/src/sys/classes/viewer/interface/viewreg.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
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 - control whether 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   Notes:
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   Notes:
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   Notes:
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
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: `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerType`
361 
362 @*/
363 PetscErrorCode PetscViewerCreate(MPI_Comm comm, PetscViewer *inviewer) {
364   PetscViewer viewer;
365 
366   PetscFunctionBegin;
367   *inviewer = NULL;
368   PetscCall(PetscViewerInitializePackage());
369   PetscCall(PetscHeaderCreate(viewer, PETSC_VIEWER_CLASSID, "PetscViewer", "PetscViewer", "Viewer", comm, PetscViewerDestroy, PetscViewerView));
370   *inviewer    = viewer;
371   viewer->data = NULL;
372   PetscFunctionReturn(0);
373 }
374 
375 /*@C
376    PetscViewerSetType - Builds PetscViewer for a particular implementation.
377 
378    Collective on PetscViewer
379 
380    Input Parameters:
381 +  viewer      - the PetscViewer context
382 -  type        - for example, PETSCVIEWERASCII
383 
384    Options Database Command:
385 .  -viewer_type  <type> - Sets the type; use -help for a list
386     of available methods (for instance, ascii)
387 
388    Level: advanced
389 
390    Notes:
391    See "include/petscviewer.h" for available methods (for instance,
392    PETSCVIEWERSOCKET)
393 
394 .seealso: `PetscViewerCreate()`, `PetscViewerGetType()`, `PetscViewerType`, `PetscViewerPushFormat()`
395 @*/
396 PetscErrorCode PetscViewerSetType(PetscViewer viewer, PetscViewerType type) {
397   PetscBool match;
398   PetscErrorCode (*r)(PetscViewer);
399 
400   PetscFunctionBegin;
401   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
402   PetscValidCharPointer(type, 2);
403   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, type, &match));
404   if (match) PetscFunctionReturn(0);
405 
406   /* cleanup any old type that may be there */
407   PetscTryTypeMethod(viewer, destroy);
408   viewer->ops->destroy = NULL;
409   viewer->data         = NULL;
410 
411   PetscCall(PetscMemzero(viewer->ops, sizeof(struct _PetscViewerOps)));
412 
413   PetscCall(PetscFunctionListFind(PetscViewerList, type, &r));
414   PetscCheck(r, PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscViewer type given: %s", type);
415 
416   PetscCall(PetscObjectChangeTypeName((PetscObject)viewer, type));
417   PetscCall((*r)(viewer));
418   PetscFunctionReturn(0);
419 }
420 
421 /*@C
422    PetscViewerRegister - Adds a viewer
423 
424    Not Collective
425 
426    Input Parameters:
427 +  name_solver - name of a new user-defined viewer
428 -  routine_create - routine to create method context
429 
430    Level: developer
431    Notes:
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 the graphics type from the options database.
455       Defaults to a PETSc X windows graphics.
456 
457    Collective on PetscViewer
458 
459    Input Parameter:
460 .     PetscViewer - the graphics context
461 
462    Level: intermediate
463 
464    Notes:
465     Must be called after PetscViewerCreate() before the PetscViewer is used.
466 
467 .seealso: `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerType`
468 
469 @*/
470 PetscErrorCode PetscViewerSetFromOptions(PetscViewer viewer) {
471   char      vtype[256];
472   PetscBool flg;
473 
474   PetscFunctionBegin;
475   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
476 
477   if (!PetscViewerList) PetscCall(PetscViewerRegisterAll());
478   PetscObjectOptionsBegin((PetscObject)viewer);
479   PetscCall(PetscOptionsFList("-viewer_type", "Type of PetscViewer", "None", PetscViewerList, (char *)(((PetscObject)viewer)->type_name ? ((PetscObject)viewer)->type_name : PETSCVIEWERASCII), vtype, 256, &flg));
480   if (flg) PetscCall(PetscViewerSetType(viewer, vtype));
481   /* type has not been set? */
482   if (!((PetscObject)viewer)->type_name) PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII));
483   PetscTryTypeMethod(viewer, setfromoptions, PetscOptionsObject);
484 
485   /* process any options handlers added with PetscObjectAddOptionsHandler() */
486   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)viewer, PetscOptionsObject));
487   PetscCall(PetscViewerViewFromOptions(viewer, NULL, "-viewer_view"));
488   PetscOptionsEnd();
489   PetscFunctionReturn(0);
490 }
491 
492 PetscErrorCode PetscViewerFlowControlStart(PetscViewer viewer, PetscInt *mcnt, PetscInt *cnt) {
493   PetscFunctionBegin;
494   PetscCall(PetscViewerBinaryGetFlowControl(viewer, mcnt));
495   PetscCall(PetscViewerBinaryGetFlowControl(viewer, cnt));
496   PetscFunctionReturn(0);
497 }
498 
499 PetscErrorCode PetscViewerFlowControlStepMain(PetscViewer viewer, PetscInt i, PetscInt *mcnt, PetscInt cnt) {
500   MPI_Comm comm;
501 
502   PetscFunctionBegin;
503   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
504   if (i >= *mcnt) {
505     *mcnt += cnt;
506     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
507   }
508   PetscFunctionReturn(0);
509 }
510 
511 PetscErrorCode PetscViewerFlowControlEndMain(PetscViewer viewer, PetscInt *mcnt) {
512   MPI_Comm comm;
513   PetscFunctionBegin;
514   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
515   *mcnt = 0;
516   PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
517   PetscFunctionReturn(0);
518 }
519 
520 PetscErrorCode PetscViewerFlowControlStepWorker(PetscViewer viewer, PetscMPIInt rank, PetscInt *mcnt) {
521   MPI_Comm comm;
522   PetscFunctionBegin;
523   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
524   while (PETSC_TRUE) {
525     if (rank < *mcnt) break;
526     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
527   }
528   PetscFunctionReturn(0);
529 }
530 
531 PetscErrorCode PetscViewerFlowControlEndWorker(PetscViewer viewer, PetscInt *mcnt) {
532   MPI_Comm comm;
533   PetscFunctionBegin;
534   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
535   while (PETSC_TRUE) {
536     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
537     if (!*mcnt) break;
538   }
539   PetscFunctionReturn(0);
540 }
541