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 CHKERRQ(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 CHKERRQ(PetscFree(socket->fmt)); 60 if (prec > 0) { 61 CHKERRQ(PetscMalloc1(16,&socket->fmt)); 62 CHKERRQ(PetscSNPrintf(socket->fmt,16," %%.%" PetscInt_FMT "e",prec)); 63 } else { 64 CHKERRQ(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 CHKERRQ(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 PetscValidPointer(dim,4); 135 PetscValidPointer(Vfield,6); 136 CHKERRQ(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 CHKERRQ(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 CHKERRQ(PetscObjectGetName(Vfield[i],&name)); 155 CHKERRQ(PetscStrallocpy(name,&socket->windowtitle[i])); 156 CHKERRQ(PetscStrallocpy(fec_type[i],&socket->fec_type[i])); 157 CHKERRQ(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 PetscCheckFalse(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) CHKERRQ((*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 CHKERRQ(PetscFree(info->fmt)); 177 CHKERRQ(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 CHKERRQ(PetscObjectQuery((PetscObject)window,"_glvis_info_container",(PetscObject*)&container)); 190 if (!container) { 191 CHKERRQ(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 CHKERRQ(PetscContainerCreate(PetscObjectComm((PetscObject)window),&container)); 198 CHKERRQ(PetscContainerSetPointer(container,(void*)info)); 199 CHKERRQ(PetscContainerSetUserDestroy(container,PetscViewerGLVisInfoDestroy_Private)); 200 CHKERRQ(PetscObjectCompose((PetscObject)window,"_glvis_info_container",(PetscObject)container)); 201 CHKERRQ(PetscContainerDestroy(&container)); 202 } else { 203 CHKERRQ(PetscContainerGetPointer(container,(void**)&info)); 204 } 205 CHKERRQ(PetscFree(info->fmt)); 206 CHKERRQ(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, 220 we disable the socket viewer */ 221 ldis = ierr ? PETSC_TRUE : PETSC_FALSE; 222 CHKERRMPI(MPIU_Allreduce(&ldis,&dis,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)viewer))); 223 if (dis) { 224 socket->status = PETSCVIEWERGLVIS_DISABLED; 225 CHKERRQ(PetscViewerDestroy(&window)); 226 } 227 *view = window; 228 PetscFunctionReturn(0); 229 } 230 231 PetscErrorCode PetscViewerGLVisPause_Private(PetscViewer viewer) 232 { 233 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 234 235 PetscFunctionBegin; 236 if (socket->type == PETSC_VIEWER_GLVIS_SOCKET && socket->pause > 0) { 237 CHKERRQ(PetscSleep(socket->pause)); 238 } 239 PetscFunctionReturn(0); 240 } 241 242 /* DM specific support */ 243 PetscErrorCode PetscViewerGLVisSetDM_Private(PetscViewer viewer, PetscObject dm) 244 { 245 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 246 247 PetscFunctionBegin; 248 PetscCheckFalse(socket->dm && socket->dm != dm,PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Cannot change DM associated with the GLVis viewer"); 249 if (!socket->dm) { 250 PetscErrorCode (*setupwithdm)(PetscObject,PetscViewer) = NULL; 251 252 CHKERRQ(PetscObjectQueryFunction(dm,"DMSetUpGLVisViewer_C",&setupwithdm)); 253 if (setupwithdm) { 254 CHKERRQ((*setupwithdm)(dm,viewer)); 255 } else SETERRQ(PetscObjectComm(dm),PETSC_ERR_SUP,"No support for DM type %s",dm->type_name); 256 CHKERRQ(PetscObjectReference(dm)); 257 socket->dm = dm; 258 } 259 PetscFunctionReturn(0); 260 } 261 262 PetscErrorCode PetscViewerGLVisGetDMWindow_Private(PetscViewer viewer,PetscViewer *view) 263 { 264 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 265 266 PetscFunctionBegin; 267 PetscValidPointer(view,2); 268 if (!socket->meshwindow) { 269 if (socket->type == PETSC_VIEWER_GLVIS_SOCKET) { 270 CHKERRQ(PetscViewerGLVisGetNewWindow_Private(viewer,&socket->meshwindow)); 271 } else { 272 size_t len; 273 PetscBool isstdout; 274 275 CHKERRQ(PetscStrlen(socket->name,&len)); 276 CHKERRQ(PetscStrcmp(socket->name,"stdout",&isstdout)); 277 if (!socket->name || !len || isstdout) { 278 CHKERRQ(PetscViewerASCIIOpen(PETSC_COMM_SELF,"stdout",&socket->meshwindow)); 279 } else { 280 PetscMPIInt rank; 281 char filename[PETSC_MAX_PATH_LEN]; 282 CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank)); 283 CHKERRQ(PetscSNPrintf(filename,PETSC_MAX_PATH_LEN,"%s-mesh.%06d",socket->name,rank)); 284 CHKERRQ(PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&socket->meshwindow)); 285 } 286 } 287 if (socket->meshwindow) { 288 CHKERRQ(PetscViewerPushFormat(socket->meshwindow,PETSC_VIEWER_ASCII_GLVIS)); 289 } 290 } 291 if (socket->meshwindow) { 292 CHKERRQ(PetscViewerGLVisAttachInfo_Private(viewer,socket->meshwindow)); 293 } 294 *view = socket->meshwindow; 295 PetscFunctionReturn(0); 296 } 297 298 PetscErrorCode PetscViewerGLVisRestoreDMWindow_Private(PetscViewer viewer,PetscViewer *view) 299 { 300 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 301 302 PetscFunctionBegin; 303 PetscValidPointer(view,2); 304 PetscCheckFalse(*view && *view != socket->meshwindow,PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Viewer was not obtained from PetscViewerGLVisGetDMWindow()"); 305 if (*view) { 306 CHKERRQ(PetscViewerFlush(*view)); 307 CHKERRQ(PetscBarrier((PetscObject)viewer)); 308 } 309 if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { /* destroy the viewer, as it is associated with a single time step */ 310 CHKERRQ(PetscViewerDestroy(&socket->meshwindow)); 311 } else if (!*view) { /* something went wrong (SIGPIPE) so we just zero the private pointer */ 312 socket->meshwindow = NULL; 313 } 314 *view = NULL; 315 PetscFunctionReturn(0); 316 } 317 318 PetscErrorCode PetscViewerGLVisGetType_Private(PetscViewer viewer,PetscViewerGLVisType *type) 319 { 320 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 321 322 PetscFunctionBegin; 323 PetscValidPointer(type,2); 324 *type = socket->type; 325 PetscFunctionReturn(0); 326 } 327 328 /* 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 */ 329 PetscErrorCode PetscViewerGLVisGetStatus_Private(PetscViewer viewer, PetscViewerGLVisStatus *sockstatus) 330 { 331 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 332 333 PetscFunctionBegin; 334 PetscValidPointer(sockstatus,2); 335 if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { 336 socket->status = PETSCVIEWERGLVIS_DISCONNECTED; 337 } else if (socket->status == PETSCVIEWERGLVIS_DISCONNECTED && socket->nwindow) { 338 PetscInt i; 339 PetscBool lconn,conn; 340 341 for (i=0,lconn=PETSC_TRUE;i<socket->nwindow;i++) 342 if (!socket->window[i]) 343 lconn = PETSC_FALSE; 344 345 CHKERRMPI(MPIU_Allreduce(&lconn,&conn,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)viewer))); 346 if (conn) socket->status = PETSCVIEWERGLVIS_CONNECTED; 347 } 348 *sockstatus = socket->status; 349 PetscFunctionReturn(0); 350 } 351 352 PetscErrorCode PetscViewerGLVisGetDM_Private(PetscViewer viewer, PetscObject* dm) 353 { 354 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 355 356 PetscFunctionBegin; 357 *dm = socket->dm; 358 PetscFunctionReturn(0); 359 } 360 361 PetscErrorCode PetscViewerGLVisGetFields_Private(PetscViewer viewer, PetscInt* nfield, const char **fec[], PetscInt *spacedim[], PetscErrorCode(**g2lfield)(PetscObject,PetscInt,PetscObject[],void*), PetscObject *Ufield[], void **userctx) 362 { 363 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 364 365 PetscFunctionBegin; 366 if (nfield) *nfield = socket->nwindow; 367 if (fec) *fec = (const char**)socket->fec_type; 368 if (spacedim) *spacedim = socket->spacedim; 369 if (g2lfield) *g2lfield = socket->g2lfield; 370 if (Ufield) *Ufield = socket->Ufield; 371 if (userctx) *userctx = socket->userctx; 372 PetscFunctionReturn(0); 373 } 374 375 /* accessor routines for the viewer windows: 376 PETSC_VIEWER_GLVIS_DUMP : it returns a new viewer every time 377 PETSC_VIEWER_GLVIS_SOCKET : it returns the socket, and creates it if not yet done. 378 */ 379 PetscErrorCode PetscViewerGLVisGetWindow_Private(PetscViewer viewer,PetscInt wid,PetscViewer* view) 380 { 381 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 382 PetscViewerGLVisStatus status; 383 384 PetscFunctionBegin; 385 PetscValidLogicalCollectiveInt(viewer,wid,2); 386 PetscValidPointer(view,3); 387 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); 388 status = socket->status; 389 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); 390 switch (status) { 391 case PETSCVIEWERGLVIS_DISCONNECTED: 392 PetscCheck(!socket->window[wid],PETSC_COMM_SELF,PETSC_ERR_USER,"This should not happen"); 393 else if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { 394 size_t len; 395 PetscBool isstdout; 396 397 CHKERRQ(PetscStrlen(socket->name,&len)); 398 CHKERRQ(PetscStrcmp(socket->name,"stdout",&isstdout)); 399 if (!socket->name || !len || isstdout) { 400 CHKERRQ(PetscViewerASCIIOpen(PETSC_COMM_SELF,"stdout",&socket->window[wid])); 401 } else { 402 PetscMPIInt rank; 403 char filename[PETSC_MAX_PATH_LEN]; 404 405 CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank)); 406 CHKERRQ(PetscSNPrintf(filename,PETSC_MAX_PATH_LEN,"%s-%s-%" PetscInt_FMT ".%06d",socket->name,socket->windowtitle[wid],socket->snapid,rank)); 407 CHKERRQ(PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&socket->window[wid])); 408 } 409 } else { 410 CHKERRQ(PetscViewerGLVisGetNewWindow_Private(viewer,&socket->window[wid])); 411 } 412 if (socket->window[wid]) { 413 CHKERRQ(PetscViewerPushFormat(socket->window[wid],PETSC_VIEWER_ASCII_GLVIS)); 414 } 415 *view = socket->window[wid]; 416 break; 417 case PETSCVIEWERGLVIS_CONNECTED: 418 *view = socket->window[wid]; 419 break; 420 case PETSCVIEWERGLVIS_DISABLED: 421 *view = NULL; 422 break; 423 default: 424 SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Unhandled socket status %d",(int)status); 425 } 426 if (*view) { 427 CHKERRQ(PetscViewerGLVisAttachInfo_Private(viewer,*view)); 428 } 429 PetscFunctionReturn(0); 430 } 431 432 /* Restore the window viewer 433 PETSC_VIEWER_GLVIS_DUMP : destroys the temporary created ASCII viewer used for dumping 434 PETSC_VIEWER_GLVIS_SOCKET: - if the returned window viewer is not NULL, just zeros the pointer. 435 - it the returned window viewer is NULL, assumes something went wrong 436 with the socket (i.e. SIGPIPE when a user closes the popup window) 437 and that the caller already handled it (see VecView_GLVis). 438 */ 439 PetscErrorCode PetscViewerGLVisRestoreWindow_Private(PetscViewer viewer,PetscInt wid, PetscViewer* view) 440 { 441 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 442 443 PetscFunctionBegin; 444 PetscValidHeaderSpecificType(viewer,PETSC_VIEWER_CLASSID,1,PETSCVIEWERGLVIS); 445 PetscValidLogicalCollectiveInt(viewer,wid,2); 446 PetscValidPointer(view,3); 447 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); 448 PetscCheckFalse(*view && *view != socket->window[wid],PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Viewer was not obtained from PetscViewerGLVisGetWindow()"); 449 if (*view) { 450 CHKERRQ(PetscViewerFlush(*view)); 451 CHKERRQ(PetscBarrier((PetscObject)viewer)); 452 } 453 if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { /* destroy the viewer, as it is associated with a single time step */ 454 CHKERRQ(PetscViewerDestroy(&socket->window[wid])); 455 } else if (!*view) { /* something went wrong (SIGPIPE) so we just zero the private pointer */ 456 socket->window[wid] = NULL; 457 } 458 *view = NULL; 459 PetscFunctionReturn(0); 460 } 461 462 /* default window appearance in the PETSC_VIEWER_GLVIS_SOCKET case */ 463 PetscErrorCode PetscViewerGLVisInitWindow_Private(PetscViewer viewer, PetscBool mesh, PetscInt dim, const char *name) 464 { 465 PetscViewerGLVisInfo info; 466 PetscContainer container; 467 468 PetscFunctionBegin; 469 CHKERRQ(PetscObjectQuery((PetscObject)viewer,"_glvis_info_container",(PetscObject*)&container)); 470 PetscCheck(container,PETSC_COMM_SELF,PETSC_ERR_USER,"Viewer was not obtained from PetscGLVisViewerGetNewWindow_Private"); 471 CHKERRQ(PetscContainerGetPointer(container,(void**)&info)); 472 if (info->init) PetscFunctionReturn(0); 473 474 /* Configure window */ 475 if (info->size[0] > 0) { 476 CHKERRQ(PetscViewerASCIIPrintf(viewer,"window_size %" PetscInt_FMT " %" PetscInt_FMT "\n",info->size[0],info->size[1])); 477 } 478 if (name) { 479 CHKERRQ(PetscViewerASCIIPrintf(viewer,"window_title '%s'\n",name)); 480 } 481 482 /* Configure default view */ 483 if (mesh) { 484 switch (dim) { 485 case 1: 486 CHKERRQ(PetscViewerASCIIPrintf(viewer,"keys m\n")); /* show mesh */ 487 break; 488 case 2: 489 CHKERRQ(PetscViewerASCIIPrintf(viewer,"keys m\n")); /* show mesh */ 490 break; 491 case 3: /* TODO: decide default view in 3D */ 492 break; 493 } 494 } else { 495 CHKERRQ(PetscViewerASCIIPrintf(viewer,"keys cm\n")); /* show colorbar and mesh */ 496 switch (dim) { 497 case 1: 498 CHKERRQ(PetscViewerASCIIPrintf(viewer,"keys RRjl\n")); /* set to 1D (side view), turn off perspective and light */ 499 break; 500 case 2: 501 CHKERRQ(PetscViewerASCIIPrintf(viewer,"keys Rjl\n")); /* set to 2D (top view), turn off perspective and light */ 502 break; 503 case 3: 504 break; 505 } 506 CHKERRQ(PetscViewerASCIIPrintf(viewer,"autoscale value\n")); /* update value-range; keep mesh-extents fixed */ 507 } 508 509 { /* Additional keys and commands */ 510 char keys[256] = "", cmds[2*PETSC_MAX_PATH_LEN] = ""; 511 PetscOptions opt = ((PetscObject)viewer)->options; 512 const char *pre = ((PetscObject)viewer)->prefix; 513 514 CHKERRQ(PetscOptionsGetString(opt,pre,"-glvis_keys",keys,sizeof(keys),NULL)); 515 CHKERRQ(PetscOptionsGetString(opt,pre,"-glvis_exec",cmds,sizeof(cmds),NULL)); 516 if (keys[0]) CHKERRQ(PetscViewerASCIIPrintf(viewer,"keys %s\n",keys)); 517 if (cmds[0]) CHKERRQ(PetscViewerASCIIPrintf(viewer,"%s\n",cmds)); 518 } 519 520 /* Pause visualization */ 521 if (!mesh && info->pause == -1) { 522 CHKERRQ(PetscViewerASCIIPrintf(viewer,"autopause 1\n")); 523 } 524 if (!mesh && info->pause == 0) { 525 CHKERRQ(PetscViewerASCIIPrintf(viewer,"pause\n")); 526 } 527 528 info->init = PETSC_TRUE; 529 PetscFunctionReturn(0); 530 } 531 532 static PetscErrorCode PetscViewerDestroy_GLVis(PetscViewer viewer) 533 { 534 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 535 PetscInt i; 536 537 PetscFunctionBegin; 538 for (i=0;i<socket->nwindow;i++) { 539 CHKERRQ(PetscViewerDestroy(&socket->window[i])); 540 CHKERRQ(PetscFree(socket->windowtitle[i])); 541 CHKERRQ(PetscFree(socket->fec_type[i])); 542 CHKERRQ(PetscObjectDestroy(&socket->Ufield[i])); 543 } 544 CHKERRQ(PetscFree(socket->name)); 545 CHKERRQ(PetscFree5(socket->window,socket->windowtitle,socket->fec_type,socket->spacedim,socket->Ufield)); 546 CHKERRQ(PetscFree(socket->fmt)); 547 CHKERRQ(PetscViewerDestroy(&socket->meshwindow)); 548 CHKERRQ(PetscObjectDestroy(&socket->dm)); 549 if (socket->destroyctx && socket->userctx) CHKERRQ((*socket->destroyctx)(socket->userctx)); 550 551 CHKERRQ(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetPrecision_C",NULL)); 552 CHKERRQ(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetSnapId_C",NULL)); 553 CHKERRQ(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetFields_C",NULL)); 554 CHKERRQ(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",NULL)); 555 CHKERRQ(PetscFree(socket)); 556 viewer->data = NULL; 557 PetscFunctionReturn(0); 558 } 559 560 static PetscErrorCode PetscViewerSetFromOptions_GLVis(PetscOptionItems *PetscOptionsObject,PetscViewer v) 561 { 562 PetscViewerGLVis socket = (PetscViewerGLVis)v->data; 563 PetscInt nsizes = 2, prec = PETSC_DECIDE; 564 PetscBool set; 565 566 PetscFunctionBegin; 567 CHKERRQ(PetscOptionsHead(PetscOptionsObject,"GLVis PetscViewer Options")); 568 CHKERRQ(PetscOptionsInt("-glvis_precision","Number of digits for floating point values","PetscViewerGLVisSetPrecision",prec,&prec,&set)); 569 if (set) CHKERRQ(PetscViewerGLVisSetPrecision(v,prec)); 570 CHKERRQ(PetscOptionsIntArray("-glvis_size","Window sizes",NULL,socket->windowsizes,&nsizes,&set)); 571 if (set && (nsizes == 1 || socket->windowsizes[1] < 0)) socket->windowsizes[1] = socket->windowsizes[0]; 572 CHKERRQ(PetscOptionsReal("-glvis_pause","-1 to pause after each visualization, otherwise sleeps for given seconds",NULL,socket->pause,&socket->pause,NULL)); 573 CHKERRQ(PetscOptionsName("-glvis_keys","Additional keys to configure visualization",NULL,NULL)); 574 CHKERRQ(PetscOptionsName("-glvis_exec","Additional commands to configure visualization",NULL,NULL)); 575 CHKERRQ(PetscOptionsTail()); 576 PetscFunctionReturn(0); 577 } 578 579 static PetscErrorCode PetscViewerFileSetName_GLVis(PetscViewer viewer, const char name[]) 580 { 581 char *sport; 582 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 583 584 PetscFunctionBegin; 585 socket->type = PETSC_VIEWER_GLVIS_DUMP; 586 /* we accept localhost^port */ 587 CHKERRQ(PetscFree(socket->name)); 588 CHKERRQ(PetscStrallocpy(name,&socket->name)); 589 CHKERRQ(PetscStrchr(socket->name,'^',&sport)); 590 if (sport) { 591 PetscInt port = 19916; 592 size_t len; 593 PetscErrorCode ierr; 594 595 *sport++ = 0; 596 CHKERRQ(PetscStrlen(sport,&len)); 597 ierr = PetscOptionsStringToInt(sport,&port); 598 if (PetscUnlikely(ierr)) { 599 socket->port = 19916; 600 } else { 601 socket->port = (port != PETSC_DECIDE && port != PETSC_DEFAULT) ? port : 19916; 602 } 603 socket->type = PETSC_VIEWER_GLVIS_SOCKET; 604 } 605 PetscFunctionReturn(0); 606 } 607 608 /*@C 609 PetscViewerGLVisOpen - Opens a GLVis type viewer 610 611 Collective 612 613 Input Parameters: 614 + comm - the MPI communicator 615 . type - the viewer type: PETSC_VIEWER_GLVIS_SOCKET for real-time visualization or PETSC_VIEWER_GLVIS_DUMP for dumping to disk 616 . name - either the hostname where the GLVis server is running or the base filename for dumping the data for subsequent visualizations 617 - port - socket port where the GLVis server is listening. Not referenced when type is PETSC_VIEWER_GLVIS_DUMP 618 619 Output Parameters: 620 - viewer - the PetscViewer object 621 622 Options Database Keys: 623 + -glvis_precision <precision> - Sets number of digits for floating point values 624 . -glvis_size <width,height> - Sets the window size (in pixels) 625 . -glvis_pause <pause> - Sets time (in seconds) that the program pauses after each visualization 626 (0 is default, -1 implies every visualization) 627 . -glvis_keys - Additional keys to configure visualization 628 - -glvis_exec - Additional commands to configure visualization 629 630 Notes: 631 misses Fortran binding 632 633 Level: beginner 634 635 .seealso: PetscViewerCreate(), PetscViewerSetType(), PetscViewerGLVisType 636 @*/ 637 PetscErrorCode PetscViewerGLVisOpen(MPI_Comm comm, PetscViewerGLVisType type, const char name[], PetscInt port, PetscViewer *viewer) 638 { 639 PetscViewerGLVis socket; 640 641 PetscFunctionBegin; 642 CHKERRQ(PetscViewerCreate(comm,viewer)); 643 CHKERRQ(PetscViewerSetType(*viewer,PETSCVIEWERGLVIS)); 644 645 socket = (PetscViewerGLVis)((*viewer)->data); 646 socket->type = type; 647 if (type == PETSC_VIEWER_GLVIS_DUMP || name) { 648 CHKERRQ(PetscFree(socket->name)); 649 CHKERRQ(PetscStrallocpy(name,&socket->name)); 650 } 651 socket->port = (!port || port == PETSC_DETERMINE || port == PETSC_DECIDE) ? 19916 : port; 652 653 CHKERRQ(PetscViewerSetFromOptions(*viewer)); 654 PetscFunctionReturn(0); 655 } 656 657 /* 658 PETSC_VIEWER_GLVIS_ - Creates an GLVIS PetscViewer shared by all processors in a communicator. 659 660 Collective 661 662 Input Parameter: 663 . comm - the MPI communicator to share the GLVIS PetscViewer 664 665 Level: intermediate 666 667 Notes: 668 misses Fortran bindings 669 670 Environmental variables: 671 + PETSC_VIEWER_GLVIS_FILENAME : output filename (if specified dump to disk, and takes precedence on PETSC_VIEWER_GLVIS_HOSTNAME) 672 . PETSC_VIEWER_GLVIS_HOSTNAME : machine where the GLVis server is listening (defaults to localhost) 673 - PETSC_VIEWER_GLVIS_PORT : port opened by the GLVis server (defaults to 19916) 674 675 Notes: 676 Unlike almost all other PETSc routines, PETSC_VIEWER_GLVIS_ does not return 677 an error code. The GLVIS PetscViewer is usually used in the form 678 $ XXXView(XXX object, PETSC_VIEWER_GLVIS_(comm)); 679 680 .seealso: PetscViewerGLVISOpen(), PetscViewerGLVisType, PetscViewerCreate(), PetscViewerDestroy() 681 */ 682 PetscViewer PETSC_VIEWER_GLVIS_(MPI_Comm comm) 683 { 684 PetscErrorCode ierr; 685 PetscBool flg; 686 PetscViewer viewer; 687 PetscViewerGLVisType type; 688 char fname[PETSC_MAX_PATH_LEN],sport[16]; 689 PetscInt port = 19916; /* default for GLVis */ 690 691 PetscFunctionBegin; 692 ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg); 693 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 694 if (!flg) { 695 type = PETSC_VIEWER_GLVIS_SOCKET; 696 ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_HOSTNAME",fname,PETSC_MAX_PATH_LEN,&flg); 697 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 698 if (!flg) { 699 ierr = PetscStrcpy(fname,"localhost"); 700 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 701 } 702 ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_PORT",sport,16,&flg); 703 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 704 if (flg) { 705 ierr = PetscOptionsStringToInt(sport,&port); 706 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 707 } 708 } else { 709 type = PETSC_VIEWER_GLVIS_DUMP; 710 } 711 ierr = PetscViewerGLVisOpen(comm,type,fname,port,&viewer); 712 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 713 ierr = PetscObjectRegisterDestroy((PetscObject)viewer); 714 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(NULL);} 715 PetscFunctionReturn(viewer); 716 } 717 718 PETSC_EXTERN PetscErrorCode PetscViewerCreate_GLVis(PetscViewer viewer) 719 { 720 PetscViewerGLVis socket; 721 722 PetscFunctionBegin; 723 CHKERRQ(PetscNewLog(viewer,&socket)); 724 725 /* defaults to socket viewer */ 726 CHKERRQ(PetscStrallocpy("localhost",&socket->name)); 727 socket->port = 19916; /* GLVis default listening port */ 728 socket->type = PETSC_VIEWER_GLVIS_SOCKET; 729 socket->pause = 0; /* just pause the first time */ 730 731 socket->windowsizes[0] = 600; 732 socket->windowsizes[1] = 600; 733 734 /* defaults to full precision */ 735 CHKERRQ(PetscStrallocpy(" %g",&socket->fmt)); 736 737 viewer->data = (void*)socket; 738 viewer->ops->destroy = PetscViewerDestroy_GLVis; 739 viewer->ops->setfromoptions = PetscViewerSetFromOptions_GLVis; 740 741 CHKERRQ(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetPrecision_C",PetscViewerGLVisSetPrecision_GLVis)); 742 CHKERRQ(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetSnapId_C",PetscViewerGLVisSetSnapId_GLVis)); 743 CHKERRQ(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetFields_C",PetscViewerGLVisSetFields_GLVis)); 744 CHKERRQ(PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",PetscViewerFileSetName_GLVis)); 745 PetscFunctionReturn(0); 746 } 747 748 /* this is a private implementation of a SOCKET with ASCII data format 749 GLVis does not currently handle binary socket streams */ 750 #if defined(PETSC_HAVE_UNISTD_H) 751 #include <unistd.h> 752 #endif 753 754 #if !defined(PETSC_HAVE_WINDOWS_H) 755 static PetscErrorCode (*PetscViewerDestroy_ASCII)(PetscViewer); 756 757 static PetscErrorCode PetscViewerDestroy_ASCII_Socket(PetscViewer viewer) 758 { 759 FILE *stream; 760 PetscErrorCode ierr = 0; 761 PetscFunctionBegin; 762 CHKERRQ(PetscViewerASCIIGetPointer(viewer,&stream)); 763 if (stream) { 764 ierr = fclose(stream); 765 PetscCheck(!ierr,PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on stream"); 766 } 767 CHKERRQ(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 PetscValidPointer(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 CHKERRQ(PetscSNPrintf(err,1024,"Cannot connect to socket on %s:%" PetscInt_FMT ". Socket visualization is disabled\n",hostname,port)); 795 CHKERRQ(PetscInfo(NULL,"%s",err)); 796 *viewer = NULL; 797 PetscFunctionReturn(sierr); 798 } else { 799 char msg[1024]; 800 801 CHKERRQ(PetscSNPrintf(msg,1024,"Successfully connect to socket on %s:%" PetscInt_FMT ". Socket visualization is enabled\n",hostname,port)); 802 CHKERRQ(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 CHKERRQ(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 CHKERRMPI(MPIU_Allreduce(&flag,&brokenpipe,1,MPIU_BOOL,MPI_LOR,comm)); 851 if (brokenpipe) { 852 FILE *sock, *null = fopen(PETSC_DEVNULL,"w"); 853 CHKERRQ(PetscViewerASCIIGetPointer(*win,&sock)); 854 CHKERRQ(PetscViewerASCIISetFILE(*win,null)); 855 CHKERRQ(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