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