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