xref: /petsc/src/sys/classes/viewer/impls/ascii/filev.c (revision bceecc9d159ce1d8af409ced93a62eb3330908de)
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 Synopsis:
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 Note:
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 Synopsis:
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 Note:
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 Note:
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 Note:
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 -  datatype - 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