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 | }