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