xref: /petsc/src/sys/classes/viewer/impls/ascii/filev.c (revision 8a7d4057d9226490dba4e1a062f54f84e7d90861)
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 %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 static PetscErrorCode PetscViewerDestroy_ASCII(PetscViewer viewer)
38 {
39   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
40   PetscViewerLink   *vlink;
41   PetscBool          flg;
42 
43   PetscFunctionBegin;
44   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
45   PetscCall(PetscViewerFileClose_ASCII(viewer));
46   PetscCall(PetscFree(vascii));
47 
48   /* remove the viewer from the list in the MPI Communicator */
49   if (Petsc_Viewer_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelViewer, &Petsc_Viewer_keyval, (void *)0));
50 
51   PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval, (void **)&vlink, (PetscMPIInt *)&flg));
52   if (flg) {
53     if (vlink && vlink->viewer == viewer) {
54       if (vlink->next) {
55         PetscCallMPI(MPI_Comm_set_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval, vlink->next));
56       } else {
57         PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval));
58       }
59       PetscCall(PetscFree(vlink));
60     } else {
61       while (vlink && vlink->next) {
62         if (vlink->next->viewer == viewer) {
63           PetscViewerLink *nv = vlink->next;
64           vlink->next         = vlink->next->next;
65           PetscCall(PetscFree(nv));
66         }
67         vlink = vlink->next;
68       }
69     }
70   }
71 
72   if (Petsc_Viewer_Stdout_keyval != MPI_KEYVAL_INVALID) {
73     PetscViewer aviewer;
74     PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stdout_keyval, (void **)&aviewer, (PetscMPIInt *)&flg));
75     if (flg && aviewer == viewer) PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stdout_keyval));
76   }
77   if (Petsc_Viewer_Stderr_keyval != MPI_KEYVAL_INVALID) {
78     PetscViewer aviewer;
79     PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stderr_keyval, (void **)&aviewer, (PetscMPIInt *)&flg));
80     if (flg && aviewer == viewer) PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stderr_keyval));
81   }
82   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", NULL));
83   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", NULL));
84   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", NULL));
85   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", NULL));
86   PetscFunctionReturn(PETSC_SUCCESS);
87 }
88 
89 static PetscErrorCode PetscViewerDestroy_ASCII_SubViewer(PetscViewer viewer)
90 {
91   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
92 
93   PetscFunctionBegin;
94   PetscCall(PetscViewerRestoreSubViewer(vascii->bviewer, 0, &viewer));
95   PetscFunctionReturn(PETSC_SUCCESS);
96 }
97 
98 static PetscErrorCode PetscViewerFlush_ASCII(PetscViewer viewer)
99 {
100   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
101   MPI_Comm           comm;
102   PetscMPIInt        rank, size;
103   FILE              *fd = vascii->fd;
104 
105   PetscFunctionBegin;
106   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
107   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
108   PetscCallMPI(MPI_Comm_rank(comm, &rank));
109   PetscCallMPI(MPI_Comm_size(comm, &size));
110 
111   if (!vascii->bviewer && rank == 0 && (vascii->mode != FILE_MODE_READ)) PetscCall(PetscFFlush(vascii->fd));
112 
113   if (vascii->allowsynchronized) {
114     PetscMPIInt tag, i, j, n = 0, dummy = 0;
115     char       *message;
116     MPI_Status  status;
117 
118     PetscCall(PetscCommDuplicate(comm, &comm, &tag));
119 
120     /* First processor waits for messages from all other processors */
121     if (rank == 0) {
122       /* flush my own messages that I may have queued up */
123       PrintfQueue next = vascii->petsc_printfqueuebase, previous;
124       for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
125         if (!vascii->bviewer) {
126           PetscCall(PetscFPrintf(comm, fd, "%s", next->string));
127         } else {
128           PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", next->string));
129         }
130         previous = next;
131         next     = next->next;
132         PetscCall(PetscFree(previous->string));
133         PetscCall(PetscFree(previous));
134       }
135       vascii->petsc_printfqueue       = NULL;
136       vascii->petsc_printfqueuelength = 0;
137       for (i = 1; i < size; i++) {
138         /* to prevent a flood of messages to process zero, request each message separately */
139         PetscCallMPI(MPI_Send(&dummy, 1, MPI_INT, i, tag, comm));
140         PetscCallMPI(MPI_Recv(&n, 1, MPI_INT, i, tag, comm, &status));
141         for (j = 0; j < n; j++) {
142           PetscMPIInt size = 0;
143 
144           PetscCallMPI(MPI_Recv(&size, 1, MPI_INT, i, tag, comm, &status));
145           PetscCall(PetscMalloc1(size, &message));
146           PetscCallMPI(MPI_Recv(message, size, MPI_CHAR, i, tag, comm, &status));
147           if (!vascii->bviewer) {
148             PetscCall(PetscFPrintf(comm, fd, "%s", message));
149           } else {
150             PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", message));
151           }
152           PetscCall(PetscFree(message));
153         }
154       }
155     } else { /* other processors send queue to processor 0 */
156       PrintfQueue next = vascii->petsc_printfqueuebase, previous;
157 
158       PetscCallMPI(MPI_Recv(&dummy, 1, MPI_INT, 0, tag, comm, &status));
159       PetscCallMPI(MPI_Send(&vascii->petsc_printfqueuelength, 1, MPI_INT, 0, tag, comm));
160       for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
161         PetscCallMPI(MPI_Send(&next->size, 1, MPI_INT, 0, tag, comm));
162         PetscCallMPI(MPI_Send(next->string, next->size, MPI_CHAR, 0, tag, comm));
163         previous = next;
164         next     = next->next;
165         PetscCall(PetscFree(previous->string));
166         PetscCall(PetscFree(previous));
167       }
168       vascii->petsc_printfqueue       = NULL;
169       vascii->petsc_printfqueuelength = 0;
170     }
171     PetscCall(PetscCommDestroy(&comm));
172   }
173   PetscFunctionReturn(PETSC_SUCCESS);
174 }
175 
176 /*@C
177   PetscViewerASCIIGetPointer - Extracts the file pointer from an ASCII `PetscViewer`.
178 
179   Not Collective, depending on the viewer the value may be meaningless except for process 0 of the viewer; No Fortran Support
180 
181   Input Parameter:
182 . viewer - `PetscViewer` context, obtained from `PetscViewerASCIIOpen()`
183 
184   Output Parameter:
185 . fd - file pointer
186 
187   Level: intermediate
188 
189   Note:
190   For the standard `PETSCVIEWERASCII` the value is valid only on MPI rank 0 of the viewer
191 
192 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscViewerASCIIOpen()`, `PetscViewerDestroy()`, `PetscViewerSetType()`,
193           `PetscViewerCreate()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`
194 @*/
195 PetscErrorCode PetscViewerASCIIGetPointer(PetscViewer viewer, FILE **fd)
196 {
197   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
198 
199   PetscFunctionBegin;
200   PetscCheck(!vascii->fileunit, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot request file pointer for viewers that use Fortran files");
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 /*@
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 /*@
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 /*@
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 /*@
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 petscviewerasciisetfileunit_      PETSCVIEWERASCIISETFILEUNIT
510     #define petscviewerasciiworldsetfileunit_ PETSCVIEWERASCIIWORLDSETFILEUNIT
511     #define petscfortranprinttounit_          PETSCFORTRANPRINTTOUNIT
512   #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE)
513     #define petscviewerasciiopenwithfileunit_ petscviewerasciiopenwithfileunit
514     #define petscviewerasciisetfileunit_      petscviewerasciisetfileunit
515     #define petscviewerasciiworldsetfileunit_ petscviewerasciiworldsetfileunit
516     #define petscfortranprinttounit_          petscfortranprinttounit
517   #endif
518 
519   #if defined(__cplusplus)
520 extern "C" void petscfortranprinttounit_(PetscInt *, const char *, PetscErrorCode *, PETSC_FORTRAN_CHARLEN_T);
521   #else
522 extern void petscfortranprinttounit_(PetscInt *, const char *, PetscErrorCode *, PETSC_FORTRAN_CHARLEN_T);
523   #endif
524 
525   #define PETSCDEFAULTBUFFERSIZE 8 * 1024
526 
527 static PetscInt PETSC_VIEWER_ASCII_WORLD_fileunit = 0;
528 
529 // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
530 /*MC
531   PetscViewerASCIIWORLDSetFileUnit - sets `PETSC_VIEWER_STDOUT_WORLD` to write to a Fortran IO unit
532 
533   Synopsis:
534   #include <petscviewer.h>
535   void PetscViewerASCIIWORLDSetFileUnit(PetscInt unit, PetscErrorCode ierr)
536 
537   Input Parameter:
538 . unit - the unit number
539 
540   Output Parameter:
541 . ierr - the error code
542 
543   Level: intermediate
544 
545   Notes:
546   Must be called before `PetscInitialize()`
547 
548   This may not work currently with some viewers that (improperly) use the `fd` directly instead of `PetscViewerASCIIPrintf()`
549 
550   With this option, for example, `-log_options` results will be saved to the Fortran file
551 
552   Any process may call this but only the unit passed on the first process is used
553 
554   Fortran Note:
555   Only for Fortran
556 
557   Developer Note:
558   `PetscViewerASCIIWORLDSetFilename()` could be added in the future
559 
560 .seealso: `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFileUnit()`, `PetscViewerASCIIWORLDSetFileUnit()`
561 M*/
562 PETSC_EXTERN void petscviewerasciiworldsetfileunit_(PetscInt *unit, PetscErrorCode *ierr)
563 {
564   PETSC_VIEWER_ASCII_WORLD_fileunit = *unit;
565 }
566 
567   #include <petsc/private/fortranimpl.h>
568 
569 // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
570 /*MC
571   PetscViewerASCIISetFileUnit - sets the `PETSCVIEWERASCII` to write to a Fortran IO unit
572 
573   Synopsis:
574   #include <petscviewer.h>
575   void PetscViewerASCIISetFileUnit(PetscViewer lab, PetscInt unit, PetscErrorCode ierr)
576 
577   Input Parameters:
578 + lab  - the viewer
579 - unit - the unit number
580 
581   Output Parameter:
582 . ierr - the error code
583 
584   Level: intermediate
585 
586   Note:
587   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`
588 
589   Fortran Notes:
590   Only for Fortran, use  `PetscViewerASCIISetFILE()` for C
591 
592 .seealso: `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFileUnit()`, `PetscViewerASCIIWORLDSetFileUnit()`
593 M*/
594 PETSC_EXTERN void petscviewerasciisetfileunit_(PetscViewer *lab, PetscInt *unit, PetscErrorCode *ierr)
595 {
596   PetscViewer_ASCII *vascii;
597   PetscViewer        v;
598 
599   PetscPatchDefaultViewers_Fortran(lab, v);
600   vascii = (PetscViewer_ASCII *)v->data;
601   if (vascii->mode == FILE_MODE_READ) {
602     *ierr = PETSC_ERR_ARG_WRONGSTATE;
603     return;
604   }
605   vascii->fileunit = *unit;
606 }
607 
608 // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
609 /*MC
610   PetscViewerASCIIOpenWithFileUnit - opens a `PETSCVIEWERASCII` to write to a Fortran IO unit
611 
612   Synopsis:
613   #include <petscviewer.h>
614   void PetscViewerASCIIOpenWithFileUnit(MPI_Comm comm, PetscInt unit, PetscViewer viewer, PetscErrorCode ierr)
615 
616   Input Parameters:
617 + comm - the `MPI_Comm` to share the viewer
618 - unit - the unit number
619 
620   Output Parameters:
621 + lab  - the viewer
622 - ierr - the error code
623 
624   Level: intermediate
625 
626   Note:
627   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`
628 
629   Fortran Notes:
630   Only for Fortran, use  `PetscViewerASCIIOpenWithFILE()` for C
631 
632 .seealso: `PetscViewerASCIISetFileUnit()`, `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFILE()`
633 M*/
634 PETSC_EXTERN void petscviewerasciiopenwithfileunit_(MPI_Comm *comm, PetscInt *unit, PetscViewer *lab, PetscErrorCode *ierr)
635 {
636   *ierr = PetscViewerCreate(MPI_Comm_f2c(*(MPI_Fint *)&*comm), lab);
637   if (*ierr) return;
638   *ierr = PetscViewerSetType(*lab, PETSCVIEWERASCII);
639   if (*ierr) return;
640   *ierr = PetscViewerFileSetMode(*lab, FILE_MODE_WRITE);
641   if (*ierr) return;
642   petscviewerasciisetfileunit_(lab, unit, ierr);
643 }
644 
645 static PetscErrorCode PetscVFPrintfFortran(PetscInt unit, const char format[], va_list Argp)
646 {
647   PetscErrorCode ierr;
648   char           str[PETSCDEFAULTBUFFERSIZE];
649   size_t         len;
650 
651   PetscFunctionBegin;
652   PetscCall(PetscVSNPrintf(str, sizeof(str), format, NULL, Argp));
653   PetscCall(PetscStrlen(str, &len));
654   petscfortranprinttounit_(&unit, str, &ierr, (int)len);
655   PetscFunctionReturn(PETSC_SUCCESS);
656 }
657 
658 static PetscErrorCode PetscFPrintfFortran(PetscInt unit, const char str[])
659 {
660   PetscErrorCode ierr;
661   size_t         len;
662 
663   PetscFunctionBegin;
664   PetscCall(PetscStrlen(str, &len));
665   petscfortranprinttounit_(&unit, str, &ierr, (int)len);
666   PetscFunctionReturn(PETSC_SUCCESS);
667 }
668 
669 #else
670 
671 /* these will never be used; but are needed to link with */
672 static PetscErrorCode PetscVFPrintfFortran(PetscInt unit, const char format[], va_list Argp)
673 {
674   PetscFunctionBegin;
675   PetscFunctionReturn(PETSC_SUCCESS);
676 }
677 
678 static PetscErrorCode PetscFPrintfFortran(PetscInt unit, const char str[])
679 {
680   PetscFunctionBegin;
681   PetscFunctionReturn(PETSC_SUCCESS);
682 }
683 #endif
684 
685 /*@
686   PetscViewerASCIIGetStdout - Creates a `PETSCVIEWERASCII` `PetscViewer` shared by all processes
687   in a communicator that prints to `stdout`. Error returning version of `PETSC_VIEWER_STDOUT_()`
688 
689   Collective
690 
691   Input Parameter:
692 . comm - the MPI communicator to share the `PetscViewer`
693 
694   Output Parameter:
695 . viewer - the viewer
696 
697   Level: beginner
698 
699   Note:
700   Use `PetscViewerDestroy()` to destroy it
701 
702   Developer Note:
703   This should be used in all PETSc source code instead of `PETSC_VIEWER_STDOUT_()` since it allows error checking
704 
705 .seealso: [](sec_viewers), `PetscViewerASCIIGetStderr()`, `PETSC_VIEWER_DRAW_()`, `PetscViewerASCIIOpen()`, `PETSC_VIEWER_STDERR_`, `PETSC_VIEWER_STDOUT_WORLD`,
706           `PETSC_VIEWER_STDOUT_SELF`
707 @*/
708 PetscErrorCode PetscViewerASCIIGetStdout(MPI_Comm comm, PetscViewer *viewer)
709 {
710   PetscBool flg;
711   MPI_Comm  ncomm;
712 
713   PetscFunctionBegin;
714   PetscAssertPointer(viewer, 2);
715   PetscCall(PetscSpinlockLock(&PetscViewerASCIISpinLockStdout));
716   PetscCall(PetscCommDuplicate(comm, &ncomm, NULL));
717   if (Petsc_Viewer_Stdout_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Stdout_keyval, NULL));
718   PetscCallMPI(MPI_Comm_get_attr(ncomm, Petsc_Viewer_Stdout_keyval, (void **)viewer, (PetscMPIInt *)&flg));
719   if (!flg) { /* PetscViewer not yet created */
720 #if defined(PETSC_USE_FORTRAN_BINDINGS)
721     PetscMPIInt size, gsize;
722 
723     PetscCallMPI(MPI_Comm_size(comm, &size));
724     PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &gsize));
725     if (size == gsize) { PetscCallMPI(MPI_Bcast(&PETSC_VIEWER_ASCII_WORLD_fileunit, 1, MPIU_INT, 0, comm)); }
726     if (PETSC_VIEWER_ASCII_WORLD_fileunit) {
727       PetscErrorCode ierr;
728 
729       petscviewerasciiopenwithfileunit_(&ncomm, &PETSC_VIEWER_ASCII_WORLD_fileunit, viewer, &ierr);
730     } else
731 #endif
732     {
733       PetscCall(PetscViewerCreate(ncomm, viewer));
734       PetscCall(PetscViewerSetType(*viewer, PETSCVIEWERASCII));
735       PetscCall(PetscViewerFileSetName(*viewer, "stdout"));
736     }
737     PetscCall(PetscObjectRegisterDestroy((PetscObject)*viewer));
738     PetscCallMPI(MPI_Comm_set_attr(ncomm, Petsc_Viewer_Stdout_keyval, (void *)*viewer));
739   }
740   PetscCall(PetscCommDestroy(&ncomm));
741   PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockStdout));
742   PetscFunctionReturn(PETSC_SUCCESS);
743 }
744 
745 /*@C
746   PetscViewerASCIIPrintf - Prints to a file, only from the first
747   processor in the `PetscViewer` of type `PETSCVIEWERASCII`
748 
749   Not Collective, but only the first MPI rank in the viewer has any effect
750 
751   Input Parameters:
752 + viewer - obtained with `PetscViewerASCIIOpen()`
753 - format - the usual printf() format string
754 
755   Level: developer
756 
757   Fortran Notes:
758   The call sequence is `PetscViewerASCIIPrintf`(`PetscViewer`, character(*), int ierr) from Fortran.
759   That is, you can only pass a single character string from Fortran.
760 
761 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
762           `PetscViewerASCIIPushTab()`, `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`,
763           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushSynchronized()`
764 @*/
765 PetscErrorCode PetscViewerASCIIPrintf(PetscViewer viewer, const char format[], ...)
766 {
767   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
768   PetscMPIInt        rank;
769   PetscInt           tab = 0, intab = ascii->tab;
770   FILE              *fd = ascii->fd;
771   PetscBool          iascii;
772 
773   PetscFunctionBegin;
774   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
775   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
776   PetscAssertPointer(format, 2);
777   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
778   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
779   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
780   if (rank) PetscFunctionReturn(PETSC_SUCCESS);
781 
782   if (ascii->bviewer) { /* pass string up to parent viewer */
783     char   *string;
784     va_list Argp;
785     size_t  fullLength;
786 
787     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
788     for (; tab < ascii->tab; tab++) { string[2 * tab] = string[2 * tab + 1] = ' '; }
789     va_start(Argp, format);
790     PetscCall(PetscVSNPrintf(string + 2 * intab, QUEUESTRINGSIZE - 2 * intab, format, &fullLength, Argp));
791     va_end(Argp);
792     PetscCall(PetscViewerASCIISynchronizedPrintf(ascii->bviewer, "%s", string));
793     PetscCall(PetscFree(string));
794   } else { /* write directly to file */
795     va_list Argp;
796 
797     tab = intab;
798     while (tab--) {
799       if (!ascii->fileunit) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "  "));
800       else PetscCall(PetscFPrintfFortran(ascii->fileunit, "   "));
801     }
802 
803     va_start(Argp, format);
804     if (!ascii->fileunit) PetscCall((*PetscVFPrintf)(fd, format, Argp));
805     else PetscCall(PetscVFPrintfFortran(ascii->fileunit, format, Argp));
806     va_end(Argp);
807     PetscCall(PetscFFlush(fd));
808   }
809   PetscFunctionReturn(PETSC_SUCCESS);
810 }
811 
812 /*@
813   PetscViewerFileSetName - Sets the name of the file the `PetscViewer` should use.
814 
815   Collective
816 
817   Input Parameters:
818 + viewer - the `PetscViewer`; for example, of type `PETSCVIEWERASCII` or `PETSCVIEWERBINARY`
819 - name   - the name of the file it should use
820 
821   Level: advanced
822 
823   Note:
824   This will have no effect on viewers that are not related to files
825 
826 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerDestroy()`,
827           `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`
828 @*/
829 PetscErrorCode PetscViewerFileSetName(PetscViewer viewer, const char name[])
830 {
831   char filename[PETSC_MAX_PATH_LEN];
832 
833   PetscFunctionBegin;
834   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
835   PetscAssertPointer(name, 2);
836   PetscCall(PetscStrreplace(PetscObjectComm((PetscObject)viewer), name, filename, sizeof(filename)));
837   PetscTryMethod(viewer, "PetscViewerFileSetName_C", (PetscViewer, const char[]), (viewer, filename));
838   PetscFunctionReturn(PETSC_SUCCESS);
839 }
840 
841 /*@C
842   PetscViewerFileGetName - Gets the name of the file the `PetscViewer` is using
843 
844   Not Collective
845 
846   Input Parameter:
847 . viewer - the `PetscViewer`
848 
849   Output Parameter:
850 . name - the name of the file it is using
851 
852   Level: advanced
853 
854   Note:
855   This will have no effect on viewers that are not related to files
856 
857 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerFileSetName()`
858 @*/
859 PetscErrorCode PetscViewerFileGetName(PetscViewer viewer, const char *name[])
860 {
861   PetscFunctionBegin;
862   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
863   PetscAssertPointer(name, 2);
864   PetscUseMethod(viewer, "PetscViewerFileGetName_C", (PetscViewer, const char **), (viewer, name));
865   PetscFunctionReturn(PETSC_SUCCESS);
866 }
867 
868 static PetscErrorCode PetscViewerFileGetName_ASCII(PetscViewer viewer, const char **name)
869 {
870   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
871 
872   PetscFunctionBegin;
873   *name = vascii->filename;
874   PetscFunctionReturn(PETSC_SUCCESS);
875 }
876 
877 #include <errno.h>
878 static PetscErrorCode PetscViewerFileSetName_ASCII(PetscViewer viewer, const char name[])
879 {
880   size_t             len;
881   char               fname[PETSC_MAX_PATH_LEN], *gz = NULL;
882   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
883   PetscBool          isstderr, isstdout;
884   PetscMPIInt        rank;
885 
886   PetscFunctionBegin;
887   PetscCall(PetscViewerFileClose_ASCII(viewer));
888   if (!name) PetscFunctionReturn(PETSC_SUCCESS);
889   PetscCall(PetscStrallocpy(name, &vascii->filename));
890 
891   /* Is this file to be compressed */
892   vascii->storecompressed = PETSC_FALSE;
893 
894   PetscCall(PetscStrstr(vascii->filename, ".gz", &gz));
895   if (gz) {
896     PetscCall(PetscStrlen(gz, &len));
897     if (len == 3) {
898       PetscCheck(vascii->mode == FILE_MODE_WRITE, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Cannot open ASCII PetscViewer file that is compressed; uncompress it manually first");
899       *gz                     = 0;
900       vascii->storecompressed = PETSC_TRUE;
901     }
902   }
903   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
904   if (rank == 0) {
905     PetscCall(PetscStrcmp(name, "stderr", &isstderr));
906     PetscCall(PetscStrcmp(name, "stdout", &isstdout));
907     /* empty filename means stdout */
908     if (name[0] == 0) isstdout = PETSC_TRUE;
909     if (isstderr) vascii->fd = PETSC_STDERR;
910     else if (isstdout) vascii->fd = PETSC_STDOUT;
911     else {
912       PetscCall(PetscFixFilename(name, fname));
913       switch (vascii->mode) {
914       case FILE_MODE_READ:
915         vascii->fd = fopen(fname, "r");
916         break;
917       case FILE_MODE_WRITE:
918         vascii->fd = fopen(fname, "w");
919         break;
920       case FILE_MODE_APPEND:
921         vascii->fd = fopen(fname, "a");
922         break;
923       case FILE_MODE_UPDATE:
924         vascii->fd = fopen(fname, "r+");
925         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
926         break;
927       case FILE_MODE_APPEND_UPDATE:
928         /* I really want a file which is opened at the end for updating,
929            not a+, which opens at the beginning, but makes writes at the end.
930         */
931         vascii->fd = fopen(fname, "r+");
932         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
933         else {
934           int ret = fseek(vascii->fd, 0, SEEK_END);
935           PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "fseek() failed with error code %d", ret);
936         }
937         break;
938       default:
939         SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vascii->mode]);
940       }
941       PetscCheck(vascii->fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open PetscViewer file: %s due to \"%s\"", fname, strerror(errno));
942     }
943   }
944   PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", name));
945   PetscFunctionReturn(PETSC_SUCCESS);
946 }
947 
948 static PetscErrorCode PetscViewerGetSubViewer_ASCII(PetscViewer viewer, MPI_Comm subcomm, PetscViewer *outviewer)
949 {
950   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data, *ovascii;
951 
952   PetscFunctionBegin;
953   PetscCheck(!vascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer already obtained from PetscViewer and not restored");
954   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
955   /*
956      The following line is a bug; it does another PetscViewerASCIIPushSynchronized() on viewer, but if it is removed the code won't work
957      because it relies on this behavior in other places. In particular this line causes the synchronized flush to occur when the viewer is destroyed
958      (since the count never gets to zero) in some examples this displays information that otherwise would be lost
959 
960      This code also means another call to PetscViewerASCIIPopSynchronized() must be made after the PetscViewerRestoreSubViewer(), see, for example,
961      PCView_GASM().
962   */
963   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
964   PetscCall(PetscViewerFlush(viewer));
965   PetscCall(PetscViewerCreate(subcomm, outviewer));
966   PetscCall(PetscViewerSetType(*outviewer, PETSCVIEWERASCII));
967   PetscCall(PetscViewerASCIIPushSynchronized(*outviewer));
968   ovascii            = (PetscViewer_ASCII *)(*outviewer)->data;
969   ovascii->fd        = vascii->fd;
970   ovascii->closefile = PETSC_FALSE;
971 
972   vascii->sviewer                                      = *outviewer;
973   (*outviewer)->format                                 = viewer->format;
974   ((PetscViewer_ASCII *)((*outviewer)->data))->bviewer = viewer;
975   (*outviewer)->ops->destroy                           = PetscViewerDestroy_ASCII_SubViewer;
976   PetscFunctionReturn(PETSC_SUCCESS);
977 }
978 
979 static PetscErrorCode PetscViewerRestoreSubViewer_ASCII(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer)
980 {
981   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
982 
983   PetscFunctionBegin;
984   PetscCheck(ascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer never obtained from PetscViewer");
985   PetscCheck(ascii->sviewer == *outviewer, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "This PetscViewer did not generate this SubViewer");
986 
987   PetscCall(PetscViewerASCIIPopSynchronized(*outviewer));
988   ascii->sviewer             = NULL;
989   (*outviewer)->ops->destroy = PetscViewerDestroy_ASCII;
990   PetscCall(PetscViewerDestroy(outviewer));
991   PetscCall(PetscViewerFlush(viewer));
992   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
993   PetscFunctionReturn(PETSC_SUCCESS);
994 }
995 
996 static PetscErrorCode PetscViewerView_ASCII(PetscViewer v, PetscViewer viewer)
997 {
998   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)v->data;
999 
1000   PetscFunctionBegin;
1001   if (ascii->fileunit) PetscCall(PetscViewerASCIIPrintf(viewer, "Fortran FILE UNIT: %" PetscInt_FMT "\n", ascii->fileunit));
1002   else if (ascii->filename) PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", ascii->filename));
1003   PetscFunctionReturn(PETSC_SUCCESS);
1004 }
1005 
1006 /*MC
1007    PETSCVIEWERASCII - A viewer that prints to `stdout`, `stderr`, or an ASCII file
1008 
1009   Level: beginner
1010 
1011 .seealso: [](sec_viewers), `PETSC_VIEWER_STDOUT_()`, `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`,
1012           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`,
1013           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
1014 M*/
1015 PETSC_EXTERN PetscErrorCode PetscViewerCreate_ASCII(PetscViewer viewer)
1016 {
1017   PetscViewer_ASCII *vascii;
1018 
1019   PetscFunctionBegin;
1020   PetscCall(PetscNew(&vascii));
1021   viewer->data = (void *)vascii;
1022 
1023   viewer->ops->destroy          = PetscViewerDestroy_ASCII;
1024   viewer->ops->flush            = PetscViewerFlush_ASCII;
1025   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_ASCII;
1026   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_ASCII;
1027   viewer->ops->view             = PetscViewerView_ASCII;
1028   viewer->ops->read             = PetscViewerASCIIRead;
1029 
1030   /* defaults to stdout unless set with PetscViewerFileSetName() */
1031   vascii->fd        = PETSC_STDOUT;
1032   vascii->mode      = FILE_MODE_WRITE;
1033   vascii->bviewer   = NULL;
1034   vascii->subviewer = NULL;
1035   vascii->sviewer   = NULL;
1036   vascii->tab       = 0;
1037   vascii->tab_store = 0;
1038   vascii->filename  = NULL;
1039   vascii->closefile = PETSC_TRUE;
1040 
1041   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_ASCII));
1042   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_ASCII));
1043   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_ASCII));
1044   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_ASCII));
1045   PetscFunctionReturn(PETSC_SUCCESS);
1046 }
1047 
1048 /*@C
1049   PetscViewerASCIISynchronizedPrintf - Prints synchronized output to the specified `PETSCVIEWERASCII` file from
1050   several processors.  Output of the first processor is followed by that of the
1051   second, etc.
1052 
1053   Not Collective, must call collective `PetscViewerFlush()` to get the results flushed
1054 
1055   Input Parameters:
1056 + viewer - the `PETSCVIEWERASCII` `PetscViewer`
1057 - format - the usual printf() format string
1058 
1059   Level: intermediate
1060 
1061   Notes:
1062   You must have previously called `PetscViewerASCIIPushSynchronized()` to allow this routine to be called.
1063   Then you can do multiple independent calls to this routine.
1064 
1065   The actual synchronized print is then done using `PetscViewerFlush()`.
1066   `PetscViewerASCIIPopSynchronized()` should be then called if we are already done with the synchronized output
1067   to conclude the "synchronized session".
1068 
1069   So the typical calling sequence looks like
1070 .vb
1071     PetscViewerASCIIPushSynchronized(viewer);
1072     PetscViewerASCIISynchronizedPrintf(viewer, ...);
1073     PetscViewerASCIISynchronizedPrintf(viewer, ...);
1074     ...
1075     PetscViewerFlush(viewer);
1076     PetscViewerASCIISynchronizedPrintf(viewer, ...);
1077     PetscViewerASCIISynchronizedPrintf(viewer, ...);
1078     ...
1079     PetscViewerFlush(viewer);
1080     PetscViewerASCIIPopSynchronized(viewer);
1081 .ve
1082 
1083   Fortran Notes:
1084   Can only print a single character* string
1085 
1086 .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
1087           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
1088           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
1089 @*/
1090 PetscErrorCode PetscViewerASCIISynchronizedPrintf(PetscViewer viewer, const char format[], ...)
1091 {
1092   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
1093   PetscMPIInt        rank;
1094   PetscInt           tab = 0;
1095   MPI_Comm           comm;
1096   PetscBool          iascii;
1097 
1098   PetscFunctionBegin;
1099   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1100   PetscAssertPointer(format, 2);
1101   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1102   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
1103   PetscCheck(vascii->allowsynchronized, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "First call PetscViewerASCIIPushSynchronized() to allow this call");
1104 
1105   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
1106   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1107 
1108   if (vascii->bviewer) {
1109     char   *string;
1110     va_list Argp;
1111     size_t  fullLength;
1112 
1113     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
1114     for (; tab < vascii->tab; tab++) { string[2 * tab] = string[2 * tab + 1] = ' '; }
1115     va_start(Argp, format);
1116     PetscCall(PetscVSNPrintf(string + 2 * tab, QUEUESTRINGSIZE - 2 * tab, format, &fullLength, Argp));
1117     va_end(Argp);
1118     PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", string));
1119     PetscCall(PetscFree(string));
1120   } else if (rank == 0) { /* First processor prints immediately to fp */
1121     va_list Argp;
1122     FILE   *fp = vascii->fd;
1123 
1124     tab = vascii->tab;
1125     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fp, "  "));
1126 
1127     va_start(Argp, format);
1128     PetscCall((*PetscVFPrintf)(fp, format, Argp));
1129     va_end(Argp);
1130     PetscCall(PetscFFlush(fp));
1131     if (petsc_history) {
1132       va_start(Argp, format);
1133       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
1134       va_end(Argp);
1135       PetscCall(PetscFFlush(petsc_history));
1136     }
1137     va_end(Argp);
1138   } else { /* other processors add to queue */
1139     char       *string;
1140     va_list     Argp;
1141     size_t      fullLength;
1142     PrintfQueue next;
1143 
1144     PetscCall(PetscNew(&next));
1145     if (vascii->petsc_printfqueue) {
1146       vascii->petsc_printfqueue->next = next;
1147       vascii->petsc_printfqueue       = next;
1148     } else {
1149       vascii->petsc_printfqueuebase = vascii->petsc_printfqueue = next;
1150     }
1151     vascii->petsc_printfqueuelength++;
1152     next->size = QUEUESTRINGSIZE;
1153     PetscCall(PetscCalloc1(next->size, &next->string));
1154     string = next->string;
1155 
1156     tab = vascii->tab;
1157     tab *= 2;
1158     while (tab--) *string++ = ' ';
1159     va_start(Argp, format);
1160     PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, &fullLength, Argp));
1161     va_end(Argp);
1162     if (fullLength > (size_t)(next->size - 2 * vascii->tab)) {
1163       PetscCall(PetscFree(next->string));
1164       next->size = fullLength + 2 * vascii->tab;
1165       PetscCall(PetscCalloc1(next->size, &next->string));
1166       string = next->string;
1167       tab    = 2 * vascii->tab;
1168       while (tab--) *string++ = ' ';
1169       va_start(Argp, format);
1170       PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, NULL, Argp));
1171       va_end(Argp);
1172     }
1173   }
1174   PetscFunctionReturn(PETSC_SUCCESS);
1175 }
1176 
1177 /*@C
1178   PetscViewerASCIIRead - Reads from a `PETSCVIEWERASCII` file
1179 
1180   Only MPI rank 0 in the `PetscViewer` may call this
1181 
1182   Input Parameters:
1183 + viewer - the `PETSCVIEWERASCII` viewer
1184 . data   - location to write the data, treated as an array of type indicated by `datatype`
1185 . num    - number of items of data to read
1186 - dtype  - type of data to read
1187 
1188   Output Parameter:
1189 . count - number of items of data actually read, or `NULL`
1190 
1191   Level: beginner
1192 
1193 .seealso: [](sec_viewers), `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetName()`
1194           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
1195           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
1196 @*/
1197 PetscErrorCode PetscViewerASCIIRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype)
1198 {
1199   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
1200   FILE              *fd     = vascii->fd;
1201   PetscInt           i;
1202   int                ret = 0;
1203   PetscMPIInt        rank;
1204 
1205   PetscFunctionBegin;
1206   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1207   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
1208   PetscCheck(rank == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Can only be called from process 0 in the PetscViewer");
1209   for (i = 0; i < num; i++) {
1210     if (dtype == PETSC_CHAR) ret = fscanf(fd, "%c", &(((char *)data)[i]));
1211     else if (dtype == PETSC_STRING) ret = fscanf(fd, "%s", &(((char *)data)[i]));
1212     else if (dtype == PETSC_INT) ret = fscanf(fd, "%" PetscInt_FMT, &(((PetscInt *)data)[i]));
1213     else if (dtype == PETSC_ENUM) ret = fscanf(fd, "%d", &(((int *)data)[i]));
1214     else if (dtype == PETSC_INT64) ret = fscanf(fd, "%" PetscInt64_FMT, &(((PetscInt64 *)data)[i]));
1215     else if (dtype == PETSC_LONG) ret = fscanf(fd, "%ld", &(((long *)data)[i]));
1216     else if (dtype == PETSC_FLOAT) ret = fscanf(fd, "%f", &(((float *)data)[i]));
1217     else if (dtype == PETSC_DOUBLE) ret = fscanf(fd, "%lg", &(((double *)data)[i]));
1218 #if defined(PETSC_USE_REAL___FLOAT128)
1219     else if (dtype == PETSC___FLOAT128) {
1220       double tmp;
1221       ret                     = fscanf(fd, "%lg", &tmp);
1222       ((__float128 *)data)[i] = tmp;
1223     }
1224 #endif
1225     else
1226       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data type %d not supported", (int)dtype);
1227     PetscCheck(ret, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Conversion error for data type %d", (int)dtype);
1228     if (ret < 0) break; /* Proxy for EOF, need to check for it in configure */
1229   }
1230   if (count) *count = i;
1231   else PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Insufficient data, read only %" PetscInt_FMT " < %" PetscInt_FMT " items", i, num);
1232   PetscFunctionReturn(PETSC_SUCCESS);
1233 }
1234