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