xref: /petsc/src/sys/classes/viewer/impls/ascii/filev.c (revision c621c6acee7d76a547b2bdc269801f31fedb2451)
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 /*@C
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 /*@C
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 /*@C
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 /*@C
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 petscviewerasciisetfilefileunit_  PETSCVIEWERASCIISETFILEUNIT
511     #define petscfortranprinttounit_          PETSCFORTRANPRINTTOUNIT
512   #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE)
513     #define petscviewerasciiopenwithfileunit_ petscviewerasciiopenwithfileunit
514     #define petscviewerasciisetfileunit_      petscviewerasciisetfileunit
515     #define petscfortranprinttounit_          petscfortranprinttounit
516   #endif
517 
518   #if defined(__cplusplus)
519 extern "C" void petscfortranprinttounit_(PetscInt *, const char *, PetscErrorCode *, PETSC_FORTRAN_CHARLEN_T);
520   #else
521 extern void petscfortranprinttounit_(PetscInt *, const char *, PetscErrorCode *, PETSC_FORTRAN_CHARLEN_T);
522   #endif
523 
524   #define PETSCDEFAULTBUFFERSIZE 8 * 1024
525 
526 // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
527 /*MC
528   PetscViewerASCIISetFileUnit - sets the `PETSCVIEWERASCII` to write to a Fortran IO unit
529 
530   Synopsis:
531   #include <petscviewer.h>
532   void PetscViewerASCIISetFileUnit(PetscViewer lab, PetscInt unit, PetscErrorCode ierr)
533 
534   Input Parameters:
535 + lab  - the viewer
536 - unit - the unit number
537 
538   Output Parameter:
539 . ierr - the error code
540 
541   Level: intermediate
542 
543   Note:
544   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`
545 
546   Fortran Notes:
547   Only for Fortran, use  `PetscViewerASCIISetFILE()` for C
548 
549 .seealso: `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFileUnit()`
550 M*/
551 PETSC_EXTERN void petscviewerasciisetfileunit_(PetscViewer *lab, PetscInt *unit, PetscErrorCode *ierr)
552 {
553   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)(*lab)->data;
554 
555   if (vascii->mode == FILE_MODE_READ) {
556     *ierr = PETSC_ERR_ARG_WRONGSTATE;
557     return;
558   }
559   vascii->fileunit = *unit;
560 }
561 
562 // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
563 /*MC
564   PetscViewerASCIIOpenWithFileUnit - opens a `PETSCVIEWERASCII` to write to a Fortran IO unit
565 
566   Synopsis:
567   #include <petscviewer.h>
568   void PetscViewerASCIIOpenWithFileUnit(MPI_Comm comm, PetscInt unit, PetscViewer viewer, PetscErrorCode ierr)
569 
570   Input Parameters:
571 + comm - the `MPI_Comm` to share the viewer
572 - unit - the unit number
573 
574   Output Parameters:
575 + lab  - the viewer
576 - ierr - the error code
577 
578   Level: intermediate
579 
580   Note:
581   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`
582 
583   Fortran Notes:
584   Only for Fortran, use  `PetscViewerASCIIOpenWithFILE()` for C
585 
586 .seealso: `PetscViewerASCIISetFileUnit()`, `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFILE()`
587 M*/
588 PETSC_EXTERN void petscviewerasciiopenwithfileunit_(MPI_Comm *comm, PetscInt *unit, PetscViewer *lab, PetscErrorCode *ierr)
589 {
590   *ierr = PetscViewerCreate(MPI_Comm_f2c(*(MPI_Fint *)&*comm), lab);
591   if (*ierr) return;
592   *ierr = PetscViewerSetType(*lab, PETSCVIEWERASCII);
593   if (*ierr) return;
594   *ierr = PetscViewerFileSetMode(*lab, FILE_MODE_WRITE);
595   if (*ierr) return;
596   petscviewerasciisetfileunit_(lab, unit, ierr);
597 }
598 
599 static PetscErrorCode PetscVFPrintfFortran(PetscInt unit, const char format[], va_list Argp)
600 {
601   PetscErrorCode ierr;
602   char           str[PETSCDEFAULTBUFFERSIZE];
603   size_t         len;
604 
605   PetscFunctionBegin;
606   PetscCall(PetscVSNPrintf(str, sizeof(str), format, NULL, Argp));
607   PetscCall(PetscStrlen(str, &len));
608   petscfortranprinttounit_(&unit, str, &ierr, (int)len);
609   PetscFunctionReturn(PETSC_SUCCESS);
610 }
611 
612 static PetscErrorCode PetscFPrintfFortran(PetscInt unit, const char str[])
613 {
614   PetscErrorCode ierr;
615   size_t         len;
616 
617   PetscFunctionBegin;
618   PetscCall(PetscStrlen(str, &len));
619   petscfortranprinttounit_(&unit, str, &ierr, (int)len);
620   PetscFunctionReturn(PETSC_SUCCESS);
621 }
622 
623 #else
624 
625 /* these will never be used; but are needed to link with */
626 static PetscErrorCode PetscVFPrintfFortran(PetscInt unit, const char format[], va_list Argp)
627 {
628   PetscFunctionBegin;
629   PetscFunctionReturn(PETSC_SUCCESS);
630 }
631 
632 static PetscErrorCode PetscFPrintfFortran(PetscInt unit, const char str[])
633 {
634   PetscFunctionBegin;
635   PetscFunctionReturn(PETSC_SUCCESS);
636 }
637 #endif
638 
639 /*@C
640   PetscViewerASCIIPrintf - Prints to a file, only from the first
641   processor in the `PetscViewer` of type `PETSCVIEWERASCII`
642 
643   Not Collective, but only the first MPI rank in the viewer has any effect
644 
645   Input Parameters:
646 + viewer - obtained with `PetscViewerASCIIOpen()`
647 - format - the usual printf() format string
648 
649   Level: developer
650 
651   Fortran Notes:
652   The call sequence is `PetscViewerASCIIPrintf`(`PetscViewer`, character(*), int ierr) from Fortran.
653   That is, you can only pass a single character string from Fortran.
654 
655 .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
656           `PetscViewerASCIIPushTab()`, `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`,
657           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushSynchronized()`
658 @*/
659 PetscErrorCode PetscViewerASCIIPrintf(PetscViewer viewer, const char format[], ...)
660 {
661   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
662   PetscMPIInt        rank;
663   PetscInt           tab = 0, intab = ascii->tab;
664   FILE              *fd = ascii->fd;
665   PetscBool          iascii;
666 
667   PetscFunctionBegin;
668   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
669   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
670   PetscAssertPointer(format, 2);
671   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
672   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
673   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
674   if (rank) PetscFunctionReturn(PETSC_SUCCESS);
675 
676   if (ascii->bviewer) { /* pass string up to parent viewer */
677     char   *string;
678     va_list Argp;
679     size_t  fullLength;
680 
681     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
682     for (; tab < ascii->tab; tab++) { string[2 * tab] = string[2 * tab + 1] = ' '; }
683     va_start(Argp, format);
684     PetscCall(PetscVSNPrintf(string + 2 * intab, QUEUESTRINGSIZE - 2 * intab, format, &fullLength, Argp));
685     va_end(Argp);
686     PetscCall(PetscViewerASCIISynchronizedPrintf(ascii->bviewer, "%s", string));
687     PetscCall(PetscFree(string));
688   } else { /* write directly to file */
689     va_list Argp;
690 
691     tab = intab;
692     while (tab--) {
693       if (!ascii->fileunit) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "  "));
694       else PetscCall(PetscFPrintfFortran(ascii->fileunit, "   "));
695     }
696 
697     va_start(Argp, format);
698     if (!ascii->fileunit) PetscCall((*PetscVFPrintf)(fd, format, Argp));
699     else PetscCall(PetscVFPrintfFortran(ascii->fileunit, format, Argp));
700     va_end(Argp);
701     PetscCall(PetscFFlush(fd));
702   }
703   PetscFunctionReturn(PETSC_SUCCESS);
704 }
705 
706 /*@C
707   PetscViewerFileSetName - Sets the name of the file the `PetscViewer` should use.
708 
709   Collective
710 
711   Input Parameters:
712 + viewer - the `PetscViewer`; for example, of type `PETSCVIEWERASCII` or `PETSCVIEWERBINARY`
713 - name   - the name of the file it should use
714 
715   Level: advanced
716 
717   Note:
718   This will have no effect on viewers that are not related to files
719 
720 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerDestroy()`,
721           `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`
722 @*/
723 PetscErrorCode PetscViewerFileSetName(PetscViewer viewer, const char name[])
724 {
725   char filename[PETSC_MAX_PATH_LEN];
726 
727   PetscFunctionBegin;
728   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
729   PetscAssertPointer(name, 2);
730   PetscCall(PetscStrreplace(PetscObjectComm((PetscObject)viewer), name, filename, sizeof(filename)));
731   PetscTryMethod(viewer, "PetscViewerFileSetName_C", (PetscViewer, const char[]), (viewer, filename));
732   PetscFunctionReturn(PETSC_SUCCESS);
733 }
734 
735 /*@C
736   PetscViewerFileGetName - Gets the name of the file the `PetscViewer` is using
737 
738   Not Collective
739 
740   Input Parameter:
741 . viewer - the `PetscViewer`
742 
743   Output Parameter:
744 . name - the name of the file it is using
745 
746   Level: advanced
747 
748   Note:
749   This will have no effect on viewers that are not related to files
750 
751 .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerFileSetName()`
752 @*/
753 PetscErrorCode PetscViewerFileGetName(PetscViewer viewer, const char **name)
754 {
755   PetscFunctionBegin;
756   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
757   PetscAssertPointer(name, 2);
758   PetscUseMethod(viewer, "PetscViewerFileGetName_C", (PetscViewer, const char **), (viewer, name));
759   PetscFunctionReturn(PETSC_SUCCESS);
760 }
761 
762 static PetscErrorCode PetscViewerFileGetName_ASCII(PetscViewer viewer, const char **name)
763 {
764   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
765 
766   PetscFunctionBegin;
767   *name = vascii->filename;
768   PetscFunctionReturn(PETSC_SUCCESS);
769 }
770 
771 #include <errno.h>
772 static PetscErrorCode PetscViewerFileSetName_ASCII(PetscViewer viewer, const char name[])
773 {
774   size_t             len;
775   char               fname[PETSC_MAX_PATH_LEN], *gz = NULL;
776   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
777   PetscBool          isstderr, isstdout;
778   PetscMPIInt        rank;
779 
780   PetscFunctionBegin;
781   PetscCall(PetscViewerFileClose_ASCII(viewer));
782   if (!name) PetscFunctionReturn(PETSC_SUCCESS);
783   PetscCall(PetscStrallocpy(name, &vascii->filename));
784 
785   /* Is this file to be compressed */
786   vascii->storecompressed = PETSC_FALSE;
787 
788   PetscCall(PetscStrstr(vascii->filename, ".gz", &gz));
789   if (gz) {
790     PetscCall(PetscStrlen(gz, &len));
791     if (len == 3) {
792       PetscCheck(vascii->mode == FILE_MODE_WRITE, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Cannot open ASCII PetscViewer file that is compressed; uncompress it manually first");
793       *gz                     = 0;
794       vascii->storecompressed = PETSC_TRUE;
795     }
796   }
797   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
798   if (rank == 0) {
799     PetscCall(PetscStrcmp(name, "stderr", &isstderr));
800     PetscCall(PetscStrcmp(name, "stdout", &isstdout));
801     /* empty filename means stdout */
802     if (name[0] == 0) isstdout = PETSC_TRUE;
803     if (isstderr) vascii->fd = PETSC_STDERR;
804     else if (isstdout) vascii->fd = PETSC_STDOUT;
805     else {
806       PetscCall(PetscFixFilename(name, fname));
807       switch (vascii->mode) {
808       case FILE_MODE_READ:
809         vascii->fd = fopen(fname, "r");
810         break;
811       case FILE_MODE_WRITE:
812         vascii->fd = fopen(fname, "w");
813         break;
814       case FILE_MODE_APPEND:
815         vascii->fd = fopen(fname, "a");
816         break;
817       case FILE_MODE_UPDATE:
818         vascii->fd = fopen(fname, "r+");
819         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
820         break;
821       case FILE_MODE_APPEND_UPDATE:
822         /* I really want a file which is opened at the end for updating,
823            not a+, which opens at the beginning, but makes writes at the end.
824         */
825         vascii->fd = fopen(fname, "r+");
826         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
827         else {
828           int ret = fseek(vascii->fd, 0, SEEK_END);
829           PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "fseek() failed with error code %d", ret);
830         }
831         break;
832       default:
833         SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vascii->mode]);
834       }
835       PetscCheck(vascii->fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open PetscViewer file: %s due to \"%s\"", fname, strerror(errno));
836     }
837   }
838   PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", name));
839   PetscFunctionReturn(PETSC_SUCCESS);
840 }
841 
842 static PetscErrorCode PetscViewerGetSubViewer_ASCII(PetscViewer viewer, MPI_Comm subcomm, PetscViewer *outviewer)
843 {
844   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data, *ovascii;
845 
846   PetscFunctionBegin;
847   PetscCheck(!vascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer already obtained from PetscViewer and not restored");
848   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
849   /*
850      The following line is a bug; it does another PetscViewerASCIIPushSynchronized() on viewer, but if it is removed the code won't work
851      because it relies on this behavior in other places. In particular this line causes the synchronized flush to occur when the viewer is destroyed
852      (since the count never gets to zero) in some examples this displays information that otherwise would be lost
853 
854      This code also means another call to PetscViewerASCIIPopSynchronized() must be made after the PetscViewerRestoreSubViewer(), see, for example,
855      PCView_GASM().
856   */
857   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
858   PetscCall(PetscViewerFlush(viewer));
859   PetscCall(PetscViewerCreate(subcomm, outviewer));
860   PetscCall(PetscViewerSetType(*outviewer, PETSCVIEWERASCII));
861   PetscCall(PetscViewerASCIIPushSynchronized(*outviewer));
862   ovascii            = (PetscViewer_ASCII *)(*outviewer)->data;
863   ovascii->fd        = vascii->fd;
864   ovascii->closefile = PETSC_FALSE;
865 
866   vascii->sviewer                                      = *outviewer;
867   (*outviewer)->format                                 = viewer->format;
868   ((PetscViewer_ASCII *)((*outviewer)->data))->bviewer = viewer;
869   (*outviewer)->ops->destroy                           = PetscViewerDestroy_ASCII_SubViewer;
870   PetscFunctionReturn(PETSC_SUCCESS);
871 }
872 
873 static PetscErrorCode PetscViewerRestoreSubViewer_ASCII(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer)
874 {
875   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
876 
877   PetscFunctionBegin;
878   PetscCheck(ascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer never obtained from PetscViewer");
879   PetscCheck(ascii->sviewer == *outviewer, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "This PetscViewer did not generate this SubViewer");
880 
881   PetscCall(PetscViewerASCIIPopSynchronized(*outviewer));
882   ascii->sviewer             = NULL;
883   (*outviewer)->ops->destroy = PetscViewerDestroy_ASCII;
884   PetscCall(PetscViewerDestroy(outviewer));
885   PetscCall(PetscViewerFlush(viewer));
886   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
887   PetscFunctionReturn(PETSC_SUCCESS);
888 }
889 
890 static PetscErrorCode PetscViewerView_ASCII(PetscViewer v, PetscViewer viewer)
891 {
892   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)v->data;
893 
894   PetscFunctionBegin;
895   if (ascii->filename) PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", ascii->filename));
896   PetscFunctionReturn(PETSC_SUCCESS);
897 }
898 
899 /*MC
900    PETSCVIEWERASCII - A viewer that prints to stdout or an ASCII file
901 
902   Level: beginner
903 
904 .seealso: [](sec_viewers), `PETSC_VIEWER_STDOUT_()`, `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`,
905           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`,
906           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
907 M*/
908 PETSC_EXTERN PetscErrorCode PetscViewerCreate_ASCII(PetscViewer viewer)
909 {
910   PetscViewer_ASCII *vascii;
911 
912   PetscFunctionBegin;
913   PetscCall(PetscNew(&vascii));
914   viewer->data = (void *)vascii;
915 
916   viewer->ops->destroy          = PetscViewerDestroy_ASCII;
917   viewer->ops->flush            = PetscViewerFlush_ASCII;
918   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_ASCII;
919   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_ASCII;
920   viewer->ops->view             = PetscViewerView_ASCII;
921   viewer->ops->read             = PetscViewerASCIIRead;
922 
923   /* defaults to stdout unless set with PetscViewerFileSetName() */
924   vascii->fd        = PETSC_STDOUT;
925   vascii->mode      = FILE_MODE_WRITE;
926   vascii->bviewer   = NULL;
927   vascii->subviewer = NULL;
928   vascii->sviewer   = NULL;
929   vascii->tab       = 0;
930   vascii->tab_store = 0;
931   vascii->filename  = NULL;
932   vascii->closefile = PETSC_TRUE;
933 
934   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_ASCII));
935   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_ASCII));
936   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_ASCII));
937   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_ASCII));
938   PetscFunctionReturn(PETSC_SUCCESS);
939 }
940 
941 /*@C
942   PetscViewerASCIISynchronizedPrintf - Prints synchronized output to the specified `PETSCVIEWERASCII` file from
943   several processors.  Output of the first processor is followed by that of the
944   second, etc.
945 
946   Not Collective, must call collective `PetscViewerFlush()` to get the results flushed
947 
948   Input Parameters:
949 + viewer - the `PETSCVIEWERASCII` `PetscViewer`
950 - format - the usual printf() format string
951 
952   Level: intermediate
953 
954   Notes:
955   You must have previously called `PetscViewerASCIIPushSynchronized()` to allow this routine to be called.
956   Then you can do multiple independent calls to this routine.
957 
958   The actual synchronized print is then done using `PetscViewerFlush()`.
959   `PetscViewerASCIIPopSynchronized()` should be then called if we are already done with the synchronized output
960   to conclude the "synchronized session".
961 
962   So the typical calling sequence looks like
963 .vb
964     PetscViewerASCIIPushSynchronized(viewer);
965     PetscViewerASCIISynchronizedPrintf(viewer, ...);
966     PetscViewerASCIISynchronizedPrintf(viewer, ...);
967     ...
968     PetscViewerFlush(viewer);
969     PetscViewerASCIISynchronizedPrintf(viewer, ...);
970     PetscViewerASCIISynchronizedPrintf(viewer, ...);
971     ...
972     PetscViewerFlush(viewer);
973     PetscViewerASCIIPopSynchronized(viewer);
974 .ve
975 
976   Fortran Notes:
977   Can only print a single character* string
978 
979 .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
980           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
981           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
982 @*/
983 PetscErrorCode PetscViewerASCIISynchronizedPrintf(PetscViewer viewer, const char format[], ...)
984 {
985   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
986   PetscMPIInt        rank;
987   PetscInt           tab = 0;
988   MPI_Comm           comm;
989   PetscBool          iascii;
990 
991   PetscFunctionBegin;
992   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
993   PetscAssertPointer(format, 2);
994   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
995   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
996   PetscCheck(vascii->allowsynchronized, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "First call PetscViewerASCIIPushSynchronized() to allow this call");
997 
998   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
999   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1000 
1001   if (vascii->bviewer) {
1002     char   *string;
1003     va_list Argp;
1004     size_t  fullLength;
1005 
1006     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
1007     for (; tab < vascii->tab; tab++) { string[2 * tab] = string[2 * tab + 1] = ' '; }
1008     va_start(Argp, format);
1009     PetscCall(PetscVSNPrintf(string + 2 * tab, QUEUESTRINGSIZE - 2 * tab, format, &fullLength, Argp));
1010     va_end(Argp);
1011     PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", string));
1012     PetscCall(PetscFree(string));
1013   } else if (rank == 0) { /* First processor prints immediately to fp */
1014     va_list Argp;
1015     FILE   *fp = vascii->fd;
1016 
1017     tab = vascii->tab;
1018     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fp, "  "));
1019 
1020     va_start(Argp, format);
1021     PetscCall((*PetscVFPrintf)(fp, format, Argp));
1022     va_end(Argp);
1023     PetscCall(PetscFFlush(fp));
1024     if (petsc_history) {
1025       va_start(Argp, format);
1026       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
1027       va_end(Argp);
1028       PetscCall(PetscFFlush(petsc_history));
1029     }
1030     va_end(Argp);
1031   } else { /* other processors add to queue */
1032     char       *string;
1033     va_list     Argp;
1034     size_t      fullLength;
1035     PrintfQueue next;
1036 
1037     PetscCall(PetscNew(&next));
1038     if (vascii->petsc_printfqueue) {
1039       vascii->petsc_printfqueue->next = next;
1040       vascii->petsc_printfqueue       = next;
1041     } else {
1042       vascii->petsc_printfqueuebase = vascii->petsc_printfqueue = next;
1043     }
1044     vascii->petsc_printfqueuelength++;
1045     next->size = QUEUESTRINGSIZE;
1046     PetscCall(PetscCalloc1(next->size, &next->string));
1047     string = next->string;
1048 
1049     tab = vascii->tab;
1050     tab *= 2;
1051     while (tab--) *string++ = ' ';
1052     va_start(Argp, format);
1053     PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, &fullLength, Argp));
1054     va_end(Argp);
1055     if (fullLength > (size_t)(next->size - 2 * vascii->tab)) {
1056       PetscCall(PetscFree(next->string));
1057       next->size = fullLength + 2 * vascii->tab;
1058       PetscCall(PetscCalloc1(next->size, &next->string));
1059       string = next->string;
1060       tab    = 2 * vascii->tab;
1061       while (tab--) *string++ = ' ';
1062       va_start(Argp, format);
1063       PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, NULL, Argp));
1064       va_end(Argp);
1065     }
1066   }
1067   PetscFunctionReturn(PETSC_SUCCESS);
1068 }
1069 
1070 /*@C
1071   PetscViewerASCIIRead - Reads from a `PETSCVIEWERASCII` file
1072 
1073   Only MPI rank 0 in the `PetscViewer` may call this
1074 
1075   Input Parameters:
1076 + viewer - the `PETSCVIEWERASCII` viewer
1077 . data   - location to write the data, treated as an array of type indicated by `datatype`
1078 . num    - number of items of data to read
1079 - dtype  - type of data to read
1080 
1081   Output Parameter:
1082 . count - number of items of data actually read, or `NULL`
1083 
1084   Level: beginner
1085 
1086 .seealso: [](sec_viewers), `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetName()`
1087           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
1088           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
1089 @*/
1090 PetscErrorCode PetscViewerASCIIRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype)
1091 {
1092   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
1093   FILE              *fd     = vascii->fd;
1094   PetscInt           i;
1095   int                ret = 0;
1096   PetscMPIInt        rank;
1097 
1098   PetscFunctionBegin;
1099   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
1100   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
1101   PetscCheck(rank == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Can only be called from process 0 in the PetscViewer");
1102   for (i = 0; i < num; i++) {
1103     if (dtype == PETSC_CHAR) ret = fscanf(fd, "%c", &(((char *)data)[i]));
1104     else if (dtype == PETSC_STRING) ret = fscanf(fd, "%s", &(((char *)data)[i]));
1105     else if (dtype == PETSC_INT) ret = fscanf(fd, "%" PetscInt_FMT, &(((PetscInt *)data)[i]));
1106     else if (dtype == PETSC_ENUM) ret = fscanf(fd, "%d", &(((int *)data)[i]));
1107     else if (dtype == PETSC_INT64) ret = fscanf(fd, "%" PetscInt64_FMT, &(((PetscInt64 *)data)[i]));
1108     else if (dtype == PETSC_LONG) ret = fscanf(fd, "%ld", &(((long *)data)[i]));
1109     else if (dtype == PETSC_FLOAT) ret = fscanf(fd, "%f", &(((float *)data)[i]));
1110     else if (dtype == PETSC_DOUBLE) ret = fscanf(fd, "%lg", &(((double *)data)[i]));
1111 #if defined(PETSC_USE_REAL___FLOAT128)
1112     else if (dtype == PETSC___FLOAT128) {
1113       double tmp;
1114       ret                     = fscanf(fd, "%lg", &tmp);
1115       ((__float128 *)data)[i] = tmp;
1116     }
1117 #endif
1118     else
1119       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data type %d not supported", (int)dtype);
1120     PetscCheck(ret, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Conversion error for data type %d", (int)dtype);
1121     if (ret < 0) break; /* Proxy for EOF, need to check for it in configure */
1122   }
1123   if (count) *count = i;
1124   else PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Insufficient data, read only %" PetscInt_FMT " < %" PetscInt_FMT " items", i, num);
1125   PetscFunctionReturn(PETSC_SUCCESS);
1126 }
1127