1    | /***************************************
2    |   $Header: /cvsroot/petscgraphics/tsview-ng.c,v 1.35 2004/11/30 14:35:54 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   | /*+ Declared in illuminator.c, these give the current number of triangles on
36   |   this node and corner coordinates and color information for each triangle. +*/
37   | extern int num_triangles;
38   | extern PetscScalar vertices[];
39   | 
40   | GladeXML *xml;
41   | /* Filename list */
42   | int entrynum=0, total_entries=0, current_timestep;
43   | char *the_basename, *basedirname, **stepnames=NULL;
44   | double current_time;
45   | 
46   | /* Window parameters and drawables */
47   | int width=0, height=0, bpp=3, nx, ny, dataview_count=1;
48   | GtkWidget *dataviews [1];
49   | guchar *rgbbuf [1] = { NULL }, scalar_rgb[120000], ternary_rgb[120000],
50   |   vector_rgb[120000], shear_rgb[120000];
51   | gboolean scalar_auto_set=TRUE, ternary_auto_set=TRUE, vector_auto_set=TRUE,
52   |   shear_auto_set=TRUE;
53   | double sizemag;
54   | PetscTruth transp;
55   | 
56   | /* PETSc structures etc. */
57   | DA theda;
58   | Vec global;
59   | PetscScalar minmax[6] = { 0.,1., 0.,1., 0.,1. };
60   | PetscScalar scales[11]; /* 2 scalar, 2 vector, 6 ternary, 1 tensor */
61   | field_plot_type *fieldtypes;
62   | int dimensions, num_fields, current_field, *field_index, num_variables[1],
63   |   **variable_indices;
64   | 
65   | /* First some primary functions which do stuff, then callbacks, then main(). */
66   | 
67   | #undef __FUNCT__
68   | #define __FUNCT__ "render_dataviews"
69   | 
70   | void render_dataviews ()
71   | {
72   |   int viewnum, nx,ny,nz, ierr;
73   | 
74   |   DPRINTF ("Rendering dataviews\n",0);
75   |   if (dataview_count != 1)
76   |     {
77   |       printf ("dataview_count != 1 is not yet supported\n");
78   |       exit(0);
79   |     }
80   |   for (viewnum=0; viewnum<dataview_count; viewnum++)
81   |     {
82   |       int nx,ny, xs,ys, xm,ym, i;
83   |       PetscScalar minval, maxval, refmag, *global_array;
84   |       GtkType type;
85   |       char thestatus [100];
86   | 
87   |       /* (Re)allocate buffer */
88   |       DPRINTF ("(Re)allocating RGB buffer\n",0);
89   |       if (!(rgbbuf [viewnum] =
90   | 	    (guchar *) realloc (rgbbuf [viewnum],
91   | 				bpp*width*height*sizeof(guchar)))) {
92   | 	  printf ("ERROR: can't reallocate RGB buffer\n");
93   | 	  exit (1); }
94   | 
95   |       /* Render into rgbbuf [viewnum] */
96   |       ierr = DAGetInfo (theda, PETSC_NULL, &nx,&ny,PETSC_NULL,
97   | 			PETSC_NULL,PETSC_NULL,PETSC_NULL, PETSC_NULL,
98   | 			PETSC_NULL,PETSC_NULL,PETSC_NULL); CHKERRQ (ierr);
99   |       ierr = DAGetCorners (theda, &xs,&ys,PETSC_NULL, &xm,&ym,PETSC_NULL);
100  |       CHKERRQ (ierr);
101  |       if (dimensions == 2)
102  | 	{
103  | 	  char maxes [6][20];
104  | 
105  | 	  ierr = VecGetArray (global, &global_array); CHKERRQ (ierr);
106  | 
107  | 	  /* Plot with automatic or manual scaling, as appropriate */
108  | 	  switch (fieldtypes [current_field])
109  | 	    {
110  | 	    case FIELD_SCALAR:
111  | 	      if (scalar_auto_set)
112  | 		{
113  | 		  auto_scale (global_array, xm*ym, num_fields, current_field,
114  | 			      fieldtypes [current_field], 2, scales);
115  | 		  snprintf (maxes[0], 19, "%g", scales[0]);
116  | 		  snprintf (maxes[1], 19, "%g", scales[1]);
117  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
118  | 						 (xml, "scalar_min_entry")),
119  | 				      maxes[0]);
120  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
121  | 						 (xml, "scalar_max_entry")),
122  | 				      maxes[1]);
123  | 		}
124  | 	      ierr = render_rgb_local_2d
125  | 		(rgbbuf [viewnum], width,height,width, bpp, global_array,
126  | 		 num_fields, current_field, fieldtypes [current_field],
127  | 		 scales, nx,ny, xs,ys, xm,ym);
128  | 	      CHKERRQ (ierr);
129  | 	      break;
130  | 
131  | 	    case FIELD_TERNARY:
132  | 	      if (ternary_auto_set)
133  | 		{
134  | 		  auto_scale (global_array, xm*ym, num_fields, current_field,
135  | 			      fieldtypes [current_field], 2, scales+2);
136  | 		  snprintf (maxes[0], 19, "%g", scales[2]);
137  | 		  snprintf (maxes[1], 19, "%g", scales[3]);
138  | 		  snprintf (maxes[2], 19, "%g", scales[4]);
139  | 		  snprintf (maxes[3], 19, "%g", scales[5]);
140  | 		  snprintf (maxes[4], 19, "%g", scales[6]);
141  | 		  snprintf (maxes[5], 19, "%g", scales[7]);
142  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
143  | 						 (xml, "ternary_1A_entry")),
144  | 				      maxes[0]);
145  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
146  | 						 (xml, "ternary_1B_entry")),
147  | 				      maxes[1]);
148  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
149  | 						 (xml, "ternary_2A_entry")),
150  | 				      maxes[2]);
151  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget 
152  | 						 (xml, "ternary_2B_entry")),
153  | 				      maxes[3]);
154  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
155  | 						 (xml, "ternary_3A_entry")),
156  | 				      maxes[4]);
157  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
158  | 						 (xml, "ternary_3B_entry")),
159  | 				      maxes[5]);
160  | 		}
161  | 	      ierr = render_rgb_local_2d
162  | 		(rgbbuf [viewnum], width,height,width, bpp, global_array,
163  | 		 num_fields, current_field, fieldtypes [current_field],
164  | 		 scales+2, nx,ny, xs,ys, xm,ym);
165  | 	      CHKERRQ (ierr);
166  | 	      break;
167  | 
168  | 	    case FIELD_VECTOR:
169  | 	      if (vector_auto_set)
170  | 		{
171  | 		  auto_scale (global_array, xm*ym, num_fields, current_field,
172  | 			      fieldtypes [current_field], 2, scales+8);
173  | 		  snprintf (maxes[0], 19, "%g", scales[9]);
174  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
175  | 						 (xml, "vector_max_entry")),
176  | 				      maxes[0]);
177  | 		}
178  | 	      ierr = render_rgb_local_2d
179  | 		(rgbbuf [viewnum], width,height,width, bpp, global_array,
180  | 		 num_fields, current_field, fieldtypes [current_field],
181  | 		 scales+8, nx,ny, xs,ys, xm,ym);
182  | 	      CHKERRQ (ierr);
183  | 	      break;
184  | 
185  | 	    case FIELD_TENSOR_SHEAR:
186  | 	      if (shear_auto_set)
187  | 		{
188  | 		  auto_scale (global_array, xm*ym, num_fields, current_field,
189  | 			      fieldtypes [current_field], 2, scales+10);
190  | 		  snprintf (maxes[0], 19, "%g", scales[10]);
191  | 		  gtk_entry_set_text (GTK_ENTRY (glade_xml_get_widget
192  | 						 (xml, "shear_max_entry")),
193  | 				      maxes[0]);
194  | 		}
195  | 	      ierr = render_rgb_local_2d
196  | 		(rgbbuf [viewnum], width,height,width, bpp, global_array,
197  | 		 num_fields, current_field, fieldtypes [current_field],
198  | 		 scales+10, nx,ny, xs,ys, xm,ym);
199  | 	      CHKERRQ (ierr);
200  | 	      break;
201  | 	    }
202  | 
203  | 	  ierr = VecRestoreArray (global, &global_array); CHKERRQ (ierr);
204  | 	}
205  |       else
206  | 	{
207  | 	  /* Fixed negative z-direction for now */
208  | 	  PetscScalar eye[3], dir[3] = {0, 0, -1.}, right[3] = {.5, 0., 0.};
209  | 	  eye[0] = 0.5*(minmax[0]+minmax[1]);
210  | 	  eye[1] = 0.5*(minmax[2]+minmax[3]);
211  | 	  eye[2] = minmax[5] + minmax[1]-minmax[0];
212  | 
213  | 	  ierr = DATriangulate
214  | 	    (theda, global, current_field, minmax, PETSC_DECIDE, PETSC_NULL,
215  | 	     PETSC_NULL, PETSC_FALSE, PETSC_FALSE, PETSC_FALSE); CHKERRQ(ierr);
216  | 
217  | 	  for (i=0; i<width*height; i++)
218  | 	    {
219  | 	      rgbbuf[viewnum][4*i] = 0x50;
220  | 	      rgbbuf[viewnum][4*i+1] = 0x50;
221  | 	      rgbbuf[viewnum][4*i+2] = 0x50;
222  | 	      rgbbuf[viewnum][4*i+3] = 0xFF;
223  | 	    }
224  | 	  ierr = render_rgb_local_3d
225  | 	    (rgbbuf [viewnum], width,height, bpp, num_triangles, vertices,
226  | 	     eye, dir, right);
227  | 	  for (i=0; i<width*height; i++)
228  | 	    {
229  | 	      guchar tmp = rgbbuf[viewnum][4*i];
230  | 	      rgbbuf[viewnum][4*i] = rgbbuf[viewnum][4*i+2];
231  | 	      rgbbuf[viewnum][4*i+2] = tmp;
232  | 	    }
233  | 	  num_triangles = 0;
234  | 	}
235  | 
236  |       /* Draw buffer onto window */
237  |       DPRINTF ("Painting rgb%s buffer onto window\n", (bpp==4) ? "_32" : "");
238  |       if (!dataviews [viewnum])
239  | 	dataviews [viewnum] = glade_xml_get_widget (xml, "plot_area");
240  |       gtk_drawing_area_size (GTK_DRAWING_AREA (dataviews [viewnum]),
241  | 			     width, height);
242  |       if (bpp == 3)
243  | 	gdk_draw_rgb_image (dataviews [viewnum]->window,
244  | 			    dataviews[viewnum]->style->fg_gc[GTK_STATE_NORMAL],
245  | 			    0, 0, width, height, GDK_RGB_DITHER_MAX,
246  | 			    rgbbuf [viewnum], width * bpp);
247  |       else if (bpp == 4)
248  | 	gdk_draw_rgb_32_image (dataviews [viewnum]->window,
249  | 			    dataviews[viewnum]->style->fg_gc[GTK_STATE_NORMAL],
250  | 			    0, 0, width, height, GDK_RGB_DITHER_MAX,
251  | 			    rgbbuf [viewnum], width * bpp);
252  |     }
253  | }
254  | 
255  | 
256  | #undef __FUNCT__
257  | #define __FUNCT__ "myfilter"
258  | 
259  | /*+ Little variable for myfilter() and refresh_stepnames(). +*/
260  | static char *basefilename;
261  | 
262  | /*++++++++++++++++++++++++++++++++++++++
263  |   This function returns non-zero for "qualifying" file names which start with
264  |   the stored files' basename.time and end with
265  |   +latex+{\tt .cpu0000.meta}.
266  |   +html+ <tt>.cpu0000.meta</tt>.
267  |   It is used as the
268  |   +latex+{\tt select()} function for {\tt scandir()} in {\tt main()}.
269  |   +html+ <tt>select()</tt> function for <tt>scandir()</tt> in <tt>main()</tt>.
270  | 
271  |   int myfilter Returns non-zero for qualifying filenames.
272  | 
273  |   const struct dirent *direntry Directory entry with filename to test.
274  |   ++++++++++++++++++++++++++++++++++++++*/
275  | 
276  | int myfilter (const struct dirent *direntry)
277  | {
278  |   if ((!strncmp (direntry->d_name, basefilename, strlen(basefilename))) &&
279  |       (!strncmp (direntry->d_name + strlen(basefilename), ".time", 5)))
280  |     return (!strncmp (direntry->d_name + strlen(direntry->d_name) - 13,
281  | 		      ".cpu0000.meta", 13));
282  |   return 0;
283  | }
284  | 
285  | 
286  | void on_plot_area_expose_event (GtkWidget *widget, GdkEventExpose *event,
287  | 				gpointer user_data)
288  | {
289  |   if (bpp == 3)
290  |     gdk_draw_rgb_image (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
291  | 			0, 0, width, height, GDK_RGB_DITHER_MAX, rgbbuf [0],
292  | 			width * bpp);
293  |   else if (bpp == 4)
294  |     gdk_draw_rgb_32_image (widget->window,
295  | 			   widget->style->fg_gc[GTK_STATE_NORMAL],
296  | 			   0, 0, width, height, GDK_RGB_DITHER_MAX, rgbbuf [0],
297  | 			   width * bpp);
298  | }
299  | 
300  | void on_scalar_scale_area_expose_event
301  | (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
302  | { gdk_draw_rgb_image (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
303  | 		      0, 0, 200, 200, GDK_RGB_DITHER_MAX, scalar_rgb, 600); }
304  | 
305  | void on_ternary_scale_area_expose_event
306  | (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
307  | { gdk_draw_rgb_image (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
308  | 		      0, 0, 200, 200, GDK_RGB_DITHER_MAX, ternary_rgb, 600); }
309  | 
310  | void on_vector_scale_area_expose_event
311  | (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
312  | { gdk_draw_rgb_image (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
313  | 		      0, 0, 200, 200, GDK_RGB_DITHER_MAX, vector_rgb, 600); }
314  | 
315  | void on_shear_scale_area_expose_event
316  | (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
317  | { gdk_draw_rgb_image (widget->window, widget->style->fg_gc[GTK_STATE_NORMAL],
318  | 		      0, 0, 200, 200, GDK_RGB_DITHER_MAX, shear_rgb, 600); }
319  | 
320  | void on_scalar_auto_checkbutton_toggled
321  | (GtkWidget *thebutton, gpointer user_data)
322  | {
323  |   scalar_auto_set = gtk_toggle_button_get_active
324  |     (GTK_TOGGLE_BUTTON (thebutton));
325  |   if (scalar_auto_set)
326  |     {
327  |       gtk_widget_set_sensitive
328  | 	(glade_xml_get_widget (xml, "scalar_min_label"), FALSE);
329  |       gtk_widget_set_sensitive
330  | 	(glade_xml_get_widget (xml, "scalar_max_label"), FALSE);
331  |       gtk_widget_set_sensitive
332  | 	(glade_xml_get_widget (xml, "scalar_min_entry"), FALSE);
333  |       gtk_widget_set_sensitive
334  | 	(glade_xml_get_widget (xml, "scalar_max_entry"), FALSE);
335  |     }
336  |   else
337  |     {
338  |       gtk_widget_set_sensitive
339  | 	(glade_xml_get_widget (xml, "scalar_min_label"), TRUE);
340  |       gtk_widget_set_sensitive
341  | 	(glade_xml_get_widget (xml, "scalar_max_label"), TRUE);
342  |       gtk_widget_set_sensitive
343  | 	(glade_xml_get_widget (xml, "scalar_min_entry"), TRUE);
344  |       gtk_widget_set_sensitive
345  | 	(glade_xml_get_widget (xml, "scalar_max_entry"), TRUE);
346  |     }
347  | }
348  | 
349  | void on_ternary_auto_checkbutton_toggled
350  | (GtkWidget *thebutton, gpointer user_data)
351  | {
352  |   ternary_auto_set = gtk_toggle_button_get_active
353  |     (GTK_TOGGLE_BUTTON (thebutton));
354  |   if (ternary_auto_set)
355  |     {
356  |       gtk_widget_set_sensitive
357  | 	(glade_xml_get_widget (xml, "ternary_1A_label"), FALSE);
358  |       gtk_widget_set_sensitive
359  | 	(glade_xml_get_widget (xml, "ternary_1B_label"), FALSE);
360  |       gtk_widget_set_sensitive
361  | 	(glade_xml_get_widget (xml, "ternary_2A_label"), FALSE);
362  |       gtk_widget_set_sensitive
363  | 	(glade_xml_get_widget (xml, "ternary_2B_label"), FALSE);
364  |       gtk_widget_set_sensitive
365  | 	(glade_xml_get_widget (xml, "ternary_3A_label"), FALSE);
366  |       gtk_widget_set_sensitive
367  | 	(glade_xml_get_widget (xml, "ternary_3B_label"), FALSE);
368  |       gtk_widget_set_sensitive
369  | 	(glade_xml_get_widget (xml, "ternary_1A_entry"), FALSE);
370  |       gtk_widget_set_sensitive
371  | 	(glade_xml_get_widget (xml, "ternary_1B_entry"), FALSE);
372  |       gtk_widget_set_sensitive
373  | 	(glade_xml_get_widget (xml, "ternary_2A_entry"), FALSE);
374  |       gtk_widget_set_sensitive
375  | 	(glade_xml_get_widget (xml, "ternary_2B_entry"), FALSE);
376  |       gtk_widget_set_sensitive
377  | 	(glade_xml_get_widget (xml, "ternary_3A_entry"), FALSE);
378  |       gtk_widget_set_sensitive
379  | 	(glade_xml_get_widget (xml, "ternary_3B_entry"), FALSE);
380  |     }
381  |   else
382  |     {
383  |       gtk_widget_set_sensitive
384  | 	(glade_xml_get_widget (xml, "ternary_1A_label"), TRUE);
385  |       gtk_widget_set_sensitive
386  | 	(glade_xml_get_widget (xml, "ternary_1B_label"), TRUE);
387  |       gtk_widget_set_sensitive
388  | 	(glade_xml_get_widget (xml, "ternary_2A_label"), TRUE);
389  |       gtk_widget_set_sensitive
390  | 	(glade_xml_get_widget (xml, "ternary_2B_label"), TRUE);
391  |       gtk_widget_set_sensitive
392  | 	(glade_xml_get_widget (xml, "ternary_3A_label"), TRUE);
393  |       gtk_widget_set_sensitive
394  | 	(glade_xml_get_widget (xml, "ternary_3B_label"), TRUE);
395  |       gtk_widget_set_sensitive
396  | 	(glade_xml_get_widget (xml, "ternary_1A_entry"), TRUE);
397  |       gtk_widget_set_sensitive
398  | 	(glade_xml_get_widget (xml, "ternary_1B_entry"), TRUE);
399  |       gtk_widget_set_sensitive
400  | 	(glade_xml_get_widget (xml, "ternary_2A_entry"), TRUE);
401  |       gtk_widget_set_sensitive
402  | 	(glade_xml_get_widget (xml, "ternary_2B_entry"), TRUE);
403  |       gtk_widget_set_sensitive
404  | 	(glade_xml_get_widget (xml, "ternary_3A_entry"), TRUE);
405  |       gtk_widget_set_sensitive
406  | 	(glade_xml_get_widget (xml, "ternary_3B_entry"), TRUE);
407  |     }
408  | }
409  | 
410  | void on_vector_auto_checkbutton_toggled
411  | (GtkWidget *thebutton, gpointer user_data)
412  | {
413  |   vector_auto_set = gtk_toggle_button_get_active
414  |     (GTK_TOGGLE_BUTTON (thebutton));
415  |   if (vector_auto_set)
416  |     {
417  |       gtk_widget_set_sensitive
418  | 	(glade_xml_get_widget (xml, "vector_max_label"), FALSE);
419  |       gtk_widget_set_sensitive
420  | 	(glade_xml_get_widget (xml, "vector_symm_label"), FALSE);
421  |       gtk_widget_set_sensitive
422  | 	(glade_xml_get_widget (xml, "vector_max_entry"), FALSE);
423  |       gtk_widget_set_sensitive
424  | 	(glade_xml_get_widget (xml, "vector_symm_spinbutton"), FALSE);
425  |     }
426  |   else
427  |     {
428  |       gtk_widget_set_sensitive
429  | 	(glade_xml_get_widget (xml, "vector_max_label"), TRUE);
430  |       gtk_widget_set_sensitive
431  | 	(glade_xml_get_widget (xml, "vector_symm_label"), TRUE);
432  |       gtk_widget_set_sensitive
433  | 	(glade_xml_get_widget (xml, "vector_max_entry"), TRUE);
434  |       gtk_widget_set_sensitive
435  | 	(glade_xml_get_widget (xml, "vector_symm_spinbutton"), TRUE);
436  |     }
437  | }
438  | 
439  | void on_shear_auto_checkbutton_toggled
440  | (GtkWidget *thebutton, gpointer user_data)
441  | {
442  |   shear_auto_set = gtk_toggle_button_get_active
443  |     (GTK_TOGGLE_BUTTON (thebutton));
444  |   if (shear_auto_set)
445  |     {
446  |       gtk_widget_set_sensitive
447  | 	(glade_xml_get_widget (xml, "shear_max_label"), FALSE);
448  |       gtk_widget_set_sensitive
449  | 	(glade_xml_get_widget (xml, "shear_max_entry"), FALSE);
450  |     }
451  |   else
452  |     {
453  |       gtk_widget_set_sensitive
454  | 	(glade_xml_get_widget (xml, "shear_max_label"), TRUE);
455  |       gtk_widget_set_sensitive
456  | 	(glade_xml_get_widget (xml, "shear_max_entry"), TRUE);
457  |     }
458  | }
459  | 
460  | void on_scalar_min_entry_changed (GtkWidget *theentry, gpointer user_data)
461  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
462  |   sscanf (entrytext, "%lf", scales); }
463  | 
464  | void on_scalar_max_entry_changed (GtkWidget *theentry, gpointer user_data)
465  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
466  |   sscanf (entrytext, "%lf", scales+1); }
467  | 
468  | void on_ternary_1A_entry_changed (GtkWidget *theentry, gpointer user_data)
469  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
470  |   sscanf (entrytext, "%lf", scales+2); }
471  | 
472  | void on_ternary_1B_entry_changed (GtkWidget *theentry, gpointer user_data)
473  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
474  |   sscanf (entrytext, "%lf", scales+3); }
475  | 
476  | void on_ternary_2A_entry_changed (GtkWidget *theentry, gpointer user_data)
477  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
478  |   sscanf (entrytext, "%lf", scales+4); }
479  | 
480  | void on_ternary_2B_entry_changed (GtkWidget *theentry, gpointer user_data)
481  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
482  |   sscanf (entrytext, "%lf", scales+5); }
483  | 
484  | void on_ternary_3A_entry_changed (GtkWidget *theentry, gpointer user_data)
485  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
486  |   sscanf (entrytext, "%lf", scales+6); }
487  | 
488  | void on_ternary_3B_entry_changed (GtkWidget *theentry, gpointer user_data)
489  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
490  |   sscanf (entrytext, "%lf", scales+7); }
491  | 
492  | void on_vector_max_entry_changed (GtkWidget *theentry, gpointer user_data)
493  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
494  |   sscanf (entrytext, "%lf", scales+9); }
495  | 
496  | void on_vector_symm_spinbutton_changed (GtkWidget *theentry,gpointer user_data)
497  | { int symmetry;
498  |   G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
499  |   sscanf (entrytext, "%d", &symmetry);
500  |   /* Because this sometimes sends events with outrageous symmetry numbers */
501  |   if (symmetry <= 10) {
502  |     render_scale_2d (vector_rgb, 200, 200, 3, FIELD_VECTOR, symmetry);
503  |     on_vector_scale_area_expose_event
504  |       (glade_xml_get_widget (xml, "vector_scale_area"), NULL, user_data); }}
505  | 
506  | void on_shear_max_entry_changed (GtkWidget *theentry, gpointer user_data)
507  | { G_CONST_RETURN gchar *entrytext = gtk_entry_get_text (GTK_ENTRY (theentry));
508  |   sscanf (entrytext, "%lf", scales+10); }
509  | 
510  | /*++++++++++++++++++++++++++++++++++++++
511  |   This loads the names of the files into a long list.
512  |   ++++++++++++++++++++++++++++++++++++++*/
513  | 
514  | int refresh_stepnames ()
515  | {
516  |   struct dirent **namelist;
517  |   char *filec, *dirc;
518  |   int i, ierr;
519  | 
520  |   filec = strdup (the_basename);
521  |   dirc = strdup (the_basename);
522  |   basefilename = basename (filec);
523  |   basedirname = dirname (dirc);
524  | 
525  |   total_entries = scandir (basedirname, &namelist, myfilter, alphasort);
526  |   if (!total_entries)
527  |     {
528  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "No such files\n");
529  |       CHKERRQ (ierr);
530  |       return 1;
531  |     }
532  |   if (total_entries < 0)
533  |     {
534  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Error scanning directory %s\n",
535  | 			  basedirname); CHKERRQ (ierr);
536  |       ierr = PetscFinalize (); CHKERRQ(ierr);
537  |       return 1;
538  |     }
539  |   DPRINTF ("%d eligible files:\n", total_entries);
540  | 
541  |   if (!(stepnames = (char **) realloc
542  | 	(stepnames, total_entries*sizeof (char *))))
543  |     {
544  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Error allocating memory\n");
545  |       CHKERRQ (ierr);
546  |       return 1;
547  |     }
548  |   for (i=0; i<total_entries; i++)
549  |     {
550  |       int filength = strlen(namelist[i]->d_name);
551  | 
552  |       stepnames [i] = (char *) malloc ((filength-12)*sizeof(char));
553  |       strncpy (stepnames [i], namelist[i]->d_name, filength-13);
554  |       stepnames [i] [filength-13] = '\0';
555  |       free (namelist[i]);
556  |       DPRINTF ("[%d] %s\n", i, stepnames [i]);
557  |       CHKERRQ (ierr);
558  |     }
559  | 
560  |   free (namelist);
561  |   return 0;
562  | }
563  | 
564  | void change_variable (GtkWidget *widget, gpointer user_data)
565  | {
566  |   current_field = GPOINTER_TO_INT (widget);
567  |   DPRINTF ("Switching to variable %d\n", current_field);
568  |   render_dataviews();
569  |   gtk_notebook_set_current_page
570  |     (GTK_NOTEBOOK (glade_xml_get_widget (xml, "scale_notebook")),
571  |      fieldtypes [current_field] >> 4);
572  | }
573  | 
574  | void on_mag_spin_value_changed (GtkWidget *mag_spin, gpointer user_data) {
575  |   G_CONST_RETURN gchar *entrytext;
576  |   entrytext = gtk_entry_get_text (GTK_ENTRY (mag_spin));
577  |   sscanf (entrytext, "%lf", &sizemag);
578  |   width = (int) (minmax [1] * sizemag);
579  |   height = (int) (minmax [3] * sizemag);
580  | 
581  |   render_dataviews();
582  | }
583  | 
584  | 
585  | void display_timestep (int usermetacount, char **usermetanames,
586  | 		       char **usermetadata)
587  | {
588  |   int i;
589  |   static char step_buffer [20], time_buffer [20];
590  | 
591  |   for (i=0; i<usermetacount; i++)
592  |     {
593  |       if (!strncmp (usermetanames [i], "timestep", 8))
594  | 	sscanf (usermetadata [i], "%d", &current_timestep);
595  |       else if (!strncmp (usermetanames [i], "time", 4))
596  | 	sscanf (usermetadata [i], "%lf", &current_time);
597  |     }
598  |   snprintf (step_buffer, 19, "Timestep: %d", current_timestep);
599  |   gtk_label_set_text (GTK_LABEL (glade_xml_get_widget (xml, "timestep_label")),
600  | 		      step_buffer);
601  |   snprintf (time_buffer, 19, "Time: %g", current_time);
602  |   gtk_label_set_text (GTK_LABEL (glade_xml_get_widget (xml, "time_label")),
603  | 		      time_buffer);
604  | 
605  |   on_mag_spin_value_changed (glade_xml_get_widget (xml, "mag_spin"), NULL);
606  | }
607  | 
608  | 
609  | void on_save_activate (GtkWidget *widget, gpointer user_data)
610  | {
611  |   int i, ierr;
612  |   char **usermetanames, **usermetadata, filename [200], number[10];
613  |   FILE *outppm;
614  | 
615  |   strncpy (filename, basedirname, 198);
616  |   strcat (filename, "/");
617  |   strncat (filename, stepnames [entrynum], 198 - strlen (filename));
618  |   snprintf (number, 9, "-f%d", current_field);
619  |   strncat (filename, number, 198 - strlen (filename));
620  |   strncat (filename, ".ppm", 198 - strlen (filename));
621  | 
622  |   DPRINTF ("Saving image with filename %s\n", filename);
623  |   if (!(outppm = fopen (filename, "w")))
624  |     {
625  |       PetscPrintf (PETSC_COMM_WORLD, "Error opening file %s\n", filename);
626  |       return;
627  |     }
628  |   fprintf (outppm, "P6\n%d %d\n255\n", width, height);
629  |   /* If more than 3 bytes per pixel, write just the first three (RGB) */
630  |   if (bpp == 3)
631  |     fwrite (rgbbuf [0], sizeof (guchar), 3*width*height, outppm);
632  |   else
633  |     for (i=0; i<width*height; i++)
634  |       fwrite (rgbbuf [0] + i*bpp, sizeof (guchar), 3, outppm);
635  |   fclose (outppm);
636  | }
637  | 
638  | 
639  | void on_timestep_spin_value_changed (GtkWidget *timestep_spin, gpointer user_data) {
640  |   int usermetacount, ierr;
641  |   G_CONST_RETURN gchar *entrytext;
642  |   char **usermetanames, **usermetadata, filename [200], **field_name;
643  |   GtkWidget *variable_options, *variable_menu, **variable_item;
644  | 
645  |   entrytext = gtk_entry_get_text (GTK_ENTRY (timestep_spin));
646  |   sscanf (entrytext, "%d", &entrynum);
647  | 
648  |   /* Bound the entrynum between 0 and total_entries-1; -11 is the minimum of
649  |      the widget (from jump), 1000001 is the maximum. */
650  |   if ((entrynum < 0 && entrynum != -11) || entrynum == 1000001)
651  |     entrynum = total_entries-1;
652  |   if ((entrynum >= total_entries && entrynum != 1000001) || entrynum == -11)
653  |     entrynum = 0;
654  |   gtk_spin_button_set_value (GTK_SPIN_BUTTON (timestep_spin),
655  | 			     (gfloat) entrynum);
656  | 
657  |   strncpy (filename, basedirname, 198);
658  |   strcat (filename, "/");
659  |   strncat (filename, stepnames [entrynum], 198 - strlen (filename));
660  | 
661  |   ierr = IlluMultiRead (theda, global, filename, &usermetacount,&usermetanames,
662  | 			&usermetadata); CHKERRQ (ierr);
663  | 
664  |   display_timestep (usermetacount, usermetanames, usermetadata);
665  | }
666  | 
667  | 
668  | void on_refresh_activate (GtkWidget *none, gpointer user_data) {
669  |   if (refresh_stepnames ()) exit (1); }
670  | 
671  | 
672  | void on_about_activate (GtkWidget *none, gpointer user_data) {
673  |   gtk_widget_show (glade_xml_get_widget (xml, "about")); }
674  | 
675  | 
676  | #undef __FUNCT__
677  | #define __FUNCT__ "main"
678  | 
679  | /*++++++++++++++++++++++++++++++++++++++
680  |   This is
681  |   +latex+{\tt main()}.
682  |   +html+ <tt>main()</tt>.
683  | 
684  |   int main It returns an int to the OS.
685  | 
686  |   int argc Argument count.
687  | 
688  |   char *argv[] Arguments.
689  |   ++++++++++++++++++++++++++++++++++++++*/
690  | 
691  | int main (int argc, char *argv[])
692  | {
693  |   int usermetacount=0, i, ierr;
694  |   char **usermetanames, **usermetadata, filename [200], **field_name;
695  |   GtkWidget *variable_options, *variable_menu, **variable_item;
696  | 
697  |   /*+ After
698  |     +latex+{\tt PETSc}
699  |     +html+ <tt>PETSc</tt>
700  |     and glade/GNOME initialization, it gets the list of files matching the
701  |     basename. +*/
702  |   ierr = PetscInitialize (&argc, &argv, (char *)0, help); CHKERRQ (ierr);
703  | 
704  |   if (argc<2)
705  |     {
706  |       ierr = PetscPrintf (PETSC_COMM_WORLD, "Usage: tsview basename\n");
707  |       CHKERRQ (ierr);
708  |       return 1;
709  |     }
710  | 
711  | #ifdef DEBUG
712  |   ierr = PetscPrintf (PETSC_COMM_WORLD, "Command line:"); CHKERRQ (ierr);
713  |   for (i=0; i<argc; i++)
714  |     {
715  |       ierr = PetscPrintf (PETSC_COMM_WORLD, " %s", argv[i]); CHKERRQ (ierr);
716  |     }
717  |   ierr = PetscPrintf (PETSC_COMM_WORLD, "\n"); CHKERRQ (ierr);
718  | #endif
719  | 
720  |   ierr = PetscOptionsHasName (PETSC_NULL, "-no_transparency", &transp);
721  |   CHKERRQ (ierr);
722  |   transp = !transp;
723  | 
724  |   /* Kludge alert!  Setting argc to avoid gnome_program_init errors;
725  |      fix: use GNOME arguments instead of PETSc. */
726  |   argc=2;
727  | 
728  |   DPRINTF ("Running gnome_program_init with argc=%d\n", argc);
729  |   gnome_program_init ("TSView", VERSION, LIBGNOMEUI_MODULE, argc, argv, NULL);
730  | 
731  |   strncpy (filename, GLADE_DIRECTORY, 187);
732  |   strcat (filename, "/tsview.glade");
733  |   DPRINTF ("Loading Glade file %s\n", filename);
734  |   xml = glade_xml_new (filename, NULL, NULL);
735  |   glade_xml_signal_autoconnect (xml);
736  | 
737  |   if (argc>1)
738  |     the_basename = argv[1];
739  |   else
740  |     {
741  |       /* Put in filter for .time0000000.cpu0000.meta */
742  |       gtk_widget_show (glade_xml_get_widget (xml, "open_fileselect"));
743  |     }
744  | 
745  |   DPRINTF ("Loading list of timestep names\n",0);
746  |   if (refresh_stepnames ())
747  |     exit (1);
748  | 
749  |   DPRINTF ("Loading first timestep, creating distributed array\n",0);
750  |   strncpy (filename, basedirname, 198);
751  |   strcat (filename, "/");
752  |   strncat (filename, stepnames [0], 198 - strlen (stepnames [0]));
753  |   ierr = IlluMultiLoad (filename, &theda, minmax+1,minmax+3,minmax+5,
754  | 			&fieldtypes, &usermetacount, &usermetanames,
755  | 			&usermetadata);
756  |   CHKERRQ (ierr);
757  | 
758  |   /* Usermetadata xwidth, ywidth, zwidth override minmax in case IlluMulti
759  |      version of saved data is 0.1. */
760  |   DPRINTF ("Checking usermetadata for width information\n",0);
761  |   for (i=0; i<usermetacount; i++)
762  |     {
763  |       if (!strncmp (usermetanames [i], "xwidth", 6))
764  | 	sscanf (usermetadata [i], "%lf", minmax+1);
765  |       else if (!strncmp (usermetanames [i], "ywidth", 6))
766  | 	sscanf (usermetadata [i], "%lf", minmax+3);
767  |       else if (!strncmp (usermetanames [i], "zwidth", 6))
768  | 	sscanf (usermetadata [i], "%lf", minmax+5);
769  |     }
770  | 
771  |   DPRINTF ("Getting distributed array global vector and info\n",0);
772  |   ierr = DAGetGlobalVector (theda, &global); CHKERRQ (ierr);
773  |   ierr = DAGetInfo (theda, &dimensions, PETSC_NULL,PETSC_NULL,PETSC_NULL,
774  | 		    PETSC_NULL,PETSC_NULL,PETSC_NULL, &num_fields,
775  | 		    PETSC_NULL,PETSC_NULL,PETSC_NULL); CHKERRQ (ierr);
776  |   if (dimensions == 1)
777  |     SETERRQ (PETSC_ERR_ARG_OUTOFRANGE, "tsview-ng only supports 2-D or 3-D distributed arrays.")
778  |   else if (dimensions == 2)
779  |     bpp = 3;
780  |   else
781  |     bpp = 4;
782  | 
783  |   /* Build menu of field variables */
784  |   variable_options = glade_xml_get_widget (xml, "variable_menu");
785  |   gtk_option_menu_remove_menu (GTK_OPTION_MENU (variable_options));
786  |   variable_menu = gtk_menu_new ();
787  |   variable_item = (GtkWidget **) malloc (num_fields * sizeof (GtkWidget *));
788  |   field_name = (char **) malloc (num_fields * sizeof (char *));
789  |   field_index = (int *) malloc (num_fields * sizeof (int));
790  |   /* For now, use scalar plots for all types in 3-D */
791  |   if (dimensions == 2)
792  |     field_indices (num_fields, dimensions, fieldtypes, field_index);
793  |   else
794  |     for (i=0; i<num_fields; i++)
795  |       field_index[i] = i;
796  |   DPRINTF ("Field indices:\n",0);
797  |   for (i=0; i<num_fields && field_index [i] != -1; i++)
798  |     {
799  |       ierr = DAGetFieldName (theda, field_index [i], field_name+i);
800  |       CHKERRQ (ierr);
801  |       DPRINTF ("%d index %d name %s\n", i, field_index [i], field_name [i]);
802  |       variable_item [i] = gtk_menu_item_new_with_label (field_name [i]);
803  |       gtk_menu_append (GTK_MENU (variable_menu), variable_item [i]);
804  |       gtk_signal_connect_object (GTK_OBJECT (variable_item [i]), "activate",
805  | 				 GTK_SIGNAL_FUNC (change_variable),
806  | 				 GINT_TO_POINTER (field_index [i]));
807  |       gtk_widget_show (variable_item [i]);
808  |     }
809  |   gtk_option_menu_set_menu (GTK_OPTION_MENU (variable_options), variable_menu);
810  |   gtk_widget_show (variable_menu);
811  |   gtk_widget_show (variable_options);
812  | 
813  |   /* Scale images */
814  |   render_scale_2d (scalar_rgb, 200, 200, 3, FIELD_SCALAR, 1);
815  |   render_scale_2d (ternary_rgb, 200, 200, 3, FIELD_TERNARY, 1);
816  |   render_scale_2d (vector_rgb, 200, 200, 3, FIELD_VECTOR, 1);
817  |   render_scale_2d (shear_rgb, 200, 200, 3, FIELD_TENSOR_SHEAR, 1);
818  | 
819  |   gtk_notebook_set_current_page
820  |     (GTK_NOTEBOOK (glade_xml_get_widget (xml, "scale_notebook")),
821  |      fieldtypes [0] >> 4);
822  | 
823  |   /* Main window title */
824  |   {
825  |     char main_window_title[100] = "TSView: ";
826  |     GtkWidget *main_window = glade_xml_get_widget (xml, "main_window");
827  | 
828  |     strncat (main_window_title, basename (the_basename), 90);
829  |     gtk_window_set_title (GTK_WINDOW (main_window), main_window_title);
830  |     gtk_widget_show (main_window);
831  |   }
832  | 
833  |   DPRINTF ("Displaying first timestep\n",0);
834  |   display_timestep (usermetacount, usermetanames, usermetadata);
835  | 
836  |   DPRINTF ("Running main loop\n",0);
837  |   gtk_main();
838  | 
839  |   DPRINTF ("Finalizing and exitting.\n",0);
840  |   ierr = PetscFinalize (); CHKERRQ(ierr);
841  |   return 0;
842  | }