1 | /*************************************** 2 | $Header: /cvsroot/petscgraphics/tsview.c,v 1.35 2004/07/02 20:50:41 hazelsct Exp $ 3 | 4 | This program views the output of a time series saved using 5 | +latex+{\tt IlluMultiSave()}. 6 | +html+ <tt>IlluMultiSave()</tt>. 7 | It basically just switches between timesteps; future versions may be more 8 | interesting. The neat part of it is that it loads multiprocessor data and 9 | displays it on a single CPU. 10 | ***************************************/ 11 | 12 | static char help[] = "Displays the output of of a timestep series saved using IlluMultiSave().\n\ 13 | Usage:\n\ 14 | \n\ 15 | tsview <basename> [-no_transparency]\n\ 16 | \n\ 17 | Then interactively flip through the timesteps (h or ? lists commands).\n"; 18 | 19 | #define HELP_STRING "tsview commands:\n\ 20 | <enter> Display next timestep\n\ 21 | b Display previous timestep\n\ 22 | i increment Set the next timestep increment\n\ 23 | ### Jump to timestep ###\n\ 24 | t Toggle Geomview transparency (3-D only)\n\ 25 | v Change field displayed (3-D only)\n\ 26 | p [v1 v2 ...] Set contour values for plotting or \"auto\" (3-D only)\n\ 27 | r Reloads entries in a directory\n\ 28 | s size Set maximum dimension of PETSc viewer windows (2-D only)\n\ 29 | cx, cy, cz Toggle xcut, ycut, zcut (cut last row/plane of periodic DA)\n\ 30 | gx30-90, y,z Set plot x range to 30-90, same for y and z\n\ 31 | h/? Print this information\n\ 32 | q/x Quit tsview\n" 33 | 34 | #include "illuminator.h" 35 | #include <sys/dir.h> /* For scandir(), alphasort, struct dirent */ 36 | #include <libgen.h> /* For dirname(), basename() */ 37 | #include <string.h> /* For strdup() */ 38 | #include <stdlib.h> /* Needed for readline stuff below */ 39 | #include <term.h> /* ncurses header for readline */ 40 | #include <readline/readline.h> /* For command line editing */ 41 | #include <readline/history.h> /* For command line history */ 42 | 43 | /* Build with -DDEBUG for debugging output */ 44 | #undef DPRINTF 45 | #ifdef DEBUG 46 | #define DPRINTF(fmt, args...) PetscPrintf (PETSC_COMM_WORLD, "%s: " fmt, __FUNCT__, args) 47 | #else 48 | #define DPRINTF(fmt, args...) 49 | #endif 50 | 51 | char *basefilename; 52 | 53 | 54 | #undef __FUNCT__ 55 | #define __FUNCT__ "myfilter" 56 | 57 | /*++++++++++++++++++++++++++++++++++++++ 58 | This function returns non-zero for "qualifying" file names which start with 59 | the stored files' basename and end with 60 | +latex+{\tt .cpu0000.meta}. 61 | +html+ <tt>.cpu0000.meta</tt>. 62 | It is used as the 63 | +latex+{\tt select()} function for {\tt scandir()} in {\tt main()}. 64 | +html+ <tt>select()</tt> function for <tt>scandir()</tt> in <tt>main()</tt>. 65 | 66 | int myfilter Returns non-zero for qualifying filenames. 67 | 68 | const struct dirent *direntry Directory entry with filename to test. 69 | ++++++++++++++++++++++++++++++++++++++*/ 70 | 71 | int myfilter (const struct dirent *direntry) 72 | { 73 | if ((!strncmp (direntry->d_name, basefilename, strlen(basefilename)))) 74 | return (!strncmp (direntry->d_name + strlen(direntry->d_name) - 13, 75 | ".cpu0000.meta", 13)); 76 | return 0; 77 | } 78 | 79 | 80 | /*+++++++++++++++++++++++++++++++++++++ 81 | 82 | Functions for reading the command line 83 | and avoiding reading empty lines 84 | 85 | Probably this function is not Petsc 86 | safe, but we'll see. 87 | 88 | +++++++++++++++++++++++++++++++++++++*/ 89 | 90 | /* A static variable for holding the line. */ 91 | static char *line_read = (char *)NULL; 92 | 93 | /* Read a string, and return a pointer to it. 94 | Returns NULL on EOF. */ 95 | 96 | 97 | 98 | char* rl_gets (char* message) 99 | { 100 | /* If the buffer has already been allocated, 101 | return the memory to the free pool. */ 102 | if (line_read) 103 | { 104 | free (line_read); 105 | line_read = (char *)NULL; 106 | } 107 | 108 | /* Get a line from the user. */ 109 | line_read = readline (message); 110 | 111 | /* If the line has any text in it, 112 | save it on the history. */ 113 | if (line_read && *line_read) 114 | add_history (line_read); 115 | 116 | return (line_read); 117 | } 118 | 119 | 120 | /* 121 | Failed attempt to make a Petsc safe readline 122 | Lefted here for reference 123 | 124 | It is based on PetscSynchronizedFGets, but instead of using 125 | fgets() it uses rl_gets() 126 | 127 | */ 128 | 129 | int PetscSynchronizedFReadline(MPI_Comm comm,char* message,char* string) 130 | { 131 | int ierr,rank, len; 132 | PetscFunctionBegin; 133 | ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 134 | 135 | /* First processor prints immediately to stdin*/ 136 | if (!rank) { 137 | string = rl_gets(message); 138 | } 139 | 140 | len = strlen(string); 141 | 142 | ierr = MPI_Bcast(string,len,MPI_BYTE,0,comm);CHKERRQ(ierr); 143 | PetscFunctionReturn(0); 144 | } 145 | 146 | 147 | #undef __FUNCT__ 148 | #define __FUNCT__ "main" 149 | 150 | /*++++++++++++++++++++++++++++++++++++++ 151 | This is 152 | +latex+{\tt main()}. 153 | +html+ <tt>main()</tt>. 154 | 155 | int main It returns an int to the OS. 156 | 157 | int argc Argument count. 158 | 159 | char *argv[] Arguments. 160 | ++++++++++++++++++++++++++++++++++++++*/ 161 | 162 | int main (int argc, char *argv[]) 163 | { 164 | int total_entries, current_entry, dims, i, ierr, windowsize=300, plots=0, 165 | increment=1, xmin=0,xmax=-1, ymin=0,ymax=-1, zmin=0,zmax=-1; 166 | struct dirent **namelist; 167 | char **files, *thefilename, *filec, *dirc, *basedirname; 168 | PetscViewer theviewer; 169 | PetscTruth loaded = PETSC_FALSE, transp=PETSC_TRUE; 170 | 171 | if (argc<2) 172 | { 173 | ierr = PetscPrintf (PETSC_COMM_WORLD, "Usage: tsview basename\n"); 174 | CHKERRQ (ierr); 175 | return 1; 176 | } 177 | 178 | /*+ After 179 | +latex+{\tt PETSc} 180 | +html+ <tt>PETSc</tt> 181 | initialization, it gets the list of files matching the basename. +*/ 182 | ierr = PetscInitialize (&argc, &argv, (char *)0, help); CHKERRQ (ierr); 183 | 184 | DPRINTF ("Command line:",0); CHKERRQ (ierr); 185 | #ifdef DEBUG 186 | for (i=0; i<argc; i++) 187 | { 188 | ierr = PetscPrintf (PETSC_COMM_WORLD, " %s", argv[i]); CHKERRQ (ierr); 189 | } 190 | ierr = PetscPrintf (PETSC_COMM_WORLD, "\n"); CHKERRQ (ierr); 191 | #endif 192 | 193 | filec = strdup (argv[1]); 194 | dirc = strdup (argv[1]); 195 | basefilename = basename (filec); 196 | basedirname = dirname (dirc); 197 | 198 | ierr = PetscOptionsHasName (PETSC_NULL, "-no_transparency", &transp); 199 | CHKERRQ (ierr); 200 | transp = !transp; 201 | 202 | total_entries = scandir (basedirname, &namelist, myfilter, alphasort); 203 | if (!total_entries) 204 | { 205 | ierr = PetscPrintf (PETSC_COMM_WORLD, "No such files, exiting\n"); 206 | CHKERRQ (ierr); 207 | exit (1); 208 | } 209 | if (total_entries < 0) 210 | { 211 | ierr = PetscPrintf (PETSC_COMM_WORLD, "Error scanning directory %s\n", 212 | basedirname); CHKERRQ (ierr); 213 | ierr = PetscFinalize (); CHKERRQ(ierr); 214 | return 1; 215 | } 216 | ierr = PetscPrintf (PETSC_COMM_WORLD, "%d eligible files:\n", total_entries); 217 | CHKERRQ (ierr); 218 | 219 | if (!(files = (char **) malloc (total_entries * sizeof (char *)))) 220 | { 221 | ierr = PetscPrintf (PETSC_COMM_WORLD, "Error allocating memory\n"); 222 | CHKERRQ (ierr); 223 | ierr = PetscFinalize (); CHKERRQ(ierr); 224 | return 1; 225 | } 226 | for (i=0; i<total_entries; i++) 227 | { 228 | int filength = strlen(namelist[i]->d_name); 229 | 230 | files [i] = (char *) malloc ((filength-12)*sizeof(char)); 231 | strncpy (files [i], namelist[i]->d_name, filength-13); 232 | files [i] [filength-13] = '\0'; 233 | free (namelist[i]); 234 | ierr = PetscPrintf (PETSC_COMM_WORLD, "[%d] %s\n", i, files [i]); 235 | CHKERRQ (ierr); 236 | } 237 | free (namelist); 238 | 239 | /*+In the main loop, the various timesteps are displayed, with options: 240 | +latex+\begin{itemize} \item 241 | +html+ <ul><li> 242 | A number jumps to that entry in the files table. 243 | +latex+\item {\stt <return>} 244 | +html+ <li><tt><return></tt> 245 | loads the next file. 246 | +latex+\item {\tt b} 247 | +html+ <li><tt>b</tt> 248 | goes back one file. 249 | +latex+\item {\tt q} 250 | +html+ <li><tt>q</tt> 251 | quits the program. 252 | +latex+\end{itemize} 253 | +html+ </ul> 254 | +*/ 255 | current_entry=0; 256 | while (1) 257 | { 258 | DA theda; 259 | Vec global; 260 | int usermetacount=0, fields, display_field; 261 | char basis [strlen(argv[1]) + 20], **usermetanames, **usermetadata, 262 | *instring; 263 | PetscScalar minmax[6], plot_vals[6], plot_colors[24] = 264 | { 1.,0.,0.,.5, 1.,1.,0.,.5, 0.,1.,0.,.5, 0.,1.,1.,.5, 0.,0.,1.,.5, 265 | 1.,0.,1.,.5 }; 266 | field_plot_type *fieldtypes; 267 | 268 | /* Load the vector */ 269 | strcpy (basis, basedirname); 270 | strcat (basis, "/"); 271 | strcat (basis, files[current_entry]); 272 | ierr = PetscPrintf (PETSC_COMM_WORLD, "Loading entry %d, basename %s\n", 273 | current_entry, basis); 274 | if (loaded) 275 | { 276 | ierr = IlluMultiRead (theda, global, basis, &usermetacount, 277 | &usermetanames, &usermetadata); 278 | CHKERRQ (ierr); 279 | } 280 | else 281 | { 282 | DPRINTF ("Loading first timestep, creating distributed array\n",0); 283 | display_field = 0; 284 | minmax [0] = minmax [2] = minmax [4] = 0.; 285 | minmax [1] = minmax [3] = minmax [5] = 1.; 286 | ierr = IlluMultiLoad (basis, &theda, minmax+1, minmax+3, minmax+5, 287 | &fieldtypes, &usermetacount, &usermetanames, 288 | &usermetadata); CHKERRQ (ierr); 289 | ierr = DAGetGlobalVector (theda, &global); CHKERRQ (ierr); 290 | loaded = PETSC_TRUE; 291 | 292 | ierr = DAGetInfo (theda, &dims, PETSC_NULL,PETSC_NULL,PETSC_NULL, 293 | PETSC_NULL,PETSC_NULL,PETSC_NULL, &fields, 294 | PETSC_NULL,PETSC_NULL,PETSC_NULL); CHKERRQ (ierr); 295 | 296 | /* Usermetadata xwidth, ywidth, zwidth override minmax in case 297 | version is 0.1. */ 298 | for (i=0; i<usermetacount; i++) 299 | { 300 | if (!strncmp (usermetanames [i], "xwidth", 6)) 301 | sscanf (usermetadata [i], "%lf", minmax+1); 302 | else if (!strncmp (usermetanames [i], "ywidth", 6)) 303 | sscanf (usermetadata [i], "%lf", minmax+3); 304 | else if (!strncmp (usermetanames [i], "zwidth", 6)) 305 | sscanf (usermetadata [i], "%lf", minmax+5); 306 | } 307 | 308 | if (dims<3) 309 | { 310 | int width=windowsize, height=windowsize; 311 | 312 | ierr = PetscPrintf (PETSC_COMM_WORLD, 313 | "For viewing 2-D data, try tsview-ng!\n"); 314 | CHKERRQ (ierr); 315 | 316 | if (minmax[1]<minmax[3]) 317 | width *= minmax[1]/minmax[3]; 318 | else 319 | height *= minmax[3]/minmax[1]; 320 | 321 | ierr = PetscViewerDrawOpen 322 | (PETSC_COMM_WORLD, 0, "", PETSC_DECIDE, PETSC_DECIDE, 323 | width, height, &theviewer); CHKERRQ (ierr); 324 | } 325 | else 326 | { 327 | ierr = GeomviewBegin (PETSC_COMM_WORLD); 328 | } 329 | } 330 | 331 | /* Print user data */ 332 | ierr = PetscPrintf (PETSC_COMM_WORLD, "User data:\n"); CHKERRQ (ierr); 333 | for (i=0; i<usermetacount; i++) 334 | { 335 | ierr = PetscPrintf (PETSC_COMM_WORLD, "%s = %s\n", usermetanames [i], 336 | usermetadata [i]); CHKERRQ (ierr); 337 | } 338 | 339 | /* View the vector */ 340 | if (dims<3) 341 | { 342 | ierr = VecView (global, theviewer); CHKERRQ (ierr); 343 | } 344 | else 345 | { 346 | /*+ The Illuminator-based 3-D viewer can only display one field at a 347 | time. At the beginning, that is field 0, and is cycled using the 348 | +latex+{\tt v} 349 | +html+ <tt>v</tt> 350 | command. +*/ 351 | PetscScalar minval, maxval; 352 | char *fieldname; 353 | 354 | ierr = VecStrideMin (global, display_field, PETSC_NULL, &minval); 355 | CHKERRQ (ierr); 356 | ierr = VecStrideMax (global, display_field, PETSC_NULL, &maxval); 357 | CHKERRQ (ierr); 358 | ierr = DAGetFieldName (theda, display_field, &fieldname); 359 | CHKERRQ (ierr); 360 | ierr = PetscPrintf (PETSC_COMM_WORLD, 361 | "Displaying field %d [%g-%g]: %s\n", 362 | display_field, minval, maxval, fieldname); 363 | CHKERRQ (ierr); 364 | 365 | DPRINTF ("Calculating triangle locations\n",0); 366 | if (plots) 367 | { 368 | ierr = DATriangulateRange (theda, global, display_field, minmax, 369 | plots, plot_vals, plot_colors, 370 | xmin,xmax, ymin,ymax, zmin,zmax); 371 | } 372 | else 373 | { 374 | ierr = DATriangulateRange (theda, global, display_field, minmax, 375 | PETSC_DECIDE, PETSC_NULL, PETSC_NULL, 376 | xmin,xmax, ymin,ymax, zmin,zmax); 377 | CHKERRQ (ierr); 378 | } 379 | DPRINTF ("Consolidating triangles on head node and visualizing\n",0); 380 | ierr = GeomviewDisplayTriangulation 381 | (PETSC_COMM_WORLD, minmax, fieldname, transp); 382 | CHKERRQ (ierr); 383 | } 384 | 385 | /* Free user data */ 386 | for (i=0; i<usermetacount; i++) 387 | { 388 | free (usermetanames [i]); 389 | free (usermetadata [i]); 390 | } 391 | free (usermetanames); 392 | free (usermetadata); 393 | 394 | /* Get user input */ 395 | /* ierr = PetscPrintf (PETSC_COMM_WORLD, "What to do? (h for options) "); 396 | CHKERRQ (ierr); 397 | ierr = PetscSynchronizedFGets (PETSC_COMM_WORLD, stdin, 99, instring); 398 | CHKERRQ (ierr); */ 399 | /* This is probably not PETSc-safe */ 400 | instring = rl_gets("What to do? (h for options)> "); 401 | 402 | switch (instring [0]) 403 | { 404 | case 'q': 405 | case 'Q': 406 | case 'x': 407 | case 'X': 408 | { 409 | if (dims < 3) 410 | { 411 | ierr = PetscViewerDestroy (theviewer); CHKERRQ (ierr); 412 | } 413 | else 414 | { 415 | ierr = GeomviewEnd (PETSC_COMM_WORLD); CHKERRQ (ierr); 416 | } 417 | ierr = PetscFinalize(); CHKERRQ (ierr); 418 | return 0; 419 | } 420 | case 't': 421 | case 'T': 422 | { 423 | transp=!transp; 424 | break; 425 | } 426 | case 'h': 427 | case 'H': 428 | case '?': 429 | { 430 | ierr = PetscPrintf (PETSC_COMM_WORLD, HELP_STRING); 431 | break; 432 | } 433 | case '0': 434 | case '1': 435 | case '2': 436 | case '3': 437 | case '4': 438 | case '5': 439 | case '6': 440 | case '7': 441 | case '8': 442 | case '9': 443 | { 444 | current_entry = atoi (instring); 445 | break; 446 | } 447 | case 'b': 448 | case 'B': 449 | { 450 | current_entry--; 451 | break; 452 | } 453 | case 'i': 454 | case 'I': 455 | { 456 | /* printf ("instring=\"%s\"\n",instring); */ 457 | if (instring[1] && instring[2]) 458 | { 459 | sscanf (instring, "i %d", &increment); 460 | } 461 | else 462 | { 463 | ierr=PetscPrintf (PETSC_COMM_WORLD, 464 | "Increment: %d\n",increment); 465 | CHKERRQ (ierr); 466 | } 467 | break; 468 | } 469 | case 'v': 470 | case 'V': 471 | { 472 | if (dims == 3) 473 | display_field = (display_field+1) % fields; 474 | break; 475 | } 476 | case 'r': 477 | case 'R': 478 | { 479 | total_entries = scandir (basedirname, &namelist, myfilter, 480 | alphasort); 481 | 482 | if (!(files = (char **) realloc (files,total_entries * sizeof (char *)))) 483 | { 484 | ierr = PetscPrintf (PETSC_COMM_WORLD, "Error allocating memory\n"); 485 | CHKERRQ (ierr); 486 | ierr = PetscFinalize (); CHKERRQ(ierr); 487 | return 1; 488 | } 489 | for (i=0; i<total_entries; i++) 490 | { 491 | int filength = strlen(namelist[i]->d_name); 492 | 493 | files [i] = (char *) malloc ((filength-12)*sizeof(char)); 494 | strncpy (files [i], namelist[i]->d_name, filength-13); 495 | files [i] [filength-13] = '\0'; 496 | free (namelist[i]); 497 | ierr = PetscPrintf (PETSC_COMM_WORLD, "[%d] %s\n", i, files [i]); 498 | CHKERRQ (ierr); 499 | } 500 | free (namelist); 501 | 502 | ierr = PetscPrintf (PETSC_COMM_WORLD, "Total Entries: %d\n", 503 | total_entries); 504 | CHKERRQ (ierr); 505 | break; 506 | } 507 | case 's': 508 | case 'S': 509 | { 510 | if (instring[1] && instring[2] && dims<3) 511 | { 512 | sscanf (instring+2, "%d", &windowsize); 513 | 514 | if (windowsize) 515 | { 516 | int width=windowsize, height=windowsize; 517 | 518 | ierr = PetscViewerDestroy (theviewer); CHKERRQ (ierr); 519 | 520 | if (minmax[1]<minmax[3]) 521 | width *= minmax[1]/minmax[3]; 522 | else 523 | height *= minmax[3]/minmax[1]; 524 | 525 | ierr = PetscViewerDrawOpen 526 | (PETSC_COMM_WORLD, 0, "", PETSC_DECIDE, PETSC_DECIDE, 527 | width, height, &theviewer); CHKERRQ (ierr); 528 | } 529 | else 530 | { 531 | ierr=PetscPrintf (PETSC_COMM_WORLD, 532 | "Usage: \"s ###\" (2-D only)\n"); 533 | CHKERRQ (ierr); 534 | } 535 | } 536 | else 537 | { 538 | ierr=PetscPrintf (PETSC_COMM_WORLD, 539 | "Usage: \"s ###\" (2-D only)\n"); 540 | CHKERRQ (ierr); 541 | } 542 | break; 543 | } 544 | case 'p': 545 | case 'P': 546 | { 547 | int count=0, newplots=0; 548 | 549 | if (dims<3) 550 | { 551 | ierr=PetscPrintf (PETSC_COMM_WORLD, 552 | "The 'p' command is for 2-D only.\n"); 553 | CHKERRQ (ierr); 554 | break; 555 | } 556 | 557 | if (instring[1]=='\0' || instring[2]=='\0') 558 | { 559 | ierr = PetscPrintf (PETSC_COMM_WORLD, 560 | "Current plot contour isoquants:"); 561 | CHKERRQ (ierr); 562 | if (plots == 0) 563 | { 564 | ierr = PetscPrintf (PETSC_COMM_WORLD, 565 | " auto (20%%, 40%%, 60%%, 80%%)"); 566 | CHKERRQ (ierr); 567 | } 568 | for (count=0; count<plots; count++) 569 | { 570 | ierr = PetscPrintf (PETSC_COMM_WORLD, " %g", 571 | plot_vals[count]); CHKERRQ (ierr); 572 | } 573 | ierr = PetscPrintf (PETSC_COMM_WORLD, "\n"); CHKERRQ (ierr); 574 | break; 575 | } 576 | 577 | while (newplots<6 && instring[count] != '\0') 578 | { 579 | while ((instring[count] < '0' || instring[count] > '9') && 580 | instring[count] != '-' && instring[count] != '.' && 581 | instring[count] != '\0') 582 | count++; 583 | 584 | if (instring[count]) 585 | { 586 | #if defined(PETSC_USE_SINGLE) 587 | sscanf (instring+count, "%f", plot_vals+newplots); 588 | #else 589 | sscanf (instring+count, "%lf", plot_vals+newplots); 590 | #endif 591 | newplots++; 592 | while ((instring[count] >= '0' && instring[count] <= '9')|| 593 | instring[count] == '-' || instring[count] == '.') 594 | count++; 595 | } 596 | } 597 | plots = newplots; 598 | break; 599 | } 600 | case 'c': 601 | case 'C': 602 | { 603 | if (instring[1] == 'x' || instring[1] == 'X') 604 | xmax = (xmax == -2) ? -1 : -2; 605 | if (instring[1] == 'y' || instring[1] == 'Y') 606 | ymax = (ymax == -2) ? -1 : -2; 607 | if (instring[1] == 'z' || instring[1] == 'Z') 608 | zmax = (zmax == -2) ? -1 : -2; 609 | DPRINTF ("x %d-%d, y %d-%d, z %d-%d\n", xmin, xmax, ymin, ymax, 610 | zmin, zmax); 611 | break; 612 | } 613 | case 'g': 614 | case 'G': 615 | { 616 | int mingrid, maxgrid; 617 | sscanf (instring+2, "%d-%d", &mingrid, &maxgrid); 618 | if (instring[1] == 'x' || instring[1] == 'X') 619 | { 620 | xmin = mingrid; 621 | xmax = maxgrid; 622 | } 623 | if (instring[1] == 'y' || instring[1] == 'Y') 624 | { 625 | ymin = mingrid; 626 | ymax = maxgrid; 627 | } 628 | if (instring[1] == 'z' || instring[1] == 'Z') 629 | { 630 | zmin = mingrid; 631 | zmax = maxgrid; 632 | } 633 | DPRINTF ("x %d-%d, y %d-%d, z %d-%d\n", xmin, xmax, ymin, ymax, 634 | zmin, zmax); 635 | break; 636 | } 637 | default: 638 | current_entry+=increment; 639 | } 640 | if (current_entry < 0) 641 | current_entry = total_entries-1; 642 | if (current_entry >= total_entries) 643 | current_entry = 0; 644 | } 645 | 646 | free (filec); 647 | free (dirc); 648 | }