Date: 2025-03-28T21:11:10+00:00

Actual source code: drawv.c

      1: #include <../src/sys/classes/viewer/impls/draw/vdraw.h>
      2: #include <petscviewer.h>

      4: static PetscErrorCode PetscViewerDestroy_Draw(PetscViewer v)
      5: {
      6:   PetscInt          i;
      7:   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)v->data;

      9:   PetscFunctionBegin;
     10:   PetscCheck(!vdraw->singleton_made, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Destroying PetscViewer without first restoring singleton");
     11:   for (i = 0; i < vdraw->draw_max; i++) {
     12:     PetscCall(PetscDrawAxisDestroy(&vdraw->drawaxis[i]));
     13:     PetscCall(PetscDrawLGDestroy(&vdraw->drawlg[i]));
     14:     PetscCall(PetscDrawDestroy(&vdraw->draw[i]));
     15:   }
     16:   PetscCall(PetscFree(vdraw->display));
     17:   PetscCall(PetscFree(vdraw->title));
     18:   PetscCall(PetscFree3(vdraw->draw, vdraw->drawlg, vdraw->drawaxis));
     19:   PetscCall(PetscFree(vdraw->bounds));
     20:   PetscCall(PetscFree(vdraw->drawtype));
     21:   PetscCall(PetscFree(v->data));
     22:   PetscFunctionReturn(PETSC_SUCCESS);
     23: }

     25: static PetscErrorCode PetscViewerFlush_Draw(PetscViewer v)
     26: {
     27:   PetscInt          i;
     28:   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)v->data;

     30:   PetscFunctionBegin;
     31:   for (i = 0; i < vdraw->draw_max; i++) {
     32:     if (vdraw->draw[i]) PetscCall(PetscDrawFlush(vdraw->draw[i]));
     33:   }
     34:   PetscFunctionReturn(PETSC_SUCCESS);
     35: }

     37: /*@
     38:   PetscViewerDrawGetDraw - Returns `PetscDraw` object from `PETSCVIEWERDRAW` `PetscViewer` object.
     39:   This `PetscDraw` object may then be used to perform graphics using `PetscDraw` commands.

     41:   Collective

     43:   Input Parameters:
     44: + viewer       - the `PetscViewer` (created with `PetscViewerDrawOpen()` of type `PETSCVIEWERDRAW`)
     45: - windownumber - indicates which subwindow (usually 0) to obtain

     47:   Output Parameter:
     48: . draw - the draw object

     50:   Level: intermediate

     52: .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`
     53: @*/
     54: PetscErrorCode PetscViewerDrawGetDraw(PetscViewer viewer, PetscInt windownumber, PetscDraw *draw)
     55: {
     56:   PetscViewer_Draw *vdraw;
     57:   PetscBool         isdraw;

     59:   PetscFunctionBegin;
     62:   if (draw) PetscAssertPointer(draw, 3);
     63:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
     64:   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
     65:   PetscCheck(windownumber >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Window number cannot be negative");
     66:   vdraw = (PetscViewer_Draw *)viewer->data;

     68:   windownumber += vdraw->draw_base;
     69:   if (windownumber >= vdraw->draw_max) {
     70:     /* allocate twice as many slots as needed */
     71:     PetscInt       draw_max = vdraw->draw_max;
     72:     PetscDraw     *tdraw    = vdraw->draw;
     73:     PetscDrawLG   *drawlg   = vdraw->drawlg;
     74:     PetscDrawAxis *drawaxis = vdraw->drawaxis;

     76:     vdraw->draw_max = 2 * windownumber;

     78:     PetscCall(PetscCalloc3(vdraw->draw_max, &vdraw->draw, vdraw->draw_max, &vdraw->drawlg, vdraw->draw_max, &vdraw->drawaxis));
     79:     PetscCall(PetscArraycpy(vdraw->draw, tdraw, draw_max));
     80:     PetscCall(PetscArraycpy(vdraw->drawlg, drawlg, draw_max));
     81:     PetscCall(PetscArraycpy(vdraw->drawaxis, drawaxis, draw_max));
     82:     PetscCall(PetscFree3(tdraw, drawlg, drawaxis));
     83:   }

     85:   if (!vdraw->draw[windownumber]) {
     86:     char *title = vdraw->title, tmp_str[128];
     87:     if (windownumber) {
     88:       PetscCall(PetscSNPrintf(tmp_str, sizeof(tmp_str), "%s:%" PetscInt_FMT, vdraw->title ? vdraw->title : "", windownumber));
     89:       title = tmp_str;
     90:     }
     91:     PetscCall(PetscDrawCreate(PetscObjectComm((PetscObject)viewer), vdraw->display, title, PETSC_DECIDE, PETSC_DECIDE, vdraw->w, vdraw->h, &vdraw->draw[windownumber]));
     92:     if (vdraw->drawtype) PetscCall(PetscDrawSetType(vdraw->draw[windownumber], vdraw->drawtype));
     93:     PetscCall(PetscDrawSetPause(vdraw->draw[windownumber], vdraw->pause));
     94:     PetscCall(PetscDrawSetOptionsPrefix(vdraw->draw[windownumber], ((PetscObject)viewer)->prefix));
     95:     PetscCall(PetscDrawSetFromOptions(vdraw->draw[windownumber]));
     96:   }
     97:   if (draw) *draw = vdraw->draw[windownumber];
     99:   PetscFunctionReturn(PETSC_SUCCESS);
    100: }

    102: /*@
    103:   PetscViewerDrawBaseAdd - add to the base integer that is added to the `windownumber` passed to `PetscViewerDrawGetDraw()`

    105:   Logically Collective

    107:   Input Parameters:
    108: + viewer       - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
    109: - windownumber - how much to add to the base

    111:   Level: developer

    113:   Note:
    114:   A `PETSCVIEWERDRAW` may have multiple `PetscDraw` subwindows, this increases the number of the subwindow that is returned with `PetscViewerDrawGetDraw()`

    116: .seealso: [](sec_viewers), `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`, `PetscViewerDrawBaseSet()`
    117: @*/
    118: PetscErrorCode PetscViewerDrawBaseAdd(PetscViewer viewer, PetscInt windownumber)
    119: {
    120:   PetscViewer_Draw *vdraw;
    121:   PetscBool         isdraw;

    123:   PetscFunctionBegin;
    126:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    127:   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
    128:   vdraw = (PetscViewer_Draw *)viewer->data;

    130:   PetscCheck(windownumber + vdraw->draw_base >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Resulting base %" PetscInt_FMT " cannot be negative", windownumber + vdraw->draw_base);
    131:   vdraw->draw_base += windownumber;
    132:   PetscFunctionReturn(PETSC_SUCCESS);
    133: }

    135: /*@
    136:   PetscViewerDrawBaseSet - sets the base integer that is added to the `windownumber` passed to `PetscViewerDrawGetDraw()`

    138:   Logically Collective

    140:   Input Parameters:
    141: + viewer       - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
    142: - windownumber - value to set the base

    144:   Level: developer

    146:   Note:
    147:   A `PETSCVIEWERDRAW` may have multiple `PetscDraw` subwindows, this increases the number of the subwindow that is returned with `PetscViewerDrawGetDraw()`

    149: .seealso: [](sec_viewers), `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`, `PetscViewerDrawBaseAdd()`
    150: @*/
    151: PetscErrorCode PetscViewerDrawBaseSet(PetscViewer viewer, PetscInt windownumber)
    152: {
    153:   PetscViewer_Draw *vdraw;
    154:   PetscBool         isdraw;

    156:   PetscFunctionBegin;
    159:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    160:   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
    161:   vdraw = (PetscViewer_Draw *)viewer->data;

    163:   PetscCheck(windownumber >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Resulting base %" PetscInt_FMT " cannot be negative", windownumber);
    164:   vdraw->draw_base = windownumber;
    165:   PetscFunctionReturn(PETSC_SUCCESS);
    166: }

    168: /*@
    169:   PetscViewerDrawGetDrawLG - Returns a `PetscDrawLG` object from `PetscViewer` object of type `PETSCVIEWERDRAW`.
    170:   This `PetscDrawLG` object may then be used to perform graphics using `PetscDrawLG` commands.

    172:   Collective

    174:   Input Parameters:
    175: + viewer       - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
    176: - windownumber - indicates which subwindow (usually 0)

    178:   Output Parameter:
    179: . drawlg - the draw line graph object

    181:   Level: intermediate

    183:   Note:
    184:   A `PETSCVIEWERDRAW` may have multiple `PetscDraw` subwindows

    186: .seealso: [](sec_viewers), `PetscDrawLG`, `PetscViewerDrawGetDraw()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`
    187: @*/
    188: PetscErrorCode PetscViewerDrawGetDrawLG(PetscViewer viewer, PetscInt windownumber, PetscDrawLG *drawlg)
    189: {
    190:   PetscBool         isdraw;
    191:   PetscViewer_Draw *vdraw;

    193:   PetscFunctionBegin;
    196:   PetscAssertPointer(drawlg, 3);
    197:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    198:   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
    199:   PetscCheck(windownumber >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Window number cannot be negative");
    200:   vdraw = (PetscViewer_Draw *)viewer->data;

    202:   if (windownumber + vdraw->draw_base >= vdraw->draw_max || !vdraw->draw[windownumber + vdraw->draw_base]) PetscCall(PetscViewerDrawGetDraw(viewer, windownumber, NULL));
    203:   if (!vdraw->drawlg[windownumber + vdraw->draw_base]) {
    204:     PetscCall(PetscDrawLGCreate(vdraw->draw[windownumber + vdraw->draw_base], 1, &vdraw->drawlg[windownumber + vdraw->draw_base]));
    205:     PetscCall(PetscDrawLGSetFromOptions(vdraw->drawlg[windownumber + vdraw->draw_base]));
    206:   }
    207:   *drawlg = vdraw->drawlg[windownumber + vdraw->draw_base];
    208:   PetscFunctionReturn(PETSC_SUCCESS);
    209: }

    211: /*@
    212:   PetscViewerDrawGetDrawAxis - Returns a `PetscDrawAxis` object from a `PetscViewer` object of type `PETSCVIEWERDRAW`.
    213:   This `PetscDrawAxis` object may then be used to perform graphics using `PetscDrawAxis` commands.

    215:   Collective

    217:   Input Parameters:
    218: + viewer       - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
    219: - windownumber - indicates which subwindow (usually 0)

    221:   Output Parameter:
    222: . drawaxis - the draw axis object

    224:   Level: advanced

    226:   Note:
    227:   A `PETSCVIEWERDRAW` may have multiple `PetscDraw` subwindows

    229: .seealso: [](sec_viewers), `PetscViewerDrawGetDraw()`, `PetscViewerDrawGetLG()`, `PetscViewerDrawOpen()`
    230: @*/
    231: PetscErrorCode PetscViewerDrawGetDrawAxis(PetscViewer viewer, PetscInt windownumber, PetscDrawAxis *drawaxis)
    232: {
    233:   PetscBool         isdraw;
    234:   PetscViewer_Draw *vdraw;

    236:   PetscFunctionBegin;
    239:   PetscAssertPointer(drawaxis, 3);
    240:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    241:   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
    242:   PetscCheck(windownumber >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Window number cannot be negative");
    243:   vdraw = (PetscViewer_Draw *)viewer->data;

    245:   if (windownumber + vdraw->draw_base >= vdraw->draw_max || !vdraw->draw[windownumber + vdraw->draw_base]) PetscCall(PetscViewerDrawGetDraw(viewer, windownumber, NULL));
    246:   if (!vdraw->drawaxis[windownumber + vdraw->draw_base]) PetscCall(PetscDrawAxisCreate(vdraw->draw[windownumber + vdraw->draw_base], &vdraw->drawaxis[windownumber + vdraw->draw_base]));
    247:   *drawaxis = vdraw->drawaxis[windownumber + vdraw->draw_base];
    248:   PetscFunctionReturn(PETSC_SUCCESS);
    249: }

    251: PetscErrorCode PetscViewerDrawResize(PetscViewer v, int w, int h)
    252: {
    253:   PetscViewer_Draw *vdraw;
    254:   PetscBool         isdraw;

    256:   PetscFunctionBegin;
    258:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
    259:   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
    260:   vdraw = (PetscViewer_Draw *)v->data;

    262:   if (w >= 1) vdraw->w = w;
    263:   if (h >= 1) vdraw->h = h;
    264:   PetscFunctionReturn(PETSC_SUCCESS);
    265: }

    267: PetscErrorCode PetscViewerDrawSetInfo(PetscViewer v, const char display[], const char title[], int x, int y, int w, int h)
    268: {
    269:   PetscViewer_Draw *vdraw;
    270:   PetscBool         isdraw;

    272:   PetscFunctionBegin;
    274:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
    275:   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
    276:   vdraw = (PetscViewer_Draw *)v->data;

    278:   PetscCall(PetscStrallocpy(display, &vdraw->display));
    279:   PetscCall(PetscStrallocpy(title, &vdraw->title));
    280:   if (w >= 1) vdraw->w = w;
    281:   if (h >= 1) vdraw->h = h;
    282:   PetscFunctionReturn(PETSC_SUCCESS);
    283: }

    285: PetscErrorCode PetscViewerDrawSetDrawType(PetscViewer v, PetscDrawType drawtype)
    286: {
    287:   PetscViewer_Draw *vdraw;
    288:   PetscBool         isdraw;

    290:   PetscFunctionBegin;
    292:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
    293:   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
    294:   vdraw = (PetscViewer_Draw *)v->data;

    296:   PetscCall(PetscFree(vdraw->drawtype));
    297:   PetscCall(PetscStrallocpy(drawtype, (char **)&vdraw->drawtype));
    298:   PetscFunctionReturn(PETSC_SUCCESS);
    299: }

    301: PetscErrorCode PetscViewerDrawGetDrawType(PetscViewer v, PetscDrawType *drawtype)
    302: {
    303:   PetscViewer_Draw *vdraw;
    304:   PetscBool         isdraw;

    306:   PetscFunctionBegin;
    308:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
    309:   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
    310:   vdraw = (PetscViewer_Draw *)v->data;

    312:   *drawtype = vdraw->drawtype;
    313:   PetscFunctionReturn(PETSC_SUCCESS);
    314: }

    316: PetscErrorCode PetscViewerDrawSetTitle(PetscViewer v, const char title[])
    317: {
    318:   PetscViewer_Draw *vdraw;
    319:   PetscBool         isdraw;

    321:   PetscFunctionBegin;
    323:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
    324:   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
    325:   vdraw = (PetscViewer_Draw *)v->data;

    327:   PetscCall(PetscFree(vdraw->title));
    328:   PetscCall(PetscStrallocpy(title, &vdraw->title));
    329:   PetscFunctionReturn(PETSC_SUCCESS);
    330: }

    332: PetscErrorCode PetscViewerDrawGetTitle(PetscViewer v, const char *title[])
    333: {
    334:   PetscViewer_Draw *vdraw;
    335:   PetscBool         isdraw;

    337:   PetscFunctionBegin;
    339:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
    340:   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
    341:   vdraw = (PetscViewer_Draw *)v->data;

    343:   *title = vdraw->title;
    344:   PetscFunctionReturn(PETSC_SUCCESS);
    345: }

    347: /*@
    348:   PetscViewerDrawOpen - Opens a `PetscDraw` window for use as a `PetscViewer` with type
    349:   `PETSCVIEWERDRAW`.

    351:   Collective

    353:   Input Parameters:
    354: + comm    - communicator that will share window
    355: . display - the X display on which to open, or `NULL` for the local machine
    356: . title   - the title to put in the title bar, or `NULL` for no title
    357: . x       - horizontal screen coordinate of the upper left corner of window, or use `PETSC_DECIDE`
    358: . y       - vertical screen coordinate of the upper left corner of window, or use `PETSC_DECIDE`
    359: . w       - window width in pixels, or may use `PETSC_DECIDE` or `PETSC_DRAW_FULL_SIZE`, `PETSC_DRAW_HALF_SIZE`,`PETSC_DRAW_THIRD_SIZE`, `PETSC_DRAW_QUARTER_SIZE`
    360: - h       - window height in pixels, or may use `PETSC_DECIDE` or `PETSC_DRAW_FULL_SIZE`, `PETSC_DRAW_HALF_SIZE`,`PETSC_DRAW_THIRD_SIZE`, `PETSC_DRAW_QUARTER_SIZE`

    362:   Output Parameter:
    363: . viewer - the `PetscViewer`

    365:   Options Database Keys:
    366: + -draw_type          - use x or null
    367: . -nox                - Disables all x-windows output
    368: . -display <name>     - Specifies name of machine for the X display
    369: . -geometry <x,y,w,h> - allows setting the window location and size
    370: - -draw_pause <pause> - Sets time (in seconds) that the
    371:      program pauses after PetscDrawPause() has been called
    372:      (0 is default, -1 implies until user input).

    374:   Level: beginner

    376:   Notes:
    377:   If you want to do graphics in this window, you must call `PetscViewerDrawGetDraw()` and
    378:   perform the graphics on the `PetscDraw` object.

    380:   Format options include\:
    381: + `PETSC_VIEWER_DRAW_BASIC` - displays with basic format
    382: - `PETSC_VIEWER_DRAW_LG`    - displays using a line graph

    384:   Fortran Notes:
    385:   Whenever indicating null character data in a Fortran code,
    386:   `PETSC_NULL_CHARACTER` must be employed; using NULL is not
    387:   correct for character data!  Thus, `PETSC_NULL_CHARACTER` can be
    388:   used for the display and title input parameters.

    390: .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscDrawCreate()`, `PetscViewerDestroy()`, `PetscViewerDrawGetDraw()`, `PetscViewerCreate()`, `PETSC_VIEWER_DRAW_`,
    391:           `PETSC_VIEWER_DRAW_WORLD`, `PETSC_VIEWER_DRAW_SELF`
    392: @*/
    393: PetscErrorCode PetscViewerDrawOpen(MPI_Comm comm, const char display[], const char title[], int x, int y, int w, int h, PetscViewer *viewer)
    394: {
    395:   PetscFunctionBegin;
    396:   PetscCall(PetscViewerCreate(comm, viewer));
    397:   PetscCall(PetscViewerSetType(*viewer, PETSCVIEWERDRAW));
    398:   PetscCall(PetscViewerDrawSetInfo(*viewer, display, title, x, y, w, h));
    399:   PetscFunctionReturn(PETSC_SUCCESS);
    400: }

    402: #include <petsc/private/drawimpl.h>

    404: static PetscErrorCode PetscViewerGetSubViewer_Draw(PetscViewer viewer, MPI_Comm comm, PetscViewer *sviewer)
    405: {
    406:   PetscMPIInt       rank;
    407:   PetscInt          i;
    408:   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)viewer->data, *svdraw;

    410:   PetscFunctionBegin;
    411:   PetscCheck(!vdraw->singleton_made, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Trying to get SubViewer without first restoring previous");
    412:   /* only processor zero can use the PetscViewer draw singleton */
    413:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
    414:   if (rank == 0) {
    415:     PetscMPIInt flg;
    416:     PetscDraw   draw, sdraw;

    418:     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, comm, &flg));
    419:     PetscCheck(flg == MPI_IDENT || flg == MPI_CONGRUENT, PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscViewerGetSubViewer() for PETSCVIEWERDRAW requires a singleton MPI_Comm");
    420:     PetscCall(PetscViewerCreate(comm, sviewer));
    421:     PetscCall(PetscViewerSetType(*sviewer, PETSCVIEWERDRAW));
    422:     svdraw             = (PetscViewer_Draw *)(*sviewer)->data;
    423:     (*sviewer)->format = viewer->format;
    424:     for (i = 0; i < vdraw->draw_max; i++) { /* XXX this is wrong if svdraw->draw_max (initially 5) < vdraw->draw_max */
    425:       if (vdraw->draw[i]) PetscCall(PetscDrawGetSingleton(vdraw->draw[i], &svdraw->draw[i]));
    426:     }
    427:     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
    428:     PetscCall(PetscViewerDrawGetDraw(*sviewer, 0, &sdraw));
    429:     if (draw->savefilename) {
    430:       PetscCall(PetscDrawSetSave(sdraw, draw->savefilename));
    431:       sdraw->savefilecount  = draw->savefilecount;
    432:       sdraw->savesinglefile = draw->savesinglefile;
    433:       sdraw->savemoviefps   = draw->savemoviefps;
    434:       sdraw->saveonclear    = draw->saveonclear;
    435:       sdraw->saveonflush    = draw->saveonflush;
    436:     }
    437:     if (draw->savefinalfilename) PetscCall(PetscDrawSetSaveFinalImage(sdraw, draw->savefinalfilename));
    438:   } else {
    439:     PetscDraw draw;
    440:     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
    441:   }
    442:   vdraw->singleton_made = PETSC_TRUE;
    443:   PetscFunctionReturn(PETSC_SUCCESS);
    444: }

    446: static PetscErrorCode PetscViewerRestoreSubViewer_Draw(PetscViewer viewer, MPI_Comm comm, PetscViewer *sviewer)
    447: {
    448:   PetscMPIInt       rank;
    449:   PetscInt          i;
    450:   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)viewer->data, *svdraw;

    452:   PetscFunctionBegin;
    453:   PetscCheck(vdraw->singleton_made, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Trying to restore a singleton that was not gotten");
    454:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
    455:   if (rank == 0) {
    456:     PetscDraw draw, sdraw;

    458:     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
    459:     PetscCall(PetscViewerDrawGetDraw(*sviewer, 0, &sdraw));
    460:     if (draw->savefilename) {
    461:       draw->savefilecount = sdraw->savefilecount;
    462:       PetscCallMPI(MPI_Bcast(&draw->savefilecount, 1, MPIU_INT, 0, PetscObjectComm((PetscObject)draw)));
    463:     }
    464:     svdraw = (PetscViewer_Draw *)(*sviewer)->data;
    465:     for (i = 0; i < vdraw->draw_max; i++) {
    466:       if (vdraw->draw[i] && svdraw->draw[i]) PetscCall(PetscDrawRestoreSingleton(vdraw->draw[i], &svdraw->draw[i]));
    467:     }
    468:     PetscCall(PetscFree3(svdraw->draw, svdraw->drawlg, svdraw->drawaxis));
    469:     PetscCall(PetscFree((*sviewer)->data));
    470:     PetscCall(PetscHeaderDestroy(sviewer));
    471:   } else {
    472:     PetscDraw draw;

    474:     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
    475:     if (draw->savefilename) PetscCallMPI(MPI_Bcast(&draw->savefilecount, 1, MPIU_INT, 0, PetscObjectComm((PetscObject)draw)));
    476:   }

    478:   vdraw->singleton_made = PETSC_FALSE;
    479:   PetscFunctionReturn(PETSC_SUCCESS);
    480: }

    482: static PetscErrorCode PetscViewerSetFromOptions_Draw(PetscViewer v, PetscOptionItems *PetscOptionsObject)
    483: {
    484:   PetscReal bounds[16];
    485:   PetscInt  nbounds = 16;
    486:   PetscBool flg;

    488:   PetscFunctionBegin;
    489:   PetscOptionsHeadBegin(PetscOptionsObject, "Draw PetscViewer Options");
    490:   PetscCall(PetscOptionsRealArray("-draw_bounds", "Bounds to put on plots axis", "PetscViewerDrawSetBounds", bounds, &nbounds, &flg));
    491:   if (flg) PetscCall(PetscViewerDrawSetBounds(v, nbounds / 2, bounds));
    492:   PetscOptionsHeadEnd();
    493:   PetscFunctionReturn(PETSC_SUCCESS);
    494: }

    496: static PetscErrorCode PetscViewerView_Draw(PetscViewer viewer, PetscViewer v)
    497: {
    498:   PetscDraw         draw;
    499:   PetscInt          i;
    500:   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)viewer->data;
    501:   PetscBool         iascii;

    503:   PetscFunctionBegin;
    504:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
    505:   if (iascii) PetscCall(PetscViewerASCIIPrintf(v, "Draw viewer is of type %s\n", vdraw->drawtype));
    506:   /*  If the PetscViewer has just been created then no vdraw->draw yet
    507:       exists so this will not actually call the viewer on any draws. */
    508:   for (i = 0; i < vdraw->draw_base; i++) {
    509:     if (vdraw->draw[i]) {
    510:       PetscCall(PetscViewerDrawGetDraw(viewer, i, &draw));
    511:       PetscCall(PetscDrawView(draw, v));
    512:     }
    513:   }
    514:   PetscFunctionReturn(PETSC_SUCCESS);
    515: }

    517: /*MC
    518:    PETSCVIEWERDRAW - A viewer that generates graphics, either to the screen or a file

    520:   Level: beginner

    522: .seealso: [](sec_viewers), `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`, `PETSC_VIEWER_DRAW_()`, `PETSC_VIEWER_DRAW_SELF`, `PETSC_VIEWER_DRAW_WORLD`,
    523:           `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`,
    524:           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`,
    525:           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
    526: M*/
    527: PETSC_EXTERN PetscErrorCode PetscViewerCreate_Draw(PetscViewer viewer)
    528: {
    529:   PetscViewer_Draw *vdraw;

    531:   PetscFunctionBegin;
    532:   PetscCall(PetscNew(&vdraw));
    533:   viewer->data = (void *)vdraw;

    535:   viewer->ops->flush            = PetscViewerFlush_Draw;
    536:   viewer->ops->view             = PetscViewerView_Draw;
    537:   viewer->ops->destroy          = PetscViewerDestroy_Draw;
    538:   viewer->ops->setfromoptions   = PetscViewerSetFromOptions_Draw;
    539:   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_Draw;
    540:   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_Draw;

    542:   /* these are created on the fly if requested */
    543:   vdraw->draw_max  = 5;
    544:   vdraw->draw_base = 0;
    545:   vdraw->w         = PETSC_DECIDE;
    546:   vdraw->h         = PETSC_DECIDE;

    548:   PetscCall(PetscCalloc3(vdraw->draw_max, &vdraw->draw, vdraw->draw_max, &vdraw->drawlg, vdraw->draw_max, &vdraw->drawaxis));
    549:   vdraw->singleton_made = PETSC_FALSE;
    550:   PetscFunctionReturn(PETSC_SUCCESS);
    551: }

    553: /*@
    554:   PetscViewerDrawClear - Clears a `PetscDraw` graphic associated with a `PetscViewer`.

    556:   Not Collective

    558:   Input Parameter:
    559: . viewer - the `PetscViewer`

    561:   Level: intermediate

    563: .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
    564: @*/
    565: PetscErrorCode PetscViewerDrawClear(PetscViewer viewer)
    566: {
    567:   PetscViewer_Draw *vdraw;
    568:   PetscBool         isdraw;
    569:   PetscInt          i;

    571:   PetscFunctionBegin;
    573:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    574:   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
    575:   vdraw = (PetscViewer_Draw *)viewer->data;

    577:   for (i = 0; i < vdraw->draw_max; i++) {
    578:     if (vdraw->draw[i]) PetscCall(PetscDrawClear(vdraw->draw[i]));
    579:   }
    580:   PetscFunctionReturn(PETSC_SUCCESS);
    581: }

    583: /*@
    584:   PetscViewerDrawGetPause - Gets the pause value (how long to pause before an image is changed)  in the `PETSCVIEWERDRAW` `PetscViewer`

    586:   Not Collective

    588:   Input Parameter:
    589: . viewer - the `PetscViewer`

    591:   Output Parameter:
    592: . pause - the pause value

    594:   Level: intermediate

    596: .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
    597: @*/
    598: PetscErrorCode PetscViewerDrawGetPause(PetscViewer viewer, PetscReal *pause)
    599: {
    600:   PetscViewer_Draw *vdraw;
    601:   PetscBool         isdraw;
    602:   PetscInt          i;
    603:   PetscDraw         draw;

    605:   PetscFunctionBegin;
    607:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    608:   if (!isdraw) {
    609:     *pause = 0.0;
    610:     PetscFunctionReturn(PETSC_SUCCESS);
    611:   }
    612:   vdraw = (PetscViewer_Draw *)viewer->data;

    614:   for (i = 0; i < vdraw->draw_max; i++) {
    615:     if (vdraw->draw[i]) {
    616:       PetscCall(PetscDrawGetPause(vdraw->draw[i], pause));
    617:       PetscFunctionReturn(PETSC_SUCCESS);
    618:     }
    619:   }
    620:   /* none exist yet so create one and get its pause */
    621:   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
    622:   PetscCall(PetscDrawGetPause(draw, pause));
    623:   PetscFunctionReturn(PETSC_SUCCESS);
    624: }

    626: /*@
    627:   PetscViewerDrawSetPause - Sets a pause for each `PetscDraw` in the `PETSCVIEWERDRAW` `PetscViewer`

    629:   Not Collective

    631:   Input Parameters:
    632: + viewer - the `PetscViewer`
    633: - pause  - the pause value

    635:   Level: intermediate

    637: .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
    638: @*/
    639: PetscErrorCode PetscViewerDrawSetPause(PetscViewer viewer, PetscReal pause)
    640: {
    641:   PetscViewer_Draw *vdraw;
    642:   PetscBool         isdraw;
    643:   PetscInt          i;

    645:   PetscFunctionBegin;
    647:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    648:   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
    649:   vdraw = (PetscViewer_Draw *)viewer->data;

    651:   vdraw->pause = pause;
    652:   for (i = 0; i < vdraw->draw_max; i++) {
    653:     if (vdraw->draw[i]) PetscCall(PetscDrawSetPause(vdraw->draw[i], pause));
    654:   }
    655:   PetscFunctionReturn(PETSC_SUCCESS);
    656: }

    658: /*@
    659:   PetscViewerDrawSetHold - Holds previous image when drawing new image in a `PETSCVIEWERDRAW`

    661:   Not Collective

    663:   Input Parameters:
    664: + viewer - the `PetscViewer`
    665: - hold   - `PETSC_TRUE` indicates to hold the previous image

    667:   Level: intermediate

    669: .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
    670: @*/
    671: PetscErrorCode PetscViewerDrawSetHold(PetscViewer viewer, PetscBool hold)
    672: {
    673:   PetscViewer_Draw *vdraw;
    674:   PetscBool         isdraw;

    676:   PetscFunctionBegin;
    678:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    679:   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
    680:   vdraw = (PetscViewer_Draw *)viewer->data;

    682:   vdraw->hold = hold;
    683:   PetscFunctionReturn(PETSC_SUCCESS);
    684: }

    686: /*@
    687:   PetscViewerDrawGetHold - Checks if the `PETSCVIEWERDRAW` `PetscViewer` holds previous image when drawing new image

    689:   Not Collective

    691:   Input Parameter:
    692: . viewer - the `PetscViewer`

    694:   Output Parameter:
    695: . hold - indicates to hold or not

    697:   Level: intermediate

    699: .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
    700: @*/
    701: PetscErrorCode PetscViewerDrawGetHold(PetscViewer viewer, PetscBool *hold)
    702: {
    703:   PetscViewer_Draw *vdraw;
    704:   PetscBool         isdraw;

    706:   PetscFunctionBegin;
    708:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    709:   if (!isdraw) {
    710:     *hold = PETSC_FALSE;
    711:     PetscFunctionReturn(PETSC_SUCCESS);
    712:   }
    713:   vdraw = (PetscViewer_Draw *)viewer->data;

    715:   *hold = vdraw->hold;
    716:   PetscFunctionReturn(PETSC_SUCCESS);
    717: }

    719: /*
    720:     The variable Petsc_Viewer_Draw_keyval is used to indicate an MPI attribute that
    721:   is attached to a communicator, in this case the attribute is a PetscViewer.
    722: */
    723: PetscMPIInt Petsc_Viewer_Draw_keyval = MPI_KEYVAL_INVALID;

    725: /*@C
    726:     PETSC_VIEWER_DRAW_ - Creates a window `PETSCVIEWERDRAW` `PetscViewer` shared by all processors
    727:                      in an MPI communicator.

    729:      Collective

    731:      Input Parameter:
    732: .    comm - the MPI communicator to share the window `PetscViewer`

    734:      Level: intermediate

    736:      Notes:
    737:      This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it

    739:      Unlike almost all other PETSc routines, `PETSC_VIEWER_DRAW_()` does not return
    740:      an error code.  The window is usually used in the form
    741: $       XXXView(XXX object, PETSC_VIEWER_DRAW_(comm));

    743: .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewer`, `PETSC_VIEWER_DRAW_WORLD`, `PETSC_VIEWER_DRAW_SELF`, `PetscViewerDrawOpen()`,
    744: @*/
    745: PetscViewer PETSC_VIEWER_DRAW_(MPI_Comm comm)
    746: {
    747:   PetscMPIInt flag;
    748:   PetscViewer viewer;
    749:   MPI_Comm    ncomm;

    751:   PetscFunctionBegin;
    752:   PetscCallNull(PetscCommDuplicate(comm, &ncomm, NULL));
    753:   if (Petsc_Viewer_Draw_keyval == MPI_KEYVAL_INVALID) { PetscCallMPINull(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Draw_keyval, NULL)); }
    754:   PetscCallMPINull(MPI_Comm_get_attr(ncomm, Petsc_Viewer_Draw_keyval, (void **)&viewer, &flag));
    755:   if (!flag) { /* PetscViewer not yet created */
    756:     PetscCallNull(PetscViewerDrawOpen(ncomm, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, &viewer));
    757:     PetscCallNull(PetscObjectRegisterDestroy((PetscObject)viewer));
    758:     PetscCallMPINull(MPI_Comm_set_attr(ncomm, Petsc_Viewer_Draw_keyval, (void *)viewer));
    759:   }
    760:   PetscCallNull(PetscCommDestroy(&ncomm));
    761:   PetscFunctionReturn(viewer);
    762: }

    764: /*@
    765:   PetscViewerDrawSetBounds - sets the upper and lower bounds to be used in plotting in a `PETSCVIEWERDRAW` `PetscViewer`

    767:   Collective

    769:   Input Parameters:
    770: + viewer  - the Petsc`Viewer` (created with `PetscViewerDrawOpen()`)
    771: . nbounds - number of plots that can be made with this viewer, for example the dof passed to `DMDACreate()`
    772: - bounds  - the actual bounds, the size of this is 2*`nbounds`, the values are stored in the order min F_0, max F_0, min F_1, max F_1, .....

    774:   Options Database Key:
    775: . -draw_bounds  minF0,maxF0,minF1,maxF1 - the lower left and upper right bounds

    777:   Level: intermediate

    779:   Note:
    780:   this determines the colors used in 2d contour plots generated with VecView() for `DMDA` in 2d. Any values in the vector below or above the
    781:   bounds are moved to the bound value before plotting. In this way the color index from color to physical value remains the same for all plots generated with
    782:   this viewer. Otherwise the color to physical value meaning changes with each new image if this is not set.

    784: .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`
    785: @*/
    786: PetscErrorCode PetscViewerDrawSetBounds(PetscViewer viewer, PetscInt nbounds, const PetscReal *bounds)
    787: {
    788:   PetscViewer_Draw *vdraw;
    789:   PetscBool         isdraw;

    791:   PetscFunctionBegin;
    793:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    794:   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
    795:   vdraw = (PetscViewer_Draw *)viewer->data;

    797:   vdraw->nbounds = nbounds;
    798:   PetscCall(PetscFree(vdraw->bounds));
    799:   PetscCall(PetscMalloc1(2 * nbounds, &vdraw->bounds));
    800:   PetscCall(PetscArraycpy(vdraw->bounds, bounds, 2 * nbounds));
    801:   PetscFunctionReturn(PETSC_SUCCESS);
    802: }

    804: /*@C
    805:   PetscViewerDrawGetBounds - gets the upper and lower bounds to be used in plotting set with `PetscViewerDrawSetBounds()`

    807:   Collective

    809:   Input Parameter:
    810: . viewer - the `PetscViewer` (created with `PetscViewerDrawOpen()`)

    812:   Output Parameters:
    813: + nbounds - number of plots that can be made with this viewer, for example the dof passed to `DMDACreate()`
    814: - bounds  - the actual bounds, the size of this is 2*`nbounds`, the values are stored in the order min F_0, max F_0, min F_1, max F_1, .....

    816:   Level: intermediate

    818: .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`, `PetscViewerDrawSetBounds()`
    819: @*/
    820: PetscErrorCode PetscViewerDrawGetBounds(PetscViewer viewer, PetscInt *nbounds, const PetscReal *bounds[])
    821: {
    822:   PetscViewer_Draw *vdraw;
    823:   PetscBool         isdraw;

    825:   PetscFunctionBegin;
    827:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
    828:   if (!isdraw) {
    829:     if (nbounds) *nbounds = 0;
    830:     if (bounds) *bounds = NULL;
    831:     PetscFunctionReturn(PETSC_SUCCESS);
    832:   }
    833:   vdraw = (PetscViewer_Draw *)viewer->data;

    835:   if (nbounds) *nbounds = vdraw->nbounds;
    836:   if (bounds) *bounds = vdraw->bounds;
    837:   PetscFunctionReturn(PETSC_SUCCESS);
    838: }