xref: /petsc/src/sys/classes/viewer/impls/draw/drawv.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
1 
2 #include <../src/sys/classes/viewer/impls/draw/vdraw.h> /*I "petscdraw.h" I*/
3 #include <petscviewer.h>                                /*I "petscviewer.h" I*/
4 
5 static PetscErrorCode PetscViewerDestroy_Draw(PetscViewer v) {
6   PetscInt          i;
7   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)v->data;
8 
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(0);
23 }
24 
25 static PetscErrorCode PetscViewerFlush_Draw(PetscViewer v) {
26   PetscInt          i;
27   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)v->data;
28 
29   PetscFunctionBegin;
30   for (i = 0; i < vdraw->draw_max; i++) {
31     if (vdraw->draw[i]) PetscCall(PetscDrawFlush(vdraw->draw[i]));
32   }
33   PetscFunctionReturn(0);
34 }
35 
36 /*@C
37     PetscViewerDrawGetDraw - Returns PetscDraw object from PetscViewer object.
38     This PetscDraw object may then be used to perform graphics using
39     PetscDrawXXX() commands.
40 
41     Collective on PetscViewer
42 
43     Input Parameters:
44 +   viewer - the PetscViewer (created with PetscViewerDrawOpen())
45 -   windownumber - indicates which subwindow (usually 0)
46 
47     Output Parameter:
48 .   draw - the draw object
49 
50     Level: intermediate
51 
52 .seealso: `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`
53 @*/
54 PetscErrorCode PetscViewerDrawGetDraw(PetscViewer viewer, PetscInt windownumber, PetscDraw *draw) {
55   PetscViewer_Draw *vdraw;
56   PetscBool         isdraw;
57 
58   PetscFunctionBegin;
59   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
60   PetscValidLogicalCollectiveInt(viewer, windownumber, 2);
61   if (draw) PetscValidPointer(draw, 3);
62   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
63   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
64   PetscCheck(windownumber >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Window number cannot be negative");
65   vdraw = (PetscViewer_Draw *)viewer->data;
66 
67   windownumber += vdraw->draw_base;
68   if (windownumber >= vdraw->draw_max) {
69     /* allocate twice as many slots as needed */
70     PetscInt       draw_max = vdraw->draw_max;
71     PetscDraw     *tdraw    = vdraw->draw;
72     PetscDrawLG   *drawlg   = vdraw->drawlg;
73     PetscDrawAxis *drawaxis = vdraw->drawaxis;
74 
75     vdraw->draw_max = 2 * windownumber;
76 
77     PetscCall(PetscCalloc3(vdraw->draw_max, &vdraw->draw, vdraw->draw_max, &vdraw->drawlg, vdraw->draw_max, &vdraw->drawaxis));
78     PetscCall(PetscArraycpy(vdraw->draw, tdraw, draw_max));
79     PetscCall(PetscArraycpy(vdraw->drawlg, drawlg, draw_max));
80     PetscCall(PetscArraycpy(vdraw->drawaxis, drawaxis, draw_max));
81     PetscCall(PetscFree3(tdraw, drawlg, drawaxis));
82   }
83 
84   if (!vdraw->draw[windownumber]) {
85     char *title = vdraw->title, tmp_str[128];
86     if (windownumber) {
87       PetscCall(PetscSNPrintf(tmp_str, sizeof(tmp_str), "%s:%" PetscInt_FMT, vdraw->title ? vdraw->title : "", windownumber));
88       title = tmp_str;
89     }
90     PetscCall(PetscDrawCreate(PetscObjectComm((PetscObject)viewer), vdraw->display, title, PETSC_DECIDE, PETSC_DECIDE, vdraw->w, vdraw->h, &vdraw->draw[windownumber]));
91     PetscCall(PetscLogObjectParent((PetscObject)viewer, (PetscObject)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];
98   if (draw) PetscValidHeaderSpecific(*draw, PETSC_DRAW_CLASSID, 3);
99   PetscFunctionReturn(0);
100 }
101 
102 /*@C
103     PetscViewerDrawBaseAdd - add to the base integer that is added to the windownumber passed to PetscViewerDrawGetDraw()
104 
105     Logically Collective on PetscViewer
106 
107     Input Parameters:
108 +  viewer - the PetscViewer (created with PetscViewerDrawOpen())
109 -   windownumber - how much to add to the base
110 
111     Level: developer
112 
113 .seealso: `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`, `PetscViewerDrawBaseSet()`
114 @*/
115 PetscErrorCode PetscViewerDrawBaseAdd(PetscViewer viewer, PetscInt windownumber) {
116   PetscViewer_Draw *vdraw;
117   PetscBool         isdraw;
118 
119   PetscFunctionBegin;
120   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
121   PetscValidLogicalCollectiveInt(viewer, windownumber, 2);
122   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
123   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
124   vdraw = (PetscViewer_Draw *)viewer->data;
125 
126   PetscCheck(windownumber + vdraw->draw_base >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Resulting base %" PetscInt_FMT " cannot be negative", windownumber + vdraw->draw_base);
127   vdraw->draw_base += windownumber;
128   PetscFunctionReturn(0);
129 }
130 
131 /*@C
132     PetscViewerDrawBaseSet - sets the base integer that is added to the windownumber passed to PetscViewerDrawGetDraw()
133 
134     Logically Collective on PetscViewer
135 
136     Input Parameters:
137 +   viewer - the PetscViewer (created with PetscViewerDrawOpen())
138 -   windownumber - value to set the base
139 
140     Level: developer
141 
142 .seealso: `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`, `PetscViewerDrawBaseAdd()`
143 @*/
144 PetscErrorCode PetscViewerDrawBaseSet(PetscViewer viewer, PetscInt windownumber) {
145   PetscViewer_Draw *vdraw;
146   PetscBool         isdraw;
147 
148   PetscFunctionBegin;
149   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
150   PetscValidLogicalCollectiveInt(viewer, windownumber, 2);
151   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
152   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
153   vdraw = (PetscViewer_Draw *)viewer->data;
154 
155   PetscCheck(windownumber >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Resulting base %" PetscInt_FMT " cannot be negative", windownumber);
156   vdraw->draw_base = windownumber;
157   PetscFunctionReturn(0);
158 }
159 
160 /*@C
161     PetscViewerDrawGetDrawLG - Returns PetscDrawLG object from PetscViewer object.
162     This PetscDrawLG object may then be used to perform graphics using
163     PetscDrawLGXXX() commands.
164 
165     Collective on PetscViewer
166 
167     Input Parameters:
168 +   PetscViewer - the PetscViewer (created with PetscViewerDrawOpen())
169 -   windownumber - indicates which subwindow (usually 0)
170 
171     Output Parameter:
172 .   draw - the draw line graph object
173 
174     Level: intermediate
175 
176 .seealso: `PetscViewerDrawGetDraw()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`
177 @*/
178 PetscErrorCode PetscViewerDrawGetDrawLG(PetscViewer viewer, PetscInt windownumber, PetscDrawLG *drawlg) {
179   PetscBool         isdraw;
180   PetscViewer_Draw *vdraw;
181 
182   PetscFunctionBegin;
183   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
184   PetscValidLogicalCollectiveInt(viewer, windownumber, 2);
185   PetscValidPointer(drawlg, 3);
186   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
187   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
188   PetscCheck(windownumber >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Window number cannot be negative");
189   vdraw = (PetscViewer_Draw *)viewer->data;
190 
191   if (windownumber + vdraw->draw_base >= vdraw->draw_max || !vdraw->draw[windownumber + vdraw->draw_base]) PetscCall(PetscViewerDrawGetDraw(viewer, windownumber, NULL));
192   if (!vdraw->drawlg[windownumber + vdraw->draw_base]) {
193     PetscCall(PetscDrawLGCreate(vdraw->draw[windownumber + vdraw->draw_base], 1, &vdraw->drawlg[windownumber + vdraw->draw_base]));
194     PetscCall(PetscLogObjectParent((PetscObject)viewer, (PetscObject)vdraw->drawlg[windownumber + vdraw->draw_base]));
195     PetscCall(PetscDrawLGSetFromOptions(vdraw->drawlg[windownumber + vdraw->draw_base]));
196   }
197   *drawlg = vdraw->drawlg[windownumber + vdraw->draw_base];
198   PetscFunctionReturn(0);
199 }
200 
201 /*@C
202     PetscViewerDrawGetDrawAxis - Returns PetscDrawAxis object from PetscViewer object.
203     This PetscDrawAxis object may then be used to perform graphics using
204     PetscDrawAxisXXX() commands.
205 
206     Collective on PetscViewer
207 
208     Input Parameters:
209 +   viewer - the PetscViewer (created with PetscViewerDrawOpen()
210 -   windownumber - indicates which subwindow (usually 0)
211 
212     Output Parameter:
213 .   drawaxis - the draw axis object
214 
215     Level: advanced
216 
217 .seealso: `PetscViewerDrawGetDraw()`, `PetscViewerDrawGetLG()`, `PetscViewerDrawOpen()`
218 @*/
219 PetscErrorCode PetscViewerDrawGetDrawAxis(PetscViewer viewer, PetscInt windownumber, PetscDrawAxis *drawaxis) {
220   PetscBool         isdraw;
221   PetscViewer_Draw *vdraw;
222 
223   PetscFunctionBegin;
224   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
225   PetscValidLogicalCollectiveInt(viewer, windownumber, 2);
226   PetscValidPointer(drawaxis, 3);
227   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
228   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
229   PetscCheck(windownumber >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Window number cannot be negative");
230   vdraw = (PetscViewer_Draw *)viewer->data;
231 
232   if (windownumber + vdraw->draw_base >= vdraw->draw_max || !vdraw->draw[windownumber + vdraw->draw_base]) PetscCall(PetscViewerDrawGetDraw(viewer, windownumber, NULL));
233   if (!vdraw->drawaxis[windownumber + vdraw->draw_base]) {
234     PetscCall(PetscDrawAxisCreate(vdraw->draw[windownumber + vdraw->draw_base], &vdraw->drawaxis[windownumber + vdraw->draw_base]));
235     PetscCall(PetscLogObjectParent((PetscObject)viewer, (PetscObject)vdraw->drawaxis[windownumber + vdraw->draw_base]));
236   }
237   *drawaxis = vdraw->drawaxis[windownumber + vdraw->draw_base];
238   PetscFunctionReturn(0);
239 }
240 
241 PetscErrorCode PetscViewerDrawResize(PetscViewer v, int w, int h) {
242   PetscViewer_Draw *vdraw;
243   PetscBool         isdraw;
244 
245   PetscFunctionBegin;
246   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
247   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
248   if (!isdraw) PetscFunctionReturn(0);
249   vdraw = (PetscViewer_Draw *)v->data;
250 
251   if (w >= 1) vdraw->w = w;
252   if (h >= 1) vdraw->h = h;
253   PetscFunctionReturn(0);
254 }
255 
256 PetscErrorCode PetscViewerDrawSetInfo(PetscViewer v, const char display[], const char title[], int x, int y, int w, int h) {
257   PetscViewer_Draw *vdraw;
258   PetscBool         isdraw;
259 
260   PetscFunctionBegin;
261   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
262   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
263   if (!isdraw) PetscFunctionReturn(0);
264   vdraw = (PetscViewer_Draw *)v->data;
265 
266   PetscCall(PetscStrallocpy(display, &vdraw->display));
267   PetscCall(PetscStrallocpy(title, &vdraw->title));
268   if (w >= 1) vdraw->w = w;
269   if (h >= 1) vdraw->h = h;
270   PetscFunctionReturn(0);
271 }
272 
273 PetscErrorCode PetscViewerDrawSetDrawType(PetscViewer v, PetscDrawType drawtype) {
274   PetscViewer_Draw *vdraw;
275   PetscBool         isdraw;
276 
277   PetscFunctionBegin;
278   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
279   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
280   if (!isdraw) PetscFunctionReturn(0);
281   vdraw = (PetscViewer_Draw *)v->data;
282 
283   PetscCall(PetscFree(vdraw->drawtype));
284   PetscCall(PetscStrallocpy(drawtype, (char **)&vdraw->drawtype));
285   PetscFunctionReturn(0);
286 }
287 
288 PetscErrorCode PetscViewerDrawGetDrawType(PetscViewer v, PetscDrawType *drawtype) {
289   PetscViewer_Draw *vdraw;
290   PetscBool         isdraw;
291 
292   PetscFunctionBegin;
293   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
294   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
295   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
296   vdraw = (PetscViewer_Draw *)v->data;
297 
298   *drawtype = vdraw->drawtype;
299   PetscFunctionReturn(0);
300 }
301 
302 PetscErrorCode PetscViewerDrawSetTitle(PetscViewer v, const char title[]) {
303   PetscViewer_Draw *vdraw;
304   PetscBool         isdraw;
305 
306   PetscFunctionBegin;
307   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
308   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
309   if (!isdraw) PetscFunctionReturn(0);
310   vdraw = (PetscViewer_Draw *)v->data;
311 
312   PetscCall(PetscFree(vdraw->title));
313   PetscCall(PetscStrallocpy(title, &vdraw->title));
314   PetscFunctionReturn(0);
315 }
316 
317 PetscErrorCode PetscViewerDrawGetTitle(PetscViewer v, const char *title[]) {
318   PetscViewer_Draw *vdraw;
319   PetscBool         isdraw;
320 
321   PetscFunctionBegin;
322   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
323   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
324   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
325   vdraw = (PetscViewer_Draw *)v->data;
326 
327   *title = vdraw->title;
328   PetscFunctionReturn(0);
329 }
330 
331 /*@C
332    PetscViewerDrawOpen - Opens a window for use as a PetscViewer. If you want to
333    do graphics in this window, you must call PetscViewerDrawGetDraw() and
334    perform the graphics on the PetscDraw object.
335 
336    Collective
337 
338    Input Parameters:
339 +  comm - communicator that will share window
340 .  display - the X display on which to open, or null for the local machine
341 .  title - the title to put in the title bar, or null for no title
342 .  x, y - the screen coordinates of the upper left corner of window, or use PETSC_DECIDE
343 -  w, h - window width and height in pixels, or may use PETSC_DECIDE or PETSC_DRAW_FULL_SIZE, PETSC_DRAW_HALF_SIZE,
344           PETSC_DRAW_THIRD_SIZE, PETSC_DRAW_QUARTER_SIZE
345 
346    Output Parameter:
347 . viewer - the PetscViewer
348 
349    Format Options:
350 +  PETSC_VIEWER_DRAW_BASIC - displays with basic format
351 -  PETSC_VIEWER_DRAW_LG    - displays using a line graph
352 
353    Options Database Keys:
354 +  -draw_type - use x or null
355 .  -nox - Disables all x-windows output
356 .  -display <name> - Specifies name of machine for the X display
357 .  -geometry <x,y,w,h> - allows setting the window location and size
358 -  -draw_pause <pause> - Sets time (in seconds) that the
359      program pauses after PetscDrawPause() has been called
360      (0 is default, -1 implies until user input).
361 
362    Level: beginner
363 
364    Notes:
365      PetscViewerDrawOpen() calls PetscDrawCreate(), so see the manual pages for PetscDrawCreate()
366 
367    Note for Fortran Programmers:
368    Whenever indicating null character data in a Fortran code,
369    PETSC_NULL_CHARACTER must be employed; using NULL is not
370    correct for character data!  Thus, PETSC_NULL_CHARACTER can be
371    used for the display and title input parameters.
372 
373 .seealso: `PetscDrawCreate()`, `PetscViewerDestroy()`, `PetscViewerDrawGetDraw()`, `PetscViewerCreate()`, `PETSC_VIEWER_DRAW_`,
374           `PETSC_VIEWER_DRAW_WORLD`, `PETSC_VIEWER_DRAW_SELF`
375 @*/
376 PetscErrorCode PetscViewerDrawOpen(MPI_Comm comm, const char display[], const char title[], int x, int y, int w, int h, PetscViewer *viewer) {
377   PetscFunctionBegin;
378   PetscCall(PetscViewerCreate(comm, viewer));
379   PetscCall(PetscViewerSetType(*viewer, PETSCVIEWERDRAW));
380   PetscCall(PetscViewerDrawSetInfo(*viewer, display, title, x, y, w, h));
381   PetscFunctionReturn(0);
382 }
383 
384 #include <petsc/private/drawimpl.h>
385 
386 PetscErrorCode PetscViewerGetSubViewer_Draw(PetscViewer viewer, MPI_Comm comm, PetscViewer *sviewer) {
387   PetscMPIInt       rank;
388   PetscInt          i;
389   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)viewer->data, *svdraw;
390 
391   PetscFunctionBegin;
392   PetscCheck(!vdraw->singleton_made, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Trying to get SubViewer without first restoring previous");
393   /* only processor zero can use the PetscViewer draw singleton */
394   if (sviewer) *sviewer = NULL;
395   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
396   if (rank == 0) {
397     PetscMPIInt flg;
398     PetscDraw   draw, sdraw;
399 
400     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, comm, &flg));
401     PetscCheck(flg == MPI_IDENT || flg == MPI_CONGRUENT, PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscViewerGetSubViewer() for PETSCVIEWERDRAW requires a singleton MPI_Comm");
402     PetscCall(PetscViewerCreate(comm, sviewer));
403     PetscCall(PetscViewerSetType(*sviewer, PETSCVIEWERDRAW));
404     svdraw             = (PetscViewer_Draw *)(*sviewer)->data;
405     (*sviewer)->format = viewer->format;
406     for (i = 0; i < vdraw->draw_max; i++) { /* XXX this is wrong if svdraw->draw_max (initially 5) < vdraw->draw_max */
407       if (vdraw->draw[i]) PetscCall(PetscDrawGetSingleton(vdraw->draw[i], &svdraw->draw[i]));
408     }
409     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
410     PetscCall(PetscViewerDrawGetDraw(*sviewer, 0, &sdraw));
411     if (draw->savefilename) {
412       PetscCall(PetscDrawSetSave(sdraw, draw->savefilename));
413       sdraw->savefilecount  = draw->savefilecount;
414       sdraw->savesinglefile = draw->savesinglefile;
415       sdraw->savemoviefps   = draw->savemoviefps;
416       sdraw->saveonclear    = draw->saveonclear;
417       sdraw->saveonflush    = draw->saveonflush;
418     }
419     if (draw->savefinalfilename) PetscCall(PetscDrawSetSaveFinalImage(sdraw, draw->savefinalfilename));
420   } else {
421     PetscDraw draw;
422     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
423   }
424   vdraw->singleton_made = PETSC_TRUE;
425   PetscFunctionReturn(0);
426 }
427 
428 PetscErrorCode PetscViewerRestoreSubViewer_Draw(PetscViewer viewer, MPI_Comm comm, PetscViewer *sviewer) {
429   PetscMPIInt       rank;
430   PetscInt          i;
431   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)viewer->data, *svdraw;
432 
433   PetscFunctionBegin;
434   PetscCheck(vdraw->singleton_made, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Trying to restore a singleton that was not gotten");
435   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
436   if (rank == 0) {
437     PetscDraw draw, sdraw;
438 
439     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
440     PetscCall(PetscViewerDrawGetDraw(*sviewer, 0, &sdraw));
441     if (draw->savefilename) {
442       draw->savefilecount = sdraw->savefilecount;
443       PetscCallMPI(MPI_Bcast(&draw->savefilecount, 1, MPIU_INT, 0, PetscObjectComm((PetscObject)draw)));
444     }
445     svdraw = (PetscViewer_Draw *)(*sviewer)->data;
446     for (i = 0; i < vdraw->draw_max; i++) {
447       if (vdraw->draw[i] && svdraw->draw[i]) PetscCall(PetscDrawRestoreSingleton(vdraw->draw[i], &svdraw->draw[i]));
448     }
449     PetscCall(PetscFree3(svdraw->draw, svdraw->drawlg, svdraw->drawaxis));
450     PetscCall(PetscFree((*sviewer)->data));
451     PetscCall(PetscHeaderDestroy(sviewer));
452   } else {
453     PetscDraw draw;
454 
455     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
456     if (draw->savefilename) PetscCallMPI(MPI_Bcast(&draw->savefilecount, 1, MPIU_INT, 0, PetscObjectComm((PetscObject)draw)));
457   }
458 
459   vdraw->singleton_made = PETSC_FALSE;
460   PetscFunctionReturn(0);
461 }
462 
463 PetscErrorCode PetscViewerSetFromOptions_Draw(PetscViewer v, PetscOptionItems *PetscOptionsObject) {
464   PetscReal bounds[16];
465   PetscInt  nbounds = 16;
466   PetscBool flg;
467 
468   PetscFunctionBegin;
469   PetscOptionsHeadBegin(PetscOptionsObject, "Draw PetscViewer Options");
470   PetscCall(PetscOptionsRealArray("-draw_bounds", "Bounds to put on plots axis", "PetscViewerDrawSetBounds", bounds, &nbounds, &flg));
471   if (flg) PetscCall(PetscViewerDrawSetBounds(v, nbounds / 2, bounds));
472   PetscOptionsHeadEnd();
473   PetscFunctionReturn(0);
474 }
475 
476 PetscErrorCode PetscViewerView_Draw(PetscViewer viewer, PetscViewer v) {
477   PetscDraw         draw;
478   PetscInt          i;
479   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)viewer->data;
480 
481   PetscFunctionBegin;
482   /*  If the PetscViewer has just been created then no vdraw->draw yet
483       exists so this will not actually call the viewer on any draws. */
484   for (i = 0; i < vdraw->draw_base; i++) {
485     if (vdraw->draw[i]) {
486       PetscCall(PetscViewerDrawGetDraw(viewer, i, &draw));
487       PetscCall(PetscDrawView(draw, v));
488     }
489   }
490   PetscFunctionReturn(0);
491 }
492 
493 /*MC
494    PETSCVIEWERDRAW - A viewer that generates graphics, either to the screen or a file
495 
496 .seealso: `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`, `PETSC_VIEWER_DRAW_()`, `PETSC_VIEWER_DRAW_SELF`, `PETSC_VIEWER_DRAW_WORLD`,
497           `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`,
498           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`,
499           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
500 
501   Level: beginner
502 
503 M*/
504 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Draw(PetscViewer viewer) {
505   PetscViewer_Draw *vdraw;
506 
507   PetscFunctionBegin;
508   PetscCall(PetscNewLog(viewer, &vdraw));
509   viewer->data = (void *)vdraw;
510 
511   viewer->ops->flush            = PetscViewerFlush_Draw;
512   viewer->ops->view             = PetscViewerView_Draw;
513   viewer->ops->destroy          = PetscViewerDestroy_Draw;
514   viewer->ops->setfromoptions   = PetscViewerSetFromOptions_Draw;
515   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_Draw;
516   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_Draw;
517 
518   /* these are created on the fly if requested */
519   vdraw->draw_max  = 5;
520   vdraw->draw_base = 0;
521   vdraw->w         = PETSC_DECIDE;
522   vdraw->h         = PETSC_DECIDE;
523 
524   PetscCall(PetscCalloc3(vdraw->draw_max, &vdraw->draw, vdraw->draw_max, &vdraw->drawlg, vdraw->draw_max, &vdraw->drawaxis));
525   vdraw->singleton_made = PETSC_FALSE;
526   PetscFunctionReturn(0);
527 }
528 
529 /*@
530     PetscViewerDrawClear - Clears a PetscDraw graphic associated with a PetscViewer.
531 
532     Not Collective
533 
534     Input Parameter:
535 .  viewer - the PetscViewer
536 
537     Level: intermediate
538 
539 .seealso: `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
540 
541 @*/
542 PetscErrorCode PetscViewerDrawClear(PetscViewer viewer) {
543   PetscViewer_Draw *vdraw;
544   PetscBool         isdraw;
545   PetscInt          i;
546 
547   PetscFunctionBegin;
548   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
549   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
550   if (!isdraw) PetscFunctionReturn(0);
551   vdraw = (PetscViewer_Draw *)viewer->data;
552 
553   for (i = 0; i < vdraw->draw_max; i++) {
554     if (vdraw->draw[i]) PetscCall(PetscDrawClear(vdraw->draw[i]));
555   }
556   PetscFunctionReturn(0);
557 }
558 
559 /*@
560     PetscViewerDrawGetPause - Gets a pause for the first present draw
561 
562     Not Collective
563 
564     Input Parameter:
565 .  viewer - the PetscViewer
566 
567     Output Parameter:
568 .  pause - the pause value
569 
570     Level: intermediate
571 
572 .seealso: `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
573 
574 @*/
575 PetscErrorCode PetscViewerDrawGetPause(PetscViewer viewer, PetscReal *pause) {
576   PetscViewer_Draw *vdraw;
577   PetscBool         isdraw;
578   PetscInt          i;
579   PetscDraw         draw;
580 
581   PetscFunctionBegin;
582   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
583   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
584   if (!isdraw) {
585     *pause = 0.0;
586     PetscFunctionReturn(0);
587   }
588   vdraw = (PetscViewer_Draw *)viewer->data;
589 
590   for (i = 0; i < vdraw->draw_max; i++) {
591     if (vdraw->draw[i]) {
592       PetscCall(PetscDrawGetPause(vdraw->draw[i], pause));
593       PetscFunctionReturn(0);
594     }
595   }
596   /* none exist yet so create one and get its pause */
597   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
598   PetscCall(PetscDrawGetPause(draw, pause));
599   PetscFunctionReturn(0);
600 }
601 
602 /*@
603     PetscViewerDrawSetPause - Sets a pause for each PetscDraw in the viewer
604 
605     Not Collective
606 
607     Input Parameters:
608 +  viewer - the PetscViewer
609 -  pause - the pause value
610 
611     Level: intermediate
612 
613 .seealso: `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
614 
615 @*/
616 PetscErrorCode PetscViewerDrawSetPause(PetscViewer viewer, PetscReal pause) {
617   PetscViewer_Draw *vdraw;
618   PetscBool         isdraw;
619   PetscInt          i;
620 
621   PetscFunctionBegin;
622   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
623   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
624   if (!isdraw) PetscFunctionReturn(0);
625   vdraw = (PetscViewer_Draw *)viewer->data;
626 
627   vdraw->pause = pause;
628   for (i = 0; i < vdraw->draw_max; i++) {
629     if (vdraw->draw[i]) PetscCall(PetscDrawSetPause(vdraw->draw[i], pause));
630   }
631   PetscFunctionReturn(0);
632 }
633 
634 /*@
635     PetscViewerDrawSetHold - Holds previous image when drawing new image
636 
637     Not Collective
638 
639     Input Parameters:
640 +  viewer - the PetscViewer
641 -  hold - indicates to hold or not
642 
643     Level: intermediate
644 
645 .seealso: `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
646 
647 @*/
648 PetscErrorCode PetscViewerDrawSetHold(PetscViewer viewer, PetscBool hold) {
649   PetscViewer_Draw *vdraw;
650   PetscBool         isdraw;
651 
652   PetscFunctionBegin;
653   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
654   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
655   if (!isdraw) PetscFunctionReturn(0);
656   vdraw = (PetscViewer_Draw *)viewer->data;
657 
658   vdraw->hold = hold;
659   PetscFunctionReturn(0);
660 }
661 
662 /*@
663     PetscViewerDrawGetHold - Checks if holds previous image when drawing new image
664 
665     Not Collective
666 
667     Input Parameter:
668 .  viewer - the PetscViewer
669 
670     Output Parameter:
671 .  hold - indicates to hold or not
672 
673     Level: intermediate
674 
675 .seealso: `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
676 
677 @*/
678 PetscErrorCode PetscViewerDrawGetHold(PetscViewer viewer, PetscBool *hold) {
679   PetscViewer_Draw *vdraw;
680   PetscBool         isdraw;
681 
682   PetscFunctionBegin;
683   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
684   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
685   if (!isdraw) {
686     *hold = PETSC_FALSE;
687     PetscFunctionReturn(0);
688   }
689   vdraw = (PetscViewer_Draw *)viewer->data;
690 
691   *hold = vdraw->hold;
692   PetscFunctionReturn(0);
693 }
694 
695 /* ---------------------------------------------------------------------*/
696 /*
697     The variable Petsc_Viewer_Draw_keyval is used to indicate an MPI attribute that
698   is attached to a communicator, in this case the attribute is a PetscViewer.
699 */
700 PetscMPIInt Petsc_Viewer_Draw_keyval = MPI_KEYVAL_INVALID;
701 
702 /*@C
703     PETSC_VIEWER_DRAW_ - Creates a window PetscViewer shared by all processors
704                      in a communicator.
705 
706      Collective
707 
708      Input Parameter:
709 .    comm - the MPI communicator to share the window PetscViewer
710 
711      Level: intermediate
712 
713      Notes:
714      Unlike almost all other PETSc routines, PETSC_VIEWER_DRAW_ does not return
715      an error code.  The window is usually used in the form
716 $       XXXView(XXX object,PETSC_VIEWER_DRAW_(comm));
717 
718 .seealso: `PETSC_VIEWER_DRAW_WORLD`, `PETSC_VIEWER_DRAW_SELF`, `PetscViewerDrawOpen()`,
719 @*/
720 PetscViewer PETSC_VIEWER_DRAW_(MPI_Comm comm) {
721   PetscErrorCode ierr;
722   PetscMPIInt    flag;
723   PetscViewer    viewer;
724   MPI_Comm       ncomm;
725 
726   PetscFunctionBegin;
727   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
728   if (ierr) {
729     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
730     PetscFunctionReturn(NULL);
731   }
732   if (Petsc_Viewer_Draw_keyval == MPI_KEYVAL_INVALID) {
733     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Draw_keyval, NULL);
734     if (ierr) {
735       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
736       PetscFunctionReturn(NULL);
737     }
738   }
739   ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Draw_keyval, (void **)&viewer, &flag);
740   if (ierr) {
741     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
742     PetscFunctionReturn(NULL);
743   }
744   if (!flag) { /* PetscViewer not yet created */
745     ierr = PetscViewerDrawOpen(ncomm, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, &viewer);
746     if (ierr) {
747       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
748       PetscFunctionReturn(NULL);
749     }
750     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
751     if (ierr) {
752       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
753       PetscFunctionReturn(NULL);
754     }
755     ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Draw_keyval, (void *)viewer);
756     if (ierr) {
757       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
758       PetscFunctionReturn(NULL);
759     }
760   }
761   ierr = PetscCommDestroy(&ncomm);
762   if (ierr) {
763     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
764     PetscFunctionReturn(NULL);
765   }
766   PetscFunctionReturn(viewer);
767 }
768 
769 /*@
770     PetscViewerDrawSetBounds - sets the upper and lower bounds to be used in plotting
771 
772     Collective on PetscViewer
773 
774     Input Parameters:
775 +   viewer - the PetscViewer (created with PetscViewerDrawOpen())
776 .   nbounds - number of plots that can be made with this viewer, for example the dof passed to DMDACreate()
777 -   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, .....
778 
779     Options Database:
780 .   -draw_bounds  minF0,maxF0,minF1,maxF1 - the lower left and upper right bounds
781 
782     Level: intermediate
783 
784     Notes:
785     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
786       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
787       this viewer. Otherwise the color to physical value meaning changes with each new image if this is not set.
788 
789 .seealso: `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`
790 @*/
791 PetscErrorCode PetscViewerDrawSetBounds(PetscViewer viewer, PetscInt nbounds, const PetscReal *bounds) {
792   PetscViewer_Draw *vdraw;
793   PetscBool         isdraw;
794 
795   PetscFunctionBegin;
796   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
797   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
798   if (!isdraw) PetscFunctionReturn(0);
799   vdraw = (PetscViewer_Draw *)viewer->data;
800 
801   vdraw->nbounds = nbounds;
802   PetscCall(PetscFree(vdraw->bounds));
803   PetscCall(PetscMalloc1(2 * nbounds, &vdraw->bounds));
804   PetscCall(PetscArraycpy(vdraw->bounds, bounds, 2 * nbounds));
805   PetscFunctionReturn(0);
806 }
807 
808 /*@C
809     PetscViewerDrawGetBounds - gets the upper and lower bounds to be used in plotting set with PetscViewerDrawSetBounds()
810 
811     Collective on PetscViewer
812 
813     Input Parameter:
814 .   viewer - the PetscViewer (created with PetscViewerDrawOpen())
815 
816     Output Parameters:
817 +   nbounds - number of plots that can be made with this viewer, for example the dof passed to DMDACreate()
818 -   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, .....
819 
820     Level: intermediate
821 
822 .seealso: `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`, `PetscViewerDrawSetBounds()`
823 @*/
824 PetscErrorCode PetscViewerDrawGetBounds(PetscViewer viewer, PetscInt *nbounds, const PetscReal **bounds) {
825   PetscViewer_Draw *vdraw;
826   PetscBool         isdraw;
827 
828   PetscFunctionBegin;
829   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
830   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
831   if (!isdraw) {
832     if (nbounds) *nbounds = 0;
833     if (bounds) *bounds = NULL;
834     PetscFunctionReturn(0);
835   }
836   vdraw = (PetscViewer_Draw *)viewer->data;
837 
838   if (nbounds) *nbounds = vdraw->nbounds;
839   if (bounds) *bounds = vdraw->bounds;
840   PetscFunctionReturn(0);
841 }
842