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