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 PetscMPIInt rank; 282 char filename[PETSC_MAX_PATH_LEN]; 283 284 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank);CHKERRQ(ierr); 285 ierr = PetscSNPrintf(filename,PETSC_MAX_PATH_LEN,"%s-mesh.%06d",socket->name,rank);CHKERRQ(ierr); 286 ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&socket->meshwindow);CHKERRQ(ierr); 287 } 288 if (socket->meshwindow) { 289 ierr = PetscViewerPushFormat(socket->meshwindow,PETSC_VIEWER_ASCII_GLVIS);CHKERRQ(ierr); 290 } 291 } 292 if (socket->meshwindow) { 293 ierr = PetscViewerGLVisAttachInfo_Private(viewer,socket->meshwindow);CHKERRQ(ierr); 294 } 295 *view = socket->meshwindow; 296 PetscFunctionReturn(0); 297 } 298 299 PetscErrorCode PetscViewerGLVisGetType_Private(PetscViewer viewer,PetscViewerGLVisType *type) 300 { 301 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 302 303 PetscFunctionBegin; 304 PetscValidPointer(type,2); 305 *type = socket->type; 306 PetscFunctionReturn(0); 307 } 308 309 /* 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 */ 310 PetscErrorCode PetscViewerGLVisGetStatus_Private(PetscViewer viewer, PetscViewerGLVisStatus *sockstatus) 311 { 312 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 313 314 PetscFunctionBegin; 315 PetscValidPointer(sockstatus,2); 316 if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { 317 socket->status = PETSCVIEWERGLVIS_DISCONNECTED; 318 } else if (socket->status == PETSCVIEWERGLVIS_DISCONNECTED && socket->nwindow) { 319 PetscInt i; 320 PetscBool lconn,conn; 321 PetscErrorCode ierr; 322 323 for (i=0,lconn=PETSC_TRUE;i<socket->nwindow;i++) 324 if (!socket->window[i]) 325 lconn = PETSC_FALSE; 326 327 ierr = MPI_Allreduce(&lconn,&conn,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)viewer));CHKERRQ(ierr); 328 if (conn) socket->status = PETSCVIEWERGLVIS_CONNECTED; 329 } 330 *sockstatus = socket->status; 331 PetscFunctionReturn(0); 332 } 333 334 PetscErrorCode PetscViewerGLVisGetDM_Private(PetscViewer viewer, PetscObject* dm) 335 { 336 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 337 338 PetscFunctionBegin; 339 *dm = socket->dm; 340 PetscFunctionReturn(0); 341 } 342 343 PetscErrorCode PetscViewerGLVisGetFields_Private(PetscViewer viewer, PetscInt* nfield, const char **fec[], PetscInt *spacedim[], PetscErrorCode(**g2lfield)(PetscObject,PetscInt,PetscObject[],void*), PetscObject *Ufield[], void **userctx) 344 { 345 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 346 347 PetscFunctionBegin; 348 if (nfield) *nfield = socket->nwindow; 349 if (fec) *fec = (const char**)socket->fec_type; 350 if (spacedim) *spacedim = socket->spacedim; 351 if (g2lfield) *g2lfield = socket->g2lfield; 352 if (Ufield) *Ufield = socket->Ufield; 353 if (userctx) *userctx = socket->userctx; 354 PetscFunctionReturn(0); 355 } 356 357 /* accessor routines for the viewer windows: 358 PETSC_VIEWER_GLVIS_DUMP : it returns a new viewer every time 359 PETSC_VIEWER_GLVIS_SOCKET : it returns the socket, and creates it if not yet done. 360 */ 361 PetscErrorCode PetscViewerGLVisGetWindow_Private(PetscViewer viewer,PetscInt wid,PetscViewer* view) 362 { 363 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 364 PetscViewerGLVisStatus status; 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 get window id %D: allowed range [0,%D)",wid,socket->nwindow-1); 371 status = socket->status; 372 if (socket->type == PETSC_VIEWER_GLVIS_DUMP && socket->window[wid]) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_USER,"Window %D is already in use",wid); 373 switch (status) { 374 case PETSCVIEWERGLVIS_DISCONNECTED: 375 if (socket->window[wid]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"This should not happen"); 376 if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { 377 PetscMPIInt rank; 378 char filename[PETSC_MAX_PATH_LEN]; 379 380 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)viewer),&rank);CHKERRQ(ierr); 381 ierr = PetscSNPrintf(filename,PETSC_MAX_PATH_LEN,"%s-%s-%d.%06d",socket->name,socket->windowtitle[wid],socket->snapid,rank);CHKERRQ(ierr); 382 ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,filename,&socket->window[wid]);CHKERRQ(ierr); 383 } else { 384 ierr = PetscViewerGLVisGetNewWindow_Private(viewer,&socket->window[wid]);CHKERRQ(ierr); 385 } 386 if (socket->window[wid]) { 387 ierr = PetscViewerPushFormat(socket->window[wid],PETSC_VIEWER_ASCII_GLVIS);CHKERRQ(ierr); 388 } 389 *view = socket->window[wid]; 390 break; 391 case PETSCVIEWERGLVIS_CONNECTED: 392 *view = socket->window[wid]; 393 break; 394 case PETSCVIEWERGLVIS_DISABLED: 395 *view = NULL; 396 break; 397 default: 398 SETERRQ1(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Unhandled socket status %d\n",(int)status); 399 break; 400 } 401 if (*view) { 402 ierr = PetscViewerGLVisAttachInfo_Private(viewer,*view);CHKERRQ(ierr); 403 } 404 PetscFunctionReturn(0); 405 } 406 407 /* Restore the window viewer 408 PETSC_VIEWER_GLVIS_DUMP : destroys the temporary created ASCII viewer used for dumping 409 PETSC_VIEWER_GLVIS_SOCKET: - if the returned window viewer is not NULL, just zeros the pointer. 410 - it the returned window viewer is NULL, assumes something went wrong 411 with the socket (i.e. SIGPIPE when a user closes the popup window) 412 and that the caller already handled it (see VecView_GLVis). 413 */ 414 PetscErrorCode PetscViewerGLVisRestoreWindow_Private(PetscViewer viewer,PetscInt wid, PetscViewer* view) 415 { 416 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 417 PetscErrorCode ierr; 418 419 PetscFunctionBegin; 420 PetscValidLogicalCollectiveInt(viewer,wid,2); 421 PetscValidPointer(view,3); 422 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); 423 if (*view && *view != socket->window[wid]) SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_USER,"Viewer was not obtained from PetscViewerGLVisGetWindow"); 424 if (*view) { 425 ierr = PetscViewerFlush(*view);CHKERRQ(ierr); 426 ierr = PetscBarrier((PetscObject)viewer);CHKERRQ(ierr); 427 } 428 if (socket->type == PETSC_VIEWER_GLVIS_DUMP) { /* destroy the viewer, as it is associated with a single time step */ 429 ierr = PetscViewerDestroy(&socket->window[wid]);CHKERRQ(ierr); 430 } else if (!*view) { /* something went wrong (SIGPIPE) so we just zero the private pointer */ 431 socket->window[wid] = NULL; 432 } 433 *view = NULL; 434 PetscFunctionReturn(0); 435 } 436 437 /* default window appearance in the PETSC_VIEWER_GLVIS_SOCKET case */ 438 PetscErrorCode PetscViewerGLVisInitWindow_Private(PetscViewer viewer, PetscBool mesh, PetscInt dim, const char *name) 439 { 440 PetscErrorCode ierr; 441 PetscViewerGLVisInfo info; 442 PetscContainer container; 443 444 PetscFunctionBegin; 445 ierr = PetscObjectQuery((PetscObject)viewer,"_glvis_info_container",(PetscObject*)&container);CHKERRQ(ierr); 446 if (!container) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Viewer was not obtained from PetscGLVisViewerGetNewWindow_Private"); 447 ierr = PetscContainerGetPointer(container,(void**)&info);CHKERRQ(ierr); 448 if (info->init) { 449 if (info->pause < 0) { 450 ierr = PetscViewerASCIIPrintf(viewer,"pause\n");CHKERRQ(ierr); /* pause */ 451 } 452 PetscFunctionReturn(0); 453 } 454 ierr = PetscViewerASCIIPrintf(viewer,"window_size 800 800\n");CHKERRQ(ierr); 455 if (name) { 456 ierr = PetscViewerASCIIPrintf(viewer,"window_title '%s'\n",name);CHKERRQ(ierr); 457 } 458 if (mesh) { 459 switch (dim) { 460 case 1: 461 break; 462 case 2: 463 ierr = PetscViewerASCIIPrintf(viewer,"keys cmeeppppp\n");CHKERRQ(ierr); /* show colorbar, mesh and ranks */ 464 break; 465 case 3: /* TODO: decide default view in 3D */ 466 break; 467 } 468 } else { 469 ierr = PetscViewerASCIIPrintf(viewer,"keys cm\n");CHKERRQ(ierr); /* show colorbar and mesh */ 470 switch (dim) { 471 case 1: 472 ierr = PetscViewerASCIIPrintf(viewer,"keys RRj\n");CHKERRQ(ierr); /* set to 1D (side view) and turn off perspective */ 473 break; 474 case 2: 475 ierr = PetscViewerASCIIPrintf(viewer,"keys Rjl\n");CHKERRQ(ierr); /* set to 2D (top view), turn off perspective and light */ 476 break; 477 case 3: 478 break; 479 } 480 ierr = PetscViewerASCIIPrintf(viewer,"autoscale value\n");CHKERRQ(ierr); /* update value-range; keep mesh-extents fixed */ 481 if (info->pause == 0) { 482 ierr = PetscViewerASCIIPrintf(viewer,"pause\n");CHKERRQ(ierr); /* pause */ 483 } 484 } 485 info->init = PETSC_TRUE; 486 PetscFunctionReturn(0); 487 } 488 489 static PetscErrorCode PetscViewerDestroy_GLVis(PetscViewer viewer) 490 { 491 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 492 PetscInt i; 493 PetscErrorCode ierr; 494 495 PetscFunctionBegin; 496 for (i=0;i<socket->nwindow;i++) { 497 ierr = PetscViewerDestroy(&socket->window[i]);CHKERRQ(ierr); 498 ierr = PetscFree(socket->windowtitle[i]);CHKERRQ(ierr); 499 ierr = PetscFree(socket->fec_type[i]);CHKERRQ(ierr); 500 ierr = PetscObjectDestroy(&socket->Ufield[i]);CHKERRQ(ierr); 501 } 502 ierr = PetscFree(socket->name);CHKERRQ(ierr); 503 ierr = PetscFree5(socket->window,socket->windowtitle,socket->fec_type,socket->spacedim,socket->Ufield);CHKERRQ(ierr); 504 ierr = PetscFree(socket->fmt);CHKERRQ(ierr); 505 ierr = PetscViewerDestroy(&socket->meshwindow);CHKERRQ(ierr); 506 ierr = PetscObjectDestroy(&socket->dm);CHKERRQ(ierr); 507 if (socket->destroyctx && socket->userctx) { ierr = (*socket->destroyctx)(socket->userctx);CHKERRQ(ierr); } 508 509 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetPrecision_C",NULL);CHKERRQ(ierr); 510 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetSnapId_C",NULL);CHKERRQ(ierr); 511 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetFields_C",NULL);CHKERRQ(ierr); 512 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",NULL);CHKERRQ(ierr); 513 ierr = PetscFree(socket);CHKERRQ(ierr); 514 viewer->data = NULL; 515 PetscFunctionReturn(0); 516 } 517 518 static PetscErrorCode PetscViewerSetFromOptions_GLVis(PetscOptionItems *PetscOptionsObject,PetscViewer v) 519 { 520 PetscErrorCode ierr; 521 PetscViewerGLVis socket = (PetscViewerGLVis)v->data; 522 523 PetscFunctionBegin; 524 ierr = PetscOptionsHead(PetscOptionsObject,"GLVis PetscViewer Options");CHKERRQ(ierr); 525 ierr = PetscOptionsReal("-viewer_glvis_pause","-1 to pause after each visualization, otherwise sleeps for given seconds",NULL,socket->pause,&socket->pause,NULL);CHKERRQ(ierr); 526 ierr = PetscOptionsTail();CHKERRQ(ierr); 527 PetscFunctionReturn(0); 528 } 529 530 static PetscErrorCode PetscViewerSetFileName_GLVis(PetscViewer viewer, const char name[]) 531 { 532 char *sport; 533 PetscViewerGLVis socket = (PetscViewerGLVis)viewer->data; 534 PetscErrorCode ierr; 535 536 PetscFunctionBegin; 537 socket->type = PETSC_VIEWER_GLVIS_DUMP; 538 /* we accept localhost^port */ 539 ierr = PetscFree(socket->name);CHKERRQ(ierr); 540 ierr = PetscStrallocpy(name,&socket->name);CHKERRQ(ierr); 541 ierr = PetscStrchr(socket->name,'^',&sport);CHKERRQ(ierr); 542 if (sport) { 543 PetscInt port = 19916; 544 size_t len; 545 546 *sport++ = 0; 547 ierr = PetscStrlen(sport,&len);CHKERRQ(ierr); 548 if (len) ierr = PetscOptionsStringToInt(sport,&port); 549 if (!ierr) { 550 socket->port = (port != PETSC_DECIDE && port != PETSC_DEFAULT) ? port : 19916; 551 } else { 552 socket->port = 19916; 553 } 554 socket->type = PETSC_VIEWER_GLVIS_SOCKET; 555 } 556 PetscFunctionReturn(0); 557 } 558 559 /* 560 PetscViewerGLVisOpen - Opens a GLVis type viewer 561 562 Collective on comm 563 564 Input Parameters: 565 + comm - the MPI communicator 566 . type - the viewer type: PETSC_VIEWER_GLVIS_SOCKET for real-time visualization or PETSC_VIEWER_GLVIS_DUMP for dumping to disk 567 . name - either the hostname where the GLVis server is running or the base filename for dumping the data for subsequent visualizations 568 - port - socket port where the GLVis server is listening. Not referenced when type is PETSC_VIEWER_GLVIS_DUMP 569 570 Output Parameters: 571 - viewer - the PetscViewer object 572 573 Notes: misses Fortran binding 574 575 Level: beginner 576 577 .seealso: PetscViewerCreate(), PetscViewerSetType(), PetscViewerGLVisType 578 */ 579 PETSC_EXTERN PetscErrorCode PetscViewerGLVisOpen(MPI_Comm comm, PetscViewerGLVisType type, const char* name, PetscInt port, PetscViewer* viewer) 580 { 581 PetscViewerGLVis socket; 582 PetscErrorCode ierr; 583 584 PetscFunctionBegin; 585 ierr = PetscViewerCreate(comm,viewer);CHKERRQ(ierr); 586 ierr = PetscViewerSetType(*viewer,PETSCVIEWERGLVIS);CHKERRQ(ierr); 587 588 socket = (PetscViewerGLVis)((*viewer)->data); 589 ierr = PetscFree(socket->name);CHKERRQ(ierr); 590 ierr = PetscStrallocpy(name,&socket->name);CHKERRQ(ierr); 591 socket->type = type; 592 socket->port = port; 593 594 ierr = PetscViewerSetFromOptions(*viewer);CHKERRQ(ierr); 595 PetscFunctionReturn(0); 596 } 597 598 /* 599 PETSC_VIEWER_GLVIS_ - Creates an GLVIS PetscViewer shared by all processors in a communicator. 600 601 Collective on MPI_Comm 602 603 Input Parameter: 604 . comm - the MPI communicator to share the GLVIS PetscViewer 605 606 Level: intermediate 607 608 Notes: misses Fortran bindings 609 610 Environmental variables: 611 + PETSC_VIEWER_GLVIS_FILENAME : output filename (if specified dump to disk, and takes precedence on PETSC_VIEWER_GLVIS_HOSTNAME) 612 . PETSC_VIEWER_GLVIS_HOSTNAME : machine where the GLVis server is listening (defaults to localhost) 613 - PETSC_VIEWER_GLVIS_PORT : port opened by the GLVis server (defaults to 19916) 614 615 Notes: 616 Unlike almost all other PETSc routines, PETSC_VIEWER_GLVIS_ does not return 617 an error code. The GLVIS PetscViewer is usually used in the form 618 $ XXXView(XXX object, PETSC_VIEWER_GLVIS_(comm)); 619 620 .seealso: PetscViewerGLVISOpen(), PetscViewerGLVisType, PetscViewerCreate(), PetscViewerDestroy() 621 */ 622 PETSC_EXTERN PetscViewer PETSC_VIEWER_GLVIS_(MPI_Comm comm) 623 { 624 PetscErrorCode ierr; 625 PetscBool flg; 626 PetscViewer viewer; 627 PetscViewerGLVisType type; 628 char fname[PETSC_MAX_PATH_LEN],sport[16]; 629 PetscInt port = 19916; /* default for GLVis */ 630 631 PetscFunctionBegin; 632 ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_FILENAME",fname,PETSC_MAX_PATH_LEN,&flg); 633 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 634 if (!flg) { 635 type = PETSC_VIEWER_GLVIS_SOCKET; 636 ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_HOSTNAME",fname,PETSC_MAX_PATH_LEN,&flg); 637 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 638 if (!flg) { 639 ierr = PetscStrcpy(fname,"localhost"); 640 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 641 } 642 ierr = PetscOptionsGetenv(comm,"PETSC_VIEWER_GLVIS_PORT",sport,16,&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 = PetscOptionsStringToInt(sport,&port); 646 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 647 } 648 } else { 649 type = PETSC_VIEWER_GLVIS_DUMP; 650 } 651 ierr = PetscViewerGLVisOpen(comm,type,fname,port,&viewer); 652 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 653 ierr = PetscObjectRegisterDestroy((PetscObject)viewer); 654 if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_VIEWER_GLVIS_",__FILE__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," ");PetscFunctionReturn(0);} 655 PetscFunctionReturn(viewer); 656 } 657 658 PETSC_EXTERN PetscErrorCode PetscViewerCreate_GLVis(PetscViewer viewer) 659 { 660 PetscViewerGLVis socket; 661 PetscErrorCode ierr; 662 663 PetscFunctionBegin; 664 ierr = PetscNewLog(viewer,&socket);CHKERRQ(ierr); 665 666 /* defaults to socket viewer */ 667 ierr = PetscStrallocpy("localhost",&socket->name);CHKERRQ(ierr); 668 socket->port = 19916; /* GLVis default listening port */ 669 socket->type = PETSC_VIEWER_GLVIS_SOCKET; 670 socket->pause = 0; /* just pause the first time */ 671 672 /* defaults to full precision */ 673 ierr = PetscStrallocpy(" %g",&socket->fmt);CHKERRQ(ierr); 674 675 viewer->data = (void*)socket; 676 viewer->ops->destroy = PetscViewerDestroy_GLVis; 677 viewer->ops->setfromoptions = PetscViewerSetFromOptions_GLVis; 678 679 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetPrecision_C",PetscViewerGLVisSetPrecision_GLVis);CHKERRQ(ierr); 680 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetSnapId_C",PetscViewerGLVisSetSnapId_GLVis);CHKERRQ(ierr); 681 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerGLVisSetFields_C",PetscViewerGLVisSetFields_GLVis);CHKERRQ(ierr); 682 ierr = PetscObjectComposeFunction((PetscObject)viewer,"PetscViewerFileSetName_C",PetscViewerSetFileName_GLVis);CHKERRQ(ierr); 683 PetscFunctionReturn(0); 684 } 685 686 /* this is a private implementation of a SOCKET with ASCII data format 687 GLVis does not currently handle binary socket streams */ 688 #if defined(PETSC_HAVE_UNISTD_H) 689 #include <unistd.h> 690 #endif 691 692 #if !defined(PETSC_HAVE_WINDOWS_H) 693 static PetscErrorCode (*PetscViewerDestroy_ASCII)(PetscViewer); 694 695 static PetscErrorCode PetscViewerDestroy_ASCII_Socket(PetscViewer viewer) 696 { 697 FILE *stream; 698 PetscErrorCode ierr = 0; 699 PetscFunctionBegin; 700 ierr = PetscViewerASCIIGetPointer(viewer,&stream);CHKERRQ(ierr); 701 if (stream) { 702 ierr = fclose(stream); 703 if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fclose() failed on stream"); 704 } 705 ierr = PetscViewerDestroy_ASCII(viewer);CHKERRQ(ierr); 706 PetscFunctionReturn(0); 707 } 708 #endif 709 710 static PetscErrorCode PetscViewerASCIISocketOpen(MPI_Comm comm,const char* hostname,PetscInt port,PetscViewer* viewer) 711 { 712 #if defined(PETSC_HAVE_WINDOWS_H) 713 PetscFunctionBegin; 714 SETERRQ(comm,PETSC_ERR_SUP,"Not implemented for Windows"); 715 #else 716 FILE *stream = NULL; 717 int fd; 718 PetscErrorCode ierr; 719 720 PetscFunctionBegin; 721 PetscValidPointer(hostname,2); 722 PetscValidPointer(viewer,4); 723 #if defined(PETSC_USE_SOCKET_VIEWER) 724 ierr = PetscOpenSocket(hostname,port,&fd); 725 #else 726 SETERRQ(comm,PETSC_ERR_SUP,"Missing Socket viewer"); 727 #endif 728 if (ierr) { 729 PetscInt sierr = ierr; 730 char err[1024]; 731 732 ierr = PetscSNPrintf(err,1024,"Cannot connect to socket on %s:%D. Socket visualization is disabled\n",hostname,port);CHKERRQ(ierr); 733 ierr = PetscInfo(NULL,err);CHKERRQ(ierr); 734 *viewer = NULL; 735 PetscFunctionReturn(sierr); 736 } else { 737 char msg[1024]; 738 739 ierr = PetscSNPrintf(msg,1024,"Successfully connect to socket on %s:%D. Socket visualization is enabled\n",hostname,port);CHKERRQ(ierr); 740 ierr = PetscInfo(NULL,msg);CHKERRQ(ierr); 741 } 742 stream = fdopen(fd,"w"); /* Not possible on Windows */ 743 if (!stream) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Cannot open stream from socket %s:%d",hostname,port); 744 ierr = PetscViewerASCIIOpenWithFILE(PETSC_COMM_SELF,stream,viewer);CHKERRQ(ierr); 745 PetscViewerDestroy_ASCII = (*viewer)->ops->destroy; 746 (*viewer)->ops->destroy = PetscViewerDestroy_ASCII_Socket; 747 #endif 748 PetscFunctionReturn(0); 749 } 750