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