xref: /petsc/src/sys/classes/viewer/impls/draw/drawv.c (revision bbd20b7e897435610760efc4b644bee35cb0ddb2)
1 #include <../src/sys/classes/viewer/impls/draw/vdraw.h> /*I "petscdraw.h" I*/
2 #include <petscviewer.h>                                /*I "petscviewer.h" I*/
3 
4 static PetscErrorCode PetscViewerDestroy_Draw(PetscViewer v)
5 {
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(PETSC_SUCCESS);
23 }
24 
25 static PetscErrorCode PetscViewerFlush_Draw(PetscViewer v)
26 {
27   PetscInt          i;
28   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)v->data;
29 
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 }
36 
37 /*@
38   PetscViewerDrawGetDraw - Returns `PetscDraw` object from `PETSCVIEWERDRAW` `PetscViewer` object.
39   This `PetscDraw` object may then be used to perform graphics using `PetscDraw` commands.
40 
41   Collective
42 
43   Input Parameters:
44 + viewer       - the `PetscViewer` (created with `PetscViewerDrawOpen()` of type `PETSCVIEWERDRAW`)
45 - windownumber - indicates which subwindow (usually 0) to obtain
46 
47   Output Parameter:
48 . draw - the draw object
49 
50   Level: intermediate
51 
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;
58 
59   PetscFunctionBegin;
60   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
61   PetscValidLogicalCollectiveInt(viewer, windownumber, 2);
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;
67 
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;
75 
76     vdraw->draw_max = 2 * windownumber;
77 
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   }
84 
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];
98   if (draw) PetscValidHeaderSpecific(*draw, PETSC_DRAW_CLASSID, 3);
99   PetscFunctionReturn(PETSC_SUCCESS);
100 }
101 
102 /*@
103   PetscViewerDrawBaseAdd - add to the base integer that is added to the `windownumber` passed to `PetscViewerDrawGetDraw()`
104 
105   Logically Collective
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: [](sec_viewers), `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`, `PetscViewerDrawBaseSet()`
117 @*/
118 PetscErrorCode PetscViewerDrawBaseAdd(PetscViewer viewer, PetscInt windownumber)
119 {
120   PetscViewer_Draw *vdraw;
121   PetscBool         isdraw;
122 
123   PetscFunctionBegin;
124   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
125   PetscValidLogicalCollectiveInt(viewer, windownumber, 2);
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;
129 
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 }
134 
135 /*@
136   PetscViewerDrawBaseSet - sets the base integer that is added to the `windownumber` passed to `PetscViewerDrawGetDraw()`
137 
138   Logically Collective
139 
140   Input Parameters:
141 + viewer       - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
142 - windownumber - value to set the base
143 
144   Level: developer
145 
146   Note:
147   A `PETSCVIEWERDRAW` may have multiple `PetscDraw` subwindows, this increases the number of the subwindow that is returned with `PetscViewerDrawGetDraw()`
148 
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;
155 
156   PetscFunctionBegin;
157   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
158   PetscValidLogicalCollectiveInt(viewer, windownumber, 2);
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;
162 
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 }
167 
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.
171 
172   Collective
173 
174   Input Parameters:
175 + viewer       - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
176 - windownumber - indicates which subwindow (usually 0)
177 
178   Output Parameter:
179 . drawlg - the draw line graph object
180 
181   Level: intermediate
182 
183   Note:
184   A `PETSCVIEWERDRAW` may have multiple `PetscDraw` subwindows
185 
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;
192 
193   PetscFunctionBegin;
194   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
195   PetscValidLogicalCollectiveInt(viewer, windownumber, 2);
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;
201 
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 }
210 
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.
214 
215   Collective
216 
217   Input Parameters:
218 + viewer       - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
219 - windownumber - indicates which subwindow (usually 0)
220 
221   Output Parameter:
222 . drawaxis - the draw axis object
223 
224   Level: advanced
225 
226   Note:
227   A `PETSCVIEWERDRAW` may have multiple `PetscDraw` subwindows
228 
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;
235 
236   PetscFunctionBegin;
237   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
238   PetscValidLogicalCollectiveInt(viewer, windownumber, 2);
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;
244 
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 }
250 
251 PetscErrorCode PetscViewerDrawResize(PetscViewer v, int w, int h)
252 {
253   PetscViewer_Draw *vdraw;
254   PetscBool         isdraw;
255 
256   PetscFunctionBegin;
257   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
258   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
259   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
260   vdraw = (PetscViewer_Draw *)v->data;
261 
262   if (w >= 1) vdraw->w = w;
263   if (h >= 1) vdraw->h = h;
264   PetscFunctionReturn(PETSC_SUCCESS);
265 }
266 
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;
271 
272   PetscFunctionBegin;
273   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
274   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
275   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
276   vdraw = (PetscViewer_Draw *)v->data;
277 
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 }
284 
285 PetscErrorCode PetscViewerDrawSetDrawType(PetscViewer v, PetscDrawType drawtype)
286 {
287   PetscViewer_Draw *vdraw;
288   PetscBool         isdraw;
289 
290   PetscFunctionBegin;
291   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
292   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERDRAW, &isdraw));
293   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
294   vdraw = (PetscViewer_Draw *)v->data;
295 
296   PetscCall(PetscFree(vdraw->drawtype));
297   PetscCall(PetscStrallocpy(drawtype, (char **)&vdraw->drawtype));
298   PetscFunctionReturn(PETSC_SUCCESS);
299 }
300 
301 PetscErrorCode PetscViewerDrawGetDrawType(PetscViewer v, PetscDrawType *drawtype)
302 {
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   PetscCheck(isdraw, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Must be draw type PetscViewer");
310   vdraw = (PetscViewer_Draw *)v->data;
311 
312   *drawtype = vdraw->drawtype;
313   PetscFunctionReturn(PETSC_SUCCESS);
314 }
315 
316 PetscErrorCode PetscViewerDrawSetTitle(PetscViewer v, const char title[])
317 {
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   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
325   vdraw = (PetscViewer_Draw *)v->data;
326 
327   PetscCall(PetscFree(vdraw->title));
328   PetscCall(PetscStrallocpy(title, &vdraw->title));
329   PetscFunctionReturn(PETSC_SUCCESS);
330 }
331 
332 PetscErrorCode PetscViewerDrawGetTitle(PetscViewer v, const char *title[])
333 {
334   PetscViewer_Draw *vdraw;
335   PetscBool         isdraw;
336 
337   PetscFunctionBegin;
338   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 1);
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;
342 
343   *title = vdraw->title;
344   PetscFunctionReturn(PETSC_SUCCESS);
345 }
346 
347 /*@
348   PetscViewerDrawOpen - Opens a `PetscDraw` window for use as a `PetscViewer` with type
349   `PETSCVIEWERDRAW`.
350 
351   Collective
352 
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`
361 
362   Output Parameter:
363 . viewer - the `PetscViewer`
364 
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).
373 
374   Level: beginner
375 
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.
379 
380   Format options include\:
381 + `PETSC_VIEWER_DRAW_BASIC` - displays with basic format
382 - `PETSC_VIEWER_DRAW_LG`    - displays using a line graph
383 
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.
389 
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 }
401 
402 #include <petsc/private/drawimpl.h>
403 
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;
409 
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;
417 
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 }
445 
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;
451 
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;
457 
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;
473 
474     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
475     if (draw->savefilename) PetscCallMPI(MPI_Bcast(&draw->savefilecount, 1, MPIU_INT, 0, PetscObjectComm((PetscObject)draw)));
476   }
477 
478   vdraw->singleton_made = PETSC_FALSE;
479   PetscFunctionReturn(PETSC_SUCCESS);
480 }
481 
482 static PetscErrorCode PetscViewerSetFromOptions_Draw(PetscViewer v, PetscOptionItems *PetscOptionsObject)
483 {
484   PetscReal bounds[16];
485   PetscInt  nbounds = 16;
486   PetscBool flg;
487 
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 }
495 
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;
502 
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 }
516 
517 /*MC
518    PETSCVIEWERDRAW - A viewer that generates graphics, either to the screen or a file
519 
520   Level: beginner
521 
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;
530 
531   PetscFunctionBegin;
532   PetscCall(PetscNew(&vdraw));
533   viewer->data = (void *)vdraw;
534 
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;
541 
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;
547 
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 }
552 
553 /*@
554   PetscViewerDrawClear - Clears a `PetscDraw` graphic associated with a `PetscViewer`.
555 
556   Not Collective
557 
558   Input Parameter:
559 . viewer - the `PetscViewer`
560 
561   Level: intermediate
562 
563 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
564 @*/
565 PetscErrorCode PetscViewerDrawClear(PetscViewer viewer)
566 {
567   PetscViewer_Draw *vdraw;
568   PetscBool         isdraw;
569   PetscInt          i;
570 
571   PetscFunctionBegin;
572   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
573   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
574   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
575   vdraw = (PetscViewer_Draw *)viewer->data;
576 
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 }
582 
583 /*@
584   PetscViewerDrawGetPause - Gets the pause value (how long to pause before an image is changed)  in the `PETSCVIEWERDRAW` `PetscViewer`
585 
586   Not Collective
587 
588   Input Parameter:
589 . viewer - the `PetscViewer`
590 
591   Output Parameter:
592 . pause - the pause value
593 
594   Level: intermediate
595 
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;
604 
605   PetscFunctionBegin;
606   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
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;
613 
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 }
625 
626 /*@
627   PetscViewerDrawSetPause - Sets a pause for each `PetscDraw` in the `PETSCVIEWERDRAW` `PetscViewer`
628 
629   Not Collective
630 
631   Input Parameters:
632 + viewer - the `PetscViewer`
633 - pause  - the pause value
634 
635   Level: intermediate
636 
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;
644 
645   PetscFunctionBegin;
646   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
647   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
648   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
649   vdraw = (PetscViewer_Draw *)viewer->data;
650 
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 }
657 
658 /*@
659   PetscViewerDrawSetHold - Holds previous image when drawing new image in a `PETSCVIEWERDRAW`
660 
661   Not Collective
662 
663   Input Parameters:
664 + viewer - the `PetscViewer`
665 - hold   - `PETSC_TRUE` indicates to hold the previous image
666 
667   Level: intermediate
668 
669 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
670 @*/
671 PetscErrorCode PetscViewerDrawSetHold(PetscViewer viewer, PetscBool hold)
672 {
673   PetscViewer_Draw *vdraw;
674   PetscBool         isdraw;
675 
676   PetscFunctionBegin;
677   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
678   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
679   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
680   vdraw = (PetscViewer_Draw *)viewer->data;
681 
682   vdraw->hold = hold;
683   PetscFunctionReturn(PETSC_SUCCESS);
684 }
685 
686 /*@
687   PetscViewerDrawGetHold - Checks if the `PETSCVIEWERDRAW` `PetscViewer` holds previous image when drawing new image
688 
689   Not Collective
690 
691   Input Parameter:
692 . viewer - the `PetscViewer`
693 
694   Output Parameter:
695 . hold - indicates to hold or not
696 
697   Level: intermediate
698 
699 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
700 @*/
701 PetscErrorCode PetscViewerDrawGetHold(PetscViewer viewer, PetscBool *hold)
702 {
703   PetscViewer_Draw *vdraw;
704   PetscBool         isdraw;
705 
706   PetscFunctionBegin;
707   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
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;
714 
715   *hold = vdraw->hold;
716   PetscFunctionReturn(PETSC_SUCCESS);
717 }
718 
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;
724 
725 /*@C
726     PETSC_VIEWER_DRAW_ - Creates a window `PETSCVIEWERDRAW` `PetscViewer` shared by all processors
727                      in an MPI communicator.
728 
729      Collective
730 
731      Input Parameter:
732 .    comm - the MPI communicator to share the window `PetscViewer`
733 
734      Level: intermediate
735 
736      Notes:
737      This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it
738 
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));
742 
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;
750 
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 }
763 
764 /*@
765   PetscViewerDrawSetBounds - sets the upper and lower bounds to be used in plotting in a `PETSCVIEWERDRAW` `PetscViewer`
766 
767   Collective
768 
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, .....
773 
774   Options Database Key:
775 . -draw_bounds  minF0,maxF0,minF1,maxF1 - the lower left and upper right bounds
776 
777   Level: intermediate
778 
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.
783 
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;
790 
791   PetscFunctionBegin;
792   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
793   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
794   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
795   vdraw = (PetscViewer_Draw *)viewer->data;
796 
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 }
803 
804 /*@C
805   PetscViewerDrawGetBounds - gets the upper and lower bounds to be used in plotting set with `PetscViewerDrawSetBounds()`
806 
807   Collective
808 
809   Input Parameter:
810 . viewer - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
811 
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, .....
815 
816   Level: intermediate
817 
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;
824 
825   PetscFunctionBegin;
826   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
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;
834 
835   if (nbounds) *nbounds = vdraw->nbounds;
836   if (bounds) *bounds = vdraw->bounds;
837   PetscFunctionReturn(PETSC_SUCCESS);
838 }
839