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