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