xref: /petsc/src/sys/classes/viewer/impls/draw/drawv.c (revision 66af8762ec03dbef0e079729eb2a1734a35ed7ff)
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 /*@C
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 /*@C
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 /*@C
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 /*@C
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 /*@C
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 /*@C
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   if (sviewer) *sviewer = NULL;
414   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
415   if (rank == 0) {
416     PetscMPIInt flg;
417     PetscDraw   draw, sdraw;
418 
419     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, comm, &flg));
420     PetscCheck(flg == MPI_IDENT || flg == MPI_CONGRUENT, PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscViewerGetSubViewer() for PETSCVIEWERDRAW requires a singleton MPI_Comm");
421     PetscCall(PetscViewerCreate(comm, sviewer));
422     PetscCall(PetscViewerSetType(*sviewer, PETSCVIEWERDRAW));
423     svdraw             = (PetscViewer_Draw *)(*sviewer)->data;
424     (*sviewer)->format = viewer->format;
425     for (i = 0; i < vdraw->draw_max; i++) { /* XXX this is wrong if svdraw->draw_max (initially 5) < vdraw->draw_max */
426       if (vdraw->draw[i]) PetscCall(PetscDrawGetSingleton(vdraw->draw[i], &svdraw->draw[i]));
427     }
428     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
429     PetscCall(PetscViewerDrawGetDraw(*sviewer, 0, &sdraw));
430     if (draw->savefilename) {
431       PetscCall(PetscDrawSetSave(sdraw, draw->savefilename));
432       sdraw->savefilecount  = draw->savefilecount;
433       sdraw->savesinglefile = draw->savesinglefile;
434       sdraw->savemoviefps   = draw->savemoviefps;
435       sdraw->saveonclear    = draw->saveonclear;
436       sdraw->saveonflush    = draw->saveonflush;
437     }
438     if (draw->savefinalfilename) PetscCall(PetscDrawSetSaveFinalImage(sdraw, draw->savefinalfilename));
439   } else {
440     PetscDraw draw;
441     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
442   }
443   vdraw->singleton_made = PETSC_TRUE;
444   PetscFunctionReturn(PETSC_SUCCESS);
445 }
446 
447 static PetscErrorCode PetscViewerRestoreSubViewer_Draw(PetscViewer viewer, MPI_Comm comm, PetscViewer *sviewer)
448 {
449   PetscMPIInt       rank;
450   PetscInt          i;
451   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)viewer->data, *svdraw;
452 
453   PetscFunctionBegin;
454   PetscCheck(vdraw->singleton_made, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Trying to restore a singleton that was not gotten");
455   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
456   if (rank == 0) {
457     PetscDraw draw, sdraw;
458 
459     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
460     PetscCall(PetscViewerDrawGetDraw(*sviewer, 0, &sdraw));
461     if (draw->savefilename) {
462       draw->savefilecount = sdraw->savefilecount;
463       PetscCallMPI(MPI_Bcast(&draw->savefilecount, 1, MPIU_INT, 0, PetscObjectComm((PetscObject)draw)));
464     }
465     svdraw = (PetscViewer_Draw *)(*sviewer)->data;
466     for (i = 0; i < vdraw->draw_max; i++) {
467       if (vdraw->draw[i] && svdraw->draw[i]) PetscCall(PetscDrawRestoreSingleton(vdraw->draw[i], &svdraw->draw[i]));
468     }
469     PetscCall(PetscFree3(svdraw->draw, svdraw->drawlg, svdraw->drawaxis));
470     PetscCall(PetscFree((*sviewer)->data));
471     PetscCall(PetscHeaderDestroy(sviewer));
472   } else {
473     PetscDraw draw;
474 
475     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
476     if (draw->savefilename) PetscCallMPI(MPI_Bcast(&draw->savefilecount, 1, MPIU_INT, 0, PetscObjectComm((PetscObject)draw)));
477   }
478 
479   vdraw->singleton_made = PETSC_FALSE;
480   PetscFunctionReturn(PETSC_SUCCESS);
481 }
482 
483 static PetscErrorCode PetscViewerSetFromOptions_Draw(PetscViewer v, PetscOptionItems *PetscOptionsObject)
484 {
485   PetscReal bounds[16];
486   PetscInt  nbounds = 16;
487   PetscBool flg;
488 
489   PetscFunctionBegin;
490   PetscOptionsHeadBegin(PetscOptionsObject, "Draw PetscViewer Options");
491   PetscCall(PetscOptionsRealArray("-draw_bounds", "Bounds to put on plots axis", "PetscViewerDrawSetBounds", bounds, &nbounds, &flg));
492   if (flg) PetscCall(PetscViewerDrawSetBounds(v, nbounds / 2, bounds));
493   PetscOptionsHeadEnd();
494   PetscFunctionReturn(PETSC_SUCCESS);
495 }
496 
497 static PetscErrorCode PetscViewerView_Draw(PetscViewer viewer, PetscViewer v)
498 {
499   PetscDraw         draw;
500   PetscInt          i;
501   PetscViewer_Draw *vdraw = (PetscViewer_Draw *)viewer->data;
502   PetscBool         iascii;
503 
504   PetscFunctionBegin;
505   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
506   if (iascii) PetscCall(PetscViewerASCIIPrintf(v, "Draw viewer is of type %s\n", vdraw->drawtype));
507   /*  If the PetscViewer has just been created then no vdraw->draw yet
508       exists so this will not actually call the viewer on any draws. */
509   for (i = 0; i < vdraw->draw_base; i++) {
510     if (vdraw->draw[i]) {
511       PetscCall(PetscViewerDrawGetDraw(viewer, i, &draw));
512       PetscCall(PetscDrawView(draw, v));
513     }
514   }
515   PetscFunctionReturn(PETSC_SUCCESS);
516 }
517 
518 /*MC
519    PETSCVIEWERDRAW - A viewer that generates graphics, either to the screen or a file
520 
521   Level: beginner
522 
523 .seealso: [](sec_viewers), `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`, `PETSC_VIEWER_DRAW_()`, `PETSC_VIEWER_DRAW_SELF`, `PETSC_VIEWER_DRAW_WORLD`,
524           `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`,
525           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`,
526           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
527 M*/
528 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Draw(PetscViewer viewer)
529 {
530   PetscViewer_Draw *vdraw;
531 
532   PetscFunctionBegin;
533   PetscCall(PetscNew(&vdraw));
534   viewer->data = (void *)vdraw;
535 
536   viewer->ops->flush            = PetscViewerFlush_Draw;
537   viewer->ops->view             = PetscViewerView_Draw;
538   viewer->ops->destroy          = PetscViewerDestroy_Draw;
539   viewer->ops->setfromoptions   = PetscViewerSetFromOptions_Draw;
540   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_Draw;
541   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_Draw;
542 
543   /* these are created on the fly if requested */
544   vdraw->draw_max  = 5;
545   vdraw->draw_base = 0;
546   vdraw->w         = PETSC_DECIDE;
547   vdraw->h         = PETSC_DECIDE;
548 
549   PetscCall(PetscCalloc3(vdraw->draw_max, &vdraw->draw, vdraw->draw_max, &vdraw->drawlg, vdraw->draw_max, &vdraw->drawaxis));
550   vdraw->singleton_made = PETSC_FALSE;
551   PetscFunctionReturn(PETSC_SUCCESS);
552 }
553 
554 /*@
555   PetscViewerDrawClear - Clears a `PetscDraw` graphic associated with a `PetscViewer`.
556 
557   Not Collective
558 
559   Input Parameter:
560 . viewer - the `PetscViewer`
561 
562   Level: intermediate
563 
564 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
565 @*/
566 PetscErrorCode PetscViewerDrawClear(PetscViewer viewer)
567 {
568   PetscViewer_Draw *vdraw;
569   PetscBool         isdraw;
570   PetscInt          i;
571 
572   PetscFunctionBegin;
573   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
574   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
575   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
576   vdraw = (PetscViewer_Draw *)viewer->data;
577 
578   for (i = 0; i < vdraw->draw_max; i++) {
579     if (vdraw->draw[i]) PetscCall(PetscDrawClear(vdraw->draw[i]));
580   }
581   PetscFunctionReturn(PETSC_SUCCESS);
582 }
583 
584 /*@
585   PetscViewerDrawGetPause - Gets the pause value (how long to pause before an image is changed)  in the `PETSCVIEWERDRAW` `PetscViewer`
586 
587   Not Collective
588 
589   Input Parameter:
590 . viewer - the `PetscViewer`
591 
592   Output Parameter:
593 . pause - the pause value
594 
595   Level: intermediate
596 
597 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
598 @*/
599 PetscErrorCode PetscViewerDrawGetPause(PetscViewer viewer, PetscReal *pause)
600 {
601   PetscViewer_Draw *vdraw;
602   PetscBool         isdraw;
603   PetscInt          i;
604   PetscDraw         draw;
605 
606   PetscFunctionBegin;
607   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
608   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
609   if (!isdraw) {
610     *pause = 0.0;
611     PetscFunctionReturn(PETSC_SUCCESS);
612   }
613   vdraw = (PetscViewer_Draw *)viewer->data;
614 
615   for (i = 0; i < vdraw->draw_max; i++) {
616     if (vdraw->draw[i]) {
617       PetscCall(PetscDrawGetPause(vdraw->draw[i], pause));
618       PetscFunctionReturn(PETSC_SUCCESS);
619     }
620   }
621   /* none exist yet so create one and get its pause */
622   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
623   PetscCall(PetscDrawGetPause(draw, pause));
624   PetscFunctionReturn(PETSC_SUCCESS);
625 }
626 
627 /*@
628   PetscViewerDrawSetPause - Sets a pause for each `PetscDraw` in the `PETSCVIEWERDRAW` `PetscViewer`
629 
630   Not Collective
631 
632   Input Parameters:
633 + viewer - the `PetscViewer`
634 - pause  - the pause value
635 
636   Level: intermediate
637 
638 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
639 @*/
640 PetscErrorCode PetscViewerDrawSetPause(PetscViewer viewer, PetscReal pause)
641 {
642   PetscViewer_Draw *vdraw;
643   PetscBool         isdraw;
644   PetscInt          i;
645 
646   PetscFunctionBegin;
647   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
648   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
649   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
650   vdraw = (PetscViewer_Draw *)viewer->data;
651 
652   vdraw->pause = pause;
653   for (i = 0; i < vdraw->draw_max; i++) {
654     if (vdraw->draw[i]) PetscCall(PetscDrawSetPause(vdraw->draw[i], pause));
655   }
656   PetscFunctionReturn(PETSC_SUCCESS);
657 }
658 
659 /*@
660   PetscViewerDrawSetHold - Holds previous image when drawing new image in a `PETSCVIEWERDRAW`
661 
662   Not Collective
663 
664   Input Parameters:
665 + viewer - the `PetscViewer`
666 - hold   - `PETSC_TRUE` indicates to hold the previous image
667 
668   Level: intermediate
669 
670 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
671 @*/
672 PetscErrorCode PetscViewerDrawSetHold(PetscViewer viewer, PetscBool hold)
673 {
674   PetscViewer_Draw *vdraw;
675   PetscBool         isdraw;
676 
677   PetscFunctionBegin;
678   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
679   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
680   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
681   vdraw = (PetscViewer_Draw *)viewer->data;
682 
683   vdraw->hold = hold;
684   PetscFunctionReturn(PETSC_SUCCESS);
685 }
686 
687 /*@
688   PetscViewerDrawGetHold - Checks if the `PETSCVIEWERDRAW` `PetscViewer` holds previous image when drawing new image
689 
690   Not Collective
691 
692   Input Parameter:
693 . viewer - the `PetscViewer`
694 
695   Output Parameter:
696 . hold - indicates to hold or not
697 
698   Level: intermediate
699 
700 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
701 @*/
702 PetscErrorCode PetscViewerDrawGetHold(PetscViewer viewer, PetscBool *hold)
703 {
704   PetscViewer_Draw *vdraw;
705   PetscBool         isdraw;
706 
707   PetscFunctionBegin;
708   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
709   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
710   if (!isdraw) {
711     *hold = PETSC_FALSE;
712     PetscFunctionReturn(PETSC_SUCCESS);
713   }
714   vdraw = (PetscViewer_Draw *)viewer->data;
715 
716   *hold = vdraw->hold;
717   PetscFunctionReturn(PETSC_SUCCESS);
718 }
719 
720 /*
721     The variable Petsc_Viewer_Draw_keyval is used to indicate an MPI attribute that
722   is attached to a communicator, in this case the attribute is a PetscViewer.
723 */
724 PetscMPIInt Petsc_Viewer_Draw_keyval = MPI_KEYVAL_INVALID;
725 
726 /*@C
727     PETSC_VIEWER_DRAW_ - Creates a window `PETSCVIEWERDRAW` `PetscViewer` shared by all processors
728                      in an MPI communicator.
729 
730      Collective
731 
732      Input Parameter:
733 .    comm - the MPI communicator to share the window `PetscViewer`
734 
735      Level: intermediate
736 
737      Notes:
738      This object is destroyed in `PetscFinalize()`, `PetscViewerDestroy()` should never be called on it
739 
740      Unlike almost all other PETSc routines, `PETSC_VIEWER_DRAW_()` does not return
741      an error code.  The window is usually used in the form
742 $       XXXView(XXX object, PETSC_VIEWER_DRAW_(comm));
743 
744 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewer`, `PETSC_VIEWER_DRAW_WORLD`, `PETSC_VIEWER_DRAW_SELF`, `PetscViewerDrawOpen()`,
745 @*/
746 PetscViewer PETSC_VIEWER_DRAW_(MPI_Comm comm)
747 {
748   PetscErrorCode ierr;
749   PetscMPIInt    flag, mpi_ierr;
750   PetscViewer    viewer;
751   MPI_Comm       ncomm;
752 
753   PetscFunctionBegin;
754   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
755   if (ierr) {
756     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
757     PetscFunctionReturn(NULL);
758   }
759   if (Petsc_Viewer_Draw_keyval == MPI_KEYVAL_INVALID) {
760     mpi_ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Draw_keyval, NULL);
761     if (mpi_ierr) {
762       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
763       PetscFunctionReturn(NULL);
764     }
765   }
766   mpi_ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Draw_keyval, (void **)&viewer, &flag);
767   if (mpi_ierr) {
768     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
769     PetscFunctionReturn(NULL);
770   }
771   if (!flag) { /* PetscViewer not yet created */
772     ierr                              = PetscViewerDrawOpen(ncomm, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, &viewer);
773     ((PetscObject)viewer)->persistent = PETSC_TRUE;
774     if (ierr) {
775       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
776       PetscFunctionReturn(NULL);
777     }
778     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
779     if (ierr) {
780       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
781       PetscFunctionReturn(NULL);
782     }
783     mpi_ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Draw_keyval, (void *)viewer);
784     if (mpi_ierr) {
785       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
786       PetscFunctionReturn(NULL);
787     }
788   }
789   ierr = PetscCommDestroy(&ncomm);
790   if (ierr) {
791     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
792     PetscFunctionReturn(NULL);
793   }
794   PetscFunctionReturn(viewer);
795 }
796 
797 /*@
798   PetscViewerDrawSetBounds - sets the upper and lower bounds to be used in plotting in a `PETSCVIEWERDRAW` `PetscViewer`
799 
800   Collective
801 
802   Input Parameters:
803 + viewer  - the Petsc`Viewer` (created with `PetscViewerDrawOpen()`)
804 . nbounds - number of plots that can be made with this viewer, for example the dof passed to `DMDACreate()`
805 - 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, .....
806 
807   Options Database Key:
808 . -draw_bounds  minF0,maxF0,minF1,maxF1 - the lower left and upper right bounds
809 
810   Level: intermediate
811 
812   Note:
813   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
814   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
815   this viewer. Otherwise the color to physical value meaning changes with each new image if this is not set.
816 
817 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`
818 @*/
819 PetscErrorCode PetscViewerDrawSetBounds(PetscViewer viewer, PetscInt nbounds, const PetscReal *bounds)
820 {
821   PetscViewer_Draw *vdraw;
822   PetscBool         isdraw;
823 
824   PetscFunctionBegin;
825   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
826   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
827   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
828   vdraw = (PetscViewer_Draw *)viewer->data;
829 
830   vdraw->nbounds = nbounds;
831   PetscCall(PetscFree(vdraw->bounds));
832   PetscCall(PetscMalloc1(2 * nbounds, &vdraw->bounds));
833   PetscCall(PetscArraycpy(vdraw->bounds, bounds, 2 * nbounds));
834   PetscFunctionReturn(PETSC_SUCCESS);
835 }
836 
837 /*@C
838   PetscViewerDrawGetBounds - gets the upper and lower bounds to be used in plotting set with `PetscViewerDrawSetBounds()`
839 
840   Collective
841 
842   Input Parameter:
843 . viewer - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
844 
845   Output Parameters:
846 + nbounds - number of plots that can be made with this viewer, for example the dof passed to `DMDACreate()`
847 - 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, .....
848 
849   Level: intermediate
850 
851 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`, `PetscViewerDrawSetBounds()`
852 @*/
853 PetscErrorCode PetscViewerDrawGetBounds(PetscViewer viewer, PetscInt *nbounds, const PetscReal **bounds)
854 {
855   PetscViewer_Draw *vdraw;
856   PetscBool         isdraw;
857 
858   PetscFunctionBegin;
859   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
860   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
861   if (!isdraw) {
862     if (nbounds) *nbounds = 0;
863     if (bounds) *bounds = NULL;
864     PetscFunctionReturn(PETSC_SUCCESS);
865   }
866   vdraw = (PetscViewer_Draw *)viewer->data;
867 
868   if (nbounds) *nbounds = vdraw->nbounds;
869   if (bounds) *bounds = vdraw->bounds;
870   PetscFunctionReturn(PETSC_SUCCESS);
871 }
872