1    | /***************************************
2    |   $Header: /cvsroot/petscgraphics/tsview.c,v 1.31 2003/11/19 00:48:34 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   |   ###           Jump to timestep ###\n\
23   |   t             Toggle Geomview transparency (3-D only)\n\
24   |   v             Change field displayed (3-D only)\n\
25   |   p [v1 v2 ...] Set contour values for plotting or \"auto\" (3-D only)\n\
26   |   s size        Set maximum dimension of PETSc viewer windows (2-D only)\n\
27   |   h/?           Print this information\n\
28   |   q/x           Quit tsview\n"
29   | 
30   | #include "illuminator.h"
31   | #include <sys/dir.h> /* For scandir(), alphasort, struct dirent */
32   | #include <libgen.h>  /* For dirname(), basename() */
33   | #include <string.h>  /* For strdup() */
34   | 
35   | /* Build with -DDEBUG for debugging output */
36   | #undef DPRINTF
37   | #ifdef DEBUG
38   | #define DPRINTF(fmt, args...) PetscPrintf (PETSC_COMM_WORLD, "%s: " fmt, __FUNCT__, args)
39   | #else
40   | #define DPRINTF(fmt, args...)
41   | #endif
42   | 
43   | char *basefilename;
44   | 
45   | 
46   | #undef __FUNCT__
47   | #define __FUNCT__ "myfilter"
48   | 
49   | /*++++++++++++++++++++++++++++++++++++++
50   |   This function returns non-zero for "qualifying" file names which start with
51   |   the stored files' basename and end with
52   |   +latex+{\tt .cpu0000.meta}.
53   |   +html+ <tt>.cpu0000.meta</tt>.
54   |   It is used as the
55   |   +latex+{\tt select()} function for {\tt scandir()} in {\tt main()}.
56   |   +html+ <tt>select()</tt> function for <tt>scandir()</tt> in <tt>main()</tt>.
57   | 
58   |   int myfilter Returns non-zero for qualifying filenames.
59   | 
60   |   const struct dirent *direntry Directory entry with filename to test.
61   |   ++++++++++++++++++++++++++++++++++++++*/
62   | 
63   | int myfilter (const struct dirent *direntry)
64   | {
65   |   if ((!strncmp (direntry->d_name, basefilename, strlen(basefilename))))
66   |     return (!strncmp (direntry->d_name + strlen(direntry->d_name) - 13,
67   | 		      ".cpu0000.meta", 13));
68   |   return 0;
69   | }
70   | 
71   | 
72   | #undef __FUNCT__
73   | #define __FUNCT__ "main"
74   | 
75   | /*++++++++++++++++++++++++++++++++++++++
76   |   This is
77   |   +latex+{\tt main()}.
78   |   +html+ <tt>main()</tt>.
79   | 
80   |   int main It returns an int to the OS.
81   | 
82   |   int argc Argument count.
83   | 
84   |   char *argv[] Arguments.
85   |   ++++++++++++++++++++++++++++++++++++++*/
86   | 
87   | int main (int argc, char *argv[])
88   | {
89   |   int total_entries, current_entry, dims, i, ierr, windowsize=300, plots=0;
90   |   struct dirent **namelist;
91   |   char **files, *thefilename, *filec, *dirc, *basedirname;
92   |   PetscViewer theviewer;
93   |   PetscTruth loaded = PETSC_FALSE, transp=PETSC_TRUE;
94   | 
95   |   if (argc<2)
96   |     {
97   |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Usage: tsview basename\n");
98   |       CHKERRQ (ierr);
99   |       return 1;
100  |     }
101  | 
102  |   /*+ After
103  |     +latex+{\tt PETSc}
104  |     +html+ <tt>PETSc</tt>
105  |     initialization, it gets the list of files matching the basename. +*/
106  |   ierr = PetscInitialize (&argc, &argv, (char *)0, help); CHKERRQ (ierr);
107  | 
108  |   DPRINTF ("Command line:",0); CHKERRQ (ierr);
109  | #ifdef DEBUG
110  |   for (i=0; i<argc; i++)
111  |     {
112  |       ierr = PetscPrintf (PETSC_COMM_WORLD, " %s", argv[i]); CHKERRQ (ierr);
113  |     }
114  |   ierr = PetscPrintf (PETSC_COMM_WORLD, "\n"); CHKERRQ (ierr);
115  | #endif
116  | 
117  |   filec = strdup (argv[1]);
118  |   dirc = strdup (argv[1]);
119  |   basefilename = basename (filec);
120  |   basedirname = dirname (dirc);
121  | 
122  |   ierr = PetscOptionsHasName (PETSC_NULL, "-no_transparency", &transp);
123  |   CHKERRQ (ierr);
124  |   transp = !transp;
125  | 
126  |   total_entries = scandir (basedirname, &namelist, myfilter, alphasort);
127  |   if (!total_entries)
128  |     {
129  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "No such files, exiting\n");
130  |       CHKERRQ (ierr);
131  |       exit (1);
132  |     }
133  |   if (total_entries < 0)
134  |     {
135  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Error scanning directory %s\n",
136  | 			  basedirname); CHKERRQ (ierr);
137  |       ierr = PetscFinalize (); CHKERRQ(ierr);
138  |       return 1;
139  |     }
140  |   ierr = PetscPrintf (PETSC_COMM_WORLD, "%d eligible files:\n", total_entries);
141  |   CHKERRQ (ierr);
142  | 
143  |   if (!(files = (char **) malloc (total_entries * sizeof (char *))))
144  |     {
145  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Error allocating memory\n");
146  |       CHKERRQ (ierr);
147  |       ierr = PetscFinalize (); CHKERRQ(ierr);
148  |       return 1;
149  |     }
150  |   for (i=0; i<total_entries; i++)
151  |     {
152  |       int filength = strlen(namelist[i]->d_name);
153  | 
154  |       files [i] = (char *) malloc ((filength-12)*sizeof(char));
155  |       strncpy (files [i], namelist[i]->d_name, filength-13);
156  |       files [i] [filength-13] = '\0';
157  |       free (namelist[i]);
158  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "[%d] %s\n", i, files [i]);
159  |       CHKERRQ (ierr);
160  |     }
161  |   free (namelist);
162  | 
163  |   /*+In the main loop, the various timesteps are displayed, with options:
164  |     +latex+\begin{itemize} \item
165  |     +html+ <ul><li>
166  |     A number jumps to that entry in the files table.
167  |     +latex+\item {\stt <return>}
168  |     +html+ <li><tt>&lt;return&gt;</tt>
169  |     loads the next file.
170  |     +latex+\item {\tt b}
171  |     +html+ <li><tt>b</tt>
172  |     goes back one file.
173  |     +latex+\item {\tt q}
174  |     +html+ <li><tt>q</tt>
175  |     quits the program.
176  |     +latex+\end{itemize}
177  |     +html+ </ul>
178  |     +*/
179  |   current_entry=0;
180  |   while (1)
181  |     {
182  |       DA theda;
183  |       Vec global;
184  |       int usermetacount=0, fields, display_field;
185  |       char basis [strlen(argv[1]) + 20], **usermetanames, **usermetadata,
186  | 	instring [100];
187  |       PetscScalar minmax[6], plot_vals[6], plot_colors[24] =
188  | 	{ 1.,0.,0.,.5, 1.,1.,0.,.5, 0.,1.,0.,.5, 0.,1.,1.,.5, 0.,0.,1.,.5,
189  | 	  1.,0.,1.,.5 };
190  |       field_plot_type *fieldtypes;
191  | 
192  |       /* Load the vector */
193  |       strcpy (basis, basedirname);
194  |       strcat (basis, "/");
195  |       strcat (basis, files[current_entry]);
196  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Loading entry %d, basename %s\n",
197  | 			  current_entry, basis);
198  |       if (loaded)
199  | 	{
200  | 	  ierr = IlluMultiRead (theda, global, basis, &usermetacount,
201  | 				&usermetanames, &usermetadata);
202  | 	  CHKERRQ (ierr);
203  | 	}
204  |       else
205  | 	{
206  | 	  DPRINTF ("Loading first timestep, creating distributed array\n",0);
207  | 	  display_field = 0;
208  | 	  minmax [0] = minmax [2] = minmax [4] = 0.;
209  | 	  minmax [1] = minmax [3] = minmax [5] = 1.;
210  | 	  ierr = IlluMultiLoad (basis, &theda, minmax+1, minmax+3, minmax+5,
211  | 				&fieldtypes, &usermetacount, &usermetanames,
212  | 				&usermetadata); CHKERRQ (ierr);
213  | 	  ierr = DAGetGlobalVector (theda, &global); CHKERRQ (ierr);
214  | 	  loaded = PETSC_TRUE;
215  | 
216  | 	  ierr = DAGetInfo (theda, &dims, PETSC_NULL,PETSC_NULL,PETSC_NULL,
217  | 			    PETSC_NULL,PETSC_NULL,PETSC_NULL, &fields,
218  | 			    PETSC_NULL,PETSC_NULL,PETSC_NULL); CHKERRQ (ierr);
219  | 
220  | 	  /* Usermetadata xwidth, ywidth, zwidth override minmax in case
221  | 	     version is 0.1. */
222  | 	  for (i=0; i<usermetacount; i++)
223  | 	    {
224  | 	      if (!strncmp (usermetanames [i], "xwidth", 6))
225  | 		sscanf (usermetadata [i], "%lf", minmax+1);
226  | 	      else if (!strncmp (usermetanames [i], "ywidth", 6))
227  | 		sscanf (usermetadata [i], "%lf", minmax+3);
228  | 	      else if (!strncmp (usermetanames [i], "zwidth", 6))
229  | 		sscanf (usermetadata [i], "%lf", minmax+5);
230  | 	    }
231  | 
232  | 	  if (dims<3)
233  | 	    {
234  | 	      int width=windowsize, height=windowsize;
235  | 
236  | 	      if (minmax[1]<minmax[3])
237  | 		width  *= minmax[1]/minmax[3];
238  | 	      else
239  | 		height *= minmax[3]/minmax[1];
240  | 
241  | 	      ierr = PetscViewerDrawOpen
242  | 		(PETSC_COMM_WORLD, 0, "", PETSC_DECIDE, PETSC_DECIDE,
243  | 		 width, height, &theviewer); CHKERRQ (ierr);
244  | 	    }
245  | 	  else
246  | 	    {
247  | 	      ierr = GeomviewBegin (PETSC_COMM_WORLD);
248  | 	    }
249  | 	}
250  | 
251  |       /* Print user data */
252  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "User data:\n"); CHKERRQ (ierr);
253  |       for (i=0; i<usermetacount; i++)
254  | 	{
255  | 	  ierr = PetscPrintf (PETSC_COMM_WORLD, "%s = %s\n", usermetanames [i],
256  | 			      usermetadata [i]); CHKERRQ (ierr);
257  | 	}
258  | 
259  |       /* View the vector */
260  |       if (dims<3)
261  | 	{
262  | 	  ierr = VecView (global, theviewer); CHKERRQ (ierr);
263  | 	}
264  |       else
265  | 	{
266  | 	  /*+ The Illuminator-based 3-D viewer can only display one field at a
267  | 	    time.  At the beginning, that is field 0, and is cycled using the
268  | 	    +latex+{\tt v}
269  | 	    +html+ <tt>v</tt>
270  | 	    command. +*/
271  | 	  PetscScalar minval, maxval;
272  | 	  char *fieldname;
273  | 
274  | 	  ierr = VecStrideMin (global, display_field, PETSC_NULL, &minval);
275  | 	  CHKERRQ (ierr);
276  | 	  ierr = VecStrideMax (global, display_field, PETSC_NULL, &maxval);
277  | 	  CHKERRQ (ierr);
278  | 	  ierr = DAGetFieldName (theda, display_field, &fieldname);
279  | 	  CHKERRQ (ierr);
280  | 	  ierr = PetscPrintf (PETSC_COMM_WORLD,
281  | 			      "Displaying field %d [%g-%g]: %s\n",
282  | 			      display_field, minval, maxval, fieldname);
283  | 	  CHKERRQ (ierr);
284  | 
285  | 	  DPRINTF ("Calculating triangle locations\n",0);
286  | 	  if (plots)
287  | 	    {
288  | 	      ierr = DATriangulate (theda, global, display_field, minmax,
289  | 				    plots, plot_vals, plot_colors);
290  | 	    }
291  | 	  else
292  | 	    {
293  | 	      ierr = DATriangulate (theda, global, display_field, minmax,
294  | 				    PETSC_DECIDE, PETSC_NULL, PETSC_NULL);
295  | 	      CHKERRQ (ierr);
296  | 	    }
297  | 	  DPRINTF ("Consolidating triangles on head node and visualizing\n",0);
298  | 	  ierr = GeomviewDisplayTriangulation
299  | 	    (PETSC_COMM_WORLD, minmax, fieldname, transp);
300  | 	  CHKERRQ (ierr);
301  | 	}
302  | 
303  |       /* Free user data */
304  |       for (i=0; i<usermetacount; i++)
305  | 	{
306  | 	  free (usermetanames [i]);
307  | 	  free (usermetadata [i]);
308  | 	}
309  |       free (usermetanames);
310  |       free (usermetadata);
311  | 
312  |       /* Get user input */
313  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "What to do? (h for options) ");
314  |       CHKERRQ (ierr);
315  |       ierr = PetscSynchronizedFGets (PETSC_COMM_WORLD, stdin, 99, instring);
316  |       CHKERRQ (ierr);
317  | 
318  |       switch (instring [0])
319  | 	{
320  | 	case 'q':
321  | 	case 'Q':
322  | 	case 'x':
323  | 	case 'X':
324  | 	  {
325  | 	    if (dims < 3)
326  | 	      {
327  | 		ierr = PetscViewerDestroy (theviewer); CHKERRQ (ierr);
328  | 	      }
329  | 	    else
330  | 	      {
331  | 		ierr = GeomviewEnd (PETSC_COMM_WORLD); CHKERRQ (ierr);
332  | 	      }
333  | 	    ierr = PetscFinalize(); CHKERRQ (ierr);
334  | 	    return 0;
335  | 	  }
336  | 	case 't':
337  | 	case 'T':
338  | 	  {
339  | 	    transp=!transp;
340  | 	    break;
341  | 	  }
342  | 	case 'h':
343  | 	case 'H':
344  | 	case '?':
345  | 	  {
346  | 	    ierr = PetscPrintf (PETSC_COMM_WORLD, HELP_STRING);
347  | 	    break;
348  | 	  }
349  | 	case '0':
350  | 	case '1':
351  | 	case '2':
352  | 	case '3':
353  | 	case '4':
354  | 	case '5':
355  | 	case '6':
356  | 	case '7':
357  | 	case '8':
358  | 	case '9':
359  | 	  {
360  | 	    current_entry = atoi (instring);
361  | 	    break;
362  | 	  }
363  | 	case 'b':
364  | 	case 'B':
365  | 	  {
366  | 	    current_entry--;
367  | 	    break;
368  | 	  }
369  | 	case 'v':
370  | 	case 'V':
371  | 	  {
372  | 	    if (dims == 3)
373  | 	      display_field = (display_field+1) % fields;
374  | 	    break;
375  | 	  }
376  | 	case 's':
377  | 	case 'S':
378  | 	  {
379  | 	    printf ("instring=\"%s\"\n",instring);
380  | 	    if (instring[1] && instring[2] && dims<3)
381  | 	      {
382  | 		sscanf (instring+2, "%d", &windowsize);
383  | 
384  | 		if (windowsize)
385  | 		  {
386  | 		    int width=windowsize, height=windowsize;
387  | 
388  | 		    ierr = PetscViewerDestroy (theviewer); CHKERRQ (ierr);
389  | 
390  | 		    if (minmax[1]<minmax[3])
391  | 		      width  *= minmax[1]/minmax[3];
392  | 		    else
393  | 		      height *= minmax[3]/minmax[1];
394  | 
395  | 		    ierr = PetscViewerDrawOpen
396  | 		      (PETSC_COMM_WORLD, 0, "", PETSC_DECIDE, PETSC_DECIDE,
397  | 		       width, height, &theviewer); CHKERRQ (ierr);
398  | 		  }
399  | 		else
400  | 		  {
401  | 		    ierr=PetscPrintf (PETSC_COMM_WORLD,
402  | 				      "Usage: \"s ###\" (2-D only)\n");
403  | 		    CHKERRQ (ierr);
404  | 		  }
405  | 	      }
406  | 	    else
407  | 	      {
408  | 		ierr=PetscPrintf (PETSC_COMM_WORLD,
409  | 				  "Usage: \"s ###\" (2-D only)\n");
410  | 		CHKERRQ (ierr);
411  | 	      }
412  | 	    break;
413  | 	  }
414  | 	case 'p':
415  | 	case 'P':
416  | 	  {
417  | 	    int count=0, newplots=0;
418  | 
419  | 	    if (dims<3)
420  | 	      {
421  | 		ierr=PetscPrintf (PETSC_COMM_WORLD,
422  | 				  "The 'p' command is for 2-D only.\n");
423  | 		CHKERRQ (ierr);
424  | 		break;
425  | 	      }
426  | 
427  | 	    if (instring[1]=='\0' || instring[2]=='\0')
428  | 	      {
429  | 		ierr = PetscPrintf (PETSC_COMM_WORLD,
430  | 				    "Current plot contour isoquants:");
431  | 		CHKERRQ (ierr);
432  | 		if (plots == 0)
433  | 		  {
434  | 		    ierr = PetscPrintf (PETSC_COMM_WORLD,
435  | 					" auto (20%%, 40%%, 60%%, 80%%)");
436  | 		    CHKERRQ (ierr);
437  | 		  }
438  | 		for (count=0; count<plots; count++)
439  | 		  {
440  | 		    ierr = PetscPrintf (PETSC_COMM_WORLD, " %g",
441  | 					plot_vals[count]); CHKERRQ (ierr);
442  | 		  }
443  | 		ierr = PetscPrintf (PETSC_COMM_WORLD, "\n"); CHKERRQ (ierr);
444  | 		break;
445  | 	      }
446  | 
447  | 	    while (newplots<6 && instring[count] != '\0')
448  | 	      {
449  | 		while ((instring[count] < '0' || instring[count] > '9') &&
450  | 		       instring[count] != '-' && instring[count] != '.' &&
451  | 		       instring[count] != '\0')
452  | 		  count++;
453  | 
454  | 		if (instring[count])
455  | 		  {
456  | #if defined(PETSC_USE_SINGLE)
457  | 		    sscanf (instring+count, "%f", plot_vals+newplots);
458  | #else
459  | 		    sscanf (instring+count, "%lf", plot_vals+newplots);
460  | #endif
461  | 		    newplots++;
462  | 		    while ((instring[count] >= '0' && instring[count] <= '9')||
463  | 			   instring[count] == '-' || instring[count] == '.')
464  | 		      count++;
465  | 		  }
466  | 	      }
467  | 	    plots = newplots;
468  | 	    break;
469  | 	  }
470  | 	default:
471  | 	  current_entry++;
472  | 	}
473  |       if (current_entry < 0)
474  | 	current_entry = total_entries-1;
475  |       if (current_entry >= total_entries)
476  | 	current_entry = 0;
477  |     }
478  | 
479  |   free (filec);
480  |   free (dirc);
481  | }