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