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