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 PetscCheckFalse(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 PetscCheckFalse(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) { 287 PetscCall(PetscViewerPushFormat(socket->meshwindow,PETSC_VIEWER_ASCII_GLVIS)); 288 } 289 } 290 if (socket->meshwindow) { 291 PetscCall(PetscViewerGLVisAttachInfo_Private(viewer,socket->meshwindow)); 292 } 293 *view = socket->meshwindow; 294 PetscFunctionReturn(0); 295 } 296 297 PetscErrorCode PetscViewerGLVisRestoreDMWindow_Private(PetscViewer viewer,PetscViewer *view) 298 { 299 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 300 301 PetscFunctionBegin; 302 PetscValidPointer(view,2); 303 PetscCheckFalse(*view && *view != socket->meshwindow,PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Viewer was not obtained from PetscViewerGLVisGetDMWindow()"); 304 if (*view) { 305 PetscCall(PetscViewerFlush(*view)); 306 PetscCall(PetscBarrier((PetscObject)viewer)); 307 } 308 if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { /* destroy the viewer, as it is associated with a single time step */ 309 PetscCall(PetscViewerDestroy(&socket->meshwindow)); 310 } else if (!*view) { /* something went wrong (SIGPIPE) so we just zero the private pointer */ 311 socket->meshwindow = NULL; 312 } 313 *view = NULL; 314 PetscFunctionReturn(0); 315 } 316 317 PetscErrorCode PetscViewerGLVisGetType_Private(PetscViewer viewer,PetscViewerGLVisType *type) 318 { 319 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 320 321 PetscFunctionBegin; 322 PetscValidPointer(type,2); 323 *type = socket->type; 324 PetscFunctionReturn(0); 325 } 326 327 /* 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 */ 328 PetscErrorCode PetscViewerGLVisGetStatus_Private(PetscViewer viewer, PetscViewerGLVisStatus *sockstatus) 329 { 330 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 331 332 PetscFunctionBegin; 333 PetscValidPointer(sockstatus,2); 334 if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { 335 socket->status = PETSCVIEWERGLVIS_DISCONNECTED; 336 } else if (socket->status == PETSCVIEWERGLVIS_DISCONNECTED && socket->nwindow) { 337 PetscInt i; 338 PetscBool lconn,conn; 339 340 for (i=0,lconn=PETSC_TRUE;i<socket->nwindow;i++) 341 if (!socket->window[i]) 342 lconn = PETSC_FALSE; 343 344 PetscCall(MPIU_Allreduce(&lconn,&conn,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)viewer))); 345 if (conn) socket->status = PETSCVIEWERGLVIS_CONNECTED; 346 } 347 *sockstatus = socket->status; 348 PetscFunctionReturn(0); 349 } 350 351 PetscErrorCode PetscViewerGLVisGetDM_Private(PetscViewer viewer, PetscObject* dm) 352 { 353 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 354 355 PetscFunctionBegin; 356 *dm = socket->dm; 357 PetscFunctionReturn(0); 358 } 359 360 PetscErrorCode PetscViewerGLVisGetFields_Private(PetscViewer viewer, PetscInt* nfield, const char **fec[], PetscInt *spacedim[], PetscErrorCode(**g2lfield)(PetscObject,PetscInt,PetscObject[],void*), PetscObject *Ufield[], void **userctx) 361 { 362 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 363 364 PetscFunctionBegin; 365 if (nfield) *nfield = socket->nwindow; 366 if (fec) *fec = (const char**)socket->fec_type; 367 if (spacedim) *spacedim = socket->spacedim; 368 if (g2lfield) *g2lfield = socket->g2lfield; 369 if (Ufield) *Ufield = socket->Ufield; 370 if (userctx) *userctx = socket->userctx; 371 PetscFunctionReturn(0); 372 } 373 374 /* accessor routines for the viewer windows: 375 PETSC_VIEWER_GLVIS_DUMP : it returns a new viewer every time 376 PETSC_VIEWER_GLVIS_SOCKET : it returns the socket, and creates it if not yet done. 377 */ 378 PetscErrorCode PetscViewerGLVisGetWindow_Private(PetscViewer viewer,PetscInt wid,PetscViewer* view) 379 { 380 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 381 PetscViewerGLVisStatus status; 382 383 PetscFunctionBegin; 384 PetscValidLogicalCollectiveInt(viewer,wid,2); 385 PetscValidPointer(view,3); 386 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); 387 status = socket->status; 388 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); 389 switch (status) { 390 case PETSCVIEWERGLVIS_DISCONNECTED: 391 PetscCheck(!socket->window[wid],PETSC_COMM_SELF,PETSC_ERR_USER,"This should not happen"); 392 else if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { 393 size_t len; 394 PetscBool isstdout; 395 396 PetscCall(PetscStrlen(socket->name,&len)); 397 PetscCall(PetscStrcmp(socket->name,"stdout",&isstdout)); 398 if (!socket->name || !len || isstdout) { 399 PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF,"stdout",&socket->window[wid])); 400 } else { 401 PetscMPIInt rank; 402 char filename[PETSC_MAX_PATH_LEN]; 403 404 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank)); 405 PetscCall(PetscSNPrintf(filename,PETSC_MAX_PATH_LEN,"%s-%s-%" PetscInt_FMT ".%06d",socket->name,socket->windowtitle[wid],socket->snapid,rank)); 406 PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&socket->window[wid])); 407 } 408 } else { 409 PetscCall(PetscViewerGLVisGetNewWindow_Private(viewer,&socket->window[wid])); 410 } 411 if (socket->window[wid]) { 412 PetscCall(PetscViewerPushFormat(socket->window[wid],PETSC_VIEWER_ASCII_GLVIS)); 413 } 414 *view = socket->window[wid]; 415 break; 416 case PETSCVIEWERGLVIS_CONNECTED: 417 *view = socket->window[wid]; 418 break; 419 case PETSCVIEWERGLVIS_DISABLED: 420 *view = NULL; 421 break; 422 default: 423 SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Unhandled socket status %d",(int)status); 424 } 425 if (*view) { 426 PetscCall(PetscViewerGLVisAttachInfo_Private(viewer,*view)); 427 } 428 PetscFunctionReturn(0); 429 } 430 431 /* Restore the window viewer 432 PETSC_VIEWER_GLVIS_DUMP : destroys the temporary created ASCII viewer used for dumping 433 PETSC_VIEWER_GLVIS_SOCKET: - if the returned window viewer is not NULL, just zeros the pointer. 434 - it the returned window viewer is NULL, assumes something went wrong 435 with the socket (i.e. SIGPIPE when a user closes the popup window) 436 and that the caller already handled it (see VecView_GLVis). 437 */ 438 PetscErrorCode PetscViewerGLVisRestoreWindow_Private(PetscViewer viewer,PetscInt wid, PetscViewer* view) 439 { 440 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 441 442 PetscFunctionBegin; 443 PetscValidHeaderSpecificType(viewer,PETSC_VIEWER_CLASSID,1,PETSCVIEWERGLVIS); 444 PetscValidLogicalCollectiveInt(viewer,wid,2); 445 PetscValidPointer(view,3); 446 PetscCheckFalse(wid < 0 || wid > socket->nwindow-1,PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Cannot restore window id %" PetscInt_FMT ": allowed range [0,%" PetscInt_FMT ")",wid,socket->nwindow); 447 PetscCheckFalse(*view && *view != socket->window[wid],PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Viewer was not obtained from PetscViewerGLVisGetWindow()"); 448 if (*view) { 449 PetscCall(PetscViewerFlush(*view)); 450 PetscCall(PetscBarrier((PetscObject)viewer)); 451 } 452 if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { /* destroy the viewer, as it is associated with a single time step */ 453 PetscCall(PetscViewerDestroy(&socket->window[wid])); 454 } else if (!*view) { /* something went wrong (SIGPIPE) so we just zero the private pointer */ 455 socket->window[wid] = NULL; 456 } 457 *view = NULL; 458 PetscFunctionReturn(0); 459 } 460 461 /* default window appearance in the PETSC_VIEWER_GLVIS_SOCKET case */ 462 PetscErrorCode PetscViewerGLVisInitWindow_Private(PetscViewer viewer, PetscBool mesh, PetscInt dim, const char *name) 463 { 464 PetscViewerGLVisInfo info; 465 PetscContainer container; 466 467 PetscFunctionBegin; 468 PetscCall(PetscObjectQuery((PetscObject)viewer,"_glvis_info_container",(PetscObject*)&container)); 469 PetscCheck(container,PETSC_COMM_SELF,PETSC_ERR_USER,"Viewer was not obtained from PetscGLVisViewerGetNewWindow_Private"); 470 PetscCall(PetscContainerGetPointer(container,(void**)&info)); 471 if (info->init) PetscFunctionReturn(0); 472 473 /* Configure window */ 474 if (info->size[0] > 0) { 475 PetscCall(PetscViewerASCIIPrintf(viewer,"window_size %" PetscInt_FMT " %" PetscInt_FMT "\n",info->size[0],info->size[1])); 476 } 477 if (name) { 478 PetscCall(PetscViewerASCIIPrintf(viewer,"window_title '%s'\n",name)); 479 } 480 481 /* Configure default view */ 482 if (mesh) { 483 switch (dim) { 484 case 1: 485 PetscCall(PetscViewerASCIIPrintf(viewer,"keys m\n")); /* show mesh */ 486 break; 487 case 2: 488 PetscCall(PetscViewerASCIIPrintf(viewer,"keys m\n")); /* show mesh */ 489 break; 490 case 3: /* TODO: decide default view in 3D */ 491 break; 492 } 493 } else { 494 PetscCall(PetscViewerASCIIPrintf(viewer,"keys cm\n")); /* show colorbar and mesh */ 495 switch (dim) { 496 case 1: 497 PetscCall(PetscViewerASCIIPrintf(viewer,"keys RRjl\n")); /* set to 1D (side view), turn off perspective and light */ 498 break; 499 case 2: 500 PetscCall(PetscViewerASCIIPrintf(viewer,"keys Rjl\n")); /* set to 2D (top view), turn off perspective and light */ 501 break; 502 case 3: 503 break; 504 } 505 PetscCall(PetscViewerASCIIPrintf(viewer,"autoscale value\n")); /* update value-range; keep mesh-extents fixed */ 506 } 507 508 { /* Additional keys and commands */ 509 char keys[256] = "", cmds[2*PETSC_MAX_PATH_LEN] = ""; 510 PetscOptions opt = ((PetscObject)viewer)->options; 511 const char *pre = ((PetscObject)viewer)->prefix; 512 513 PetscCall(PetscOptionsGetString(opt,pre,"-glvis_keys",keys,sizeof(keys),NULL)); 514 PetscCall(PetscOptionsGetString(opt,pre,"-glvis_exec",cmds,sizeof(cmds),NULL)); 515 if (keys[0]) PetscCall(PetscViewerASCIIPrintf(viewer,"keys %s\n",keys)); 516 if (cmds[0]) PetscCall(PetscViewerASCIIPrintf(viewer,"%s\n",cmds)); 517 } 518 519 /* Pause visualization */ 520 if (!mesh && info->pause == -1) { 521 PetscCall(PetscViewerASCIIPrintf(viewer,"autopause 1\n")); 522 } 523 if (!mesh && info->pause == 0) { 524 PetscCall(PetscViewerASCIIPrintf(viewer,"pause\n")); 525 } 526 527 info->init = PETSC_TRUE; 528 PetscFunctionReturn(0); 529 } 530 531 static PetscErrorCode PetscViewerDestroy_GLVis(PetscViewer viewer) 532 { 533 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 534 PetscInt i; 535 536 PetscFunctionBegin; 537 for (i=0;i<socket->nwindow;i++) { 538 PetscCall(PetscViewerDestroy(&socket->window[i])); 539 PetscCall(PetscFree(socket->windowtitle[i])); 540 PetscCall(PetscFree(socket->fec_type[i])); 541 PetscCall(PetscObjectDestroy(&socket->Ufield[i])); 542 } 543 PetscCall(PetscFree(socket->name)); 544 PetscCall(PetscFree5(socket->window,socket->windowtitle,socket->fec_type,socket->spacedim,socket->Ufield)); 545 PetscCall(PetscFree(socket->fmt)); 546 PetscCall(PetscViewerDestroy(&socket->meshwindow)); 547 PetscCall(PetscObjectDestroy(&socket->dm)); 548 if (socket->destroyctx && socket->userctx) PetscCall((*socket->destroyctx)(socket->userctx)); 549 550 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetPrecision_C",NULL)); 551 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetSnapId_C",NULL)); 552 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetFields_C",NULL)); 553 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",NULL)); 554 PetscCall(PetscFree(socket)); 555 viewer->data = NULL; 556 PetscFunctionReturn(0); 557 } 558 559 static PetscErrorCode PetscViewerSetFromOptions_GLVis(PetscOptionItems *PetscOptionsObject,PetscViewer v) 560 { 561 PetscViewerGLVis socket = (PetscViewerGLVis)v->data; 562 PetscInt nsizes = 2, prec = PETSC_DECIDE; 563 PetscBool set; 564 565 PetscFunctionBegin; 566 PetscOptionsHeadBegin(PetscOptionsObject,"GLVis PetscViewer Options"); 567 PetscCall(PetscOptionsInt("-glvis_precision","Number of digits for floating point values","PetscViewerGLVisSetPrecision",prec,&prec,&set)); 568 if (set) PetscCall(PetscViewerGLVisSetPrecision(v,prec)); 569 PetscCall(PetscOptionsIntArray("-glvis_size","Window sizes",NULL,socket->windowsizes,&nsizes,&set)); 570 if (set && (nsizes == 1 || socket->windowsizes[1] < 0)) socket->windowsizes[1] = socket->windowsizes[0]; 571 PetscCall(PetscOptionsReal("-glvis_pause","-1 to pause after each visualization, otherwise sleeps for given seconds",NULL,socket->pause,&socket->pause,NULL)); 572 PetscCall(PetscOptionsName("-glvis_keys","Additional keys to configure visualization",NULL,NULL)); 573 PetscCall(PetscOptionsName("-glvis_exec","Additional commands to configure visualization",NULL,NULL)); 574 PetscOptionsHeadEnd(); 575 PetscFunctionReturn(0); 576 } 577 578 static PetscErrorCode PetscViewerFileSetName_GLVis(PetscViewer viewer, const char name[]) 579 { 580 char *sport; 581 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 582 583 PetscFunctionBegin; 584 socket->type = PETSC_VIEWER_GLVIS_DUMP; 585 /* we accept localhost^port */ 586 PetscCall(PetscFree(socket->name)); 587 PetscCall(PetscStrallocpy(name,&socket->name)); 588 PetscCall(PetscStrchr(socket->name,'^',&sport)); 589 if (sport) { 590 PetscInt port = 19916; 591 size_t len; 592 PetscErrorCode ierr; 593 594 *sport++ = 0; 595 PetscCall(PetscStrlen(sport,&len)); 596 ierr = PetscOptionsStringToInt(sport,&port); 597 if (PetscUnlikely(ierr)) { 598 socket->port = 19916; 599 } else { 600 socket->port = (port != PETSC_DECIDE && port != PETSC_DEFAULT) ? port : 19916; 601 } 602 socket->type = PETSC_VIEWER_GLVIS_SOCKET; 603 } 604 PetscFunctionReturn(0); 605 } 606 607 /*@C 608 PetscViewerGLVisOpen - Opens a GLVis type viewer 609 610 Collective 611 612 Input Parameters: 613 + comm - the MPI communicator 614 . type - the viewer type: PETSC_VIEWER_GLVIS_SOCKET for real-time visualization or PETSC_VIEWER_GLVIS_DUMP for dumping to disk 615 . name - either the hostname where the GLVis server is running or the base filename for dumping the data for subsequent visualizations 616 - port - socket port where the GLVis server is listening. Not referenced when type is PETSC_VIEWER_GLVIS_DUMP 617 618 Output Parameters: 619 - viewer - the PetscViewer object 620 621 Options Database Keys: 622 + -glvis_precision <precision> - Sets number of digits for floating point values 623 . -glvis_size <width,height> - Sets the window size (in pixels) 624 . -glvis_pause <pause> - Sets time (in seconds) that the program pauses after each visualization 625 (0 is default, -1 implies every visualization) 626 . -glvis_keys - Additional keys to configure visualization 627 - -glvis_exec - Additional commands to configure visualization 628 629 Notes: 630 misses Fortran binding 631 632 Level: beginner 633 634 .seealso: PetscViewerCreate(), PetscViewerSetType(), PetscViewerGLVisType 635 @*/ 636 PetscErrorCode PetscViewerGLVisOpen(MPI_Comm comm, PetscViewerGLVisType type, const char name[], PetscInt port, PetscViewer *viewer) 637 { 638 PetscViewerGLVis socket; 639 640 PetscFunctionBegin; 641 PetscCall(PetscViewerCreate(comm,viewer)); 642 PetscCall(PetscViewerSetType(*viewer,PETSCVIEWERGLVIS)); 643 644 socket = (PetscViewerGLVis)((*viewer)->data); 645 socket->type = type; 646 if (type == PETSC_VIEWER_GLVIS_DUMP || name) { 647 PetscCall(PetscFree(socket->name)); 648 PetscCall(PetscStrallocpy(name,&socket->name)); 649 } 650 socket->port = (!port || port == PETSC_DETERMINE || port == PETSC_DECIDE) ? 19916 : port; 651 652 PetscCall(PetscViewerSetFromOptions(*viewer)); 653 PetscFunctionReturn(0); 654 } 655 656 /* 657 PETSC_VIEWER_GLVIS_ - Creates an GLVIS PetscViewer shared by all processors in a communicator. 658 659 Collective 660 661 Input Parameter: 662 . comm - the MPI communicator to share the GLVIS PetscViewer 663 664 Level: intermediate 665 666 Notes: 667 misses Fortran bindings 668 669 Environmental variables: 670 + PETSC_VIEWER_GLVIS_FILENAME : output filename (if specified dump to disk, and takes precedence on PETSC_VIEWER_GLVIS_HOSTNAME) 671 . PETSC_VIEWER_GLVIS_HOSTNAME : machine where the GLVis server is listening (defaults to localhost) 672 - PETSC_VIEWER_GLVIS_PORT : port opened by the GLVis server (defaults to 19916) 673 674 Notes: 675 Unlike almost all other PETSc routines, PETSC_VIEWER_GLVIS_ does not return 676 an error code. The GLVIS PetscViewer is usually used in the form 677 $ XXXView(XXX object, PETSC_VIEWER_GLVIS_(comm)); 678 679 .seealso: PetscViewerGLVISOpen(), PetscViewerGLVisType, PetscViewerCreate(), PetscViewerDestroy() 680 */ 681 PetscViewer PETSC_VIEWER_GLVIS_(MPI_Comm comm) 682 { 683 PetscErrorCode ierr; 684 PetscBool flg; 685 PetscViewer viewer; 686 PetscViewerGLVisType type; 687 char fname[PETSC_MAX_PATH_LEN],sport[16]; 688 PetscInt port = 19916; /* default for GLVis */ 689 690 PetscFunctionBegin; 691 ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg); 692 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 693 if (!flg) { 694 type = PETSC_VIEWER_GLVIS_SOCKET; 695 ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_HOSTNAME",fname,PETSC_MAX_PATH_LEN,&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 = PetscStrcpy(fname,"localhost"); 699 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 700 } 701 ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_PORT",sport,16,&flg); 702 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 703 if (flg) { 704 ierr = PetscOptionsStringToInt(sport,&port); 705 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 706 } 707 } else { 708 type = PETSC_VIEWER_GLVIS_DUMP; 709 } 710 ierr = PetscViewerGLVisOpen(comm,type,fname,port,&viewer); 711 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 712 ierr = PetscObjectRegisterDestroy((PetscObject)viewer); 713 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 714 PetscFunctionReturn(viewer); 715 } 716 717 PETSC_EXTERN PetscErrorCode PetscViewerCreate_GLVis(PetscViewer viewer) 718 { 719 PetscViewerGLVis socket; 720 721 PetscFunctionBegin; 722 PetscCall(PetscNewLog(viewer,&socket)); 723 724 /* defaults to socket viewer */ 725 PetscCall(PetscStrallocpy("localhost",&socket->name)); 726 socket->port = 19916; /* GLVis default listening port */ 727 socket->type = PETSC_VIEWER_GLVIS_SOCKET; 728 socket->pause = 0; /* just pause the first time */ 729 730 socket->windowsizes[0] = 600; 731 socket->windowsizes[1] = 600; 732 733 /* defaults to full precision */ 734 PetscCall(PetscStrallocpy(" %g",&socket->fmt)); 735 736 viewer->data = (void*)socket; 737 viewer->ops->destroy = PetscViewerDestroy_GLVis; 738 viewer->ops->setfromoptions = PetscViewerSetFromOptions_GLVis; 739 740 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetPrecision_C",PetscViewerGLVisSetPrecision_GLVis)); 741 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetSnapId_C",PetscViewerGLVisSetSnapId_GLVis)); 742 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetFields_C",PetscViewerGLVisSetFields_GLVis)); 743 PetscCall(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",PetscViewerFileSetName_GLVis)); 744 PetscFunctionReturn(0); 745 } 746 747 /* this is a private implementation of a SOCKET with ASCII data format 748 GLVis does not currently handle binary socket streams */ 749 #if defined(PETSC_HAVE_UNISTD_H) 750 #include <unistd.h> 751 #endif 752 753 #if !defined(PETSC_HAVE_WINDOWS_H) 754 static PetscErrorCode (*PetscViewerDestroy_ASCII)(PetscViewer); 755 756 static PetscErrorCode PetscViewerDestroy_ASCII_Socket(PetscViewer viewer) 757 { 758 FILE *stream; 759 int err = 0; 760 761 PetscFunctionBegin; 762 PetscCall(PetscViewerASCIIGetPointer(viewer,&stream)); 763 if (stream) { 764 err = fclose(stream); 765 PetscCheck(err,PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on stream"); 766 } 767 PetscCall(PetscViewerDestroy_ASCII(viewer)); 768 PetscFunctionReturn(0); 769 } 770 #endif 771 772 static PetscErrorCode PetscViewerASCIISocketOpen(MPI_Comm comm,const char* hostname,PetscInt port,PetscViewer* viewer) 773 { 774 #if defined(PETSC_HAVE_WINDOWS_H) 775 PetscFunctionBegin; 776 SETERRQ(comm,PETSC_ERR_SUP,"Not implemented for Windows"); 777 #else 778 FILE *stream = NULL; 779 int fd=0; 780 PetscErrorCode ierr; 781 782 PetscFunctionBegin; 783 PetscValidCharPointer(hostname,2); 784 PetscValidPointer(viewer,4); 785 #if defined(PETSC_USE_SOCKET_VIEWER) 786 ierr = PetscOpenSocket(hostname,port,&fd); 787 #else 788 SETERRQ(comm,PETSC_ERR_SUP,"Missing Socket viewer"); 789 #endif 790 if (PetscUnlikely(ierr)) { 791 PetscInt sierr = ierr; 792 char err[1024]; 793 794 PetscCall(PetscSNPrintf(err,1024,"Cannot connect to socket on %s:%" PetscInt_FMT ". Socket visualization is disabled\n",hostname,port)); 795 PetscCall(PetscInfo(NULL,"%s",err)); 796 *viewer = NULL; 797 PetscFunctionReturn(sierr); 798 } else { 799 char msg[1024]; 800 801 PetscCall(PetscSNPrintf(msg,1024,"Successfully connect to socket on %s:%" PetscInt_FMT ". Socket visualization is enabled\n",hostname,port)); 802 PetscCall(PetscInfo(NULL,"%s",msg)); 803 } 804 stream = fdopen(fd,"w"); /* Not possible on Windows */ 805 PetscCheck(stream,PETSC_COMM_SELF,PETSC_ERR_SYS,"Cannot open stream from socket %s:%" PetscInt_FMT,hostname,port); 806 PetscCall(PetscViewerASCIIOpenWithFILE(PETSC_COMM_SELF,stream,viewer)); 807 PetscViewerDestroy_ASCII = (*viewer)->ops->destroy; 808 (*viewer)->ops->destroy = PetscViewerDestroy_ASCII_Socket; 809 #endif 810 PetscFunctionReturn(0); 811 } 812 813 #if !defined(PETSC_MISSING_SIGPIPE) 814 815 #include <signal.h> 816 817 #if defined(PETSC_HAVE_WINDOWS_H) 818 #define PETSC_DEVNULL "NUL" 819 #else 820 #define PETSC_DEVNULL "/dev/null" 821 #endif 822 823 static volatile PetscBool PetscGLVisBrokenPipe = PETSC_FALSE; 824 825 static void (*PetscGLVisSigHandler_save)(int) = NULL; 826 827 static void PetscGLVisSigHandler_SIGPIPE(PETSC_UNUSED int sig) 828 { 829 PetscGLVisBrokenPipe = PETSC_TRUE; 830 #if !defined(PETSC_MISSING_SIG_IGN) 831 signal(SIGPIPE,SIG_IGN); 832 #endif 833 } 834 835 PetscErrorCode PetscGLVisCollectiveBegin(PETSC_UNUSED MPI_Comm comm,PETSC_UNUSED PetscViewer *win) 836 { 837 PetscFunctionBegin; 838 PetscCheck(!PetscGLVisSigHandler_save,comm,PETSC_ERR_PLIB,"Nested call to %s()",PETSC_FUNCTION_NAME); 839 PetscGLVisBrokenPipe = PETSC_FALSE; 840 PetscGLVisSigHandler_save = signal(SIGPIPE,PetscGLVisSigHandler_SIGPIPE); 841 PetscFunctionReturn(0); 842 } 843 844 PetscErrorCode PetscGLVisCollectiveEnd(MPI_Comm comm,PetscViewer *win) 845 { 846 PetscBool flag,brokenpipe; 847 848 PetscFunctionBegin; 849 flag = PetscGLVisBrokenPipe; 850 PetscCall(MPIU_Allreduce(&flag,&brokenpipe,1,MPIU_BOOL,MPI_LOR,comm)); 851 if (brokenpipe) { 852 FILE *sock, *null = fopen(PETSC_DEVNULL,"w"); 853 PetscCall(PetscViewerASCIIGetPointer(*win,&sock)); 854 PetscCall(PetscViewerASCIISetFILE(*win,null)); 855 PetscCall(PetscViewerDestroy(win)); 856 if (sock) (void)fclose(sock); 857 } 858 (void)signal(SIGPIPE,PetscGLVisSigHandler_save); 859 PetscGLVisSigHandler_save = NULL; 860 PetscGLVisBrokenPipe = PETSC_FALSE; 861 PetscFunctionReturn(0); 862 } 863 864 #else 865 866 PetscErrorCode PetscGLVisCollectiveBegin(PETSC_UNUSED MPI_Comm comm,PETSC_UNUSED PetscViewer *win) 867 { 868 PetscFunctionBegin; 869 PetscFunctionReturn(0); 870 } 871 872 PetscErrorCode PetscGLVisCollectiveEnd(PETSC_UNUSED MPI_Comm comm,PETSC_UNUSED PetscViewer *win) 873 { 874 PetscFunctionBegin; 875 PetscFunctionReturn(0); 876 } 877 878 #endif 879