1 | /*************************************** 2 | $Header: /cvsroot/petscgraphics/tsview.c,v 1.34 2004/05/25 14:03:38 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 | h/? Print this information\n\ 31 | q/x Quit tsview\n" 32 | 33 | #include "illuminator.h" 34 | #include <sys/dir.h> /* For scandir(), alphasort, struct dirent */ 35 | #include <libgen.h> /* For dirname(), basename() */ 36 | #include <string.h> /* For strdup() */ 37 | #include <stdlib.h> /* Needed for readline stuff below */ 38 | #include <term.h> /* ncurses header for readline */ 39 | #include <readline/readline.h> /* For command line editing */ 40 | #include <readline/history.h> /* For command line history */ 41 | 42 | /* Build with -DDEBUG for debugging output */ 43 | #undef DPRINTF 44 | #ifdef DEBUG 45 | #define DPRINTF(fmt, args...) PetscPrintf (PETSC_COMM_WORLD, "%s: " fmt, __FUNCT__, args) 46 | #else 47 | #define DPRINTF(fmt, args...) 48 | #endif 49 | 50 | char *basefilename; 51 | 52 | 53 | #undef __FUNCT__ 54 | #define __FUNCT__ "myfilter" 55 | 56 | /*++++++++++++++++++++++++++++++++++++++ 57 | This function returns non-zero for "qualifying" file names which start with 58 | the stored files' basename and end with 59 | +latex+{\tt .cpu0000.meta}. 60 | +html+ <tt>.cpu0000.meta</tt>. 61 | It is used as the 62 | +latex+{\tt select()} function for {\tt scandir()} in {\tt main()}. 63 | +html+ <tt>select()</tt> function for <tt>scandir()</tt> in <tt>main()</tt>. 64 | 65 | int myfilter Returns non-zero for qualifying filenames. 66 | 67 | const struct dirent *direntry Directory entry with filename to test. 68 | ++++++++++++++++++++++++++++++++++++++*/ 69 | 70 | int myfilter (const struct dirent *direntry) 71 | { 72 | if ((!strncmp (direntry->d_name, basefilename, strlen(basefilename)))) 73 | return (!strncmp (direntry->d_name + strlen(direntry->d_name) - 13, 74 | ".cpu0000.meta", 13)); 75 | return 0; 76 | } 77 | 78 | 79 | /*+++++++++++++++++++++++++++++++++++++ 80 | 81 | Functions for reading the command line 82 | and avoiding reading empty lines 83 | 84 | Probably this function is not Petsc 85 | safe, but we'll see. 86 | 87 | +++++++++++++++++++++++++++++++++++++*/ 88 | 89 | /* A static variable for holding the line. */ 90 | static char *line_read = (char *)NULL; 91 | 92 | /* Read a string, and return a pointer to it. 93 | Returns NULL on EOF. */ 94 | 95 | 96 | 97 | char* rl_gets (char* message) 98 | { 99 | /* If the buffer has already been allocated, 100 | return the memory to the free pool. */ 101 | if (line_read) 102 | { 103 | free (line_read); 104 | line_read = (char *)NULL; 105 | } 106 | 107 | /* Get a line from the user. */ 108 | line_read = readline (message); 109 | 110 | /* If the line has any text in it, 111 | save it on the history. */ 112 | if (line_read && *line_read) 113 | add_history (line_read); 114 | 115 | return (line_read); 116 | } 117 | 118 | 119 | /* 120 | Failed attempt to make a Petsc safe readline 121 | Lefted here for reference 122 | 123 | It is based on PetscSynchronizedFGets, but instead of using 124 | fgets() it uses rl_gets() 125 | 126 | */ 127 | 128 | int PetscSynchronizedFReadline(MPI_Comm comm,char* message,char* string) 129 | { 130 | int ierr,rank, len; 131 | PetscFunctionBegin; 132 | ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 133 | 134 | /* First processor prints immediately to stdin*/ 135 | if (!rank) { 136 | string = rl_gets(message); 137 | } 138 | 139 | len = strlen(string); 140 | 141 | ierr = MPI_Bcast(string,len,MPI_BYTE,0,comm);CHKERRQ(ierr); 142 | PetscFunctionReturn(0); 143 | } 144 | 145 | 146 | #undef __FUNCT__ 147 | #define __FUNCT__ "main" 148 | 149 | /*++++++++++++++++++++++++++++++++++++++ 150 | This is 151 | +latex+{\tt main()}. 152 | +html+ <tt>main()</tt>. 153 | 154 | int main It returns an int to the OS. 155 | 156 | int argc Argument count. 157 | 158 | char *argv[] Arguments. 159 | ++++++++++++++++++++++++++++++++++++++*/ 160 | 161 | int main (int argc, char *argv[]) 162 | { 163 | int total_entries, current_entry, dims, i, ierr, windowsize=300, plots=0, 164 | increment=1; 165 | struct dirent **namelist; 166 | char **files, *thefilename, *filec, *dirc, *basedirname; 167 | PetscViewer theviewer; 168 | PetscTruth loaded = PETSC_FALSE, transp=PETSC_TRUE, 169 | xcut=PETSC_FALSE, ycut=PETSC_FALSE, zcut=PETSC_FALSE; 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 = DATriangulate (theda, global, display_field, minmax, 369 | plots, plot_vals, plot_colors, 370 | xcut, ycut, zcut); 371 | } 372 | else 373 | { 374 | ierr = DATriangulate (theda, global, display_field, minmax, 375 | PETSC_DECIDE, PETSC_NULL, PETSC_NULL, 376 | xcut, ycut, zcut); 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 | xcut = !xcut; 605 | if (instring[1] == 'y' || instring[1] == 'Y') 606 | ycut = !ycut; 607 | if (instring[1] == 'z' || instring[1] == 'Z') 608 | zcut = !zcut; 609 | break; 610 | } 611 | default: 612 | current_entry+=increment; 613 | } 614 | if (current_entry < 0) 615 | current_entry = total_entries-1; 616 | if (current_entry >= total_entries) 617 | current_entry = 0; 618 | } 619 | 620 | free (filec); 621 | free (dirc); 622 | }