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