Date: 2026-06-01T23:13:41+00:00

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: static PetscErrorCode PetscViewerDestroy_ASCII(PetscViewer viewer)
     38: {
     39:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
     40:   PetscViewerLink   *vlink;
     41:   PetscMPIInt        iflg;

     43:   PetscFunctionBegin;
     44:   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
     45:   PetscCall(PetscViewerFileClose_ASCII(viewer));
     46:   PetscCall(PetscFree(vascii));

     48:   /* remove the viewer from the list in the MPI Communicator */
     49:   if (Petsc_Viewer_keyval == MPI_KEYVAL_INVALID) PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, Petsc_DelViewer, &Petsc_Viewer_keyval, NULL));

     51:   PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval, (void **)&vlink, &iflg));
     52:   if (iflg) {
     53:     if (vlink && vlink->viewer == viewer) {
     54:       if (vlink->next) {
     55:         PetscCallMPI(MPI_Comm_set_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval, vlink->next));
     56:       } else {
     57:         PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_keyval));
     58:       }
     59:       PetscCall(PetscFree(vlink));
     60:     } else {
     61:       while (vlink && vlink->next) {
     62:         if (vlink->next->viewer == viewer) {
     63:           PetscViewerLink *nv = vlink->next;
     64:           vlink->next         = vlink->next->next;
     65:           PetscCall(PetscFree(nv));
     66:         }
     67:         vlink = vlink->next;
     68:       }
     69:     }
     70:   }

     72:   if (Petsc_Viewer_Stdout_keyval != MPI_KEYVAL_INVALID) {
     73:     PetscViewer aviewer;
     74:     PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stdout_keyval, (void **)&aviewer, &iflg));
     75:     if (iflg && aviewer == viewer) PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stdout_keyval));
     76:   }
     77:   if (Petsc_Viewer_Stderr_keyval != MPI_KEYVAL_INVALID) {
     78:     PetscViewer aviewer;
     79:     PetscCallMPI(MPI_Comm_get_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stderr_keyval, (void **)&aviewer, &iflg));
     80:     if (iflg && aviewer == viewer) PetscCallMPI(MPI_Comm_delete_attr(PetscObjectComm((PetscObject)viewer), Petsc_Viewer_Stderr_keyval));
     81:   }
     82:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", NULL));
     83:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", NULL));
     84:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", NULL));
     85:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", NULL));
     86:   PetscFunctionReturn(PETSC_SUCCESS);
     87: }

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

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

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

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

    103:   Input Parameter:
    104: . viewer - `PetscViewer` context, obtained from `PetscViewerASCIIOpen()`

    106:   Output Parameter:
    107: . fd - file pointer

    109:   Level: intermediate

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

    114: .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscViewerASCIIOpen()`, `PetscViewerDestroy()`, `PetscViewerSetType()`,
    115:           `PetscViewerCreate()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`
    116: @*/
    117: PetscErrorCode PetscViewerASCIIGetPointer(PetscViewer viewer, FILE **fd)
    118: {
    119:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;

    121:   PetscFunctionBegin;
    122:   PetscCheck(!vascii->fileunit, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot request file pointer for viewers that use Fortran files");
    123:   *fd = vascii->fd;
    124:   PetscFunctionReturn(PETSC_SUCCESS);
    125: }

    127: static PetscErrorCode PetscViewerFileGetMode_ASCII(PetscViewer viewer, PetscFileMode *mode)
    128: {
    129:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;

    131:   PetscFunctionBegin;
    132:   *mode = vascii->mode;
    133:   PetscFunctionReturn(PETSC_SUCCESS);
    134: }

    136: static PetscErrorCode PetscViewerFileSetMode_ASCII(PetscViewer viewer, PetscFileMode mode)
    137: {
    138:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;

    140:   PetscFunctionBegin;
    141:   vascii->mode = mode;
    142:   PetscFunctionReturn(PETSC_SUCCESS);
    143: }

    145: /*
    146:    If petsc_history is on, then all Petsc*Printf() results are saved
    147:    if the appropriate (usually .petschistory) file.
    148: */
    149: PETSC_INTERN FILE *petsc_history;

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

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

    156:   Input Parameters:
    157: + viewer - obtained with `PetscViewerASCIIOpen()`
    158: - tabs   - number of tabs

    160:   Level: developer

    162:   Note:
    163:   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage

    165: .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
    166:           `PetscViewerASCIIGetTab()`,
    167:           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
    168:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`,
    169:           `PetscViewerASCIIPushTab()`
    170: @*/
    171: PetscErrorCode PetscViewerASCIISetTab(PetscViewer viewer, PetscInt tabs)
    172: {
    173:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
    174:   PetscBool          isascii;

    176:   PetscFunctionBegin;
    178:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    179:   if (isascii) ascii->tab = tabs;
    180:   PetscFunctionReturn(PETSC_SUCCESS);
    181: }

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

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

    188:   Input Parameter:
    189: . viewer - obtained with `PetscViewerASCIIOpen()`

    191:   Output Parameter:
    192: . tabs - number of tabs

    194:   Level: developer

    196: .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
    197:           `PetscViewerASCIISetTab()`,
    198:           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
    199:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
    200: @*/
    201: PetscErrorCode PetscViewerASCIIGetTab(PetscViewer viewer, PetscInt *tabs)
    202: {
    203:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
    204:   PetscBool          isascii;

    206:   PetscFunctionBegin;
    208:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    209:   if (isascii && tabs) *tabs = ascii->tab;
    210:   PetscFunctionReturn(PETSC_SUCCESS);
    211: }

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

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

    218:   Input Parameters:
    219: + viewer - obtained with `PetscViewerASCIIOpen()`
    220: - tabs   - number of tabs

    222:   Level: developer

    224:   Note:
    225:   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage

    227: .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
    228:           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
    229:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushTab()`
    230: @*/
    231: PetscErrorCode PetscViewerASCIIAddTab(PetscViewer viewer, PetscInt tabs)
    232: {
    233:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
    234:   PetscBool          isascii;

    236:   PetscFunctionBegin;
    238:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    239:   if (isascii) ascii->tab += tabs;
    240:   PetscFunctionReturn(PETSC_SUCCESS);
    241: }

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

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

    248:   Input Parameters:
    249: + viewer - obtained with `PetscViewerASCIIOpen()`
    250: - tabs   - number of tabs

    252:   Level: developer

    254:   Note:
    255:   `PetscViewerASCIIPushTab()` and `PetscViewerASCIIPopTab()` are the preferred usage

    257: .seealso: [](sec_viewers), `PETSCVIEWERASCII`, `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
    258:           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
    259:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`,
    260:           `PetscViewerASCIIPushTab()`
    261: @*/
    262: PetscErrorCode PetscViewerASCIISubtractTab(PetscViewer viewer, PetscInt tabs)
    263: {
    264:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
    265:   PetscBool          isascii;

    267:   PetscFunctionBegin;
    269:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    270:   if (isascii) ascii->tab -= tabs;
    271:   PetscFunctionReturn(PETSC_SUCCESS);
    272: }

    274: /*@
    275:   PetscViewerASCIIPushSynchronized - Allows calls to `PetscViewerASCIISynchronizedPrintf()` for this viewer

    277:   Collective

    279:   Input Parameter:
    280: . viewer - obtained with `PetscViewerASCIIOpen()`

    282:   Level: intermediate

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

    287: .seealso: [](sec_viewers), `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
    288:           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
    289:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
    290: @*/
    291: PetscErrorCode PetscViewerASCIIPushSynchronized(PetscViewer viewer)
    292: {
    293:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
    294:   PetscBool          isascii;

    296:   PetscFunctionBegin;
    298:   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
    299:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    300:   if (isascii) ascii->allowsynchronized++;
    301:   PetscFunctionReturn(PETSC_SUCCESS);
    302: }

    304: /*@
    305:   PetscViewerASCIIPopSynchronized - Undoes most recent `PetscViewerASCIIPushSynchronized()` for this viewer

    307:   Collective

    309:   Input Parameter:
    310: . viewer - obtained with `PetscViewerASCIIOpen()`

    312:   Level: intermediate

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

    317: .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerFlush()`,
    318:           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
    319:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
    320: @*/
    321: PetscErrorCode PetscViewerASCIIPopSynchronized(PetscViewer viewer)
    322: {
    323:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
    324:   PetscBool          isascii;

    326:   PetscFunctionBegin;
    328:   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
    329:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    330:   if (isascii) {
    331:     ascii->allowsynchronized--;
    332:     PetscCheck(ascii->allowsynchronized >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Called more times than PetscViewerASCIIPushSynchronized()");
    333:   }
    334:   PetscFunctionReturn(PETSC_SUCCESS);
    335: }

    337: /*@
    338:   PetscViewerASCIIPushTab - Adds one more tab to the amount that `PetscViewerASCIIPrintf()`
    339:   lines are tabbed.

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

    343:   Input Parameter:
    344: . viewer - obtained with `PetscViewerASCIIOpen()`

    346:   Level: developer

    348: .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
    349:           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
    350:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
    351: @*/
    352: PetscErrorCode PetscViewerASCIIPushTab(PetscViewer viewer)
    353: {
    354:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
    355:   PetscBool          isascii;

    357:   PetscFunctionBegin;
    359:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    360:   if (isascii) ascii->tab++;
    361:   PetscFunctionReturn(PETSC_SUCCESS);
    362: }

    364: /*@
    365:   PetscViewerASCIIPopTab - Removes one tab from the amount that `PetscViewerASCIIPrintf()` lines are tabbed that was provided by
    366:   `PetscViewerASCIIPushTab()`

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

    370:   Input Parameter:
    371: . viewer - obtained with `PetscViewerASCIIOpen()`

    373:   Level: developer

    375: .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
    376:           `PetscViewerASCIIPushTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
    377:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
    378: @*/
    379: PetscErrorCode PetscViewerASCIIPopTab(PetscViewer viewer)
    380: {
    381:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
    382:   PetscBool          isascii;

    384:   PetscFunctionBegin;
    386:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    387:   if (isascii) {
    388:     PetscCheck(ascii->tab > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "More tabs popped than pushed");
    389:     ascii->tab--;
    390:   }
    391:   PetscFunctionReturn(PETSC_SUCCESS);
    392: }

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

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

    399:   Input Parameters:
    400: + viewer - obtained with `PetscViewerASCIIOpen()`
    401: - flg    - `PETSC_TRUE` or `PETSC_FALSE`

    403:   Level: developer

    405: .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`,
    406:           `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`, `PetscViewerASCIIPushTab()`, `PetscViewerASCIIOpen()`,
    407:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`
    408: @*/
    409: PetscErrorCode PetscViewerASCIIUseTabs(PetscViewer viewer, PetscBool flg)
    410: {
    411:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
    412:   PetscBool          isascii;

    414:   PetscFunctionBegin;
    416:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    417:   if (isascii) {
    418:     if (flg) ascii->tab = ascii->tab_store;
    419:     else {
    420:       ascii->tab_store = ascii->tab;
    421:       ascii->tab       = 0;
    422:     }
    423:   }
    424:   PetscFunctionReturn(PETSC_SUCCESS);
    425: }

    427: #if defined(PETSC_USE_FORTRAN_BINDINGS)

    429:   #if defined(PETSC_HAVE_FORTRAN_CAPS)
    430:     #define petscviewerasciiopenwithfileunit_  PETSCVIEWERASCIIOPENWITHFILEUNIT
    431:     #define petscviewerasciisetfileunit_       PETSCVIEWERASCIISETFILEUNIT
    432:     #define petscviewerasciistdoutsetfileunit_ PETSCVIEWERASCIISTDOUTSETFILEUNIT
    433:     #define petscfortranprinttofileunit_       PETSCFORTRANPRINTTOFILEUNIT
    434:   #elif !defined(PETSC_HAVE_FORTRAN_UNDERSCORE)
    435:     #define petscviewerasciiopenwithfileunit_  petscviewerasciiopenwithfileunit
    436:     #define petscviewerasciisetfileunit_       petscviewerasciisetfileunit
    437:     #define petscviewerasciistdoutsetfileunit_ petscviewerasciistdoutsetfileunit
    438:     #define petscfortranprinttofileunit_       petscfortranprinttofileunit
    439:   #endif

    441:   #if defined(__cplusplus)
    442: extern "C" void petscfortranprinttofileunit_(int *, const char *, PetscErrorCode *, PETSC_FORTRAN_CHARLEN_T);
    443:   #else
    444: extern void petscfortranprinttofileunit_(int *, const char *, PetscErrorCode *, PETSC_FORTRAN_CHARLEN_T);
    445:   #endif

    447:   #define PETSCDEFAULTBUFFERSIZE 8 * 1024

    449: static int PETSC_VIEWER_ASCII_STDOUT_fileunit = 0;

    451: // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
    452: /*MC
    453:   PetscViewerASCIIStdoutSetFileUnit - sets `PETSC_VIEWER_STDOUT_()` to write to a Fortran IO unit

    455:   Synopsis:
    456: #include <petscviewer.h>
    457:   void PetscViewerASCIIStdoutSetFileUnit(PetscInt unit, PetscErrorCode ierr)

    459:   Input Parameter:
    460: . unit - the unit number

    462:   Output Parameter:
    463: . ierr - the error code

    465:   Level: intermediate

    467:   Notes:
    468:   Can be called before `PetscInitialize()`

    470:   Immediately changes the output for all `PETSC_VIEWER_STDOUT_()` viewers

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

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

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

    478:   Fortran Note:
    479:   Only for Fortran

    481:   Developer Note:
    482:   `PetscViewerASCIIWORLDSetFilename()` and `PetscViewerASCIIWORLDSetFILE()` could be added

    484: .seealso: `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFileUnit()`, `PetscViewerASCIIStdoutSetFileUnit()`,
    485:           `PETSC_VIEWER_STDOUT_()`, `PetscViewerASCIIGetStdout()`
    486: M*/
    487: PETSC_EXTERN void petscviewerasciistdoutsetfileunit_(int *unit, PetscErrorCode *ierr)
    488: {
    489:   #if defined(PETSC_USE_FORTRAN_BINDINGS)
    490:   PETSC_VIEWER_ASCII_STDOUT_fileunit = *unit;
    491:   #endif
    492: }

    494: #include <petsc/private/ftnimpl.h>

    496: // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
    497: /*MC
    498:   PetscViewerASCIISetFileUnit - sets the `PETSCVIEWERASCII` `PetscViewer` to write to a Fortran IO unit

    500:   Synopsis:
    501: #include <petscviewer.h>
    502:   void PetscViewerASCIISetFileUnit(PetscViewer viewer, PetscInt unit, PetscErrorCode ierr)

    504:   Input Parameters:
    505: + viewer - the viewer
    506: - unit   - the unit number

    508:   Output Parameter:
    509: . ierr - the error code

    511:   Level: intermediate

    513:   Note:
    514:   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`

    516:   Fortran Notes:
    517:   Only for Fortran, use  `PetscViewerASCIISetFILE()` for C

    519: .seealso: `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFileUnit()`, `PetscViewerASCIIStdoutSetFileUnit()`
    520: M*/
    521: PETSC_EXTERN void petscviewerasciisetfileunit_(PetscViewer *viewer, int *unit, PetscErrorCode *ierr)
    522: {
    523:   PetscViewer_ASCII *vascii;
    524:   PetscViewer        v;

    526:   PetscPatchDefaultViewers_Fortran(viewer, v);
    527:   vascii = (PetscViewer_ASCII *)v->data;
    528:   if (vascii->mode == FILE_MODE_READ) {
    529:     *ierr = PETSC_ERR_ARG_WRONGSTATE;
    530:     return;
    531:   }
    532:   vascii->fileunit = *unit;
    533: }

    535: // PetscClangLinter pragma disable: -fdoc-synopsis-macro-explicit-synopsis-valid-header
    536: /*MC
    537:   PetscViewerASCIIOpenWithFileUnit - opens a `PETSCVIEWERASCII` to write to a Fortran IO unit

    539:   Synopsis:
    540: #include <petscviewer.h>
    541:   void PetscViewerASCIIOpenWithFileUnit((MPI_Fint comm, integer unit, PetscViewer viewer, PetscErrorCode ierr)

    543:   Input Parameters:
    544: + comm - the `MPI_Comm` to share the viewer
    545: - unit - the unit number

    547:   Output Parameters:
    548: + viewer - the viewer
    549: - ierr   - the error code

    551:   Level: intermediate

    553:   Note:
    554:   `PetscViewerDestroy()` does not close the unit for this `PetscViewer`

    556:   Fortran Notes:
    557:   Only for Fortran, use  `PetscViewerASCIIOpenWithFILE()` for C

    559: .seealso: `PetscViewerASCIISetFileUnit()`, `PetscViewerASCIISetFILE()`, `PETSCVIEWERASCII`, `PetscViewerASCIIOpenWithFILE()`
    560: M*/
    561: PETSC_EXTERN void petscviewerasciiopenwithfileunit_(MPI_Fint *comm, int *unit, PetscViewer *viewer, PetscErrorCode *ierr)
    562: {
    563:   *ierr = PetscViewerCreate(MPI_Comm_f2c(*(MPI_Fint *)&*comm), viewer);
    564:   if (*ierr) return;
    565:   *ierr = PetscViewerSetType(*viewer, PETSCVIEWERASCII);
    566:   if (*ierr) return;
    567:   *ierr = PetscViewerFileSetMode(*viewer, FILE_MODE_WRITE);
    568:   if (*ierr) return;
    569:   petscviewerasciisetfileunit_(viewer, unit, ierr);
    570: }

    572: static PetscErrorCode PetscVFPrintfFortran(int unit, const char format[], va_list Argp)
    573: {
    574:   PetscErrorCode ierr;
    575:   char           str[PETSCDEFAULTBUFFERSIZE];
    576:   size_t         len;

    578:   PetscFunctionBegin;
    579:   PetscCall(PetscVSNPrintf(str, sizeof(str), format, NULL, Argp));
    580:   PetscCall(PetscStrlen(str, &len));
    581:   petscfortranprinttofileunit_(&unit, str, &ierr, (int)len);
    582:   PetscFunctionReturn(PETSC_SUCCESS);
    583: }

    585: static PetscErrorCode PetscFPrintfFortran(int unit, const char str[])
    586: {
    587:   PetscErrorCode ierr;
    588:   size_t         len;

    590:   PetscFunctionBegin;
    591:   PetscCall(PetscStrlen(str, &len));
    592:   petscfortranprinttofileunit_(&unit, str, &ierr, (int)len);
    593:   PetscFunctionReturn(PETSC_SUCCESS);
    594: }

    596: #else

    598: /* these will never be used; but are needed to link with */
    599: static PetscErrorCode PetscVFPrintfFortran(int unit, const char format[], va_list Argp)
    600: {
    601:   PetscFunctionBegin;
    602:   PetscFunctionReturn(PETSC_SUCCESS);
    603: }

    605: static PetscErrorCode PetscFPrintfFortran(int unit, const char str[])
    606: {
    607:   PetscFunctionBegin;
    608:   PetscFunctionReturn(PETSC_SUCCESS);
    609: }
    610: #endif

    612: /*@
    613:   PetscViewerASCIIGetStdout - Creates a `PETSCVIEWERASCII` `PetscViewer` shared by all processes
    614:   in a communicator that prints to `stdout`. Error returning version of `PETSC_VIEWER_STDOUT_()`

    616:   Collective

    618:   Input Parameter:
    619: . comm - the MPI communicator to share the `PetscViewer`

    621:   Output Parameter:
    622: . viewer - the viewer

    624:   Level: beginner

    626:   Note:
    627:   Use `PetscViewerDestroy()` to destroy it

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

    632: .seealso: [](sec_viewers), `PetscViewerASCIIGetStderr()`, `PETSC_VIEWER_DRAW_()`, `PetscViewerASCIIOpen()`, `PETSC_VIEWER_STDERR_`, `PETSC_VIEWER_STDOUT_WORLD`,
    633:           `PETSC_VIEWER_STDOUT_SELF`
    634: @*/
    635: PetscErrorCode PetscViewerASCIIGetStdout(MPI_Comm comm, PetscViewer *viewer)
    636: {
    637:   PetscMPIInt iflg;
    638:   MPI_Comm    ncomm;

    640:   PetscFunctionBegin;
    641:   PetscAssertPointer(viewer, 2);
    642:   PetscCall(PetscSpinlockLock(&PetscViewerASCIISpinLockStdout));
    643:   PetscCall(PetscCommDuplicate(comm, &ncomm, NULL));
    644:   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));
    645:   PetscCallMPI(MPI_Comm_get_attr(ncomm, Petsc_Viewer_Stdout_keyval, (void **)viewer, &iflg));
    646:   if (!iflg) { /* PetscViewer not yet created */
    647: #if defined(PETSC_USE_FORTRAN_BINDINGS)
    648:     PetscCallMPI(MPI_Bcast(&PETSC_VIEWER_ASCII_STDOUT_fileunit, 1, MPI_INT, 0, comm));
    649:     if (PETSC_VIEWER_ASCII_STDOUT_fileunit) {
    650:       PetscErrorCode ierr;
    651:       MPI_Fint       fcomm = MPI_Comm_c2f(ncomm);

    653:       petscviewerasciiopenwithfileunit_(&fcomm, &PETSC_VIEWER_ASCII_STDOUT_fileunit, viewer, &ierr);
    654:     } else
    655: #endif
    656:     {
    657:       PetscViewerFormat format;
    658:       PetscBool         set;

    660:       PetscCall(PetscViewerCreate(ncomm, viewer));
    661:       PetscCall(PetscViewerSetType(*viewer, PETSCVIEWERASCII));
    662:       PetscCall(PetscOptionsGetEnum(NULL, NULL, "-petsc_viewer_stdout_format", PetscViewerFormats, (PetscEnum *)&format, &set));
    663:       if (set) PetscCall(PetscViewerPushFormat(*viewer, format));
    664:       PetscCall(PetscViewerFileSetName(*viewer, "stdout"));
    665:     }
    666:     PetscCall(PetscObjectRegisterDestroy((PetscObject)*viewer));
    667:     PetscCallMPI(MPI_Comm_set_attr(ncomm, Petsc_Viewer_Stdout_keyval, (void *)*viewer));
    668:   }
    669:   PetscCall(PetscCommDestroy(&ncomm));
    670:   PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockStdout));
    671: #if defined(PETSC_USE_FORTRAN_BINDINGS)
    672:   ((PetscViewer_ASCII *)(*viewer)->data)->fileunit = PETSC_VIEWER_ASCII_STDOUT_fileunit;
    673: #endif
    674:   PetscFunctionReturn(PETSC_SUCCESS);
    675: }

    677: /*@C
    678:   PetscViewerASCIIPrintf - Prints to a file, only from the first
    679:   processor in the `PetscViewer` of type `PETSCVIEWERASCII`

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

    683:   Input Parameters:
    684: + viewer - obtained with `PetscViewerASCIIOpen()`
    685: - format - the usual printf() format string

    687:   Level: developer

    689:   Fortran Note:
    690:   The call sequence is `PetscViewerASCIIPrintf`(`PetscViewer`, character(*), int ierr).
    691:   That is, you can only pass a single character string from Fortran.

    693: .seealso: [](sec_viewers), `PetscPrintf()`, `PetscSynchronizedPrintf()`, `PetscViewerASCIIOpen()`,
    694:           `PetscViewerASCIIPushTab()`, `PetscViewerASCIIPopTab()`, `PetscViewerASCIISynchronizedPrintf()`,
    695:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`, `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPushSynchronized()`
    696: @*/
    697: PetscErrorCode PetscViewerASCIIPrintf(PetscViewer viewer, const char format[], ...)
    698: {
    699:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;
    700:   PetscMPIInt        rank;
    701:   PetscInt           tab = 0, intab = ascii->tab;
    702:   FILE              *fd = ascii->fd;
    703:   PetscBool          isascii;

    705:   PetscFunctionBegin;
    707:   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
    708:   PetscAssertPointer(format, 2);
    709:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    710:   PetscCheck(isascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
    711:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
    712:   if (rank) PetscFunctionReturn(PETSC_SUCCESS);

    714:   if (ascii->bviewer) { /* pass string up to parent viewer */
    715:     char   *string;
    716:     va_list Argp;
    717:     size_t  fullLength;

    719:     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
    720:     for (; tab < ascii->tab; tab++) string[2 * tab] = string[2 * tab + 1] = ' ';
    721:     va_start(Argp, format);
    722:     PetscCall(PetscVSNPrintf(string + 2 * intab, QUEUESTRINGSIZE - 2 * intab, format, &fullLength, Argp));
    723:     va_end(Argp);
    724:     PetscCall(PetscViewerASCIISynchronizedPrintf(ascii->bviewer, "%s", string));
    725:     PetscCall(PetscFree(string));
    726:   } else { /* write directly to file */
    727:     va_list Argp;

    729:     tab = intab;
    730:     while (tab--) {
    731:       if (!ascii->fileunit) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "  "));
    732:       else PetscCall(PetscFPrintfFortran(ascii->fileunit, "   "));
    733:     }

    735:     va_start(Argp, format);
    736:     if (!ascii->fileunit) PetscCall((*PetscVFPrintf)(fd, format, Argp));
    737:     else PetscCall(PetscVFPrintfFortran(ascii->fileunit, format, Argp));
    738:     va_end(Argp);
    739:     PetscCall(PetscFFlush(fd));
    740:   }
    741:   PetscFunctionReturn(PETSC_SUCCESS);
    742: }

    744: /*@
    745:   PetscViewerFileSetName - Sets the name of the file the `PetscViewer` should use.

    747:   Collective

    749:   Input Parameters:
    750: + viewer - the `PetscViewer`; for example, of type `PETSCVIEWERASCII` or `PETSCVIEWERBINARY`
    751: - name   - the name of the file it should use

    753:   Level: advanced

    755:   Note:
    756:   This will have no effect on viewers that are not related to files

    758: .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerDestroy()`,
    759:           `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`
    760: @*/
    761: PetscErrorCode PetscViewerFileSetName(PetscViewer viewer, const char name[])
    762: {
    763:   char filename[PETSC_MAX_PATH_LEN];

    765:   PetscFunctionBegin;
    767:   PetscAssertPointer(name, 2);
    768:   PetscCall(PetscStrreplace(PetscObjectComm((PetscObject)viewer), name, filename, sizeof(filename)));
    769:   PetscTryMethod(viewer, "PetscViewerFileSetName_C", (PetscViewer, const char[]), (viewer, filename));
    770:   PetscFunctionReturn(PETSC_SUCCESS);
    771: }

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

    776:   Not Collective

    778:   Input Parameter:
    779: . viewer - the `PetscViewer`

    781:   Output Parameter:
    782: . name - the name of the file it is using

    784:   Level: advanced

    786:   Note:
    787:   This will have no effect on viewers that are not related to files

    789: .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerFileSetName()`
    790: @*/
    791: PetscErrorCode PetscViewerFileGetName(PetscViewer viewer, const char *name[])
    792: {
    793:   PetscFunctionBegin;
    795:   PetscAssertPointer(name, 2);
    796:   PetscUseMethod(viewer, "PetscViewerFileGetName_C", (PetscViewer, const char **), (viewer, name));
    797:   PetscFunctionReturn(PETSC_SUCCESS);
    798: }

    800: static PetscErrorCode PetscViewerFileGetName_ASCII(PetscViewer viewer, const char **name)
    801: {
    802:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;

    804:   PetscFunctionBegin;
    805:   *name = vascii->filename;
    806:   PetscFunctionReturn(PETSC_SUCCESS);
    807: }

    809: #include <errno.h>
    810: static PetscErrorCode PetscViewerFileSetName_ASCII(PetscViewer viewer, const char name[])
    811: {
    812:   size_t             len;
    813:   char               fname[PETSC_MAX_PATH_LEN], *gz = NULL;
    814:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
    815:   PetscBool          isstderr, isstdout;
    816:   PetscMPIInt        rank;

    818:   PetscFunctionBegin;
    819:   PetscCall(PetscViewerFileClose_ASCII(viewer));
    820:   if (!name) PetscFunctionReturn(PETSC_SUCCESS);
    821:   PetscCall(PetscStrallocpy(name, &vascii->filename));

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

    826:   PetscCall(PetscStrstr(vascii->filename, ".gz", &gz));
    827:   if (gz) {
    828:     PetscCall(PetscStrlen(gz, &len));
    829:     if (len == 3) {
    830:       PetscCheck(vascii->mode == FILE_MODE_WRITE, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Cannot open ASCII PetscViewer file that is compressed; uncompress it manually first");
    831:       *gz                     = 0;
    832:       vascii->storecompressed = PETSC_TRUE;
    833:     }
    834:   }
    835:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
    836:   if (rank == 0) {
    837:     PetscCall(PetscStrcmp(name, "stderr", &isstderr));
    838:     PetscCall(PetscStrcmp(name, "stdout", &isstdout));
    839:     /* empty filename means stdout */
    840:     if (name[0] == 0) isstdout = PETSC_TRUE;
    841:     if (isstderr) vascii->fd = PETSC_STDERR;
    842:     else if (isstdout) vascii->fd = PETSC_STDOUT;
    843:     else {
    844:       PetscCall(PetscFixFilename(name, fname));
    845:       switch (vascii->mode) {
    846:       case FILE_MODE_READ:
    847:         vascii->fd = fopen(fname, "r");
    848:         break;
    849:       case FILE_MODE_WRITE:
    850:         vascii->fd = fopen(fname, "w");
    851:         break;
    852:       case FILE_MODE_APPEND:
    853:         vascii->fd = fopen(fname, "a");
    854:         break;
    855:       case FILE_MODE_UPDATE:
    856:         vascii->fd = fopen(fname, "r+");
    857:         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
    858:         break;
    859:       case FILE_MODE_APPEND_UPDATE:
    860:         /* I really want a file which is opened at the end for updating,
    861:            not a+, which opens at the beginning, but makes writes at the end.
    862:         */
    863:         vascii->fd = fopen(fname, "r+");
    864:         if (!vascii->fd) vascii->fd = fopen(fname, "w+");
    865:         else {
    866:           int ret = fseek(vascii->fd, 0, SEEK_END);
    867:           PetscCheck(!ret, PETSC_COMM_SELF, PETSC_ERR_LIB, "fseek() failed with error code %d", ret);
    868:         }
    869:         break;
    870:       default:
    871:         SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unsupported file mode %s", PetscFileModes[vascii->mode]);
    872:       }
    873:       PetscCheck(vascii->fd, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open PetscViewer file: %s due to \"%s\"", fname, strerror(errno));
    874:     }
    875:   }
    876:   PetscCall(PetscLogObjectState((PetscObject)viewer, "File: %s", name));
    877:   PetscFunctionReturn(PETSC_SUCCESS);
    878: }

    880: static PetscErrorCode PetscViewerGetSubViewer_ASCII(PetscViewer viewer, MPI_Comm subcomm, PetscViewer *outviewer)
    881: {
    882:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data, *ovascii;

    884:   PetscFunctionBegin;
    885:   PetscCheck(!vascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer already obtained from PetscViewer and not restored");
    886:   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
    887:   /*
    888:      The following line is a bug; it does another PetscViewerASCIIPushSynchronized() on viewer, but if it is removed the code won't work
    889:      because it relies on this behavior in other places. In particular this line causes the synchronized flush to occur when the viewer is destroyed
    890:      (since the count never gets to zero) in some examples this displays information that otherwise would be lost

    892:      This code also means another call to PetscViewerASCIIPopSynchronized() must be made after the PetscViewerRestoreSubViewer(), see, for example,
    893:      PCView_GASM().
    894:   */
    895:   PetscCall(PetscViewerASCIIPushSynchronized(viewer));
    896:   PetscCall(PetscViewerFlush(viewer));
    897:   PetscCall(PetscViewerCreate(subcomm, outviewer));
    898:   PetscCall(PetscViewerSetType(*outviewer, PETSCVIEWERASCII));
    899:   PetscCall(PetscViewerASCIIPushSynchronized(*outviewer));
    900:   ovascii            = (PetscViewer_ASCII *)(*outviewer)->data;
    901:   ovascii->fd        = vascii->fd;
    902:   ovascii->fileunit  = vascii->fileunit;
    903:   ovascii->closefile = PETSC_FALSE;

    905:   vascii->sviewer                                      = *outviewer;
    906:   (*outviewer)->format                                 = viewer->format;
    907:   ((PetscViewer_ASCII *)((*outviewer)->data))->bviewer = viewer;
    908:   (*outviewer)->ops->destroy                           = PetscViewerDestroy_ASCII_SubViewer;
    909:   PetscFunctionReturn(PETSC_SUCCESS);
    910: }

    912: static PetscErrorCode PetscViewerRestoreSubViewer_ASCII(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer)
    913: {
    914:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;

    916:   PetscFunctionBegin;
    917:   PetscCheck(ascii->sviewer, PETSC_COMM_SELF, PETSC_ERR_ORDER, "SubViewer never obtained from PetscViewer");
    918:   PetscCheck(ascii->sviewer == *outviewer, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "This PetscViewer did not generate this SubViewer");

    920:   PetscCall(PetscViewerASCIIPopSynchronized(*outviewer));
    921:   ascii->sviewer             = NULL;
    922:   (*outviewer)->ops->destroy = PetscViewerDestroy_ASCII;
    923:   PetscCall(PetscViewerDestroy(outviewer));
    924:   PetscCall(PetscViewerFlush(viewer));
    925:   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
    926:   PetscFunctionReturn(PETSC_SUCCESS);
    927: }

    929: static PetscErrorCode PetscViewerView_ASCII(PetscViewer v, PetscViewer viewer)
    930: {
    931:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)v->data;

    933:   PetscFunctionBegin;
    934:   if (ascii->fileunit) PetscCall(PetscViewerASCIIPrintf(viewer, "Fortran FILE UNIT: %d\n", ascii->fileunit));
    935:   else if (ascii->filename) PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", ascii->filename));
    936:   PetscFunctionReturn(PETSC_SUCCESS);
    937: }

    939: static PetscErrorCode PetscViewerFlush_ASCII(PetscViewer viewer)
    940: {
    941:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
    942:   MPI_Comm           comm;
    943:   PetscMPIInt        rank, size;
    944:   FILE              *fd = vascii->fd;

    946:   PetscFunctionBegin;
    947:   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
    948:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
    949:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
    950:   PetscCallMPI(MPI_Comm_size(comm, &size));

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

    954:   if (vascii->allowsynchronized) {
    955:     PetscMPIInt tag, i, j, n = 0, dummy = 0;
    956:     char       *message;
    957:     MPI_Status  status;

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

    961:     /* First processor waits for messages from all other processors */
    962:     if (rank == 0) {
    963:       /* flush my own messages that I may have queued up */
    964:       PrintfQueue next = vascii->petsc_printfqueuebase, previous;
    965:       for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
    966:         if (!vascii->bviewer) {
    967:           if (!vascii->fileunit) PetscCall(PetscFPrintf(comm, fd, "%s", next->string));
    968:           else PetscCall(PetscFPrintfFortran(vascii->fileunit, next->string));
    969:         } else {
    970:           PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", next->string));
    971:         }
    972:         previous = next;
    973:         next     = next->next;
    974:         PetscCall(PetscFree(previous->string));
    975:         PetscCall(PetscFree(previous));
    976:       }
    977:       vascii->petsc_printfqueue       = NULL;
    978:       vascii->petsc_printfqueuelength = 0;
    979:       for (i = 1; i < size; i++) {
    980:         /* to prevent a flood of messages to process zero, request each message separately */
    981:         PetscCallMPI(MPI_Send(&dummy, 1, MPI_INT, i, tag, comm));
    982:         PetscCallMPI(MPI_Recv(&n, 1, MPI_INT, i, tag, comm, &status));
    983:         for (j = 0; j < n; j++) {
    984:           size_t size;

    986:           PetscCallMPI(MPI_Recv(&size, 1, MPIU_SIZE_T, i, tag, comm, &status));
    987:           PetscCall(PetscMalloc1(size, &message));
    988:           PetscCallMPI(MPI_Recv(message, (PetscMPIInt)size, MPI_CHAR, i, tag, comm, &status));
    989:           if (!vascii->bviewer) {
    990:             if (!vascii->fileunit) PetscCall(PetscFPrintf(comm, fd, "%s", message));
    991:             else PetscCall(PetscFPrintfFortran(vascii->fileunit, message));
    992:           } else {
    993:             PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", message));
    994:           }
    995:           PetscCall(PetscFree(message));
    996:         }
    997:       }
    998:     } else { /* other processors send queue to processor 0 */
    999:       PrintfQueue next = vascii->petsc_printfqueuebase, previous;

    1001:       PetscCallMPI(MPI_Recv(&dummy, 1, MPI_INT, 0, tag, comm, &status));
    1002:       PetscCallMPI(MPI_Send(&vascii->petsc_printfqueuelength, 1, MPI_INT, 0, tag, comm));
    1003:       for (i = 0; i < vascii->petsc_printfqueuelength; i++) {
    1004:         PetscCallMPI(MPI_Send(&next->size, 1, MPIU_SIZE_T, 0, tag, comm));
    1005:         PetscCallMPI(MPI_Send(next->string, (PetscMPIInt)next->size, MPI_CHAR, 0, tag, comm));
    1006:         previous = next;
    1007:         next     = next->next;
    1008:         PetscCall(PetscFree(previous->string));
    1009:         PetscCall(PetscFree(previous));
    1010:       }
    1011:       vascii->petsc_printfqueue       = NULL;
    1012:       vascii->petsc_printfqueuelength = 0;
    1013:     }
    1014:     PetscCall(PetscCommDestroy(&comm));
    1015:   }
    1016:   PetscFunctionReturn(PETSC_SUCCESS);
    1017: }

    1019: /*MC
    1020:    PETSCVIEWERASCII - A viewer that prints to `stdout`, `stderr`, or an ASCII file

    1022:   Level: beginner

    1024: .seealso: [](sec_viewers), `PETSC_VIEWER_STDOUT_()`, `PETSC_VIEWER_STDOUT_SELF`, `PETSC_VIEWER_STDOUT_WORLD`, `PetscViewerCreate()`, `PetscViewerASCIIOpen()`,
    1025:           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERBINARY`, `PETSCVIEWERMATLAB`,
    1026:           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
    1027: M*/
    1028: PETSC_EXTERN PetscErrorCode PetscViewerCreate_ASCII(PetscViewer viewer)
    1029: {
    1030:   PetscViewer_ASCII *vascii;

    1032:   PetscFunctionBegin;
    1033:   PetscCall(PetscNew(&vascii));
    1034:   viewer->data = (void *)vascii;

    1036:   viewer->ops->destroy          = PetscViewerDestroy_ASCII;
    1037:   viewer->ops->flush            = PetscViewerFlush_ASCII;
    1038:   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_ASCII;
    1039:   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_ASCII;
    1040:   viewer->ops->view             = PetscViewerView_ASCII;
    1041:   viewer->ops->read             = PetscViewerASCIIRead;

    1043:   /* defaults to stdout unless set with PetscViewerFileSetName() */
    1044:   vascii->fd        = PETSC_STDOUT;
    1045:   vascii->mode      = FILE_MODE_WRITE;
    1046:   vascii->bviewer   = NULL;
    1047:   vascii->subviewer = NULL;
    1048:   vascii->sviewer   = NULL;
    1049:   vascii->tab       = 0;
    1050:   vascii->tab_store = 0;
    1051:   vascii->filename  = NULL;
    1052:   vascii->closefile = PETSC_TRUE;

    1054:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_ASCII));
    1055:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_ASCII));
    1056:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_ASCII));
    1057:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_ASCII));
    1058:   PetscFunctionReturn(PETSC_SUCCESS);
    1059: }

    1061: /*@C
    1062:   PetscViewerASCIISynchronizedPrintf - Prints synchronized output to the specified `PETSCVIEWERASCII` file from
    1063:   several processors.  Output of the first processor is followed by that of the
    1064:   second, etc.

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

    1068:   Input Parameters:
    1069: + viewer - the `PETSCVIEWERASCII` `PetscViewer`
    1070: - format - the usual printf() format string

    1072:   Level: intermediate

    1074:   Notes:
    1075:   You must have previously called `PetscViewerASCIIPushSynchronized()` to allow this routine to be called.
    1076:   Then you can do multiple independent calls to this routine.

    1078:   The actual synchronized print is then done using `PetscViewerFlush()`.
    1079:   `PetscViewerASCIIPopSynchronized()` should be then called if we are already done with the synchronized output
    1080:   to conclude the "synchronized session".

    1082:   So the typical calling sequence looks like
    1083: .vb
    1084:     PetscViewerASCIIPushSynchronized(viewer);
    1085:     PetscViewerASCIISynchronizedPrintf(viewer, ...);
    1086:     PetscViewerASCIISynchronizedPrintf(viewer, ...);
    1087:     ...
    1088:     PetscViewerFlush(viewer);
    1089:     PetscViewerASCIISynchronizedPrintf(viewer, ...);
    1090:     PetscViewerASCIISynchronizedPrintf(viewer, ...);
    1091:     ...
    1092:     PetscViewerFlush(viewer);
    1093:     PetscViewerASCIIPopSynchronized(viewer);
    1094: .ve

    1096:   Fortran Note:
    1097:   The call sequence is `PetscViewerASCIISynchronizedPrintf`(`PetscViewer`, `character(*)`, `PetscErrorCode` ierr)
    1098:   That is, you can only pass a single character string from Fortran.

    1100: .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
    1101:           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
    1102:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
    1103: @*/
    1104: PetscErrorCode PetscViewerASCIISynchronizedPrintf(PetscViewer viewer, const char format[], ...)
    1105: {
    1106:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
    1107:   PetscMPIInt        rank;
    1108:   PetscInt           tab = 0;
    1109:   MPI_Comm           comm;
    1110:   PetscBool          isascii;

    1112:   PetscFunctionBegin;
    1114:   PetscAssertPointer(format, 2);
    1115:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
    1116:   PetscCheck(isascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
    1117:   PetscCheck(vascii->allowsynchronized, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "First call PetscViewerASCIIPushSynchronized() to allow this call");

    1119:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
    1120:   PetscCallMPI(MPI_Comm_rank(comm, &rank));

    1122:   if (vascii->bviewer) {
    1123:     char   *string;
    1124:     va_list Argp;
    1125:     size_t  fullLength;

    1127:     PetscCall(PetscCalloc1(QUEUESTRINGSIZE, &string));
    1128:     for (; tab < vascii->tab; tab++) string[2 * tab] = string[2 * tab + 1] = ' ';
    1129:     va_start(Argp, format);
    1130:     PetscCall(PetscVSNPrintf(string + 2 * tab, QUEUESTRINGSIZE - 2 * tab, format, &fullLength, Argp));
    1131:     va_end(Argp);
    1132:     PetscCall(PetscViewerASCIISynchronizedPrintf(vascii->bviewer, "%s", string));
    1133:     PetscCall(PetscFree(string));
    1134:   } else if (rank == 0) { /* First processor prints immediately to fp */
    1135:     va_list Argp;
    1136:     FILE   *fp = vascii->fd;

    1138:     tab = vascii->tab;
    1139:     while (tab--) {
    1140:       if (!vascii->fileunit) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fp, "  "));
    1141:       else PetscCall(PetscFPrintfFortran(vascii->fileunit, "   "));
    1142:     }

    1144:     va_start(Argp, format);
    1145:     if (!vascii->fileunit) PetscCall((*PetscVFPrintf)(fp, format, Argp));
    1146:     else PetscCall(PetscVFPrintfFortran(vascii->fileunit, format, Argp));
    1147:     va_end(Argp);
    1148:     PetscCall(PetscFFlush(fp));
    1149:     if (petsc_history) {
    1150:       va_start(Argp, format);
    1151:       PetscCall((*PetscVFPrintf)(petsc_history, format, Argp));
    1152:       va_end(Argp);
    1153:       PetscCall(PetscFFlush(petsc_history));
    1154:     }
    1155:   } else { /* other processors add to queue */
    1156:     char       *string;
    1157:     va_list     Argp;
    1158:     size_t      fullLength;
    1159:     PrintfQueue next;

    1161:     PetscCall(PetscNew(&next));
    1162:     if (vascii->petsc_printfqueue) {
    1163:       vascii->petsc_printfqueue->next = next;
    1164:       vascii->petsc_printfqueue       = next;
    1165:     } else {
    1166:       vascii->petsc_printfqueuebase = vascii->petsc_printfqueue = next;
    1167:     }
    1168:     vascii->petsc_printfqueuelength++;
    1169:     next->size = QUEUESTRINGSIZE;
    1170:     PetscCall(PetscCalloc1(next->size, &next->string));
    1171:     string = next->string;

    1173:     tab = vascii->tab;
    1174:     tab *= 2;
    1175:     while (tab--) *string++ = ' ';
    1176:     va_start(Argp, format);
    1177:     PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, &fullLength, Argp));
    1178:     va_end(Argp);
    1179:     if (fullLength > next->size - 2 * vascii->tab) {
    1180:       PetscCall(PetscFree(next->string));
    1181:       next->size = fullLength + 2 * vascii->tab;
    1182:       PetscCall(PetscCalloc1(next->size, &next->string));
    1183:       string = next->string;
    1184:       tab    = 2 * vascii->tab;
    1185:       while (tab--) *string++ = ' ';
    1186:       va_start(Argp, format);
    1187:       PetscCall(PetscVSNPrintf(string, next->size - 2 * vascii->tab, format, NULL, Argp));
    1188:       va_end(Argp);
    1189:     }
    1190:   }
    1191:   PetscFunctionReturn(PETSC_SUCCESS);
    1192: }

    1194: /*@C
    1195:   PetscViewerASCIIRead - Reads from a `PETSCVIEWERASCII` file

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

    1199:   Input Parameters:
    1200: + viewer - the `PETSCVIEWERASCII` viewer
    1201: . data   - location to write the data, treated as an array of type indicated by `datatype`
    1202: . num    - number of items of data to read
    1203: - dtype  - type of data to read

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

    1208:   Level: beginner

    1210: .seealso: [](sec_viewers), `PetscViewerASCIIOpen()`, `PetscViewerPushFormat()`, `PetscViewerDestroy()`, `PetscViewerCreate()`, `PetscViewerFileSetMode()`, `PetscViewerFileSetName()`,
    1211:           `VecView()`, `MatView()`, `VecLoad()`, `MatLoad()`, `PetscViewerBinaryGetDescriptor()`,
    1212:           `PetscViewerBinaryGetInfoPointer()`, `PetscFileMode`, `PetscViewer`, `PetscViewerBinaryRead()`
    1213: @*/
    1214: PetscErrorCode PetscViewerASCIIRead(PetscViewer viewer, void *data, PetscInt num, PetscInt *count, PetscDataType dtype)
    1215: {
    1216:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
    1217:   FILE              *fd     = vascii->fd;
    1218:   PetscInt           i;
    1219:   int                ret = 0;
    1220:   PetscMPIInt        rank;

    1222:   PetscFunctionBegin;
    1224:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
    1225:   PetscCheck(rank == 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Can only be called from process 0 in the PetscViewer");
    1226:   for (i = 0; i < num; i++) {
    1227:     if (dtype == PETSC_CHAR) ret = fscanf(fd, "%c", &(((char *)data)[i]));
    1228:     else if (dtype == PETSC_STRING) ret = fscanf(fd, "%s", &(((char *)data)[i]));
    1229:     else if (dtype == PETSC_INT) ret = fscanf(fd, "%" PetscInt_FMT, &(((PetscInt *)data)[i]));
    1230:     else if (dtype == PETSC_ENUM) ret = fscanf(fd, "%d", &(((int *)data)[i]));
    1231:     else if (dtype == PETSC_INT64) ret = fscanf(fd, "%" PetscInt64_FMT, &(((PetscInt64 *)data)[i]));
    1232:     else if (dtype == PETSC_LONG) ret = fscanf(fd, "%ld", &(((long *)data)[i]));
    1233:     else if (dtype == PETSC_COUNT) ret = fscanf(fd, "%" PetscCount_FMT, &(((PetscCount *)data)[i]));
    1234:     else if (dtype == PETSC_FLOAT) ret = fscanf(fd, "%f", &(((float *)data)[i]));
    1235:     else if (dtype == PETSC_DOUBLE) ret = fscanf(fd, "%lg", &(((double *)data)[i]));
    1236: #if defined(PETSC_USE_REAL___FLOAT128)
    1237:     else if (dtype == PETSC___FLOAT128) {
    1238:       double tmp;
    1239:       ret                     = fscanf(fd, "%lg", &tmp);
    1240:       ((__float128 *)data)[i] = tmp;
    1241:     }
    1242: #endif
    1243:     else
    1244:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data type %d not supported", (int)dtype);
    1245:     PetscCheck(ret, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Conversion error for data type %d", (int)dtype);
    1246:     if (ret < 0) break; /* Proxy for EOF, need to check for it in configure */
    1247:   }
    1248:   if (count) *count = i;
    1249:   else PetscCheck(ret >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Insufficient data, read only %" PetscInt_FMT " < %" PetscInt_FMT " items", i, num);
    1250:   PetscFunctionReturn(PETSC_SUCCESS);
    1251: }