xref: /petsc/src/sys/classes/viewer/impls/draw/drawv.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
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(0);
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(0);
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 on viewer
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: `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(0);
102 }
103 
104 /*@C
105     PetscViewerDrawBaseAdd - add to the base integer that is added to the windownumber passed to `PetscViewerDrawGetDraw()`
106 
107     Logically Collective on viewer
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: `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(0);
135 }
136 
137 /*@C
138     PetscViewerDrawBaseSet - sets the base integer that is added to the windownumber passed to `PetscViewerDrawGetDraw()`
139 
140     Logically Collective on viewer
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: `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(0);
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 on viewer
175 
176     Input Parameters:
177 +   PetscViewer - 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: `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(0);
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 on viewer
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: `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(0);
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(0);
262   vdraw = (PetscViewer_Draw *)v->data;
263 
264   if (w >= 1) vdraw->w = w;
265   if (h >= 1) vdraw->h = h;
266   PetscFunctionReturn(0);
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(0);
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(0);
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(0);
296   vdraw = (PetscViewer_Draw *)v->data;
297 
298   PetscCall(PetscFree(vdraw->drawtype));
299   PetscCall(PetscStrallocpy(drawtype, (char **)&vdraw->drawtype));
300   PetscFunctionReturn(0);
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(0);
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(0);
327   vdraw = (PetscViewer_Draw *)v->data;
328 
329   PetscCall(PetscFree(vdraw->title));
330   PetscCall(PetscStrallocpy(title, &vdraw->title));
331   PetscFunctionReturn(0);
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(0);
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, y - the screen coordinates of the upper left corner of window, or use `PETSC_DECIDE`
361 -  w, h - window width and height in pixels, or may use `PETSC_DECIDE` or `PETSC_DRAW_FULL_SIZE`, `PETSC_DRAW_HALF_SIZE`,
362           `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    Note for Fortran Programmers:
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: `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(0);
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(0);
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(0);
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(0);
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 
501   PetscFunctionBegin;
502   /*  If the PetscViewer has just been created then no vdraw->draw yet
503       exists so this will not actually call the viewer on any draws. */
504   for (i = 0; i < vdraw->draw_base; i++) {
505     if (vdraw->draw[i]) {
506       PetscCall(PetscViewerDrawGetDraw(viewer, i, &draw));
507       PetscCall(PetscDrawView(draw, v));
508     }
509   }
510   PetscFunctionReturn(0);
511 }
512 
513 /*MC
514    PETSCVIEWERDRAW - A viewer that generates graphics, either to the screen or a file
515 
516   Level: beginner
517 
518 .seealso: `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`, `PETSC_VIEWER_DRAW_()`, `PETSC_VIEWER_DRAW_SELF`, `PETSC_VIEWER_DRAW_WORLD`,
519           `PetscViewerCreate()`, `PetscViewerASCIIOpen()`, `PetscViewerBinaryOpen()`, `PETSCVIEWERBINARY`,
520           `PetscViewerMatlabOpen()`, `VecView()`, `DMView()`, `PetscViewerMatlabPutArray()`, `PETSCVIEWERASCII`, `PETSCVIEWERMATLAB`,
521           `PetscViewerFileSetName()`, `PetscViewerFileSetMode()`, `PetscViewerFormat`, `PetscViewerType`, `PetscViewerSetType()`
522 M*/
523 PETSC_EXTERN PetscErrorCode PetscViewerCreate_Draw(PetscViewer viewer)
524 {
525   PetscViewer_Draw *vdraw;
526 
527   PetscFunctionBegin;
528   PetscCall(PetscNew(&vdraw));
529   viewer->data = (void *)vdraw;
530 
531   viewer->ops->flush            = PetscViewerFlush_Draw;
532   viewer->ops->view             = PetscViewerView_Draw;
533   viewer->ops->destroy          = PetscViewerDestroy_Draw;
534   viewer->ops->setfromoptions   = PetscViewerSetFromOptions_Draw;
535   viewer->ops->getsubviewer     = PetscViewerGetSubViewer_Draw;
536   viewer->ops->restoresubviewer = PetscViewerRestoreSubViewer_Draw;
537 
538   /* these are created on the fly if requested */
539   vdraw->draw_max  = 5;
540   vdraw->draw_base = 0;
541   vdraw->w         = PETSC_DECIDE;
542   vdraw->h         = PETSC_DECIDE;
543 
544   PetscCall(PetscCalloc3(vdraw->draw_max, &vdraw->draw, vdraw->draw_max, &vdraw->drawlg, vdraw->draw_max, &vdraw->drawaxis));
545   vdraw->singleton_made = PETSC_FALSE;
546   PetscFunctionReturn(0);
547 }
548 
549 /*@
550     PetscViewerDrawClear - Clears a `PetscDraw` graphic associated with a `PetscViewer`.
551 
552     Not Collective
553 
554     Input Parameter:
555 .  viewer - the `PetscViewer`
556 
557     Level: intermediate
558 
559 .seealso: `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
560 @*/
561 PetscErrorCode PetscViewerDrawClear(PetscViewer viewer)
562 {
563   PetscViewer_Draw *vdraw;
564   PetscBool         isdraw;
565   PetscInt          i;
566 
567   PetscFunctionBegin;
568   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
569   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
570   if (!isdraw) PetscFunctionReturn(0);
571   vdraw = (PetscViewer_Draw *)viewer->data;
572 
573   for (i = 0; i < vdraw->draw_max; i++) {
574     if (vdraw->draw[i]) PetscCall(PetscDrawClear(vdraw->draw[i]));
575   }
576   PetscFunctionReturn(0);
577 }
578 
579 /*@
580     PetscViewerDrawGetPause - Gets the pause value (how long to pause before an image is changed)  in the `PETSCVIEWERDRAW` `PetscViewer`
581 
582     Not Collective
583 
584     Input Parameter:
585 .  viewer - the `PetscViewer`
586 
587     Output Parameter:
588 .  pause - the pause value
589 
590     Level: intermediate
591 
592 .seealso: `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
593 @*/
594 PetscErrorCode PetscViewerDrawGetPause(PetscViewer viewer, PetscReal *pause)
595 {
596   PetscViewer_Draw *vdraw;
597   PetscBool         isdraw;
598   PetscInt          i;
599   PetscDraw         draw;
600 
601   PetscFunctionBegin;
602   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
603   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
604   if (!isdraw) {
605     *pause = 0.0;
606     PetscFunctionReturn(0);
607   }
608   vdraw = (PetscViewer_Draw *)viewer->data;
609 
610   for (i = 0; i < vdraw->draw_max; i++) {
611     if (vdraw->draw[i]) {
612       PetscCall(PetscDrawGetPause(vdraw->draw[i], pause));
613       PetscFunctionReturn(0);
614     }
615   }
616   /* none exist yet so create one and get its pause */
617   PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
618   PetscCall(PetscDrawGetPause(draw, pause));
619   PetscFunctionReturn(0);
620 }
621 
622 /*@
623     PetscViewerDrawSetPause - Sets a pause for each `PetscDraw` in the `PETSCVIEWERDRAW` `PetscViewer`
624 
625     Not Collective
626 
627     Input Parameters:
628 +  viewer - the `PetscViewer`
629 -  pause - the pause value
630 
631     Level: intermediate
632 
633 .seealso: `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
634 @*/
635 PetscErrorCode PetscViewerDrawSetPause(PetscViewer viewer, PetscReal pause)
636 {
637   PetscViewer_Draw *vdraw;
638   PetscBool         isdraw;
639   PetscInt          i;
640 
641   PetscFunctionBegin;
642   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
643   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
644   if (!isdraw) PetscFunctionReturn(0);
645   vdraw = (PetscViewer_Draw *)viewer->data;
646 
647   vdraw->pause = pause;
648   for (i = 0; i < vdraw->draw_max; i++) {
649     if (vdraw->draw[i]) PetscCall(PetscDrawSetPause(vdraw->draw[i], pause));
650   }
651   PetscFunctionReturn(0);
652 }
653 
654 /*@
655     PetscViewerDrawSetHold - Holds previous image when drawing new image
656 
657     Not Collective
658 
659     Input Parameters:
660 +  viewer - the `PetscViewer`
661 -  hold - `PETSC_TRUE` indicates to hold the previous image
662 
663     Level: intermediate
664 
665 .seealso: `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
666 @*/
667 PetscErrorCode PetscViewerDrawSetHold(PetscViewer viewer, PetscBool hold)
668 {
669   PetscViewer_Draw *vdraw;
670   PetscBool         isdraw;
671 
672   PetscFunctionBegin;
673   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
674   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
675   if (!isdraw) PetscFunctionReturn(0);
676   vdraw = (PetscViewer_Draw *)viewer->data;
677 
678   vdraw->hold = hold;
679   PetscFunctionReturn(0);
680 }
681 
682 /*@
683     PetscViewerDrawGetHold - Checks if the `PETSCVIEWERDRAW` `PetscViewer` holds previous image when drawing new image
684 
685     Not Collective
686 
687     Input Parameter:
688 .  viewer - the `PetscViewer`
689 
690     Output Parameter:
691 .  hold - indicates to hold or not
692 
693     Level: intermediate
694 
695 .seealso: `PETSCVIEWERDRAW`, `PetscViewerDrawOpen()`, `PetscViewerDrawGetDraw()`,
696 @*/
697 PetscErrorCode PetscViewerDrawGetHold(PetscViewer viewer, PetscBool *hold)
698 {
699   PetscViewer_Draw *vdraw;
700   PetscBool         isdraw;
701 
702   PetscFunctionBegin;
703   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
704   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
705   if (!isdraw) {
706     *hold = PETSC_FALSE;
707     PetscFunctionReturn(0);
708   }
709   vdraw = (PetscViewer_Draw *)viewer->data;
710 
711   *hold = vdraw->hold;
712   PetscFunctionReturn(0);
713 }
714 
715 /* ---------------------------------------------------------------------*/
716 /*
717     The variable Petsc_Viewer_Draw_keyval is used to indicate an MPI attribute that
718   is attached to a communicator, in this case the attribute is a PetscViewer.
719 */
720 PetscMPIInt Petsc_Viewer_Draw_keyval = MPI_KEYVAL_INVALID;
721 
722 /*@C
723     PETSC_VIEWER_DRAW_ - Creates a window `PETSCVIEWERDRAW` `PetscViewer` shared by all processors
724                      in a communicator.
725 
726      Collective
727 
728      Input Parameter:
729 .    comm - the MPI communicator to share the window `PetscViewer`
730 
731      Level: intermediate
732 
733      Note:
734      Unlike almost all other PETSc routines, `PETSC_VIEWER_DRAW_()` does not return
735      an error code.  The window is usually used in the form
736 $       XXXView(XXX object,PETSC_VIEWER_DRAW_(comm));
737 
738 .seealso: `PETSCVIEWERDRAW`, `PetscViewer`, `PETSC_VIEWER_DRAW_WORLD`, `PETSC_VIEWER_DRAW_SELF`, `PetscViewerDrawOpen()`,
739 @*/
740 PetscViewer PETSC_VIEWER_DRAW_(MPI_Comm comm)
741 {
742   PetscErrorCode ierr;
743   PetscMPIInt    flag;
744   PetscViewer    viewer;
745   MPI_Comm       ncomm;
746 
747   PetscFunctionBegin;
748   ierr = PetscCommDuplicate(comm, &ncomm, NULL);
749   if (ierr) {
750     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
751     PetscFunctionReturn(NULL);
752   }
753   if (Petsc_Viewer_Draw_keyval == MPI_KEYVAL_INVALID) {
754     ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_Viewer_Draw_keyval, NULL);
755     if (ierr) {
756       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
757       PetscFunctionReturn(NULL);
758     }
759   }
760   ierr = MPI_Comm_get_attr(ncomm, Petsc_Viewer_Draw_keyval, (void **)&viewer, &flag);
761   if (ierr) {
762     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
763     PetscFunctionReturn(NULL);
764   }
765   if (!flag) { /* PetscViewer not yet created */
766     ierr = PetscViewerDrawOpen(ncomm, NULL, NULL, PETSC_DECIDE, PETSC_DECIDE, 300, 300, &viewer);
767     if (ierr) {
768       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
769       PetscFunctionReturn(NULL);
770     }
771     ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
772     if (ierr) {
773       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
774       PetscFunctionReturn(NULL);
775     }
776     ierr = MPI_Comm_set_attr(ncomm, Petsc_Viewer_Draw_keyval, (void *)viewer);
777     if (ierr) {
778       PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
779       PetscFunctionReturn(NULL);
780     }
781   }
782   ierr = PetscCommDestroy(&ncomm);
783   if (ierr) {
784     PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_DRAW_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_REPEAT, " ");
785     PetscFunctionReturn(NULL);
786   }
787   PetscFunctionReturn(viewer);
788 }
789 
790 /*@
791     PetscViewerDrawSetBounds - sets the upper and lower bounds to be used in plotting
792 
793     Collective on viewer
794 
795     Input Parameters:
796 +   viewer - the Petsc`Viewer` (created with `PetscViewerDrawOpen()`)
797 .   nbounds - number of plots that can be made with this viewer, for example the dof passed to `DMDACreate()`
798 -   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, .....
799 
800     Options Database Key:
801 .   -draw_bounds  minF0,maxF0,minF1,maxF1 - the lower left and upper right bounds
802 
803     Level: intermediate
804 
805     Note:
806     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
807       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
808       this viewer. Otherwise the color to physical value meaning changes with each new image if this is not set.
809 
810 .seealso: `PETSCVIEWERDRAW`, `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`
811 @*/
812 PetscErrorCode PetscViewerDrawSetBounds(PetscViewer viewer, PetscInt nbounds, const PetscReal *bounds)
813 {
814   PetscViewer_Draw *vdraw;
815   PetscBool         isdraw;
816 
817   PetscFunctionBegin;
818   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
819   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
820   if (!isdraw) PetscFunctionReturn(0);
821   vdraw = (PetscViewer_Draw *)viewer->data;
822 
823   vdraw->nbounds = nbounds;
824   PetscCall(PetscFree(vdraw->bounds));
825   PetscCall(PetscMalloc1(2 * nbounds, &vdraw->bounds));
826   PetscCall(PetscArraycpy(vdraw->bounds, bounds, 2 * nbounds));
827   PetscFunctionReturn(0);
828 }
829 
830 /*@C
831     PetscViewerDrawGetBounds - gets the upper and lower bounds to be used in plotting set with `PetscViewerDrawSetBounds()`
832 
833     Collective on viewer
834 
835     Input Parameter:
836 .   viewer - the `PetscViewer` (created with `PetscViewerDrawOpen()`)
837 
838     Output Parameters:
839 +   nbounds - number of plots that can be made with this viewer, for example the dof passed to `DMDACreate()`
840 -   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, .....
841 
842     Level: intermediate
843 
844 .seealso: `PETSCVIEWERDRAW`, `PetscViewerDrawGetLG()`, `PetscViewerDrawGetAxis()`, `PetscViewerDrawOpen()`, `PetscViewerDrawSetBounds()`
845 @*/
846 PetscErrorCode PetscViewerDrawGetBounds(PetscViewer viewer, PetscInt *nbounds, const PetscReal **bounds)
847 {
848   PetscViewer_Draw *vdraw;
849   PetscBool         isdraw;
850 
851   PetscFunctionBegin;
852   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 1);
853   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
854   if (!isdraw) {
855     if (nbounds) *nbounds = 0;
856     if (bounds) *bounds = NULL;
857     PetscFunctionReturn(0);
858   }
859   vdraw = (PetscViewer_Draw *)viewer->data;
860 
861   if (nbounds) *nbounds = vdraw->nbounds;
862   if (bounds) *bounds = vdraw->bounds;
863   PetscFunctionReturn(0);
864 }
865