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