1    | /***************************************
2    |   $Header: /cvsroot/petscgraphics/tsview-ng.c,v 1.10 2004/05/21 22:08:44 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   | #include "illuminator.h"
20   | #include <glade/glade.h>
21   | #include <gnome.h>
22   | #include <libgnomeui/libgnomeui.h>
23   | #include <sys/dir.h> /* For scandir(), alphasort, struct dirent */
24   | #include <libgen.h>  /* For dirname(), basename() */
25   | #include <string.h>  /* For strdup() */
26   | 
27   | /* Build with -DDEBUG for debugging output */
28   | #undef DPRINTF
29   | #ifdef DEBUG
30   | #define DPRINTF(fmt, args...) PetscPrintf (PETSC_COMM_WORLD, "%s: " fmt, __FUNCT__, args)
31   | #else
32   | #define DPRINTF(fmt, args...)
33   | #endif
34   | 
35   | GladeXML *xml;
36   | /* Filename list */
37   | int entrynum=0, total_entries=0, current_timestep;
38   | char *the_basename, *basedirname, **stepnames=NULL;
39   | double current_time;
40   | 
41   | /* Window parameters and drawables */
42   | int width=0, height=0, nx, ny, dataview_count=1;
43   | GtkWidget *dataviews [1];
44   | guchar *rgbbuf [1] = { NULL };
45   | double sizemag;
46   | PetscTruth transp;
47   | 
48   | /* Maximum intensity for hueintense plots */
49   | PetscScalar vecmax=-1.;
50   | 
51   | /* PETSc structures etc. */
52   | DA theda;
53   | Vec global;
54   | PetscScalar minmax[6] = { 0.,1., 0.,1., 0.,1. };
55   | field_plot_type *fieldtypes;
56   | int dimensions, num_fields, num_variables[1], **variable_indices;
57   | 
58   | /* First some main functions which do stuff, then callbacks, then main(). */
59   | static inline void pseudocolor (PetscScalar val, PetscScalar min,
60   | 				   PetscScalar max, guchar *pixel)
61   | {
62   |   PetscScalar shade = (val - min) / (max - min);
63   |   /* Old stuff *
64   |   if (shade < 0.2) {      /* red -> yellow *
65   |     *pixel++ = 255;
66   |     *pixel++ = 1275*shade;
67   |     *pixel++ = 0; }
68   |   else if (shade < 0.4) { /* yellow -> green *
69   |     *pixel++ = 510-1275*shade;
70   |     *pixel++ = 255;
71   |     *pixel++ = 0; }
72   |   else if (shade < 0.6) { /* green -> cyan *
73   |     *pixel++ = 0;
74   |     *pixel++ = 255;
75   |     *pixel++ = 1275*shade-510; }
76   |   else if (shade < 0.8) { /* cyan -> blue *
77   |     *pixel++ = 0;
78   |     *pixel++ = 1020-1275*shade;
79   |     *pixel++ = 255; }
80   |   else {                  /* blue -> magenta *
81   |     *pixel++ = 1275*shade-1020;
82   |     *pixel++ = 0;
83   |     *pixel++ = 255; }
84   |   /* New stuff */
85   |   if (shade < 0.25) {      /* red -> yellow */
86   |     *pixel++ = 255;
87   |     *pixel++ = 1020*shade;
88   |     *pixel++ = 0; }
89   |   else if (shade < 0.5) { /* yellow -> green */
90   |     *pixel++ = 510-1020*shade;
91   |     *pixel++ = 255;
92   |     *pixel++ = 0; }
93   |   else if (shade < 0.75) { /* green -> cyan */
94   |     *pixel++ = 0;
95   |     *pixel++ = 255;
96   |     *pixel++ = 1020*shade-510; }
97   |   else { /* cyan -> blue */
98   |     *pixel++ = 0;
99   |     *pixel++ = 1020-1020*shade;
100  |     *pixel++ = 255; }
101  | }
102  | 
103  | static inline void pseudohueintcolor
104  | (PetscScalar vx, PetscScalar vy, PetscScalar refmag, guchar *pixel)
105  | {
106  |   PetscScalar mag=sqrt(vx*vx+vy*vy), theta=atan2(vy,vx), red, green, blue;
107  |   if (refmag <= 0.)
108  |     {
109  |       *pixel = *(pixel+1) = *(pixel+2) = 0;
110  |       return;
111  |     }
112  |   mag = (mag > refmag) ? 1.0 : mag/refmag;
113  |   /* Old pseudocolor */
114  |   /* red = (theta<-M_PI*5./6.)? 1.5/M_PI*(-M_PI*5./6.-theta):
115  |     ((theta<-M_PI/6.)? 0.:
116  |      ((theta<M_PI/2.)? 1.5/M_PI*(theta+M_PI/6.): 1.5/M_PI*(M_PI*7./6.-theta)));
117  |   green = (theta<-M_PI*5./6.)? 1.5/M_PI*(theta+M_PI*3./2.):
118  |     ((theta<-M_PI/6.)? 1.5/M_PI*(-M_PI/6.-theta):
119  |      ((theta<M_PI/2.)? 0.: 1.5/M_PI*(theta-M_PI/2.)));
120  |   blue = (theta<-M_PI*5./6.)? 0.:
121  |     ((theta<-M_PI/6.)? 1.5/M_PI*(theta+M_PI*5./6.):
122  |     ((theta<M_PI/2.)? 1.5/M_PI*(M_PI/2.-theta): 0.)); */
123  | 
124  |   /* New pseudocolor: green, yellow, red, blue at 0, 90, 180, 270 degrees */
125  |   red = 2./M_PI * ((theta<-M_PI/2.) ? -M_PI/2.-theta :
126  | 		   ((theta<0.) ? 0. : ((theta<M_PI/2.) ? theta : M_PI/2.)));
127  |   green = 2./M_PI * ((theta<-M_PI/2.) ? 0. :
128  | 		     ((theta<0.) ? theta+M_PI/2. :
129  | 		      ((theta<M_PI/2.) ? M_PI/2. : M_PI-theta)));
130  |   blue = 2./M_PI * ((theta<-M_PI/2.) ? theta+M_PI :
131  | 		    ((theta<0.) ? -theta : 0.));
132  | 
133  |   *pixel++ = 255*mag*red;
134  |   *pixel++ = 255*mag*green;
135  |   *pixel++ = 255*mag*blue;
136  | }
137  | 
138  | static inline void pseudoternarycolor
139  | (PetscScalar A, PetscScalar B, PetscScalar Corner1A, PetscScalar Corner1B,
140  |  PetscScalar Corner2A, PetscScalar Corner2B, PetscScalar Corner3A,
141  |  PetscScalar Corner3B, guchar *pixel)
142  | {
143  |   PetscScalar x1, x2, inverse_det;
144  | 
145  |   /* Transform A,B into x1,x2 based on corners */
146  |   A        -= Corner3A;
147  |   Corner1A -= Corner3A;
148  |   Corner2A -= Corner3A;
149  |   B        -= Corner3B;
150  |   Corner1B -= Corner3B;
151  |   Corner2B -= Corner3B;
152  |   inverse_det = 1./(Corner1A*Corner2B - Corner2A*Corner1B);
153  |   x1 = (A*Corner2B - B*Corner2A) * inverse_det;
154  |   x2 = (B*Corner1A - A*Corner1B) * inverse_det;
155  | 
156  |   /* Now colorize */
157  |   *pixel++ = 255*(1.-x1);
158  |   *pixel++ = 255*(x1+x2);
159  |   *pixel++ = 255*(1.-x2);
160  | }
161  | 
162  | /* Find the maximum magnitude of a 2-D vector field in an array */
163  | PetscScalar ArrayMaxMag (PetscScalar *global, int points, int fields,int field)
164  | {
165  |   int i;
166  |   PetscScalar retval;
167  | 
168  |   retval = global[field]*global[field] + global[field+1]*global[field+1];
169  | 
170  |   for (i=1; i<points; i++)
171  |     retval = PetscMax (retval, global[i*fields+field]*global[i*fields+field] +
172  | 		       global[i*fields+field+1]*global[i*fields+field+1]);
173  |   return sqrt (retval);
174  | }
175  | 
176  | void paint_rgb (guchar *rgb, int rwidth, int rheight, DA rgbda, Vec rgbglobal,
177  | 		int display_field)
178  | {
179  |   int nx,ny,nz, ix,iy, ierr;
180  |   PetscScalar *global_array, minval, maxval, refmag;
181  | 
182  |   ierr = DAGetInfo (rgbda, PETSC_NULL, &nx,&ny,&nz,
183  | 		    PETSC_NULL,PETSC_NULL,PETSC_NULL, PETSC_NULL,
184  | 		    PETSC_NULL,PETSC_NULL,PETSC_NULL); CHKERRQ (ierr);
185  | 
186  |   ierr = VecStrideMin (rgbglobal, display_field, PETSC_NULL, &minval);
187  |   CHKERRQ (ierr);
188  |   ierr = VecStrideMax (rgbglobal, display_field, PETSC_NULL, &maxval);
189  |   CHKERRQ (ierr);
190  | 
191  |   ierr = VecGetArray (rgbglobal, &global_array);
192  | 
193  |   /* If a vector field, then find max magnitude in fields 0-1 */
194  |   if (fieldtypes[display_field] == FIELD_VECTOR_HUEINTENSE ||
195  |       fieldtypes[display_field] == FIELD_VECTOR_ARROWS)
196  |     {
197  |       if (vecmax > 0)
198  | 	refmag = vecmax;
199  |       else
200  | 	refmag = ArrayMaxMag (global_array, nx*ny, num_fields, display_field);
201  |       printf ("Reference vector magnitude = %g\n", refmag);
202  |     }
203  | 
204  |   for (iy=0; iy<rheight; iy++)
205  |     for (ix=0; ix<rwidth; ix++)
206  |       {
207  | 	int vecindex;
208  | 	guchar *pixel;
209  | 	vecindex = (((rheight-iy-1)*ny/rheight)*nx+ ix*nx/rwidth)*num_fields+
210  | 	  display_field;
211  | 	pixel = rgb + 3*(iy*rwidth + ix);
212  | 
213  | 	if (fieldtypes[display_field] == FIELD_TERNARY_RGB)
214  | 	  pseudoternarycolor
215  | 	    (global_array [vecindex], global_array [vecindex+1],
216  | 	     0.,0., 1.,0., 0.,1., pixel);
217  | 	else if (fieldtypes[display_field] == FIELD_VECTOR_HUEINTENSE ||
218  | 		 fieldtypes[display_field] == FIELD_VECTOR_ARROWS)
219  | 	  pseudohueintcolor
220  | 	    (global_array [vecindex], global_array [vecindex+1], refmag,
221  | 	     pixel);
222  | 	else
223  | 	  pseudocolor (global_array [vecindex], minval, maxval, pixel);
224  |       }
225  |   ierr = VecRestoreArray (rgbglobal, &global_array);
226  | }
227  | 
228  | void render_dataviews ()
229  | {
230  |   int viewnum, nx,ny,nz, ierr;
231  |   GtkWidget *thebar = glade_xml_get_widget(xml, "appbar1");
232  | 
233  |   if (dataview_count != 1)
234  |     {
235  |       printf ("dataview_count != 1 is not yet supported\n");
236  |       exit(0);
237  |     }
238  |   for (viewnum=0; viewnum<dataview_count; viewnum++)
239  |     {
240  |       int ix,iy, display_field=0;
241  |       PetscScalar minval, maxval, refmag, *global_array;
242  |       GtkType type;
243  |       char thestatus [100];
244  | 
245  |       /* (Re)allocate buffer */
246  |       if (!(rgbbuf [viewnum] =
247  | 	    (guchar *) realloc (rgbbuf [viewnum],
248  | 				3*width*height*sizeof(guchar)))) {
249  | 	  printf ("ERROR: can't reallocate RGB buffer\n");
250  | 	  exit (1); }
251  | 
252  |       sprintf (thestatus, "Rendering view %d...", viewnum);
253  |       gnome_appbar_set_default (GNOME_APPBAR (thebar), thestatus);
254  | 
255  |       /* Render into rgbbuf */
256  |       paint_rgb (rgbbuf [viewnum], width,height, theda, global, display_field);
257  | 
258  |       /* Draw buffer onto window */
259  |       if (!dataviews [viewnum])
260  | 	dataviews [viewnum] = glade_xml_get_widget (xml, "plot_area");
261  |       gtk_drawing_area_size (GTK_DRAWING_AREA (dataviews [viewnum]),
262  | 			     width, height);
263  |       gdk_draw_rgb_image (dataviews [viewnum]->window,
264  | 			  dataviews [viewnum]->style->fg_gc[GTK_STATE_NORMAL],
265  | 			  0, 0, width, height, GDK_RGB_DITHER_MAX,
266  | 			  rgbbuf [viewnum], width * 3);
267  |     }
268  |   gnome_appbar_set_default (GNOME_APPBAR (thebar), "Done.");
269  | }
270  | 
271  | 
272  | #undef __FUNCT__
273  | #define __FUNCT__ "myfilter"
274  | 
275  | /*+ Little variable for myfilter() and refresh_stepnames(). +*/
276  | static char *basefilename;
277  | 
278  | /*++++++++++++++++++++++++++++++++++++++
279  |   This function returns non-zero for "qualifying" file names which start with
280  |   the stored files' basename.time and end with
281  |   +latex+{\tt .cpu0000.meta}.
282  |   +html+ <tt>.cpu0000.meta</tt>.
283  |   It is used as the
284  |   +latex+{\tt select()} function for {\tt scandir()} in {\tt main()}.
285  |   +html+ <tt>select()</tt> function for <tt>scandir()</tt> in <tt>main()</tt>.
286  | 
287  |   int myfilter Returns non-zero for qualifying filenames.
288  | 
289  |   const struct dirent *direntry Directory entry with filename to test.
290  |   ++++++++++++++++++++++++++++++++++++++*/
291  | 
292  | int myfilter (const struct dirent *direntry)
293  | {
294  |   if ((!strncmp (direntry->d_name, basefilename, strlen(basefilename))) &&
295  |       (!strncmp (direntry->d_name + strlen(basefilename), ".time", 5)))
296  |     return (!strncmp (direntry->d_name + strlen(direntry->d_name) - 13,
297  | 		      ".cpu0000.meta", 13));
298  |   return 0;
299  | }
300  | 
301  | 
302  | void on_plot_area_expose_event (GtkWidget *widget, GdkEventExpose *event,
303  | 				   gpointer user_data)
304  | {
305  |   gdk_draw_rgb_image (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
306  | 		      0, 0, width, height, GDK_RGB_DITHER_MAX, rgbbuf [0],
307  | 		      width * 3);
308  | }
309  | 
310  | /*++++++++++++++++++++++++++++++++++++++
311  |   This loads the names of the files into a long list.
312  |   ++++++++++++++++++++++++++++++++++++++*/
313  | 
314  | int refresh_stepnames ()
315  | {
316  |   struct dirent **namelist;
317  |   char *filec, *dirc;
318  |   int i, ierr;
319  | 
320  |   filec = strdup (the_basename);
321  |   dirc = strdup (the_basename);
322  |   basefilename = basename (filec);
323  |   basedirname = dirname (dirc);
324  | 
325  |   total_entries = scandir (basedirname, &namelist, myfilter, alphasort);
326  |   if (!total_entries)
327  |     {
328  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "No such files\n");
329  |       CHKERRQ (ierr);
330  |       return 1;
331  |     }
332  |   if (total_entries < 0)
333  |     {
334  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Error scanning directory %s\n",
335  | 			  basedirname); CHKERRQ (ierr);
336  |       ierr = PetscFinalize (); CHKERRQ(ierr);
337  |       return 1;
338  |     }
339  |   ierr = PetscPrintf (PETSC_COMM_WORLD, "%d eligible files:\n", total_entries);
340  |   CHKERRQ (ierr);
341  | 
342  |   if (!(stepnames = (char **) realloc
343  | 	(stepnames, total_entries*sizeof (char *))))
344  |     {
345  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Error allocating memory\n");
346  |       CHKERRQ (ierr);
347  |       return 1;
348  |     }
349  |   for (i=0; i<total_entries; i++)
350  |     {
351  |       int filength = strlen(namelist[i]->d_name);
352  | 
353  |       stepnames [i] = (char *) malloc ((filength-12)*sizeof(char));
354  |       strncpy (stepnames [i], namelist[i]->d_name, filength-13);
355  |       stepnames [i] [filength-13] = '\0';
356  |       free (namelist[i]);
357  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "[%d] %s\n", i, stepnames [i]);
358  |       CHKERRQ (ierr);
359  |     }
360  | 
361  |   free (namelist);
362  |   return 0;
363  | }
364  | 
365  | 
366  | void on_mag_spin_value_changed (GtkWidget *mag_spin, gpointer user_data) {
367  |   G_CONST_RETURN gchar *entrytext;
368  |   entrytext = gtk_entry_get_text (GTK_ENTRY (mag_spin));
369  |   sscanf (entrytext, "%lf", &sizemag);
370  |   width = (int) (minmax [1] * sizemag);
371  |   height = (int) (minmax [3] * sizemag);
372  | 
373  |   render_dataviews(dataviews, dataview_count);
374  | }
375  | 
376  | 
377  | void display_timestep (int usermetacount, char **usermetanames,
378  | 		       char **usermetadata)
379  | {
380  |   int i;
381  |   static char step_buffer [20], time_buffer [20];
382  | 
383  |   for (i=0; i<usermetacount; i++)
384  |     {
385  |       if (!strncmp (usermetanames [i], "timestep", 8))
386  | 	sscanf (usermetadata [i], "%d", &current_timestep);
387  |       else if (!strncmp (usermetanames [i], "time", 4))
388  | 	sscanf (usermetadata [i], "%lf", &current_time);
389  |     }
390  |   snprintf (step_buffer, 19, "Timestep: %d", current_timestep);
391  |   gtk_label_set_text (GTK_LABEL (glade_xml_get_widget (xml, "timestep_label")),
392  | 		      step_buffer);
393  |   snprintf (time_buffer, 19, "Time: %g", current_time);
394  |   gtk_label_set_text (GTK_LABEL (glade_xml_get_widget (xml, "time_label")),
395  | 		      time_buffer);
396  | 
397  |   on_mag_spin_value_changed (glade_xml_get_widget (xml, "mag_spin"), NULL);
398  | }
399  | 
400  | 
401  | void on_save_activate (GtkWidget *widget, gpointer user_data)
402  | {
403  |   int i, ierr;
404  |   char **usermetanames, **usermetadata, filename [200], thestatus [200];
405  |   GtkWidget *thebar = glade_xml_get_widget(xml, "appbar1");
406  |   FILE *outppm;
407  | 
408  |   strncpy (filename, basedirname, 198);
409  |   strcat (filename, "/");
410  |   strncat (filename, stepnames [entrynum], 198 - strlen (filename));
411  |   strncat (filename, ".ppm", 198 - strlen (filename));
412  | 
413  |   sprintf (thestatus, "Saving entry %d in filename %s", entrynum, filename);
414  |   gnome_appbar_set_default (GNOME_APPBAR (thebar), thestatus);
415  | 
416  |   if (!(outppm = fopen (filename, "w")))
417  |     printf ("Error opening file %s\n", filename);
418  |   fprintf (outppm, "P6\n%d %d\n255\n", width, height);
419  |   fwrite (rgbbuf [0], sizeof (guchar), 3*width*height, outppm);
420  |   fclose (outppm);
421  | 
422  |   sprintf (thestatus, "Saved entry %d in filename %s", entrynum, filename);
423  |   gnome_appbar_set_default (GNOME_APPBAR (thebar), thestatus);
424  | }
425  | 
426  | 
427  | void on_timestep_spin_value_changed (GtkWidget *timestep_spin, gpointer user_data) {
428  |   int usermetacount, ierr;
429  |   G_CONST_RETURN gchar *entrytext;
430  |   char **usermetanames, **usermetadata, filename [200], thestatus [200];
431  |   GtkWidget *thebar = glade_xml_get_widget(xml, "appbar1");
432  | 
433  |   entrytext = gtk_entry_get_text (GTK_ENTRY (timestep_spin));
434  |   sscanf (entrytext, "%d", &entrynum);
435  | 
436  |   /* Bound the entrynum between 0 and total_entries-1; -11 is the minimum of
437  |      the widget (from jump), 1000001 is the maximum. */
438  |   if ((entrynum < 0 && entrynum != -11) || entrynum == 1000001)
439  |     entrynum = total_entries-1;
440  |   if ((entrynum >= total_entries && entrynum != 1000001) || entrynum == -11)
441  |     entrynum = 0;
442  |   gtk_spin_button_set_value (GTK_SPIN_BUTTON (timestep_spin),
443  | 			     (gfloat) entrynum);
444  | 
445  |   strncpy (filename, basedirname, 198);
446  |   strcat (filename, "/");
447  |   strncat (filename, stepnames [entrynum], 198 - strlen (filename));
448  | 
449  |   sprintf (thestatus, "Loading entry %d, basename %s\n", entrynum, filename);
450  |   gnome_appbar_set_default (GNOME_APPBAR (thebar), thestatus);
451  | 
452  |   ierr = IlluMultiRead (theda, global, filename, &usermetacount,&usermetanames,
453  | 			&usermetadata); CHKERRQ (ierr);
454  | 
455  |   display_timestep (usermetacount, usermetanames, usermetadata);
456  | }
457  | 
458  | 
459  | void on_refresh_activate (GtkWidget *none, gpointer user_data) {
460  |   if (refresh_stepnames ()) exit (1); }
461  | 
462  | 
463  | void on_about_activate (GtkWidget *none, gpointer user_data) {
464  |   gtk_widget_show (glade_xml_get_widget (xml, "about")); }
465  | 
466  | 
467  | /*
468  | #define HELP_STRING "tsview commands:\n\
469  |   <enter> Display next timestep\n\
470  |   b       Display previous timestep\n\
471  |   ###     Jump to timestep ###\n\
472  |   t       Toggle Geomview transparency (3-D only)\n\
473  |   v       Change field displayed (3-D only)\n\
474  |   h/?     Print this information\n\
475  |   q/x     Quit tsview\n"
476  | 
477  | int start (int argc, char *argv[])
478  | {
479  |   int total_entries, current_entry, dims, i, ierr;
480  |   PetscViewer theviewer;
481  |   PetscTruth loaded = PETSC_FALSE, transp=PETSC_TRUE; */
482  | 
483  |   /*+In the main loop, the various timesteps are displayed, with options:
484  |     +latex+\begin{itemize} \item
485  |     +html+ <ul><li>
486  |     A number jumps to that entry in the files table.
487  |     +latex+\item {\stt <return>}
488  |     +html+ <li><tt>&lt;return&gt;</tt>
489  |     loads the next file.
490  |     +latex+\item {\tt b}
491  |     +html+ <li><tt>b</tt>
492  |     goes back one file.
493  |     +latex+\item {\tt q}
494  |     +html+ <li><tt>q</tt>
495  |     quits the program.
496  |     +latex+\end{itemize}
497  |     +html+ </ul>
498  |     +*/
499  |   /*  current_entry=0;
500  |   while (1)
501  |     {
502  | 
503  |       else
504  | 	{
505  | 
506  | 	  if (dims<3)
507  | 	    {
508  | 	      int width=300, height=300;
509  | 
510  | 	      if (minmax[1]<minmax[3])
511  | 		width  *= minmax[1]/minmax[3];
512  | 	      else
513  | 		height *= minmax[3]/minmax[1];
514  | 
515  | 	      ierr = PetscViewerDrawOpen
516  | 		(PETSC_COMM_WORLD, 0, "", PETSC_DECIDE, PETSC_DECIDE,
517  | 		 width, height, &theviewer); CHKERRQ (ierr);
518  | 	    }
519  | 	  else
520  | 	    {
521  | 	      ierr = GeomviewBegin (PETSC_COMM_WORLD);
522  | 	    }
523  | 	}
524  | 
525  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "User data:\n"); CHKERRQ (ierr);
526  |       for (i=0; i<usermetacount; i++)
527  | 	{
528  | 	  ierr = PetscPrintf (PETSC_COMM_WORLD, "%s = %s\n", usermetanames [i],
529  | 			      usermetadata [i]); CHKERRQ (ierr);
530  | 	}
531  | 
532  |       if (dims<3)
533  | 	{
534  | 	  ierr = VecView (global, theviewer); CHKERRQ (ierr);
535  | 	}
536  |       else
537  |       { */
538  | 	  /*+ The Illuminator-based 3-D viewer can only display one field at a
539  | 	    time.  At the beginning, that is field 0, and is cycled using the
540  | 	    +latex+{\tt v}
541  | 	    +html+ <tt>v</tt>
542  | 	    command. +*/
543  | 	  /* PetscScalar minval, maxval;
544  | 	  char *fieldname;
545  | 
546  | 	  ierr = VecStrideMin (global, display_field, PETSC_NULL, &minval);
547  | 	  CHKERRQ (ierr);
548  | 	  ierr = VecStrideMax (global, display_field, PETSC_NULL, &maxval);
549  | 	  CHKERRQ (ierr);
550  | 	  ierr = PetscPrintf (PETSC_COMM_WORLD,
551  | 			      "Displaying field %d [%g-%g]: %s\n",
552  | 			      display_field, minval, maxval, fieldname);
553  | 	  CHKERRQ (ierr);
554  | 
555  | 	  DPRINTF ("Calculating triangle locations\n",0);
556  | 	  ierr = DATriangulate (theda, global, display_field, minmax,
557  | 				PETSC_DECIDE, PETSC_NULL, PETSC_NULL);
558  | 	  CHKERRQ (ierr);
559  | 	  ierr = DAGetFieldName (theda, display_field, &fieldname);
560  | 	  CHKERRQ (ierr);
561  | 	  DPRINTF ("Consolidating triangles on head node and visualizing\n",0);
562  | 	  ierr = GeomviewDisplayTriangulation
563  | 	    (PETSC_COMM_WORLD, minmax, fieldname, transp);
564  | 	  CHKERRQ (ierr);
565  | 	  }
566  | 
567  |       for (i=0; i<usermetacount; i++)
568  | 	{
569  | 	  free (usermetanames [i]);
570  | 	  free (usermetadata [i]);
571  | 	}
572  |       free (usermetanames);
573  |       free (usermetadata);
574  | 
575  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "What to do? (h for options) ");
576  |       CHKERRQ (ierr);
577  |       ierr = PetscSynchronizedFGets (PETSC_COMM_WORLD, stdin, 99, instring);
578  |       CHKERRQ (ierr);
579  | 
580  |       switch (instring [0])
581  | 	{
582  | 	case 'q':
583  | 	case 'Q':
584  | 	case 'x':
585  | 	case 'X':
586  | 	  {
587  | 	    if (dims < 3)
588  | 	      {
589  | 		ierr = PetscViewerDestroy (theviewer); CHKERRQ (ierr);
590  | 	      }
591  | 	    else
592  | 	      {
593  | 		ierr = GeomviewEnd (PETSC_COMM_WORLD); CHKERRQ (ierr);
594  | 	      }
595  | 	    ierr = PetscFinalize(); CHKERRQ (ierr);
596  | 	    return 0;
597  | 	  }
598  | 	case 't':
599  | 	case 'T':
600  | 	  {
601  | 	    transp=!transp;
602  | 	    break;
603  | 	  }
604  | 	case 'h':
605  | 	case 'H':
606  | 	case '?':
607  | 	  {
608  | 	    ierr = PetscPrintf (PETSC_COMM_WORLD, HELP_STRING);
609  | 	    break;
610  | 	  }
611  | 	case '0':
612  | 	case '1':
613  | 	case '2':
614  | 	case '3':
615  | 	case '4':
616  | 	case '5':
617  | 	case '6':
618  | 	case '7':
619  | 	case '8':
620  | 	case '9':
621  | 	  {
622  | 	    current_entry = atoi (instring);
623  | 	    break;
624  | 	  }
625  | 	case 'b':
626  | 	case 'B':
627  | 	  {
628  | 	    current_entry--;
629  | 	    break;
630  | 	  }
631  | 	case 'v':
632  | 	case 'V':
633  | 	  {
634  | 	    if (dims == 3)
635  | 	      display_field = (display_field+1) % fields;
636  | 	  }
637  | 	default:
638  | 	  current_entry++;
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  |     } */
647  | 
648  | #undef __FUNCT__
649  | #define __FUNCT__ "main"
650  | 
651  | /*++++++++++++++++++++++++++++++++++++++
652  |   This is
653  |   +latex+{\tt main()}.
654  |   +html+ <tt>main()</tt>.
655  | 
656  |   int main It returns an int to the OS.
657  | 
658  |   int argc Argument count.
659  | 
660  |   char *argv[] Arguments.
661  |   ++++++++++++++++++++++++++++++++++++++*/
662  | 
663  | int main (int argc, char *argv[])
664  | {
665  |   /* GnomeProgram *app; */
666  |   /* struct poptOption options [] = {
667  |     { "vector_max", 'vm', POPT_ARG_FLOAT, &vecmax, 0, "Reference vector length", "VECMAX" },
668  |     { NULL, '\0', 0, NULL, 0, NULL, NULL }}; */
669  |   int usermetacount=0, i, ierr;
670  |   char **usermetanames, **usermetadata, filename [200];
671  | 
672  |   /*+ After
673  |     +latex+{\tt PETSc}
674  |     +html+ <tt>PETSc</tt>
675  |     and glade/GNOME initialization, it gets the list of files matching the
676  |     basename. +*/
677  |   ierr = PetscInitialize (&argc, &argv, (char *)0, help); CHKERRQ (ierr);
678  | 
679  |   if (argc<2)
680  |     {
681  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Usage: tsview basename\n");
682  |       CHKERRQ (ierr);
683  |       return 1;
684  |     }
685  | 
686  | #ifdef DEBUG
687  |   ierr = PetscPrintf (PETSC_COMM_WORLD, "Command line:"); CHKERRQ (ierr);
688  |   for (i=0; i<argc; i++)
689  |     {
690  |       ierr = PetscPrintf (PETSC_COMM_WORLD, " %s", argv[i]); CHKERRQ (ierr);
691  |     }
692  |   ierr = PetscPrintf (PETSC_COMM_WORLD, "\n"); CHKERRQ (ierr);
693  | #endif
694  | 
695  |   vecmax = -1.0;
696  |   ierr = PetscOptionsGetScalar (PETSC_NULL, "-vector_max", &vecmax,PETSC_NULL);
697  |   CHKERRQ (ierr);
698  |   ierr = PetscOptionsHasName (PETSC_NULL, "-no_transparency", &transp);
699  |   CHKERRQ (ierr);
700  |   transp = !transp;
701  | 
702  |   /* Kludge alert!  Setting argc to avoid gnome_program_init errors;
703  |      fix: use GNOME arguments instead of PETSc. */
704  |   argc=2;
705  | 
706  |   gnome_program_init ("TSView", VERSION, LIBGNOMEUI_MODULE, argc, argv, NULL);
707  | 
708  |   strncpy (filename, GLADE_DIRECTORY, 187);
709  |   strcat (filename, "/tsview.glade");
710  |   xml = glade_xml_new (filename, NULL, NULL);
711  |   glade_xml_signal_autoconnect (xml);
712  | 
713  |   if (argc>1)
714  |     the_basename = argv[1];
715  |   else
716  |     {
717  |       /* Put in filter for .time0000000.cpu0000.meta */
718  |       gtk_widget_show (glade_xml_get_widget (xml, "open_fileselect"));
719  |     }
720  | 
721  |   if (refresh_stepnames ())
722  |     exit (1);
723  | 
724  |   DPRINTF ("Loading first timestep, creating distributed array\n",0);
725  |   strncpy (filename, basedirname, 198);
726  |   strcat (filename, "/");
727  |   strncat (filename, stepnames [0], 198 - strlen (stepnames [0]));
728  |   ierr = IlluMultiLoad (filename, &theda, minmax+1,minmax+3,minmax+5,
729  | 			&fieldtypes, &usermetacount, &usermetanames,
730  | 			&usermetadata);
731  |   CHKERRQ (ierr);
732  | 
733  |   /* Usermetadata xwidth, ywidth, zwidth override minmax in case IlluMulti
734  |      version of saved data is 0.1. */
735  |   for (i=0; i<usermetacount; i++)
736  |     {
737  |       if (!strncmp (usermetanames [i], "xwidth", 6))
738  | 	sscanf (usermetadata [i], "%lf", minmax+1);
739  |       else if (!strncmp (usermetanames [i], "ywidth", 6))
740  | 	sscanf (usermetadata [i], "%lf", minmax+3);
741  |       else if (!strncmp (usermetanames [i], "zwidth", 6))
742  | 	sscanf (usermetadata [i], "%lf", minmax+5);
743  |     }
744  | 
745  |   ierr = DAGetGlobalVector (theda, &global); CHKERRQ (ierr);
746  |   ierr = DAGetInfo (theda, &dimensions, PETSC_NULL,PETSC_NULL,PETSC_NULL,
747  | 		    PETSC_NULL,PETSC_NULL,PETSC_NULL, &num_fields,
748  | 		    PETSC_NULL,PETSC_NULL,PETSC_NULL); CHKERRQ (ierr);
749  | 
750  |   /* Main window title */
751  |   {
752  |     char main_window_title[100] = "TSView: ";
753  |     strncat (main_window_title, basename (the_basename), 90);
754  |     gtk_window_set_title
755  |       (GTK_WINDOW (glade_xml_get_widget (xml, "main_window")),
756  |        main_window_title);
757  |   }
758  |   gtk_widget_set_sensitive (glade_xml_get_widget (xml, "toolbar"), TRUE);
759  |   gtk_widget_show (glade_xml_get_widget (xml, "vbox1"));
760  | 
761  |   display_timestep (usermetacount, usermetanames, usermetadata);
762  | 
763  |   gtk_main();
764  | 
765  |   DPRINTF ("Finalizing and exitting.\n",0);
766  |   ierr = PetscFinalize (); CHKERRQ(ierr);
767  |   return 0;
768  | }