xref: /petsc/src/sys/classes/viewer/impls/ascii/filev.c (revision 4cc2b5b5fe4ffd09e5956b56d7cdc4f43e324103)
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 /* ----------------------------------------------------------------------*/
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   PetscCheck(!vascii->fileunit, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot request file pointer for viewers that use Fortran files");
202   *fd = vascii->fd;
203   PetscFunctionReturn(PETSC_SUCCESS);
204 }
205 
206 static PetscErrorCode PetscViewerFileGetMode_ASCII(PetscViewer viewer, PetscFileMode *mode)
207 {
208   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
209 
210   PetscFunctionBegin;
211   *mode = vascii->mode;
212   PetscFunctionReturn(PETSC_SUCCESS);
213 }
214 
215 static PetscErrorCode PetscViewerFileSetMode_ASCII(PetscViewer viewer, PetscFileMode mode)
216 {
217   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
218 
219   PetscFunctionBegin;
220   vascii->mode = mode;
221   PetscFunctionReturn(PETSC_SUCCESS);
222 }
223 
224 /*
225    If petsc_history is on, then all Petsc*Printf() results are saved
226    if the appropriate (usually .petschistory) file.
227 */
228 PETSC_INTERN FILE *petsc_history;
229 
230 /*@
231   PetscViewerASCIISetTab - Causes `PetscViewer` to tab in a number of times before printing
232 
233   Not Collective, but only first processor in set has any effect; No Fortran Support
234 
235   Input Parameters:
236 + viewer - obtained with `PetscViewerASCIIOpen()`
237 - tabs   - number of tabs
238 
239   Level: developer
240 
241   Note:
242   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage
243 
244 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
245           `PetscViewerASCIIGetTab()`,
246           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
247           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`,
248           `PetscViewerASCIIPushTab()`
249 @*/
250 PetscErrorCode PetscViewerASCIISetTab(PetscViewer viewer, PetscInt tabs)
251 {
252   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
253   PetscBool          iascii;
254 
255   PetscFunctionBegin;
256   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
257   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
258   if (iascii) ascii->tab = tabs;
259   PetscFunctionReturn(PETSC_SUCCESS);
260 }
261 
262 /*@
263   PetscViewerASCIIGetTab - Return the number of tabs used by `PetscViewer`.
264 
265   Not Collective, meaningful on first processor only; No Fortran Support
266 
267   Input Parameter:
268 . viewer - obtained with `PetscViewerASCIIOpen()`
269 
270   Output Parameter:
271 . tabs - number of tabs
272 
273   Level: developer
274 
275 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
276           `PetscViewerASCIISetTab()`,
277           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
278           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
279 @*/
280 PetscErrorCode PetscViewerASCIIGetTab(PetscViewer viewer, PetscInt *tabs)
281 {
282   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
283   PetscBool          iascii;
284 
285   PetscFunctionBegin;
286   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
287   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
288   if (iascii && tabs) *tabs = ascii->tab;
289   PetscFunctionReturn(PETSC_SUCCESS);
290 }
291 
292 /*@
293   PetscViewerASCIIAddTab - Add to the number of times a `PETSCVIEWERASCII` viewer tabs before printing
294 
295   Not Collective, but only first processor in set has any effect; No Fortran Support
296 
297   Input Parameters:
298 + viewer - obtained with `PetscViewerASCIIOpen()`
299 - tabs   - number of tabs
300 
301   Level: developer
302 
303   Note:
304   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage
305 
306 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
307           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
308           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
309 @*/
310 PetscErrorCode PetscViewerASCIIAddTab(PetscViewer viewer, PetscInt tabs)
311 {
312   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
313   PetscBool          iascii;
314 
315   PetscFunctionBegin;
316   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
317   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
318   if (iascii) ascii->tab += tabs;
319   PetscFunctionReturn(PETSC_SUCCESS);
320 }
321 
322 /*@
323   PetscViewerASCIISubtractTab - Subtracts from the number of times a `PETSCVIEWERASCII` viewer tabs before printing
324 
325   Not Collective, but only first processor in set has any effect; No Fortran Support
326 
327   Input Parameters:
328 + viewer - obtained with `PetscViewerASCIIOpen()`
329 - tabs   - number of tabs
330 
331   Level: developer
332 
333   Note:
334   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage
335 
336 .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
337           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
338           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`,
339           `PetscViewerASCIIPushTab()`
340 @*/
341 PetscErrorCode PetscViewerASCIISubtractTab(PetscViewer viewer, PetscInt tabs)
342 {
343   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
344   PetscBool          iascii;
345 
346   PetscFunctionBegin;
347   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
348   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
349   if (iascii) ascii->tab -= tabs;
350   PetscFunctionReturn(PETSC_SUCCESS);
351 }
352 
353 /*@
354   PetscViewerASCIIPushSynchronized - Allows calls to `PetscViewerASCIISynchronizedPrintf()` for this viewer
355 
356   Collective
357 
358   Input Parameter:
359 . viewer - obtained with `PetscViewerASCIIOpen()`
360 
361   Level: intermediate
362 
363   Note:
364   See documentation of `PetscViewerASCIISynchronizedPrintf()` for more details how the synchronized output should be done properly.
365 
366 .seealso: [](sec_viewers), `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
367           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
368           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
369 @*/
370 PetscErrorCode PetscViewerASCIIPushSynchronized(PetscViewer viewer)
371 {
372   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
373   PetscBool          iascii;
374 
375   PetscFunctionBegin;
376   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
377   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
378   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
379   if (iascii) ascii->allowsynchronized++;
380   PetscFunctionReturn(PETSC_SUCCESS);
381 }
382 
383 /*@
384   PetscViewerASCIIPopSynchronized - Undoes most recent `PetscViewerASCIIPushSynchronized()` for this viewer
385 
386   Collective
387 
388   Input Parameter:
389 . viewer - obtained with `PetscViewerASCIIOpen()`
390 
391   Level: intermediate
392 
393   Note:
394   See documentation of `PetscViewerASCIISynchronizedPrintf()` for more details how the synchronized output should be done properly.
395 
396 .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`,
397           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
398           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
399 @*/
400 PetscErrorCode PetscViewerASCIIPopSynchronized(PetscViewer viewer)
401 {
402   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
403   PetscBool          iascii;
404 
405   PetscFunctionBegin;
406   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
407   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
408   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
409   if (iascii) {
410     ascii->allowsynchronized--;
411     PetscCheck(ascii->allowsynchronized >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called more times than PetscViewerASCIIPushSynchronized()");
412   }
413   PetscFunctionReturn(PETSC_SUCCESS);
414 }
415 
416 /*@
417   PetscViewerASCIIPushTab - Adds one more tab to the amount that `PetscViewerASCIIPrintf()`
418   lines are tabbed.
419 
420   Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support
421 
422   Input Parameter:
423 . viewer - obtained with `PetscViewerASCIIOpen()`
424 
425   Level: developer
426 
427 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
428           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
429           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
430 @*/
431 PetscErrorCode PetscViewerASCIIPushTab(PetscViewer viewer)
432 {
433   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
434   PetscBool          iascii;
435 
436   PetscFunctionBegin;
437   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
438   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
439   if (iascii) ascii->tab++;
440   PetscFunctionReturn(PETSC_SUCCESS);
441 }
442 
443 /*@
444   PetscViewerASCIIPopTab - Removes one tab from the amount that `PetscViewerASCIIPrintf()` lines are tabbed that was provided by
445   `PetscViewerASCIIPushTab()`
446 
447   Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support
448 
449   Input Parameter:
450 . viewer - obtained with `PetscViewerASCIIOpen()`
451 
452   Level: developer
453 
454 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
455           `PetscViewerASCIIPushTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
456           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
457 @*/
458 PetscErrorCode PetscViewerASCIIPopTab(PetscViewer viewer)
459 {
460   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
461   PetscBool          iascii;
462 
463   PetscFunctionBegin;
464   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
465   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
466   if (iascii) {
467     PetscCheck(ascii->tab > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "More tabs popped than pushed");
468     ascii->tab--;
469   }
470   PetscFunctionReturn(PETSC_SUCCESS);
471 }
472 
473 /*@
474   PetscViewerASCIIUseTabs - Turns on or off the use of tabs with the `PETSCVIEWERASCII` `PetscViewer`
475 
476   Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support
477 
478   Input Parameters:
479 + viewer - obtained with `PetscViewerASCIIOpen()`
480 - flg    - `PETSC_TRUE` or `PETSC_FALSE`
481 
482   Level: developer
483 
484 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
485           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPushTab()`, `PetscViewerASCIIOpen()`,
486           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
487 @*/
488 PetscErrorCode PetscViewerASCIIUseTabs(PetscViewer viewer, PetscBool flg)
489 {
490   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
491   PetscBool          iascii;
492 
493   PetscFunctionBegin;
494   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
495   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
496   if (iascii) {
497     if (flg) ascii->tab = ascii->tab_store;
498     else {
499       ascii->tab_store = ascii->tab;
500       ascii->tab       = 0;
501     }
502   }
503   PetscFunctionReturn(PETSC_SUCCESS);
504 }
505 
506 #if defined(PETSC_USE_FORTRAN_BINDINGS)
507 
508   #if defined(PETSC_HAVE_FORTRAN_CAPS)
509     #define petscviewerasciiopenwithfileunit_ PETSCVIEWERASCIIOPENWITHFILEUNIT
510     #define petscviewerasciisetfileunit_      PETSCVIEWERASCIISETFILEUNIT
511     #define petscviewerasciiworldsetfileunit_ PETSCVIEWERASCIIWORLDSETFILEUNIT
512     #define petscfortranprinttounit_          PETSCFORTRANPRINTTOUNIT
513   #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE)
514     #define petscviewerasciiopenwithfileunit_ petscviewerasciiopenwithfileunit
515     #define petscviewerasciisetfileunit_      petscviewerasciisetfileunit
516     #define petscviewerasciiworldsetfileunit_ petscviewerasciiworldsetfileunit
517     #define petscfortranprinttounit_          petscfortranprinttounit
518   #endif
519 
520   #if defined(__cplusplus)
521 extern "C" void petscfortranprinttounit_(PetscInt *, const char *, PetscErrorCode *, PETSC_FORTRAN_CHARLEN_T);
522   #else
523 extern void petscfortranprinttounit_(PetscInt *, const char *, PetscErrorCode *, PETSC_FORTRAN_CHARLEN_T);
524   #endif
525 
526   #define PETSCDEFAULTBUFFERSIZE 8 * 1024
527 
528 static PetscInt PETSC_VIEWER_ASCII_WORLD_fileunit = 0;
529 
530 // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
531 /*MC
532   PetscViewerASCIIWORLDSetFileUnit - sets `PETSC_VIEWER_STDOUT_WORLD` to write to a Fortran IO unit
533 
534   Synopsis:
535   #include <petscviewer.h>
536   void PetscViewerASCIIWORLDSetFileUnit(PetscInt unit, PetscErrorCode ierr)
537 
538   Input Parameter:
539 . unit - the unit number
540 
541   Output Parameter:
542 . ierr - the error code
543 
544   Level: intermediate
545 
546   Notes:
547   Must be called before `PetscInitialize()`
548 
549   This may not work currently with some viewers that (improperly) use the `fd` directly instead of `PetscViewerASCIIPrintf()`
550 
551   With this option, for example, `-log_options` results will be saved to the Fortran file
552 
553   Any process may call this but only the unit passed on the first process is used
554 
555   Fortran Note:
556   Only for Fortran
557 
558   Developer Note:
559   `PetscViewerASCIIWORLDSetFilename()` could be added in the future
560 
561 .seealso: `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFileUnit()`, `PetscViewerASCIIWORLDSetFileUnit()`
562 M*/
563 PETSC_EXTERN void petscviewerasciiworldsetfileunit_(PetscInt *unit, PetscErrorCode *ierr)
564 {
565   PETSC_VIEWER_ASCII_WORLD_fileunit = *unit;
566 }
567 
568   #include <petsc/private/fortranimpl.h>
569 
570 // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
571 /*MC
572   PetscViewerASCIISetFileUnit - sets the `PETSCVIEWERASCII` to write to a Fortran IO unit
573 
574   Synopsis:
575   #include <petscviewer.h>
576   void PetscViewerASCIISetFileUnit(PetscViewer lab, PetscInt unit, PetscErrorCode ierr)
577 
578   Input Parameters:
579 + lab  - the viewer
580 - unit - the unit number
581 
582   Output Parameter:
583 . ierr - the error code
584 
585   Level: intermediate
586 
587   Note:
588   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`
589 
590   Fortran Notes:
591   Only for Fortran, use  `PetscViewerASCIISetFILE()` for C
592 
593 .seealso: `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFileUnit()`, `PetscViewerASCIIWORLDSetFileUnit()`
594 M*/
595 PETSC_EXTERN void petscviewerasciisetfileunit_(PetscViewer *lab, PetscInt *unit, PetscErrorCode *ierr)
596 {
597   PetscViewer_ASCII *vascii;
598   PetscViewer        v;
599 
600   PetscPatchDefaultViewers_Fortran(lab, v);
601   vascii = (PetscViewer_ASCII *)v->data;
602   if (vascii->mode == FILE_MODE_READ) {
603     *ierr = PETSC_ERR_ARG_WRONGSTATE;
604     return;
605   }
606   vascii->fileunit = *unit;
607 }
608 
609 // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
610 /*MC
611   PetscViewerASCIIOpenWithFileUnit - opens a `PETSCVIEWERASCII` to write to a Fortran IO unit
612 
613   Synopsis:
614   #include <petscviewer.h>
615   void PetscViewerASCIIOpenWithFileUnit(MPI_Comm comm, PetscInt unit, PetscViewer viewer, PetscErrorCode ierr)
616 
617   Input Parameters:
618 + comm - the `MPI_Comm` to share the viewer
619 - unit - the unit number
620 
621   Output Parameters:
622 + lab  - the viewer
623 - ierr - the error code
624 
625   Level: intermediate
626 
627   Note:
628   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`
629 
630   Fortran Notes:
631   Only for Fortran, use  `PetscViewerASCIIOpenWithFILE()` for C
632 
633 .seealso: `PetscViewerASCIISetFileUnit()`, `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFILE()`
634 M*/
635 PETSC_EXTERN void petscviewerasciiopenwithfileunit_(MPI_Comm *comm, PetscInt *unit, PetscViewer *lab, PetscErrorCode *ierr)
636 {
637   *ierr = PetscViewerCreate(MPI_Comm_f2c(*(MPI_Fint *)&*comm), lab);
638   if (*ierr) return;
639   *ierr = PetscViewerSetType(*lab, PETSCVIEWERASCII);
640   if (*ierr) return;
641   *ierr = PetscViewerFileSetMode(*lab, FILE_MODE_WRITE);
642   if (*ierr) return;
643   petscviewerasciisetfileunit_(lab, unit, ierr);
644 }
645 
646 static PetscErrorCode PetscVFPrintfFortran(PetscInt unit, const char format[], va_list Argp)
647 {
648   PetscErrorCode ierr;
649   char           str[PETSCDEFAULTBUFFERSIZE];
650   size_t         len;
651 
652   PetscFunctionBegin;
653   PetscCall(PetscVSNPrintf(str, sizeof(str), format, NULL, Argp));
654   PetscCall(PetscStrlen(str, &len));
655   petscfortranprinttounit_(&unit, str, &ierr, (int)len);
656   PetscFunctionReturn(PETSC_SUCCESS);
657 }
658 
659 static PetscErrorCode PetscFPrintfFortran(PetscInt unit, const char str[])
660 {
661   PetscErrorCode ierr;
662   size_t         len;
663 
664   PetscFunctionBegin;
665   PetscCall(PetscStrlen(str, &len));
666   petscfortranprinttounit_(&unit, str, &ierr, (int)len);
667   PetscFunctionReturn(PETSC_SUCCESS);
668 }
669 
670 #else
671 
672 /* these will never be used; but are needed to link with */
673 static PetscErrorCode PetscVFPrintfFortran(PetscInt unit, const char format[], va_list Argp)
674 {
675   PetscFunctionBegin;
676   PetscFunctionReturn(PETSC_SUCCESS);
677 }
678 
679 static PetscErrorCode PetscFPrintfFortran(PetscInt unit, const char str[])
680 {
681   PetscFunctionBegin;
682   PetscFunctionReturn(PETSC_SUCCESS);
683 }
684 #endif
685 
686 /*@
687   PetscViewerASCIIGetStdout - Creates a `PETSCVIEWERASCII` `PetscViewer` shared by all processes
688   in a communicator. Error returning version of `PETSC_VIEWER_STDOUT_()`
689 
690   Collective
691 
692   Input Parameter:
693 . comm - the MPI communicator to share the `PetscViewer`
694 
695   Output Parameter:
696 . viewer - the viewer
697 
698   Level: beginner
699 
700   Note:
701   This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it
702 
703   Developer Note:
704   This should be used in all PETSc source code instead of `PETSC_VIEWER_STDOUT_()` since it allows error checking
705 
706 .seealso: [](sec_viewers), `PETSC_VIEWER_DRAW_()`, `PetscViewerASCIIOpen()`, `PETSC_VIEWER_STDERR_`, `PETSC_VIEWER_STDOUT_WORLD`,
707           `PETSC_VIEWER_STDOUT_SELF`
708 @*/
709 PetscErrorCode PetscViewerASCIIGetStdout(MPI_Comm comm, PetscViewer *viewer)
710 {
711   PetscBool flg;
712   MPI_Comm  ncomm;
713 
714   PetscFunctionBegin;
715   PetscAssertPointer(viewer, 2);
716   PetscCall(PetscSpinlockLock(&PetscViewerASCIISpinLockStdout));
717   PetscCall(PetscCommDuplicate(comm, &ncomm, NULL));
718   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));
719   PetscCallMPI(MPI_Comm_get_attr(ncomm, Petsc_Viewer_Stdout_keyval, (void **)viewer, (PetscMPIInt *)&flg));
720   if (!flg) { /* PetscViewer not yet created */
721 #if defined(PETSC_USE_FORTRAN_BINDINGS)
722     PetscMPIInt size, gsize;
723 
724     PetscCallMPI(MPI_Comm_size(comm, &size));
725     PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &gsize));
726     if (size == gsize) { PetscCallMPI(MPI_Bcast(&PETSC_VIEWER_ASCII_WORLD_fileunit, 1, MPIU_INT, 0, comm)); }
727     if (PETSC_VIEWER_ASCII_WORLD_fileunit) {
728       PetscErrorCode ierr;
729 
730       petscviewerasciiopenwithfileunit_(&ncomm, &PETSC_VIEWER_ASCII_WORLD_fileunit, viewer, &ierr);
731     } else
732 #endif
733       PetscCall(PetscViewerASCIIOpen(ncomm, "stdout", viewer));
734     ((PetscObject)*viewer)->persistent = PETSC_TRUE;
735     PetscCall(PetscObjectRegisterDestroy((PetscObject)*viewer));
736     PetscCallMPI(MPI_Comm_set_attr(ncomm, Petsc_Viewer_Stdout_keyval, (void *)*viewer));
737   }
738   PetscCall(PetscCommDestroy(&ncomm));
739   PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockStdout));
740   PetscFunctionReturn(PETSC_SUCCESS);
741 }
742 
743 /*@C
744   PetscViewerASCIIPrintf - Prints to a file, only from the first
745   processor in the `PetscViewer` of type `PETSCVIEWERASCII`
746 
747   Not Collective, but only the first MPI rank in the viewer has any effect
748 
749   Input Parameters:
750 + viewer - obtained with `PetscViewerASCIIOpen()`
751 - format - the usual printf() format string
752 
753   Level: developer
754 
755   Fortran Notes:
756   The call sequence is `PetscViewerASCIIPrintf`(`PetscViewer`, character(*), int ierr) from Fortran.
757   That is, you can only pass a single character string from Fortran.
758 
759 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
760           `PetscViewerASCIIPushTab()`, `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`,
761           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushSynchronized()`
762 @*/
763 PetscErrorCode PetscViewerASCIIPrintf(PetscViewer viewer, const char format[], ...)
764 {
765   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
766   PetscMPIInt        rank;
767   PetscInt           tab = 0, intab = ascii->tab;
768   FILE              *fd = ascii->fd;
769   PetscBool          iascii;
770 
771   PetscFunctionBegin;
772   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
773   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
774   PetscAssertPointer(format, 2);
775   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
776   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
777   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
778   if (rank) PetscFunctionReturn(PETSC_SUCCESS);
779 
780   if (ascii->bviewer) { /* pass string up to parent viewer */
781     char   *string;
782     va_list Argp;
783     size_t  fullLength;
784 
785     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
786     for (; tab < ascii->tab; tab++) { string[2 * tab] = string[2 * tab + 1] = ' '; }
787     va_start(Argp, format);
788     PetscCall(PetscVSNPrintf(string + 2 * intab, QUEUESTRINGSIZE - 2 * intab, format, &fullLength, Argp));
789     va_end(Argp);
790     PetscCall(PetscViewerASCIISynchronizedPrintf(ascii->bviewer, "%s", string));
791     PetscCall(PetscFree(string));
792   } else { /* write directly to file */
793     va_list Argp;
794 
795     tab = intab;
796     while (tab--) {
797       if (!ascii->fileunit) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "  "));
798       else PetscCall(PetscFPrintfFortran(ascii->fileunit, "   "));
799     }
800 
801     va_start(Argp, format);
802     if (!ascii->fileunit) PetscCall((*PetscVFPrintf)(fd, format, Argp));
803     else PetscCall(PetscVFPrintfFortran(ascii->fileunit, format, Argp));
804     va_end(Argp);
805     PetscCall(PetscFFlush(fd));
806   }
807   PetscFunctionReturn(PETSC_SUCCESS);
808 }
809 
810 /*@
811   PetscViewerFileSetName - Sets the name of the file the `PetscViewer` should use.
812 
813   Collective
814 
815   Input Parameters:
816 + viewer - the `PetscViewer`; for example, of type `PETSCVIEWERASCII` or `PETSCVIEWERBINARY`
817 - name   - the name of the file it should use
818 
819   Level: advanced
820 
821   Note:
822   This will have no effect on viewers that are not related to files
823 
824 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerDestroy()`,
825           `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`
826 @*/
827 PetscErrorCode PetscViewerFileSetName(PetscViewer viewer, const char name[])
828 {
829   char filename[PETSC_MAX_PATH_LEN];
830 
831   PetscFunctionBegin;
832   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
833   PetscAssertPointer(name, 2);
834   PetscCall(PetscStrreplace(PetscObjectComm((PetscObject)viewer), name, filename, sizeof(filename)));
835   PetscTryMethod(viewer, "PetscViewerFileSetName_C", (PetscViewer, const char[]), (viewer, filename));
836   PetscFunctionReturn(PETSC_SUCCESS);
837 }
838 
839 /*@C
840   PetscViewerFileGetName - Gets the name of the file the `PetscViewer` is using
841 
842   Not Collective
843 
844   Input Parameter:
845 . viewer - the `PetscViewer`
846 
847   Output Parameter:
848 . name - the name of the file it is using
849 
850   Level: advanced
851 
852   Note:
853   This will have no effect on viewers that are not related to files
854 
855 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerFileSetName()`
856 @*/
857 PetscErrorCode PetscViewerFileGetName(PetscViewer viewer, const char *name[])
858 {
859   PetscFunctionBegin;
860   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
861   PetscAssertPointer(name, 2);
862   PetscUseMethod(viewer, "PetscViewerFileGetName_C", (PetscViewer, const char **), (viewer, name));
863   PetscFunctionReturn(PETSC_SUCCESS);
864 }
865 
866 static PetscErrorCode PetscViewerFileGetName_ASCII(PetscViewer viewer, const char **name)
867 {
868   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
869 
870   PetscFunctionBegin;
871   *name = vascii->filename;
872   PetscFunctionReturn(PETSC_SUCCESS);
873 }
874 
875 #include <errno.h>
876 static PetscErrorCode PetscViewerFileSetName_ASCII(PetscViewer viewer, const char name[])
877 {
878   size_t             len;
879   char               fname[PETSC_MAX_PATH_LEN], *gz = NULL;
880   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
881   PetscBool          isstderr, isstdout;
882   PetscMPIInt        rank;
883 
884   PetscFunctionBegin;
885   PetscCall(PetscViewerFileClose_ASCII(viewer));
886   if (!name) PetscFunctionReturn(PETSC_SUCCESS);
887   PetscCall(PetscStrallocpy(name, &vascii->filename));
888 
889   /* Is this file to be compressed */
890   vascii->storecompressed = PETSC_FALSE;
891 
892   PetscCall(PetscStrstr(vascii->filename, ".gz", &gz));
893   if (gz) {
894     PetscCall(PetscStrlen(gz, &len));
895     if (len == 3) {
896       PetscCheck(vascii->mode == FILE_MODE_WRITE, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Cannot open ASCII PetscViewer file that is compressed; uncompress it manually first");
897       *gz                     = 0;
898       vascii->storecompressed = PETSC_TRUE;
899     }
900   }
901   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
902   if (rank == 0) {
903     PetscCall(PetscStrcmp(name, "stderr", &isstderr));
904     PetscCall(PetscStrcmp(name, "stdout", &isstdout));
905     /* empty filename means stdout */
906     if (name[0] == 0) isstdout = PETSC_TRUE;
907     if (isstderr) vascii->fd = PETSC_STDERR;
908     else if (isstdout) vascii->fd = PETSC_STDOUT;
909     else {
910       PetscCall(PetscFixFilename(name, fname));
911       switch (vascii->mode) {
912       case FILE_MODE_READ:
913         vascii->fd = fopen(fname, "r");
914         break;
915       case FILE_MODE_WRITE:
916         vascii->fd = fopen(fname, "w");
917         break;
918       case FILE_MODE_APPEND:
919         vascii->fd = fopen(fname, "a");
920         break;
921       case FILE_MODE_UPDATE:
922         vascii->fd = fopen(fname, "r+");
923         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
924         break;
925       case FILE_MODE_APPEND_UPDATE:
926         /* I really want a file which is opened at the end for updating,
927            not a+, which opens at the beginning, but makes writes at the end.
928         */
929         vascii->fd = fopen(fname, "r+");
930         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
931         else {
932           int ret = fseek(vascii->fd, 0, SEEK_END);
933           PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "fseek() failed with error code %d", ret);
934         }
935         break;
936       default:
937         SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vascii->mode]);
938       }
939       PetscCheck(vascii->fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open PetscViewer file: %s due to \"%s\"", fname, strerror(errno));
940     }
941   }
942   PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", name));
943   PetscFunctionReturn(PETSC_SUCCESS);
944 }
945 
946 static PetscErrorCode PetscViewerGetSubViewer_ASCII(PetscViewer viewer, MPI_Comm subcomm, PetscViewer *outviewer)
947 {
948   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data, *ovascii;
949 
950   PetscFunctionBegin;
951   PetscCheck(!vascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer already obtained from PetscViewer and not restored");
952   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
953   /*
954      The following line is a bug; it does another PetscViewerASCIIPushSynchronized() on viewer, but if it is removed the code won't work
955      because it relies on this behavior in other places. In particular this line causes the synchronized flush to occur when the viewer is destroyed
956      (since the count never gets to zero) in some examples this displays information that otherwise would be lost
957 
958      This code also means another call to PetscViewerASCIIPopSynchronized() must be made after the PetscViewerRestoreSubViewer(), see, for example,
959      PCView_GASM().
960   */
961   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
962   PetscCall(PetscViewerFlush(viewer));
963   PetscCall(PetscViewerCreate(subcomm, outviewer));
964   PetscCall(PetscViewerSetType(*outviewer, PETSCVIEWERASCII));
965   PetscCall(PetscViewerASCIIPushSynchronized(*outviewer));
966   ovascii            = (PetscViewer_ASCII *)(*outviewer)->data;
967   ovascii->fd        = vascii->fd;
968   ovascii->closefile = PETSC_FALSE;
969 
970   vascii->sviewer                                      = *outviewer;
971   (*outviewer)->format                                 = viewer->format;
972   ((PetscViewer_ASCII *)((*outviewer)->data))->bviewer = viewer;
973   (*outviewer)->ops->destroy                           = PetscViewerDestroy_ASCII_SubViewer;
974   PetscFunctionReturn(PETSC_SUCCESS);
975 }
976 
977 static PetscErrorCode PetscViewerRestoreSubViewer_ASCII(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer)
978 {
979   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
980 
981   PetscFunctionBegin;
982   PetscCheck(ascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer never obtained from PetscViewer");
983   PetscCheck(ascii->sviewer == *outviewer, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "This PetscViewer did not generate this SubViewer");
984 
985   PetscCall(PetscViewerASCIIPopSynchronized(*outviewer));
986   ascii->sviewer             = NULL;
987   (*outviewer)->ops->destroy = PetscViewerDestroy_ASCII;
988   PetscCall(PetscViewerDestroy(outviewer));
989   PetscCall(PetscViewerFlush(viewer));
990   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
991   PetscFunctionReturn(PETSC_SUCCESS);
992 }
993 
994 static PetscErrorCode PetscViewerView_ASCII(PetscViewer v, PetscViewer viewer)
995 {
996   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)v->data;
997 
998   PetscFunctionBegin;
999   if (ascii->fileunit) PetscCall(PetscViewerASCIIPrintf(viewer, "Fortran FILE UNIT: %" PetscInt_FMT "\n", ascii->fileunit));
1000   else if (ascii->filename) PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", ascii->filename));
1001   PetscFunctionReturn(PETSC_SUCCESS);
1002 }
1003 
1004 /*MC
1005    PETSCVIEWERASCII - A viewer that prints to stdout or an ASCII file
1006 
1007   Level: beginner
1008 
1009 .seealso: [](sec_viewers), `PETSC_VIEWER_STDOUT_()`, `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`,
1010           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`,
1011           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
1012 M*/
1013 PETSC_EXTERN PetscErrorCode PetscViewerCreate_ASCII(PetscViewer viewer)
1014 {
1015   PetscViewer_ASCII *vascii;
1016 
1017   PetscFunctionBegin;
1018   PetscCall(PetscNew(&vascii));
1019   viewer->data = (void *)vascii;
1020 
1021   viewer->ops->destroy          = PetscViewerDestroy_ASCII;
1022   viewer->ops->flush            = PetscViewerFlush_ASCII;
1023   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_ASCII;
1024   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_ASCII;
1025   viewer->ops->view             = PetscViewerView_ASCII;
1026   viewer->ops->read             = PetscViewerASCIIRead;
1027 
1028   /* defaults to stdout unless set with PetscViewerFileSetName() */
1029   vascii->fd        = PETSC_STDOUT;
1030   vascii->mode      = FILE_MODE_WRITE;
1031   vascii->bviewer   = NULL;
1032   vascii->subviewer = NULL;
1033   vascii->sviewer   = NULL;
1034   vascii->tab       = 0;
1035   vascii->tab_store = 0;
1036   vascii->filename  = NULL;
1037   vascii->closefile = PETSC_TRUE;
1038 
1039   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_ASCII));
1040   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_ASCII));
1041   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_ASCII));
1042   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_ASCII));
1043   PetscFunctionReturn(PETSC_SUCCESS);
1044 }
1045 
1046 /*@C
1047   PetscViewerASCIISynchronizedPrintf - Prints synchronized output to the specified `PETSCVIEWERASCII` file from
1048   several processors.  Output of the first processor is followed by that of the
1049   second, etc.
1050 
1051   Not Collective, must call collective `PetscViewerFlush()` to get the results flushed
1052 
1053   Input Parameters:
1054 + viewer - the `PETSCVIEWERASCII` `PetscViewer`
1055 - format - the usual printf() format string
1056 
1057   Level: intermediate
1058 
1059   Notes:
1060   You must have previously called `PetscViewerASCIIPushSynchronized()` to allow this routine to be called.
1061   Then you can do multiple independent calls to this routine.
1062 
1063   The actual synchronized print is then done using `PetscViewerFlush()`.
1064   `PetscViewerASCIIPopSynchronized()` should be then called if we are already done with the synchronized output
1065   to conclude the "synchronized session".
1066 
1067   So the typical calling sequence looks like
1068 .vb
1069     PetscViewerASCIIPushSynchronized(viewer);
1070     PetscViewerASCIISynchronizedPrintf(viewer, ...);
1071     PetscViewerASCIISynchronizedPrintf(viewer, ...);
1072     ...
1073     PetscViewerFlush(viewer);
1074     PetscViewerASCIISynchronizedPrintf(viewer, ...);
1075     PetscViewerASCIISynchronizedPrintf(viewer, ...);
1076     ...
1077     PetscViewerFlush(viewer);
1078     PetscViewerASCIIPopSynchronized(viewer);
1079 .ve
1080 
1081   Fortran Notes:
1082   Can only print a single character* string
1083 
1084 .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
1085           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
1086           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
1087 @*/
1088 PetscErrorCode PetscViewerASCIISynchronizedPrintf(PetscViewer viewer, const char format[], ...)
1089 {
1090   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
1091   PetscMPIInt        rank;
1092   PetscInt           tab = 0;
1093   MPI_Comm           comm;
1094   PetscBool          iascii;
1095 
1096   PetscFunctionBegin;
1097   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1098   PetscAssertPointer(format, 2);
1099   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
1100   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
1101   PetscCheck(vascii->allowsynchronized, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "First call PetscViewerASCIIPushSynchronized() to allow this call");
1102 
1103   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
1104   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1105 
1106   if (vascii->bviewer) {
1107     char   *string;
1108     va_list Argp;
1109     size_t  fullLength;
1110 
1111     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
1112     for (; tab < vascii->tab; tab++) { string[2 * tab] = string[2 * tab + 1] = ' '; }
1113     va_start(Argp, format);
1114     PetscCall(PetscVSNPrintf(string + 2 * tab, QUEUESTRINGSIZE - 2 * tab, format, &fullLength, Argp));
1115     va_end(Argp);
1116     PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", string));
1117     PetscCall(PetscFree(string));
1118   } else if (rank == 0) { /* First processor prints immediately to fp */
1119     va_list Argp;
1120     FILE   *fp = vascii->fd;
1121 
1122     tab = vascii->tab;
1123     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fp, "  "));
1124 
1125     va_start(Argp, format);
1126     PetscCall((*PetscVFPrintf)(fp, format, Argp));
1127     va_end(Argp);
1128     PetscCall(PetscFFlush(fp));
1129     if (petsc_history) {
1130       va_start(Argp, format);
1131       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
1132       va_end(Argp);
1133       PetscCall(PetscFFlush(petsc_history));
1134     }
1135     va_end(Argp);
1136   } else { /* other processors add to queue */
1137     char       *string;
1138     va_list     Argp;
1139     size_t      fullLength;
1140     PrintfQueue next;
1141 
1142     PetscCall(PetscNew(&next));
1143     if (vascii->petsc_printfqueue) {
1144       vascii->petsc_printfqueue->next = next;
1145       vascii->petsc_printfqueue       = next;
1146     } else {
1147       vascii->petsc_printfqueuebase = vascii->petsc_printfqueue = next;
1148     }
1149     vascii->petsc_printfqueuelength++;
1150     next->size = QUEUESTRINGSIZE;
1151     PetscCall(PetscCalloc1(next->size, &next->string));
1152     string = next->string;
1153 
1154     tab = vascii->tab;
1155     tab *= 2;
1156     while (tab--) *string++ = ' ';
1157     va_start(Argp, format);
1158     PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, &fullLength, Argp));
1159     va_end(Argp);
1160     if (fullLength > (size_t)(next->size - 2 * vascii->tab)) {
1161       PetscCall(PetscFree(next->string));
1162       next->size = fullLength + 2 * vascii->tab;
1163       PetscCall(PetscCalloc1(next->size, &next->string));
1164       string = next->string;
1165       tab    = 2 * vascii->tab;
1166       while (tab--) *string++ = ' ';
1167       va_start(Argp, format);
1168       PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, NULL, Argp));
1169       va_end(Argp);
1170     }
1171   }
1172   PetscFunctionReturn(PETSC_SUCCESS);
1173 }
1174 
1175 /*@C
1176   PetscViewerASCIIRead - Reads from a `PETSCVIEWERASCII` file
1177 
1178   Only MPI rank 0 in the `PetscViewer` may call this
1179 
1180   Input Parameters:
1181 + viewer - the `PETSCVIEWERASCII` viewer
1182 . data   - location to write the data, treated as an array of type indicated by `datatype`
1183 . num    - number of items of data to read
1184 - dtype  - type of data to read
1185 
1186   Output Parameter:
1187 . count - number of items of data actually read, or `NULL`
1188 
1189   Level: beginner
1190 
1191 .seealso: [](sec_viewers), `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetName()`
1192           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
1193           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
1194 @*/
1195 PetscErrorCode PetscViewerASCIIRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype)
1196 {
1197   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
1198   FILE              *fd     = vascii->fd;
1199   PetscInt           i;
1200   int                ret = 0;
1201   PetscMPIInt        rank;
1202 
1203   PetscFunctionBegin;
1204   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1205   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
1206   PetscCheck(rank == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Can only be called from process 0 in the PetscViewer");
1207   for (i = 0; i < num; i++) {
1208     if (dtype == PETSC_CHAR) ret = fscanf(fd, "%c", &(((char *)data)[i]));
1209     else if (dtype == PETSC_STRING) ret = fscanf(fd, "%s", &(((char *)data)[i]));
1210     else if (dtype == PETSC_INT) ret = fscanf(fd, "%" PetscInt_FMT, &(((PetscInt *)data)[i]));
1211     else if (dtype == PETSC_ENUM) ret = fscanf(fd, "%d", &(((int *)data)[i]));
1212     else if (dtype == PETSC_INT64) ret = fscanf(fd, "%" PetscInt64_FMT, &(((PetscInt64 *)data)[i]));
1213     else if (dtype == PETSC_LONG) ret = fscanf(fd, "%ld", &(((long *)data)[i]));
1214     else if (dtype == PETSC_FLOAT) ret = fscanf(fd, "%f", &(((float *)data)[i]));
1215     else if (dtype == PETSC_DOUBLE) ret = fscanf(fd, "%lg", &(((double *)data)[i]));
1216 #if defined(PETSC_USE_REAL___FLOAT128)
1217     else if (dtype == PETSC___FLOAT128) {
1218       double tmp;
1219       ret                     = fscanf(fd, "%lg", &tmp);
1220       ((__float128 *)data)[i] = tmp;
1221     }
1222 #endif
1223     else
1224       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data type %d not supported", (int)dtype);
1225     PetscCheck(ret, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Conversion error for data type %d", (int)dtype);
1226     if (ret < 0) break; /* Proxy for EOF, need to check for it in configure */
1227   }
1228   if (count) *count = i;
1229   else PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Insufficient data, read only %" PetscInt_FMT " < %" PetscInt_FMT " items", i, num);
1230   PetscFunctionReturn(PETSC_SUCCESS);
1231 }
1232