xref: /petsc/src/sys/classes/draw/interface/drawreg.c (revision 8d3c1932cd76dc2d1ac854cce48898cc6ac885a3)
1 
2 /*
3        Provides the registration process for PETSc PetscDraw routines
4 */
5 #include <petsc/private/drawimpl.h>  /*I "petscdraw.h" I*/
6 #include <petscviewer.h>             /*I "petscviewer.h" I*/
7 #if defined(PETSC_HAVE_SAWS)
8 #include <petscviewersaws.h>
9 #endif
10 
11 /*
12    Contains the list of registered PetscDraw routines
13 */
14 PetscFunctionList PetscDrawList = 0;
15 
16 #undef __FUNCT__
17 #define __FUNCT__ "PetscDrawView"
18 /*@C
19    PetscDrawView - Prints the PetscDraw data structure.
20 
21    Collective on PetscDraw
22 
23    Input Parameters:
24 +  indraw - the PetscDraw context
25 -  viewer - visualization context
26 
27    See PetscDrawSetFromOptions() for options database keys
28 
29    Note:
30    The available visualization contexts include
31 +     PETSC_VIEWER_STDOUT_SELF - standard output (default)
32 -     PETSC_VIEWER_STDOUT_WORLD - synchronized standard
33          output where only the first processor opens
34          the file.  All other processors send their
35          data to the first processor to print.
36 
37    The user can open an alternative visualization context with
38    PetscViewerASCIIOpen() - output to a specified file.
39 
40    Level: beginner
41 
42 .keywords: PetscDraw, view
43 
44 .seealso: PCView(), PetscViewerASCIIOpen()
45 @*/
46 PetscErrorCode  PetscDrawView(PetscDraw indraw,PetscViewer viewer)
47 {
48   PetscErrorCode ierr;
49   PetscBool      isdraw;
50 #if defined(PETSC_HAVE_SAWS)
51   PetscBool      issaws;
52 #endif
53 
54   PetscFunctionBegin;
55   PetscValidHeaderSpecific(indraw,PETSC_DRAW_CLASSID,1);
56   if (!viewer) {
57     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)indraw),&viewer);CHKERRQ(ierr);
58   }
59   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
60   PetscCheckSameComm(indraw,1,viewer,2);
61 
62   ierr = PetscObjectPrintClassNamePrefixType((PetscObject)indraw,viewer);CHKERRQ(ierr);
63   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr);
64 #if defined(PETSC_HAVE_SAWS)
65   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSAWS,&issaws);CHKERRQ(ierr);
66 #endif
67   if (isdraw) {
68     PetscDraw draw;
69     char      str[36];
70     PetscReal x,y,bottom,h;
71 
72     ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr);
73     ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr);
74     ierr   = PetscStrcpy(str,"PetscDraw: ");CHKERRQ(ierr);
75     ierr   = PetscStrcat(str,((PetscObject)indraw)->type_name);CHKERRQ(ierr);
76     ierr   = PetscDrawStringBoxed(draw,x,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);CHKERRQ(ierr);
77     bottom = y - h;
78     ierr = PetscDrawPushCurrentPoint(draw,x,bottom);CHKERRQ(ierr);
79 #if defined(PETSC_HAVE_SAWS)
80   } else if (issaws) {
81     PetscMPIInt rank;
82 
83     ierr = PetscObjectName((PetscObject)indraw);CHKERRQ(ierr);
84     ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);
85     if (!((PetscObject)indraw)->amsmem && !rank) {
86       ierr = PetscObjectViewSAWs((PetscObject)indraw,viewer);CHKERRQ(ierr);
87     }
88 #endif
89   } else if (indraw->ops->view) {
90     ierr = (*indraw->ops->view)(indraw,viewer);CHKERRQ(ierr);
91   }
92   PetscFunctionReturn(0);
93 }
94 
95 #undef __FUNCT__
96 #define __FUNCT__ "PetscDrawCreate"
97 /*@C
98    PetscDrawCreate - Creates a graphics context.
99 
100    Collective on MPI_Comm
101 
102    Input Parameter:
103 +  comm - MPI communicator
104 .  display - X display when using X windows
105 .  title - optional title added to top of window
106 .  x,y - coordinates of lower left corner of window or PETSC_DECIDE
107 -  w, h - width and height of window or PETSC_DECIDE or PETSC_DRAW_HALF_SIZE, PETSC_DRAW_FULL_SIZE,
108           or PETSC_DRAW_THIRD_SIZE or PETSC_DRAW_QUARTER_SIZE
109 
110    Output Parameter:
111 .  draw - location to put the PetscDraw context
112 
113    Level: beginner
114 
115    Concepts: graphics^creating context
116    Concepts: drawing^creating context
117 
118 .seealso: PetscDrawSetFromOptions(), PetscDrawDestroy(), PetscDrawSetType()
119 @*/
120 PetscErrorCode  PetscDrawCreate(MPI_Comm comm,const char display[],const char title[],int x,int y,int w,int h,PetscDraw *indraw)
121 {
122   PetscDraw      draw;
123   PetscErrorCode ierr;
124   PetscReal      dpause;
125   PetscBool      flag;
126 
127   PetscFunctionBegin;
128   ierr = PetscDrawInitializePackage();CHKERRQ(ierr);
129   *indraw = 0;
130   ierr = PetscHeaderCreate(draw,PETSC_DRAW_CLASSID,"Draw","Graphics","Draw",comm,PetscDrawDestroy,PetscDrawView);CHKERRQ(ierr);
131 
132   draw->data    = 0;
133   ierr          = PetscStrallocpy(title,&draw->title);CHKERRQ(ierr);
134   ierr          = PetscStrallocpy(display,&draw->display);CHKERRQ(ierr);
135   draw->x       = x;
136   draw->y       = y;
137   draw->w       = w;
138   draw->h       = h;
139   draw->pause   = 0.0;
140   draw->coor_xl = 0.0;
141   draw->coor_xr = 1.0;
142   draw->coor_yl = 0.0;
143   draw->coor_yr = 1.0;
144   draw->port_xl = 0.0;
145   draw->port_xr = 1.0;
146   draw->port_yl = 0.0;
147   draw->port_yr = 1.0;
148   draw->popup   = 0;
149 
150   ierr = PetscOptionsGetReal(NULL,"-draw_pause",&dpause,&flag);CHKERRQ(ierr);
151   if (flag) draw->pause = dpause;
152   draw->savefilename  = NULL;
153   draw->savefilemovie = PETSC_FALSE;
154   draw->savefilecount = -1;
155 
156   ierr = PetscDrawSetCurrentPoint(draw,.5,.9);CHKERRQ(ierr);
157 
158   draw->boundbox_xl  = .5;
159   draw->boundbox_xr  = .5;
160   draw->boundbox_yl  = .9;
161   draw->boundbox_yr  = .9;
162 
163   *indraw = draw;
164   PetscFunctionReturn(0);
165 }
166 
167 #undef __FUNCT__
168 #define __FUNCT__ "PetscDrawSetType"
169 /*@C
170    PetscDrawSetType - Builds graphics object for a particular implementation
171 
172    Collective on PetscDraw
173 
174    Input Parameter:
175 +  draw      - the graphics context
176 -  type      - for example, PETSC_DRAW_X
177 
178    Options Database Command:
179 .  -draw_type  <type> - Sets the type; use -help for a list of available methods (for instance, x)
180 
181    See PetscDrawSetFromOptions for additional options database keys
182 
183    Level: intermediate
184 
185    Notes:
186    See "petsc/include/petscdraw.h" for available methods (for instance,
187    PETSC_DRAW_X)
188 
189    Concepts: drawing^X windows
190    Concepts: X windows^graphics
191    Concepts: drawing^Microsoft Windows
192 
193 .seealso: PetscDrawSetFromOptions(), PetscDrawCreate(), PetscDrawDestroy()
194 @*/
195 PetscErrorCode  PetscDrawSetType(PetscDraw draw,PetscDrawType type)
196 {
197   PetscErrorCode ierr,(*r)(PetscDraw);
198   PetscBool      match;
199   PetscBool      flg=PETSC_FALSE;
200 
201   PetscFunctionBegin;
202   PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1);
203   PetscValidCharPointer(type,2);
204 
205   ierr = PetscObjectTypeCompare((PetscObject)draw,type,&match);CHKERRQ(ierr);
206   if (match) PetscFunctionReturn(0);
207 
208   /*  User requests no graphics */
209   ierr = PetscOptionsHasName(NULL,"-nox",&flg);CHKERRQ(ierr);
210 
211   /*
212      This is not ideal, but it allows codes to continue to run if X graphics
213    was requested but is not installed on this machine. Mostly this is for
214    testing.
215    */
216 #if !defined(PETSC_HAVE_X)
217   if (!flg) {
218     ierr = PetscStrcmp(type,PETSC_DRAW_X,&match);CHKERRQ(ierr);
219     if (match) {
220       PetscBool dontwarn = PETSC_TRUE;
221       flg  = PETSC_TRUE;
222       ierr = PetscOptionsHasName(NULL,"-nox_warning",&dontwarn);CHKERRQ(ierr);
223       if (!dontwarn) (*PetscErrorPrintf)("PETSc installed without X windows on this machine\nproceeding without graphics\n");
224     }
225   }
226 #endif
227   if (flg) type = PETSC_DRAW_NULL;
228 
229   ierr =  PetscFunctionListFind(PetscDrawList,type,&r);CHKERRQ(ierr);
230   if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown PetscDraw type given: %s",type);
231   if (draw->ops->destroy) {ierr = (*draw->ops->destroy)(draw);CHKERRQ(ierr);}
232   ierr = PetscMemzero(draw->ops,sizeof(struct _PetscDrawOps));CHKERRQ(ierr);
233   ierr       = PetscObjectChangeTypeName((PetscObject)draw,type);CHKERRQ(ierr);
234   ierr       = (*r)(draw);CHKERRQ(ierr);
235   PetscFunctionReturn(0);
236 }
237 
238 #undef __FUNCT__
239 #define __FUNCT__ "PetscDrawGetType"
240 /*@C
241    PetscDrawGetType - Gets the PetscDraw type as a string from the PetscDraw object.
242 
243    Not Collective
244 
245    Input Parameter:
246 .  draw - Krylov context
247 
248    Output Parameters:
249 .  name - name of PetscDraw method
250 
251    Level: advanced
252 
253 @*/
254 PetscErrorCode  PetscDrawGetType(PetscDraw draw,PetscDrawType *type)
255 {
256   PetscFunctionBegin;
257   PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1);
258   PetscValidPointer(type,2);
259   *type = ((PetscObject)draw)->type_name;
260   PetscFunctionReturn(0);
261 }
262 
263 #undef __FUNCT__
264 #define __FUNCT__ "PetscDrawRegister"
265 /*@C
266    PetscDrawRegister - Adds a method to the graphics package.
267 
268    Not Collective
269 
270    Input Parameters:
271 +  name_solver - name of a new user-defined graphics class
272 -  routine_create - routine to create method context
273 
274    Level: developer
275 
276    Notes:
277    PetscDrawRegister() may be called multiple times to add several user-defined graphics classes
278 
279    Sample usage:
280 .vb
281    PetscDrawRegister("my_draw_type", MyDrawCreate);
282 .ve
283 
284    Then, your specific graphics package can be chosen with the procedural interface via
285 $     PetscDrawSetType(ksp,"my_draw_type")
286    or at runtime via the option
287 $     -draw_type my_draw_type
288 
289    Concepts: graphics^registering new draw classes
290    Concepts: PetscDraw^registering new draw classes
291 
292 .seealso: PetscDrawRegisterAll(), PetscDrawRegisterDestroy()
293 @*/
294 PetscErrorCode  PetscDrawRegister(const char *sname,PetscErrorCode (*function)(PetscDraw))
295 {
296   PetscErrorCode ierr;
297 
298   PetscFunctionBegin;
299   ierr = PetscFunctionListAdd(&PetscDrawList,sname,function);CHKERRQ(ierr);
300   PetscFunctionReturn(0);
301 }
302 
303 #undef __FUNCT__
304 #define __FUNCT__ "PetscDrawSetFromOptions"
305 /*@
306    PetscDrawSetFromOptions - Sets the graphics type from the options database.
307       Defaults to a PETSc X windows graphics.
308 
309    Collective on PetscDraw
310 
311    Input Parameter:
312 .     draw - the graphics context
313 
314    Options Database Keys:
315 +   -nox - do not use X graphics (ignore graphics calls, but run program correctly)
316 .   -nox_warning - when X windows support is not installed this prevents the warning message from being printed
317 .   -draw_pause <pause amount> -- -1 indicates wait for mouse input, -2 indicates pause when window is to be destroyed
318 .   -draw_marker_type - <x,point>
319 .   -draw_save [optional filename] - (X windows only) saves each image before it is cleared to a file
320 .   -draw_save_final_image [optional filename] - (X windows only) saves the final image displayed in a window
321 .   -draw_save_movie - converts image files to a movie  at the end of the run. See PetscDrawSetSave()
322 .   -draw_save_on_flush - saves an image on each flush in addition to each clear
323 -   -draw_save_single_file - saves each new image in the same file, normally each new image is saved in a new file with filename_%d
324 
325    Level: intermediate
326 
327    Notes:
328     Must be called after PetscDrawCreate() before the PetscDraw is used.
329 
330     Concepts: drawing^setting options
331     Concepts: graphics^setting options
332 
333 .seealso: PetscDrawCreate(), PetscDrawSetType(), PetscDrawSetSave(), PetscDrawSetSaveFinalImage()
334 
335 @*/
336 PetscErrorCode  PetscDrawSetFromOptions(PetscDraw draw)
337 {
338   PetscErrorCode    ierr;
339   PetscBool         flg,nox;
340   char              vtype[256];
341   const char        *def;
342   PetscReal         dpause;
343 #if !defined(PETSC_USE_WINDOWS_GRAPHICS) && !defined(PETSC_HAVE_X)
344   PetscBool         warn;
345 #endif
346 
347   PetscFunctionBegin;
348   PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1);
349 
350   if (!PetscDrawList) {
351     ierr = PetscDrawRegisterAll();CHKERRQ(ierr);
352   }
353 
354   if (((PetscObject)draw)->type_name) def = ((PetscObject)draw)->type_name;
355   else {
356     ierr = PetscOptionsHasName(NULL,"-nox",&nox);CHKERRQ(ierr);
357     def  = PETSC_DRAW_NULL;
358 #if defined(PETSC_USE_WINDOWS_GRAPHICS)
359     if (!nox) def = PETSC_DRAW_WIN32;
360 #elif defined(PETSC_HAVE_X)
361     if (!nox) def = PETSC_DRAW_X;
362 #elif defined(PETSC_HAVE_GLUT)
363     if (!nox) def = PETSC_DRAW_GLUT;
364 #elif defined(PETSC_HAVE_OPENGLES)
365     if (!nox) def = PETSC_DRAW_OPENGLES;
366 #else
367     ierr = PetscOptionsHasName(NULL,"-nox_warning",&warn);CHKERRQ(ierr);
368     if (!nox && !warn) (*PetscErrorPrintf)("PETSc installed without X windows, Microsoft Graphics, OpenGL ES, or GLUT/OpenGL on this machine\nproceeding without graphics\n");
369 #endif
370   }
371   ierr = PetscObjectOptionsBegin((PetscObject)draw);CHKERRQ(ierr);
372   ierr = PetscOptionsFList("-draw_type","Type of graphical output","PetscDrawSetType",PetscDrawList,def,vtype,256,&flg);CHKERRQ(ierr);
373   if (flg) {
374     ierr = PetscDrawSetType(draw,vtype);CHKERRQ(ierr);
375   } else if (!((PetscObject)draw)->type_name) {
376     ierr = PetscDrawSetType(draw,def);CHKERRQ(ierr);
377   }
378   ierr = PetscOptionsName("-nox","Run without graphics","None",&nox);CHKERRQ(ierr);
379 #if defined(PETSC_HAVE_X)
380   {
381     char      filename[PETSC_MAX_PATH_LEN];
382     PetscBool save,movie = PETSC_FALSE;
383     ierr = PetscOptionsBool("-draw_save_movie","Make a movie from the images saved (X Windows only)","PetscDrawSetSave",movie,&movie,NULL);CHKERRQ(ierr);
384     ierr = PetscOptionsBool("-draw_save_single_file","Each new image replaces previous image in file","PetscDrawSetSave",draw->savesinglefile,&draw->savesinglefile,NULL);CHKERRQ(ierr);
385     ierr = PetscOptionsString("-draw_save","Save graphics to file (X Windows only)","PetscDrawSetSave",filename,filename,PETSC_MAX_PATH_LEN,&save);CHKERRQ(ierr);
386     if (save) {
387       ierr = PetscDrawSetSave(draw,filename,movie);CHKERRQ(ierr);
388     }
389     ierr = PetscOptionsString("-draw_save_final_image","Save graphics to file (X Windows only)","PetscDrawSetSaveFinalImage",filename,filename,PETSC_MAX_PATH_LEN,&save);CHKERRQ(ierr);
390     if (save) {
391       ierr = PetscDrawSetSaveFinalImage(draw,filename);CHKERRQ(ierr);
392     }
393     ierr = PetscOptionsBool("-draw_save_on_flush","Save graphics to file (X Windows only) on each flush","PetscDrawSetSave",draw->saveonflush,&draw->saveonflush,NULL);CHKERRQ(ierr);
394   }
395 #endif
396   ierr = PetscOptionsGetReal(NULL,"-draw_pause",&dpause,&flg);CHKERRQ(ierr);
397   if (flg) draw->pause = dpause;
398 
399   ierr = PetscOptionsEnum("-draw_marker_type","Type of marker to use on plots","PetscDrawSetMarkerType",PetscDrawMarkerTypes,(PetscEnum)draw->markertype,(PetscEnum *)&draw->markertype,NULL);CHKERRQ(ierr);
400 
401   /* process any options handlers added with PetscObjectAddOptionsHandler() */
402   ierr = PetscObjectProcessOptionsHandlers((PetscObject)draw);CHKERRQ(ierr);
403 
404   ierr = PetscDrawViewFromOptions(draw,NULL,"-draw_view");CHKERRQ(ierr);
405   ierr = PetscOptionsEnd();CHKERRQ(ierr);
406   PetscFunctionReturn(0);
407 }
408 
409 #undef __FUNCT__
410 #define __FUNCT__ "PetscDrawSetSave"
411 /*@C
412    PetscDrawSetSave - Saves images produced in a PetscDraw into a file as a Gif file using AfterImage
413 
414    Collective on PetscDraw
415 
416    Input Parameter:
417 +  draw      - the graphics context
418 .  filename  - name of the file, if .ext then uses name of draw object plus .ext using .ext to determine the image type, if NULL use .Gif image type
419 -  movie - produce a movie of all the images
420 
421    Options Database Command:
422 +  -draw_save  <filename> - filename could be name.ext or .ext (where .ext determines the type of graphics file to save, for example .Gif)
423 .  -draw_save_movie
424 .  -draw_save_final_image [optional filename] - (X windows only) saves the final image displayed in a window
425 .  -draw_save_on_flush - saves an image on each flush in addition to each clear
426 -  -draw_save_single_file - saves each new image in the same file, normally each new image is saved in a new file with filename_%d
427 
428    Level: intermediate
429 
430    Concepts: X windows^graphics
431 
432    Notes: You should call this BEFORE calling PetscDrawClear() and creating your image.
433 
434    Requires that PETSc be configured with the option --with-afterimage to save the images and ffmpeg must be in your path to make the movie
435 
436    The .ext formats that are supported depend on what formats AfterImage was configured with; on the Apple Mac both .Gif and .Jpeg are supported.
437 
438    If X windows generates an error message about X_CreateWindow() failing then Afterimage was installed without X windows. Reinstall Afterimage using the
439    ./configure flags --x-includes=/pathtoXincludes --x-libraries=/pathtoXlibraries   For example under Mac OS X Mountain Lion --x-includes=/opt/X11/include -x-libraries=/opt/X11/lib
440 
441 
442 .seealso: PetscDrawSetFromOptions(), PetscDrawCreate(), PetscDrawDestroy(), PetscDrawSetSaveFinalImage()
443 @*/
444 PetscErrorCode  PetscDrawSetSave(PetscDraw draw,const char *filename,PetscBool movie)
445 {
446   PetscErrorCode ierr;
447   char           *ext;
448 
449   PetscFunctionBegin;
450   PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1);
451   ierr = PetscFree(draw->savefilename);CHKERRQ(ierr);
452 
453   /* determine extension of filename */
454   if (filename && filename[0]) {
455     ierr = PetscStrchr(filename,'.',&ext);CHKERRQ(ierr);
456     if (!ext) SETERRQ1(PetscObjectComm((PetscObject)draw),PETSC_ERR_ARG_INCOMP,"Filename %s should end with graphics extension (for example .Gif)",filename);
457   } else {
458     ext = (char *)".Gif";
459   }
460   if (ext == filename) filename = NULL;
461   ierr = PetscStrallocpy(ext,&draw->savefilenameext);CHKERRQ(ierr);
462 
463   draw->savefilemovie = movie;
464   if (filename && filename[0]) {
465     size_t  l1,l2;
466     ierr = PetscStrlen(filename,&l1);CHKERRQ(ierr);
467     ierr = PetscStrlen(ext,&l2);CHKERRQ(ierr);
468     ierr = PetscMalloc1(l1-l2+1,&draw->savefilename);CHKERRQ(ierr);
469     ierr = PetscStrncpy(draw->savefilename,filename,l1-l2+1);CHKERRQ(ierr);
470   } else {
471     const char *name;
472 
473     ierr = PetscObjectGetName((PetscObject)draw,&name);CHKERRQ(ierr);
474     ierr = PetscStrallocpy(name,&draw->savefilename);CHKERRQ(ierr);
475   }
476   ierr = PetscInfo2(NULL,"Will save images to file %s%s\n",draw->savefilename,draw->savefilenameext);CHKERRQ(ierr);
477   if (draw->ops->setsave) {
478     ierr = (*draw->ops->setsave)(draw,draw->savefilename);CHKERRQ(ierr);
479   }
480   PetscFunctionReturn(0);
481 }
482 
483 #undef __FUNCT__
484 #define __FUNCT__ "PetscDrawSetSaveFinalImage"
485 /*@C
486    PetscDrawSetSaveFinalImage - Saves the finale image produced in a PetscDraw into a file as a Gif file using AfterImage
487 
488    Collective on PetscDraw
489 
490    Input Parameter:
491 +  draw      - the graphics context
492 -  filename  - name of the file, if NULL uses name of draw object
493 
494    Options Database Command:
495 .  -draw_save_final_image  <filename>
496 
497    Level: intermediate
498 
499    Concepts: X windows^graphics
500 
501    Notes: You should call this BEFORE calling PetscDrawClear() and creating your image.
502 
503    Requires that PETSc be configured with the option --with-afterimage to save the images and ffmpeg must be in your path to make the movie
504 
505    If X windows generates an error message about X_CreateWindow() failing then Afterimage was installed without X windows. Reinstall Afterimage using the
506    ./configure flags --x-includes=/pathtoXincludes --x-libraries=/pathtoXlibraries   For example under Mac OS X Mountain Lion --x-includes=/opt/X11/include -x-libraries=/opt/X11/lib
507 
508 
509 .seealso: PetscDrawSetFromOptions(), PetscDrawCreate(), PetscDrawDestroy(), PetscDrawSetSave()
510 @*/
511 PetscErrorCode  PetscDrawSetSaveFinalImage(PetscDraw draw,const char *filename)
512 {
513   PetscErrorCode ierr;
514 
515   PetscFunctionBegin;
516   PetscValidHeaderSpecific(draw,PETSC_DRAW_CLASSID,1);
517   ierr = PetscFree(draw->savefinalfilename);CHKERRQ(ierr);
518 
519   if (filename && filename[0]) {
520     ierr = PetscStrallocpy(filename,&draw->savefinalfilename);CHKERRQ(ierr);
521   } else {
522     const char *name;
523     ierr = PetscObjectGetName((PetscObject)draw,&name);CHKERRQ(ierr);
524     ierr = PetscStrallocpy(name,&draw->savefinalfilename);CHKERRQ(ierr);
525   }
526   PetscFunctionReturn(0);
527 }
528