xref: /petsc/src/sys/classes/viewer/impls/glvis/glvis.c (revision 276c5506312304d9c58828fa177e3f5c76c17b23)
1 #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for fdopen */
2 
3 #include <petsc/private/viewerimpl.h> /*I   "petscviewer.h" I*/
4 #include <petsc/private/petscimpl.h>  /*I   "petscsys.h"    I*/
5 #include <petsc/private/glvisviewerimpl.h>
6 
7 /* we may eventually make this function public */
8 static PetscErrorCode PetscViewerASCIISocketOpen(MPI_Comm,const char*,PetscInt,PetscViewer*);
9 
10 struct _n_PetscViewerGLVis {
11   PetscViewerGLVisStatus status;
12   PetscViewerGLVisType   type;                                                  /* either PETSC_VIEWER_GLVIS_DUMP or PETSC_VIEWER_GLVIS_SOCKET */
13   char                   *name;                                                 /* prefix for filename, or hostname, depending on the type */
14   PetscInt               port;                                                  /* used just for the socket case */
15   PetscReal              pause;                                                 /* if positive, calls PetscSleep(pause) after each VecView_GLVis call */
16   PetscViewer            meshwindow;                                            /* used just by the ASCII dumping */
17   PetscObject            dm;                                                    /* DM as passed by PetscViewerGLVisSetDM_Private(): should contain discretization info */
18   PetscInt               nwindow;                                               /* number of windows/fields to be visualized */
19   PetscViewer            *window;
20   char                   **windowtitle;
21   char                   **fec_type;                                            /* type of elements to be used for visualization, see FiniteElementCollection::Name() */
22   PetscErrorCode         (*g2lfield)(PetscObject,PetscInt,PetscObject[],void*); /* global to local operation for generating dofs to be visualized */
23   PetscInt               *spacedim;                                             /* geometrical space dimension (just used to initialize the scene) */
24   PetscObject            *Ufield;                                               /* work vectors for visualization */
25   PetscInt               snapid;                                                /* snapshot id, use PetscViewerGLVisSetSnapId to change this value*/
26   void                   *userctx;                                              /* User context, used by g2lfield */
27   PetscErrorCode         (*destroyctx)(void*);                                  /* destroy routine for userctx */
28   char*                  fmt;                                                   /* format string for FP values */
29 };
30 typedef struct _n_PetscViewerGLVis *PetscViewerGLVis;
31 
32 /*@
33      PetscViewerGLVisSetPrecision - Set the number of digits for floating point values
34 
35   Not Collective
36 
37   Input Parameters:
38 +  viewer - the PetscViewer
39 -  prec   - the number of digits required
40 
41   Level: beginner
42 
43 .seealso: PetscViewerGLVisOpen(), PetscViewerGLVisSetFields(), PetscViewerCreate(), PetscViewerSetType()
44 @*/
45 PetscErrorCode PetscViewerGLVisSetPrecision(PetscViewer viewer, PetscInt prec)
46 {
47   PetscErrorCode ierr;
48 
49   PetscFunctionBegin;
50   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
51   ierr = PetscTryMethod(viewer,"PetscViewerGLVisSetPrecision_C",(PetscViewer,PetscInt),(viewer,prec));CHKERRQ(ierr);
52   PetscFunctionReturn(0);
53 }
54 
55 static PetscErrorCode PetscViewerGLVisSetPrecision_GLVis(PetscViewer viewer, PetscInt prec)
56 {
57   PetscErrorCode   ierr;
58   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
59 
60   PetscFunctionBegin;
61   ierr = PetscFree(socket->fmt);CHKERRQ(ierr);
62   if (prec > 0) {
63     ierr = PetscMalloc1(16,&socket->fmt);CHKERRQ(ierr);
64     ierr = PetscSNPrintf(socket->fmt,16," %%.%De",prec);CHKERRQ(ierr);
65   } else {
66     ierr = PetscStrallocpy(" %g",&socket->fmt);CHKERRQ(ierr);
67   }
68   PetscFunctionReturn(0);
69 }
70 
71 /*@
72      PetscViewerGLVisSetSnapId - Set the snapshot id. Only relevant when the viewer is of type PETSC_VIEWER_GLVIS_DUMP
73 
74   Logically Collective on PetscViewer
75 
76   Input Parameters:
77 +  viewer - the PetscViewer
78 -  id     - the current snapshot id in a time-dependent simulation
79 
80   Level: beginner
81 
82 .seealso: PetscViewerGLVisOpen(), PetscViewerGLVisSetFields(), PetscViewerCreate(), PetscViewerSetType()
83 @*/
84 PetscErrorCode PetscViewerGLVisSetSnapId(PetscViewer viewer, PetscInt id)
85 {
86   PetscErrorCode ierr;
87 
88   PetscFunctionBegin;
89   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
90   PetscValidLogicalCollectiveInt(viewer,id,2);
91   ierr = PetscTryMethod(viewer,"PetscViewerGLVisSetSnapId_C",(PetscViewer,PetscInt),(viewer,id));CHKERRQ(ierr);
92   PetscFunctionReturn(0);
93 }
94 
95 static PetscErrorCode PetscViewerGLVisSetSnapId_GLVis(PetscViewer viewer, PetscInt id)
96 {
97   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
98 
99   PetscFunctionBegin;
100   socket->snapid = id;
101   PetscFunctionReturn(0);
102 }
103 
104 /*@C
105      PetscViewerGLVisSetFields - Sets the required information to visualize different fields from a vector.
106 
107   Logically Collective on PetscViewer
108 
109   Input Parameters:
110 +  viewer     - the PetscViewer
111 .  nf         - number of fields to be visualized
112 .  fec_type   - the type of finite element to be used to visualize the data (see FiniteElementCollection::Name() in MFEM)
113 .  dim        - array of space dimension for field vectors (used to initialize the scene)
114 .  g2lfields  - User routine to compute the local field vectors to be visualized; PetscObject is used in place of Vec on the prototype
115 .  Vfield     - array of work vectors, one for each field
116 .  ctx        - User context to store the relevant data to apply g2lfields
117 -  destroyctx - Destroy function for userctx
118 
119   Notes: g2lfields is called on the vector V to be visualized in order to extract the relevant dofs to be put in Vfield[], as
120 .vb
121   g2lfields((PetscObject)V,nfields,(PetscObject*)Vfield[],ctx).
122 .ve
123   For vector spaces, the block size of Vfield[i] represents the vector dimension. It misses the Fortran bindings.
124   PETSc will take ownership of the work vectors.
125   The names of the Vfield vectors will be displayed in the window title.
126 
127   Level: intermediate
128 
129 .seealso: PetscViewerGLVisOpen(), PetscViewerCreate(), PetscViewerSetType(), PetscObjectSetName()
130 @*/
131 PetscErrorCode PetscViewerGLVisSetFields(PetscViewer viewer, PetscInt nf, const char* fec_type[], PetscInt dim[], PetscErrorCode(*g2l)(PetscObject,PetscInt,PetscObject[],void*), PetscObject Vfield[], void* ctx, PetscErrorCode(*destroyctx)(void*))
132 {
133   PetscErrorCode ierr;
134 
135   PetscFunctionBegin;
136   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,1);
137   PetscValidLogicalCollectiveInt(viewer,nf,2);
138   if (!fec_type) SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"You need to provide the FiniteElementCollection names for the fields");
139   PetscValidPointer(fec_type,3);
140   PetscValidPointer(dim,4);
141   PetscValidPointer(Vfield,6);
142   ierr = PetscTryMethod(viewer,"PetscViewerGLVisSetFields_C",(PetscViewer,PetscInt,const char*[],PetscInt[],PetscErrorCode(*)(PetscObject,PetscInt,PetscObject[],void*),PetscObject[],void*,PetscErrorCode(*)(void*)),(viewer,nf,fec_type,dim,g2l,Vfield,ctx,destroyctx));CHKERRQ(ierr);
143   PetscFunctionReturn(0);
144 }
145 
146 static PetscErrorCode PetscViewerGLVisSetFields_GLVis(PetscViewer viewer, PetscInt nfields, const char* fec_type[], PetscInt dim[], PetscErrorCode(*g2l)(PetscObject,PetscInt,PetscObject[],void*), PetscObject Vfield[], void* ctx, PetscErrorCode(*destroyctx)(void*))
147 {
148   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
149   PetscInt         i;
150   PetscErrorCode   ierr;
151 
152   PetscFunctionBegin;
153   if (socket->nwindow && socket->nwindow != nfields) SETERRQ2(PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Cannot set number of fields %D with number of windows %D",nfields,socket->nwindow);
154   if (!socket->nwindow) {
155     socket->nwindow = nfields;
156 
157     ierr = PetscCalloc5(nfields,&socket->window,nfields,&socket->windowtitle,nfields,&socket->fec_type,nfields,&socket->spacedim,nfields,&socket->Ufield);CHKERRQ(ierr);
158     for (i=0;i<nfields;i++) {
159       const char     *name;
160 
161       ierr = PetscObjectGetName(Vfield[i],&name);CHKERRQ(ierr);
162       ierr = PetscStrallocpy(name,&socket->windowtitle[i]);CHKERRQ(ierr);
163       ierr = PetscStrallocpy(fec_type[i],&socket->fec_type[i]);CHKERRQ(ierr);
164       ierr = PetscObjectReference(Vfield[i]);CHKERRQ(ierr);
165       socket->Ufield[i] = Vfield[i];
166       socket->spacedim[i] = dim[i];
167     }
168   }
169   /* number of fields are not allowed to vary */
170   if (nfields != socket->nwindow) SETERRQ2(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Cannot visualize %D fields using %D socket windows",nfields,socket->nwindow);
171   socket->g2lfield = g2l;
172   if (socket->destroyctx && socket->userctx) { ierr = (*socket->destroyctx)(socket->userctx);CHKERRQ(ierr); }
173   socket->userctx = ctx;
174   socket->destroyctx = destroyctx;
175   PetscFunctionReturn(0);
176 }
177 
178 static PetscErrorCode PetscViewerGLVisInfoDestroy_Private(void *ptr)
179 {
180   PetscViewerGLVisInfo info = (PetscViewerGLVisInfo)ptr;
181   PetscErrorCode       ierr;
182 
183   PetscFunctionBegin;
184   ierr = PetscFree(info->fmt);CHKERRQ(ierr);
185   ierr = PetscFree(info);CHKERRQ(ierr);
186   PetscFunctionReturn(0);
187 }
188 
189 /* we can decide to prevent specific processes from using the viewer */
190 static PetscErrorCode PetscViewerGLVisAttachInfo_Private(PetscViewer viewer, PetscViewer window)
191 {
192   PetscViewerGLVis     socket = (PetscViewerGLVis)viewer->data;
193   PetscErrorCode       ierr;
194   PetscContainer       container;
195   PetscViewerGLVisInfo info;
196 
197   PetscFunctionBegin;
198   ierr = PetscObjectQuery((PetscObject)window,"_glvis_info_container",(PetscObject*)&container);CHKERRQ(ierr);
199   if (!container) {
200     ierr = PetscNew(&info);CHKERRQ(ierr);
201     info->enabled = PETSC_TRUE;
202     info->init    = PETSC_FALSE;
203     info->pause   = socket->pause;
204     ierr = PetscContainerCreate(PetscObjectComm((PetscObject)window),&container);CHKERRQ(ierr);
205     ierr = PetscContainerSetPointer(container,(void*)info);CHKERRQ(ierr);
206     ierr = PetscContainerSetUserDestroy(container,PetscViewerGLVisInfoDestroy_Private);CHKERRQ(ierr);
207     ierr = PetscObjectCompose((PetscObject)window,"_glvis_info_container",(PetscObject)container);CHKERRQ(ierr);
208     ierr = PetscContainerDestroy(&container);CHKERRQ(ierr);
209   } else {
210     ierr = PetscContainerGetPointer(container,(void**)&info);CHKERRQ(ierr);
211   }
212   ierr = PetscFree(info->fmt);CHKERRQ(ierr);
213   ierr = PetscStrallocpy(socket->fmt,&info->fmt);CHKERRQ(ierr);
214   PetscFunctionReturn(0);
215 }
216 
217 static PetscErrorCode PetscViewerGLVisGetNewWindow_Private(PetscViewer viewer,PetscViewer *view)
218 {
219   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
220   PetscViewer      window = NULL;
221   PetscBool        ldis,dis;
222   PetscErrorCode   ierr;
223 
224   PetscFunctionBegin;
225   ierr = PetscViewerASCIISocketOpen(PETSC_COMM_SELF,socket->name,socket->port,&window);
226   /* if we could not estabilish a connection the first time,
227      we disable the socket viewer */
228   ldis = ierr ? PETSC_TRUE : PETSC_FALSE;
229   ierr = MPI_Allreduce(&ldis,&dis,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)viewer));CHKERRQ(ierr);
230   if (dis) {
231     socket->status = PETSCVIEWERGLVIS_DISABLED;
232     ierr  = PetscViewerDestroy(&window);CHKERRQ(ierr);
233   }
234   *view = window;
235   PetscFunctionReturn(0);
236 }
237 
238 PetscErrorCode PetscViewerGLVisPause_Private(PetscViewer viewer)
239 {
240   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
241   PetscErrorCode   ierr;
242 
243   PetscFunctionBegin;
244   if (socket->pause > 0) {
245     ierr = PetscSleep(socket->pause);CHKERRQ(ierr);
246   }
247   PetscFunctionReturn(0);
248 }
249 
250 /* DM specific support */
251 PetscErrorCode PetscViewerGLVisSetDM_Private(PetscViewer viewer, PetscObject dm)
252 {
253   PetscErrorCode   ierr;
254   PetscViewerGLVis socket  = (PetscViewerGLVis)viewer->data;
255 
256   PetscFunctionBegin;
257   if (socket->dm && socket->dm != dm) SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Cannot change DM associated with the GLVis viewer");
258   if (!socket->dm) {
259     PetscErrorCode (*setupwithdm)(PetscObject,PetscViewer) = NULL;
260 
261     ierr = PetscObjectQueryFunction(dm,"DMSetUpGLVisViewer_C",&setupwithdm);CHKERRQ(ierr);
262     if (setupwithdm) {
263       ierr = (*setupwithdm)(dm,viewer);CHKERRQ(ierr);
264     } else SETERRQ1(PetscObjectComm(dm),PETSC_ERR_SUP,"No support for DM type %s",dm->type_name);
265     ierr = PetscObjectReference(dm);CHKERRQ(ierr);
266     socket->dm = dm;
267   }
268   PetscFunctionReturn(0);
269 }
270 
271 PetscErrorCode PetscViewerGLVisGetDMWindow_Private(PetscViewer viewer,PetscViewer* view)
272 {
273   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
274   PetscErrorCode   ierr;
275 
276   PetscFunctionBegin;
277   if (!socket->meshwindow) {
278     if (socket->type == PETSC_VIEWER_GLVIS_SOCKET) {
279       ierr = PetscViewerGLVisGetNewWindow_Private(viewer,&socket->meshwindow);CHKERRQ(ierr);
280     } else {
281       PetscMPIInt rank;
282       char        filename[PETSC_MAX_PATH_LEN];
283 
284       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank);CHKERRQ(ierr);
285       ierr = PetscSNPrintf(filename,PETSC_MAX_PATH_LEN,"%s-mesh.%06d",socket->name,rank);CHKERRQ(ierr);
286       ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&socket->meshwindow);CHKERRQ(ierr);
287     }
288     if (socket->meshwindow) {
289       ierr = PetscViewerPushFormat(socket->meshwindow,PETSC_VIEWER_ASCII_GLVIS);CHKERRQ(ierr);
290     }
291   }
292   if (socket->meshwindow) {
293     ierr = PetscViewerGLVisAttachInfo_Private(viewer,socket->meshwindow);CHKERRQ(ierr);
294   }
295   *view = socket->meshwindow;
296   PetscFunctionReturn(0);
297 }
298 
299 PetscErrorCode PetscViewerGLVisGetType_Private(PetscViewer viewer,PetscViewerGLVisType *type)
300 {
301   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
302 
303   PetscFunctionBegin;
304   PetscValidPointer(type,2);
305   *type = socket->type;
306   PetscFunctionReturn(0);
307 }
308 
309 /* This function is only relevant in the SOCKET_GLIVS case. The status is computed the first time it is requested, as GLVis currently has issues when connecting the first time through the socket */
310 PetscErrorCode PetscViewerGLVisGetStatus_Private(PetscViewer viewer, PetscViewerGLVisStatus *sockstatus)
311 {
312   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
313 
314   PetscFunctionBegin;
315   PetscValidPointer(sockstatus,2);
316   if (socket->type == PETSC_VIEWER_GLVIS_DUMP) {
317     socket->status = PETSCVIEWERGLVIS_DISCONNECTED;
318   } else if (socket->status == PETSCVIEWERGLVIS_DISCONNECTED && socket->nwindow) {
319     PetscInt       i;
320     PetscBool      lconn,conn;
321     PetscErrorCode ierr;
322 
323     for (i=0,lconn=PETSC_TRUE;i<socket->nwindow;i++)
324       if (!socket->window[i])
325         lconn = PETSC_FALSE;
326 
327     ierr = MPI_Allreduce(&lconn,&conn,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)viewer));CHKERRQ(ierr);
328     if (conn) socket->status = PETSCVIEWERGLVIS_CONNECTED;
329   }
330   *sockstatus = socket->status;
331   PetscFunctionReturn(0);
332 }
333 
334 PetscErrorCode PetscViewerGLVisGetDM_Private(PetscViewer viewer, PetscObject* dm)
335 {
336   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
337 
338   PetscFunctionBegin;
339   *dm = socket->dm;
340   PetscFunctionReturn(0);
341 }
342 
343 PetscErrorCode PetscViewerGLVisGetFields_Private(PetscViewer viewer, PetscInt* nfield, const char **fec[], PetscInt *spacedim[], PetscErrorCode(**g2lfield)(PetscObject,PetscInt,PetscObject[],void*), PetscObject *Ufield[], void **userctx)
344 {
345   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
346 
347   PetscFunctionBegin;
348   if (nfield)   *nfield   = socket->nwindow;
349   if (fec)      *fec      = (const char**)socket->fec_type;
350   if (spacedim) *spacedim = socket->spacedim;
351   if (g2lfield) *g2lfield = socket->g2lfield;
352   if (Ufield)   *Ufield   = socket->Ufield;
353   if (userctx)  *userctx  = socket->userctx;
354   PetscFunctionReturn(0);
355 }
356 
357 /* accessor routines for the viewer windows:
358    PETSC_VIEWER_GLVIS_DUMP   : it returns a new viewer every time
359    PETSC_VIEWER_GLVIS_SOCKET : it returns the socket, and creates it if not yet done.
360 */
361 PetscErrorCode PetscViewerGLVisGetWindow_Private(PetscViewer viewer,PetscInt wid,PetscViewer* view)
362 {
363   PetscViewerGLVis       socket = (PetscViewerGLVis)viewer->data;
364   PetscViewerGLVisStatus status;
365   PetscErrorCode         ierr;
366 
367   PetscFunctionBegin;
368   PetscValidLogicalCollectiveInt(viewer,wid,2);
369   PetscValidPointer(view,3);
370   if (wid < 0 || wid > socket->nwindow-1) SETERRQ2(PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Cannot get window id %D: allowed range [0,%D)",wid,socket->nwindow-1);
371   status = socket->status;
372   if (socket->type == PETSC_VIEWER_GLVIS_DUMP && socket->window[wid]) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Window %D is already in use",wid);
373   switch (status) {
374     case PETSCVIEWERGLVIS_DISCONNECTED:
375       if (socket->window[wid]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"This should not happen");
376       if (socket->type == PETSC_VIEWER_GLVIS_DUMP) {
377         PetscMPIInt rank;
378         char        filename[PETSC_MAX_PATH_LEN];
379 
380         ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank);CHKERRQ(ierr);
381         ierr = PetscSNPrintf(filename,PETSC_MAX_PATH_LEN,"%s-%s-%d.%06d",socket->name,socket->windowtitle[wid],socket->snapid,rank);CHKERRQ(ierr);
382         ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&socket->window[wid]);CHKERRQ(ierr);
383       } else {
384         ierr = PetscViewerGLVisGetNewWindow_Private(viewer,&socket->window[wid]);CHKERRQ(ierr);
385       }
386       if (socket->window[wid]) {
387         ierr = PetscViewerPushFormat(socket->window[wid],PETSC_VIEWER_ASCII_GLVIS);CHKERRQ(ierr);
388       }
389       *view = socket->window[wid];
390       break;
391     case PETSCVIEWERGLVIS_CONNECTED:
392       *view = socket->window[wid];
393       break;
394     case PETSCVIEWERGLVIS_DISABLED:
395       *view = NULL;
396       break;
397     default:
398       SETERRQ1(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Unhandled socket status %d\n",(int)status);
399       break;
400   }
401   if (*view) {
402     ierr = PetscViewerGLVisAttachInfo_Private(viewer,*view);CHKERRQ(ierr);
403   }
404   PetscFunctionReturn(0);
405 }
406 
407 /* Restore the window viewer
408    PETSC_VIEWER_GLVIS_DUMP  : destroys the temporary created ASCII viewer used for dumping
409    PETSC_VIEWER_GLVIS_SOCKET: - if the returned window viewer is not NULL, just zeros the pointer.
410                  - it the returned window viewer is NULL, assumes something went wrong
411                    with the socket (i.e. SIGPIPE when a user closes the popup window)
412                    and that the caller already handled it (see VecView_GLVis).
413 */
414 PetscErrorCode PetscViewerGLVisRestoreWindow_Private(PetscViewer viewer,PetscInt wid, PetscViewer* view)
415 {
416   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
417   PetscErrorCode   ierr;
418 
419   PetscFunctionBegin;
420   PetscValidLogicalCollectiveInt(viewer,wid,2);
421   PetscValidPointer(view,3);
422   if (wid < 0 || wid > socket->nwindow-1) SETERRQ2(PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Cannot restore window id %D: allowed range [0,%D)",wid,socket->nwindow);
423   if (*view && *view != socket->window[wid]) SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Viewer was not obtained from PetscViewerGLVisGetWindow");
424   if (*view) {
425     ierr = PetscViewerFlush(*view);CHKERRQ(ierr);
426     ierr = PetscBarrier((PetscObject)viewer);CHKERRQ(ierr);
427   }
428   if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { /* destroy the viewer, as it is associated with a single time step */
429     ierr = PetscViewerDestroy(&socket->window[wid]);CHKERRQ(ierr);
430   } else if (!*view) { /* something went wrong (SIGPIPE) so we just zero the private pointer */
431     socket->window[wid] = NULL;
432   }
433   *view = NULL;
434   PetscFunctionReturn(0);
435 }
436 
437 /* default window appearance in the PETSC_VIEWER_GLVIS_SOCKET case */
438 PetscErrorCode PetscViewerGLVisInitWindow_Private(PetscViewer viewer, PetscBool mesh, PetscInt dim, const char *name)
439 {
440   PetscErrorCode       ierr;
441   PetscViewerGLVisInfo info;
442   PetscContainer       container;
443 
444   PetscFunctionBegin;
445   ierr = PetscObjectQuery((PetscObject)viewer,"_glvis_info_container",(PetscObject*)&container);CHKERRQ(ierr);
446   if (!container) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Viewer was not obtained from PetscGLVisViewerGetNewWindow_Private");
447   ierr = PetscContainerGetPointer(container,(void**)&info);CHKERRQ(ierr);
448   if (info->init) {
449     if (info->pause < 0) {
450       ierr = PetscViewerASCIIPrintf(viewer,"pause\n");CHKERRQ(ierr); /* pause */
451     }
452     PetscFunctionReturn(0);
453   }
454   ierr = PetscViewerASCIIPrintf(viewer,"window_size 800 800\n");CHKERRQ(ierr);
455   if (name) {
456     ierr = PetscViewerASCIIPrintf(viewer,"window_title '%s'\n",name);CHKERRQ(ierr);
457   }
458   if (mesh) {
459     switch (dim) {
460     case 1:
461       break;
462     case 2:
463       ierr = PetscViewerASCIIPrintf(viewer,"keys cmeeppppp\n");CHKERRQ(ierr); /* show colorbar, mesh and ranks */
464       break;
465     case 3: /* TODO: decide default view in 3D */
466       break;
467     }
468   } else {
469     ierr = PetscViewerASCIIPrintf(viewer,"keys cm\n");CHKERRQ(ierr); /* show colorbar and mesh */
470     switch (dim) {
471     case 1:
472       ierr = PetscViewerASCIIPrintf(viewer,"keys RRj\n");CHKERRQ(ierr); /* set to 1D (side view) and turn off perspective */
473       break;
474     case 2:
475       ierr = PetscViewerASCIIPrintf(viewer,"keys Rjl\n");CHKERRQ(ierr); /* set to 2D (top view), turn off perspective and light */
476       break;
477     case 3:
478       break;
479     }
480     ierr = PetscViewerASCIIPrintf(viewer,"autoscale value\n");CHKERRQ(ierr); /* update value-range; keep mesh-extents fixed */
481     if (info->pause == 0) {
482       ierr = PetscViewerASCIIPrintf(viewer,"pause\n");CHKERRQ(ierr); /* pause */
483     }
484   }
485   info->init = PETSC_TRUE;
486   PetscFunctionReturn(0);
487 }
488 
489 static PetscErrorCode PetscViewerDestroy_GLVis(PetscViewer viewer)
490 {
491   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
492   PetscInt         i;
493   PetscErrorCode   ierr;
494 
495   PetscFunctionBegin;
496   for (i=0;i<socket->nwindow;i++) {
497     ierr = PetscViewerDestroy(&socket->window[i]);CHKERRQ(ierr);
498     ierr = PetscFree(socket->windowtitle[i]);CHKERRQ(ierr);
499     ierr = PetscFree(socket->fec_type[i]);CHKERRQ(ierr);
500     ierr = PetscObjectDestroy(&socket->Ufield[i]);CHKERRQ(ierr);
501   }
502   ierr = PetscFree(socket->name);CHKERRQ(ierr);
503   ierr = PetscFree5(socket->window,socket->windowtitle,socket->fec_type,socket->spacedim,socket->Ufield);CHKERRQ(ierr);
504   ierr = PetscFree(socket->fmt);CHKERRQ(ierr);
505   ierr = PetscViewerDestroy(&socket->meshwindow);CHKERRQ(ierr);
506   ierr = PetscObjectDestroy(&socket->dm);CHKERRQ(ierr);
507   if (socket->destroyctx && socket->userctx) { ierr = (*socket->destroyctx)(socket->userctx);CHKERRQ(ierr); }
508 
509   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetPrecision_C",NULL);CHKERRQ(ierr);
510   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetSnapId_C",NULL);CHKERRQ(ierr);
511   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetFields_C",NULL);CHKERRQ(ierr);
512   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",NULL);CHKERRQ(ierr);
513   ierr = PetscFree(socket);CHKERRQ(ierr);
514   viewer->data = NULL;
515   PetscFunctionReturn(0);
516 }
517 
518 static PetscErrorCode PetscViewerSetFromOptions_GLVis(PetscOptionItems *PetscOptionsObject,PetscViewer v)
519 {
520   PetscErrorCode   ierr;
521   PetscViewerGLVis socket = (PetscViewerGLVis)v->data;
522 
523   PetscFunctionBegin;
524   ierr = PetscOptionsHead(PetscOptionsObject,"GLVis PetscViewer Options");CHKERRQ(ierr);
525   ierr = PetscOptionsReal("-viewer_glvis_pause","-1 to pause after each visualization, otherwise sleeps for given seconds",NULL,socket->pause,&socket->pause,NULL);CHKERRQ(ierr);
526   ierr = PetscOptionsTail();CHKERRQ(ierr);
527   PetscFunctionReturn(0);
528 }
529 
530 static PetscErrorCode PetscViewerSetFileName_GLVis(PetscViewer viewer, const char name[])
531 {
532   char             *sport;
533   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
534   PetscErrorCode   ierr;
535 
536   PetscFunctionBegin;
537   socket->type = PETSC_VIEWER_GLVIS_DUMP;
538   /* we accept localhost^port */
539   ierr = PetscFree(socket->name);CHKERRQ(ierr);
540   ierr = PetscStrallocpy(name,&socket->name);CHKERRQ(ierr);
541   ierr = PetscStrchr(socket->name,'^',&sport);CHKERRQ(ierr);
542   if (sport) {
543     PetscInt port = 19916;
544     size_t   len;
545 
546     *sport++ = 0;
547     ierr = PetscStrlen(sport,&len);CHKERRQ(ierr);
548     if (len) ierr = PetscOptionsStringToInt(sport,&port);
549     if (!ierr) {
550       socket->port = (port != PETSC_DECIDE && port != PETSC_DEFAULT) ? port : 19916;
551     } else {
552       socket->port = 19916;
553     }
554     socket->type = PETSC_VIEWER_GLVIS_SOCKET;
555   }
556   PetscFunctionReturn(0);
557 }
558 
559 /*
560      PetscViewerGLVisOpen - Opens a GLVis type viewer
561 
562   Collective on comm
563 
564   Input Parameters:
565 +  comm      - the MPI communicator
566 .  type      - the viewer type: PETSC_VIEWER_GLVIS_SOCKET for real-time visualization or PETSC_VIEWER_GLVIS_DUMP for dumping to disk
567 .  name      - either the hostname where the GLVis server is running or the base filename for dumping the data for subsequent visualizations
568 -  port      - socket port where the GLVis server is listening. Not referenced when type is PETSC_VIEWER_GLVIS_DUMP
569 
570   Output Parameters:
571 -  viewer    - the PetscViewer object
572 
573   Notes: misses Fortran binding
574 
575   Level: beginner
576 
577 .seealso: PetscViewerCreate(), PetscViewerSetType(), PetscViewerGLVisType
578 */
579 PETSC_EXTERN PetscErrorCode PetscViewerGLVisOpen(MPI_Comm comm, PetscViewerGLVisType type, const char* name, PetscInt port, PetscViewer* viewer)
580 {
581   PetscViewerGLVis socket;
582   PetscErrorCode   ierr;
583 
584   PetscFunctionBegin;
585   ierr = PetscViewerCreate(comm,viewer);CHKERRQ(ierr);
586   ierr = PetscViewerSetType(*viewer,PETSCVIEWERGLVIS);CHKERRQ(ierr);
587 
588   socket       = (PetscViewerGLVis)((*viewer)->data);
589   ierr         = PetscFree(socket->name);CHKERRQ(ierr);
590   ierr         = PetscStrallocpy(name,&socket->name);CHKERRQ(ierr);
591   socket->type = type;
592   socket->port = port;
593 
594   ierr = PetscViewerSetFromOptions(*viewer);CHKERRQ(ierr);
595   PetscFunctionReturn(0);
596 }
597 
598 /*
599   PETSC_VIEWER_GLVIS_ - Creates an GLVIS PetscViewer shared by all processors in a communicator.
600 
601   Collective on MPI_Comm
602 
603   Input Parameter:
604 . comm - the MPI communicator to share the GLVIS PetscViewer
605 
606   Level: intermediate
607 
608   Notes: misses Fortran bindings
609 
610   Environmental variables:
611 + PETSC_VIEWER_GLVIS_FILENAME : output filename (if specified dump to disk, and takes precedence on PETSC_VIEWER_GLVIS_HOSTNAME)
612 . PETSC_VIEWER_GLVIS_HOSTNAME : machine where the GLVis server is listening (defaults to localhost)
613 - PETSC_VIEWER_GLVIS_PORT     : port opened by the GLVis server (defaults to 19916)
614 
615   Notes:
616   Unlike almost all other PETSc routines, PETSC_VIEWER_GLVIS_ does not return
617   an error code.  The GLVIS PetscViewer is usually used in the form
618 $       XXXView(XXX object, PETSC_VIEWER_GLVIS_(comm));
619 
620 .seealso: PetscViewerGLVISOpen(), PetscViewerGLVisType, PetscViewerCreate(), PetscViewerDestroy()
621 */
622 PETSC_EXTERN PetscViewer PETSC_VIEWER_GLVIS_(MPI_Comm comm)
623 {
624   PetscErrorCode       ierr;
625   PetscBool            flg;
626   PetscViewer          viewer;
627   PetscViewerGLVisType type;
628   char                 fname[PETSC_MAX_PATH_LEN],sport[16];
629   PetscInt             port = 19916; /* default for GLVis */
630 
631   PetscFunctionBegin;
632   ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg);
633   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
634   if (!flg) {
635     type = PETSC_VIEWER_GLVIS_SOCKET;
636     ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_HOSTNAME",fname,PETSC_MAX_PATH_LEN,&flg);
637     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
638     if (!flg) {
639       ierr = PetscStrcpy(fname,"localhost");
640       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
641     }
642     ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_PORT",sport,16,&flg);
643     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
644     if (flg) {
645       ierr = PetscOptionsStringToInt(sport,&port);
646       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
647     }
648   } else {
649     type = PETSC_VIEWER_GLVIS_DUMP;
650   }
651   ierr = PetscViewerGLVisOpen(comm,type,fname,port,&viewer);
652   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
653   ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
654   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
655   PetscFunctionReturn(viewer);
656 }
657 
658 PETSC_EXTERN PetscErrorCode PetscViewerCreate_GLVis(PetscViewer viewer)
659 {
660   PetscViewerGLVis socket;
661   PetscErrorCode   ierr;
662 
663   PetscFunctionBegin;
664   ierr = PetscNewLog(viewer,&socket);CHKERRQ(ierr);
665 
666   /* defaults to socket viewer */
667   ierr = PetscStrallocpy("localhost",&socket->name);CHKERRQ(ierr);
668   socket->port  = 19916; /* GLVis default listening port */
669   socket->type  = PETSC_VIEWER_GLVIS_SOCKET;
670   socket->pause = 0; /* just pause the first time */
671 
672   /* defaults to full precision */
673   ierr = PetscStrallocpy(" %g",&socket->fmt);CHKERRQ(ierr);
674 
675   viewer->data                = (void*)socket;
676   viewer->ops->destroy        = PetscViewerDestroy_GLVis;
677   viewer->ops->setfromoptions = PetscViewerSetFromOptions_GLVis;
678 
679   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetPrecision_C",PetscViewerGLVisSetPrecision_GLVis);CHKERRQ(ierr);
680   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetSnapId_C",PetscViewerGLVisSetSnapId_GLVis);CHKERRQ(ierr);
681   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetFields_C",PetscViewerGLVisSetFields_GLVis);CHKERRQ(ierr);
682   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",PetscViewerSetFileName_GLVis);CHKERRQ(ierr);
683   PetscFunctionReturn(0);
684 }
685 
686 /* this is a private implementation of a SOCKET with ASCII data format
687    GLVis does not currently handle binary socket streams */
688 #if defined(PETSC_HAVE_UNISTD_H)
689 #include <unistd.h>
690 #endif
691 
692 #if !defined(PETSC_HAVE_WINDOWS_H)
693 static PetscErrorCode (*PetscViewerDestroy_ASCII)(PetscViewer);
694 
695 static PetscErrorCode PetscViewerDestroy_ASCII_Socket(PetscViewer viewer)
696 {
697   FILE *stream;
698   PetscErrorCode ierr = 0;
699   PetscFunctionBegin;
700   ierr = PetscViewerASCIIGetPointer(viewer,&stream);CHKERRQ(ierr);
701   if (stream) {
702     ierr = fclose(stream);
703     if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on stream");
704   }
705   ierr = PetscViewerDestroy_ASCII(viewer);CHKERRQ(ierr);
706   PetscFunctionReturn(0);
707 }
708 #endif
709 
710 static PetscErrorCode PetscViewerASCIISocketOpen(MPI_Comm comm,const char* hostname,PetscInt port,PetscViewer* viewer)
711 {
712 #if defined(PETSC_HAVE_WINDOWS_H)
713   PetscFunctionBegin;
714   SETERRQ(comm,PETSC_ERR_SUP,"Not implemented for Windows");
715 #else
716   FILE           *stream = NULL;
717   int            fd;
718   PetscErrorCode ierr;
719 
720   PetscFunctionBegin;
721   PetscValidPointer(hostname,2);
722   PetscValidPointer(viewer,4);
723 #if defined(PETSC_USE_SOCKET_VIEWER)
724   ierr = PetscOpenSocket(hostname,port,&fd);
725 #else
726   SETERRQ(comm,PETSC_ERR_SUP,"Missing Socket viewer");
727 #endif
728   if (ierr) {
729     PetscInt sierr = ierr;
730     char     err[1024];
731 
732     ierr    = PetscSNPrintf(err,1024,"Cannot connect to socket on %s:%D. Socket visualization is disabled\n",hostname,port);CHKERRQ(ierr);
733     ierr    = PetscInfo(NULL,err);CHKERRQ(ierr);
734     *viewer = NULL;
735     PetscFunctionReturn(sierr);
736   } else {
737     char msg[1024];
738 
739     ierr = PetscSNPrintf(msg,1024,"Successfully connect to socket on %s:%D. Socket visualization is enabled\n",hostname,port);CHKERRQ(ierr);
740     ierr = PetscInfo(NULL,msg);CHKERRQ(ierr);
741   }
742   stream = fdopen(fd,"w"); /* Not possible on Windows */
743   if (!stream) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Cannot open stream from socket %s:%d",hostname,port);
744   ierr = PetscViewerASCIIOpenWithFILE(PETSC_COMM_SELF,stream,viewer);CHKERRQ(ierr);
745   PetscViewerDestroy_ASCII = (*viewer)->ops->destroy;
746   (*viewer)->ops->destroy = PetscViewerDestroy_ASCII_Socket;
747 #endif
748   PetscFunctionReturn(0);
749 }
750