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