Actual source code: filev.c

  1: #include <../src/sys/classes/viewer/impls/ascii/asciiimpl.h>

  3: #define QUEUESTRINGSIZE 8192

  5: static PetscErrorCode PetscViewerFileClose_ASCII(PetscViewer viewer)
  6: {
  7:   PetscMPIInt        rank;
  8:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
  9:   int                err;

 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: }

 37: /* ----------------------------------------------------------------------*/
 38: static PetscErrorCode PetscViewerDestroy_ASCII(PetscViewer viewer)
 39: {
 40:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
 41:   PetscViewerLink   *vlink;
 42:   PetscBool          flg;

 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));

 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));

 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:   }

 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: }

 90: static PetscErrorCode PetscViewerDestroy_ASCII_SubViewer(PetscViewer viewer)
 91: {
 92:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;

 94:   PetscFunctionBegin;
 95:   PetscCall(PetscViewerRestoreSubViewer(vascii->bviewer, 0, &viewer));
 96:   PetscFunctionReturn(PETSC_SUCCESS);
 97: }

 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;

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));

112:   if (!vascii->bviewer && rank == 0 && (vascii->mode != FILE_MODE_READ)) PetscCall(PetscFFlush(vascii->fd));

114:   if (vascii->allowsynchronized) {
115:     PetscMPIInt tag, i, j, n = 0, dummy = 0;
116:     char       *message;
117:     MPI_Status  status;

119:     PetscCall(PetscCommDuplicate(comm, &comm, &tag));

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;

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;

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: }

177: /*@C
178:   PetscViewerASCIIGetPointer - Extracts the file pointer from an ASCII `PetscViewer`.

180:   Not Collective, depending on the viewer the value may be meaningless except for process 0 of the viewer; No Fortran Support

182:   Input Parameter:
183: . viewer - `PetscViewer` context, obtained from `PetscViewerASCIIOpen()`

185:   Output Parameter:
186: . fd - file pointer

188:   Level: intermediate

190:   Note:
191:   For the standard `PETSCVIEWERASCII` the value is valid only on MPI rank 0 of the viewer

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;

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: }

206: static PetscErrorCode PetscViewerFileGetMode_ASCII(PetscViewer viewer, PetscFileMode *mode)
207: {
208:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;

210:   PetscFunctionBegin;
211:   *mode = vascii->mode;
212:   PetscFunctionReturn(PETSC_SUCCESS);
213: }

215: static PetscErrorCode PetscViewerFileSetMode_ASCII(PetscViewer viewer, PetscFileMode mode)
216: {
217:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;

219:   PetscFunctionBegin;
220:   vascii->mode = mode;
221:   PetscFunctionReturn(PETSC_SUCCESS);
222: }

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;

230: /*@
231:   PetscViewerASCIISetTab - Causes `PetscViewer` to tab in a number of times before printing

233:   Not Collective, but only first processor in set has any effect; No Fortran Support

235:   Input Parameters:
236: + viewer - obtained with `PetscViewerASCIIOpen()`
237: - tabs   - number of tabs

239:   Level: developer

241:   Note:
242:   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage

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;

255:   PetscFunctionBegin;
257:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
258:   if (iascii) ascii->tab = tabs;
259:   PetscFunctionReturn(PETSC_SUCCESS);
260: }

262: /*@
263:   PetscViewerASCIIGetTab - Return the number of tabs used by `PetscViewer`.

265:   Not Collective, meaningful on first processor only; No Fortran Support

267:   Input Parameter:
268: . viewer - obtained with `PetscViewerASCIIOpen()`

270:   Output Parameter:
271: . tabs - number of tabs

273:   Level: developer

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;

285:   PetscFunctionBegin;
287:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
288:   if (iascii && tabs) *tabs = ascii->tab;
289:   PetscFunctionReturn(PETSC_SUCCESS);
290: }

292: /*@
293:   PetscViewerASCIIAddTab - Add to the number of times a `PETSCVIEWERASCII` viewer tabs before printing

295:   Not Collective, but only first processor in set has any effect; No Fortran Support

297:   Input Parameters:
298: + viewer - obtained with `PetscViewerASCIIOpen()`
299: - tabs   - number of tabs

301:   Level: developer

303:   Note:
304:   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage

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;

315:   PetscFunctionBegin;
317:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
318:   if (iascii) ascii->tab += tabs;
319:   PetscFunctionReturn(PETSC_SUCCESS);
320: }

322: /*@
323:   PetscViewerASCIISubtractTab - Subtracts from the number of times a `PETSCVIEWERASCII` viewer tabs before printing

325:   Not Collective, but only first processor in set has any effect; No Fortran Support

327:   Input Parameters:
328: + viewer - obtained with `PetscViewerASCIIOpen()`
329: - tabs   - number of tabs

331:   Level: developer

333:   Note:
334:   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage

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;

346:   PetscFunctionBegin;
348:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
349:   if (iascii) ascii->tab -= tabs;
350:   PetscFunctionReturn(PETSC_SUCCESS);
351: }

353: /*@C
354:   PetscViewerASCIIPushSynchronized - Allows calls to `PetscViewerASCIISynchronizedPrintf()` for this viewer

356:   Collective

358:   Input Parameter:
359: . viewer - obtained with `PetscViewerASCIIOpen()`

361:   Level: intermediate

363:   Note:
364:   See documentation of `PetscViewerASCIISynchronizedPrintf()` for more details how the synchronized output should be done properly.

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;

375:   PetscFunctionBegin;
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: }

383: /*@C
384:   PetscViewerASCIIPopSynchronized - Undoes most recent `PetscViewerASCIIPushSynchronized()` for this viewer

386:   Collective

388:   Input Parameter:
389: . viewer - obtained with `PetscViewerASCIIOpen()`

391:   Level: intermediate

393:   Note:
394:   See documentation of `PetscViewerASCIISynchronizedPrintf()` for more details how the synchronized output should be done properly.

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;

405:   PetscFunctionBegin;
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: }

416: /*@C
417:   PetscViewerASCIIPushTab - Adds one more tab to the amount that `PetscViewerASCIIPrintf()`
418:   lines are tabbed.

420:   Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support

422:   Input Parameter:
423: . viewer - obtained with `PetscViewerASCIIOpen()`

425:   Level: developer

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;

436:   PetscFunctionBegin;
438:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
439:   if (iascii) ascii->tab++;
440:   PetscFunctionReturn(PETSC_SUCCESS);
441: }

443: /*@C
444:   PetscViewerASCIIPopTab - Removes one tab from the amount that `PetscViewerASCIIPrintf()` lines are tabbed that was provided by
445:   `PetscViewerASCIIPushTab()`

447:   Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support

449:   Input Parameter:
450: . viewer - obtained with `PetscViewerASCIIOpen()`

452:   Level: developer

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;

463:   PetscFunctionBegin;
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: }

473: /*@
474:   PetscViewerASCIIUseTabs - Turns on or off the use of tabs with the `PETSCVIEWERASCII` `PetscViewer`

476:   Not Collective, but only first MPI rank in the viewer has any effect; No Fortran Support

478:   Input Parameters:
479: + viewer - obtained with `PetscViewerASCIIOpen()`
480: - flg    - `PETSC_TRUE` or `PETSC_FALSE`

482:   Level: developer

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;

493:   PetscFunctionBegin;
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: }

506: #if defined(PETSC_USE_FORTRAN_BINDINGS)

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

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

526:   #define PETSCDEFAULTBUFFERSIZE 8 * 1024

528: static PetscInt PETSC_VIEWER_ASCII_WORLD_fileunit = 0;

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

534:   Synopsis:
535: #include <petscviewer.h>
536:   void PetscViewerASCIIWORLDSetFileUnit(PetscInt unit, PetscErrorCode ierr)

538:   Input Parameter:
539: . unit - the unit number

541:   Output Parameter:
542: . ierr - the error code

544:   Level: intermediate

546:   Notes:
547:   Must be called before `PetscInitialize()`

549:   This may not work currently with some viewers that (improperly) use the `fd` directly instead of `PetscViewerASCIIPrintf()`

551:   With this option, for example, `-log_options` results will be saved to the Fortran file

553:   Any process may call this but only the unit passed on the first process is used

555:   Fortran Note:
556:   Only for Fortran

558:   Developer Note:
559:   `PetscViewerASCIIWORLDSetFilename()` could be added in the future

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: }

568: #include <petsc/private/fortranimpl.h>

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

574:   Synopsis:
575: #include <petscviewer.h>
576:   void PetscViewerASCIISetFileUnit(PetscViewer lab, PetscInt unit, PetscErrorCode ierr)

578:   Input Parameters:
579: + lab  - the viewer
580: - unit - the unit number

582:   Output Parameter:
583: . ierr - the error code

585:   Level: intermediate

587:   Note:
588:   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`

590:   Fortran Notes:
591:   Only for Fortran, use  `PetscViewerASCIISetFILE()` for C

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;

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: }

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

613:   Synopsis:
614: #include <petscviewer.h>
615:   void PetscViewerASCIIOpenWithFileUnit(MPI_Comm comm, PetscInt unit, PetscViewer viewer, PetscErrorCode ierr)

617:   Input Parameters:
618: + comm - the `MPI_Comm` to share the viewer
619: - unit - the unit number

621:   Output Parameters:
622: + lab  - the viewer
623: - ierr - the error code

625:   Level: intermediate

627:   Note:
628:   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`

630:   Fortran Notes:
631:   Only for Fortran, use  `PetscViewerASCIIOpenWithFILE()` for C

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: }

646: static PetscErrorCode PetscVFPrintfFortran(PetscInt unit, const char format[], va_list Argp)
647: {
648:   PetscErrorCode ierr;
649:   char           str[PETSCDEFAULTBUFFERSIZE];
650:   size_t         len;

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: }

659: static PetscErrorCode PetscFPrintfFortran(PetscInt unit, const char str[])
660: {
661:   PetscErrorCode ierr;
662:   size_t         len;

664:   PetscFunctionBegin;
665:   PetscCall(PetscStrlen(str, &len));
666:   petscfortranprinttounit_(&unit, str, &ierr, (int)len);
667:   PetscFunctionReturn(PETSC_SUCCESS);
668: }

670: #else

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: }

679: static PetscErrorCode PetscFPrintfFortran(PetscInt unit, const char str[])
680: {
681:   PetscFunctionBegin;
682:   PetscFunctionReturn(PETSC_SUCCESS);
683: }
684: #endif

686: /*@
687:   PetscViewerASCIIGetStdout - Creates a `PETSCVIEWERASCII` `PetscViewer` shared by all processes
688:   in a communicator. Error returning version of `PETSC_VIEWER_STDOUT_()`

690:   Collective

692:   Input Parameter:
693: . comm - the MPI communicator to share the `PetscViewer`

695:   Output Parameter:
696: . viewer - the viewer

698:   Level: beginner

700:   Note:
701:   This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it

703:   Developer Note:
704:   This should be used in all PETSc source code instead of `PETSC_VIEWER_STDOUT_()` since it allows error checking

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;

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;

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;

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: }

742: /*@C
743:   PetscViewerASCIIPrintf - Prints to a file, only from the first
744:   processor in the `PetscViewer` of type `PETSCVIEWERASCII`

746:   Not Collective, but only the first MPI rank in the viewer has any effect

748:   Input Parameters:
749: + viewer - obtained with `PetscViewerASCIIOpen()`
750: - format - the usual printf() format string

752:   Level: developer

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.

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;

770:   PetscFunctionBegin;
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);

779:   if (ascii->bviewer) { /* pass string up to parent viewer */
780:     char   *string;
781:     va_list Argp;
782:     size_t  fullLength;

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;

794:     tab = intab;
795:     while (tab--) {
796:       if (!ascii->fileunit) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "  "));
797:       else PetscCall(PetscFPrintfFortran(ascii->fileunit, "   "));
798:     }

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: }

809: /*@C
810:   PetscViewerFileSetName - Sets the name of the file the `PetscViewer` should use.

812:   Collective

814:   Input Parameters:
815: + viewer - the `PetscViewer`; for example, of type `PETSCVIEWERASCII` or `PETSCVIEWERBINARY`
816: - name   - the name of the file it should use

818:   Level: advanced

820:   Note:
821:   This will have no effect on viewers that are not related to files

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];

830:   PetscFunctionBegin;
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: }

838: /*@C
839:   PetscViewerFileGetName - Gets the name of the file the `PetscViewer` is using

841:   Not Collective

843:   Input Parameter:
844: . viewer - the `PetscViewer`

846:   Output Parameter:
847: . name - the name of the file it is using

849:   Level: advanced

851:   Note:
852:   This will have no effect on viewers that are not related to files

854: .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerFileSetName()`
855: @*/
856: PetscErrorCode PetscViewerFileGetName(PetscViewer viewer, const char **name)
857: {
858:   PetscFunctionBegin;
860:   PetscAssertPointer(name, 2);
861:   PetscUseMethod(viewer, "PetscViewerFileGetName_C", (PetscViewer, const char **), (viewer, name));
862:   PetscFunctionReturn(PETSC_SUCCESS);
863: }

865: static PetscErrorCode PetscViewerFileGetName_ASCII(PetscViewer viewer, const char **name)
866: {
867:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;

869:   PetscFunctionBegin;
870:   *name = vascii->filename;
871:   PetscFunctionReturn(PETSC_SUCCESS);
872: }

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;

883:   PetscFunctionBegin;
884:   PetscCall(PetscViewerFileClose_ASCII(viewer));
885:   if (!name) PetscFunctionReturn(PETSC_SUCCESS);
886:   PetscCall(PetscStrallocpy(name, &vascii->filename));

888:   /* Is this file to be compressed */
889:   vascii->storecompressed = PETSC_FALSE;

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: }

945: static PetscErrorCode PetscViewerGetSubViewer_ASCII(PetscViewer viewer, MPI_Comm subcomm, PetscViewer *outviewer)
946: {
947:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data, *ovascii;

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

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;

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: }

976: static PetscErrorCode PetscViewerRestoreSubViewer_ASCII(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer)
977: {
978:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;

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");

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: }

993: static PetscErrorCode PetscViewerView_ASCII(PetscViewer v, PetscViewer viewer)
994: {
995:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)v->data;

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: }

1003: /*MC
1004:    PETSCVIEWERASCII - A viewer that prints to stdout or an ASCII file

1006:   Level: beginner

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;

1016:   PetscFunctionBegin;
1017:   PetscCall(PetscNew(&vascii));
1018:   viewer->data = (void *)vascii;

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;

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;

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: }

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.

1050:   Not Collective, must call collective `PetscViewerFlush()` to get the results flushed

1052:   Input Parameters:
1053: + viewer - the `PETSCVIEWERASCII` `PetscViewer`
1054: - format - the usual printf() format string

1056:   Level: intermediate

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.

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".

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

1080:   Fortran Notes:
1081:   Can only print a single character* string

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;

1095:   PetscFunctionBegin;
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");

1102:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
1103:   PetscCallMPI(MPI_Comm_rank(comm, &rank));

1105:   if (vascii->bviewer) {
1106:     char   *string;
1107:     va_list Argp;
1108:     size_t  fullLength;

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;

1121:     tab = vascii->tab;
1122:     while (tab--) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fp, "  "));

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;

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;

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: }

1174: /*@C
1175:   PetscViewerASCIIRead - Reads from a `PETSCVIEWERASCII` file

1177:   Only MPI rank 0 in the `PetscViewer` may call this

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

1185:   Output Parameter:
1186: . count - number of items of data actually read, or `NULL`

1188:   Level: beginner

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;

1202:   PetscFunctionBegin;
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: }