Date: 2025-03-29T05:58:43+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:   PetscBool          flg;

     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, (PetscMPIInt *)&flg));
     52:   if (flg) {
     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, (PetscMPIInt *)&flg));
     75:     if (flg && 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, (PetscMPIInt *)&flg));
     80:     if (flg && 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          iascii;

    176:   PetscFunctionBegin;
    178:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    179:   if (iascii) 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          iascii;

    206:   PetscFunctionBegin;
    208:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    209:   if (iascii && 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          iascii;

    236:   PetscFunctionBegin;
    238:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    239:   if (iascii) 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          iascii;

    267:   PetscFunctionBegin;
    269:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    270:   if (iascii) 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          iascii;

    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, &iascii));
    300:   if (iascii) 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          iascii;

    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, &iascii));
    330:   if (iascii) {
    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          iascii;

    357:   PetscFunctionBegin;
    359:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    360:   if (iascii) 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          iascii;

    384:   PetscFunctionBegin;
    386:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    387:   if (iascii) {
    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          iascii;

    414:   PetscFunctionBegin;
    416:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    417:   if (iascii) {
    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 lab, PetscInt unit, PetscErrorCode ierr)

    504:   Input Parameters:
    505: + lab  - 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 *lab, int *unit, PetscErrorCode *ierr)
    522: {
    523:   PetscViewer_ASCII *vascii;
    524:   PetscViewer        v;

    526:   PetscPatchDefaultViewers_Fortran(lab, 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: + lab  - 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 *lab, PetscErrorCode *ierr)
    562: {
    563:   *ierr = PetscViewerCreate(MPI_Comm_f2c(*(MPI_Fint *)&*comm), lab);
    564:   if (*ierr) return;
    565:   *ierr = PetscViewerSetType(*lab, PETSCVIEWERASCII);
    566:   if (*ierr) return;
    567:   *ierr = PetscViewerFileSetMode(*lab, FILE_MODE_WRITE);
    568:   if (*ierr) return;
    569:   petscviewerasciisetfileunit_(lab, 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:   PetscBool flg;
    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, (PetscMPIInt *)&flg));
    646:   if (!flg) { /* 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:       PetscCall(PetscViewerCreate(ncomm, viewer));
    658:       PetscCall(PetscViewerSetType(*viewer, PETSCVIEWERASCII));
    659:       PetscCall(PetscViewerFileSetName(*viewer, "stdout"));
    660:     }
    661:     PetscCall(PetscObjectRegisterDestroy((PetscObject)*viewer));
    662:     PetscCallMPI(MPI_Comm_set_attr(ncomm, Petsc_Viewer_Stdout_keyval, (void *)*viewer));
    663:   }
    664:   PetscCall(PetscCommDestroy(&ncomm));
    665:   PetscCall(PetscSpinlockUnlock(&PetscViewerASCIISpinLockStdout));
    666: #if defined(PETSC_USE_FORTRAN_BINDINGS)
    667:   ((PetscViewer_ASCII *)(*viewer)->data)->fileunit = PETSC_VIEWER_ASCII_STDOUT_fileunit;
    668: #endif
    669:   PetscFunctionReturn(PETSC_SUCCESS);
    670: }

    672: /*@C
    673:   PetscViewerASCIIPrintf - Prints to a file, only from the first
    674:   processor in the `PetscViewer` of type `PETSCVIEWERASCII`

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

    678:   Input Parameters:
    679: + viewer - obtained with `PetscViewerASCIIOpen()`
    680: - format - the usual printf() format string

    682:   Level: developer

    684:   Fortran Notes:
    685:   The call sequence is `PetscViewerASCIIPrintf`(`PetscViewer`, character(*), int ierr) from Fortran.
    686:   That is, you can only pass a single character string from Fortran.

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

    700:   PetscFunctionBegin;
    702:   PetscCheck(!ascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
    703:   PetscAssertPointer(format, 2);
    704:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    705:   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
    706:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
    707:   if (rank) PetscFunctionReturn(PETSC_SUCCESS);

    709:   if (ascii->bviewer) { /* pass string up to parent viewer */
    710:     char   *string;
    711:     va_list Argp;
    712:     size_t  fullLength;

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

    724:     tab = intab;
    725:     while (tab--) {
    726:       if (!ascii->fileunit) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fd, "  "));
    727:       else PetscCall(PetscFPrintfFortran(ascii->fileunit, "   "));
    728:     }

    730:     va_start(Argp, format);
    731:     if (!ascii->fileunit) PetscCall((*PetscVFPrintf)(fd, format, Argp));
    732:     else PetscCall(PetscVFPrintfFortran(ascii->fileunit, format, Argp));
    733:     va_end(Argp);
    734:     PetscCall(PetscFFlush(fd));
    735:   }
    736:   PetscFunctionReturn(PETSC_SUCCESS);
    737: }

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

    742:   Collective

    744:   Input Parameters:
    745: + viewer - the `PetscViewer`; for example, of type `PETSCVIEWERASCII` or `PETSCVIEWERBINARY`
    746: - name   - the name of the file it should use

    748:   Level: advanced

    750:   Note:
    751:   This will have no effect on viewers that are not related to files

    753: .seealso: [](sec_viewers), `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PetscViewerDestroy()`,
    754:           `PetscViewerASCIIGetPointer()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIISynchronizedPrintf()`
    755: @*/
    756: PetscErrorCode PetscViewerFileSetName(PetscViewer viewer, const char name[])
    757: {
    758:   char filename[PETSC_MAX_PATH_LEN];

    760:   PetscFunctionBegin;
    762:   PetscAssertPointer(name, 2);
    763:   PetscCall(PetscStrreplace(PetscObjectComm((PetscObject)viewer), name, filename, sizeof(filename)));
    764:   PetscTryMethod(viewer, "PetscViewerFileSetName_C", (PetscViewer, const char[]), (viewer, filename));
    765:   PetscFunctionReturn(PETSC_SUCCESS);
    766: }

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

    771:   Not Collective

    773:   Input Parameter:
    774: . viewer - the `PetscViewer`

    776:   Output Parameter:
    777: . name - the name of the file it is using

    779:   Level: advanced

    781:   Note:
    782:   This will have no effect on viewers that are not related to files

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

    795: static PetscErrorCode PetscViewerFileGetName_ASCII(PetscViewer viewer, const char **name)
    796: {
    797:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;

    799:   PetscFunctionBegin;
    800:   *name = vascii->filename;
    801:   PetscFunctionReturn(PETSC_SUCCESS);
    802: }

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

    813:   PetscFunctionBegin;
    814:   PetscCall(PetscViewerFileClose_ASCII(viewer));
    815:   if (!name) PetscFunctionReturn(PETSC_SUCCESS);
    816:   PetscCall(PetscStrallocpy(name, &vascii->filename));

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

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

    875: static PetscErrorCode PetscViewerGetSubViewer_ASCII(PetscViewer viewer, MPI_Comm subcomm, PetscViewer *outviewer)
    876: {
    877:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data, *ovascii;

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

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

    900:   vascii->sviewer                                      = *outviewer;
    901:   (*outviewer)->format                                 = viewer->format;
    902:   ((PetscViewer_ASCII *)((*outviewer)->data))->bviewer = viewer;
    903:   (*outviewer)->ops->destroy                           = PetscViewerDestroy_ASCII_SubViewer;
    904:   PetscFunctionReturn(PETSC_SUCCESS);
    905: }

    907: static PetscErrorCode PetscViewerRestoreSubViewer_ASCII(PetscViewer viewer, MPI_Comm comm, PetscViewer *outviewer)
    908: {
    909:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)viewer->data;

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

    915:   PetscCall(PetscViewerASCIIPopSynchronized(*outviewer));
    916:   ascii->sviewer             = NULL;
    917:   (*outviewer)->ops->destroy = PetscViewerDestroy_ASCII;
    918:   PetscCall(PetscViewerDestroy(outviewer));
    919:   PetscCall(PetscViewerFlush(viewer));
    920:   PetscCall(PetscViewerASCIIPopSynchronized(viewer));
    921:   PetscFunctionReturn(PETSC_SUCCESS);
    922: }

    924: static PetscErrorCode PetscViewerView_ASCII(PetscViewer v, PetscViewer viewer)
    925: {
    926:   PetscViewer_ASCII *ascii = (PetscViewer_ASCII *)v->data;

    928:   PetscFunctionBegin;
    929:   if (ascii->fileunit) PetscCall(PetscViewerASCIIPrintf(viewer, "Fortran FILE UNIT: %d\n", ascii->fileunit));
    930:   else if (ascii->filename) PetscCall(PetscViewerASCIIPrintf(viewer, "Filename: %s\n", ascii->filename));
    931:   PetscFunctionReturn(PETSC_SUCCESS);
    932: }

    934: static PetscErrorCode PetscViewerFlush_ASCII(PetscViewer viewer)
    935: {
    936:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
    937:   MPI_Comm           comm;
    938:   PetscMPIInt        rank, size;
    939:   FILE              *fd = vascii->fd;

    941:   PetscFunctionBegin;
    942:   PetscCheck(!vascii->sviewer, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "Cannot call with outstanding call to PetscViewerRestoreSubViewer()");
    943:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
    944:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
    945:   PetscCallMPI(MPI_Comm_size(comm, &size));

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

    949:   if (vascii->allowsynchronized) {
    950:     PetscMPIInt tag, i, j, n = 0, dummy = 0;
    951:     char       *message;
    952:     MPI_Status  status;

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

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

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

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

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

    1017:   Level: beginner

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

    1027:   PetscFunctionBegin;
    1028:   PetscCall(PetscNew(&vascii));
    1029:   viewer->data = (void *)vascii;

    1031:   viewer->ops->destroy          = PetscViewerDestroy_ASCII;
    1032:   viewer->ops->flush            = PetscViewerFlush_ASCII;
    1033:   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_ASCII;
    1034:   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_ASCII;
    1035:   viewer->ops->view             = PetscViewerView_ASCII;
    1036:   viewer->ops->read             = PetscViewerASCIIRead;

    1038:   /* defaults to stdout unless set with PetscViewerFileSetName() */
    1039:   vascii->fd        = PETSC_STDOUT;
    1040:   vascii->mode      = FILE_MODE_WRITE;
    1041:   vascii->bviewer   = NULL;
    1042:   vascii->subviewer = NULL;
    1043:   vascii->sviewer   = NULL;
    1044:   vascii->tab       = 0;
    1045:   vascii->tab_store = 0;
    1046:   vascii->filename  = NULL;
    1047:   vascii->closefile = PETSC_TRUE;

    1049:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_ASCII));
    1050:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetName_C", PetscViewerFileGetName_ASCII));
    1051:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileGetMode_C", PetscViewerFileGetMode_ASCII));
    1052:   PetscCall(PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetMode_C", PetscViewerFileSetMode_ASCII));
    1053:   PetscFunctionReturn(PETSC_SUCCESS);
    1054: }

    1056: /*@C
    1057:   PetscViewerASCIISynchronizedPrintf - Prints synchronized output to the specified `PETSCVIEWERASCII` file from
    1058:   several processors.  Output of the first processor is followed by that of the
    1059:   second, etc.

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

    1063:   Input Parameters:
    1064: + viewer - the `PETSCVIEWERASCII` `PetscViewer`
    1065: - format - the usual printf() format string

    1067:   Level: intermediate

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

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

    1077:   So the typical calling sequence looks like
    1078: .vb
    1079:     PetscViewerASCIIPushSynchronized(viewer);
    1080:     PetscViewerASCIISynchronizedPrintf(viewer, ...);
    1081:     PetscViewerASCIISynchronizedPrintf(viewer, ...);
    1082:     ...
    1083:     PetscViewerFlush(viewer);
    1084:     PetscViewerASCIISynchronizedPrintf(viewer, ...);
    1085:     PetscViewerASCIISynchronizedPrintf(viewer, ...);
    1086:     ...
    1087:     PetscViewerFlush(viewer);
    1088:     PetscViewerASCIIPopSynchronized(viewer);
    1089: .ve

    1091:   Fortran Notes:
    1092:   Can only print a single character* string

    1094: .seealso: [](sec_viewers), `PetscViewerASCIIPushSynchronized()`, `PetscViewerFlush()`, `PetscViewerASCIIPopSynchronized()`,
    1095:           `PetscSynchronizedPrintf()`, `PetscViewerASCIIPrintf()`, `PetscViewerASCIIOpen()`,
    1096:           `PetscViewerCreate()`, `PetscViewerDestroy()`, `PetscViewerSetType()`
    1097: @*/
    1098: PetscErrorCode PetscViewerASCIISynchronizedPrintf(PetscViewer viewer, const char format[], ...)
    1099: {
    1100:   PetscViewer_ASCII *vascii = (PetscViewer_ASCII *)viewer->data;
    1101:   PetscMPIInt        rank;
    1102:   PetscInt           tab = 0;
    1103:   MPI_Comm           comm;
    1104:   PetscBool          iascii;

    1106:   PetscFunctionBegin;
    1108:   PetscAssertPointer(format, 2);
    1109:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
    1110:   PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not ASCII PetscViewer");
    1111:   PetscCheck(vascii->allowsynchronized, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "First call PetscViewerASCIIPushSynchronized() to allow this call");

    1113:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
    1114:   PetscCallMPI(MPI_Comm_rank(comm, &rank));

    1116:   if (vascii->bviewer) {
    1117:     char   *string;
    1118:     va_list Argp;
    1119:     size_t  fullLength;

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

    1132:     tab = vascii->tab;
    1133:     while (tab--) {
    1134:       if (!vascii->fileunit) PetscCall(PetscFPrintf(PETSC_COMM_SELF, fp, "  "));
    1135:       else PetscCall(PetscFPrintfFortran(vascii->fileunit, "   "));
    1136:     }

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

    1155:     PetscCall(PetscNew(&next));
    1156:     if (vascii->petsc_printfqueue) {
    1157:       vascii->petsc_printfqueue->next = next;
    1158:       vascii->petsc_printfqueue       = next;
    1159:     } else {
    1160:       vascii->petsc_printfqueuebase = vascii->petsc_printfqueue = next;
    1161:     }
    1162:     vascii->petsc_printfqueuelength++;
    1163:     next->size = QUEUESTRINGSIZE;
    1164:     PetscCall(PetscCalloc1(next->size, &next->string));
    1165:     string = next->string;

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

    1188: /*@C
    1189:   PetscViewerASCIIRead - Reads from a `PETSCVIEWERASCII` file

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

    1193:   Input Parameters:
    1194: + viewer - the `PETSCVIEWERASCII` viewer
    1195: . data   - location to write the data, treated as an array of type indicated by `datatype`
    1196: . num    - number of items of data to read
    1197: - dtype  - type of data to read

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

    1202:   Level: beginner

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

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