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