Actual source code: viewreg.c

  1: #include <petsc/private/viewerimpl.h>
  2: #include <petsc/private/hashtable.h>
  3: #if defined(PETSC_HAVE_SAWS)
  4: #include <petscviewersaws.h>
  5: #endif

  7: PetscFunctionList PetscViewerList = NULL;

  9: PetscOptionsHelpPrinted PetscOptionsHelpPrintedSingleton = NULL;
 10: KHASH_SET_INIT_STR(HTPrinted)
 11: struct _n_PetscOptionsHelpPrinted {
 12:   khash_t(HTPrinted) *printed;
 13:   PetscSegBuffer      strings;
 14: };

 16: /*@
 17:   PetscOptionsHelpPrintedDestroy - Destroys the object used to track which help messages have already been printed

 19:   Not Collective

 21:   Input Parameter:
 22: . hp - pointer to the `PetscOptionsHelpPrinted` object to destroy; set to `NULL` on return

 24:   Level: developer

 26: .seealso: `PetscOptionsHelpPrintedCreate()`, `PetscOptionsHelpPrintedCheck()`
 27: @*/
 28: PetscErrorCode PetscOptionsHelpPrintedDestroy(PetscOptionsHelpPrinted *hp)
 29: {
 30:   PetscFunctionBegin;
 31:   if (!*hp) PetscFunctionReturn(PETSC_SUCCESS);
 32:   kh_destroy(HTPrinted, (*hp)->printed);
 33:   PetscCall(PetscSegBufferDestroy(&(*hp)->strings));
 34:   PetscCall(PetscFree(*hp));
 35:   PetscFunctionReturn(PETSC_SUCCESS);
 36: }

 38: /*@C
 39:   PetscOptionsHelpPrintedCreate - Creates an object used to manage tracking which help messages have
 40:   been printed so they will not be printed again.

 42:   Output Parameter:
 43: . hp - the created object

 45:   Not Collective

 47:   Level: developer

 49: .seealso: `PetscOptionsHelpPrintedCheck()`, `PetscOptionsHelpPrintChecked()`
 50: @*/
 51: PetscErrorCode PetscOptionsHelpPrintedCreate(PetscOptionsHelpPrinted *hp)
 52: {
 53:   PetscFunctionBegin;
 54:   PetscCall(PetscNew(hp));
 55:   (*hp)->printed = kh_init(HTPrinted);
 56:   PetscCall(PetscSegBufferCreate(sizeof(char), 10000, &(*hp)->strings));
 57:   PetscFunctionReturn(PETSC_SUCCESS);
 58: }

 60: /*@C
 61:   PetscOptionsHelpPrintedCheck - Checks if a particular pre, name pair has previous been entered (meaning the help message was printed)

 63:   Not Collective

 65:   Input Parameters:
 66: + hp   - the object used to manage tracking what help messages have been printed
 67: . pre  - the prefix part of the string, many be `NULL`
 68: - name - the string to look for (cannot be `NULL`)

 70:   Output Parameter:
 71: . found - `PETSC_TRUE` if the string was already set

 73:   Level: intermediate

 75: .seealso: `PetscOptionsHelpPrintedCreate()`
 76: @*/
 77: PetscErrorCode PetscOptionsHelpPrintedCheck(PetscOptionsHelpPrinted hp, const char *pre, const char *name, PetscBool *found)
 78: {
 79:   size_t l1, l2;
 80: #if !defined(PETSC_HAVE_THREADSAFETY)
 81:   char *both;
 82:   int   newitem;
 83: #endif

 85:   PetscFunctionBegin;
 86:   PetscCall(PetscStrlen(pre, &l1));
 87:   PetscCall(PetscStrlen(name, &l2));
 88:   if (l1 + l2 == 0) {
 89:     *found = PETSC_FALSE;
 90:     PetscFunctionReturn(PETSC_SUCCESS);
 91:   }
 92: #if !defined(PETSC_HAVE_THREADSAFETY)
 93:   size_t lboth = l1 + l2 + 1;
 94:   PetscCall(PetscSegBufferGet(hp->strings, lboth, &both));
 95:   PetscCall(PetscStrncpy(both, pre, lboth));
 96:   PetscCall(PetscStrncpy(both + l1, name, l2 + 1));
 97:   kh_put(HTPrinted, hp->printed, both, &newitem);
 98:   if (!newitem) PetscCall(PetscSegBufferUnuse(hp->strings, lboth));
 99:   *found = newitem ? PETSC_FALSE : PETSC_TRUE;
100: #else
101:   *found = PETSC_FALSE;
102: #endif
103:   PetscFunctionReturn(PETSC_SUCCESS);
104: }

106: static PetscBool noviewer = PETSC_FALSE;
107: static PetscBool noviewers[PETSCVIEWERCREATEVIEWEROFFPUSHESMAX];
108: static PetscInt  inoviewers = 0;

110: /*@
111:   PetscOptionsPushCreateViewerOff - sets if `PetscOptionsCreateViewer()`, `PetscOptionsViewer()`, and `PetscOptionsCreateViewers()` return viewers.

113:   Logically Collective

115:   Input Parameter:
116: . flg - `PETSC_TRUE` to turn off viewer creation, `PETSC_FALSE` to turn it on.

118:   Level: developer

120:   Note:
121:   Calling `XXXViewFromOptions` in an inner loop can be expensive.  This can appear, for example, when using
122:   many small subsolves.  Call this function to control viewer creation in `PetscOptionsCreateViewer()`, thus removing the expensive `XXXViewFromOptions` calls.

124:   Developer Notes:
125:   Instead of using this approach, the calls to `PetscOptionsCreateViewer()` can be moved into `XXXSetFromOptions()`

127: .seealso: [](sec_viewers), `PetscOptionsCreateViewer()`, `PetscOptionsPopCreateViewerOff()`
128: @*/
129: PetscErrorCode PetscOptionsPushCreateViewerOff(PetscBool flg)
130: {
131:   PetscFunctionBegin;
132:   PetscCheck(inoviewers < PETSCVIEWERCREATEVIEWEROFFPUSHESMAX, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many PetscOptionsPushCreateViewerOff(), perhaps you forgot PetscOptionsPopCreateViewerOff()?");

134:   noviewers[inoviewers++] = noviewer;
135:   noviewer                = flg;
136:   PetscFunctionReturn(PETSC_SUCCESS);
137: }

139: /*@
140:   PetscOptionsPopCreateViewerOff - reset whether `PetscOptionsCreateViewer()` returns a viewer.

142:   Logically Collective

144:   Level: developer

146:   Note:
147:   See `PetscOptionsPushCreateViewerOff()`

149: .seealso: [](sec_viewers), `PetscOptionsCreateViewer()`, `PetscOptionsPushCreateViewerOff()`
150: @*/
151: PetscErrorCode PetscOptionsPopCreateViewerOff(void)
152: {
153:   PetscFunctionBegin;
154:   PetscCheck(inoviewers, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many PetscOptionsPopCreateViewerOff(), perhaps you forgot PetscOptionsPushCreateViewerOff()?");
155:   noviewer = noviewers[--inoviewers];
156:   PetscFunctionReturn(PETSC_SUCCESS);
157: }

159: /*@
160:   PetscOptionsGetCreateViewerOff - do `PetscOptionsCreateViewer()`, `PetscOptionsViewer()`, and `PetscOptionsCreateViewers()` return viewers

162:   Logically Collective

164:   Output Parameter:
165: . flg - whether viewers are returned.

167:   Level: developer

169: .seealso: [](sec_viewers), `PetscOptionsCreateViewer()`, `PetscOptionsPushCreateViewerOff()`, `PetscOptionsPopCreateViewerOff()`
170: @*/
171: PetscErrorCode PetscOptionsGetCreateViewerOff(PetscBool *flg)
172: {
173:   PetscFunctionBegin;
174:   PetscAssertPointer(flg, 1);
175:   *flg = noviewer;
176:   PetscFunctionReturn(PETSC_SUCCESS);
177: }

179: static PetscErrorCode PetscOptionsCreateViewers_Single(MPI_Comm comm, const char value[], PetscViewer *viewer, PetscViewerFormat *format)
180: {
181:   char    *loc0_vtype = NULL, *loc1_fname = NULL, *loc2_fmt = NULL, *loc3_fmode = NULL;
182:   PetscInt cnt;
183:   size_t   viewer_string_length;
184:   const char *viewers[] = {PETSCVIEWERASCII, PETSCVIEWERBINARY, PETSCVIEWERDRAW, PETSCVIEWERSOCKET, PETSCVIEWERMATLAB, PETSCVIEWERSAWS, PETSCVIEWERVTK, PETSCVIEWERHDF5, PETSCVIEWERGLVIS, PETSCVIEWEREXODUSII, PETSCVIEWERPYTHON, PETSCVIEWERPYVISTA, NULL}; /* list should be automatically generated from PetscViewersList */

186:   PetscFunctionBegin;
187:   PetscCall(PetscStrlen(value, &viewer_string_length));
188:   if (!viewer_string_length) {
189:     if (format) *format = PETSC_VIEWER_DEFAULT;
190:     if (viewer) {
191:       PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
192:       PetscCall(PetscObjectReference((PetscObject)*viewer));
193:     }
194:     PetscFunctionReturn(PETSC_SUCCESS);
195:   }

197:   PetscCall(PetscStrallocpy(value, &loc0_vtype));
198:   PetscCall(PetscStrchr(loc0_vtype, ':', &loc1_fname));
199:   if (loc1_fname) {
200:     PetscBool is_daos;
201:     *loc1_fname++ = 0;
202:     // When using DAOS, the filename will have the form "daos:/path/to/file.h5", so capture the rest of it.
203:     PetscCall(PetscStrncmp(loc1_fname, "daos:", 5, &is_daos));
204:     PetscCall(PetscStrchr(loc1_fname + (is_daos == PETSC_TRUE ? 5 : 0), ':', &loc2_fmt));
205:   }
206:   if (loc2_fmt) {
207:     *loc2_fmt++ = 0;
208:     PetscCall(PetscStrchr(loc2_fmt, ':', &loc3_fmode));
209:   }
210:   if (loc3_fmode) *loc3_fmode++ = 0;
211:   PetscCall(PetscStrendswithwhich(*loc0_vtype ? loc0_vtype : "ascii", viewers, &cnt));
212:   PetscCheck(cnt <= (PetscInt)sizeof(viewers) - 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "Unknown viewer type: %s", loc0_vtype);
213:   if (viewer) {
214:     if (!loc1_fname) {
215:       switch (cnt) {
216:       case 0:
217:         PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
218:         PetscCall(PetscObjectReference((PetscObject)*viewer));
219:         break;
220:       case 1:
221:         if (!(*viewer = PETSC_VIEWER_BINARY_(comm))) PetscCall(PETSC_ERR_PLIB);
222:         PetscCall(PetscObjectReference((PetscObject)*viewer));
223:         break;
224:       case 2:
225:         if (!(*viewer = PETSC_VIEWER_DRAW_(comm))) PetscCall(PETSC_ERR_PLIB);
226:         PetscCall(PetscObjectReference((PetscObject)*viewer));
227:         break;
228: #if defined(PETSC_USE_SOCKET_VIEWER)
229:       case 3:
230:         if (!(*viewer = PETSC_VIEWER_SOCKET_(comm))) PetscCall(PETSC_ERR_PLIB);
231:         PetscCall(PetscObjectReference((PetscObject)*viewer));
232:         break;
233: #endif
234: #if defined(PETSC_HAVE_MATLAB)
235:       case 4:
236:         if (!(*viewer = PETSC_VIEWER_MATLAB_(comm))) PetscCall(PETSC_ERR_PLIB);
237:         PetscCall(PetscObjectReference((PetscObject)*viewer));
238:         break;
239: #endif
240: #if defined(PETSC_HAVE_SAWS)
241:       case 5:
242:         if (!(*viewer = PETSC_VIEWER_SAWS_(comm))) PetscCall(PETSC_ERR_PLIB);
243:         PetscCall(PetscObjectReference((PetscObject)*viewer));
244:         break;
245: #endif
246: #if defined(PETSC_HAVE_HDF5)
247:       case 7:
248:         if (!(*viewer = PETSC_VIEWER_HDF5_(comm))) PetscCall(PETSC_ERR_PLIB);
249:         PetscCall(PetscObjectReference((PetscObject)*viewer));
250:         break;
251: #endif
252:       case 8:
253:         if (!(*viewer = PETSC_VIEWER_GLVIS_(comm))) PetscCall(PETSC_ERR_PLIB);
254:         PetscCall(PetscObjectReference((PetscObject)*viewer));
255:         break;
256: #if defined(PETSC_HAVE_EXODUSII)
257:       case 9:
258:         if (!(*viewer = PETSC_VIEWER_EXODUSII_(comm))) PetscCall(PETSC_ERR_PLIB);
259:         PetscCall(PetscObjectReference((PetscObject)*viewer));
260:         break;
261: #endif
262:       case 10:
263:         if (!(*viewer = PETSC_VIEWER_PYTHON_(comm))) PetscCall(PETSC_ERR_PLIB);
264:         PetscCall(PetscObjectReference((PetscObject)*viewer));
265:         break;
266:       case 11:
267:         if (!(*viewer = PETSC_VIEWER_PYVISTA_(comm))) PetscCall(PETSC_ERR_PLIB);
268:         PetscCall(PetscObjectReference((PetscObject)*viewer));
269:         break;
270:       default:
271:         SETERRQ(comm, PETSC_ERR_SUP, "Unsupported viewer %s", loc0_vtype);
272:       }
273:     } else {
274:       if (loc2_fmt && !*loc1_fname && (cnt == 0)) { /* ASCII format without file name */
275:         PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
276:         PetscCall(PetscObjectReference((PetscObject)*viewer));
277:       } else {
278:         PetscFileMode fmode;
279:         PetscBool     flag = PETSC_FALSE;

281:         PetscCall(PetscViewerCreate(comm, viewer));
282:         PetscCall(PetscViewerSetType(*viewer, *loc0_vtype ? loc0_vtype : "ascii"));
283:         fmode = FILE_MODE_WRITE;
284:         if (loc3_fmode && *loc3_fmode) { /* Has non-empty file mode ("write" or "append") */
285:           PetscCall(PetscEnumFind(PetscFileModes, loc3_fmode, (PetscEnum *)&fmode, &flag));
286:           PetscCheck(flag, comm, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown file mode: %s", loc3_fmode);
287:         }
288:         if (loc2_fmt) {
289:           PetscBool tk, im;
290:           PetscCall(PetscStrcmp(loc1_fname, "tikz", &tk));
291:           PetscCall(PetscStrcmp(loc1_fname, "image", &im));
292:           if (tk || im) {
293:             PetscCall(PetscViewerDrawSetInfo(*viewer, NULL, loc2_fmt, PETSC_DECIDE, PETSC_DECIDE, PETSC_DECIDE, PETSC_DECIDE));
294:             *loc2_fmt = 0;
295:           }
296:         }
297:         PetscCall(PetscViewerFileSetMode(*viewer, flag ? fmode : FILE_MODE_WRITE));
298:         PetscCall(PetscViewerFileSetName(*viewer, loc1_fname));
299:         if (*loc1_fname) PetscCall(PetscViewerDrawSetDrawType(*viewer, loc1_fname));
300:         PetscCall(PetscViewerSetFromOptions(*viewer));
301:       }
302:     }
303:   }
304:   if (viewer) PetscCall(PetscViewerSetUp(*viewer));
305:   if (loc2_fmt && *loc2_fmt) {
306:     PetscViewerFormat tfmt;
307:     PetscBool         flag;

309:     PetscCall(PetscEnumFind(PetscViewerFormats, loc2_fmt, (PetscEnum *)&tfmt, &flag));
310:     if (format) *format = tfmt;
311:     PetscCheck(flag, comm, PETSC_ERR_SUP, "Unknown viewer format %s", loc2_fmt);
312:   } else if (viewer && (cnt == 6) && format) { /* Get format from VTK viewer */
313:     PetscCall(PetscViewerGetFormat(*viewer, format));
314:   }
315:   PetscCall(PetscFree(loc0_vtype));
316:   PetscFunctionReturn(PETSC_SUCCESS);
317: }

319: static PetscErrorCode PetscOptionsCreateViewers_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)
320: {
321:   const char *value;
322:   PetscBool   flag, hashelp;
323:   PetscInt    n_max;

325:   PetscFunctionBegin;
326:   PetscAssertPointer(name, 4);
327:   PetscAssertPointer(n_max_p, 5);
328:   n_max = *n_max_p;
329:   PetscCheck(n_max >= 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid size %" PetscInt_FMT " of passed arrays", *n_max_p);
330:   *n_max_p = 0;

332:   if (set) *set = PETSC_FALSE;
333:   PetscCall(PetscOptionsGetCreateViewerOff(&flag));
334:   if (flag) PetscFunctionReturn(PETSC_SUCCESS);

336:   PetscCall(PetscOptionsHasHelp(NULL, &hashelp));
337:   if (hashelp) {
338:     PetscBool found;

340:     if (!PetscOptionsHelpPrintedSingleton) PetscCall(PetscOptionsHelpPrintedCreate(&PetscOptionsHelpPrintedSingleton));
341:     PetscCall(PetscOptionsHelpPrintedCheck(PetscOptionsHelpPrintedSingleton, pre, name, &found));
342:     if (!found && viewer) {
343:       PetscCall((*PetscHelpPrintf)(comm, "----------------------------------------\nViewer (-%s%s) options:\n", pre ? pre : "", name + 1));
344:       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));
345:       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s binary[:[filename][:[format][:append]]]: %s (%s)\n", pre ? pre : "", name + 1, "Saves object to a binary file", func_name));
346:       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s draw[:[drawtype][:filename|format]] %s (%s)\n", pre ? pre : "", name + 1, "Draws object", func_name));
347:       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s socket[:port]: %s (%s)\n", pre ? pre : "", name + 1, "Pushes object to a Unix socket", func_name));
348:       PetscCall((*PetscHelpPrintf)(comm, "  -%s%s saws[:communicatorname]: %s (%s)\n", pre ? pre : "", name + 1, "Publishes object to SAWs", func_name));
349:       if (allow_multiple) PetscCall((*PetscHelpPrintf)(comm, "  -%s%s v1[,v2,...]: %s (%s)\n", pre ? pre : "", name + 1, "Multiple viewers", func_name));
350:     }
351:   }

353:   PetscCall(PetscOptionsFindPair(options, pre, name, &value, &flag));
354:   if (flag) {
355:     if (set) *set = PETSC_TRUE;
356:     if (!value) {
357:       PetscCheck(n_max > 0, comm, PETSC_ERR_ARG_SIZ, "More viewers (1) than max available (0)");
358:       if (format) *format = PETSC_VIEWER_DEFAULT;
359:       if (viewer) {
360:         PetscCall(PetscViewerASCIIGetStdout(comm, viewer));
361:         PetscCall(PetscObjectReference((PetscObject)*viewer));
362:       }
363:       *n_max_p = 1;
364:     } else {
365:       char  *loc0_viewer_string = NULL, *this_viewer_string = NULL;
366:       size_t viewer_string_length;

368:       PetscCall(PetscStrallocpy(value, &loc0_viewer_string));
369:       PetscCall(PetscStrlen(loc0_viewer_string, &viewer_string_length));
370:       this_viewer_string = loc0_viewer_string;

372:       do {
373:         PetscViewer       *this_viewer;
374:         PetscViewerFormat *this_viewer_format;
375:         char              *next_viewer_string = NULL;
376:         char              *comma_separator    = NULL;
377:         PetscInt           n                  = *n_max_p;

379:         PetscCheck(n < n_max, comm, PETSC_ERR_PLIB, "More viewers than max available (%" PetscInt_FMT ")", n_max);

381:         PetscCall(PetscStrchr(this_viewer_string, ',', &comma_separator));
382:         if (comma_separator) {
383:           PetscCheck(allow_multiple, comm, PETSC_ERR_ARG_OUTOFRANGE, "Trying to pass multiple viewers to %s: only one allowed.  Use PetscOptionsCreateViewers() instead", func_name);
384:           *comma_separator   = 0;
385:           next_viewer_string = comma_separator + 1;
386:         }
387:         this_viewer = PetscSafePointerPlusOffset(viewer, n);
388:         if (this_viewer) *this_viewer = NULL;
389:         this_viewer_format = PetscSafePointerPlusOffset(format, n);
390:         if (this_viewer_format) *this_viewer_format = PETSC_VIEWER_DEFAULT;
391:         PetscCall(PetscOptionsCreateViewers_Single(comm, this_viewer_string, this_viewer, this_viewer_format));
392:         this_viewer_string = next_viewer_string;
393:         (*n_max_p)++;
394:       } while (this_viewer_string);
395:       PetscCall(PetscFree(loc0_viewer_string));
396:     }
397:   }
398:   PetscFunctionReturn(PETSC_SUCCESS);
399: }

401: /*@C
402:   PetscOptionsCreateViewer - Creates a viewer appropriate for the type indicated by the user

404:   Collective

406:   Input Parameters:
407: + comm    - the communicator to own the viewer
408: . options - options database, use `NULL` for default global database
409: . pre     - the string to prepend to the name or `NULL`
410: - name    - the options database name that will be checked for

412:   Output Parameters:
413: + viewer - the viewer, pass `NULL` if not needed
414: . format - the `PetscViewerFormat` requested by the user, pass `NULL` if not needed
415: - set    - `PETSC_TRUE` if found, else `PETSC_FALSE`

417:   Level: intermediate

419:   Notes:
420:   The argument has the following form
421: .vb
422:     type:filename:format:filemode
423: .ve
424:   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
425: .vb
426:     hdf5:sol.h5::read
427: .ve

429:   If no value is provided ascii:stdout is used
430: +       ascii[:[filename][:[format][:append]]]  -  defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
431:   for example ascii::ascii_info prints just the information about the object not all details
432:   unless :append is given filename opens in write mode, overwriting what was already there
433: .       binary[:[filename][:[format][:append]]] -  defaults to the file binaryoutput
434: .       draw[:drawtype[:filename]]              -  for example, draw:tikz, draw:tikz:figure.tex  or draw:x
435: .       socket[:port]                           -  defaults to the standard output port
436: -       saws[:communicatorname]                 -   publishes object to the Scientific Application Webserver (SAWs)

438:   You can control whether calls to this function create a viewer (or return early with *set of `PETSC_FALSE`) with
439:   `PetscOptionsPushCreateViewerOff()`.  This is useful if calling many small subsolves, in which case XXXViewFromOptions can take
440:   an appreciable fraction of the runtime.

442:   If PETSc is configured with `--with-viewfromoptions=0` this function always returns with *set of `PETSC_FALSE`

444:   This routine is thread-safe for accessing predefined `PetscViewer`s like `PETSC_VIEWER_STDOUT_SELF` but not for accessing
445:   files by name.

447: .seealso: [](sec_viewers), `PetscViewerDestroy()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
448:           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`,
449:           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
450:           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
451:           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
452:           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
453:           `PetscOptionsFList()`, `PetscOptionsEList()`, `PetscOptionsPushCreateViewerOff()`, `PetscOptionsPopCreateViewerOff()`,
454:           `PetscOptionsCreateViewerOff()`
455: @*/
456: PetscErrorCode PetscOptionsCreateViewer(MPI_Comm comm, PetscOptions options, const char pre[], const char name[], PetscViewer *viewer, PetscViewerFormat *format, PetscBool *set)
457: {
458:   PetscInt  n_max = 1;
459:   PetscBool set_internal;

461:   PetscFunctionBegin;
462:   if (viewer) *viewer = NULL;
463:   if (format) *format = PETSC_VIEWER_DEFAULT;
464:   PetscCall(PetscOptionsCreateViewers_Internal(comm, options, pre, name, &n_max, viewer, format, &set_internal, PETSC_FUNCTION_NAME, PETSC_FALSE));
465:   if (set_internal) PetscAssert(n_max == 1, comm, PETSC_ERR_PLIB, "Unexpected: %" PetscInt_FMT " != 1 viewers set", n_max);
466:   if (set) *set = set_internal;
467:   PetscFunctionReturn(PETSC_SUCCESS);
468: }

470: /*@C
471:   PetscOptionsCreateViewers - Create multiple viewers from a comma-separated list in the options database

473:   Collective

475:   Input Parameters:
476: + comm    - the communicator to own the viewers
477: . options - options database, use `NULL` for default global database
478: . pre     - the string to prepend to the name or `NULL`
479: . name    - the options database name that will be checked for
480: - n_max   - on input: the maximum number of viewers; on output: the number of viewers in the comma-separated list

482:   Output Parameters:
483: + viewers - an array to hold at least `n_max` `PetscViewer`s, or `NULL` if not needed; on output: if not `NULL`, the
484:             first `n_max` entries are initialized `PetscViewer`s
485: . formats - an array to hold at least `n_max` `PetscViewerFormat`s, or `NULL` if not needed; on output: if not
486:             `NULL`, the first `n_max` entries are valid `PetscViewewFormat`s
487: - set     - `PETSC_TRUE` if found, else `PETSC_FALSE`

489:   Level: intermediate

491:   Note:
492:   See `PetscOptionsCreateViewer()` for how the format strings for the viewers are interpreted.

494:   Use `PetscViewerDestroy()` on each viewer, otherwise a memory leak will occur.

496:   If PETSc is configured with `--with-viewfromoptions=0` this function always returns with `n_max` of 0 and `set` of `PETSC_FALSE`

498: .seealso: [](sec_viewers), `PetscOptionsCreateViewer()`
499: @*/
500: PetscErrorCode PetscOptionsCreateViewers(MPI_Comm comm, PetscOptions options, const char pre[], const char name[], PetscInt *n_max, PetscViewer viewers[], PetscViewerFormat formats[], PetscBool *set)
501: {
502:   PetscFunctionBegin;
503:   PetscCall(PetscOptionsCreateViewers_Internal(comm, options, pre, name, n_max, viewers, formats, set, PETSC_FUNCTION_NAME, PETSC_TRUE));
504:   PetscFunctionReturn(PETSC_SUCCESS);
505: }

507: /*@
508:   PetscViewerCreate - Creates a viewing context. A `PetscViewer` represents a file, a graphical window, a Unix socket or a variety of other ways
509:   of viewing a PETSc object

511:   Collective

513:   Input Parameter:
514: . comm - MPI communicator

516:   Output Parameter:
517: . inviewer - location to put the `PetscViewer` context

519:   Level: advanced

521: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerType`
522: @*/
523: PetscErrorCode PetscViewerCreate(MPI_Comm comm, PetscViewer *inviewer)
524: {
525:   PetscViewer viewer;

527:   PetscFunctionBegin;
528:   PetscAssertPointer(inviewer, 2);
529:   PetscCall(PetscViewerInitializePackage());
530:   PetscCall(PetscHeaderCreate(viewer, PETSC_VIEWER_CLASSID, "PetscViewer", "PetscViewer", "Viewer", comm, PetscViewerDestroy, PetscViewerView));
531:   *inviewer    = viewer;
532:   viewer->data = NULL;
533:   PetscFunctionReturn(PETSC_SUCCESS);
534: }

536: /*@
537:   PetscViewerSetType - Builds `PetscViewer` for a particular implementation.

539:   Collective

541:   Input Parameters:
542: + viewer - the `PetscViewer` context obtained with `PetscViewerCreate()`
543: - type   - for example, `PETSCVIEWERASCII`

545:   Options Database Key:
546: . -viewer_type  type - Sets the type; use -help for a list of available methods (for instance, ascii)

548:   Level: advanced

550:   Note:
551:   See `PetscViewerType` for possible values

553: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerCreate()`, `PetscViewerGetType()`, `PetscViewerType`, `PetscViewerPushFormat()`
554: @*/
555: PetscErrorCode PetscViewerSetType(PetscViewer viewer, PetscViewerType type)
556: {
557:   PetscBool match;
558:   PetscErrorCode (*r)(PetscViewer);

560:   PetscFunctionBegin;
562:   PetscAssertPointer(type, 2);
563:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, type, &match));
564:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

566:   /* cleanup any old type that may be there */
567:   PetscTryTypeMethod(viewer, destroy);
568:   viewer->ops->destroy = NULL;
569:   viewer->data         = NULL;

571:   PetscCall(PetscMemzero(viewer->ops, sizeof(struct _PetscViewerOps)));

573:   PetscCall(PetscFunctionListFind(PetscViewerList, type, &r));
574:   PetscCheck(r, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscViewer type given: %s", type);

576:   PetscCall(PetscObjectChangeTypeName((PetscObject)viewer, type));
577:   PetscCall((*r)(viewer));
578:   PetscFunctionReturn(PETSC_SUCCESS);
579: }

581: /*@C
582:   PetscViewerRegister - Adds a viewer to those available for use with `PetscViewerSetType()`

584:   Not Collective, No Fortran Support

586:   Input Parameters:
587: + sname    - name of a new user-defined viewer
588: - function - routine to create method context

590:   Level: developer

592:   Note:
593:   `PetscViewerRegister()` may be called multiple times to add several user-defined viewers.

595:   Example Usage:
596: .vb
597:    PetscViewerRegister("my_viewer_type", MyViewerCreate);
598: .ve

600:   Then, your solver can be chosen with the procedural interface via
601: .vb
602:   PetscViewerSetType(viewer, "my_viewer_type")
603: .ve
604:   or at runtime via the option
605: .vb
606:   -viewer_type my_viewer_type
607: .ve

609: .seealso: [](sec_viewers), `PetscViewerRegisterAll()`
610:  @*/
611: PetscErrorCode PetscViewerRegister(const char *sname, PetscErrorCode (*function)(PetscViewer))
612: {
613:   PetscFunctionBegin;
614:   PetscCall(PetscViewerInitializePackage());
615:   PetscCall(PetscFunctionListAdd(&PetscViewerList, sname, function));
616:   PetscFunctionReturn(PETSC_SUCCESS);
617: }

619: /*@C
620:   PetscViewerSetFromOptions - Sets various options for a viewer based on values in the options database.

622:   Collective

624:   Input Parameter:
625: . viewer - the viewer context

627:   Level: intermediate

629:   Note:
630:   Must be called after `PetscViewerCreate()` but before the `PetscViewer` is used.

632: .seealso: [](sec_viewers), `PetscViewer`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerType`
633: @*/
634: PetscErrorCode PetscViewerSetFromOptions(PetscViewer viewer)
635: {
636:   char      vtype[256];
637:   PetscBool flg;

639:   PetscFunctionBegin;

642:   if (!PetscViewerList) PetscCall(PetscViewerRegisterAll());
643:   PetscObjectOptionsBegin((PetscObject)viewer);
644:   PetscCall(PetscOptionsFList("-viewer_type", "Type of PetscViewer", "None", PetscViewerList, (char *)(((PetscObject)viewer)->type_name ? ((PetscObject)viewer)->type_name : PETSCVIEWERASCII), vtype, 256, &flg));
645:   if (flg) PetscCall(PetscViewerSetType(viewer, vtype));
646:   /* type has not been set? */
647:   if (!((PetscObject)viewer)->type_name) PetscCall(PetscViewerSetType(viewer, PETSCVIEWERASCII));
648:   PetscTryTypeMethod(viewer, setfromoptions, PetscOptionsObject);

650:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
651:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)viewer, PetscOptionsObject));
652:   PetscCall(PetscViewerViewFromOptions(viewer, NULL, "-viewer_view"));
653:   PetscOptionsEnd();
654:   PetscFunctionReturn(PETSC_SUCCESS);
655: }

657: /*@
658:   PetscViewerFlowControlStart - Begin a flow-controlled viewer operation on the main MPI process

660:   Collective

662:   Input Parameter:
663: . viewer - the binary viewer

665:   Output Parameters:
666: + mcnt - the current flow-control counter on the main MPI process
667: - cnt  - the flow-control window size (also read from the viewer)

669:   Level: developer

671:   Note:
672:   Used together with `PetscViewerFlowControlStepMain()` and `PetscViewerFlowControlEndMain()` on the main process (rank 0),
673:   and with `PetscViewerFlowControlStepWorker()` and `PetscViewerFlowControlEndWorker()` on the other processes, to serialize
674:   I/O work through a bounded window so that all processes do not simultaneously flood the main process with data.

676: .seealso: `PetscViewer`, `PetscViewerFlowControlStepMain()`, `PetscViewerFlowControlEndMain()`, `PetscViewerFlowControlStepWorker()`,
677:           `PetscViewerFlowControlEndWorker()`, `PetscViewerBinaryGetFlowControl()`
678: @*/
679: PetscErrorCode PetscViewerFlowControlStart(PetscViewer viewer, PetscInt *mcnt, PetscInt *cnt)
680: {
681:   PetscFunctionBegin;
682:   PetscCall(PetscViewerBinaryGetFlowControl(viewer, mcnt));
683:   PetscCall(PetscViewerBinaryGetFlowControl(viewer, cnt));
684:   PetscFunctionReturn(PETSC_SUCCESS);
685: }

687: /*@
688:   PetscViewerFlowControlStepMain - Advance the flow-control window on the main MPI process during a viewer operation

690:   Collective

692:   Input Parameters:
693: + viewer - the binary viewer
694: . i      - the current MPI rank being served
695: - cnt    - the flow-control window size returned by `PetscViewerFlowControlStart()`

697:   Input/Output Parameter:
698: . mcnt - the running flow-control counter; incremented and broadcast when `i` reaches it

700:   Level: developer

702:   Note:
703:   Called on the main MPI process (rank 0) once per worker rank in a loop; when the current rank has caught up to `mcnt`
704:   the window is advanced by `cnt` and broadcast so waiting workers can proceed.

706: .seealso: `PetscViewer`, `PetscViewerFlowControlStart()`, `PetscViewerFlowControlEndMain()`, `PetscViewerFlowControlStepWorker()`,
707:           `PetscViewerFlowControlEndWorker()`
708: @*/
709: PetscErrorCode PetscViewerFlowControlStepMain(PetscViewer viewer, PetscInt i, PetscInt *mcnt, PetscInt cnt)
710: {
711:   MPI_Comm comm;

713:   PetscFunctionBegin;
714:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
715:   if (i >= *mcnt) {
716:     *mcnt += cnt;
717:     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
718:   }
719:   PetscFunctionReturn(PETSC_SUCCESS);
720: }

722: /*@
723:   PetscViewerFlowControlEndMain - Finish a flow-controlled viewer operation on the main MPI process by signalling completion to the workers

725:   Collective

727:   Input Parameter:
728: . viewer - the binary viewer

730:   Input/Output Parameter:
731: . mcnt - the flow-control counter; reset to 0 and broadcast to signal completion

733:   Level: developer

735:   Note:
736:   Broadcasting `mcnt = 0` releases any worker MPI processes still waiting inside `PetscViewerFlowControlEndWorker()`.

738: .seealso: `PetscViewer`, `PetscViewerFlowControlStart()`, `PetscViewerFlowControlStepMain()`, `PetscViewerFlowControlStepWorker()`,
739:           `PetscViewerFlowControlEndWorker()`
740: @*/
741: PetscErrorCode PetscViewerFlowControlEndMain(PetscViewer viewer, PetscInt *mcnt)
742: {
743:   MPI_Comm comm;

745:   PetscFunctionBegin;
746:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
747:   *mcnt = 0;
748:   PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
749:   PetscFunctionReturn(PETSC_SUCCESS);
750: }

752: /*@
753:   PetscViewerFlowControlStepWorker - Wait on a worker MPI process until the flow-control window includes this rank

755:   Collective

757:   Input Parameters:
758: + viewer - the binary viewer
759: - rank   - the calling MPI process rank

761:   Input/Output Parameter:
762: . mcnt - the flow-control counter; updated with values broadcast from the main MPI process until it exceeds `rank`

764:   Level: developer

766:   Note:
767:   Blocks in a loop of `MPI_Bcast()` until the main MPI process (through `PetscViewerFlowControlStepMain()`) advances the
768:   window past this rank, giving the worker permission to perform its I/O.

770: .seealso: `PetscViewer`, `PetscViewerFlowControlStart()`, `PetscViewerFlowControlStepMain()`, `PetscViewerFlowControlEndMain()`,
771:           `PetscViewerFlowControlEndWorker()`
772: @*/
773: PetscErrorCode PetscViewerFlowControlStepWorker(PetscViewer viewer, PetscMPIInt rank, PetscInt *mcnt)
774: {
775:   MPI_Comm comm;

777:   PetscFunctionBegin;
778:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
779:   while (PETSC_TRUE) {
780:     if (rank < *mcnt) break;
781:     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
782:   }
783:   PetscFunctionReturn(PETSC_SUCCESS);
784: }

786: /*@
787:   PetscViewerFlowControlEndWorker - Wait on a worker MPI process for the main MPI process to signal completion of a flow-controlled viewer operation

789:   Collective

791:   Input Parameter:
792: . viewer - the binary viewer

794:   Input/Output Parameter:
795: . mcnt - the flow-control counter; updated with values broadcast from the main MPI process until it becomes 0

797:   Level: developer

799:   Note:
800:   Blocks in a loop of `MPI_Bcast()` until `PetscViewerFlowControlEndMain()` sends a `mcnt = 0` completion signal.

802: .seealso: `PetscViewer`, `PetscViewerFlowControlStart()`, `PetscViewerFlowControlStepMain()`, `PetscViewerFlowControlEndMain()`,
803:           `PetscViewerFlowControlStepWorker()`
804: @*/
805: PetscErrorCode PetscViewerFlowControlEndWorker(PetscViewer viewer, PetscInt *mcnt)
806: {
807:   MPI_Comm comm;

809:   PetscFunctionBegin;
810:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
811:   while (PETSC_TRUE) {
812:     PetscCallMPI(MPI_Bcast(mcnt, 1, MPIU_INT, 0, comm));
813:     if (!*mcnt) break;
814:   }
815:   PetscFunctionReturn(PETSC_SUCCESS);
816: }