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