xref: /petsc/src/sys/classes/viewer/impls/ascii/filev.c (revision 2ad7e442857a3cef22c06b0e94de84654ca4e109)
1 #include <../src/sys/classes/viewer/impls/ascii/asciiimpl.h> /*I "petscviewer.h" I*/
2 
3 #define QUEUESTRINGSIZE 8192
4 
5 static PetscErrorCode PetscViewerFileClose_ASCII(PetscViewer viewer)
6 {
7   PetscMPIInt        rank;
8   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
9   int                err;
10 
11   PetscFunctionBegin;
12   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
13   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
14   if (rank == 0 && vascii->fd != stderr && vascii->fd != PETSC_STDOUT) {
15     if (vascii->fd && vascii->closefile) {
16       err = fclose(vascii->fd);
17       PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fclose() failed on file");
18     }
19     if (vascii->storecompressed) {
20       char  par[PETSC_MAX_PATH_LEN], buf[PETSC_MAX_PATH_LEN];
21       FILE *fp;
22       PetscCall(PetscStrncpy(par, "gzip ", sizeof(par)));
23       PetscCall(PetscStrlcat(par, vascii->filename, sizeof(par)));
24 #if defined(PETSC_HAVE_POPEN)
25       PetscCall(PetscPOpen(PETSC_COMM_SELF, NULL, par, "r", &fp));
26       PetscCheck(!fgets(buf, 1024, fp), PETSC_COMM_SELF, PETSC_ERR_LIB, "Error from compression command %s\n%s", par, buf);
27       PetscCall(PetscPClose(PETSC_COMM_SELF, fp));
28 #else
29       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "Cannot run external programs on this machine");
30 #endif
31     }
32   }
33   PetscCall(PetscFree(vascii->filename));
34   PetscFunctionReturn(PETSC_SUCCESS);
35 }
36 
37 /* ----------------------------------------------------------------------*/
38 static PetscErrorCode PetscViewerDestroy_ASCII(PetscViewer viewer)
39 {
40   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
41   PetscViewerLink   *vlink;
42   PetscBool          flg;
43 
44   PetscFunctionBegin;
45   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
46   PetscCall(PetscViewerFileClose_ASCII(viewer));
47   PetscCall(PetscFree(vascii));
48 
49   /* remove the viewer from the list in the MPI Communicator */
50   if (Petsc_Viewer_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelViewer, &Petsc_Viewer_keyval, (void *)0));
51 
52   PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
53   if (flg) {
54     if (vlink && vlink->viewer == viewer) {
55       if (vlink->next) {
56         PetscCallMPI(MPI_Comm_set_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval, vlink->next));
57       } else {
58         PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval));
59       }
60       PetscCall(PetscFree(vlink));
61     } else {
62       while (vlink && vlink->next) {
63         if (vlink->next->viewer == viewer) {
64           PetscViewerLink *nv = vlink->next;
65           vlink->next         = vlink->next->next;
66           PetscCall(PetscFree(nv));
67         }
68         vlink = vlink->next;
69       }
70     }
71   }
72 
73   if (Petsc_Viewer_Stdout_keyval != MPI_KEYVAL_INVALID) {
74     PetscViewer aviewer;
75     PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stdout_keyval, (void **)&aviewer, (PetscMPIInt *)&flg));
76     if (flg && aviewer == viewer) PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stdout_keyval));
77   }
78   if (Petsc_Viewer_Stderr_keyval != MPI_KEYVAL_INVALID) {
79     PetscViewer aviewer;
80     PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stderr_keyval, (void **)&aviewer, (PetscMPIInt *)&flg));
81     if (flg && aviewer == viewer) PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stderr_keyval));
82   }
83   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", NULL));
84   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", NULL));
85   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", NULL));
86   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", NULL));
87   PetscFunctionReturn(PETSC_SUCCESS);
88 }
89 
90 static PetscErrorCode PetscViewerDestroy_ASCII_SubViewer(PetscViewer viewer)
91 {
92   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
93 
94   PetscFunctionBegin;
95   PetscCall(PetscViewerRestoreSubViewer(vascii->bviewer, 0, &viewer));
96   PetscFunctionReturn(PETSC_SUCCESS);
97 }
98 
99 static PetscErrorCode PetscViewerFlush_ASCII(PetscViewer viewer)
100 {
101   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
102   MPI_Comm           comm;
103   PetscMPIInt        rank, size;
104   FILE              *fd = vascii->fd;
105 
106   PetscFunctionBegin;
107   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
108   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
109   PetscCallMPI(MPI_Comm_rank(comm, &rank));
110   PetscCallMPI(MPI_Comm_size(comm, &size));
111 
112   if (!vascii->bviewer && rank == 0 && (vascii->mode != FILE_MODE_READ)) PetscCall(PetscFFlush(vascii->fd));
113 
114   if (vascii->allowsynchronized) {
115     PetscMPIInt tag, i, j, n = 0, dummy = 0;
116     char       *message;
117     MPI_Status  status;
118 
119     PetscCall(PetscCommDuplicate(comm, &comm, &tag));
120 
121     /* First processor waits for messages from all other processors */
122     if (rank == 0) {
123       /* flush my own messages that I may have queued up */
124       PrintfQueue next = vascii->petsc_printfqueuebase, previous;
125       for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
126         if (!vascii->bviewer) {
127           PetscCall(PetscFPrintf(comm, fd, "%s", next->string));
128         } else {
129           PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", next->string));
130         }
131         previous = next;
132         next     = next->next;
133         PetscCall(PetscFree(previous->string));
134         PetscCall(PetscFree(previous));
135       }
136       vascii->petsc_printfqueue       = NULL;
137       vascii->petsc_printfqueuelength = 0;
138       for (i = 1; i < size; i++) {
139         /* to prevent a flood of messages to process zero, request each message separately */
140         PetscCallMPI(MPI_Send(&dummy, 1, MPI_INT, i, tag, comm));
141         PetscCallMPI(MPI_Recv(&n, 1, MPI_INT, i, tag, comm, &status));
142         for (j = 0; j < n; j++) {
143           PetscMPIInt size = 0;
144 
145           PetscCallMPI(MPI_Recv(&size, 1, MPI_INT, i, tag, comm, &status));
146           PetscCall(PetscMalloc1(size, &message));
147           PetscCallMPI(MPI_Recv(message, size, MPI_CHAR, i, tag, comm, &status));
148           if (!vascii->bviewer) {
149             PetscCall(PetscFPrintf(comm, fd, "%s", message));
150           } else {
151             PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", message));
152           }
153           PetscCall(PetscFree(message));
154         }
155       }
156     } else { /* other processors send queue to processor 0 */
157       PrintfQueue next = vascii->petsc_printfqueuebase, previous;
158 
159       PetscCallMPI(MPI_Recv(&dummy, 1, MPI_INT, 0, tag, comm, &status));
160       PetscCallMPI(MPI_Send(&vascii->petsc_printfqueuelength, 1, MPI_INT, 0, tag, comm));
161       for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
162         PetscCallMPI(MPI_Send(&next->size, 1, MPI_INT, 0, tag, comm));
163         PetscCallMPI(MPI_Send(next->string, next->size, MPI_CHAR, 0, tag, comm));
164         previous = next;
165         next     = next->next;
166         PetscCall(PetscFree(previous->string));
167         PetscCall(PetscFree(previous));
168       }
169       vascii->petsc_printfqueue       = NULL;
170       vascii->petsc_printfqueuelength = 0;
171     }
172     PetscCall(PetscCommDestroy(&comm));
173   }
174   PetscFunctionReturn(PETSC_SUCCESS);
175 }
176 
177 /*@C
178   PetscViewerASCIIGetPointer - Extracts the file pointer from an ASCII `PetscViewer`.
179 
180   Not Collective, depending on the viewer the value may be meaningless except for process 0 of the viewer; No Fortran Support
181 
182   Input Parameter:
183 . viewer - `PetscViewer` context, obtained from `PetscViewerASCIIOpen()`
184 
185   Output Parameter:
186 . fd - file pointer
187 
188   Level: intermediate
189 
190   Note:
191   For the standard `PETSCVIEWERASCII` the value is valid only on MPI rank 0 of the viewer
192 
193 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscViewerASCIIOpen()`, `PetscViewerDestroy()`, `PetscViewerSetType()`,
194           `PetscViewerCreate()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`
195 @*/
196 PetscErrorCode PetscViewerASCIIGetPointer(PetscViewer viewer, FILE **fd)
197 {
198   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
199 
200   PetscFunctionBegin;
201   *fd = vascii->fd;
202   PetscFunctionReturn(PETSC_SUCCESS);
203 }
204 
205 static PetscErrorCode PetscViewerFileGetMode_ASCII(PetscViewer viewer, PetscFileMode *mode)
206 {
207   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
208 
209   PetscFunctionBegin;
210   *mode = vascii->mode;
211   PetscFunctionReturn(PETSC_SUCCESS);
212 }
213 
214 static PetscErrorCode PetscViewerFileSetMode_ASCII(PetscViewer viewer, PetscFileMode mode)
215 {
216   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
217 
218   PetscFunctionBegin;
219   vascii->mode = mode;
220   PetscFunctionReturn(PETSC_SUCCESS);
221 }
222 
223 /*
224    If petsc_history is on, then all Petsc*Printf() results are saved
225    if the appropriate (usually .petschistory) file.
226 */
227 PETSC_INTERN FILE *petsc_history;
228 
229 /*@
230   PetscViewerASCIISetTab - Causes `PetscViewer` to tab in a number of times before printing
231 
232   Not Collective, but only first processor in set has any effect; No Fortran Support
233 
234   Input Parameters:
235 + viewer - obtained with `PetscViewerASCIIOpen()`
236 - tabs   - number of tabs
237 
238   Level: developer
239 
240   Note:
241   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage
242 
243 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
244           `PetscViewerASCIIGetTab()`,
245           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
246           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`,
247           `PetscViewerASCIIPushTab()`
248 @*/
249 PetscErrorCode PetscViewerASCIISetTab(PetscViewer viewer, PetscInt tabs)
250 {
251   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
252   PetscBool          iascii;
253 
254   PetscFunctionBegin;
255   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
256   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
257   if (iascii) ascii->tab = tabs;
258   PetscFunctionReturn(PETSC_SUCCESS);
259 }
260 
261 /*@
262   PetscViewerASCIIGetTab - Return the number of tabs used by `PetscViewer`.
263 
264   Not Collective, meaningful on first processor only; No Fortran Support
265 
266   Input Parameter:
267 . viewer - obtained with `PetscViewerASCIIOpen()`
268 
269   Output Parameter:
270 . tabs - number of tabs
271 
272   Level: developer
273 
274 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
275           `PetscViewerASCIISetTab()`,
276           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
277           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
278 @*/
279 PetscErrorCode PetscViewerASCIIGetTab(PetscViewer viewer, PetscInt *tabs)
280 {
281   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
282   PetscBool          iascii;
283 
284   PetscFunctionBegin;
285   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
286   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
287   if (iascii && tabs) *tabs = ascii->tab;
288   PetscFunctionReturn(PETSC_SUCCESS);
289 }
290 
291 /*@
292   PetscViewerASCIIAddTab - Add to the number of times a `PETSCVIEWERASCII` viewer tabs before printing
293 
294   Not Collective, but only first processor in set has any effect; No Fortran Support
295 
296   Input Parameters:
297 + viewer - obtained with `PetscViewerASCIIOpen()`
298 - tabs   - number of tabs
299 
300   Level: developer
301 
302   Note:
303   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage
304 
305 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
306           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
307           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
308 @*/
309 PetscErrorCode PetscViewerASCIIAddTab(PetscViewer viewer, PetscInt tabs)
310 {
311   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
312   PetscBool          iascii;
313 
314   PetscFunctionBegin;
315   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
316   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
317   if (iascii) ascii->tab += tabs;
318   PetscFunctionReturn(PETSC_SUCCESS);
319 }
320 
321 /*@
322   PetscViewerASCIISubtractTab - Subtracts from the number of times a `PETSCVIEWERASCII` viewer tabs before printing
323 
324   Not Collective, but only first processor in set has any effect; No Fortran Support
325 
326   Input Parameters:
327 + viewer - obtained with `PetscViewerASCIIOpen()`
328 - tabs   - number of tabs
329 
330   Level: developer
331 
332   Note:
333   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage
334 
335 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
336           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
337           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`,
338           `PetscViewerASCIIPushTab()`
339 @*/
340 PetscErrorCode PetscViewerASCIISubtractTab(PetscViewer viewer, PetscInt tabs)
341 {
342   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
343   PetscBool          iascii;
344 
345   PetscFunctionBegin;
346   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
347   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
348   if (iascii) ascii->tab -= tabs;
349   PetscFunctionReturn(PETSC_SUCCESS);
350 }
351 
352 /*@C
353   PetscViewerASCIIPushSynchronized - Allows calls to `PetscViewerASCIISynchronizedPrintf()` for this viewer
354 
355   Collective
356 
357   Input Parameter:
358 . viewer - obtained with `PetscViewerASCIIOpen()`
359 
360   Level: intermediate
361 
362   Note:
363   See documentation of `PetscViewerASCIISynchronizedPrintf()` for more details how the synchronized output should be done properly.
364 
365 .seealso: [](sec_viewers), `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
366           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
367           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
368 @*/
369 PetscErrorCode PetscViewerASCIIPushSynchronized(PetscViewer viewer)
370 {
371   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
372   PetscBool          iascii;
373 
374   PetscFunctionBegin;
375   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
376   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
377   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
378   if (iascii) ascii->allowsynchronized++;
379   PetscFunctionReturn(PETSC_SUCCESS);
380 }
381 
382 /*@C
383   PetscViewerASCIIPopSynchronized - Undoes most recent `PetscViewerASCIIPushSynchronized()` for this viewer
384 
385   Collective
386 
387   Input Parameter:
388 . viewer - obtained with `PetscViewerASCIIOpen()`
389 
390   Level: intermediate
391 
392   Note:
393   See documentation of `PetscViewerASCIISynchronizedPrintf()` for more details how the synchronized output should be done properly.
394 
395 .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`,
396           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
397           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
398 @*/
399 PetscErrorCode PetscViewerASCIIPopSynchronized(PetscViewer viewer)
400 {
401   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
402   PetscBool          iascii;
403 
404   PetscFunctionBegin;
405   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
406   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
407   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
408   if (iascii) {
409     ascii->allowsynchronized--;
410     PetscCheck(ascii->allowsynchronized >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called more times than PetscViewerASCIIPushSynchronized()");
411   }
412   PetscFunctionReturn(PETSC_SUCCESS);
413 }
414 
415 /*@C
416   PetscViewerASCIIPushTab - Adds one more tab to the amount that `PetscViewerASCIIPrintf()`
417   lines are tabbed.
418 
419   Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support
420 
421   Input Parameter:
422 . viewer - obtained with `PetscViewerASCIIOpen()`
423 
424   Level: developer
425 
426 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
427           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
428           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
429 @*/
430 PetscErrorCode PetscViewerASCIIPushTab(PetscViewer viewer)
431 {
432   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
433   PetscBool          iascii;
434 
435   PetscFunctionBegin;
436   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
437   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
438   if (iascii) ascii->tab++;
439   PetscFunctionReturn(PETSC_SUCCESS);
440 }
441 
442 /*@C
443   PetscViewerASCIIPopTab - Removes one tab from the amount that `PetscViewerASCIIPrintf()` lines are tabbed that was provided by
444   `PetscViewerASCIIPushTab()`
445 
446   Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support
447 
448   Input Parameter:
449 . viewer - obtained with `PetscViewerASCIIOpen()`
450 
451   Level: developer
452 
453 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
454           `PetscViewerASCIIPushTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
455           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
456 @*/
457 PetscErrorCode PetscViewerASCIIPopTab(PetscViewer viewer)
458 {
459   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
460   PetscBool          iascii;
461 
462   PetscFunctionBegin;
463   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
464   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
465   if (iascii) {
466     PetscCheck(ascii->tab > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "More tabs popped than pushed");
467     ascii->tab--;
468   }
469   PetscFunctionReturn(PETSC_SUCCESS);
470 }
471 
472 /*@
473   PetscViewerASCIIUseTabs - Turns on or off the use of tabs with the `PETSCVIEWERASCII` `PetscViewer`
474 
475   Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support
476 
477   Input Parameters:
478 + viewer - obtained with `PetscViewerASCIIOpen()`
479 - flg    - `PETSC_TRUE` or `PETSC_FALSE`
480 
481   Level: developer
482 
483 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
484           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPushTab()`, `PetscViewerASCIIOpen()`,
485           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
486 @*/
487 PetscErrorCode PetscViewerASCIIUseTabs(PetscViewer viewer, PetscBool flg)
488 {
489   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
490   PetscBool          iascii;
491 
492   PetscFunctionBegin;
493   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
494   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
495   if (iascii) {
496     if (flg) ascii->tab = ascii->tab_store;
497     else {
498       ascii->tab_store = ascii->tab;
499       ascii->tab       = 0;
500     }
501   }
502   PetscFunctionReturn(PETSC_SUCCESS);
503 }
504 
505 #if defined(PETSC_USE_FORTRAN_BINDINGS)
506 
507   #if defined(PETSC_HAVE_FORTRAN_CAPS)
508     #define petscviewerasciiopenwithfileunit_ PETSCVIEWERASCIIOPENWITHFILEUNIT
509     #define petscviewerasciisetfilefileunit_  PETSCVIEWERASCIISETFILEUNIT
510     #define petscfortranprinttounit_          PETSCFORTRANPRINTTOUNIT
511   #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE)
512     #define petscviewerasciiopenwithfileunit_ petscviewerasciiopenwithfileunit
513     #define petscviewerasciisetfileunit_      petscviewerasciisetfileunit
514     #define petscfortranprinttounit_          petscfortranprinttounit
515   #endif
516 
517   #if defined(__cplusplus)
518 extern "C" void petscfortranprinttounit_(PetscInt *, const char *, PetscErrorCode *, PETSC_FORTRAN_CHARLEN_T);
519   #else
520 extern void petscfortranprinttounit_(PetscInt *, const char *, PetscErrorCode *, PETSC_FORTRAN_CHARLEN_T);
521   #endif
522 
523   #define PETSCDEFAULTBUFFERSIZE 8 * 1024
524 
525 // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
526 /*MC
527   PetscViewerASCIISetFileUnit - sets the `PETSCVIEWERASCII` to write to a Fortran IO unit
528 
529   Synopsis:
530   #include <petscviewer.h>
531   void PetscViewerASCIISetFileUnit(PetscViewer lab, PetscInt unit, PetscErrorCode ierr)
532 
533   Input Parameters:
534 + lab  - the viewer
535 - unit - the unit number
536 
537   Output Parameter:
538 . ierr - the error code
539 
540   Level: intermediate
541 
542   Note:
543   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`
544 
545   Fortran Notes:
546   Only for Fortran, use  `PetscViewerASCIISetFILE()` for C
547 
548 .seealso: `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFileUnit()`
549 M*/
550 PETSC_EXTERN void petscviewerasciisetfileunit_(PetscViewer *lab, PetscInt *unit, PetscErrorCode *ierr)
551 {
552   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)(*lab)->data;
553 
554   if (vascii->mode == FILE_MODE_READ) {
555     *ierr = PETSC_ERR_ARG_WRONGSTATE;
556     return;
557   }
558   vascii->fileunit = *unit;
559 }
560 
561 // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
562 /*MC
563   PetscViewerASCIIOpenWithFileUnit - opens a `PETSCVIEWERASCII` to write to a Fortran IO unit
564 
565   Synopsis:
566   #include <petscviewer.h>
567   void PetscViewerASCIIOpenWithFileUnit(MPI_Comm comm, PetscInt unit, PetscViewer viewer, PetscErrorCode ierr)
568 
569   Input Parameters:
570 + comm - the `MPI_Comm` to share the viewer
571 - unit - the unit number
572 
573   Output Parameters:
574 + lab  - the viewer
575 - ierr - the error code
576 
577   Level: intermediate
578 
579   Note:
580   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`
581 
582   Fortran Notes:
583   Only for Fortran, use  `PetscViewerASCIIOpenWithFILE()` for C
584 
585 .seealso: `PetscViewerASCIISetFileUnit()`, `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFILE()`
586 M*/
587 PETSC_EXTERN void petscviewerasciiopenwithfileunit_(MPI_Comm *comm, PetscInt *unit, PetscViewer *lab, PetscErrorCode *ierr)
588 {
589   *ierr = PetscViewerCreate(MPI_Comm_f2c(*(MPI_Fint *)&*comm), lab);
590   if (*ierr) return;
591   *ierr = PetscViewerSetType(*lab, PETSCVIEWERASCII);
592   if (*ierr) return;
593   *ierr = PetscViewerFileSetMode(*lab, FILE_MODE_WRITE);
594   if (*ierr) return;
595   petscviewerasciisetfileunit_(lab, unit, ierr);
596 }
597 
598 static PetscErrorCode PetscVFPrintfFortran(PetscInt unit, const char format[], va_list Argp)
599 {
600   PetscErrorCode ierr;
601   char           str[PETSCDEFAULTBUFFERSIZE];
602   size_t         len;
603 
604   PetscFunctionBegin;
605   PetscCall(PetscVSNPrintf(str, sizeof(str), format, NULL, Argp));
606   PetscCall(PetscStrlen(str, &len));
607   petscfortranprinttounit_(&unit, str, &ierr, (int)len);
608   PetscFunctionReturn(PETSC_SUCCESS);
609 }
610 
611 static PetscErrorCode PetscFPrintfFortran(PetscInt unit, const char str[])
612 {
613   PetscErrorCode ierr;
614   size_t         len;
615 
616   PetscFunctionBegin;
617   PetscCall(PetscStrlen(str, &len));
618   petscfortranprinttounit_(&unit, str, &ierr, (int)len);
619   PetscFunctionReturn(PETSC_SUCCESS);
620 }
621 
622 #else
623 
624 /* these will never be used; but are needed to link with */
625 static PetscErrorCode PetscVFPrintfFortran(PetscInt unit, const char format[], va_list Argp)
626 {
627   PetscFunctionBegin;
628   PetscFunctionReturn(PETSC_SUCCESS);
629 }
630 
631 static PetscErrorCode PetscFPrintfFortran(PetscInt unit, const char str[])
632 {
633   PetscFunctionBegin;
634   PetscFunctionReturn(PETSC_SUCCESS);
635 }
636 #endif
637 
638 /*@C
639   PetscViewerASCIIPrintf - Prints to a file, only from the first
640   processor in the `PetscViewer` of type `PETSCVIEWERASCII`
641 
642   Not Collective, but only the first MPI rank in the viewer has any effect
643 
644   Input Parameters:
645 + viewer - obtained with `PetscViewerASCIIOpen()`
646 - format - the usual printf() format string
647 
648   Level: developer
649 
650   Fortran Notes:
651   The call sequence is `PetscViewerASCIIPrintf`(`PetscViewer`, character(*), int ierr) from Fortran.
652   That is, you can only pass a single character string from Fortran.
653 
654 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
655           `PetscViewerASCIIPushTab()`, `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`,
656           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushSynchronized()`
657 @*/
658 PetscErrorCode PetscViewerASCIIPrintf(PetscViewer viewer, const char format[], ...)
659 {
660   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
661   PetscMPIInt        rank;
662   PetscInt           tab, intab = ascii->tab;
663   FILE              *fd = ascii->fd;
664   PetscBool          iascii;
665 
666   PetscFunctionBegin;
667   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
668   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
669   PetscAssertPointer(format, 2);
670   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
671   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
672   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
673   if (rank) PetscFunctionReturn(PETSC_SUCCESS);
674 
675   if (ascii->bviewer) { /* pass string up to parent viewer */
676     char   *string;
677     va_list Argp;
678     size_t  fullLength;
679 
680     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
681     va_start(Argp, format);
682     PetscCall(PetscVSNPrintf(string, QUEUESTRINGSIZE, format, &fullLength, Argp));
683     va_end(Argp);
684     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%s", string));
685     PetscCall(PetscFree(string));
686   } else { /* write directly to file */
687     va_list Argp;
688     /* flush my own messages that I may have queued up */
689     PrintfQueue next = ascii->petsc_printfqueuebase, previous;
690     PetscInt    i;
691     for (i = 0; i < ascii->petsc_printfqueuelength; i++) {
692       if (!ascii->fileunit) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "%s", next->string));
693       else PetscCall(PetscFPrintfFortran(ascii->fileunit, next->string));
694       previous = next;
695       next     = next->next;
696       PetscCall(PetscFree(previous->string));
697       PetscCall(PetscFree(previous));
698     }
699     ascii->petsc_printfqueue       = NULL;
700     ascii->petsc_printfqueuelength = 0;
701     tab                            = intab;
702     while (tab--) {
703       if (!ascii->fileunit) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "  "));
704       else PetscCall(PetscFPrintfFortran(ascii->fileunit, "   "));
705     }
706 
707     va_start(Argp, format);
708     if (!ascii->fileunit) PetscCall((*PetscVFPrintf)(fd, format, Argp));
709     else PetscCall(PetscVFPrintfFortran(ascii->fileunit, format, Argp));
710     va_end(Argp);
711     PetscCall(PetscFFlush(fd));
712   }
713   PetscFunctionReturn(PETSC_SUCCESS);
714 }
715 
716 /*@C
717   PetscViewerFileSetName - Sets the name of the file the `PetscViewer` should use.
718 
719   Collective
720 
721   Input Parameters:
722 + viewer - the `PetscViewer`; for example, of type `PETSCVIEWERASCII` or `PETSCVIEWERBINARY`
723 - name   - the name of the file it should use
724 
725   Level: advanced
726 
727   Note:
728   This will have no effect on viewers that are not related to files
729 
730 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerDestroy()`,
731           `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`
732 @*/
733 PetscErrorCode PetscViewerFileSetName(PetscViewer viewer, const char name[])
734 {
735   char filename[PETSC_MAX_PATH_LEN];
736 
737   PetscFunctionBegin;
738   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
739   PetscAssertPointer(name, 2);
740   PetscCall(PetscStrreplace(PetscObjectComm((PetscObject)viewer), name, filename, sizeof(filename)));
741   PetscTryMethod(viewer, "PetscViewerFileSetName_C", (PetscViewer, const char[]), (viewer, filename));
742   PetscFunctionReturn(PETSC_SUCCESS);
743 }
744 
745 /*@C
746   PetscViewerFileGetName - Gets the name of the file the `PetscViewer` is using
747 
748   Not Collective
749 
750   Input Parameter:
751 . viewer - the `PetscViewer`
752 
753   Output Parameter:
754 . name - the name of the file it is using
755 
756   Level: advanced
757 
758   Note:
759   This will have no effect on viewers that are not related to files
760 
761 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerFileSetName()`
762 @*/
763 PetscErrorCode PetscViewerFileGetName(PetscViewer viewer, const char **name)
764 {
765   PetscFunctionBegin;
766   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
767   PetscAssertPointer(name, 2);
768   PetscUseMethod(viewer, "PetscViewerFileGetName_C", (PetscViewer, const char **), (viewer, name));
769   PetscFunctionReturn(PETSC_SUCCESS);
770 }
771 
772 static PetscErrorCode PetscViewerFileGetName_ASCII(PetscViewer viewer, const char **name)
773 {
774   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
775 
776   PetscFunctionBegin;
777   *name = vascii->filename;
778   PetscFunctionReturn(PETSC_SUCCESS);
779 }
780 
781 #include <errno.h>
782 static PetscErrorCode PetscViewerFileSetName_ASCII(PetscViewer viewer, const char name[])
783 {
784   size_t             len;
785   char               fname[PETSC_MAX_PATH_LEN], *gz = NULL;
786   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
787   PetscBool          isstderr, isstdout;
788   PetscMPIInt        rank;
789 
790   PetscFunctionBegin;
791   PetscCall(PetscViewerFileClose_ASCII(viewer));
792   if (!name) PetscFunctionReturn(PETSC_SUCCESS);
793   PetscCall(PetscStrallocpy(name, &vascii->filename));
794 
795   /* Is this file to be compressed */
796   vascii->storecompressed = PETSC_FALSE;
797 
798   PetscCall(PetscStrstr(vascii->filename, ".gz", &gz));
799   if (gz) {
800     PetscCall(PetscStrlen(gz, &len));
801     if (len == 3) {
802       PetscCheck(vascii->mode == FILE_MODE_WRITE, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Cannot open ASCII PetscViewer file that is compressed; uncompress it manually first");
803       *gz                     = 0;
804       vascii->storecompressed = PETSC_TRUE;
805     }
806   }
807   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
808   if (rank == 0) {
809     PetscCall(PetscStrcmp(name, "stderr", &isstderr));
810     PetscCall(PetscStrcmp(name, "stdout", &isstdout));
811     /* empty filename means stdout */
812     if (name[0] == 0) isstdout = PETSC_TRUE;
813     if (isstderr) vascii->fd = PETSC_STDERR;
814     else if (isstdout) vascii->fd = PETSC_STDOUT;
815     else {
816       PetscCall(PetscFixFilename(name, fname));
817       switch (vascii->mode) {
818       case FILE_MODE_READ:
819         vascii->fd = fopen(fname, "r");
820         break;
821       case FILE_MODE_WRITE:
822         vascii->fd = fopen(fname, "w");
823         break;
824       case FILE_MODE_APPEND:
825         vascii->fd = fopen(fname, "a");
826         break;
827       case FILE_MODE_UPDATE:
828         vascii->fd = fopen(fname, "r+");
829         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
830         break;
831       case FILE_MODE_APPEND_UPDATE:
832         /* I really want a file which is opened at the end for updating,
833            not a+, which opens at the beginning, but makes writes at the end.
834         */
835         vascii->fd = fopen(fname, "r+");
836         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
837         else {
838           int ret = fseek(vascii->fd, 0, SEEK_END);
839           PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "fseek() failed with error code %d", ret);
840         }
841         break;
842       default:
843         SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vascii->mode]);
844       }
845       PetscCheck(vascii->fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open PetscViewer file: %s due to \"%s\"", fname, strerror(errno));
846     }
847   }
848   PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", name));
849   PetscFunctionReturn(PETSC_SUCCESS);
850 }
851 
852 static PetscErrorCode PetscViewerGetSubViewer_ASCII(PetscViewer viewer, MPI_Comm subcomm, PetscViewer *outviewer)
853 {
854   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data, *ovascii;
855 
856   PetscFunctionBegin;
857   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
858   PetscCheck(!vascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer already obtained from PetscViewer and not restored");
859   /*
860      The following line is a bug; it does another PetscViewerASCIIPushSynchronized() on viewer, but if it is removed the code won't work
861      because it relies on this behavior in other places. In particular this line causes the synchronized flush to occur when the viewer is destroyed
862      (since the count never gets to zero) in some examples this displays information that otherwise would be lost
863 
864      This code also means another call to PetscViewerASCIIPopSynchronized() must be made after the PetscViewerRestoreSubViewer(), see, for example,
865      PCView_GASM().
866   */
867   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
868   PetscCall(PetscViewerCreate(subcomm, outviewer));
869   PetscCall(PetscViewerSetType(*outviewer, PETSCVIEWERASCII));
870   PetscCall(PetscViewerASCIIPushSynchronized(*outviewer));
871   ovascii            = (PetscViewer_ASCII *)(*outviewer)->data;
872   ovascii->fd        = vascii->fd;
873   ovascii->tab       = vascii->tab;
874   ovascii->closefile = PETSC_FALSE;
875 
876   vascii->sviewer                                      = *outviewer;
877   (*outviewer)->format                                 = viewer->format;
878   ((PetscViewer_ASCII *)((*outviewer)->data))->bviewer = viewer;
879   (*outviewer)->ops->destroy                           = PetscViewerDestroy_ASCII_SubViewer;
880   PetscFunctionReturn(PETSC_SUCCESS);
881 }
882 
883 static PetscErrorCode PetscViewerRestoreSubViewer_ASCII(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer)
884 {
885   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
886 
887   PetscFunctionBegin;
888   PetscCheck(ascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer never obtained from PetscViewer");
889   PetscCheck(ascii->sviewer == *outviewer, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "This PetscViewer did not generate this SubViewer");
890 
891   PetscCall(PetscViewerASCIIPopSynchronized(*outviewer));
892   ascii->sviewer             = NULL;
893   (*outviewer)->ops->destroy = PetscViewerDestroy_ASCII;
894   PetscCall(PetscViewerDestroy(outviewer));
895   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
896   PetscFunctionReturn(PETSC_SUCCESS);
897 }
898 
899 static PetscErrorCode PetscViewerView_ASCII(PetscViewer v, PetscViewer viewer)
900 {
901   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)v->data;
902 
903   PetscFunctionBegin;
904   if (ascii->filename) PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", ascii->filename));
905   PetscFunctionReturn(PETSC_SUCCESS);
906 }
907 
908 /*MC
909    PETSCVIEWERASCII - A viewer that prints to stdout or an ASCII file
910 
911   Level: beginner
912 
913 .seealso: [](sec_viewers), `PETSC_VIEWER_STDOUT_()`, `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`,
914           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`,
915           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
916 M*/
917 PETSC_EXTERN PetscErrorCode PetscViewerCreate_ASCII(PetscViewer viewer)
918 {
919   PetscViewer_ASCII *vascii;
920 
921   PetscFunctionBegin;
922   PetscCall(PetscNew(&vascii));
923   viewer->data = (void *)vascii;
924 
925   viewer->ops->destroy          = PetscViewerDestroy_ASCII;
926   viewer->ops->flush            = PetscViewerFlush_ASCII;
927   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_ASCII;
928   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_ASCII;
929   viewer->ops->view             = PetscViewerView_ASCII;
930   viewer->ops->read             = PetscViewerASCIIRead;
931 
932   /* defaults to stdout unless set with PetscViewerFileSetName() */
933   vascii->fd        = PETSC_STDOUT;
934   vascii->mode      = FILE_MODE_WRITE;
935   vascii->bviewer   = NULL;
936   vascii->subviewer = NULL;
937   vascii->sviewer   = NULL;
938   vascii->tab       = 0;
939   vascii->tab_store = 0;
940   vascii->filename  = NULL;
941   vascii->closefile = PETSC_TRUE;
942 
943   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_ASCII));
944   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_ASCII));
945   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_ASCII));
946   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_ASCII));
947   PetscFunctionReturn(PETSC_SUCCESS);
948 }
949 
950 /*@C
951   PetscViewerASCIISynchronizedPrintf - Prints synchronized output to the specified `PETSCVIEWERASCII` file from
952   several processors.  Output of the first processor is followed by that of the
953   second, etc.
954 
955   Not Collective, must call collective `PetscViewerFlush()` to get the results flushed
956 
957   Input Parameters:
958 + viewer - the `PETSCVIEWERASCII` `PetscViewer`
959 - format - the usual printf() format string
960 
961   Level: intermediate
962 
963   Notes:
964   You must have previously called `PetscViewerASCIIPushSynchronized()` to allow this routine to be called.
965   Then you can do multiple independent calls to this routine.
966 
967   The actual synchronized print is then done using `PetscViewerFlush()`.
968   `PetscViewerASCIIPopSynchronized()` should be then called if we are already done with the synchronized output
969   to conclude the "synchronized session".
970 
971   So the typical calling sequence looks like
972 .vb
973     PetscViewerASCIIPushSynchronized(viewer);
974     PetscViewerASCIISynchronizedPrintf(viewer, ...);
975     PetscViewerASCIISynchronizedPrintf(viewer, ...);
976     ...
977     PetscViewerFlush(viewer);
978     PetscViewerASCIISynchronizedPrintf(viewer, ...);
979     PetscViewerASCIISynchronizedPrintf(viewer, ...);
980     ...
981     PetscViewerFlush(viewer);
982    PetscViewerASCIIPopSynchronized(viewer);
983 .ve
984 
985   Fortran Notes:
986   Can only print a single character* string
987 
988 .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
989           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
990           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
991 @*/
992 PetscErrorCode PetscViewerASCIISynchronizedPrintf(PetscViewer viewer, const char format[], ...)
993 {
994   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
995   PetscMPIInt        rank;
996   PetscInt           tab = vascii->tab;
997   MPI_Comm           comm;
998   FILE              *fp;
999   PetscBool          iascii, hasbviewer = PETSC_FALSE;
1000 
1001   PetscFunctionBegin;
1002   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1003   PetscAssertPointer(format, 2);
1004   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1005   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
1006   PetscCheck(vascii->allowsynchronized, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "First call PetscViewerASCIIPushSynchronized() to allow this call");
1007 
1008   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
1009   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1010 
1011   if (vascii->bviewer) {
1012     hasbviewer = PETSC_TRUE;
1013     if (rank == 0) {
1014       vascii = (PetscViewer_ASCII *)vascii->bviewer->data;
1015       PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
1016       PetscCallMPI(MPI_Comm_rank(comm, &rank));
1017     }
1018   }
1019 
1020   fp = vascii->fd;
1021 
1022   if (rank == 0 && !hasbviewer) { /* First processor prints immediately to fp */
1023     va_list Argp;
1024     /* flush my own messages that I may have queued up */
1025     PrintfQueue next = vascii->petsc_printfqueuebase, previous;
1026     PetscInt    i;
1027     for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
1028       PetscCall(PetscFPrintf(comm, fp, "%s", next->string));
1029       previous = next;
1030       next     = next->next;
1031       PetscCall(PetscFree(previous->string));
1032       PetscCall(PetscFree(previous));
1033     }
1034     vascii->petsc_printfqueue       = NULL;
1035     vascii->petsc_printfqueuelength = 0;
1036 
1037     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fp, "  "));
1038 
1039     va_start(Argp, format);
1040     PetscCall((*PetscVFPrintf)(fp, format, Argp));
1041     va_end(Argp);
1042     PetscCall(PetscFFlush(fp));
1043     if (petsc_history) {
1044       va_start(Argp, format);
1045       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
1046       va_end(Argp);
1047       PetscCall(PetscFFlush(petsc_history));
1048     }
1049     va_end(Argp);
1050   } else { /* other processors add to queue */
1051     char       *string;
1052     va_list     Argp;
1053     size_t      fullLength;
1054     PrintfQueue next;
1055 
1056     PetscCall(PetscNew(&next));
1057     if (vascii->petsc_printfqueue) {
1058       vascii->petsc_printfqueue->next = next;
1059       vascii->petsc_printfqueue       = next;
1060     } else {
1061       vascii->petsc_printfqueuebase = vascii->petsc_printfqueue = next;
1062     }
1063     vascii->petsc_printfqueuelength++;
1064     next->size = QUEUESTRINGSIZE;
1065     PetscCall(PetscCalloc1(next->size, &next->string));
1066     string = next->string;
1067     tab *= 2;
1068     while (tab--) *string++ = ' ';
1069     va_start(Argp, format);
1070     PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, &fullLength, Argp));
1071     va_end(Argp);
1072     if (fullLength > (size_t)(next->size - 2 * vascii->tab)) {
1073       PetscCall(PetscFree(next->string));
1074       next->size = fullLength + 2 * vascii->tab;
1075       PetscCall(PetscCalloc1(next->size, &next->string));
1076       string = next->string;
1077       tab    = 2 * vascii->tab;
1078       while (tab--) *string++ = ' ';
1079       va_start(Argp, format);
1080       PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, NULL, Argp));
1081       va_end(Argp);
1082     }
1083   }
1084   PetscFunctionReturn(PETSC_SUCCESS);
1085 }
1086 
1087 /*@C
1088   PetscViewerASCIIRead - Reads from a `PETSCVIEWERASCII` file
1089 
1090   Only MPI rank 0 in the `PetscViewer` may call this
1091 
1092   Input Parameters:
1093 + viewer - the `PETSCVIEWERASCII` viewer
1094 . data   - location to write the data, treated as an array of type indicated by `datatype`
1095 . num    - number of items of data to read
1096 - dtype  - type of data to read
1097 
1098   Output Parameter:
1099 . count - number of items of data actually read, or `NULL`
1100 
1101   Level: beginner
1102 
1103 .seealso: [](sec_viewers), `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetName()`
1104           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
1105           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
1106 @*/
1107 PetscErrorCode PetscViewerASCIIRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype)
1108 {
1109   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
1110   FILE              *fd     = vascii->fd;
1111   PetscInt           i;
1112   int                ret = 0;
1113   PetscMPIInt        rank;
1114 
1115   PetscFunctionBegin;
1116   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1117   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
1118   PetscCheck(rank == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Can only be called from process 0 in the PetscViewer");
1119   for (i = 0; i < num; i++) {
1120     if (dtype == PETSC_CHAR) ret = fscanf(fd, "%c", &(((char *)data)[i]));
1121     else if (dtype == PETSC_STRING) ret = fscanf(fd, "%s", &(((char *)data)[i]));
1122     else if (dtype == PETSC_INT) ret = fscanf(fd, "%" PetscInt_FMT, &(((PetscInt *)data)[i]));
1123     else if (dtype == PETSC_ENUM) ret = fscanf(fd, "%d", &(((int *)data)[i]));
1124     else if (dtype == PETSC_INT64) ret = fscanf(fd, "%" PetscInt64_FMT, &(((PetscInt64 *)data)[i]));
1125     else if (dtype == PETSC_LONG) ret = fscanf(fd, "%ld", &(((long *)data)[i]));
1126     else if (dtype == PETSC_FLOAT) ret = fscanf(fd, "%f", &(((float *)data)[i]));
1127     else if (dtype == PETSC_DOUBLE) ret = fscanf(fd, "%lg", &(((double *)data)[i]));
1128 #if defined(PETSC_USE_REAL___FLOAT128)
1129     else if (dtype == PETSC___FLOAT128) {
1130       double tmp;
1131       ret                     = fscanf(fd, "%lg", &tmp);
1132       ((__float128 *)data)[i] = tmp;
1133     }
1134 #endif
1135     else
1136       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data type %d not supported", (int)dtype);
1137     PetscCheck(ret, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Conversion error for data type %d", (int)dtype);
1138     if (ret < 0) break; /* Proxy for EOF, need to check for it in configure */
1139   }
1140   if (count) *count = i;
1141   else PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Insufficient data, read only %" PetscInt_FMT " < %" PetscInt_FMT " items", i, num);
1142   PetscFunctionReturn(PETSC_SUCCESS);
1143 }
1144