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