xref: /petsc/src/sys/classes/viewer/impls/glvis/glvis.c (revision 4e22ec7992ea0a5a8658409cbeedb7110d765e7d)
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       size_t    len;
282       PetscBool isstdout;
283 
284       ierr = PetscStrlen(socket->name,&len);CHKERRQ(ierr);
285       ierr = PetscStrcmp(socket->name,"stdout",&isstdout);CHKERRQ(ierr);
286       if (!socket->name || !len || isstdout) {
287         ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,"stdout",&socket->meshwindow);CHKERRQ(ierr);
288       } else {
289         PetscMPIInt rank;
290         char        filename[PETSC_MAX_PATH_LEN];
291         ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank);CHKERRQ(ierr);
292         ierr = PetscSNPrintf(filename,PETSC_MAX_PATH_LEN,"%s-mesh.%06d",socket->name,rank);CHKERRQ(ierr);
293         ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&socket->meshwindow);CHKERRQ(ierr);
294       }
295     }
296     if (socket->meshwindow) {
297       ierr = PetscViewerPushFormat(socket->meshwindow,PETSC_VIEWER_ASCII_GLVIS);CHKERRQ(ierr);
298     }
299   }
300   if (socket->meshwindow) {
301     ierr = PetscViewerGLVisAttachInfo_Private(viewer,socket->meshwindow);CHKERRQ(ierr);
302   }
303   *view = socket->meshwindow;
304   PetscFunctionReturn(0);
305 }
306 
307 PetscErrorCode PetscViewerGLVisGetType_Private(PetscViewer viewer,PetscViewerGLVisType *type)
308 {
309   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
310 
311   PetscFunctionBegin;
312   PetscValidPointer(type,2);
313   *type = socket->type;
314   PetscFunctionReturn(0);
315 }
316 
317 /* 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 */
318 PetscErrorCode PetscViewerGLVisGetStatus_Private(PetscViewer viewer, PetscViewerGLVisStatus *sockstatus)
319 {
320   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
321 
322   PetscFunctionBegin;
323   PetscValidPointer(sockstatus,2);
324   if (socket->type == PETSC_VIEWER_GLVIS_DUMP) {
325     socket->status = PETSCVIEWERGLVIS_DISCONNECTED;
326   } else if (socket->status == PETSCVIEWERGLVIS_DISCONNECTED && socket->nwindow) {
327     PetscInt       i;
328     PetscBool      lconn,conn;
329     PetscErrorCode ierr;
330 
331     for (i=0,lconn=PETSC_TRUE;i<socket->nwindow;i++)
332       if (!socket->window[i])
333         lconn = PETSC_FALSE;
334 
335     ierr = MPI_Allreduce(&lconn,&conn,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)viewer));CHKERRQ(ierr);
336     if (conn) socket->status = PETSCVIEWERGLVIS_CONNECTED;
337   }
338   *sockstatus = socket->status;
339   PetscFunctionReturn(0);
340 }
341 
342 PetscErrorCode PetscViewerGLVisGetDM_Private(PetscViewer viewer, PetscObject* dm)
343 {
344   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
345 
346   PetscFunctionBegin;
347   *dm = socket->dm;
348   PetscFunctionReturn(0);
349 }
350 
351 PetscErrorCode PetscViewerGLVisGetFields_Private(PetscViewer viewer, PetscInt* nfield, const char **fec[], PetscInt *spacedim[], PetscErrorCode(**g2lfield)(PetscObject,PetscInt,PetscObject[],void*), PetscObject *Ufield[], void **userctx)
352 {
353   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
354 
355   PetscFunctionBegin;
356   if (nfield)   *nfield   = socket->nwindow;
357   if (fec)      *fec      = (const char**)socket->fec_type;
358   if (spacedim) *spacedim = socket->spacedim;
359   if (g2lfield) *g2lfield = socket->g2lfield;
360   if (Ufield)   *Ufield   = socket->Ufield;
361   if (userctx)  *userctx  = socket->userctx;
362   PetscFunctionReturn(0);
363 }
364 
365 /* accessor routines for the viewer windows:
366    PETSC_VIEWER_GLVIS_DUMP   : it returns a new viewer every time
367    PETSC_VIEWER_GLVIS_SOCKET : it returns the socket, and creates it if not yet done.
368 */
369 PetscErrorCode PetscViewerGLVisGetWindow_Private(PetscViewer viewer,PetscInt wid,PetscViewer* view)
370 {
371   PetscViewerGLVis       socket = (PetscViewerGLVis)viewer->data;
372   PetscViewerGLVisStatus status;
373   PetscErrorCode         ierr;
374 
375   PetscFunctionBegin;
376   PetscValidLogicalCollectiveInt(viewer,wid,2);
377   PetscValidPointer(view,3);
378   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);
379   status = socket->status;
380   if (socket->type == PETSC_VIEWER_GLVIS_DUMP && socket->window[wid]) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Window %D is already in use",wid);
381   switch (status) {
382     case PETSCVIEWERGLVIS_DISCONNECTED:
383       if (socket->window[wid]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"This should not happen");
384       if (socket->type == PETSC_VIEWER_GLVIS_DUMP) {
385         size_t    len;
386         PetscBool isstdout;
387 
388         ierr = PetscStrlen(socket->name,&len);CHKERRQ(ierr);
389         ierr = PetscStrcmp(socket->name,"stdout",&isstdout);CHKERRQ(ierr);
390         if (!socket->name || !len || isstdout) {
391           ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,"stdout",&socket->window[wid]);CHKERRQ(ierr);
392         } else {
393           PetscMPIInt rank;
394           char        filename[PETSC_MAX_PATH_LEN];
395 
396           ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank);CHKERRQ(ierr);
397           ierr = PetscSNPrintf(filename,PETSC_MAX_PATH_LEN,"%s-%s-%d.%06d",socket->name,socket->windowtitle[wid],socket->snapid,rank);CHKERRQ(ierr);
398           ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&socket->window[wid]);CHKERRQ(ierr);
399         }
400       } else {
401         ierr = PetscViewerGLVisGetNewWindow_Private(viewer,&socket->window[wid]);CHKERRQ(ierr);
402       }
403       if (socket->window[wid]) {
404         ierr = PetscViewerPushFormat(socket->window[wid],PETSC_VIEWER_ASCII_GLVIS);CHKERRQ(ierr);
405       }
406       *view = socket->window[wid];
407       break;
408     case PETSCVIEWERGLVIS_CONNECTED:
409       *view = socket->window[wid];
410       break;
411     case PETSCVIEWERGLVIS_DISABLED:
412       *view = NULL;
413       break;
414     default:
415       SETERRQ1(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Unhandled socket status %d\n",(int)status);
416       break;
417   }
418   if (*view) {
419     ierr = PetscViewerGLVisAttachInfo_Private(viewer,*view);CHKERRQ(ierr);
420   }
421   PetscFunctionReturn(0);
422 }
423 
424 /* Restore the window viewer
425    PETSC_VIEWER_GLVIS_DUMP  : destroys the temporary created ASCII viewer used for dumping
426    PETSC_VIEWER_GLVIS_SOCKET: - if the returned window viewer is not NULL, just zeros the pointer.
427                  - it the returned window viewer is NULL, assumes something went wrong
428                    with the socket (i.e. SIGPIPE when a user closes the popup window)
429                    and that the caller already handled it (see VecView_GLVis).
430 */
431 PetscErrorCode PetscViewerGLVisRestoreWindow_Private(PetscViewer viewer,PetscInt wid, PetscViewer* view)
432 {
433   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
434   PetscErrorCode   ierr;
435 
436   PetscFunctionBegin;
437   PetscValidLogicalCollectiveInt(viewer,wid,2);
438   PetscValidPointer(view,3);
439   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);
440   if (*view && *view != socket->window[wid]) SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Viewer was not obtained from PetscViewerGLVisGetWindow");
441   if (*view) {
442     ierr = PetscViewerFlush(*view);CHKERRQ(ierr);
443     ierr = PetscBarrier((PetscObject)viewer);CHKERRQ(ierr);
444   }
445   if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { /* destroy the viewer, as it is associated with a single time step */
446     ierr = PetscViewerDestroy(&socket->window[wid]);CHKERRQ(ierr);
447   } else if (!*view) { /* something went wrong (SIGPIPE) so we just zero the private pointer */
448     socket->window[wid] = NULL;
449   }
450   *view = NULL;
451   PetscFunctionReturn(0);
452 }
453 
454 /* default window appearance in the PETSC_VIEWER_GLVIS_SOCKET case */
455 PetscErrorCode PetscViewerGLVisInitWindow_Private(PetscViewer viewer, PetscBool mesh, PetscInt dim, const char *name)
456 {
457   PetscErrorCode       ierr;
458   PetscViewerGLVisInfo info;
459   PetscContainer       container;
460 
461   PetscFunctionBegin;
462   ierr = PetscObjectQuery((PetscObject)viewer,"_glvis_info_container",(PetscObject*)&container);CHKERRQ(ierr);
463   if (!container) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Viewer was not obtained from PetscGLVisViewerGetNewWindow_Private");
464   ierr = PetscContainerGetPointer(container,(void**)&info);CHKERRQ(ierr);
465   if (info->init) {
466     if (info->pause < 0) {
467       ierr = PetscViewerASCIIPrintf(viewer,"pause\n");CHKERRQ(ierr); /* pause */
468     }
469     PetscFunctionReturn(0);
470   }
471   ierr = PetscViewerASCIIPrintf(viewer,"window_size 800 800\n");CHKERRQ(ierr);
472   if (name) {
473     ierr = PetscViewerASCIIPrintf(viewer,"window_title '%s'\n",name);CHKERRQ(ierr);
474   }
475   if (mesh) {
476     switch (dim) {
477     case 1:
478       break;
479     case 2:
480       ierr = PetscViewerASCIIPrintf(viewer,"keys cmeeppppp\n");CHKERRQ(ierr); /* show colorbar, mesh and ranks */
481       break;
482     case 3: /* TODO: decide default view in 3D */
483       break;
484     }
485   } else {
486     ierr = PetscViewerASCIIPrintf(viewer,"keys cm\n");CHKERRQ(ierr); /* show colorbar and mesh */
487     switch (dim) {
488     case 1:
489       ierr = PetscViewerASCIIPrintf(viewer,"keys RRj\n");CHKERRQ(ierr); /* set to 1D (side view) and turn off perspective */
490       break;
491     case 2:
492       ierr = PetscViewerASCIIPrintf(viewer,"keys Rjl\n");CHKERRQ(ierr); /* set to 2D (top view), turn off perspective and light */
493       break;
494     case 3:
495       break;
496     }
497     ierr = PetscViewerASCIIPrintf(viewer,"autoscale value\n");CHKERRQ(ierr); /* update value-range; keep mesh-extents fixed */
498     if (info->pause == 0) {
499       ierr = PetscViewerASCIIPrintf(viewer,"pause\n");CHKERRQ(ierr); /* pause */
500     }
501   }
502   info->init = PETSC_TRUE;
503   PetscFunctionReturn(0);
504 }
505 
506 static PetscErrorCode PetscViewerDestroy_GLVis(PetscViewer viewer)
507 {
508   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
509   PetscInt         i;
510   PetscErrorCode   ierr;
511 
512   PetscFunctionBegin;
513   for (i=0;i<socket->nwindow;i++) {
514     ierr = PetscViewerDestroy(&socket->window[i]);CHKERRQ(ierr);
515     ierr = PetscFree(socket->windowtitle[i]);CHKERRQ(ierr);
516     ierr = PetscFree(socket->fec_type[i]);CHKERRQ(ierr);
517     ierr = PetscObjectDestroy(&socket->Ufield[i]);CHKERRQ(ierr);
518   }
519   ierr = PetscFree(socket->name);CHKERRQ(ierr);
520   ierr = PetscFree5(socket->window,socket->windowtitle,socket->fec_type,socket->spacedim,socket->Ufield);CHKERRQ(ierr);
521   ierr = PetscFree(socket->fmt);CHKERRQ(ierr);
522   ierr = PetscViewerDestroy(&socket->meshwindow);CHKERRQ(ierr);
523   ierr = PetscObjectDestroy(&socket->dm);CHKERRQ(ierr);
524   if (socket->destroyctx && socket->userctx) { ierr = (*socket->destroyctx)(socket->userctx);CHKERRQ(ierr); }
525 
526   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetPrecision_C",NULL);CHKERRQ(ierr);
527   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetSnapId_C",NULL);CHKERRQ(ierr);
528   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetFields_C",NULL);CHKERRQ(ierr);
529   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",NULL);CHKERRQ(ierr);
530   ierr = PetscFree(socket);CHKERRQ(ierr);
531   viewer->data = NULL;
532   PetscFunctionReturn(0);
533 }
534 
535 static PetscErrorCode PetscViewerSetFromOptions_GLVis(PetscOptionItems *PetscOptionsObject,PetscViewer v)
536 {
537   PetscErrorCode   ierr;
538   PetscViewerGLVis socket = (PetscViewerGLVis)v->data;
539 
540   PetscFunctionBegin;
541   ierr = PetscOptionsHead(PetscOptionsObject,"GLVis PetscViewer Options");CHKERRQ(ierr);
542   ierr = PetscOptionsReal("-viewer_glvis_pause","-1 to pause after each visualization, otherwise sleeps for given seconds",NULL,socket->pause,&socket->pause,NULL);CHKERRQ(ierr);
543   ierr = PetscOptionsTail();CHKERRQ(ierr);
544   PetscFunctionReturn(0);
545 }
546 
547 static PetscErrorCode PetscViewerSetFileName_GLVis(PetscViewer viewer, const char name[])
548 {
549   char             *sport;
550   PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
551   PetscErrorCode   ierr;
552 
553   PetscFunctionBegin;
554   socket->type = PETSC_VIEWER_GLVIS_DUMP;
555   /* we accept localhost^port */
556   ierr = PetscFree(socket->name);CHKERRQ(ierr);
557   ierr = PetscStrallocpy(name,&socket->name);CHKERRQ(ierr);
558   ierr = PetscStrchr(socket->name,'^',&sport);CHKERRQ(ierr);
559   if (sport) {
560     PetscInt port = 19916;
561     size_t   len;
562 
563     *sport++ = 0;
564     ierr = PetscStrlen(sport,&len);CHKERRQ(ierr);
565     if (len) ierr = PetscOptionsStringToInt(sport,&port);
566     if (!ierr) {
567       socket->port = (port != PETSC_DECIDE && port != PETSC_DEFAULT) ? port : 19916;
568     } else {
569       socket->port = 19916;
570     }
571     socket->type = PETSC_VIEWER_GLVIS_SOCKET;
572   }
573   PetscFunctionReturn(0);
574 }
575 
576 /*
577      PetscViewerGLVisOpen - Opens a GLVis type viewer
578 
579   Collective on comm
580 
581   Input Parameters:
582 +  comm      - the MPI communicator
583 .  type      - the viewer type: PETSC_VIEWER_GLVIS_SOCKET for real-time visualization or PETSC_VIEWER_GLVIS_DUMP for dumping to disk
584 .  name      - either the hostname where the GLVis server is running or the base filename for dumping the data for subsequent visualizations
585 -  port      - socket port where the GLVis server is listening. Not referenced when type is PETSC_VIEWER_GLVIS_DUMP
586 
587   Output Parameters:
588 -  viewer    - the PetscViewer object
589 
590   Notes: misses Fortran binding
591 
592   Level: beginner
593 
594 .seealso: PetscViewerCreate(), PetscViewerSetType(), PetscViewerGLVisType
595 */
596 PETSC_EXTERN PetscErrorCode PetscViewerGLVisOpen(MPI_Comm comm, PetscViewerGLVisType type, const char* name, PetscInt port, PetscViewer* viewer)
597 {
598   PetscViewerGLVis socket;
599   PetscErrorCode   ierr;
600 
601   PetscFunctionBegin;
602   ierr = PetscViewerCreate(comm,viewer);CHKERRQ(ierr);
603   ierr = PetscViewerSetType(*viewer,PETSCVIEWERGLVIS);CHKERRQ(ierr);
604 
605   socket       = (PetscViewerGLVis)((*viewer)->data);
606   ierr         = PetscFree(socket->name);CHKERRQ(ierr);
607   ierr         = PetscStrallocpy(name,&socket->name);CHKERRQ(ierr);
608   socket->type = type;
609   socket->port = port;
610 
611   ierr = PetscViewerSetFromOptions(*viewer);CHKERRQ(ierr);
612   PetscFunctionReturn(0);
613 }
614 
615 /*
616   PETSC_VIEWER_GLVIS_ - Creates an GLVIS PetscViewer shared by all processors in a communicator.
617 
618   Collective on MPI_Comm
619 
620   Input Parameter:
621 . comm - the MPI communicator to share the GLVIS PetscViewer
622 
623   Level: intermediate
624 
625   Notes: misses Fortran bindings
626 
627   Environmental variables:
628 + PETSC_VIEWER_GLVIS_FILENAME : output filename (if specified dump to disk, and takes precedence on PETSC_VIEWER_GLVIS_HOSTNAME)
629 . PETSC_VIEWER_GLVIS_HOSTNAME : machine where the GLVis server is listening (defaults to localhost)
630 - PETSC_VIEWER_GLVIS_PORT     : port opened by the GLVis server (defaults to 19916)
631 
632   Notes:
633   Unlike almost all other PETSc routines, PETSC_VIEWER_GLVIS_ does not return
634   an error code.  The GLVIS PetscViewer is usually used in the form
635 $       XXXView(XXX object, PETSC_VIEWER_GLVIS_(comm));
636 
637 .seealso: PetscViewerGLVISOpen(), PetscViewerGLVisType, PetscViewerCreate(), PetscViewerDestroy()
638 */
639 PETSC_EXTERN PetscViewer PETSC_VIEWER_GLVIS_(MPI_Comm comm)
640 {
641   PetscErrorCode       ierr;
642   PetscBool            flg;
643   PetscViewer          viewer;
644   PetscViewerGLVisType type;
645   char                 fname[PETSC_MAX_PATH_LEN],sport[16];
646   PetscInt             port = 19916; /* default for GLVis */
647 
648   PetscFunctionBegin;
649   ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg);
650   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
651   if (!flg) {
652     type = PETSC_VIEWER_GLVIS_SOCKET;
653     ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_HOSTNAME",fname,PETSC_MAX_PATH_LEN,&flg);
654     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
655     if (!flg) {
656       ierr = PetscStrcpy(fname,"localhost");
657       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
658     }
659     ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_PORT",sport,16,&flg);
660     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
661     if (flg) {
662       ierr = PetscOptionsStringToInt(sport,&port);
663       if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
664     }
665   } else {
666     type = PETSC_VIEWER_GLVIS_DUMP;
667   }
668   ierr = PetscViewerGLVisOpen(comm,type,fname,port,&viewer);
669   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
670   ierr = PetscObjectRegisterDestroy((PetscObject)viewer);
671   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);}
672   PetscFunctionReturn(viewer);
673 }
674 
675 PETSC_EXTERN PetscErrorCode PetscViewerCreate_GLVis(PetscViewer viewer)
676 {
677   PetscViewerGLVis socket;
678   PetscErrorCode   ierr;
679 
680   PetscFunctionBegin;
681   ierr = PetscNewLog(viewer,&socket);CHKERRQ(ierr);
682 
683   /* defaults to socket viewer */
684   ierr = PetscStrallocpy("localhost",&socket->name);CHKERRQ(ierr);
685   socket->port  = 19916; /* GLVis default listening port */
686   socket->type  = PETSC_VIEWER_GLVIS_SOCKET;
687   socket->pause = 0; /* just pause the first time */
688 
689   /* defaults to full precision */
690   ierr = PetscStrallocpy(" %g",&socket->fmt);CHKERRQ(ierr);
691 
692   viewer->data                = (void*)socket;
693   viewer->ops->destroy        = PetscViewerDestroy_GLVis;
694   viewer->ops->setfromoptions = PetscViewerSetFromOptions_GLVis;
695 
696   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetPrecision_C",PetscViewerGLVisSetPrecision_GLVis);CHKERRQ(ierr);
697   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetSnapId_C",PetscViewerGLVisSetSnapId_GLVis);CHKERRQ(ierr);
698   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetFields_C",PetscViewerGLVisSetFields_GLVis);CHKERRQ(ierr);
699   ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",PetscViewerSetFileName_GLVis);CHKERRQ(ierr);
700   PetscFunctionReturn(0);
701 }
702 
703 /* this is a private implementation of a SOCKET with ASCII data format
704    GLVis does not currently handle binary socket streams */
705 #if defined(PETSC_HAVE_UNISTD_H)
706 #include <unistd.h>
707 #endif
708 
709 #if !defined(PETSC_HAVE_WINDOWS_H)
710 static PetscErrorCode (*PetscViewerDestroy_ASCII)(PetscViewer);
711 
712 static PetscErrorCode PetscViewerDestroy_ASCII_Socket(PetscViewer viewer)
713 {
714   FILE *stream;
715   PetscErrorCode ierr = 0;
716   PetscFunctionBegin;
717   ierr = PetscViewerASCIIGetPointer(viewer,&stream);CHKERRQ(ierr);
718   if (stream) {
719     ierr = fclose(stream);
720     if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on stream");
721   }
722   ierr = PetscViewerDestroy_ASCII(viewer);CHKERRQ(ierr);
723   PetscFunctionReturn(0);
724 }
725 #endif
726 
727 static PetscErrorCode PetscViewerASCIISocketOpen(MPI_Comm comm,const char* hostname,PetscInt port,PetscViewer* viewer)
728 {
729 #if defined(PETSC_HAVE_WINDOWS_H)
730   PetscFunctionBegin;
731   SETERRQ(comm,PETSC_ERR_SUP,"Not implemented for Windows");
732 #else
733   FILE           *stream = NULL;
734   int            fd;
735   PetscErrorCode ierr;
736 
737   PetscFunctionBegin;
738   PetscValidPointer(hostname,2);
739   PetscValidPointer(viewer,4);
740 #if defined(PETSC_USE_SOCKET_VIEWER)
741   ierr = PetscOpenSocket(hostname,port,&fd);
742 #else
743   SETERRQ(comm,PETSC_ERR_SUP,"Missing Socket viewer");
744 #endif
745   if (ierr) {
746     PetscInt sierr = ierr;
747     char     err[1024];
748 
749     ierr    = PetscSNPrintf(err,1024,"Cannot connect to socket on %s:%D. Socket visualization is disabled\n",hostname,port);CHKERRQ(ierr);
750     ierr    = PetscInfo(NULL,err);CHKERRQ(ierr);
751     *viewer = NULL;
752     PetscFunctionReturn(sierr);
753   } else {
754     char msg[1024];
755 
756     ierr = PetscSNPrintf(msg,1024,"Successfully connect to socket on %s:%D. Socket visualization is enabled\n",hostname,port);CHKERRQ(ierr);
757     ierr = PetscInfo(NULL,msg);CHKERRQ(ierr);
758   }
759   stream = fdopen(fd,"w"); /* Not possible on Windows */
760   if (!stream) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Cannot open stream from socket %s:%d",hostname,port);
761   ierr = PetscViewerASCIIOpenWithFILE(PETSC_COMM_SELF,stream,viewer);CHKERRQ(ierr);
762   PetscViewerDestroy_ASCII = (*viewer)->ops->destroy;
763   (*viewer)->ops->destroy = PetscViewerDestroy_ASCII_Socket;
764 #endif
765   PetscFunctionReturn(0);
766 }
767