Actual source code: glvis.c
1: #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for fdopen() */
3: #include <petsc/private/viewerimpl.h>
4: #include <petsc/private/petscimpl.h>
5: #include <petsc/private/glvisviewerimpl.h>
7: /* we may eventually make this function public */
8: static PetscErrorCode PetscViewerASCIISocketOpen(MPI_Comm, const char *, PetscInt, PetscViewer *);
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: PetscInt windowsizes[2];
22: char **fec_type; /* type of elements to be used for visualization, see FiniteElementCollection::Name() */
23: PetscErrorCode (*g2lfield)(PetscObject, PetscInt, PetscObject[], void *); /* global to local operation for generating dofs to be visualized */
24: PetscInt *spacedim; /* geometrical space dimension (just used to initialize the scene) */
25: PetscObject *Ufield; /* work vectors for visualization */
26: PetscInt snapid; /* snapshot id, use PetscViewerGLVisSetSnapId to change this value*/
27: void *userctx; /* User context, used by g2lfield */
28: PetscErrorCode (*destroyctx)(void *); /* destroy routine for userctx */
29: char *fmt; /* format string for FP values */
30: };
31: typedef struct _n_PetscViewerGLVis *PetscViewerGLVis;
33: /*@
34: PetscViewerGLVisSetPrecision - Set the number of digits for floating point values to be displayed
36: Not Collective
38: Input Parameters:
39: + viewer - the `PetscViewer` of type `PETSCVIEWERGLVIS`
40: - prec - the number of digits required
42: Level: beginner
44: .seealso: [](sec_viewers), `PETSCVIEWERGLVIS`, `PetscViewerGLVisOpen()`, `PetscViewerGLVisSetFields()`, `PetscViewerCreate()`, `PetscViewerSetType()`
45: @*/
46: PetscErrorCode PetscViewerGLVisSetPrecision(PetscViewer viewer, PetscInt prec)
47: {
49: PetscTryMethod(viewer, "PetscViewerGLVisSetPrecision_C", (PetscViewer, PetscInt), (viewer, prec));
50: return 0;
51: }
53: static PetscErrorCode PetscViewerGLVisSetPrecision_GLVis(PetscViewer viewer, PetscInt prec)
54: {
55: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
57: PetscFree(socket->fmt);
58: if (prec > 0) {
59: PetscMalloc1(16, &socket->fmt);
60: PetscSNPrintf(socket->fmt, 16, " %%.%" PetscInt_FMT "e", prec);
61: } else {
62: PetscStrallocpy(" %g", &socket->fmt);
63: }
64: return 0;
65: }
67: /*@
68: PetscViewerGLVisSetSnapId - Set the snapshot id. Only relevant when the `PetscViewerGLVisType` is `PETSC_VIEWER_GLVIS_DUMP`
70: Logically Collective
72: Input Parameters:
73: + viewer - the `PetscViewer` of type `PETSCVIEWERGLVIS`
74: - id - the current snapshot id in a time-dependent simulation
76: Level: beginner
78: .seealso: [](sec_viewers), `PETSCVIEWERGLVIS`, `PetscViewerGLVisOpen()`, `PetscViewerGLVisSetFields()`, `PetscViewerCreate()`, `PetscViewerSetType()`
79: @*/
80: PetscErrorCode PetscViewerGLVisSetSnapId(PetscViewer viewer, PetscInt id)
81: {
84: PetscTryMethod(viewer, "PetscViewerGLVisSetSnapId_C", (PetscViewer, PetscInt), (viewer, id));
85: return 0;
86: }
88: static PetscErrorCode PetscViewerGLVisSetSnapId_GLVis(PetscViewer viewer, PetscInt id)
89: {
90: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
92: socket->snapid = id;
93: return 0;
94: }
96: /*@C
97: PetscViewerGLVisSetFields - Sets the required information to visualize different fields from a vector.
99: Logically Collective
101: Input Parameters:
102: + viewer - the `PetscViewer` of type `PETSCVIEWERGLVIS`
103: . nf - number of fields to be visualized
104: . fec_type - the type of finite element to be used to visualize the data (see FiniteElementCollection::Name() in MFEM)
105: . dim - array of space dimension for field vectors (used to initialize the scene)
106: . g2lfields - User routine to compute the local field vectors to be visualized; PetscObject is used in place of Vec on the prototype
107: . Vfield - array of work vectors, one for each field
108: . ctx - User context to store the relevant data to apply g2lfields
109: - destroyctx - Destroy function for userctx
111: Notes:
112: g2lfields is called on the vector V to be visualized in order to extract the relevant dofs to be put in Vfield[], as
113: .vb
114: g2lfields((PetscObject)V,nfields,(PetscObject*)Vfield[],ctx).
115: .ve
117: For vector spaces, the block size of Vfield[i] represents the vector dimension.
118: The names of the Vfield vectors will be displayed in the window title.
120: Level: intermediate
122: .seealso: [](sec_viewers), `PETSCVIEWERGLVIS`, `PetscViewerGLVisOpen()`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscObjectSetName()`
123: @*/
124: 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 *))
125: {
132: 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));
133: return 0;
134: }
136: 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 *))
137: {
138: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
139: PetscInt i;
142: if (!socket->nwindow) {
143: socket->nwindow = nfields;
145: PetscCalloc5(nfields, &socket->window, nfields, &socket->windowtitle, nfields, &socket->fec_type, nfields, &socket->spacedim, nfields, &socket->Ufield);
146: for (i = 0; i < nfields; i++) {
147: const char *name;
149: PetscObjectGetName(Vfield[i], &name);
150: PetscStrallocpy(name, &socket->windowtitle[i]);
151: PetscStrallocpy(fec_type[i], &socket->fec_type[i]);
152: PetscObjectReference(Vfield[i]);
153: socket->Ufield[i] = Vfield[i];
154: socket->spacedim[i] = dim[i];
155: }
156: }
157: /* number of fields are not allowed to vary */
159: socket->g2lfield = g2l;
160: if (socket->destroyctx && socket->userctx) (*socket->destroyctx)(socket->userctx);
161: socket->userctx = ctx;
162: socket->destroyctx = destroyctx;
163: return 0;
164: }
166: static PetscErrorCode PetscViewerGLVisInfoDestroy_Private(void *ptr)
167: {
168: PetscViewerGLVisInfo info = (PetscViewerGLVisInfo)ptr;
170: PetscFree(info->fmt);
171: PetscFree(info);
172: return 0;
173: }
175: /* we can decide to prevent specific processes from using the viewer */
176: static PetscErrorCode PetscViewerGLVisAttachInfo_Private(PetscViewer viewer, PetscViewer window)
177: {
178: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
179: PetscContainer container;
180: PetscViewerGLVisInfo info;
182: PetscObjectQuery((PetscObject)window, "_glvis_info_container", (PetscObject *)&container);
183: if (!container) {
184: PetscNew(&info);
185: info->enabled = PETSC_TRUE;
186: info->init = PETSC_FALSE;
187: info->size[0] = socket->windowsizes[0];
188: info->size[1] = socket->windowsizes[1];
189: info->pause = socket->pause;
190: PetscContainerCreate(PetscObjectComm((PetscObject)window), &container);
191: PetscContainerSetPointer(container, (void *)info);
192: PetscContainerSetUserDestroy(container, PetscViewerGLVisInfoDestroy_Private);
193: PetscObjectCompose((PetscObject)window, "_glvis_info_container", (PetscObject)container);
194: PetscContainerDestroy(&container);
195: } else {
196: PetscContainerGetPointer(container, (void **)&info);
197: }
198: PetscFree(info->fmt);
199: PetscStrallocpy(socket->fmt, &info->fmt);
200: return 0;
201: }
203: static PetscErrorCode PetscViewerGLVisGetNewWindow_Private(PetscViewer viewer, PetscViewer *view)
204: {
205: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
206: PetscViewer window = NULL;
207: PetscBool ldis, dis;
209: PetscViewerASCIISocketOpen(PETSC_COMM_SELF, socket->name, socket->port, &window);
210: /* if we could not establish a connection, we disable the socket viewer on all MPI ranks */
211: ldis = !viewer ? PETSC_TRUE : PETSC_FALSE;
212: MPIU_Allreduce(&ldis, &dis, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)viewer));
213: if (dis) {
214: socket->status = PETSCVIEWERGLVIS_DISABLED;
215: PetscViewerDestroy(&window);
216: }
217: *view = window;
218: return 0;
219: }
221: PetscErrorCode PetscViewerGLVisPause_Private(PetscViewer viewer)
222: {
223: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
225: if (socket->type == PETSC_VIEWER_GLVIS_SOCKET && socket->pause > 0) PetscSleep(socket->pause);
226: return 0;
227: }
229: /* DM specific support */
230: PetscErrorCode PetscViewerGLVisSetDM_Private(PetscViewer viewer, PetscObject dm)
231: {
232: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
235: if (!socket->dm) {
236: PetscErrorCode (*setupwithdm)(PetscObject, PetscViewer) = NULL;
238: PetscObjectQueryFunction(dm, "DMSetUpGLVisViewer_C", &setupwithdm);
239: if (setupwithdm) {
240: (*setupwithdm)(dm, viewer);
241: } else SETERRQ(PetscObjectComm(dm), PETSC_ERR_SUP, "No support for DM type %s", dm->type_name);
242: PetscObjectReference(dm);
243: socket->dm = dm;
244: }
245: return 0;
246: }
248: PetscErrorCode PetscViewerGLVisGetDMWindow_Private(PetscViewer viewer, PetscViewer *view)
249: {
250: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
253: if (!socket->meshwindow) {
254: if (socket->type == PETSC_VIEWER_GLVIS_SOCKET) {
255: PetscViewerGLVisGetNewWindow_Private(viewer, &socket->meshwindow);
256: } else {
257: size_t len;
258: PetscBool isstdout;
260: PetscStrlen(socket->name, &len);
261: PetscStrcmp(socket->name, "stdout", &isstdout);
262: if (!socket->name || !len || isstdout) {
263: PetscViewerASCIIOpen(PETSC_COMM_SELF, "stdout", &socket->meshwindow);
264: } else {
265: PetscMPIInt rank;
266: char filename[PETSC_MAX_PATH_LEN];
267: MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank);
268: PetscSNPrintf(filename, PETSC_MAX_PATH_LEN, "%s-mesh.%06d", socket->name, rank);
269: PetscViewerASCIIOpen(PETSC_COMM_SELF, filename, &socket->meshwindow);
270: }
271: }
272: if (socket->meshwindow) PetscViewerPushFormat(socket->meshwindow, PETSC_VIEWER_ASCII_GLVIS);
273: }
274: if (socket->meshwindow) PetscViewerGLVisAttachInfo_Private(viewer, socket->meshwindow);
275: *view = socket->meshwindow;
276: return 0;
277: }
279: PetscErrorCode PetscViewerGLVisRestoreDMWindow_Private(PetscViewer viewer, PetscViewer *view)
280: {
281: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
285: if (*view) {
286: PetscViewerFlush(*view);
287: PetscBarrier((PetscObject)viewer);
288: }
289: if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { /* destroy the viewer, as it is associated with a single time step */
290: PetscViewerDestroy(&socket->meshwindow);
291: } else if (!*view) { /* something went wrong (SIGPIPE) so we just zero the private pointer */
292: socket->meshwindow = NULL;
293: }
294: *view = NULL;
295: return 0;
296: }
298: PetscErrorCode PetscViewerGLVisGetType_Private(PetscViewer viewer, PetscViewerGLVisType *type)
299: {
300: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
303: *type = socket->type;
304: return 0;
305: }
307: /* 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 */
308: PetscErrorCode PetscViewerGLVisGetStatus_Private(PetscViewer viewer, PetscViewerGLVisStatus *sockstatus)
309: {
310: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
313: if (socket->type == PETSC_VIEWER_GLVIS_DUMP) {
314: socket->status = PETSCVIEWERGLVIS_DISCONNECTED;
315: } else if (socket->status == PETSCVIEWERGLVIS_DISCONNECTED && socket->nwindow) {
316: PetscInt i;
317: PetscBool lconn, conn;
319: for (i = 0, lconn = PETSC_TRUE; i < socket->nwindow; i++)
320: if (!socket->window[i]) lconn = PETSC_FALSE;
322: MPIU_Allreduce(&lconn, &conn, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)viewer));
323: if (conn) socket->status = PETSCVIEWERGLVIS_CONNECTED;
324: }
325: *sockstatus = socket->status;
326: return 0;
327: }
329: PetscErrorCode PetscViewerGLVisGetDM_Private(PetscViewer viewer, PetscObject *dm)
330: {
331: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
333: *dm = socket->dm;
334: return 0;
335: }
337: PetscErrorCode PetscViewerGLVisGetFields_Private(PetscViewer viewer, PetscInt *nfield, const char **fec[], PetscInt *spacedim[], PetscErrorCode (**g2lfield)(PetscObject, PetscInt, PetscObject[], void *), PetscObject *Ufield[], void **userctx)
338: {
339: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
341: if (nfield) *nfield = socket->nwindow;
342: if (fec) *fec = (const char **)socket->fec_type;
343: if (spacedim) *spacedim = socket->spacedim;
344: if (g2lfield) *g2lfield = socket->g2lfield;
345: if (Ufield) *Ufield = socket->Ufield;
346: if (userctx) *userctx = socket->userctx;
347: return 0;
348: }
350: /* accessor routines for the viewer windows:
351: PETSC_VIEWER_GLVIS_DUMP : it returns a new viewer every time
352: PETSC_VIEWER_GLVIS_SOCKET : it returns the socket, and creates it if not yet done.
353: */
354: PetscErrorCode PetscViewerGLVisGetWindow_Private(PetscViewer viewer, PetscInt wid, PetscViewer *view)
355: {
356: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
357: PetscViewerGLVisStatus status;
362: status = socket->status;
364: switch (status) {
365: case PETSCVIEWERGLVIS_DISCONNECTED:
367: if (socket->type == PETSC_VIEWER_GLVIS_DUMP) {
368: size_t len;
369: PetscBool isstdout;
371: PetscStrlen(socket->name, &len);
372: PetscStrcmp(socket->name, "stdout", &isstdout);
373: if (!socket->name || !len || isstdout) {
374: PetscViewerASCIIOpen(PETSC_COMM_SELF, "stdout", &socket->window[wid]);
375: } else {
376: PetscMPIInt rank;
377: char filename[PETSC_MAX_PATH_LEN];
379: MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank);
380: PetscSNPrintf(filename, PETSC_MAX_PATH_LEN, "%s-%s-%" PetscInt_FMT ".%06d", socket->name, socket->windowtitle[wid], socket->snapid, rank);
381: PetscViewerASCIIOpen(PETSC_COMM_SELF, filename, &socket->window[wid]);
382: }
383: } else {
384: PetscViewerGLVisGetNewWindow_Private(viewer, &socket->window[wid]);
385: }
386: if (socket->window[wid]) PetscViewerPushFormat(socket->window[wid], PETSC_VIEWER_ASCII_GLVIS);
387: *view = socket->window[wid];
388: break;
389: case PETSCVIEWERGLVIS_CONNECTED:
390: *view = socket->window[wid];
391: break;
392: case PETSCVIEWERGLVIS_DISABLED:
393: *view = NULL;
394: break;
395: default:
396: SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Unhandled socket status %d", (int)status);
397: }
398: if (*view) PetscViewerGLVisAttachInfo_Private(viewer, *view);
399: return 0;
400: }
402: /* Restore the window viewer
403: PETSC_VIEWER_GLVIS_DUMP : destroys the temporary created ASCII viewer used for dumping
404: PETSC_VIEWER_GLVIS_SOCKET: - if the returned window viewer is not NULL, just zeros the pointer.
405: - it the returned window viewer is NULL, assumes something went wrong
406: with the socket (i.e. SIGPIPE when a user closes the popup window)
407: and that the caller already handled it (see VecView_GLVis).
408: */
409: PetscErrorCode PetscViewerGLVisRestoreWindow_Private(PetscViewer viewer, PetscInt wid, PetscViewer *view)
410: {
411: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
418: if (*view) {
419: PetscViewerFlush(*view);
420: PetscBarrier((PetscObject)viewer);
421: }
422: if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { /* destroy the viewer, as it is associated with a single time step */
423: PetscViewerDestroy(&socket->window[wid]);
424: } else if (!*view) { /* something went wrong (SIGPIPE) so we just zero the private pointer */
425: socket->window[wid] = NULL;
426: }
427: *view = NULL;
428: return 0;
429: }
431: /* default window appearance in the PETSC_VIEWER_GLVIS_SOCKET case */
432: PetscErrorCode PetscViewerGLVisInitWindow_Private(PetscViewer viewer, PetscBool mesh, PetscInt dim, const char *name)
433: {
434: PetscViewerGLVisInfo info;
435: PetscContainer container;
437: PetscObjectQuery((PetscObject)viewer, "_glvis_info_container", (PetscObject *)&container);
439: PetscContainerGetPointer(container, (void **)&info);
440: if (info->init) return 0;
442: /* Configure window */
443: if (info->size[0] > 0) PetscViewerASCIIPrintf(viewer, "window_size %" PetscInt_FMT " %" PetscInt_FMT "\n", info->size[0], info->size[1]);
444: if (name) PetscViewerASCIIPrintf(viewer, "window_title '%s'\n", name);
446: /* Configure default view */
447: if (mesh) {
448: switch (dim) {
449: case 1:
450: PetscViewerASCIIPrintf(viewer, "keys m\n"); /* show mesh */
451: break;
452: case 2:
453: PetscViewerASCIIPrintf(viewer, "keys m\n"); /* show mesh */
454: break;
455: case 3: /* TODO: decide default view in 3D */
456: break;
457: }
458: } else {
459: PetscViewerASCIIPrintf(viewer, "keys cm\n"); /* show colorbar and mesh */
460: switch (dim) {
461: case 1:
462: PetscViewerASCIIPrintf(viewer, "keys RRjl\n"); /* set to 1D (side view), turn off perspective and light */
463: break;
464: case 2:
465: PetscViewerASCIIPrintf(viewer, "keys Rjl\n"); /* set to 2D (top view), turn off perspective and light */
466: break;
467: case 3:
468: break;
469: }
470: PetscViewerASCIIPrintf(viewer, "autoscale value\n"); /* update value-range; keep mesh-extents fixed */
471: }
473: { /* Additional keys and commands */
474: char keys[256] = "", cmds[2 * PETSC_MAX_PATH_LEN] = "";
475: PetscOptions opt = ((PetscObject)viewer)->options;
476: const char *pre = ((PetscObject)viewer)->prefix;
478: PetscOptionsGetString(opt, pre, "-glvis_keys", keys, sizeof(keys), NULL);
479: PetscOptionsGetString(opt, pre, "-glvis_exec", cmds, sizeof(cmds), NULL);
480: if (keys[0]) PetscViewerASCIIPrintf(viewer, "keys %s\n", keys);
481: if (cmds[0]) PetscViewerASCIIPrintf(viewer, "%s\n", cmds);
482: }
484: /* Pause visualization */
485: if (!mesh && info->pause == -1) PetscViewerASCIIPrintf(viewer, "autopause 1\n");
486: if (!mesh && info->pause == 0) PetscViewerASCIIPrintf(viewer, "pause\n");
488: info->init = PETSC_TRUE;
489: return 0;
490: }
492: static PetscErrorCode PetscViewerDestroy_GLVis(PetscViewer viewer)
493: {
494: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
495: PetscInt i;
497: for (i = 0; i < socket->nwindow; i++) {
498: PetscViewerDestroy(&socket->window[i]);
499: PetscFree(socket->windowtitle[i]);
500: PetscFree(socket->fec_type[i]);
501: PetscObjectDestroy(&socket->Ufield[i]);
502: }
503: PetscFree(socket->name);
504: PetscFree5(socket->window, socket->windowtitle, socket->fec_type, socket->spacedim, socket->Ufield);
505: PetscFree(socket->fmt);
506: PetscViewerDestroy(&socket->meshwindow);
507: PetscObjectDestroy(&socket->dm);
508: if (socket->destroyctx && socket->userctx) (*socket->destroyctx)(socket->userctx);
510: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerGLVisSetPrecision_C", NULL);
511: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerGLVisSetSnapId_C", NULL);
512: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerGLVisSetFields_C", NULL);
513: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", NULL);
514: PetscFree(socket);
515: viewer->data = NULL;
516: return 0;
517: }
519: static PetscErrorCode PetscViewerSetFromOptions_GLVis(PetscViewer v, PetscOptionItems *PetscOptionsObject)
520: {
521: PetscViewerGLVis socket = (PetscViewerGLVis)v->data;
522: PetscInt nsizes = 2, prec = PETSC_DECIDE;
523: PetscBool set;
525: PetscOptionsHeadBegin(PetscOptionsObject, "GLVis PetscViewer Options");
526: PetscOptionsInt("-glvis_precision", "Number of digits for floating point values", "PetscViewerGLVisSetPrecision", prec, &prec, &set);
527: if (set) PetscViewerGLVisSetPrecision(v, prec);
528: PetscOptionsIntArray("-glvis_size", "Window sizes", NULL, socket->windowsizes, &nsizes, &set);
529: if (set && (nsizes == 1 || socket->windowsizes[1] < 0)) socket->windowsizes[1] = socket->windowsizes[0];
530: PetscOptionsReal("-glvis_pause", "-1 to pause after each visualization, otherwise sleeps for given seconds", NULL, socket->pause, &socket->pause, NULL);
531: PetscOptionsName("-glvis_keys", "Additional keys to configure visualization", NULL, NULL);
532: PetscOptionsName("-glvis_exec", "Additional commands to configure visualization", NULL, NULL);
533: PetscOptionsHeadEnd();
534: return 0;
535: }
537: static PetscErrorCode PetscViewerFileSetName_GLVis(PetscViewer viewer, const char name[])
538: {
539: char *sport;
540: PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data;
542: socket->type = PETSC_VIEWER_GLVIS_DUMP;
543: /* we accept localhost^port */
544: PetscFree(socket->name);
545: PetscStrallocpy(name, &socket->name);
546: PetscStrchr(socket->name, '^', &sport);
547: if (sport) {
548: PetscInt port = 19916;
549: size_t len;
552: *sport++ = 0;
553: PetscStrlen(sport, &len);
554: PetscOptionsStringToInt(sport, &port);
555: if (PetscUnlikely(ierr)) {
556: socket->port = 19916;
557: } else {
558: socket->port = (port != PETSC_DECIDE && port != PETSC_DEFAULT) ? port : 19916;
559: }
560: socket->type = PETSC_VIEWER_GLVIS_SOCKET;
561: }
562: return 0;
563: }
565: /*@C
566: PetscViewerGLVisOpen - Opens a `PETSCVIEWERGLVIS` `PetscViewer`
568: Collective; No Fortran Support
570: Input Parameters:
571: + comm - the MPI communicator
572: . type - the viewer type: `PETSC_VIEWER_GLVIS_SOCKET` for real-time visualization or `PETSC_VIEWER_GLVIS_DUMP` for dumping to a file
573: . name - either the hostname where the GLVis server is running or the base filename for dumping the data for subsequent visualizations
574: - port - socket port where the GLVis server is listening. Not referenced when type is `PETSC_VIEWER_GLVIS_DUMP`
576: Output Parameters:
577: - viewer - the `PetscViewer` object
579: Options Database Keys:
580: + -glvis_precision <precision> - Sets number of digits for floating point values
581: . -glvis_size <width,height> - Sets the window size (in pixels)
582: . -glvis_pause <pause> - Sets time (in seconds) that the program pauses after each visualization
583: (0 is default, -1 implies every visualization)
584: . -glvis_keys - Additional keys to configure visualization
585: - -glvis_exec - Additional commands to configure visualization
587: Level: beginner
589: .seealso: [](sec_viewers), `PETSCVIEWERGLVIS`, `PetscViewerCreate()`, `PetscViewerSetType()`, `PetscViewerGLVisType`
590: @*/
591: PetscErrorCode PetscViewerGLVisOpen(MPI_Comm comm, PetscViewerGLVisType type, const char name[], PetscInt port, PetscViewer *viewer)
592: {
593: PetscViewerGLVis socket;
595: PetscViewerCreate(comm, viewer);
596: PetscViewerSetType(*viewer, PETSCVIEWERGLVIS);
598: socket = (PetscViewerGLVis)((*viewer)->data);
599: socket->type = type;
600: if (type == PETSC_VIEWER_GLVIS_DUMP || name) {
601: PetscFree(socket->name);
602: PetscStrallocpy(name, &socket->name);
603: }
604: socket->port = (!port || port == PETSC_DETERMINE || port == PETSC_DECIDE) ? 19916 : port;
606: PetscViewerSetFromOptions(*viewer);
607: return 0;
608: }
610: /*@C
611: PETSC_VIEWER_GLVIS_ - Creates a `PETSCVIEWERGLVIS` `PetscViewer` shared by all processors in a communicator.
613: Collective; No Fortran Support
615: Input Parameter:
616: . comm - the MPI communicator to share the `PETSCVIEWERGLVIS` `PetscViewer`
618: Environmental variables:
619: + `PETSC_VIEWER_GLVIS_FILENAME` - output filename (if specified dump to disk, and takes precedence on `PETSC_VIEWER_GLVIS_HOSTNAME`)
620: . `PETSC_VIEWER_GLVIS_HOSTNAME` - machine where the GLVis server is listening (defaults to localhost)
621: - `PETSC_VIEWER_GLVIS_PORT` - port opened by the GLVis server (defaults to 19916)
623: Level: intermediate
625: Note:
626: Unlike almost all other PETSc routines, `PETSC_VIEWER_GLVIS_()` does not return
627: an error code. It is usually used in the form
628: $ XXXView(XXX object, PETSC_VIEWER_GLVIS_(comm));
630: .seealso: [](sec_viewers), `PETSCVIEWERGLVIS`, `PetscViewer`, `PetscViewerGLVISOpen()`, `PetscViewerGLVisType`, `PetscViewerCreate()`, `PetscViewerDestroy()`
631: @*/
632: PetscViewer PETSC_VIEWER_GLVIS_(MPI_Comm comm)
633: {
634: PetscErrorCode ierr;
635: PetscBool flg;
636: PetscViewer viewer;
637: PetscViewerGLVisType type;
638: char fname[PETSC_MAX_PATH_LEN], sport[16];
639: PetscInt port = 19916; /* default for GLVis */
641: PetscOptionsGetenv(comm, "PETSC_VIEWER_GLVIS_FILENAME", fname, PETSC_MAX_PATH_LEN, &flg);
642: if (ierr) {
643: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_GLVIS_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
644: return NULL;
645: }
646: if (!flg) {
647: type = PETSC_VIEWER_GLVIS_SOCKET;
648: PetscOptionsGetenv(comm, "PETSC_VIEWER_GLVIS_HOSTNAME", fname, PETSC_MAX_PATH_LEN, &flg);
649: if (ierr) {
650: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_GLVIS_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
651: return NULL;
652: }
653: if (!flg) {
654: PetscStrcpy(fname, "localhost");
655: if (ierr) {
656: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_GLVIS_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
657: return NULL;
658: }
659: }
660: PetscOptionsGetenv(comm, "PETSC_VIEWER_GLVIS_PORT", sport, 16, &flg);
661: if (ierr) {
662: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_GLVIS_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
663: return NULL;
664: }
665: if (flg) {
666: PetscOptionsStringToInt(sport, &port);
667: if (ierr) {
668: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_GLVIS_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
669: return NULL;
670: }
671: }
672: } else {
673: type = PETSC_VIEWER_GLVIS_DUMP;
674: }
675: PetscViewerGLVisOpen(comm, type, fname, port, &viewer);
676: if (ierr) {
677: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_GLVIS_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
678: return NULL;
679: }
680: PetscObjectRegisterDestroy((PetscObject)viewer);
681: if (ierr) {
682: PetscError(PETSC_COMM_SELF, __LINE__, "PETSC_VIEWER_GLVIS_", __FILE__, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, " ");
683: return NULL;
684: }
685: return viewer;
686: }
688: PETSC_EXTERN PetscErrorCode PetscViewerCreate_GLVis(PetscViewer viewer)
689: {
690: PetscViewerGLVis socket;
692: PetscNew(&socket);
694: /* defaults to socket viewer */
695: PetscStrallocpy("localhost", &socket->name);
696: socket->port = 19916; /* GLVis default listening port */
697: socket->type = PETSC_VIEWER_GLVIS_SOCKET;
698: socket->pause = 0; /* just pause the first time */
700: socket->windowsizes[0] = 600;
701: socket->windowsizes[1] = 600;
703: /* defaults to full precision */
704: PetscStrallocpy(" %g", &socket->fmt);
706: viewer->data = (void *)socket;
707: viewer->ops->destroy = PetscViewerDestroy_GLVis;
708: viewer->ops->setfromoptions = PetscViewerSetFromOptions_GLVis;
710: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerGLVisSetPrecision_C", PetscViewerGLVisSetPrecision_GLVis);
711: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerGLVisSetSnapId_C", PetscViewerGLVisSetSnapId_GLVis);
712: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerGLVisSetFields_C", PetscViewerGLVisSetFields_GLVis);
713: PetscObjectComposeFunction((PetscObject)viewer, "PetscViewerFileSetName_C", PetscViewerFileSetName_GLVis);
714: return 0;
715: }
717: /* this is a private implementation of a SOCKET with ASCII data format
718: GLVis does not currently handle binary socket streams */
719: #if defined(PETSC_HAVE_UNISTD_H)
720: #include <unistd.h>
721: #endif
723: #ifndef PETSC_HAVE_WINDOWS_H
724: static PetscErrorCode (*PetscViewerDestroy_ASCII)(PetscViewer);
726: static PetscErrorCode PetscViewerDestroy_ASCII_Socket(PetscViewer viewer)
727: {
728: FILE *stream;
730: PetscViewerASCIIGetPointer(viewer, &stream);
731: if (stream) {
732: int retv = fclose(stream);
734: }
735: PetscViewerDestroy_ASCII(viewer);
736: return 0;
737: }
738: #endif
740: /*
741: This attempts to return a NULL viewer if it is unable to open a socket connection.
743: The code below involving PetscUnlikely(ierr) is illegal in PETSc, one can NEVER attempt to recover once an error is initiated in PETSc.
745: The correct approach is to refactor PetscOpenSocket() to not initiate an error under certain failure conditions but instead either return a special value
746: of fd to indicate it was impossible to open the socket, or add another return argument to it indicating the socket was not opened.
747: */
748: static PetscErrorCode PetscViewerASCIISocketOpen(MPI_Comm comm, const char *hostname, PetscInt port, PetscViewer *viewer)
749: {
750: #if defined(PETSC_HAVE_WINDOWS_H)
751: SETERRQ(comm, PETSC_ERR_SUP, "Not implemented for Windows");
752: #else
753: FILE *stream = NULL;
754: int fd = 0;
759: #if defined(PETSC_USE_SOCKET_VIEWER)
760: PetscOpenSocket(hostname, port, &fd);
761: #else
762: SETERRQ(comm, PETSC_ERR_SUP, "Missing Socket viewer");
763: #endif
764: /*
765: The following code is illegal in PETSc, one can NEVER attempt to recover once an error is initiated in PETSc.
766: The correct approach is to refactor PetscOpenSocket() to not initiate an error under certain conditions but instead either return a special value
767: of fd to indicate it was impossible to open the socket, or add another return argument to it indicating the socket was not opened.
768: */
769: if (PetscUnlikely(ierr)) {
770: char err[1024];
772: PetscSNPrintf(err, 1024, "Cannot connect to socket on %s:%" PetscInt_FMT ". Socket visualization is disabled\n", hostname, port);
773: PetscInfo(NULL, "%s", err);
774: *viewer = NULL;
775: return 0;
776: } else {
777: char msg[1024];
779: PetscSNPrintf(msg, 1024, "Successfully connect to socket on %s:%" PetscInt_FMT ". Socket visualization is enabled\n", hostname, port);
780: PetscInfo(NULL, "%s", msg);
781: }
782: stream = fdopen(fd, "w"); /* Not possible on Windows */
784: PetscViewerASCIIOpenWithFILE(PETSC_COMM_SELF, stream, viewer);
785: PetscViewerDestroy_ASCII = (*viewer)->ops->destroy;
786: (*viewer)->ops->destroy = PetscViewerDestroy_ASCII_Socket;
787: #endif
788: return 0;
789: }
791: #if !defined(PETSC_MISSING_SIGPIPE)
793: #include <signal.h>
795: #if defined(PETSC_HAVE_WINDOWS_H)
796: #define PETSC_DEVNULL "NUL"
797: #else
798: #define PETSC_DEVNULL "/dev/null"
799: #endif
801: static volatile PetscBool PetscGLVisBrokenPipe = PETSC_FALSE;
803: static void (*PetscGLVisSigHandler_save)(int) = NULL;
805: static void PetscGLVisSigHandler_SIGPIPE(PETSC_UNUSED int sig)
806: {
807: PetscGLVisBrokenPipe = PETSC_TRUE;
808: #if !defined(PETSC_MISSING_SIG_IGN)
809: signal(SIGPIPE, SIG_IGN);
810: #endif
811: }
813: PetscErrorCode PetscGLVisCollectiveBegin(PETSC_UNUSED MPI_Comm comm, PETSC_UNUSED PetscViewer *win)
814: {
816: PetscGLVisBrokenPipe = PETSC_FALSE;
817: PetscGLVisSigHandler_save = signal(SIGPIPE, PetscGLVisSigHandler_SIGPIPE);
818: return 0;
819: }
821: PetscErrorCode PetscGLVisCollectiveEnd(MPI_Comm comm, PetscViewer *win)
822: {
823: PetscBool flag, brokenpipe;
825: flag = PetscGLVisBrokenPipe;
826: MPIU_Allreduce(&flag, &brokenpipe, 1, MPIU_BOOL, MPI_LOR, comm);
827: if (brokenpipe) {
828: FILE *sock, *null = fopen(PETSC_DEVNULL, "w");
829: PetscViewerASCIIGetPointer(*win, &sock);
830: PetscViewerASCIISetFILE(*win, null);
831: PetscViewerDestroy(win);
832: if (sock) (void)fclose(sock);
833: }
834: (void)signal(SIGPIPE, PetscGLVisSigHandler_save);
835: PetscGLVisSigHandler_save = NULL;
836: PetscGLVisBrokenPipe = PETSC_FALSE;
837: return 0;
838: }
840: #else
842: PetscErrorCode PetscGLVisCollectiveBegin(PETSC_UNUSED MPI_Comm comm, PETSC_UNUSED PetscViewer *win)
843: {
844: return 0;
845: }
847: PetscErrorCode PetscGLVisCollectiveEnd(PETSC_UNUSED MPI_Comm comm, PETSC_UNUSED PetscViewer *win)
848: {
849: return 0;
850: }
852: #endif