xref: /petsc/src/sys/classes/viewer/impls/draw/drawv.c (revision 856bee69f0e0908e75ff837867b1777dfb1ced96)
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 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 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 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 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      Note:
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   PetscErrorCode ierr;
748   PetscMPIInt    flag, mpi_ierr;
749   PetscViewer    viewer;
750   MPI_Comm       ncomm;
751 
752   PetscFunctionBegin;
753   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
754   if (ierr) {
755     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
756     PetscFunctionReturn(NULL);
757   }
758   if (Petsc_Viewer_Draw_keyval == MPI_KEYVAL_INVALID) {
759     mpi_ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Draw_keyval, NULL);
760     if (mpi_ierr) {
761       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
762       PetscFunctionReturn(NULL);
763     }
764   }
765   mpi_ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Draw_keyval, (void **)&viewer, &flag);
766   if (mpi_ierr) {
767     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
768     PetscFunctionReturn(NULL);
769   }
770   if (!flag) { /* PetscViewer not yet created */
771     ierr = PetscViewerDrawOpen(ncomm, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, &viewer);
772     if (ierr) {
773       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
774       PetscFunctionReturn(NULL);
775     }
776     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
777     if (ierr) {
778       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
779       PetscFunctionReturn(NULL);
780     }
781     mpi_ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Draw_keyval, (void *)viewer);
782     if (mpi_ierr) {
783       ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
784       PetscFunctionReturn(NULL);
785     }
786   }
787   ierr = PetscCommDestroy(&ncomm);
788   if (ierr) {
789     ierr = PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
790     PetscFunctionReturn(NULL);
791   }
792   PetscFunctionReturn(viewer);
793 }
794 
795 /*@
796   PetscViewerDrawSetBounds - sets the upper and lower bounds to be used in plotting in a `PETSCVIEWERDRAW` `PetscViewer`
797 
798   Collective
799 
800   Input Parameters:
801 + viewer  - the Petsc`Viewer` (created with `PetscViewerDrawOpen()`)
802 . nbounds - number of plots that can be made with this viewer, for example the dof passed to `DMDACreate()`
803 - 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, .....
804 
805   Options Database Key:
806 . -draw_bounds  minF0,maxF0,minF1,maxF1 - the lower left and upper right bounds
807 
808   Level: intermediate
809 
810   Note:
811   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
812   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
813   this viewer. Otherwise the color to physical value meaning changes with each new image if this is not set.
814 
815 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`
816 @*/
817 PetscErrorCode PetscViewerDrawSetBounds(PetscViewer viewer, PetscInt nbounds, const PetscReal *bounds)
818 {
819   PetscViewer_Draw *vdraw;
820   PetscBool         isdraw;
821 
822   PetscFunctionBegin;
823   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
824   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
825   if (!isdraw) PetscFunctionReturn(PETSC_SUCCESS);
826   vdraw = (PetscViewer_Draw *)viewer->data;
827 
828   vdraw->nbounds = nbounds;
829   PetscCall(PetscFree(vdraw->bounds));
830   PetscCall(PetscMalloc1(2 * nbounds, &vdraw->bounds));
831   PetscCall(PetscArraycpy(vdraw->bounds, bounds, 2 * nbounds));
832   PetscFunctionReturn(PETSC_SUCCESS);
833 }
834 
835 /*@C
836   PetscViewerDrawGetBounds - gets the upper and lower bounds to be used in plotting set with `PetscViewerDrawSetBounds()`
837 
838   Collective
839 
840   Input Parameter:
841 . viewer - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
842 
843   Output Parameters:
844 + nbounds - number of plots that can be made with this viewer, for example the dof passed to `DMDACreate()`
845 - 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, .....
846 
847   Level: intermediate
848 
849 .seealso: [](sec_viewers), `PETSCVIEWERDRAW`, `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`, `PetscViewerDrawSetBounds()`
850 @*/
851 PetscErrorCode PetscViewerDrawGetBounds(PetscViewer viewer, PetscInt *nbounds, const PetscReal **bounds)
852 {
853   PetscViewer_Draw *vdraw;
854   PetscBool         isdraw;
855 
856   PetscFunctionBegin;
857   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
858   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
859   if (!isdraw) {
860     if (nbounds) *nbounds = 0;
861     if (bounds) *bounds = NULL;
862     PetscFunctionReturn(PETSC_SUCCESS);
863   }
864   vdraw = (PetscViewer_Draw *)viewer->data;
865 
866   if (nbounds) *nbounds = vdraw->nbounds;
867   if (bounds) *bounds = vdraw->bounds;
868   PetscFunctionReturn(PETSC_SUCCESS);
869 }
870