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