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